diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2026-01-21 16:39:29 +0100 |
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2026-01-21 16:39:29 +0100 |
| commit | 6d9e4c74372bd08c75d7c2dbdccc4d713caabbd9 (patch) | |
| tree | 5507f0c9317fc4eb7317fb7192ac745cd0a69644 | |
| parent | 419a620dc452b9cd6aa684d99bcff352f7ab7f13 (diff) | |
| parent | f6ef3d9ff81240e9bcc030f2da132eb0f8a761d7 (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.c | 83 | ||||
| -rw-r--r-- | drivers/firmware/imx/sm-misc.c | 37 | ||||
| -rw-r--r-- | drivers/soc/imx/soc-imx8m.c | 6 | ||||
| -rw-r--r-- | drivers/soc/imx/soc-imx9.c | 46 | ||||
| -rw-r--r-- | include/linux/scmi_imx_protocol.h | 2 |
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 */ |
