diff options
Diffstat (limited to 'drivers/soc/mediatek/mtk-scpsys.c')
-rw-r--r-- | drivers/soc/mediatek/mtk-scpsys.c | 214 |
1 files changed, 146 insertions, 68 deletions
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c index 503222d0d0da..f669d3754627 100644 --- a/drivers/soc/mediatek/mtk-scpsys.c +++ b/drivers/soc/mediatek/mtk-scpsys.c @@ -21,7 +21,7 @@ #include <dt-bindings/power/mt8173-power.h> #define MTK_POLL_DELAY_US 10 -#define MTK_POLL_TIMEOUT (jiffies_to_usecs(HZ)) +#define MTK_POLL_TIMEOUT USEC_PER_SEC #define MTK_SCPD_ACTIVE_WAKEUP BIT(0) #define MTK_SCPD_FWAIT_SRAM BIT(1) @@ -108,6 +108,17 @@ static const char * const clk_names[] = { #define MAX_CLKS 3 +/** + * struct scp_domain_data - scp domain data for power on/off flow + * @name: The domain name. + * @sta_mask: The mask for power on/off status bit. + * @ctl_offs: The offset for main power control register. + * @sram_pdn_bits: The mask for sram power control bits. + * @sram_pdn_ack_bits: The mask for sram power control acked bits. + * @bus_prot_mask: The mask for single step bus protection. + * @clk_id: The basic clocks required by this power domain. + * @caps: The flag for active wake-up action. + */ struct scp_domain_data { const char *name; u32 sta_mask; @@ -180,32 +191,132 @@ static int scpsys_domain_is_on(struct scp_domain *scpd) return -EINVAL; } +static int scpsys_regulator_enable(struct scp_domain *scpd) +{ + if (!scpd->supply) + return 0; + + return regulator_enable(scpd->supply); +} + +static int scpsys_regulator_disable(struct scp_domain *scpd) +{ + if (!scpd->supply) + return 0; + + return regulator_disable(scpd->supply); +} + +static void scpsys_clk_disable(struct clk *clk[], int max_num) +{ + int i; + + for (i = max_num - 1; i >= 0; i--) + clk_disable_unprepare(clk[i]); +} + +static int scpsys_clk_enable(struct clk *clk[], int max_num) +{ + int i, ret = 0; + + for (i = 0; i < max_num && clk[i]; i++) { + ret = clk_prepare_enable(clk[i]); + if (ret) { + scpsys_clk_disable(clk, i); + break; + } + } + + return ret; +} + +static int scpsys_sram_enable(struct scp_domain *scpd, void __iomem *ctl_addr) +{ + u32 val; + u32 pdn_ack = scpd->data->sram_pdn_ack_bits; + int tmp; + + val = readl(ctl_addr); + val &= ~scpd->data->sram_pdn_bits; + writel(val, ctl_addr); + + /* Either wait until SRAM_PDN_ACK all 0 or have a force wait */ + if (MTK_SCPD_CAPS(scpd, MTK_SCPD_FWAIT_SRAM)) { + /* + * Currently, MTK_SCPD_FWAIT_SRAM is necessary only for + * MT7622_POWER_DOMAIN_WB and thus just a trivial setup + * is applied here. + */ + usleep_range(12000, 12100); + } else { + /* Either wait until SRAM_PDN_ACK all 1 or 0 */ + int ret = readl_poll_timeout(ctl_addr, tmp, + (tmp & pdn_ack) == 0, + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); + if (ret < 0) + return ret; + } + + return 0; +} + +static int scpsys_sram_disable(struct scp_domain *scpd, void __iomem *ctl_addr) +{ + u32 val; + u32 pdn_ack = scpd->data->sram_pdn_ack_bits; + int tmp; + + val = readl(ctl_addr); + val |= scpd->data->sram_pdn_bits; + writel(val, ctl_addr); + + /* Either wait until SRAM_PDN_ACK all 1 or 0 */ + return readl_poll_timeout(ctl_addr, tmp, + (tmp & pdn_ack) == pdn_ack, + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); +} + +static int scpsys_bus_protect_enable(struct scp_domain *scpd) +{ + struct scp *scp = scpd->scp; + + if (!scpd->data->bus_prot_mask) + return 0; + + return mtk_infracfg_set_bus_protection(scp->infracfg, + scpd->data->bus_prot_mask, + scp->bus_prot_reg_update); +} + +static int scpsys_bus_protect_disable(struct scp_domain *scpd) +{ + struct scp *scp = scpd->scp; + + if (!scpd->data->bus_prot_mask) + return 0; + + return mtk_infracfg_clear_bus_protection(scp->infracfg, + scpd->data->bus_prot_mask, + scp->bus_prot_reg_update); +} + static int scpsys_power_on(struct generic_pm_domain *genpd) { struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd); struct scp *scp = scpd->scp; void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs; - u32 pdn_ack = scpd->data->sram_pdn_ack_bits; u32 val; int ret, tmp; - int i; - if (scpd->supply) { - ret = regulator_enable(scpd->supply); - if (ret) - return ret; - } - - for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) { - ret = clk_prepare_enable(scpd->clk[i]); - if (ret) { - for (--i; i >= 0; i--) - clk_disable_unprepare(scpd->clk[i]); + ret = scpsys_regulator_enable(scpd); + if (ret < 0) + return ret; - goto err_clk; - } - } + ret = scpsys_clk_enable(scpd->clk, MAX_CLKS); + if (ret) + goto err_clk; + /* subsys power on */ val = readl(ctl_addr); val |= PWR_ON_BIT; writel(val, ctl_addr); @@ -227,43 +338,20 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) val |= PWR_RST_B_BIT; writel(val, ctl_addr); - val &= ~scpd->data->sram_pdn_bits; - writel(val, ctl_addr); - - /* Either wait until SRAM_PDN_ACK all 0 or have a force wait */ - if (MTK_SCPD_CAPS(scpd, MTK_SCPD_FWAIT_SRAM)) { - /* - * Currently, MTK_SCPD_FWAIT_SRAM is necessary only for - * MT7622_POWER_DOMAIN_WB and thus just a trivial setup is - * applied here. - */ - usleep_range(12000, 12100); - - } else { - ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == 0, - MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); - if (ret < 0) - goto err_pwr_ack; - } + ret = scpsys_sram_enable(scpd, ctl_addr); + if (ret < 0) + goto err_pwr_ack; - if (scpd->data->bus_prot_mask) { - ret = mtk_infracfg_clear_bus_protection(scp->infracfg, - scpd->data->bus_prot_mask, - scp->bus_prot_reg_update); - if (ret) - goto err_pwr_ack; - } + ret = scpsys_bus_protect_disable(scpd); + if (ret < 0) + goto err_pwr_ack; return 0; err_pwr_ack: - for (i = MAX_CLKS - 1; i >= 0; i--) { - if (scpd->clk[i]) - clk_disable_unprepare(scpd->clk[i]); - } + scpsys_clk_disable(scpd->clk, MAX_CLKS); err_clk: - if (scpd->supply) - regulator_disable(scpd->supply); + scpsys_regulator_disable(scpd); dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name); @@ -275,29 +363,19 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd); struct scp *scp = scpd->scp; void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs; - u32 pdn_ack = scpd->data->sram_pdn_ack_bits; u32 val; int ret, tmp; - int i; - - if (scpd->data->bus_prot_mask) { - ret = mtk_infracfg_set_bus_protection(scp->infracfg, - scpd->data->bus_prot_mask, - scp->bus_prot_reg_update); - if (ret) - goto out; - } - val = readl(ctl_addr); - val |= scpd->data->sram_pdn_bits; - writel(val, ctl_addr); + ret = scpsys_bus_protect_enable(scpd); + if (ret < 0) + goto out; - /* wait until SRAM_PDN_ACK all 1 */ - ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == pdn_ack, - MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); + ret = scpsys_sram_disable(scpd, ctl_addr); if (ret < 0) goto out; + /* subsys power off */ + val = readl(ctl_addr); val |= PWR_ISO_BIT; writel(val, ctl_addr); @@ -319,11 +397,11 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) if (ret < 0) goto out; - for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) - clk_disable_unprepare(scpd->clk[i]); + scpsys_clk_disable(scpd->clk, MAX_CLKS); - if (scpd->supply) - regulator_disable(scpd->supply); + ret = scpsys_regulator_disable(scpd); + if (ret < 0) + goto out; return 0; |