Index | Thread | Search

From:
Paul Fertser <fercerpav@gmail.com>
Subject:
rkpmic(4) support system power down
To:
tech@openbsd.org
Date:
Thu, 21 Nov 2024 15:03:32 +0300

Download raw body.

Thread
Hello,

When the board DT suggests with the documented property
"rockchip,system-power-controller" we can power it down by asking the
PMIC directly just seize the opportunity to not count on (potentially
outdated) TF-A to do the right thing.

Tested on Pinebook Pro which has RK808 PMIC. The others were added
based on reading the corresponding datasheets so compile-tested only.

---

diff --git a/sys/dev/fdt/rkpmic.c b/sys/dev/fdt/rkpmic.c
index cec42e25a..b65bbb4d3 100644
--- a/sys/dev/fdt/rkpmic.c
+++ b/sys/dev/fdt/rkpmic.c
@@ -33,6 +33,8 @@
 
 #include <dev/clock_subr.h>
 
+extern void (*powerdownfn)(void);
+
 #define RK80X_SECONDS		0x00
 #define RK80X_MINUTES		0x01
 #define RK80X_HOURS		0x02
@@ -52,10 +54,20 @@
 #define RK809_RTC_STATUS	0x0e
 #define  RK80X_RTC_STATUS_POWER_UP	0x80
 
+#define RK805_DEV_CTRL		0x4b
+#define  RK805_DEV_CTRL_DEV_OFF	0x01
+
+#define RK806_SYS_CFG3		0x72
+#define  RK806_SYS_CFG3_DEV_OFF	0x01
+
+#define RK808_DEVCTRL		0x4b
+#define  RK808_DEVCTRL_DEV_OFF_RST	0x08
+
 #define RK809_PMIC_SYS_CFG3	0xf4
 #define  RK809_PMIC_SYS_CFG3_SLP_FUN_MASK	0x18
 #define  RK809_PMIC_SYS_CFG3_SLP_FUN_NONE	0x00
 #define  RK809_PMIC_SYS_CFG3_SLP_FUN_SLEEP	0x08
+#define  RK809_PMIC_SYS_CFG3_DEV_OFF		0x01
 #define RK809_PMIC_INT_STS0	0xf8
 #define RK809_PMIC_INT_MSK0	0xf9
 #define  RK809_PMIC_INT_MSK0_PWRON_FALL_INT_IM	0x01
@@ -338,6 +350,8 @@ struct rkpmic_softc {
 	struct spi_config sc_spi_conf;
 
 	int sc_rtc_ctrl_reg, sc_rtc_status_reg;
+	uint8_t sc_dev_ctrl_reg, sc_dev_off_val;
+
 	struct todr_chip_handle sc_todr;
 	const struct rkpmic_regdata *sc_regdata;
 
@@ -382,6 +396,9 @@ 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 *);
 
+struct rkpmic_softc *rkpmic_sc;
+void    rkpmic_powerdown(void);
+
 int
 rkpmic_i2c_match(struct device *parent, void *match, void *aux)
 {
@@ -447,24 +464,34 @@ rkpmic_attach(struct device *parent, struct device *self, void *aux)
 		chip = "RK805";
 		sc->sc_rtc_ctrl_reg = RK805_RTC_CTRL;
 		sc->sc_rtc_status_reg = RK805_RTC_STATUS;
+		sc->sc_dev_ctrl_reg = RK805_DEV_CTRL;
+		sc->sc_dev_off_val = RK805_DEV_CTRL_DEV_OFF;
 		sc->sc_regdata = rk805_regdata;
 	} else if (OF_is_compatible(sc->sc_node, "rockchip,rk806")) {
 		chip = "RK806";
+		sc->sc_dev_ctrl_reg = RK806_SYS_CFG3;
+		sc->sc_dev_off_val = RK806_SYS_CFG3_DEV_OFF;
 		sc->sc_regdata = rk806_regdata;
 	} else if (OF_is_compatible(sc->sc_node, "rockchip,rk808")) {
 		chip = "RK808";
 		sc->sc_rtc_ctrl_reg = RK808_RTC_CTRL;
 		sc->sc_rtc_status_reg = RK808_RTC_STATUS;
+		sc->sc_dev_ctrl_reg = RK808_DEVCTRL;
+		sc->sc_dev_off_val = RK808_DEVCTRL_DEV_OFF_RST;
 		sc->sc_regdata = rk808_regdata;
 	} else if (OF_is_compatible(sc->sc_node, "rockchip,rk809")) {
 		chip = "RK809";
 		sc->sc_rtc_ctrl_reg = RK809_RTC_CTRL;
 		sc->sc_rtc_status_reg = RK809_RTC_STATUS;
+		sc->sc_dev_ctrl_reg = RK809_PMIC_SYS_CFG3;
+		sc->sc_dev_off_val = RK809_PMIC_SYS_CFG3_DEV_OFF;
 		sc->sc_regdata = rk809_regdata;
 	} else {
 		chip = "RK817";
 		sc->sc_rtc_ctrl_reg = RK809_RTC_CTRL;
 		sc->sc_rtc_status_reg = RK809_RTC_STATUS;
+		sc->sc_dev_ctrl_reg = RK809_PMIC_SYS_CFG3;
+		sc->sc_dev_off_val = RK809_PMIC_SYS_CFG3_DEV_OFF;
 		sc->sc_regdata = rk817_regdata;
 	}
 	printf(": %s\n", chip);
@@ -511,6 +538,11 @@ rkpmic_attach(struct device *parent, struct device *self, void *aux)
 			device_register_wakeup(&sc->sc_dev);
 #endif
 	}
+
+	if (OF_getpropbool(sc->sc_node, "rockchip,system-power-controller")) {
+		rkpmic_sc = sc;
+		powerdownfn = rkpmic_powerdown;
+	}
 }
 
 int
@@ -557,6 +589,14 @@ rkpmic_intr(void *arg)
 	return 1;
 }
 
+void
+rkpmic_powerdown(void)
+{
+	struct rkpmic_softc *sc = rkpmic_sc;
+	rkpmic_reg_write(sc, sc->sc_dev_ctrl_reg,
+	    rkpmic_reg_read(sc, sc->sc_dev_ctrl_reg) | sc->sc_dev_off_val);
+}
+
 struct rkpmic_regulator {
 	struct rkpmic_softc *rr_sc;