Add a MT8189-specific feature to the mtk-power-domain driver.

Some domains split their bus protection policy in two: one part has to
be released before the subsys clocks are enabled and the rest
afterwards, and correspondingly re-applied in the opposite order on
power off. The MT8189 mm-infra domain is the first user.

Add a subclk flag to the bus protection data and a
BUS_PROT_WR_IGN_SUBCLK() macro to set it, then run the enable and
disable loops twice, once for each phase. Existing entries all have the
flag clear, so they keep being released after the subsys clocks are
enabled exactly as before.

Signed-off-by: David Lechner <[email protected]>
---
 drivers/power/domain/mtk-power-domain.c | 30 ++++++++++++++++++++++++++----
 drivers/power/domain/mtk-power-domain.h | 19 ++++++++++++++-----
 2 files changed, 40 insertions(+), 9 deletions(-)

diff --git a/drivers/power/domain/mtk-power-domain.c 
b/drivers/power/domain/mtk-power-domain.c
index 8696ac21245..24b4991e469 100644
--- a/drivers/power/domain/mtk-power-domain.c
+++ b/drivers/power/domain/mtk-power-domain.c
@@ -83,11 +83,14 @@ static int _scpsys_bus_protect_disable(const struct 
mtk_scpsys_bus_prot_data *bp
 }
 
 static int scpsys_bus_protect_enable(const struct mtk_scpsys_bus_prot_data 
*bpd,
-                                    int bpd_size, void __iomem *reg)
+                                    int bpd_size, void __iomem *reg, bool 
subclk)
 {
        int ret, i;
 
        for (i = 0; i < bpd_size; i++) {
+               if (bpd[i].subclk != subclk)
+                       continue;
+
                ret = _scpsys_bus_protect_enable(&bpd[i], reg);
                if (ret)
                        return ret;
@@ -97,11 +100,14 @@ static int scpsys_bus_protect_enable(const struct 
mtk_scpsys_bus_prot_data *bpd,
 }
 
 static int scpsys_bus_protect_disable(const struct mtk_scpsys_bus_prot_data 
*bpd,
-                                     int bpd_size, void __iomem *reg)
+                                     int bpd_size, void __iomem *reg, bool 
subclk)
 {
        int i, ret;
 
        for (i = bpd_size - 1; i >= 0; i--) {
+               if (bpd[i].subclk != subclk)
+                       continue;
+
                ret = _scpsys_bus_protect_disable(&bpd[i], reg);
                if (ret)
                        return ret;
@@ -189,6 +195,15 @@ static int mtk_scpsys_power_on(struct power_domain 
*power_domain)
        val |= PWR_RST_B_BIT;
        writel(val, ctl_addr);
 
+       /*
+        * Some domains split the bus protection policy in two: one part has to
+        * be released before the subsys clocks are enabled and the rest after.
+        */
+       ret = scpsys_bus_protect_disable(data->bp_infracfg, 
SPM_MAX_BUS_PROT_DATA,
+                                        infracfg, true);
+       if (ret < 0)
+               return ret;
+
        ret = clk_enable_bulk(&domain->subsys_clks);
        if (ret)
                return ret;
@@ -206,7 +221,8 @@ static int mtk_scpsys_power_on(struct power_domain 
*power_domain)
                if (ret)
                        return ret;
        }
-       ret = scpsys_bus_protect_disable(data->bp_infracfg, 
SPM_MAX_BUS_PROT_DATA, infracfg);
+       ret = scpsys_bus_protect_disable(data->bp_infracfg, 
SPM_MAX_BUS_PROT_DATA,
+                                        infracfg, false);
        if (ret < 0)
                return ret;
 
@@ -243,7 +259,8 @@ static int mtk_scpsys_power_off(struct power_domain 
*power_domain)
                        return ret;
        }
 
-       ret = scpsys_bus_protect_enable(data->bp_infracfg, 
SPM_MAX_BUS_PROT_DATA, infracfg);
+       ret = scpsys_bus_protect_enable(data->bp_infracfg, 
SPM_MAX_BUS_PROT_DATA,
+                                       infracfg, false);
        if (ret < 0)
                return ret;
 
@@ -260,6 +277,11 @@ static int mtk_scpsys_power_off(struct power_domain 
*power_domain)
        if (ret)
                return ret;
 
+       ret = scpsys_bus_protect_enable(data->bp_infracfg, 
SPM_MAX_BUS_PROT_DATA,
+                                       infracfg, true);
+       if (ret < 0)
+               return ret;
+
        val |= PWR_ISO_BIT;
        writel(val, ctl_addr);
 
diff --git a/drivers/power/domain/mtk-power-domain.h 
b/drivers/power/domain/mtk-power-domain.h
index 09f9fb3e5e9..ef2603bbdbc 100644
--- a/drivers/power/domain/mtk-power-domain.h
+++ b/drivers/power/domain/mtk-power-domain.h
@@ -72,6 +72,11 @@ struct mtk_scpsys_bus_prot_data {
        u32 bus_prot_sta;
        bool bus_prot_reg_update;
        bool ignore_clr_ack;
+       /*
+        * Release this protection before the subsys clocks are enabled and
+        * re-apply it after they are disabled, instead of the other way round.
+        */
+       bool subclk;
 };
 
 struct mtk_scp_domain_data {
@@ -112,7 +117,7 @@ struct mtk_scpsys {
        struct mtk_scp_domain *domains;
 };
 
-#define _BUS_PROT(_mask, _set, _clr, _sta_mask, _sta, _update, _ignore) { \
+#define _BUS_PROT(_mask, _set, _clr, _sta_mask, _sta, _update, _ignore, 
_subclk) { \
        .bus_prot_mask = (_mask),                               \
        .bus_prot_set = (_set),                                 \
        .bus_prot_clr = (_clr),                                 \
@@ -120,19 +125,23 @@ struct mtk_scpsys {
        .bus_prot_sta = (_sta),                                 \
        .bus_prot_reg_update = (_update),                       \
        .ignore_clr_ack = (_ignore),                            \
+       .subclk = (_subclk),                                    \
 }
 
 #define BUS_PROT_WR(_mask, _set, _clr, _sta)                   \
-       _BUS_PROT(_mask, _set, _clr, _mask, _sta, false, false)
+       _BUS_PROT(_mask, _set, _clr, _mask, _sta, false, false, false)
 
 #define BUS_PROT_WR_IGN(_mask, _set, _clr, _sta)               \
-       _BUS_PROT(_mask, _set, _clr, _mask, _sta, false, true)
+       _BUS_PROT(_mask, _set, _clr, _mask, _sta, false, true, false)
+
+#define BUS_PROT_WR_IGN_SUBCLK(_mask, _set, _clr, _sta)                \
+       _BUS_PROT(_mask, _set, _clr, _mask, _sta, false, true, true)
 
 #define BUS_PROT_WR_STA_MASK(_mask, _sta_mask, _set, _clr, _sta) \
-       _BUS_PROT(_mask, _set, _clr, _sta_mask, _sta, false, false)
+       _BUS_PROT(_mask, _set, _clr, _sta_mask, _sta, false, false, false)
 
 #define BUS_PROT_WR_IGN_STA_MASK(_mask, _sta_mask, _set, _clr, _sta) \
-       _BUS_PROT(_mask, _set, _clr, _sta_mask, _sta, false, true)
+       _BUS_PROT(_mask, _set, _clr, _sta_mask, _sta, false, true, false)
 
 int mtk_scpsys_probe(struct udevice *dev);
 int mtk_power_controller_probe(struct udevice *dev);

-- 
2.43.0

Reply via email to