summarylogtreecommitdiffstats
path: root/0003-add-ipts.patch
diff options
context:
space:
mode:
authorSuperBo2017-04-14 10:55:04 +0700
committerSuperBo2017-04-14 10:55:04 +0700
commit206b410774e218ee71e81f5423e7dd5555bb49ac (patch)
tree7bdcfad091050f1ba8ba90cb2f215a7c72a44de9 /0003-add-ipts.patch
parentb25e4971f2cf9cecd64f31f6cb2e4e78790f2f35 (diff)
downloadaur-206b410774e218ee71e81f5423e7dd5555bb49ac.tar.gz
Update to 4.9 LTS branch
Diffstat (limited to '0003-add-ipts.patch')
-rw-r--r--0003-add-ipts.patch5933
1 files changed, 5933 insertions, 0 deletions
diff --git a/0003-add-ipts.patch b/0003-add-ipts.patch
new file mode 100644
index 00000000000..24f5152a034
--- /dev/null
+++ b/0003-add-ipts.patch
@@ -0,0 +1,5933 @@
+diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
+index a998c2b..eb4796b 100644
+--- a/drivers/gpu/drm/i915/Makefile
++++ b/drivers/gpu/drm/i915/Makefile
+@@ -107,6 +107,9 @@ i915-y += dvo_ch7017.o \
+ intel_sdvo.o \
+ intel_tv.o
+
++# intel precise touch & stylus
++i915-y += intel_ipts.o
++
+ # virtual gpu code
+ i915-y += i915_vgpu.o
+
+diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
+index 18dfdd5..33c8e4b 100644
+--- a/drivers/gpu/drm/i915/i915_drv.c
++++ b/drivers/gpu/drm/i915/i915_drv.c
+@@ -49,6 +49,7 @@
+ #include "i915_trace.h"
+ #include "i915_vgpu.h"
+ #include "intel_drv.h"
++#include "intel_ipts.h"
+
+ static struct drm_driver driver;
+
+@@ -633,6 +634,10 @@ static int i915_load_modeset_init(struct drm_device *dev)
+
+ drm_kms_helper_poll_init(dev);
+
++pr_info(">> let init ipts\n");
++ if (INTEL_GEN(dev) >= 9 && i915.enable_guc_submission)
++ intel_ipts_init(dev);
++
+ return 0;
+
+ cleanup_gem:
+@@ -1269,6 +1274,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) >= 9 && i915.enable_guc_submission)
++ intel_ipts_cleanup(dev);
++
+ intel_fbdev_fini(dev);
+
+ if (i915_gem_suspend(dev))
+diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
+index 685e9e06..7eeb03e 100644
+--- a/drivers/gpu/drm/i915/i915_drv.h
++++ b/drivers/gpu/drm/i915/i915_drv.h
+@@ -3407,6 +3407,8 @@ struct drm_i915_gem_object *
+ i915_gem_alloc_context_obj(struct drm_device *dev, size_t size);
+ struct i915_gem_context *
+ i915_gem_context_create_gvt(struct drm_device *dev);
++struct i915_gem_context *
++i915_gem_context_create_ipts(struct drm_device *dev);
+
+ static inline struct i915_gem_context *
+ i915_gem_context_lookup(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 df10f4e9..baea2e9 100644
+--- a/drivers/gpu/drm/i915/i915_gem_context.c
++++ b/drivers/gpu/drm/i915/i915_gem_context.c
+@@ -405,6 +405,17 @@ i915_gem_context_create_gvt(struct drm_device *dev)
+ return ctx;
+ }
+
++struct i915_gem_context *i915_gem_context_create_ipts(struct drm_device *dev)
++{
++ struct i915_gem_context *ctx;
++
++ BUG_ON(!mutex_is_locked(&dev->struct_mutex));
++
++ ctx = i915_gem_create_context(dev, NULL);
++
++ return ctx;
++}
++
+ static void i915_gem_context_unpin(struct i915_gem_context *ctx,
+ struct intel_engine_cs *engine)
+ {
+diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
+index 3106dcc..6a5065e 100644
+--- a/drivers/gpu/drm/i915/i915_guc_submission.c
++++ b/drivers/gpu/drm/i915/i915_guc_submission.c
+@@ -333,7 +333,13 @@ static void guc_ctx_desc_init(struct intel_guc *guc,
+
+ memset(&desc, 0, sizeof(desc));
+
+- desc.attribute = GUC_CTX_DESC_ATTR_ACTIVE | GUC_CTX_DESC_ATTR_KERNEL;
++ desc.attribute = GUC_CTX_DESC_ATTR_ACTIVE;
++ if ((client->priority == GUC_CTX_PRIORITY_KMD_NORMAL) ||
++ (client->priority == GUC_CTX_PRIORITY_KMD_HIGH)) {
++ desc.attribute |= GUC_CTX_DESC_ATTR_KERNEL;
++ } else {
++ desc.attribute |= GUC_CTX_DESC_ATTR_PCH;
++ }
+ desc.context_id = client->ctx_index;
+ desc.priority = client->priority;
+ desc.db_id = client->doorbell_id;
+@@ -1098,6 +1104,47 @@ int intel_guc_suspend(struct drm_device *dev)
+ return host2guc_action(guc, data, ARRAY_SIZE(data));
+ }
+
++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_CTX_PRIORITY_NORMAL,
++ ctx);
++ if (!client) {
++ DRM_ERROR("Failed to create normal GuC client!\n");
++ return -ENOMEM;
++ }
++
++ guc->ipts_client = client;
++ host2guc_sample_forcewake(guc, client);
++ 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(dev_priv, 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;
++
++ if (host2guc_allocate_doorbell(guc, guc->ipts_client))
++ DRM_ERROR("Not able to reacquire IPTS doorbell\n");
++}
+
+ /**
+ * intel_guc_resume() - notify GuC resuming from suspend state
+diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
+index 3fc286c..d48d0f1 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
+@@ -1288,6 +1289,8 @@ gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir, int test_shift)
+ notify_ring(engine);
+ if (iir & (GT_CONTEXT_SWITCH_INTERRUPT << test_shift))
+ tasklet_schedule(&engine->irq_tasklet);
++ if (iir & (GT_RENDER_PIPECTL_NOTIFY_INTERRUPT << test_shift))
++ intel_ipts_notify_complete();
+ }
+
+ static irqreturn_t gen8_gt_irq_ack(struct drm_i915_private *dev_priv,
+@@ -3680,7 +3683,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 768ad89..d1d99e3 100644
+--- a/drivers/gpu/drm/i915/i915_params.c
++++ b/drivers/gpu/drm/i915/i915_params.c
+@@ -55,8 +55,8 @@ struct i915_params i915 __read_mostly = {
+ .verbose_state_checks = 1,
+ .nuclear_pageflip = 0,
+ .edp_vswing = 0,
+- .enable_guc_loading = 0,
+- .enable_guc_submission = 0,
++ .enable_guc_loading = 2,
++ .enable_guc_submission = 2,
+ .guc_log_level = -1,
+ .enable_dp_mst = true,
+ .inject_load_failure = 0,
+@@ -209,12 +209,12 @@ MODULE_PARM_DESC(edp_vswing,
+ module_param_named_unsafe(enable_guc_loading, i915.enable_guc_loading, int, 0400);
+ MODULE_PARM_DESC(enable_guc_loading,
+ "Enable GuC firmware loading "
+- "(-1=auto, 0=never [default], 1=if available, 2=required)");
++ "(-1=auto, 0=never, 1=if available, 2=required [default])");
+
+ module_param_named_unsafe(enable_guc_submission, i915.enable_guc_submission, int, 0400);
+ MODULE_PARM_DESC(enable_guc_submission,
+ "Enable GuC submission "
+- "(-1=auto, 0=never [default], 1=if available, 2=required)");
++ "(-1=auto, 0=never, 1=if available, 2=required [default])");
+
+ module_param_named(guc_log_level, i915.guc_log_level, int, 0400);
+ MODULE_PARM_DESC(guc_log_level,
+diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
+index 5cdf7aa..0b8dd19 100644
+--- a/drivers/gpu/drm/i915/intel_guc.h
++++ b/drivers/gpu/drm/i915/intel_guc.h
+@@ -133,6 +133,7 @@ struct intel_guc {
+ struct ida ctx_ids;
+
+ struct i915_guc_client *execbuf_client;
++ struct i915_guc_client *ipts_client;
+
+ DECLARE_BITMAP(doorbell_bitmap, GUC_MAX_DOORBELLS);
+ uint32_t db_cacheline; /* Cyclic counter mod pagesize */
+@@ -163,5 +164,9 @@ int i915_guc_wq_reserve(struct drm_i915_gem_request *rq);
+ void i915_guc_wq_unreserve(struct drm_i915_gem_request *request);
+ void i915_guc_submission_disable(struct drm_i915_private *dev_priv);
+ void i915_guc_submission_fini(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_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
+index 6fd39ef..5a21181 100644
+--- a/drivers/gpu/drm/i915/intel_guc_loader.c
++++ b/drivers/gpu/drm/i915/intel_guc_loader.c
+@@ -126,7 +126,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);
+diff --git a/drivers/gpu/drm/i915/intel_ipts.c b/drivers/gpu/drm/i915/intel_ipts.c
+new file mode 100644
+index 0000000..f4a2440
+--- /dev/null
++++ b/drivers/gpu/drm/i915/intel_ipts.c
+@@ -0,0 +1,621 @@
++/*
++ * 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 <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/intel_ipts_if.h>
++#include <drm/drmP.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)
++{
++ 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(intel_ipts.dev, 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 = intel_ipts.dev->dev_private;
++ int ret = 0;
++
++ if (ipts_ctx->ppgtt) {
++ vm = &ipts_ctx->ppgtt->base;
++ } else {
++ vm = &dev_priv->ggtt.base;
++ }
++
++ vma = i915_gem_obj_lookup_or_create_vma(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 = intel_ipts.dev->dev_private;
++ 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;
++ }
++
++ ret = intel_lr_context_pin(ipts_ctx, &dev_priv->engine[RCS]);
++ if (ret) {
++ DRM_DEBUG("lr context pinning failed : %d\n", 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 = intel_ipts.dev->dev_private;
++ 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;
++ }
++
++ intel_lr_context_unpin(ipts_ctx, &dev_priv->engine[RCS]);
++ 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 = intel_ipts.dev->dev_private;
++ 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->client_base;
++ desc = (struct guc_process_desc *)((u64)base + client->proc_desc_offset);
++
++ desc->wq_base_addr = (u64)base + client->wq_offset;
++ 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 + client->wq_offset;
++ 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 = intel_ipts.dev->dev_private;
++ 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_gem_obj_lookup_or_create_vma(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)
++{
++ 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(intel_ipts.dev)->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;
++
++ 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 0adb879..7e69bce 100644
+--- a/drivers/gpu/drm/i915/intel_lrc.c
++++ b/drivers/gpu/drm/i915/intel_lrc.c
+@@ -228,10 +228,6 @@ enum {
+
+ #define WA_TAIL_DWORDS 2
+
+-static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
+- struct intel_engine_cs *engine);
+-static int intel_lr_context_pin(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,
+@@ -712,7 +708,7 @@ intel_logical_ring_advance(struct drm_i915_gem_request *request)
+ return 0;
+ }
+
+-static int intel_lr_context_pin(struct i915_gem_context *ctx,
++int intel_lr_context_pin(struct i915_gem_context *ctx,
+ struct intel_engine_cs *engine)
+ {
+ struct intel_context *ce = &ctx->engine[engine->id];
+@@ -1809,7 +1805,8 @@ int logical_render_ring_init(struct intel_engine_cs *engine)
+ int ret;
+
+ 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;
+
+@@ -2097,7 +2094,7 @@ uint32_t intel_lr_context_size(struct intel_engine_cs *engine)
+ return ret;
+ }
+
+-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 4fed816..acac3f5 100644
+--- a/drivers/gpu/drm/i915/intel_lrc.h
++++ b/drivers/gpu/drm/i915/intel_lrc.h
+@@ -82,6 +82,10 @@ int intel_engines_init(struct drm_device *dev);
+ struct i915_gem_context;
+
+ uint32_t intel_lr_context_size(struct intel_engine_cs *engine);
++int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
++ struct intel_engine_cs *engine);
++int intel_lr_context_pin(struct i915_gem_context *ctx,
++ struct intel_engine_cs *engine);
+ void intel_lr_context_unpin(struct i915_gem_context *ctx,
+ struct intel_engine_cs *engine);
+
+diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
+index be4b4d5..6ba5e21 100644
+--- a/drivers/gpu/drm/i915/intel_panel.c
++++ b/drivers/gpu/drm/i915/intel_panel.c
+@@ -34,6 +34,7 @@
+ #include <linux/moduleparam.h>
+ #include <linux/pwm.h>
+ #include "intel_drv.h"
++#include "intel_ipts.h"
+
+ #define CRC_PMIC_PWM_PERIOD_NS 21333
+
+@@ -714,6 +715,9 @@ static void lpt_disable_backlight(struct intel_connector *connector)
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ u32 tmp;
+
++ if (INTEL_GEN(connector->base.dev) >= 9 && i915.enable_guc_submission)
++ intel_ipts_notify_backlight_status(false);
++
+ intel_panel_actually_set_backlight(connector, 0);
+
+ /*
+@@ -883,6 +887,9 @@ static void lpt_enable_backlight(struct intel_connector *connector)
+
+ /* This won't stick until the above enable. */
+ intel_panel_actually_set_backlight(connector, panel->backlight.level);
++
++ if (INTEL_GEN(connector->base.dev) >= 9 && i915.enable_guc_submission)
++ intel_ipts_notify_backlight_status(true);
+ }
+
+ static void pch_enable_backlight(struct intel_connector *connector)
+diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
+index 89e9032..3abad23 100644
+--- a/drivers/hid/hid-multitouch.c
++++ b/drivers/hid/hid-multitouch.c
+@@ -548,8 +548,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 (td->cc_index < 0) {
++ td->cc_index = field->index;
++ td->cc_value_index = usage->usage_index;
++ }
++
+ return 1;
+ case HID_DG_CONTACTMAX:
+ /* we don't set td->last_slot_field as contactcount and
+@@ -842,7 +846,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ field->application != HID_DG_PEN &&
+ field->application != HID_DG_TOUCHPAD &&
+ field->application != HID_GD_KEYBOARD &&
+- field->application != HID_CP_CONSUMER_CONTROL)
++ field->application != HID_CP_CONSUMER_CONTROL &&
++ field->application != HID_GD_MOUSE &&
++ field->logical != HID_DG_TOUCHSCREEN)
+ return -1;
+
+ /*
+@@ -1023,6 +1029,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);
++ } else if (hi->report->field[0]->logical == HID_DG_TOUCHSCREEN) {
++ suffix = "SingleTouch";
++ /* force BTN_STYLUS to allow tablet matching in udev */
++ __set_bit(BTN_STYLUS, hi->input->keybit);
+ } else {
+ switch (field->application) {
+ case HID_GD_KEYBOARD:
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 64971ba..88132a2 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -773,6 +773,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 3198336..7760d02 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -44,6 +44,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 <linux/debugfs.h>
++#include <linux/ctype.h>
++#include <linux/uaccess.h>
++
++#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 <linux/kthread.h>
++#include <linux/delay.h>
++#include <linux/intel_ipts_if.h>
++
++#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..cc3ad0d
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-hid.c
+@@ -0,0 +1,455 @@
++/*
++ * 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 <linux/module.h>
++#include <linux/firmware.h>
++#include <linux/hid.h>
++#include <linux/vmalloc.h>
++
++#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)
++{
++ struct hid_device *hid = ipts->hid;
++ hid_destroy_device(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 <linux/module.h>
++#include <linux/firmware.h>
++#include <linux/vmalloc.h>
++#include <linux/intel_ipts_if.h>
++
++#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 <linux/mei_cl_bus.h>
++#include <linux/module.h>
++#include <linux/mod_devicetable.h>
++#include <linux/hid.h>
++#include <linux/dma-mapping.h>
++#include <linux/kthread.h>
++#include <linux/intel_ipts_if.h>
++
++#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..b53f668
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-msg-handler.c
+@@ -0,0 +1,433 @@
++#include <linux/mei_cl_bus.h>
++
++#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;
++
++#ifdef ENABLE_IPTS_DEBUG
++ ipts->sensor_mode = TOUCH_SENSOR_MODE_HID; /* start with HID */
++#endif
++
++ 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..c353b81
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-resource.c
+@@ -0,0 +1,277 @@
++#include <linux/dma-mapping.h>
++
++#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_DMA32);
++ 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_DMA32);
++
++ 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_DMA32);
++ 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..a7a4846
+--- /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 <linux/types.h>
++#include <linux/mei_cl_bus.h>
++#include <linux/hid.h>
++#include <linux/intel_ipts_if.h>
++
++#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 7ad15d6..92e105b 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 f3ffd88..1a0af7f 100644
+--- a/drivers/misc/mei/pci-me.c
++++ b/drivers/misc/mei/pci-me.c
+@@ -85,6 +85,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)},
+
+diff --git a/firmware/Makefile b/firmware/Makefile
+index e297e1b..f6f9941 100644
+--- a/firmware/Makefile
++++ b/firmware/Makefile
+@@ -135,6 +135,7 @@ fw-shipped-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda/xircom_pgs.fw
+ fw-shipped-$(CONFIG_USB_VICAM) += vicam/firmware.fw
+ fw-shipped-$(CONFIG_VIDEO_CPIA2) += cpia2/stv0672_vp4.bin
+ fw-shipped-$(CONFIG_YAM) += yam/1200.bin yam/9600.bin
++fw-shipped-$(CONFIG_INTEL_IPTS) += intel/ipts/ipts_fw_config.bin
+
+ fw-shipped-all := $(fw-shipped-y) $(fw-shipped-m) $(fw-shipped-)
+
+diff --git a/firmware/intel/ipts/ipts_fw_config.bin b/firmware/intel/ipts/ipts_fw_config.bin
+new file mode 100644
+index 0000000..2522e8f
+Binary files /dev/null and b/firmware/intel/ipts/ipts_fw_config.bin differ
+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