diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c index 8d49d9ee3cd2..632c5dcdceda 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.c +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c @@ -555,9 +555,11 @@ static int scpsys_ctl_pwrseq_on(struct scpsys_domain *pd) return 0; } -static void scpsys_ctl_pwrseq_off(struct scpsys_domain *pd) +static int scpsys_ctl_pwrseq_off(struct scpsys_domain *pd) { struct scpsys *scpsys = pd->scpsys; + bool tmp; + int ret; switch (pd->data->rtff_type) { case SCPSYS_RTFF_TYPE_GENERIC: @@ -589,6 +591,41 @@ static void scpsys_ctl_pwrseq_off(struct scpsys_domain *pd) 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_BIT); + + /* wait until PWR_ACK = 0 */ + ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, !tmp, MTK_POLL_DELAY_US, + MTK_POLL_TIMEOUT); + if (ret < 0) + return ret; + + return 0; +} + +static int scpsys_simple_pwrseq_on(struct scpsys_domain *pd) +{ + struct scpsys *scpsys = pd->scpsys; + + /* Enable subsys clock input and trigger power domain reset state */ + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); + + /* Wait for the hardware to stabilize */ + udelay(1); + + /* Get out of reset: set power on */ + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); + + return 0; +} + +static int scpsys_simple_pwrseq_off(struct scpsys_domain *pd) +{ + struct scpsys *scpsys = pd->scpsys; + + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT); + + return 0; } static int scpsys_modem_pwrseq_on(struct scpsys_domain *pd) @@ -611,14 +648,24 @@ static int scpsys_modem_pwrseq_on(struct scpsys_domain *pd) return 0; } -static void scpsys_modem_pwrseq_off(struct scpsys_domain *pd) +static int scpsys_modem_pwrseq_off(struct scpsys_domain *pd) { struct scpsys *scpsys = pd->scpsys; + bool tmp; + int ret; regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT); if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SKIP_RESET_B)) regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); + + /* wait until PWR_ACK = 0 */ + ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, !tmp, MTK_POLL_DELAY_US, + MTK_POLL_TIMEOUT); + if (ret < 0) + return ret; + + return 0; } static int scpsys_power_on(struct generic_pm_domain *genpd) @@ -641,6 +688,8 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) if (MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_PWRSEQ)) ret = scpsys_modem_pwrseq_on(pd); + else if (MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ)) + ret = scpsys_simple_pwrseq_on(pd); else ret = scpsys_ctl_pwrseq_on(pd); @@ -668,9 +717,11 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) goto err_pwr_ack; } - ret = scpsys_sram_enable(pd); - if (ret < 0) - goto err_disable_subsys_clks; + if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ)) { + ret = scpsys_sram_enable(pd); + if (ret < 0) + goto err_disable_subsys_clks; + } ret = scpsys_bus_protect_disable(pd, 0); if (ret < 0) @@ -688,7 +739,8 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) err_enable_bus_protect: scpsys_bus_protect_enable(pd, 0); err_disable_sram: - scpsys_sram_disable(pd); + if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ)) + scpsys_sram_disable(pd); err_disable_subsys_clks: if (!MTK_SCPD_CAPS(pd, MTK_SCPD_STRICT_BUS_PROTECTION)) clk_bulk_disable_unprepare(pd->num_subsys_clks, @@ -703,16 +755,17 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) static int scpsys_power_off_internal(struct scpsys_domain *pd) { struct scpsys *scpsys = pd->scpsys; - bool tmp; int ret; ret = scpsys_bus_protect_enable(pd, 0); if (ret < 0) return ret; - ret = scpsys_sram_disable(pd); - if (ret < 0) - return ret; + if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ)) { + ret = scpsys_sram_disable(pd); + if (ret < 0) + return ret; + } if (pd->data->ext_buck_iso_offs && MTK_SCPD_CAPS(pd, MTK_SCPD_EXT_BUCK_ISO)) regmap_set_bits(scpsys->base, pd->data->ext_buck_iso_offs, @@ -725,15 +778,21 @@ static int scpsys_power_off_internal(struct scpsys_domain *pd) return ret; if (MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_PWRSEQ)) - scpsys_modem_pwrseq_off(pd); + ret = scpsys_modem_pwrseq_off(pd); + else if (MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ)) + ret = scpsys_simple_pwrseq_off(pd); else - scpsys_ctl_pwrseq_off(pd); + ret = scpsys_ctl_pwrseq_off(pd); + + if (ret < 0) { + /* Re-enable clocks so that next power off doesn't break the refcount */ + int r = clk_bulk_prepare_enable(pd->num_subsys_clks, pd->subsys_clks); + + if (r) + dev_warn(scpsys->dev, "Could not re-enable clocks: %d\n", r); - /* wait until PWR_ACK = 0 */ - ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, !tmp, MTK_POLL_DELAY_US, - MTK_POLL_TIMEOUT); - if (ret < 0) return ret; + } clk_bulk_disable_unprepare(pd->num_clks, pd->clks); @@ -1109,6 +1168,12 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s regmap[2] = NULL; } + /* If no access controllers are needed, don't allocate and don't fail */ + if (num_regmaps == 0) { + scpsys->bus_prot = NULL; + return 0; + } + scpsys->bus_prot = devm_kmalloc_array(dev, num_regmaps, sizeof(*scpsys->bus_prot), GFP_KERNEL); if (!scpsys->bus_prot) diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.h b/drivers/pmdomain/mediatek/mtk-pm-domains.h index a5dca24cbc2f..092403de66fa 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.h +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.h @@ -17,6 +17,7 @@ #define MTK_SCPD_MODEM_PWRSEQ BIT(10) #define MTK_SCPD_SKIP_RESET_B BIT(11) #define MTK_SCPD_INFRA_PWR_CTL BIT(12) +#define MTK_SCPD_SIMPLE_PWRSEQ BIT(13) #define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data ? \ (_scpd)->data->caps & (_x) : \ (_scpd)->hwv_data->caps & (_x))