NFC: driver: FR63179 Add NFC dynamic protection control

Implemented NFC dynamic protection control feature in driver; performing
Ven GPIO enable/disable post TZ notifications in non-secure/secure zone
respectively.

Change-Id: I13dedf23987ce0b3b2a53881d35f6c3cf462cd92
This commit is contained in:
Mallikarjun S T
2022-04-09 21:09:35 +05:30
parent 9214369e79
commit eba3412350
4 changed files with 139 additions and 25 deletions

View File

@@ -27,6 +27,8 @@
#include "common.h" #include "common.h"
static int secure_zone = 1;
int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs,
uint8_t interface) uint8_t interface)
{ {
@@ -385,6 +387,120 @@ long nfc_dev_compat_ioctl(struct file *pfile, unsigned int cmd,
} }
#endif #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. * nfc_dev_ioctl - used to set or get data from upper layer.
* @pfile file node for opened device. * @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) if (!nfc_dev)
return -ENODEV; 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); pr_debug("%s: cmd = %x arg = %zx\n", __func__, cmd, arg);
switch (cmd) { switch (cmd) {
case NFC_SET_PWR: 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"); pr_debug("nfc ese cold reset ioctl\n");
ret = ese_cold_reset_ioctl(nfc_dev, arg); ret = ese_cold_reset_ioctl(nfc_dev, arg);
break; break;
case NFC_SECURE_ZONE:
ret = nfc_dynamic_protection_ioctl(nfc_dev, arg);
break;
default: default:
pr_err("%s: bad cmd %lu\n", __func__, arg); pr_err("%s: bad cmd %lu\n", __func__, arg);
ret = -ENOIOCTLCMD; ret = -ENOIOCTLCMD;

View File

@@ -98,6 +98,7 @@
#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, uint32_t) #define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, uint32_t)
#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, uint32_t) #define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, uint32_t)
#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, 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_IRQ_GPIO_STR "qcom,sn-irq"
#define DTS_VEN_GPIO_STR "qcom,sn-ven" #define DTS_VEN_GPIO_STR "qcom,sn-ven"
@@ -130,6 +131,9 @@ do { \
} \ } \
} while (0) } while (0)
static struct semaphore sem_eSE_pwr_off;
static chk_eSE_pwr_off;
enum ese_ioctl_request { enum ese_ioctl_request {
/* eSE POWER ON */ /* eSE POWER ON */
ESE_POWER_ON = 0, 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 validate_nfc_state_nci(struct nfc_dev *nfc_dev);
int nfc_clock_select(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_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_ */ #endif /* _COMMON_H_ */

View File

@@ -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"); pr_debug("keep ven high as NFC is enabled\n");
} }
nfc_dev->is_ese_session_active = false; nfc_dev->is_ese_session_active = false;
if(chk_eSE_pwr_off)
up(&sem_eSE_pwr_off);
} else if (arg == ESE_POWER_STATE) { } else if (arg == ESE_POWER_STATE) {
/* get VEN gpio state for eSE, as eSE also enabled through same GPIO */ /* get VEN gpio state for eSE, as eSE also enabled through same GPIO */
ret = gpio_get_value(nfc_dev->configs.gpio.ven); ret = gpio_get_value(nfc_dev->configs.gpio.ven);

View File

@@ -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_write = i2c_write;
nfc_dev->nfc_enable_intr = i2c_enable_irq; nfc_dev->nfc_enable_intr = i2c_enable_irq;
nfc_dev->nfc_disable_intr = i2c_disable_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); ret = configure_gpio(nfc_gpio->irq, GPIO_IRQ);
if (ret <= 0) { if (ret <= 0) {
pr_err("%s: unable to request nfc irq gpio [%d]\n", __func__, 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; goto err_free_gpio;
} }
client->irq = ret; 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 mutex and queues */
init_waitqueue_head(&nfc_dev->read_wq); init_waitqueue_head(&nfc_dev->read_wq);
mutex_init(&nfc_dev->read_mutex); 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"); pr_err("LDO config failed\n");
goto err_ldo_config_failed; 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) if(nfc_dev->configs.clk_pin_voting)
nfc_dev->clk_run = false; nfc_dev->clk_run = false;
else else
nfc_dev->clk_run = true; 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); device_init_wakeup(&client->dev, true);
i2c_set_clientdata(client, nfc_dev); i2c_set_clientdata(client, nfc_dev);
i2c_dev->irq_wake_up = false; 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__); pr_info("%s: probing nfc i2c successfully\n", __func__);
return 0; return 0;
err_nfcc_hw_check:
if (nfc_dev->reg) {
nfc_ldo_unvote(nfc_dev);
regulator_put(nfc_dev->reg);
}
err_ldo_config_failed: err_ldo_config_failed:
free_irq(client->irq, nfc_dev); free_irq(client->irq, nfc_dev);
err_nfc_misc_unregister: err_nfc_misc_unregister:
@@ -458,7 +438,6 @@ err_mutex_destroy:
mutex_destroy(&nfc_dev->write_mutex); mutex_destroy(&nfc_dev->write_mutex);
err_free_gpio: err_free_gpio:
gpio_free_all(nfc_dev); gpio_free_all(nfc_dev);
err_free_write_kbuf:
kfree(nfc_dev->write_kbuf); kfree(nfc_dev->write_kbuf);
err_free_read_kbuf: err_free_read_kbuf:
kfree(nfc_dev->read_kbuf); kfree(nfc_dev->read_kbuf);