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. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJdwVrCAAoJEFBXWFqHsHzOX8kH/3/YHNwwVBHY9t9UqvtYu3y+ 1jMCHRX1WdOo9ntRmREzPzAHGFXH/O06AKtWTVp+I5KK3vNy3zJR/wVaIZ3ET3ZY LK8YD7sc7/PsSHC2Tw4Lj7QnF/q4X5cvo1iL8WeySDyfZQS0UutfPn3VDAwwQGpf CCcyEou6QfxGipff597COmhaMra8tIaSYZctHFVCOh2mSz2Zny8BRKOgBSKsmPFs 83O/swSyvKlfRisFU2oUcdGX2VgMSuntTCUW9xlYXJtA8cmuUKlSvQK3KjL+KxK7 rjd+oYoBZEvA2RMgsX518lFwI5cnrIP06k93D4KfA15lePbSJ1DKrpuPbL9RHLc= =9zkv -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
8cbbff3a64
|
@ -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++) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 = soc_device_register(soc_dev_attr);
|
||||
if (IS_ERR(soc_dev)) {
|
||||
ret = PTR_ERR(soc_dev);
|
||||
soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", uid);
|
||||
if (!soc_dev_attr->serial_number) {
|
||||
ret = -ENOMEM;
|
||||
goto free_revision;
|
||||
}
|
||||
|
||||
ret = device_create_file(soc_device_to_device(soc_dev),
|
||||
&dev_attr_soc_uid);
|
||||
if (ret)
|
||||
goto free_revision;
|
||||
soc_dev = soc_device_register(soc_dev_attr);
|
||||
if (IS_ERR(soc_dev)) {
|
||||
ret = PTR_ERR(soc_dev);
|
||||
goto free_serial_number;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_serial_number:
|
||||
kfree(soc_dev_attr->serial_number);
|
||||
free_revision:
|
||||
kfree(soc_dev_attr->revision);
|
||||
free_soc_id:
|
||||
|
|
|
@ -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 = soc_device_register(soc_dev_attr);
|
||||
if (IS_ERR(soc_dev)) {
|
||||
ret = PTR_ERR(soc_dev);
|
||||
soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", soc_uid);
|
||||
if (!soc_dev_attr->serial_number) {
|
||||
ret = -ENOMEM;
|
||||
goto free_rev;
|
||||
}
|
||||
|
||||
ret = device_create_file(soc_device_to_device(soc_dev),
|
||||
&dev_attr_soc_uid);
|
||||
if (ret)
|
||||
goto free_rev;
|
||||
soc_dev = soc_device_register(soc_dev_attr);
|
||||
if (IS_ERR(soc_dev)) {
|
||||
ret = PTR_ERR(soc_dev);
|
||||
goto free_serial_number;
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue