diff options
author | Olof Johansson <olof@lixom.net> | 2019-11-06 16:46:02 +0100 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2019-11-06 16:46:03 +0100 |
commit | 8cbbff3a6423cc95fbd00c49da54952a87088d4f (patch) | |
tree | 30afb60484a8e795eb29714d68825fca9aaeae85 | |
parent | Merge tag 'samsung-drivers-5.5' of https://git.kernel.org/pub/scm/linux/kerne... (diff) | |
parent | soc: imx8mq: Read SOC revision from TF-A (diff) | |
download | linux-8cbbff3a6423cc95fbd00c49da54952a87088d4f.tar.xz linux-8cbbff3a6423cc95fbd00c49da54952a87088d4f.zip |
Merge tag 'imx-drivers-5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux into arm/drivers
i.MX drivers update for 5.5:
- Skip return check for those SCU firmware APIs that are defined as
void function in firmware.
- Use established serial_number attribute instead of custom one to show
SoC's unique ID for i.MX8 SoC drivers.
- Read i.MX8MQ SOC revision from TF-A which parses ROM and exposes the
value through a SMC call. This improves the situation that SOC
revision reports 'unknown' on some older revisions.
- Add a check and warn on unexpected SCU RX to avoid potential stack
corruption in imx-scu driver.
- Fix a sparse warning in imx-scu-irq driver by adding missing header.
- Remove an unneeded call to devm_of_platform_populate() from imx-dsp
driver.
* tag 'imx-drivers-5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux:
soc: imx8mq: Read SOC revision from TF-A
soc: imx-scu: Using existing serial_number instead of UID
soc: imx8: Using existing serial_number instead of UID
firmware: imx: add missing include of <linux/firmware/imx/sci.h>
firmware: imx: Remove call to devm_of_platform_populate
firmware: imx: Skip return value check for some special SCU firmware APIs
firmware: imx: warn on unexpected RX
Link: https://lore.kernel.org/r/20191105150315.15477-1-shawnguo@kernel.org
Signed-off-by: Olof Johansson <olof@lixom.net>
-rw-r--r-- | drivers/firmware/imx/imx-dsp.c | 2 | ||||
-rw-r--r-- | drivers/firmware/imx/imx-scu-irq.c | 1 | ||||
-rw-r--r-- | drivers/firmware/imx/imx-scu.c | 24 | ||||
-rw-r--r-- | drivers/soc/imx/soc-imx-scu.c | 34 | ||||
-rw-r--r-- | drivers/soc/imx/soc-imx8.c | 49 |
5 files changed, 79 insertions, 31 deletions
diff --git a/drivers/firmware/imx/imx-dsp.c b/drivers/firmware/imx/imx-dsp.c index a43d2db5cbdb..4265e9dbed84 100644 --- a/drivers/firmware/imx/imx-dsp.c +++ b/drivers/firmware/imx/imx-dsp.c @@ -114,7 +114,7 @@ static int imx_dsp_probe(struct platform_device *pdev) dev_info(dev, "NXP i.MX DSP IPC initialized\n"); - return devm_of_platform_populate(dev); + return 0; out: kfree(chan_name); for (j = 0; j < i; j++) { diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c index 687121f8c4d5..db655e87cdc8 100644 --- a/drivers/firmware/imx/imx-scu-irq.c +++ b/drivers/firmware/imx/imx-scu-irq.c @@ -8,6 +8,7 @@ #include <dt-bindings/firmware/imx/rsrc.h> #include <linux/firmware/imx/ipc.h> +#include <linux/firmware/imx/sci.h> #include <linux/mailbox_client.h> #define IMX_SC_IRQ_FUNC_ENABLE 1 diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx-scu.c index 04a24a863d6e..03b43b7a6d1d 100644 --- a/drivers/firmware/imx/imx-scu.c +++ b/drivers/firmware/imx/imx-scu.c @@ -107,6 +107,12 @@ static void imx_scu_rx_callback(struct mbox_client *c, void *msg) struct imx_sc_rpc_msg *hdr; u32 *data = msg; + if (!sc_ipc->msg) { + dev_warn(sc_ipc->dev, "unexpected rx idx %d 0x%08x, ignore!\n", + sc_chan->idx, *data); + return; + } + if (sc_chan->idx == 0) { hdr = msg; sc_ipc->rx_size = hdr->size; @@ -156,6 +162,7 @@ static int imx_scu_ipc_write(struct imx_sc_ipc *sc_ipc, void *msg) */ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp) { + uint8_t saved_svc, saved_func; struct imx_sc_rpc_msg *hdr; int ret; @@ -165,7 +172,11 @@ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp) mutex_lock(&sc_ipc->lock); reinit_completion(&sc_ipc->done); - sc_ipc->msg = msg; + if (have_resp) { + sc_ipc->msg = msg; + saved_svc = ((struct imx_sc_rpc_msg *)msg)->svc; + saved_func = ((struct imx_sc_rpc_msg *)msg)->func; + } sc_ipc->count = 0; ret = imx_scu_ipc_write(sc_ipc, msg); if (ret < 0) { @@ -184,9 +195,20 @@ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp) /* response status is stored in hdr->func field */ hdr = msg; ret = hdr->func; + /* + * Some special SCU firmware APIs do NOT have return value + * in hdr->func, but they do have response data, those special + * APIs are defined as void function in SCU firmware, so they + * should be treated as return success always. + */ + if ((saved_svc == IMX_SC_RPC_SVC_MISC) && + (saved_func == IMX_SC_MISC_FUNC_UNIQUE_ID || + saved_func == IMX_SC_MISC_FUNC_GET_BUTTON_STATUS)) + ret = 0; } out: + sc_ipc->msg = NULL; mutex_unlock(&sc_ipc->lock); dev_dbg(sc_ipc->dev, "RPC SVC done\n"); diff --git a/drivers/soc/imx/soc-imx-scu.c b/drivers/soc/imx/soc-imx-scu.c index 50831ebf126a..f2eace5b50fe 100644 --- a/drivers/soc/imx/soc-imx-scu.c +++ b/drivers/soc/imx/soc-imx-scu.c @@ -33,12 +33,10 @@ struct imx_sc_msg_misc_get_soc_uid { u32 uid_high; } __packed; -static ssize_t soc_uid_show(struct device *dev, - struct device_attribute *attr, char *buf) +static int imx_scu_soc_uid(u64 *soc_uid) { struct imx_sc_msg_misc_get_soc_uid msg; struct imx_sc_rpc_msg *hdr = &msg.hdr; - u64 soc_uid; int ret; hdr->ver = IMX_SC_RPC_VERSION; @@ -52,15 +50,13 @@ static ssize_t soc_uid_show(struct device *dev, return ret; } - soc_uid = msg.uid_high; - soc_uid <<= 32; - soc_uid |= msg.uid_low; + *soc_uid = msg.uid_high; + *soc_uid <<= 32; + *soc_uid |= msg.uid_low; - return sprintf(buf, "%016llX\n", soc_uid); + return 0; } -static DEVICE_ATTR_RO(soc_uid); - static int imx_scu_soc_id(void) { struct imx_sc_msg_misc_get_soc_id msg; @@ -89,6 +85,7 @@ static int imx_scu_soc_probe(struct platform_device *pdev) struct soc_device_attribute *soc_dev_attr; struct soc_device *soc_dev; int id, ret; + u64 uid = 0; u32 val; ret = imx_scu_get_handle(&soc_ipc_handle); @@ -112,6 +109,10 @@ static int imx_scu_soc_probe(struct platform_device *pdev) if (id < 0) return -EINVAL; + ret = imx_scu_soc_uid(&uid); + if (ret < 0) + return -EINVAL; + /* format soc_id value passed from SCU firmware */ val = id & 0x1f; soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "0x%x", val); @@ -130,19 +131,22 @@ static int imx_scu_soc_probe(struct platform_device *pdev) goto free_soc_id; } + soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", uid); + if (!soc_dev_attr->serial_number) { + ret = -ENOMEM; + goto free_revision; + } + soc_dev = soc_device_register(soc_dev_attr); if (IS_ERR(soc_dev)) { ret = PTR_ERR(soc_dev); - goto free_revision; + goto free_serial_number; } - ret = device_create_file(soc_device_to_device(soc_dev), - &dev_attr_soc_uid); - if (ret) - goto free_revision; - return 0; +free_serial_number: + kfree(soc_dev_attr->serial_number); free_revision: kfree(soc_dev_attr->revision); free_soc_id: diff --git a/drivers/soc/imx/soc-imx8.c b/drivers/soc/imx/soc-imx8.c index b9831576dd25..d84ed736cdb0 100644 --- a/drivers/soc/imx/soc-imx8.c +++ b/drivers/soc/imx/soc-imx8.c @@ -9,6 +9,7 @@ #include <linux/slab.h> #include <linux/sys_soc.h> #include <linux/platform_device.h> +#include <linux/arm-smccc.h> #include <linux/of.h> #define REV_B1 0x21 @@ -16,6 +17,8 @@ #define IMX8MQ_SW_INFO_B1 0x40 #define IMX8MQ_SW_MAGIC_B1 0xff0055aa +#define IMX_SIP_GET_SOC_INFO 0xc2000006 + #define OCOTP_UID_LOW 0x410 #define OCOTP_UID_HIGH 0x420 @@ -29,13 +32,21 @@ struct imx8_soc_data { static u64 soc_uid; -static ssize_t soc_uid_show(struct device *dev, - struct device_attribute *attr, char *buf) +#ifdef CONFIG_HAVE_ARM_SMCCC +static u32 imx8mq_soc_revision_from_atf(void) { - return sprintf(buf, "%016llX\n", soc_uid); -} + struct arm_smccc_res res; -static DEVICE_ATTR_RO(soc_uid); + arm_smccc_smc(IMX_SIP_GET_SOC_INFO, 0, 0, 0, 0, 0, 0, 0, &res); + + if (res.a0 == SMCCC_RET_NOT_SUPPORTED) + return 0; + else + return res.a0 & 0xff; +} +#else +static inline u32 imx8mq_soc_revision_from_atf(void) { return 0; }; +#endif static u32 __init imx8mq_soc_revision(void) { @@ -51,9 +62,16 @@ static u32 __init imx8mq_soc_revision(void) ocotp_base = of_iomap(np, 0); WARN_ON(!ocotp_base); - magic = readl_relaxed(ocotp_base + IMX8MQ_SW_INFO_B1); - if (magic == IMX8MQ_SW_MAGIC_B1) - rev = REV_B1; + /* + * SOC revision on older imx8mq is not available in fuses so query + * the value from ATF instead. + */ + rev = imx8mq_soc_revision_from_atf(); + if (!rev) { + magic = readl_relaxed(ocotp_base + IMX8MQ_SW_INFO_B1); + if (magic == IMX8MQ_SW_MAGIC_B1) + rev = REV_B1; + } soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH); soc_uid <<= 32; @@ -174,22 +192,25 @@ static int __init imx8_soc_init(void) goto free_soc; } + soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", soc_uid); + if (!soc_dev_attr->serial_number) { + ret = -ENOMEM; + goto free_rev; + } + soc_dev = soc_device_register(soc_dev_attr); if (IS_ERR(soc_dev)) { ret = PTR_ERR(soc_dev); - goto free_rev; + goto free_serial_number; } - ret = device_create_file(soc_device_to_device(soc_dev), - &dev_attr_soc_uid); - if (ret) - goto free_rev; - if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT)) platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0); return 0; +free_serial_number: + kfree(soc_dev_attr->serial_number); free_rev: if (strcmp(soc_dev_attr->revision, "unknown")) kfree(soc_dev_attr->revision); |