diff --git a/nfc/common.c b/nfc/common.c index 6a1f5329d8..6539cf617d 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -27,6 +27,8 @@ #include "common.h" +static int secure_zone = 1; + int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, uint8_t interface) { @@ -385,6 +387,120 @@ long nfc_dev_compat_ioctl(struct file *pfile, unsigned int cmd, } #endif +/** + * nfc_post_init() - Configuraing Ven GPIO and hardware check + * @nfc_dev: nfc device data structure + * + * Configure GPIOs post notification from TZ, ensuring it's a non-secure zone. + * + * Return: 0 if Success(or no issue) and error ret code otherwise + */ +int nfc_post_init(struct nfc_dev *nfc_dev) +{ + int ret=0; + struct platform_configs nfc_configs; + struct platform_gpio *nfc_gpio; + + if (!nfc_dev) + return -ENODEV; + + memcpy(&nfc_configs, &nfc_dev->configs, sizeof(struct platform_configs)); + nfc_gpio = &nfc_configs.gpio; + + ret = configure_gpio(nfc_gpio->ven, GPIO_OUTPUT); + if (ret) { + pr_err("%s: unable to request nfc reset gpio [%d]\n", + __func__, nfc_gpio->ven); + return ret; + } + + ret = configure_gpio(nfc_gpio->dwl_req, GPIO_OUTPUT); + if (ret) { + pr_err("%s: unable to request nfc firm downl gpio [%d]\n", + __func__, nfc_gpio->dwl_req); + } + + ret = nfcc_hw_check(nfc_dev); + if (ret || nfc_dev->nfc_state == NFC_STATE_UNKNOWN) { + pr_err("nfc hw check failed ret %d\n", ret); + gpio_free(nfc_gpio->dwl_req); + gpio_free(nfc_gpio->ven); + return ret; + } + + /*Initialising sempahore to disbale NFC Ven GPIO only after eSE is power off flag is set */ + sema_init(&sem_eSE_pwr_off,0); + + pr_info("%s success\n", __func__); + return 0; + + +} + +/** + * nfc_dynamic_protection_ioctl() - dynamic protection control + * @nfc_dev: nfc device data structure + * @sec_zone_trans: mode that we want to move to + * If sec_zone_trans = 1; transition from non-secure zone to secure zone + * If sec_zone_trans = 0; transition from secure zone to non - secure zone + * + * nfc periheral dynamic protection control. Depending on the sec_zone_trans value, device moves to + * secure zone and non-secure zone + * + * Return: -ENOIOCTLCMD if sec_zone_trans val is not supported, 0 if Success(or no issue) + * and error ret code otherwise + */ +int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone_trans) +{ + int ret = 0; + + static int init_flag=1; + + struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + + if(sec_zone_trans == 1) { + /*check NFC is disabled, only then set Ven GPIO low*/ + if(nfc_dev->cold_reset.is_nfc_enabled == false) { + pr_debug("%s: value %d\n", __func__, gpio_get_value(nfc_gpio->ven)); + + chk_eSE_pwr_off = 1; + /*check if eSE is active, if yes, wait max of 1sec, until it's inactive */ + if(nfc_dev->is_ese_session_active == true) { + if(down_timeout(&sem_eSE_pwr_off, msecs_to_jiffies(1000))) { + /*waited for 1sec yet eSE not turned off, so, ignoring eSE power off*/ + pr_info("Forcefull shutdown of eSE\n"); + } + } + ret = nfc_ioctl_power_states(nfc_dev, 0); + /*set driver as secure zone, such that no ioctl calls are allowed*/ + secure_zone=1; + pr_info("Driver Secure flag set successful\n"); + } else { + ret = -1; + } + } + else if(sec_zone_trans == 0) { + chk_eSE_pwr_off = 0; + secure_zone=0; + + if(init_flag) { + /*Initialize once,only during the first non-secure entry*/ + ret = nfc_post_init(nfc_dev); + if(ret == 0) + init_flag=0; + } + else { + ret = nfc_ioctl_power_states(nfc_dev, 1); + } + pr_info("Func Driver Secure flag clear successful\n"); + } else { + pr_info("INVALID ARG\n"); + ret = -ENOIOCTLCMD; + } + + return ret; +} + /** * nfc_dev_ioctl - used to set or get data from upper layer. * @pfile file node for opened device. @@ -406,6 +522,14 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) if (!nfc_dev) return -ENODEV; + /*Avoiding ioctl call in secure zone*/ + if(secure_zone) { + if(cmd!=NFC_SECURE_ZONE) { + pr_debug("nfc_dev_ioctl failed\n"); + return -1; + } + } + pr_debug("%s: cmd = %x arg = %zx\n", __func__, cmd, arg); switch (cmd) { case NFC_SET_PWR: @@ -424,6 +548,9 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) pr_debug("nfc ese cold reset ioctl\n"); ret = ese_cold_reset_ioctl(nfc_dev, arg); break; + case NFC_SECURE_ZONE: + ret = nfc_dynamic_protection_ioctl(nfc_dev, arg); + break; default: pr_err("%s: bad cmd %lu\n", __func__, arg); ret = -ENOIOCTLCMD; diff --git a/nfc/common.h b/nfc/common.h index ee2b55d05f..6e4ed15996 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -98,6 +98,7 @@ #define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, uint32_t) #define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, uint32_t) #define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, uint32_t) +#define NFC_SECURE_ZONE _IOW(NFC_MAGIC, 0x0A, uint32_t) #define DTS_IRQ_GPIO_STR "qcom,sn-irq" #define DTS_VEN_GPIO_STR "qcom,sn-ven" @@ -130,6 +131,9 @@ do { \ } \ } while (0) +static struct semaphore sem_eSE_pwr_off; +static chk_eSE_pwr_off; + enum ese_ioctl_request { /* eSE POWER ON */ ESE_POWER_ON = 0, @@ -297,4 +301,6 @@ int is_nfc_data_available_for_read(struct nfc_dev *nfc_dev); int validate_nfc_state_nci(struct nfc_dev *nfc_dev); int nfc_clock_select(struct nfc_dev *nfc_dev); int nfc_clock_deselect(struct nfc_dev *nfc_dev); +int nfc_post_init(struct nfc_dev *nfc_dev); +int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone_trans); #endif /* _COMMON_H_ */ diff --git a/nfc/ese_cold_reset.c b/nfc/ese_cold_reset.c index ad0aa2c6a3..309f245101 100644 --- a/nfc/ese_cold_reset.c +++ b/nfc/ese_cold_reset.c @@ -47,6 +47,8 @@ int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg) pr_debug("keep ven high as NFC is enabled\n"); } nfc_dev->is_ese_session_active = false; + if(chk_eSE_pwr_off) + up(&sem_eSE_pwr_off); } else if (arg == ESE_POWER_STATE) { /* get VEN gpio state for eSE, as eSE also enabled through same GPIO */ ret = gpio_get_value(nfc_dev->configs.gpio.ven); diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index 30a2828c62..4b47ef10a5 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -375,12 +375,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) nfc_dev->nfc_write = i2c_write; nfc_dev->nfc_enable_intr = i2c_enable_irq; nfc_dev->nfc_disable_intr = i2c_disable_irq; - ret = configure_gpio(nfc_gpio->ven, GPIO_OUTPUT); - if (ret) { - pr_err("%s: unable to request nfc reset gpio [%d]\n", __func__, - nfc_gpio->ven); - goto err_free_write_kbuf; - } + ret = configure_gpio(nfc_gpio->irq, GPIO_IRQ); if (ret <= 0) { pr_err("%s: unable to request nfc irq gpio [%d]\n", __func__, @@ -388,11 +383,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) goto err_free_gpio; } client->irq = ret; - ret = configure_gpio(nfc_gpio->dwl_req, GPIO_OUTPUT); - if (ret) { - pr_err("%s: unable to request nfc firm downl gpio [%d]\n", - __func__, nfc_gpio->dwl_req); - } + /* init mutex and queues */ init_waitqueue_head(&nfc_dev->read_wq); mutex_init(&nfc_dev->read_mutex); @@ -421,20 +412,13 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) pr_err("LDO config failed\n"); goto err_ldo_config_failed; } - ret = nfcc_hw_check(nfc_dev); - if (ret || nfc_dev->nfc_state == NFC_STATE_UNKNOWN) { - pr_err("nfc hw check failed ret %d\n", ret); - goto err_nfcc_hw_check; - } if(nfc_dev->configs.clk_pin_voting) nfc_dev->clk_run = false; else nfc_dev->clk_run = true; - gpio_set_ven(nfc_dev, 1); - gpio_set_ven(nfc_dev, 0); - gpio_set_ven(nfc_dev, 1); + device_init_wakeup(&client->dev, true); i2c_set_clientdata(client, nfc_dev); i2c_dev->irq_wake_up = false; @@ -443,11 +427,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) pr_info("%s: probing nfc i2c successfully\n", __func__); return 0; -err_nfcc_hw_check: - if (nfc_dev->reg) { - nfc_ldo_unvote(nfc_dev); - regulator_put(nfc_dev->reg); - } + err_ldo_config_failed: free_irq(client->irq, nfc_dev); err_nfc_misc_unregister: @@ -458,7 +438,6 @@ err_mutex_destroy: mutex_destroy(&nfc_dev->write_mutex); err_free_gpio: gpio_free_all(nfc_dev); -err_free_write_kbuf: kfree(nfc_dev->write_kbuf); err_free_read_kbuf: kfree(nfc_dev->read_kbuf);