Commit 8cbbff3a authored by Olof Johansson's avatar Olof Johansson
Browse files

Merge tag 'imx-drivers-5.5' of...

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: default avatarOlof Johansson <olof@lixom.net>
parents 171cfeec 768e1a8e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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++) {
+1 −0
Original line number Diff line number Diff line
@@ -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
+23 −1
Original line number Diff line number Diff line
@@ -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);

	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");
+19 −15
Original line number Diff line number Diff line
@@ -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:
+35 −14
Original line number Diff line number Diff line
@@ -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);

	/*
	 * 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);