Some MediaTek power domains cannot be brought up with the plain
sram_pdn sequence the driver implements today. Two variations exist,
matching the MTK_SCPD_SRAM_ISO and MTK_SCPD_SRAM_PDN_INVERTED flags in
the Linux driver:
- the domain's SRAM sits behind an isolation cell that has to be
released once the SRAM is powered, and re-asserted before powering
it down again, and
- the sram_pdn bits are active low, so they are set to power the SRAM
up rather than cleared, and the ack then reads back as all ones.
Add a caps field to struct mtk_scp_domain_data and implement both
variations in the power on and power off paths, so that a per-SoC driver
can describe such a domain.
Signed-off-by: David Lechner <[email protected]>
---
drivers/power/domain/mtk-power-domain.c | 51 +++++++++++++++++++++++++++------
drivers/power/domain/mtk-power-domain.h | 17 +++++++++++
2 files changed, 60 insertions(+), 8 deletions(-)
diff --git a/drivers/power/domain/mtk-power-domain.c
b/drivers/power/domain/mtk-power-domain.c
index 768ab8bab9c..60dd9ee9d2f 100644
--- a/drivers/power/domain/mtk-power-domain.c
+++ b/drivers/power/domain/mtk-power-domain.c
@@ -9,6 +9,7 @@
#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
+#include <linux/delay.h>
#include <linux/err.h>
#include <linux/iopoll.h>
#include <dm/device_compat.h>
@@ -240,13 +241,32 @@ static int mtk_scpsys_power_on(struct power_domain
*power_domain)
if (ret)
return ret;
- val &= ~data->sram_pdn_bits;
- writel(val, ctl_addr);
-
- ret = readl_poll_timeout(ctl_addr, tmp, !(tmp & pdn_ack), 100);
+ /*
+ * An inverted sram_pdn bit is set, not cleared, to power the SRAM up,
+ * and the ack is then expected to read back as all ones.
+ */
+ if (data->caps & MTK_SCPD_SRAM_PDN_INVERTED) {
+ val |= data->sram_pdn_bits;
+ writel(val, ctl_addr);
+ ret = readl_poll_timeout(ctl_addr, tmp,
+ (tmp & pdn_ack) == pdn_ack, 100);
+ } else {
+ val &= ~data->sram_pdn_bits;
+ writel(val, ctl_addr);
+ ret = readl_poll_timeout(ctl_addr, tmp, !(tmp & pdn_ack), 100);
+ }
if (ret < 0)
return ret;
+ /* Release the SRAM isolation now that it is powered */
+ if (data->caps & MTK_SCPD_SRAM_ISO) {
+ val |= PWR_SRAM_ISOINT_B_BIT;
+ writel(val, ctl_addr);
+ udelay(1);
+ val &= ~PWR_SRAM_CLKISO_BIT;
+ writel(val, ctl_addr);
+ }
+
if (data->bus_prot_mask) {
ret = mtk_infracfg_clear_bus_protection(infracfg,
data->bus_prot_mask);
@@ -295,11 +315,26 @@ static int mtk_scpsys_power_off(struct power_domain
*power_domain)
return ret;
val = readl(ctl_addr);
- val |= data->sram_pdn_bits;
- writel(val, ctl_addr);
- ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == pdn_ack,
- 100);
+ /* Isolate the SRAM again before powering it down */
+ if (data->caps & MTK_SCPD_SRAM_ISO) {
+ val |= PWR_SRAM_CLKISO_BIT;
+ writel(val, ctl_addr);
+ udelay(1);
+ val &= ~PWR_SRAM_ISOINT_B_BIT;
+ writel(val, ctl_addr);
+ }
+
+ if (data->caps & MTK_SCPD_SRAM_PDN_INVERTED) {
+ val &= ~data->sram_pdn_bits;
+ writel(val, ctl_addr);
+ ret = readl_poll_timeout(ctl_addr, tmp, !(tmp & pdn_ack), 100);
+ } else {
+ val |= data->sram_pdn_bits;
+ writel(val, ctl_addr);
+ ret = readl_poll_timeout(ctl_addr, tmp,
+ (tmp & pdn_ack) == pdn_ack, 100);
+ }
if (ret < 0)
return ret;
diff --git a/drivers/power/domain/mtk-power-domain.h
b/drivers/power/domain/mtk-power-domain.h
index 06760286a3a..fa5c12b47d3 100644
--- a/drivers/power/domain/mtk-power-domain.h
+++ b/drivers/power/domain/mtk-power-domain.h
@@ -39,6 +39,22 @@ struct udevice;
#define PWR_ON_BIT BIT(2)
#define PWR_ON_2ND_BIT BIT(3)
#define PWR_CLK_DIS_BIT BIT(4)
+#define PWR_SRAM_CLKISO_BIT BIT(5)
+#define PWR_SRAM_ISOINT_B_BIT BIT(6)
+
+/*
+ * Domain capabilities, matching the semantics of the MTK_SCPD_* flags in the
+ * Linux driver. The values are this driver's own: only the handful of flags
+ * U-Boot has a use for are defined, so they are packed from bit 0 rather than
+ * carrying Linux's numbering.
+ *
+ * SRAM_ISO: the domain's SRAM sits behind an isolation cell that
+ * has to be released separately once it is powered.
+ * SRAM_PDN_INVERTED: @sram_pdn_bits is active low, so the bit is set to
+ * power the SRAM up rather than cleared.
+ */
+#define MTK_SCPD_SRAM_ISO BIT(0)
+#define MTK_SCPD_SRAM_PDN_INVERTED BIT(1)
#define PWR_STATUS_CONN BIT(1)
#define PWR_STATUS_DISP BIT(3)
@@ -100,6 +116,7 @@ struct mtk_scpsys_bus_prot_data {
struct mtk_scp_domain_data {
u32 sta_mask;
+ u32 caps;
int ctl_offs;
u32 sram_pdn_bits;
u32 sram_pdn_ack_bits;
--
2.43.0