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 */
+}
+

Reply via email to