summaryrefslogtreecommitdiff
path: root/drivers/firmware/imx
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware/imx')
-rw-r--r--drivers/firmware/imx/imx-scu.c25
-rw-r--r--drivers/firmware/imx/sm-misc.c78
2 files changed, 101 insertions, 2 deletions
diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx-scu.c
index 67b267a7408a..203aac421252 100644
--- a/drivers/firmware/imx/imx-scu.c
+++ b/drivers/firmware/imx/imx-scu.c
@@ -82,6 +82,17 @@ static int imx_sc_linux_errmap[IMX_SC_ERR_LAST] = {
static struct imx_sc_ipc *imx_sc_ipc_handle;
+static void imx_scu_free_mbox_chan(void *data)
+{
+ mbox_free_channel(data);
+}
+
+static void imx_scu_clear_handle(void *data)
+{
+ if (imx_sc_ipc_handle == data)
+ imx_sc_ipc_handle = NULL;
+}
+
static inline int imx_sc_to_linux_errno(int errno)
{
if (errno >= IMX_SC_ERR_NONE && errno < IMX_SC_ERR_LAST)
@@ -321,6 +332,11 @@ static int imx_scu_probe(struct platform_device *pdev)
dev_dbg(dev, "request mbox chan %s\n", chan_name);
/* chan_name is not used anymore by framework */
kfree(chan_name);
+
+ ret = devm_add_action_or_reset(dev, imx_scu_free_mbox_chan,
+ sc_chan->ch);
+ if (ret)
+ return ret;
}
sc_ipc->dev = dev;
@@ -330,6 +346,9 @@ static int imx_scu_probe(struct platform_device *pdev)
init_completion(&sc_ipc->done);
imx_sc_ipc_handle = sc_ipc;
+ ret = devm_add_action_or_reset(dev, imx_scu_clear_handle, sc_ipc);
+ if (ret)
+ return ret;
ret = imx_scu_soc_init(dev);
if (ret)
@@ -342,7 +361,11 @@ static int imx_scu_probe(struct platform_device *pdev)
dev_info(dev, "NXP i.MX SCU Initialized\n");
- return devm_of_platform_populate(dev);
+ ret = devm_of_platform_populate(dev);
+ if (ret)
+ of_platform_depopulate(dev);
+
+ return ret;
}
static const struct of_device_id imx_scu_match[] = {
diff --git a/drivers/firmware/imx/sm-misc.c b/drivers/firmware/imx/sm-misc.c
index 0a8ada329c9d..fb8d7bdb5b08 100644
--- a/drivers/firmware/imx/sm-misc.c
+++ b/drivers/firmware/imx/sm-misc.c
@@ -16,7 +16,30 @@
static const struct scmi_imx_misc_proto_ops *imx_misc_ctrl_ops;
static struct scmi_protocol_handle *ph;
-struct notifier_block scmi_imx_misc_ctrl_nb;
+static struct notifier_block scmi_imx_misc_ctrl_nb;
+
+static const char * const rst_imx95[] = {
+ "cm33_lockup", "cm33_swreq", "cm7_lockup", "cm7_swreq", "fccu",
+ "jtag_sw", "ele", "tempsense", "wdog1", "wdog2", "wdog3", "wdog4",
+ "wdog5", "jtag", "cm33_exc", "bbm", "sw", "sm_err", "fusa_sreco",
+ "pmic", "unused", "unused", "unused", "unused", "unused", "unused",
+ "unused", "unused", "unused", "unused", "unused", "por",
+};
+
+static const char * const rst_imx94[] = {
+ "cm33_lockup", "cm33_swreq", "cm70_lockup", "cm70_swreq", "fccu",
+ "jtag_sw", "ele", "tempsense", "wdog1", "wdog2", "wdog3", "wdog4",
+ "wdog5", "jtag", "wdog6", "wdog7", "wdog8", "wo_netc", "cm33s_lockup",
+ "cm33s_swreq", "cm71_lockup", "cm71_swreq", "cm33_exc", "bbm", "sw",
+ "sm_err", "fusa_sreco", "pmic", "unused", "unused", "unused", "por",
+};
+
+static const struct of_device_id allowlist[] = {
+ { .compatible = "fsl,imx952", .data = rst_imx95 },
+ { .compatible = "fsl,imx95", .data = rst_imx95 },
+ { .compatible = "fsl,imx94", .data = rst_imx94 },
+ { /* Sentinel */ }
+};
int scmi_imx_misc_ctrl_set(u32 id, u32 val)
{
@@ -56,6 +79,9 @@ static int syslog_show(struct seq_file *file, void *priv)
u16 size = SZ_4K / 4;
int ret;
+ if (!syslog)
+ return -ENOMEM;
+
if (!ph)
return -ENODEV;
@@ -75,6 +101,54 @@ static void scmi_imx_misc_put(void *p)
debugfs_remove((struct dentry *)p);
}
+static int scmi_imx_misc_get_reason(struct scmi_device *sdev)
+{
+ struct scmi_imx_misc_reset_reason boot, shutdown;
+ const char **rst;
+ bool system = true;
+ int ret;
+
+ if (!of_machine_device_match(allowlist))
+ return 0;
+
+ rst = (const char **)of_machine_get_match_data(allowlist);
+
+ ret = imx_misc_ctrl_ops->misc_reset_reason(ph, system, &boot, &shutdown, NULL);
+ if (!ret) {
+ if (boot.valid)
+ dev_info(&sdev->dev, "%s Boot reason: %s, origin: %d, errid: %d\n",
+ system ? "SYS" : "LM", rst[boot.reason],
+ boot.orig_valid ? boot.origin : -1,
+ boot.err_valid ? boot.errid : -1);
+ if (shutdown.valid)
+ dev_info(&sdev->dev, "%s shutdown reason: %s, origin: %d, errid: %d\n",
+ system ? "SYS" : "LM", rst[shutdown.reason],
+ shutdown.orig_valid ? shutdown.origin : -1,
+ shutdown.err_valid ? shutdown.errid : -1);
+ } else {
+ dev_err(&sdev->dev, "Failed to get system reset reason: %d\n", ret);
+ }
+
+ system = false;
+ ret = imx_misc_ctrl_ops->misc_reset_reason(ph, system, &boot, &shutdown, NULL);
+ if (!ret) {
+ if (boot.valid)
+ dev_info(&sdev->dev, "%s Boot reason: %s, origin: %d, errid: %d\n",
+ system ? "SYS" : "LM", rst[boot.reason],
+ boot.orig_valid ? boot.origin : -1,
+ boot.err_valid ? boot.errid : -1);
+ if (shutdown.valid)
+ dev_info(&sdev->dev, "%s shutdown reason: %s, origin: %d, errid: %d\n",
+ system ? "SYS" : "LM", rst[shutdown.reason],
+ shutdown.orig_valid ? shutdown.origin : -1,
+ shutdown.err_valid ? shutdown.errid : -1);
+ } else {
+ dev_err(&sdev->dev, "Failed to get lm reset reason: %d\n", ret);
+ }
+
+ return 0;
+}
+
static int scmi_imx_misc_ctrl_probe(struct scmi_device *sdev)
{
const struct scmi_handle *handle = sdev->handle;
@@ -133,6 +207,8 @@ static int scmi_imx_misc_ctrl_probe(struct scmi_device *sdev)
scmi_imx_dentry = debugfs_create_dir("scmi_imx", NULL);
debugfs_create_file("syslog", 0444, scmi_imx_dentry, &sdev->dev, &syslog_fops);
+ scmi_imx_misc_get_reason(sdev);
+
return devm_add_action_or_reset(&sdev->dev, scmi_imx_misc_put, scmi_imx_dentry);
}