diff --git a/patches-4.15/cameras.patch b/patches-4.15/cameras.patch new file mode 100644 index 000000000..a17ed470c --- /dev/null +++ b/patches-4.15/cameras.patch @@ -0,0 +1,150 @@ +From 5549632053d4ae06867f383694553f7af27e40c9 Mon Sep 17 00:00:00 2001 +From: Jake Day +Date: Fri, 2 Feb 2018 11:07:32 -0500 +Subject: initial support for surface cameras + + +diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c +index 28b91b7..0e5989c 100644 +--- a/drivers/media/usb/uvc/uvc_driver.c ++++ b/drivers/media/usb/uvc/uvc_driver.c +@@ -2277,6 +2277,46 @@ MODULE_PARM_DESC(timeout, "Streaming control requests timeout"); + * though they are compliant. + */ + static const struct usb_device_id uvc_ids[] = { ++ /* Microsoft Surface Pro 3 Front */ ++ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE ++ | USB_DEVICE_ID_MATCH_INT_INFO, ++ .idVendor = 0x045e, ++ .idProduct = 0x07be, ++ .bInterfaceClass = USB_CLASS_VIDEO, ++ .bInterfaceSubClass = 1, ++ .bInterfaceProtocol = 1 }, ++ /* Microsoft Surface Pro 3 Rear */ ++ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE ++ | USB_DEVICE_ID_MATCH_INT_INFO, ++ .idVendor = 0x045e, ++ .idProduct = 0x07bf, ++ .bInterfaceClass = USB_CLASS_VIDEO, ++ .bInterfaceSubClass = 1, ++ .bInterfaceProtocol = 1 }, ++ /* Microsoft Surface Pro 4 Cam */ ++ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE ++ | USB_DEVICE_ID_MATCH_INT_INFO, ++ .idVendor = 0x045e, ++ .idProduct = 0x090c, ++ .bInterfaceClass = USB_CLASS_VIDEO, ++ .bInterfaceSubClass = 1, ++ .bInterfaceProtocol = 1 }, ++ /* Microsoft Surface Book Cam 1 */ ++ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE ++ | USB_DEVICE_ID_MATCH_INT_INFO, ++ .idVendor = 0x045e, ++ .idProduct = 0x090b, ++ .bInterfaceClass = USB_CLASS_VIDEO, ++ .bInterfaceSubClass = 1, ++ .bInterfaceProtocol = 1 }, ++ /* Microsoft Surface Book Cam 2 */ ++ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE ++ | USB_DEVICE_ID_MATCH_INT_INFO, ++ .idVendor = 0x045e, ++ .idProduct = 0x091a, ++ .bInterfaceClass = USB_CLASS_VIDEO, ++ .bInterfaceSubClass = 1, ++ .bInterfaceProtocol = 1 }, + /* LogiLink Wireless Webcam */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, +diff --git a/drivers/staging/media/atomisp/i2c/ov5693/Kconfig b/drivers/staging/media/atomisp/i2c/ov5693/Kconfig +index 3f527f2..b882948 100644 +--- a/drivers/staging/media/atomisp/i2c/ov5693/Kconfig ++++ b/drivers/staging/media/atomisp/i2c/ov5693/Kconfig +@@ -1,7 +1,7 @@ + config VIDEO_ATOMISP_OV5693 + tristate "Omnivision ov5693 sensor support" + depends on ACPI +- depends on I2C && VIDEO_V4L2 ++ depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER + ---help--- + This is a Video4Linux2 sensor-level driver for the Micron + ov5693 5 Mpixel camera. +diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +index 3e7c385..9b1fc1c 100644 +--- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c ++++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +@@ -1320,11 +1320,15 @@ static int power_ctrl(struct v4l2_subdev *sd, bool flag) + static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) + { + struct ov5693_device *dev = to_ov5693_sensor(sd); ++ int ret = 0; + + if (!dev || !dev->platform_data) + return -ENODEV; + +- return dev->platform_data->gpio0_ctrl(sd, flag); ++ if (dev->platform_data->gpio0_ctrl) ++ ret = dev->platform_data->gpio0_ctrl(sd, flag); ++ ++ return ret; + } + + static int __power_up(struct v4l2_subdev *sd) +@@ -1689,7 +1693,7 @@ static int ov5693_detect(struct i2c_client *client) + OV5693_SC_CMMN_CHIP_ID_L, &low); + id = ((((u16) high) << 8) | (u16) low); + +- if (id != OV5693_ID) { ++ if (id != OV5690_ID && id != OV5693_ID) { + dev_err(&client->dev, "sensor ID error 0x%x\n", id); + return -ENODEV; + } +diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h +index 2ea6380..2168daa 100644 +--- a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h ++++ b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h +@@ -29,7 +29,7 @@ + #include + #include + +-#include "../../include/linux/atomisp_platform.h" ++#include "../../include/linux/atomisp_gmin_platform.h" + + #define OV5693_POWER_UP_RETRY_NUM 5 + +@@ -72,7 +72,8 @@ + * bits 7-0: min f-number denominator + */ + #define OV5693_F_NUMBER_RANGE 0x180a180a +-#define OV5693_ID 0x5690 ++#define OV5690_ID 0x5690 ++#define OV5693_ID 0x5693 + + #define OV5693_FINE_INTG_TIME_MIN 0 + #define OV5693_FINE_INTG_TIME_MAX_MARGIN 0 +diff --git a/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c +index bf9f34b..6797ba1 100644 +--- a/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c ++++ b/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c +@@ -251,11 +251,13 @@ static const struct gmin_cfg_var ecs7_vars[] = { + {"INT33BE:00_CsiFmt", "13"}, + {"INT33BE:00_CsiBayer", "2"}, + {"INT33BE:00_CamClk", "0"}, ++ {"INT33BE:00_ClkSrc", "1"}, + {"INT33F0:00_CsiPort", "0"}, + {"INT33F0:00_CsiLanes", "1"}, + {"INT33F0:00_CsiFmt", "13"}, + {"INT33F0:00_CsiBayer", "0"}, + {"INT33F0:00_CamClk", "1"}, ++ {"INT33BE:00_I2CAddr", "-1"}, + {"gmin_V2P8GPIO", "402"}, + {}, + }; +@@ -280,6 +282,8 @@ static const struct { + { "MRD7", mrd7_vars }, + { "ST70408", ecs7_vars }, + { "VTA0803", i8880_vars }, ++ { "Surface Book" , ecs7_vars } , ++ { "Surface Pro 4" , ecs7_vars } , + }; + + diff --git a/patches-4.15/ipts.patch b/patches-4.15/ipts.patch new file mode 100644 index 000000000..e7b2731ce --- /dev/null +++ b/patches-4.15/ipts.patch @@ -0,0 +1,6051 @@ +From 32de729864dc8bb31ca3133f02561edd62673a93 Mon Sep 17 00:00:00 2001 +From: Jake Day +Date: Fri, 2 Feb 2018 16:02:54 -0500 +Subject: Intel Precise Touch & Stylus(IPTS) support + + +diff --git a/Documentation/devicetree/bindings/input/hid-over-i2c.txt b/Documentation/devicetree/bindings/input/hid-over-i2c.txt +index 28e8bd8..4d3da9d 100644 +--- a/Documentation/devicetree/bindings/input/hid-over-i2c.txt ++++ b/Documentation/devicetree/bindings/input/hid-over-i2c.txt +@@ -31,7 +31,7 @@ device-specific compatible properties, which should be used in addition to the + + - vdd-supply: phandle of the regulator that provides the supply voltage. + - post-power-on-delay-ms: time required by the device after enabling its regulators +- before it is ready for communication. Must be used with 'vdd-supply'. ++ or powering it on, before it is ready for communication. + + Example: + +diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile +index 2acf3b3..ab69d8d 100644 +--- a/drivers/gpu/drm/i915/Makefile ++++ b/drivers/gpu/drm/i915/Makefile +@@ -123,6 +123,9 @@ i915-y += dvo_ch7017.o \ + intel_sdvo.o \ + intel_tv.o + ++# intel precise touch & stylus ++i915-y += intel_ipts.o ++ + # Post-mortem debug and GPU hang state capture + i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += i915_gpu_error.o + i915-$(CONFIG_DRM_I915_SELFTEST) += \ +diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c +index 2cf10d1..7fc4324 100644 +--- a/drivers/gpu/drm/i915/i915_drv.c ++++ b/drivers/gpu/drm/i915/i915_drv.c +@@ -51,6 +51,7 @@ + #include "i915_vgpu.h" + #include "intel_drv.h" + #include "intel_uc.h" ++#include "intel_ipts.h" + + static struct drm_driver driver; + +@@ -691,6 +692,9 @@ static int i915_load_modeset_init(struct drm_device *dev) + + drm_kms_helper_poll_init(dev); + ++ if (INTEL_GEN(dev_priv) >= 9 && i915_modparams.enable_guc_submission) ++ intel_ipts_init(dev); ++ + return 0; + + cleanup_gem: +@@ -1394,6 +1398,9 @@ void i915_driver_unload(struct drm_device *dev) + struct drm_i915_private *dev_priv = to_i915(dev); + struct pci_dev *pdev = dev_priv->drm.pdev; + ++ if (INTEL_GEN(dev_priv) >= 9 && i915_modparams.enable_guc_submission) ++ intel_ipts_cleanup(dev); ++ + i915_driver_unregister(dev_priv); + + if (i915_gem_suspend(dev_priv)) +diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h +index e143004..46b6dbe 100644 +--- a/drivers/gpu/drm/i915/i915_drv.h ++++ b/drivers/gpu/drm/i915/i915_drv.h +@@ -3804,6 +3804,9 @@ void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj, + void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj, + struct sg_table *pages); + ++struct i915_gem_context * ++i915_gem_context_create_ipts(struct drm_device *dev); ++ + static inline struct i915_gem_context * + __i915_gem_context_lookup_rcu(struct drm_i915_file_private *file_priv, u32 id) + { +diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c +index f782cf2..a8dd495 100644 +--- a/drivers/gpu/drm/i915/i915_gem_context.c ++++ b/drivers/gpu/drm/i915/i915_gem_context.c +@@ -449,6 +449,18 @@ destroy_kernel_context(struct i915_gem_context **ctxp) + i915_gem_context_free(ctx); + } + ++struct i915_gem_context *i915_gem_context_create_ipts(struct drm_device *dev) ++{ ++ struct drm_i915_private *dev_priv = dev->dev_private; ++ struct i915_gem_context *ctx; ++ ++ BUG_ON(!mutex_is_locked(&dev->struct_mutex)); ++ ++ ctx = i915_gem_create_context(dev_priv, NULL); ++ ++ return ctx; ++} ++ + int i915_gem_contexts_init(struct drm_i915_private *dev_priv) + { + struct i915_gem_context *ctx; +diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c +index f84c267..485d86e 100644 +--- a/drivers/gpu/drm/i915/i915_guc_submission.c ++++ b/drivers/gpu/drm/i915/i915_guc_submission.c +@@ -331,7 +331,14 @@ static void guc_stage_desc_init(struct intel_guc *guc, + desc = __get_stage_desc(client); + memset(desc, 0, sizeof(*desc)); + +- desc->attribute = GUC_STAGE_DESC_ATTR_ACTIVE | GUC_STAGE_DESC_ATTR_KERNEL; ++ desc->attribute = GUC_STAGE_DESC_ATTR_ACTIVE; ++ if ((client->priority == GUC_CLIENT_PRIORITY_KMD_NORMAL) || ++ (client->priority == GUC_CLIENT_PRIORITY_KMD_HIGH)) { ++ desc->attribute |= GUC_STAGE_DESC_ATTR_KERNEL; ++ } else { ++ desc->attribute |= GUC_STAGE_DESC_ATTR_PCH; ++ } ++ + desc->stage_id = client->stage_id; + desc->priority = client->priority; + desc->db_id = client->doorbell_id; +@@ -1042,7 +1049,8 @@ static void guc_interrupts_capture(struct drm_i915_private *dev_priv) + I915_WRITE(RING_MODE_GEN7(engine), irqs); + + /* route USER_INTERRUPT to Host, all others are sent to GuC. */ +- irqs = GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT | ++ irqs = (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT) ++ << GEN8_RCS_IRQ_SHIFT | + GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT; + /* These three registers have the same bit definitions */ + I915_WRITE(GUC_BCS_RCS_IER, ~irqs); +@@ -1176,3 +1184,47 @@ void i915_guc_submission_disable(struct drm_i915_private *dev_priv) + guc_client_free(guc->execbuf_client); + guc->execbuf_client = NULL; + } ++ ++int i915_guc_ipts_submission_enable(struct drm_i915_private *dev_priv, ++ struct i915_gem_context *ctx) ++{ ++ struct intel_guc *guc = &dev_priv->guc; ++ struct i915_guc_client *client; ++ ++ /* client for execbuf submission */ ++ client = guc_client_alloc(dev_priv, ++ INTEL_INFO(dev_priv)->ring_mask, ++ GUC_CLIENT_PRIORITY_NORMAL, ++ ctx); ++ if (!client) { ++ DRM_ERROR("Failed to create normal GuC client!\n"); ++ return -ENOMEM; ++ } ++ ++ guc->ipts_client = client; ++ intel_guc_sample_forcewake(guc); ++ guc_init_doorbell_hw(guc); ++ ++ return 0; ++} ++ ++void i915_guc_ipts_submission_disable(struct drm_i915_private *dev_priv) ++{ ++ struct intel_guc *guc = &dev_priv->guc; ++ ++ if (!guc->ipts_client) ++ return; ++ ++ guc_client_free(guc->ipts_client); ++ guc->ipts_client = NULL; ++} ++ ++void i915_guc_ipts_reacquire_doorbell(struct drm_i915_private *dev_priv) ++{ ++ struct intel_guc *guc = &dev_priv->guc; ++ ++ int err = __guc_allocate_doorbell(guc, guc->ipts_client->stage_id); ++ ++ if (err) ++ DRM_ERROR("Not able to reacquire IPTS doorbell\n"); ++} +diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c +index f820584..d7d68d7 100644 +--- a/drivers/gpu/drm/i915/i915_irq.c ++++ b/drivers/gpu/drm/i915/i915_irq.c +@@ -36,6 +36,7 @@ + #include "i915_drv.h" + #include "i915_trace.h" + #include "intel_drv.h" ++#include "intel_ipts.h" + + /** + * DOC: interrupt handling +@@ -1399,6 +1400,9 @@ gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir, int test_shift) + tasklet |= i915_modparams.enable_guc_submission; + } + ++ if (iir & (GT_RENDER_PIPECTL_NOTIFY_INTERRUPT << test_shift)) ++ intel_ipts_notify_complete(); ++ + if (tasklet) + tasklet_hi_schedule(&execlists->irq_tasklet); + } +@@ -3560,7 +3564,8 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv) + { + /* These are interrupts we'll toggle with the ring mask register */ + uint32_t gt_interrupts[] = { +- GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT | ++ GT_RENDER_PIPECTL_NOTIFY_INTERRUPT << GEN8_RCS_IRQ_SHIFT | ++ GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT | + GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT | + GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT | + GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT, +diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c +index b4faeb6..38774d6 100644 +--- a/drivers/gpu/drm/i915/i915_params.c ++++ b/drivers/gpu/drm/i915/i915_params.c +@@ -164,11 +164,11 @@ i915_param_named_unsafe(edp_vswing, int, 0400, + + i915_param_named_unsafe(enable_guc_loading, int, 0400, + "Enable GuC firmware loading " +- "(-1=auto, 0=never [default], 1=if available, 2=required)"); ++ "(-1=auto, 0=never, 1=if available [default], 2=required)"); + + i915_param_named_unsafe(enable_guc_submission, int, 0400, + "Enable GuC submission " +- "(-1=auto, 0=never [default], 1=if available, 2=required)"); ++ "(-1=auto, 0=never, 1=if available [default], 2=required)"); + + i915_param_named(guc_log_level, int, 0400, + "GuC firmware logging level (-1:disabled (default), 0-3:enabled)"); +diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h +index c729226..c38cef0 100644 +--- a/drivers/gpu/drm/i915/i915_params.h ++++ b/drivers/gpu/drm/i915/i915_params.h +@@ -44,8 +44,8 @@ + param(int, disable_power_well, -1) \ + param(int, enable_ips, 1) \ + param(int, invert_brightness, 0) \ +- param(int, enable_guc_loading, 0) \ +- param(int, enable_guc_submission, 0) \ ++ param(int, enable_guc_loading, 1) \ ++ param(int, enable_guc_submission, 1) \ + param(int, guc_log_level, -1) \ + param(char *, guc_firmware_path, NULL) \ + param(char *, huc_firmware_path, NULL) \ +diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h +index 418450b..c1bd36c 100644 +--- a/drivers/gpu/drm/i915/intel_guc.h ++++ b/drivers/gpu/drm/i915/intel_guc.h +@@ -56,6 +56,7 @@ struct intel_guc { + struct ida stage_ids; + + struct i915_guc_client *execbuf_client; ++ struct i915_guc_client *ipts_client; + + DECLARE_BITMAP(doorbell_bitmap, GUC_NUM_DOORBELLS); + /* Cyclic counter mod pagesize */ +@@ -116,5 +117,9 @@ int intel_guc_suspend(struct drm_i915_private *dev_priv); + int intel_guc_resume(struct drm_i915_private *dev_priv); + struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size); + u32 intel_guc_wopcm_size(struct drm_i915_private *dev_priv); ++int i915_guc_ipts_submission_enable(struct drm_i915_private *dev_priv, ++ struct i915_gem_context *ctx); ++void i915_guc_ipts_submission_disable(struct drm_i915_private *dev_priv); ++void i915_guc_ipts_reacquire_doorbell(struct drm_i915_private *dev_priv); + + #endif +diff --git a/drivers/gpu/drm/i915/intel_ipts.c b/drivers/gpu/drm/i915/intel_ipts.c +new file mode 100644 +index 0000000..f5fa111 +--- /dev/null ++++ b/drivers/gpu/drm/i915/intel_ipts.c +@@ -0,0 +1,627 @@ ++/* ++ * Copyright 2016 Intel Corporation ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include "i915_guc_submission.h" ++#include "i915_drv.h" ++ ++#define SUPPORTED_IPTS_INTERFACE_VERSION 1 ++ ++#define REACQUIRE_DB_THRESHOLD 8 ++#define DB_LOST_CHECK_STEP1_INTERVAL 2000 /* ms */ ++#define DB_LOST_CHECK_STEP2_INTERVAL 500 /* ms */ ++ ++/* intel IPTS ctx for ipts support */ ++typedef struct intel_ipts { ++ struct drm_device *dev; ++ struct i915_gem_context *ipts_context; ++ intel_ipts_callback_t ipts_clbks; ++ ++ /* buffers' list */ ++ struct { ++ spinlock_t lock; ++ struct list_head list; ++ } buffers; ++ ++ void *data; ++ ++ struct delayed_work reacquire_db_work; ++ intel_ipts_wq_info_t wq_info; ++ u32 old_tail; ++ u32 old_head; ++ bool need_reacquire_db; ++ ++ bool connected; ++ bool initialized; ++} intel_ipts_t; ++ ++intel_ipts_t intel_ipts; ++ ++typedef struct intel_ipts_object { ++ struct list_head list; ++ struct drm_i915_gem_object *gem_obj; ++ void *cpu_addr; ++} intel_ipts_object_t; ++ ++static intel_ipts_object_t *ipts_object_create(size_t size, u32 flags) ++{ ++ struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev); ++ intel_ipts_object_t *obj = NULL; ++ struct drm_i915_gem_object *gem_obj = NULL; ++ int ret = 0; ++ ++ obj = kzalloc(sizeof(*obj), GFP_KERNEL); ++ if (!obj) ++ return NULL; ++ ++ size = roundup(size, PAGE_SIZE); ++ if (size == 0) { ++ ret = -EINVAL; ++ goto err_out; ++ } ++ ++ /* Allocate the new object */ ++ gem_obj = i915_gem_object_create(dev_priv, size); ++ if (gem_obj == NULL) { ++ ret = -ENOMEM; ++ goto err_out; ++ } ++ ++ if (flags & IPTS_BUF_FLAG_CONTIGUOUS) { ++ ret = i915_gem_object_attach_phys(gem_obj, PAGE_SIZE); ++ if (ret) { ++ pr_info(">> ipts no contiguous : %d\n", ret); ++ goto err_out; ++ } ++ } ++ ++ obj->gem_obj = gem_obj; ++ ++ spin_lock(&intel_ipts.buffers.lock); ++ list_add_tail(&obj->list, &intel_ipts.buffers.list); ++ spin_unlock(&intel_ipts.buffers.lock); ++ ++ return obj; ++ ++err_out: ++ if (gem_obj) ++ i915_gem_free_object(&gem_obj->base); ++ ++ if (obj) ++ kfree(obj); ++ ++ return NULL; ++} ++ ++static void ipts_object_free(intel_ipts_object_t* obj) ++{ ++ spin_lock(&intel_ipts.buffers.lock); ++ list_del(&obj->list); ++ spin_unlock(&intel_ipts.buffers.lock); ++ ++ i915_gem_free_object(&obj->gem_obj->base); ++ kfree(obj); ++} ++ ++static int ipts_object_pin(intel_ipts_object_t* obj, ++ struct i915_gem_context *ipts_ctx) ++{ ++ struct i915_address_space *vm = NULL; ++ struct i915_vma *vma = NULL; ++ struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev); ++ int ret = 0; ++ ++ if (ipts_ctx->ppgtt) { ++ vm = &ipts_ctx->ppgtt->base; ++ } else { ++ vm = &dev_priv->ggtt.base; ++ } ++ ++ vma = i915_vma_instance(obj->gem_obj, vm, NULL); ++ if (IS_ERR(vma)) { ++ DRM_ERROR("cannot find or create vma\n"); ++ return -1; ++ } ++ ++ ret = i915_vma_pin(vma, 0, PAGE_SIZE, PIN_USER); ++ ++ return ret; ++} ++ ++static void ipts_object_unpin(intel_ipts_object_t *obj) ++{ ++ /* TBD: Add support */ ++} ++ ++static void* ipts_object_map(intel_ipts_object_t *obj) ++{ ++ ++ return i915_gem_object_pin_map(obj->gem_obj, I915_MAP_WB); ++} ++ ++static void ipts_object_unmap(intel_ipts_object_t* obj) ++{ ++ i915_gem_object_unpin_map(obj->gem_obj); ++ obj->cpu_addr = NULL; ++} ++ ++static int create_ipts_context(void) ++{ ++ struct i915_gem_context *ipts_ctx = NULL; ++ struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev); ++ struct intel_ring *pin_ret; ++ int ret = 0; ++ ++ /* Initialize the context right away.*/ ++ ret = i915_mutex_lock_interruptible(intel_ipts.dev); ++ if (ret) { ++ DRM_ERROR("i915_mutex_lock_interruptible failed \n"); ++ return ret; ++ } ++ ++ ipts_ctx = i915_gem_context_create_ipts(intel_ipts.dev); ++ if (IS_ERR(ipts_ctx)) { ++ DRM_ERROR("Failed to create IPTS context (error %ld)\n", ++ PTR_ERR(ipts_ctx)); ++ ret = PTR_ERR(ipts_ctx); ++ goto err_unlock; ++ } ++ ++ ret = execlists_context_deferred_alloc(ipts_ctx, dev_priv->engine[RCS]); ++ if (ret) { ++ DRM_DEBUG("lr context allocation failed : %d\n", ret); ++ goto err_ctx; ++ } ++ ++ pin_ret = execlists_context_pin(dev_priv->engine[RCS], ipts_ctx); ++ if (IS_ERR(pin_ret)) { ++ DRM_DEBUG("lr context pinning failed : %ld\n", PTR_ERR(pin_ret)); ++ goto err_ctx; ++ } ++ ++ /* Release the mutex */ ++ mutex_unlock(&intel_ipts.dev->struct_mutex); ++ ++ spin_lock_init(&intel_ipts.buffers.lock); ++ INIT_LIST_HEAD(&intel_ipts.buffers.list); ++ ++ intel_ipts.ipts_context = ipts_ctx; ++ ++ return 0; ++ ++err_ctx: ++ if (ipts_ctx) ++ i915_gem_context_put(ipts_ctx); ++ ++err_unlock: ++ mutex_unlock(&intel_ipts.dev->struct_mutex); ++ ++ return ret; ++} ++ ++static void destroy_ipts_context(void) ++{ ++ struct i915_gem_context *ipts_ctx = NULL; ++ struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev); ++ int ret = 0; ++ ++ ipts_ctx = intel_ipts.ipts_context; ++ ++ /* Initialize the context right away.*/ ++ ret = i915_mutex_lock_interruptible(intel_ipts.dev); ++ if (ret) { ++ DRM_ERROR("i915_mutex_lock_interruptible failed \n"); ++ return; ++ } ++ ++ execlists_context_unpin(dev_priv->engine[RCS], ipts_ctx); ++ i915_gem_context_put(ipts_ctx); ++ ++ mutex_unlock(&intel_ipts.dev->struct_mutex); ++} ++ ++int intel_ipts_notify_complete(void) ++{ ++ if (intel_ipts.ipts_clbks.workload_complete) ++ intel_ipts.ipts_clbks.workload_complete(intel_ipts.data); ++ ++ return 0; ++} ++ ++int intel_ipts_notify_backlight_status(bool backlight_on) ++{ ++ if (intel_ipts.ipts_clbks.notify_gfx_status) { ++ if (backlight_on) { ++ intel_ipts.ipts_clbks.notify_gfx_status( ++ IPTS_NOTIFY_STA_BACKLIGHT_ON, ++ intel_ipts.data); ++ schedule_delayed_work(&intel_ipts.reacquire_db_work, ++ msecs_to_jiffies(DB_LOST_CHECK_STEP1_INTERVAL)); ++ } else { ++ intel_ipts.ipts_clbks.notify_gfx_status( ++ IPTS_NOTIFY_STA_BACKLIGHT_OFF, ++ intel_ipts.data); ++ cancel_delayed_work(&intel_ipts.reacquire_db_work); ++ } ++ } ++ ++ return 0; ++} ++ ++static void intel_ipts_reacquire_db(intel_ipts_t *intel_ipts_p) ++{ ++ int ret = 0; ++ ++ ret = i915_mutex_lock_interruptible(intel_ipts_p->dev); ++ if (ret) { ++ DRM_ERROR("i915_mutex_lock_interruptible failed \n"); ++ return; ++ } ++ ++ /* Reacquire the doorbell */ ++ i915_guc_ipts_reacquire_doorbell(intel_ipts_p->dev->dev_private); ++ ++ mutex_unlock(&intel_ipts_p->dev->struct_mutex); ++ ++ return; ++} ++ ++static int intel_ipts_get_wq_info(uint64_t gfx_handle, ++ intel_ipts_wq_info_t *wq_info) ++{ ++ if (gfx_handle != (uint64_t)&intel_ipts) { ++ DRM_ERROR("invalid gfx handle\n"); ++ return -EINVAL; ++ } ++ ++ *wq_info = intel_ipts.wq_info; ++ ++ intel_ipts_reacquire_db(&intel_ipts); ++ schedule_delayed_work(&intel_ipts.reacquire_db_work, ++ msecs_to_jiffies(DB_LOST_CHECK_STEP1_INTERVAL)); ++ ++ return 0; ++} ++ ++static int set_wq_info(void) ++{ ++ struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev); ++ struct intel_guc *guc = &dev_priv->guc; ++ struct i915_guc_client *client; ++ struct guc_process_desc *desc; ++ void *base = NULL; ++ intel_ipts_wq_info_t *wq_info; ++ u64 phy_base = 0; ++ ++ wq_info = &intel_ipts.wq_info; ++ ++ client = guc->ipts_client; ++ if (!client) { ++ DRM_ERROR("IPTS GuC client is NOT available\n"); ++ return -EINVAL; ++ } ++ ++ base = client->vaddr; ++ desc = (struct guc_process_desc *)((u64)base + client->proc_desc_offset); ++ ++ desc->wq_base_addr = (u64)base + GUC_DB_SIZE; ++ desc->db_base_addr = (u64)base + client->doorbell_offset; ++ ++ /* IPTS expects physical addresses to pass it to ME */ ++ phy_base = sg_dma_address(client->vma->pages->sgl); ++ ++ wq_info->db_addr = desc->db_base_addr; ++ wq_info->db_phy_addr = phy_base + client->doorbell_offset; ++ wq_info->db_cookie_offset = offsetof(struct guc_doorbell_info, cookie); ++ wq_info->wq_addr = desc->wq_base_addr; ++ wq_info->wq_phy_addr = phy_base + GUC_DB_SIZE; ++ wq_info->wq_head_addr = (u64)&desc->head; ++ wq_info->wq_head_phy_addr = phy_base + client->proc_desc_offset + ++ offsetof(struct guc_process_desc, head); ++ wq_info->wq_tail_addr = (u64)&desc->tail; ++ wq_info->wq_tail_phy_addr = phy_base + client->proc_desc_offset + ++ offsetof(struct guc_process_desc, tail); ++ wq_info->wq_size = desc->wq_size_bytes; ++ ++ return 0; ++} ++ ++static int intel_ipts_init_wq(void) ++{ ++ int ret = 0; ++ ++ ret = i915_mutex_lock_interruptible(intel_ipts.dev); ++ if (ret) { ++ DRM_ERROR("i915_mutex_lock_interruptible failed\n"); ++ return ret; ++ } ++ ++ /* disable IPTS submission */ ++ i915_guc_ipts_submission_disable(intel_ipts.dev->dev_private); ++ ++ /* enable IPTS submission */ ++ ret = i915_guc_ipts_submission_enable(intel_ipts.dev->dev_private, ++ intel_ipts.ipts_context); ++ if (ret) { ++ DRM_ERROR("i915_guc_ipts_submission_enable failed : %d\n", ret); ++ goto out; ++ } ++ ++ ret = set_wq_info(); ++ if (ret) { ++ DRM_ERROR("set_wq_info failed\n"); ++ goto out; ++ } ++ ++out: ++ mutex_unlock(&intel_ipts.dev->struct_mutex); ++ ++ return ret; ++} ++ ++static void intel_ipts_release_wq(void) ++{ ++ int ret = 0; ++ ++ ret = i915_mutex_lock_interruptible(intel_ipts.dev); ++ if (ret) { ++ DRM_ERROR("i915_mutex_lock_interruptible failed\n"); ++ return; ++ } ++ ++ /* disable IPTS submission */ ++ i915_guc_ipts_submission_disable(intel_ipts.dev->dev_private); ++ ++ mutex_unlock(&intel_ipts.dev->struct_mutex); ++} ++ ++static int intel_ipts_map_buffer(u64 gfx_handle, intel_ipts_mapbuffer_t *mapbuf) ++{ ++ intel_ipts_object_t* obj; ++ struct i915_gem_context *ipts_ctx = NULL; ++ struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev); ++ struct i915_address_space *vm = NULL; ++ struct i915_vma *vma = NULL; ++ int ret = 0; ++ ++ if (gfx_handle != (uint64_t)&intel_ipts) { ++ DRM_ERROR("invalid gfx handle\n"); ++ return -EINVAL; ++ } ++ ++ /* Acquire mutex first */ ++ ret = i915_mutex_lock_interruptible(intel_ipts.dev); ++ if (ret) { ++ DRM_ERROR("i915_mutex_lock_interruptible failed \n"); ++ return -EINVAL; ++ } ++ ++ obj = ipts_object_create(mapbuf->size, mapbuf->flags); ++ if (!obj) ++ return -ENOMEM; ++ ++ ipts_ctx = intel_ipts.ipts_context; ++ ret = ipts_object_pin(obj, ipts_ctx); ++ if (ret) { ++ DRM_ERROR("Not able to pin iTouch obj\n"); ++ ipts_object_free(obj); ++ mutex_unlock(&intel_ipts.dev->struct_mutex); ++ return -ENOMEM; ++ } ++ ++ if (mapbuf->flags & IPTS_BUF_FLAG_CONTIGUOUS) { ++ obj->cpu_addr = obj->gem_obj->phys_handle->vaddr; ++ } else { ++ obj->cpu_addr = ipts_object_map(obj); ++ } ++ ++ if (ipts_ctx->ppgtt) { ++ vm = &ipts_ctx->ppgtt->base; ++ } else { ++ vm = &dev_priv->ggtt.base; ++ } ++ ++ vma = i915_vma_instance(obj->gem_obj, vm, NULL); ++ if (IS_ERR(vma)) { ++ DRM_ERROR("cannot find or create vma\n"); ++ return -EINVAL; ++ } ++ ++ mapbuf->gfx_addr = (void*)vma->node.start; ++ mapbuf->cpu_addr = (void*)obj->cpu_addr; ++ mapbuf->buf_handle = (u64)obj; ++ if (mapbuf->flags & IPTS_BUF_FLAG_CONTIGUOUS) { ++ mapbuf->phy_addr = (u64)obj->gem_obj->phys_handle->busaddr; ++ } ++ ++ /* Release the mutex */ ++ mutex_unlock(&intel_ipts.dev->struct_mutex); ++ ++ return 0; ++} ++ ++static int intel_ipts_unmap_buffer(uint64_t gfx_handle, uint64_t buf_handle) ++{ ++ intel_ipts_object_t* obj = (intel_ipts_object_t*)buf_handle; ++ ++ if (gfx_handle != (uint64_t)&intel_ipts) { ++ DRM_ERROR("invalid gfx handle\n"); ++ return -EINVAL; ++ } ++ ++ if (!obj->gem_obj->phys_handle) ++ ipts_object_unmap(obj); ++ ipts_object_unpin(obj); ++ ipts_object_free(obj); ++ ++ return 0; ++} ++ ++int intel_ipts_connect(intel_ipts_connect_t *ipts_connect) ++{ ++ struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev); ++ int ret = 0; ++ ++ if (!intel_ipts.initialized) ++ return -EIO; ++ ++ if (ipts_connect && ipts_connect->if_version <= ++ SUPPORTED_IPTS_INTERFACE_VERSION) { ++ ++ /* return gpu operations for ipts */ ++ ipts_connect->ipts_ops.get_wq_info = intel_ipts_get_wq_info; ++ ipts_connect->ipts_ops.map_buffer = intel_ipts_map_buffer; ++ ipts_connect->ipts_ops.unmap_buffer = intel_ipts_unmap_buffer; ++ ipts_connect->gfx_version = INTEL_INFO(dev_priv)->gen; ++ ipts_connect->gfx_handle = (uint64_t)&intel_ipts; ++ ++ /* save callback and data */ ++ intel_ipts.data = ipts_connect->data; ++ intel_ipts.ipts_clbks = ipts_connect->ipts_cb; ++ ++ intel_ipts.connected = true; ++ } else { ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(intel_ipts_connect); ++ ++void intel_ipts_disconnect(uint64_t gfx_handle) ++{ ++ if (!intel_ipts.initialized) ++ return; ++ ++ if (gfx_handle != (uint64_t)&intel_ipts || ++ intel_ipts.connected == false) { ++ DRM_ERROR("invalid gfx handle\n"); ++ return; ++ } ++ ++ intel_ipts.data = 0; ++ memset(&intel_ipts.ipts_clbks, 0, sizeof(intel_ipts_callback_t)); ++ ++ intel_ipts.connected = false; ++} ++EXPORT_SYMBOL_GPL(intel_ipts_disconnect); ++ ++static void reacquire_db_work_func(struct work_struct *work) ++{ ++ struct delayed_work *d_work = container_of(work, struct delayed_work, ++ work); ++ intel_ipts_t *intel_ipts_p = container_of(d_work, intel_ipts_t, ++ reacquire_db_work); ++ u32 head; ++ u32 tail; ++ u32 size; ++ u32 load; ++ ++ head = *(u32*)intel_ipts_p->wq_info.wq_head_addr; ++ tail = *(u32*)intel_ipts_p->wq_info.wq_tail_addr; ++ size = intel_ipts_p->wq_info.wq_size; ++ ++ if (head >= tail) ++ load = head - tail; ++ else ++ load = head + size - tail; ++ ++ if (load < REACQUIRE_DB_THRESHOLD) { ++ intel_ipts_p->need_reacquire_db = false; ++ goto reschedule_work; ++ } ++ ++ if (intel_ipts_p->need_reacquire_db) { ++ if (intel_ipts_p->old_head == head && intel_ipts_p->old_tail == tail) ++ intel_ipts_reacquire_db(intel_ipts_p); ++ intel_ipts_p->need_reacquire_db = false; ++ } else { ++ intel_ipts_p->old_head = head; ++ intel_ipts_p->old_tail = tail; ++ intel_ipts_p->need_reacquire_db = true; ++ ++ /* recheck */ ++ schedule_delayed_work(&intel_ipts_p->reacquire_db_work, ++ msecs_to_jiffies(DB_LOST_CHECK_STEP2_INTERVAL)); ++ return; ++ } ++ ++reschedule_work: ++ schedule_delayed_work(&intel_ipts_p->reacquire_db_work, ++ msecs_to_jiffies(DB_LOST_CHECK_STEP1_INTERVAL)); ++} ++ ++/** ++ * intel_ipts_init - Initialize ipts support ++ * @dev: drm device ++ * ++ * Setup the required structures for ipts. ++ */ ++int intel_ipts_init(struct drm_device *dev) ++{ ++ int ret = 0; ++ ++ pr_info("ipts: initializing ipts\n"); ++ ++ intel_ipts.dev = dev; ++ INIT_DELAYED_WORK(&intel_ipts.reacquire_db_work, reacquire_db_work_func); ++ ++ ret = create_ipts_context(); ++ if (ret) ++ return -ENOMEM; ++ ++ ret = intel_ipts_init_wq(); ++ if (ret) ++ return ret; ++ ++ intel_ipts.initialized = true; ++ DRM_DEBUG_DRIVER("Intel iTouch framework initialized\n"); ++ ++ return ret; ++} ++ ++void intel_ipts_cleanup(struct drm_device *dev) ++{ ++ intel_ipts_object_t *obj, *n; ++ ++ if (intel_ipts.dev == dev) { ++ list_for_each_entry_safe(obj, n, &intel_ipts.buffers.list, list) { ++ list_del(&obj->list); ++ ++ if (!obj->gem_obj->phys_handle) ++ ipts_object_unmap(obj); ++ ipts_object_unpin(obj); ++ i915_gem_free_object(&obj->gem_obj->base); ++ kfree(obj); ++ } ++ ++ intel_ipts_release_wq(); ++ destroy_ipts_context(); ++ cancel_delayed_work(&intel_ipts.reacquire_db_work); ++ } ++} +diff --git a/drivers/gpu/drm/i915/intel_ipts.h b/drivers/gpu/drm/i915/intel_ipts.h +new file mode 100644 +index 0000000..a6965d1 +--- /dev/null ++++ b/drivers/gpu/drm/i915/intel_ipts.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright © 2016 Intel Corporation ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ * ++ */ ++#ifndef _INTEL_IPTS_H_ ++#define _INTEL_IPTS_H_ ++ ++struct drm_device; ++ ++int intel_ipts_init(struct drm_device *dev); ++void intel_ipts_cleanup(struct drm_device *dev); ++int intel_ipts_notify_backlight_status(bool backlight_on); ++int intel_ipts_notify_complete(void); ++ ++#endif //_INTEL_IPTS_H_ +diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c +index e71a8cd..78a35f7 100644 +--- a/drivers/gpu/drm/i915/intel_lrc.c ++++ b/drivers/gpu/drm/i915/intel_lrc.c +@@ -212,8 +212,6 @@ + #define WA_TAIL_BYTES (sizeof(u32) * WA_TAIL_DWORDS) + #define PREEMPT_ID 0x1 + +-static int execlists_context_deferred_alloc(struct i915_gem_context *ctx, +- struct intel_engine_cs *engine); + static void execlists_init_reg_state(u32 *reg_state, + struct i915_gem_context *ctx, + struct intel_engine_cs *engine, +@@ -1060,7 +1058,7 @@ static void execlists_schedule(struct drm_i915_gem_request *request, int prio) + spin_unlock_irq(&engine->timeline->lock); + } + +-static struct intel_ring * ++struct intel_ring * + execlists_context_pin(struct intel_engine_cs *engine, + struct i915_gem_context *ctx) + { +@@ -1122,7 +1120,7 @@ execlists_context_pin(struct intel_engine_cs *engine, + return ERR_PTR(ret); + } + +-static void execlists_context_unpin(struct intel_engine_cs *engine, ++void execlists_context_unpin(struct intel_engine_cs *engine, + struct i915_gem_context *ctx) + { + struct intel_context *ce = &ctx->engine[engine->id]; +@@ -1981,6 +1979,9 @@ int logical_render_ring_init(struct intel_engine_cs *engine) + + logical_ring_setup(engine); + ++ engine->irq_keep_mask |= GT_RENDER_PIPECTL_NOTIFY_INTERRUPT ++ << GEN8_RCS_IRQ_SHIFT; ++ + if (HAS_L3_DPF(dev_priv)) + engine->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT; + +@@ -2213,7 +2214,7 @@ populate_lr_context(struct i915_gem_context *ctx, + return 0; + } + +-static int execlists_context_deferred_alloc(struct i915_gem_context *ctx, ++int execlists_context_deferred_alloc(struct i915_gem_context *ctx, + struct intel_engine_cs *engine) + { + struct drm_i915_gem_object *ctx_obj; +diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h +index 689fde1..54a076d 100644 +--- a/drivers/gpu/drm/i915/intel_lrc.h ++++ b/drivers/gpu/drm/i915/intel_lrc.h +@@ -112,4 +112,12 @@ intel_lr_context_descriptor(struct i915_gem_context *ctx, + int intel_sanitize_enable_execlists(struct drm_i915_private *dev_priv, + int enable_execlists); + ++struct intel_ring * ++execlists_context_pin(struct intel_engine_cs *engine, ++ struct i915_gem_context *ctx); ++void execlists_context_unpin(struct intel_engine_cs *engine, ++ struct i915_gem_context *ctx); ++int execlists_context_deferred_alloc(struct i915_gem_context *ctx, ++ struct intel_engine_cs *engine); ++ + #endif /* _INTEL_LRC_H_ */ +diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c +index adc51e4..c23c8c1 100644 +--- a/drivers/gpu/drm/i915/intel_panel.c ++++ b/drivers/gpu/drm/i915/intel_panel.c +@@ -34,6 +34,7 @@ + #include + #include + #include "intel_drv.h" ++#include "intel_ipts.h" + + #define CRC_PMIC_PWM_PERIOD_NS 21333 + +@@ -719,6 +720,9 @@ static void lpt_disable_backlight(const struct drm_connector_state *old_conn_sta + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + u32 tmp; + ++ if (INTEL_GEN(dev_priv) >= 9 && i915_modparams.enable_guc_submission) ++ intel_ipts_notify_backlight_status(false); ++ + intel_panel_actually_set_backlight(old_conn_state, 0); + + /* +@@ -906,6 +910,9 @@ static void lpt_enable_backlight(const struct intel_crtc_state *crtc_state, + + /* This won't stick until the above enable. */ + intel_panel_actually_set_backlight(conn_state, panel->backlight.level); ++ ++ if (INTEL_GEN(dev_priv) >= 9 && i915_modparams.enable_guc_submission) ++ intel_ipts_notify_backlight_status(true); + } + + static void pch_enable_backlight(const struct intel_crtc_state *crtc_state, +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index dd416e9..6d2e8d3 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -145,6 +145,7 @@ struct mt_device { + + static void mt_post_parse_default_settings(struct mt_device *td); + static void mt_post_parse(struct mt_device *td); ++static int cc_seen = 0; + + /* classes of device behavior */ + #define MT_CLS_DEFAULT 0x0001 +@@ -605,8 +606,12 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, + if (field->index >= field->report->maxfield || + usage->usage_index >= field->report_count) + return 1; +- td->cc_index = field->index; +- td->cc_value_index = usage->usage_index; ++ ++ if(cc_seen != 1) { ++ td->cc_index = field->index; ++ td->cc_value_index = usage->usage_index; ++ cc_seen++; ++ } + return 1; + case HID_DG_CONTACTMAX: + /* we don't set td->last_slot_field as contactcount and +@@ -643,6 +648,16 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, + return 0; + } + ++static int mt_touch_input_mapped(struct hid_device *hdev, struct hid_input *hi, ++ struct hid_field *field, struct hid_usage *usage, ++ unsigned long **bit, int *max) ++{ ++ if (usage->type == EV_KEY || usage->type == EV_ABS) ++ set_bit(usage->type, hi->input->evbit); ++ ++ return -1; ++} ++ + static int mt_compute_slot(struct mt_device *td, struct input_dev *input) + { + __s32 quirks = td->mtclass.quirks; +@@ -972,9 +987,11 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + field->application != HID_DG_TOUCHSCREEN && + field->application != HID_DG_PEN && + field->application != HID_DG_TOUCHPAD && ++ field->application != HID_GD_MOUSE && + field->application != HID_GD_KEYBOARD && + field->application != HID_GD_SYSTEM_CONTROL && + field->application != HID_CP_CONSUMER_CONTROL && ++ field->logical != HID_DG_TOUCHSCREEN && + field->application != HID_GD_WIRELESS_RADIO_CTLS && + !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && + td->mtclass.quirks & MT_QUIRK_ASUS_CUSTOM_UP)) +@@ -1037,10 +1054,8 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + return 0; + + if (field->application == HID_DG_TOUCHSCREEN || +- field->application == HID_DG_TOUCHPAD) { +- /* We own these mappings, tell hid-input to ignore them */ +- return -1; +- } ++ field->application == HID_DG_TOUCHPAD) ++ return mt_touch_input_mapped(hdev, hi, field, usage, bit, max); + + /* let hid-core decide for the others */ + return 0; +@@ -1183,6 +1198,7 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + suffix = "Pen"; + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); ++ __set_bit(INPUT_PROP_DIRECT, hi->input->propbit); + } else { + switch (field->application) { + case HID_GD_KEYBOARD: +@@ -1198,9 +1214,10 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + suffix = "Pen"; + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); ++ __set_bit(INPUT_PROP_DIRECT, hi->input->propbit); + break; + case HID_DG_TOUCHSCREEN: +- /* we do not set suffix = "Touchscreen" */ ++ suffix = "Touchscreen"; + break; + case HID_DG_TOUCHPAD: + suffix = "Touchpad"; +@@ -1330,6 +1347,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; + td->cc_index = -1; + td->mt_report_id = -1; ++ cc_seen = 0; + hid_set_drvdata(hdev, td); + + td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields), +diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c +index e054ee4..7230243 100644 +--- a/drivers/hid/i2c-hid/i2c-hid.c ++++ b/drivers/hid/i2c-hid/i2c-hid.c +@@ -934,11 +934,6 @@ static int i2c_hid_of_probe(struct i2c_client *client, + } + pdata->hid_descriptor_address = val; + +- ret = of_property_read_u32(dev->of_node, "post-power-on-delay-ms", +- &val); +- if (!ret) +- pdata->post_power_delay_ms = val; +- + return 0; + } + +@@ -955,6 +950,16 @@ static inline int i2c_hid_of_probe(struct i2c_client *client, + } + #endif + ++static void i2c_hid_fwnode_probe(struct i2c_client *client, ++ struct i2c_hid_platform_data *pdata) ++{ ++ u32 val; ++ ++ if (!device_property_read_u32(&client->dev, "post-power-on-delay-ms", ++ &val)) ++ pdata->post_power_delay_ms = val; ++} ++ + static int i2c_hid_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) + { +@@ -998,6 +1003,9 @@ static int i2c_hid_probe(struct i2c_client *client, + ihid->pdata = *platform_data; + } + ++ /* Parse platform agnostic common properties from ACPI / device tree */ ++ i2c_hid_fwnode_probe(client, &ihid->pdata); ++ + ihid->pdata.supply = devm_regulator_get(&client->dev, "vdd"); + if (IS_ERR(ihid->pdata.supply)) { + ret = PTR_ERR(ihid->pdata.supply); +diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig +index f1a5c23..3111140 100644 +--- a/drivers/misc/Kconfig ++++ b/drivers/misc/Kconfig +@@ -503,6 +503,7 @@ source "drivers/misc/ti-st/Kconfig" + source "drivers/misc/lis3lv02d/Kconfig" + source "drivers/misc/altera-stapl/Kconfig" + source "drivers/misc/mei/Kconfig" ++source "drivers/misc/ipts/Kconfig" + source "drivers/misc/vmw_vmci/Kconfig" + source "drivers/misc/mic/Kconfig" + source "drivers/misc/genwqe/Kconfig" +diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile +index 5ca5f64..1673753 100644 +--- a/drivers/misc/Makefile ++++ b/drivers/misc/Makefile +@@ -43,6 +43,7 @@ obj-y += lis3lv02d/ + obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o + obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ + obj-$(CONFIG_INTEL_MEI) += mei/ ++obj-$(CONFIG_INTEL_IPTS) += ipts/ + obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/ + obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o + obj-$(CONFIG_SRAM) += sram.o +diff --git a/drivers/misc/ipts/Kconfig b/drivers/misc/ipts/Kconfig +new file mode 100644 +index 0000000..360ed38 +--- /dev/null ++++ b/drivers/misc/ipts/Kconfig +@@ -0,0 +1,9 @@ ++config INTEL_IPTS ++ tristate "Intel Precise Touch & Stylus" ++ select INTEL_MEI ++ depends on X86 && PCI && HID ++ help ++ Intel Precise Touch & Stylus support ++ Supported SoCs: ++ Intel Skylake ++ Intel Kabylake +diff --git a/drivers/misc/ipts/Makefile b/drivers/misc/ipts/Makefile +new file mode 100644 +index 0000000..1783e9c +--- /dev/null ++++ b/drivers/misc/ipts/Makefile +@@ -0,0 +1,13 @@ ++# ++# Makefile - Intel Precise Touch & Stylus device driver ++# Copyright (c) 2016, Intel Corporation. ++# ++ ++obj-$(CONFIG_INTEL_IPTS)+= intel-ipts.o ++intel-ipts-objs += ipts-mei.o ++intel-ipts-objs += ipts-hid.o ++intel-ipts-objs += ipts-msg-handler.o ++intel-ipts-objs += ipts-kernel.o ++intel-ipts-objs += ipts-resource.o ++intel-ipts-objs += ipts-gfx.o ++intel-ipts-$(CONFIG_DEBUG_FS) += ipts-dbgfs.o +diff --git a/drivers/misc/ipts/ipts-binary-spec.h b/drivers/misc/ipts/ipts-binary-spec.h +new file mode 100644 +index 0000000..87d4bc4 +--- /dev/null ++++ b/drivers/misc/ipts/ipts-binary-spec.h +@@ -0,0 +1,118 @@ ++/* ++ * ++ * Intel Precise Touch & Stylus binary spec ++ * Copyright (c) 2016 Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ */ ++ ++#ifndef _IPTS_BINARY_SPEC_H ++#define _IPTS_BINARY_SPEC_H ++ ++#define IPTS_BIN_HEADER_VERSION 2 ++ ++#pragma pack(1) ++ ++/* we support 16 output buffers(1:feedback, 15:HID) */ ++#define MAX_NUM_OUTPUT_BUFFERS 16 ++ ++typedef enum { ++ IPTS_BIN_KERNEL, ++ IPTS_BIN_RO_DATA, ++ IPTS_BIN_RW_DATA, ++ IPTS_BIN_SENSOR_FRAME, ++ IPTS_BIN_OUTPUT, ++ IPTS_BIN_DYNAMIC_STATE_HEAP, ++ IPTS_BIN_PATCH_LOCATION_LIST, ++ IPTS_BIN_ALLOCATION_LIST, ++ IPTS_BIN_COMMAND_BUFFER_PACKET, ++ IPTS_BIN_TAG, ++} ipts_bin_res_type_t; ++ ++typedef struct ipts_bin_header { ++ char str[4]; ++ unsigned int version; ++ ++#if IPTS_BIN_HEADER_VERSION > 1 ++ unsigned int gfxcore; ++ unsigned int revid; ++#endif ++} ipts_bin_header_t; ++ ++typedef struct ipts_bin_alloc { ++ unsigned int handle; ++ unsigned int reserved; ++} ipts_bin_alloc_t; ++ ++typedef struct ipts_bin_alloc_list { ++ unsigned int num; ++ ipts_bin_alloc_t alloc[]; ++} ipts_bin_alloc_list_t; ++ ++typedef struct ipts_bin_cmdbuf { ++ unsigned int size; ++ char data[]; ++} ipts_bin_cmdbuf_t; ++ ++typedef struct ipts_bin_res { ++ unsigned int handle; ++ ipts_bin_res_type_t type; ++ unsigned int initialize; ++ unsigned int aligned_size; ++ unsigned int size; ++ char data[]; ++} ipts_bin_res_t; ++ ++typedef enum { ++ IPTS_INPUT, ++ IPTS_OUTPUT, ++ IPTS_CONFIGURATION, ++ IPTS_CALIBRATION, ++ IPTS_FEATURE, ++} ipts_bin_io_buffer_type_t; ++ ++typedef struct ipts_bin_io_header { ++ char str[10]; ++ unsigned short type; ++} ipts_bin_io_header_t; ++ ++typedef struct ipts_bin_res_list { ++ unsigned int num; ++ ipts_bin_res_t res[]; ++} ipts_bin_res_list_t; ++ ++typedef struct ipts_bin_patch { ++ unsigned int index; ++ unsigned int reserved1[2]; ++ unsigned int alloc_offset; ++ unsigned int patch_offset; ++ unsigned int reserved2; ++} ipts_bin_patch_t; ++ ++typedef struct ipts_bin_patch_list { ++ unsigned int num; ++ ipts_bin_patch_t patch[]; ++} ipts_bin_patch_list_t; ++ ++typedef struct ipts_bin_guc_wq_info { ++ unsigned int batch_offset; ++ unsigned int size; ++ char data[]; ++} ipts_bin_guc_wq_info_t; ++ ++typedef struct ipts_bin_bufid_patch { ++ unsigned int imm_offset; ++ unsigned int mem_offset; ++} ipts_bin_bufid_patch_t; ++ ++#pragma pack() ++ ++#endif /* _IPTS_BINARY_SPEC_H */ +diff --git a/drivers/misc/ipts/ipts-dbgfs.c b/drivers/misc/ipts/ipts-dbgfs.c +new file mode 100644 +index 0000000..1c5c92f +--- /dev/null ++++ b/drivers/misc/ipts/ipts-dbgfs.c +@@ -0,0 +1,152 @@ ++/* ++ * Intel Precise Touch & Stylus device driver ++ * Copyright (c) 2016, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ */ ++#include ++#include ++#include ++ ++#include "ipts.h" ++#include "ipts-sensor-regs.h" ++#include "ipts-msg-handler.h" ++#include "ipts-state.h" ++ ++const char sensor_mode_fmt[] = "sensor mode : %01d\n"; ++const char ipts_status_fmt[] = "sensor mode : %01d\nipts state : %01d\n"; ++ ++static ssize_t ipts_dbgfs_mode_read(struct file *fp, char __user *ubuf, ++ size_t cnt, loff_t *ppos) ++{ ++ ipts_info_t *ipts = fp->private_data; ++ char mode[80]; ++ int len = 0; ++ ++ if (cnt < sizeof(sensor_mode_fmt) - 3) ++ return -EINVAL; ++ ++ len = scnprintf(mode, 80, sensor_mode_fmt, ipts->sensor_mode); ++ if (len < 0) ++ return -EIO; ++ ++ return simple_read_from_buffer(ubuf, cnt, ppos, mode, len); ++} ++ ++static ssize_t ipts_dbgfs_mode_write(struct file *fp, const char __user *ubuf, ++ size_t cnt, loff_t *ppos) ++{ ++ ipts_info_t *ipts = fp->private_data; ++ ipts_state_t state; ++ int sensor_mode, len; ++ char mode[3]; ++ ++ if (cnt == 0 || cnt > 3) ++ return -EINVAL; ++ ++ state = ipts_get_state(ipts); ++ if (state != IPTS_STA_RAW_DATA_STARTED && state != IPTS_STA_HID_STARTED) { ++ return -EIO; ++ } ++ ++ len = cnt; ++ if (copy_from_user(mode, ubuf, len)) ++ return -EFAULT; ++ ++ while(len > 0 && (isspace(mode[len-1]) || mode[len-1] == '\n')) ++ len--; ++ mode[len] = '\0'; ++ ++ if (sscanf(mode, "%d", &sensor_mode) != 1) ++ return -EINVAL; ++ ++ if (sensor_mode != TOUCH_SENSOR_MODE_RAW_DATA && ++ sensor_mode != TOUCH_SENSOR_MODE_HID) { ++ return -EINVAL; ++ } ++ ++ if (sensor_mode == ipts->sensor_mode) ++ return 0; ++ ++ ipts_switch_sensor_mode(ipts, sensor_mode); ++ ++ return cnt; ++} ++ ++static const struct file_operations ipts_mode_dbgfs_fops = { ++ .open = simple_open, ++ .read = ipts_dbgfs_mode_read, ++ .write = ipts_dbgfs_mode_write, ++ .llseek = generic_file_llseek, ++}; ++ ++static ssize_t ipts_dbgfs_status_read(struct file *fp, char __user *ubuf, ++ size_t cnt, loff_t *ppos) ++{ ++ ipts_info_t *ipts = fp->private_data; ++ char status[256]; ++ int len = 0; ++ ++ if (cnt < sizeof(ipts_status_fmt) - 3) ++ return -EINVAL; ++ ++ len = scnprintf(status, 256, ipts_status_fmt, ipts->sensor_mode, ++ ipts->state); ++ if (len < 0) ++ return -EIO; ++ ++ return simple_read_from_buffer(ubuf, cnt, ppos, status, len); ++} ++ ++static const struct file_operations ipts_status_dbgfs_fops = { ++ .open = simple_open, ++ .read = ipts_dbgfs_status_read, ++ .llseek = generic_file_llseek, ++}; ++ ++void ipts_dbgfs_deregister(ipts_info_t* ipts) ++{ ++ if (!ipts->dbgfs_dir) ++ return; ++ ++ debugfs_remove_recursive(ipts->dbgfs_dir); ++ ipts->dbgfs_dir = NULL; ++} ++ ++int ipts_dbgfs_register(ipts_info_t* ipts, const char *name) ++{ ++ struct dentry *dir, *f; ++ ++ dir = debugfs_create_dir(name, NULL); ++ if (!dir) ++ return -ENOMEM; ++ ++ f = debugfs_create_file("mode", S_IRUSR | S_IWUSR, dir, ++ ipts, &ipts_mode_dbgfs_fops); ++ if (!f) { ++ ipts_err(ipts, "debugfs mode creation failed\n"); ++ goto err; ++ } ++ ++ f = debugfs_create_file("status", S_IRUSR, dir, ++ ipts, &ipts_status_dbgfs_fops); ++ if (!f) { ++ ipts_err(ipts, "debugfs status creation failed\n"); ++ goto err; ++ } ++ ++ ipts->dbgfs_dir = dir; ++ ++ return 0; ++err: ++ ipts_dbgfs_deregister(ipts); ++ return -ENODEV; ++} +diff --git a/drivers/misc/ipts/ipts-gfx.c b/drivers/misc/ipts/ipts-gfx.c +new file mode 100644 +index 0000000..5172777 +--- /dev/null ++++ b/drivers/misc/ipts/ipts-gfx.c +@@ -0,0 +1,184 @@ ++/* ++ * ++ * Intel Integrated Touch Gfx Interface Layer ++ * Copyright (c) 2016 Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ */ ++#include ++#include ++#include ++ ++#include "ipts.h" ++#include "ipts-msg-handler.h" ++#include "ipts-state.h" ++ ++static void gfx_processing_complete(void *data) ++{ ++ ipts_info_t *ipts = data; ++ ++ if (ipts_get_state(ipts) == IPTS_STA_RAW_DATA_STARTED) { ++ schedule_work(&ipts->raw_data_work); ++ return; ++ } ++ ++ ipts_dbg(ipts, "not ready to handle gfx event\n"); ++} ++ ++static void notify_gfx_status(u32 status, void *data) ++{ ++ ipts_info_t *ipts = data; ++ ++ ipts->gfx_status = status; ++ schedule_work(&ipts->gfx_status_work); ++} ++ ++static int connect_gfx(ipts_info_t *ipts) ++{ ++ int ret = 0; ++ intel_ipts_connect_t ipts_connect; ++ ++ ipts_connect.if_version = IPTS_INTERFACE_V1; ++ ipts_connect.ipts_cb.workload_complete = gfx_processing_complete; ++ ipts_connect.ipts_cb.notify_gfx_status = notify_gfx_status; ++ ipts_connect.data = (void*)ipts; ++ ++ ret = intel_ipts_connect(&ipts_connect); ++ if (ret) ++ return ret; ++ ++ /* TODO: gfx version check */ ++ ipts->gfx_info.gfx_handle = ipts_connect.gfx_handle; ++ ipts->gfx_info.ipts_ops = ipts_connect.ipts_ops; ++ ++ return ret; ++} ++ ++static void disconnect_gfx(ipts_info_t *ipts) ++{ ++ intel_ipts_disconnect(ipts->gfx_info.gfx_handle); ++} ++ ++#ifdef RUN_DBG_THREAD ++#include "../mei/mei_dev.h" ++ ++static struct task_struct *dbg_thread; ++ ++static void ipts_print_dbg_info(ipts_info_t* ipts) ++{ ++ char fw_sts_str[MEI_FW_STATUS_STR_SZ]; ++ u32 *db, *head, *tail; ++ intel_ipts_wq_info_t* wq_info; ++ ++ wq_info = &ipts->resource.wq_info; ++ ++ mei_fw_status_str(ipts->cldev->bus, fw_sts_str, MEI_FW_STATUS_STR_SZ); ++ pr_info(">> tdt : fw status : %s\n", fw_sts_str); ++ ++ db = (u32*)wq_info->db_addr; ++ head = (u32*)wq_info->wq_head_addr; ++ tail = (u32*)wq_info->wq_tail_addr; ++ pr_info(">> == DB s:%x, c:%x ==\n", *db, *(db+1)); ++ pr_info(">> == WQ h:%u, t:%u ==\n", *head, *tail); ++} ++ ++static int ipts_dbg_thread(void *data) ++{ ++ ipts_info_t *ipts = (ipts_info_t *)data; ++ ++ pr_info(">> start debug thread\n"); ++ ++ while (!kthread_should_stop()) { ++ if (ipts_get_state(ipts) != IPTS_STA_RAW_DATA_STARTED) { ++ pr_info("state is not IPTS_STA_RAW_DATA_STARTED : %d\n", ++ ipts_get_state(ipts)); ++ msleep(5000); ++ continue; ++ } ++ ++ ipts_print_dbg_info(ipts); ++ ++ msleep(3000); ++ } ++ ++ return 0; ++} ++#endif ++ ++int ipts_open_gpu(ipts_info_t *ipts) ++{ ++ int ret = 0; ++ ++ ret = connect_gfx(ipts); ++ if (ret) { ++ ipts_dbg(ipts, "cannot connect GPU\n"); ++ return ret; ++ } ++ ++ ret = ipts->gfx_info.ipts_ops.get_wq_info(ipts->gfx_info.gfx_handle, ++ &ipts->resource.wq_info); ++ if (ret) { ++ ipts_dbg(ipts, "error in get_wq_info\n"); ++ return ret; ++ } ++ ++#ifdef RUN_DBG_THREAD ++ dbg_thread = kthread_run(ipts_dbg_thread, (void *)ipts, "ipts_debug"); ++#endif ++ ++ return 0; ++} ++ ++void ipts_close_gpu(ipts_info_t *ipts) ++{ ++ disconnect_gfx(ipts); ++ ++#ifdef RUN_DBG_THREAD ++ kthread_stop(dbg_thread); ++#endif ++} ++ ++intel_ipts_mapbuffer_t *ipts_map_buffer(ipts_info_t *ipts, u32 size, u32 flags) ++{ ++ intel_ipts_mapbuffer_t *buf; ++ u64 handle; ++ int ret; ++ ++ buf = devm_kzalloc(&ipts->cldev->dev, sizeof(*buf), GFP_KERNEL); ++ if (!buf) ++ return NULL; ++ ++ buf->size = size; ++ buf->flags = flags; ++ ++ handle = ipts->gfx_info.gfx_handle; ++ ret = ipts->gfx_info.ipts_ops.map_buffer(handle, buf); ++ if (ret) { ++ devm_kfree(&ipts->cldev->dev, buf); ++ return NULL; ++ } ++ ++ return buf; ++} ++ ++void ipts_unmap_buffer(ipts_info_t *ipts, intel_ipts_mapbuffer_t *buf) ++{ ++ u64 handle; ++ int ret; ++ ++ if (!buf) ++ return; ++ ++ handle = ipts->gfx_info.gfx_handle; ++ ret = ipts->gfx_info.ipts_ops.unmap_buffer(handle, buf->buf_handle); ++ ++ devm_kfree(&ipts->cldev->dev, buf); ++} +diff --git a/drivers/misc/ipts/ipts-gfx.h b/drivers/misc/ipts/ipts-gfx.h +new file mode 100644 +index 0000000..03a5f35 +--- /dev/null ++++ b/drivers/misc/ipts/ipts-gfx.h +@@ -0,0 +1,24 @@ ++/* ++ * Intel Precise Touch & Stylus gpu wrapper ++ * Copyright (c) 2016, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ */ ++ ++ ++#ifndef _IPTS_GFX_H_ ++#define _IPTS_GFX_H_ ++ ++int ipts_open_gpu(ipts_info_t *ipts); ++void ipts_close_gpu(ipts_info_t *ipts); ++intel_ipts_mapbuffer_t *ipts_map_buffer(ipts_info_t *ipts, u32 size, u32 flags); ++void ipts_unmap_buffer(ipts_info_t *ipts, intel_ipts_mapbuffer_t *buf); ++ ++#endif // _IPTS_GFX_H_ +diff --git a/drivers/misc/ipts/ipts-hid.c b/drivers/misc/ipts/ipts-hid.c +new file mode 100644 +index 0000000..3b3be61 +--- /dev/null ++++ b/drivers/misc/ipts/ipts-hid.c +@@ -0,0 +1,456 @@ ++/* ++ * Intel Precise Touch & Stylus HID driver ++ * ++ * Copyright (c) 2016, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "ipts.h" ++#include "ipts-resource.h" ++#include "ipts-sensor-regs.h" ++#include "ipts-msg-handler.h" ++ ++#define BUS_MEI 0x44 ++ ++#define HID_DESC_INTEL "intel/ipts/intel_desc.bin" ++#define HID_DESC_VENDOR "intel/ipts/vendor_desc.bin" ++MODULE_FIRMWARE(HID_DESC_INTEL); ++MODULE_FIRMWARE(HID_DESC_VENDOR); ++ ++typedef enum output_buffer_payload_type { ++ OUTPUT_BUFFER_PAYLOAD_ERROR = 0, ++ OUTPUT_BUFFER_PAYLOAD_HID_INPUT_REPORT, ++ OUTPUT_BUFFER_PAYLOAD_HID_FEATURE_REPORT, ++ OUTPUT_BUFFER_PAYLOAD_KERNEL_LOAD, ++ OUTPUT_BUFFER_PAYLOAD_FEEDBACK_BUFFER ++} output_buffer_payload_type_t; ++ ++typedef struct kernel_output_buffer_header { ++ u16 length; ++ u8 payload_type; ++ u8 reserved1; ++ touch_hid_private_data_t hid_private_data; ++ u8 reserved2[28]; ++ u8 data[0]; ++} kernel_output_buffer_header_t; ++ ++typedef struct kernel_output_payload_error { ++ u16 severity; ++ u16 source; ++ u8 code[4]; ++ char string[128]; ++} kernel_output_payload_error_t; ++ ++static int ipts_hid_get_hid_descriptor(ipts_info_t *ipts, u8 **desc, int *size) ++{ ++ u8 *buf; ++ int hid_size = 0, ret = 0; ++ const struct firmware *intel_desc = NULL; ++ const struct firmware *vendor_desc = NULL; ++ const char *intel_desc_path = HID_DESC_INTEL; ++ const char *vendor_desc_path = HID_DESC_VENDOR; ++ ++ ret = request_firmware(&intel_desc, intel_desc_path, &ipts->cldev->dev); ++ if (ret) { ++ goto no_hid; ++ } ++ hid_size = intel_desc->size; ++ ++ ret = request_firmware(&vendor_desc, vendor_desc_path, &ipts->cldev->dev); ++ if (ret) { ++ ipts_dbg(ipts, "error in reading HID Vendor Descriptor\n"); ++ } else { ++ hid_size += vendor_desc->size; ++ } ++ ++ ipts_dbg(ipts, "hid size = %d\n", hid_size); ++ buf = vmalloc(hid_size); ++ if (buf == NULL) { ++ ret = -ENOMEM; ++ goto no_mem; ++ } ++ ++ memcpy(buf, intel_desc->data, intel_desc->size); ++ if (vendor_desc) { ++ memcpy(&buf[intel_desc->size], vendor_desc->data, ++ vendor_desc->size); ++ release_firmware(vendor_desc); ++ } ++ ++ release_firmware(intel_desc); ++ ++ *desc = buf; ++ *size = hid_size; ++ ++ return 0; ++no_mem : ++ if (vendor_desc) ++ release_firmware(vendor_desc); ++ release_firmware(intel_desc); ++ ++no_hid : ++ return ret; ++} ++ ++static int ipts_hid_parse(struct hid_device *hid) ++{ ++ ipts_info_t *ipts = hid->driver_data; ++ int ret = 0, size; ++ u8 *buf; ++ ++ ipts_dbg(ipts, "ipts_hid_parse() start\n"); ++ ret = ipts_hid_get_hid_descriptor(ipts, &buf, &size); ++ if (ret != 0) { ++ ipts_dbg(ipts, "ipts_hid_ipts_get_hid_descriptor ret %d\n", ret); ++ return -EIO; ++ } ++ ++ ret = hid_parse_report(hid, buf, size); ++ vfree(buf); ++ if (ret) { ++ ipts_err(ipts, "hid_parse_report error : %d\n", ret); ++ goto out; ++ } ++ ++ ipts->hid_desc_ready = true; ++out: ++ return ret; ++} ++ ++static int ipts_hid_start(struct hid_device *hid) ++{ ++ return 0; ++} ++ ++static void ipts_hid_stop(struct hid_device *hid) ++{ ++ return; ++} ++ ++static int ipts_hid_open(struct hid_device *hid) ++{ ++ return 0; ++} ++ ++static void ipts_hid_close(struct hid_device *hid) ++{ ++ ipts_info_t *ipts = hid->driver_data; ++ ++ ipts->hid_desc_ready = false; ++ ++ return; ++} ++ ++static int ipts_hid_send_hid2me_feedback(ipts_info_t *ipts, u32 fb_data_type, ++ __u8 *buf, size_t count) ++{ ++ ipts_buffer_info_t *fb_buf; ++ touch_feedback_hdr_t *feedback; ++ u8 *payload; ++ int header_size; ++ ipts_state_t state; ++ ++ header_size = sizeof(touch_feedback_hdr_t); ++ ++ if (count > ipts->resource.hid2me_buffer_size - header_size) ++ return -EINVAL; ++ ++ state = ipts_get_state(ipts); ++ if (state != IPTS_STA_RAW_DATA_STARTED && state != IPTS_STA_HID_STARTED) ++ return 0; ++ ++ fb_buf = ipts_get_hid2me_buffer(ipts); ++ feedback = (touch_feedback_hdr_t *)fb_buf->addr; ++ payload = fb_buf->addr + header_size; ++ memset(feedback, 0, header_size); ++ ++ feedback->feedback_data_type = fb_data_type; ++ feedback->feedback_cmd_type = TOUCH_FEEDBACK_CMD_TYPE_NONE; ++ feedback->payload_size_bytes = count; ++ feedback->buffer_id = TOUCH_HID_2_ME_BUFFER_ID; ++ feedback->protocol_ver = 0; ++ feedback->reserved[0] = 0xAC; ++ ++ /* copy payload */ ++ memcpy(payload, buf, count); ++ ++ ipts_send_feedback(ipts, TOUCH_HID_2_ME_BUFFER_ID, 0); ++ ++ return 0; ++} ++ ++static int ipts_hid_raw_request(struct hid_device *hid, ++ unsigned char report_number, __u8 *buf, ++ size_t count, unsigned char report_type, ++ int reqtype) ++{ ++ ipts_info_t *ipts = hid->driver_data; ++ u32 fb_data_type; ++ ++ ipts_dbg(ipts, "hid raw request => report %d, request %d\n", ++ (int)report_type, reqtype); ++ ++ if (report_type != HID_FEATURE_REPORT) ++ return 0; ++ ++ switch (reqtype) { ++ case HID_REQ_GET_REPORT: ++ fb_data_type = TOUCH_FEEDBACK_DATA_TYPE_GET_FEATURES; ++ break; ++ case HID_REQ_SET_REPORT: ++ fb_data_type = TOUCH_FEEDBACK_DATA_TYPE_SET_FEATURES; ++ break; ++ default: ++ ipts_err(ipts, "raw request not supprted: %d\n", reqtype); ++ return -EIO; ++ } ++ ++ return ipts_hid_send_hid2me_feedback(ipts, fb_data_type, buf, count); ++} ++ ++static int ipts_hid_output_report(struct hid_device *hid, ++ __u8 *buf, size_t count) ++{ ++ ipts_info_t *ipts = hid->driver_data; ++ u32 fb_data_type; ++ ++ ipts_dbg(ipts, "hid output report\n"); ++ ++ fb_data_type = TOUCH_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; ++ ++ return ipts_hid_send_hid2me_feedback(ipts, fb_data_type, buf, count); ++} ++ ++static struct hid_ll_driver ipts_hid_ll_driver = { ++ .parse = ipts_hid_parse, ++ .start = ipts_hid_start, ++ .stop = ipts_hid_stop, ++ .open = ipts_hid_open, ++ .close = ipts_hid_close, ++ .raw_request = ipts_hid_raw_request, ++ .output_report = ipts_hid_output_report, ++}; ++ ++int ipts_hid_init(ipts_info_t *ipts) ++{ ++ int ret = 0; ++ struct hid_device *hid; ++ ++ hid = hid_allocate_device(); ++ if (IS_ERR(hid)) { ++ ret = PTR_ERR(hid); ++ goto err_dev; ++ } ++ ++ hid->driver_data = ipts; ++ hid->ll_driver = &ipts_hid_ll_driver; ++ hid->dev.parent = &ipts->cldev->dev; ++ hid->bus = BUS_MEI; ++ hid->version = ipts->device_info.fw_rev; ++ hid->vendor = ipts->device_info.vendor_id; ++ hid->product = ipts->device_info.device_id; ++ ++ snprintf(hid->phys, sizeof(hid->phys), "heci3"); ++ snprintf(hid->name, sizeof(hid->name), ++ "%s %04hX:%04hX", "ipts", hid->vendor, hid->product); ++ ++ ret = hid_add_device(hid); ++ if (ret) { ++ if (ret != -ENODEV) ++ ipts_err(ipts, "can't add hid device: %d\n", ret); ++ goto err_mem_free; ++ } ++ ++ ipts->hid = hid; ++ ++ return 0; ++ ++err_mem_free: ++ hid_destroy_device(hid); ++err_dev: ++ return ret; ++} ++ ++void ipts_hid_release(ipts_info_t *ipts) ++{ ++ if (!ipts->hid) ++ return; ++ hid_destroy_device(ipts->hid); ++} ++ ++int ipts_handle_hid_data(ipts_info_t *ipts, ++ touch_sensor_hid_ready_for_data_rsp_data_t *hid_rsp) ++{ ++ touch_raw_data_hdr_t *raw_header; ++ ipts_buffer_info_t *buffer_info; ++ touch_feedback_hdr_t *feedback; ++ u8 *raw_data; ++ int touch_data_buffer_index; ++ int transaction_id; ++ int ret = 0; ++ ++ touch_data_buffer_index = (int)hid_rsp->touch_data_buffer_index; ++ buffer_info = ipts_get_touch_data_buffer_hid(ipts); ++ raw_header = (touch_raw_data_hdr_t *)buffer_info->addr; ++ transaction_id = raw_header->hid_private_data.transaction_id; ++ ++ raw_data = (u8*)raw_header + sizeof(touch_raw_data_hdr_t); ++ if (raw_header->data_type == TOUCH_RAW_DATA_TYPE_HID_REPORT) { ++ memcpy(ipts->hid_input_report, raw_data, ++ raw_header->raw_data_size_bytes); ++ ++ ret = hid_input_report(ipts->hid, HID_INPUT_REPORT, ++ (u8*)ipts->hid_input_report, ++ raw_header->raw_data_size_bytes, 1); ++ if (ret) { ++ ipts_err(ipts, "error in hid_input_report : %d\n", ret); ++ } ++ } else if (raw_header->data_type == TOUCH_RAW_DATA_TYPE_GET_FEATURES) { ++ /* TODO: implement together with "get feature ioctl" */ ++ } else if (raw_header->data_type == TOUCH_RAW_DATA_TYPE_ERROR) { ++ touch_error_t *touch_err = (touch_error_t *)raw_data; ++ ++ ipts_err(ipts, "error type : %d, me fw error : %x, err reg : %x\n", ++ touch_err->touch_error_type, ++ touch_err->touch_me_fw_error.value, ++ touch_err->touch_error_register.reg_value); ++ } ++ ++ /* send feedback data for HID mode */ ++ buffer_info = ipts_get_feedback_buffer(ipts, touch_data_buffer_index); ++ feedback = (touch_feedback_hdr_t *)buffer_info->addr; ++ memset(feedback, 0, sizeof(touch_feedback_hdr_t)); ++ feedback->feedback_cmd_type = TOUCH_FEEDBACK_CMD_TYPE_NONE; ++ feedback->payload_size_bytes = 0; ++ feedback->buffer_id = touch_data_buffer_index; ++ feedback->protocol_ver = 0; ++ feedback->reserved[0] = 0xAC; ++ ++ ret = ipts_send_feedback(ipts, touch_data_buffer_index, transaction_id); ++ ++ return ret; ++} ++ ++static int handle_outputs(ipts_info_t *ipts, int parallel_idx) ++{ ++ kernel_output_buffer_header_t *out_buf_hdr; ++ ipts_buffer_info_t *output_buf, *fb_buf = NULL; ++ u8 *input_report, *payload; ++ u32 transaction_id; ++ int i, payload_size, ret = 0, header_size; ++ ++ header_size = sizeof(kernel_output_buffer_header_t); ++ output_buf = ipts_get_output_buffers_by_parallel_id(ipts, parallel_idx); ++ for (i = 0; i < ipts->resource.num_of_outputs; i++) { ++ out_buf_hdr = (kernel_output_buffer_header_t*)output_buf[i].addr; ++ if (out_buf_hdr->length < header_size) ++ continue; ++ ++ payload_size = out_buf_hdr->length - header_size; ++ payload = out_buf_hdr->data; ++ ++ switch(out_buf_hdr->payload_type) { ++ case OUTPUT_BUFFER_PAYLOAD_HID_INPUT_REPORT: ++ input_report = ipts->hid_input_report; ++ memcpy(input_report, payload, payload_size); ++ hid_input_report(ipts->hid, HID_INPUT_REPORT, ++ input_report, payload_size, 1); ++ break; ++ case OUTPUT_BUFFER_PAYLOAD_HID_FEATURE_REPORT: ++ ipts_dbg(ipts, "output hid feature report\n"); ++ break; ++ case OUTPUT_BUFFER_PAYLOAD_KERNEL_LOAD: ++ ipts_dbg(ipts, "output kernel load\n"); ++ break; ++ case OUTPUT_BUFFER_PAYLOAD_FEEDBACK_BUFFER: ++ { ++ /* send feedback data for raw data mode */ ++ fb_buf = ipts_get_feedback_buffer(ipts, ++ parallel_idx); ++ transaction_id = out_buf_hdr-> ++ hid_private_data.transaction_id; ++ memcpy(fb_buf->addr, payload, payload_size); ++ break; ++ } ++ case OUTPUT_BUFFER_PAYLOAD_ERROR: ++ { ++ kernel_output_payload_error_t *err_payload; ++ ++ if (payload_size == 0) ++ break; ++ ++ err_payload = ++ (kernel_output_payload_error_t*)payload; ++ ++ ipts_err(ipts, "error : severity : %d," ++ " source : %d," ++ " code : %d:%d:%d:%d\n" ++ "string %s\n", ++ err_payload->severity, ++ err_payload->source, ++ err_payload->code[0], ++ err_payload->code[1], ++ err_payload->code[2], ++ err_payload->code[3], ++ err_payload->string); ++ ++ break; ++ } ++ default: ++ ipts_err(ipts, "invalid output buffer payload\n"); ++ break; ++ } ++ } ++ ++ if (fb_buf) { ++ ret = ipts_send_feedback(ipts, parallel_idx, transaction_id); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int handle_output_buffers(ipts_info_t *ipts, int cur_idx, int end_idx) ++{ ++ int max_num_of_buffers = ipts_get_num_of_parallel_buffers(ipts); ++ ++ do { ++ cur_idx++; /* cur_idx has last completed so starts with +1 */ ++ cur_idx %= max_num_of_buffers; ++ handle_outputs(ipts, cur_idx); ++ } while (cur_idx != end_idx); ++ ++ return 0; ++} ++ ++int ipts_handle_processed_data(ipts_info_t *ipts) ++{ ++ int ret = 0; ++ int current_buffer_idx; ++ int last_buffer_idx; ++ ++ current_buffer_idx = *ipts->last_submitted_id; ++ last_buffer_idx = ipts->last_buffer_completed; ++ ++ if (current_buffer_idx == last_buffer_idx) ++ return 0; ++ ++ ipts->last_buffer_completed = current_buffer_idx; ++ handle_output_buffers(ipts, last_buffer_idx, current_buffer_idx); ++ ++ return ret; ++} +diff --git a/drivers/misc/ipts/ipts-hid.h b/drivers/misc/ipts/ipts-hid.h +new file mode 100644 +index 0000000..f1b22c9 +--- /dev/null ++++ b/drivers/misc/ipts/ipts-hid.h +@@ -0,0 +1,34 @@ ++/* ++ * Intel Precise Touch & Stylus HID definition ++ * ++ * Copyright (c) 2016, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ */ ++ ++#ifndef _IPTS_HID_H_ ++#define _IPTS_HID_H_ ++ ++#define BUS_MEI 0x44 ++ ++#if 0 /* TODO : we have special report ID. will implement them */ ++#define WRITE_CHANNEL_REPORT_ID 0xa ++#define READ_CHANNEL_REPORT_ID 0xb ++#define CONFIG_CHANNEL_REPORT_ID 0xd ++#define VENDOR_INFO_REPORT_ID 0xF ++#define SINGLE_TOUCH_REPORT_ID 0x40 ++#endif ++ ++int ipts_hid_init(ipts_info_t *ipts); ++void ipts_hid_release(ipts_info_t *ipts); ++int ipts_handle_hid_data(ipts_info_t *ipts, ++ touch_sensor_hid_ready_for_data_rsp_data_t *hid_rsp); ++ ++#endif /* _IPTS_HID_H_ */ +diff --git a/drivers/misc/ipts/ipts-kernel.c b/drivers/misc/ipts/ipts-kernel.c +new file mode 100644 +index 0000000..ca5e24c +--- /dev/null ++++ b/drivers/misc/ipts/ipts-kernel.c +@@ -0,0 +1,1050 @@ ++#include ++#include ++#include ++#include ++ ++#include "ipts.h" ++#include "ipts-resource.h" ++#include "ipts-binary-spec.h" ++#include "ipts-state.h" ++#include "ipts-msg-handler.h" ++#include "ipts-gfx.h" ++ ++#define MAX_IOCL_FILE_NAME_LEN 80 ++#define MAX_IOCL_FILE_PATH_LEN 256 ++ ++#pragma pack(1) ++typedef struct bin_data_file_info { ++ u32 io_buffer_type; ++ u32 flags; ++ char file_name[MAX_IOCL_FILE_NAME_LEN]; ++} bin_data_file_info_t; ++ ++typedef struct bin_fw_info { ++ char fw_name[MAX_IOCL_FILE_NAME_LEN]; ++ ++ /* list of parameters to load a kernel */ ++ s32 vendor_output; /* output index. -1 for no use */ ++ u32 num_of_data_files; ++ bin_data_file_info_t data_file[]; ++} bin_fw_info_t; ++ ++typedef struct bin_fw_list { ++ u32 num_of_fws; ++ bin_fw_info_t fw_info[]; ++} bin_fw_list_t; ++#pragma pack() ++ ++/* OpenCL kernel */ ++typedef struct bin_workload { ++ int cmdbuf_index; ++ int iobuf_input; ++ int iobuf_output[MAX_NUM_OUTPUT_BUFFERS]; ++} bin_workload_t; ++ ++typedef struct bin_buffer { ++ unsigned int handle; ++ intel_ipts_mapbuffer_t *buf; ++ bool no_unmap; /* only releasing vendor kernel unmaps output buffers */ ++} bin_buffer_t; ++ ++typedef struct bin_alloc_info { ++ bin_buffer_t *buffs; ++ int num_of_allocations; ++ int num_of_outputs; ++ ++ int num_of_buffers; ++} bin_alloc_info_t; ++ ++typedef struct bin_guc_wq_item { ++ unsigned int batch_offset; ++ unsigned int size; ++ char data[]; ++} bin_guc_wq_item_t; ++ ++typedef struct bin_kernel_info { ++ bin_workload_t *wl; ++ bin_alloc_info_t *alloc_info; ++ bin_guc_wq_item_t *guc_wq_item; ++ ipts_bin_bufid_patch_t bufid_patch; ++ ++ bool is_vendor; /* 1: vendor, 0: postprocessing */ ++} bin_kernel_info_t; ++ ++typedef struct bin_kernel_list { ++ intel_ipts_mapbuffer_t *bufid_buf; ++ int num_of_kernels; ++ bin_kernel_info_t kernels[]; ++} bin_kernel_list_t; ++ ++typedef struct bin_parse_info { ++ u8 *data; ++ int size; ++ int parsed; ++ ++ bin_fw_info_t *fw_info; ++ ++ /* only used by postprocessing */ ++ bin_kernel_info_t *vendor_kernel; ++ u32 interested_vendor_output; /* interested vendor output index */ ++} bin_parse_info_t; ++ ++#define BDW_SURFACE_BASE_ADDRESS 0x6101000e ++#define SURFACE_STATE_OFFSET_WORD 4 ++#define SBA_OFFSET_BYTES 16384 ++#define LASTSUBMITID_DEFAULT_VALUE -1 ++ ++#define IPTS_FW_PATH_FMT "intel/ipts/%s" ++#define IPTS_FW_CONFIG_FILE "intel/ipts/ipts_fw_config.bin" ++ ++MODULE_FIRMWARE(IPTS_FW_CONFIG_FILE); ++ ++#define IPTS_INPUT_ON ((u32)1 << IPTS_INPUT) ++#define IPTS_OUTPUT_ON ((u32)1 << IPTS_OUTPUT) ++#define IPTS_CONFIGURATION_ON ((u32)1 << IPTS_CONFIGURATION) ++#define IPTS_CALIBRATION_ON ((u32)1 << IPTS_CALIBRATION) ++#define IPTS_FEATURE_ON ((u32)1 << IPTS_FEATURE) ++ ++#define DATA_FILE_FLAG_SHARE 0x00000001 ++#define DATA_FILE_FLAG_ALLOC_CONTIGUOUS 0x00000002 ++ ++static int bin_read_fw(ipts_info_t *ipts, const char *fw_name, ++ u8* data, int size) ++{ ++ const struct firmware *fw = NULL; ++ char fw_path[MAX_IOCL_FILE_PATH_LEN]; ++ int ret = 0; ++ ++ snprintf(fw_path, MAX_IOCL_FILE_PATH_LEN, IPTS_FW_PATH_FMT, fw_name); ++ ret = request_firmware(&fw, fw_path, &ipts->cldev->dev); ++ if (ret) { ++ ipts_err(ipts, "cannot read fw %s\n", fw_path); ++ return ret; ++ } ++ ++ if (fw->size > size) { ++ ipts_dbg(ipts, "too small buffer to contain fw data\n"); ++ ret = -EINVAL; ++ goto rel_return; ++ } ++ ++ memcpy(data, fw->data, fw->size); ++ ++rel_return: ++ release_firmware(fw); ++ ++ return ret; ++} ++ ++ ++static bin_data_file_info_t* bin_get_data_file_info(bin_fw_info_t* fw_info, ++ u32 io_buffer_type) ++{ ++ int i; ++ ++ for (i = 0; i < fw_info->num_of_data_files; i++) { ++ if (fw_info->data_file[i].io_buffer_type == io_buffer_type) ++ break; ++ } ++ ++ if (i == fw_info->num_of_data_files) ++ return NULL; ++ ++ return &fw_info->data_file[i]; ++} ++ ++static inline bool is_shared_data(const bin_data_file_info_t *data_file) ++{ ++ if (data_file) ++ return (!!(data_file->flags & DATA_FILE_FLAG_SHARE)); ++ ++ return false; ++} ++ ++static inline bool is_alloc_cont_data(const bin_data_file_info_t *data_file) ++{ ++ if (data_file) ++ return (!!(data_file->flags & DATA_FILE_FLAG_ALLOC_CONTIGUOUS)); ++ ++ return false; ++} ++ ++static inline bool is_parsing_vendor_kernel(const bin_parse_info_t *parse_info) ++{ ++ /* vendor_kernel == null while loading itself(vendor kernel) */ ++ return parse_info->vendor_kernel == NULL; ++} ++ ++static int bin_read_allocation_list(ipts_info_t *ipts, ++ bin_parse_info_t *parse_info, ++ bin_alloc_info_t *alloc_info) ++{ ++ ipts_bin_alloc_list_t *alloc_list; ++ int alloc_idx, parallel_idx, num_of_parallels, buf_idx, num_of_buffers; ++ int parsed, size; ++ ++ parsed = parse_info->parsed; ++ size = parse_info->size; ++ ++ alloc_list = (ipts_bin_alloc_list_t *)&parse_info->data[parsed]; ++ ++ /* validation check */ ++ if (sizeof(alloc_list->num) > size - parsed) ++ return -EINVAL; ++ ++ /* read the number of aloocations */ ++ parsed += sizeof(alloc_list->num); ++ ++ /* validation check */ ++ if (sizeof(alloc_list->alloc[0]) * alloc_list->num > size - parsed) ++ return -EINVAL; ++ ++ num_of_parallels = ipts_get_num_of_parallel_buffers(ipts); ++ num_of_buffers = num_of_parallels * alloc_list->num + num_of_parallels; ++ ++ alloc_info->buffs = vmalloc(sizeof(bin_buffer_t) * num_of_buffers); ++ if (alloc_info->buffs == NULL) ++ return -ENOMEM; ++ ++ memset(alloc_info->buffs, 0, sizeof(bin_buffer_t) * num_of_buffers); ++ for (alloc_idx = 0; alloc_idx < alloc_list->num; alloc_idx++) { ++ for (parallel_idx = 0; parallel_idx < num_of_parallels; ++ parallel_idx++) { ++ buf_idx = alloc_idx + (parallel_idx * alloc_list->num); ++ alloc_info->buffs[buf_idx].handle = ++ alloc_list->alloc[alloc_idx].handle; ++ ++ } ++ ++ parsed += sizeof(alloc_list->alloc[0]); ++ } ++ ++ parse_info->parsed = parsed; ++ alloc_info->num_of_allocations = alloc_list->num; ++ alloc_info->num_of_buffers = num_of_buffers; ++ ++ ipts_dbg(ipts, "number of allocations = %d, buffers = %d\n", ++ alloc_info->num_of_allocations, ++ alloc_info->num_of_buffers); ++ ++ return 0; ++} ++ ++static void patch_SBA(u32 *buf_addr, u64 gpu_addr, int size) ++{ ++ u64 *stateBase; ++ u64 SBA; ++ u32 inst; ++ int i; ++ ++ SBA = gpu_addr + SBA_OFFSET_BYTES; ++ ++ for (i = 0; i < size/4; i++) { ++ inst = buf_addr[i]; ++ if (inst == BDW_SURFACE_BASE_ADDRESS) { ++ stateBase = (u64*)&buf_addr[i + SURFACE_STATE_OFFSET_WORD]; ++ *stateBase |= SBA; ++ *stateBase |= 0x01; // enable ++ break; ++ } ++ } ++} ++ ++static int bin_read_cmd_buffer(ipts_info_t *ipts, ++ bin_parse_info_t *parse_info, ++ bin_alloc_info_t *alloc_info, ++ bin_workload_t *wl) ++{ ++ ipts_bin_cmdbuf_t *cmd; ++ intel_ipts_mapbuffer_t *buf; ++ int cmdbuf_idx, size, parsed, parallel_idx, num_of_parallels; ++ ++ size = parse_info->size; ++ parsed = parse_info->parsed; ++ ++ cmd = (ipts_bin_cmdbuf_t *)&parse_info->data[parsed]; ++ ++ if (sizeof(cmd->size) > size - parsed) ++ return -EINVAL; ++ ++ parsed += sizeof(cmd->size); ++ if (cmd->size > size - parsed) ++ return -EINVAL; ++ ++ ipts_dbg(ipts, "cmd buf size = %d\n", cmd->size); ++ ++ num_of_parallels = ipts_get_num_of_parallel_buffers(ipts); ++ /* command buffers are located after the other allocations */ ++ cmdbuf_idx = num_of_parallels * alloc_info->num_of_allocations; ++ for (parallel_idx = 0; parallel_idx < num_of_parallels; parallel_idx++) { ++ buf = ipts_map_buffer(ipts, cmd->size, 0); ++ if (buf == NULL) ++ return -ENOMEM; ++ ++ ipts_dbg(ipts, "cmd_idx[%d] = %d, g:0x%p, c:0x%p\n", parallel_idx, ++ cmdbuf_idx, buf->gfx_addr, buf->cpu_addr); ++ ++ memcpy((void *)buf->cpu_addr, &(cmd->data[0]), cmd->size); ++ patch_SBA(buf->cpu_addr, (u64)buf->gfx_addr, cmd->size); ++ alloc_info->buffs[cmdbuf_idx].buf = buf; ++ wl[parallel_idx].cmdbuf_index = cmdbuf_idx; ++ ++ cmdbuf_idx++; ++ } ++ ++ parsed += cmd->size; ++ parse_info->parsed = parsed; ++ ++ return 0; ++} ++ ++static int bin_find_alloc(ipts_info_t *ipts, ++ bin_alloc_info_t *alloc_info, ++ u32 handle) ++{ ++ int i; ++ ++ for (i = 0; i < alloc_info->num_of_allocations; i++) { ++ if (alloc_info->buffs[i].handle == handle) ++ return i; ++ } ++ ++ return -1; ++} ++ ++static intel_ipts_mapbuffer_t* bin_get_vendor_kernel_output( ++ bin_parse_info_t *parse_info, ++ int parallel_idx) ++{ ++ bin_kernel_info_t *vendor = parse_info->vendor_kernel; ++ bin_alloc_info_t *alloc_info; ++ int buf_idx, vendor_output_idx; ++ ++ alloc_info = vendor->alloc_info; ++ vendor_output_idx = parse_info->interested_vendor_output; ++ ++ if (vendor_output_idx >= alloc_info->num_of_outputs) ++ return NULL; ++ ++ buf_idx = vendor->wl[parallel_idx].iobuf_output[vendor_output_idx]; ++ return alloc_info->buffs[buf_idx].buf; ++} ++ ++static int bin_read_res_list(ipts_info_t *ipts, ++ bin_parse_info_t *parse_info, ++ bin_alloc_info_t *alloc_info, ++ bin_workload_t *wl) ++{ ++ ipts_bin_res_list_t *res_list; ++ ipts_bin_res_t *res; ++ intel_ipts_mapbuffer_t *buf; ++ bin_data_file_info_t *data_file; ++ u8 *bin_data; ++ int i, size, parsed, parallel_idx, num_of_parallels, output_idx = -1; ++ int buf_idx, num_of_alloc; ++ u32 buf_size, flags, io_buf_type; ++ bool initialize; ++ ++ parsed = parse_info->parsed; ++ size = parse_info->size; ++ bin_data = parse_info->data; ++ ++ res_list = (ipts_bin_res_list_t *)&parse_info->data[parsed]; ++ if (sizeof(res_list->num) > (size - parsed)) ++ return -EINVAL; ++ parsed += sizeof(res_list->num); ++ num_of_parallels = ipts_get_num_of_parallel_buffers(ipts); ++ ++ ipts_dbg(ipts, "number of resources %u\n", res_list->num); ++ for (i = 0; i < res_list->num; i++) { ++ initialize = false; ++ io_buf_type = 0; ++ flags = 0; ++ ++ /* initial data */ ++ data_file = NULL; ++ ++ res = (ipts_bin_res_t *)(&(bin_data[parsed])); ++ if (sizeof(res[0]) > (size - parsed)) { ++ return -EINVAL; ++ } ++ ++ ipts_dbg(ipts, "Resource(%d):handle 0x%08x type %u init %u" ++ " size %u alsigned %u\n", ++ i, res->handle, res->type, res->initialize, ++ res->size, res->aligned_size); ++ parsed += sizeof(res[0]); ++ ++ if (res->initialize) { ++ if (res->size > (size - parsed)) { ++ return -EINVAL; ++ } ++ parsed += res->size; ++ } ++ ++ initialize = res->initialize; ++ if (initialize && res->size > sizeof(ipts_bin_io_header_t)) { ++ ipts_bin_io_header_t *io_hdr; ++ io_hdr = (ipts_bin_io_header_t *)(&res->data[0]); ++ if (strncmp(io_hdr->str, "INTELTOUCH", 10) == 0) { ++ data_file = bin_get_data_file_info( ++ parse_info->fw_info, ++ (u32)io_hdr->type); ++ switch (io_hdr->type) { ++ case IPTS_INPUT: ++ ipts_dbg(ipts, "input detected\n"); ++ io_buf_type = IPTS_INPUT_ON; ++ flags = IPTS_BUF_FLAG_CONTIGUOUS; ++ break; ++ case IPTS_OUTPUT: ++ ipts_dbg(ipts, "output detected\n"); ++ io_buf_type = IPTS_OUTPUT_ON; ++ output_idx++; ++ break; ++ default: ++ if ((u32)io_hdr->type > 31) { ++ ipts_err(ipts, ++ "invalid io buffer : %u\n", ++ (u32)io_hdr->type); ++ continue; ++ } ++ ++ if (is_alloc_cont_data(data_file)) ++ flags = IPTS_BUF_FLAG_CONTIGUOUS; ++ ++ io_buf_type = ((u32)1 << (u32)io_hdr->type); ++ ipts_dbg(ipts, "special io buffer %u\n", ++ io_hdr->type); ++ break; ++ } ++ ++ initialize = false; ++ } ++ } ++ ++ num_of_alloc = alloc_info->num_of_allocations; ++ buf_idx = bin_find_alloc(ipts, alloc_info, res->handle); ++ if (buf_idx == -1) { ++ ipts_dbg(ipts, "cannot find alloc info\n"); ++ return -EINVAL; ++ } ++ for (parallel_idx = 0; parallel_idx < num_of_parallels; ++ parallel_idx++, buf_idx += num_of_alloc) { ++ if (!res->aligned_size) ++ continue; ++ ++ if (!(parallel_idx == 0 || ++ (io_buf_type && !is_shared_data(data_file)))) ++ continue; ++ ++ buf_size = res->aligned_size; ++ if (io_buf_type & IPTS_INPUT_ON) { ++ buf_size = max_t(u32, ++ ipts->device_info.frame_size, ++ buf_size); ++ wl[parallel_idx].iobuf_input = buf_idx; ++ } else if (io_buf_type & IPTS_OUTPUT_ON) { ++ wl[parallel_idx].iobuf_output[output_idx] = buf_idx; ++ ++ if (!is_parsing_vendor_kernel(parse_info) && ++ output_idx > 0) { ++ ipts_err(ipts, ++ "postproc with more than one inout" ++ " is not supported : %d\n", output_idx); ++ return -EINVAL; ++ } ++ } ++ ++ if (!is_parsing_vendor_kernel(parse_info) && ++ io_buf_type & IPTS_OUTPUT_ON) { ++ buf = bin_get_vendor_kernel_output( ++ parse_info, ++ parallel_idx); ++ alloc_info->buffs[buf_idx].no_unmap = true; ++ } else ++ buf = ipts_map_buffer(ipts, buf_size, flags); ++ ++ if (buf == NULL) { ++ ipts_dbg(ipts, "ipts_map_buffer failed\n"); ++ return -ENOMEM; ++ } ++ ++ if (initialize) { ++ memcpy((void *)buf->cpu_addr, &(res->data[0]), ++ res->size); ++ } else { ++ if (data_file && strlen(data_file->file_name)) { ++ bin_read_fw(ipts, data_file->file_name, ++ buf->cpu_addr, buf_size); ++ } else if (is_parsing_vendor_kernel(parse_info) || ++ !(io_buf_type & IPTS_OUTPUT_ON)) { ++ memset((void *)buf->cpu_addr, 0, res->size); ++ } ++ } ++ ++ alloc_info->buffs[buf_idx].buf = buf; ++ } ++ } ++ ++ alloc_info->num_of_outputs = output_idx + 1; ++ parse_info->parsed = parsed; ++ ++ return 0; ++} ++ ++static int bin_read_patch_list(ipts_info_t *ipts, ++ bin_parse_info_t *parse_info, ++ bin_alloc_info_t *alloc_info, ++ bin_workload_t *wl) ++{ ++ ipts_bin_patch_list_t *patch_list; ++ ipts_bin_patch_t *patch; ++ intel_ipts_mapbuffer_t *cmd = NULL; ++ u8 *batch; ++ int parsed, size, i, parallel_idx, num_of_parallels, cmd_idx, buf_idx; ++ unsigned int gtt_offset; ++ ++ parsed = parse_info->parsed; ++ size = parse_info->size; ++ patch_list = (ipts_bin_patch_list_t *)&parse_info->data[parsed]; ++ ++ if (sizeof(patch_list->num) > (size - parsed)) { ++ return -EFAULT; ++ } ++ parsed += sizeof(patch_list->num); ++ ++ num_of_parallels = ipts_get_num_of_parallel_buffers(ipts); ++ patch = (ipts_bin_patch_t *)(&patch_list->patch[0]); ++ for (i = 0; i < patch_list->num; i++) { ++ if (sizeof(patch_list->patch[0]) > (size - parsed)) { ++ return -EFAULT; ++ } ++ ++ for (parallel_idx = 0; parallel_idx < num_of_parallels; ++ parallel_idx++) { ++ cmd_idx = wl[parallel_idx].cmdbuf_index; ++ buf_idx = patch[i].index + parallel_idx * ++ alloc_info->num_of_allocations; ++ ++ if (alloc_info->buffs[buf_idx].buf == NULL) { ++ /* buffer shared */ ++ buf_idx = patch[i].index; ++ } ++ ++ cmd = alloc_info->buffs[cmd_idx].buf; ++ batch = (char *)(u64)cmd->cpu_addr; ++ ++ gtt_offset = 0; ++ if(alloc_info->buffs[buf_idx].buf != NULL) { ++ gtt_offset = (u32)(u64) ++ alloc_info->buffs[buf_idx].buf->gfx_addr; ++ } ++ gtt_offset += patch[i].alloc_offset; ++ ++ batch += patch[i].patch_offset; ++ *(u32*)batch = gtt_offset; ++ } ++ ++ parsed += sizeof(patch_list->patch[0]); ++ } ++ ++ parse_info->parsed = parsed; ++ ++ return 0; ++} ++ ++static int bin_read_guc_wq_item(ipts_info_t *ipts, ++ bin_parse_info_t *parse_info, ++ bin_guc_wq_item_t **guc_wq_item) ++{ ++ ipts_bin_guc_wq_info_t *bin_guc_wq; ++ bin_guc_wq_item_t *item; ++ u8 *wi_data; ++ int size, parsed, hdr_size, wi_size; ++ int i, batch_offset; ++ ++ parsed = parse_info->parsed; ++ size = parse_info->size; ++ bin_guc_wq = (ipts_bin_guc_wq_info_t *)&parse_info->data[parsed]; ++ ++ wi_size = bin_guc_wq->size; ++ wi_data = bin_guc_wq->data; ++ batch_offset = bin_guc_wq->batch_offset; ++ ipts_dbg(ipts, "wi size = %d, bt offset = %d\n", wi_size, batch_offset); ++ for (i = 0; i < wi_size / sizeof(u32); i++) { ++ ipts_dbg(ipts, "wi[%d] = 0x%08x\n", i, *((u32*)wi_data + i)); ++ } ++ hdr_size = sizeof(bin_guc_wq->size) + sizeof(bin_guc_wq->batch_offset); ++ ++ if (hdr_size > (size - parsed)) { ++ return -EINVAL; ++ } ++ parsed += hdr_size; ++ ++ item = vmalloc(sizeof(bin_guc_wq_item_t) + wi_size); ++ if (item == NULL) ++ return -ENOMEM; ++ ++ item->size = wi_size; ++ item->batch_offset = batch_offset; ++ memcpy(item->data, wi_data, wi_size); ++ ++ *guc_wq_item = item; ++ ++ parsed += wi_size; ++ parse_info->parsed = parsed; ++ ++ return 0; ++} ++ ++static int bin_setup_guc_workqueue(ipts_info_t *ipts, ++ bin_kernel_list_t *kernel_list) ++{ ++ bin_alloc_info_t *alloc_info; ++ bin_workload_t *wl; ++ bin_kernel_info_t *kernel; ++ u8 *wq_start, *wq_addr, *wi_data; ++ bin_buffer_t *bin_buf; ++ int wq_size, wi_size, parallel_idx, cmd_idx, k_idx, iter_size; ++ int i, num_of_parallels, batch_offset, k_num, total_workload; ++ ++ wq_addr = (u8*)ipts->resource.wq_info.wq_addr; ++ wq_size = ipts->resource.wq_info.wq_size; ++ num_of_parallels = ipts_get_num_of_parallel_buffers(ipts); ++ total_workload = ipts_get_wq_item_size(ipts); ++ k_num = kernel_list->num_of_kernels; ++ ++ iter_size = total_workload * num_of_parallels; ++ if (wq_size % iter_size) { ++ ipts_err(ipts, "wq item cannot fit into wq\n"); ++ return -EINVAL; ++ } ++ ++ wq_start = wq_addr; ++ for (parallel_idx = 0; parallel_idx < num_of_parallels; ++ parallel_idx++) { ++ kernel = &kernel_list->kernels[0]; ++ for (k_idx = 0; k_idx < k_num; k_idx++, kernel++) { ++ wl = kernel->wl; ++ alloc_info = kernel->alloc_info; ++ ++ batch_offset = kernel->guc_wq_item->batch_offset; ++ wi_size = kernel->guc_wq_item->size; ++ wi_data = &kernel->guc_wq_item->data[0]; ++ ++ cmd_idx = wl[parallel_idx].cmdbuf_index; ++ bin_buf = &alloc_info->buffs[cmd_idx]; ++ ++ /* Patch the WQ Data with proper batch buffer offset */ ++ *(u32*)(wi_data + batch_offset) = ++ (u32)(unsigned long)(bin_buf->buf->gfx_addr); ++ ++ memcpy(wq_addr, wi_data, wi_size); ++ ++ wq_addr += wi_size; ++ } ++ } ++ ++ for (i = 0; i < (wq_size / iter_size) - 1; i++) { ++ memcpy(wq_addr, wq_start, iter_size); ++ wq_addr += iter_size; ++ } ++ ++ return 0; ++} ++ ++static int bin_read_bufid_patch(ipts_info_t *ipts, ++ bin_parse_info_t *parse_info, ++ ipts_bin_bufid_patch_t *bufid_patch) ++{ ++ ipts_bin_bufid_patch_t *patch; ++ int size, parsed; ++ ++ parsed = parse_info->parsed; ++ size = parse_info->size; ++ patch = (ipts_bin_bufid_patch_t *)&parse_info->data[parsed]; ++ ++ if (sizeof(ipts_bin_bufid_patch_t) > (size - parsed)) { ++ ipts_dbg(ipts, "invalid bufid info\n"); ++ return -EINVAL; ++ } ++ parsed += sizeof(ipts_bin_bufid_patch_t); ++ ++ memcpy(bufid_patch, patch, sizeof(ipts_bin_bufid_patch_t)); ++ ++ parse_info->parsed = parsed; ++ ++ return 0; ++} ++ ++static int bin_setup_bufid_buffer(ipts_info_t *ipts, bin_kernel_list_t *kernel_list) ++{ ++ intel_ipts_mapbuffer_t *buf, *cmd_buf; ++ bin_kernel_info_t *last_kernel; ++ bin_alloc_info_t *alloc_info; ++ bin_workload_t *wl; ++ u8 *batch; ++ int parallel_idx, num_of_parallels, cmd_idx; ++ u32 mem_offset, imm_offset; ++ ++ buf = ipts_map_buffer(ipts, PAGE_SIZE, 0); ++ if (!buf) { ++ return -ENOMEM; ++ } ++ ++ last_kernel = &kernel_list->kernels[kernel_list->num_of_kernels - 1]; ++ ++ mem_offset = last_kernel->bufid_patch.mem_offset; ++ imm_offset = last_kernel->bufid_patch.imm_offset; ++ wl = last_kernel->wl; ++ alloc_info = last_kernel->alloc_info; ++ ++ /* Initialize the buffer with default value */ ++ *((u32*)buf->cpu_addr) = LASTSUBMITID_DEFAULT_VALUE; ++ ipts->current_buffer_index = LASTSUBMITID_DEFAULT_VALUE; ++ ipts->last_buffer_completed = LASTSUBMITID_DEFAULT_VALUE; ++ ipts->last_submitted_id = (int*)buf->cpu_addr; ++ ++ num_of_parallels = ipts_get_num_of_parallel_buffers(ipts); ++ for (parallel_idx = 0; parallel_idx < num_of_parallels; parallel_idx++) { ++ cmd_idx = wl[parallel_idx].cmdbuf_index; ++ cmd_buf = alloc_info->buffs[cmd_idx].buf; ++ batch = (u8*)(u64)cmd_buf->cpu_addr; ++ ++ *((u32*)(batch + mem_offset)) = (u32)(u64)(buf->gfx_addr); ++ *((u32*)(batch + imm_offset)) = parallel_idx; ++ } ++ ++ kernel_list->bufid_buf = buf; ++ ++ return 0; ++} ++ ++static void unmap_buffers(ipts_info_t *ipts, bin_alloc_info_t *alloc_info) ++{ ++ bin_buffer_t *buffs; ++ int i, num_of_buffers; ++ ++ num_of_buffers = alloc_info->num_of_buffers; ++ buffs = &alloc_info->buffs[0]; ++ ++ for (i = 0; i < num_of_buffers; i++) { ++ if (buffs[i].no_unmap != true && buffs[i].buf != NULL) ++ ipts_unmap_buffer(ipts, buffs[i].buf); ++ } ++} ++ ++static int load_kernel(ipts_info_t *ipts, bin_parse_info_t *parse_info, ++ bin_kernel_info_t *kernel) ++{ ++ ipts_bin_header_t *hdr; ++ bin_workload_t *wl; ++ bin_alloc_info_t *alloc_info; ++ bin_guc_wq_item_t *guc_wq_item = NULL; ++ ipts_bin_bufid_patch_t bufid_patch; ++ int num_of_parallels, ret; ++ ++ num_of_parallels = ipts_get_num_of_parallel_buffers(ipts); ++ ++ /* check header version and magic numbers */ ++ hdr = (ipts_bin_header_t *)parse_info->data; ++ if (hdr->version != IPTS_BIN_HEADER_VERSION || ++ strncmp(hdr->str, "IOCL", 4) != 0) { ++ ipts_err(ipts, "binary header is not correct version = %d, " ++ "string = %c%c%c%c\n", hdr->version, ++ hdr->str[0], hdr->str[1], ++ hdr->str[2], hdr->str[3] ); ++ return -EINVAL; ++ } ++ ++ parse_info->parsed = sizeof(ipts_bin_header_t); ++ wl = vmalloc(sizeof(bin_workload_t) * num_of_parallels); ++ if (wl == NULL) ++ return -ENOMEM; ++ memset(wl, 0, sizeof(bin_workload_t) * num_of_parallels); ++ ++ alloc_info = vmalloc(sizeof(bin_alloc_info_t)); ++ if (alloc_info == NULL) { ++ vfree(wl); ++ return -ENOMEM; ++ } ++ memset(alloc_info, 0, sizeof(bin_alloc_info_t)); ++ ++ ipts_dbg(ipts, "kernel setup(size : %d)\n", parse_info->size); ++ ++ ret = bin_read_allocation_list(ipts, parse_info, alloc_info); ++ if (ret) { ++ ipts_dbg(ipts, "error read_allocation_list\n"); ++ goto setup_error; ++ } ++ ++ ret = bin_read_cmd_buffer(ipts, parse_info, alloc_info, wl); ++ if (ret) { ++ ipts_dbg(ipts, "error read_cmd_buffer\n"); ++ goto setup_error; ++ } ++ ++ ret = bin_read_res_list(ipts, parse_info, alloc_info, wl); ++ if (ret) { ++ ipts_dbg(ipts, "error read_res_list\n"); ++ goto setup_error; ++ } ++ ++ ret = bin_read_patch_list(ipts, parse_info, alloc_info, wl); ++ if (ret) { ++ ipts_dbg(ipts, "error read_patch_list\n"); ++ goto setup_error; ++ } ++ ++ ret = bin_read_guc_wq_item(ipts, parse_info, &guc_wq_item); ++ if (ret) { ++ ipts_dbg(ipts, "error read_guc_workqueue\n"); ++ goto setup_error; ++ } ++ ++ memset(&bufid_patch, 0, sizeof(bufid_patch)); ++ ret = bin_read_bufid_patch(ipts, parse_info, &bufid_patch); ++ if (ret) { ++ ipts_dbg(ipts, "error read_bufid_patch\n"); ++ goto setup_error; ++ } ++ ++ kernel->wl = wl; ++ kernel->alloc_info = alloc_info; ++ kernel->is_vendor = is_parsing_vendor_kernel(parse_info); ++ kernel->guc_wq_item = guc_wq_item; ++ memcpy(&kernel->bufid_patch, &bufid_patch, sizeof(bufid_patch)); ++ ++ return 0; ++ ++setup_error: ++ vfree(guc_wq_item); ++ ++ unmap_buffers(ipts, alloc_info); ++ ++ vfree(alloc_info->buffs); ++ vfree(alloc_info); ++ vfree(wl); ++ ++ return ret; ++} ++ ++void bin_setup_input_output(ipts_info_t *ipts, bin_kernel_list_t *kernel_list) ++{ ++ bin_kernel_info_t *vendor_kernel; ++ bin_workload_t *wl; ++ intel_ipts_mapbuffer_t *buf; ++ bin_alloc_info_t *alloc_info; ++ int parallel_idx, num_of_parallels, i, buf_idx; ++ ++ vendor_kernel = &kernel_list->kernels[0]; ++ ++ wl = vendor_kernel->wl; ++ alloc_info = vendor_kernel->alloc_info; ++ ipts->resource.num_of_outputs = alloc_info->num_of_outputs; ++ num_of_parallels = ipts_get_num_of_parallel_buffers(ipts); ++ ++ for (parallel_idx = 0; parallel_idx < num_of_parallels; parallel_idx++) { ++ buf_idx = wl[parallel_idx].iobuf_input; ++ buf = alloc_info->buffs[buf_idx].buf; ++ ++ ipts_dbg(ipts, "in_buf[%d](%d) c:%p, p:%p, g:%p\n", ++ parallel_idx, buf_idx, (void*)buf->cpu_addr, ++ (void*)buf->phy_addr, (void*)buf->gfx_addr); ++ ++ ipts_set_input_buffer(ipts, parallel_idx, buf->cpu_addr, ++ buf->phy_addr); ++ ++ for (i = 0; i < alloc_info->num_of_outputs; i++) { ++ buf_idx = wl[parallel_idx].iobuf_output[i]; ++ buf = alloc_info->buffs[buf_idx].buf; ++ ++ ipts_dbg(ipts, "out_buf[%d][%d] c:%p, p:%p, g:%p\n", ++ parallel_idx, i, (void*)buf->cpu_addr, ++ (void*)buf->phy_addr, (void*)buf->gfx_addr); ++ ++ ipts_set_output_buffer(ipts, parallel_idx, i, ++ buf->cpu_addr, buf->phy_addr); ++ } ++ } ++} ++ ++static void unload_kernel(ipts_info_t *ipts, bin_kernel_info_t *kernel) ++{ ++ bin_alloc_info_t *alloc_info = kernel->alloc_info; ++ bin_guc_wq_item_t *guc_wq_item = kernel->guc_wq_item; ++ ++ if (guc_wq_item) { ++ vfree(guc_wq_item); ++ } ++ ++ if (alloc_info) { ++ unmap_buffers(ipts, alloc_info); ++ ++ vfree(alloc_info->buffs); ++ vfree(alloc_info); ++ } ++} ++ ++static int setup_kernel(ipts_info_t *ipts, bin_fw_list_t *fw_list) ++{ ++ bin_kernel_list_t *kernel_list = NULL; ++ bin_kernel_info_t *kernel = NULL; ++ const struct firmware *fw = NULL; ++ bin_workload_t *wl; ++ bin_fw_info_t *fw_info; ++ char *fw_name, *fw_data; ++ bin_parse_info_t parse_info; ++ int ret = 0, kernel_idx = 0, num_of_kernels = 0; ++ int vendor_output_idx, total_workload = 0; ++ char fw_path[MAX_IOCL_FILE_PATH_LEN]; ++ ++ num_of_kernels = fw_list->num_of_fws; ++ kernel_list = vmalloc(sizeof(*kernel) * num_of_kernels + sizeof(*kernel_list)); ++ if (kernel_list == NULL) ++ return -ENOMEM; ++ ++ memset(kernel_list, 0, sizeof(*kernel) * num_of_kernels + sizeof(*kernel_list)); ++ kernel_list->num_of_kernels = num_of_kernels; ++ kernel = &kernel_list->kernels[0]; ++ ++ fw_data = (char *)&fw_list->fw_info[0]; ++ for (kernel_idx = 0; kernel_idx < num_of_kernels; kernel_idx++) { ++ fw_info = (bin_fw_info_t *)fw_data; ++ fw_name = &fw_info->fw_name[0]; ++ vendor_output_idx = fw_info->vendor_output; ++ snprintf(fw_path, MAX_IOCL_FILE_PATH_LEN, IPTS_FW_PATH_FMT, fw_name); ++ ret = request_firmware(&fw, (const char *)fw_path, &ipts->cldev->dev); ++ if (ret) { ++ ipts_err(ipts, "cannot read fw %s\n", fw_path); ++ goto error_exit; ++ } ++ ++ parse_info.data = (u8*)fw->data; ++ parse_info.size = fw->size; ++ parse_info.parsed = 0; ++ parse_info.fw_info = fw_info; ++ parse_info.vendor_kernel = (kernel_idx == 0) ? NULL : &kernel[0]; ++ parse_info.interested_vendor_output = vendor_output_idx; ++ ++ ret = load_kernel(ipts, &parse_info, &kernel[kernel_idx]); ++ if (ret) { ++ ipts_err(ipts, "do_setup_kernel error : %d\n", ret); ++ release_firmware(fw); ++ goto error_exit; ++ } ++ ++ release_firmware(fw); ++ ++ total_workload += kernel[kernel_idx].guc_wq_item->size; ++ ++ /* advance to the next kernel */ ++ fw_data += sizeof(bin_fw_info_t); ++ fw_data += sizeof(bin_data_file_info_t) * fw_info->num_of_data_files; ++ } ++ ++ ipts_set_wq_item_size(ipts, total_workload); ++ ++ ret = bin_setup_guc_workqueue(ipts, kernel_list); ++ if (ret) { ++ ipts_dbg(ipts, "error setup_guc_workqueue\n"); ++ goto error_exit; ++ } ++ ++ ret = bin_setup_bufid_buffer(ipts, kernel_list); ++ if (ret) { ++ ipts_dbg(ipts, "error setup_lastbubmit_buffer\n"); ++ goto error_exit; ++ } ++ ++ bin_setup_input_output(ipts, kernel_list); ++ ++ /* workload is not needed during run-time so free them */ ++ for (kernel_idx = 0; kernel_idx < num_of_kernels; kernel_idx++) { ++ wl = kernel[kernel_idx].wl; ++ vfree(wl); ++ } ++ ++ ipts->kernel_handle = (u64)kernel_list; ++ ++ return 0; ++ ++error_exit: ++ ++ for (kernel_idx = 0; kernel_idx < num_of_kernels; kernel_idx++) { ++ wl = kernel[kernel_idx].wl; ++ vfree(wl); ++ unload_kernel(ipts, &kernel[kernel_idx]); ++ } ++ ++ vfree(kernel_list); ++ ++ return ret; ++} ++ ++ ++static void release_kernel(ipts_info_t *ipts) ++{ ++ bin_kernel_list_t *kernel_list; ++ bin_kernel_info_t *kernel; ++ int k_idx, k_num; ++ ++ kernel_list = (bin_kernel_list_t *)ipts->kernel_handle; ++ k_num = kernel_list->num_of_kernels; ++ kernel = &kernel_list->kernels[0]; ++ ++ for (k_idx = 0; k_idx < k_num; k_idx++) { ++ unload_kernel(ipts, kernel); ++ kernel++; ++ } ++ ++ ipts_unmap_buffer(ipts, kernel_list->bufid_buf); ++ ++ vfree(kernel_list); ++ ipts->kernel_handle = 0; ++} ++ ++int ipts_init_kernels(ipts_info_t *ipts) ++{ ++ const struct firmware *config_fw = NULL; ++ const char *config_fw_path = IPTS_FW_CONFIG_FILE; ++ bin_fw_list_t *fw_list; ++ int ret; ++ ++ ret = ipts_open_gpu(ipts); ++ if (ret) { ++ ipts_err(ipts, "open gpu error : %d\n", ret); ++ return ret; ++ } ++ ++ ret = request_firmware(&config_fw, config_fw_path, &ipts->cldev->dev); ++ if (ret) { ++ ipts_err(ipts, "request firmware error : %d\n", ret); ++ goto close_gpu; ++ } ++ ++ fw_list = (bin_fw_list_t *)config_fw->data; ++ ret = setup_kernel(ipts, fw_list); ++ if (ret) { ++ ipts_err(ipts, "setup kernel error : %d\n", ret); ++ goto close_firmware; ++ } ++ ++ release_firmware(config_fw); ++ ++ return ret; ++ ++close_firmware: ++ release_firmware(config_fw); ++ ++close_gpu: ++ ipts_close_gpu(ipts); ++ ++ return ret; ++} ++ ++void ipts_release_kernels(ipts_info_t *ipts) ++{ ++ release_kernel(ipts); ++ ipts_close_gpu(ipts); ++} +diff --git a/drivers/misc/ipts/ipts-kernel.h b/drivers/misc/ipts/ipts-kernel.h +new file mode 100644 +index 0000000..0e7f139 +--- /dev/null ++++ b/drivers/misc/ipts/ipts-kernel.h +@@ -0,0 +1,23 @@ ++/* ++ * ++ * Intel Precise Touch & Stylus Linux driver ++ * Copyright (c) 2016, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ */ ++ ++#ifndef _ITPS_GFX_H ++#define _ITPS_GFX_H ++ ++int ipts_init_kernels(ipts_info_t *ipts); ++void ipts_release_kernels(ipts_info_t *ipts); ++ ++#endif +diff --git a/drivers/misc/ipts/ipts-mei-msgs.h b/drivers/misc/ipts/ipts-mei-msgs.h +new file mode 100644 +index 0000000..8ca1468 +--- /dev/null ++++ b/drivers/misc/ipts/ipts-mei-msgs.h +@@ -0,0 +1,585 @@ ++/* ++ * Precise Touch HECI Message ++ * ++ * Copyright (c) 2013-2016, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ */ ++ ++#ifndef _IPTS_MEI_MSGS_H_ ++#define _IPTS_MEI_MSGS_H_ ++ ++#include "ipts-sensor-regs.h" ++ ++#pragma pack(1) ++ ++ ++// Initial protocol version ++#define TOUCH_HECI_CLIENT_PROTOCOL_VERSION 10 ++ ++// GUID that identifies the Touch HECI client. ++#define TOUCH_HECI_CLIENT_GUID \ ++ {0x3e8d0870, 0x271a, 0x4208, {0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04}} ++ ++ ++// define C_ASSERT macro to check structure size and fail compile for unexpected mismatch ++#ifndef C_ASSERT ++#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] ++#endif ++ ++ ++// General Type Defines for compatibility with HID driver and BIOS ++#ifndef BIT0 ++#define BIT0 1 ++#endif ++#ifndef BIT1 ++#define BIT1 2 ++#endif ++#ifndef BIT2 ++#define BIT2 4 ++#endif ++ ++ ++#define TOUCH_SENSOR_GET_DEVICE_INFO_CMD 0x00000001 ++#define TOUCH_SENSOR_GET_DEVICE_INFO_RSP 0x80000001 ++ ++ ++#define TOUCH_SENSOR_SET_MODE_CMD 0x00000002 ++#define TOUCH_SENSOR_SET_MODE_RSP 0x80000002 ++ ++ ++#define TOUCH_SENSOR_SET_MEM_WINDOW_CMD 0x00000003 ++#define TOUCH_SENSOR_SET_MEM_WINDOW_RSP 0x80000003 ++ ++ ++#define TOUCH_SENSOR_QUIESCE_IO_CMD 0x00000004 ++#define TOUCH_SENSOR_QUIESCE_IO_RSP 0x80000004 ++ ++ ++#define TOUCH_SENSOR_HID_READY_FOR_DATA_CMD 0x00000005 ++#define TOUCH_SENSOR_HID_READY_FOR_DATA_RSP 0x80000005 ++ ++ ++#define TOUCH_SENSOR_FEEDBACK_READY_CMD 0x00000006 ++#define TOUCH_SENSOR_FEEDBACK_READY_RSP 0x80000006 ++ ++ ++#define TOUCH_SENSOR_CLEAR_MEM_WINDOW_CMD 0x00000007 ++#define TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP 0x80000007 ++ ++ ++#define TOUCH_SENSOR_NOTIFY_DEV_READY_CMD 0x00000008 ++#define TOUCH_SENSOR_NOTIFY_DEV_READY_RSP 0x80000008 ++ ++ ++#define TOUCH_SENSOR_SET_POLICIES_CMD 0x00000009 ++#define TOUCH_SENSOR_SET_POLICIES_RSP 0x80000009 ++ ++ ++#define TOUCH_SENSOR_GET_POLICIES_CMD 0x0000000A ++#define TOUCH_SENSOR_GET_POLICIES_RSP 0x8000000A ++ ++ ++#define TOUCH_SENSOR_RESET_CMD 0x0000000B ++#define TOUCH_SENSOR_RESET_RSP 0x8000000B ++ ++ ++#define TOUCH_SENSOR_READ_ALL_REGS_CMD 0x0000000C ++#define TOUCH_SENSOR_READ_ALL_REGS_RSP 0x8000000C ++ ++ ++#define TOUCH_SENSOR_CMD_ERROR_RSP 0x8FFFFFFF // M2H: ME sends this message to indicate previous command was unrecognized/unsupported ++ ++ ++ ++//******************************************************************* ++// ++// Touch Sensor Status Codes ++// ++//******************************************************************* ++typedef enum touch_status ++{ ++ TOUCH_STATUS_SUCCESS = 0, // 0 Requested operation was successful ++ TOUCH_STATUS_INVALID_PARAMS, // 1 Invalid parameter(s) sent ++ TOUCH_STATUS_ACCESS_DENIED, // 2 Unable to validate address range ++ TOUCH_STATUS_CMD_SIZE_ERROR, // 3 HECI message incorrect size for specified command ++ TOUCH_STATUS_NOT_READY, // 4 Memory window not set or device is not armed for operation ++ TOUCH_STATUS_REQUEST_OUTSTANDING, // 5 There is already an outstanding message of the same type, must wait for response before sending another request of that type ++ TOUCH_STATUS_NO_SENSOR_FOUND, // 6 Sensor could not be found. Either no sensor is connected, the sensor has not yet initialized, or the system is improperly configured. ++ TOUCH_STATUS_OUT_OF_MEMORY, // 7 Not enough memory/storage for requested operation ++ TOUCH_STATUS_INTERNAL_ERROR, // 8 Unexpected error occurred ++ TOUCH_STATUS_SENSOR_DISABLED, // 9 Used in TOUCH_SENSOR_HID_READY_FOR_DATA_RSP to indicate sensor has been disabled or reset and must be reinitialized. ++ TOUCH_STATUS_COMPAT_CHECK_FAIL, // 10 Used to indicate compatibility revision check between sensor and ME failed, or protocol ver between ME/HID/Kernels failed. ++ TOUCH_STATUS_SENSOR_EXPECTED_RESET, // 11 Indicates sensor went through a reset initiated by ME ++ TOUCH_STATUS_SENSOR_UNEXPECTED_RESET, // 12 Indicates sensor went through an unexpected reset ++ TOUCH_STATUS_RESET_FAILED, // 13 Requested sensor reset failed to complete ++ TOUCH_STATUS_TIMEOUT, // 14 Operation timed out ++ TOUCH_STATUS_TEST_MODE_FAIL, // 15 Test mode pattern did not match expected values ++ TOUCH_STATUS_SENSOR_FAIL_FATAL, // 16 Indicates sensor reported fatal error during reset sequence. Further progress is not possible. ++ TOUCH_STATUS_SENSOR_FAIL_NONFATAL, // 17 Indicates sensor reported non-fatal error during reset sequence. HID/BIOS logs error and attempts to continue. ++ TOUCH_STATUS_INVALID_DEVICE_CAPS, // 18 Indicates sensor reported invalid capabilities, such as not supporting required minimum frequency or I/O mode. ++ TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS, // 19 Indicates that command cannot be complete until ongoing Quiesce I/O flow has completed. ++ TOUCH_STATUS_MAX // 20 Invalid value, never returned ++} touch_status_t; ++C_ASSERT(sizeof(touch_status_t) == 4); ++ ++ ++ ++//******************************************************************* ++// ++// Defines for message structures used for Host to ME communication ++// ++//******************************************************************* ++ ++ ++typedef enum touch_sensor_mode ++{ ++ TOUCH_SENSOR_MODE_HID = 0, // Set mode to HID mode ++ TOUCH_SENSOR_MODE_RAW_DATA, // Set mode to Raw Data mode ++ TOUCH_SENSOR_MODE_SENSOR_DEBUG = 4, // Used like TOUCH_SENSOR_MODE_HID but data coming from sensor is not necessarily a HID packet. ++ TOUCH_SENSOR_MODE_MAX // Invalid value ++} touch_sensor_mode_t; ++C_ASSERT(sizeof(touch_sensor_mode_t) == 4); ++ ++typedef struct touch_sensor_set_mode_cmd_data ++{ ++ touch_sensor_mode_t sensor_mode; // Indicate desired sensor mode ++ u32 Reserved[3]; // For future expansion ++} touch_sensor_set_mode_cmd_data_t; ++C_ASSERT(sizeof(touch_sensor_set_mode_cmd_data_t) == 16); ++ ++ ++#define TOUCH_SENSOR_MAX_DATA_BUFFERS 16 ++#define TOUCH_HID_2_ME_BUFFER_ID TOUCH_SENSOR_MAX_DATA_BUFFERS ++#define TOUCH_HID_2_ME_BUFFER_SIZE_MAX 1024 ++#define TOUCH_INVALID_BUFFER_ID 0xFF ++ ++typedef struct touch_sensor_set_mem_window_cmd_data ++{ ++ u32 touch_data_buffer_addr_lower[TOUCH_SENSOR_MAX_DATA_BUFFERS]; // Lower 32 bits of Touch Data Buffer physical address. Size of each buffer should be TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.FrameSize ++ u32 touch_data_buffer_addr_upper[TOUCH_SENSOR_MAX_DATA_BUFFERS]; // Upper 32 bits of Touch Data Buffer physical address. Size of each buffer should be TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.FrameSize ++ u32 tail_offset_addr_lower; // Lower 32 bits of Tail Offset physical address ++ u32 tail_offset_addr_upper; // Upper 32 bits of Tail Offset physical address, always 32 bit, increment by WorkQueueItemSize ++ u32 doorbell_cookie_addr_lower; // Lower 32 bits of Doorbell register physical address ++ u32 doorbell_cookie_addr_upper; // Upper 32 bits of Doorbell register physical address, always 32 bit, increment as integer, rollover to 1 ++ u32 feedback_buffer_addr_lower[TOUCH_SENSOR_MAX_DATA_BUFFERS]; // Lower 32 bits of Feedback Buffer physical address. Size of each buffer should be TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.FeedbackSize ++ u32 feedback_buffer_addr_upper[TOUCH_SENSOR_MAX_DATA_BUFFERS]; // Upper 32 bits of Feedback Buffer physical address. Size of each buffer should be TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.FeedbackSize ++ u32 hid2me_buffer_addr_lower; // Lower 32 bits of dedicated HID to ME communication buffer. Size is Hid2MeBufferSize. ++ u32 hid2me_buffer_addr_upper; // Upper 32 bits of dedicated HID to ME communication buffer. Size is Hid2MeBufferSize. ++ u32 hid2me_buffer_size; // Size in bytes of Hid2MeBuffer, can be no bigger than TOUCH_HID_2_ME_BUFFER_SIZE_MAX ++ u8 reserved1; // For future expansion ++ u8 work_queue_item_size; // Size in bytes of the GuC Work Queue Item pointed to by TailOffset ++ u16 work_queue_size; // Size in bytes of the entire GuC Work Queue ++ u32 reserved[8]; // For future expansion ++} touch_sensor_set_mem_window_cmd_data_t; ++C_ASSERT(sizeof(touch_sensor_set_mem_window_cmd_data_t) == 320); ++ ++ ++#define TOUCH_SENSOR_QUIESCE_FLAG_GUC_RESET BIT0 // indicates GuC got reset and ME must re-read GuC data such as TailOffset and Doorbell Cookie values ++ ++typedef struct touch_sensor_quiesce_io_cmd_data ++{ ++ u32 quiesce_flags; // Optionally set TOUCH_SENSOR_QUIESCE_FLAG_GUC_RESET ++ u32 reserved[2]; ++} touch_sensor_quiesce_io_cmd_data_t; ++C_ASSERT(sizeof(touch_sensor_quiesce_io_cmd_data_t) == 12); ++ ++ ++typedef struct touch_sensor_feedback_ready_cmd_data ++{ ++ u8 feedback_index; // Index value from 0 to TOUCH_HID_2_ME_BUFFER_ID used to indicate which Feedback Buffer to use. Using special value TOUCH_HID_2_ME_BUFFER_ID ++ // is an indication to ME to get feedback data from the Hid2Me buffer instead of one of the standard Feedback buffers. ++ u8 reserved1[3]; // For future expansion ++ u32 transaction_id; // Transaction ID that was originally passed to host in TOUCH_HID_PRIVATE_DATA. Used to track round trip of a given transaction for performance measurements. ++ u32 reserved2[2]; // For future expansion ++} touch_sensor_feedback_ready_cmd_data_t; ++C_ASSERT(sizeof(touch_sensor_feedback_ready_cmd_data_t) == 16); ++ ++ ++#define TOUCH_DEFAULT_DOZE_TIMER_SECONDS 30 ++ ++typedef enum touch_freq_override ++{ ++ TOUCH_FREQ_OVERRIDE_NONE, // Do not apply any override ++ TOUCH_FREQ_OVERRIDE_10MHZ, // Force frequency to 10MHz (not currently supported) ++ TOUCH_FREQ_OVERRIDE_17MHZ, // Force frequency to 17MHz ++ TOUCH_FREQ_OVERRIDE_30MHZ, // Force frequency to 30MHz ++ TOUCH_FREQ_OVERRIDE_50MHZ, // Force frequency to 50MHz (not currently supported) ++ TOUCH_FREQ_OVERRIDE_MAX // Invalid value ++} touch_freq_override_t; ++C_ASSERT(sizeof(touch_freq_override_t) == 4); ++ ++typedef enum touch_spi_io_mode_override ++{ ++ TOUCH_SPI_IO_MODE_OVERRIDE_NONE, // Do not apply any override ++ TOUCH_SPI_IO_MODE_OVERRIDE_SINGLE, // Force Single I/O ++ TOUCH_SPI_IO_MODE_OVERRIDE_DUAL, // Force Dual I/O ++ TOUCH_SPI_IO_MODE_OVERRIDE_QUAD, // Force Quad I/O ++ TOUCH_SPI_IO_MODE_OVERRIDE_MAX // Invalid value ++} touch_spi_io_mode_override_t; ++C_ASSERT(sizeof(touch_spi_io_mode_override_t) == 4); ++ ++// Debug Policy bits used by TOUCH_POLICY_DATA.DebugOverride ++#define TOUCH_DBG_POLICY_OVERRIDE_STARTUP_TIMER_DIS BIT0 // Disable sensor startup timer ++#define TOUCH_DBG_POLICY_OVERRIDE_SYNC_BYTE_DIS BIT1 // Disable Sync Byte check ++#define TOUCH_DBG_POLICY_OVERRIDE_ERR_RESET_DIS BIT2 // Disable error resets ++ ++typedef struct touch_policy_data ++{ ++ u32 reserved0; // For future expansion. ++ u32 doze_timer :16; // Value in seconds, after which ME will put the sensor into Doze power state if no activity occurs. Set ++ // to 0 to disable Doze mode (not recommended). Value will be set to TOUCH_DEFAULT_DOZE_TIMER_SECONDS by ++ // default. ++ touch_freq_override_t freq_override :3; // Override frequency requested by sensor ++ touch_spi_io_mode_override_t spi_io_override :3; // Override IO mode requested by sensor ++ u32 reserved1 :10; // For future expansion ++ u32 reserved2; // For future expansion ++ u32 debug_override; // Normally all bits will be zero. Bits will be defined as needed for enabling special debug features ++} touch_policy_data_t; ++C_ASSERT(sizeof(touch_policy_data_t) == 16); ++ ++typedef struct touch_sensor_set_policies_cmd_data ++{ ++ touch_policy_data_t policy_data; // Contains the desired policy to be set ++} touch_sensor_set_policies_cmd_data_t; ++C_ASSERT(sizeof(touch_sensor_set_policies_cmd_data_t) == 16); ++ ++ ++typedef enum touch_sensor_reset_type ++{ ++ TOUCH_SENSOR_RESET_TYPE_HARD, // Hardware Reset using dedicated GPIO pin ++ TOUCH_SENSOR_RESET_TYPE_SOFT, // Software Reset using command written over SPI interface ++ TOUCH_SENSOR_RESET_TYPE_MAX // Invalid value ++} touch_sensor_reset_type_t; ++C_ASSERT(sizeof(touch_sensor_reset_type_t) == 4); ++ ++typedef struct touch_sensor_reset_cmd_data ++{ ++ touch_sensor_reset_type_t reset_type; // Indicate desired reset type ++ u32 reserved; // For future expansion ++} touch_sensor_reset_cmd_data_t; ++C_ASSERT(sizeof(touch_sensor_reset_cmd_data_t) == 8); ++ ++ ++// ++// Host to ME message ++// ++typedef struct touch_sensor_msg_h2m ++{ ++ u32 command_code; ++ union ++ { ++ touch_sensor_set_mode_cmd_data_t set_mode_cmd_data; ++ touch_sensor_set_mem_window_cmd_data_t set_window_cmd_data; ++ touch_sensor_quiesce_io_cmd_data_t quiesce_io_cmd_data; ++ touch_sensor_feedback_ready_cmd_data_t feedback_ready_cmd_data; ++ touch_sensor_set_policies_cmd_data_t set_policies_cmd_data; ++ touch_sensor_reset_cmd_data_t reset_cmd_data; ++ } h2m_data; ++} touch_sensor_msg_h2m_t; ++C_ASSERT(sizeof(touch_sensor_msg_h2m_t) == 324); ++ ++ ++//******************************************************************* ++// ++// Defines for message structures used for ME to Host communication ++// ++//******************************************************************* ++ ++// I/O mode values used by TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA. ++typedef enum touch_spi_io_mode ++{ ++ TOUCH_SPI_IO_MODE_SINGLE = 0, // Sensor set for Single I/O SPI ++ TOUCH_SPI_IO_MODE_DUAL, // Sensor set for Dual I/O SPI ++ TOUCH_SPI_IO_MODE_QUAD, // Sensor set for Quad I/O SPI ++ TOUCH_SPI_IO_MODE_MAX // Invalid value ++} touch_spi_io_mode_t; ++C_ASSERT(sizeof(touch_spi_io_mode_t) == 4); ++ ++// ++// TOUCH_SENSOR_GET_DEVICE_INFO_RSP code is sent in response to TOUCH_SENSOR_GET_DEVICE_INFO_CMD. This code will be followed ++// by TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA. ++// ++// Possible Status values: ++// TOUCH_STATUS_SUCCESS: Command was processed successfully and sensor details are reported. ++// TOUCH_STATUS_CMD_SIZE_ERROR: Command sent did not match expected size. Other fields will not contain valid data. ++// TOUCH_STATUS_NO_SENSOR_FOUND: Sensor has not yet been detected. Other fields will not contain valid data. ++// TOUCH_STATUS_INVALID_DEVICE_CAPS: Indicates sensor does not support minimum required Frequency or I/O Mode. ME firmware will choose best possible option for the errant ++// field. Caller should attempt to continue. ++// TOUCH_STATUS_COMPAT_CHECK_FAIL: Indicates TouchIC/ME compatibility mismatch. Caller should attempt to continue. ++// ++typedef struct touch_sensor_get_device_info_rsp_data ++{ ++ u16 vendor_id; // Touch Sensor vendor ID ++ u16 device_id; // Touch Sensor device ID ++ u32 hw_rev; // Touch Sensor Hardware Revision ++ u32 fw_rev; // Touch Sensor Firmware Revision ++ u32 frame_size; // Max size of one frame returned by Touch IC in bytes. This data will be TOUCH_RAW_DATA_HDR followed ++ // by a payload. The payload can be raw data or a HID structure depending on mode. ++ u32 feedback_size; // Max size of one Feedback structure in bytes ++ touch_sensor_mode_t sensor_mode; // Current operating mode of the sensor ++ u32 max_touch_points :8; // Maximum number of simultaneous touch points that can be reported by sensor ++ touch_freq_t spi_frequency :8; // SPI bus Frequency supported by sensor and ME firmware ++ touch_spi_io_mode_t spi_io_mode :8; // SPI bus I/O Mode supported by sensor and ME firmware ++ u32 reserved0 :8; // For future expansion ++ u8 sensor_minor_eds_rev; // Minor version number of EDS spec supported by sensor (from Compat Rev ID Reg) ++ u8 sensor_major_eds_rev; // Major version number of EDS spec supported by sensor (from Compat Rev ID Reg) ++ u8 me_minor_eds_rev; // Minor version number of EDS spec supported by ME ++ u8 me_major_eds_rev; // Major version number of EDS spec supported by ME ++ u8 sensor_eds_intf_rev; // EDS Interface Revision Number supported by sensor (from Compat Rev ID Reg) ++ u8 me_eds_intf_rev; // EDS Interface Revision Number supported by ME ++ u8 kernel_compat_ver; // EU Kernel Compatibility Version (from Compat Rev ID Reg) ++ u8 reserved1; // For future expansion ++ u32 reserved2[2]; // For future expansion ++} touch_sensor_get_device_info_rsp_data_t; ++C_ASSERT(sizeof(touch_sensor_get_device_info_rsp_data_t) == 44); ++ ++ ++// ++// TOUCH_SENSOR_SET_MODE_RSP code is sent in response to TOUCH_SENSOR_SET_MODE_CMD. This code will be followed ++// by TOUCH_SENSOR_SET_MODE_RSP_DATA. ++// ++// Possible Status values: ++// TOUCH_STATUS_SUCCESS: Command was processed successfully and mode was set. ++// TOUCH_STATUS_CMD_SIZE_ERROR: Command sent did not match expected size. Other fields will not contain valid data. ++// TOUCH_STATUS_INVALID_PARAMS: Input parameters are out of range. ++// ++typedef struct touch_sensor_set_mode_rsp_data ++{ ++ u32 reserved[3]; // For future expansion ++} touch_sensor_set_mode_rsp_data_t; ++C_ASSERT(sizeof(touch_sensor_set_mode_rsp_data_t) == 12); ++ ++ ++// ++// TOUCH_SENSOR_SET_MEM_WINDOW_RSP code is sent in response to TOUCH_SENSOR_SET_MEM_WINDOW_CMD. This code will be followed ++// by TOUCH_SENSOR_SET_MEM_WINDOW_RSP_DATA. ++// ++// Possible Status values: ++// TOUCH_STATUS_SUCCESS: Command was processed successfully and memory window was set. ++// TOUCH_STATUS_CMD_SIZE_ERROR: Command sent did not match expected size. Other fields will not contain valid data. ++// TOUCH_STATUS_INVALID_PARAMS: Input parameters are out of range. ++// TOUCH_STATUS_ACCESS_DENIED: Unable to map host address ranges for DMA. ++// TOUCH_STATUS_OUT_OF_MEMORY: Unable to allocate enough space for needed buffers. ++// ++typedef struct touch_sensor_set_mem_window_rsp_data ++{ ++ u32 reserved[3]; // For future expansion ++} touch_sensor_set_mem_window_rsp_data_t; ++C_ASSERT(sizeof(touch_sensor_set_mem_window_rsp_data_t) == 12); ++ ++ ++// ++// TOUCH_SENSOR_QUIESCE_IO_RSP code is sent in response to TOUCH_SENSOR_QUIESCE_IO_CMD. This code will be followed ++// by TOUCH_SENSOR_QUIESCE_IO_RSP_DATA. ++// ++// Possible Status values: ++// TOUCH_STATUS_SUCCESS: Command was processed successfully and touch flow has stopped. ++// TOUCH_STATUS_CMD_SIZE_ERROR: Command sent did not match expected size. Other fields will not contain valid data. ++// TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS: Indicates that Quiesce I/O is already in progress and this command cannot be accepted at this time. ++// TOUCH_STATIS_TIMEOUT: Indicates ME timed out waiting for Quiesce I/O flow to complete. ++// ++typedef struct touch_sensor_quiesce_io_rsp_data ++{ ++ u32 reserved[3]; // For future expansion ++} touch_sensor_quiesce_io_rsp_data_t; ++C_ASSERT(sizeof(touch_sensor_quiesce_io_rsp_data_t) == 12); ++ ++ ++// Reset Reason values used in TOUCH_SENSOR_HID_READY_FOR_DATA_RSP_DATA ++typedef enum touch_reset_reason ++{ ++ TOUCH_RESET_REASON_UNKNOWN = 0, // Reason for sensor reset is not known ++ TOUCH_RESET_REASON_FEEDBACK_REQUEST, // Reset was requested as part of TOUCH_SENSOR_FEEDBACK_READY_CMD ++ TOUCH_RESET_REASON_HECI_REQUEST, // Reset was requested via TOUCH_SENSOR_RESET_CMD ++ TOUCH_RESET_REASON_MAX ++} touch_reset_reason_t; ++C_ASSERT(sizeof(touch_reset_reason_t) == 4); ++ ++// ++// TOUCH_SENSOR_HID_READY_FOR_DATA_RSP code is sent in response to TOUCH_SENSOR_HID_READY_FOR_DATA_CMD. This code will be followed ++// by TOUCH_SENSOR_HID_READY_FOR_DATA_RSP_DATA. ++// ++// Possible Status values: ++// TOUCH_STATUS_SUCCESS: Command was processed successfully and HID data was sent by DMA. This will only be sent in HID mode. ++// TOUCH_STATUS_CMD_SIZE_ERROR: Command sent did not match expected size. Other fields will not contain valid data. ++// TOUCH_STATUS_REQUEST_OUTSTANDING: Previous request is still outstanding, ME FW cannot handle another request for the same command. ++// TOUCH_STATUS_NOT_READY: Indicates memory window has not yet been set by BIOS/HID. ++// TOUCH_STATUS_SENSOR_DISABLED: Indicates that ME to HID communication has been stopped either by TOUCH_SENSOR_QUIESCE_IO_CMD or TOUCH_SENSOR_CLEAR_MEM_WINDOW_CMD. ++// TOUCH_STATUS_SENSOR_UNEXPECTED_RESET: Sensor signaled a Reset Interrupt. ME did not expect this and has no info about why this occurred. ++// TOUCH_STATUS_SENSOR_EXPECTED_RESET: Sensor signaled a Reset Interrupt. ME either directly requested this reset, or it was expected as part of a defined flow in the EDS. ++// TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS: Indicates that Quiesce I/O is already in progress and this command cannot be accepted at this time. ++// TOUCH_STATUS_TIMEOUT: Sensor did not generate a reset interrupt in the time allotted. Could indicate sensor is not connected or malfunctioning. ++// ++typedef struct touch_sensor_hid_ready_for_data_rsp_data ++{ ++ u32 data_size; // Size of the data the ME DMA'd into a RawDataBuffer. Valid only when Status == TOUCH_STATUS_SUCCESS ++ u8 touch_data_buffer_index; // Index to indicate which RawDataBuffer was used. Valid only when Status == TOUCH_STATUS_SUCCESS ++ u8 reset_reason; // If Status is TOUCH_STATUS_SENSOR_EXPECTED_RESET, ME will provide the cause. See TOUCH_RESET_REASON. ++ u8 reserved1[2]; // For future expansion ++ u32 reserved2[5]; // For future expansion ++} touch_sensor_hid_ready_for_data_rsp_data_t; ++C_ASSERT(sizeof(touch_sensor_hid_ready_for_data_rsp_data_t) == 28); ++ ++ ++// ++// TOUCH_SENSOR_FEEDBACK_READY_RSP code is sent in response to TOUCH_SENSOR_FEEDBACK_READY_CMD. This code will be followed ++// by TOUCH_SENSOR_FEEDBACK_READY_RSP_DATA. ++// ++// Possible Status values: ++// TOUCH_STATUS_SUCCESS: Command was processed successfully and any feedback or commands were sent to sensor. ++// TOUCH_STATUS_CMD_SIZE_ERROR: Command sent did not match expected size. Other fields will not contain valid data. ++// TOUCH_STATUS_INVALID_PARAMS: Input parameters are out of range. ++// TOUCH_STATUS_COMPAT_CHECK_FAIL Indicates ProtocolVer does not match ME supported version. (non-fatal error) ++// TOUCH_STATUS_INTERNAL_ERROR: Unexpected error occurred. This should not normally be seen. ++// TOUCH_STATUS_OUT_OF_MEMORY: Insufficient space to store Calibration Data ++// ++typedef struct touch_sensor_feedback_ready_rsp_data ++{ ++ u8 feedback_index; // Index value from 0 to TOUCH_SENSOR_MAX_DATA_BUFFERS used to indicate which Feedback Buffer to use ++ u8 reserved1[3]; // For future expansion ++ u32 reserved2[6]; // For future expansion ++} touch_sensor_feedback_ready_rsp_data_t; ++C_ASSERT(sizeof(touch_sensor_feedback_ready_rsp_data_t) == 28); ++ ++ ++// ++// TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP code is sent in response to TOUCH_SENSOR_CLEAR_MEM_WINDOW_CMD. This code will be followed ++// by TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP_DATA. ++// ++// Possible Status values: ++// TOUCH_STATUS_SUCCESS: Command was processed successfully and memory window was set. ++// TOUCH_STATUS_CMD_SIZE_ERROR: Command sent did not match expected size. Other fields will not contain valid data. ++// TOUCH_STATUS_INVALID_PARAMS: Input parameters are out of range. ++// TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS: Indicates that Quiesce I/O is already in progress and this command cannot be accepted at this time. ++// ++typedef struct touch_sensor_clear_mem_window_rsp_data ++{ ++ u32 reserved[3]; // For future expansion ++} touch_sensor_clear_mem_window_rsp_data_t; ++C_ASSERT(sizeof(touch_sensor_clear_mem_window_rsp_data_t) == 12); ++ ++ ++// ++// TOUCH_SENSOR_NOTIFY_DEV_READY_RSP code is sent in response to TOUCH_SENSOR_NOTIFY_DEV_READY_CMD. This code will be followed ++// by TOUCH_SENSOR_NOTIFY_DEV_READY_RSP_DATA. ++// ++// Possible Status values: ++// TOUCH_STATUS_SUCCESS: Command was processed successfully and sensor has been detected by ME FW. ++// TOUCH_STATUS_CMD_SIZE_ERROR: Command sent did not match expected size. ++// TOUCH_STATUS_REQUEST_OUTSTANDING: Previous request is still outstanding, ME FW cannot handle another request for the same command. ++// TOUCH_STATUS_TIMEOUT: Sensor did not generate a reset interrupt in the time allotted. Could indicate sensor is not connected or malfunctioning. ++// TOUCH_STATUS_SENSOR_FAIL_FATAL: Sensor indicated a fatal error, further operation is not possible. Error details can be found in ErrReg. ++// TOUCH_STATUS_SENSOR_FAIL_NONFATAL: Sensor indicated a non-fatal error. Error should be logged by caller and init flow can continue. Error details can be found in ErrReg. ++// ++typedef struct touch_sensor_notify_dev_ready_rsp_data ++{ ++ touch_err_reg_t err_reg; // Value of sensor Error Register, field is only valid for Status == TOUCH_STATUS_SENSOR_FAIL_FATAL or TOUCH_STATUS_SENSOR_FAIL_NONFATAL ++ u32 reserved[2]; // For future expansion ++} touch_sensor_notify_dev_ready_rsp_data_t; ++C_ASSERT(sizeof(touch_sensor_notify_dev_ready_rsp_data_t) == 12); ++ ++ ++// ++// TOUCH_SENSOR_SET_POLICIES_RSP code is sent in response to TOUCH_SENSOR_SET_POLICIES_CMD. This code will be followed ++// by TOUCH_SENSOR_SET_POLICIES_RSP_DATA. ++// ++// Possible Status values: ++// TOUCH_STATUS_SUCCESS: Command was processed successfully and new policies were set. ++// TOUCH_STATUS_CMD_SIZE_ERROR: Command sent did not match expected size. Other fields will not contain valid data. ++// TOUCH_STATUS_INVALID_PARAMS: Input parameters are out of range. ++// ++typedef struct touch_sensor_set_policies_rsp_data ++{ ++ u32 reserved[3]; // For future expansion ++} touch_sensor_set_policies_rsp_data_t; ++C_ASSERT(sizeof(touch_sensor_set_policies_rsp_data_t) == 12); ++ ++ ++// ++// TOUCH_SENSOR_GET_POLICIES_RSP code is sent in response to TOUCH_SENSOR_GET_POLICIES_CMD. This code will be followed ++// by TOUCH_SENSOR_GET_POLICIES_RSP_DATA. ++// ++// Possible Status values: ++// TOUCH_STATUS_SUCCESS: Command was processed successfully and new policies were set. ++// TOUCH_STATUS_CMD_SIZE_ERROR: Command sent did not match expected size. Other fields will not contain valid data. ++// ++typedef struct touch_sensor_get_policies_rsp_data ++{ ++ touch_policy_data_t policy_data; // Contains the current policy ++} touch_sensor_get_policies_rsp_data_t; ++C_ASSERT(sizeof(touch_sensor_get_policies_rsp_data_t) == 16); ++ ++ ++// ++// TOUCH_SENSOR_RESET_RSP code is sent in response to TOUCH_SENSOR_RESET_CMD. This code will be followed ++// by TOUCH_SENSOR_RESET_RSP_DATA. ++// ++// Possible Status values: ++// TOUCH_STATUS_SUCCESS: Command was processed successfully and sensor reset was completed. ++// TOUCH_STATUS_CMD_SIZE_ERROR: Command sent did not match expected size. Other fields will not contain valid data. ++// TOUCH_STATUS_INVALID_PARAMS: Input parameters are out of range. ++// TOUCH_STATUS_TIMEOUT: Sensor did not generate a reset interrupt in the time allotted. Could indicate sensor is not connected or malfunctioning. ++// TOUCH_STATUS_RESET_FAILED: Sensor generated an invalid or unexpected interrupt. ++// TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS: Indicates that Quiesce I/O is already in progress and this command cannot be accepted at this time. ++// ++typedef struct touch_sensor_reset_rsp_data ++{ ++ u32 reserved[3]; // For future expansion ++} touch_sensor_reset_rsp_data_t; ++C_ASSERT(sizeof(touch_sensor_reset_rsp_data_t) == 12); ++ ++ ++// ++// TOUCH_SENSOR_READ_ALL_REGS_RSP code is sent in response to TOUCH_SENSOR_READ_ALL_REGS_CMD. This code will be followed ++// by TOUCH_SENSOR_READ_ALL_REGS_RSP_DATA. ++// ++// Possible Status values: ++// TOUCH_STATUS_SUCCESS: Command was processed successfully and new policies were set. ++// TOUCH_STATUS_CMD_SIZE_ERROR: Command sent did not match expected size. Other fields will not contain valid data. ++// ++typedef struct touch_sensor_read_all_regs_rsp_data ++{ ++ touch_reg_block_t sensor_regs; // Returns first 64 bytes of register space used for normal touch operation. Does not include test mode register. ++ u32 reserved[4]; ++} touch_sensor_read_all_regs_rsp_data_t; ++C_ASSERT(sizeof(touch_sensor_read_all_regs_rsp_data_t) == 80); ++ ++// ++// ME to Host Message ++// ++typedef struct touch_sensor_msg_m2h ++{ ++ u32 command_code; ++ touch_status_t status; ++ union ++ { ++ touch_sensor_get_device_info_rsp_data_t device_info_rsp_data; ++ touch_sensor_set_mode_rsp_data_t set_mode_rsp_data; ++ touch_sensor_set_mem_window_rsp_data_t set_mem_window_rsp_data; ++ touch_sensor_quiesce_io_rsp_data_t quiesce_io_rsp_data; ++ touch_sensor_hid_ready_for_data_rsp_data_t hid_ready_for_data_rsp_data; ++ touch_sensor_feedback_ready_rsp_data_t feedback_ready_rsp_data; ++ touch_sensor_clear_mem_window_rsp_data_t clear_mem_window_rsp_data; ++ touch_sensor_notify_dev_ready_rsp_data_t notify_dev_ready_rsp_data; ++ touch_sensor_set_policies_rsp_data_t set_policies_rsp_data; ++ touch_sensor_get_policies_rsp_data_t get_policies_rsp_data; ++ touch_sensor_reset_rsp_data_t reset_rsp_data; ++ touch_sensor_read_all_regs_rsp_data_t read_all_regs_rsp_data; ++ } m2h_data; ++} touch_sensor_msg_m2h_t; ++C_ASSERT(sizeof(touch_sensor_msg_m2h_t) == 88); ++ ++ ++#define TOUCH_MSG_SIZE_MAX_BYTES (MAX(sizeof(touch_sensor_msg_m2h_t), sizeof(touch_sensor_msg_h2m_t))) ++ ++#pragma pack() ++ ++#endif // _IPTS_MEI_MSGS_H_ +diff --git a/drivers/misc/ipts/ipts-mei.c b/drivers/misc/ipts/ipts-mei.c +new file mode 100644 +index 0000000..39667e7 +--- /dev/null ++++ b/drivers/misc/ipts/ipts-mei.c +@@ -0,0 +1,282 @@ ++/* ++ * MEI client driver for Intel Precise Touch and Stylus ++ * ++ * Copyright (c) 2016, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ipts.h" ++#include "ipts-hid.h" ++#include "ipts-msg-handler.h" ++#include "ipts-mei-msgs.h" ++#include "ipts-binary-spec.h" ++#include "ipts-state.h" ++ ++#define IPTS_DRIVER_NAME "ipts" ++#define IPTS_MEI_UUID UUID_LE(0x3e8d0870, 0x271a, 0x4208, \ ++ 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) ++ ++static struct mei_cl_device_id ipts_mei_cl_tbl[] = { ++ { "", IPTS_MEI_UUID, MEI_CL_VERSION_ANY}, ++ {} ++}; ++ ++static ssize_t sensor_mode_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ ipts_info_t *ipts; ++ ipts = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%d\n", ipts->sensor_mode); ++} ++ ++//TODO: Verify the function implementation ++static ssize_t sensor_mode_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, ++ size_t count) ++{ ++ int ret; ++ long val; ++ ipts_info_t *ipts; ++ ++ ipts = dev_get_drvdata(dev); ++ ret = kstrtol(buf, 10, &val); ++ if (ret) ++ return ret; ++ ++ ipts_dbg(ipts, "try sensor mode = %ld\n", val); ++ ++ switch (val) { ++ case TOUCH_SENSOR_MODE_HID: ++ break; ++ case TOUCH_SENSOR_MODE_RAW_DATA: ++ break; ++ default: ++ ipts_err(ipts, "sensor mode %ld is not supported\n", val); ++ } ++ ++ return count; ++} ++ ++static ssize_t device_info_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ ipts_info_t *ipts; ++ ++ ipts = dev_get_drvdata(dev); ++ return sprintf(buf, "vendor id = 0x%04hX\n" ++ "device id = 0x%04hX\n" ++ "HW rev = 0x%08X\n" ++ "firmware rev = 0x%08X\n", ++ ipts->device_info.vendor_id, ipts->device_info.device_id, ++ ipts->device_info.hw_rev, ipts->device_info.fw_rev); ++} ++ ++static DEVICE_ATTR_RW(sensor_mode); ++static DEVICE_ATTR_RO(device_info); ++ ++static struct attribute *ipts_attrs[] = { ++ &dev_attr_sensor_mode.attr, ++ &dev_attr_device_info.attr, ++ NULL ++}; ++ ++static const struct attribute_group ipts_grp = { ++ .attrs = ipts_attrs, ++}; ++ ++MODULE_DEVICE_TABLE(mei, ipts_mei_cl_tbl); ++ ++static void raw_data_work_func(struct work_struct *work) ++{ ++ ipts_info_t *ipts = container_of(work, ipts_info_t, raw_data_work); ++ ++ ipts_handle_processed_data(ipts); ++} ++ ++static void gfx_status_work_func(struct work_struct *work) ++{ ++ ipts_info_t *ipts = container_of(work, ipts_info_t, gfx_status_work); ++ ipts_state_t state; ++ int status = ipts->gfx_status; ++ ++ ipts_dbg(ipts, "notify gfx status : %d\n", status); ++ ++ state = ipts_get_state(ipts); ++ ++ if (state == IPTS_STA_RAW_DATA_STARTED || state == IPTS_STA_HID_STARTED) { ++ if (status == IPTS_NOTIFY_STA_BACKLIGHT_ON && ++ ipts->display_status == false) { ++ ipts_send_sensor_clear_mem_window_cmd(ipts); ++ ipts->display_status = true; ++ } else if (status == IPTS_NOTIFY_STA_BACKLIGHT_OFF && ++ ipts->display_status == true) { ++ ipts_send_sensor_quiesce_io_cmd(ipts); ++ ipts->display_status = false; ++ } ++ } ++} ++ ++/* event loop */ ++static int ipts_mei_cl_event_thread(void *data) ++{ ++ ipts_info_t *ipts = (ipts_info_t *)data; ++ struct mei_cl_device *cldev = ipts->cldev; ++ ssize_t msg_len; ++ touch_sensor_msg_m2h_t m2h_msg; ++ ++ while (!kthread_should_stop()) { ++ msg_len = mei_cldev_recv(cldev, (u8*)&m2h_msg, sizeof(m2h_msg)); ++ if (msg_len <= 0) { ++ ipts_err(ipts, "error in reading m2h msg\n"); ++ continue; ++ } ++ ++ if (ipts_handle_resp(ipts, &m2h_msg, msg_len) != 0) { ++ ipts_err(ipts, "error in handling resp msg\n"); ++ } ++ } ++ ++ ipts_dbg(ipts, "!! end event loop !!\n"); ++ ++ return 0; ++} ++ ++static void init_work_func(struct work_struct *work) ++{ ++ ipts_info_t *ipts = container_of(work, ipts_info_t, init_work); ++ ++ ipts->sensor_mode = TOUCH_SENSOR_MODE_RAW_DATA; ++ ipts->display_status = true; ++ ++ ipts_start(ipts); ++} ++ ++static int ipts_mei_cl_probe(struct mei_cl_device *cldev, ++ const struct mei_cl_device_id *id) ++{ ++ int ret = 0; ++ ipts_info_t *ipts = NULL; ++ ++ pr_info("probing Intel Precise Touch & Stylus\n"); ++ ++ // setup the DMA BIT mask, the system will choose the best possible ++ if (dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64)) == 0) { ++ pr_info("IPTS using DMA_BIT_MASK(64)\n"); ++ } else if (dma_coerce_mask_and_coherent(&cldev->dev, ++ DMA_BIT_MASK(32)) == 0) { ++ pr_info("IPTS using DMA_BIT_MASK(32)\n"); ++ } else { ++ pr_err("IPTS: No suitable DMA available\n"); ++ return -EFAULT; ++ } ++ ++ ret = mei_cldev_enable(cldev); ++ if (ret < 0) { ++ pr_err("cannot enable IPTS\n"); ++ return ret; ++ } ++ ++ ipts = devm_kzalloc(&cldev->dev, sizeof(ipts_info_t), GFP_KERNEL); ++ if (ipts == NULL) { ++ ret = -ENOMEM; ++ goto disable_mei; ++ } ++ ipts->cldev = cldev; ++ mei_cldev_set_drvdata(cldev, ipts); ++ ++ ipts->event_loop = kthread_run(ipts_mei_cl_event_thread, (void*)ipts, ++ "ipts_event_thread"); ++ ++ if(ipts_dbgfs_register(ipts, "ipts")) ++ pr_debug("cannot register debugfs for IPTS\n"); ++ ++ INIT_WORK(&ipts->init_work, init_work_func); ++ INIT_WORK(&ipts->raw_data_work, raw_data_work_func); ++ INIT_WORK(&ipts->gfx_status_work, gfx_status_work_func); ++ ++ ret = sysfs_create_group(&cldev->dev.kobj, &ipts_grp); ++ if (ret != 0) { ++ pr_debug("cannot create sysfs for IPTS\n"); ++ } ++ ++ schedule_work(&ipts->init_work); ++ ++ return 0; ++ ++disable_mei : ++ mei_cldev_disable(cldev); ++ ++ return ret; ++} ++ ++static int ipts_mei_cl_remove(struct mei_cl_device *cldev) ++{ ++ ipts_info_t *ipts = mei_cldev_get_drvdata(cldev); ++ ++ ipts_stop(ipts); ++ ++ sysfs_remove_group(&cldev->dev.kobj, &ipts_grp); ++ ipts_hid_release(ipts); ++ ipts_dbgfs_deregister(ipts); ++ mei_cldev_disable(cldev); ++ ++ kthread_stop(ipts->event_loop); ++ ++ pr_info("IPTS removed\n"); ++ ++ return 0; ++} ++ ++static struct mei_cl_driver ipts_mei_cl_driver = { ++ .id_table = ipts_mei_cl_tbl, ++ .name = IPTS_DRIVER_NAME, ++ .probe = ipts_mei_cl_probe, ++ .remove = ipts_mei_cl_remove, ++}; ++ ++static int ipts_mei_cl_init(void) ++{ ++ int ret; ++ ++ pr_info("IPTS %s() is called\n", __func__); ++ ++ ret = mei_cldev_driver_register(&ipts_mei_cl_driver); ++ if (ret) { ++ pr_err("unable to register IPTS mei client driver\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void __exit ipts_mei_cl_exit(void) ++{ ++ pr_info("IPTS %s() is called\n", __func__); ++ ++ mei_cldev_driver_unregister(&ipts_mei_cl_driver); ++} ++ ++module_init(ipts_mei_cl_init); ++module_exit(ipts_mei_cl_exit); ++ ++MODULE_DESCRIPTION ++ ("Intel(R) Management Engine Interface Client Driver for "\ ++ "Intel Precision Touch and Sylus"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/misc/ipts/ipts-msg-handler.c b/drivers/misc/ipts/ipts-msg-handler.c +new file mode 100644 +index 0000000..1396ecc +--- /dev/null ++++ b/drivers/misc/ipts/ipts-msg-handler.c +@@ -0,0 +1,431 @@ ++#include ++ ++#include "ipts.h" ++#include "ipts-hid.h" ++#include "ipts-resource.h" ++#include "ipts-mei-msgs.h" ++ ++int ipts_handle_cmd(ipts_info_t *ipts, u32 cmd, void *data, int data_size) ++{ ++ int ret = 0; ++ touch_sensor_msg_h2m_t h2m_msg; ++ int len = 0; ++ ++ memset(&h2m_msg, 0, sizeof(h2m_msg)); ++ ++ h2m_msg.command_code = cmd; ++ len = sizeof(h2m_msg.command_code) + data_size; ++ if (data != NULL && data_size != 0) ++ memcpy(&h2m_msg.h2m_data, data, data_size); /* copy payload */ ++ ++ ret = mei_cldev_send(ipts->cldev, (u8*)&h2m_msg, len); ++ if (ret < 0) { ++ ipts_err(ipts, "mei_cldev_send() error 0x%X:%d\n", ++ cmd, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_send_feedback(ipts_info_t *ipts, int buffer_idx, u32 transaction_id) ++{ ++ int ret; ++ int cmd_len; ++ touch_sensor_feedback_ready_cmd_data_t fb_ready_cmd; ++ ++ cmd_len = sizeof(touch_sensor_feedback_ready_cmd_data_t); ++ memset(&fb_ready_cmd, 0, cmd_len); ++ ++ fb_ready_cmd.feedback_index = buffer_idx; ++ fb_ready_cmd.transaction_id = transaction_id; ++ ++ ret = ipts_handle_cmd(ipts, TOUCH_SENSOR_FEEDBACK_READY_CMD, ++ &fb_ready_cmd, cmd_len); ++ ++ return ret; ++} ++ ++int ipts_send_sensor_quiesce_io_cmd(ipts_info_t *ipts) ++{ ++ int ret; ++ int cmd_len; ++ touch_sensor_quiesce_io_cmd_data_t quiesce_io_cmd; ++ ++ cmd_len = sizeof(touch_sensor_quiesce_io_cmd_data_t); ++ memset(&quiesce_io_cmd, 0, cmd_len); ++ ++ ret = ipts_handle_cmd(ipts, TOUCH_SENSOR_QUIESCE_IO_CMD, ++ &quiesce_io_cmd, cmd_len); ++ ++ return ret; ++} ++ ++int ipts_send_sensor_hid_ready_for_data_cmd(ipts_info_t *ipts) ++{ ++ return ipts_handle_cmd(ipts, TOUCH_SENSOR_HID_READY_FOR_DATA_CMD, NULL, 0); ++} ++ ++int ipts_send_sensor_clear_mem_window_cmd(ipts_info_t *ipts) ++{ ++ return ipts_handle_cmd(ipts, TOUCH_SENSOR_CLEAR_MEM_WINDOW_CMD, NULL, 0); ++} ++ ++static int check_validity(touch_sensor_msg_m2h_t *m2h_msg, u32 msg_len) ++{ ++ int ret = 0; ++ int valid_msg_len = sizeof(m2h_msg->command_code); ++ u32 cmd_code = m2h_msg->command_code; ++ ++ switch (cmd_code) { ++ case TOUCH_SENSOR_SET_MODE_RSP: ++ valid_msg_len += ++ sizeof(touch_sensor_set_mode_rsp_data_t); ++ break; ++ case TOUCH_SENSOR_SET_MEM_WINDOW_RSP: ++ valid_msg_len += ++ sizeof(touch_sensor_set_mem_window_rsp_data_t); ++ break; ++ case TOUCH_SENSOR_QUIESCE_IO_RSP: ++ valid_msg_len += ++ sizeof(touch_sensor_quiesce_io_rsp_data_t); ++ break; ++ case TOUCH_SENSOR_HID_READY_FOR_DATA_RSP: ++ valid_msg_len += ++ sizeof(touch_sensor_hid_ready_for_data_rsp_data_t); ++ break; ++ case TOUCH_SENSOR_FEEDBACK_READY_RSP: ++ valid_msg_len += ++ sizeof(touch_sensor_feedback_ready_rsp_data_t); ++ break; ++ case TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP: ++ valid_msg_len += ++ sizeof(touch_sensor_clear_mem_window_rsp_data_t); ++ break; ++ case TOUCH_SENSOR_NOTIFY_DEV_READY_RSP: ++ valid_msg_len += ++ sizeof(touch_sensor_notify_dev_ready_rsp_data_t); ++ break; ++ case TOUCH_SENSOR_SET_POLICIES_RSP: ++ valid_msg_len += ++ sizeof(touch_sensor_set_policies_rsp_data_t); ++ break; ++ case TOUCH_SENSOR_GET_POLICIES_RSP: ++ valid_msg_len += ++ sizeof(touch_sensor_get_policies_rsp_data_t); ++ break; ++ case TOUCH_SENSOR_RESET_RSP: ++ valid_msg_len += ++ sizeof(touch_sensor_reset_rsp_data_t); ++ break; ++ } ++ ++ if (valid_msg_len != msg_len) { ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++int ipts_start(ipts_info_t *ipts) ++{ ++ int ret = 0; ++ /* TODO : check if we need to do SET_POLICIES_CMD ++ we need to do this when protocol version doesn't match with reported one ++ how we keep vendor specific data is the first thing to solve */ ++ ++ ipts_set_state(ipts, IPTS_STA_INIT); ++ ipts->num_of_parallel_data_buffers = TOUCH_SENSOR_MAX_DATA_BUFFERS; ++ ++ ipts->sensor_mode = TOUCH_SENSOR_MODE_RAW_DATA; /* start with RAW_DATA */ ++ ++ ret = ipts_handle_cmd(ipts, TOUCH_SENSOR_NOTIFY_DEV_READY_CMD, NULL, 0); ++ ++ return ret; ++} ++ ++void ipts_stop(ipts_info_t *ipts) ++{ ++ ipts_state_t old_state; ++ ++ old_state = ipts_get_state(ipts); ++ ipts_set_state(ipts, IPTS_STA_STOPPING); ++ ++ if (old_state < IPTS_STA_RESOURCE_READY) ++ return; ++ ++ if (old_state == IPTS_STA_RAW_DATA_STARTED || ++ old_state == IPTS_STA_HID_STARTED) { ++ ipts_free_default_resource(ipts); ++ ipts_free_raw_data_resource(ipts); ++ ++ return; ++ } ++} ++ ++int ipts_restart(ipts_info_t *ipts) ++{ ++ int ret = 0; ++ ++ ipts_dbg(ipts, "ipts restart\n"); ++ ++ ipts_stop(ipts); ++ ++ ipts->retry++; ++ if (ipts->retry == IPTS_MAX_RETRY && ++ ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA) { ++ /* try with HID mode */ ++ ipts->sensor_mode = TOUCH_SENSOR_MODE_HID; ++ } else if (ipts->retry > IPTS_MAX_RETRY) { ++ return -EPERM; ++ } ++ ++ ipts_send_sensor_quiesce_io_cmd(ipts); ++ ipts->restart = true; ++ ++ return ret; ++} ++ ++int ipts_switch_sensor_mode(ipts_info_t *ipts, int new_sensor_mode) ++{ ++ int ret = 0; ++ ++ ipts->new_sensor_mode = new_sensor_mode; ++ ipts->switch_sensor_mode = true; ++ ret = ipts_send_sensor_quiesce_io_cmd(ipts); ++ ++ return ret; ++} ++ ++#define rsp_failed(ipts, cmd, status) ipts_err(ipts, \ ++ "0x%08x failed status = %d\n", cmd, status); ++ ++int ipts_handle_resp(ipts_info_t *ipts, touch_sensor_msg_m2h_t *m2h_msg, ++ u32 msg_len) ++{ ++ int ret = 0; ++ int rsp_status = 0; ++ int cmd_status = 0; ++ int cmd_len = 0; ++ u32 cmd; ++ ++ if (!check_validity(m2h_msg, msg_len)) { ++ ipts_err(ipts, "wrong rsp\n"); ++ return -EINVAL; ++ } ++ ++ rsp_status = m2h_msg->status; ++ cmd = m2h_msg->command_code; ++ ++ switch (cmd) { ++ case TOUCH_SENSOR_NOTIFY_DEV_READY_RSP: ++ if (rsp_status != 0 && ++ rsp_status != TOUCH_STATUS_SENSOR_FAIL_NONFATAL) { ++ rsp_failed(ipts, cmd, rsp_status); ++ break; ++ } ++ ++ cmd_status = ipts_handle_cmd(ipts, ++ TOUCH_SENSOR_GET_DEVICE_INFO_CMD, ++ NULL, 0); ++ break; ++ case TOUCH_SENSOR_GET_DEVICE_INFO_RSP: ++ if (rsp_status != 0 && ++ rsp_status != TOUCH_STATUS_COMPAT_CHECK_FAIL) { ++ rsp_failed(ipts, cmd, rsp_status); ++ break; ++ } ++ ++ memcpy(&ipts->device_info, ++ &m2h_msg->m2h_data.device_info_rsp_data, ++ sizeof(touch_sensor_get_device_info_rsp_data_t)); ++ ++ /* ++ TODO : support raw_request during HID init. ++ Although HID init happens here, technically most of ++ reports (for both direction) can be issued only ++ after SET_MEM_WINDOWS_CMD since they may require ++ ME or touch IC. If ipts vendor requires raw_request ++ during HID init, we need to consider to move HID init. ++ */ ++ if (ipts->hid_desc_ready == false) { ++ ret = ipts_hid_init(ipts); ++ if (ret) ++ break; ++ } ++ ++ cmd_status = ipts_send_sensor_clear_mem_window_cmd(ipts); ++ ++ break; ++ case TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP: ++ { ++ touch_sensor_set_mode_cmd_data_t sensor_mode_cmd; ++ ++ if (rsp_status != 0 && ++ rsp_status != TOUCH_STATUS_TIMEOUT) { ++ rsp_failed(ipts, cmd, rsp_status); ++ break; ++ } ++ ++ /* allocate default resource : common & hid only */ ++ if (!ipts_is_default_resource_ready(ipts)) { ++ ret = ipts_allocate_default_resource(ipts); ++ if (ret) ++ break; ++ } ++ ++ if (ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA && ++ !ipts_is_raw_data_resource_ready(ipts)) { ++ ret = ipts_allocate_raw_data_resource(ipts); ++ if (ret) { ++ ipts_free_default_resource(ipts); ++ break; ++ } ++ } ++ ++ ipts_set_state(ipts, IPTS_STA_RESOURCE_READY); ++ ++ cmd_len = sizeof(touch_sensor_set_mode_cmd_data_t); ++ memset(&sensor_mode_cmd, 0, cmd_len); ++ sensor_mode_cmd.sensor_mode = ipts->sensor_mode; ++ cmd_status = ipts_handle_cmd(ipts, ++ TOUCH_SENSOR_SET_MODE_CMD, ++ &sensor_mode_cmd, cmd_len); ++ break; ++ } ++ case TOUCH_SENSOR_SET_MODE_RSP: ++ { ++ touch_sensor_set_mem_window_cmd_data_t smw_cmd; ++ ++ if (rsp_status != 0) { ++ rsp_failed(ipts, cmd, rsp_status); ++ break; ++ } ++ ++ cmd_len = sizeof(touch_sensor_set_mem_window_cmd_data_t); ++ memset(&smw_cmd, 0, cmd_len); ++ ipts_get_set_mem_window_cmd_data(ipts, &smw_cmd); ++ cmd_status = ipts_handle_cmd(ipts, ++ TOUCH_SENSOR_SET_MEM_WINDOW_CMD, ++ &smw_cmd, cmd_len); ++ break; ++ } ++ case TOUCH_SENSOR_SET_MEM_WINDOW_RSP: ++ if (rsp_status != 0) { ++ rsp_failed(ipts, cmd, rsp_status); ++ break; ++ } ++ ++ cmd_status = ipts_send_sensor_hid_ready_for_data_cmd(ipts); ++ if (cmd_status) ++ break; ++ ++ if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID) { ++ ipts_set_state(ipts, IPTS_STA_HID_STARTED); ++ } else if (ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA) { ++ ipts_set_state(ipts, IPTS_STA_RAW_DATA_STARTED); ++ } ++ ++ ipts_err(ipts, "touch enabled %d\n", ipts_get_state(ipts)); ++ ++ break; ++ case TOUCH_SENSOR_HID_READY_FOR_DATA_RSP: ++ { ++ touch_sensor_hid_ready_for_data_rsp_data_t *hid_data; ++ ipts_state_t state; ++ ++ if (rsp_status != 0 && ++ rsp_status != TOUCH_STATUS_SENSOR_DISABLED) { ++ rsp_failed(ipts, cmd, rsp_status); ++ break; ++ } ++ ++ state = ipts_get_state(ipts); ++ if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID && ++ state == IPTS_STA_HID_STARTED) { ++ ++ hid_data = &m2h_msg->m2h_data.hid_ready_for_data_rsp_data; ++ ++ /* HID mode only uses buffer 0 */ ++ if (hid_data->touch_data_buffer_index != 0) ++ break; ++ ++ /* handle hid data */ ++ ipts_handle_hid_data(ipts, hid_data); ++ } ++ ++ break; ++ } ++ case TOUCH_SENSOR_FEEDBACK_READY_RSP: ++ if (rsp_status != 0 && ++ rsp_status != TOUCH_STATUS_COMPAT_CHECK_FAIL) { ++ rsp_failed(ipts, cmd, rsp_status); ++ break; ++ } ++ ++ if (m2h_msg->m2h_data.feedback_ready_rsp_data. ++ feedback_index == TOUCH_HID_2_ME_BUFFER_ID) ++ break; ++ ++ if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID) { ++ cmd_status = ipts_handle_cmd(ipts, ++ TOUCH_SENSOR_HID_READY_FOR_DATA_CMD, ++ NULL, 0); ++ } ++ ++ /* reset retry since we are getting touch data */ ++ ipts->retry = 0; ++ ++ break; ++ case TOUCH_SENSOR_QUIESCE_IO_RSP: ++ { ++ ipts_state_t state; ++ ++ if (rsp_status != 0) { ++ rsp_failed(ipts, cmd, rsp_status); ++ break; ++ } ++ ++ state = ipts_get_state(ipts); ++ if (state == IPTS_STA_STOPPING && ipts->restart) { ++ ipts_dbg(ipts, "restart\n"); ++ ipts_start(ipts); ++ ipts->restart = 0; ++ break; ++ } ++ ++ /* support sysfs debug node for switch sensor mode */ ++ if (ipts->switch_sensor_mode) { ++ ipts_set_state(ipts, IPTS_STA_INIT); ++ ipts->sensor_mode = ipts->new_sensor_mode; ++ ipts->switch_sensor_mode = false; ++ ++ ipts_send_sensor_clear_mem_window_cmd(ipts); ++ } ++ ++ break; ++ } ++ } ++ ++ /* handle error in rsp_status */ ++ if (rsp_status != 0) { ++ switch (rsp_status) { ++ case TOUCH_STATUS_SENSOR_EXPECTED_RESET: ++ case TOUCH_STATUS_SENSOR_UNEXPECTED_RESET: ++ ipts_dbg(ipts, "sensor reset %d\n", rsp_status); ++ ipts_restart(ipts); ++ break; ++ default: ++ ipts_dbg(ipts, "cmd : 0x%08x, status %d\n", ++ cmd, ++ rsp_status); ++ break; ++ } ++ } ++ ++ if (cmd_status) { ++ ipts_restart(ipts); ++ } ++ ++ return ret; ++} +diff --git a/drivers/misc/ipts/ipts-msg-handler.h b/drivers/misc/ipts/ipts-msg-handler.h +new file mode 100644 +index 0000000..b8e27d3 +--- /dev/null ++++ b/drivers/misc/ipts/ipts-msg-handler.h +@@ -0,0 +1,32 @@ ++/* ++ * ++ * Intel Precise Touch & Stylus ME message handler ++ * Copyright (c) 2016, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ */ ++ ++#ifndef _IPTS_MSG_HANDLER_H ++#define _IPTS_MSG_HANDLER_H ++ ++int ipts_handle_cmd(ipts_info_t *ipts, u32 cmd, void *data, int data_size); ++int ipts_start(ipts_info_t *ipts); ++void ipts_stop(ipts_info_t *ipts); ++int ipts_switch_sensor_mode(ipts_info_t *ipts, int new_sensor_mode); ++int ipts_handle_resp(ipts_info_t *ipts, touch_sensor_msg_m2h_t *m2h_msg, ++ u32 msg_len); ++int ipts_handle_processed_data(ipts_info_t *ipts); ++int ipts_send_feedback(ipts_info_t *ipts, int buffer_idx, u32 transaction_id); ++int ipts_send_sensor_quiesce_io_cmd(ipts_info_t *ipts); ++int ipts_send_sensor_hid_ready_for_data_cmd(ipts_info_t *ipts); ++int ipts_send_sensor_clear_mem_window_cmd(ipts_info_t *ipts); ++ ++#endif /* _IPTS_MSG_HANDLER_H */ +diff --git a/drivers/misc/ipts/ipts-resource.c b/drivers/misc/ipts/ipts-resource.c +new file mode 100644 +index 0000000..47607ef +--- /dev/null ++++ b/drivers/misc/ipts/ipts-resource.c +@@ -0,0 +1,277 @@ ++#include ++ ++#include "ipts.h" ++#include "ipts-mei-msgs.h" ++#include "ipts-kernel.h" ++ ++static void free_common_resource(ipts_info_t *ipts) ++{ ++ char *addr; ++ ipts_buffer_info_t *feedback_buffer; ++ dma_addr_t dma_addr; ++ u32 buffer_size; ++ int i, num_of_parallels; ++ ++ if (ipts->resource.me2hid_buffer) { ++ devm_kfree(&ipts->cldev->dev, ipts->resource.me2hid_buffer); ++ ipts->resource.me2hid_buffer = 0; ++ } ++ ++ addr = ipts->resource.hid2me_buffer.addr; ++ dma_addr = ipts->resource.hid2me_buffer.dma_addr; ++ buffer_size = ipts->resource.hid2me_buffer_size; ++ ++ if (ipts->resource.hid2me_buffer.addr) { ++ dmam_free_coherent(&ipts->cldev->dev, buffer_size, addr, dma_addr); ++ ipts->resource.hid2me_buffer.addr = 0; ++ ipts->resource.hid2me_buffer.dma_addr = 0; ++ ipts->resource.hid2me_buffer_size = 0; ++ } ++ ++ feedback_buffer = ipts->resource.feedback_buffer; ++ num_of_parallels = ipts_get_num_of_parallel_buffers(ipts); ++ for (i = 0; i < num_of_parallels; i++) { ++ if (feedback_buffer[i].addr) { ++ dmam_free_coherent(&ipts->cldev->dev, ++ ipts->device_info.feedback_size, ++ feedback_buffer[i].addr, ++ feedback_buffer[i].dma_addr); ++ feedback_buffer[i].addr = 0; ++ feedback_buffer[i].dma_addr = 0; ++ } ++ } ++} ++ ++static int allocate_common_resource(ipts_info_t *ipts) ++{ ++ char *addr, *me2hid_addr; ++ ipts_buffer_info_t *feedback_buffer; ++ dma_addr_t dma_addr; ++ int i, ret = 0, num_of_parallels; ++ u32 buffer_size; ++ ++ buffer_size = ipts->device_info.feedback_size; ++ ++ addr = dmam_alloc_coherent(&ipts->cldev->dev, ++ buffer_size, ++ &dma_addr, ++ GFP_ATOMIC|__GFP_ZERO); ++ if (addr == NULL) ++ return -ENOMEM; ++ ++ me2hid_addr = devm_kzalloc(&ipts->cldev->dev, buffer_size, GFP_KERNEL); ++ if (me2hid_addr == NULL) { ++ ret = -ENOMEM; ++ goto release_resource; ++ } ++ ++ ipts->resource.hid2me_buffer.addr = addr; ++ ipts->resource.hid2me_buffer.dma_addr = dma_addr; ++ ipts->resource.hid2me_buffer_size = buffer_size; ++ ipts->resource.me2hid_buffer = me2hid_addr; ++ ++ feedback_buffer = ipts->resource.feedback_buffer; ++ num_of_parallels = ipts_get_num_of_parallel_buffers(ipts); ++ for (i = 0; i < num_of_parallels; i++) { ++ feedback_buffer[i].addr = dmam_alloc_coherent(&ipts->cldev->dev, ++ ipts->device_info.feedback_size, ++ &feedback_buffer[i].dma_addr, ++ GFP_ATOMIC|__GFP_ZERO); ++ ++ if (feedback_buffer[i].addr == NULL) { ++ ret = -ENOMEM; ++ goto release_resource; ++ } ++ } ++ ++ return 0; ++ ++release_resource: ++ free_common_resource(ipts); ++ ++ return ret; ++} ++ ++void ipts_free_raw_data_resource(ipts_info_t *ipts) ++{ ++ if (ipts_is_raw_data_resource_ready(ipts)) { ++ ipts->resource.raw_data_resource_ready = false; ++ ++ ipts_release_kernels(ipts); ++ } ++} ++ ++static int allocate_hid_resource(ipts_info_t *ipts) ++{ ++ ipts_buffer_info_t *buffer_hid; ++ ++ /* hid mode uses only one touch data buffer */ ++ buffer_hid = &ipts->resource.touch_data_buffer_hid; ++ buffer_hid->addr = dmam_alloc_coherent(&ipts->cldev->dev, ++ ipts->device_info.frame_size, ++ &buffer_hid->dma_addr, ++ GFP_ATOMIC|__GFP_ZERO); ++ if (buffer_hid->addr == NULL) { ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static void free_hid_resource(ipts_info_t *ipts) ++{ ++ ipts_buffer_info_t *buffer_hid; ++ ++ buffer_hid = &ipts->resource.touch_data_buffer_hid; ++ if (buffer_hid->addr) { ++ dmam_free_coherent(&ipts->cldev->dev, ++ ipts->device_info.frame_size, ++ buffer_hid->addr, ++ buffer_hid->dma_addr); ++ buffer_hid->addr = 0; ++ buffer_hid->dma_addr = 0; ++ } ++} ++ ++int ipts_allocate_default_resource(ipts_info_t *ipts) ++{ ++ int ret; ++ ++ ret = allocate_common_resource(ipts); ++ if (ret) { ++ ipts_dbg(ipts, "cannot allocate common resource\n"); ++ return ret; ++ } ++ ++ ret = allocate_hid_resource(ipts); ++ if (ret) { ++ ipts_dbg(ipts, "cannot allocate hid resource\n"); ++ free_common_resource(ipts); ++ return ret; ++ } ++ ++ ipts->resource.default_resource_ready = true; ++ ++ return 0; ++} ++ ++void ipts_free_default_resource(ipts_info_t *ipts) ++{ ++ if (ipts_is_default_resource_ready(ipts)) { ++ ipts->resource.default_resource_ready = false; ++ ++ free_hid_resource(ipts); ++ free_common_resource(ipts); ++ } ++} ++ ++int ipts_allocate_raw_data_resource(ipts_info_t *ipts) ++{ ++ int ret = 0; ++ ++ ret = ipts_init_kernels(ipts); ++ if (ret) { ++ return ret; ++ } ++ ++ ipts->resource.raw_data_resource_ready = true; ++ ++ return 0; ++} ++ ++static void get_hid_only_smw_cmd_data(ipts_info_t *ipts, ++ touch_sensor_set_mem_window_cmd_data_t *data, ++ ipts_resource_t *resrc) ++{ ++ ipts_buffer_info_t *touch_buf; ++ ipts_buffer_info_t *feedback_buf; ++ ++ touch_buf = &resrc->touch_data_buffer_hid; ++ feedback_buf = &resrc->feedback_buffer[0]; ++ ++ data->touch_data_buffer_addr_lower[0] = ++ lower_32_bits(touch_buf->dma_addr); ++ data->touch_data_buffer_addr_upper[0] = ++ upper_32_bits(touch_buf->dma_addr); ++ data->feedback_buffer_addr_lower[0] = ++ lower_32_bits(feedback_buf->dma_addr); ++ data->feedback_buffer_addr_upper[0] = ++ upper_32_bits(feedback_buf->dma_addr); ++} ++ ++static void get_raw_data_only_smw_cmd_data(ipts_info_t *ipts, ++ touch_sensor_set_mem_window_cmd_data_t *data, ++ ipts_resource_t *resrc) ++{ ++ u64 wq_tail_phy_addr; ++ u64 cookie_phy_addr; ++ ipts_buffer_info_t *touch_buf; ++ ipts_buffer_info_t *feedback_buf; ++ int i, num_of_parallels; ++ ++ touch_buf = resrc->touch_data_buffer_raw; ++ feedback_buf = resrc->feedback_buffer; ++ ++ num_of_parallels = ipts_get_num_of_parallel_buffers(ipts); ++ for (i = 0; i < num_of_parallels; i++) { ++ data->touch_data_buffer_addr_lower[i] = ++ lower_32_bits(touch_buf[i].dma_addr); ++ data->touch_data_buffer_addr_upper[i] = ++ upper_32_bits(touch_buf[i].dma_addr); ++ data->feedback_buffer_addr_lower[i] = ++ lower_32_bits(feedback_buf[i].dma_addr); ++ data->feedback_buffer_addr_upper[i] = ++ upper_32_bits(feedback_buf[i].dma_addr); ++ } ++ ++ wq_tail_phy_addr = resrc->wq_info.wq_tail_phy_addr; ++ data->tail_offset_addr_lower = lower_32_bits(wq_tail_phy_addr); ++ data->tail_offset_addr_upper = upper_32_bits(wq_tail_phy_addr); ++ ++ cookie_phy_addr = resrc->wq_info.db_phy_addr + ++ resrc->wq_info.db_cookie_offset; ++ data->doorbell_cookie_addr_lower = lower_32_bits(cookie_phy_addr); ++ data->doorbell_cookie_addr_upper = upper_32_bits(cookie_phy_addr); ++ data->work_queue_size = resrc->wq_info.wq_size; ++ ++ data->work_queue_item_size = resrc->wq_item_size; ++} ++ ++void ipts_get_set_mem_window_cmd_data(ipts_info_t *ipts, ++ touch_sensor_set_mem_window_cmd_data_t *data) ++{ ++ ipts_resource_t *resrc = &ipts->resource; ++ ++ if (ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA) ++ get_raw_data_only_smw_cmd_data(ipts, data, resrc); ++ else if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID) ++ get_hid_only_smw_cmd_data(ipts, data, resrc); ++ ++ /* hid2me is common for "raw data" and "hid" */ ++ data->hid2me_buffer_addr_lower = ++ lower_32_bits(resrc->hid2me_buffer.dma_addr); ++ data->hid2me_buffer_addr_upper = ++ upper_32_bits(resrc->hid2me_buffer.dma_addr); ++ data->hid2me_buffer_size = resrc->hid2me_buffer_size; ++} ++ ++void ipts_set_input_buffer(ipts_info_t *ipts, int parallel_idx, ++ u8* cpu_addr, u64 dma_addr) ++{ ++ ipts_buffer_info_t *touch_buf; ++ ++ touch_buf = ipts->resource.touch_data_buffer_raw; ++ touch_buf[parallel_idx].dma_addr = dma_addr; ++ touch_buf[parallel_idx].addr = cpu_addr; ++} ++ ++void ipts_set_output_buffer(ipts_info_t *ipts, int parallel_idx, int output_idx, ++ u8* cpu_addr, u64 dma_addr) ++{ ++ ipts_buffer_info_t *output_buf; ++ ++ output_buf = &ipts->resource.raw_data_mode_output_buffer[parallel_idx][output_idx]; ++ ++ output_buf->dma_addr = dma_addr; ++ output_buf->addr = cpu_addr; ++} +diff --git a/drivers/misc/ipts/ipts-resource.h b/drivers/misc/ipts/ipts-resource.h +new file mode 100644 +index 0000000..7d66ac7 +--- /dev/null ++++ b/drivers/misc/ipts/ipts-resource.h +@@ -0,0 +1,30 @@ ++/* ++ * Intel Precise Touch & Stylus state codes ++ * ++ * Copyright (c) 2016, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ */ ++ ++#ifndef _IPTS_RESOURCE_H_ ++#define _IPTS_RESOURCE_H_ ++ ++int ipts_allocate_default_resource(ipts_info_t *ipts); ++void ipts_free_default_resource(ipts_info_t *ipts); ++int ipts_allocate_raw_data_resource(ipts_info_t *ipts); ++void ipts_free_raw_data_resource(ipts_info_t *ipts); ++void ipts_get_set_mem_window_cmd_data(ipts_info_t *ipts, ++ touch_sensor_set_mem_window_cmd_data_t *data); ++void ipts_set_input_buffer(ipts_info_t *ipts, int parallel_idx, ++ u8* cpu_addr, u64 dma_addr); ++void ipts_set_output_buffer(ipts_info_t *ipts, int parallel_idx, int output_idx, ++ u8* cpu_addr, u64 dma_addr); ++ ++#endif // _IPTS_RESOURCE_H_ +diff --git a/drivers/misc/ipts/ipts-sensor-regs.h b/drivers/misc/ipts/ipts-sensor-regs.h +new file mode 100644 +index 0000000..96812b0 +--- /dev/null ++++ b/drivers/misc/ipts/ipts-sensor-regs.h +@@ -0,0 +1,700 @@ ++/* ++ * Touch Sensor Register definition ++ * ++ * Copyright (c) 2013-2016, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ */ ++ ++ ++#ifndef _TOUCH_SENSOR_REGS_H ++#define _TOUCH_SENSOR_REGS_H ++ ++#pragma pack(1) ++ ++// define C_ASSERT macro to check structure size and fail compile for unexpected mismatch ++#ifndef C_ASSERT ++#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] ++#endif ++ ++// ++// Compatibility versions for this header file ++// ++#define TOUCH_EDS_REV_MINOR 0 ++#define TOUCH_EDS_REV_MAJOR 1 ++#define TOUCH_EDS_INTF_REV 1 ++#define TOUCH_PROTOCOL_VER 0 ++ ++ ++// ++// Offset 00h: TOUCH_STS: Status Register ++// This register is read by the SPI Controller immediately following an interrupt. ++// ++#define TOUCH_STS_REG_OFFSET 0x00 ++ ++typedef enum touch_sts_reg_int_type ++{ ++ TOUCH_STS_REG_INT_TYPE_DATA_AVAIL = 0, // Touch Data Available ++ TOUCH_STS_REG_INT_TYPE_RESET_OCCURRED, // Reset Occurred ++ TOUCH_STS_REG_INT_TYPE_ERROR_OCCURRED, // Error Occurred ++ TOUCH_STS_REG_INT_TYPE_VENDOR_DATA, // Vendor specific data, treated same as raw frame ++ TOUCH_STS_REG_INT_TYPE_GET_FEATURES, // Get Features response data available ++ TOUCH_STS_REG_INT_TYPE_MAX ++} touch_sts_reg_int_type_t; ++C_ASSERT(sizeof(touch_sts_reg_int_type_t) == 4); ++ ++typedef enum touch_sts_reg_pwr_state ++{ ++ TOUCH_STS_REG_PWR_STATE_SLEEP = 0, // Sleep ++ TOUCH_STS_REG_PWR_STATE_DOZE, // Doze ++ TOUCH_STS_REG_PWR_STATE_ARMED, // Armed ++ TOUCH_STS_REG_PWR_STATE_SENSING, // Sensing ++ TOUCH_STS_REG_PWR_STATE_MAX ++} touch_sts_reg_pwr_state_t; ++C_ASSERT(sizeof(touch_sts_reg_pwr_state_t) == 4); ++ ++typedef enum touch_sts_reg_init_state ++{ ++ TOUCH_STS_REG_INIT_STATE_READY_FOR_OP = 0, // Ready for normal operation ++ TOUCH_STS_REG_INIT_STATE_FW_NEEDED, // Touch IC needs its Firmware loaded ++ TOUCH_STS_REG_INIT_STATE_DATA_NEEDED, // Touch IC needs its Data loaded ++ TOUCH_STS_REG_INIT_STATE_INIT_ERROR, // Error info in TOUCH_ERR_REG ++ TOUCH_STS_REG_INIT_STATE_MAX ++} touch_sts_reg_init_state_t; ++C_ASSERT(sizeof(touch_sts_reg_init_state_t) == 4); ++ ++#define TOUCH_SYNC_BYTE_VALUE 0x5A ++ ++typedef union touch_sts_reg ++{ ++ u32 reg_value; ++ ++ struct ++ { ++ // When set, this indicates the hardware has data that needs to be read. ++ u32 int_status :1; ++ // see TOUCH_STS_REG_INT_TYPE ++ u32 int_type :4; ++ // see TOUCH_STS_REG_PWR_STATE ++ u32 pwr_state :2; ++ // see TOUCH_STS_REG_INIT_STATE ++ u32 init_state :2; ++ // Busy bit indicates that sensor cannot accept writes at this time ++ u32 busy :1; ++ // Reserved ++ u32 reserved :14; ++ // Synchronization bit, should always be TOUCH_SYNC_BYTE_VALUE ++ u32 sync_byte :8; ++ } fields; ++} touch_sts_reg_t; ++C_ASSERT(sizeof(touch_sts_reg_t) == 4); ++ ++ ++// ++// Offset 04h: TOUCH_FRAME_CHAR: Frame Characteristics Register ++// This registers describes the characteristics of each data frame read by the SPI Controller in ++// response to a touch interrupt. ++// ++#define TOUCH_FRAME_CHAR_REG_OFFSET 0x04 ++ ++typedef union touch_frame_char_reg ++{ ++ u32 reg_value; ++ ++ struct ++ { ++ // Micro-Frame Size (MFS): Indicates the size of a touch micro-frame in byte increments. ++ // When a micro-frame is to be read for processing (in data mode), this is the total number of ++ // bytes that must be read per interrupt, split into multiple read commands no longer than RPS. ++ // Maximum micro-frame size is 256KB. ++ u32 microframe_size :18; ++ // Micro-Frames per Frame (MFPF): Indicates the number of micro-frames per frame. If a ++ // sensor's frame does not contain micro-frames this value will be 1. Valid values are 1-31. ++ u32 microframes_per_frame :5; ++ // Micro-Frame Index (MFI): Indicates the index of the micro-frame within a frame. This allows ++ // the SPI Controller to maintain synchronization with the sensor and determine when the final ++ // micro-frame has arrived. Valid values are 1-31. ++ u32 microframe_index :5; ++ // HID/Raw Data: This bit describes whether the data from the sensor is Raw data or a HID ++ // report. When set, the data is a HID report. ++ u32 hid_report :1; ++ // Reserved ++ u32 reserved :3; ++ } fields; ++} touch_frame_char_reg_t; ++C_ASSERT(sizeof(touch_frame_char_reg_t) == 4); ++ ++ ++// ++// Offset 08h: Touch Error Register ++// ++#define TOUCH_ERR_REG_OFFSET 0x08 ++ ++// bit definition is vendor specific ++typedef union touch_err_reg ++{ ++ u32 reg_value; ++ ++ struct ++ { ++ u32 invalid_fw :1; ++ u32 invalid_data :1; ++ u32 self_test_failed :1; ++ u32 reserved :12; ++ u32 fatal_error :1; ++ u32 vendor_errors :16; ++ } fields; ++} touch_err_reg_t; ++C_ASSERT(sizeof(touch_err_reg_t) == 4); ++ ++ ++// ++// Offset 0Ch: RESERVED ++// This register is reserved for future use. ++// ++ ++ ++// ++// Offset 10h: Touch Identification Register ++// ++#define TOUCH_ID_REG_OFFSET 0x10 ++ ++#define TOUCH_ID_REG_VALUE 0x43495424 ++ ++// expected value is "$TIC" or 0x43495424 ++typedef u32 touch_id_reg_t; ++C_ASSERT(sizeof(touch_id_reg_t) == 4); ++ ++ ++// ++// Offset 14h: TOUCH_DATA_SZ: Touch Data Size Register ++// This register describes the maximum size of frames and feedback data ++// ++#define TOUCH_DATA_SZ_REG_OFFSET 0x14 ++ ++#define TOUCH_MAX_FRAME_SIZE_INCREMENT 64 ++#define TOUCH_MAX_FEEDBACK_SIZE_INCREMENT 64 ++ ++#define TOUCH_SENSOR_MAX_FRAME_SIZE (32 * 1024) // Max allowed frame size 32KB ++#define TOUCH_SENSOR_MAX_FEEDBACK_SIZE (16 * 1024) // Max allowed feedback size 16KB ++ ++typedef union touch_data_sz_reg ++{ ++ u32 reg_value; ++ ++ struct ++ { ++ // This value describes the maximum frame size in 64byte increments. ++ u32 max_frame_size :12; ++ // This value describes the maximum feedback size in 64byte increments. ++ u32 max_feedback_size :8; ++ // Reserved ++ u32 reserved :12; ++ } fields; ++} touch_data_sz_reg_t; ++C_ASSERT(sizeof(touch_data_sz_reg_t) == 4); ++ ++ ++// ++// Offset 18h: TOUCH_CAPABILITIES: Touch Capabilities Register ++// This register informs the host as to the capabilities of the touch IC. ++// ++#define TOUCH_CAPS_REG_OFFSET 0x18 ++ ++typedef enum touch_caps_reg_read_delay_time ++{ ++ TOUCH_CAPS_REG_READ_DELAY_TIME_0, ++ TOUCH_CAPS_REG_READ_DELAY_TIME_10uS, ++ TOUCH_CAPS_REG_READ_DELAY_TIME_50uS, ++ TOUCH_CAPS_REG_READ_DELAY_TIME_100uS, ++ TOUCH_CAPS_REG_READ_DELAY_TIME_150uS, ++ TOUCH_CAPS_REG_READ_DELAY_TIME_250uS, ++ TOUCH_CAPS_REG_READ_DELAY_TIME_500uS, ++ TOUCH_CAPS_REG_READ_DELAY_TIME_1mS, ++} touch_caps_reg_read_delay_time_t; ++C_ASSERT(sizeof(touch_caps_reg_read_delay_time_t) == 4); ++ ++#define TOUCH_BULK_DATA_MAX_WRITE_INCREMENT 64 ++ ++typedef union touch_caps_reg ++{ ++ u32 reg_value; ++ ++ struct ++ { ++ // Reserved for future frequency ++ u32 reserved0 :1; ++ // 17 MHz (14 MHz on Atom) Supported: 0b - Not supported, 1b - Supported ++ u32 supported_17Mhz :1; ++ // 30 MHz (25MHz on Atom) Supported: 0b - Not supported, 1b - Supported ++ u32 supported_30Mhz :1; ++ // 50 MHz Supported: 0b - Not supported, 1b - Supported ++ u32 supported_50Mhz :1; ++ // Reserved ++ u32 reserved1 :4; ++ // Single I/O Supported: 0b - Not supported, 1b - Supported ++ u32 supported_single_io :1; ++ // Dual I/O Supported: 0b - Not supported, 1b - Supported ++ u32 supported_dual_io :1; ++ // Quad I/O Supported: 0b - Not supported, 1b - Supported ++ u32 supported_quad_io :1; ++ // Bulk Data Area Max Write Size: The amount of data the SPI Controller can write to the bulk ++ // data area before it has to poll the busy bit. This field is in multiples of 64 bytes. The ++ // SPI Controller will write the amount of data specified in this field, then check and wait ++ // for the Status.Busy bit to be zero before writing the next data chunk. This field is 6 bits ++ // long, allowing for 4KB of contiguous writes w/o a poll of the busy bit. If this field is ++ // 0x00 the Touch IC has no limit in the amount of data the SPI Controller can write to the ++ // bulk data area. ++ u32 bulk_data_max_write :6; ++ // Read Delay Timer Value: This field describes the delay the SPI Controller will initiate when ++ // a read interrupt follows a write data command. Uses values from TOUCH_CAPS_REG_READ_DELAY_TIME ++ u32 read_delay_timer_value :3; ++ // Reserved ++ u32 reserved2 :4; ++ // Maximum Touch Points: A byte value based on the HID descriptor definition. ++ u32 max_touch_points :8; ++ } fields; ++} touch_caps_reg_t; ++C_ASSERT(sizeof(touch_caps_reg_t) == 4); ++ ++ ++// ++// Offset 1Ch: TOUCH_CFG: Touch Configuration Register ++// This register allows the SPI Controller to configure the touch sensor as needed during touch ++// operations. ++// ++#define TOUCH_CFG_REG_OFFSET 0x1C ++ ++typedef enum touch_cfg_reg_bulk_xfer_size ++{ ++ TOUCH_CFG_REG_BULK_XFER_SIZE_4B = 0, // Bulk Data Transfer Size is 4 bytes ++ TOUCH_CFG_REG_BULK_XFER_SIZE_8B, // Bulk Data Transfer Size is 8 bytes ++ TOUCH_CFG_REG_BULK_XFER_SIZE_16B, // Bulk Data Transfer Size is 16 bytes ++ TOUCH_CFG_REG_BULK_XFER_SIZE_32B, // Bulk Data Transfer Size is 32 bytes ++ TOUCH_CFG_REG_BULK_XFER_SIZE_64B, // Bulk Data Transfer Size is 64 bytes ++ TOUCH_CFG_REG_BULK_XFER_SIZE_MAX ++} touch_cfg_reg_bulk_xfer_size_t; ++C_ASSERT(sizeof(touch_cfg_reg_bulk_xfer_size_t) == 4); ++ ++// Frequency values used by TOUCH_CFG_REG and TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA. ++typedef enum touch_freq ++{ ++ TOUCH_FREQ_RSVD = 0, // Reserved value ++ TOUCH_FREQ_17MHZ, // Sensor set for 17MHz operation (14MHz on Atom) ++ TOUCH_FREQ_30MHZ, // Sensor set for 30MHz operation (25MHz on Atom) ++ TOUCH_FREQ_MAX // Invalid value ++} touch_freq_t; ++C_ASSERT(sizeof(touch_freq_t) == 4); ++ ++typedef union touch_cfg_reg ++{ ++ u32 reg_value; ++ ++ struct ++ { ++ // Touch Enable (TE): This bit is used as a HW semaphore for the Touch IC to guarantee to the ++ // SPI Controller to that (when 0) no sensing operations will occur and only the Reset ++ // interrupt will be generated. When TE is cleared by the SPI Controller: ++ // - TICs must flush all output buffers ++ // - TICs must De-assert any pending interrupt ++ // - ME must throw away any partial frame and pending interrupt must be cleared/not serviced. ++ // The SPI Controller will only modify the configuration of the TIC when TE is cleared. TE is ++ // defaulted to 0h on a power-on reset. ++ u32 touch_enable :1; ++ // Data/HID Packet Mode (DHPM): Raw Data Mode: 0h, HID Packet Mode: 1h ++ u32 dhpm :1; ++ // Bulk Data Transfer Size: This field represents the amount of data written to the Bulk Data ++ // Area (SPI Offset 0x1000-0x2FFF) in a single SPI write protocol ++ u32 bulk_xfer_size :4; ++ // Frequency Select: Frequency for the TouchIC to run at. Use values from TOUCH_FREQ ++ u32 freq_select :3; ++ // Reserved ++ u32 reserved :23; ++ } fields; ++} touch_cfg_reg_t; ++C_ASSERT(sizeof(touch_cfg_reg_t) == 4); ++ ++ ++// ++// Offset 20h: TOUCH_CMD: Touch Command Register ++// This register is used for sending commands to the Touch IC. ++// ++#define TOUCH_CMD_REG_OFFSET 0x20 ++ ++typedef enum touch_cmd_reg_code ++{ ++ TOUCH_CMD_REG_CODE_NOP = 0, // No Operation ++ TOUCH_CMD_REG_CODE_SOFT_RESET, // Soft Reset ++ TOUCH_CMD_REG_CODE_PREP_4_READ, // Prepare All Registers for Read ++ TOUCH_CMD_REG_CODE_GEN_TEST_PACKETS, // Generate Test Packets according to value in TOUCH_TEST_CTRL_REG ++ TOUCH_CMD_REG_CODE_MAX ++} touch_cmd_reg_code_t; ++C_ASSERT(sizeof(touch_cmd_reg_code_t) == 4); ++ ++typedef union touch_cmd_reg ++{ ++ u32 reg_value; ++ ++ struct ++ { ++ // Command Code: See TOUCH_CMD_REG_CODE ++ u32 command_code :8; ++ // Reserved ++ u32 reserved :24; ++ } fields; ++} touch_cmd_reg_t; ++C_ASSERT(sizeof(touch_cmd_reg_t) == 4); ++ ++ ++// ++// Offset 24h: Power Management Control ++// This register is used for active power management. The Touch IC is allowed to mover from Doze or ++// Armed to Sensing after a touch has occurred. All other transitions will be made at the request ++// of the SPI Controller. ++// ++#define TOUCH_PWR_MGMT_CTRL_REG_OFFSET 0x24 ++ ++typedef enum touch_pwr_mgmt_ctrl_reg_cmd ++{ ++ TOUCH_PWR_MGMT_CTRL_REG_CMD_NOP = 0, // No change to power state ++ TOUCH_PWR_MGMT_CTRL_REG_CMD_SLEEP, // Sleep - set when the system goes into connected standby ++ TOUCH_PWR_MGMT_CTRL_REG_CMD_DOZE, // Doze - set after 300 seconds of inactivity ++ TOUCH_PWR_MGMT_CTRL_REG_CMD_ARMED, // Armed - Set by FW when a "finger off" message is received from the EUs ++ TOUCH_PWR_MGMT_CTRL_REG_CMD_SENSING, // Sensing - not typically set by FW ++ TOUCH_PWR_MGMT_CTRL_REG_CMD_MAX // Values will result in no change to the power state of the Touch IC ++} touch_pwr_mgmt_ctrl_reg_cmd_t; ++C_ASSERT(sizeof(touch_pwr_mgmt_ctrl_reg_cmd_t) == 4); ++ ++typedef union touch_pwr_mgmt_ctrl_reg ++{ ++ u32 reg_value; ++ ++ struct ++ { ++ // Power State Command: See TOUCH_PWR_MGMT_CTRL_REG_CMD ++ u32 pwr_state_cmd :3; ++ // Reserved ++ u32 reserved :29; ++ } fields; ++} touch_pwr_mgmt_ctrl_reg_t; ++C_ASSERT(sizeof(touch_pwr_mgmt_ctrl_reg_t) == 4); ++ ++ ++// ++// Offset 28h: Vendor HW Information Register ++// This register is used to relay Intel-assigned vendor ID information to the SPI Controller, which ++// may be forwarded to SW running on the host CPU. ++// ++#define TOUCH_VEN_HW_INFO_REG_OFFSET 0x28 ++ ++typedef union touch_ven_hw_info_reg ++{ ++ u32 reg_value; ++ ++ struct ++ { ++ // Touch Sensor Vendor ID ++ u32 vendor_id :16; ++ // Touch Sensor Device ID ++ u32 device_id :16; ++ } fields; ++} touch_ven_hw_info_reg_t; ++C_ASSERT(sizeof(touch_ven_hw_info_reg_t) == 4); ++ ++ ++// ++// Offset 2Ch: HW Revision ID Register ++// This register is used to relay vendor HW revision information to the SPI Controller which may be ++// forwarded to SW running on the host CPU. ++// ++#define TOUCH_HW_REV_REG_OFFSET 0x2C ++ ++typedef u32 touch_hw_rev_reg_t; // bit definition is vendor specific ++C_ASSERT(sizeof(touch_hw_rev_reg_t) == 4); ++ ++ ++// ++// Offset 30h: FW Revision ID Register ++// This register is used to relay vendor FW revision information to the SPI Controller which may be ++// forwarded to SW running on the host CPU. ++// ++#define TOUCH_FW_REV_REG_OFFSET 0x30 ++ ++typedef u32 touch_fw_rev_reg_t; // bit definition is vendor specific ++C_ASSERT(sizeof(touch_fw_rev_reg_t) == 4); ++ ++ ++// ++// Offset 34h: Compatibility Revision ID Register ++// This register is used to relay vendor compatibility information to the SPI Controller which may ++// be forwarded to SW running on the host CPU. Compatibility Information is a numeric value given ++// by Intel to the Touch IC vendor based on the major and minor revision of the EDS supported. From ++// a nomenclature point of view in an x.y revision number of the EDS, the major version is the value ++// of x and the minor version is the value of y. For example, a Touch IC supporting an EDS version ++// of 0.61 would contain a major version of 0 and a minor version of 61 in the register. ++// ++#define TOUCH_COMPAT_REV_REG_OFFSET 0x34 ++ ++typedef union touch_compat_rev_reg ++{ ++ u32 reg_value; ++ ++ struct ++ { ++ // EDS Minor Revision ++ u8 minor; ++ // EDS Major Revision ++ u8 major; ++ // Interface Revision Number (from EDS) ++ u8 intf_rev; ++ // EU Kernel Compatibility Version - vendor specific value ++ u8 kernel_compat_ver; ++ } fields; ++} touch_compat_rev_reg_t; ++C_ASSERT(sizeof(touch_compat_rev_reg_t) == 4); ++ ++ ++// ++// Touch Register Block is the full set of registers from offset 0x00h to 0x3F ++// This is the entire set of registers needed for normal touch operation. It does not include test ++// registers such as TOUCH_TEST_CTRL_REG ++// ++#define TOUCH_REG_BLOCK_OFFSET TOUCH_STS_REG_OFFSET ++ ++typedef struct touch_reg_block ++{ ++ touch_sts_reg_t sts_reg; // 0x00 ++ touch_frame_char_reg_t frame_char_reg; // 0x04 ++ touch_err_reg_t error_reg; // 0x08 ++ u32 reserved0; // 0x0C ++ touch_id_reg_t id_reg; // 0x10 ++ touch_data_sz_reg_t data_size_reg; // 0x14 ++ touch_caps_reg_t caps_reg; // 0x18 ++ touch_cfg_reg_t cfg_reg; // 0x1C ++ touch_cmd_reg_t cmd_reg; // 0x20 ++ touch_pwr_mgmt_ctrl_reg_t pwm_mgme_ctrl_reg; // 0x24 ++ touch_ven_hw_info_reg_t ven_hw_info_reg; // 0x28 ++ touch_hw_rev_reg_t hw_rev_reg; // 0x2C ++ touch_fw_rev_reg_t fw_rev_reg; // 0x30 ++ touch_compat_rev_reg_t compat_rev_reg; // 0x34 ++ u32 reserved1; // 0x38 ++ u32 reserved2; // 0x3C ++} touch_reg_block_t; ++C_ASSERT(sizeof(touch_reg_block_t) == 64); ++ ++ ++// ++// Offset 40h: Test Control Register ++// This register ++// ++#define TOUCH_TEST_CTRL_REG_OFFSET 0x40 ++ ++typedef union touch_test_ctrl_reg ++{ ++ u32 reg_value; ++ ++ struct ++ { ++ // Size of Test Frame in Raw Data Mode: This field specifies the test frame size in raw data ++ // mode in multiple of 64 bytes. For example, if this field value is 16, the test frame size ++ // will be 16x64 = 1K. ++ u32 raw_test_frame_size :16; ++ // Number of Raw Data Frames or HID Report Packets Generation. This field represents the number ++ // of test frames or HID reports to be generated when test mode is enabled. When multiple ++ // packets/frames are generated, they need be generated at 100 Hz frequency, i.e. 10ms per ++ // packet/frame. ++ u32 num_test_frames :16; ++ } fields; ++} touch_test_ctrl_reg_t; ++C_ASSERT(sizeof(touch_test_ctrl_reg_t) == 4); ++ ++ ++// ++// Offsets 0x000 to 0xFFF are reserved for Intel-defined Registers ++// ++#define TOUCH_REGISTER_LIMIT 0xFFF ++ ++ ++// ++// Data Window: Address 0x1000-0x1FFFF ++// The data window is reserved for writing and reading large quantities of data to and from the ++// sensor. ++// ++#define TOUCH_DATA_WINDOW_OFFSET 0x1000 ++#define TOUCH_DATA_WINDOW_LIMIT 0x1FFFF ++ ++#define TOUCH_SENSOR_MAX_OFFSET TOUCH_DATA_WINDOW_LIMIT ++ ++ ++// ++// The following data structures represent the headers defined in the Data Structures chapter of the ++// Intel Integrated Touch EDS ++// ++ ++// Enumeration used in TOUCH_RAW_DATA_HDR ++typedef enum touch_raw_data_types ++{ ++ TOUCH_RAW_DATA_TYPE_FRAME = 0, ++ TOUCH_RAW_DATA_TYPE_ERROR, // RawData will be the TOUCH_ERROR struct below ++ TOUCH_RAW_DATA_TYPE_VENDOR_DATA, // Set when InterruptType is Vendor Data ++ TOUCH_RAW_DATA_TYPE_HID_REPORT, ++ TOUCH_RAW_DATA_TYPE_GET_FEATURES, ++ TOUCH_RAW_DATA_TYPE_MAX ++} touch_raw_data_types_t; ++C_ASSERT(sizeof(touch_raw_data_types_t) == 4); ++ ++// Private data structure. Kernels must copy to HID driver buffer ++typedef struct touch_hid_private_data ++{ ++ u32 transaction_id; ++ u8 reserved[28]; ++} touch_hid_private_data_t; ++C_ASSERT(sizeof(touch_hid_private_data_t) == 32); ++ ++// This is the data structure sent from the PCH FW to the EU kernel ++typedef struct touch_raw_data_hdr ++{ ++ u32 data_type; // use values from TOUCH_RAW_DATA_TYPES ++ u32 raw_data_size_bytes; // The size in bytes of the raw data read from the ++ // sensor, does not include TOUCH_RAW_DATA_HDR. Will ++ // be the sum of all uFrames, or size of TOUCH_ERROR ++ // for if DataType is TOUCH_RAW_DATA_TYPE_ERROR ++ u32 buffer_id; // An ID to qualify with the feedback data to track ++ // buffer usage ++ u32 protocol_ver; // Must match protocol version of the EDS ++ u8 kernel_compat_id; // Copied from the Compatibility Revision ID Reg ++ u8 reserved[15]; // Padding to extend header to full 64 bytes and ++ // allow for growth ++ touch_hid_private_data_t hid_private_data; // Private data structure. Kernels must copy to HID ++ // driver buffer ++} touch_raw_data_hdr_t; ++C_ASSERT(sizeof(touch_raw_data_hdr_t) == 64); ++ ++typedef struct touch_raw_data ++{ ++ touch_raw_data_hdr_t header; ++ u8 raw_data[1]; // used to access the raw data as an array and keep the ++ // compilers happy. Actual size of this array is ++ // Header.RawDataSizeBytes ++} touch_raw_data_t; ++ ++ ++// The following section describes the data passed in TOUCH_RAW_DATA.RawData when DataType equals ++// TOUCH_RAW_DATA_TYPE_ERROR ++// Note: This data structure is also applied to HID mode ++typedef enum touch_err_types ++{ ++ TOUCH_RAW_DATA_ERROR = 0, ++ TOUCH_RAW_ERROR_MAX ++} touch_err_types_t; ++C_ASSERT(sizeof(touch_err_types_t) == 4); ++ ++typedef union touch_me_fw_error ++{ ++ u32 value; ++ ++ struct ++ { ++ u32 invalid_frame_characteristics : 1; ++ u32 microframe_index_invalid : 1; ++ u32 reserved : 30; ++ } fields; ++} touch_me_fw_error_t; ++C_ASSERT(sizeof(touch_me_fw_error_t) == 4); ++ ++typedef struct touch_error ++{ ++ u8 touch_error_type; // This must be a value from TOUCH_ERROR_TYPES ++ u8 reserved[3]; ++ touch_me_fw_error_t touch_me_fw_error; ++ touch_err_reg_t touch_error_register; // Contains the value copied from the Touch Error Reg ++} touch_error_t; ++C_ASSERT(sizeof(touch_error_t) == 12); ++ ++// Enumeration used in TOUCH_FEEDBACK_BUFFER ++typedef enum touch_feedback_cmd_types ++{ ++ TOUCH_FEEDBACK_CMD_TYPE_NONE = 0, ++ TOUCH_FEEDBACK_CMD_TYPE_SOFT_RESET, ++ TOUCH_FEEDBACK_CMD_TYPE_GOTO_ARMED, ++ TOUCH_FEEDBACK_CMD_TYPE_GOTO_SENSING, ++ TOUCH_FEEDBACK_CMD_TYPE_GOTO_SLEEP, ++ TOUCH_FEEDBACK_CMD_TYPE_GOTO_DOZE, ++ TOUCH_FEEDBACK_CMD_TYPE_HARD_RESET, ++ TOUCH_FEEDBACK_CMD_TYPE_MAX ++} touch_feedback_cmd_types_t; ++C_ASSERT(sizeof(touch_feedback_cmd_types_t) == 4); ++ ++// Enumeration used in TOUCH_FEEDBACK_HDR ++typedef enum touch_feedback_data_types ++{ ++ TOUCH_FEEDBACK_DATA_TYPE_FEEDBACK = 0, // This is vendor specific feedback to be written to the sensor ++ TOUCH_FEEDBACK_DATA_TYPE_SET_FEATURES, // This is a set features command to be written to the sensor ++ TOUCH_FEEDBACK_DATA_TYPE_GET_FEATURES, // This is a get features command to be written to the sensor ++ TOUCH_FEEDBACK_DATA_TYPE_OUTPUT_REPORT, // This is a HID output report to be written to the sensor ++ TOUCH_FEEDBACK_DATA_TYPE_STORE_DATA, // This is calibration data to be written to system flash ++ TOUCH_FEEDBACK_DATA_TYPE_MAX ++} touch_feedback_data_types_t; ++C_ASSERT(sizeof(touch_feedback_data_types_t) == 4); ++ ++// This is the data structure sent from the EU kernels back to the ME FW. ++// In addition to "feedback" data, the FW can execute a "command" described by the command type parameter. ++// Any payload data will always be sent to the TIC first, then any command will be issued. ++typedef struct touch_feedback_hdr ++{ ++ u32 feedback_cmd_type; // use values from TOUCH_FEEDBACK_CMD_TYPES ++ u32 payload_size_bytes; // The amount of data to be written to the sensor, not including the header ++ u32 buffer_id; // The ID of the raw data buffer that generated this feedback data ++ u32 protocol_ver; // Must match protocol version of the EDS ++ u32 feedback_data_type; // use values from TOUCH_FEEDBACK_DATA_TYPES. This is not relevant if PayloadSizeBytes is 0 ++ u32 spi_offest; // The offset from TOUCH_DATA_WINDOW_OFFSET at which to write the Payload data. Maximum offset is 0x1EFFF. ++ u8 reserved[40]; // Padding to extend header to full 64 bytes and allow for growth ++} touch_feedback_hdr_t; ++C_ASSERT(sizeof(touch_feedback_hdr_t) == 64); ++ ++typedef struct touch_feedback_buffer ++{ ++ touch_feedback_hdr_t Header; ++ u8 feedback_data[1]; // used to access the feedback data as an array and keep the compilers happy. Actual size of this array is Header.PayloadSizeBytes ++} touch_feedback_buffer_t; ++ ++ ++// ++// This data structure describes the header prepended to all data ++// written to the touch IC at the bulk data write (TOUCH_DATA_WINDOW_OFFSET + TOUCH_FEEDBACK_HDR.SpiOffest) address. ++typedef enum touch_write_data_type ++{ ++ TOUCH_WRITE_DATA_TYPE_FW_LOAD = 0, ++ TOUCH_WRITE_DATA_TYPE_DATA_LOAD, ++ TOUCH_WRITE_DATA_TYPE_FEEDBACK, ++ TOUCH_WRITE_DATA_TYPE_SET_FEATURES, ++ TOUCH_WRITE_DATA_TYPE_GET_FEATURES, ++ TOUCH_WRITE_DATA_TYPE_OUTPUT_REPORT, ++ TOUCH_WRITE_DATA_TYPE_NO_DATA_USE_DEFAULTS, ++ TOUCH_WRITE_DATA_TYPE_MAX ++} touch_write_data_type_t; ++C_ASSERT(sizeof(touch_write_data_type_t) == 4); ++ ++typedef struct touch_write_hdr ++{ ++ u32 write_data_type; // Use values from TOUCH_WRITE_DATA_TYPE ++ u32 write_data_len; // This field designates the amount of data to follow ++} touch_write_hdr_t; ++C_ASSERT(sizeof(touch_write_hdr_t) == 8); ++ ++typedef struct touch_write_data ++{ ++ touch_write_hdr_t header; ++ u8 write_data[1]; // used to access the write data as an array and keep the compilers happy. Actual size of this array is Header.WriteDataLen ++} touch_write_data_t; ++ ++#pragma pack() ++ ++#endif // _TOUCH_SENSOR_REGS_H +diff --git a/drivers/misc/ipts/ipts-state.h b/drivers/misc/ipts/ipts-state.h +new file mode 100644 +index 0000000..39a2eaf +--- /dev/null ++++ b/drivers/misc/ipts/ipts-state.h +@@ -0,0 +1,29 @@ ++/* ++ * Intel Precise Touch & Stylus state codes ++ * ++ * Copyright (c) 2016, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ */ ++ ++#ifndef _IPTS_STATE_H_ ++#define _IPTS_STATE_H_ ++ ++/* ipts driver states */ ++typedef enum ipts_state { ++ IPTS_STA_NONE, ++ IPTS_STA_INIT, ++ IPTS_STA_RESOURCE_READY, ++ IPTS_STA_HID_STARTED, ++ IPTS_STA_RAW_DATA_STARTED, ++ IPTS_STA_STOPPING ++} ipts_state_t; ++ ++#endif // _IPTS_STATE_H_ +diff --git a/drivers/misc/ipts/ipts.h b/drivers/misc/ipts/ipts.h +new file mode 100644 +index 0000000..1fcd021 +--- /dev/null ++++ b/drivers/misc/ipts/ipts.h +@@ -0,0 +1,200 @@ ++/* ++ * ++ * Intel Management Engine Interface (Intel MEI) Client Driver for IPTS ++ * Copyright (c) 2016, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ */ ++ ++#ifndef _IPTS_H_ ++#define _IPTS_H_ ++ ++#include ++#include ++#include ++#include ++ ++#include "ipts-mei-msgs.h" ++#include "ipts-state.h" ++#include "ipts-binary-spec.h" ++ ++//#define ENABLE_IPTS_DEBUG /* enable IPTS debug */ ++ ++#ifdef ENABLE_IPTS_DEBUG ++ ++#define ipts_info(ipts, format, arg...) do {\ ++ dev_info(&ipts->cldev->dev, format, ##arg);\ ++} while (0) ++ ++#define ipts_dbg(ipts, format, arg...) do {\ ++ dev_info(&ipts->cldev->dev, format, ##arg);\ ++} while (0) ++ ++//#define RUN_DBG_THREAD ++ ++#else ++ ++#define ipts_info(ipts, format, arg...) do {} while(0); ++#define ipts_dbg(ipts, format, arg...) do {} while(0); ++ ++#endif ++ ++#define ipts_err(ipts, format, arg...) do {\ ++ dev_err(&ipts->cldev->dev, format, ##arg);\ ++} while (0) ++ ++#define HID_PARALLEL_DATA_BUFFERS TOUCH_SENSOR_MAX_DATA_BUFFERS ++ ++#define IPTS_MAX_RETRY 3 ++ ++typedef struct ipts_buffer_info { ++ char *addr; ++ dma_addr_t dma_addr; ++} ipts_buffer_info_t; ++ ++typedef struct ipts_gfx_info { ++ u64 gfx_handle; ++ intel_ipts_ops_t ipts_ops; ++} ipts_gfx_info_t; ++ ++typedef struct ipts_resource { ++ /* ME & Gfx resource */ ++ ipts_buffer_info_t touch_data_buffer_raw[HID_PARALLEL_DATA_BUFFERS]; ++ ipts_buffer_info_t touch_data_buffer_hid; ++ ++ ipts_buffer_info_t feedback_buffer[HID_PARALLEL_DATA_BUFFERS]; ++ ++ ipts_buffer_info_t hid2me_buffer; ++ u32 hid2me_buffer_size; ++ ++ u8 wq_item_size; ++ intel_ipts_wq_info_t wq_info; ++ ++ /* ME2HID buffer */ ++ char *me2hid_buffer; ++ ++ /* Gfx specific resource */ ++ ipts_buffer_info_t raw_data_mode_output_buffer ++ [HID_PARALLEL_DATA_BUFFERS][MAX_NUM_OUTPUT_BUFFERS]; ++ ++ int num_of_outputs; ++ ++ bool default_resource_ready; ++ bool raw_data_resource_ready; ++} ipts_resource_t; ++ ++typedef struct ipts_info { ++ struct mei_cl_device *cldev; ++ struct hid_device *hid; ++ ++ struct work_struct init_work; ++ struct work_struct raw_data_work; ++ struct work_struct gfx_status_work; ++ ++ struct task_struct *event_loop; ++ ++#if IS_ENABLED(CONFIG_DEBUG_FS) ++ struct dentry *dbgfs_dir; ++#endif ++ ++ ipts_state_t state; ++ ++ touch_sensor_mode_t sensor_mode; ++ touch_sensor_get_device_info_rsp_data_t device_info; ++ ipts_resource_t resource; ++ u8 hid_input_report[HID_MAX_BUFFER_SIZE]; ++ int num_of_parallel_data_buffers; ++ bool hid_desc_ready; ++ ++ int current_buffer_index; ++ int last_buffer_completed; ++ int *last_submitted_id; ++ ++ ipts_gfx_info_t gfx_info; ++ u64 kernel_handle; ++ int gfx_status; ++ bool display_status; ++ ++ bool switch_sensor_mode; ++ touch_sensor_mode_t new_sensor_mode; ++ ++ int retry; ++ bool restart; ++} ipts_info_t; ++ ++#if IS_ENABLED(CONFIG_DEBUG_FS) ++int ipts_dbgfs_register(ipts_info_t *ipts, const char *name); ++void ipts_dbgfs_deregister(ipts_info_t *ipts); ++#else ++static int ipts_dbgfs_register(ipts_info_t *ipts, const char *name); ++static void ipts_dbgfs_deregister(ipts_info_t *ipts); ++#endif /* CONFIG_DEBUG_FS */ ++ ++/* inline functions */ ++static inline void ipts_set_state(ipts_info_t *ipts, ipts_state_t state) ++{ ++ ipts->state = state; ++} ++ ++static inline ipts_state_t ipts_get_state(const ipts_info_t *ipts) ++{ ++ return ipts->state; ++} ++ ++static inline bool ipts_is_default_resource_ready(const ipts_info_t *ipts) ++{ ++ return ipts->resource.default_resource_ready; ++} ++ ++static inline bool ipts_is_raw_data_resource_ready(const ipts_info_t *ipts) ++{ ++ return ipts->resource.raw_data_resource_ready; ++} ++ ++static inline ipts_buffer_info_t* ipts_get_feedback_buffer(ipts_info_t *ipts, ++ int buffer_idx) ++{ ++ return &ipts->resource.feedback_buffer[buffer_idx]; ++} ++ ++static inline ipts_buffer_info_t* ipts_get_touch_data_buffer_hid(ipts_info_t *ipts) ++{ ++ return &ipts->resource.touch_data_buffer_hid; ++} ++ ++static inline ipts_buffer_info_t* ipts_get_output_buffers_by_parallel_id( ++ ipts_info_t *ipts, ++ int parallel_idx) ++{ ++ return &ipts->resource.raw_data_mode_output_buffer[parallel_idx][0]; ++} ++ ++static inline ipts_buffer_info_t* ipts_get_hid2me_buffer(ipts_info_t *ipts) ++{ ++ return &ipts->resource.hid2me_buffer; ++} ++ ++static inline void ipts_set_wq_item_size(ipts_info_t *ipts, u8 size) ++{ ++ ipts->resource.wq_item_size = size; ++} ++ ++static inline u8 ipts_get_wq_item_size(const ipts_info_t *ipts) ++{ ++ return ipts->resource.wq_item_size; ++} ++ ++static inline int ipts_get_num_of_parallel_buffers(const ipts_info_t *ipts) ++{ ++ return ipts->num_of_parallel_data_buffers; ++} ++ ++#endif // _IPTS_H_ +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index 0ccccba..c29f128 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -119,6 +119,7 @@ + + #define MEI_DEV_ID_SPT 0x9D3A /* Sunrise Point */ + #define MEI_DEV_ID_SPT_2 0x9D3B /* Sunrise Point 2 */ ++#define MEI_DEV_ID_SPT_4 0x9D3E /* Sunrise Point 4 */ + #define MEI_DEV_ID_SPT_H 0xA13A /* Sunrise Point H */ + #define MEI_DEV_ID_SPT_H_2 0xA13B /* Sunrise Point H 2 */ + +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index f4f1755..451005f 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -86,6 +86,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + + {MEI_PCI_DEVICE(MEI_DEV_ID_SPT, MEI_ME_PCH8_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_2, MEI_ME_PCH8_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_4, MEI_ME_PCH8_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, MEI_ME_PCH8_SPS_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, MEI_ME_PCH8_SPS_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_LBG, MEI_ME_PCH8_CFG)}, +diff --git a/include/linux/intel_ipts_if.h b/include/linux/intel_ipts_if.h +new file mode 100644 +index 0000000..f329bbf +--- /dev/null ++++ b/include/linux/intel_ipts_if.h +@@ -0,0 +1,75 @@ ++/* ++ * ++ * GFX interface to support Intel Precise Touch & Stylus ++ * Copyright (c) 2016 Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ */ ++ ++#ifndef INTEL_IPTS_IF_H ++#define INTEL_IPTS_IF_H ++ ++enum { ++ IPTS_INTERFACE_V1 = 1, ++}; ++ ++#define IPTS_BUF_FLAG_CONTIGUOUS 0x01 ++ ++#define IPTS_NOTIFY_STA_BACKLIGHT_OFF 0x00 ++#define IPTS_NOTIFY_STA_BACKLIGHT_ON 0x01 ++ ++typedef struct intel_ipts_mapbuffer { ++ u32 size; ++ u32 flags; ++ void *gfx_addr; ++ void *cpu_addr; ++ u64 buf_handle; ++ u64 phy_addr; ++} intel_ipts_mapbuffer_t; ++ ++typedef struct intel_ipts_wq_info { ++ u64 db_addr; ++ u64 db_phy_addr; ++ u32 db_cookie_offset; ++ u32 wq_size; ++ u64 wq_addr; ++ u64 wq_phy_addr; ++ u64 wq_head_addr; /* head of wq is managed by GPU */ ++ u64 wq_head_phy_addr; /* head of wq is managed by GPU */ ++ u64 wq_tail_addr; /* tail of wq is managed by CSME */ ++ u64 wq_tail_phy_addr; /* tail of wq is managed by CSME */ ++} intel_ipts_wq_info_t; ++ ++typedef struct intel_ipts_ops { ++ int (*get_wq_info)(uint64_t gfx_handle, intel_ipts_wq_info_t *wq_info); ++ int (*map_buffer)(uint64_t gfx_handle, intel_ipts_mapbuffer_t *mapbuffer); ++ int (*unmap_buffer)(uint64_t gfx_handle, uint64_t buf_handle); ++} intel_ipts_ops_t; ++ ++typedef struct intel_ipts_callback { ++ void (*workload_complete)(void *data); ++ void (*notify_gfx_status)(u32 status, void *data); ++} intel_ipts_callback_t; ++ ++typedef struct intel_ipts_connect { ++ intel_ipts_callback_t ipts_cb; /* input : callback addresses */ ++ void *data; /* input : callback data */ ++ u32 if_version; /* input : interface version */ ++ ++ u32 gfx_version; /* output : gfx version */ ++ u64 gfx_handle; /* output : gfx handle */ ++ intel_ipts_ops_t ipts_ops; /* output : gfx ops for IPTS */ ++} intel_ipts_connect_t; ++ ++int intel_ipts_connect(intel_ipts_connect_t *ipts_connect); ++void intel_ipts_disconnect(uint64_t gfx_handle); ++ ++#endif // INTEL_IPTS_IF_H diff --git a/patches-4.15/keyboards_and_covers.patch b/patches-4.15/keyboards_and_covers.patch new file mode 100644 index 000000000..7a7f49e7e --- /dev/null +++ b/patches-4.15/keyboards_and_covers.patch @@ -0,0 +1,153 @@ +From 0c1ec9426772daa2d4cedc2eae807419eba9abfb Mon Sep 17 00:00:00 2001 +From: Jake Day +Date: Fri, 2 Feb 2018 11:23:08 -0500 +Subject: support for surface keyboards and covers + + +diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c +index 0c3f608..b0e22c0 100644 +--- a/drivers/hid/hid-core.c ++++ b/drivers/hid/hid-core.c +@@ -723,7 +723,8 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type) + hid->group = HID_GROUP_SENSOR_HUB; + + if (hid->vendor == USB_VENDOR_ID_MICROSOFT && +- hid->product == USB_DEVICE_ID_MS_POWER_COVER && ++ (hid->product == USB_DEVICE_ID_MS_SURFACE_LAPTOP || ++ hid->product == USB_DEVICE_ID_MS_POWER_COVER) && + hid->group == HID_GROUP_MULTITOUCH) + hid->group = HID_GROUP_GENERIC; + +@@ -2183,6 +2184,7 @@ static const struct hid_device_id hid_have_special_driver[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_LAPTOP) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, + #endif +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index 5da3d62..1295dcb 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -767,11 +767,21 @@ + #define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1 0x0732 + #define USB_DEVICE_ID_MS_DIGITAL_MEDIA_600 0x0750 + #define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500 0x076c +-#define USB_DEVICE_ID_MS_COMFORT_KEYBOARD 0x00e3 +-#define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799 +-#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 +-#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 +-#define USB_DEVICE_ID_MS_POWER_COVER 0x07da ++#define USB_DEVICE_ID_MS_COMFORT_KEYBOARD 0x00e3 ++#define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799 ++#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 ++#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 ++#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07de ++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 0x07dc ++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_1 0x07de ++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 0x07e2 ++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP 0x07dd ++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4 0x07e8 ++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_1 0x07e4 ++#define USB_DEVICE_ID_MS_SURFACE_BOOK 0x07cd ++#define USB_DEVICE_ID_MS_SURFACE_BOOK_2 0x0922 ++#define USB_DEVICE_ID_MS_SURFACE_LAPTOP 0xf001 ++#define USB_DEVICE_ID_MS_POWER_COVER 0x07da + + #define USB_VENDOR_ID_MOJO 0x8282 + #define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 +diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c +index 96e7d32..9127164 100644 +--- a/drivers/hid/hid-microsoft.c ++++ b/drivers/hid/hid-microsoft.c +@@ -274,6 +274,8 @@ static const struct hid_device_id ms_devices[] = { + .driver_data = MS_NOGET }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500), + .driver_data = MS_DUPLICATE_USAGES }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_LAPTOP), ++ .driver_data = MS_HIDINPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), + .driver_data = MS_HIDINPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD), +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 65ea23b..dd416e9 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -1638,6 +1638,52 @@ static const struct hid_device_id mt_devices[] = { + HID_USB_DEVICE(USB_VENDOR_ID_LG, + USB_DEVICE_ID_LG_MELFAS_MT) }, + ++ /* Microsoft Touch Cover */ ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_TOUCH_COVER_2) }, ++ ++ /* Microsoft Type Cover */ ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_TYPE_COVER_2) }, ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_TYPE_COVER_3) }, ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_TYPE_COVER_PRO_3) }, ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_1) }, ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2) }, ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) }, ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_TYPE_COVER_PRO_4) }, ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_1) }, ++ ++ /* Microsoft Surface Book */ ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_SURFACE_BOOK) }, ++ ++ /* Microsoft Surface Book 2 */ ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_SURFACE_BOOK_2) }, ++ ++ /* Microsoft Power Cover */ ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_POWER_COVER) }, ++ + /* MosArt panels */ + { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, + MT_USB_DEVICE(USB_VENDOR_ID_ASUS, +diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c +index 331f7f3..6ff429f 100644 +--- a/drivers/hid/usbhid/hid-quirks.c ++++ b/drivers/hid/usbhid/hid-quirks.c +@@ -108,8 +108,18 @@ static const struct hid_blacklist { + { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A, HID_QUIRK_ALWAYS_POLL }, + { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2, HID_QUIRK_NO_INIT_REPORTS }, +- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2, HID_QUIRK_NO_INIT_REPORTS }, ++ { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2, HID_QUIRK_NO_INIT_REPORTS }, ++ { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS }, ++ { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3, HID_QUIRK_NO_INIT_REPORTS }, ++ { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_1, HID_QUIRK_NO_INIT_REPORTS }, ++ { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2, HID_QUIRK_NO_INIT_REPORTS }, ++ { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP, HID_QUIRK_NO_INIT_REPORTS }, ++ { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4, HID_QUIRK_NO_INIT_REPORTS }, ++ { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_1, HID_QUIRK_NO_INIT_REPORTS }, ++ { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_BOOK, HID_QUIRK_NO_INIT_REPORTS }, ++ { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_BOOK_2, HID_QUIRK_NO_INIT_REPORTS }, ++ { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_LAPTOP, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS }, diff --git a/patches-4.15/sdcard_reader.patch b/patches-4.15/sdcard_reader.patch new file mode 100644 index 000000000..49d83359f --- /dev/null +++ b/patches-4.15/sdcard_reader.patch @@ -0,0 +1,20 @@ +From fbd83f772a3be3a00bae323f6d71a59b26352c57 Mon Sep 17 00:00:00 2001 +From: Jake Day +Date: Fri, 2 Feb 2018 11:22:21 -0500 +Subject: fix for surface sd card reader + + +diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c +index cf7bbcb..826fdb8 100644 +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -4047,7 +4047,8 @@ void usb_enable_lpm(struct usb_device *udev) + if (!udev || !udev->parent || + udev->speed < USB_SPEED_SUPER || + !udev->lpm_capable || +- udev->state < USB_STATE_DEFAULT) ++ udev->state < USB_STATE_DEFAULT || ++ !udev->bos || !udev->bos->ss_cap) + return; + + udev->lpm_disable_count--; diff --git a/patches-4.15/surfacedock.patch b/patches-4.15/surfacedock.patch new file mode 100644 index 000000000..8482bebd0 --- /dev/null +++ b/patches-4.15/surfacedock.patch @@ -0,0 +1,36 @@ +From 3600aaa37a16777a07aa34672f12e30a1ae4d95b Mon Sep 17 00:00:00 2001 +From: Jake Day +Date: Fri, 2 Feb 2018 11:21:06 -0500 +Subject: support for surface dock + + +diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c +index 05dca3e..59c2fcc 100644 +--- a/drivers/net/usb/cdc_ether.c ++++ b/drivers/net/usb/cdc_ether.c +@@ -807,13 +807,6 @@ static const struct usb_device_id products[] = { + .driver_info = 0, + }, + +-/* Microsoft Surface 3 dock (based on Realtek RTL8153) */ +-{ +- USB_DEVICE_AND_INTERFACE_INFO(MICROSOFT_VENDOR_ID, 0x07c6, USB_CLASS_COMM, +- USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), +- .driver_info = 0, +-}, +- + /* TP-LINK UE300 USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */ + { + USB_DEVICE_AND_INTERFACE_INFO(TPLINK_VENDOR_ID, 0x0601, USB_CLASS_COMM, +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index 0657203..0a52ea0 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -5323,7 +5323,6 @@ static const struct usb_device_id rtl8152_table[] = { + {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8152)}, + {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)}, + {REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07ab)}, +- {REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07c6)}, + {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)}, + {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x304f)}, + {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3062)}, diff --git a/patches-4.15/wifi.patch b/patches-4.15/wifi.patch new file mode 100644 index 000000000..196ac089e --- /dev/null +++ b/patches-4.15/wifi.patch @@ -0,0 +1,173 @@ +From a359b5adc91cb9f2d3cc07705d804ef60bf6e4e3 Mon Sep 17 00:00:00 2001 +From: Jake Day +Date: Fri, 2 Feb 2018 12:57:32 -0500 +Subject: fixes for marvell mwifiex + + +diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +index 042a1d0..fc9041f 100644 +--- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c ++++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +@@ -200,8 +200,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, + + do { + /* Check if AMSDU can accommodate this MSDU */ +- if ((skb_aggr->len + skb_src->len + LLC_SNAP_LEN) > +- adapter->tx_buf_size) ++ if (skb_tailroom(skb_aggr) < (skb_src->len + LLC_SNAP_LEN)) + break; + + skb_src = skb_dequeue(&pra_list->skb_head); +diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c +index 6e0d9a9..d008687 100644 +--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c ++++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c +@@ -416,6 +416,9 @@ mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy, + + ps_mode = enabled; + ++ mwifiex_dbg(priv->adapter, ERROR, "overriding ps_mode to false\n"); ++ ps_mode = 0; ++ + return mwifiex_drv_set_power(priv, &ps_mode); + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c +index e1aa860..328829b 100644 +--- a/drivers/net/wireless/marvell/mwifiex/init.c ++++ b/drivers/net/wireless/marvell/mwifiex/init.c +@@ -60,7 +60,7 @@ static void wakeup_timer_fn(struct timer_list *t) + adapter->hw_status = MWIFIEX_HW_STATUS_RESET; + mwifiex_cancel_all_pending_cmd(adapter); + +- if (adapter->if_ops.card_reset && !adapter->hs_activated) ++ if (adapter->if_ops.card_reset) + adapter->if_ops.card_reset(adapter); + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index cd31494..50df1c0 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -310,6 +310,8 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev) + mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN); + } + ++ cancel_work_sync(&card->work); ++ + mwifiex_remove_card(adapter); + } + +@@ -1729,6 +1731,16 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) + } + + rx_len = get_unaligned_le16(skb->data); ++ ++ ++ if (rx_len == 0) { ++ mwifiex_dbg(adapter, ERROR, ++ "0 byte cmdrsp\n"); ++ mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, ++ PCI_DMA_FROMDEVICE); ++ return 0; ++ } ++ + skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len); + skb_trim(skb, rx_len); + +diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c +index fd5183c..832824a 100644 +--- a/drivers/net/wireless/marvell/mwifiex/sdio.c ++++ b/drivers/net/wireless/marvell/mwifiex/sdio.c +@@ -399,6 +399,8 @@ mwifiex_sdio_remove(struct sdio_func *func) + mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN); + } + ++ cancel_work_sync(&card->work); ++ + mwifiex_remove_card(adapter); + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +index fb09014..5b8329e 100644 +--- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c ++++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +@@ -2313,7 +2313,7 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) + if (ret) + return -1; + +- if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { ++ if (0 && priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { + /* Enable IEEE PS by default */ + priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; + ret = mwifiex_send_cmd(priv, +@@ -2336,8 +2336,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) + return -1; + } + +- mwifiex_send_cmd(priv, HostCmd_CMD_CHAN_REGION_CFG, +- HostCmd_ACT_GEN_GET, 0, NULL, true); ++ //mwifiex_send_cmd(priv, HostCmd_CMD_CHAN_REGION_CFG, ++ // HostCmd_ACT_GEN_GET, 0, NULL, true); + } + + /* get tx rate */ +@@ -2369,7 +2369,7 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) + if (ret) + return -1; + +- if (!disable_auto_ds && first_sta && ++ if (0 && !disable_auto_ds && first_sta && + priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { + /* Enable auto deep sleep */ + auto_ds.auto_ds = DEEP_SLEEP_ON; +diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c +index 1bd4e13..27d2bac 100644 +--- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c ++++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c +@@ -48,9 +48,14 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv, + struct host_cmd_ds_802_11_ps_mode_enh *pm; + unsigned long flags; + +- mwifiex_dbg(adapter, ERROR, +- "CMD_RESP: cmd %#x error, result=%#x\n", +- resp->command, resp->result); ++ if (resp->command == 271 && resp->result == 2){ ++ // ignore this command as the firmware does not support it ++ } ++ else { ++ mwifiex_dbg(adapter, ERROR, ++ "CMD_RESP: cmd %#x error, result=%#x\n", ++ resp->command, resp->result); ++ } + + if (adapter->curr_cmd->wait_q_enabled) + adapter->cmd_wait_q.status = -1; +diff --git a/net/wireless/sme.c b/net/wireless/sme.c +index fdb3646..b44b23b 100644 +--- a/net/wireless/sme.c ++++ b/net/wireless/sme.c +@@ -690,6 +690,11 @@ void __cfg80211_connect_result(struct net_device *dev, + return; + } + ++ if (WARN_ON(!wdev->ssid_len)) { ++ cfg80211_put_bss(wdev->wiphy, cr->bss); ++ return; ++ } ++ + nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev, cr, + GFP_KERNEL); + +@@ -1105,7 +1110,7 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, + /* + * If we have an ssid_len, we're trying to connect or are + * already connected, so reject a new SSID unless it's the +- * same (which is the case for re-association.) ++ * same (which is the case for Re-Association. + */ + if (wdev->ssid_len && + (wdev->ssid_len != connect->ssid_len || +diff --git a/scripts/leaking_addresses.pl b/scripts/leaking_addresses.pl +old mode 100755 +new mode 100644