diff --git a/sys/arm64/rockchip/rk805.c b/sys/arm64/rockchip/rk805.c --- a/sys/arm64/rockchip/rk805.c +++ b/sys/arm64/rockchip/rk805.c @@ -31,8 +31,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -844,6 +846,29 @@ return (error); } +static void +rk805_poweroff(void *arg, int howto) +{ + device_t dev = arg; + int error; + uint8_t val; + + if ((howto & RB_POWEROFF) == 0) + return; + + device_printf(dev, "Powering off...\n"); + error = rk805_read(dev, RK805_DEV_CTRL, &val, 1); + if (error == 0) { + val |= RK805_DEV_CTRL_OFF; + error = rk805_write(dev, RK805_DEV_CTRL, &val, 1); + + /* Wait a bit for the command to take effect. */ + if (error == 0) + DELAY(100); + } + device_printf(dev, "Power off failed\n"); +} + static int rk805_attach(device_t dev) { @@ -907,6 +932,17 @@ } } + if (OF_hasprop(ofw_bus_get_node(dev), + "rockchip,system-power-controller")) { + /* + * The priority is chosen to override PSCI and EFI shutdown + * methods as those two just hang without powering off on Rock64 + * at least. + */ + EVENTHANDLER_REGISTER(shutdown_final, rk805_poweroff, dev, + SHUTDOWN_PRI_LAST - 2); + } + return (0); } diff --git a/sys/arm64/rockchip/rk805reg.h b/sys/arm64/rockchip/rk805reg.h --- a/sys/arm64/rockchip/rk805reg.h +++ b/sys/arm64/rockchip/rk805reg.h @@ -93,6 +93,10 @@ #define RK808_LDO8_ON_VSEL 0x49 #define RK808_LDO8_SLEEP_VSEL 0x4A +#define RK805_DEV_CTRL 0x4B +#define RK805_DEV_CTRL_OFF (1 << 0) +#define RK805_DEV_CTRL_SLP (1 << 1) + enum rk805_regulator { RK805_DCDC1 = 0, RK805_DCDC2,