This patch enables OpenBSD to power off the Pinebook Pro, e.g., as a result of 'shutdown -h -p now'. This is a workaround for lack of a proper fix in ATF, proposed but abandoned, see: https://review.trustedfirmware.org/c/TF-A/trusted-firmware-a/+/7726 Threfore, the present patch should probably not be merged; the fix linked above should be upstreamed instead. But for the time being, it might be useful as it does the job of powering off the SoC via poking into the RK808 register and hooking that up as OpenBSD's powerdownfn. Many thanks and all credits to Tomasz Bielecki for sharing this patch with me, which I am publishing (with his permission) unchanged. Index: sys/dev/fdt/rkpmic.c =================================================================== RCS file: /cvs/src/sys/dev/fdt/rkpmic.c,v retrieving revision 1.9 diff -u -p -r1.9 rkpmic.c --- sys/dev/fdt/rkpmic.c 24 Oct 2021 17:52:27 -0000 1.9 +++ sys/dev/fdt/rkpmic.c 3 Mar 2022 20:54:19 -0000 @@ -28,6 +28,8 @@ #include +extern void (*powerdownfn)(void); + extern todr_chip_handle_t todr_handle; #define RK80X_SECONDS 0x00 @@ -49,6 +51,9 @@ extern todr_chip_handle_t todr_handle; #define RK809_RTC_STATUS 0x0e #define RK80X_RTC_STATUS_POWER_UP 0x80 +#define RK808_DEVCTRL 0x4b +#define RK808_DEV_OFF_MASK (1 << 3) + struct rkpmic_vsel_range { uint32_t base, delta; uint8_t vsel_min, vsel_max; @@ -234,11 +239,13 @@ struct rkpmic_softc { i2c_tag_t sc_tag; i2c_addr_t sc_addr; - int sc_rtc_ctrl_reg, sc_rtc_status_reg; + int sc_dev_ctrl_reg, sc_rtc_ctrl_reg, sc_rtc_status_reg; struct todr_chip_handle sc_todr; struct rkpmic_regdata *sc_regdata; }; +struct rkpmic_softc *rkpmic; + int rkpmic_match(struct device *, void *, void *); void rkpmic_attach(struct device *, struct device *, void *); @@ -257,6 +264,7 @@ int rkpmic_clock_read(struct rkpmic_soft int rkpmic_clock_write(struct rkpmic_softc *, struct clock_ymdhms *); int rkpmic_gettime(struct todr_chip_handle *, struct timeval *); int rkpmic_settime(struct todr_chip_handle *, struct timeval *); +void rkpmic_powerdown(void); int rkpmic_match(struct device *parent, void *match, void *aux) @@ -292,9 +300,11 @@ rkpmic_attach(struct device *parent, str sc->sc_regdata = rk805_regdata; } else if (OF_is_compatible(node, "rockchip,rk808")) { chip = "RK808"; + sc->sc_dev_ctrl_reg = RK808_DEVCTRL; sc->sc_rtc_ctrl_reg = RK808_RTC_CTRL; sc->sc_rtc_status_reg = RK808_RTC_STATUS; sc->sc_regdata = rk808_regdata; + powerdownfn = rkpmic_powerdown; } else { chip = "RK809"; sc->sc_rtc_ctrl_reg = RK809_RTC_CTRL; @@ -303,6 +313,8 @@ rkpmic_attach(struct device *parent, str } printf(": %s\n", chip); + rkpmic = sc; + node = OF_getnodebyname(node, "regulators"); if (node == 0) return; @@ -596,4 +608,15 @@ rkpmic_clock_write(struct rkpmic_softc * rkpmic_reg_write(sc, sc->sc_rtc_status_reg, RK80X_RTC_STATUS_POWER_UP); return 0; +} + +void +rkpmic_powerdown(void) +{ + uint8_t dev_ctrl; + struct rkpmic_softc *sc = rkpmic; + + dev_ctrl = rkpmic_reg_read(sc, sc->sc_dev_ctrl_reg); + dev_ctrl |= RK808_DEV_OFF_MASK; + rkpmic_reg_write(sc, sc->sc_dev_ctrl_reg, dev_ctrl); }