pmdomain: mediatek: Add support for RTFF Hardware in MT8196/MT6991

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>
This commit is contained in:
AngeloGioacchino Del Regno
2025-08-05 09:47:44 +02:00
committed by Ulf Hansson
parent 16d861d2bc
commit 9d02c94342
2 changed files with 111 additions and 1 deletions
+93 -1
View File
@@ -39,6 +39,12 @@
#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);
@@ -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;