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