From 6aca8a8c075f551ee266d7c806e467109db4eabe Mon Sep 17 00:00:00 2001 From: Ritesh Kumar Date: Wed, 21 Oct 2020 13:56:08 +0530 Subject: [PATCH] input: touchscreen: focaltech: TUI error handling state machine Introduce state machine for various checkpoints in trusted touch usecase. In error scenarios, this state machine helps driver to rollback to previous state. Change-Id: Ia9f9e01905b5d1561dd21ea782cf9f09001d35a7 Signed-off-by: Ritesh Kumar --- .../focaltech_touch/focaltech_core.c | 581 ++++++++++++------ .../focaltech_touch/focaltech_core.h | 53 +- .../focaltech_touch/focaltech_ex_fun.c | 54 ++ 3 files changed, 508 insertions(+), 180 deletions(-) diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_core.c b/drivers/input/touchscreen/focaltech_touch/focaltech_core.c index e5dc7106c8c5..4b569e61c93c 100644 --- a/drivers/input/touchscreen/focaltech_touch/focaltech_core.c +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_core.c @@ -100,6 +100,8 @@ static int fts_ts_probe_delayed(struct fts_ts_data *fts_data); #ifdef CONFIG_FTS_TRUSTED_TOUCH +static void fts_ts_trusted_touch_abort_handler(struct fts_ts_data *fts_data, + int error); static struct hh_acl_desc *fts_ts_vm_get_acl(enum hh_vm_names vm_name) { struct hh_acl_desc *acl_desc; @@ -241,7 +243,28 @@ static void fts_ts_vm_deinit(struct fts_ts_data *fts_data) #ifdef CONFIG_ARCH_QTI_VM static int fts_ts_vm_mem_release(struct fts_ts_data *fts_data); -static void fts_ts_trusted_touch_vm_mode_disable(struct fts_ts_data *fts_data); +static void fts_ts_trusted_touch_tvm_vm_mode_disable(struct fts_ts_data *fts_data); +static void fts_ts_trusted_touch_abort_tvm(struct fts_ts_data *fts_data); +static void fts_ts_trusted_touch_event_notify(struct fts_ts_data *fts_data, int event); + +static int fts_ts_trusted_touch_get_tvm_driver_state(struct fts_ts_data *fts_data) +{ + int state; + + mutex_lock(&fts_data->vm_info->tvm_state_mutex); + state = atomic_read(&fts_data->vm_info->tvm_state); + mutex_unlock(&fts_data->vm_info->tvm_state_mutex); + + return state; +} + +static void fts_ts_trusted_touch_set_tvm_driver_state(struct fts_ts_data *fts_data, + int state) +{ + mutex_lock(&fts_data->vm_info->tvm_state_mutex); + atomic_set(&fts_data->vm_info->tvm_state, state); + mutex_unlock(&fts_data->vm_info->tvm_state_mutex); +} static int fts_ts_sgl_cmp(const void *a, const void *b) { @@ -293,69 +316,130 @@ static int fts_ts_vm_handle_vm_hardware(struct fts_ts_data *fts_data) } fts_irq_enable(); + fts_ts_trusted_touch_set_tvm_driver_state(fts_data, TVM_INTERRUPT_ENABLED); return rc; } +static void fts_ts_trusted_touch_tvm_vm_mode_enable(struct fts_ts_data *fts_data) +{ + + struct hh_sgl_desc *sgl_desc, *expected_sgl_desc; + struct hh_acl_desc *acl_desc; + struct irq_data *irq_data; + int rc = 0; + int irq = 0; + + if (fts_ts_trusted_touch_get_tvm_driver_state(fts_data) != + TVM_ALL_RESOURCES_LENT_NOTIFIED) { + pr_err("All lend notifications not received\n"); + fts_ts_trusted_touch_event_notify(fts_data, + TRUSTED_TOUCH_EVENT_NOTIFICATIONS_PENDING); + return; + } + + acl_desc = fts_ts_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(fts_data->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_ts_trusted_touch_set_tvm_driver_state(fts_data, TVM_IOMEM_ACCEPTED); + + /* Initiate i2c session on tvm */ + rc = pm_runtime_get_sync(fts_data->client->adapter->dev.parent); + if (rc < 0) { + pr_err("failed to get sync rc:%d\n", rc); + goto acl_fail; + } + fts_ts_trusted_touch_set_tvm_driver_state(fts_data, TVM_I2C_SESSION_ACQUIRED); + + expected_sgl_desc = fts_ts_vm_get_sgl(fts_data->vm_info); + if (fts_ts_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); + + irq = hh_irq_accept(fts_data->vm_info->irq_label, -1, IRQ_TYPE_EDGE_RISING); + if (irq < 0) { + pr_err("failed to accept irq\n"); + goto accept_fail; + } + fts_ts_trusted_touch_set_tvm_driver_state(fts_data, TVM_IRQ_ACCEPTED); + + + irq_data = irq_get_irq_data(irq); + if (!irq_data) { + pr_err("Invalid irq data for trusted touch\n"); + goto accept_fail; + } + if (!irq_data->hwirq) { + pr_err("Invalid irq in irq data\n"); + goto accept_fail; + } + if (irq_data->hwirq != fts_data->vm_info->hw_irq) { + pr_err("Invalid irq lent\n"); + goto accept_fail; + } + + pr_debug("irq:returned from accept:%d\n", irq); + fts_data->irq = irq; + + rc = fts_ts_vm_handle_vm_hardware(fts_data); + if (rc) { + pr_err(" Delayed probe failure on VM!\n"); + goto accept_fail; + } + atomic_set(&fts_data->trusted_touch_enabled, 1); + pr_info("trusted touch enabled\n"); + + return; +sgl_cmp_fail: + kfree(expected_sgl_desc); +acl_fail: + kfree(acl_desc); +accept_fail: + fts_ts_trusted_touch_abort_handler(fts_data, + TRUSTED_TOUCH_EVENT_ACCEPT_FAILURE); +} static void fts_ts_vm_irq_on_lend_callback(void *data, unsigned long notif_type, enum hh_irq_label label) { struct fts_ts_data *fts_data = data; - struct irq_data *irq_data; - int irq = 0; - int const resource_timeout = msecs_to_jiffies(2000); - int rc = 0; - irq = hh_irq_accept(fts_data->vm_info->irq_label, -1, - IRQ_TYPE_EDGE_RISING); - if (irq < 0) { - pr_err("failed to accept irq\n"); - goto irq_fail; + pr_debug("received irq lend request for label:%d\n", label); + if (fts_ts_trusted_touch_get_tvm_driver_state(fts_data) == + TVM_IOMEM_LENT_NOTIFIED) { + fts_ts_trusted_touch_set_tvm_driver_state(fts_data, + TVM_ALL_RESOURCES_LENT_NOTIFIED); + } else { + fts_ts_trusted_touch_set_tvm_driver_state(fts_data, + TVM_IRQ_LENT_NOTIFIED); } - atomic_set(&fts_data->vm_info->tvm_owns_irq, 1); - irq_data = irq_get_irq_data(irq); - if (!irq_data) { - pr_err("Invalid irq data for trusted touch\n"); - goto irq_fail; - } - if (!irq_data->hwirq) { - pr_err("Invalid irq in irq data\n"); - goto irq_fail; - } - if (irq_data->hwirq != fts_data->vm_info->hw_irq) { - pr_err("Invalid irq lent\n"); - goto irq_fail; - } - - pr_debug("irq:returned from accept:%d\n", irq); - fts_data->irq = irq; - if (!wait_for_completion_timeout(&fts_data->resource_checkpoint, - resource_timeout)) { - pr_err("Resources not acquired in TVM\n"); - goto irq_fail; - } - - rc = fts_ts_vm_handle_vm_hardware(fts_data); - if (rc) { - pr_err(" Delayed probe failure on VM!\n"); - goto irq_fail; - } - - atomic_set(&fts_data->trusted_touch_enabled, 1); - return; -irq_fail: - fts_ts_trusted_touch_vm_mode_disable(fts_data); } static void fts_ts_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_data *fts_data; - int rc = 0; if (notif_type != HH_RM_NOTIF_MEM_SHARED || tag != HH_MEM_NOTIFIER_TAG_TOUCH) { @@ -379,62 +463,31 @@ static void fts_ts_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; - } - - acl_desc = fts_ts_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(fts_data->client->adapter->dev.parent); - if (rc < 0) { - pr_err("failed to get sync rc:%d\n", rc); - (void)fts_ts_vm_mem_release(fts_data); - atomic_set(&fts_data->vm_info->tvm_owns_iomem, 0); - goto acl_fail; - } - complete(&fts_data->resource_checkpoint); - - expected_sgl_desc = fts_ts_vm_get_sgl(vm_info); - if (fts_ts_vm_compare_sgl_desc(expected_sgl_desc, sgl_desc)) { - pr_err("IO sg list does not match\n"); - goto sgl_cmp_fail; + return; } vm_info->vm_mem_handle = payload->mem_handle; - kfree(expected_sgl_desc); - kfree(acl_desc); - return; - -sgl_cmp_fail: - kfree(expected_sgl_desc); -acl_fail: - kfree(acl_desc); -onlend_fail: - fts_ts_trusted_touch_vm_mode_disable(fts_data); + pr_debug("received mem lend request with handle:%d\n", + vm_info->vm_mem_handle); + if (fts_ts_trusted_touch_get_tvm_driver_state(fts_data) == + TVM_IRQ_LENT_NOTIFIED) { + fts_ts_trusted_touch_set_tvm_driver_state(fts_data, + TVM_ALL_RESOURCES_LENT_NOTIFIED); + } else { + fts_ts_trusted_touch_set_tvm_driver_state(fts_data, + TVM_IOMEM_LENT_NOTIFIED); + } } static int fts_ts_vm_mem_release(struct fts_ts_data *fts_data) { int rc = 0; + if (!fts_data->vm_info->vm_mem_handle) { + pr_err("Invalid memory handle\n"); + return -EINVAL; + } + rc = hh_rm_mem_release(fts_data->vm_info->vm_mem_handle, 0); if (rc) pr_err("VM mem release failed: rc=%d\n", rc); @@ -444,44 +497,58 @@ static int fts_ts_vm_mem_release(struct fts_ts_data *fts_data) HH_MEM_NOTIFIER_TAG_TOUCH, 0); if (rc) pr_err("Failed to notify mem release to PVM: rc=%d\n"); + pr_debug("vm mem release succeded\n"); fts_data->vm_info->vm_mem_handle = 0; return rc; } -static void fts_ts_trusted_touch_vm_mode_disable(struct fts_ts_data *fts_data) +static void fts_ts_trusted_touch_tvm_vm_mode_disable(struct fts_ts_data *fts_data) { int rc = 0; - - if (atomic_read(&fts_data->vm_info->tvm_owns_iomem) && - atomic_read(&fts_data->vm_info->tvm_owns_irq)) - fts_irq_disable(); - - if (atomic_read(&fts_data->vm_info->tvm_owns_iomem)) { - fts_release_all_finger(); - rc = fts_ts_vm_mem_release(fts_data); - if (rc) - pr_err("Failed to release mem rc:%d\n", rc); - else - atomic_set(&fts_data->vm_info->tvm_owns_iomem, 0); - pm_runtime_put_sync(fts_data->client->adapter->dev.parent); + if (atomic_read(&fts_data->trusted_touch_abort_status)) { + fts_ts_trusted_touch_abort_tvm(fts_data); + return; } - if (atomic_read(&fts_data->vm_info->tvm_owns_irq)) { - rc = hh_irq_release(fts_data->vm_info->irq_label); - if (rc) - pr_err("Failed to release irq rc:%d\n", rc); - else - atomic_set(&fts_data->vm_info->tvm_owns_irq, 0); + fts_irq_disable(); + fts_ts_trusted_touch_set_tvm_driver_state(fts_data, + TVM_INTERRUPT_DISABLED); - rc = hh_irq_release_notify(fts_data->vm_info->irq_label); - if (rc) - pr_err("Failed to notify release irq rc:%d\n", rc); + rc = hh_irq_release(fts_data->vm_info->irq_label); + if (rc) { + pr_err("Failed to release irq rc:%d\n", rc); + goto error; + } else { + fts_ts_trusted_touch_set_tvm_driver_state(fts_data, + TVM_IRQ_RELEASED); } + rc = hh_irq_release_notify(fts_data->vm_info->irq_label); + if (rc) + pr_err("Failed to notify release irq rc:%d\n", rc); + + pr_debug("vm irq release succeded\n"); + + fts_release_all_finger(); + rc = fts_ts_vm_mem_release(fts_data); + if (rc) { + pr_err("Failed to release mem rc:%d\n", rc); + goto error; + } else { + fts_ts_trusted_touch_set_tvm_driver_state(fts_data, + TVM_IOMEM_RELEASED); + } + pm_runtime_put_sync(fts_data->client->adapter->dev.parent); + fts_ts_trusted_touch_set_tvm_driver_state(fts_data, + TVM_I2C_SESSION_RELEASED); + fts_ts_trusted_touch_set_tvm_driver_state(fts_data, TRUSTED_TOUCH_TVM_INIT); atomic_set(&fts_data->trusted_touch_enabled, 0); - reinit_completion(&fts_data->resource_checkpoint); - pr_debug("trusted touch disabled\n"); + pr_info("trusted touch disabled\n"); + return; +error: + fts_ts_trusted_touch_abort_handler(fts_data, + TRUSTED_TOUCH_EVENT_RELEASE_FAILURE); } int fts_ts_handle_trusted_touch_tvm(struct fts_ts_data *fts_data, int value) @@ -490,13 +557,14 @@ int fts_ts_handle_trusted_touch_tvm(struct fts_ts_data *fts_data, int value) switch (value) { case 0: - if (atomic_read(&fts_data->trusted_touch_enabled) == 0) { + if ((atomic_read(&fts_data->trusted_touch_enabled) == 0) && + (atomic_read(&fts_data->trusted_touch_abort_status) == 0)) { pr_err("Trusted touch is already disabled\n"); break; } if (atomic_read(&fts_data->trusted_touch_mode) == TRUSTED_TOUCH_VM_MODE) { - fts_ts_trusted_touch_vm_mode_disable(fts_data); + fts_ts_trusted_touch_tvm_vm_mode_disable(fts_data); } else { pr_err("Unsupported trusted touch mode\n"); } @@ -510,7 +578,7 @@ int fts_ts_handle_trusted_touch_tvm(struct fts_ts_data *fts_data, int value) } if (atomic_read(&fts_data->trusted_touch_mode) == TRUSTED_TOUCH_VM_MODE) { - pr_err("Cannot turnon trusted touch(vm mode) in VM\n"); + fts_ts_trusted_touch_tvm_vm_mode_enable(fts_data); } else { pr_err("Unsupported trusted touch mode\n"); } @@ -525,8 +593,115 @@ int fts_ts_handle_trusted_touch_tvm(struct fts_ts_data *fts_data, int value) return err; } +static void fts_ts_trusted_touch_abort_tvm(struct fts_ts_data *fts_data) +{ + int rc = 0; + int tvm_state = fts_ts_trusted_touch_get_tvm_driver_state(fts_data); + + 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_irq_disable(); + case TVM_IRQ_ACCEPTED: + case TVM_INTERRUPT_DISABLED: + rc = hh_irq_release(fts_data->vm_info->irq_label); + if (rc) + pr_err("Failed to release irq rc:%d\n", rc); + rc = hh_irq_release_notify(fts_data->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: + fts_release_all_finger(); + rc = fts_ts_vm_mem_release(fts_data); + if (rc) + pr_err("Failed to release mem rc:%d\n", rc); + case TVM_IOMEM_RELEASED: + pm_runtime_put_sync(fts_data->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(&fts_data->trusted_touch_enabled, 0); + } + + atomic_set(&fts_data->trusted_touch_abort_status, 0); + fts_ts_trusted_touch_set_tvm_driver_state(fts_data, TRUSTED_TOUCH_TVM_INIT); +} + #else +static void fts_ts_bus_put(struct fts_ts_data *fts_data); + +static int fts_ts_trusted_touch_get_pvm_driver_state(struct fts_ts_data *fts_data) +{ + int state; + + mutex_lock(&fts_data->vm_info->pvm_state_mutex); + state = atomic_read(&fts_data->vm_info->pvm_state); + mutex_unlock(&fts_data->vm_info->pvm_state_mutex); + + return state; + +} + +static void fts_ts_trusted_touch_set_pvm_driver_state(struct fts_ts_data *fts_data, + int state) +{ + mutex_lock(&fts_data->vm_info->pvm_state_mutex); + atomic_set(&fts_data->vm_info->pvm_state, state); + mutex_unlock(&fts_data->vm_info->pvm_state_mutex); +} + +static void fts_ts_trusted_touch_abort_pvm(struct fts_ts_data *fts_data) +{ + int rc = 0; + int pvm_state = fts_ts_trusted_touch_get_pvm_driver_state(fts_data); + + 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(fts_data->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(fts_data->vm_info->vm_mem_handle, 0); + if (rc) + pr_err("failed to reclaim iomem on pvm rc:%d\n", rc); + fts_data->vm_info->vm_mem_handle = 0; + case PVM_IOMEM_RECLAIMED: + case PVM_INTERRUPT_DISABLED: + fts_irq_enable(); + case PVM_I2C_RESOURCE_ACQUIRED: + case PVM_INTERRUPT_ENABLED: + fts_ts_bus_put(fts_data); + complete(&fts_data->trusted_touch_powerdown); + case TRUSTED_TOUCH_PVM_INIT: + case PVM_I2C_RESOURCE_RELEASED: + atomic_set(&fts_data->trusted_touch_enabled, 0); + } + + atomic_set(&fts_data->trusted_touch_abort_status, 0); + + fts_ts_trusted_touch_set_pvm_driver_state(fts_data, TRUSTED_TOUCH_PVM_INIT); +} + static int fts_ts_clk_prepare_enable(struct fts_ts_data *fts_data) { int ret; @@ -591,18 +766,48 @@ static struct hh_notify_vmid_desc *fts_ts_vm_get_vmid(hh_vmid_t vmid) return vmid_desc; } -static void fts_ts_trusted_touch_complete(struct fts_ts_data *fts_data) +static void fts_trusted_touch_pvm_vm_mode_disable(struct fts_ts_data *fts_data) { - if (atomic_read(&fts_data->vm_info->pvm_owns_iomem) && - atomic_read(&fts_data->vm_info->pvm_owns_irq)) { - fts_irq_enable(); - fts_ts_bus_put(fts_data); - complete(&fts_data->trusted_touch_powerdown); - atomic_set(&fts_data->trusted_touch_enabled, 0); - pr_debug("reenabled interrupts on PVM\n"); - } else { - pr_err("PVM does not own irq and IOMEM\n"); + int rc = 0; + + if (atomic_read(&fts_data->trusted_touch_abort_status)) { + fts_ts_trusted_touch_abort_pvm(fts_data); + return; } + + if (fts_ts_trusted_touch_get_pvm_driver_state(fts_data) != + PVM_ALL_RESOURCES_RELEASE_NOTIFIED) + pr_err("all release notifications are not received yet\n"); + + rc = hh_irq_reclaim(fts_data->vm_info->irq_label); + if (rc) { + pr_err("failed to reclaim irq on pvm rc:%d\n", rc); + goto error; + } + fts_ts_trusted_touch_set_pvm_driver_state(fts_data, + PVM_IRQ_RECLAIMED); + + rc = hh_rm_mem_reclaim(fts_data->vm_info->vm_mem_handle, 0); + if (rc) { + pr_err("Trusted touch VM mem reclaim failed rc:%d\n", rc); + goto error; + } + fts_ts_trusted_touch_set_pvm_driver_state(fts_data, PVM_IOMEM_RECLAIMED); + fts_data->vm_info->vm_mem_handle = 0; + + fts_irq_enable(); + fts_ts_trusted_touch_set_pvm_driver_state(fts_data, PVM_INTERRUPT_ENABLED); + fts_ts_bus_put(fts_data); + fts_ts_trusted_touch_set_pvm_driver_state(fts_data, + PVM_I2C_RESOURCE_RELEASED); + complete(&fts_data->trusted_touch_powerdown); + fts_ts_trusted_touch_set_pvm_driver_state(fts_data, + TRUSTED_TOUCH_PVM_INIT); + atomic_set(&fts_data->trusted_touch_enabled, 0); + return; +error: + fts_ts_trusted_touch_abort_handler(fts_data, + TRUSTED_TOUCH_EVENT_RECLAIM_FAILURE); } static void fts_ts_vm_irq_on_release_callback(void *data, @@ -610,26 +815,36 @@ static void fts_ts_vm_irq_on_release_callback(void *data, enum hh_irq_label label) { struct fts_ts_data *fts_data = data; - int rc = 0; - rc = hh_irq_reclaim(fts_data->vm_info->irq_label); - if (rc) - pr_err("failed to reclaim irq on pvm rc:%d\n", rc); - else - atomic_set(&fts_data->vm_info->pvm_owns_irq, 1); + if (notif_type != HH_RM_NOTIF_VM_IRQ_RELEASED) { + pr_err("invalid notification type\n"); + return; + } + + if (fts_ts_trusted_touch_get_pvm_driver_state(fts_data) == + PVM_IOMEM_RELEASE_NOTIFIED) { + fts_ts_trusted_touch_set_pvm_driver_state(fts_data, + PVM_ALL_RESOURCES_RELEASE_NOTIFIED); + } else { + fts_ts_trusted_touch_set_pvm_driver_state(fts_data, + PVM_IRQ_RELEASE_NOTIFIED); + } } static void fts_ts_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_data *fts_data; - 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; } @@ -638,7 +853,6 @@ static void fts_ts_vm_mem_on_release_handler(enum hh_mem_notifier_tag tag, return; } - payload = (struct hh_rm_notif_mem_released_payload *)notif_msg; fts_data = (struct fts_ts_data *)entry_data; vm_info = fts_data->vm_info; if (!vm_info) { @@ -646,18 +860,20 @@ static void fts_ts_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_ts_trusted_touch_get_pvm_driver_state(fts_data) == + PVM_IRQ_RELEASE_NOTIFIED) { + fts_ts_trusted_touch_set_pvm_driver_state(fts_data, + PVM_ALL_RESOURCES_RELEASE_NOTIFIED); + } else { + fts_ts_trusted_touch_set_pvm_driver_state(fts_data, + PVM_IOMEM_RELEASE_NOTIFIED); } - atomic_set(&vm_info->pvm_owns_iomem, 1); - vm_info->vm_mem_handle = 0; } static int fts_ts_vm_mem_lend(struct fts_ts_data *fts_data) @@ -692,6 +908,10 @@ static int fts_ts_vm_mem_lend(struct fts_ts_data *fts_data) goto error; } + pr_info("vm mem lend succeded\n"); + + fts_ts_trusted_touch_set_pvm_driver_state(fts_data, PVM_IOMEM_LENT); + hh_rm_get_vmid(HH_TRUSTED_VM, &trusted_vmid); vmid_desc = fts_ts_vm_get_vmid(trusted_vmid); @@ -703,6 +923,8 @@ static int fts_ts_vm_mem_lend(struct fts_ts_data *fts_data) goto vmid_error; } + fts_ts_trusted_touch_set_pvm_driver_state(fts_data, PVM_IOMEM_LENT_NOTIFIED); + fts_data->vm_info->vm_mem_handle = mem_handle; vmid_error: kfree(vmid_desc); @@ -714,7 +936,7 @@ sgl_error: return rc; } -static int fts_ts_trusted_touch_vm_mode_enable(struct fts_ts_data *fts_data) +static int fts_ts_trusted_touch_pvm_vm_mode_enable(struct fts_ts_data *fts_data) { int rc = 0; struct trusted_touch_vm_info *vm_info = fts_data->vm_info; @@ -726,35 +948,42 @@ static int fts_ts_trusted_touch_vm_mode_enable(struct fts_ts_data *fts_data) return rc; } + fts_ts_trusted_touch_set_pvm_driver_state(fts_data, PVM_I2C_RESOURCE_ACQUIRED); /* flush pending interurpts from FIFO */ fts_irq_disable(); + fts_ts_trusted_touch_set_pvm_driver_state(fts_data, PVM_INTERRUPT_DISABLED); fts_release_all_finger(); rc = fts_ts_vm_mem_lend(fts_data); 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, fts_data->irq, &fts_ts_vm_irq_on_release_callback, fts_data); 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", fts_data->irq); + fts_ts_trusted_touch_set_pvm_driver_state(fts_data, 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_ts_trusted_touch_set_pvm_driver_state(fts_data, PVM_IRQ_LENT_NOTIFIED); reinit_completion(&fts_data->trusted_touch_powerdown); atomic_set(&fts_data->trusted_touch_enabled, 1); pr_debug("trusted touch enabled\n"); return rc; +error: + fts_ts_trusted_touch_abort_handler(fts_data, TRUSTED_TOUCH_EVENT_LEND_FAILURE); + return rc; } int fts_ts_handle_trusted_touch_pvm(struct fts_ts_data *fts_data, int value) @@ -763,13 +992,14 @@ int fts_ts_handle_trusted_touch_pvm(struct fts_ts_data *fts_data, int value) switch (value) { case 0: - if (atomic_read(&fts_data->trusted_touch_enabled) == 0) { + if (atomic_read(&fts_data->trusted_touch_enabled) == 0 && + (atomic_read(&fts_data->trusted_touch_abort_status) == 0)) { pr_err("Trusted touch is already disabled\n"); break; } if (atomic_read(&fts_data->trusted_touch_mode) == TRUSTED_TOUCH_VM_MODE) { - fts_ts_trusted_touch_complete(fts_data); + fts_trusted_touch_pvm_vm_mode_disable(fts_data); } else { pr_err("Unsupported trusted touch mode\n"); } @@ -783,7 +1013,7 @@ int fts_ts_handle_trusted_touch_pvm(struct fts_ts_data *fts_data, int value) } if (atomic_read(&fts_data->trusted_touch_mode) == TRUSTED_TOUCH_VM_MODE) { - err = fts_ts_trusted_touch_vm_mode_enable(fts_data); + err = fts_ts_trusted_touch_pvm_vm_mode_enable(fts_data); } else { pr_err("Unsupported trusted touch mode\n"); } @@ -799,6 +1029,19 @@ int fts_ts_handle_trusted_touch_pvm(struct fts_ts_data *fts_data, int value) #endif +static void fts_ts_trusted_touch_event_notify(struct fts_ts_data *fts_data, int event) +{ + atomic_set(&fts_data->trusted_touch_event, event); + sysfs_notify(&fts_data->client->dev.kobj, NULL, "trusted_touch_event"); +} + +static void fts_ts_trusted_touch_abort_handler(struct fts_ts_data *fts_data, int error) +{ + atomic_set(&fts_data->trusted_touch_abort_status, error); + pr_err("TUI session aborted with failure:%d\n", error); + fts_ts_trusted_touch_event_notify(fts_data, error); +} + static int fts_ts_vm_init(struct fts_ts_data *fts_data) { int rc = 0; @@ -824,9 +1067,8 @@ static int fts_ts_vm_init(struct fts_ts_data *fts_data) vm_info->mem_cookie = mem_cookie; rc = hh_irq_wait_for_lend_v2(vm_info->irq_label, HH_PRIMARY_VM, &fts_ts_vm_irq_on_lend_callback, fts_data); - atomic_set(&vm_info->tvm_owns_irq, 0); - atomic_set(&vm_info->tvm_owns_iomem, 0); - init_completion(&fts_data->resource_checkpoint); + mutex_init(&fts_data->vm_info->tvm_state_mutex); + fts_ts_trusted_touch_set_tvm_driver_state(fts_data, TRUSTED_TOUCH_TVM_INIT); #else mem_cookie = hh_mem_notifier_register(HH_MEM_NOTIFIER_TAG_TOUCH, fts_ts_vm_mem_on_release_handler, fts_data); @@ -836,8 +1078,8 @@ static int fts_ts_vm_init(struct fts_ts_data *fts_data) 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(&fts_data->vm_info->pvm_state_mutex); + fts_ts_trusted_touch_set_pvm_driver_state(fts_data, TRUSTED_TOUCH_PVM_INIT); #endif return rc; init_fail: @@ -1557,17 +1799,6 @@ static irqreturn_t fts_irq_handler(int irq, void *data) return IRQ_HANDLED; } -#ifdef CONFIG_FTS_TRUSTED_TOUCH -#ifndef CONFIG_ARCH_QTI_VM - if (atomic_read(&fts_data->trusted_touch_enabled)) { - if (atomic_read(&fts_data->vm_info->pvm_owns_iomem) && - atomic_read(&fts_data->vm_info->pvm_owns_irq)) { - pr_err("Trusted Touch Enabled: Cannot service irq\n"); - return IRQ_HANDLED; - } - } -#endif -#endif fts_irq_read_report(); return IRQ_HANDLED; } diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_core.h b/drivers/input/touchscreen/focaltech_touch/focaltech_core.h index ca7112f0a449..ddfd46fd2c92 100644 --- a/drivers/input/touchscreen/focaltech_touch/focaltech_core.h +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_core.h @@ -144,6 +144,48 @@ 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 +}; + +#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_NOTIFICATIONS_PENDING 5 + #ifdef CONFIG_FTS_TRUSTED_TOUCH #define TRUSTED_TOUCH_MEM_LABEL 0x7 @@ -157,11 +199,11 @@ 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 }; #endif @@ -225,11 +267,12 @@ struct fts_ts_data { 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/focaltech_touch/focaltech_ex_fun.c b/drivers/input/touchscreen/focaltech_touch/focaltech_ex_fun.c index 4389bed4cb4c..3b9174432e2b 100644 --- a/drivers/input/touchscreen/focaltech_touch/focaltech_ex_fun.c +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_ex_fun.c @@ -1120,6 +1120,58 @@ static ssize_t trusted_touch_enable_store(struct device *dev, return err; } +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_data *info; + + if (!client) + return scnprintf(buf, PAGE_SIZE, "client is null\n"); + + info = i2c_get_clientdata(client); + if (!info) { + FTS_ERROR("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_data *info; + unsigned long value; + int err = 0; + + if (!client) + return -EIO; + info = i2c_get_clientdata(client); + if (!info) { + FTS_ERROR("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; +} + #endif /* get the fw version example:cat fw_version */ @@ -1148,6 +1200,7 @@ static DEVICE_ATTR(fts_touch_point, S_IRUGO | S_IWUSR, fts_tpbuf_show, fts_tpbuf static DEVICE_ATTR(fts_log_level, S_IRUGO | S_IWUSR, fts_log_level_show, fts_log_level_store); #ifdef CONFIG_FTS_TRUSTED_TOUCH static DEVICE_ATTR_RW(trusted_touch_enable); +static DEVICE_ATTR_RW(trusted_touch_event); #endif /* add your attr in here*/ @@ -1163,6 +1216,7 @@ static struct attribute *fts_attributes[] = { &dev_attr_fts_log_level.attr, #ifdef CONFIG_FTS_TRUSTED_TOUCH &dev_attr_trusted_touch_enable.attr, + &dev_attr_trusted_touch_event.attr, #endif NULL };