From: Peng Fan <peng.fan@nxp.com>
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@nxp.com>
---
.../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
On Thu, Mar 5, 2026 at 3:55 AM Peng Fan (OSS) <peng.fan@oss.nxp.com> wrote: > > From: Peng Fan <peng.fan@nxp.com> > > 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@nxp.com> Reviewed-by: Daniel Baluta <daniel.baluta@nxp.com> Thanks Peng for your explanations!
On Thu, Mar 05, 2026 at 09:56:44AM +0800, Peng Fan (OSS) wrote: > From: Peng Fan <peng.fan@nxp.com> > > MISC protocol supports getting reset reason per Logical Machine or > System. Add the API for user to retrieve the information from System > Manager. > Sorry for missing this earlier. It looks good though my usual rant is that this MISC protocol is becoming never ending dumping ground for all sorts of info you want kernel to dump in dmesg. Anyways, I am not too bothered as it is not any user ABI. If, you plan to ask i.MX maintainers to pick this up, Reviewed-by: Sudeep Holla <sudeep.holla@kernel.org> If not, I need their ack for 2/2/ -- Regards, Sudeep
On Thu, Mar 5, 2026 at 3:55 AM Peng Fan (OSS) <peng.fan@oss.nxp.com> wrote:
>
> From: Peng Fan <peng.fan@nxp.com>
>
> MISC protocol supports getting reset reason per Logical Machine or
> System. Add the API for user to retrieve the information from System
> Manager.
[..]
> +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)
I would move this macros outside of the struct. Although the intention
is good it makes everything hard to read.
Just do:
struct scmi_imx_misc_reset_reason_out {
__le32 b_flags; /* MISC_BOOT_FLAG_* flags */
__le32 s_flags; /* MISC_SHUTDOWN_FLAG_* flags */
/* Array of extended info words */
__le32 extinfo[MISC_EXT_INFO_LEN_MAX];
}
[...]
> +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);
What does system = 0 mean? can you directly do in->flags = 0?
> +
> + ret = ph->xops->do_xfer(ph, t);
Is it mandatory to call ph->xops->xfer_put(ph, t); even if ret ! = 0?
Because we can get rid of one level of indentation with:
ret = ph->xops->do_xfer(ph, t);
if (ret)
return ret;
Hi Daniel,
Thanks for giving a look.
On Thu, Mar 05, 2026 at 08:52:41AM +0200, Daniel Baluta wrote:
>On Thu, Mar 5, 2026 at 3:55 AM Peng Fan (OSS) <peng.fan@oss.nxp.com> wrote:
>>
>> From: Peng Fan <peng.fan@nxp.com>
>>
>> MISC protocol supports getting reset reason per Logical Machine or
>> System. Add the API for user to retrieve the information from System
>> Manager.
>
>[..]
>
>> +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)
>
>I would move this macros outside of the struct. Although the intention
>is good it makes everything hard to read.
I followed arm_scmi coding style, such as
drivers/firmware/arm_scmi/clock.c
drivers/firmware/arm_scmi/perf.c
and etc.
I would not break the rule here.
>
>Just do:
>
>struct scmi_imx_misc_reset_reason_out {
>__le32 b_flags; /* MISC_BOOT_FLAG_* flags */
>__le32 s_flags; /* MISC_SHUTDOWN_FLAG_* flags */
> /* Array of extended info words */
> __le32 extinfo[MISC_EXT_INFO_LEN_MAX];
>}
>
>[...]
>
>> +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);
>
>What does system = 0 mean? can you directly do in->flags = 0?
If system is false, that means to get LM(logial machine) reset reason.
If system is true, that means to get system reset reason.
grep "cpu_to_le32(0)" ./drivers/firmware/arm_scmi/ -rn
You will see other usage, I just follow same style here.
>
>
>> +
>> + ret = ph->xops->do_xfer(ph, t);
>
>Is it mandatory to call ph->xops->xfer_put(ph, t); even if ret ! = 0?
>Because we can get rid of one level of indentation with:
yes, xfer_put is mandatory.
Thanks,
Peng.
>
> ret = ph->xops->do_xfer(ph, t);
> if (ret)
> return ret;
© 2016 - 2026 Red Hat, Inc.