mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 07:03:28 -04:00
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:
committed by
Ulf Hansson
parent
16d861d2bc
commit
9d02c94342
@@ -39,6 +39,12 @@
|
|||||||
#define PWR_SRAM_CLKISO_BIT BIT(5)
|
#define PWR_SRAM_CLKISO_BIT BIT(5)
|
||||||
#define PWR_SRAM_ISOINT_B_BIT BIT(6)
|
#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 scpsys_domain {
|
||||||
struct generic_pm_domain genpd;
|
struct generic_pm_domain genpd;
|
||||||
const struct scpsys_domain_data *data;
|
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)
|
static int scpsys_ctl_pwrseq_on(struct scpsys_domain *pd)
|
||||||
{
|
{
|
||||||
struct scpsys *scpsys = pd->scpsys;
|
struct scpsys *scpsys = pd->scpsys;
|
||||||
bool tmp;
|
bool do_rtff_nrestore, tmp;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* subsys power on */
|
/* subsys power on */
|
||||||
@@ -260,10 +266,72 @@ static int scpsys_ctl_pwrseq_on(struct scpsys_domain *pd)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
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_CLK_DIS_BIT);
|
||||||
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_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);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,8 +339,32 @@ static void scpsys_ctl_pwrseq_off(struct scpsys_domain *pd)
|
|||||||
{
|
{
|
||||||
struct scpsys *scpsys = pd->scpsys;
|
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 */
|
/* subsys power off */
|
||||||
regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT);
|
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_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_RST_B_BIT);
|
||||||
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_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;
|
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
|
* struct scpsys_domain_data - scp domain data for power on/off flow
|
||||||
* @name: The name of the power domain.
|
* @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_offs: The offset for external buck isolation
|
||||||
* @ext_buck_iso_mask: The mask for external buck isolation
|
* @ext_buck_iso_mask: The mask for external buck isolation
|
||||||
* @caps: The flag for active wake-up action.
|
* @caps: The flag for active wake-up action.
|
||||||
|
* @rtff_type: The power domain RTFF HW type
|
||||||
* @bp_cfg: bus protection configuration for any subsystem
|
* @bp_cfg: bus protection configuration for any subsystem
|
||||||
*/
|
*/
|
||||||
struct scpsys_domain_data {
|
struct scpsys_domain_data {
|
||||||
@@ -129,6 +146,7 @@ struct scpsys_domain_data {
|
|||||||
int ext_buck_iso_offs;
|
int ext_buck_iso_offs;
|
||||||
u32 ext_buck_iso_mask;
|
u32 ext_buck_iso_mask;
|
||||||
u16 caps;
|
u16 caps;
|
||||||
|
enum scpsys_rtff_type rtff_type;
|
||||||
const struct scpsys_bus_prot_data bp_cfg[SPM_MAX_BUS_PROT_DATA];
|
const struct scpsys_bus_prot_data bp_cfg[SPM_MAX_BUS_PROT_DATA];
|
||||||
int pwr_sta_offs;
|
int pwr_sta_offs;
|
||||||
int pwr_sta2nd_offs;
|
int pwr_sta2nd_offs;
|
||||||
|
|||||||
Reference in New Issue
Block a user