]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
pmdomain: mediatek: Add support for RTFF Hardware in MT8196/MT6991
authorAngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Tue, 5 Aug 2025 07:47:44 +0000 (09:47 +0200)
committerUlf Hansson <ulf.hansson@linaro.org>
Tue, 19 Aug 2025 12:12:40 +0000 (14:12 +0200)
New generation SoCs use a new RTFF Hardware to save power during
operation of various IPs, other than managing isolation of the
internal buck converters during powerup/down of power domains.

Since some of the power domains need different RTFF handling, add
a new scpys_rtff_type enumeration and hold the value for each
power domain in struct scpsys_domain_data.

If RTFF HW is available, the RTFF additional power sequences are
handled in scpsys_ctl_pwrseq_{on,off}().

Reviewed-by: NĂ­colas F. R. A. Prado <nfraprado@collabora.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Link: https://lore.kernel.org/r/20250805074746.29457-9-angelogioacchino.delregno@collabora.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/pmdomain/mediatek/mtk-pm-domains.c
drivers/pmdomain/mediatek/mtk-pm-domains.h

index cf749ba5c3c7aaa68a3727d38fc3c20a13b8e1ae..0ebe7379b94e50f357e30afae0803afad848e6c1 100644 (file)
 #define PWR_SRAM_CLKISO_BIT            BIT(5)
 #define PWR_SRAM_ISOINT_B_BIT          BIT(6)
 
+#define PWR_RTFF_SAVE                  BIT(24)
+#define PWR_RTFF_NRESTORE              BIT(25)
+#define PWR_RTFF_CLK_DIS               BIT(26)
+#define PWR_RTFF_SAVE_FLAG             BIT(27)
+#define PWR_RTFF_UFS_CLK_DIS           BIT(28)
+
 struct scpsys_domain {
        struct generic_pm_domain genpd;
        const struct scpsys_domain_data *data;
@@ -247,7 +253,7 @@ static int scpsys_regulator_disable(struct regulator *supply)
 static int scpsys_ctl_pwrseq_on(struct scpsys_domain *pd)
 {
        struct scpsys *scpsys = pd->scpsys;
-       bool tmp;
+       bool do_rtff_nrestore, tmp;
        int ret;
 
        /* subsys power on */
@@ -260,10 +266,72 @@ static int scpsys_ctl_pwrseq_on(struct scpsys_domain *pd)
        if (ret < 0)
                return ret;
 
+       if (pd->data->rtff_type == SCPSYS_RTFF_TYPE_PCIE_PHY)
+               regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS);
+
        regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT);
        regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT);
+
+       /* Wait for RTFF HW to sync buck isolation state if this is PCIe PHY RTFF */
+       if (pd->data->rtff_type == SCPSYS_RTFF_TYPE_PCIE_PHY)
+               udelay(5);
+
        regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
 
+       /*
+        * RTFF HW state may be modified by secure world or remote processors.
+        *
+        * With the only exception of STOR_UFS, which always needs save/restore,
+        * check if this power domain's RTFF is already on before trying to do
+        * the NRESTORE procedure, otherwise the system will lock up.
+        */
+       switch (pd->data->rtff_type) {
+       case SCPSYS_RTFF_TYPE_GENERIC:
+       case SCPSYS_RTFF_TYPE_PCIE_PHY:
+       {
+               u32 ctl_status;
+
+               regmap_read(scpsys->base, pd->data->ctl_offs, &ctl_status);
+               do_rtff_nrestore = ctl_status & PWR_RTFF_SAVE_FLAG;
+               break;
+       }
+       case SCPSYS_RTFF_TYPE_STOR_UFS:
+               /* STOR_UFS always needs NRESTORE */
+               do_rtff_nrestore = true;
+               break;
+       default:
+               do_rtff_nrestore = false;
+               break;
+       }
+
+       /* Return early if RTFF NRESTORE shall not be done */
+       if (!do_rtff_nrestore)
+               return 0;
+
+       switch (pd->data->rtff_type) {
+       case SCPSYS_RTFF_TYPE_GENERIC:
+               regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE_FLAG);
+               regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS);
+               regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_NRESTORE);
+               regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_NRESTORE);
+               regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS);
+               break;
+       case SCPSYS_RTFF_TYPE_PCIE_PHY:
+               regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE_FLAG);
+               regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_NRESTORE);
+               regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_NRESTORE);
+               regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS);
+               break;
+       case SCPSYS_RTFF_TYPE_STOR_UFS:
+               regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_UFS_CLK_DIS);
+               regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_NRESTORE);
+               regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_NRESTORE);
+               regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_UFS_CLK_DIS);
+               break;
+       default:
+               break;
+       }
+
        return 0;
 }
 
