summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2026-01-21 16:39:29 +0100
committerArnd Bergmann <arnd@arndb.de>2026-01-21 16:39:29 +0100
commit6d9e4c74372bd08c75d7c2dbdccc4d713caabbd9 (patch)
tree5507f0c9317fc4eb7317fb7192ac745cd0a69644
parent419a620dc452b9cd6aa684d99bcff352f7ab7f13 (diff)
parentf6ef3d9ff81240e9bcc030f2da132eb0f8a761d7 (diff)
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: Arnd Bergmann <arnd@arndb.de>
-rw-r--r--drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c83
-rw-r--r--drivers/firmware/imx/sm-misc.c37
-rw-r--r--drivers/soc/imx/soc-imx8m.c6
-rw-r--r--drivers/soc/imx/soc-imx9.c46
-rw-r--r--include/linux/scmi_imx_protocol.h2
5 files changed, 142 insertions, 32 deletions
diff --git a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c
index 73d80f221b9d..0ada753367ef 100644
--- a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c
+++ b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c
@@ -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)
diff --git a/drivers/firmware/imx/sm-misc.c b/drivers/firmware/imx/sm-misc.c
index fc3ee12c2be8..0a8ada329c9d 100644
--- a/drivers/firmware/imx/sm-misc.c
+++ b/drivers/firmware/imx/sm-misc.c
@@ -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[] = {
diff --git a/drivers/soc/imx/soc-imx8m.c b/drivers/soc/imx/soc-imx8m.c
index 04a1b60f2f2b..8e2322999f09 100644
--- a/drivers/soc/imx/soc-imx8m.c
+++ b/drivers/soc/imx/soc-imx8m.c
@@ -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);
diff --git a/drivers/soc/imx/soc-imx9.c b/drivers/soc/imx/soc-imx9.c
index b46d22cf0212..d67bc7402b10 100644
--- a/drivers/soc/imx/soc-imx9.c
+++ b/drivers/soc/imx/soc-imx9.c
@@ -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", },
{ }
};
diff --git a/include/linux/scmi_imx_protocol.h b/include/linux/scmi_imx_protocol.h
index 27bd372cbfb1..2407d7693b6b 100644
--- a/include/linux/scmi_imx_protocol.h
+++ b/include/linux/scmi_imx_protocol.h
@@ -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 */