Skip to content

Commit

Permalink
soc/tegra: pmc: Move powergate initialisation to probe
Browse files Browse the repository at this point in the history
Commit 8df1274 ("soc/tegra: pmc: Enable XUSB partitions on boot")
was added as a workaround to ensure that the XUSB powergates or domains
were turned on early during boot because as this time the Tegra XHCI
driver did not handle the power domains at all. Now that the Tegra XHCI
driver has been updated to properly managed the power domains, the
workaround to enable the XUSB power domain early has been removed. This
also means that we can now move the initialisation of the powergates
into the PMC driver probe. Therefore, move the powergate initialisation
into the PMC driver probe and return any errors detected. To handle any
errors, functions to cleanup and remove any power-domains registered
with the generic power-domain framework have been added.

Finally the initialisation of the 'powergates_available' bitmask is kept
in the PMC early init function to allow the legacy PMC powergate APIs to
be called during early boot for enabling secondary CPUs on 32-bit Tegra
devices.

Signed-off-by: Jon Hunter <[email protected]>
Signed-off-by: Thierry Reding <[email protected]>
  • Loading branch information
jonhunter authored and thierryreding committed Apr 17, 2019
1 parent a46b51c commit 6ac2a01
Showing 1 changed file with 68 additions and 15 deletions.
83 changes: 68 additions & 15 deletions drivers/soc/tegra/pmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -990,20 +990,21 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg,
return err;
}

static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
{
struct device *dev = pmc->dev;
struct tegra_powergate *pg;
int id, err;
int id, err = 0;
bool off;

pg = kzalloc(sizeof(*pg), GFP_KERNEL);
if (!pg)
return;
return -ENOMEM;

id = tegra_powergate_lookup(pmc, np->name);
if (id < 0) {
dev_err(dev, "powergate lookup failed for %pOFn: %d\n", np, id);
err = -ENODEV;
goto free_mem;
}

Expand Down Expand Up @@ -1056,7 +1057,7 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)

dev_dbg(dev, "added PM domain %s\n", pg->genpd.name);

return;
return 0;

remove_genpd:
pm_genpd_remove(&pg->genpd);
Expand All @@ -1075,25 +1076,67 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)

free_mem:
kfree(pg);

return err;
}

static void tegra_powergate_init(struct tegra_pmc *pmc,
struct device_node *parent)
static int tegra_powergate_init(struct tegra_pmc *pmc,
struct device_node *parent)
{
struct device_node *np, *child;
unsigned int i;
int err = 0;

np = of_get_child_by_name(parent, "powergates");
if (!np)
return 0;

/* Create a bitmap of the available and valid partitions */
for (i = 0; i < pmc->soc->num_powergates; i++)
if (pmc->soc->powergates[i])
set_bit(i, pmc->powergates_available);
for_each_child_of_node(np, child) {
err = tegra_powergate_add(pmc, child);
if (err < 0) {
of_node_put(child);
break;
}
}

of_node_put(np);

return err;
}

static void tegra_powergate_remove(struct generic_pm_domain *genpd)
{
struct tegra_powergate *pg = to_powergate(genpd);

reset_control_put(pg->reset);

while (pg->num_clks--)
clk_put(pg->clks[pg->num_clks]);

kfree(pg->clks);

set_bit(pg->id, pmc->powergates_available);

kfree(pg);
}

static void tegra_powergate_remove_all(struct device_node *parent)
{
struct generic_pm_domain *genpd;
struct device_node *np, *child;

np = of_get_child_by_name(parent, "powergates");
if (!np)
return;

for_each_child_of_node(np, child)
tegra_powergate_add(pmc, child);
for_each_child_of_node(np, child) {
of_genpd_del_provider(child);

genpd = of_genpd_remove_last(child);
if (IS_ERR(genpd))
continue;

tegra_powergate_remove(genpd);
}

of_node_put(np);
}
Expand Down Expand Up @@ -2054,9 +2097,13 @@ static int tegra_pmc_probe(struct platform_device *pdev)
if (err)
goto cleanup_restart_handler;

err = tegra_powergate_init(pmc, pdev->dev.of_node);
if (err < 0)
goto cleanup_powergates;

err = tegra_pmc_irq_init(pmc);
if (err < 0)
goto cleanup_restart_handler;
goto cleanup_powergates;

mutex_lock(&pmc->powergates_lock);
iounmap(pmc->base);
Expand All @@ -2067,6 +2114,8 @@ static int tegra_pmc_probe(struct platform_device *pdev)

return 0;

cleanup_powergates:
tegra_powergate_remove_all(pdev->dev.of_node);
cleanup_restart_handler:
unregister_restart_handler(&tegra_pmc_restart_handler);
cleanup_debugfs:
Expand Down Expand Up @@ -2763,6 +2812,7 @@ static int __init tegra_pmc_early_init(void)
const struct of_device_id *match;
struct device_node *np;
struct resource regs;
unsigned int i;
bool invert;

mutex_init(&pmc->powergates_lock);
Expand Down Expand Up @@ -2819,7 +2869,10 @@ static int __init tegra_pmc_early_init(void)
if (pmc->soc->maybe_tz_only)
pmc->tz_only = tegra_pmc_detect_tz_only(pmc);

tegra_powergate_init(pmc, np);
/* Create a bitmap of the available and valid partitions */
for (i = 0; i < pmc->soc->num_powergates; i++)
if (pmc->soc->powergates[i])
set_bit(i, pmc->powergates_available);

/*
* Invert the interrupt polarity if a PMC device tree node
Expand Down

0 comments on commit 6ac2a01

Please sign in to comment.