Unverified Commit 6d9e4c74 authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

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

Merge tag 'imx-drivers-6.20' of https://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux into soc/drivers

i.MX drivers changes for 6.20:

- A few changes from Peng Fan adding dump syslog support for i.MX
  System Manager firmware driver, cleaning up soc-imx9 driver, fixing
  error handling for soc-imx8m driver

* tag 'imx-drivers-6.20' of https://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux

:
  soc: imx8m: Fix error handling for clk_prepare_enable()
  soc: imx: Spport i.MX9[4,52]
  soc: imx: Use dev_err_probe() for i.MX9
  soc: imx: Use device-managed APIs for i.MX9
  firmware: imx: sm-misc: Dump syslog info
  firmware: arm_scmi: imx: Support getting syslog of MISC protocol

Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents 419a620d f6ef3d9f
Loading
Loading
Loading
Loading
+83 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ enum scmi_imx_misc_protocol_cmd {
	SCMI_IMX_MISC_DISCOVER_BUILD_INFO = 0x6,
	SCMI_IMX_MISC_CTRL_NOTIFY = 0x8,
	SCMI_IMX_MISC_CFG_INFO_GET = 0xC,
	SCMI_IMX_MISC_SYSLOG_GET = 0xD,
	SCMI_IMX_MISC_BOARD_INFO = 0xE,
};

@@ -88,6 +89,19 @@ struct scmi_imx_misc_cfg_info_out {
	u8 cfgname[MISC_MAX_CFGNAME];
};

struct scmi_imx_misc_syslog_in {
	__le32 flags;
	__le32 index;
};

#define REMAINING(x)	le32_get_bits((x), GENMASK(31, 20))
#define RETURNED(x)	le32_get_bits((x), GENMASK(11, 0))

struct scmi_imx_misc_syslog_out {
	__le32 numlogflags;
	__le32 syslog[];
};

static int scmi_imx_misc_attributes_get(const struct scmi_protocol_handle *ph,
					struct scmi_imx_misc_info *mi)
{
@@ -370,10 +384,79 @@ static int scmi_imx_misc_cfg_info_get(const struct scmi_protocol_handle *ph)
	return ret;
}

struct scmi_imx_misc_syslog_ipriv {
	u32 *array;
	u16 *size;
};

static void iter_misc_syslog_prepare_message(void *message, u32 desc_index,
					     const void *priv)
{
	struct scmi_imx_misc_syslog_in *msg = message;

	msg->flags = cpu_to_le32(0);
	msg->index = cpu_to_le32(desc_index);
}

static int iter_misc_syslog_update_state(struct scmi_iterator_state *st,
					 const void *response, void *priv)
{
	const struct scmi_imx_misc_syslog_out *r = response;
	struct scmi_imx_misc_syslog_ipriv *p = priv;

	st->num_returned = RETURNED(r->numlogflags);
	st->num_remaining = REMAINING(r->numlogflags);
	*p->size = st->num_returned + st->num_remaining;

	return 0;
}

static int
iter_misc_syslog_process_response(const struct scmi_protocol_handle *ph,
				  const void *response,
				  struct scmi_iterator_state *st, void *priv)
{
	const struct scmi_imx_misc_syslog_out *r = response;
	struct scmi_imx_misc_syslog_ipriv *p = priv;

	p->array[st->desc_index + st->loop_idx] =
		le32_to_cpu(r->syslog[st->loop_idx]);

	return 0;
}

static int scmi_imx_misc_syslog_get(const struct scmi_protocol_handle *ph, u16 *size,
				    void *array)
{
	struct scmi_iterator_ops ops = {
		.prepare_message = iter_misc_syslog_prepare_message,
		.update_state = iter_misc_syslog_update_state,
		.process_response = iter_misc_syslog_process_response,
	};
	struct scmi_imx_misc_syslog_ipriv ipriv = {
		.array = array,
		.size = size,
	};
	void *iter;

	if (!array || !size || !*size)
		return -EINVAL;

	iter = ph->hops->iter_response_init(ph, &ops, *size, SCMI_IMX_MISC_SYSLOG_GET,
					    sizeof(struct scmi_imx_misc_syslog_in),
					    &ipriv);
	if (IS_ERR(iter))
		return PTR_ERR(iter);

	/* If firmware return NOT SUPPORTED, propagate value to caller */
	return ph->hops->iter_response_run(iter);
}

