diff options
Diffstat (limited to 'drivers/pmdomain/mediatek/mtk-pm-domains.c')
-rw-r--r-- | drivers/pmdomain/mediatek/mtk-pm-domains.c | 172 |
1 files changed, 114 insertions, 58 deletions
diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c index ee962804b8..e274e3315f 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.c +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c @@ -24,6 +24,7 @@ #include "mt8188-pm-domains.h" #include "mt8192-pm-domains.h" #include "mt8195-pm-domains.h" +#include "mt8365-pm-domains.h" #define MTK_POLL_DELAY_US 10 #define MTK_POLL_TIMEOUT USEC_PER_SEC @@ -44,6 +45,7 @@ struct scpsys_domain { struct clk_bulk_data *clks; int num_subsys_clks; struct clk_bulk_data *subsys_clks; + struct regmap *infracfg_nao; struct regmap *infracfg; struct regmap *smi; struct regulator *supply; @@ -118,64 +120,79 @@ static int scpsys_sram_disable(struct scpsys_domain *pd) MTK_POLL_TIMEOUT); } -static int _scpsys_bus_protect_enable(const struct scpsys_bus_prot_data *bpd, struct regmap *regmap) +static struct regmap *scpsys_bus_protect_get_regmap(struct scpsys_domain *pd, + const struct scpsys_bus_prot_data *bpd) { - int i, ret; + if (bpd->flags & BUS_PROT_COMPONENT_SMI) + return pd->smi; + else + return pd->infracfg; +} - for (i = 0; i < SPM_MAX_BUS_PROT_DATA; i++) { - u32 val, mask = bpd[i].bus_prot_mask; +static struct regmap *scpsys_bus_protect_get_sta_regmap(struct scpsys_domain *pd, + const struct scpsys_bus_prot_data *bpd) +{ + if (bpd->flags & BUS_PROT_STA_COMPONENT_INFRA_NAO) + return pd->infracfg_nao; + else + return scpsys_bus_protect_get_regmap(pd, bpd); +} - if (!mask) - break; +static int scpsys_bus_protect_clear(struct scpsys_domain *pd, + const struct scpsys_bus_prot_data *bpd) +{ + struct regmap *sta_regmap = scpsys_bus_protect_get_sta_regmap(pd, bpd); + struct regmap *regmap = scpsys_bus_protect_get_regmap(pd, bpd); + u32 sta_mask = bpd->bus_prot_sta_mask; + u32 expected_ack; + u32 val; - if (bpd[i].bus_prot_reg_update) - regmap_set_bits(regmap, bpd[i].bus_prot_set, mask); - else - regmap_write(regmap, bpd[i].bus_prot_set, mask); + expected_ack = (bpd->flags & BUS_PROT_STA_COMPONENT_INFRA_NAO ? sta_mask : 0); - ret = regmap_read_poll_timeout(regmap, bpd[i].bus_prot_sta, - val, (val & mask) == mask, - MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); - if (ret) - return ret; - } + if (bpd->flags & BUS_PROT_REG_UPDATE) + regmap_clear_bits(regmap, bpd->bus_prot_clr, bpd->bus_prot_set_clr_mask); + else + regmap_write(regmap, bpd->bus_prot_clr, bpd->bus_prot_set_clr_mask); - return 0; + if (bpd->flags & BUS_PROT_IGNORE_CLR_ACK) + return 0; + + return regmap_read_poll_timeout(sta_regmap, bpd->bus_prot_sta, + val, (val & sta_mask) == expected_ack, + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); } -static int scpsys_bus_protect_enable(struct scpsys_domain *pd) +static int scpsys_bus_protect_set(struct scpsys_domain *pd, + const struct scpsys_bus_prot_data *bpd) { - int ret; + struct regmap *sta_regmap = scpsys_bus_protect_get_sta_regmap(pd, bpd); + struct regmap *regmap = scpsys_bus_protect_get_regmap(pd, bpd); + u32 sta_mask = bpd->bus_prot_sta_mask; + u32 val; - ret = _scpsys_bus_protect_enable(pd->data->bp_infracfg, pd->infracfg); - if (ret) - return ret; + if (bpd->flags & BUS_PROT_REG_UPDATE) + regmap_set_bits(regmap, bpd->bus_prot_set, bpd->bus_prot_set_clr_mask); + else + regmap_write(regmap, bpd->bus_prot_set, bpd->bus_prot_set_clr_mask); - return _scpsys_bus_protect_enable(pd->data->bp_smi, pd->smi); + return regmap_read_poll_timeout(sta_regmap, bpd->bus_prot_sta, + val, (val & sta_mask) == sta_mask, + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); } -static int _scpsys_bus_protect_disable(const struct scpsys_bus_prot_data *bpd, - struct regmap *regmap) +static int scpsys_bus_protect_enable(struct scpsys_domain *pd) { - int i, ret; - - for (i = SPM_MAX_BUS_PROT_DATA - 1; i >= 0; i--) { - u32 val, mask = bpd[i].bus_prot_mask; + for (int i = 0; i < SPM_MAX_BUS_PROT_DATA; i++) { + const struct scpsys_bus_prot_data *bpd = &pd->data->bp_cfg[i]; + int ret; - if (!mask) - continue; + if (!bpd->bus_prot_set_clr_mask) + break; - if (bpd[i].bus_prot_reg_update) - regmap_clear_bits(regmap, bpd[i].bus_prot_clr, mask); + if (bpd->flags & BUS_PROT_INVERTED) + ret = scpsys_bus_protect_clear(pd, bpd); else - regmap_write(regmap, bpd[i].bus_prot_clr, mask); - - if (bpd[i].ignore_clr_ack) - continue; - - ret = regmap_read_poll_timeout(regmap, bpd[i].bus_prot_sta, - val, !(val & mask), - MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); + ret = scpsys_bus_protect_set(pd, bpd); if (ret) return ret; } @@ -185,13 +202,22 @@ static int _scpsys_bus_protect_disable(const struct scpsys_bus_prot_data *bpd, static int scpsys_bus_protect_disable(struct scpsys_domain *pd) { - int ret; + for (int i = SPM_MAX_BUS_PROT_DATA - 1; i >= 0; i--) { + const struct scpsys_bus_prot_data *bpd = &pd->data->bp_cfg[i]; + int ret; - ret = _scpsys_bus_protect_disable(pd->data->bp_smi, pd->smi); - if (ret) - return ret; + if (!bpd->bus_prot_set_clr_mask) + continue; + + if (bpd->flags & BUS_PROT_INVERTED) + ret = scpsys_bus_protect_set(pd, bpd); + else + ret = scpsys_bus_protect_clear(pd, bpd); + if (ret) + return ret; + } - return _scpsys_bus_protect_disable(pd->data->bp_infracfg, pd->infracfg); + return 0; } static int scpsys_regulator_enable(struct regulator *supply) @@ -237,9 +263,17 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT); regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); - ret = clk_bulk_prepare_enable(pd->num_subsys_clks, pd->subsys_clks); - if (ret) - goto err_pwr_ack; + /* + * In few Mediatek platforms(e.g. MT6779), the bus protect policy is + * stricter, which leads to bus protect release must be prior to bus + * access. + */ + if (!MTK_SCPD_CAPS(pd, MTK_SCPD_STRICT_BUS_PROTECTION)) { + ret = clk_bulk_prepare_enable(pd->num_subsys_clks, + pd->subsys_clks); + if (ret) + goto err_pwr_ack; + } ret = scpsys_sram_enable(pd); if (ret < 0) @@ -249,12 +283,23 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) if (ret < 0) goto err_disable_sram; + if (MTK_SCPD_CAPS(pd, MTK_SCPD_STRICT_BUS_PROTECTION)) { + ret = clk_bulk_prepare_enable(pd->num_subsys_clks, + pd->subsys_clks); + if (ret) + goto err_enable_bus_protect; + } + return 0; +err_enable_bus_protect: + scpsys_bus_protect_enable(pd); err_disable_sram: scpsys_sram_disable(pd); err_disable_subsys_clks: - clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks); + if (!MTK_SCPD_CAPS(pd, MTK_SCPD_STRICT_BUS_PROTECTION)) + clk_bulk_disable_unprepare(pd->num_subsys_clks, + pd->subsys_clks); err_pwr_ack: clk_bulk_disable_unprepare(pd->num_clks, pd->clks); err_reg: @@ -373,6 +418,14 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no return ERR_CAST(pd->smi); } + if (MTK_SCPD_CAPS(pd, MTK_SCPD_HAS_INFRA_NAO)) { + pd->infracfg_nao = syscon_regmap_lookup_by_phandle(node, "mediatek,infracfg-nao"); + if (IS_ERR(pd->infracfg_nao)) + return ERR_CAST(pd->infracfg_nao); + } else { + pd->infracfg_nao = NULL; + } + num_clks = of_clk_get_parent_count(node); if (num_clks > 0) { /* Calculate number of subsys_clks */ @@ -508,6 +561,11 @@ static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *paren goto err_put_node; } + /* recursive call to add all subdomains */ + ret = scpsys_add_subdomain(scpsys, child); + if (ret) + goto err_put_node; + ret = pm_genpd_add_subdomain(parent_pd, child_pd); if (ret) { dev_err(scpsys->dev, "failed to add %s subdomain to parent %s\n", @@ -517,11 +575,6 @@ static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *paren dev_dbg(scpsys->dev, "%s add subdomain: %s\n", parent_pd->name, child_pd->name); } - - /* recursive call to add all subdomains */ - ret = scpsys_add_subdomain(scpsys, child); - if (ret) - goto err_put_node; } return 0; @@ -535,9 +588,6 @@ static void scpsys_remove_one_domain(struct scpsys_domain *pd) { int ret; - if (scpsys_domain_is_on(pd)) - scpsys_power_off(&pd->genpd); - /* * We're in the error cleanup already, so we only complain, * but won't emit another error on top of the original one. @@ -547,6 +597,8 @@ static void scpsys_remove_one_domain(struct scpsys_domain *pd) dev_err(pd->scpsys->dev, "failed to remove domain '%s' : %d - state may be inconsistent\n", pd->genpd.name, ret); + if (scpsys_domain_is_on(pd)) + scpsys_power_off(&pd->genpd); clk_bulk_put(pd->num_clks, pd->clks); clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks); @@ -600,6 +652,10 @@ static const struct of_device_id scpsys_of_match[] = { .compatible = "mediatek,mt8195-power-controller", .data = &mt8195_scpsys_data, }, + { + .compatible = "mediatek,mt8365-power-controller", + .data = &mt8365_scpsys_data, + }, { } }; |