From f5353c60507cb96195cd56499ee5e56a92388645 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 30 Dec 2015 17:13:29 +0100 Subject: soc/tegra: pmc: Use register definitions instead of magic values Use register definitions for the main SoC reset operation instead of hard-coding magic values. Note that the PMC_RST_STATUS register isn't actually accessed, but since it is mentioned in a comment the definitions are added for completeness. Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index bb173456bbff..d13516981629 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -51,6 +51,7 @@ #define PMC_CNTRL_CPU_PWRREQ_POLARITY (1 << 15) /* CPU pwr req polarity */ #define PMC_CNTRL_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */ #define PMC_CNTRL_INTR_POLARITY (1 << 17) /* inverts INTR polarity */ +#define PMC_CNTRL_MAIN_RST (1 << 4) #define DPD_SAMPLE 0x020 #define DPD_SAMPLE_ENABLE (1 << 0) @@ -80,6 +81,14 @@ #define PMC_SENSOR_CTRL_SCRATCH_WRITE (1 << 2) #define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1) +#define PMC_RST_STATUS 0x1b4 +#define PMC_RST_STATUS_POR 0 +#define PMC_RST_STATUS_WATCHDOG 1 +#define PMC_RST_STATUS_SENSOR 2 +#define PMC_RST_STATUS_SW_MAIN 3 +#define PMC_RST_STATUS_LP0 4 +#define PMC_RST_STATUS_AOTAG 5 + #define IO_DPD_REQ 0x1b8 #define IO_DPD_REQ_CODE_IDLE (0 << 30) #define IO_DPD_REQ_CODE_OFF (1 << 30) @@ -638,9 +647,10 @@ static int tegra_pmc_restart_notify(struct notifier_block *this, tegra_pmc_writel(value, PMC_SCRATCH0); - value = tegra_pmc_readl(0); - value |= 0x10; - tegra_pmc_writel(value, 0); + /* reset everything but PMC_SCRATCH0 and PMC_RST_STATUS */ + value = tegra_pmc_readl(PMC_CNTRL); + value |= PMC_CNTRL_MAIN_RST; + tegra_pmc_writel(value, PMC_CNTRL); return NOTIFY_DONE; } -- cgit v1.2.3 From 05cfb988a4d08f84abd2f474d8dd771e7528d975 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Wed, 29 Jun 2016 10:17:47 +0100 Subject: soc/tegra: pmc: Initialise resets associated with a power partition When registering the Tegra power partitions with the generic PM domain framework, the current state of the each partition is checked and used as the default state for the partition. However, the state of each reset associated with the partition is not initialised and so it is possible that the state of the resets are not in the expected state. For example, if a partition is on, then the resets should be de-asserted and if the partition is off, the resets should be asserted. There have been cases where the bootloader has powered on a partition and only de-asserted some of the resets to some of the devices in the partition. This can cause accesses to these devices to hang the system when the kernel boots and attempts to probe these devices. Ideally, the driver for the device should ensure the reset has been de-asserted when probing, but the resets cannot be shared between the PMC driver (that needs to de-assert/assert the reset when turning the partition on or off) and another driver because we cannot ensure the reset is in the correct state. To ensure the resets are in the correct state, when using the generic PM domain framework, put each reset associated with the partition in the correct state (based upon the partition's current state) when obtaining the resets for a partition. Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index d13516981629..8a421a0b1ece 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -738,7 +738,7 @@ err: } static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, - struct device_node *np) + struct device_node *np, bool off) { struct reset_control *rst; unsigned int i, count; @@ -758,6 +758,16 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, err = PTR_ERR(pg->resets[i]); goto error; } + + if (off) + err = reset_control_assert(pg->resets[i]); + else + err = reset_control_deassert(pg->resets[i]); + + if (err) { + reset_control_put(pg->resets[i]); + goto error; + } } pg->num_resets = count; @@ -798,14 +808,14 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) pg->genpd.power_on = tegra_genpd_power_on; pg->pmc = pmc; + off = !tegra_powergate_is_powered(pg->id); + if (tegra_powergate_of_get_clks(pg, np)) goto set_available; - if (tegra_powergate_of_get_resets(pg, np)) + if (tegra_powergate_of_get_resets(pg, np, off)) goto remove_clks; - off = !tegra_powergate_is_powered(pg->id); - pm_genpd_init(&pg->genpd, NULL, off); if (of_genpd_add_provider_simple(np, &pg->genpd)) -- cgit v1.2.3 From 403db2d21c8f8576d38211e5ec17d149c49e528b Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 28 Jun 2016 11:38:23 +0100 Subject: soc/tegra: pmc: Ensure powergate is available when powering on The function tegra_power_sequence_power_up() is a public function used to power on a partition. When this function is called, we do not check to see if the partition being powered up is valid/available. Fix this by checking to see that the partition is valid/available. Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 8a421a0b1ece..52a9e9703668 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -549,6 +549,9 @@ int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk, struct tegra_powergate pg; int err; + if (!tegra_powergate_is_available(id)) + return -EINVAL; + pg.id = id; pg.clks = &clk; pg.num_clks = 1; -- cgit v1.2.3 From 11131895cd1ba1cf58a87c6acb574cbeec5818af Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 28 Jun 2016 11:38:24 +0100 Subject: soc/tegra: pmc: Fix early initialisation of PMC During early initialisation, the available power partitions for a given device is configured as well as the polarity of the PMC interrupt. Both of which should only be configured if there is a valid device node for the PMC device. This is because the soc data used for configuring the power partitions is only available if a device node for the PMC is found and the code to configure the interrupt polarity uses the device node pointer directly. Some early device-tree images may not have this device node and so fix this by ensuring the device node pointer is valid when configuring these items. Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 52a9e9703668..2e031c4ad547 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -1550,27 +1550,29 @@ static int __init tegra_pmc_early_init(void) return -ENXIO; } - /* Create a bit-map 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); - mutex_init(&pmc->powergates_lock); - /* - * Invert the interrupt polarity if a PMC device tree node exists and - * contains the nvidia,invert-interrupt property. - */ - invert = of_property_read_bool(np, "nvidia,invert-interrupt"); + if (np) { + /* Create a bit-map 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); - value = tegra_pmc_readl(PMC_CNTRL); + /* + * Invert the interrupt polarity if a PMC device tree node + * exists and contains the nvidia,invert-interrupt property. + */ + invert = of_property_read_bool(np, "nvidia,invert-interrupt"); - if (invert) - value |= PMC_CNTRL_INTR_POLARITY; - else - value &= ~PMC_CNTRL_INTR_POLARITY; + value = tegra_pmc_readl(PMC_CNTRL); - tegra_pmc_writel(value, PMC_CNTRL); + if (invert) + value |= PMC_CNTRL_INTR_POLARITY; + else + value &= ~PMC_CNTRL_INTR_POLARITY; + + tegra_pmc_writel(value, PMC_CNTRL); + } return 0; } -- cgit v1.2.3 From 718a2426e82076e4eddc2a041c8e944c9f9b3e61 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 28 Jun 2016 11:38:25 +0100 Subject: soc/tegra: pmc: Don't populate SoC data until register space is mapped The public functions exported by the PMC driver use the presence of the SoC data pointer to determine if the PMC device is configured and the registers can be accessed. However, the SoC data is populated before the PMC register space is mapped and this opens a window where the SoC data pointer is valid but the register space has not yet been mapped which could lead to a crash. Furthermore, if the mapping of the PMC register space fails, then the SoC data pointer is not cleared and so would expose a larger window where a crash could occur. Fix this by initialising the SoC data pointer after the PMC register space has been mapped. Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 2e031c4ad547..ed2b2c83e4eb 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -1540,8 +1540,6 @@ static int __init tegra_pmc_early_init(void) pr_err("failed to get PMC registers\n"); return -ENXIO; } - - pmc->soc = match->data; } pmc->base = ioremap_nocache(regs.start, resource_size(®s)); @@ -1553,6 +1551,8 @@ static int __init tegra_pmc_early_init(void) mutex_init(&pmc->powergates_lock); if (np) { + pmc->soc = match->data; + /* Create a bit-map of the available and valid partitions */ for (i = 0; i < pmc->soc->num_powergates; i++) if (pmc->soc->powergates[i]) -- cgit v1.2.3 From 61fd284be8be06db1339ca4c9217f5a13b50074f Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 28 Jun 2016 11:38:26 +0100 Subject: soc/tegra: pmc: Ensure mutex is always initialised The mutex used by the PMC driver may not be initialised if early initialisation of the driver fails. If this does happen, then it could be possible for callers of the public PMC functions to still attempt to acquire the mutex. Fix this by initialising the mutex as soon as possible to ensure it will always be initialised. Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index ed2b2c83e4eb..483d54623ec5 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -1504,6 +1504,8 @@ static int __init tegra_pmc_early_init(void) bool invert; u32 value; + mutex_init(&pmc->powergates_lock); + np = of_find_matching_node_and_match(NULL, tegra_pmc_match, &match); if (!np) { /* @@ -1548,8 +1550,6 @@ static int __init tegra_pmc_early_init(void) return -ENXIO; } - mutex_init(&pmc->powergates_lock); - if (np) { pmc->soc = match->data; -- cgit v1.2.3 From b69a625826ecc563414aea5846e31b05184292f4 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 28 Jun 2016 11:38:27 +0100 Subject: soc/tegra: pmc: Add missing of_node_put() Add missing of_node_put() in PMC early initialisation function to avoid leaking the device nodes. Signed-off-by: Jon Hunter [treding@nvidia.com: squash in a couple more of_node_put() calls] Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 483d54623ec5..48e1de2f7aeb 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -1540,6 +1540,7 @@ static int __init tegra_pmc_early_init(void) */ if (of_address_to_resource(np, 0, ®s) < 0) { pr_err("failed to get PMC registers\n"); + of_node_put(np); return -ENXIO; } } @@ -1547,6 +1548,7 @@ static int __init tegra_pmc_early_init(void) pmc->base = ioremap_nocache(regs.start, resource_size(®s)); if (!pmc->base) { pr_err("failed to map PMC registers\n"); + of_node_put(np); return -ENXIO; } @@ -1572,6 +1574,8 @@ static int __init tegra_pmc_early_init(void) value &= ~PMC_CNTRL_INTR_POLARITY; tegra_pmc_writel(value, PMC_CNTRL); + + of_node_put(np); } return 0; -- cgit v1.2.3 From a83f1fc3f33930d01e579b9d4de92a045297b402 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 28 Jun 2016 11:38:28 +0100 Subject: soc/tegra: pmc: Don't probe PMC if early initialisation fails Commit 0259f522e04f ('soc/tegra: pmc: Restore base address on probe failure') fixes an issue where the PMC base address pointer is not restored on probe failure. However, this fix creates another problem where if early initialisation of the PMC driver fails and an initial mapping for the PMC address space is not created, then when the PMC device is probed, the PMC base address pointer will not be valid and this will cause a crash when tegra_pmc_init() is called and attempts to access a register. Although the PMC address space is mapped a 2nd time during the probe and so this could be fixed by populating the base address pointer earlier during the probe, this adds more complexity to the code. Moreover, the PMC probe also assumes the the soc data pointer is also initialised when the device is probed and if not will also lead to a crash when calling tegra_pmc_init_tsense_reset(). Given that if the early initialisation does fail then something bad has happen, it seems acceptable to allow the PMC device probe to fail as well. Therefore, if the PMC base address pointer or soc data pointer are not valid when probing the PMC device, WARN and return an error. Fixes: 0259f522e04f ('soc/tegra: pmc: Restore base address on probe failure') Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 48e1de2f7aeb..1f702538f8ec 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -1228,6 +1228,14 @@ static int tegra_pmc_probe(struct platform_device *pdev) struct resource *res; int err; + /* + * Early initialisation should have configured an initial + * register mapping and setup the soc data pointer. If these + * are not valid then something went badly wrong! + */ + if (WARN_ON(!pmc->base || !pmc->soc)) + return -ENODEV; + err = tegra_pmc_parse_dt(pmc, pdev->dev.of_node); if (err < 0) return err; -- cgit v1.2.3 From da8f4b458944dccc371dba240cfa18c27b7b9802 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 30 Jun 2016 12:12:55 +0200 Subject: soc/tegra: pmc: Use whitespace more consistently Use blank lines after blocks and before labels for consistency with the existing code in the file. Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 1f702538f8ec..2ccbdfe751db 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -408,6 +408,7 @@ static int tegra_powergate_power_up(struct tegra_powergate *pg, disable_clks: tegra_powergate_disable_clocks(pg); usleep_range(10, 20); + powergate_off: tegra_powergate_set(pg->id, false); @@ -445,6 +446,7 @@ assert_resets: usleep_range(10, 20); tegra_powergate_reset_deassert(pg); usleep_range(10, 20); + disable_clks: tegra_powergate_disable_clocks(pg); @@ -735,6 +737,7 @@ static int tegra_powergate_of_get_clks(struct tegra_powergate *pg, err: while (i--) clk_put(pg->clks[i]); + kfree(pg->clks); return err; @@ -780,6 +783,7 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, error: while (i--) reset_control_put(pg->resets[i]); + kfree(pg->resets); return err; @@ -831,11 +835,13 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) remove_resets: while (pg->num_resets--) reset_control_put(pg->resets[pg->num_resets]); + kfree(pg->resets); remove_clks: while (pg->num_clks--) clk_put(pg->clks[pg->num_clks]); + kfree(pg->clks); set_available: -- cgit v1.2.3 From c2710ac9f5a8dab4f9bb080713452fe6286ca83d Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 30 Jun 2016 11:56:24 +0100 Subject: soc/tegra: pmc: Add specific error messages When initialising a powergate, only a single error message is shown if the initialisation fails. Add more error messages to give specific details of what failed if the initialisation failed and remove the generic failure message. Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 2ccbdfe751db..ecc1ec0a4ada 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -792,16 +792,19 @@ error: static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) { struct tegra_powergate *pg; + int id, err; bool off; - int id; pg = kzalloc(sizeof(*pg), GFP_KERNEL); if (!pg) - goto error; + return; id = tegra_powergate_lookup(pmc, np->name); - if (id < 0) + if (id < 0) { + dev_err(pmc->dev, "powergate lookup failed for %s: %d\n", + np->name, id); goto free_mem; + } /* * Clear the bit for this powergate so it cannot be managed @@ -817,16 +820,28 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) off = !tegra_powergate_is_powered(pg->id); - if (tegra_powergate_of_get_clks(pg, np)) + err = tegra_powergate_of_get_clks(pg, np); + if (err < 0) { + dev_err(pmc->dev, "failed to get clocks for %s: %d\n", + np->name, err); goto set_available; + } - if (tegra_powergate_of_get_resets(pg, np, off)) + err = tegra_powergate_of_get_resets(pg, np, off); + if (err < 0) { + dev_err(pmc->dev, "failed to get resets for %s: %d\n", + np->name, err); goto remove_clks; + } pm_genpd_init(&pg->genpd, NULL, off); - if (of_genpd_add_provider_simple(np, &pg->genpd)) + err = of_genpd_add_provider_simple(np, &pg->genpd); + if (err < 0) { + dev_err(pmc->dev, "failed to add genpd provider for %s: %d\n", + np->name, err); goto remove_resets; + } dev_dbg(pmc->dev, "added power domain %s\n", pg->genpd.name); @@ -849,9 +864,6 @@ set_available: free_mem: kfree(pg); - -error: - dev_err(pmc->dev, "failed to create power domain for %s\n", np->name); } static void tegra_powergate_init(struct tegra_pmc *pmc) -- cgit v1.2.3 From e2d17960532d925a202682ce72379c6055068ca4 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 30 Jun 2016 11:56:25 +0100 Subject: soc/tegra: pmc: Initialise power partitions early If CONFIG_PM_GENERIC_DOMAINS is not enabled, then power partitions associated with a device will not be enabled automatically by the PM core when the device is in use. To avoid situations where a device in a power partition is to be used but the partition is not enabled, initialise the power partitions for Tegra early in the boot process and if CONFIG_PM_GENERIC_DOMAINS is not enabled, then power on all partitions defined in the device-tree blob. Note that if CONFIG_PM_GENERIC_DOMAINS is not enabled, after the partitions are turned on, the clocks and resets used as part of the sequence for turning on the partition are released again as they are no longer needed by the PMC driver. Another benefit of this is that this avoids any issues of sharing resets between the PMC driver and other device drivers that may wish to independently control a particular reset. Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index ecc1ec0a4ada..7199726198e1 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -834,6 +834,9 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) goto remove_clks; } + if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) + goto power_on_cleanup; + pm_genpd_init(&pg->genpd, NULL, off); err = of_genpd_add_provider_simple(np, &pg->genpd); @@ -847,6 +850,10 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) return; +power_on_cleanup: + if (off) + WARN_ON(tegra_powergate_power_up(pg, true)); + remove_resets: while (pg->num_resets--) reset_control_put(pg->resets[pg->num_resets]); @@ -866,11 +873,18 @@ free_mem: kfree(pg); } -static void tegra_powergate_init(struct tegra_pmc *pmc) +static void tegra_powergate_init(struct tegra_pmc *pmc, + struct device_node *parent) { struct device_node *np, *child; + unsigned int i; - np = of_get_child_by_name(pmc->dev->of_node, "powergates"); + /* 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); + + np = of_get_child_by_name(parent, "powergates"); if (!np) return; @@ -1291,8 +1305,6 @@ static int tegra_pmc_probe(struct platform_device *pdev) return err; } - tegra_powergate_init(pmc); - mutex_lock(&pmc->powergates_lock); iounmap(pmc->base); pmc->base = base; @@ -1526,7 +1538,6 @@ 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; u32 value; @@ -1581,10 +1592,7 @@ static int __init tegra_pmc_early_init(void) if (np) { pmc->soc = match->data; - /* Create a bit-map 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); + tegra_powergate_init(pmc, np); /* * Invert the interrupt polarity if a PMC device tree node -- cgit v1.2.3 From 8df127456f29c719eb2b458018298b1980f1218e Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 30 Jun 2016 11:56:26 +0100 Subject: soc/tegra: pmc: Enable XUSB partitions on boot The Tegra XHCI driver does not currently manage the Tegra XUSB power partitions and so it these partitions have not been enabled by the bootloader then the system will crash when probing the XHCI device. While proper support for managing the power partitions is being developed to the XHCI driver for Tegra, for now power on all the XUSB partitions for USB host and super-speed on boot if the XHCI driver is enabled. Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 7199726198e1..71c834f3847e 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -837,6 +837,18 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) goto power_on_cleanup; + /* + * FIXME: If XHCI is enabled for Tegra, then power-up the XUSB + * host and super-speed partitions. Once the XHCI driver + * manages the partitions itself this code can be removed. Note + * that we don't register these partitions with the genpd core + * to avoid it from powering down the partitions as they appear + * to be unused. + */ + if (IS_ENABLED(CONFIG_USB_XHCI_TEGRA) && + (id == TEGRA_POWERGATE_XUSBA || id == TEGRA_POWERGATE_XUSBC)) + goto power_on_cleanup; + pm_genpd_init(&pg->genpd, NULL, off); err = of_genpd_add_provider_simple(np, &pg->genpd); -- cgit v1.2.3