@@ -271,8 +339,32 @@ static void scpsys_ctl_pwrseq_off(struct scpsys_domain *pd)
 {
        struct scpsys *scpsys = pd->scpsys;
 
+       switch (pd->data->rtff_type) {
+       case SCPSYS_RTFF_TYPE_GENERIC:
+       case SCPSYS_RTFF_TYPE_PCIE_PHY:
+               regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS);
+               regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE);
+               regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE);
+               regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS);
+               regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE_FLAG);
+               break;
+       case SCPSYS_RTFF_TYPE_STOR_UFS:
+               regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_UFS_CLK_DIS);
+               regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE);
+               regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE);
+               regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_UFS_CLK_DIS);
+               break;
+       default:
+               break;
+       }
+
        /* subsys power off */
        regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT);
+
+       /* Wait for RTFF HW to sync buck isolation state if this is PCIe PHY RTFF */
+       if (pd->data->rtff_type == SCPSYS_RTFF_TYPE_PCIE_PHY)
+               udelay(1);
+
        regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT);
        regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
        regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT);
index 931a54f1c5caf102d03364bfed98460eff45704e..b2e3dee0383119ccbf0f0e1451108a9dd2eb84d0 100644 (file)
@@ -108,6 +108,22 @@ struct scpsys_bus_prot_data {
        u8 flags;
 };
 
+/**
+ * enum scpsys_rtff_type - Type of RTFF Hardware for power domain
+ * @SCPSYS_RTFF_NONE:          RTFF HW not present or domain not RTFF managed
+ * @SCPSYS_RTFF_TYPE_GENERIC:  Non-CPU, peripheral-generic RTFF HW
+ * @SCPSYS_RTFF_TYPE_PCIE_PHY: PCI-Express PHY specific RTFF HW
+ * @SCPSYS_RTFF_TYPE_STOR_UFS: Storage (UFS) specific RTFF HW
+ * @SCPSYS_RTFF_TYPE_MAX:      Number of supported RTFF HW Types
+ */
+enum scpsys_rtff_type {
+       SCPSYS_RTFF_NONE = 0,
+       SCPSYS_RTFF_TYPE_GENERIC,
+       SCPSYS_RTFF_TYPE_PCIE_PHY,
+       SCPSYS_RTFF_TYPE_STOR_UFS,
+       SCPSYS_RTFF_TYPE_MAX
+};
+
 /**
  * struct scpsys_domain_data - scp domain data for power on/off flow
  * @name: The name of the power domain.
@@ -118,6 +134,7 @@ struct scpsys_bus_prot_data {
  * @ext_buck_iso_offs: The offset for external buck isolation
  * @ext_buck_iso_mask: The mask for external buck isolation
  * @caps: The flag for active wake-up action.
+ * @rtff_type: The power domain RTFF HW type
  * @bp_cfg: bus protection configuration for any subsystem
  */
 struct scpsys_domain_data {
@@ -129,6 +146,7 @@ struct scpsys_domain_data {
        int ext_buck_iso_offs;
        u32 ext_buck_iso_mask;
        u16 caps;
+       enum scpsys_rtff_type rtff_type;
        const struct scpsys_bus_prot_data bp_cfg[SPM_MAX_BUS_PROT_DATA];
        int pwr_sta_offs;
        int pwr_sta2nd_offs;