diff --git a/arch/arm64/configs/vendor/genericarmv8-64_defconfig b/arch/arm64/configs/vendor/genericarmv8-64_defconfig index 9b1a06b91e46..c906cb50c352 100644 --- a/arch/arm64/configs/vendor/genericarmv8-64_defconfig +++ b/arch/arm64/configs/vendor/genericarmv8-64_defconfig @@ -151,6 +151,8 @@ CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_ATMEL_MXT=m CONFIG_TOUCHSCREEN_ST=y CONFIG_ST_TRUSTED_TOUCH=y +CONFIG_TOUCHSCREEN_FTS=y +CONFIG_FTS_TRUSTED_TOUCH=y CONFIG_INPUT_MISC=y # CONFIG_SERIO_SERPORT is not set CONFIG_SERIO_AMBAKMI=y diff --git a/arch/arm64/configs/vendor/lahaina_GKI.config b/arch/arm64/configs/vendor/lahaina_GKI.config index e901030d3059..0db72e6249f9 100644 --- a/arch/arm64/configs/vendor/lahaina_GKI.config +++ b/arch/arm64/configs/vendor/lahaina_GKI.config @@ -211,6 +211,7 @@ CONFIG_TOUCHSCREEN_USB_COMPOSITE=m CONFIG_TOUCHSCREEN_ST=m CONFIG_ST_TRUSTED_TOUCH=y CONFIG_TOUCHSCREEN_FTS=m +CONFIG_FTS_TRUSTED_TOUCH=y CONFIG_TOUCHSCREEN_ATMEL_MXT=m CONFIG_SPS=m CONFIG_SPS_SUPPORT_NDP_BAM=y diff --git a/drivers/input/touchscreen/focaltech_touch/Kconfig b/drivers/input/touchscreen/focaltech_touch/Kconfig index e306f02058a7..1a5edec3d8e0 100644 --- a/drivers/input/touchscreen/focaltech_touch/Kconfig +++ b/drivers/input/touchscreen/focaltech_touch/Kconfig @@ -12,3 +12,12 @@ config TOUCHSCREEN_FTS_DIRECTORY string "Focaltech ts directory name" default "focaltech_touch" depends on TOUCHSCREEN_FTS + +config FTS_TRUSTED_TOUCH + bool "Focaltech Trusted Touch" + depends on TOUCHSCREEN_FTS + help + Say Y here to enable Focaltech Trusted Touch. + If unsure, say N. + +#endif diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_core.c b/drivers/input/touchscreen/focaltech_touch/focaltech_core.c index 3ca97d949b52..2fb409092368 100644 --- a/drivers/input/touchscreen/focaltech_touch/focaltech_core.c +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_core.c @@ -32,11 +32,14 @@ * Included header files *****************************************************************************/ #include +#include #include #include #include #include #include +#include +#include #if defined(CONFIG_DRM) #include #elif defined(CONFIG_FB) @@ -48,6 +51,22 @@ #endif #include "focaltech_core.h" +#if defined(CONFIG_FTS_TRUSTED_TOUCH) +#include +#include +#include +#include +#include +#include +#include +#include +#include "linux/haven/hh_irq_lend.h" +#include "linux/haven/hh_msgq.h" +#include "linux/haven/hh_mem_notifier.h" +#include "linux/haven/hh_rm_drv.h" +#include +#endif + /***************************************************************************** * Private constant and macro definitions using #define *****************************************************************************/ @@ -76,6 +95,822 @@ static struct drm_panel *active_panel; *****************************************************************************/ static int fts_ts_suspend(struct device *dev); static int fts_ts_resume(struct device *dev); +static irqreturn_t fts_irq_handler(int irq, void *data); +static int fts_ts_probe_delayed(struct fts_ts_data *fts_data); + +#ifdef CONFIG_FTS_TRUSTED_TOUCH + +static struct hh_acl_desc *fts_ts_vm_get_acl(enum hh_vm_names vm_name) +{ + struct hh_acl_desc *acl_desc; + hh_vmid_t vmid; + + hh_rm_get_vmid(vm_name, &vmid); + + acl_desc = kzalloc(offsetof(struct hh_acl_desc, acl_entries[1]), + GFP_KERNEL); + if (!acl_desc) + return ERR_PTR(ENOMEM); + + acl_desc->n_acl_entries = 1; + acl_desc->acl_entries[0].vmid = vmid; + acl_desc->acl_entries[0].perms = HH_RM_ACL_R | HH_RM_ACL_W; + + return acl_desc; +} + +static struct hh_sgl_desc *fts_ts_vm_get_sgl( + struct trusted_touch_vm_info *vm_info) +{ + struct hh_sgl_desc *sgl_desc; + int i; + + sgl_desc = kzalloc(offsetof(struct hh_sgl_desc, + sgl_entries[vm_info->iomem_list_size]), GFP_KERNEL); + if (!sgl_desc) + return ERR_PTR(ENOMEM); + + sgl_desc->n_sgl_entries = vm_info->iomem_list_size; + + for (i = 0; i < vm_info->iomem_list_size; i++) { + sgl_desc->sgl_entries[i].ipa_base = vm_info->iomem_bases[i]; + sgl_desc->sgl_entries[i].size = vm_info->iomem_sizes[i]; + } + + return sgl_desc; +} + +static int fts_ts_populate_vm_info(struct fts_ts_data *fts_data) +{ + int rc = 0; + struct trusted_touch_vm_info *vm_info; + struct device_node *np = fts_data->client->dev.of_node; + int num_regs, num_sizes = 0; + + vm_info = kzalloc(sizeof(struct trusted_touch_vm_info), GFP_KERNEL); + if (!vm_info) { + rc = -ENOMEM; + goto error; + } + + fts_data->vm_info = vm_info; + vm_info->irq_label = HH_IRQ_LABEL_TRUSTED_TOUCH; + vm_info->vm_name = HH_TRUSTED_VM; + rc = of_property_read_u32(np, "focaltech,trusted-touch-spi-irq", + &vm_info->hw_irq); + if (rc) { + pr_err("Failed to read trusted touch SPI irq:%d\n", rc); + goto vm_error; + } + num_regs = of_property_count_u32_elems(np, + "focaltech,trusted-touch-io-bases"); + if (num_regs < 0) { + pr_err("Invalid number of IO regions specified\n"); + rc = -EINVAL; + goto vm_error; + } + + num_sizes = of_property_count_u32_elems(np, + "focaltech,trusted-touch-io-sizes"); + if (num_sizes < 0) { + pr_err("Invalid number of IO regions specified\n"); + rc = -EINVAL; + goto vm_error; + } + + if (num_regs != num_sizes) { + pr_err("IO bases and sizes doe not match\n"); + rc = -EINVAL; + goto vm_error; + } + + vm_info->iomem_list_size = num_regs; + + vm_info->iomem_bases = kcalloc(num_regs, sizeof(*vm_info->iomem_bases), + GFP_KERNEL); + if (!vm_info->iomem_bases) { + rc = -ENOMEM; + goto vm_error; + } + + rc = of_property_read_u32_array(np, "focaltech,trusted-touch-io-bases", + vm_info->iomem_bases, vm_info->iomem_list_size); + if (rc) { + pr_err("Failed to read trusted touch io bases:%d\n", rc); + goto io_bases_error; + } + + vm_info->iomem_sizes = kzalloc( + sizeof(*vm_info->iomem_sizes) * num_sizes, GFP_KERNEL); + if (!vm_info->iomem_sizes) { + rc = -ENOMEM; + goto io_bases_error; + } + + rc = of_property_read_u32_array(np, "focaltech,trusted-touch-io-sizes", + vm_info->iomem_sizes, vm_info->iomem_list_size); + if (rc) { + pr_err("Failed to read trusted touch io sizes:%d\n", rc); + goto io_sizes_error; + } + return rc; + +io_sizes_error: + kfree(vm_info->iomem_sizes); +io_bases_error: + kfree(vm_info->iomem_bases); +vm_error: + kfree(vm_info); +error: + return rc; +} + +static void fts_ts_destroy_vm_info(struct fts_ts_data *fts_data) +{ + kfree(fts_data->vm_info->iomem_sizes); + kfree(fts_data->vm_info->iomem_bases); + kfree(fts_data->vm_info); +} + +static void fts_ts_vm_deinit(struct fts_ts_data *fts_data) +{ + if (fts_data->vm_info->mem_cookie) + hh_mem_notifier_unregister(fts_data->vm_info->mem_cookie); + fts_ts_destroy_vm_info(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 int fts_ts_sgl_cmp(const void *a, const void *b) +{ + struct hh_sgl_entry *left = (struct hh_sgl_entry *)a; + struct hh_sgl_entry *right = (struct hh_sgl_entry *)b; + + return (left->ipa_base - right->ipa_base); +} + +static int fts_ts_vm_compare_sgl_desc(struct hh_sgl_desc *expected, + struct hh_sgl_desc *received) +{ + int idx; + + if (expected->n_sgl_entries != received->n_sgl_entries) + return -E2BIG; + sort(received->sgl_entries, received->n_sgl_entries, + sizeof(received->sgl_entries[0]), fts_ts_sgl_cmp, NULL); + sort(expected->sgl_entries, expected->n_sgl_entries, + sizeof(expected->sgl_entries[0]), fts_ts_sgl_cmp, NULL); + + for (idx = 0; idx < expected->n_sgl_entries; idx++) { + struct hh_sgl_entry *left = &expected->sgl_entries[idx]; + struct hh_sgl_entry *right = &received->sgl_entries[idx]; + + if ((left->ipa_base != right->ipa_base) || + (left->size != right->size)) { + pr_err("sgl mismatch: left_base:%d right base:%d left size:%d right size:%d\n", + left->ipa_base, right->ipa_base, + left->size, right->size); + return -EINVAL; + } + } + return 0; +} + +static int fts_ts_vm_handle_vm_hardware(struct fts_ts_data *fts_data) +{ + int rc = 0; + + if (atomic_read(&fts_data->delayed_vm_probe_pending)) { + rc = fts_ts_probe_delayed(fts_data); + if (rc) { + pr_err(" Delayed probe failure on VM!\n"); + return rc; + } + atomic_set(&fts_data->delayed_vm_probe_pending, 0); + return rc; + } + + fts_irq_enable(); + return rc; +} + +static void fts_ts_vm_irq_on_lend_callback(void *data, 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; + } + 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) { + pr_err("Invalid command passed from rm\n"); + return; + } + + if (!entry_data || !notif_msg) { + pr_err("Invalid entry data passed from rm\n"); + return; + } + + fts_data = (struct fts_ts_data *)entry_data; + vm_info = fts_data->vm_info; + if (!vm_info) { + pr_err("Invalid vm_info\n"); + return; + } + + payload = (struct hh_rm_notif_mem_shared_payload *)notif_msg; + 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; + } + + 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); +} + +static int fts_ts_vm_mem_release(struct fts_ts_data *fts_data) +{ + int rc = 0; + + 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); + + rc = hh_rm_mem_notify(fts_data->vm_info->vm_mem_handle, + HH_RM_MEM_NOTIFY_OWNER, + HH_MEM_NOTIFIER_TAG_TOUCH, 0); + if (rc) + pr_err("Failed to notify mem release to PVM: rc=%d\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) +{ + 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->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); + } + atomic_set(&fts_data->trusted_touch_enabled, 0); + reinit_completion(&fts_data->resource_checkpoint); + pr_debug("trusted touch disabled\n"); +} + +int fts_ts_handle_trusted_touch_tvm(struct fts_ts_data *fts_data, int value) +{ + int err = 0; + + switch (value) { + case 0: + if (atomic_read(&fts_data->trusted_touch_enabled) == 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); + } else { + pr_err("Unsupported trusted touch mode\n"); + } + break; + + case 1: + if (atomic_read(&fts_data->trusted_touch_enabled)) { + pr_err("Trusted touch usecase underway\n"); + err = -EBUSY; + break; + } + if (atomic_read(&fts_data->trusted_touch_mode) == + TRUSTED_TOUCH_VM_MODE) { + pr_err("Cannot turnon trusted touch(vm mode) in VM\n"); + } else { + pr_err("Unsupported trusted touch mode\n"); + } + break; + + default: + FTS_ERROR("unsupported value: %lu\n", value); + err = -EINVAL; + break; + } + + return err; +} + +#else + +static int fts_ts_clk_prepare_enable(struct fts_ts_data *fts_data) +{ + int ret; + + ret = clk_prepare_enable(fts_data->iface_clk); + if (ret) { + FTS_ERROR("error on clk_prepare_enable(iface_clk):%d\n", ret); + return ret; + } + + ret = clk_prepare_enable(fts_data->core_clk); + if (ret) { + clk_disable_unprepare(fts_data->iface_clk); + FTS_ERROR("error clk_prepare_enable(core_clk):%d\n", ret); + } + return ret; +} + +static void fts_ts_clk_disable_unprepare(struct fts_ts_data *fts_data) +{ + clk_disable_unprepare(fts_data->core_clk); + clk_disable_unprepare(fts_data->iface_clk); +} + +static int fts_ts_bus_get(struct fts_ts_data *fts_data) +{ + int rc = 0; + + mutex_lock(&fts_data->fts_clk_io_ctrl_mutex); + rc = pm_runtime_get_sync(fts_data->client->adapter->dev.parent); + if (rc >= 0 && fts_data->core_clk != NULL && + fts_data->iface_clk != NULL) { + rc = fts_ts_clk_prepare_enable(fts_data); + if (rc) + pm_runtime_put_sync( + fts_data->client->adapter->dev.parent); + } + mutex_unlock(&fts_data->fts_clk_io_ctrl_mutex); + return rc; +} + +static void fts_ts_bus_put(struct fts_ts_data *fts_data) +{ + mutex_lock(&fts_data->fts_clk_io_ctrl_mutex); + if (fts_data->core_clk != NULL && fts_data->iface_clk != NULL) + fts_ts_clk_disable_unprepare(fts_data); + pm_runtime_put_sync(fts_data->client->adapter->dev.parent); + mutex_unlock(&fts_data->fts_clk_io_ctrl_mutex); +} + +static struct hh_notify_vmid_desc *fts_ts_vm_get_vmid(hh_vmid_t vmid) +{ + struct hh_notify_vmid_desc *vmid_desc; + + vmid_desc = kzalloc(offsetof(struct hh_notify_vmid_desc, + vmid_entries[1]), GFP_KERNEL); + if (!vmid_desc) + return ERR_PTR(ENOMEM); + + vmid_desc->n_vmid_entries = 1; + vmid_desc->vmid_entries[0].vmid = vmid; + return vmid_desc; +} + +static void fts_ts_trusted_touch_complete(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"); + } +} + +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); +} + +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 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"); + return; + } + + if (!entry_data || !notif_msg) { + pr_err(" Invalid data or notification message\n"); + 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) { + pr_err(" Invalid vm_info\n"); + return; + } + + if (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; + } + 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) +{ + struct hh_acl_desc *acl_desc; + struct hh_sgl_desc *sgl_desc; + struct hh_notify_vmid_desc *vmid_desc; + hh_memparcel_handle_t mem_handle; + hh_vmid_t trusted_vmid; + int rc = 0; + + acl_desc = fts_ts_vm_get_acl(HH_TRUSTED_VM); + if (IS_ERR(acl_desc)) { + pr_err("Failed to get acl of IO memories for Trusted touch\n"); + PTR_ERR(acl_desc); + return -EINVAL; + } + + sgl_desc = fts_ts_vm_get_sgl(fts_data->vm_info); + if (IS_ERR(sgl_desc)) { + pr_err("Failed to get sgl of IO memories for Trusted touch\n"); + PTR_ERR(sgl_desc); + rc = -EINVAL; + goto sgl_error; + } + + rc = hh_rm_mem_lend(HH_RM_MEM_TYPE_IO, 0, TRUSTED_TOUCH_MEM_LABEL, + acl_desc, sgl_desc, NULL, &mem_handle); + if (rc) { + pr_err("Failed to lend IO memories for Trusted touch rc:%d\n", + rc); + goto error; + } + + hh_rm_get_vmid(HH_TRUSTED_VM, &trusted_vmid); + + vmid_desc = fts_ts_vm_get_vmid(trusted_vmid); + + rc = hh_rm_mem_notify(mem_handle, HH_RM_MEM_NOTIFY_RECIPIENT, + HH_MEM_NOTIFIER_TAG_TOUCH, vmid_desc); + if (rc) { + pr_err("Failed to notify mem lend to hypervisor rc:%d\n", rc); + goto vmid_error; + } + + fts_data->vm_info->vm_mem_handle = mem_handle; +vmid_error: + kfree(vmid_desc); +error: + kfree(sgl_desc); +sgl_error: + kfree(acl_desc); + + return rc; +} + +static int fts_ts_trusted_touch_vm_mode_enable(struct fts_ts_data *fts_data) +{ + int rc = 0; + struct trusted_touch_vm_info *vm_info = fts_data->vm_info; + + /* i2c session start and resource acquire */ + if (fts_ts_bus_get(fts_data) < 0) { + FTS_ERROR("fts_ts_bus_get failed\n"); + rc = -EIO; + return rc; + } + + /* flush pending interurpts from FIFO */ + fts_irq_disable(); + fts_release_all_finger(); + + rc = fts_ts_vm_mem_lend(fts_data); + if (rc) { + pr_err("Failed to lend memory\n"); + return -EINVAL; + } + atomic_set(&vm_info->pvm_owns_iomem, 0); + + rc = hh_irq_lend(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; + } + atomic_set(&vm_info->pvm_owns_irq, 0); + + reinit_completion(&fts_data->trusted_touch_powerdown); + atomic_set(&fts_data->trusted_touch_enabled, 1); + pr_debug("trusted touch enabled\n"); + return rc; +} + +int fts_ts_handle_trusted_touch_pvm(struct fts_ts_data *fts_data, int value) +{ + int err = 0; + + switch (value) { + case 0: + if (atomic_read(&fts_data->trusted_touch_enabled) == 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); + } else { + pr_err("Unsupported trusted touch mode\n"); + } + break; + + case 1: + if (atomic_read(&fts_data->trusted_touch_enabled)) { + pr_err("Trusted touch usecase underway\n"); + err = -EBUSY; + break; + } + if (atomic_read(&fts_data->trusted_touch_mode) == + TRUSTED_TOUCH_VM_MODE) { + err = fts_ts_trusted_touch_vm_mode_enable(fts_data); + } else { + pr_err("Unsupported trusted touch mode\n"); + } + break; + + default: + FTS_ERROR("unsupported value: %lu\n", value); + err = -EINVAL; + break; + } + return err; +} + +#endif + +static int fts_ts_vm_init(struct fts_ts_data *fts_data) +{ + int rc = 0; + struct trusted_touch_vm_info *vm_info; + void *mem_cookie; + + rc = fts_ts_populate_vm_info(fts_data); + if (rc) { + pr_err("Cannot setup vm pipeline\n"); + rc = -EINVAL; + goto fail; + } + + vm_info = fts_data->vm_info; +#ifdef CONFIG_ARCH_QTI_VM + mem_cookie = hh_mem_notifier_register(HH_MEM_NOTIFIER_TAG_TOUCH, + fts_ts_vm_mem_on_lend_handler, fts_data); + if (!mem_cookie) { + pr_err("Failed to register on lend mem notifier\n"); + rc = -EINVAL; + goto init_fail; + } + vm_info->mem_cookie = mem_cookie; + rc = hh_irq_wait_for_lend(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); +#else + mem_cookie = hh_mem_notifier_register(HH_MEM_NOTIFIER_TAG_TOUCH, + fts_ts_vm_mem_on_release_handler, fts_data); + if (!mem_cookie) { + pr_err("Failed to register on release mem notifier\n"); + rc = -EINVAL; + 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); +#endif + return rc; +init_fail: + fts_ts_vm_deinit(fts_data); +fail: + return rc; +} + +static void fts_ts_dt_parse_trusted_touch_info(struct fts_ts_data *fts_data) +{ + struct device_node *np = fts_data->client->dev.of_node; + int rc = 0; + const char *selection; + const char *environment; + + rc = of_property_read_string(np, "focaltech,trusted-touch-mode", + &selection); + if (rc) { + dev_warn(&fts_data->client->dev, + "%s: No trusted touch mode selection made\n", __func__); + atomic_set(&fts_data->trusted_touch_mode, + TRUSTED_TOUCH_MODE_NONE); + return; + } + + if (!strcmp(selection, "vm_mode")) { + atomic_set(&fts_data->trusted_touch_mode, + TRUSTED_TOUCH_VM_MODE); + pr_err("Selected trusted touch mode to VM mode\n"); + } else { + atomic_set(&fts_data->trusted_touch_mode, + TRUSTED_TOUCH_MODE_NONE); + pr_err("Invalid trusted_touch mode\n"); + } + + rc = of_property_read_string(np, "focaltech,touch-environment", + &environment); + if (rc) { + dev_warn(&fts_data->client->dev, + "%s: No trusted touch mode environment\n", __func__); + } + fts_data->touch_environment = environment; + pr_err("Trusted touch environment:%s\n", + fts_data->touch_environment); +} + +static void fts_ts_trusted_touch_init(struct fts_ts_data *fts_data) +{ + int rc = 0; + + atomic_set(&fts_data->trusted_touch_initialized, 0); + fts_ts_dt_parse_trusted_touch_info(fts_data); + + if (atomic_read(&fts_data->trusted_touch_mode) == + TRUSTED_TOUCH_MODE_NONE) + return; + + init_completion(&fts_data->trusted_touch_powerdown); + + /* Get clocks */ + fts_data->core_clk = devm_clk_get(fts_data->client->dev.parent, + "m-ahb"); + if (IS_ERR(fts_data->core_clk)) { + fts_data->core_clk = NULL; + dev_warn(&fts_data->client->dev, + "%s: core_clk is not defined\n", __func__); + } + + fts_data->iface_clk = devm_clk_get(fts_data->client->dev.parent, + "se-clk"); + if (IS_ERR(fts_data->iface_clk)) { + fts_data->iface_clk = NULL; + dev_warn(&fts_data->client->dev, + "%s: iface_clk is not defined\n", __func__); + } + + if (atomic_read(&fts_data->trusted_touch_mode) == + TRUSTED_TOUCH_VM_MODE) { + rc = fts_ts_vm_init(fts_data); + if (rc) + pr_err("Failed to init VM\n"); + } + atomic_set(&fts_data->trusted_touch_initialized, 1); +} + +#endif /***************************************************************************** * Name: fts_wait_tp_to_valid @@ -702,6 +1537,24 @@ static void fts_irq_read_report(void) static irqreturn_t fts_irq_handler(int irq, void *data) { + struct fts_ts_data *fts_data = data; + + if (!fts_data) { + pr_err("%s: Invalid fts_data\n", __func__); + 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; } @@ -711,13 +1564,20 @@ static int fts_irq_registration(struct fts_ts_data *ts_data) int ret = 0; struct fts_ts_platform_data *pdata = ts_data->pdata; +#ifdef CONFIG_ARCH_QTI_VM + pdata->irq_gpio_flags = IRQF_TRIGGER_RISING | IRQF_ONESHOT; + FTS_INFO("irq:%d, flag:%x", ts_data->irq, pdata->irq_gpio_flags); + ret = request_threaded_irq(ts_data->irq, NULL, fts_irq_handler, + pdata->irq_gpio_flags, + FTS_DRIVER_NAME, ts_data); +#else ts_data->irq = gpio_to_irq(pdata->irq_gpio); pdata->irq_gpio_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; FTS_INFO("irq:%d, flag:%x", ts_data->irq, pdata->irq_gpio_flags); ret = request_threaded_irq(ts_data->irq, NULL, fts_irq_handler, pdata->irq_gpio_flags, FTS_DRIVER_NAME, ts_data); - +#endif return ret; } @@ -1365,6 +2225,80 @@ static void fts_ts_late_resume(struct early_suspend *handler) } #endif +static int fts_ts_probe_delayed(struct fts_ts_data *fts_data) +{ + int error = 0; + int ret = 0; + +/* Avoid setting up hardware for TVM during probe */ +#ifdef CONFIG_FTS_TRUSTED_TOUCH +#ifdef CONFIG_ARCH_QTI_VM + if (!atomic_read(&fts_data->delayed_vm_probe_pending)) { + atomic_set(&fts_data->delayed_vm_probe_pending, 1); + return 0; + } + goto tvm_setup; +#endif +#endif + ret = fts_gpio_configure(fts_data); + if (ret) { + FTS_ERROR("configure the gpios fail"); + goto err_gpio_config; + } + +#if FTS_POWER_SOURCE_CUST_EN + ret = fts_power_source_init(fts_data); + if (ret) { + FTS_ERROR("fail to get power(regulator)"); + goto err_power_init; + } +#endif + +#if (!FTS_CHIP_IDC) + fts_reset_proc(200); +#endif + + ret = fts_get_ic_information(fts_data); + if (ret) { + FTS_ERROR("not focal IC, unregister driver"); + goto err_irq_req; + } + +#ifdef CONFIG_ARCH_QTI_VM +tvm_setup: +#endif + error = fts_irq_registration(fts_data); + if (error) { + FTS_ERROR("request irq failed"); +#ifdef CONFIG_ARCH_QTI_VM + return error; +#endif + goto err_irq_req; + } + +#ifdef CONFIG_ARCH_QTI_VM + return error; +#endif + + ret = fts_fwupg_init(fts_data); + if (ret) + FTS_ERROR("init fw upgrade fail"); + + return error; + +err_irq_req: + if (gpio_is_valid(fts_data->pdata->reset_gpio)) + gpio_free(fts_data->pdata->reset_gpio); + if (gpio_is_valid(fts_data->pdata->irq_gpio)) + gpio_free(fts_data->pdata->irq_gpio); +#if FTS_POWER_SOURCE_CUST_EN +err_power_init: + fts_power_source_exit(fts_data); +#endif +err_gpio_config: + return error; +} + static int fts_ts_probe_entry(struct fts_ts_data *ts_data) { int ret = 0; @@ -1419,30 +2353,6 @@ static int fts_ts_probe_entry(struct fts_ts_data *ts_data) goto err_report_buffer; } - ret = fts_gpio_configure(ts_data); - if (ret) { - FTS_ERROR("configure the gpios fail"); - goto err_gpio_config; - } - -#if FTS_POWER_SOURCE_CUST_EN - ret = fts_power_source_init(ts_data); - if (ret) { - FTS_ERROR("fail to get power(regulator)"); - goto err_power_init; - } -#endif - -#if (!FTS_CHIP_IDC) - fts_reset_proc(200); -#endif - - ret = fts_get_ic_information(ts_data); - if (ret) { - FTS_ERROR("not focal IC, unregister driver"); - goto err_irq_req; - } - ret = fts_create_apk_debug_channel(ts_data); if (ret) { FTS_ERROR("create apk debug node fail"); @@ -1478,17 +2388,6 @@ static int fts_ts_probe_entry(struct fts_ts_data *ts_data) } #endif - ret = fts_irq_registration(ts_data); - if (ret) { - FTS_ERROR("request irq failed"); - goto err_irq_req; - } - - ret = fts_fwupg_init(ts_data); - if (ret) { - FTS_ERROR("init fw upgrade fail"); - } - #if defined(CONFIG_DRM) if (ts_data->ts_workqueue) { INIT_WORK(&ts_data->resume_work, fts_resume_work); @@ -1516,19 +2415,20 @@ static int fts_ts_probe_entry(struct fts_ts_data *ts_data) register_early_suspend(&ts_data->early_suspend); #endif +#ifdef CONFIG_FTS_TRUSTED_TOUCH + fts_ts_trusted_touch_init(ts_data); + mutex_init(&(ts_data->fts_clk_io_ctrl_mutex)); +#endif + ret = fts_ts_probe_delayed(ts_data); + if (ret) { + FTS_ERROR("Failed to enable resources\n"); + goto err_probe_delayed; + } + FTS_FUNC_EXIT(); return 0; -err_irq_req: -#if FTS_POWER_SOURCE_CUST_EN -err_power_init: - fts_power_source_exit(ts_data); -#endif - if (gpio_is_valid(ts_data->pdata->reset_gpio)) - gpio_free(ts_data->pdata->reset_gpio); - if (gpio_is_valid(ts_data->pdata->irq_gpio)) - gpio_free(ts_data->pdata->irq_gpio); -err_gpio_config: +err_probe_delayed: kfree_safe(ts_data->point_buf); kfree_safe(ts_data->events); err_report_buffer: @@ -1620,6 +2520,11 @@ static int fts_ts_suspend(struct device *dev) FTS_INFO("fw upgrade in process, can't suspend"); return 0; } +#ifdef CONFIG_FTS_TRUSTED_TOUCH + if (atomic_read(&fts_data->trusted_touch_enabled)) + wait_for_completion_interruptible( + &fts_data->trusted_touch_powerdown); +#endif #if FTS_ESDCHECK_EN fts_esdcheck_suspend(); @@ -1853,7 +2758,11 @@ static void __exit fts_ts_exit(void) { i2c_del_driver(&fts_ts_driver); } +#ifdef CONFIG_ARCH_QTI_VM +module_init(fts_ts_init); +#else late_initcall(fts_ts_init); +#endif module_exit(fts_ts_exit); MODULE_AUTHOR("FocalTech Driver Team"); diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_core.h b/drivers/input/touchscreen/focaltech_touch/focaltech_core.h index cb5e78f688bc..d88f16d29a9b 100644 --- a/drivers/input/touchscreen/focaltech_touch/focaltech_core.h +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_core.h @@ -61,6 +61,7 @@ #include #include #include +#include #include "focaltech_common.h" /***************************************************************************** @@ -138,6 +139,33 @@ struct ts_event { int area; }; +enum trusted_touch_mode_config { + TRUSTED_TOUCH_VM_MODE, + TRUSTED_TOUCH_MODE_NONE +}; + +#ifdef CONFIG_FTS_TRUSTED_TOUCH +#define TRUSTED_TOUCH_MEM_LABEL 0x7 + +struct trusted_touch_vm_info { + enum hh_irq_label irq_label; + enum hh_vm_names vm_name; + u32 hw_irq; + hh_memparcel_handle_t vm_mem_handle; + u32 *iomem_bases; + u32 *iomem_sizes; + u32 iomem_list_size; + void *mem_cookie; +#ifdef CONFIG_ARCH_QTI_VM + atomic_t tvm_owns_iomem; + atomic_t tvm_owns_irq; +#else + atomic_t pvm_owns_iomem; + atomic_t pvm_owns_irq; +#endif +}; +#endif + struct fts_ts_data { struct i2c_client *client; struct spi_device *spi; @@ -190,6 +218,20 @@ struct fts_ts_data { #elif defined(CONFIG_HAS_EARLYSUSPEND) struct early_suspend early_suspend; #endif + +#ifdef CONFIG_FTS_TRUSTED_TOUCH + struct trusted_touch_vm_info *vm_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 delayed_vm_probe_pending; + atomic_t trusted_touch_mode; +#endif }; /***************************************************************************** @@ -258,4 +300,6 @@ int fts_ex_mode_recovery(struct fts_ts_data *ts_data); void fts_irq_disable(void); void fts_irq_enable(void); +int fts_ts_handle_trusted_touch_pvm(struct fts_ts_data *ts_data, int value); +int fts_ts_handle_trusted_touch_tvm(struct fts_ts_data *ts_data, int value); #endif /* __LINUX_FOCALTECH_CORE_H__ */ diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_ex_fun.c b/drivers/input/touchscreen/focaltech_touch/focaltech_ex_fun.c index 00abd44983e1..4389bed4cb4c 100644 --- a/drivers/input/touchscreen/focaltech_touch/focaltech_ex_fun.c +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_ex_fun.c @@ -633,7 +633,7 @@ static ssize_t fts_bootmode_show( } /* fts_tpfwver interface */ -static ssize_t fts_tpfwver_show( +static ssize_t fts_fw_version_show( struct device *dev, struct device_attribute *attr, char *buf) { struct fts_ts_data *ts_data = fts_data; @@ -659,7 +659,7 @@ static ssize_t fts_tpfwver_show( return num_read_chars; } -static ssize_t fts_tpfwver_store( +static ssize_t fts_fw_version_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -1058,8 +1058,72 @@ static ssize_t fts_log_level_store( return count; } +#ifdef CONFIG_FTS_TRUSTED_TOUCH + +static ssize_t trusted_touch_enable_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_enabled)); +} + +static ssize_t trusted_touch_enable_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; + +#ifdef CONFIG_ARCH_QTI_VM + err = fts_ts_handle_trusted_touch_tvm(info, value); + if (err) { + pr_err("Failed to handle trusted touch in tvm\n"); + return -EINVAL; + } +#else + err = fts_ts_handle_trusted_touch_pvm(info, value); + if (err) { + pr_err("Failed to handle trusted touch in pvm\n"); + return -EINVAL; + } +#endif + err = count; + return err; +} + +#endif + /* get the fw version example:cat fw_version */ -static DEVICE_ATTR(fts_fw_version, S_IRUGO | S_IWUSR, fts_tpfwver_show, fts_tpfwver_store); +static DEVICE_ATTR_RW(fts_fw_version); /* read and write register(s) * All data type is **HEX** @@ -1082,6 +1146,9 @@ static DEVICE_ATTR(fts_irq, S_IRUGO | S_IWUSR, fts_irq_show, fts_irq_store); static DEVICE_ATTR(fts_boot_mode, S_IRUGO | S_IWUSR, fts_bootmode_show, fts_bootmode_store); static DEVICE_ATTR(fts_touch_point, S_IRUGO | S_IWUSR, fts_tpbuf_show, fts_tpbuf_store); 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); +#endif /* add your attr in here*/ static struct attribute *fts_attributes[] = { @@ -1094,6 +1161,9 @@ static struct attribute *fts_attributes[] = { &dev_attr_fts_boot_mode.attr, &dev_attr_fts_touch_point.attr, &dev_attr_fts_log_level.attr, +#ifdef CONFIG_FTS_TRUSTED_TOUCH + &dev_attr_trusted_touch_enable.attr, +#endif NULL };