[PATCH 1/2] firmware: arm_scmi: imx: Support getting reset reason of MISC protocol

From: Peng Fan (OSS)

Date: Wed Mar 04 2026 - 20:56:15 EST


From: Peng Fan <peng.fan@xxxxxxx>

MISC protocol supports getting reset reason per Logical Machine or
System. Add the API for user to retrieve the information from System
Manager.

Signed-off-by: Peng Fan <peng.fan@xxxxxxx>
---
.../firmware/arm_scmi/vendors/imx/imx-sm-misc.c | 86 ++++++++++++++++++++++
include/linux/scmi_imx_protocol.h | 14 ++++
2 files changed, 100 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 0ada753367efe5cbcb8124ea46c05736c49f1ab8..637973fb45e6508c200211708358299cf7cbe3f1 100644
--- a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c
+++ b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c
@@ -27,6 +27,7 @@ enum scmi_imx_misc_protocol_cmd {
SCMI_IMX_MISC_CTRL_GET = 0x4,
SCMI_IMX_MISC_DISCOVER_BUILD_INFO = 0x6,
SCMI_IMX_MISC_CTRL_NOTIFY = 0x8,
+ SCMI_IMX_MISC_RESET_REASON_GET = 0xA,
SCMI_IMX_MISC_CFG_INFO_GET = 0xC,
SCMI_IMX_MISC_SYSLOG_GET = 0xD,
SCMI_IMX_MISC_BOARD_INFO = 0xE,
@@ -89,6 +90,37 @@ struct scmi_imx_misc_cfg_info_out {
u8 cfgname[MISC_MAX_CFGNAME];
};

+struct scmi_imx_misc_reset_reason_in {
+#define MISC_REASON_FLAG_SYSTEM BIT(0)
+ __le32 flags;
+};
+
+struct scmi_imx_misc_reset_reason_out {
+ /* Boot reason flags */
+#define MISC_BOOT_FLAG_VLD BIT(31)
+#define MISC_BOOT_FLAG_ORG_VLD BIT(28)
+#define MISC_BOOT_FLAG_ORIGIN GENMASK(27, 24)
+#define MISC_BOOT_FLAG_O_SHIFT 24
+#define MISC_BOOT_FLAG_ERR_VLD BIT(23)
+#define MISC_BOOT_FLAG_ERR_ID GENMASK(22, 8)
+#define MISC_BOOT_FLAG_E_SHIFT 8
+#define MISC_BOOT_FLAG_REASON GENMASK(7, 0)
+ __le32 b_flags;
+ /* Shutdown reason flags */
+#define MISC_SHUTDOWN_FLAG_VLD BIT(31)
+#define MISC_SHUTDOWN_FLAG_EXT_LEN GENMASK(30, 29)
+#define MISC_SHUTDOWN_FLAG_ORG_VLD BIT(28)
+#define MISC_SHUTDOWN_FLAG_ORIGIN GENMASK(27, 24)
+#define MISC_SHUTDOWN_FLAG_O_SHIFT 24
+#define MISC_SHUTDOWN_FLAG_ERR_VLD BIT(23)
+#define MISC_SHUTDOWN_FLAG_ERR_ID GENMASK(22, 8)
+#define MISC_SHUTDOWN_FLAG_E_SHIFT 8
+#define MISC_SHUTDOWN_FLAG_REASON GENMASK(7, 0)
+ __le32 s_flags;
+ /* Array of extended info words */
+ __le32 extinfo[MISC_EXT_INFO_LEN_MAX];
+};
+
struct scmi_imx_misc_syslog_in {
__le32 flags;
__le32 index;
@@ -452,11 +484,65 @@ static int scmi_imx_misc_syslog_get(const struct scmi_protocol_handle *ph, u16 *
return ph->hops->iter_response_run(iter);
}

+static int scmi_imx_misc_reset_reason(const struct scmi_protocol_handle *ph, bool system,
+ struct scmi_imx_misc_reset_reason *boot_r,
+ struct scmi_imx_misc_reset_reason *shut_r,
+ u32 *extinfo)
+{
+ struct scmi_imx_misc_reset_reason_in *in;
+ struct scmi_imx_misc_reset_reason_out *out;
+ struct scmi_xfer *t;
+ int ret;
+
+ ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_RESET_REASON_GET, sizeof(*in),
+ sizeof(*out), &t);
+ if (ret)
+ return ret;
+
+ in = t->tx.buf;
+ if (system)
+ in->flags = le32_encode_bits(1, MISC_REASON_FLAG_SYSTEM);
+ else
+ in->flags = cpu_to_le32(0);
+
+ ret = ph->xops->do_xfer(ph, t);
+ if (!ret) {
+ out = t->rx.buf;
+ if (boot_r) {
+ boot_r->valid = le32_get_bits(out->b_flags, MISC_BOOT_FLAG_VLD);
+ boot_r->orig_valid = le32_get_bits(out->b_flags, MISC_BOOT_FLAG_ORG_VLD);
+ boot_r->err_valid = le32_get_bits(out->b_flags, MISC_BOOT_FLAG_ERR_VLD);
+ boot_r->reason = le32_get_bits(out->b_flags, MISC_BOOT_FLAG_REASON);
+ boot_r->origin = le32_get_bits(out->b_flags, MISC_BOOT_FLAG_ORIGIN);
+ boot_r->errid = le32_get_bits(out->b_flags, MISC_BOOT_FLAG_ERR_ID);
+ }
+
+ if (shut_r) {
+ shut_r->valid = le32_get_bits(out->s_flags, MISC_SHUTDOWN_FLAG_VLD);
+ shut_r->orig_valid = le32_get_bits(out->s_flags,
+ MISC_SHUTDOWN_FLAG_ORG_VLD);
+ shut_r->err_valid = le32_get_bits(out->s_flags,
+ MISC_SHUTDOWN_FLAG_ERR_VLD);
+ shut_r->reason = le32_get_bits(out->s_flags, MISC_SHUTDOWN_FLAG_REASON);
+ shut_r->origin = le32_get_bits(out->s_flags, MISC_SHUTDOWN_FLAG_ORIGIN);
+ shut_r->errid = le32_get_bits(out->s_flags, MISC_SHUTDOWN_FLAG_ERR_ID);
+ }
+
+ if (extinfo)
+ memcpy_from_le32(extinfo, out->extinfo, MISC_EXT_INFO_LEN_MAX);
+ }
+
+ ph->xops->xfer_put(ph, t);
+
+ return ret;
+}
+
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,
+ .misc_reset_reason = scmi_imx_misc_reset_reason,
};

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 2407d7693b6ba1303e07629e45e2a7eaaa906fd3..ab867463c08cc297e063aa1dc4189132a5ddb61a 100644
--- a/include/linux/scmi_imx_protocol.h
+++ b/include/linux/scmi_imx_protocol.h
@@ -52,6 +52,17 @@ struct scmi_imx_misc_ctrl_notify_report {
unsigned int flags;
};

+
+#define MISC_EXT_INFO_LEN_MAX 4
+struct scmi_imx_misc_reset_reason {
+ bool valid:1;
+ bool orig_valid:1;
+ bool err_valid:1;
+ u32 reason;
+ u32 origin;
+ u32 errid;
+};
+
struct scmi_imx_misc_proto_ops {
int (*misc_ctrl_set)(const struct scmi_protocol_handle *ph, u32 id,
u32 num, u32 *val);
@@ -61,6 +72,9 @@ struct scmi_imx_misc_proto_ops {
u32 ctrl_id, u32 evt_id, u32 flags);
int (*misc_syslog)(const struct scmi_protocol_handle *ph, u16 *size,
void *array);
+ int (*misc_reset_reason)(const struct scmi_protocol_handle *ph,
+ bool system, struct scmi_imx_misc_reset_reason *boot_r,
+ struct scmi_imx_misc_reset_reason *shut_r, u32 *extinfo);
};

/* See LMM_ATTRIBUTES in imx95.rst */

--
2.37.1