Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 358c7917 authored by Olof Johansson's avatar Olof Johansson
Browse files

Merge tag 'tegra-for-4.8-soc' of...

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: default avatarOlof Johansson <olof@lixom.net>
parents e1d1dfc2 8582f6d1
Loading
Loading
Loading
Loading
+112 −37
Original line number Diff line number Diff line
@@ -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 @@ static int tegra_powergate_power_down(struct tegra_powergate *pg)
	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 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg,
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))
	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;
	}

	if (tegra_powergate_of_get_resets(pg, np))
	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;
	}

	off = !tegra_powergate_is_powered(pg->id);
	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 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)

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,28 +1589,26 @@ static int __init tegra_pmc_early_init(void)
		 */
		if (of_address_to_resource(np, 0, &regs) < 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(&regs));
	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 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");

@@ -1549,6 +1621,9 @@ static int __init tegra_pmc_early_init(void)

		tegra_pmc_writel(value, PMC_CNTRL);

		of_node_put(np);
	}

	return 0;
}
early_initcall(tegra_pmc_early_init);
+1 −1
Original line number Diff line number Diff line
@@ -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)