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 <riteshk@codeaurora.org>
This commit is contained in:
Ritesh Kumar 2020-10-21 13:56:08 +05:30 • committed by Gerrit - the friendly Code Review server
commit 6aca8a8c07
3 changed files with 486 additions and 158 deletions

View file

@ -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;
}

View file

@ -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

View file

@ -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
};