static const struct scmi_imx_misc_proto_ops scmi_imx_misc_proto_ops = {
	.misc_ctrl_set = scmi_imx_misc_ctrl_set,
	.misc_ctrl_get = scmi_imx_misc_ctrl_get,
	.misc_ctrl_req_notify = scmi_imx_misc_ctrl_notify,
	.misc_syslog = scmi_imx_misc_syslog_get,
};

static int scmi_imx_misc_protocol_init(const struct scmi_protocol_handle *ph)
+36 −1
Original line number Diff line number Diff line
@@ -3,12 +3,16 @@
 * Copyright 2024 NXP
 */

#include <linux/debugfs.h>
#include <linux/device/devres.h>
#include <linux/firmware/imx/sm.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/scmi_protocol.h>
#include <linux/scmi_imx_protocol.h>
#include <linux/seq_file.h>
#include <linux/sizes.h>

static const struct scmi_imx_misc_proto_ops *imx_misc_ctrl_ops;
static struct scmi_protocol_handle *ph;
@@ -44,10 +48,38 @@ static int scmi_imx_misc_ctrl_notifier(struct notifier_block *nb,
	return 0;
}

static int syslog_show(struct seq_file *file, void *priv)
{
	/* 4KB is large enough for syslog */
	void *syslog __free(kfree) = kmalloc(SZ_4K, GFP_KERNEL);
	/* syslog API use num words, not num bytes */
	u16 size = SZ_4K / 4;
	int ret;

	if (!ph)
		return -ENODEV;

	ret = imx_misc_ctrl_ops->misc_syslog(ph, &size, syslog);
	if (ret)
		return ret;

	seq_hex_dump(file, " ", DUMP_PREFIX_NONE, 16, sizeof(u32), syslog, size * 4, false);
	seq_putc(file, '\n');

	return 0;
}
DEFINE_SHOW_ATTRIBUTE(syslog);

static void scmi_imx_misc_put(void *p)
{
	debugfs_remove((struct dentry *)p);
}

static int scmi_imx_misc_ctrl_probe(struct scmi_device *sdev)
{
	const struct scmi_handle *handle = sdev->handle;
	struct device_node *np = sdev->dev.of_node;
	struct dentry *scmi_imx_dentry;
	u32 src_id, flags;
	int ret, i, num;

@@ -98,7 +130,10 @@ static int scmi_imx_misc_ctrl_probe(struct scmi_device *sdev)
		}
	}

	return 0;
	scmi_imx_dentry = debugfs_create_dir("scmi_imx", NULL);
	debugfs_create_file("syslog", 0444, scmi_imx_dentry, &sdev->dev, &syslog_fops);

	return devm_add_action_or_reset(&sdev->dev, scmi_imx_misc_put, scmi_imx_dentry);
}

