* [PATCH v2 1/2] power: reset: add MCF5441x RCM power-on reason driver
2026-06-07 8:49 [PATCH v2 0/2] Coldfire m5441x: add RCM power-on reason driver Jean-Michel Hautbois
@ 2026-06-07 8:49 ` Jean-Michel Hautbois
2026-06-17 14:27 ` Uwe Kleine-König
2026-06-07 8:49 ` [PATCH v2 2/2] m68k: coldfire/5441x: register mcf-rcm-reset platform device Jean-Michel Hautbois
1 sibling, 1 reply; 4+ messages in thread
From: Jean-Michel Hautbois @ 2026-06-07 8:49 UTC (permalink / raw)
To: Geert Uytterhoeven, Sebastian Reichel, Greg Ungerer
Cc: linux-m68k, linux-kernel, linux-pm, Jean-Michel Hautbois
Add a driver that decodes the Reset Status Register (RSR) of the
Freescale ColdFire MCF5441x Reset Controller Module at probe time
and exposes the cause via the power_on_reason sysfs ABI.
The RSR can latch several cause bits simultaneously (Reference
Manual chapter 12.3.2); the driver picks one cause per a priority
that favours the most explanatory diagnostic.
The register layout is described in the driver so it can be built
with COMPILE_TEST on any architecture.
Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
---
MAINTAINERS | 6 ++
drivers/power/reset/Kconfig | 12 ++++
drivers/power/reset/Makefile | 1 +
drivers/power/reset/mcf-rcm-reset.c | 126 ++++++++++++++++++++++++++++++++++++
4 files changed, 145 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index e035a3be797c..a82adb6fa40f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10196,6 +10196,12 @@ S: Maintained
F: drivers/mmc/host/sdhci-esdhc-mcf.c
F: include/linux/platform_data/mmc-esdhc-mcf.h
+FREESCALE COLDFIRE M5441X RCM POWER-ON REASON DRIVER
+M: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
+L: linux-m68k@lists.linux-m68k.org
+S: Maintained
+F: drivers/power/reset/mcf-rcm-reset.c
+
FREESCALE DIU FRAMEBUFFER DRIVER
M: Timur Tabi <timur@kernel.org>
L: linux-fbdev@vger.kernel.org
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 124afb99febe..bce996bbef28 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -128,6 +128,18 @@ config POWER_RESET_LINKSTATION
Say Y here if you have a Buffalo LinkStation LS421D/E.
+config POWER_RESET_MCF_RCM
+ tristate "Freescale ColdFire RCM power-on reason driver"
+ depends on M5441x || COMPILE_TEST
+ depends on HAS_IOMEM
+ help
+ This driver exposes the cause of the last reset on Freescale
+ ColdFire 5441x SoCs through the standard power_on_reason sysfs
+ ABI. It reads the Reset Status Register (RSR) of the Reset
+ Controller Module once at probe time and reports a normalised
+ string (regular power-up, reset button action, software reset
+ or unknown reason).
+
config POWER_RESET_MACSMC
tristate "Apple SMC reset/power-off driver"
depends on MFD_MACSMC
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index d7ae97241a83..e31cab4ba78e 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
obj-$(CONFIG_POWER_RESET_LINKSTATION) += linkstation-poweroff.o
+obj-$(CONFIG_POWER_RESET_MCF_RCM) += mcf-rcm-reset.o
obj-$(CONFIG_POWER_RESET_MACSMC) += macsmc-reboot.o
obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
obj-$(CONFIG_POWER_RESET_MT6323) += mt6323-poweroff.o
diff --git a/drivers/power/reset/mcf-rcm-reset.c b/drivers/power/reset/mcf-rcm-reset.c
new file mode 100644
index 000000000000..a3164bdcdfb3
--- /dev/null
+++ b/drivers/power/reset/mcf-rcm-reset.c
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Freescale ColdFire MCF5441x RCM power-on reason driver
+ *
+ * Copyright (C) 2026 Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
+ */
+
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power/power_on_reason.h>
+
+/*
+ * Reset Status Register (RSR) layout, MCF54418 Reference Manual chapter
+ * 12.3.2. The register is 8-bit read-only and latches the cause (or
+ * causes) of the most recent reset until the next one occurs.
+ */
+#define MCF_RSR_SOFT 0x20 /* Last reset caused by software */
+#define MCF_RSR_LOC 0x10 /* Last reset caused by PLL loss of clock */
+#define MCF_RSR_POR 0x08 /* Last reset caused by power-on */
+#define MCF_RSR_EXT 0x04 /* Last reset caused by external pin */
+#define MCF_RSR_WDRCORE 0x02 /* Last reset caused by core watchdog */
+#define MCF_RSR_LOL 0x01 /* Last reset caused by PLL loss of lock */
+
+#define MCF_RSR_KNOWN_CAUSES (MCF_RSR_POR | MCF_RSR_EXT | MCF_RSR_WDRCORE | \
+ MCF_RSR_LOC | MCF_RSR_LOL | MCF_RSR_SOFT)
+
+struct mcf_rcm {
+ const char *reason;
+};
+
+/*
+ * Decode RSR into a power_on_reason string.
+ *
+ * The MCF5441x Reset Status Register can latch several cause bits at the
+ * same time (Reference Manual chapter 12.3.2: "one or more status bits
+ * may be set at the same time"). A power-on, for example, also resets
+ * the PLL and may co-flag LOC and LOL during the boot sequence. The
+ * power_on_reason ABI carries a single string, so this routine picks
+ * one cause; the chosen priority surfaces the most explanatory one for
+ * diagnostics:
+ *
+ * POR cold boot dominates any spurious co-flagged cause
+ * EXT operator action via the RESET pin
+ * WDRCORE core watchdog timeout, a fault to investigate
+ * LOC, LOL PLL clock or lock failure, hardware fault
+ * SOFT explicit software-requested reset
+ */
+static const char *mcf_rcm_decode(u8 rsr)
+{
+ if (rsr & MCF_RSR_POR)
+ return POWER_ON_REASON_REGULAR;
+ if (rsr & MCF_RSR_EXT)
+ return POWER_ON_REASON_RST_BTN;
+ if (rsr & MCF_RSR_WDRCORE)
+ return POWER_ON_REASON_WATCHDOG;
+ if (rsr & (MCF_RSR_LOC | MCF_RSR_LOL))
+ return POWER_ON_REASON_CPU_CLK_FAIL;
+ if (rsr & MCF_RSR_SOFT)
+ return POWER_ON_REASON_SOFTWARE;
+ return POWER_ON_REASON_UNKNOWN;
+}
+
+static ssize_t power_on_reason_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mcf_rcm *rcm = platform_get_drvdata(to_platform_device(dev));
+
+ return sysfs_emit(buf, "%s\n", rcm->reason);
+}
+static DEVICE_ATTR_RO(power_on_reason);
+
+static struct attribute *mcf_rcm_attrs[] = {
+ &dev_attr_power_on_reason.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(mcf_rcm);
+
+static int mcf_rcm_probe(struct platform_device *pdev)
+{
+ struct mcf_rcm *rcm;
+ void __iomem *base;
+ u8 rsr;
+
+ rcm = devm_kzalloc(&pdev->dev, sizeof(*rcm), GFP_KERNEL);
+ if (!rcm)
+ return -ENOMEM;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ rsr = readb_relaxed(base);
+ rcm->reason = mcf_rcm_decode(rsr);
+
+ platform_set_drvdata(pdev, rcm);
+
+ if (!(rsr & MCF_RSR_KNOWN_CAUSES))
+ dev_warn(&pdev->dev, "Unknown reset cause (RSR=0x%02x)\n", rsr);
+ else
+ dev_info(&pdev->dev, "Starting after %s (RSR=0x%02x)\n",
+ rcm->reason, rsr);
+
+ return 0;
+}
+
+static const struct platform_device_id mcf_rcm_id[] = {
+ { "mcf-rcm-reset", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, mcf_rcm_id);
+
+static struct platform_driver mcf_rcm_driver = {
+ .probe = mcf_rcm_probe,
+ .id_table = mcf_rcm_id,
+ .driver = {
+ .name = "mcf-rcm-reset",
+ .dev_groups = mcf_rcm_groups,
+ },
+};
+module_platform_driver(mcf_rcm_driver);
+
+MODULE_AUTHOR("Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>");
+MODULE_DESCRIPTION("Freescale ColdFire RCM power-on reason driver");
+MODULE_LICENSE("GPL");
--
2.39.5
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH v2 2/2] m68k: coldfire/5441x: register mcf-rcm-reset platform device
2026-06-07 8:49 [PATCH v2 0/2] Coldfire m5441x: add RCM power-on reason driver Jean-Michel Hautbois
2026-06-07 8:49 ` [PATCH v2 1/2] power: reset: add MCF5441x " Jean-Michel Hautbois
@ 2026-06-07 8:49 ` Jean-Michel Hautbois
1 sibling, 0 replies; 4+ messages in thread
From: Jean-Michel Hautbois @ 2026-06-07 8:49 UTC (permalink / raw)
To: Geert Uytterhoeven, Sebastian Reichel, Greg Ungerer
Cc: linux-m68k, linux-kernel, linux-pm, Jean-Michel Hautbois
Add SoC-level registration of the mcf-rcm-reset platform device so the
power_on_reason sysfs attribute is created on every MCF5441x board
without per-board boilerplate.
Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
---
arch/m68k/coldfire/m5441x.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/arch/m68k/coldfire/m5441x.c b/arch/m68k/coldfire/m5441x.c
index 7a25cfc7ac07..852e52d95eaf 100644
--- a/arch/m68k/coldfire/m5441x.c
+++ b/arch/m68k/coldfire/m5441x.c
@@ -11,6 +11,7 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/clk.h>
+#include <linux/platform_device.h>
#include <asm/machdep.h>
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
@@ -239,6 +240,30 @@ static void __init m5441x_fec_init(void)
__raw_writeb(0x03, MCFGPIO_PAR_FEC);
}
+/*
+ * Reset Controller Module status register. Exposed to userspace as
+ * /sys/devices/platform/mcf-rcm-reset/power_on_reason by the mcf-rcm-reset
+ * driver (drivers/power/reset/mcf-rcm-reset.c).
+ */
+static struct resource m5441x_rcm_resource[] = {
+ {
+ .start = MCF_RSR,
+ .end = MCF_RSR,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static int __init m5441x_rcm_init(void)
+{
+ struct platform_device *pdev;
+
+ pdev = platform_device_register_simple("mcf-rcm-reset", -1,
+ m5441x_rcm_resource,
+ ARRAY_SIZE(m5441x_rcm_resource));
+ return PTR_ERR_OR_ZERO(pdev);
+}
+arch_initcall(m5441x_rcm_init);
+
void __init config_BSP(char *commandp, int size)
{
m5441x_clk_init();
--
2.39.5
^ permalink raw reply related [flat|nested] 4+ messages in thread