/* Read ISO and ISO2SW power down delays */
regmap_read(pd->regmap, pd->reg_offs + GPC_PGC_PDNSCR_OFFS, &val);
iso = val & 0x3f;
iso2sw = (val >> 8) & 0x3f;
/* Gate off domain when powered down */
regmap_update_bits(pd->regmap, pd->reg_offs + GPC_PGC_CTRL_OFFS,
0x1, 0x1);
/* Request GPC to power down domain */
val = BIT(pd->cntr_pdn_bit);
regmap_update_bits(pd->regmap, GPC_CNTR, val, val);
staticint imx6_pm_domain_power_on(struct generic_pm_domain *genpd)
{ struct imx_pm_domain *pd = to_imx_pm_domain(genpd); int i, ret;
u32 val, req;
if (pd->supply) {
ret = regulator_enable(pd->supply); if (ret) {
pr_err("%s: failed to enable regulator: %d\n",
__func__, ret); return ret;
}
}
/* Enable reset clocks for all devices in the domain */ for (i = 0; i < pd->num_clks; i++)
clk_prepare_enable(pd->clk[i]);
/* Gate off domain when powered down */
regmap_update_bits(pd->regmap, pd->reg_offs + GPC_PGC_CTRL_OFFS,
0x1, 0x1);
/* Request GPC to power up domain */
req = BIT(pd->cntr_pdn_bit + 1);
regmap_update_bits(pd->regmap, GPC_CNTR, req, req);
/* Wait for the PGC to handle the request */
ret = regmap_read_poll_timeout(pd->regmap, GPC_CNTR, val, !(val & req),
1, 50); if (ret)
pr_err("powerup request on domain %s timed out\n", genpd->name);
/* Wait for reset to propagate through peripherals */
usleep_range(5, 10);
/* Disable reset clocks for all devices in the domain */ for (i = 0; i < pd->num_clks; i++)
clk_disable_unprepare(pd->clk[i]);
return 0;
}
staticint imx_pgc_get_clocks(struct device *dev, struct imx_pm_domain *domain)
{ int i, ret;
for (i = 0; ; i++) { struct clk *clk = of_clk_get(dev->of_node, i); if (IS_ERR(clk)) break; if (i >= GPC_CLK_MAX) {
dev_err(dev, "more than %d clocks\n", GPC_CLK_MAX);
ret = -EINVAL; goto clk_err;
}
domain->clk[i] = clk;
}
domain->num_clks = i;
return 0;
clk_err: while (i--)
clk_put(domain->clk[i]);
return ret;
}
staticvoid imx_pgc_put_clocks(struct imx_pm_domain *domain)
{ int i;
for (i = domain->num_clks - 1; i >= 0; i--)
clk_put(domain->clk[i]);
}
staticint imx_pgc_parse_dt(struct device *dev, struct imx_pm_domain *domain)
{ /* try to get the domain supply regulator */
domain->supply = devm_regulator_get_optional(dev, "power"); if (IS_ERR(domain->supply)) { if (PTR_ERR(domain->supply) == -ENODEV)
domain->supply = NULL; else return PTR_ERR(domain->supply);
}
/* try to get all clocks needed for reset propagation */ return imx_pgc_get_clocks(dev, domain);
}
/* if this PD is associated with a DT node try to parse it */ if (dev->of_node) {
ret = imx_pgc_parse_dt(dev, domain); if (ret) return ret;
}
/* initially power on the domain */ if (domain->base.power_on)
domain->base.power_on(&domain->base);
if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
pm_genpd_init(&domain->base, NULL, false);
ret = of_genpd_add_provider_simple(dev->of_node, &domain->base); if (ret) goto genpd_err;
}
staticint imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap, unsignedint num_domains)
{ struct imx_pm_domain *domain; int i, ret;
for (i = 0; i < num_domains; i++) {
domain = &imx_gpc_domains[i];
domain->regmap = regmap;
domain->ipg_rate_mhz = 66;
if (i == 1) {
domain->supply = devm_regulator_get(dev, "pu"); if (IS_ERR(domain->supply)) return PTR_ERR(domain->supply);
ret = imx_pgc_get_clocks(dev, domain); if (ret) goto clk_err;
domain->base.power_on(&domain->base);
}
}
for (i = 0; i < num_domains; i++)
pm_genpd_init(&imx_gpc_domains[i].base, NULL, false);
if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
ret = of_genpd_add_provider_onecell(dev->of_node,
&imx_gpc_onecell_data); if (ret) goto genpd_err;
}
return 0;
genpd_err: for (i = 0; i < num_domains; i++)
pm_genpd_remove(&imx_gpc_domains[i].base);
imx_pgc_put_clocks(&imx_gpc_domains[GPC_PGC_DOMAIN_PU]);
clk_err: return ret;
}
/* bail out if DT too old and doesn't provide the necessary info */ if (!of_property_present(pdev->dev.of_node, "#power-domain-cells") &&
!pgc_node) return 0;
base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base);
regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base,
&imx_gpc_regmap_config); if (IS_ERR(regmap)) {
ret = PTR_ERR(regmap);
dev_err(&pdev->dev, "failed to init regmap: %d\n",
ret); return ret;
}
/* * Disable PU power down by runtime PM if ERR009619 is present. * * The PRE clock will be paused for several cycles when turning on the * PU domain LDO from power down state. If PRE is in use at that time, * the IPU/PRG cannot get the correct display data from the PRE. * * This is not a concern when the whole system enters suspend state, so * it's safe to power down PU in this case.
*/ if (of_id_data->err009619_present)
imx_gpc_domains[GPC_PGC_DOMAIN_PU].base.flags |=
GENPD_FLAG_RPM_ALWAYS_ON;
/* Keep DISP always on if ERR006287 is present */ if (of_id_data->err006287_present)
imx_gpc_domains[GPC_PGC_DOMAIN_DISPLAY].base.flags |=
GENPD_FLAG_ALWAYS_ON;
if (!pgc_node) {
ret = imx_gpc_old_dt_init(&pdev->dev, regmap,
of_id_data->num_domains); if (ret) return ret;
} else { struct imx_pm_domain *domain; struct platform_device *pd_pdev; struct clk *ipg_clk; unsignedint ipg_rate_mhz; int domain_index;
/* bail out if DT too old and doesn't provide the necessary info */ if (!of_property_present(pdev->dev.of_node, "#power-domain-cells") &&
!pgc_node) return;
/* * If the old DT binding is used the toplevel driver needs to * de-register the power domains
*/ if (!pgc_node) {
of_genpd_del_provider(pdev->dev.of_node);
ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_PU].base); if (ret) {
dev_err(&pdev->dev, "Failed to remove PU power domain (%pe)\n",
ERR_PTR(ret)); return;
}
imx_pgc_put_clocks(&imx_gpc_domains[GPC_PGC_DOMAIN_PU]);
ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_ARM].base); if (ret) {
dev_err(&pdev->dev, "Failed to remove ARM power domain (%pe)\n",
ERR_PTR(ret)); return;
}
}
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.