soc/tegra: Changes for v4.8-rc1
Contains fixes and cleanups to the PMC driver, as well as some fixes for the generic PM domain support and some prep work to support PCIe on 64- bit ARM. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJXdn7eAAoJEN0jrNd/PrOhDc4P/2U04qs7hhaI94NmrWBDto2O OKHezveursISPEFZ+FebMF5mSNwdBG0RitKm813TwoYDEKk6Dc7GV4nQHwHPVYqW 7xK2VrqU3GpEXXSgGu6dupwx/W6ID/L6gkghg01yVVwuvuNOrCDqWTv5EM++9Ydg 5SPBP2Nvc3CQr/Q71WU8uQueTmtQoQanZC8an/CBzRO2nA8HDBDaXfQ+dgkP/U8l QfM9TJbFgbg9s+gwboL9UwnFmDtNNRDFPEYU8Ij9q+VDW4LEodErrVVO2NSwVhG4 A8KlkUO6N/pHRTjWnERHXUS/kCUM7BRoOum+KjMUdz3SO6iSuZFaKUein7R2fld4 iV+ichP+DpnkdSpPtgTcFYUeGM1QWfBij+9owloCE4k1pr08hS8eYWxReZ9rsVGN 43ZBZg/ia41RhojfNDtAK0ntXhak7t5DIiDpi9OO7pvCtU6aYxZxzFu+C9UiCcZ3 zPHDxHkCVEjbSdrbd6AhkOIbQ9BKk9pab0iya+B3JSJTFensxYkLhAbYkmDgXiPA 8+pySykkmogBJjsiKBbANlz+5c0etMnjTpd9jBzBuagKahfpZndHtCL8VlA2Blhh d7KORcCf1PCEoqALoj0NXhi7IxF9KrbonpQcFspWV4zFSdhBkj5O8wkR10J5q4zG 4iJt7/bmYoWO/dbRTjbr =eFoM -----END PGP SIGNATURE----- Merge tag 'tegra-for-4.8-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into next/drivers soc/tegra: Changes for v4.8-rc1 Contains fixes and cleanups to the PMC driver, as well as some fixes for the generic PM domain support and some prep work to support PCIe on 64- bit ARM. * tag 'tegra-for-4.8-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux: soc/tegra: Stub out PCIe IRQ workaround on 64-bit ARM soc/tegra: pmc: Enable XUSB partitions on boot soc/tegra: pmc: Initialise power partitions early soc/tegra: pmc: Add specific error messages soc/tegra: pmc: Use whitespace more consistently soc/tegra: pmc: Don't probe PMC if early initialisation fails soc/tegra: pmc: Add missing of_node_put() soc/tegra: pmc: Ensure mutex is always initialised soc/tegra: pmc: Don't populate SoC data until register space is mapped soc/tegra: pmc: Fix early initialisation of PMC soc/tegra: pmc: Ensure powergate is available when powering on soc/tegra: pmc: Initialise resets associated with a power partition soc/tegra: pmc: Use register definitions instead of magic values Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
commit
358c79174a
|
@ -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)
|
||||
|
@ -399,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);
|
||||
|
||||
|
@ -436,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);
|
||||
|
||||
|
@ -540,6 +551,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;
|
||||
|
@ -638,9 +652,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;
|
||||
}
|
||||
|
@ -722,13 +737,14 @@ static int tegra_powergate_of_get_clks(struct tegra_powergate *pg,
|
|||
err:
|
||||
while (i--)
|
||||
clk_put(pg->clks[i]);
|
||||
|
||||
kfree(pg->clks);
|
||||
|
||||
return 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;
|
||||
|
@ -748,6 +764,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;
|
||||
|
@ -757,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;
|
||||
|
@ -765,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
|
||||
|
@ -788,31 +818,64 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
|
|||
pg->genpd.power_on = tegra_genpd_power_on;
|
||||
pg->pmc = pmc;
|
||||
|
||||
if (tegra_powergate_of_get_clks(pg, np))
|
||||
goto set_available;
|
||||
|
||||
if (tegra_powergate_of_get_resets(pg, np))
|
||||
goto remove_clks;
|
||||
|
||||
off = !tegra_powergate_is_powered(pg->id);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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]);
|
||||
|
||||
kfree(pg->resets);
|
||||
|
||||
remove_clks:
|
||||
while (pg->num_clks--)
|
||||
clk_put(pg->clks[pg->num_clks]);
|
||||
|
||||
kfree(pg->clks);
|
||||
|
||||
set_available:
|
||||
|
@ -820,16 +883,20 @@ 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)
|
||||
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;
|
||||
|
||||
|
@ -1205,6 +1272,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;
|
||||
|
@ -1242,8 +1317,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;
|
||||
|
@ -1477,10 +1550,11 @@ 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;
|
||||
|
||||
mutex_init(&pmc->powergates_lock);
|
||||
|
||||
np = of_find_matching_node_and_match(NULL, tegra_pmc_match, &match);
|
||||
if (!np) {
|
||||
/*
|
||||
|
@ -1515,39 +1589,40 @@ 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;
|
||||
}
|
||||
|
||||
pmc->soc = match->data;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if (np) {
|
||||
pmc->soc = match->data;
|
||||
|
||||
mutex_init(&pmc->powergates_lock);
|
||||
tegra_powergate_init(pmc, np);
|
||||
|
||||
/*
|
||||
* 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");
|
||||
/*
|
||||
* 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");
|
||||
|
||||
value = tegra_pmc_readl(PMC_CNTRL);
|
||||
value = tegra_pmc_readl(PMC_CNTRL);
|
||||
|
||||
if (invert)
|
||||
value |= PMC_CNTRL_INTR_POLARITY;
|
||||
else
|
||||
value &= ~PMC_CNTRL_INTR_POLARITY;
|
||||
if (invert)
|
||||
value |= PMC_CNTRL_INTR_POLARITY;
|
||||
else
|
||||
value &= ~PMC_CNTRL_INTR_POLARITY;
|
||||
|
||||
tegra_pmc_writel(value, PMC_CNTRL);
|
||||
tegra_pmc_writel(value, PMC_CNTRL);
|
||||
|
||||
of_node_put(np);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#ifndef __SOC_TEGRA_CPUIDLE_H__
|
||||
#define __SOC_TEGRA_CPUIDLE_H__
|
||||
|
||||
#ifdef CONFIG_CPU_IDLE
|
||||
#if defined(CONFIG_ARM) && defined(CONFIG_CPU_IDLE)
|
||||
void tegra_cpuidle_pcie_irqs_in_use(void);
|
||||
#else
|
||||
static inline void tegra_cpuidle_pcie_irqs_in_use(void)
|
||||
|
|
Loading…
Reference in a new issue