static const struct scmi_device_id scmi_id_table[] = {
+5 −1
Original line number Diff line number Diff line
@@ -148,7 +148,11 @@ static int imx8m_soc_prepare(struct platform_device *pdev, const char *ocotp_com
		goto err_clk;
	}

	return clk_prepare_enable(drvdata->clk);
	ret = clk_prepare_enable(drvdata->clk);
	if (ret)
		goto err_clk;

	return 0;

err_clk:
	iounmap(drvdata->ocotp_base);
+16 −30
Original line number Diff line number Diff line
@@ -12,12 +12,13 @@
#include <linux/sys_soc.h>

#define IMX_SIP_GET_SOC_INFO	0xc2000006
#define SOC_ID(x)		(((x) & 0xFFFF) >> 8)
#define SOC_ID(x)		(((x) & 0xFF) ? ((x) & 0xFFFF) >> 4 : ((x) & 0xFFFF) >> 8)
#define SOC_REV_MAJOR(x)	((((x) >> 28) & 0xF) - 0x9)
#define SOC_REV_MINOR(x)	(((x) >> 24) & 0xF)

static int imx9_soc_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct soc_device_attribute *attr;
	struct arm_smccc_res res;
	struct soc_device *sdev;
@@ -25,17 +26,15 @@ static int imx9_soc_probe(struct platform_device *pdev)
	u64 uid127_64, uid63_0;
	int err;

	attr = kzalloc(sizeof(*attr), GFP_KERNEL);
	attr = devm_kzalloc(dev, sizeof(*attr), GFP_KERNEL);
	if (!attr)
		return -ENOMEM;

	err = of_property_read_string(of_root, "model", &attr->machine);
	if (err) {
		pr_err("%s: missing model property: %d\n", __func__, err);
		goto attr;
	}
	if (err)
		return dev_err_probe(dev, err, "%s: missing model property\n", __func__);

	attr->family = kasprintf(GFP_KERNEL, "Freescale i.MX");
	attr->family = devm_kasprintf(dev, GFP_KERNEL, "Freescale i.MX");

	/*
	 * Retrieve the soc id, rev & uid info:
@@ -45,46 +44,33 @@ static int imx9_soc_probe(struct platform_device *pdev)
	 * res.a3: uid[63:0];
	 */
	arm_smccc_smc(IMX_SIP_GET_SOC_INFO, 0, 0, 0, 0, 0, 0, 0, &res);
	if (res.a0 != SMCCC_RET_SUCCESS) {
		pr_err("%s: SMC failed: 0x%lx\n", __func__, res.a0);
		err = -EINVAL;
		goto family;
	}
	if (res.a0 != SMCCC_RET_SUCCESS)
		return dev_err_probe(dev, -EINVAL, "%s: SMC failed: 0x%lx\n", __func__, res.a0);

	soc_id = SOC_ID(res.a1);
	rev_major = SOC_REV_MAJOR(res.a1);
	rev_minor = SOC_REV_MINOR(res.a1);

	attr->soc_id = kasprintf(GFP_KERNEL, "i.MX%2x", soc_id);
	attr->revision = kasprintf(GFP_KERNEL, "%d.%d", rev_major, rev_minor);
	attr->soc_id = devm_kasprintf(dev, GFP_KERNEL, "i.MX%2x", soc_id);
	attr->revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d", rev_major, rev_minor);

	uid127_64 = res.a2;
	uid63_0 = res.a3;
	attr->serial_number = kasprintf(GFP_KERNEL, "%016llx%016llx", uid127_64, uid63_0);
	attr->serial_number = devm_kasprintf(dev, GFP_KERNEL, "%016llx%016llx", uid127_64, uid63_0);

	sdev = soc_device_register(attr);
	if (IS_ERR(sdev)) {
		err = PTR_ERR(sdev);
		pr_err("%s failed to register SoC as a device: %d\n", __func__, err);
		goto serial_number;
	}
	if (IS_ERR(sdev))
		return dev_err_probe(dev, PTR_ERR(sdev),
				     "%s failed to register SoC as a device\n", __func__);

	return 0;

serial_number:
	kfree(attr->serial_number);
	kfree(attr->revision);
	kfree(attr->soc_id);
family:
	kfree(attr->family);
attr:
	kfree(attr);
	return err;
}

static __maybe_unused const struct of_device_id imx9_soc_match[] = {
	{ .compatible = "fsl,imx93", },
	{ .compatible = "fsl,imx94", },
	{ .compatible = "fsl,imx95", },
	{ .compatible = "fsl,imx952", },
	{ }
};

+2 −0
Original line number Diff line number Diff line
@@ -59,6 +59,8 @@ struct scmi_imx_misc_proto_ops {
			     u32 *num, u32 *val);
	int (*misc_ctrl_req_notify)(const struct scmi_protocol_handle *ph,
				    u32 ctrl_id, u32 evt_id, u32 flags);
	int (*misc_syslog)(const struct scmi_protocol_handle *ph, u16 *size,
			   void *array);
};

/* See LMM_ATTRIBUTES in imx95.rst */