/* Either wait until SRAM_PDN_ACK all 1 or 0 */
ret = regmap_read_poll_timeout(scpsys->base, pd->data->ctl_offs, tmp,
(tmp & pdn_ack) == 0, MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); if (ret < 0) return ret;
/* * 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) goto err_disable_subsys_clks;
ret = scpsys_bus_protect_disable(pd); 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;
}
ret = of_property_read_u32(node, "reg", &id); if (ret) {
dev_err(scpsys->dev, "%pOF: failed to retrieve domain id from reg: %d\n",
node, ret); return ERR_PTR(-EINVAL);
}
if (id >= scpsys->soc_data->num_domains) {
dev_err(scpsys->dev, "%pOF: invalid domain id %d\n", node, id); return ERR_PTR(-EINVAL);
}
domain_data = &scpsys->soc_data->domains_data[id]; if (domain_data->sta_mask == 0) {
dev_err(scpsys->dev, "%pOF: undefined domain id %d\n", node, id); return ERR_PTR(-EINVAL);
}
pd = devm_kzalloc(scpsys->dev, sizeof(*pd), GFP_KERNEL); if (!pd) return ERR_PTR(-ENOMEM);
pd->data = domain_data;
pd->scpsys = scpsys;
if (MTK_SCPD_CAPS(pd, MTK_SCPD_DOMAIN_SUPPLY)) {
pd->supply = devm_of_regulator_get_optional(scpsys->dev, node, "domain"); if (IS_ERR(pd->supply)) return dev_err_cast_probe(scpsys->dev, pd->supply, "%pOF: failed to get power supply.\n",
node);
}
pd->infracfg = syscon_regmap_lookup_by_phandle_optional(node, "mediatek,infracfg"); if (IS_ERR(pd->infracfg)) return dev_err_cast_probe(scpsys->dev, pd->infracfg, "%pOF: failed to get infracfg regmap\n",
node);
smi_node = of_parse_phandle(node, "mediatek,smi", 0); if (smi_node) {
pd->smi = device_node_to_regmap(smi_node);
of_node_put(smi_node); if (IS_ERR(pd->smi)) return dev_err_cast_probe(scpsys->dev, pd->smi, "%pOF: failed to get SMI regmap\n",
node);
}
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 dev_err_cast_probe(scpsys->dev, pd->infracfg_nao, "%pOF: failed to get infracfg-nao regmap\n",
node);
} else {
pd->infracfg_nao = NULL;
}
num_clks = of_clk_get_parent_count(node); if (num_clks > 0) { /* Calculate number of subsys_clks */
of_property_for_each_string(node, "clock-names", prop, clk_name) { char *subsys;
subsys = strchr(clk_name, '-'); if (subsys)
pd->num_subsys_clks++; else
pd->num_clks++;
}
pd->clks = devm_kcalloc(scpsys->dev, pd->num_clks, sizeof(*pd->clks), GFP_KERNEL); if (!pd->clks) return ERR_PTR(-ENOMEM);
pd->subsys_clks = devm_kcalloc(scpsys->dev, pd->num_subsys_clks, sizeof(*pd->subsys_clks), GFP_KERNEL); if (!pd->subsys_clks) return ERR_PTR(-ENOMEM);
}
for (i = 0; i < pd->num_clks; i++) {
clk = of_clk_get(node, i); if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
dev_err_probe(scpsys->dev, ret, "%pOF: failed to get clk at index %d\n", node, i); goto err_put_clocks;
}
pd->clks[clk_ind++].clk = clk;
}
for (i = 0; i < pd->num_subsys_clks; i++) {
clk = of_clk_get(node, i + clk_ind); if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
dev_err_probe(scpsys->dev, ret, "%pOF: failed to get clk at index %d\n", node,
i + clk_ind); goto err_put_subsys_clocks;
}
pd->subsys_clks[i].clk = clk;
}
/* * Initially turn on all domains to make the domains usable * with !CONFIG_PM and to get the hardware in sync with the * software. The unused domains will be switched off during * late_init time.
*/ if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF)) { if (scpsys_domain_is_on(pd))
dev_warn(scpsys->dev, "%pOF: A default off power domain has been ON\n", node);
} else {
ret = scpsys_power_on(&pd->genpd); if (ret < 0) {
dev_err(scpsys->dev, "%pOF: failed to power on domain: %d\n", node, ret); goto err_put_subsys_clocks;
}
if (MTK_SCPD_CAPS(pd, MTK_SCPD_ALWAYS_ON))
pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
}
if (scpsys->domains[id]) {
ret = -EINVAL;
dev_err(scpsys->dev, "power domain with id %d already exists, check your device-tree\n", id); goto err_put_subsys_clocks;
}
if (!pd->data->name)
pd->genpd.name = node->name; else
pd->genpd.name = pd->data->name;
ret = of_property_read_u32(parent, "reg", &id); if (ret) {
dev_err(scpsys->dev, "%pOF: failed to get parent domain id\n", child); goto err_put_node;
}
if (!scpsys->pd_data.domains[id]) {
ret = -EINVAL;
dev_err(scpsys->dev, "power domain with id %d does not exist\n", id); goto err_put_node;
}
parent_pd = scpsys->pd_data.domains[id];
child_pd = scpsys_add_one_domain(scpsys, child); if (IS_ERR(child_pd)) {
ret = PTR_ERR(child_pd);
dev_err_probe(scpsys->dev, ret, "%pOF: failed to get child domain id\n",
child); 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",
child_pd->name, parent_pd->name); goto err_put_node;
} else {
dev_dbg(scpsys->dev, "%s add subdomain: %s\n", parent_pd->name,
child_pd->name);
}
}
return 0;
err_put_node:
of_node_put(child); return ret;
}
staticvoid scpsys_remove_one_domain(struct scpsys_domain *pd)
{ int ret;
/* * We're in the error cleanup already, so we only complain, * but won't emit another error on top of the original one.
*/
ret = pm_genpd_remove(&pd->genpd); if (ret < 0)
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);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.