Module Name: src
Committed By: mlelstv
Date: Mon Jun 10 06:03:49 UTC 2024
Modified Files:
src/sys/arch/arm/broadcom: bcm2835_pmwdog.c
Log Message:
Add support for poweroff.
There is no circuitry to actually remove power from RPI, but you can reboot
into a low power state. Depending on model/firmware release you need a power
cycle or a GPIO signal to leave the low power state again. Add-on hardware
is usually unaffected.
To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/broadcom/bcm2835_pmwdog.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/arm/broadcom/bcm2835_pmwdog.c
diff -u src/sys/arch/arm/broadcom/bcm2835_pmwdog.c:1.2 src/sys/arch/arm/broadcom/bcm2835_pmwdog.c:1.3
--- src/sys/arch/arm/broadcom/bcm2835_pmwdog.c:1.2 Wed Jan 27 03:10:19 2021
+++ src/sys/arch/arm/broadcom/bcm2835_pmwdog.c Mon Jun 10 06:03:48 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: bcm2835_pmwdog.c,v 1.2 2021/01/27 03:10:19 thorpej Exp $ */
+/* $NetBSD: bcm2835_pmwdog.c,v 1.3 2024/06/10 06:03:48 mlelstv Exp $ */
/*-
* Copyright (c) 2012, 2016 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bcm2835_pmwdog.c,v 1.2 2021/01/27 03:10:19 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bcm2835_pmwdog.c,v 1.3 2024/06/10 06:03:48 mlelstv Exp $");
#include <sys/param.h>
@@ -54,12 +54,19 @@ __KERNEL_RCSID(0, "$NetBSD: bcm2835_pmwd
#endif
#define BCM2835_PM_PASSWORD 0x5a000000
+#define BCM2835_PM_PASSWORD_MASK 0xff000000
#define BCM2835_PM_RSTC 0x1c
#define BCM2835_PM_RSTC_CONFIGMASK 0x00000030
#define BCM2835_PM_RSTC_FULL_RESET 0x00000020
#define BCM2835_PM_RSTC_RESET 0x00000102
+#define BCM2835_PM_RSTS 0x20
+#define BCM2835_PM_RSTS_PART(x) \
+ ((uint16_t)((x) & 0x01) << 0 | (uint16_t)((x) & 0x02) << 1 | \
+ (uint16_t)((x) & 0x04) << 2 | (uint16_t)((x) & 0x08) << 3 | \
+ (uint16_t)((x) & 0x10) << 4 | (uint16_t)((x) & 0x20) << 5)
+
#define BCM2835_PM_WDOG 0x24
#define BCM2835_PM_WDOG_TIMEMASK 0x000fffff
@@ -82,6 +89,10 @@ static void bcmpmwdog_set_timeout(struct
static int bcmpmwdog_setmode(struct sysmon_wdog *);
static int bcmpmwdog_tickle(struct sysmon_wdog *);
+/* fdt power controller */
+static void bcm2835_power_reset(device_t);
+static void bcm2835_power_poweroff(device_t);
+
CFATTACH_DECL_NEW(bcmpmwdog_fdt, sizeof(struct bcm2835pmwdog_softc),
bcmpmwdog_match, bcmpmwdog_attach, NULL, NULL);
@@ -90,6 +101,11 @@ static const struct device_compatible_en
DEVICE_COMPAT_EOL
};
+static struct fdtbus_power_controller_func bcmpmwdog_power_funcs = {
+ .reset = bcm2835_power_reset,
+ .poweroff = bcm2835_power_poweroff
+};
+
/* ARGSUSED */
static int
bcmpmwdog_match(device_t parent, cfdata_t match, void *aux)
@@ -136,6 +152,9 @@ bcmpmwdog_attach(device_t parent, device
sc->sc_smw.smw_period = BCM2835_PM_DEFAULT_PERIOD;
if (sysmon_wdog_register(&sc->sc_smw) != 0)
aprint_error_dev(self, "couldn't register watchdog\n");
+
+ fdtbus_register_power_controller(self, phandle,
+ &bcmpmwdog_power_funcs);
}
static void
@@ -176,6 +195,17 @@ bcmpmwdog_setmode(struct sysmon_wdog *sm
return error;
}
+static void
+bcmpmwdog_set_partition(struct bcm2835pmwdog_softc *sc, uint8_t part)
+{
+ uint32_t tmp;
+
+ tmp = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BCM2835_PM_RSTS);
+ tmp &= ~(BCM2835_PM_PASSWORD_MASK | BCM2835_PM_RSTS_PART(~0));
+ tmp |= BCM2835_PM_PASSWORD | BCM2835_PM_RSTS_PART(part);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, BCM2835_PM_RSTS, tmp);
+}
+
static int
bcmpmwdog_tickle(struct sysmon_wdog *smw)
{
@@ -187,11 +217,43 @@ bcmpmwdog_tickle(struct sysmon_wdog *smw
return 0;
}
+static void
+bcm2835_restart(struct bcm2835pmwdog_softc *sc, int partition)
+{
+ uint32_t timeout = 10;
+
+ bcmpmwdog_set_partition(sc, partition);
+ bcmpmwdog_set_timeout(sc, timeout);
+}
+
void
bcm2835_system_reset(void)
{
struct bcm2835pmwdog_softc *sc = bcm2835pmwdog_sc;
- uint32_t timeout = 10;
- bcmpmwdog_set_timeout(sc, timeout);
+ bcm2835_restart(sc, 0);
+}
+
+static void
+bcm2835_power_reset(device_t self)
+{
+ struct bcm2835pmwdog_softc *sc = device_private(self);
+
+ bcm2835_restart(sc, 0);
+
+ for (;;) continue;
+ /* NOTREACHED */
}
+
+static void
+bcm2835_power_poweroff(device_t self)
+{
+ struct bcm2835pmwdog_softc *sc = device_private(self);
+
+ /* Boot from partition 63 is magic to halt boot process */
+ bcm2835_restart(sc, 63);
+
+ for (;;) continue;
+ /* NOTREACHED */
+}
+