From 4fa62e80c7dba7ff419dea23f10bcb125e38bde3 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 29 Oct 2025 20:07:01 +0800 Subject: [PATCH 1/6] firmware: arm_scmi: imx: Support getting syslog of MISC protocol MISC protocol supports getting system log regarding system sleep latency, wakeup interrupt and etc. Add the API for user to retrieve the information from SM. Signed-off-by: Peng Fan Acked-by: Sudeep Holla Signed-off-by: Shawn Guo --- .../arm_scmi/vendors/imx/imx-sm-misc.c | 83 +++++++++++++++++++ include/linux/scmi_imx_protocol.h | 2 + 2 files changed, 85 insertions(+) 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 700a3f24f4ef..eae0b0562f6c 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, }; @@ -89,6 +90,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) { @@ -371,10 +385,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/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 */ From 80a4062e8821861c3ce7407ea5b23afa959917e2 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 29 Oct 2025 20:07:02 +0800 Subject: [PATCH 2/6] firmware: imx: sm-misc: Dump syslog info Add debugfs interface to read System Manager syslog info Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/firmware/imx/sm-misc.c | 37 +++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) 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 +#include #include #include #include #include #include #include +#include +#include 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[] = { From ab382a6ee25f0b571cffad66b2e6aaf0d2d245ec Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 17 Dec 2025 20:42:07 +0800 Subject: [PATCH 3/6] soc: imx: Use device-managed APIs for i.MX9 Use device-managed APi to simplify code. Signed-off-by: Peng Fan Reviewed-by: Frank Li Signed-off-by: Shawn Guo --- drivers/soc/imx/soc-imx9.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/drivers/soc/imx/soc-imx9.c b/drivers/soc/imx/soc-imx9.c index b46d22cf0212..0b1c59c7ddb2 100644 --- a/drivers/soc/imx/soc-imx9.c +++ b/drivers/soc/imx/soc-imx9.c @@ -18,6 +18,7 @@ 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,17 @@ 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; + return err; } - 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: @@ -47,39 +48,28 @@ static int imx9_soc_probe(struct platform_device *pdev) 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; + return -EINVAL; } 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; + return err; } 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[] = { From 36ca5298fc426f7c69111c7d4ef9310d2dc2d296 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 17 Dec 2025 20:42:08 +0800 Subject: [PATCH 4/6] soc: imx: Use dev_err_probe() for i.MX9 Use dev_err_probe() to simplify code. No functional changes. Signed-off-by: Peng Fan Reviewed-by: Frank Li Signed-off-by: Shawn Guo --- drivers/soc/imx/soc-imx9.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/soc/imx/soc-imx9.c b/drivers/soc/imx/soc-imx9.c index 0b1c59c7ddb2..d9a686299c5f 100644 --- a/drivers/soc/imx/soc-imx9.c +++ b/drivers/soc/imx/soc-imx9.c @@ -31,10 +31,8 @@ static int imx9_soc_probe(struct platform_device *pdev) return -ENOMEM; err = of_property_read_string(of_root, "model", &attr->machine); - if (err) { - pr_err("%s: missing model property: %d\n", __func__, err); - return err; - } + if (err) + return dev_err_probe(dev, err, "%s: missing model property\n", __func__); attr->family = devm_kasprintf(dev, GFP_KERNEL, "Freescale i.MX"); @@ -46,10 +44,8 @@ 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); - return -EINVAL; - } + 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); @@ -63,11 +59,9 @@ static int imx9_soc_probe(struct platform_device *pdev) 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); - return err; - } + if (IS_ERR(sdev)) + return dev_err_probe(dev, PTR_ERR(sdev), + "%s failed to register SoC as a device\n", __func__); return 0; } From 4acaf8b293c8b03301508764dc3e586658186730 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 17 Dec 2025 20:42:09 +0800 Subject: [PATCH 5/6] soc: imx: Spport i.MX9[4,52] Add i.MX9[4,52] machine compatible to allow soc device could be created. SOC_ID is 16bit format data: - i.MX943: 0x9430 - i.MX952: 0x9520 Update SOC_ID macro to get the accurate data. Co-developed-by: Jacky Bai Signed-off-by: Jacky Bai Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/soc/imx/soc-imx9.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/soc/imx/soc-imx9.c b/drivers/soc/imx/soc-imx9.c index d9a686299c5f..d67bc7402b10 100644 --- a/drivers/soc/imx/soc-imx9.c +++ b/drivers/soc/imx/soc-imx9.c @@ -12,7 +12,7 @@ #include #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) @@ -68,7 +68,9 @@ static int imx9_soc_probe(struct platform_device *pdev) static __maybe_unused const struct of_device_id imx9_soc_match[] = { { .compatible = "fsl,imx93", }, + { .compatible = "fsl,imx94", }, { .compatible = "fsl,imx95", }, + { .compatible = "fsl,imx952", }, { } }; From f6ef3d9ff81240e9bcc030f2da132eb0f8a761d7 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 14 Jan 2026 06:12:41 +0800 Subject: [PATCH 6/6] soc: imx8m: Fix error handling for clk_prepare_enable() imx8m_soc_prepare() directly returns the result of clk_prepare_enable(), which skips proper cleanup if the clock enable fails. Check the return value of clk_prepare_enable() and release resources if failure. Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202601111406.ZVV3YaiU-lkp@intel.com/ Signed-off-by: Peng Fan Reviewed-by: Marco Felsch Reviewed-by: Daniel Baluta Signed-off-by: Shawn Guo --- drivers/soc/imx/soc-imx8m.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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);