diff --git a/drivers/input/touchscreen/st/fts.c b/drivers/input/touchscreen/st/fts.c index 21c12f74fb99..89549315d215 100644 --- a/drivers/input/touchscreen/st/fts.c +++ b/drivers/input/touchscreen/st/fts.c @@ -124,6 +124,8 @@ static int fts_probe_delayed(struct fts_ts_info *info); #ifdef CONFIG_ST_TRUSTED_TOUCH +static void fts_trusted_touch_abort_handler(struct fts_ts_info *info, + int error); static struct hh_acl_desc *fts_vm_get_acl(enum hh_vm_names vm_name) { struct hh_acl_desc *acl_desc; @@ -264,7 +266,72 @@ static void fts_vm_deinit(struct fts_ts_info *info) #ifdef CONFIG_ARCH_QTI_VM static int fts_vm_mem_release(struct fts_ts_info *info); -static void fts_trusted_touch_vm_mode_disable(struct fts_ts_info *info); +static void fts_trusted_touch_tvm_vm_mode_disable(struct fts_ts_info *info); +static void fts_trusted_touch_abort_tvm(struct fts_ts_info *info); +static void fts_trusted_touch_event_notify(struct fts_ts_info *info, int event); + +void fts_trusted_touch_tvm_i2c_failure_report(struct fts_ts_info *info) +{ + pr_err("initiating trusted touch abort due to i2c failure\n"); + fts_trusted_touch_abort_handler(info, + TRUSTED_TOUCH_EVENT_I2C_FAILURE); +} + +static void fts_trusted_touch_reset_gpio_toggle(struct fts_ts_info *info) +{ + void __iomem *base; + + base = ioremap(TOUCH_RESET_GPIO_BASE, TOUCH_RESET_GPIO_SIZE); + writel_relaxed(0x1, base + TOUCH_RESET_GPIO_OFFSET); + /* wait until toggle to finish*/ + wmb(); + writel_relaxed(0x0, base + TOUCH_RESET_GPIO_OFFSET); + /* wait until toggle to finish*/ + wmb(); + iounmap(base); +} + +static void fts_trusted_touch_intr_gpio_toggle(struct fts_ts_info *info, + bool enable) +{ + void __iomem *base; + u32 val; + + base = ioremap(TOUCH_INTR_GPIO_BASE, TOUCH_INTR_GPIO_SIZE); + val = readl_relaxed(base + TOUCH_RESET_GPIO_OFFSET); + if (enable) { + val |= BIT(0); + writel_relaxed(val, base + TOUCH_INTR_GPIO_OFFSET); + /* wait until toggle to finish*/ + wmb(); + } else { + val &= ~BIT(0); + writel_relaxed(val, base + TOUCH_INTR_GPIO_OFFSET); + /* wait until toggle to finish*/ + wmb(); + } + iounmap(base); +} + +static int fts_trusted_touch_get_tvm_driver_state(struct fts_ts_info *info) +{ + int state; + + mutex_lock(&info->vm_info->tvm_state_mutex); + state = atomic_read(&info->vm_info->tvm_state); + mutex_unlock(&info->vm_info->tvm_state_mutex); + + return state; + +} + +static void fts_trusted_touch_set_tvm_driver_state(struct fts_ts_info *info, + int state) +{ + mutex_lock(&info->vm_info->tvm_state_mutex); + atomic_set(&info->vm_info->tvm_state, state); + mutex_unlock(&info->vm_info->tvm_state_mutex); +} static int fts_sgl_cmp(const void *a, const void *b) { @@ -317,69 +384,132 @@ static int fts_vm_handle_vm_hardware(struct fts_ts_info *info) queue_delayed_work(info->fwu_workqueue, &info->fwu_work, msecs_to_jiffies(EXP_FN_WORK_DELAY_MS)); + flushFIFO(); fts_interrupt_enable(info); + fts_trusted_touch_set_tvm_driver_state(info, TVM_INTERRUPT_ENABLED); return rc; } -static void fts_vm_irq_on_lend_callback(void *data, - unsigned long notif_type, - enum hh_irq_label label) +static void fts_trusted_touch_tvm_vm_mode_enable(struct fts_ts_info *info) { - struct fts_ts_info *info = data; + struct hh_sgl_desc *sgl_desc, *expected_sgl_desc; + struct hh_acl_desc *acl_desc; struct irq_data *irq_data; - int irq = 0; - int const resource_timeout = msecs_to_jiffies(2000); int rc = 0; + int irq = 0; + if (fts_trusted_touch_get_tvm_driver_state(info) != + TVM_ALL_RESOURCES_LENT_NOTIFIED) { + pr_err("All lend notifications not received\n"); + fts_trusted_touch_event_notify(info, + TRUSTED_TOUCH_EVENT_NOTIFICATIONS_PENDING); + return; + } + + acl_desc = fts_vm_get_acl(HH_TRUSTED_VM); + if (IS_ERR(acl_desc)) { + pr_err("failed to populated acl data:rc=%d\n", + PTR_ERR(acl_desc)); + goto accept_fail; + } + + sgl_desc = hh_rm_mem_accept(info->vm_info->vm_mem_handle, + HH_RM_MEM_TYPE_IO, + HH_RM_TRANS_TYPE_LEND, + HH_RM_MEM_ACCEPT_VALIDATE_ACL_ATTRS | + HH_RM_MEM_ACCEPT_VALIDATE_LABEL | + HH_RM_MEM_ACCEPT_DONE, TRUSTED_TOUCH_MEM_LABEL, + acl_desc, NULL, NULL, 0); + if (IS_ERR_OR_NULL(sgl_desc)) { + pr_err("failed to do mem accept :rc=%d\n", + PTR_ERR(sgl_desc)); + goto acl_fail; + } + fts_trusted_touch_set_tvm_driver_state(info, TVM_IOMEM_ACCEPTED); + + /* Initiate i2c session on tvm */ + rc = pm_runtime_get_sync(info->client->adapter->dev.parent); + if (rc < 0) { + pr_err("failed to get sync rc:%d\n", rc); + goto acl_fail; + } + fts_trusted_touch_set_tvm_driver_state(info, TVM_I2C_SESSION_ACQUIRED); + + expected_sgl_desc = fts_vm_get_sgl(info->vm_info); + if (fts_vm_compare_sgl_desc(expected_sgl_desc, sgl_desc)) { + pr_err("IO sg list does not match\n"); + goto sgl_cmp_fail; + } + + kfree(expected_sgl_desc); + kfree(acl_desc); + + fts_trusted_touch_intr_gpio_toggle(info, false); irq = hh_irq_accept(info->vm_info->irq_label, -1, IRQ_TYPE_LEVEL_HIGH); if (irq < 0) { pr_err("failed to accept irq\n"); - goto irq_fail; + goto accept_fail; } - atomic_set(&info->vm_info->tvm_owns_irq, 1); + fts_trusted_touch_set_tvm_driver_state(info, TVM_IRQ_ACCEPTED); + + irq_data = irq_get_irq_data(irq); if (!irq_data) { pr_err("Invalid irq data for trusted touch\n"); - goto irq_fail; + goto accept_fail; } if (!irq_data->hwirq) { pr_err("Invalid irq in irq data\n"); - goto irq_fail; + goto accept_fail; } if (irq_data->hwirq != info->vm_info->hw_irq) { pr_err("Invalid irq lent\n"); - goto irq_fail; + goto accept_fail; } pr_debug("irq:returned from accept:%d\n", irq); info->client->irq = irq; - if (!wait_for_completion_timeout(&info->resource_checkpoint, - resource_timeout)) { - pr_err("Resources not acquired in TVM\n"); - goto irq_fail; - } rc = fts_vm_handle_vm_hardware(info); if (rc) { pr_err(" Delayed probe failure on VM!\n"); - goto irq_fail; + goto accept_fail; } - atomic_set(&info->trusted_touch_enabled, 1); + pr_info("trusted touch enabled\n"); + return; -irq_fail: - fts_trusted_touch_vm_mode_disable(info); +sgl_cmp_fail: + kfree(expected_sgl_desc); +acl_fail: + kfree(acl_desc); +accept_fail: + fts_trusted_touch_abort_handler(info, + TRUSTED_TOUCH_EVENT_ACCEPT_FAILURE); +} + +static void fts_vm_irq_on_lend_callback(void *data, unsigned long notif_type, + enum hh_irq_label label) +{ + struct fts_ts_info *info = data; + + pr_debug("received irq lend request for label:%d\n", label); + if (fts_trusted_touch_get_tvm_driver_state(info) == + TVM_IOMEM_LENT_NOTIFIED) { + fts_trusted_touch_set_tvm_driver_state(info, + TVM_ALL_RESOURCES_LENT_NOTIFIED); + } else { + fts_trusted_touch_set_tvm_driver_state(info, + TVM_IRQ_LENT_NOTIFIED); + } } static void fts_vm_mem_on_lend_handler(enum hh_mem_notifier_tag tag, unsigned long notif_type, void *entry_data, void *notif_msg) { struct hh_rm_notif_mem_shared_payload *payload; - struct hh_sgl_desc *sgl_desc, *expected_sgl_desc; - struct hh_acl_desc *acl_desc; struct trusted_touch_vm_info *vm_info; struct fts_ts_info *info; - int rc = 0; if (notif_type != HH_RM_NOTIF_MEM_SHARED || tag != HH_MEM_NOTIFIER_TAG_TOUCH) { @@ -403,62 +533,31 @@ static void fts_vm_mem_on_lend_handler(enum hh_mem_notifier_tag tag, if (payload->trans_type != HH_RM_TRANS_TYPE_LEND || payload->label != TRUSTED_TOUCH_MEM_LABEL) { pr_err("Invalid label or transaction type\n"); - goto onlend_fail; + return; } - - acl_desc = fts_vm_get_acl(HH_TRUSTED_VM); - if (IS_ERR(acl_desc)) { - pr_err("failed to populated acl data:rc=%d\n", - PTR_ERR(acl_desc)); - goto onlend_fail; - } - - sgl_desc = hh_rm_mem_accept(payload->mem_handle, HH_RM_MEM_TYPE_IO, - HH_RM_TRANS_TYPE_LEND, - HH_RM_MEM_ACCEPT_VALIDATE_ACL_ATTRS | - HH_RM_MEM_ACCEPT_VALIDATE_LABEL | - HH_RM_MEM_ACCEPT_DONE, payload->label, acl_desc, - NULL, NULL, 0); - if (IS_ERR_OR_NULL(sgl_desc)) { - pr_err("failed to do mem accept :rc=%d\n", - PTR_ERR(sgl_desc)); - goto acl_fail; - } - atomic_set(&vm_info->tvm_owns_iomem, 1); - - /* Initiate i2c session on tvm */ - rc = pm_runtime_get_sync(info->client->adapter->dev.parent); - if (rc < 0) { - pr_err("failed to get sync rc:%d\n", rc); - (void)fts_vm_mem_release(info); - atomic_set(&info->vm_info->tvm_owns_iomem, 0); - goto acl_fail; - } - complete(&info->resource_checkpoint); - - expected_sgl_desc = fts_vm_get_sgl(vm_info); - if (fts_vm_compare_sgl_desc(expected_sgl_desc, sgl_desc)) { - pr_err("IO sg list does not match\n"); - goto sgl_cmp_fail; - } - vm_info->vm_mem_handle = payload->mem_handle; - kfree(expected_sgl_desc); - kfree(acl_desc); - return; + pr_debug("received mem lend request with handle:%d\n", + vm_info->vm_mem_handle); -sgl_cmp_fail: - kfree(expected_sgl_desc); -acl_fail: - kfree(acl_desc); -onlend_fail: - fts_trusted_touch_vm_mode_disable(info); + if (fts_trusted_touch_get_tvm_driver_state(info) == + TVM_IRQ_LENT_NOTIFIED) { + fts_trusted_touch_set_tvm_driver_state(info, + TVM_ALL_RESOURCES_LENT_NOTIFIED); + } else { + fts_trusted_touch_set_tvm_driver_state(info, + TVM_IOMEM_LENT_NOTIFIED); + } } static int fts_vm_mem_release(struct fts_ts_info *info) { int rc = 0; + if (!info->vm_info->vm_mem_handle) { + pr_err("Invalid memory handle\n"); + return -EINVAL; + } + rc = hh_rm_mem_release(info->vm_info->vm_mem_handle, 0); if (rc) pr_err("VM mem release failed: rc=%d\n", rc); @@ -468,45 +567,59 @@ static int fts_vm_mem_release(struct fts_ts_info *info) HH_MEM_NOTIFIER_TAG_TOUCH, 0); if (rc) pr_err("Failed to notify mem release to PVM: rc=%d\n"); + pr_info("vm mem release succeded\n"); info->vm_info->vm_mem_handle = 0; return rc; } -static void fts_trusted_touch_vm_mode_disable(struct fts_ts_info *info) +static void fts_trusted_touch_tvm_vm_mode_disable(struct fts_ts_info *info) { int rc = 0; - - if (atomic_read(&info->vm_info->tvm_owns_iomem) && - atomic_read(&info->vm_info->tvm_owns_irq)) - fts_interrupt_disable(info); - - if (atomic_read(&info->vm_info->tvm_owns_iomem)) { - flushFIFO(); - release_all_touches(info); - rc = fts_vm_mem_release(info); - if (rc) - pr_err("Failed to release mem rc:%d\n", rc); - else - atomic_set(&info->vm_info->tvm_owns_iomem, 0); - pm_runtime_put_sync(info->client->adapter->dev.parent); + if (atomic_read(&info->trusted_touch_abort_status)) { + fts_trusted_touch_abort_tvm(info); + return; } - if (atomic_read(&info->vm_info->tvm_owns_irq)) { - rc = hh_irq_release(info->vm_info->irq_label); - if (rc) - pr_err("Failed to release irq rc:%d\n", rc); - else - atomic_set(&info->vm_info->tvm_owns_irq, 0); + fts_interrupt_disable(info); + fts_trusted_touch_set_tvm_driver_state(info, + TVM_INTERRUPT_DISABLED); - rc = hh_irq_release_notify(info->vm_info->irq_label); - if (rc) - pr_err("Failed to notify release irq rc:%d\n", rc); + rc = hh_irq_release(info->vm_info->irq_label); + if (rc) { + pr_err("Failed to release irq rc:%d\n", rc); + goto error; + } else { + fts_trusted_touch_set_tvm_driver_state(info, + TVM_IRQ_RELEASED); } + rc = hh_irq_release_notify(info->vm_info->irq_label); + if (rc) + pr_err("Failed to notify release irq rc:%d\n", rc); + + pr_info("vm irq release succeded\n"); + + flushFIFO(); + release_all_touches(info); + rc = fts_vm_mem_release(info); + if (rc) { + pr_err("Failed to release mem rc:%d\n", rc); + goto error; + } else { + fts_trusted_touch_set_tvm_driver_state(info, + TVM_IOMEM_RELEASED); + } + pm_runtime_put_sync(info->client->adapter->dev.parent); + fts_trusted_touch_set_tvm_driver_state(info, + TVM_I2C_SESSION_RELEASED); + fts_trusted_touch_set_tvm_driver_state(info, TRUSTED_TOUCH_TVM_INIT); atomic_set(&info->trusted_touch_enabled, 0); - reinit_completion(&info->resource_checkpoint); - pr_debug("trusted touch disabled\n"); + pr_info("trusted touch disabled\n"); + return; +error: + fts_trusted_touch_abort_handler(info, + TRUSTED_TOUCH_EVENT_RELEASE_FAILURE); } static int fts_handle_trusted_touch_tvm(struct fts_ts_info *info, int value) @@ -515,13 +628,14 @@ static int fts_handle_trusted_touch_tvm(struct fts_ts_info *info, int value) switch (value) { case 0: - if (atomic_read(&info->trusted_touch_enabled) == 0) { + if (atomic_read(&info->trusted_touch_enabled) == 0 && + (atomic_read(&info->trusted_touch_abort_status) == 0)) { pr_err("Trusted touch is already disabled\n"); break; } if (atomic_read(&info->trusted_touch_mode) == TRUSTED_TOUCH_VM_MODE) { - fts_trusted_touch_vm_mode_disable(info); + fts_trusted_touch_tvm_vm_mode_disable(info); } else { pr_err("Unsupported trusted touch mode\n"); } @@ -535,7 +649,7 @@ static int fts_handle_trusted_touch_tvm(struct fts_ts_info *info, int value) } if (atomic_read(&info->trusted_touch_mode) == TRUSTED_TOUCH_VM_MODE) { - pr_err("Cannot turnon trusted touch(vm mode) in VM\n"); + fts_trusted_touch_tvm_vm_mode_enable(info); } else { pr_err("Unsupported trusted touch mode\n"); } @@ -550,8 +664,117 @@ static int fts_handle_trusted_touch_tvm(struct fts_ts_info *info, int value) return err; } +static void fts_trusted_touch_abort_tvm(struct fts_ts_info *info) +{ + int rc = 0; + int tvm_state = fts_trusted_touch_get_tvm_driver_state(info); + + if (tvm_state >= TRUSTED_TOUCH_TVM_STATE_MAX) { + pr_err("invalid tvm driver state: %d\n", tvm_state); + return; + } + + switch (tvm_state) { + case TVM_INTERRUPT_ENABLED: + fts_interrupt_disable(info); + case TVM_IRQ_ACCEPTED: + case TVM_INTERRUPT_DISABLED: + rc = hh_irq_release(info->vm_info->irq_label); + if (rc) + pr_err("Failed to release irq rc:%d\n", rc); + rc = hh_irq_release_notify(info->vm_info->irq_label); + if (rc) + pr_err("Failed to notify irq release rc:%d\n", rc); + case TVM_I2C_SESSION_ACQUIRED: + case TVM_IOMEM_ACCEPTED: + case TVM_IRQ_RELEASED: + flushFIFO(); + release_all_touches(info); + rc = fts_vm_mem_release(info); + if (rc) + pr_err("Failed to release mem rc:%d\n", rc); + case TVM_IOMEM_RELEASED: + pm_runtime_put_sync(info->client->adapter->dev.parent); + case TVM_I2C_SESSION_RELEASED: + case TVM_IOMEM_LENT_NOTIFIED: + case TVM_IRQ_LENT_NOTIFIED: + case TVM_ALL_RESOURCES_LENT_NOTIFIED: + case TRUSTED_TOUCH_TVM_INIT: + atomic_set(&info->trusted_touch_enabled, 0); + } + + atomic_set(&info->trusted_touch_abort_status, 0); + fts_trusted_touch_set_tvm_driver_state(info, TRUSTED_TOUCH_TVM_INIT); +} + #else +static void fts_bus_put(struct fts_ts_info *info); +static int fts_trusted_touch_get_pvm_driver_state(struct fts_ts_info *info) +{ + int state; + + mutex_lock(&info->vm_info->pvm_state_mutex); + state = atomic_read(&info->vm_info->pvm_state); + mutex_unlock(&info->vm_info->pvm_state_mutex); + + return state; + +} + +static void fts_trusted_touch_set_pvm_driver_state(struct fts_ts_info *info, + int state) +{ + mutex_lock(&info->vm_info->pvm_state_mutex); + atomic_set(&info->vm_info->pvm_state, state); + mutex_unlock(&info->vm_info->pvm_state_mutex); +} + +static void fts_trusted_touch_abort_pvm(struct fts_ts_info *info) +{ + int rc = 0; + int pvm_state = fts_trusted_touch_get_pvm_driver_state(info); + + if (pvm_state >= TRUSTED_TOUCH_PVM_STATE_MAX) { + pr_err("Invalid driver state: %d\n", pvm_state); + return; + } + + switch (pvm_state) { + case PVM_IRQ_RELEASE_NOTIFIED: + case PVM_ALL_RESOURCES_RELEASE_NOTIFIED: + case PVM_IRQ_LENT: + case PVM_IRQ_LENT_NOTIFIED: + rc = hh_irq_reclaim(info->vm_info->irq_label); + if (rc) + pr_err("failed to reclaim irq on pvm rc:%d\n", rc); + case PVM_IRQ_RECLAIMED: + case PVM_IOMEM_LENT: + case PVM_IOMEM_LENT_NOTIFIED: + case PVM_IOMEM_RELEASE_NOTIFIED: + rc = hh_rm_mem_reclaim(info->vm_info->vm_mem_handle, 0); + if (rc) + pr_err("failed to reclaim iomem on pvm rc:%d\n", rc); + info->vm_info->vm_mem_handle = 0; + case PVM_IOMEM_RECLAIMED: + case PVM_INTERRUPT_DISABLED: + flushFIFO(); + fts_interrupt_enable(info); + case PVM_I2C_RESOURCE_ACQUIRED: + case PVM_INTERRUPT_ENABLED: + fts_bus_put(info); + complete(&info->trusted_touch_powerdown); + case TRUSTED_TOUCH_PVM_INIT: + case PVM_I2C_RESOURCE_RELEASED: + atomic_set(&info->trusted_touch_enabled, 0); + } + + atomic_set(&info->trusted_touch_abort_status, 0); + + fts_trusted_touch_set_pvm_driver_state(info, TRUSTED_TOUCH_PVM_INIT); +} + + static int fts_clk_prepare_enable(struct fts_ts_info *info) { int ret; @@ -616,45 +839,85 @@ static struct hh_notify_vmid_desc *fts_vm_get_vmid(hh_vmid_t vmid) return vmid_desc; } -static void fts_trusted_touch_complete(struct fts_ts_info *info) +static void fts_trusted_touch_pvm_vm_mode_disable(struct fts_ts_info *info) { - if (atomic_read(&info->vm_info->pvm_owns_iomem) && - atomic_read(&info->vm_info->pvm_owns_irq)) { - fts_interrupt_enable(info); - fts_bus_put(info); - complete(&info->trusted_touch_powerdown); - atomic_set(&info->trusted_touch_enabled, 0); - pr_debug("reenabled interrupts on PVM\n"); - } else { - pr_err("PVM does not own irq and IOMEM\n"); - } -} - -static void fts_vm_irq_on_release_callback(void *data, - unsigned long notif_type, - enum hh_irq_label label) -{ - struct fts_ts_info *info = data; int rc = 0; + if (atomic_read(&info->trusted_touch_abort_status)) { + fts_trusted_touch_abort_pvm(info); + return; + } + + if (fts_trusted_touch_get_pvm_driver_state(info) != + PVM_ALL_RESOURCES_RELEASE_NOTIFIED) + pr_err("all release notifications are not received yet\n"); + rc = hh_irq_reclaim(info->vm_info->irq_label); - if (rc) + if (rc) { pr_err("failed to reclaim irq on pvm rc:%d\n", rc); - else - atomic_set(&info->vm_info->pvm_owns_irq, 1); + goto error; + } + fts_trusted_touch_set_pvm_driver_state(info, + PVM_IRQ_RECLAIMED); + + rc = hh_rm_mem_reclaim(info->vm_info->vm_mem_handle, 0); + if (rc) { + pr_err("Trusted touch VM mem reclaim failed rc:%d\n", rc); + goto error; + } + fts_trusted_touch_set_pvm_driver_state(info, PVM_IOMEM_RECLAIMED); + info->vm_info->vm_mem_handle = 0; + + flushFIFO(); + fts_interrupt_enable(info); + fts_trusted_touch_set_pvm_driver_state(info, PVM_INTERRUPT_ENABLED); + fts_bus_put(info); + fts_trusted_touch_set_pvm_driver_state(info, + PVM_I2C_RESOURCE_RELEASED); + complete(&info->trusted_touch_powerdown); + fts_trusted_touch_set_pvm_driver_state(info, + TRUSTED_TOUCH_PVM_INIT); + atomic_set(&info->trusted_touch_enabled, 0); + return; +error: + fts_trusted_touch_abort_handler(info, + TRUSTED_TOUCH_EVENT_RECLAIM_FAILURE); +} + +static void fts_vm_irq_on_release_callback(void *data, unsigned long notif_type, + enum hh_irq_label label) +{ + struct fts_ts_info *info = data; + + if (notif_type != HH_RM_NOTIF_VM_IRQ_RELEASED) { + pr_err("invalid notification type\n"); + return; + } + + if (fts_trusted_touch_get_pvm_driver_state(info) == + PVM_IOMEM_RELEASE_NOTIFIED) { + fts_trusted_touch_set_pvm_driver_state(info, + PVM_ALL_RESOURCES_RELEASE_NOTIFIED); + } else { + fts_trusted_touch_set_pvm_driver_state(info, + PVM_IRQ_RELEASE_NOTIFIED); + } } static void fts_vm_mem_on_release_handler(enum hh_mem_notifier_tag tag, unsigned long notif_type, void *entry_data, void *notif_msg) { - struct hh_rm_notif_mem_released_payload *payload; + struct hh_rm_notif_mem_released_payload *release_payload; struct trusted_touch_vm_info *vm_info; struct fts_ts_info *info; - int rc = 0; - if (notif_type != HH_RM_NOTIF_MEM_RELEASED || - tag != HH_MEM_NOTIFIER_TAG_TOUCH) { - pr_err(" Invalid tag or command passed\n"); + if (notif_type != HH_RM_NOTIF_MEM_RELEASED) { + pr_err(" Invalid notification type\n"); + return; + } + + if (tag != HH_MEM_NOTIFIER_TAG_TOUCH) { + pr_err(" Invalid tag\n"); return; } @@ -663,7 +926,6 @@ static void fts_vm_mem_on_release_handler(enum hh_mem_notifier_tag tag, return; } - payload = (struct hh_rm_notif_mem_released_payload *)notif_msg; info = (struct fts_ts_info *)entry_data; vm_info = info->vm_info; if (!vm_info) { @@ -671,18 +933,20 @@ static void fts_vm_mem_on_release_handler(enum hh_mem_notifier_tag tag, return; } - if (payload->mem_handle != vm_info->vm_mem_handle) { + release_payload = (struct hh_rm_notif_mem_released_payload *)notif_msg; + if (release_payload->mem_handle != vm_info->vm_mem_handle) { pr_err("Invalid mem handle detected\n"); return; } - rc = hh_rm_mem_reclaim(payload->mem_handle, 0); - if (rc) { - pr_err("Trusted touch VM mem release failed rc:%d\n", rc); - return; + if (fts_trusted_touch_get_pvm_driver_state(info) == + PVM_IRQ_RELEASE_NOTIFIED) { + fts_trusted_touch_set_pvm_driver_state(info, + PVM_ALL_RESOURCES_RELEASE_NOTIFIED); + } else { + fts_trusted_touch_set_pvm_driver_state(info, + PVM_IOMEM_RELEASE_NOTIFIED); } - atomic_set(&vm_info->pvm_owns_iomem, 1); - vm_info->vm_mem_handle = 0; } static int fts_vm_mem_lend(struct fts_ts_info *info) @@ -716,6 +980,9 @@ static int fts_vm_mem_lend(struct fts_ts_info *info) rc); goto error; } + pr_info("vm mem lend succeded\n"); + + fts_trusted_touch_set_pvm_driver_state(info, PVM_IOMEM_LENT); hh_rm_get_vmid(HH_TRUSTED_VM, &trusted_vmid); @@ -727,6 +994,7 @@ static int fts_vm_mem_lend(struct fts_ts_info *info) pr_err("Failed to notify mem lend to hypervisor rc:%d\n", rc); goto vmid_error; } + fts_trusted_touch_set_pvm_driver_state(info, PVM_IOMEM_LENT_NOTIFIED); info->vm_info->vm_mem_handle = mem_handle; vmid_error: @@ -739,7 +1007,7 @@ sgl_error: return rc; } -static int fts_trusted_touch_vm_mode_enable(struct fts_ts_info *info) +static int fts_trusted_touch_pvm_vm_mode_enable(struct fts_ts_info *info) { int rc = 0; struct trusted_touch_vm_info *vm_info = info->vm_info; @@ -750,37 +1018,44 @@ static int fts_trusted_touch_vm_mode_enable(struct fts_ts_info *info) rc = -EIO; return rc; } + fts_trusted_touch_set_pvm_driver_state(info, PVM_I2C_RESOURCE_ACQUIRED); /* flush pending interurpts from FIFO */ fts_interrupt_disable(info); + fts_trusted_touch_set_pvm_driver_state(info, PVM_INTERRUPT_DISABLED); + flushFIFO(); release_all_touches(info); rc = fts_vm_mem_lend(info); if (rc) { pr_err("Failed to lend memory\n"); - return -EINVAL; + goto error; } - atomic_set(&vm_info->pvm_owns_iomem, 0); rc = hh_irq_lend_v2(vm_info->irq_label, vm_info->vm_name, info->client->irq, &fts_vm_irq_on_release_callback, info); if (rc) { pr_err("Failed to lend irq\n"); - return -EINVAL; + goto error; } - atomic_set(&vm_info->pvm_owns_irq, 0); + pr_info("vm irq lend succeded for irq:%d\n", info->client->irq); + fts_trusted_touch_set_pvm_driver_state(info, PVM_IRQ_LENT); rc = hh_irq_lend_notify(vm_info->irq_label); if (rc) { pr_err("Failed to notify irq\n"); - return -EINVAL; + goto error; } + fts_trusted_touch_set_pvm_driver_state(info, PVM_IRQ_LENT_NOTIFIED); reinit_completion(&info->trusted_touch_powerdown); atomic_set(&info->trusted_touch_enabled, 1); pr_debug("trusted touch enabled\n"); return rc; +error: + fts_trusted_touch_abort_handler(info, TRUSTED_TOUCH_EVENT_LEND_FAILURE); + return rc; } static int fts_handle_trusted_touch_pvm(struct fts_ts_info *info, int value) @@ -789,13 +1064,14 @@ static int fts_handle_trusted_touch_pvm(struct fts_ts_info *info, int value) switch (value) { case 0: - if (atomic_read(&info->trusted_touch_enabled) == 0) { + if (atomic_read(&info->trusted_touch_enabled) == 0 && + (atomic_read(&info->trusted_touch_abort_status) == 0)) { pr_err("Trusted touch is already disabled\n"); break; } if (atomic_read(&info->trusted_touch_mode) == TRUSTED_TOUCH_VM_MODE) { - fts_trusted_touch_complete(info); + fts_trusted_touch_pvm_vm_mode_disable(info); } else { pr_err("Unsupported trusted touch mode\n"); } @@ -809,7 +1085,7 @@ static int fts_handle_trusted_touch_pvm(struct fts_ts_info *info, int value) } if (atomic_read(&info->trusted_touch_mode) == TRUSTED_TOUCH_VM_MODE) { - err = fts_trusted_touch_vm_mode_enable(info); + err = fts_trusted_touch_pvm_vm_mode_enable(info); } else { pr_err("Unsupported trusted touch mode\n"); } @@ -823,6 +1099,26 @@ static int fts_handle_trusted_touch_pvm(struct fts_ts_info *info, int value) return err; } #endif +static void fts_trusted_touch_event_notify(struct fts_ts_info *info, int event) +{ + atomic_set(&info->trusted_touch_event, event); + sysfs_notify(&info->client->dev.kobj, NULL, "trusted_touch_event"); +} + +static void fts_trusted_touch_abort_handler(struct fts_ts_info *info, int error) +{ + atomic_set(&info->trusted_touch_abort_status, error); + pr_err("TUI session aborted with failure:%d\n", error); +#ifdef CONFIG_ARCH_QTI_VM + pr_err("Resetting touch controller\n"); + if (fts_trusted_touch_get_tvm_driver_state(info) >= TVM_IOMEM_ACCEPTED + && error == TRUSTED_TOUCH_EVENT_I2C_FAILURE) { + pr_err("Resetting touch controller\n"); + fts_trusted_touch_reset_gpio_toggle(info); + } +#endif + fts_trusted_touch_event_notify(info, error); +} static int fts_vm_init(struct fts_ts_info *info) { @@ -849,9 +1145,8 @@ static int fts_vm_init(struct fts_ts_info *info) vm_info->mem_cookie = mem_cookie; rc = hh_irq_wait_for_lend_v2(vm_info->irq_label, HH_PRIMARY_VM, &fts_vm_irq_on_lend_callback, info); - atomic_set(&vm_info->tvm_owns_irq, 0); - atomic_set(&vm_info->tvm_owns_iomem, 0); - init_completion(&info->resource_checkpoint); + mutex_init(&info->vm_info->tvm_state_mutex); + fts_trusted_touch_set_tvm_driver_state(info, TRUSTED_TOUCH_TVM_INIT); #else mem_cookie = hh_mem_notifier_register(HH_MEM_NOTIFIER_TAG_TOUCH, fts_vm_mem_on_release_handler, info); @@ -861,8 +1156,8 @@ static int fts_vm_init(struct fts_ts_info *info) goto init_fail; } vm_info->mem_cookie = mem_cookie; - atomic_set(&vm_info->pvm_owns_irq, 1); - atomic_set(&vm_info->pvm_owns_iomem, 1); + mutex_init(&info->vm_info->pvm_state_mutex); + fts_trusted_touch_set_pvm_driver_state(info, TRUSTED_TOUCH_PVM_INIT); #endif return rc; init_fail: @@ -936,6 +1231,58 @@ static void fts_trusted_touch_init(struct fts_ts_info *info) atomic_set(&info->trusted_touch_initialized, 1); } +static ssize_t trusted_touch_event_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info; + + if (!client) + return scnprintf(buf, PAGE_SIZE, "client is null\n"); + + info = i2c_get_clientdata(client); + if (!info) { + logError(0, "info is null\n"); + return scnprintf(buf, PAGE_SIZE, "info is null\n"); + } + + return scnprintf(buf, PAGE_SIZE, "%d", + atomic_read(&info->trusted_touch_event)); +} + +static ssize_t trusted_touch_event_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info; + unsigned long value; + int err = 0; + + if (!client) + return -EIO; + info = i2c_get_clientdata(client); + if (!info) { + logError(0, "info is null\n"); + return -EIO; + } + if (count > 2) + return -EINVAL; + + err = kstrtoul(buf, 10, &value); + if (err != 0) + return err; + + if (!atomic_read(&info->trusted_touch_initialized)) + return -EIO; + + if (value) + return -EIO; + + atomic_set(&info->trusted_touch_event, value); + + return count; +} + static ssize_t fts_trusted_touch_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -3572,6 +3919,7 @@ static DEVICE_ATTR(trusted_touch_enable, 0664, fts_trusted_touch_enable_show, fts_trusted_touch_enable_store); +static DEVICE_ATTR_RW(trusted_touch_event); #endif /* /sys/devices/soc.0/f9928000.i2c/i2c-6/6-0049 */ @@ -3625,6 +3973,7 @@ static struct attribute *fts_attr_group[] = { #endif #ifdef CONFIG_ST_TRUSTED_TOUCH &dev_attr_trusted_touch_enable.attr, + &dev_attr_trusted_touch_event.attr, #endif NULL, }; @@ -4324,17 +4673,7 @@ static irqreturn_t fts_interrupt_handler(int irq, void *handle) pr_err("%s: Invalid info\n", __func__); return IRQ_HANDLED; } -#ifdef CONFIG_ST_TRUSTED_TOUCH -#ifndef CONFIG_ARCH_QTI_VM - if (atomic_read(&info->vm_info->pvm_owns_iomem) && - atomic_read(&info->vm_info->pvm_owns_irq) && - atomic_read(&info->trusted_touch_enabled)) { - pr_err("%s: Cannot service interrupts in PVM while trusted touch is enabled\n", - __func__); - return IRQ_HANDLED; - } -#endif -#endif + disable_irq_nosync(info->client->irq); queue_work(info->event_wq, &info->work); @@ -4414,13 +4753,26 @@ static void fts_interrupt_uninstall(struct fts_ts_info *info) static void fts_interrupt_enable(struct fts_ts_info *info) { + int ret = 0; #ifdef FTS_USE_POLLING_MODE hrtimer_start(&info->timer, ktime_set(0, 10000000), HRTIMER_MODE_REL); #else enable_irq(info->client->irq); #endif /* enable the touch IC irq */ - fts_enableInterrupt(); + ret = fts_enableInterrupt(); +#ifdef CONFIG_ST_TRUSTED_TOUCH +#ifndef CONFIG_ARCH_QTI_VM + if ((ret < 0) && atomic_read(&info->trusted_touch_enabled)) { + fts_chip_powercycle2(info, 300); + ret = fts_system_reset(); + ret |= fts_mode_handler(info, 0); + ret |= fts_enableInterrupt(); + if (ret < 0) + pr_err("failed to enable touch interrupts\n"); + } +#endif +#endif } static void fts_interrupt_disable(struct fts_ts_info *info) diff --git a/drivers/input/touchscreen/st/fts.h b/drivers/input/touchscreen/st/fts.h index 9be46c210d69..2745a18d4238 100644 --- a/drivers/input/touchscreen/st/fts.h +++ b/drivers/input/touchscreen/st/fts.h @@ -217,9 +217,59 @@ enum trusted_touch_mode_config { TRUSTED_TOUCH_MODE_NONE }; +enum trusted_touch_pvm_states { + TRUSTED_TOUCH_PVM_INIT, + PVM_I2C_RESOURCE_ACQUIRED, + PVM_INTERRUPT_DISABLED, + PVM_IOMEM_LENT, + PVM_IOMEM_LENT_NOTIFIED, + PVM_IRQ_LENT, + PVM_IRQ_LENT_NOTIFIED, + PVM_IOMEM_RELEASE_NOTIFIED, + PVM_IRQ_RELEASE_NOTIFIED, + PVM_ALL_RESOURCES_RELEASE_NOTIFIED, + PVM_IRQ_RECLAIMED, + PVM_IOMEM_RECLAIMED, + PVM_INTERRUPT_ENABLED, + PVM_I2C_RESOURCE_RELEASED, + TRUSTED_TOUCH_PVM_STATE_MAX +}; + +enum trusted_touch_tvm_states { + TRUSTED_TOUCH_TVM_INIT, + TVM_IOMEM_LENT_NOTIFIED, + TVM_IRQ_LENT_NOTIFIED, + TVM_ALL_RESOURCES_LENT_NOTIFIED, + TVM_IOMEM_ACCEPTED, + TVM_I2C_SESSION_ACQUIRED, + TVM_IRQ_ACCEPTED, + TVM_INTERRUPT_ENABLED, + TVM_INTERRUPT_DISABLED, + TVM_IRQ_RELEASED, + TVM_IOMEM_RELEASED, + TVM_I2C_SESSION_RELEASED, + TRUSTED_TOUCH_TVM_STATE_MAX +}; + #ifdef CONFIG_ST_TRUSTED_TOUCH #define TRUSTED_TOUCH_MEM_LABEL 0x7 +#define TOUCH_RESET_GPIO_BASE 0xF116000 +#define TOUCH_RESET_GPIO_SIZE 0x1000 +#define TOUCH_RESET_GPIO_OFFSET 0x4 +#define TOUCH_INTR_GPIO_BASE 0xF117000 +#define TOUCH_INTR_GPIO_SIZE 0x1000 +#define TOUCH_INTR_GPIO_OFFSET 0x8 + +#define TRUSTED_TOUCH_EVENT_LEND_FAILURE -1 +#define TRUSTED_TOUCH_EVENT_LEND_NOTIFICATION_FAILURE -2 +#define TRUSTED_TOUCH_EVENT_ACCEPT_FAILURE -3 +#define TRUSTED_TOUCH_EVENT_FUNCTIONAL_FAILURE -4 +#define TRUSTED_TOUCH_EVENT_RELEASE_FAILURE -5 +#define TRUSTED_TOUCH_EVENT_RECLAIM_FAILURE -6 +#define TRUSTED_TOUCH_EVENT_I2C_FAILURE -7 +#define TRUSTED_TOUCH_EVENT_NOTIFICATIONS_PENDING 5 + struct trusted_touch_vm_info { enum hh_irq_label irq_label; enum hh_vm_names vm_name; @@ -230,13 +280,17 @@ struct trusted_touch_vm_info { u32 iomem_list_size; void *mem_cookie; #ifdef CONFIG_ARCH_QTI_VM - atomic_t tvm_owns_iomem; - atomic_t tvm_owns_irq; + struct mutex tvm_state_mutex; + atomic_t tvm_state; #else - atomic_t pvm_owns_iomem; - atomic_t pvm_owns_irq; + struct mutex pvm_state_mutex; + atomic_t pvm_state; #endif }; + +#ifdef CONFIG_ARCH_QTI_VM +void fts_trusted_touch_tvm_i2c_failure_report(struct fts_ts_info *info); +#endif #endif /* @@ -359,11 +413,12 @@ struct fts_ts_info { struct mutex fts_clk_io_ctrl_mutex; const char *touch_environment; struct completion trusted_touch_powerdown; - struct completion resource_checkpoint; struct clk *core_clk; struct clk *iface_clk; atomic_t trusted_touch_initialized; atomic_t trusted_touch_enabled; + atomic_t trusted_touch_event; + atomic_t trusted_touch_abort_status; atomic_t delayed_vm_probe_pending; atomic_t trusted_touch_mode; #endif diff --git a/drivers/input/touchscreen/st/fts_lib/ftsIO.c b/drivers/input/touchscreen/st/fts_lib/ftsIO.c index ba0fb18e3307..12f02d9424ff 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsIO.c +++ b/drivers/input/touchscreen/st/fts_lib/ftsIO.c @@ -34,6 +34,7 @@ * */ +#include #include #include #include @@ -141,13 +142,32 @@ int fts_readCmd(u8 *cmd, int cmdLength, u8 *outBuf, int byteToRead) while (retry < I2C_RETRY && ret < OK) { ret = i2c_transfer(client->adapter, I2CMsg, 2); retry++; - if (ret < OK) + if (ret < OK) { +#ifdef CONFIG_ST_TRUSTED_TOUCH +#ifdef CONFIG_ARCH_QTI_VM + if (atomic_read(&info->trusted_touch_enabled) && + ret == -ECONNRESET){ + pr_err("failed i2c read reacquiring session\n"); + pm_runtime_put_sync( + info->client->adapter->dev.parent); + pm_runtime_get_sync( + info->client->adapter->dev.parent); + } +#endif +#endif msleep(I2C_WAIT_BEFORE_RETRY); + } } if (ret < 0) { +#ifdef CONFIG_ST_TRUSTED_TOUCH +#ifdef CONFIG_ARCH_QTI_VM + pr_err("initiating abort due to i2c xfer failure\n"); + fts_trusted_touch_tvm_i2c_failure_report(info); +#endif +#endif logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_R); - return ERROR_I2C_R; + return ret; } memcpy(outBuf, buf + cmdLength, byteToRead); @@ -189,13 +209,34 @@ int fts_writeCmd(u8 *cmd, int cmdLength) while (retry < I2C_RETRY && ret < OK) { ret = i2c_transfer(client->adapter, I2CMsg, 1); retry++; - if (ret < OK) + if (ret < OK) { +#ifdef CONFIG_ST_TRUSTED_TOUCH +#ifdef CONFIG_ARCH_QTI_VM + if (atomic_read(&info->trusted_touch_enabled) && + ret == -ECONNRESET){ + pr_err("failed i2c write reacquiring session\n"); + pm_runtime_put_sync( + info->client->adapter->dev.parent); + pm_runtime_get_sync( + info->client->adapter->dev.parent); + + } +#endif +#endif msleep(I2C_WAIT_BEFORE_RETRY); + logError(1, "ERROR: %d\n", ret); + } //logError(1,"%s fts_writeCmd: attempt %d\n", tag, retry); } if (ret < 0) { +#ifdef CONFIG_ST_TRUSTED_TOUCH +#ifdef CONFIG_ARCH_QTI_VM + pr_err("initiating abort due to i2c xfer failure\n"); + fts_trusted_touch_tvm_i2c_failure_report(info); +#endif +#endif logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_W); - return ERROR_I2C_W; + return ret; } return OK; } diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTool.c b/drivers/input/touchscreen/st/fts_lib/ftsTool.c index 543682d1e3c6..55285fd18892 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsTool.c +++ b/drivers/input/touchscreen/st/fts_lib/ftsTool.c @@ -789,11 +789,13 @@ int fts_disableInterrupt(void) int fts_enableInterrupt(void) { u8 cmd[4] = { FTS_CMD_HW_REG_W, 0x00, 0x00, IER_ENABLE }; + int ret = 0; u16ToU8_be(IER_ADDR, &cmd[1]); - if (fts_writeCmd(cmd, 4) < 0) { - logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_W); - return ERROR_I2C_W; + ret = fts_writeCmd(cmd, 4); + if (ret < 0) { + logError(1, "%s %s: ERROR %d\n", tag, __func__, ret); + return ret; } logError(0, "%s Interrupt Enabled!\n", tag); return OK;