mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-02-13 15:23:28 -05:00
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>
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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", },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user