Merge "input: touchscreen: st: toggle reset gpio during error on SVM"

This commit is contained in:
qctecmdr 2020-10-08 15:24:52 -07:00 • committed by Gerrit - the friendly Code Review server
commit 43cd233e24
4 changed files with 618 additions and 168 deletions

View file

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

View file

@ -217,9 +217,59 @@ enum trusted_touch_mode_config {
TRUSTED_TOUCH_MODE_NONE
};
enum trusted_touch_pvm_states {
TRUSTED_TOUCH_PVM_INIT,
PVM_I2C_RESOURCE_ACQUIRED,
PVM_INTERRUPT_DISABLED,
PVM_IOMEM_LENT,
PVM_IOMEM_LENT_NOTIFIED,
PVM_IRQ_LENT,
PVM_IRQ_LENT_NOTIFIED,
PVM_IOMEM_RELEASE_NOTIFIED,
PVM_IRQ_RELEASE_NOTIFIED,
PVM_ALL_RESOURCES_RELEASE_NOTIFIED,
PVM_IRQ_RECLAIMED,
PVM_IOMEM_RECLAIMED,
PVM_INTERRUPT_ENABLED,
PVM_I2C_RESOURCE_RELEASED,
TRUSTED_TOUCH_PVM_STATE_MAX
};
enum trusted_touch_tvm_states {
TRUSTED_TOUCH_TVM_INIT,
TVM_IOMEM_LENT_NOTIFIED,
TVM_IRQ_LENT_NOTIFIED,
TVM_ALL_RESOURCES_LENT_NOTIFIED,
TVM_IOMEM_ACCEPTED,
TVM_I2C_SESSION_ACQUIRED,
TVM_IRQ_ACCEPTED,
TVM_INTERRUPT_ENABLED,
TVM_INTERRUPT_DISABLED,
TVM_IRQ_RELEASED,
TVM_IOMEM_RELEASED,
TVM_I2C_SESSION_RELEASED,
TRUSTED_TOUCH_TVM_STATE_MAX
};
#ifdef CONFIG_ST_TRUSTED_TOUCH
#define TRUSTED_TOUCH_MEM_LABEL 0x7
#define TOUCH_RESET_GPIO_BASE 0xF116000
#define TOUCH_RESET_GPIO_SIZE 0x1000
#define TOUCH_RESET_GPIO_OFFSET 0x4
#define TOUCH_INTR_GPIO_BASE 0xF117000
#define TOUCH_INTR_GPIO_SIZE 0x1000
#define TOUCH_INTR_GPIO_OFFSET 0x8
#define TRUSTED_TOUCH_EVENT_LEND_FAILURE -1
#define TRUSTED_TOUCH_EVENT_LEND_NOTIFICATION_FAILURE -2
#define TRUSTED_TOUCH_EVENT_ACCEPT_FAILURE -3
#define TRUSTED_TOUCH_EVENT_FUNCTIONAL_FAILURE -4
#define TRUSTED_TOUCH_EVENT_RELEASE_FAILURE -5
#define TRUSTED_TOUCH_EVENT_RECLAIM_FAILURE -6
#define TRUSTED_TOUCH_EVENT_I2C_FAILURE -7
#define TRUSTED_TOUCH_EVENT_NOTIFICATIONS_PENDING 5
struct trusted_touch_vm_info {
enum hh_irq_label irq_label;
enum hh_vm_names vm_name;
@ -230,13 +280,17 @@ struct trusted_touch_vm_info {
u32 iomem_list_size;
void *mem_cookie;
#ifdef CONFIG_ARCH_QTI_VM
atomic_t tvm_owns_iomem;
atomic_t tvm_owns_irq;
struct mutex tvm_state_mutex;
atomic_t tvm_state;
#else
atomic_t pvm_owns_iomem;
atomic_t pvm_owns_irq;
struct mutex pvm_state_mutex;
atomic_t pvm_state;
#endif
};
#ifdef CONFIG_ARCH_QTI_VM
void fts_trusted_touch_tvm_i2c_failure_report(struct fts_ts_info *info);
#endif
#endif
/*
@ -359,11 +413,12 @@ struct fts_ts_info {
struct mutex fts_clk_io_ctrl_mutex;
const char *touch_environment;
struct completion trusted_touch_powerdown;
struct completion resource_checkpoint;
struct clk *core_clk;
struct clk *iface_clk;
atomic_t trusted_touch_initialized;
atomic_t trusted_touch_enabled;
atomic_t trusted_touch_event;
atomic_t trusted_touch_abort_status;
atomic_t delayed_vm_probe_pending;
atomic_t trusted_touch_mode;
#endif

View file

@ -34,6 +34,7 @@
*
*/
#include <linux/pm_runtime.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
@ -141,13 +142,32 @@ int fts_readCmd(u8 *cmd, int cmdLength, u8 *outBuf, int byteToRead)
while (retry < I2C_RETRY && ret < OK) {
ret = i2c_transfer(client->adapter, I2CMsg, 2);
retry++;
if (ret < OK)
if (ret < OK) {
#ifdef CONFIG_ST_TRUSTED_TOUCH
#ifdef CONFIG_ARCH_QTI_VM
if (atomic_read(&info->trusted_touch_enabled) &&
ret == -ECONNRESET){
pr_err("failed i2c read reacquiring session\n");
pm_runtime_put_sync(
info->client->adapter->dev.parent);
pm_runtime_get_sync(
info->client->adapter->dev.parent);
}
#endif
#endif
msleep(I2C_WAIT_BEFORE_RETRY);
}
}
if (ret < 0) {
#ifdef CONFIG_ST_TRUSTED_TOUCH
#ifdef CONFIG_ARCH_QTI_VM
pr_err("initiating abort due to i2c xfer failure\n");
fts_trusted_touch_tvm_i2c_failure_report(info);
#endif
#endif
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_I2C_R);
return ERROR_I2C_R;
return ret;
}
memcpy(outBuf, buf + cmdLength, byteToRead);
@ -189,13 +209,34 @@ int fts_writeCmd(u8 *cmd, int cmdLength)
while (retry < I2C_RETRY && ret < OK) {
ret = i2c_transfer(client->adapter, I2CMsg, 1);
retry++;
if (ret < OK)
if (ret < OK) {
#ifdef CONFIG_ST_TRUSTED_TOUCH
#ifdef CONFIG_ARCH_QTI_VM
if (atomic_read(&info->trusted_touch_enabled) &&
ret == -ECONNRESET){
pr_err("failed i2c write reacquiring session\n");
pm_runtime_put_sync(
info->client->adapter->dev.parent);
pm_runtime_get_sync(
info->client->adapter->dev.parent);
}
#endif
#endif
msleep(I2C_WAIT_BEFORE_RETRY);
logError(1, "ERROR: %d\n", ret);
}
//logError(1,"%s fts_writeCmd: attempt %d\n", tag, retry);
}
if (ret < 0) {
#ifdef CONFIG_ST_TRUSTED_TOUCH
#ifdef CONFIG_ARCH_QTI_VM
pr_err("initiating abort due to i2c xfer failure\n");
fts_trusted_touch_tvm_i2c_failure_report(info);
#endif
#endif
logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_W);
return ERROR_I2C_W;
return ret;
}
return OK;
}

View file

@ -789,11 +789,13 @@ int fts_disableInterrupt(void)
int fts_enableInterrupt(void)
{
u8 cmd[4] = { FTS_CMD_HW_REG_W, 0x00, 0x00, IER_ENABLE };
int ret = 0;
u16ToU8_be(IER_ADDR, &cmd[1]);
if (fts_writeCmd(cmd, 4) < 0) {
logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_W);
return ERROR_I2C_W;
ret = fts_writeCmd(cmd, 4);
if (ret < 0) {
logError(1, "%s %s: ERROR %d\n", tag, __func__, ret);
return ret;
}
logError(0, "%s Interrupt Enabled!\n", tag);
return OK;