linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V3 00/17] SC7 entry and exit support for Tegra210
@ 2019-06-18  7:46 Sowjanya Komatineni
  2019-06-18  7:46 ` [PATCH V3 01/17] irqchip: tegra: do not disable COP IRQ during suspend Sowjanya Komatineni
                   ` (16 more replies)
  0 siblings, 17 replies; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18  7:46 UTC (permalink / raw)
  To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, skomatineni, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

This patch series includes Tegra210 deepsleep support with RTC alarm
wake event.

This series also includes save and restore of PLLs, clocks, OSC contexts
for deepsleep exit to normal operation.

This patch series doesn't support 100% suspend/resume to allow fully
functional state upon resume and we are working on some more drivers suspend
and resume implementations.

[V3]: Changes between V2 & V3 are
	- V2 feedback fixes
	- GPIO restore should happen prior to Pinctrl restore to prevent
	  glitch on GPIO lines. So using resume_noirq for gpio tegra to allow
	  gpio resume prior to pinctrl resume.
	- Implemented save_context and restore_context callbacks for clock
	  plls, pll outs and dividers in corresponding drivers.
	  Note: Peripheral clocks and clock enable and reset need to be in
	  Tegra210 clock suspend/resume as they need to be in proper sequence
	  w.r.t DFLL resume for restoring CPU clock.
	- Removed gpio-tegra changes for hierarchical support to have PMC as
	  parent to GPIOs for GPIO wake event support. Thierry is working on
	  gpiolib for some cleanup before adding hierarchical support. So
	  holding on to GPIO wake support for now.

[V2] : V1 feedback fixes
	Patch 0002: This version still using syscore. Thierry suggest not to
	use syscore and waiting on suggestion from Linux Walleij for any better
	way of storing current state of pins before suspend entry and restoring
	them on resume at very early stage. So left this the same way as V1 and
	will address once I get more feedback on this.
	Also need to findout and implement proper way of forcing resume order
	between pinctrl and gpio driver.

[V1]:	Tegra210 SC7 entry and exit thru RTC wake and Power button GPIO wake
	using hierarchical IRQ with PMC as parent to GPIO.


Sowjanya Komatineni (17):
  irqchip: tegra: do not disable COP IRQ during suspend
  pinctrl: tegra: add suspend and resume support
  gpio: tegra: use resume_noirq for tegra gpio resume
  clk: tegra: save and restore divider rate
  clk: tegra: pllout: save and restore pllout context
  clk: tegra: pll: save and restore pll context
  clk: tegra: save and restore CPU and System clocks context
  clk: tegra: add support for peripheral clock suspend and resume
  clk: tegra: support for saving and restoring OSC clock context
  clk: tegra: add suspend resume support for DFLL
  clk: tegra210: support for Tegra210 clocks suspend and resume
  soc/tegra: pmc: allow support for more tegra wake
  soc/tegra: pmc: add pmc wake support for tegra210
  arm64: tegra: enable wake from deep sleep on RTC alarm.
  soc/tegra: pmc: configure core power request polarity
  soc/tegra: pmc: configure deep sleep control settings
  arm64: dts: tegra210-p2180: Jetson TX1 SC7 timings

 arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi |   7 +
 arch/arm64/boot/dts/nvidia/tegra210.dtsi       |   5 +-
 drivers/clk/tegra/clk-dfll.c                   |  78 +++++++++
 drivers/clk/tegra/clk-dfll.h                   |   2 +
 drivers/clk/tegra/clk-divider.c                |  23 +++
 drivers/clk/tegra/clk-pll-out.c                |  28 ++++
 drivers/clk/tegra/clk-pll.c                    | 115 +++++++++----
 drivers/clk/tegra/clk-tegra-fixed.c            |  14 ++
 drivers/clk/tegra/clk-tegra-super-gen4.c       |   4 -
 drivers/clk/tegra/clk-tegra210.c               | 218 ++++++++++++++++++++++++-
 drivers/clk/tegra/clk.c                        | 150 ++++++++++++++++-
 drivers/clk/tegra/clk.h                        |  29 +++-
 drivers/gpio/gpio-tegra.c                      |  17 +-
 drivers/irqchip/irq-tegra.c                    |  21 ++-
 drivers/pinctrl/tegra/pinctrl-tegra.c          |  62 +++++++
 drivers/pinctrl/tegra/pinctrl-tegra.h          |   5 +
 drivers/pinctrl/tegra/pinctrl-tegra114.c       |   1 +
 drivers/pinctrl/tegra/pinctrl-tegra124.c       |   1 +
 drivers/pinctrl/tegra/pinctrl-tegra20.c        |   1 +
 drivers/pinctrl/tegra/pinctrl-tegra210.c       |  13 ++
 drivers/pinctrl/tegra/pinctrl-tegra30.c        |   1 +
 drivers/soc/tegra/pmc.c                        | 143 +++++++++++++++-
 22 files changed, 880 insertions(+), 58 deletions(-)

-- 
2.7.4


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH V3 01/17] irqchip: tegra: do not disable COP IRQ during suspend
  2019-06-18  7:46 [PATCH V3 00/17] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
@ 2019-06-18  7:46 ` Sowjanya Komatineni
  2019-06-18  9:19   ` Marc Zyngier
  2019-06-18 10:58   ` Thierry Reding
  2019-06-18  7:46 ` [PATCH V3 02/17] pinctrl: tegra: add suspend and resume support Sowjanya Komatineni
                   ` (15 subsequent siblings)
  16 siblings, 2 replies; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18  7:46 UTC (permalink / raw)
  To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, skomatineni, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

Tegra210 platforms use sc7 entry firmware to program Tegra LP0/SC7 entry
sequence and sc7 entry firmware is run from COP/BPMP-Lite.

So, COP/BPMP-Lite still need IRQ function to finish SC7 suspend sequence
for Tegra210.

This patch has fix for leaving the COP IRQ enabled for Tegra210 during
interrupt controller suspend operation.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/irqchip/irq-tegra.c | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-tegra.c b/drivers/irqchip/irq-tegra.c
index e1f771c72fc4..cf0c07052064 100644
--- a/drivers/irqchip/irq-tegra.c
+++ b/drivers/irqchip/irq-tegra.c
@@ -44,18 +44,22 @@ static unsigned int num_ictlrs;
 
 struct tegra_ictlr_soc {
 	unsigned int num_ictlrs;
+	bool supports_sc7;
 };
 
 static const struct tegra_ictlr_soc tegra20_ictlr_soc = {
 	.num_ictlrs = 4,
+	.supports_sc7 = false,
 };
 
 static const struct tegra_ictlr_soc tegra30_ictlr_soc = {
 	.num_ictlrs = 5,
+	.supports_sc7 = false,
 };
 
 static const struct tegra_ictlr_soc tegra210_ictlr_soc = {
 	.num_ictlrs = 6,
+	.supports_sc7 = true,
 };
 
 static const struct of_device_id ictlr_matches[] = {
@@ -67,6 +71,7 @@ static const struct of_device_id ictlr_matches[] = {
 
 struct tegra_ictlr_info {
 	void __iomem *base[TEGRA_MAX_NUM_ICTLRS];
+	const struct tegra_ictlr_soc *soc;
 #ifdef CONFIG_PM_SLEEP
 	u32 cop_ier[TEGRA_MAX_NUM_ICTLRS];
 	u32 cop_iep[TEGRA_MAX_NUM_ICTLRS];
@@ -147,8 +152,19 @@ static int tegra_ictlr_suspend(void)
 		lic->cop_ier[i] = readl_relaxed(ictlr + ICTLR_COP_IER);
 		lic->cop_iep[i] = readl_relaxed(ictlr + ICTLR_COP_IEP_CLASS);
 
-		/* Disable COP interrupts */
-		writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
+		/*
+		 * AVP/COP/BPMP-Lite is the Tegra boot processor.
+		 *
+		 * Tegra210 system suspend flow uses sc7entry firmware which
+		 * is executed by COP/BPMP and it includes disabling COP IRQ,
+		 * clamping CPU rail, turning off VDD_CPU, and preparing the
+		 * system to go to SC7/LP0.
+		 *
+		 * COP/BPMP wakes up when COP IRQ is triggered and runs
+		 * sc7entry-firmware. So need to keep COP interrupt enabled.
+		 */
+		if (!lic->soc->supports_sc7)
+			writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
 
 		/* Disable CPU interrupts */
 		writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR);
@@ -339,6 +355,7 @@ static int __init tegra_ictlr_init(struct device_node *node,
 		goto out_unmap;
 	}
 
+	lic->soc = soc;
 	tegra_ictlr_syscore_init();
 
 	pr_info("%pOF: %d interrupts forwarded to %pOF\n",
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH V3 02/17] pinctrl: tegra: add suspend and resume support
  2019-06-18  7:46 [PATCH V3 00/17] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
  2019-06-18  7:46 ` [PATCH V3 01/17] irqchip: tegra: do not disable COP IRQ during suspend Sowjanya Komatineni
@ 2019-06-18  7:46 ` Sowjanya Komatineni
  2019-06-18  9:22   ` Dmitry Osipenko
  2019-06-18 11:31   ` Thierry Reding
  2019-06-18  7:46 ` [PATCH V3 03/17] gpio: tegra: use resume_noirq for tegra gpio resume Sowjanya Komatineni
                   ` (14 subsequent siblings)
  16 siblings, 2 replies; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18  7:46 UTC (permalink / raw)
  To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, skomatineni, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

This patch adds suspend and resume support for Tegra pinctrl driver
and registers them to syscore so the pinmux settings are restored
before the devices resume.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/pinctrl/tegra/pinctrl-tegra.c    | 62 ++++++++++++++++++++++++++++++++
 drivers/pinctrl/tegra/pinctrl-tegra.h    |  5 +++
 drivers/pinctrl/tegra/pinctrl-tegra114.c |  1 +
 drivers/pinctrl/tegra/pinctrl-tegra124.c |  1 +
 drivers/pinctrl/tegra/pinctrl-tegra20.c  |  1 +
 drivers/pinctrl/tegra/pinctrl-tegra210.c | 13 +++++++
 drivers/pinctrl/tegra/pinctrl-tegra30.c  |  1 +
 7 files changed, 84 insertions(+)

diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
index 34596b246578..ceced30d8bd1 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
@@ -20,11 +20,16 @@
 #include <linux/pinctrl/pinmux.h>
 #include <linux/pinctrl/pinconf.h>
 #include <linux/slab.h>
+#include <linux/syscore_ops.h>
 
 #include "../core.h"
 #include "../pinctrl-utils.h"
 #include "pinctrl-tegra.h"
 
+#define EMMC2_PAD_CFGPADCTRL_0			0x1c8
+#define EMMC4_PAD_CFGPADCTRL_0			0x1e0
+#define EMMC_DPD_PARKING			(0x1fff << 14)
+
 static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 reg)
 {
 	return readl(pmx->regs[bank] + reg);
@@ -619,6 +624,48 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
 			pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
 		}
 	}
+
+	if (pmx->soc->has_park_padcfg) {
+		val = pmx_readl(pmx, 0, EMMC2_PAD_CFGPADCTRL_0);
+		val &= ~EMMC_DPD_PARKING;
+		pmx_writel(pmx, val, 0, EMMC2_PAD_CFGPADCTRL_0);
+
+		val = pmx_readl(pmx, 0, EMMC4_PAD_CFGPADCTRL_0);
+		val &= ~EMMC_DPD_PARKING;
+		pmx_writel(pmx, val, 0, EMMC4_PAD_CFGPADCTRL_0);
+	}
+}
+
+int __maybe_unused tegra_pinctrl_suspend(struct device *dev)
+{
+	struct tegra_pmx *pmx = dev_get_drvdata(dev);
+	u32 *backup_regs = pmx->backup_regs;
+	u32 *regs;
+	int i, j;
+
+	for (i = 0; i < pmx->nbanks; i++) {
+		regs = pmx->regs[i];
+		for (j = 0; j < pmx->reg_bank_size[i] / 4; j++)
+			*backup_regs++ = readl(regs++);
+	}
+
+	return pinctrl_force_sleep(pmx->pctl);
+}
+
+int __maybe_unused tegra_pinctrl_resume(struct device *dev)
+{
+	struct tegra_pmx *pmx = dev_get_drvdata(dev);
+	u32 *backup_regs = pmx->backup_regs;
+	u32 *regs;
+	int i, j;
+
+	for (i = 0; i < pmx->nbanks; i++) {
+		regs = pmx->regs[i];
+		for (j = 0; j < pmx->reg_bank_size[i] / 4; j++)
+			writel(*backup_regs++, regs++);
+	}
+
+	return 0;
 }
 
 static bool gpio_node_has_range(const char *compatible)
@@ -645,6 +692,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
 	int i;
 	const char **group_pins;
 	int fn, gn, gfn;
+	unsigned long backup_regs_size = 0;
 
 	pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
 	if (!pmx)
@@ -697,6 +745,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
 		if (!res)
 			break;
+		backup_regs_size += resource_size(res);
 	}
 	pmx->nbanks = i;
 
@@ -705,11 +754,24 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
 	if (!pmx->regs)
 		return -ENOMEM;
 
+	pmx->reg_bank_size = devm_kcalloc(&pdev->dev, pmx->nbanks,
+					  sizeof(*pmx->reg_bank_size),
+					  GFP_KERNEL);
+	if (!pmx->reg_bank_size)
+		return -ENOMEM;
+
+	pmx->backup_regs = devm_kzalloc(&pdev->dev, backup_regs_size,
+					GFP_KERNEL);
+	if (!pmx->backup_regs)
+		return -ENOMEM;
+
 	for (i = 0; i < pmx->nbanks; i++) {
 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
 		pmx->regs[i] = devm_ioremap_resource(&pdev->dev, res);
 		if (IS_ERR(pmx->regs[i]))
 			return PTR_ERR(pmx->regs[i]);
+
+		pmx->reg_bank_size[i] = resource_size(res);
 	}
 
 	pmx->pctl = devm_pinctrl_register(&pdev->dev, &tegra_pinctrl_desc, pmx);
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
index 287702660783..d63e472ee0e1 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra.h
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
@@ -17,6 +17,8 @@ struct tegra_pmx {
 
 	int nbanks;
 	void __iomem **regs;
+	size_t *reg_bank_size;
+	u32 *backup_regs;
 };
 
 enum tegra_pinconf_param {
@@ -191,8 +193,11 @@ struct tegra_pinctrl_soc_data {
 	bool hsm_in_mux;
 	bool schmitt_in_mux;
 	bool drvtype_in_mux;
+	bool has_park_padcfg;
 };
 
 int tegra_pinctrl_probe(struct platform_device *pdev,
 			const struct tegra_pinctrl_soc_data *soc_data);
+int __maybe_unused tegra_pinctrl_suspend(struct device *dev);
+int __maybe_unused tegra_pinctrl_resume(struct device *dev);
 #endif
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra114.c b/drivers/pinctrl/tegra/pinctrl-tegra114.c
index 762151f17a88..06ea8164df9d 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra114.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra114.c
@@ -1841,6 +1841,7 @@ static const struct tegra_pinctrl_soc_data tegra114_pinctrl = {
 	.hsm_in_mux = false,
 	.schmitt_in_mux = false,
 	.drvtype_in_mux = false,
+	.has_park_padcfg = false,
 };
 
 static int tegra114_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra124.c b/drivers/pinctrl/tegra/pinctrl-tegra124.c
index 930c43758c92..abc8fe92d154 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra124.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra124.c
@@ -2053,6 +2053,7 @@ static const struct tegra_pinctrl_soc_data tegra124_pinctrl = {
 	.hsm_in_mux = false,
 	.schmitt_in_mux = false,
 	.drvtype_in_mux = false,
+	.has_park_padcfg = false,
 };
 
 static int tegra124_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra20.c b/drivers/pinctrl/tegra/pinctrl-tegra20.c
index 4b7837e38fb5..993b82cbfba7 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra20.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra20.c
@@ -2223,6 +2223,7 @@ static const struct tegra_pinctrl_soc_data tegra20_pinctrl = {
 	.hsm_in_mux = false,
 	.schmitt_in_mux = false,
 	.drvtype_in_mux = false,
+	.has_park_padcfg = false,
 };
 
 static const char *cdev1_parents[] = {
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra210.c b/drivers/pinctrl/tegra/pinctrl-tegra210.c
index 0b56ad5c9c1c..10e8a2ec8094 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra210.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra210.c
@@ -1555,6 +1555,7 @@ static const struct tegra_pinctrl_soc_data tegra210_pinctrl = {
 	.hsm_in_mux = true,
 	.schmitt_in_mux = true,
 	.drvtype_in_mux = true,
+	.has_park_padcfg = true,
 };
 
 static int tegra210_pinctrl_probe(struct platform_device *pdev)
@@ -1562,6 +1563,17 @@ static int tegra210_pinctrl_probe(struct platform_device *pdev)
 	return tegra_pinctrl_probe(pdev, &tegra210_pinctrl);
 }
 
+#ifdef CONFIG_PM_SLEEP
+static const struct dev_pm_ops tegra_pinctrl_pm = {
+	.suspend = &tegra_pinctrl_suspend,
+	.resume = &tegra_pinctrl_resume
+};
+
+#define TEGRA_PINCTRL_PM	(&tegra_pinctrl_pm)
+#else
+#define TEGRA_PINCTRL_PM	NULL
+#endif
+
 static const struct of_device_id tegra210_pinctrl_of_match[] = {
 	{ .compatible = "nvidia,tegra210-pinmux", },
 	{ },
@@ -1571,6 +1583,7 @@ static struct platform_driver tegra210_pinctrl_driver = {
 	.driver = {
 		.name = "tegra210-pinctrl",
 		.of_match_table = tegra210_pinctrl_of_match,
+		.pm    = TEGRA_PINCTRL_PM,
 	},
 	.probe = tegra210_pinctrl_probe,
 };
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra30.c b/drivers/pinctrl/tegra/pinctrl-tegra30.c
index 610124c3d192..779ee40e5f21 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra30.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra30.c
@@ -2476,6 +2476,7 @@ static const struct tegra_pinctrl_soc_data tegra30_pinctrl = {
 	.hsm_in_mux = false,
 	.schmitt_in_mux = false,
 	.drvtype_in_mux = false,
+	.has_park_padcfg = false,
 };
 
 static int tegra30_pinctrl_probe(struct platform_device *pdev)
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH V3 03/17] gpio: tegra: use resume_noirq for tegra gpio resume
  2019-06-18  7:46 [PATCH V3 00/17] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
  2019-06-18  7:46 ` [PATCH V3 01/17] irqchip: tegra: do not disable COP IRQ during suspend Sowjanya Komatineni
  2019-06-18  7:46 ` [PATCH V3 02/17] pinctrl: tegra: add suspend and resume support Sowjanya Komatineni
@ 2019-06-18  7:46 ` Sowjanya Komatineni
  2019-06-18 11:39   ` Thierry Reding
  2019-06-18  7:46 ` [PATCH V3 04/17] clk: tegra: save and restore divider rate Sowjanya Komatineni
                   ` (13 subsequent siblings)
  16 siblings, 1 reply; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18  7:46 UTC (permalink / raw)
  To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, skomatineni, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

During SC7 resume, PARKED bit clear from the pinmux registers may
cause a glitch on the GPIO lines.

So, Tegra GPIOs restore should happen prior to restoring Tegra pinmux
to keep the GPIO lines in a known good state prior to clearing PARKED
bit.

This patch has fix for this by moving Tegra GPIO restore to happen
during resume_noirq.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/gpio/gpio-tegra.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index f57bfc07ae22..f3c58c597ab9 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -410,7 +410,7 @@ static void tegra_gpio_irq_handler(struct irq_desc *desc)
 }
 
 #ifdef CONFIG_PM_SLEEP
-static int tegra_gpio_resume(struct device *dev)
+static int tegra_gpio_resume_noirq(struct device *dev)
 {
 	struct tegra_gpio_info *tgi = dev_get_drvdata(dev);
 	unsigned long flags;
@@ -506,6 +506,15 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
 
 	return irq_set_irq_wake(bank->irq, enable);
 }
+
+static const struct dev_pm_ops tegra_gpio_pm_ops = {
+	.suspend = &tegra_gpio_suspend,
+	.resume_noirq = &tegra_gpio_resume_noirq
+};
+
+#define TEGRA_GPIO_PM	(&tegra_gpio_pm_ops)
+#else
+#define TEGRA_GPIO_PM	NULL
 #endif
 
 #ifdef	CONFIG_DEBUG_FS
@@ -553,10 +562,6 @@ static inline void tegra_gpio_debuginit(struct tegra_gpio_info *tgi)
 
 #endif
 
-static const struct dev_pm_ops tegra_gpio_pm_ops = {
-	SET_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume)
-};
-
 static int tegra_gpio_probe(struct platform_device *pdev)
 {
 	struct tegra_gpio_info *tgi;
@@ -706,7 +711,7 @@ static const struct of_device_id tegra_gpio_of_match[] = {
 static struct platform_driver tegra_gpio_driver = {
 	.driver		= {
 		.name	= "tegra-gpio",
-		.pm	= &tegra_gpio_pm_ops,
+		.pm	= TEGRA_GPIO_PM,
 		.of_match_table = tegra_gpio_of_match,
 	},
 	.probe		= tegra_gpio_probe,
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH V3 04/17] clk: tegra: save and restore divider rate
  2019-06-18  7:46 [PATCH V3 00/17] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (2 preceding siblings ...)
  2019-06-18  7:46 ` [PATCH V3 03/17] gpio: tegra: use resume_noirq for tegra gpio resume Sowjanya Komatineni
@ 2019-06-18  7:46 ` Sowjanya Komatineni
  2019-06-18 11:40   ` Thierry Reding
  2019-06-18  7:46 ` [PATCH V3 05/17] clk: tegra: pllout: save and restore pllout context Sowjanya Komatineni
                   ` (12 subsequent siblings)
  16 siblings, 1 reply; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18  7:46 UTC (permalink / raw)
  To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, skomatineni, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

This patch implements context save and restore for clock divider.

During system suspend, core power goes off and looses the settings
of the Tegra CAR controller registers.

So during suspend entry the context of clock divider is saved and
on resume context is restored back for normal operation.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/clk/tegra/clk-divider.c | 23 +++++++++++++++++++++++
 drivers/clk/tegra/clk.h         |  2 ++
 2 files changed, 25 insertions(+)

diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c
index e76731fb7d69..ecb7ff9ce97e 100644
--- a/drivers/clk/tegra/clk-divider.c
+++ b/drivers/clk/tegra/clk-divider.c
@@ -109,10 +109,33 @@ static int clk_frac_div_set_rate(struct clk_hw *hw, unsigned long rate,
 	return 0;
 }
 
+static int clk_divider_save_context(struct clk_hw *hw)
+{
+	struct tegra_clk_frac_div *divider = to_clk_frac_div(hw);
+	struct clk_hw *parent = clk_hw_get_parent(hw);
+	unsigned long parent_rate = clk_hw_get_rate(parent);
+
+	divider->rate = clk_frac_div_recalc_rate(hw, parent_rate);
+
+	return 0;
+}
+
+static void clk_divider_restore_context(struct clk_hw *hw)
+{
+	struct tegra_clk_frac_div *divider = to_clk_frac_div(hw);
+	struct clk_hw *parent = clk_hw_get_parent(hw);
+	unsigned long parent_rate = clk_hw_get_rate(parent);
+
+	if (clk_frac_div_set_rate(hw, divider->rate, parent_rate) < 0)
+		WARN_ON(1);
+}
+
 const struct clk_ops tegra_clk_frac_div_ops = {
 	.recalc_rate = clk_frac_div_recalc_rate,
 	.set_rate = clk_frac_div_set_rate,
 	.round_rate = clk_frac_div_round_rate,
+	.save_context = clk_divider_save_context,
+	.restore_context = clk_divider_restore_context,
 };
 
 struct clk *tegra_clk_register_divider(const char *name,
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 905bf1096558..83623f5f55f3 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -42,6 +42,7 @@ struct clk *tegra_clk_register_sync_source(const char *name,
  * @width:	width of the divider bit field
  * @frac_width:	width of the fractional bit field
  * @lock:	register lock
+ * @rate:	rate during suspend and resume
  *
  * Flags:
  * TEGRA_DIVIDER_ROUND_UP - This flags indicates to round up the divider value.
@@ -62,6 +63,7 @@ struct tegra_clk_frac_div {
 	u8		width;
 	u8		frac_width;
 	spinlock_t	*lock;
+	unsigned long	rate;
 };
 
 #define to_clk_frac_div(_hw) container_of(_hw, struct tegra_clk_frac_div, hw)
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH V3 05/17] clk: tegra: pllout: save and restore pllout context
  2019-06-18  7:46 [PATCH V3 00/17] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (3 preceding siblings ...)
  2019-06-18  7:46 ` [PATCH V3 04/17] clk: tegra: save and restore divider rate Sowjanya Komatineni
@ 2019-06-18  7:46 ` Sowjanya Komatineni
  2019-06-18 11:41   ` Thierry Reding
  2019-06-18  7:46 ` [PATCH V3 06/17] clk: tegra: pll: save and restore pll context Sowjanya Komatineni
                   ` (11 subsequent siblings)
  16 siblings, 1 reply; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18  7:46 UTC (permalink / raw)
  To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, skomatineni, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

This patch implements save and restore of pllout context.

During system suspend, core power goes off and looses the settings
of the Tegra CAR controller registers.

So during suspend entry the state of pllout is saved and on resume
it is restored back to have pllout in same state as before suspend.

pllout rate is saved and restore in clock divider so it will be at
same rate as before suspend when pllout state is restored.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/clk/tegra/clk-pll-out.c | 28 ++++++++++++++++++++++++++++
 drivers/clk/tegra/clk.h         |  3 +++
 2 files changed, 31 insertions(+)

diff --git a/drivers/clk/tegra/clk-pll-out.c b/drivers/clk/tegra/clk-pll-out.c
index 35f2bf00e1e6..52d140379ce3 100644
--- a/drivers/clk/tegra/clk-pll-out.c
+++ b/drivers/clk/tegra/clk-pll-out.c
@@ -69,10 +69,38 @@ static void clk_pll_out_disable(struct clk_hw *hw)
 		spin_unlock_irqrestore(pll_out->lock, flags);
 }
 
+static int tegra_clk_pll_out_save_context(struct clk_hw *hw)
+{
+	struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
+
+	if (!strcmp(__clk_get_name(hw->clk), "pll_re_out1"))
+		pll_out->pllout_ctx = readl_relaxed(pll_out->reg);
+	else
+		pll_out->pllout_ctx = clk_hw_get_rate(hw);
+
+	return 0;
+}
+
+static void tegra_clk_pll_out_restore_context(struct clk_hw *hw)
+{
+	struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
+
+	if (!strcmp(__clk_get_name(hw->clk), "pll_re_out1")) {
+		writel_relaxed(pll_out->pllout_ctx, pll_out->reg);
+	} else {
+		if (!__clk_get_enable_count(hw->clk))
+			clk_pll_out_disable(hw);
+		else
+			clk_pll_out_enable(hw);
+	}
+}
+
 const struct clk_ops tegra_clk_pll_out_ops = {
 	.is_enabled = clk_pll_out_is_enabled,
 	.enable = clk_pll_out_enable,
 	.disable = clk_pll_out_disable,
+	.save_context = tegra_clk_pll_out_save_context,
+	.restore_context = tegra_clk_pll_out_restore_context,
 };
 
 struct clk *tegra_clk_register_pll_out(const char *name,
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 83623f5f55f3..b47f373c35ad 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -439,6 +439,8 @@ struct clk *tegra_clk_register_pllu_tegra210(const char *name,
  * @rst_bit_idx:	bit to reset PLL divider
  * @lock:		register lock
  * @flags:		hardware-specific flags
+ * @pllout_ctx:		pllout context to save and restore during suspend
+ *			and resume
  */
 struct tegra_clk_pll_out {
 	struct clk_hw	hw;
@@ -447,6 +449,7 @@ struct tegra_clk_pll_out {
 	u8		rst_bit_idx;
 	spinlock_t	*lock;
 	u8		flags;
+	unsigned int	pllout_ctx;
 };
 
 #define to_clk_pll_out(_hw) container_of(_hw, struct tegra_clk_pll_out, hw)
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH V3 06/17] clk: tegra: pll: save and restore pll context
  2019-06-18  7:46 [PATCH V3 00/17] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (4 preceding siblings ...)
  2019-06-18  7:46 ` [PATCH V3 05/17] clk: tegra: pllout: save and restore pllout context Sowjanya Komatineni
@ 2019-06-18  7:46 ` Sowjanya Komatineni
  2019-06-18 11:45   ` Thierry Reding
  2019-06-25 20:46   ` Stephen Boyd
  2019-06-18  7:46 ` [PATCH V3 07/17] clk: tegra: save and restore CPU and System clocks context Sowjanya Komatineni
                   ` (10 subsequent siblings)
  16 siblings, 2 replies; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18  7:46 UTC (permalink / raw)
  To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, skomatineni, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

This patch implements save and restore of pll context.

During system suspend, core power goes off and looses the settings
of the Tegra CAR controller registers.

So during suspend entry pll rate is stored and on resume it is
restored back along with its state.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/clk/tegra/clk-pll.c | 115 ++++++++++++++++++++++++++++++++------------
 drivers/clk/tegra/clk.h     |   6 ++-
 2 files changed, 88 insertions(+), 33 deletions(-)

diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 1583f5fc992f..4b0ed8fc6268 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -1008,6 +1008,54 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw,
 	return rate;
 }
 
+void tegra_clk_sync_state_pll(struct clk_hw *hw)
+{
+	if (!__clk_get_enable_count(hw->clk))
+		clk_pll_disable(hw);
+	else
+		clk_pll_enable(hw);
+}
+
+static int tegra_clk_pll_save_context(struct clk_hw *hw)
+{
+	struct tegra_clk_pll *pll = to_clk_pll(hw);
+
+	pll->rate = clk_hw_get_rate(hw);
+
+	if (!strcmp(__clk_get_name(hw->clk), "pll_mb"))
+		pll->pllbase_ctx = pll_readl_base(pll);
+	else if (!strcmp(__clk_get_name(hw->clk), "pll_re_vco"))
+		pll->pllbase_ctx = pll_readl_base(pll) & (0xf << 16);
+
+	return 0;
+}
+
+static void tegra_clk_pll_restore_context(struct clk_hw *hw)
+{
+	struct tegra_clk_pll *pll = to_clk_pll(hw);
+	u32 val;
+
+	if (clk_pll_is_enabled(hw))
+		return;
+
+	if (!strcmp(__clk_get_name(hw->clk), "pll_mb")) {
+		pll_writel_base(pll->pllbase_ctx, pll);
+	} else if (!strcmp(__clk_get_name(hw->clk), "pll_re_vco")) {
+		val = pll_readl_base(pll);
+		val &= ~(0xf << 16);
+		pll_writel_base(pll->pllbase_ctx | val, pll);
+	}
+
+	if (pll->params->set_defaults)
+		pll->params->set_defaults(pll);
+
+	clk_set_rate(hw->clk, pll->rate);
+
+	/* do not sync pllx state here. pllx is sync'd after dfll resume */
+	if (strcmp(__clk_get_name(hw->clk), "pll_x"))
+		tegra_clk_sync_state_pll(hw);
+}
+
 const struct clk_ops tegra_clk_pll_ops = {
 	.is_enabled = clk_pll_is_enabled,
 	.enable = clk_pll_enable,
@@ -1015,6 +1063,8 @@ const struct clk_ops tegra_clk_pll_ops = {
 	.recalc_rate = clk_pll_recalc_rate,
 	.round_rate = clk_pll_round_rate,
 	.set_rate = clk_pll_set_rate,
+	.save_context = tegra_clk_pll_save_context,
+	.restore_context = tegra_clk_pll_restore_context,
 };
 
 const struct clk_ops tegra_clk_plle_ops = {
@@ -1802,6 +1852,27 @@ static int clk_pllu_tegra114_enable(struct clk_hw *hw)
 
 	return ret;
 }
+
+static void _clk_plle_tegra_init_parent(struct tegra_clk_pll *pll)
+{
+	u32 val, val_aux;
+
+	/* ensure parent is set to pll_ref */
+	val = pll_readl_base(pll);
+	val_aux = pll_readl(pll->params->aux_reg, pll);
+
+	if (val & PLL_BASE_ENABLE) {
+		if ((val_aux & PLLE_AUX_PLLRE_SEL) ||
+		    (val_aux & PLLE_AUX_PLLP_SEL))
+			WARN(1, "pll_e enabled with unsupported parent %s\n",
+			     (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" :
+			     "pll_re_vco");
+	} else {
+		val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL);
+		pll_writel(val_aux, pll->params->aux_reg, pll);
+		fence_udelay(1, pll->clk_base);
+	}
+}
 #endif
 
 static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base,
@@ -2214,27 +2285,12 @@ struct clk *tegra_clk_register_plle_tegra114(const char *name,
 {
 	struct tegra_clk_pll *pll;
 	struct clk *clk;
-	u32 val, val_aux;
 
 	pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
 	if (IS_ERR(pll))
 		return ERR_CAST(pll);
 
-	/* ensure parent is set to pll_re_vco */
-
-	val = pll_readl_base(pll);
-	val_aux = pll_readl(pll_params->aux_reg, pll);
-
-	if (val & PLL_BASE_ENABLE) {
-		if ((val_aux & PLLE_AUX_PLLRE_SEL) ||
-			(val_aux & PLLE_AUX_PLLP_SEL))
-			WARN(1, "pll_e enabled with unsupported parent %s\n",
-			  (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" :
-					"pll_re_vco");
-	} else {
-		val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL);
-		pll_writel(val_aux, pll_params->aux_reg, pll);
-	}
+	_clk_plle_tegra_init_parent(pll);
 
 	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
 				      &tegra_clk_plle_tegra114_ops);
@@ -2276,6 +2332,8 @@ static const struct clk_ops tegra_clk_pllss_ops = {
 	.recalc_rate = clk_pll_recalc_rate,
 	.round_rate = clk_pll_ramp_round_rate,
 	.set_rate = clk_pllxc_set_rate,
+	.save_context = tegra_clk_pll_save_context,
+	.restore_context = tegra_clk_pll_restore_context,
 };
 
 struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
@@ -2520,11 +2578,19 @@ static void clk_plle_tegra210_disable(struct clk_hw *hw)
 		spin_unlock_irqrestore(pll->lock, flags);
 }
 
+static void tegra_clk_plle_t210_restore_context(struct clk_hw *hw)
+{
+	struct tegra_clk_pll *pll = to_clk_pll(hw);
+
+	_clk_plle_tegra_init_parent(pll);
+}
+
 static const struct clk_ops tegra_clk_plle_tegra210_ops = {
 	.is_enabled =  clk_plle_tegra210_is_enabled,
 	.enable = clk_plle_tegra210_enable,
 	.disable = clk_plle_tegra210_disable,
 	.recalc_rate = clk_pll_recalc_rate,
+	.restore_context = tegra_clk_plle_t210_restore_context,
 };
 
 struct clk *tegra_clk_register_plle_tegra210(const char *name,
@@ -2535,27 +2601,12 @@ struct clk *tegra_clk_register_plle_tegra210(const char *name,
 {
 	struct tegra_clk_pll *pll;
 	struct clk *clk;
-	u32 val, val_aux;
 
 	pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
 	if (IS_ERR(pll))
 		return ERR_CAST(pll);
 
-	/* ensure parent is set to pll_re_vco */
-
-	val = pll_readl_base(pll);
-	val_aux = pll_readl(pll_params->aux_reg, pll);
-
-	if (val & PLLE_BASE_ENABLE) {
-		if ((val_aux & PLLE_AUX_PLLRE_SEL) ||
-			(val_aux & PLLE_AUX_PLLP_SEL))
-			WARN(1, "pll_e enabled with unsupported parent %s\n",
-			  (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" :
-					"pll_re_vco");
-	} else {
-		val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL);
-		pll_writel(val_aux, pll_params->aux_reg, pll);
-	}
+	_clk_plle_tegra_init_parent(pll);
 
 	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
 				      &tegra_clk_plle_tegra210_ops);
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index b47f373c35ad..581deb4f3ac0 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -310,6 +310,8 @@ struct tegra_clk_pll_params {
  * @pmc:	address of PMC, required to read override bits
  * @lock:	register lock
  * @params:	PLL parameters
+ * @rate:	rate during system suspend and resume
+ * @pllbase_ctx: pll base register value during suspend and resume
  */
 struct tegra_clk_pll {
 	struct clk_hw	hw;
@@ -317,6 +319,8 @@ struct tegra_clk_pll {
 	void __iomem	*pmc;
 	spinlock_t	*lock;
 	struct tegra_clk_pll_params	*params;
+	unsigned long	rate;
+	unsigned int	pllbase_ctx;
 };
 
 #define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw)
@@ -834,7 +838,7 @@ u16 tegra_pll_get_fixed_mdiv(struct clk_hw *hw, unsigned long input_rate);
 int tegra_pll_p_div_to_hw(struct tegra_clk_pll *pll, u8 p_div);
 int div_frac_get(unsigned long rate, unsigned parent_rate, u8 width,
 		 u8 frac_width, u8 flags);
-
+void tegra_clk_sync_state_pll(struct clk_hw *hw);
 
 /* Combined read fence with delay */
 #define fence_udelay(delay, reg)	\
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH V3 07/17] clk: tegra: save and restore CPU and System clocks context
  2019-06-18  7:46 [PATCH V3 00/17] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (5 preceding siblings ...)
  2019-06-18  7:46 ` [PATCH V3 06/17] clk: tegra: pll: save and restore pll context Sowjanya Komatineni
@ 2019-06-18  7:46 ` Sowjanya Komatineni
  2019-06-18 11:48   ` Thierry Reding
  2019-06-18  7:46 ` [PATCH V3 08/17] clk: tegra: add support for peripheral clock suspend and resume Sowjanya Komatineni
                   ` (9 subsequent siblings)
  16 siblings, 1 reply; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18  7:46 UTC (permalink / raw)
  To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, skomatineni, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

During system suspend state, core power goes off and looses all the
CAR controller register settings.

This patch creates APIs for saving and restoring the context of Tegra
CPUG, CPULP and SCLK.

CPU and System clock context includes
- CPUG, CPULP, and SCLK burst policy settings for clock sourcea of all
  their normal states.
- SCLK divisor and System clock rate for restoring SCLK, AHB and APB
  rates on resume.
- OSC_DIV settings which are used as reference clock input to some PLLs.
- SPARE_REG and CLK_MASK settings.

These APIs are used in Tegra210 clock driver during suspend and resume
operation.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/clk/tegra/clk-tegra-super-gen4.c |  4 --
 drivers/clk/tegra/clk.c                  | 80 ++++++++++++++++++++++++++++++++
 drivers/clk/tegra/clk.h                  | 14 ++++++
 3 files changed, 94 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c
index cdfe7c9697e1..ed69ec4d883e 100644
--- a/drivers/clk/tegra/clk-tegra-super-gen4.c
+++ b/drivers/clk/tegra/clk-tegra-super-gen4.c
@@ -19,10 +19,6 @@
 #define PLLX_MISC2 0x514
 #define PLLX_MISC3 0x518
 
-#define CCLKG_BURST_POLICY 0x368
-#define CCLKLP_BURST_POLICY 0x370
-#define SCLK_BURST_POLICY 0x028
-#define SYSTEM_CLK_RATE 0x030
 #define SCLK_DIVIDER 0x2c
 
 static DEFINE_SPINLOCK(sysrate_lock);
diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
index 573e3c967ae1..26690663157a 100644
--- a/drivers/clk/tegra/clk.c
+++ b/drivers/clk/tegra/clk.c
@@ -70,6 +70,12 @@ static struct clk **clks;
 static int clk_num;
 static struct clk_onecell_data clk_data;
 
+static u32 cclkg_burst_policy_ctx[2];
+static u32 cclklp_burst_policy_ctx[2];
+static u32 sclk_burst_policy_ctx[2];
+static u32 sys_clk_divisor_ctx, system_rate_ctx;
+static u32 spare_ctx, misc_clk_enb_ctx, clk_arm_ctx;
+
 /* Handlers for SoC-specific reset lines */
 static int (*special_reset_assert)(unsigned long);
 static int (*special_reset_deassert)(unsigned long);
@@ -199,6 +205,80 @@ const struct tegra_clk_periph_regs *get_reg_bank(int clkid)
 	}
 }
 
+void tegra_cclkg_burst_policy_save_context(void)
+{
+	int i;
+
+	for (i = 0; i < BURST_POLICY_REG_SIZE; i++)
+		cclkg_burst_policy_ctx[i] = readl_relaxed(clk_base +
+							  CCLKG_BURST_POLICY +
+							  (i * 4));
+}
+
+void tegra_cclkg_burst_policy_restore_context(void)
+{
+	int i;
+
+	for (i = 0; i < BURST_POLICY_REG_SIZE; i++)
+		writel_relaxed(cclkg_burst_policy_ctx[i],
+			       clk_base + CCLKG_BURST_POLICY + (i * 4));
+
+	fence_udelay(2, clk_base);
+}
+
+void tegra_sclk_cclklp_burst_policy_save_context(void)
+{
+	int i;
+
+	for (i = 0; i < BURST_POLICY_REG_SIZE; i++) {
+		cclklp_burst_policy_ctx[i] = readl_relaxed(clk_base +
+							  CCLKLP_BURST_POLICY +
+							  (i * 4));
+
+		sclk_burst_policy_ctx[i] = readl_relaxed(clk_base +
+							  SCLK_BURST_POLICY +
+							  (i * 4));
+	}
+
+	sys_clk_divisor_ctx = readl_relaxed(clk_base + SYS_CLK_DIV);
+	system_rate_ctx = readl_relaxed(clk_base + SYSTEM_CLK_RATE);
+	spare_ctx = readl_relaxed(clk_base + SPARE_REG0);
+	misc_clk_enb_ctx = readl_relaxed(clk_base + MISC_CLK_ENB);
+	clk_arm_ctx = readl_relaxed(clk_base + CLK_MASK_ARM);
+}
+
+void tegra_sclk_cpulp_burst_policy_restore_context(void)
+{
+	int i;
+	u32 val;
+
+	/*
+	 * resume SCLK and CPULP clocks
+	 * for SCLk, set safe dividers values first and then restore source
+	 * and dividers
+	 */
+
+	writel_relaxed(0x1, clk_base + SYSTEM_CLK_RATE);
+	val = readl_relaxed(clk_base + SYS_CLK_DIV);
+	if (val < sys_clk_divisor_ctx)
+		writel_relaxed(sys_clk_divisor_ctx, clk_base + SYS_CLK_DIV);
+
+	fence_udelay(2, clk_base);
+
+	for (i = 0; i < BURST_POLICY_REG_SIZE; i++) {
+		writel_relaxed(cclklp_burst_policy_ctx[i],
+			       clk_base + CCLKLP_BURST_POLICY + (i * 4));
+		writel_relaxed(sclk_burst_policy_ctx[i],
+			       clk_base + SCLK_BURST_POLICY + (i * 4));
+	}
+
+	writel_relaxed(sys_clk_divisor_ctx, clk_base + SYS_CLK_DIV);
+	writel_relaxed(system_rate_ctx, clk_base + SYSTEM_CLK_RATE);
+	writel_relaxed(spare_ctx, clk_base + SPARE_REG0);
+	writel_relaxed(misc_clk_enb_ctx, clk_base + MISC_CLK_ENB);
+	writel_relaxed(clk_arm_ctx, clk_base + CLK_MASK_ARM);
+}
+
 struct clk ** __init tegra_clk_init(void __iomem *regs, int num, int banks)
 {
 	clk_base = regs;
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 581deb4f3ac0..c8f8a23096e2 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -10,6 +10,16 @@
 #include <linux/clkdev.h>
 #include <linux/delay.h>
 
+#define SCLK_BURST_POLICY	0x28
+#define SYSTEM_CLK_RATE		0x30
+#define CLK_MASK_ARM		0x44
+#define MISC_CLK_ENB		0x48
+#define CCLKG_BURST_POLICY	0x368
+#define CCLKLP_BURST_POLICY	0x370
+#define SYS_CLK_DIV		0x400
+#define SPARE_REG0 		0x55c
+#define BURST_POLICY_REG_SIZE	2
+
 /**
  * struct tegra_clk_sync_source - external clock source from codec
  *
@@ -839,6 +849,10 @@ int tegra_pll_p_div_to_hw(struct tegra_clk_pll *pll, u8 p_div);
 int div_frac_get(unsigned long rate, unsigned parent_rate, u8 width,
 		 u8 frac_width, u8 flags);
 void tegra_clk_sync_state_pll(struct clk_hw *hw);
+void tegra_cclkg_burst_policy_save_context(void);
+void tegra_cclkg_burst_policy_restore_context(void);
+void tegra_sclk_cclklp_burst_policy_save_context(void);
+void tegra_sclk_cpulp_burst_policy_restore_context(void);
 
 /* Combined read fence with delay */
 #define fence_udelay(delay, reg)	\
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH V3 08/17] clk: tegra: add support for peripheral clock suspend and resume
  2019-06-18  7:46 [PATCH V3 00/17] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (6 preceding siblings ...)
  2019-06-18  7:46 ` [PATCH V3 07/17] clk: tegra: save and restore CPU and System clocks context Sowjanya Komatineni
@ 2019-06-18  7:46 ` Sowjanya Komatineni
  2019-06-18 11:50   ` Thierry Reding
  2019-06-18  7:46 ` [PATCH V3 09/17] clk: tegra: support for saving and restoring OSC clock context Sowjanya Komatineni
                   ` (8 subsequent siblings)
  16 siblings, 1 reply; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18  7:46 UTC (permalink / raw)
  To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, skomatineni, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

This patch creates APIs to save and restore the state of all
peripheral clocks reset and enables.

These APIs are invoked by Tegra210 clock driver during suspend and
resume to save the peripheral clocks state before suspend and to
restore them on resume.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/clk/tegra/clk.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/clk/tegra/clk.h |  3 +++
 2 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
index 26690663157a..bd3b46c5f941 100644
--- a/drivers/clk/tegra/clk.c
+++ b/drivers/clk/tegra/clk.c
@@ -70,6 +70,7 @@ static struct clk **clks;
 static int clk_num;
 static struct clk_onecell_data clk_data;
 
+static u32 *periph_ctx;
 static u32 cclkg_burst_policy_ctx[2];
 static u32 cclklp_burst_policy_ctx[2];
 static u32 sclk_burst_policy_ctx[2];
@@ -279,6 +280,63 @@ void tegra_sclk_cpulp_burst_policy_restore_context(void)
 	writel_relaxed(clk_arm_ctx, clk_base + CLK_MASK_ARM);
 }
 
+void tegra_clk_periph_suspend(void __iomem *clk_base)
+{
+	int i, idx;
+
+	idx = 0;
+	for (i = 0; i < periph_banks; i++, idx++)
+		periph_ctx[idx] =
+			readl_relaxed(clk_base + periph_regs[i].rst_reg);
+
+	for (i = 0; i < periph_banks; i++, idx++)
+		periph_ctx[idx] =
+			readl_relaxed(clk_base + periph_regs[i].enb_reg);
+}
+
+void tegra_clk_periph_force_on(u32 *clks_on, int count, void __iomem *clk_base)
+{
+	int i;
+
+	WARN_ON(count != periph_banks);
+
+	for (i = 0; i < count; i++)
+		writel_relaxed(clks_on[i], clk_base + periph_regs[i].enb_reg);
+}
+
+void tegra_clk_periph_resume(void __iomem *clk_base)
+{
+	int i, idx;
+
+	idx = 0;
+	for (i = 0; i < periph_banks; i++, idx++)
+		writel_relaxed(periph_ctx[idx],
+			       clk_base + periph_regs[i].rst_reg);
+
+	/* ensure all resets have propagated */
+	fence_udelay(2, clk_base);
+	tegra_read_chipid();
+
+	for (i = 0; i < periph_banks; i++, idx++)
+		writel_relaxed(periph_ctx[idx],
+			       clk_base + periph_regs[i].enb_reg);
+
+	/* ensure all enables have propagated */
+	fence_udelay(2, clk_base);
+	tegra_read_chipid();
+}
+
+static int tegra_clk_suspend_ctx_init(int banks)
+{
+	int err = 0;
+
+	periph_ctx = kcalloc(2 * banks, sizeof(*periph_ctx), GFP_KERNEL);
+	if (!periph_ctx)
+		err = -ENOMEM;
+
+	return err;
+}
+
 struct clk ** __init tegra_clk_init(void __iomem *regs, int num, int banks)
 {
 	clk_base = regs;
@@ -295,11 +353,21 @@ struct clk ** __init tegra_clk_init(void __iomem *regs, int num, int banks)
 	periph_banks = banks;
 
 	clks = kcalloc(num, sizeof(struct clk *), GFP_KERNEL);
-	if (!clks)
+	if (!clks) {
 		kfree(periph_clk_enb_refcnt);
+		return NULL;
+	}
 
 	clk_num = num;
 
+	if (IS_ENABLED(CONFIG_PM_SLEEP)) {
+		if (tegra_clk_suspend_ctx_init(banks)) {
+			kfree(periph_clk_enb_refcnt);
+			kfree(clks);
+			return NULL;
+		}
+	}
+
 	return clks;
 }
 
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index c8f8a23096e2..a354cacae5a6 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -853,6 +853,9 @@ void tegra_cclkg_burst_policy_save_context(void);
 void tegra_cclkg_burst_policy_restore_context(void);
 void tegra_sclk_cclklp_burst_policy_save_context(void);
 void tegra_sclk_cpulp_burst_policy_restore_context(void);
+void tegra_clk_periph_suspend(void __iomem *clk_base);
+void tegra_clk_periph_resume(void __iomem *clk_base);
+void tegra_clk_periph_force_on(u32 *clks_on, int count, void __iomem *clk_base);
 
 /* Combined read fence with delay */
 #define fence_udelay(delay, reg)	\
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH V3 09/17] clk: tegra: support for saving and restoring OSC clock context
  2019-06-18  7:46 [PATCH V3 00/17] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (7 preceding siblings ...)
  2019-06-18  7:46 ` [PATCH V3 08/17] clk: tegra: add support for peripheral clock suspend and resume Sowjanya Komatineni
@ 2019-06-18  7:46 ` Sowjanya Komatineni
  2019-06-18 11:51   ` Thierry Reding
  2019-06-18  7:46 ` [PATCH V3 10/17] clk: tegra: add suspend resume support for DFLL Sowjanya Komatineni
                   ` (7 subsequent siblings)
  16 siblings, 1 reply; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18  7:46 UTC (permalink / raw)
  To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, skomatineni, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

This patch adds support for storing OSC clock frequency and the
drive-strength during OSC clock init and creates an API to restore
OSC control register value from the saved context.

This API is invoked by Tegra210 clock driver during system resume
to restore the  OSC clock settings.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/clk/tegra/clk-tegra-fixed.c | 14 ++++++++++++++
 drivers/clk/tegra/clk.h             |  1 +
 2 files changed, 15 insertions(+)

diff --git a/drivers/clk/tegra/clk-tegra-fixed.c b/drivers/clk/tegra/clk-tegra-fixed.c
index 8d91b2b191cf..e8df0ccbffd0 100644
--- a/drivers/clk/tegra/clk-tegra-fixed.c
+++ b/drivers/clk/tegra/clk-tegra-fixed.c
@@ -17,7 +17,10 @@
 #define OSC_CTRL			0x50
 #define OSC_CTRL_OSC_FREQ_SHIFT		28
 #define OSC_CTRL_PLL_REF_DIV_SHIFT	26
+#define OSC_CTRL_MASK			(0x3f2 |	\
+					(0xf << OSC_CTRL_OSC_FREQ_SHIFT))
 
+static u32 osc_ctrl_ctx;
 int __init tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks,
 			      unsigned long *input_freqs, unsigned int num,
 			      unsigned int clk_m_div, unsigned long *osc_freq,
@@ -29,6 +32,7 @@ int __init tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks,
 	unsigned osc_idx;
 
 	val = readl_relaxed(clk_base + OSC_CTRL);
+	osc_ctrl_ctx = val & OSC_CTRL_MASK;
 	osc_idx = val >> OSC_CTRL_OSC_FREQ_SHIFT;
 
 	if (osc_idx < num)
@@ -96,3 +100,13 @@ void __init tegra_fixed_clk_init(struct tegra_clk *tegra_clks)
 		*dt_clk = clk;
 	}
 }
+
+void tegra_clk_osc_resume(void __iomem *clk_base)
+{
+	u32 val;
+
+	val = readl_relaxed(clk_base + OSC_CTRL) & ~OSC_CTRL_MASK;
+	val |= osc_ctrl_ctx;
+	writel_relaxed(val, clk_base + OSC_CTRL);
+	fence_udelay(2, clk_base);
+}
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index a354cacae5a6..bb34a19aaf26 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -856,6 +856,7 @@ void tegra_sclk_cpulp_burst_policy_restore_context(void);
 void tegra_clk_periph_suspend(void __iomem *clk_base);
 void tegra_clk_periph_resume(void __iomem *clk_base);
 void tegra_clk_periph_force_on(u32 *clks_on, int count, void __iomem *clk_base);
+void tegra_clk_osc_resume(void __iomem *clk_base);
 
 /* Combined read fence with delay */
 #define fence_udelay(delay, reg)	\
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH V3 10/17] clk: tegra: add suspend resume support for DFLL
  2019-06-18  7:46 [PATCH V3 00/17] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (8 preceding siblings ...)
  2019-06-18  7:46 ` [PATCH V3 09/17] clk: tegra: support for saving and restoring OSC clock context Sowjanya Komatineni
@ 2019-06-18  7:46 ` Sowjanya Komatineni
  2019-06-18 11:59   ` Thierry Reding
  2019-06-18  7:46 ` [PATCH V3 11/17] clk: tegra210: support for Tegra210 clocks suspend and resume Sowjanya Komatineni
                   ` (6 subsequent siblings)
  16 siblings, 1 reply; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18  7:46 UTC (permalink / raw)
  To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, skomatineni, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

This patch creates APIs for supporting Tegra210 clock driver to
perform DFLL suspend and resume operation.

During suspend, DFLL mode is saved and on resume Tegra210 clock driver
invokes DFLL resume API to re-initialize DFLL to enable target device
clock in open loop mode or closed loop mode.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/clk/tegra/clk-dfll.c | 78 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/tegra/clk-dfll.h |  2 ++
 2 files changed, 80 insertions(+)

diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c
index f8688c2ddf1a..a1f37cf99b00 100644
--- a/drivers/clk/tegra/clk-dfll.c
+++ b/drivers/clk/tegra/clk-dfll.c
@@ -277,6 +277,7 @@ struct tegra_dfll {
 	unsigned long			dvco_rate_min;
 
 	enum dfll_ctrl_mode		mode;
+	enum dfll_ctrl_mode		resume_mode;
 	enum dfll_tune_range		tune_range;
 	struct dentry			*debugfs_dir;
 	struct clk_hw			dfll_clk_hw;
@@ -1864,6 +1865,83 @@ static int dfll_fetch_common_params(struct tegra_dfll *td)
 }
 
 /*
+ * tegra_dfll_suspend
+ * @pdev: DFLL instance
+ *
+ * dfll controls clock/voltage to other devices, including CPU. Therefore,
+ * dfll driver pm suspend callback does not stop cl-dvfs operations.
+ */
+void tegra_dfll_suspend(struct platform_device *pdev)
+{
+	struct tegra_dfll *td = dev_get_drvdata(&pdev->dev);
+
+	if (!td)
+		return;
+
+	if (td->mode <= DFLL_DISABLED)
+		return;
+
+	td->resume_mode = td->mode;
+	switch (td->mode) {
+	case DFLL_CLOSED_LOOP:
+		dfll_set_mode(td, DFLL_CLOSED_LOOP);
+		dfll_set_frequency_request(td, &td->last_req);
+
+		dfll_unlock(td);
+		break;
+	default:
+		break;
+	}
+}
+
+/**
+ * tegra_dfll_resume - reprogram the DFLL after context-loss
+ * @pdev: DFLL instance
+ *
+ * Re-initialize and enable target device clock in open loop mode. Called
+ * directly from SoC clock resume syscore operation. Closed loop will be
+ * re-entered in platform syscore ops as well after CPU clock source is
+ * switched to DFLL in open loop.
+ */
+void tegra_dfll_resume(struct platform_device *pdev, bool on_dfll)
+{
+	struct tegra_dfll *td = dev_get_drvdata(&pdev->dev);
+
+	if (!td)
+		return;
+
+	if (on_dfll) {
+		if (td->resume_mode == DFLL_CLOSED_LOOP)
+			dfll_lock(td);
+		td->resume_mode = DFLL_DISABLED;
+		return;
+	}
+
+	reset_control_deassert(td->dvco_rst);
+
+	pm_runtime_get(td->dev);
+
+	/* Re-init DFLL */
+	dfll_init_out_if(td);
+	dfll_set_default_params(td);
+	dfll_set_open_loop_config(td);
+
+	pm_runtime_put(td->dev);
+
+	/* Restore last request and mode up to open loop */
+	switch (td->resume_mode) {
+	case DFLL_CLOSED_LOOP:
+	case DFLL_OPEN_LOOP:
+		dfll_set_mode(td, DFLL_OPEN_LOOP);
+		if (td->pmu_if == TEGRA_DFLL_PMU_I2C)
+			dfll_i2c_set_output_enabled(td, false);
+		break;
+	default:
+		break;
+	}
+}
+
+/*
  * API exported to per-SoC platform drivers
  */
 
diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h
index 1b14ebe7268b..c21fc2061a20 100644
--- a/drivers/clk/tegra/clk-dfll.h
+++ b/drivers/clk/tegra/clk-dfll.h
@@ -40,6 +40,8 @@ struct tegra_dfll_soc_data {
 int tegra_dfll_register(struct platform_device *pdev,
 			struct tegra_dfll_soc_data *soc);
 struct tegra_dfll_soc_data *tegra_dfll_unregister(struct platform_device *pdev);
+void tegra_dfll_suspend(struct platform_device *pdev);
+void tegra_dfll_resume(struct platform_device *pdev, bool on_dfll);
 int tegra_dfll_runtime_suspend(struct device *dev);
 int tegra_dfll_runtime_resume(struct device *dev);
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH V3 11/17] clk: tegra210: support for Tegra210 clocks suspend and resume
  2019-06-18  7:46 [PATCH V3 00/17] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (9 preceding siblings ...)
  2019-06-18  7:46 ` [PATCH V3 10/17] clk: tegra: add suspend resume support for DFLL Sowjanya Komatineni
@ 2019-06-18  7:46 ` Sowjanya Komatineni
  2019-06-18 12:16   ` Thierry Reding
  2019-06-18  7:46 ` [PATCH V3 12/17] soc/tegra: pmc: allow support for more tegra wake Sowjanya Komatineni
                   ` (5 subsequent siblings)
  16 siblings, 1 reply; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18  7:46 UTC (permalink / raw)
  To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, skomatineni, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

This patch adds system suspend and resume support for Tegra210
clocks.

All the CAR controller settings are lost on suspend when core power
goes off.

This patch has implementation for saving and restoring all the PLLs
and clocks context during system suspend and resume to have the
system back to operating state.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/clk/tegra/clk-tegra210.c | 218 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 211 insertions(+), 7 deletions(-)

diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index e1ba62d2b1a0..c34d92e871f4 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -9,10 +9,12 @@
 #include <linux/clkdev.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_platform.h>
 #include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/mutex.h>
 #include <linux/clk/tegra.h>
+#include <linux/syscore_ops.h>
 #include <dt-bindings/clock/tegra210-car.h>
 #include <dt-bindings/reset/tegra210-car.h>
 #include <linux/iopoll.h>
@@ -20,6 +22,7 @@
 #include <soc/tegra/pmc.h>
 
 #include "clk.h"
+#include "clk-dfll.h"
 #include "clk-id.h"
 
 /*
@@ -36,6 +39,8 @@
 #define CLK_SOURCE_LA 0x1f8
 #define CLK_SOURCE_SDMMC2 0x154
 #define CLK_SOURCE_SDMMC4 0x164
+#define CLK_OUT_ENB_Y 0x298
+#define CLK_ENB_PLLP_OUT_CPU BIT(31)
 
 #define PLLC_BASE 0x80
 #define PLLC_OUT 0x84
@@ -225,6 +230,7 @@
 
 #define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2a8
 #define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2ac
+#define CPU_SOFTRST_CTRL 0x380
 
 #define LVL2_CLK_GATE_OVRA 0xf8
 #define LVL2_CLK_GATE_OVRC 0x3a0
@@ -2820,6 +2826,7 @@ static int tegra210_enable_pllu(void)
 	struct tegra_clk_pll_freq_table *fentry;
 	struct tegra_clk_pll pllu;
 	u32 reg;
+	int ret;
 
 	for (fentry = pll_u_freq_table; fentry->input_rate; fentry++) {
 		if (fentry->input_rate == pll_ref_freq)
@@ -2836,7 +2843,7 @@ static int tegra210_enable_pllu(void)
 	reg = readl_relaxed(clk_base + pllu.params->ext_misc_reg[0]);
 	reg &= ~BIT(pllu.params->iddq_bit_idx);
 	writel_relaxed(reg, clk_base + pllu.params->ext_misc_reg[0]);
-	udelay(5);
+	fence_udelay(5, clk_base);
 
 	reg = readl_relaxed(clk_base + PLLU_BASE);
 	reg &= ~GENMASK(20, 0);
@@ -2844,13 +2851,13 @@ static int tegra210_enable_pllu(void)
 	reg |= fentry->n << 8;
 	reg |= fentry->p << 16;
 	writel(reg, clk_base + PLLU_BASE);
-	udelay(1);
+	fence_udelay(1, clk_base);
 	reg |= PLL_ENABLE;
 	writel(reg, clk_base + PLLU_BASE);
+	fence_udelay(1, clk_base);
 
-	readl_relaxed_poll_timeout_atomic(clk_base + PLLU_BASE, reg,
-					  reg & PLL_BASE_LOCK, 2, 1000);
-	if (!(reg & PLL_BASE_LOCK)) {
+	ret = tegra210_wait_for_mask(&pllu, PLLU_BASE, PLL_BASE_LOCK);
+	if (ret) {
 		pr_err("Timed out waiting for PLL_U to lock\n");
 		return -ETIMEDOUT;
 	}
@@ -2890,12 +2897,12 @@ static int tegra210_init_pllu(void)
 		reg = readl_relaxed(clk_base + XUSB_PLL_CFG0);
 		reg &= ~XUSB_PLL_CFG0_PLLU_LOCK_DLY_MASK;
 		writel_relaxed(reg, clk_base + XUSB_PLL_CFG0);
-		udelay(1);
+		fence_udelay(1, clk_base);
 
 		reg = readl_relaxed(clk_base + PLLU_HW_PWRDN_CFG0);
 		reg |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
 		writel_relaxed(reg, clk_base + PLLU_HW_PWRDN_CFG0);
-		udelay(1);
+		fence_udelay(1, clk_base);
 
 		reg = readl_relaxed(clk_base + PLLU_BASE);
 		reg &= ~PLLU_BASE_CLKENABLE_USB;
@@ -3282,6 +3289,188 @@ static void tegra210_disable_cpu_clock(u32 cpu)
 }
 
 #ifdef CONFIG_PM_SLEEP
+static u32 cpu_softrst_ctx[3];
+static struct platform_device *dfll_pdev;
+static u32 *periph_clk_src_ctx;
+struct periph_source_bank {
+	u32 start;
+	u32 end;
+};
+
+static struct periph_source_bank periph_srcs[] = {
+	[0] = {
+		.start = 0x100,
+		.end = 0x198,
+	},
+	[1] = {
+		.start = 0x1a0,
+		.end = 0x1f8,
+	},
+	[2] = {
+		.start = 0x3b4,
+		.end = 0x42c,
+	},
+	[3] = {
+		.start = 0x49c,
+		.end = 0x4b4,
+	},
+	[4] = {
+		.start = 0x560,
+		.end = 0x564,
+	},
+	[5] = {
+		.start = 0x600,
+		.end = 0x678,
+	},
+	[6] = {
+		.start = 0x694,
+		.end = 0x6a0,
+	},
+	[7] = {
+		.start = 0x6b8,
+		.end = 0x718,
+	},
+};
+
+/* This array lists the valid clocks for each periph clk bank */
+static u32 periph_clks_on[] = {
+	0xdcd7dff9,
+	0x87d1f3e7,
+	0xf3fed3fa,
+	0xffc18cfb,
+	0x793fb7ff,
+	0x3fe66fff,
+	0xfc1fc7ff,
+};
+
+static struct platform_device *dfll_pdev;
+#define car_readl(_base, _off) readl_relaxed(clk_base + (_base) + ((_off) * 4))
+#define car_writel(_val, _base, _off) \
+		writel_relaxed(_val, clk_base + (_base) + ((_off) * 4))
+
+static u32 * __init tegra210_init_suspend_ctx(void)
+{
+	int i, size = 0;
+
+	for (i = 0; i < ARRAY_SIZE(periph_srcs); i++)
+		size += periph_srcs[i].end - periph_srcs[i].start + 4;
+
+	periph_clk_src_ctx = kmalloc(size, GFP_KERNEL);
+
+	return periph_clk_src_ctx;
+}
+
+static int tegra210_clk_suspend(void)
+{
+	int i;
+	unsigned long off;
+	struct device_node *node;
+	u32 *clk_rst_ctx = periph_clk_src_ctx;
+	u32 val;
+
+	tegra_cclkg_burst_policy_save_context();
+
+	if (!dfll_pdev) {
+		node = of_find_compatible_node(NULL, NULL,
+					       "nvidia,tegra210-dfll");
+		if (node)
+			dfll_pdev = of_find_device_by_node(node);
+		of_node_put(node);
+		if (!dfll_pdev)
+			pr_err("dfll node not found. no suspend for dfll\n");
+	}
+
+	if (dfll_pdev)
+		tegra_dfll_suspend(dfll_pdev);
+
+	/* Enable PLLP_OUT_CPU after dfll suspend */
+	val = car_readl(CLK_OUT_ENB_Y, 0);
+	val |= CLK_ENB_PLLP_OUT_CPU;
+	car_writel(val, CLK_OUT_ENB_Y, 0);
+
+	tegra_clk_periph_suspend(clk_base);
+
+	for (i = 0; i < ARRAY_SIZE(periph_srcs); i++)
+		for (off = periph_srcs[i].start; off <= periph_srcs[i].end;
+		     off += 4)
+			*clk_rst_ctx++ = car_readl(off, 0);
+
+	tegra_sclk_cclklp_burst_policy_save_context();
+
+	for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
+		cpu_softrst_ctx[i] = car_readl(CPU_SOFTRST_CTRL, i);
+
+	clk_save_context();
+
+	return 0;
+}
+
+static void tegra210_clk_resume(void)
+{
+	int i;
+	unsigned long off;
+	u32 val;
+	u32 *clk_rst_ctx = periph_clk_src_ctx;
+	struct clk_hw *parent;
+	struct clk *clk;
+
+	for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
+		car_writel(cpu_softrst_ctx[i], CPU_SOFTRST_CTRL, i);
+
+	tegra_clk_osc_resume(clk_base);
+
+	/*
+	 * restore all the plls before configuring clocks and resetting
+	 * the devices.
+	 */
+	tegra210_init_pllu();
+	tegra_sclk_cpulp_burst_policy_restore_context();
+	clk_restore_context();
+
+	/* enable all clocks before configuring clock sources */
+	tegra_clk_periph_force_on(periph_clks_on, ARRAY_SIZE(periph_clks_on),
+				  clk_base);
+	/* wait for all writes to happen to have all the clocks enabled */
+	wmb();
+	fence_udelay(2, clk_base);
+
+	/* restore all the devices clock sources */
+	for (i = 0; i < ARRAY_SIZE(periph_srcs); i++)
+		for (off = periph_srcs[i].start; off <= periph_srcs[i].end;
+		     off += 4)
+			car_writel(*clk_rst_ctx++, off, 0);
+
+	/* propagate and restore resets, restore clock state */
+	fence_udelay(5, clk_base);
+	tegra_clk_periph_resume(clk_base);
+
+	/*
+	 * restore CPUG clocks:
+	 * - enable DFLL in open loop mode
+	 * - switch CPUG to DFLL clock source
+	 * - close DFLL loop
+	 * - sync PLLX state
+	 */
+	if (dfll_pdev)
+		tegra_dfll_resume(dfll_pdev, false);
+
+	tegra_cclkg_burst_policy_restore_context();
+	fence_udelay(2, clk_base);
+
+	if (dfll_pdev)
+		tegra_dfll_resume(dfll_pdev, true);
+
+	parent = clk_hw_get_parent(__clk_get_hw(clks[TEGRA210_CLK_CCLK_G]));
+	clk = clks[TEGRA210_CLK_PLL_X];
+	if (parent != __clk_get_hw(clk))
+		tegra_clk_sync_state_pll(__clk_get_hw(clk));
+
+	/* Disable PLL_OUT_CPU after DFLL resume */
+	val = car_readl(CLK_OUT_ENB_Y, 0);
+	val &= ~CLK_ENB_PLLP_OUT_CPU;
+	car_writel(val, CLK_OUT_ENB_Y, 0);
+}
+
 static void tegra210_cpu_clock_suspend(void)
 {
 	/* switch coresite to clk_m, save off original source */
@@ -3295,8 +3484,20 @@ static void tegra210_cpu_clock_resume(void)
 	writel(tegra210_cpu_clk_sctx.clk_csite_src,
 				clk_base + CLK_SOURCE_CSITE);
 }
+#else
+#define tegra210_clk_suspend	NULL
+#define tegra210_clk_resume	NULL
+static inline u32 *tegra210_init_suspend_ctx(void)
+{
+	return NULL;
+}
 #endif
 
+static struct syscore_ops tegra_clk_syscore_ops = {
+	.suspend = tegra210_clk_suspend,
+	.resume = tegra210_clk_resume,
+};
+
 static struct tegra_cpu_car_ops tegra210_cpu_car_ops = {
 	.wait_for_reset	= tegra210_wait_cpu_in_reset,
 	.disable_clock	= tegra210_disable_cpu_clock,
@@ -3580,5 +3781,8 @@ static void __init tegra210_clock_init(struct device_node *np)
 	tegra210_mbist_clk_init();
 
 	tegra_cpu_car_ops = &tegra210_cpu_car_ops;
+
+	if (tegra210_init_suspend_ctx())
+		register_syscore_ops(&tegra_clk_syscore_ops);
 }
 CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH V3 12/17] soc/tegra: pmc: allow support for more tegra wake
  2019-06-18  7:46 [PATCH V3 00/17] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (10 preceding siblings ...)
  2019-06-18  7:46 ` [PATCH V3 11/17] clk: tegra210: support for Tegra210 clocks suspend and resume Sowjanya Komatineni
@ 2019-06-18  7:46 ` Sowjanya Komatineni
  2019-06-18  9:26   ` Marc Zyngier
  2019-06-18  7:46 ` [PATCH V3 13/17] soc/tegra: pmc: add pmc wake support for tegra210 Sowjanya Komatineni
                   ` (4 subsequent siblings)
  16 siblings, 1 reply; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18  7:46 UTC (permalink / raw)
  To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, skomatineni, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

This patch allows to create separate irq_set_wake and irq_set_type
implementations for different tegra designs PMC that has different
wake models which require difference wake registers and different
programming sequence.

AOWAKE model support is available for Tegra186 and Tegra194 only
and it resides within PMC and supports tiered wake architecture.

Tegra210 and prior tegra designs uses PMC directly to receive wake
events and coordinate the wake sequence.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/soc/tegra/pmc.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index edd4fe06810f..e87f29a35fcf 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -226,6 +226,8 @@ struct tegra_pmc_soc {
 	void (*setup_irq_polarity)(struct tegra_pmc *pmc,
 				   struct device_node *np,
 				   bool invert);
+	int (*irq_set_wake)(struct irq_data *data, unsigned int on);
+	int (*irq_set_type)(struct irq_data *data, unsigned int type);
 
 	const char * const *reset_sources;
 	unsigned int num_reset_sources;
@@ -1919,7 +1921,7 @@ static const struct irq_domain_ops tegra_pmc_irq_domain_ops = {
 	.alloc = tegra_pmc_irq_alloc,
 };
 
-static int tegra_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
+static int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
 {
 	struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
 	unsigned int offset, bit;
@@ -1951,7 +1953,7 @@ static int tegra_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
 	return 0;
 }
 
-static int tegra_pmc_irq_set_type(struct irq_data *data, unsigned int type)
+static int tegra186_pmc_irq_set_type(struct irq_data *data, unsigned int type)
 {
 	struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
 	u32 value;
@@ -2005,8 +2007,10 @@ static int tegra_pmc_irq_init(struct tegra_pmc *pmc)
 	pmc->irq.irq_unmask = irq_chip_unmask_parent;
 	pmc->irq.irq_eoi = irq_chip_eoi_parent;
 	pmc->irq.irq_set_affinity = irq_chip_set_affinity_parent;
-	pmc->irq.irq_set_type = tegra_pmc_irq_set_type;
-	pmc->irq.irq_set_wake = tegra_pmc_irq_set_wake;
+	if (pmc->soc->irq_set_type)
+		pmc->irq.irq_set_type = pmc->soc->irq_set_type;
+	if (pmc->soc->irq_set_wake)
+		pmc->irq.irq_set_wake = pmc->soc->irq_set_wake;
 
 	pmc->domain = irq_domain_add_hierarchy(parent, 0, 96, pmc->dev->of_node,
 					       &tegra_pmc_irq_domain_ops, pmc);
@@ -2679,6 +2683,8 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
 	.regs = &tegra186_pmc_regs,
 	.init = NULL,
 	.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
+	.irq_set_wake = tegra186_pmc_irq_set_wake,
+	.irq_set_type = tegra186_pmc_irq_set_type,
 	.reset_sources = tegra186_reset_sources,
 	.num_reset_sources = ARRAY_SIZE(tegra186_reset_sources),
 	.reset_levels = tegra186_reset_levels,
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH V3 13/17] soc/tegra: pmc: add pmc wake support for tegra210
  2019-06-18  7:46 [PATCH V3 00/17] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (11 preceding siblings ...)
  2019-06-18  7:46 ` [PATCH V3 12/17] soc/tegra: pmc: allow support for more tegra wake Sowjanya Komatineni
@ 2019-06-18  7:46 ` Sowjanya Komatineni
  2019-06-18  7:46 ` [PATCH V3 14/17] arm64: tegra: enable wake from deep sleep on RTC alarm Sowjanya Komatineni
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18  7:46 UTC (permalink / raw)
  To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, skomatineni, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

This patch implements PMC wakeup sequence for Tegra210 and defines
common used RTC alarm wake event.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/soc/tegra/pmc.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 111 insertions(+)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index e87f29a35fcf..603fc3bd73f5 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -57,6 +57,12 @@
 #define  PMC_CNTRL_SYSCLK_OE		BIT(11) /* system clock enable */
 #define  PMC_CNTRL_SYSCLK_POLARITY	BIT(10) /* sys clk polarity */
 #define  PMC_CNTRL_MAIN_RST		BIT(4)
+#define  PMC_CNTRL_LATCH_WAKEUPS	BIT(5)
+
+#define PMC_WAKE_MASK			0x0c
+#define PMC_WAKE_LEVEL			0x10
+#define PMC_WAKE_STATUS			0x14
+#define PMC_SW_WAKE_STATUS		0x18
 
 #define DPD_SAMPLE			0x020
 #define  DPD_SAMPLE_ENABLE		BIT(0)
@@ -87,6 +93,11 @@
 
 #define PMC_SCRATCH41			0x140
 
+#define PMC_WAKE2_MASK			0x160
+#define PMC_WAKE2_LEVEL			0x164
+#define PMC_WAKE2_STATUS		0x168
+#define PMC_SW_WAKE2_STATUS		0x16c
+
 #define PMC_SENSOR_CTRL			0x1b0
 #define  PMC_SENSOR_CTRL_SCRATCH_WRITE	BIT(2)
 #define  PMC_SENSOR_CTRL_ENABLE_RST	BIT(1)
@@ -1921,6 +1932,55 @@ static const struct irq_domain_ops tegra_pmc_irq_domain_ops = {
 	.alloc = tegra_pmc_irq_alloc,
 };
 
+static int tegra210_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
+{
+	struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
+	unsigned int offset, bit;
+	u32 value;
+
+	if (data->hwirq == ULONG_MAX)
+		return 0;
+
+	offset = data->hwirq / 32;
+	bit = data->hwirq % 32;
+
+	/*
+	 * latch wakeups to SW_WAKE_STATUS register to capture events
+	 * that would not make it into wakeup event register during LP0 exit.
+	 */
+	value = tegra_pmc_readl(pmc, PMC_CNTRL);
+	value |= PMC_CNTRL_LATCH_WAKEUPS;
+	tegra_pmc_writel(pmc, value, PMC_CNTRL);
+	udelay(120);
+
+	value &= ~PMC_CNTRL_LATCH_WAKEUPS;
+	tegra_pmc_writel(pmc, value, PMC_CNTRL);
+	udelay(120);
+
+	tegra_pmc_writel(pmc, 0, PMC_SW_WAKE_STATUS);
+	tegra_pmc_writel(pmc, 0, PMC_SW_WAKE2_STATUS);
+
+	tegra_pmc_writel(pmc, 0, PMC_WAKE_STATUS);
+	tegra_pmc_writel(pmc, 0, PMC_WAKE2_STATUS);
+
+	/* enable PMC wake */
+	if (data->hwirq >= 32)
+		offset = PMC_WAKE2_MASK;
+	else
+		offset = PMC_WAKE_MASK;
+
+	value = tegra_pmc_readl(pmc, offset);
+
+	if (on)
+		value |= 1 << bit;
+	else
+		value &= ~(1 << bit);
+
+	tegra_pmc_writel(pmc, value, offset);
+
+	return 0;
+}
+
 static int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
 {
 	struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
@@ -1953,6 +2013,49 @@ static int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
 	return 0;
 }
 
+static int tegra210_pmc_irq_set_type(struct irq_data *data, unsigned int type)
+{
+	struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
+	unsigned int offset, bit;
+	u32 value;
+
+	if (data->hwirq == ULONG_MAX)
+		return 0;
+
+	offset = data->hwirq / 32;
+	bit = data->hwirq % 32;
+
+	if (data->hwirq >= 32)
+		offset = PMC_WAKE2_LEVEL;
+	else
+		offset = PMC_WAKE_LEVEL;
+
+	value = tegra_pmc_readl(pmc, offset);
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+	case IRQ_TYPE_LEVEL_HIGH:
+		value |= 1 << bit;
+		break;
+
+	case IRQ_TYPE_EDGE_FALLING:
+	case IRQ_TYPE_LEVEL_LOW:
+		value &= ~(1 << bit);
+		break;
+
+	case IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING:
+		value ^= 1 << bit;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	tegra_pmc_writel(pmc, value, offset);
+
+	return 0;
+}
+
 static int tegra186_pmc_irq_set_type(struct irq_data *data, unsigned int type)
 {
 	struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
@@ -2541,6 +2644,10 @@ static const struct pinctrl_pin_desc tegra210_pin_descs[] = {
 	TEGRA210_IO_PAD_TABLE(TEGRA_IO_PIN_DESC)
 };
 
+static const struct tegra_wake_event tegra210_wake_events[] = {
+	TEGRA_WAKE_IRQ("rtc", 16, 2),
+};
+
 static const struct tegra_pmc_soc tegra210_pmc_soc = {
 	.num_powergates = ARRAY_SIZE(tegra210_powergates),
 	.powergates = tegra210_powergates,
@@ -2558,10 +2665,14 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
 	.regs = &tegra20_pmc_regs,
 	.init = tegra20_pmc_init,
 	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
+	.irq_set_wake = tegra210_pmc_irq_set_wake,
+	.irq_set_type = tegra210_pmc_irq_set_type,
 	.reset_sources = tegra210_reset_sources,
 	.num_reset_sources = ARRAY_SIZE(tegra210_reset_sources),
 	.reset_levels = NULL,
 	.num_reset_levels = 0,
+	.num_wake_events = ARRAY_SIZE(tegra210_wake_events),
+	.wake_events = tegra210_wake_events,
 };
 
 #define TEGRA186_IO_PAD_TABLE(_pad)					     \
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH V3 14/17] arm64: tegra: enable wake from deep sleep on RTC alarm.
  2019-06-18  7:46 [PATCH V3 00/17] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (12 preceding siblings ...)
  2019-06-18  7:46 ` [PATCH V3 13/17] soc/tegra: pmc: add pmc wake support for tegra210 Sowjanya Komatineni
@ 2019-06-18  7:46 ` Sowjanya Komatineni
  2019-06-18  7:46 ` [PATCH V3 15/17] soc/tegra: pmc: configure core power request polarity Sowjanya Komatineni
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18  7:46 UTC (permalink / raw)
  To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, skomatineni, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

This patch updates device tree for RTC and PMC to allow system wake
from deep sleep on RTC alarm.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra210.dtsi | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index edf27fe2f10e..d284bd6088af 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -763,7 +763,8 @@
 	rtc@7000e000 {
 		compatible = "nvidia,tegra210-rtc", "nvidia,tegra20-rtc";
 		reg = <0x0 0x7000e000 0x0 0x100>;
-		interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <16 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-parent = <&pmc>;
 		clocks = <&tegra_car TEGRA210_CLK_RTC>;
 		clock-names = "rtc";
 	};
@@ -773,6 +774,8 @@
 		reg = <0x0 0x7000e400 0x0 0x400>;
 		clocks = <&tegra_car TEGRA210_CLK_PCLK>, <&clk32k_in>;
 		clock-names = "pclk", "clk32k_in";
+		#interrupt-cells = <2>;
+		interrupt-controller;
 
 		powergates {
 			pd_audio: aud {
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH V3 15/17] soc/tegra: pmc: configure core power request polarity
  2019-06-18  7:46 [PATCH V3 00/17] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (13 preceding siblings ...)
  2019-06-18  7:46 ` [PATCH V3 14/17] arm64: tegra: enable wake from deep sleep on RTC alarm Sowjanya Komatineni
@ 2019-06-18  7:46 ` Sowjanya Komatineni
  2019-06-18  7:46 ` [PATCH V3 16/17] soc/tegra: pmc: configure deep sleep control settings Sowjanya Komatineni
  2019-06-18  7:46 ` [PATCH V3 17/17] arm64: dts: tegra210-p2180: Jetson TX1 SC7 timings Sowjanya Komatineni
  16 siblings, 0 replies; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18  7:46 UTC (permalink / raw)
  To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, skomatineni, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

This patch configures polarity of the core power request signal
in PMC control register based on the device tree property.

PMC asserts and de-asserts power request signal based on it polarity
when it need to power-up and power-down the core rail during SC7.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/soc/tegra/pmc.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 603fc3bd73f5..c9eea5ef008a 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -56,6 +56,7 @@
 #define  PMC_CNTRL_SIDE_EFFECT_LP0	BIT(14) /* LP0 when CPU pwr gated */
 #define  PMC_CNTRL_SYSCLK_OE		BIT(11) /* system clock enable */
 #define  PMC_CNTRL_SYSCLK_POLARITY	BIT(10) /* sys clk polarity */
+#define  PMC_CNTRL_PWRREQ_POLARITY	BIT(8)
 #define  PMC_CNTRL_MAIN_RST		BIT(4)
 #define  PMC_CNTRL_LATCH_WAKEUPS	BIT(5)
 
@@ -2304,6 +2305,11 @@ static void tegra20_pmc_init(struct tegra_pmc *pmc)
 	else
 		value |= PMC_CNTRL_SYSCLK_POLARITY;
 
+	if (pmc->corereq_high)
+		value &= ~PMC_CNTRL_PWRREQ_POLARITY;
+	else
+		value |= PMC_CNTRL_PWRREQ_POLARITY;
+
 	/* configure the output polarity while the request is tristated */
 	tegra_pmc_writel(pmc, value, PMC_CNTRL);
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH V3 16/17] soc/tegra: pmc: configure deep sleep control settings
  2019-06-18  7:46 [PATCH V3 00/17] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (14 preceding siblings ...)
  2019-06-18  7:46 ` [PATCH V3 15/17] soc/tegra: pmc: configure core power request polarity Sowjanya Komatineni
@ 2019-06-18  7:46 ` Sowjanya Komatineni
  2019-06-18  7:46 ` [PATCH V3 17/17] arm64: dts: tegra210-p2180: Jetson TX1 SC7 timings Sowjanya Komatineni
  16 siblings, 0 replies; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18  7:46 UTC (permalink / raw)
  To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, skomatineni, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

Tegra210 and prior Tegra chips have deep sleep entry and wakeup related
timings which are platform specific that should be configured before
entering into deep sleep.

Below are the timing specific configurations for deep sleep entry and
wakeup.
- Core rail power-on stabilization timer
- OSC clock stabilization timer after SOC rail power is stabilized.
- Core power off time is the minimum wake delay to keep the system
  in deep sleep state irrespective of any quick wake event.

These values depends on the discharge time of regulators and turn OFF
time of the PMIC to allow the complete system to finish entering into
deep sleep state.

These values vary based on the platform design and are specified
through the device tree.

This patch has implementation to configure these timings which are must
to have for proper deep sleep and wakeup operations.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/soc/tegra/pmc.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index c9eea5ef008a..1b2ecda88a26 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -89,6 +89,8 @@
 
 #define PMC_CPUPWRGOOD_TIMER		0xc8
 #define PMC_CPUPWROFF_TIMER		0xcc
+#define PMC_COREPWRGOOD_TIMER		0x3c
+#define PMC_COREPWROFF_TIMER		0xe0
 
 #define PMC_PWR_DET_VALUE		0xe4
 
@@ -2292,6 +2294,7 @@ static const struct tegra_pmc_regs tegra20_pmc_regs = {
 static void tegra20_pmc_init(struct tegra_pmc *pmc)
 {
 	u32 value;
+	unsigned long osc, pmu, off;
 
 	/* Always enable CPU power request */
 	value = tegra_pmc_readl(pmc, PMC_CNTRL);
@@ -2317,6 +2320,15 @@ static void tegra20_pmc_init(struct tegra_pmc *pmc)
 	value = tegra_pmc_readl(pmc, PMC_CNTRL);
 	value |= PMC_CNTRL_SYSCLK_OE;
 	tegra_pmc_writel(pmc, value, PMC_CNTRL);
+
+	osc = DIV_ROUND_UP_ULL(pmc->core_osc_time * 8192, 1000000);
+	pmu = DIV_ROUND_UP_ULL(pmc->core_pmu_time * 32768, 1000000);
+	off = DIV_ROUND_UP_ULL(pmc->core_off_time * 32768, 1000000);
+	if (osc && pmu)
+		tegra_pmc_writel(pmc, ((osc << 8) & 0xff00) | (pmu & 0xff),
+				 PMC_COREPWRGOOD_TIMER);
+	if (off)
+		tegra_pmc_writel(pmc, off, PMC_COREPWROFF_TIMER);
 }
 
 static void tegra20_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH V3 17/17] arm64: dts: tegra210-p2180: Jetson TX1 SC7 timings
  2019-06-18  7:46 [PATCH V3 00/17] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (15 preceding siblings ...)
  2019-06-18  7:46 ` [PATCH V3 16/17] soc/tegra: pmc: configure deep sleep control settings Sowjanya Komatineni
@ 2019-06-18  7:46 ` Sowjanya Komatineni
  16 siblings, 0 replies; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18  7:46 UTC (permalink / raw)
  To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, skomatineni, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

This patch has Jetson TX1 platform specific SC7 timing configuration
in device tree.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi b/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi
index e8654061ce03..f7c9332085f8 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi
@@ -279,6 +279,13 @@
 
 	pmc@7000e400 {
 		nvidia,invert-interrupt;
+		nvidia,suspend-mode = <0>;
+		nvidia,cpu-pwr-good-time = <0>;
+		nvidia,cpu-pwr-off-time = <0>;
+		nvidia,core-pwr-good-time = <4587 3876>;
+		nvidia,core-pwr-off-time = <39065>;
+		nvidia,core-power-req-active-high;
+		nvidia,sys-clock-req-active-high;
 	};
 
 	/* eMMC */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 01/17] irqchip: tegra: do not disable COP IRQ during suspend
  2019-06-18  7:46 ` [PATCH V3 01/17] irqchip: tegra: do not disable COP IRQ during suspend Sowjanya Komatineni
@ 2019-06-18  9:19   ` Marc Zyngier
  2019-06-18 10:58   ` Thierry Reding
  1 sibling, 0 replies; 47+ messages in thread
From: Marc Zyngier @ 2019-06-18  9:19 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
	robh+dt, digetx, devicetree

On 18/06/2019 08:46, Sowjanya Komatineni wrote:
> Tegra210 platforms use sc7 entry firmware to program Tegra LP0/SC7 entry
> sequence and sc7 entry firmware is run from COP/BPMP-Lite.
> 
> So, COP/BPMP-Lite still need IRQ function to finish SC7 suspend sequence
> for Tegra210.
> 
> This patch has fix for leaving the COP IRQ enabled for Tegra210 during
> interrupt controller suspend operation.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/irqchip/irq-tegra.c | 21 +++++++++++++++++++--
>  1 file changed, 19 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-tegra.c b/drivers/irqchip/irq-tegra.c
> index e1f771c72fc4..cf0c07052064 100644
> --- a/drivers/irqchip/irq-tegra.c
> +++ b/drivers/irqchip/irq-tegra.c
> @@ -44,18 +44,22 @@ static unsigned int num_ictlrs;
>  
>  struct tegra_ictlr_soc {
>  	unsigned int num_ictlrs;
> +	bool supports_sc7;
>  };
>  
>  static const struct tegra_ictlr_soc tegra20_ictlr_soc = {
>  	.num_ictlrs = 4,
> +	.supports_sc7 = false,

nit: that's the default for a statically initialized structure.

>  };
>  
>  static const struct tegra_ictlr_soc tegra30_ictlr_soc = {
>  	.num_ictlrs = 5,
> +	.supports_sc7 = false,
>  };
>  
>  static const struct tegra_ictlr_soc tegra210_ictlr_soc = {
>  	.num_ictlrs = 6,
> +	.supports_sc7 = true,
>  };
>  
>  static const struct of_device_id ictlr_matches[] = {
> @@ -67,6 +71,7 @@ static const struct of_device_id ictlr_matches[] = {
>  
>  struct tegra_ictlr_info {
>  	void __iomem *base[TEGRA_MAX_NUM_ICTLRS];
> +	const struct tegra_ictlr_soc *soc;
>  #ifdef CONFIG_PM_SLEEP
>  	u32 cop_ier[TEGRA_MAX_NUM_ICTLRS];
>  	u32 cop_iep[TEGRA_MAX_NUM_ICTLRS];
> @@ -147,8 +152,19 @@ static int tegra_ictlr_suspend(void)
>  		lic->cop_ier[i] = readl_relaxed(ictlr + ICTLR_COP_IER);
>  		lic->cop_iep[i] = readl_relaxed(ictlr + ICTLR_COP_IEP_CLASS);
>  
> -		/* Disable COP interrupts */
> -		writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
> +		/*
> +		 * AVP/COP/BPMP-Lite is the Tegra boot processor.
> +		 *
> +		 * Tegra210 system suspend flow uses sc7entry firmware which
> +		 * is executed by COP/BPMP and it includes disabling COP IRQ,
> +		 * clamping CPU rail, turning off VDD_CPU, and preparing the
> +		 * system to go to SC7/LP0.
> +		 *
> +		 * COP/BPMP wakes up when COP IRQ is triggered and runs
> +		 * sc7entry-firmware. So need to keep COP interrupt enabled.

It is great that you're describing what happens when the system does
support this SC7 thing...

> +		 */
> +		if (!lic->soc->supports_sc7)
> +			writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);

Except that the code actually deals with *not* having this SC7, and
you've deleted the one line of comment that was explaining it.

>  
>  		/* Disable CPU interrupts */
>  		writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR);
> @@ -339,6 +355,7 @@ static int __init tegra_ictlr_init(struct device_node *node,
>  		goto out_unmap;
>  	}
>  
> +	lic->soc = soc;
>  	tegra_ictlr_syscore_init();
>  
>  	pr_info("%pOF: %d interrupts forwarded to %pOF\n",
> 

Otherwise looks OK to me.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 02/17] pinctrl: tegra: add suspend and resume support
  2019-06-18  7:46 ` [PATCH V3 02/17] pinctrl: tegra: add suspend and resume support Sowjanya Komatineni
@ 2019-06-18  9:22   ` Dmitry Osipenko
  2019-06-18  9:30     ` Dmitry Osipenko
  2019-06-18 11:31   ` Thierry Reding
  1 sibling, 1 reply; 47+ messages in thread
From: Dmitry Osipenko @ 2019-06-18  9:22 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
	robh+dt, devicetree

18.06.2019 10:46, Sowjanya Komatineni пишет:
> This patch adds suspend and resume support for Tegra pinctrl driver
> and registers them to syscore so the pinmux settings are restored
> before the devices resume.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/pinctrl/tegra/pinctrl-tegra.c    | 62 ++++++++++++++++++++++++++++++++
>  drivers/pinctrl/tegra/pinctrl-tegra.h    |  5 +++
>  drivers/pinctrl/tegra/pinctrl-tegra114.c |  1 +
>  drivers/pinctrl/tegra/pinctrl-tegra124.c |  1 +
>  drivers/pinctrl/tegra/pinctrl-tegra20.c  |  1 +
>  drivers/pinctrl/tegra/pinctrl-tegra210.c | 13 +++++++
>  drivers/pinctrl/tegra/pinctrl-tegra30.c  |  1 +
>  7 files changed, 84 insertions(+)
> 
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
> index 34596b246578..ceced30d8bd1 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
> @@ -20,11 +20,16 @@
>  #include <linux/pinctrl/pinmux.h>
>  #include <linux/pinctrl/pinconf.h>
>  #include <linux/slab.h>
> +#include <linux/syscore_ops.h>
>  
>  #include "../core.h"
>  #include "../pinctrl-utils.h"
>  #include "pinctrl-tegra.h"
>  
> +#define EMMC2_PAD_CFGPADCTRL_0			0x1c8
> +#define EMMC4_PAD_CFGPADCTRL_0			0x1e0
> +#define EMMC_DPD_PARKING			(0x1fff << 14)
> +
>  static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 reg)
>  {
>  	return readl(pmx->regs[bank] + reg);
> @@ -619,6 +624,48 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
>  			pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
>  		}
>  	}
> +
> +	if (pmx->soc->has_park_padcfg) {
> +		val = pmx_readl(pmx, 0, EMMC2_PAD_CFGPADCTRL_0);
> +		val &= ~EMMC_DPD_PARKING;
> +		pmx_writel(pmx, val, 0, EMMC2_PAD_CFGPADCTRL_0);
> +
> +		val = pmx_readl(pmx, 0, EMMC4_PAD_CFGPADCTRL_0);
> +		val &= ~EMMC_DPD_PARKING;
> +		pmx_writel(pmx, val, 0, EMMC4_PAD_CFGPADCTRL_0);
> +	}
> +}

Is there any reason why parked_bit can't be changed to parked_bitmask like I was
asking in a comment to v2?

I suppose that it's more preferable to keep pinctrl-tegra.c platform-agnostic for
consistency when possible, hence adding platform specifics here should be discouraged.
And then the parked_bitmask will also result in a proper hardware description in the code.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 12/17] soc/tegra: pmc: allow support for more tegra wake
  2019-06-18  7:46 ` [PATCH V3 12/17] soc/tegra: pmc: allow support for more tegra wake Sowjanya Komatineni
@ 2019-06-18  9:26   ` Marc Zyngier
  0 siblings, 0 replies; 47+ messages in thread
From: Marc Zyngier @ 2019-06-18  9:26 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
	linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
	robh+dt, digetx, devicetree

On 18/06/2019 08:46, Sowjanya Komatineni wrote:
> This patch allows to create separate irq_set_wake and irq_set_type
> implementations for different tegra designs PMC that has different
> wake models which require difference wake registers and different
> programming sequence.
> 
> AOWAKE model support is available for Tegra186 and Tegra194 only
> and it resides within PMC and supports tiered wake architecture.
> 
> Tegra210 and prior tegra designs uses PMC directly to receive wake
> events and coordinate the wake sequence.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/soc/tegra/pmc.c | 14 ++++++++++----
>  1 file changed, 10 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
> index edd4fe06810f..e87f29a35fcf 100644
> --- a/drivers/soc/tegra/pmc.c
> +++ b/drivers/soc/tegra/pmc.c
> @@ -226,6 +226,8 @@ struct tegra_pmc_soc {
>  	void (*setup_irq_polarity)(struct tegra_pmc *pmc,
>  				   struct device_node *np,
>  				   bool invert);
> +	int (*irq_set_wake)(struct irq_data *data, unsigned int on);
> +	int (*irq_set_type)(struct irq_data *data, unsigned int type);
>  
>  	const char * const *reset_sources;
>  	unsigned int num_reset_sources;
> @@ -1919,7 +1921,7 @@ static const struct irq_domain_ops tegra_pmc_irq_domain_ops = {
>  	.alloc = tegra_pmc_irq_alloc,
>  };
>  
> -static int tegra_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
> +static int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
>  {
>  	struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
>  	unsigned int offset, bit;
> @@ -1951,7 +1953,7 @@ static int tegra_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
>  	return 0;
>  }
>  
> -static int tegra_pmc_irq_set_type(struct irq_data *data, unsigned int type)
> +static int tegra186_pmc_irq_set_type(struct irq_data *data, unsigned int type)
>  {
>  	struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
>  	u32 value;
> @@ -2005,8 +2007,10 @@ static int tegra_pmc_irq_init(struct tegra_pmc *pmc)
>  	pmc->irq.irq_unmask = irq_chip_unmask_parent;
>  	pmc->irq.irq_eoi = irq_chip_eoi_parent;
>  	pmc->irq.irq_set_affinity = irq_chip_set_affinity_parent;
> -	pmc->irq.irq_set_type = tegra_pmc_irq_set_type;
> -	pmc->irq.irq_set_wake = tegra_pmc_irq_set_wake;
> +	if (pmc->soc->irq_set_type)
> +		pmc->irq.irq_set_type = pmc->soc->irq_set_type;
> +	if (pmc->soc->irq_set_wake)
> +		pmc->irq.irq_set_wake = pmc->soc->irq_set_wake;

Two cases: either the value is non NULL, and we assign it, or it is
NULL, and we leave it to what it was, presumably NULL. I guess you can
drop the both ifs.

>  
>  	pmc->domain = irq_domain_add_hierarchy(parent, 0, 96, pmc->dev->of_node,
>  					       &tegra_pmc_irq_domain_ops, pmc);
> @@ -2679,6 +2683,8 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
>  	.regs = &tegra186_pmc_regs,
>  	.init = NULL,
>  	.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
> +	.irq_set_wake = tegra186_pmc_irq_set_wake,
> +	.irq_set_type = tegra186_pmc_irq_set_type,
>  	.reset_sources = tegra186_reset_sources,
>  	.num_reset_sources = ARRAY_SIZE(tegra186_reset_sources),
>  	.reset_levels = tegra186_reset_levels,
> 

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 02/17] pinctrl: tegra: add suspend and resume support
  2019-06-18  9:22   ` Dmitry Osipenko
@ 2019-06-18  9:30     ` Dmitry Osipenko
  2019-06-18 15:41       ` Stephen Warren
  0 siblings, 1 reply; 47+ messages in thread
From: Dmitry Osipenko @ 2019-06-18  9:30 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland,
	Stephen Warren
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
	robh+dt, devicetree

18.06.2019 12:22, Dmitry Osipenko пишет:
> 18.06.2019 10:46, Sowjanya Komatineni пишет:
>> This patch adds suspend and resume support for Tegra pinctrl driver
>> and registers them to syscore so the pinmux settings are restored
>> before the devices resume.
>>
>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>> ---
>>  drivers/pinctrl/tegra/pinctrl-tegra.c    | 62 ++++++++++++++++++++++++++++++++
>>  drivers/pinctrl/tegra/pinctrl-tegra.h    |  5 +++
>>  drivers/pinctrl/tegra/pinctrl-tegra114.c |  1 +
>>  drivers/pinctrl/tegra/pinctrl-tegra124.c |  1 +
>>  drivers/pinctrl/tegra/pinctrl-tegra20.c  |  1 +
>>  drivers/pinctrl/tegra/pinctrl-tegra210.c | 13 +++++++
>>  drivers/pinctrl/tegra/pinctrl-tegra30.c  |  1 +
>>  7 files changed, 84 insertions(+)
>>
>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
>> index 34596b246578..ceced30d8bd1 100644
>> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
>> @@ -20,11 +20,16 @@
>>  #include <linux/pinctrl/pinmux.h>
>>  #include <linux/pinctrl/pinconf.h>
>>  #include <linux/slab.h>
>> +#include <linux/syscore_ops.h>
>>  
>>  #include "../core.h"
>>  #include "../pinctrl-utils.h"
>>  #include "pinctrl-tegra.h"
>>  
>> +#define EMMC2_PAD_CFGPADCTRL_0			0x1c8
>> +#define EMMC4_PAD_CFGPADCTRL_0			0x1e0
>> +#define EMMC_DPD_PARKING			(0x1fff << 14)
>> +
>>  static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 reg)
>>  {
>>  	return readl(pmx->regs[bank] + reg);
>> @@ -619,6 +624,48 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
>>  			pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
>>  		}
>>  	}
>> +
>> +	if (pmx->soc->has_park_padcfg) {
>> +		val = pmx_readl(pmx, 0, EMMC2_PAD_CFGPADCTRL_0);
>> +		val &= ~EMMC_DPD_PARKING;
>> +		pmx_writel(pmx, val, 0, EMMC2_PAD_CFGPADCTRL_0);
>> +
>> +		val = pmx_readl(pmx, 0, EMMC4_PAD_CFGPADCTRL_0);
>> +		val &= ~EMMC_DPD_PARKING;
>> +		pmx_writel(pmx, val, 0, EMMC4_PAD_CFGPADCTRL_0);
>> +	}
>> +}
> 
> Is there any reason why parked_bit can't be changed to parked_bitmask like I was
> asking in a comment to v2?
> 
> I suppose that it's more preferable to keep pinctrl-tegra.c platform-agnostic for
> consistency when possible, hence adding platform specifics here should be discouraged.
> And then the parked_bitmask will also result in a proper hardware description in the code.
> 

I'm now also vaguely recalling that Stephen Warren had some kind of a "code generator"
for the pinctrl drivers. So I guess all those tables were auto-generated initially.

Stephen, maybe you could adjust the generator to take into account the bitmask (of
course if that's a part of the generated code) and then re-gen it all for Sowjanya?

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 01/17] irqchip: tegra: do not disable COP IRQ during suspend
  2019-06-18  7:46 ` [PATCH V3 01/17] irqchip: tegra: do not disable COP IRQ during suspend Sowjanya Komatineni
  2019-06-18  9:19   ` Marc Zyngier
@ 2019-06-18 10:58   ` Thierry Reding
  1 sibling, 0 replies; 47+ messages in thread
From: Thierry Reding @ 2019-06-18 10:58 UTC (permalink / raw)
  To: Sowjanya Komatineni
  Cc: jonathanh, tglx, jason, marc.zyngier, linus.walleij, stefan,
	mark.rutland, pdeschrijver, pgaikwad, sboyd, linux-clk,
	linux-gpio, jckuo, josephl, talho, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

[-- Attachment #1: Type: text/plain, Size: 661 bytes --]

On Tue, Jun 18, 2019 at 12:46:15AM -0700, Sowjanya Komatineni wrote:
> Tegra210 platforms use sc7 entry firmware to program Tegra LP0/SC7 entry
> sequence and sc7 entry firmware is run from COP/BPMP-Lite.
> 
> So, COP/BPMP-Lite still need IRQ function to finish SC7 suspend sequence
> for Tegra210.
> 
> This patch has fix for leaving the COP IRQ enabled for Tegra210 during
> interrupt controller suspend operation.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/irqchip/irq-tegra.c | 21 +++++++++++++++++++--
>  1 file changed, 19 insertions(+), 2 deletions(-)

Acked-by: Thierry Reding <treding@nvidia.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 02/17] pinctrl: tegra: add suspend and resume support
  2019-06-18  7:46 ` [PATCH V3 02/17] pinctrl: tegra: add suspend and resume support Sowjanya Komatineni
  2019-06-18  9:22   ` Dmitry Osipenko
@ 2019-06-18 11:31   ` Thierry Reding
  1 sibling, 0 replies; 47+ messages in thread
From: Thierry Reding @ 2019-06-18 11:31 UTC (permalink / raw)
  To: Sowjanya Komatineni
  Cc: jonathanh, tglx, jason, marc.zyngier, linus.walleij, stefan,
	mark.rutland, pdeschrijver, pgaikwad, sboyd, linux-clk,
	linux-gpio, jckuo, josephl, talho, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

[-- Attachment #1: Type: text/plain, Size: 8491 bytes --]

On Tue, Jun 18, 2019 at 12:46:16AM -0700, Sowjanya Komatineni wrote:
> This patch adds suspend and resume support for Tegra pinctrl driver
> and registers them to syscore so the pinmux settings are restored
> before the devices resume.

This no longer uses syscore ops, so you need to reflect that in the
commit message.

> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/pinctrl/tegra/pinctrl-tegra.c    | 62 ++++++++++++++++++++++++++++++++
>  drivers/pinctrl/tegra/pinctrl-tegra.h    |  5 +++
>  drivers/pinctrl/tegra/pinctrl-tegra114.c |  1 +
>  drivers/pinctrl/tegra/pinctrl-tegra124.c |  1 +
>  drivers/pinctrl/tegra/pinctrl-tegra20.c  |  1 +
>  drivers/pinctrl/tegra/pinctrl-tegra210.c | 13 +++++++
>  drivers/pinctrl/tegra/pinctrl-tegra30.c  |  1 +
>  7 files changed, 84 insertions(+)
> 
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
> index 34596b246578..ceced30d8bd1 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
> @@ -20,11 +20,16 @@
>  #include <linux/pinctrl/pinmux.h>
>  #include <linux/pinctrl/pinconf.h>
>  #include <linux/slab.h>
> +#include <linux/syscore_ops.h>

No longer needed.

>  
>  #include "../core.h"
>  #include "../pinctrl-utils.h"
>  #include "pinctrl-tegra.h"
>  
> +#define EMMC2_PAD_CFGPADCTRL_0			0x1c8
> +#define EMMC4_PAD_CFGPADCTRL_0			0x1e0
> +#define EMMC_DPD_PARKING			(0x1fff << 14)
> +
>  static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 reg)
>  {
>  	return readl(pmx->regs[bank] + reg);
> @@ -619,6 +624,48 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
>  			pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
>  		}
>  	}
> +
> +	if (pmx->soc->has_park_padcfg) {
> +		val = pmx_readl(pmx, 0, EMMC2_PAD_CFGPADCTRL_0);
> +		val &= ~EMMC_DPD_PARKING;
> +		pmx_writel(pmx, val, 0, EMMC2_PAD_CFGPADCTRL_0);
> +
> +		val = pmx_readl(pmx, 0, EMMC4_PAD_CFGPADCTRL_0);
> +		val &= ~EMMC_DPD_PARKING;
> +		pmx_writel(pmx, val, 0, EMMC4_PAD_CFGPADCTRL_0);
> +	}
> +}
> +
> +int __maybe_unused tegra_pinctrl_suspend(struct device *dev)
> +{
> +	struct tegra_pmx *pmx = dev_get_drvdata(dev);
> +	u32 *backup_regs = pmx->backup_regs;
> +	u32 *regs;
> +	int i, j;

Can be unsigned int.

> +
> +	for (i = 0; i < pmx->nbanks; i++) {
> +		regs = pmx->regs[i];
> +		for (j = 0; j < pmx->reg_bank_size[i] / 4; j++)
> +			*backup_regs++ = readl(regs++);
> +	}
> +
> +	return pinctrl_force_sleep(pmx->pctl);
> +}
> +
> +int __maybe_unused tegra_pinctrl_resume(struct device *dev)
> +{
> +	struct tegra_pmx *pmx = dev_get_drvdata(dev);
> +	u32 *backup_regs = pmx->backup_regs;
> +	u32 *regs;
> +	int i, j;

unsigned

> +
> +	for (i = 0; i < pmx->nbanks; i++) {
> +		regs = pmx->regs[i];
> +		for (j = 0; j < pmx->reg_bank_size[i] / 4; j++)
> +			writel(*backup_regs++, regs++);
> +	}
> +
> +	return 0;
>  }
>  
>  static bool gpio_node_has_range(const char *compatible)
> @@ -645,6 +692,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
>  	int i;
>  	const char **group_pins;
>  	int fn, gn, gfn;
> +	unsigned long backup_regs_size = 0;
>  
>  	pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
>  	if (!pmx)
> @@ -697,6 +745,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
>  		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
>  		if (!res)
>  			break;
> +		backup_regs_size += resource_size(res);
>  	}
>  	pmx->nbanks = i;
>  
> @@ -705,11 +754,24 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
>  	if (!pmx->regs)
>  		return -ENOMEM;
>  
> +	pmx->reg_bank_size = devm_kcalloc(&pdev->dev, pmx->nbanks,
> +					  sizeof(*pmx->reg_bank_size),
> +					  GFP_KERNEL);
> +	if (!pmx->reg_bank_size)
> +		return -ENOMEM;
> +
> +	pmx->backup_regs = devm_kzalloc(&pdev->dev, backup_regs_size,
> +					GFP_KERNEL);
> +	if (!pmx->backup_regs)
> +		return -ENOMEM;
> +
>  	for (i = 0; i < pmx->nbanks; i++) {
>  		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
>  		pmx->regs[i] = devm_ioremap_resource(&pdev->dev, res);
>  		if (IS_ERR(pmx->regs[i]))
>  			return PTR_ERR(pmx->regs[i]);
> +
> +		pmx->reg_bank_size[i] = resource_size(res);
>  	}
>  
>  	pmx->pctl = devm_pinctrl_register(&pdev->dev, &tegra_pinctrl_desc, pmx);
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
> index 287702660783..d63e472ee0e1 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra.h
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
> @@ -17,6 +17,8 @@ struct tegra_pmx {
>  
>  	int nbanks;
>  	void __iomem **regs;
> +	size_t *reg_bank_size;
> +	u32 *backup_regs;
>  };
>  
>  enum tegra_pinconf_param {
> @@ -191,8 +193,11 @@ struct tegra_pinctrl_soc_data {
>  	bool hsm_in_mux;
>  	bool schmitt_in_mux;
>  	bool drvtype_in_mux;
> +	bool has_park_padcfg;
>  };
>  
>  int tegra_pinctrl_probe(struct platform_device *pdev,
>  			const struct tegra_pinctrl_soc_data *soc_data);
> +int __maybe_unused tegra_pinctrl_suspend(struct device *dev);
> +int __maybe_unused tegra_pinctrl_resume(struct device *dev);
>  #endif
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra114.c b/drivers/pinctrl/tegra/pinctrl-tegra114.c
> index 762151f17a88..06ea8164df9d 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra114.c
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra114.c
> @@ -1841,6 +1841,7 @@ static const struct tegra_pinctrl_soc_data tegra114_pinctrl = {
>  	.hsm_in_mux = false,
>  	.schmitt_in_mux = false,
>  	.drvtype_in_mux = false,
> +	.has_park_padcfg = false,
>  };
>  
>  static int tegra114_pinctrl_probe(struct platform_device *pdev)
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra124.c b/drivers/pinctrl/tegra/pinctrl-tegra124.c
> index 930c43758c92..abc8fe92d154 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra124.c
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra124.c
> @@ -2053,6 +2053,7 @@ static const struct tegra_pinctrl_soc_data tegra124_pinctrl = {
>  	.hsm_in_mux = false,
>  	.schmitt_in_mux = false,
>  	.drvtype_in_mux = false,
> +	.has_park_padcfg = false,
>  };
>  
>  static int tegra124_pinctrl_probe(struct platform_device *pdev)
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra20.c b/drivers/pinctrl/tegra/pinctrl-tegra20.c
> index 4b7837e38fb5..993b82cbfba7 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra20.c
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra20.c
> @@ -2223,6 +2223,7 @@ static const struct tegra_pinctrl_soc_data tegra20_pinctrl = {
>  	.hsm_in_mux = false,
>  	.schmitt_in_mux = false,
>  	.drvtype_in_mux = false,
> +	.has_park_padcfg = false,
>  };
>  
>  static const char *cdev1_parents[] = {
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra210.c b/drivers/pinctrl/tegra/pinctrl-tegra210.c
> index 0b56ad5c9c1c..10e8a2ec8094 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra210.c
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra210.c
> @@ -1555,6 +1555,7 @@ static const struct tegra_pinctrl_soc_data tegra210_pinctrl = {
>  	.hsm_in_mux = true,
>  	.schmitt_in_mux = true,
>  	.drvtype_in_mux = true,
> +	.has_park_padcfg = true,
>  };
>  
>  static int tegra210_pinctrl_probe(struct platform_device *pdev)
> @@ -1562,6 +1563,17 @@ static int tegra210_pinctrl_probe(struct platform_device *pdev)
>  	return tegra_pinctrl_probe(pdev, &tegra210_pinctrl);
>  }
>  
> +#ifdef CONFIG_PM_SLEEP
> +static const struct dev_pm_ops tegra_pinctrl_pm = {
> +	.suspend = &tegra_pinctrl_suspend,
> +	.resume = &tegra_pinctrl_resume
> +};
> +
> +#define TEGRA_PINCTRL_PM	(&tegra_pinctrl_pm)
> +#else
> +#define TEGRA_PINCTRL_PM	NULL
> +#endif

I think we can simplify this by just dropping the #ifdef. We don't allow
!PM on Tegra anymore and suspend/resume is something that most users
will want to enable. There's very little gain in making the dev_pm_ops
conditional, and keeping them around unconditionally make it simple.

> +
>  static const struct of_device_id tegra210_pinctrl_of_match[] = {
>  	{ .compatible = "nvidia,tegra210-pinmux", },
>  	{ },
> @@ -1571,6 +1583,7 @@ static struct platform_driver tegra210_pinctrl_driver = {
>  	.driver = {
>  		.name = "tegra210-pinctrl",
>  		.of_match_table = tegra210_pinctrl_of_match,
> +		.pm    = TEGRA_PINCTRL_PM,

Please use a single space around '='. No need for arbitrary padding.

Thierry Reding

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 03/17] gpio: tegra: use resume_noirq for tegra gpio resume
  2019-06-18  7:46 ` [PATCH V3 03/17] gpio: tegra: use resume_noirq for tegra gpio resume Sowjanya Komatineni
@ 2019-06-18 11:39   ` Thierry Reding
  0 siblings, 0 replies; 47+ messages in thread
From: Thierry Reding @ 2019-06-18 11:39 UTC (permalink / raw)
  To: Sowjanya Komatineni
  Cc: jonathanh, tglx, jason, marc.zyngier, linus.walleij, stefan,
	mark.rutland, pdeschrijver, pgaikwad, sboyd, linux-clk,
	linux-gpio, jckuo, josephl, talho, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

[-- Attachment #1: Type: text/plain, Size: 2571 bytes --]

On Tue, Jun 18, 2019 at 12:46:17AM -0700, Sowjanya Komatineni wrote:
> During SC7 resume, PARKED bit clear from the pinmux registers may
> cause a glitch on the GPIO lines.
> 
> So, Tegra GPIOs restore should happen prior to restoring Tegra pinmux
> to keep the GPIO lines in a known good state prior to clearing PARKED
> bit.
> 
> This patch has fix for this by moving Tegra GPIO restore to happen
> during resume_noirq.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/gpio/gpio-tegra.c | 17 +++++++++++------
>  1 file changed, 11 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
> index f57bfc07ae22..f3c58c597ab9 100644
> --- a/drivers/gpio/gpio-tegra.c
> +++ b/drivers/gpio/gpio-tegra.c
> @@ -410,7 +410,7 @@ static void tegra_gpio_irq_handler(struct irq_desc *desc)
>  }
>  
>  #ifdef CONFIG_PM_SLEEP
> -static int tegra_gpio_resume(struct device *dev)
> +static int tegra_gpio_resume_noirq(struct device *dev)
>  {
>  	struct tegra_gpio_info *tgi = dev_get_drvdata(dev);
>  	unsigned long flags;
> @@ -506,6 +506,15 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
>  
>  	return irq_set_irq_wake(bank->irq, enable);
>  }
> +
> +static const struct dev_pm_ops tegra_gpio_pm_ops = {
> +	.suspend = &tegra_gpio_suspend,
> +	.resume_noirq = &tegra_gpio_resume_noirq
> +};
> +
> +#define TEGRA_GPIO_PM	(&tegra_gpio_pm_ops)
> +#else
> +#define TEGRA_GPIO_PM	NULL

This seems completely unnecessary...

>  #endif
>  
>  #ifdef	CONFIG_DEBUG_FS
> @@ -553,10 +562,6 @@ static inline void tegra_gpio_debuginit(struct tegra_gpio_info *tgi)
>  
>  #endif
>  
> -static const struct dev_pm_ops tegra_gpio_pm_ops = {
> -	SET_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume)
> -};
> -

... because this should work correctly irrespective of how PM_SLEEP is
configured. So I think you just need to:

	s/tegra_gpio_resume/tegra_gpio_resume_noirq/

in the above to make this work. No need for this preprocessor macro
business.

Thierry

>  static int tegra_gpio_probe(struct platform_device *pdev)
>  {
>  	struct tegra_gpio_info *tgi;
> @@ -706,7 +711,7 @@ static const struct of_device_id tegra_gpio_of_match[] = {
>  static struct platform_driver tegra_gpio_driver = {
>  	.driver		= {
>  		.name	= "tegra-gpio",
> -		.pm	= &tegra_gpio_pm_ops,
> +		.pm	= TEGRA_GPIO_PM,
>  		.of_match_table = tegra_gpio_of_match,
>  	},
>  	.probe		= tegra_gpio_probe,
> -- 
> 2.7.4
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 04/17] clk: tegra: save and restore divider rate
  2019-06-18  7:46 ` [PATCH V3 04/17] clk: tegra: save and restore divider rate Sowjanya Komatineni
@ 2019-06-18 11:40   ` Thierry Reding
  0 siblings, 0 replies; 47+ messages in thread
From: Thierry Reding @ 2019-06-18 11:40 UTC (permalink / raw)
  To: Sowjanya Komatineni
  Cc: jonathanh, tglx, jason, marc.zyngier, linus.walleij, stefan,
	mark.rutland, pdeschrijver, pgaikwad, sboyd, linux-clk,
	linux-gpio, jckuo, josephl, talho, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

[-- Attachment #1: Type: text/plain, Size: 658 bytes --]

On Tue, Jun 18, 2019 at 12:46:18AM -0700, Sowjanya Komatineni wrote:
> This patch implements context save and restore for clock divider.
> 
> During system suspend, core power goes off and looses the settings
> of the Tegra CAR controller registers.
> 
> So during suspend entry the context of clock divider is saved and
> on resume context is restored back for normal operation.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk-divider.c | 23 +++++++++++++++++++++++
>  drivers/clk/tegra/clk.h         |  2 ++
>  2 files changed, 25 insertions(+)

Acked-by: Thierry Reding <treding@nvidia.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 05/17] clk: tegra: pllout: save and restore pllout context
  2019-06-18  7:46 ` [PATCH V3 05/17] clk: tegra: pllout: save and restore pllout context Sowjanya Komatineni
@ 2019-06-18 11:41   ` Thierry Reding
  0 siblings, 0 replies; 47+ messages in thread
From: Thierry Reding @ 2019-06-18 11:41 UTC (permalink / raw)
  To: Sowjanya Komatineni
  Cc: jonathanh, tglx, jason, marc.zyngier, linus.walleij, stefan,
	mark.rutland, pdeschrijver, pgaikwad, sboyd, linux-clk,
	linux-gpio, jckuo, josephl, talho, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

[-- Attachment #1: Type: text/plain, Size: 804 bytes --]

On Tue, Jun 18, 2019 at 12:46:19AM -0700, Sowjanya Komatineni wrote:
> This patch implements save and restore of pllout context.
> 
> During system suspend, core power goes off and looses the settings
> of the Tegra CAR controller registers.
> 
> So during suspend entry the state of pllout is saved and on resume
> it is restored back to have pllout in same state as before suspend.
> 
> pllout rate is saved and restore in clock divider so it will be at
> same rate as before suspend when pllout state is restored.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk-pll-out.c | 28 ++++++++++++++++++++++++++++
>  drivers/clk/tegra/clk.h         |  3 +++
>  2 files changed, 31 insertions(+)

Acked-by: Thierry Reding <treding@nvidia.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 06/17] clk: tegra: pll: save and restore pll context
  2019-06-18  7:46 ` [PATCH V3 06/17] clk: tegra: pll: save and restore pll context Sowjanya Komatineni
@ 2019-06-18 11:45   ` Thierry Reding
  2019-06-25 20:46   ` Stephen Boyd
  1 sibling, 0 replies; 47+ messages in thread
From: Thierry Reding @ 2019-06-18 11:45 UTC (permalink / raw)
  To: Sowjanya Komatineni
  Cc: jonathanh, tglx, jason, marc.zyngier, linus.walleij, stefan,
	mark.rutland, pdeschrijver, pgaikwad, sboyd, linux-clk,
	linux-gpio, jckuo, josephl, talho, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

[-- Attachment #1: Type: text/plain, Size: 775 bytes --]

On Tue, Jun 18, 2019 at 12:46:20AM -0700, Sowjanya Komatineni wrote:
> This patch implements save and restore of pll context.
> 
> During system suspend, core power goes off and looses the settings
> of the Tegra CAR controller registers.
> 
> So during suspend entry pll rate is stored and on resume it is
> restored back along with its state.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk-pll.c | 115 ++++++++++++++++++++++++++++++++------------
>  drivers/clk/tegra/clk.h     |   6 ++-
>  2 files changed, 88 insertions(+), 33 deletions(-)

Nit: s/pll/PLL/ in the commit message, but it's up to Stephen and Mike
how important they consider this to be, so:

Acked-by: Thierry Reding <treding@nvidia.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 07/17] clk: tegra: save and restore CPU and System clocks context
  2019-06-18  7:46 ` [PATCH V3 07/17] clk: tegra: save and restore CPU and System clocks context Sowjanya Komatineni
@ 2019-06-18 11:48   ` Thierry Reding
  0 siblings, 0 replies; 47+ messages in thread
From: Thierry Reding @ 2019-06-18 11:48 UTC (permalink / raw)
  To: Sowjanya Komatineni
  Cc: jonathanh, tglx, jason, marc.zyngier, linus.walleij, stefan,
	mark.rutland, pdeschrijver, pgaikwad, sboyd, linux-clk,
	linux-gpio, jckuo, josephl, talho, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

[-- Attachment #1: Type: text/plain, Size: 2619 bytes --]

On Tue, Jun 18, 2019 at 12:46:21AM -0700, Sowjanya Komatineni wrote:
> During system suspend state, core power goes off and looses all the
> CAR controller register settings.
> 
> This patch creates APIs for saving and restoring the context of Tegra
> CPUG, CPULP and SCLK.
> 
> CPU and System clock context includes
> - CPUG, CPULP, and SCLK burst policy settings for clock sourcea of all
>   their normal states.
> - SCLK divisor and System clock rate for restoring SCLK, AHB and APB
>   rates on resume.
> - OSC_DIV settings which are used as reference clock input to some PLLs.
> - SPARE_REG and CLK_MASK settings.
> 
> These APIs are used in Tegra210 clock driver during suspend and resume
> operation.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk-tegra-super-gen4.c |  4 --
>  drivers/clk/tegra/clk.c                  | 80 ++++++++++++++++++++++++++++++++
>  drivers/clk/tegra/clk.h                  | 14 ++++++
>  3 files changed, 94 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c
> index cdfe7c9697e1..ed69ec4d883e 100644
> --- a/drivers/clk/tegra/clk-tegra-super-gen4.c
> +++ b/drivers/clk/tegra/clk-tegra-super-gen4.c
> @@ -19,10 +19,6 @@
>  #define PLLX_MISC2 0x514
>  #define PLLX_MISC3 0x518
>  
> -#define CCLKG_BURST_POLICY 0x368
> -#define CCLKLP_BURST_POLICY 0x370
> -#define SCLK_BURST_POLICY 0x028
> -#define SYSTEM_CLK_RATE 0x030
>  #define SCLK_DIVIDER 0x2c
>  
>  static DEFINE_SPINLOCK(sysrate_lock);
> diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
> index 573e3c967ae1..26690663157a 100644
> --- a/drivers/clk/tegra/clk.c
> +++ b/drivers/clk/tegra/clk.c
> @@ -70,6 +70,12 @@ static struct clk **clks;
>  static int clk_num;
>  static struct clk_onecell_data clk_data;
>  
> +static u32 cclkg_burst_policy_ctx[2];
> +static u32 cclklp_burst_policy_ctx[2];
> +static u32 sclk_burst_policy_ctx[2];
> +static u32 sys_clk_divisor_ctx, system_rate_ctx;
> +static u32 spare_ctx, misc_clk_enb_ctx, clk_arm_ctx;
> +
>  /* Handlers for SoC-specific reset lines */
>  static int (*special_reset_assert)(unsigned long);
>  static int (*special_reset_deassert)(unsigned long);
> @@ -199,6 +205,80 @@ const struct tegra_clk_periph_regs *get_reg_bank(int clkid)
>  	}
>  }
>  
> +void tegra_cclkg_burst_policy_save_context(void)
> +{
> +	int i;

This here (and the same goes for the other functions below) can be
unsigned int.

Otherwise:

Acked-by: Thierry Reding <treding@nvidia.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 08/17] clk: tegra: add support for peripheral clock suspend and resume
  2019-06-18  7:46 ` [PATCH V3 08/17] clk: tegra: add support for peripheral clock suspend and resume Sowjanya Komatineni
@ 2019-06-18 11:50   ` Thierry Reding
  0 siblings, 0 replies; 47+ messages in thread
From: Thierry Reding @ 2019-06-18 11:50 UTC (permalink / raw)
  To: Sowjanya Komatineni
  Cc: jonathanh, tglx, jason, marc.zyngier, linus.walleij, stefan,
	mark.rutland, pdeschrijver, pgaikwad, sboyd, linux-clk,
	linux-gpio, jckuo, josephl, talho, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

[-- Attachment #1: Type: text/plain, Size: 4182 bytes --]

On Tue, Jun 18, 2019 at 12:46:22AM -0700, Sowjanya Komatineni wrote:
> This patch creates APIs to save and restore the state of all
> peripheral clocks reset and enables.
> 
> These APIs are invoked by Tegra210 clock driver during suspend and
> resume to save the peripheral clocks state before suspend and to
> restore them on resume.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++-
>  drivers/clk/tegra/clk.h |  3 +++
>  2 files changed, 72 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
> index 26690663157a..bd3b46c5f941 100644
> --- a/drivers/clk/tegra/clk.c
> +++ b/drivers/clk/tegra/clk.c
> @@ -70,6 +70,7 @@ static struct clk **clks;
>  static int clk_num;
>  static struct clk_onecell_data clk_data;
>  
> +static u32 *periph_ctx;
>  static u32 cclkg_burst_policy_ctx[2];
>  static u32 cclklp_burst_policy_ctx[2];
>  static u32 sclk_burst_policy_ctx[2];
> @@ -279,6 +280,63 @@ void tegra_sclk_cpulp_burst_policy_restore_context(void)
>  	writel_relaxed(clk_arm_ctx, clk_base + CLK_MASK_ARM);
>  }
>  
> +void tegra_clk_periph_suspend(void __iomem *clk_base)
> +{
> +	int i, idx;

Can be unsigned int. Same for below.

> +
> +	idx = 0;
> +	for (i = 0; i < periph_banks; i++, idx++)
> +		periph_ctx[idx] =
> +			readl_relaxed(clk_base + periph_regs[i].rst_reg);
> +
> +	for (i = 0; i < periph_banks; i++, idx++)
> +		periph_ctx[idx] =
> +			readl_relaxed(clk_base + periph_regs[i].enb_reg);
> +}
> +
> +void tegra_clk_periph_force_on(u32 *clks_on, int count, void __iomem *clk_base)

count can also be unsigned int.

> +{
> +	int i;
> +
> +	WARN_ON(count != periph_banks);
> +
> +	for (i = 0; i < count; i++)
> +		writel_relaxed(clks_on[i], clk_base + periph_regs[i].enb_reg);
> +}
> +
> +void tegra_clk_periph_resume(void __iomem *clk_base)
> +{
> +	int i, idx;
> +
> +	idx = 0;
> +	for (i = 0; i < periph_banks; i++, idx++)
> +		writel_relaxed(periph_ctx[idx],
> +			       clk_base + periph_regs[i].rst_reg);
> +
> +	/* ensure all resets have propagated */
> +	fence_udelay(2, clk_base);
> +	tegra_read_chipid();
> +
> +	for (i = 0; i < periph_banks; i++, idx++)
> +		writel_relaxed(periph_ctx[idx],
> +			       clk_base + periph_regs[i].enb_reg);
> +
> +	/* ensure all enables have propagated */
> +	fence_udelay(2, clk_base);
> +	tegra_read_chipid();
> +}
> +
> +static int tegra_clk_suspend_ctx_init(int banks)
> +{
> +	int err = 0;
> +
> +	periph_ctx = kcalloc(2 * banks, sizeof(*periph_ctx), GFP_KERNEL);
> +	if (!periph_ctx)
> +		err = -ENOMEM;
> +
> +	return err;
> +}
> +
>  struct clk ** __init tegra_clk_init(void __iomem *regs, int num, int banks)
>  {
>  	clk_base = regs;
> @@ -295,11 +353,21 @@ struct clk ** __init tegra_clk_init(void __iomem *regs, int num, int banks)
>  	periph_banks = banks;
>  
>  	clks = kcalloc(num, sizeof(struct clk *), GFP_KERNEL);
> -	if (!clks)
> +	if (!clks) {
>  		kfree(periph_clk_enb_refcnt);
> +		return NULL;
> +	}
>  
>  	clk_num = num;
>  
> +	if (IS_ENABLED(CONFIG_PM_SLEEP)) {
> +		if (tegra_clk_suspend_ctx_init(banks)) {
> +			kfree(periph_clk_enb_refcnt);
> +			kfree(clks);
> +			return NULL;
> +		}
> +	}
> +
>  	return clks;
>  }
>  
> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
> index c8f8a23096e2..a354cacae5a6 100644
> --- a/drivers/clk/tegra/clk.h
> +++ b/drivers/clk/tegra/clk.h
> @@ -853,6 +853,9 @@ void tegra_cclkg_burst_policy_save_context(void);
>  void tegra_cclkg_burst_policy_restore_context(void);
>  void tegra_sclk_cclklp_burst_policy_save_context(void);
>  void tegra_sclk_cpulp_burst_policy_restore_context(void);
> +void tegra_clk_periph_suspend(void __iomem *clk_base);
> +void tegra_clk_periph_resume(void __iomem *clk_base);
> +void tegra_clk_periph_force_on(u32 *clks_on, int count, void __iomem *clk_base);
>  
>  /* Combined read fence with delay */
>  #define fence_udelay(delay, reg)	\

Other than the nitpicks, looks good:

Acked-by: Thierry Reding <treding@nvidia.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 09/17] clk: tegra: support for saving and restoring OSC clock context
  2019-06-18  7:46 ` [PATCH V3 09/17] clk: tegra: support for saving and restoring OSC clock context Sowjanya Komatineni
@ 2019-06-18 11:51   ` Thierry Reding
  0 siblings, 0 replies; 47+ messages in thread
From: Thierry Reding @ 2019-06-18 11:51 UTC (permalink / raw)
  To: Sowjanya Komatineni
  Cc: jonathanh, tglx, jason, marc.zyngier, linus.walleij, stefan,
	mark.rutland, pdeschrijver, pgaikwad, sboyd, linux-clk,
	linux-gpio, jckuo, josephl, talho, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

[-- Attachment #1: Type: text/plain, Size: 641 bytes --]

On Tue, Jun 18, 2019 at 12:46:23AM -0700, Sowjanya Komatineni wrote:
> This patch adds support for storing OSC clock frequency and the
> drive-strength during OSC clock init and creates an API to restore
> OSC control register value from the saved context.
> 
> This API is invoked by Tegra210 clock driver during system resume
> to restore the  OSC clock settings.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk-tegra-fixed.c | 14 ++++++++++++++
>  drivers/clk/tegra/clk.h             |  1 +
>  2 files changed, 15 insertions(+)

Acked-by: Thierry Reding <treding@nvidia.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 10/17] clk: tegra: add suspend resume support for DFLL
  2019-06-18  7:46 ` [PATCH V3 10/17] clk: tegra: add suspend resume support for DFLL Sowjanya Komatineni
@ 2019-06-18 11:59   ` Thierry Reding
  0 siblings, 0 replies; 47+ messages in thread
From: Thierry Reding @ 2019-06-18 11:59 UTC (permalink / raw)
  To: Sowjanya Komatineni
  Cc: jonathanh, tglx, jason, marc.zyngier, linus.walleij, stefan,
	mark.rutland, pdeschrijver, pgaikwad, sboyd, linux-clk,
	linux-gpio, jckuo, josephl, talho, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

[-- Attachment #1: Type: text/plain, Size: 667 bytes --]

On Tue, Jun 18, 2019 at 12:46:24AM -0700, Sowjanya Komatineni wrote:
> This patch creates APIs for supporting Tegra210 clock driver to
> perform DFLL suspend and resume operation.
> 
> During suspend, DFLL mode is saved and on resume Tegra210 clock driver
> invokes DFLL resume API to re-initialize DFLL to enable target device
> clock in open loop mode or closed loop mode.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk-dfll.c | 78 ++++++++++++++++++++++++++++++++++++++++++++
>  drivers/clk/tegra/clk-dfll.h |  2 ++
>  2 files changed, 80 insertions(+)

Acked-by: Thierry Reding <treding@nvidia.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 11/17] clk: tegra210: support for Tegra210 clocks suspend and resume
  2019-06-18  7:46 ` [PATCH V3 11/17] clk: tegra210: support for Tegra210 clocks suspend and resume Sowjanya Komatineni
@ 2019-06-18 12:16   ` Thierry Reding
  2019-06-18 17:58     ` Sowjanya Komatineni
  0 siblings, 1 reply; 47+ messages in thread
From: Thierry Reding @ 2019-06-18 12:16 UTC (permalink / raw)
  To: Sowjanya Komatineni
  Cc: jonathanh, tglx, jason, marc.zyngier, linus.walleij, stefan,
	mark.rutland, pdeschrijver, pgaikwad, sboyd, linux-clk,
	linux-gpio, jckuo, josephl, talho, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

[-- Attachment #1: Type: text/plain, Size: 11070 bytes --]

On Tue, Jun 18, 2019 at 12:46:25AM -0700, Sowjanya Komatineni wrote:
> This patch adds system suspend and resume support for Tegra210
> clocks.
> 
> All the CAR controller settings are lost on suspend when core power
> goes off.
> 
> This patch has implementation for saving and restoring all the PLLs
> and clocks context during system suspend and resume to have the
> system back to operating state.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk-tegra210.c | 218 +++++++++++++++++++++++++++++++++++++--
>  1 file changed, 211 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
> index e1ba62d2b1a0..c34d92e871f4 100644
> --- a/drivers/clk/tegra/clk-tegra210.c
> +++ b/drivers/clk/tegra/clk-tegra210.c
> @@ -9,10 +9,12 @@
>  #include <linux/clkdev.h>
>  #include <linux/of.h>
>  #include <linux/of_address.h>
> +#include <linux/of_platform.h>
>  #include <linux/delay.h>
>  #include <linux/export.h>
>  #include <linux/mutex.h>
>  #include <linux/clk/tegra.h>
> +#include <linux/syscore_ops.h>
>  #include <dt-bindings/clock/tegra210-car.h>
>  #include <dt-bindings/reset/tegra210-car.h>
>  #include <linux/iopoll.h>
> @@ -20,6 +22,7 @@
>  #include <soc/tegra/pmc.h>
>  
>  #include "clk.h"
> +#include "clk-dfll.h"
>  #include "clk-id.h"
>  
>  /*
> @@ -36,6 +39,8 @@
>  #define CLK_SOURCE_LA 0x1f8
>  #define CLK_SOURCE_SDMMC2 0x154
>  #define CLK_SOURCE_SDMMC4 0x164
> +#define CLK_OUT_ENB_Y 0x298
> +#define CLK_ENB_PLLP_OUT_CPU BIT(31)
>  
>  #define PLLC_BASE 0x80
>  #define PLLC_OUT 0x84
> @@ -225,6 +230,7 @@
>  
>  #define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2a8
>  #define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2ac
> +#define CPU_SOFTRST_CTRL 0x380
>  
>  #define LVL2_CLK_GATE_OVRA 0xf8
>  #define LVL2_CLK_GATE_OVRC 0x3a0
> @@ -2820,6 +2826,7 @@ static int tegra210_enable_pllu(void)
>  	struct tegra_clk_pll_freq_table *fentry;
>  	struct tegra_clk_pll pllu;
>  	u32 reg;
> +	int ret;
>  
>  	for (fentry = pll_u_freq_table; fentry->input_rate; fentry++) {
>  		if (fentry->input_rate == pll_ref_freq)
> @@ -2836,7 +2843,7 @@ static int tegra210_enable_pllu(void)
>  	reg = readl_relaxed(clk_base + pllu.params->ext_misc_reg[0]);
>  	reg &= ~BIT(pllu.params->iddq_bit_idx);
>  	writel_relaxed(reg, clk_base + pllu.params->ext_misc_reg[0]);
> -	udelay(5);
> +	fence_udelay(5, clk_base);
>  
>  	reg = readl_relaxed(clk_base + PLLU_BASE);
>  	reg &= ~GENMASK(20, 0);
> @@ -2844,13 +2851,13 @@ static int tegra210_enable_pllu(void)
>  	reg |= fentry->n << 8;
>  	reg |= fentry->p << 16;
>  	writel(reg, clk_base + PLLU_BASE);
> -	udelay(1);
> +	fence_udelay(1, clk_base);

These udelay() -> fence_udelay() seem like they should be a separate
patch.

>  	reg |= PLL_ENABLE;
>  	writel(reg, clk_base + PLLU_BASE);
> +	fence_udelay(1, clk_base);
>  
> -	readl_relaxed_poll_timeout_atomic(clk_base + PLLU_BASE, reg,
> -					  reg & PLL_BASE_LOCK, 2, 1000);
> -	if (!(reg & PLL_BASE_LOCK)) {
> +	ret = tegra210_wait_for_mask(&pllu, PLLU_BASE, PLL_BASE_LOCK);
> +	if (ret) {
>  		pr_err("Timed out waiting for PLL_U to lock\n");
>  		return -ETIMEDOUT;
>  	}
> @@ -2890,12 +2897,12 @@ static int tegra210_init_pllu(void)
>  		reg = readl_relaxed(clk_base + XUSB_PLL_CFG0);
>  		reg &= ~XUSB_PLL_CFG0_PLLU_LOCK_DLY_MASK;
>  		writel_relaxed(reg, clk_base + XUSB_PLL_CFG0);
> -		udelay(1);
> +		fence_udelay(1, clk_base);
>  
>  		reg = readl_relaxed(clk_base + PLLU_HW_PWRDN_CFG0);
>  		reg |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
>  		writel_relaxed(reg, clk_base + PLLU_HW_PWRDN_CFG0);
> -		udelay(1);
> +		fence_udelay(1, clk_base);
>  
>  		reg = readl_relaxed(clk_base + PLLU_BASE);
>  		reg &= ~PLLU_BASE_CLKENABLE_USB;
> @@ -3282,6 +3289,188 @@ static void tegra210_disable_cpu_clock(u32 cpu)
>  }
>  
>  #ifdef CONFIG_PM_SLEEP
> +static u32 cpu_softrst_ctx[3];
> +static struct platform_device *dfll_pdev;
> +static u32 *periph_clk_src_ctx;
> +struct periph_source_bank {

Blank line between the above two.

> +	u32 start;
> +	u32 end;
> +};
> +
> +static struct periph_source_bank periph_srcs[] = {
> +	[0] = {
> +		.start = 0x100,
> +		.end = 0x198,
> +	},
> +	[1] = {
> +		.start = 0x1a0,
> +		.end = 0x1f8,
> +	},
> +	[2] = {
> +		.start = 0x3b4,
> +		.end = 0x42c,
> +	},
> +	[3] = {
> +		.start = 0x49c,
> +		.end = 0x4b4,
> +	},
> +	[4] = {
> +		.start = 0x560,
> +		.end = 0x564,
> +	},
> +	[5] = {
> +		.start = 0x600,
> +		.end = 0x678,
> +	},
> +	[6] = {
> +		.start = 0x694,
> +		.end = 0x6a0,
> +	},
> +	[7] = {
> +		.start = 0x6b8,
> +		.end = 0x718,
> +	},
> +};
> +
> +/* This array lists the valid clocks for each periph clk bank */
> +static u32 periph_clks_on[] = {
> +	0xdcd7dff9,
> +	0x87d1f3e7,
> +	0xf3fed3fa,
> +	0xffc18cfb,
> +	0x793fb7ff,
> +	0x3fe66fff,
> +	0xfc1fc7ff,
> +};

Hm... this is a bunch of magic. Perhaps replace this by a list of the
clock IDs? That's perhaps a little more verbose, but if we ever need to
tweak the list of IDs in that periph_clks_on array, that'll be quite the
challenge.

Also, is this list a "guess" or are these all guaranteed to be always
on? What if some of these ended up getting disabled as part of suspend
already (by their users). If we force them on, won't their references
become unbalanced if the driver later enables them again on resume?

> +
> +static struct platform_device *dfll_pdev;

I think you already predeclared this one above.

> +#define car_readl(_base, _off) readl_relaxed(clk_base + (_base) + ((_off) * 4))
> +#define car_writel(_val, _base, _off) \
> +		writel_relaxed(_val, clk_base + (_base) + ((_off) * 4))
> +
> +static u32 * __init tegra210_init_suspend_ctx(void)
> +{
> +	int i, size = 0;

Can both be unsigned int.

> +
> +	for (i = 0; i < ARRAY_SIZE(periph_srcs); i++)
> +		size += periph_srcs[i].end - periph_srcs[i].start + 4;
> +
> +	periph_clk_src_ctx = kmalloc(size, GFP_KERNEL);
> +
> +	return periph_clk_src_ctx;

It's somewhat wasteful to return a global variable since you can access
it anyway. Perhaps it'd be more useful to make the function return a
boolean?

> +}
> +
> +static int tegra210_clk_suspend(void)
> +{
> +	int i;

unsigned int.

> +	unsigned long off;
> +	struct device_node *node;
> +	u32 *clk_rst_ctx = periph_clk_src_ctx;
> +	u32 val;
> +
> +	tegra_cclkg_burst_policy_save_context();
> +
> +	if (!dfll_pdev) {
> +		node = of_find_compatible_node(NULL, NULL,
> +					       "nvidia,tegra210-dfll");
> +		if (node)
> +			dfll_pdev = of_find_device_by_node(node);
> +		of_node_put(node);
> +		if (!dfll_pdev)
> +			pr_err("dfll node not found. no suspend for dfll\n");
> +	}

Wouldn't it make sense to run this only once, perhaps as part of
tegra210_init_suspend_ctx()?

> +
> +	if (dfll_pdev)
> +		tegra_dfll_suspend(dfll_pdev);
> +
> +	/* Enable PLLP_OUT_CPU after dfll suspend */
> +	val = car_readl(CLK_OUT_ENB_Y, 0);
> +	val |= CLK_ENB_PLLP_OUT_CPU;
> +	car_writel(val, CLK_OUT_ENB_Y, 0);
> +
> +	tegra_clk_periph_suspend(clk_base);
> +
> +	for (i = 0; i < ARRAY_SIZE(periph_srcs); i++)
> +		for (off = periph_srcs[i].start; off <= periph_srcs[i].end;
> +		     off += 4)
> +			*clk_rst_ctx++ = car_readl(off, 0);
> +
> +	tegra_sclk_cclklp_burst_policy_save_context();
> +
> +	for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
> +		cpu_softrst_ctx[i] = car_readl(CPU_SOFTRST_CTRL, i);
> +
> +	clk_save_context();
> +
> +	return 0;
> +}
> +
> +static void tegra210_clk_resume(void)
> +{
> +	int i;
> +	unsigned long off;
> +	u32 val;
> +	u32 *clk_rst_ctx = periph_clk_src_ctx;
> +	struct clk_hw *parent;
> +	struct clk *clk;
> +
> +	for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
> +		car_writel(cpu_softrst_ctx[i], CPU_SOFTRST_CTRL, i);
> +
> +	tegra_clk_osc_resume(clk_base);
> +
> +	/*
> +	 * restore all the plls before configuring clocks and resetting
> +	 * the devices.
> +	 */
> +	tegra210_init_pllu();
> +	tegra_sclk_cpulp_burst_policy_restore_context();
> +	clk_restore_context();
> +
> +	/* enable all clocks before configuring clock sources */
> +	tegra_clk_periph_force_on(periph_clks_on, ARRAY_SIZE(periph_clks_on),
> +				  clk_base);
> +	/* wait for all writes to happen to have all the clocks enabled */
> +	wmb();
> +	fence_udelay(2, clk_base);
> +
> +	/* restore all the devices clock sources */
> +	for (i = 0; i < ARRAY_SIZE(periph_srcs); i++)
> +		for (off = periph_srcs[i].start; off <= periph_srcs[i].end;
> +		     off += 4)
> +			car_writel(*clk_rst_ctx++, off, 0);
> +
> +	/* propagate and restore resets, restore clock state */
> +	fence_udelay(5, clk_base);
> +	tegra_clk_periph_resume(clk_base);
> +
> +	/*
> +	 * restore CPUG clocks:
> +	 * - enable DFLL in open loop mode
> +	 * - switch CPUG to DFLL clock source
> +	 * - close DFLL loop
> +	 * - sync PLLX state
> +	 */
> +	if (dfll_pdev)
> +		tegra_dfll_resume(dfll_pdev, false);
> +
> +	tegra_cclkg_burst_policy_restore_context();
> +	fence_udelay(2, clk_base);
> +
> +	if (dfll_pdev)
> +		tegra_dfll_resume(dfll_pdev, true);
> +
> +	parent = clk_hw_get_parent(__clk_get_hw(clks[TEGRA210_CLK_CCLK_G]));
> +	clk = clks[TEGRA210_CLK_PLL_X];
> +	if (parent != __clk_get_hw(clk))
> +		tegra_clk_sync_state_pll(__clk_get_hw(clk));
> +
> +	/* Disable PLL_OUT_CPU after DFLL resume */
> +	val = car_readl(CLK_OUT_ENB_Y, 0);
> +	val &= ~CLK_ENB_PLLP_OUT_CPU;
> +	car_writel(val, CLK_OUT_ENB_Y, 0);
> +}

I'm surprised by the amount of work that we need to do here. I had hoped
that the clock framework's save/restore infrastructure would be enough.
I suppose you do call clk_restore_context() somewhere in there, so maybe
this really is as good as it gets.

Thierry

> +
>  static void tegra210_cpu_clock_suspend(void)
>  {
>  	/* switch coresite to clk_m, save off original source */
> @@ -3295,8 +3484,20 @@ static void tegra210_cpu_clock_resume(void)
>  	writel(tegra210_cpu_clk_sctx.clk_csite_src,
>  				clk_base + CLK_SOURCE_CSITE);
>  }
> +#else
> +#define tegra210_clk_suspend	NULL
> +#define tegra210_clk_resume	NULL
> +static inline u32 *tegra210_init_suspend_ctx(void)
> +{
> +	return NULL;
> +}
>  #endif
>  
> +static struct syscore_ops tegra_clk_syscore_ops = {
> +	.suspend = tegra210_clk_suspend,
> +	.resume = tegra210_clk_resume,
> +};
> +
>  static struct tegra_cpu_car_ops tegra210_cpu_car_ops = {
>  	.wait_for_reset	= tegra210_wait_cpu_in_reset,
>  	.disable_clock	= tegra210_disable_cpu_clock,
> @@ -3580,5 +3781,8 @@ static void __init tegra210_clock_init(struct device_node *np)
>  	tegra210_mbist_clk_init();
>  
>  	tegra_cpu_car_ops = &tegra210_cpu_car_ops;
> +
> +	if (tegra210_init_suspend_ctx())
> +		register_syscore_ops(&tegra_clk_syscore_ops);
>  }
>  CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);
> -- 
> 2.7.4
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 02/17] pinctrl: tegra: add suspend and resume support
  2019-06-18  9:30     ` Dmitry Osipenko
@ 2019-06-18 15:41       ` Stephen Warren
  2019-06-18 16:50         ` Sowjanya Komatineni
  2019-06-19  8:33         ` Thierry Reding
  0 siblings, 2 replies; 47+ messages in thread
From: Stephen Warren @ 2019-06-18 15:41 UTC (permalink / raw)
  To: Dmitry Osipenko, Sowjanya Komatineni
  Cc: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland, pdeschrijver, pgaikwad,
	sboyd, linux-clk, linux-gpio, jckuo, josephl, talho, linux-tegra,
	linux-kernel, mperttunen, spatra, robh+dt, devicetree

On 6/18/19 3:30 AM, Dmitry Osipenko wrote:
> 18.06.2019 12:22, Dmitry Osipenko пишет:
>> 18.06.2019 10:46, Sowjanya Komatineni пишет:
>>> This patch adds suspend and resume support for Tegra pinctrl driver
>>> and registers them to syscore so the pinmux settings are restored
>>> before the devices resume.
>>>
>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>> ---
>>>   drivers/pinctrl/tegra/pinctrl-tegra.c    | 62 ++++++++++++++++++++++++++++++++
>>>   drivers/pinctrl/tegra/pinctrl-tegra.h    |  5 +++
>>>   drivers/pinctrl/tegra/pinctrl-tegra114.c |  1 +
>>>   drivers/pinctrl/tegra/pinctrl-tegra124.c |  1 +
>>>   drivers/pinctrl/tegra/pinctrl-tegra20.c  |  1 +
>>>   drivers/pinctrl/tegra/pinctrl-tegra210.c | 13 +++++++
>>>   drivers/pinctrl/tegra/pinctrl-tegra30.c  |  1 +
>>>   7 files changed, 84 insertions(+)
>>>
>>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
>>> index 34596b246578..ceced30d8bd1 100644
>>> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
>>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
>>> @@ -20,11 +20,16 @@
>>>   #include <linux/pinctrl/pinmux.h>
>>>   #include <linux/pinctrl/pinconf.h>
>>>   #include <linux/slab.h>
>>> +#include <linux/syscore_ops.h>
>>>   
>>>   #include "../core.h"
>>>   #include "../pinctrl-utils.h"
>>>   #include "pinctrl-tegra.h"
>>>   
>>> +#define EMMC2_PAD_CFGPADCTRL_0			0x1c8
>>> +#define EMMC4_PAD_CFGPADCTRL_0			0x1e0
>>> +#define EMMC_DPD_PARKING			(0x1fff << 14)
>>> +
>>>   static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 reg)
>>>   {
>>>   	return readl(pmx->regs[bank] + reg);
>>> @@ -619,6 +624,48 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
>>>   			pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
>>>   		}
>>>   	}
>>> +
>>> +	if (pmx->soc->has_park_padcfg) {
>>> +		val = pmx_readl(pmx, 0, EMMC2_PAD_CFGPADCTRL_0);
>>> +		val &= ~EMMC_DPD_PARKING;
>>> +		pmx_writel(pmx, val, 0, EMMC2_PAD_CFGPADCTRL_0);
>>> +
>>> +		val = pmx_readl(pmx, 0, EMMC4_PAD_CFGPADCTRL_0);
>>> +		val &= ~EMMC_DPD_PARKING;
>>> +		pmx_writel(pmx, val, 0, EMMC4_PAD_CFGPADCTRL_0);
>>> +	}
>>> +}
>>
>> Is there any reason why parked_bit can't be changed to parked_bitmask like I was
>> asking in a comment to v2?
>>
>> I suppose that it's more preferable to keep pinctrl-tegra.c platform-agnostic for
>> consistency when possible, hence adding platform specifics here should be discouraged.
>> And then the parked_bitmask will also result in a proper hardware description in the code.
>>
> 
> I'm now also vaguely recalling that Stephen Warren had some kind of a "code generator"
> for the pinctrl drivers. So I guess all those tables were auto-generated initially.
> 
> Stephen, maybe you could adjust the generator to take into account the bitmask (of
> course if that's a part of the generated code) and then re-gen it all for Sowjanya?

https://github.com/NVIDIA/tegra-pinmux-scripts holds the scripts that 
generate tegra-pinctrlNNN.c. See  	soc-to-kernel-pinctrl-driver.py. 
IIRC, tegra-pinctrl.c (the core file) isn't auto-generated. Sowjanya is 
welcome to send a patch to that repo if the code needs to be updated.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 02/17] pinctrl: tegra: add suspend and resume support
  2019-06-18 15:41       ` Stephen Warren
@ 2019-06-18 16:50         ` Sowjanya Komatineni
  2019-06-18 17:34           ` Sowjanya Komatineni
  2019-06-19  8:33         ` Thierry Reding
  1 sibling, 1 reply; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18 16:50 UTC (permalink / raw)
  To: Stephen Warren, Dmitry Osipenko
  Cc: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland, pdeschrijver, pgaikwad,
	sboyd, linux-clk, linux-gpio, jckuo, josephl, talho, linux-tegra,
	linux-kernel, mperttunen, spatra, robh+dt, devicetree


On 6/18/19 8:41 AM, Stephen Warren wrote:
> On 6/18/19 3:30 AM, Dmitry Osipenko wrote:
>> 18.06.2019 12:22, Dmitry Osipenko пишет:
>>> 18.06.2019 10:46, Sowjanya Komatineni пишет:
>>>> This patch adds suspend and resume support for Tegra pinctrl driver
>>>> and registers them to syscore so the pinmux settings are restored
>>>> before the devices resume.
>>>>
>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>> ---
>>>>   drivers/pinctrl/tegra/pinctrl-tegra.c    | 62 
>>>> ++++++++++++++++++++++++++++++++
>>>>   drivers/pinctrl/tegra/pinctrl-tegra.h    |  5 +++
>>>>   drivers/pinctrl/tegra/pinctrl-tegra114.c |  1 +
>>>>   drivers/pinctrl/tegra/pinctrl-tegra124.c |  1 +
>>>>   drivers/pinctrl/tegra/pinctrl-tegra20.c  |  1 +
>>>>   drivers/pinctrl/tegra/pinctrl-tegra210.c | 13 +++++++
>>>>   drivers/pinctrl/tegra/pinctrl-tegra30.c  |  1 +
>>>>   7 files changed, 84 insertions(+)
>>>>
>>>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c 
>>>> b/drivers/pinctrl/tegra/pinctrl-tegra.c
>>>> index 34596b246578..ceced30d8bd1 100644
>>>> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
>>>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
>>>> @@ -20,11 +20,16 @@
>>>>   #include <linux/pinctrl/pinmux.h>
>>>>   #include <linux/pinctrl/pinconf.h>
>>>>   #include <linux/slab.h>
>>>> +#include <linux/syscore_ops.h>
>>>>     #include "../core.h"
>>>>   #include "../pinctrl-utils.h"
>>>>   #include "pinctrl-tegra.h"
>>>>   +#define EMMC2_PAD_CFGPADCTRL_0            0x1c8
>>>> +#define EMMC4_PAD_CFGPADCTRL_0            0x1e0
>>>> +#define EMMC_DPD_PARKING            (0x1fff << 14)
>>>> +
>>>>   static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 
>>>> reg)
>>>>   {
>>>>       return readl(pmx->regs[bank] + reg);
>>>> @@ -619,6 +624,48 @@ static void 
>>>> tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
>>>>               pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
>>>>           }
>>>>       }
>>>> +
>>>> +    if (pmx->soc->has_park_padcfg) {
>>>> +        val = pmx_readl(pmx, 0, EMMC2_PAD_CFGPADCTRL_0);
>>>> +        val &= ~EMMC_DPD_PARKING;
>>>> +        pmx_writel(pmx, val, 0, EMMC2_PAD_CFGPADCTRL_0);
>>>> +
>>>> +        val = pmx_readl(pmx, 0, EMMC4_PAD_CFGPADCTRL_0);
>>>> +        val &= ~EMMC_DPD_PARKING;
>>>> +        pmx_writel(pmx, val, 0, EMMC4_PAD_CFGPADCTRL_0);
>>>> +    }
>>>> +}
>>>
>>> Is there any reason why parked_bit can't be changed to 
>>> parked_bitmask like I was
>>> asking in a comment to v2?
>>>
>>> I suppose that it's more preferable to keep pinctrl-tegra.c 
>>> platform-agnostic for
>>> consistency when possible, hence adding platform specifics here 
>>> should be discouraged.
>>> And then the parked_bitmask will also result in a proper hardware 
>>> description in the code.
>>>
>>
>> I'm now also vaguely recalling that Stephen Warren had some kind of a 
>> "code generator"
>> for the pinctrl drivers. So I guess all those tables were 
>> auto-generated initially.
>>
>> Stephen, maybe you could adjust the generator to take into account 
>> the bitmask (of
>> course if that's a part of the generated code) and then re-gen it all 
>> for Sowjanya?
>
> https://github.com/NVIDIA/tegra-pinmux-scripts holds the scripts that 
> generate tegra-pinctrlNNN.c. See soc-to-kernel-pinctrl-driver.py. 
> IIRC, tegra-pinctrl.c (the core file) isn't auto-generated. Sowjanya 
> is welcome to send a patch to that repo if the code needs to be updated.


Hi Dmitry,

Just want to be clear on my understanding of your request.

"change parked_bit to parked_bitmask" are you requested to change 
parked_bit of PINGROUP and DRV_PINGROUP to use bitmask value rather than 
bit position inorder to have parked bit configuration for EMMC PADs as 
well to happen by masking rather than checking for existence of parked_bit?

Trying to understand the reason/benefit for changing parked_bit to 
parked_bitmask.


thanks

Sowjanya


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 02/17] pinctrl: tegra: add suspend and resume support
  2019-06-18 16:50         ` Sowjanya Komatineni
@ 2019-06-18 17:34           ` Sowjanya Komatineni
  2019-06-18 20:00             ` Dmitry Osipenko
  0 siblings, 1 reply; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18 17:34 UTC (permalink / raw)
  To: Stephen Warren, Dmitry Osipenko
  Cc: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland, pdeschrijver, pgaikwad,
	sboyd, linux-clk, linux-gpio, jckuo, josephl, talho, linux-tegra,
	linux-kernel, mperttunen, spatra, robh+dt, devicetree


On 6/18/19 9:50 AM, Sowjanya Komatineni wrote:
>
> On 6/18/19 8:41 AM, Stephen Warren wrote:
>> On 6/18/19 3:30 AM, Dmitry Osipenko wrote:
>>> 18.06.2019 12:22, Dmitry Osipenko пишет:
>>>> 18.06.2019 10:46, Sowjanya Komatineni пишет:
>>>>> This patch adds suspend and resume support for Tegra pinctrl driver
>>>>> and registers them to syscore so the pinmux settings are restored
>>>>> before the devices resume.
>>>>>
>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>> ---
>>>>>   drivers/pinctrl/tegra/pinctrl-tegra.c    | 62 
>>>>> ++++++++++++++++++++++++++++++++
>>>>>   drivers/pinctrl/tegra/pinctrl-tegra.h    |  5 +++
>>>>>   drivers/pinctrl/tegra/pinctrl-tegra114.c |  1 +
>>>>>   drivers/pinctrl/tegra/pinctrl-tegra124.c |  1 +
>>>>>   drivers/pinctrl/tegra/pinctrl-tegra20.c  |  1 +
>>>>>   drivers/pinctrl/tegra/pinctrl-tegra210.c | 13 +++++++
>>>>>   drivers/pinctrl/tegra/pinctrl-tegra30.c  |  1 +
>>>>>   7 files changed, 84 insertions(+)
>>>>>
>>>>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c 
>>>>> b/drivers/pinctrl/tegra/pinctrl-tegra.c
>>>>> index 34596b246578..ceced30d8bd1 100644
>>>>> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
>>>>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
>>>>> @@ -20,11 +20,16 @@
>>>>>   #include <linux/pinctrl/pinmux.h>
>>>>>   #include <linux/pinctrl/pinconf.h>
>>>>>   #include <linux/slab.h>
>>>>> +#include <linux/syscore_ops.h>
>>>>>     #include "../core.h"
>>>>>   #include "../pinctrl-utils.h"
>>>>>   #include "pinctrl-tegra.h"
>>>>>   +#define EMMC2_PAD_CFGPADCTRL_0            0x1c8
>>>>> +#define EMMC4_PAD_CFGPADCTRL_0            0x1e0
>>>>> +#define EMMC_DPD_PARKING            (0x1fff << 14)
>>>>> +
>>>>>   static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 
>>>>> reg)
>>>>>   {
>>>>>       return readl(pmx->regs[bank] + reg);
>>>>> @@ -619,6 +624,48 @@ static void 
>>>>> tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
>>>>>               pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
>>>>>           }
>>>>>       }
>>>>> +
>>>>> +    if (pmx->soc->has_park_padcfg) {
>>>>> +        val = pmx_readl(pmx, 0, EMMC2_PAD_CFGPADCTRL_0);
>>>>> +        val &= ~EMMC_DPD_PARKING;
>>>>> +        pmx_writel(pmx, val, 0, EMMC2_PAD_CFGPADCTRL_0);
>>>>> +
>>>>> +        val = pmx_readl(pmx, 0, EMMC4_PAD_CFGPADCTRL_0);
>>>>> +        val &= ~EMMC_DPD_PARKING;
>>>>> +        pmx_writel(pmx, val, 0, EMMC4_PAD_CFGPADCTRL_0);
>>>>> +    }
>>>>> +}
>>>>
>>>> Is there any reason why parked_bit can't be changed to 
>>>> parked_bitmask like I was
>>>> asking in a comment to v2?
>>>>
>>>> I suppose that it's more preferable to keep pinctrl-tegra.c 
>>>> platform-agnostic for
>>>> consistency when possible, hence adding platform specifics here 
>>>> should be discouraged.
>>>> And then the parked_bitmask will also result in a proper hardware 
>>>> description in the code.
>>>>
>>>
>>> I'm now also vaguely recalling that Stephen Warren had some kind of 
>>> a "code generator"
>>> for the pinctrl drivers. So I guess all those tables were 
>>> auto-generated initially.
>>>
>>> Stephen, maybe you could adjust the generator to take into account 
>>> the bitmask (of
>>> course if that's a part of the generated code) and then re-gen it 
>>> all for Sowjanya?
>>
>> https://github.com/NVIDIA/tegra-pinmux-scripts holds the scripts that 
>> generate tegra-pinctrlNNN.c. See soc-to-kernel-pinctrl-driver.py. 
>> IIRC, tegra-pinctrl.c (the core file) isn't auto-generated. Sowjanya 
>> is welcome to send a patch to that repo if the code needs to be updated.
>
>
> Hi Dmitry,
>
> Just want to be clear on my understanding of your request.
>
> "change parked_bit to parked_bitmask" are you requested to change 
> parked_bit of PINGROUP and DRV_PINGROUP to use bitmask value rather 
> than bit position inorder to have parked bit configuration for EMMC 
> PADs as well to happen by masking rather than checking for existence 
> of parked_bit?
>
> Trying to understand the reason/benefit for changing parked_bit to 
> parked_bitmask.
Also, Park bits in CFGPAD registers are not common for all CFGPAD 
registers. Park bits are available only for EMMC and also those bits are 
used for something else on other CFGPAD registers so bitmask can't be 
common and this also need an update to DRV_PINGROUP macro args just only 
to handle EMMC parked_bitmask. So not sure of the benefit in using 
bitmask rather than parked_bit
>
> thanks
>
> Sowjanya
>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 11/17] clk: tegra210: support for Tegra210 clocks suspend and resume
  2019-06-18 12:16   ` Thierry Reding
@ 2019-06-18 17:58     ` Sowjanya Komatineni
  2019-06-19  8:15       ` Thierry Reding
  0 siblings, 1 reply; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18 17:58 UTC (permalink / raw)
  To: Thierry Reding
  Cc: jonathanh, tglx, jason, marc.zyngier, linus.walleij, stefan,
	mark.rutland, pdeschrijver, pgaikwad, sboyd, linux-clk,
	linux-gpio, jckuo, josephl, talho, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree


On 6/18/19 5:16 AM, Thierry Reding wrote:
> On Tue, Jun 18, 2019 at 12:46:25AM -0700, Sowjanya Komatineni wrote:
>> This patch adds system suspend and resume support for Tegra210
>> clocks.
>>
>> All the CAR controller settings are lost on suspend when core power
>> goes off.
>>
>> This patch has implementation for saving and restoring all the PLLs
>> and clocks context during system suspend and resume to have the
>> system back to operating state.
>>
>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>> ---
>>   drivers/clk/tegra/clk-tegra210.c | 218 +++++++++++++++++++++++++++++++++++++--
>>   1 file changed, 211 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
>> index e1ba62d2b1a0..c34d92e871f4 100644
>> --- a/drivers/clk/tegra/clk-tegra210.c
>> +++ b/drivers/clk/tegra/clk-tegra210.c
>> @@ -9,10 +9,12 @@
>>   #include <linux/clkdev.h>
>>   #include <linux/of.h>
>>   #include <linux/of_address.h>
>> +#include <linux/of_platform.h>
>>   #include <linux/delay.h>
>>   #include <linux/export.h>
>>   #include <linux/mutex.h>
>>   #include <linux/clk/tegra.h>
>> +#include <linux/syscore_ops.h>
>>   #include <dt-bindings/clock/tegra210-car.h>
>>   #include <dt-bindings/reset/tegra210-car.h>
>>   #include <linux/iopoll.h>
>> @@ -20,6 +22,7 @@
>>   #include <soc/tegra/pmc.h>
>>   
>>   #include "clk.h"
>> +#include "clk-dfll.h"
>>   #include "clk-id.h"
>>   
>>   /*
>> @@ -36,6 +39,8 @@
>>   #define CLK_SOURCE_LA 0x1f8
>>   #define CLK_SOURCE_SDMMC2 0x154
>>   #define CLK_SOURCE_SDMMC4 0x164
>> +#define CLK_OUT_ENB_Y 0x298
>> +#define CLK_ENB_PLLP_OUT_CPU BIT(31)
>>   
>>   #define PLLC_BASE 0x80
>>   #define PLLC_OUT 0x84
>> @@ -225,6 +230,7 @@
>>   
>>   #define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2a8
>>   #define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2ac
>> +#define CPU_SOFTRST_CTRL 0x380
>>   
>>   #define LVL2_CLK_GATE_OVRA 0xf8
>>   #define LVL2_CLK_GATE_OVRC 0x3a0
>> @@ -2820,6 +2826,7 @@ static int tegra210_enable_pllu(void)
>>   	struct tegra_clk_pll_freq_table *fentry;
>>   	struct tegra_clk_pll pllu;
>>   	u32 reg;
>> +	int ret;
>>   
>>   	for (fentry = pll_u_freq_table; fentry->input_rate; fentry++) {
>>   		if (fentry->input_rate == pll_ref_freq)
>> @@ -2836,7 +2843,7 @@ static int tegra210_enable_pllu(void)
>>   	reg = readl_relaxed(clk_base + pllu.params->ext_misc_reg[0]);
>>   	reg &= ~BIT(pllu.params->iddq_bit_idx);
>>   	writel_relaxed(reg, clk_base + pllu.params->ext_misc_reg[0]);
>> -	udelay(5);
>> +	fence_udelay(5, clk_base);
>>   
>>   	reg = readl_relaxed(clk_base + PLLU_BASE);
>>   	reg &= ~GENMASK(20, 0);
>> @@ -2844,13 +2851,13 @@ static int tegra210_enable_pllu(void)
>>   	reg |= fentry->n << 8;
>>   	reg |= fentry->p << 16;
>>   	writel(reg, clk_base + PLLU_BASE);
>> -	udelay(1);
>> +	fence_udelay(1, clk_base);
> These udelay() -> fence_udelay() seem like they should be a separate
> patch.
>
>>   	reg |= PLL_ENABLE;
>>   	writel(reg, clk_base + PLLU_BASE);
>> +	fence_udelay(1, clk_base);
>>   
>> -	readl_relaxed_poll_timeout_atomic(clk_base + PLLU_BASE, reg,
>> -					  reg & PLL_BASE_LOCK, 2, 1000);
>> -	if (!(reg & PLL_BASE_LOCK)) {
>> +	ret = tegra210_wait_for_mask(&pllu, PLLU_BASE, PLL_BASE_LOCK);
>> +	if (ret) {
>>   		pr_err("Timed out waiting for PLL_U to lock\n");
>>   		return -ETIMEDOUT;
>>   	}
>> @@ -2890,12 +2897,12 @@ static int tegra210_init_pllu(void)
>>   		reg = readl_relaxed(clk_base + XUSB_PLL_CFG0);
>>   		reg &= ~XUSB_PLL_CFG0_PLLU_LOCK_DLY_MASK;
>>   		writel_relaxed(reg, clk_base + XUSB_PLL_CFG0);
>> -		udelay(1);
>> +		fence_udelay(1, clk_base);
>>   
>>   		reg = readl_relaxed(clk_base + PLLU_HW_PWRDN_CFG0);
>>   		reg |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
>>   		writel_relaxed(reg, clk_base + PLLU_HW_PWRDN_CFG0);
>> -		udelay(1);
>> +		fence_udelay(1, clk_base);
>>   
>>   		reg = readl_relaxed(clk_base + PLLU_BASE);
>>   		reg &= ~PLLU_BASE_CLKENABLE_USB;
>> @@ -3282,6 +3289,188 @@ static void tegra210_disable_cpu_clock(u32 cpu)
>>   }
>>   
>>   #ifdef CONFIG_PM_SLEEP
>> +static u32 cpu_softrst_ctx[3];
>> +static struct platform_device *dfll_pdev;
>> +static u32 *periph_clk_src_ctx;
>> +struct periph_source_bank {
> Blank line between the above two.
>
>> +	u32 start;
>> +	u32 end;
>> +};
>> +
>> +static struct periph_source_bank periph_srcs[] = {
>> +	[0] = {
>> +		.start = 0x100,
>> +		.end = 0x198,
>> +	},
>> +	[1] = {
>> +		.start = 0x1a0,
>> +		.end = 0x1f8,
>> +	},
>> +	[2] = {
>> +		.start = 0x3b4,
>> +		.end = 0x42c,
>> +	},
>> +	[3] = {
>> +		.start = 0x49c,
>> +		.end = 0x4b4,
>> +	},
>> +	[4] = {
>> +		.start = 0x560,
>> +		.end = 0x564,
>> +	},
>> +	[5] = {
>> +		.start = 0x600,
>> +		.end = 0x678,
>> +	},
>> +	[6] = {
>> +		.start = 0x694,
>> +		.end = 0x6a0,
>> +	},
>> +	[7] = {
>> +		.start = 0x6b8,
>> +		.end = 0x718,
>> +	},
>> +};
>> +
>> +/* This array lists the valid clocks for each periph clk bank */
>> +static u32 periph_clks_on[] = {
>> +	0xdcd7dff9,
>> +	0x87d1f3e7,
>> +	0xf3fed3fa,
>> +	0xffc18cfb,
>> +	0x793fb7ff,
>> +	0x3fe66fff,
>> +	0xfc1fc7ff,
>> +};
> Hm... this is a bunch of magic. Perhaps replace this by a list of the
> clock IDs? That's perhaps a little more verbose, but if we ever need to
> tweak the list of IDs in that periph_clks_on array, that'll be quite the
> challenge.
>
> Also, is this list a "guess" or are these all guaranteed to be always
> on? What if some of these ended up getting disabled as part of suspend
> already (by their users). If we force them on, won't their references
> become unbalanced if the driver later enables them again on resume?

Yes, will replace with list of peripheral clock names..

This list is not a guess. Each entry of this list maps to CLK_ENB set 
register.

Total 7 registers are available and each bit of these registers is for 
enable/disable clock to corresponding peripheral.

Some of the bits are off as those peripheral clocks don't need to be 
enabled as we are not changing source or not using them like MIPIBIF, 
PLLG_REF..

This list of peripheral clocks are enabled during resume before changing 
clock sources and after clock source update, they are restored back to 
the state they were before suspend. So their references don't become 
unbalanced.

>> +
>> +static struct platform_device *dfll_pdev;
> I think you already predeclared this one above.
>
>> +#define car_readl(_base, _off) readl_relaxed(clk_base + (_base) + ((_off) * 4))
>> +#define car_writel(_val, _base, _off) \
>> +		writel_relaxed(_val, clk_base + (_base) + ((_off) * 4))
>> +
>> +static u32 * __init tegra210_init_suspend_ctx(void)
>> +{
>> +	int i, size = 0;
> Can both be unsigned int.
>
>> +
>> +	for (i = 0; i < ARRAY_SIZE(periph_srcs); i++)
>> +		size += periph_srcs[i].end - periph_srcs[i].start + 4;
>> +
>> +	periph_clk_src_ctx = kmalloc(size, GFP_KERNEL);
>> +
>> +	return periph_clk_src_ctx;
> It's somewhat wasteful to return a global variable since you can access
> it anyway. Perhaps it'd be more useful to make the function return a
> boolean?
>
>> +}
>> +
>> +static int tegra210_clk_suspend(void)
>> +{
>> +	int i;
> unsigned int.
>
>> +	unsigned long off;
>> +	struct device_node *node;
>> +	u32 *clk_rst_ctx = periph_clk_src_ctx;
>> +	u32 val;
>> +
>> +	tegra_cclkg_burst_policy_save_context();
>> +
>> +	if (!dfll_pdev) {
>> +		node = of_find_compatible_node(NULL, NULL,
>> +					       "nvidia,tegra210-dfll");
>> +		if (node)
>> +			dfll_pdev = of_find_device_by_node(node);
>> +		of_node_put(node);
>> +		if (!dfll_pdev)
>> +			pr_err("dfll node not found. no suspend for dfll\n");
>> +	}
> Wouldn't it make sense to run this only once, perhaps as part of
> tegra210_init_suspend_ctx()?
>
>> +
>> +	if (dfll_pdev)
>> +		tegra_dfll_suspend(dfll_pdev);
>> +
>> +	/* Enable PLLP_OUT_CPU after dfll suspend */
>> +	val = car_readl(CLK_OUT_ENB_Y, 0);
>> +	val |= CLK_ENB_PLLP_OUT_CPU;
>> +	car_writel(val, CLK_OUT_ENB_Y, 0);
>> +
>> +	tegra_clk_periph_suspend(clk_base);
>> +
>> +	for (i = 0; i < ARRAY_SIZE(periph_srcs); i++)
>> +		for (off = periph_srcs[i].start; off <= periph_srcs[i].end;
>> +		     off += 4)
>> +			*clk_rst_ctx++ = car_readl(off, 0);
>> +
>> +	tegra_sclk_cclklp_burst_policy_save_context();
>> +
>> +	for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
>> +		cpu_softrst_ctx[i] = car_readl(CPU_SOFTRST_CTRL, i);
>> +
>> +	clk_save_context();
>> +
>> +	return 0;
>> +}
>> +
>> +static void tegra210_clk_resume(void)
>> +{
>> +	int i;
>> +	unsigned long off;
>> +	u32 val;
>> +	u32 *clk_rst_ctx = periph_clk_src_ctx;
>> +	struct clk_hw *parent;
>> +	struct clk *clk;
>> +
>> +	for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
>> +		car_writel(cpu_softrst_ctx[i], CPU_SOFTRST_CTRL, i);
>> +
>> +	tegra_clk_osc_resume(clk_base);
>> +
>> +	/*
>> +	 * restore all the plls before configuring clocks and resetting
>> +	 * the devices.
>> +	 */
>> +	tegra210_init_pllu();
>> +	tegra_sclk_cpulp_burst_policy_restore_context();
>> +	clk_restore_context();
>> +
>> +	/* enable all clocks before configuring clock sources */
>> +	tegra_clk_periph_force_on(periph_clks_on, ARRAY_SIZE(periph_clks_on),
>> +				  clk_base);
>> +	/* wait for all writes to happen to have all the clocks enabled */
>> +	wmb();
>> +	fence_udelay(2, clk_base);
>> +
>> +	/* restore all the devices clock sources */
>> +	for (i = 0; i < ARRAY_SIZE(periph_srcs); i++)
>> +		for (off = periph_srcs[i].start; off <= periph_srcs[i].end;
>> +		     off += 4)
>> +			car_writel(*clk_rst_ctx++, off, 0);
>> +
>> +	/* propagate and restore resets, restore clock state */
>> +	fence_udelay(5, clk_base);
>> +	tegra_clk_periph_resume(clk_base);
>> +
>> +	/*
>> +	 * restore CPUG clocks:
>> +	 * - enable DFLL in open loop mode
>> +	 * - switch CPUG to DFLL clock source
>> +	 * - close DFLL loop
>> +	 * - sync PLLX state
>> +	 */
>> +	if (dfll_pdev)
>> +		tegra_dfll_resume(dfll_pdev, false);
>> +
>> +	tegra_cclkg_burst_policy_restore_context();
>> +	fence_udelay(2, clk_base);
>> +
>> +	if (dfll_pdev)
>> +		tegra_dfll_resume(dfll_pdev, true);
>> +
>> +	parent = clk_hw_get_parent(__clk_get_hw(clks[TEGRA210_CLK_CCLK_G]));
>> +	clk = clks[TEGRA210_CLK_PLL_X];
>> +	if (parent != __clk_get_hw(clk))
>> +		tegra_clk_sync_state_pll(__clk_get_hw(clk));
>> +
>> +	/* Disable PLL_OUT_CPU after DFLL resume */
>> +	val = car_readl(CLK_OUT_ENB_Y, 0);
>> +	val &= ~CLK_ENB_PLLP_OUT_CPU;
>> +	car_writel(val, CLK_OUT_ENB_Y, 0);
>> +}
> I'm surprised by the amount of work that we need to do here. I had hoped
> that the clock framework's save/restore infrastructure would be enough.
> I suppose you do call clk_restore_context() somewhere in there, so maybe
> this really is as good as it gets.
>
> Thierry

Reason is there are dependencies b/w the clocks and DFLL resume and 
clocks resume order needed is not same as clock tree list.

during resume as per clock tree, CPU clock configs to use DFLL will 
happen first as its first in the clock tree but DFLL resume should be 
done prior to switching CPU to use from DFLL output.

To resume DFLL, peripheral clocks should be restored.

Considering these dependencies, performing peripheral and DFLL/CPU 
resume in Tegra210 clock driver rather than in corresponding peripheral 
clk_ops using save and restore context callback.

>> +
>>   static void tegra210_cpu_clock_suspend(void)
>>   {
>>   	/* switch coresite to clk_m, save off original source */
>> @@ -3295,8 +3484,20 @@ static void tegra210_cpu_clock_resume(void)
>>   	writel(tegra210_cpu_clk_sctx.clk_csite_src,
>>   				clk_base + CLK_SOURCE_CSITE);
>>   }
>> +#else
>> +#define tegra210_clk_suspend	NULL
>> +#define tegra210_clk_resume	NULL
>> +static inline u32 *tegra210_init_suspend_ctx(void)
>> +{
>> +	return NULL;
>> +}
>>   #endif
>>   
>> +static struct syscore_ops tegra_clk_syscore_ops = {
>> +	.suspend = tegra210_clk_suspend,
>> +	.resume = tegra210_clk_resume,
>> +};
>> +
>>   static struct tegra_cpu_car_ops tegra210_cpu_car_ops = {
>>   	.wait_for_reset	= tegra210_wait_cpu_in_reset,
>>   	.disable_clock	= tegra210_disable_cpu_clock,
>> @@ -3580,5 +3781,8 @@ static void __init tegra210_clock_init(struct device_node *np)
>>   	tegra210_mbist_clk_init();
>>   
>>   	tegra_cpu_car_ops = &tegra210_cpu_car_ops;
>> +
>> +	if (tegra210_init_suspend_ctx())
>> +		register_syscore_ops(&tegra_clk_syscore_ops);
>>   }
>>   CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);
>> -- 
>> 2.7.4
>>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 02/17] pinctrl: tegra: add suspend and resume support
  2019-06-18 17:34           ` Sowjanya Komatineni
@ 2019-06-18 20:00             ` Dmitry Osipenko
  2019-06-18 20:04               ` Sowjanya Komatineni
  2019-06-19  8:31               ` Thierry Reding
  0 siblings, 2 replies; 47+ messages in thread
From: Dmitry Osipenko @ 2019-06-18 20:00 UTC (permalink / raw)
  To: Sowjanya Komatineni, Stephen Warren
  Cc: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland, pdeschrijver, pgaikwad,
	sboyd, linux-clk, linux-gpio, jckuo, josephl, talho, linux-tegra,
	linux-kernel, mperttunen, spatra, robh+dt, devicetree

18.06.2019 20:34, Sowjanya Komatineni пишет:
> 
> On 6/18/19 9:50 AM, Sowjanya Komatineni wrote:
>>
>> On 6/18/19 8:41 AM, Stephen Warren wrote:
>>> On 6/18/19 3:30 AM, Dmitry Osipenko wrote:
>>>> 18.06.2019 12:22, Dmitry Osipenko пишет:
>>>>> 18.06.2019 10:46, Sowjanya Komatineni пишет:
>>>>>> This patch adds suspend and resume support for Tegra pinctrl driver
>>>>>> and registers them to syscore so the pinmux settings are restored
>>>>>> before the devices resume.
>>>>>>
>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>> ---
>>>>>>   drivers/pinctrl/tegra/pinctrl-tegra.c    | 62 ++++++++++++++++++++++++++++++++
>>>>>>   drivers/pinctrl/tegra/pinctrl-tegra.h    |  5 +++
>>>>>>   drivers/pinctrl/tegra/pinctrl-tegra114.c |  1 +
>>>>>>   drivers/pinctrl/tegra/pinctrl-tegra124.c |  1 +
>>>>>>   drivers/pinctrl/tegra/pinctrl-tegra20.c  |  1 +
>>>>>>   drivers/pinctrl/tegra/pinctrl-tegra210.c | 13 +++++++
>>>>>>   drivers/pinctrl/tegra/pinctrl-tegra30.c  |  1 +
>>>>>>   7 files changed, 84 insertions(+)
>>>>>>
>>>>>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c
>>>>>> b/drivers/pinctrl/tegra/pinctrl-tegra.c
>>>>>> index 34596b246578..ceced30d8bd1 100644
>>>>>> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
>>>>>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
>>>>>> @@ -20,11 +20,16 @@
>>>>>>   #include <linux/pinctrl/pinmux.h>
>>>>>>   #include <linux/pinctrl/pinconf.h>
>>>>>>   #include <linux/slab.h>
>>>>>> +#include <linux/syscore_ops.h>
>>>>>>     #include "../core.h"
>>>>>>   #include "../pinctrl-utils.h"
>>>>>>   #include "pinctrl-tegra.h"
>>>>>>   +#define EMMC2_PAD_CFGPADCTRL_0            0x1c8
>>>>>> +#define EMMC4_PAD_CFGPADCTRL_0            0x1e0
>>>>>> +#define EMMC_DPD_PARKING            (0x1fff << 14)
>>>>>> +
>>>>>>   static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 reg)
>>>>>>   {
>>>>>>       return readl(pmx->regs[bank] + reg);
>>>>>> @@ -619,6 +624,48 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
>>>>>>               pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
>>>>>>           }
>>>>>>       }
>>>>>> +
>>>>>> +    if (pmx->soc->has_park_padcfg) {
>>>>>> +        val = pmx_readl(pmx, 0, EMMC2_PAD_CFGPADCTRL_0);
>>>>>> +        val &= ~EMMC_DPD_PARKING;
>>>>>> +        pmx_writel(pmx, val, 0, EMMC2_PAD_CFGPADCTRL_0);
>>>>>> +
>>>>>> +        val = pmx_readl(pmx, 0, EMMC4_PAD_CFGPADCTRL_0);
>>>>>> +        val &= ~EMMC_DPD_PARKING;
>>>>>> +        pmx_writel(pmx, val, 0, EMMC4_PAD_CFGPADCTRL_0);
>>>>>> +    }
>>>>>> +}
>>>>>
>>>>> Is there any reason why parked_bit can't be changed to parked_bitmask like I was
>>>>> asking in a comment to v2?
>>>>>
>>>>> I suppose that it's more preferable to keep pinctrl-tegra.c platform-agnostic for
>>>>> consistency when possible, hence adding platform specifics here should be discouraged.
>>>>> And then the parked_bitmask will also result in a proper hardware description in the code.
>>>>>
>>>>
>>>> I'm now also vaguely recalling that Stephen Warren had some kind of a "code generator"
>>>> for the pinctrl drivers. So I guess all those tables were auto-generated initially.
>>>>
>>>> Stephen, maybe you could adjust the generator to take into account the bitmask (of
>>>> course if that's a part of the generated code) and then re-gen it all for Sowjanya?
>>>
>>> https://github.com/NVIDIA/tegra-pinmux-scripts holds the scripts that generate
>>> tegra-pinctrlNNN.c. See soc-to-kernel-pinctrl-driver.py. IIRC, tegra-pinctrl.c (the core
>>> file) isn't auto-generated. Sowjanya is welcome to send a patch to that repo if the code
>>> needs to be updated.
>>
>>
>> Hi Dmitry,
>>
>> Just want to be clear on my understanding of your request.
>>
>> "change parked_bit to parked_bitmask" are you requested to change parked_bit of PINGROUP
>> and DRV_PINGROUP to use bitmask value rather than bit position inorder to have parked bit
>> configuration for EMMC PADs as well to happen by masking rather than checking for
>> existence of parked_bit?
>>
>> Trying to understand the reason/benefit for changing parked_bit to parked_bitmask.
> Also, Park bits in CFGPAD registers are not common for all CFGPAD registers. Park bits are
> available only for EMMC and also those bits are used for something else on other CFGPAD
> registers so bitmask can't be common and this also need an update to DRV_PINGROUP macro args
> just only to handle EMMC parked_bitmask. So not sure of the benefit in using bitmask rather

Hi Sowjanya,

The main motivation is to describe hardware properly in the drivers. Why to make a
hacky-looking workaround while you can make things properly? Especially if that doesn't take
much effort.

Stephen, thank you very much for the pointer to the script. Looks like it should be easy to
modify the script accordingly to the required change.

Sowjanya, below is a draft of the change that I'm suggesting. I see this as two separate
patches: first converts drivers to use parked_bitmask, second adds suspend-resume support.

Please note that in the end it's up to you and Tegra/PINCTRL maintainers to decide if this
is a worthwhile change that I'm suggesting. In my opinion it is much better to have a
generic solution rather than to have a special quirk solely for T210.

diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
index 34596b246578..4150da74bd44 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
@@ -613,9 +613,9 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)

 	for (i = 0; i < pmx->soc->ngroups; ++i) {
 		g = &pmx->soc->groups[i];
-		if (g->parked_bit >= 0) {
+		if (g->parked_bitmask != -1) {
 			val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
-			val &= ~(1 << g->parked_bit);
+			val &= ~g->parked_bitmask;
 			pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
 		}
 	}
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
index 287702660783..875eb7a1d838 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra.h
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
@@ -96,7 +96,7 @@ struct tegra_function {
  * @tri_reg:		Tri-state register offset.
  * @tri_bank:		Tri-state register bank.
  * @tri_bit:		Tri-state register bit.
- * @parked_bit:		Parked register bit. -1 if unsupported.
+ * @parked_bitmask:	Parked register bitmask. -1 if unsupported.
  * @einput_bit:		Enable-input register bit.
  * @odrain_bit:		Open-drain register bit.
  * @lock_bit:		Lock register bit.
@@ -146,7 +146,7 @@ struct tegra_pingroup {
 	s32 mux_bit:6;
 	s32 pupd_bit:6;
 	s32 tri_bit:6;
-	s32 parked_bit:6;
+	s32 parked_bitmask:26;
 	s32 einput_bit:6;
 	s32 odrain_bit:6;
 	s32 lock_bit:6;
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra210.c b/drivers/pinctrl/tegra/pinctrl-tegra210.c
index 0b56ad5c9c1c..d2ba13466e06 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra210.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra210.c
@@ -1302,7 +1302,7 @@ static struct tegra_function tegra210_functions[] = {
 		.lock_bit = 7,						\
 		.ioreset_bit = -1,					\
 		.rcv_sel_bit = PINGROUP_BIT_##e_io_hv(10),		\
-		.parked_bit = 5,					\
+		.parked_bitmask = BIT(5),				\
 		.hsm_bit = PINGROUP_BIT_##hsm(9),			\
 		.schmitt_bit = 12,					\
 		.drvtype_bit = PINGROUP_BIT_##drvtype(13),		\
@@ -1320,7 +1320,7 @@ static struct tegra_function tegra210_functions[] = {
 	}

 #define DRV_PINGROUP(pg_name, r, drvdn_b, drvdn_w, drvup_b, drvup_w,	\
-		     slwr_b, slwr_w, slwf_b, slwf_w)			\
+		     slwr_b, slwr_w, slwf_b, slwf_w, prk_mask)		\
 	{								\
 		.name = "drive_" #pg_name,				\
 		.pins = drive_##pg_name##_pins,				\
@@ -1335,7 +1335,7 @@ static struct tegra_function tegra210_functions[] = {
 		.rcv_sel_bit = -1,					\
 		.drv_reg = DRV_PINGROUP_REG(r),				\
 		.drv_bank = 0,						\
-		.parked_bit = -1,					\
+		.parked_bitmask = prk_mask,				\
 		.hsm_bit = -1,						\
 		.schmitt_bit = -1,					\
 		.lpmd_bit = -1,						\
@@ -1516,31 +1516,31 @@ static const struct tegra_pingroup tegra210_groups[] = {
 	PINGROUP(pz5,                  SOC,        RSVD1,  RSVD2, RSVD3, 0x3290, N,   N,       N,
     -1,    -1,      -1,      -1,      -1,      -1,     -1,     -1,     -1),

 	/* pg_name, r, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w */
-	DRV_PINGROUP(pa6,    0x9c0, 12, 5,  20, 5,  -1, -1, -1, -1),
-	DRV_PINGROUP(pcc7,   0x9c4, 12, 5,  20, 5,  -1, -1, -1, -1),
-	DRV_PINGROUP(pe6,    0x9c8, 12, 5,  20, 5,  -1, -1, -1, -1),
-	DRV_PINGROUP(pe7,    0x9cc, 12, 5,  20, 5,  -1, -1, -1, -1),
-	DRV_PINGROUP(ph6,    0x9d0, 12, 5,  20, 5,  -1, -1, -1, -1),
-	DRV_PINGROUP(pk0,    0x9d4, -1, -1, -1, -1, 28, 2,  30, 2),
-	DRV_PINGROUP(pk1,    0x9d8, -1, -1, -1, -1, 28, 2,  30, 2),
-	DRV_PINGROUP(pk2,    0x9dc, -1, -1, -1, -1, 28, 2,  30, 2),
-	DRV_PINGROUP(pk3,    0x9e0, -1, -1, -1, -1, 28, 2,  30, 2),
-	DRV_PINGROUP(pk4,    0x9e4, -1, -1, -1, -1, 28, 2,  30, 2),
-	DRV_PINGROUP(pk5,    0x9e8, -1, -1, -1, -1, 28, 2,  30, 2),
-	DRV_PINGROUP(pk6,    0x9ec, -1, -1, -1, -1, 28, 2,  30, 2),
-	DRV_PINGROUP(pk7,    0x9f0, -1, -1, -1, -1, 28, 2,  30, 2),
-	DRV_PINGROUP(pl0,    0x9f4, -1, -1, -1, -1, 28, 2,  30, 2),
-	DRV_PINGROUP(pl1,    0x9f8, -1, -1, -1, -1, 28, 2,  30, 2),
-	DRV_PINGROUP(pz0,    0x9fc, 12, 7,  20, 7,  -1, -1, -1, -1),
-	DRV_PINGROUP(pz1,    0xa00, 12, 7,  20, 7,  -1, -1, -1, -1),
-	DRV_PINGROUP(pz2,    0xa04, 12, 7,  20, 7,  -1, -1, -1, -1),
-	DRV_PINGROUP(pz3,    0xa08, 12, 7,  20, 7,  -1, -1, -1, -1),
-	DRV_PINGROUP(pz4,    0xa0c, 12, 7,  20, 7,  -1, -1, -1, -1),
-	DRV_PINGROUP(pz5,    0xa10, 12, 7,  20, 7,  -1, -1, -1, -1),
-	DRV_PINGROUP(sdmmc1, 0xa98, 12, 7,  20, 7,  28, 2,  30, 2),
-	DRV_PINGROUP(sdmmc2, 0xa9c, 2,  6,  8,  6,  28, 2,  30, 2),
-	DRV_PINGROUP(sdmmc3, 0xab0, 12, 7,  20, 7,  28, 2,  30, 2),
-	DRV_PINGROUP(sdmmc4, 0xab4, 2,  6,  8,  6,  28, 2,  30, 2),
+	DRV_PINGROUP(pa6,    0x9c0, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
+	DRV_PINGROUP(pcc7,   0x9c4, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
+	DRV_PINGROUP(pe6,    0x9c8, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
+	DRV_PINGROUP(pe7,    0x9cc, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
+	DRV_PINGROUP(ph6,    0x9d0, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
+	DRV_PINGROUP(pk0,    0x9d4, -1, -1, -1, -1, 28, 2,  30, 2, -1),
+	DRV_PINGROUP(pk1,    0x9d8, -1, -1, -1, -1, 28, 2,  30, 2, -1),
+	DRV_PINGROUP(pk2,    0x9dc, -1, -1, -1, -1, 28, 2,  30, 2, -1),
+	DRV_PINGROUP(pk3,    0x9e0, -1, -1, -1, -1, 28, 2,  30, 2, -1),
+	DRV_PINGROUP(pk4,    0x9e4, -1, -1, -1, -1, 28, 2,  30, 2, -1),
+	DRV_PINGROUP(pk5,    0x9e8, -1, -1, -1, -1, 28, 2,  30, 2, -1),
+	DRV_PINGROUP(pk6,    0x9ec, -1, -1, -1, -1, 28, 2,  30, 2, -1),
+	DRV_PINGROUP(pk7,    0x9f0, -1, -1, -1, -1, 28, 2,  30, 2, -1),
+	DRV_PINGROUP(pl0,    0x9f4, -1, -1, -1, -1, 28, 2,  30, 2, -1),
+	DRV_PINGROUP(pl1,    0x9f8, -1, -1, -1, -1, 28, 2,  30, 2, -1),
+	DRV_PINGROUP(pz0,    0x9fc, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
+	DRV_PINGROUP(pz1,    0xa00, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
+	DRV_PINGROUP(pz2,    0xa04, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
+	DRV_PINGROUP(pz3,    0xa08, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
+	DRV_PINGROUP(pz4,    0xa0c, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
+	DRV_PINGROUP(pz5,    0xa10, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
+	DRV_PINGROUP(sdmmc1, 0xa98, 12, 7,  20, 7,  28, 2,  30, 2, -1),
+	DRV_PINGROUP(sdmmc2, 0xa9c, 2,  6,  8,  6,  28, 2,  30, 2, 0x7ffc000),
+	DRV_PINGROUP(sdmmc3, 0xab0, 12, 7,  20, 7,  28, 2,  30, 2, -1),
+	DRV_PINGROUP(sdmmc4, 0xab4, 2,  6,  8,  6,  28, 2,  30, 2, 0x7ffc000),
 };

 static const struct tegra_pinctrl_soc_data tegra210_pinctrl = {

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 02/17] pinctrl: tegra: add suspend and resume support
  2019-06-18 20:00             ` Dmitry Osipenko
@ 2019-06-18 20:04               ` Sowjanya Komatineni
  2019-06-19  8:31               ` Thierry Reding
  1 sibling, 0 replies; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-18 20:04 UTC (permalink / raw)
  To: Dmitry Osipenko, Stephen Warren
  Cc: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland, pdeschrijver, pgaikwad,
	sboyd, linux-clk, linux-gpio, jckuo, josephl, talho, linux-tegra,
	linux-kernel, mperttunen, spatra, robh+dt, devicetree


On 6/18/19 1:00 PM, Dmitry Osipenko wrote:
> 18.06.2019 20:34, Sowjanya Komatineni пишет:
>> On 6/18/19 9:50 AM, Sowjanya Komatineni wrote:
>>> On 6/18/19 8:41 AM, Stephen Warren wrote:
>>>> On 6/18/19 3:30 AM, Dmitry Osipenko wrote:
>>>>> 18.06.2019 12:22, Dmitry Osipenko пишет:
>>>>>> 18.06.2019 10:46, Sowjanya Komatineni пишет:
>>>>>>> This patch adds suspend and resume support for Tegra pinctrl driver
>>>>>>> and registers them to syscore so the pinmux settings are restored
>>>>>>> before the devices resume.
>>>>>>>
>>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>>> ---
>>>>>>>    drivers/pinctrl/tegra/pinctrl-tegra.c    | 62 ++++++++++++++++++++++++++++++++
>>>>>>>    drivers/pinctrl/tegra/pinctrl-tegra.h    |  5 +++
>>>>>>>    drivers/pinctrl/tegra/pinctrl-tegra114.c |  1 +
>>>>>>>    drivers/pinctrl/tegra/pinctrl-tegra124.c |  1 +
>>>>>>>    drivers/pinctrl/tegra/pinctrl-tegra20.c  |  1 +
>>>>>>>    drivers/pinctrl/tegra/pinctrl-tegra210.c | 13 +++++++
>>>>>>>    drivers/pinctrl/tegra/pinctrl-tegra30.c  |  1 +
>>>>>>>    7 files changed, 84 insertions(+)
>>>>>>>
>>>>>>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c
>>>>>>> b/drivers/pinctrl/tegra/pinctrl-tegra.c
>>>>>>> index 34596b246578..ceced30d8bd1 100644
>>>>>>> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
>>>>>>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
>>>>>>> @@ -20,11 +20,16 @@
>>>>>>>    #include <linux/pinctrl/pinmux.h>
>>>>>>>    #include <linux/pinctrl/pinconf.h>
>>>>>>>    #include <linux/slab.h>
>>>>>>> +#include <linux/syscore_ops.h>
>>>>>>>      #include "../core.h"
>>>>>>>    #include "../pinctrl-utils.h"
>>>>>>>    #include "pinctrl-tegra.h"
>>>>>>>    +#define EMMC2_PAD_CFGPADCTRL_0            0x1c8
>>>>>>> +#define EMMC4_PAD_CFGPADCTRL_0            0x1e0
>>>>>>> +#define EMMC_DPD_PARKING            (0x1fff << 14)
>>>>>>> +
>>>>>>>    static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 reg)
>>>>>>>    {
>>>>>>>        return readl(pmx->regs[bank] + reg);
>>>>>>> @@ -619,6 +624,48 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
>>>>>>>                pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
>>>>>>>            }
>>>>>>>        }
>>>>>>> +
>>>>>>> +    if (pmx->soc->has_park_padcfg) {
>>>>>>> +        val = pmx_readl(pmx, 0, EMMC2_PAD_CFGPADCTRL_0);
>>>>>>> +        val &= ~EMMC_DPD_PARKING;
>>>>>>> +        pmx_writel(pmx, val, 0, EMMC2_PAD_CFGPADCTRL_0);
>>>>>>> +
>>>>>>> +        val = pmx_readl(pmx, 0, EMMC4_PAD_CFGPADCTRL_0);
>>>>>>> +        val &= ~EMMC_DPD_PARKING;
>>>>>>> +        pmx_writel(pmx, val, 0, EMMC4_PAD_CFGPADCTRL_0);
>>>>>>> +    }
>>>>>>> +}
>>>>>> Is there any reason why parked_bit can't be changed to parked_bitmask like I was
>>>>>> asking in a comment to v2?
>>>>>>
>>>>>> I suppose that it's more preferable to keep pinctrl-tegra.c platform-agnostic for
>>>>>> consistency when possible, hence adding platform specifics here should be discouraged.
>>>>>> And then the parked_bitmask will also result in a proper hardware description in the code.
>>>>>>
>>>>> I'm now also vaguely recalling that Stephen Warren had some kind of a "code generator"
>>>>> for the pinctrl drivers. So I guess all those tables were auto-generated initially.
>>>>>
>>>>> Stephen, maybe you could adjust the generator to take into account the bitmask (of
>>>>> course if that's a part of the generated code) and then re-gen it all for Sowjanya?
>>>> https://github.com/NVIDIA/tegra-pinmux-scripts holds the scripts that generate
>>>> tegra-pinctrlNNN.c. See soc-to-kernel-pinctrl-driver.py. IIRC, tegra-pinctrl.c (the core
>>>> file) isn't auto-generated. Sowjanya is welcome to send a patch to that repo if the code
>>>> needs to be updated.
>>>
>>> Hi Dmitry,
>>>
>>> Just want to be clear on my understanding of your request.
>>>
>>> "change parked_bit to parked_bitmask" are you requested to change parked_bit of PINGROUP
>>> and DRV_PINGROUP to use bitmask value rather than bit position inorder to have parked bit
>>> configuration for EMMC PADs as well to happen by masking rather than checking for
>>> existence of parked_bit?
>>>
>>> Trying to understand the reason/benefit for changing parked_bit to parked_bitmask.
>> Also, Park bits in CFGPAD registers are not common for all CFGPAD registers. Park bits are
>> available only for EMMC and also those bits are used for something else on other CFGPAD
>> registers so bitmask can't be common and this also need an update to DRV_PINGROUP macro args
>> just only to handle EMMC parked_bitmask. So not sure of the benefit in using bitmask rather
> Hi Sowjanya,
>
> The main motivation is to describe hardware properly in the drivers. Why to make a
> hacky-looking workaround while you can make things properly? Especially if that doesn't take
> much effort.
>
> Stephen, thank you very much for the pointer to the script. Looks like it should be easy to
> modify the script accordingly to the required change.
>
> Sowjanya, below is a draft of the change that I'm suggesting. I see this as two separate
> patches: first converts drivers to use parked_bitmask, second adds suspend-resume support.
>
> Please note that in the end it's up to you and Tegra/PINCTRL maintainers to decide if this
> is a worthwhile change that I'm suggesting. In my opinion it is much better to have a
> generic solution rather than to have a special quirk solely for T210.

OK I can change it. Just thought to find out the reason as I see other 
pinmux field also using as bits rather than bitmask.

Got it now. Will update in next version.

>
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
> index 34596b246578..4150da74bd44 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
> @@ -613,9 +613,9 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
>
>   	for (i = 0; i < pmx->soc->ngroups; ++i) {
>   		g = &pmx->soc->groups[i];
> -		if (g->parked_bit >= 0) {
> +		if (g->parked_bitmask != -1) {
>   			val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
> -			val &= ~(1 << g->parked_bit);
> +			val &= ~g->parked_bitmask;
>   			pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
>   		}
>   	}
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
> index 287702660783..875eb7a1d838 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra.h
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
> @@ -96,7 +96,7 @@ struct tegra_function {
>    * @tri_reg:		Tri-state register offset.
>    * @tri_bank:		Tri-state register bank.
>    * @tri_bit:		Tri-state register bit.
> - * @parked_bit:		Parked register bit. -1 if unsupported.
> + * @parked_bitmask:	Parked register bitmask. -1 if unsupported.
>    * @einput_bit:		Enable-input register bit.
>    * @odrain_bit:		Open-drain register bit.
>    * @lock_bit:		Lock register bit.
> @@ -146,7 +146,7 @@ struct tegra_pingroup {
>   	s32 mux_bit:6;
>   	s32 pupd_bit:6;
>   	s32 tri_bit:6;
> -	s32 parked_bit:6;
> +	s32 parked_bitmask:26;
>   	s32 einput_bit:6;
>   	s32 odrain_bit:6;
>   	s32 lock_bit:6;
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra210.c b/drivers/pinctrl/tegra/pinctrl-tegra210.c
> index 0b56ad5c9c1c..d2ba13466e06 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra210.c
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra210.c
> @@ -1302,7 +1302,7 @@ static struct tegra_function tegra210_functions[] = {
>   		.lock_bit = 7,						\
>   		.ioreset_bit = -1,					\
>   		.rcv_sel_bit = PINGROUP_BIT_##e_io_hv(10),		\
> -		.parked_bit = 5,					\
> +		.parked_bitmask = BIT(5),				\
>   		.hsm_bit = PINGROUP_BIT_##hsm(9),			\
>   		.schmitt_bit = 12,					\
>   		.drvtype_bit = PINGROUP_BIT_##drvtype(13),		\
> @@ -1320,7 +1320,7 @@ static struct tegra_function tegra210_functions[] = {
>   	}
>
>   #define DRV_PINGROUP(pg_name, r, drvdn_b, drvdn_w, drvup_b, drvup_w,	\
> -		     slwr_b, slwr_w, slwf_b, slwf_w)			\
> +		     slwr_b, slwr_w, slwf_b, slwf_w, prk_mask)		\
>   	{								\
>   		.name = "drive_" #pg_name,				\
>   		.pins = drive_##pg_name##_pins,				\
> @@ -1335,7 +1335,7 @@ static struct tegra_function tegra210_functions[] = {
>   		.rcv_sel_bit = -1,					\
>   		.drv_reg = DRV_PINGROUP_REG(r),				\
>   		.drv_bank = 0,						\
> -		.parked_bit = -1,					\
> +		.parked_bitmask = prk_mask,				\
>   		.hsm_bit = -1,						\
>   		.schmitt_bit = -1,					\
>   		.lpmd_bit = -1,						\
> @@ -1516,31 +1516,31 @@ static const struct tegra_pingroup tegra210_groups[] = {
>   	PINGROUP(pz5,                  SOC,        RSVD1,  RSVD2, RSVD3, 0x3290, N,   N,       N,
>       -1,    -1,      -1,      -1,      -1,      -1,     -1,     -1,     -1),
>
>   	/* pg_name, r, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w */
> -	DRV_PINGROUP(pa6,    0x9c0, 12, 5,  20, 5,  -1, -1, -1, -1),
> -	DRV_PINGROUP(pcc7,   0x9c4, 12, 5,  20, 5,  -1, -1, -1, -1),
> -	DRV_PINGROUP(pe6,    0x9c8, 12, 5,  20, 5,  -1, -1, -1, -1),
> -	DRV_PINGROUP(pe7,    0x9cc, 12, 5,  20, 5,  -1, -1, -1, -1),
> -	DRV_PINGROUP(ph6,    0x9d0, 12, 5,  20, 5,  -1, -1, -1, -1),
> -	DRV_PINGROUP(pk0,    0x9d4, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pk1,    0x9d8, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pk2,    0x9dc, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pk3,    0x9e0, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pk4,    0x9e4, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pk5,    0x9e8, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pk6,    0x9ec, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pk7,    0x9f0, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pl0,    0x9f4, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pl1,    0x9f8, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pz0,    0x9fc, 12, 7,  20, 7,  -1, -1, -1, -1),
> -	DRV_PINGROUP(pz1,    0xa00, 12, 7,  20, 7,  -1, -1, -1, -1),
> -	DRV_PINGROUP(pz2,    0xa04, 12, 7,  20, 7,  -1, -1, -1, -1),
> -	DRV_PINGROUP(pz3,    0xa08, 12, 7,  20, 7,  -1, -1, -1, -1),
> -	DRV_PINGROUP(pz4,    0xa0c, 12, 7,  20, 7,  -1, -1, -1, -1),
> -	DRV_PINGROUP(pz5,    0xa10, 12, 7,  20, 7,  -1, -1, -1, -1),
> -	DRV_PINGROUP(sdmmc1, 0xa98, 12, 7,  20, 7,  28, 2,  30, 2),
> -	DRV_PINGROUP(sdmmc2, 0xa9c, 2,  6,  8,  6,  28, 2,  30, 2),
> -	DRV_PINGROUP(sdmmc3, 0xab0, 12, 7,  20, 7,  28, 2,  30, 2),
> -	DRV_PINGROUP(sdmmc4, 0xab4, 2,  6,  8,  6,  28, 2,  30, 2),
> +	DRV_PINGROUP(pa6,    0x9c0, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(pcc7,   0x9c4, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(pe6,    0x9c8, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(pe7,    0x9cc, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(ph6,    0x9d0, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(pk0,    0x9d4, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pk1,    0x9d8, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pk2,    0x9dc, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pk3,    0x9e0, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pk4,    0x9e4, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pk5,    0x9e8, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pk6,    0x9ec, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pk7,    0x9f0, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pl0,    0x9f4, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pl1,    0x9f8, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pz0,    0x9fc, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(pz1,    0xa00, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(pz2,    0xa04, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(pz3,    0xa08, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(pz4,    0xa0c, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(pz5,    0xa10, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(sdmmc1, 0xa98, 12, 7,  20, 7,  28, 2,  30, 2, -1),
> +	DRV_PINGROUP(sdmmc2, 0xa9c, 2,  6,  8,  6,  28, 2,  30, 2, 0x7ffc000),
> +	DRV_PINGROUP(sdmmc3, 0xab0, 12, 7,  20, 7,  28, 2,  30, 2, -1),
> +	DRV_PINGROUP(sdmmc4, 0xab4, 2,  6,  8,  6,  28, 2,  30, 2, 0x7ffc000),
>   };
>
>   static const struct tegra_pinctrl_soc_data tegra210_pinctrl = {

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 11/17] clk: tegra210: support for Tegra210 clocks suspend and resume
  2019-06-18 17:58     ` Sowjanya Komatineni
@ 2019-06-19  8:15       ` Thierry Reding
  2019-06-21 20:44         ` Sowjanya Komatineni
  0 siblings, 1 reply; 47+ messages in thread
From: Thierry Reding @ 2019-06-19  8:15 UTC (permalink / raw)
  To: Sowjanya Komatineni
  Cc: jonathanh, tglx, jason, marc.zyngier, linus.walleij, stefan,
	mark.rutland, pdeschrijver, pgaikwad, sboyd, linux-clk,
	linux-gpio, jckuo, josephl, talho, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree

[-- Attachment #1: Type: text/plain, Size: 14750 bytes --]

On Tue, Jun 18, 2019 at 10:58:40AM -0700, Sowjanya Komatineni wrote:
> 
> On 6/18/19 5:16 AM, Thierry Reding wrote:
> > On Tue, Jun 18, 2019 at 12:46:25AM -0700, Sowjanya Komatineni wrote:
> > > This patch adds system suspend and resume support for Tegra210
> > > clocks.
> > > 
> > > All the CAR controller settings are lost on suspend when core power
> > > goes off.
> > > 
> > > This patch has implementation for saving and restoring all the PLLs
> > > and clocks context during system suspend and resume to have the
> > > system back to operating state.
> > > 
> > > Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> > > ---
> > >   drivers/clk/tegra/clk-tegra210.c | 218 +++++++++++++++++++++++++++++++++++++--
> > >   1 file changed, 211 insertions(+), 7 deletions(-)
> > > 
> > > diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
> > > index e1ba62d2b1a0..c34d92e871f4 100644
> > > --- a/drivers/clk/tegra/clk-tegra210.c
> > > +++ b/drivers/clk/tegra/clk-tegra210.c
> > > @@ -9,10 +9,12 @@
> > >   #include <linux/clkdev.h>
> > >   #include <linux/of.h>
> > >   #include <linux/of_address.h>
> > > +#include <linux/of_platform.h>
> > >   #include <linux/delay.h>
> > >   #include <linux/export.h>
> > >   #include <linux/mutex.h>
> > >   #include <linux/clk/tegra.h>
> > > +#include <linux/syscore_ops.h>
> > >   #include <dt-bindings/clock/tegra210-car.h>
> > >   #include <dt-bindings/reset/tegra210-car.h>
> > >   #include <linux/iopoll.h>
> > > @@ -20,6 +22,7 @@
> > >   #include <soc/tegra/pmc.h>
> > >   #include "clk.h"
> > > +#include "clk-dfll.h"
> > >   #include "clk-id.h"
> > >   /*
> > > @@ -36,6 +39,8 @@
> > >   #define CLK_SOURCE_LA 0x1f8
> > >   #define CLK_SOURCE_SDMMC2 0x154
> > >   #define CLK_SOURCE_SDMMC4 0x164
> > > +#define CLK_OUT_ENB_Y 0x298
> > > +#define CLK_ENB_PLLP_OUT_CPU BIT(31)
> > >   #define PLLC_BASE 0x80
> > >   #define PLLC_OUT 0x84
> > > @@ -225,6 +230,7 @@
> > >   #define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2a8
> > >   #define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2ac
> > > +#define CPU_SOFTRST_CTRL 0x380
> > >   #define LVL2_CLK_GATE_OVRA 0xf8
> > >   #define LVL2_CLK_GATE_OVRC 0x3a0
> > > @@ -2820,6 +2826,7 @@ static int tegra210_enable_pllu(void)
> > >   	struct tegra_clk_pll_freq_table *fentry;
> > >   	struct tegra_clk_pll pllu;
> > >   	u32 reg;
> > > +	int ret;
> > >   	for (fentry = pll_u_freq_table; fentry->input_rate; fentry++) {
> > >   		if (fentry->input_rate == pll_ref_freq)
> > > @@ -2836,7 +2843,7 @@ static int tegra210_enable_pllu(void)
> > >   	reg = readl_relaxed(clk_base + pllu.params->ext_misc_reg[0]);
> > >   	reg &= ~BIT(pllu.params->iddq_bit_idx);
> > >   	writel_relaxed(reg, clk_base + pllu.params->ext_misc_reg[0]);
> > > -	udelay(5);
> > > +	fence_udelay(5, clk_base);
> > >   	reg = readl_relaxed(clk_base + PLLU_BASE);
> > >   	reg &= ~GENMASK(20, 0);
> > > @@ -2844,13 +2851,13 @@ static int tegra210_enable_pllu(void)
> > >   	reg |= fentry->n << 8;
> > >   	reg |= fentry->p << 16;
> > >   	writel(reg, clk_base + PLLU_BASE);
> > > -	udelay(1);
> > > +	fence_udelay(1, clk_base);
> > These udelay() -> fence_udelay() seem like they should be a separate
> > patch.
> > 
> > >   	reg |= PLL_ENABLE;
> > >   	writel(reg, clk_base + PLLU_BASE);
> > > +	fence_udelay(1, clk_base);
> > > -	readl_relaxed_poll_timeout_atomic(clk_base + PLLU_BASE, reg,
> > > -					  reg & PLL_BASE_LOCK, 2, 1000);
> > > -	if (!(reg & PLL_BASE_LOCK)) {
> > > +	ret = tegra210_wait_for_mask(&pllu, PLLU_BASE, PLL_BASE_LOCK);
> > > +	if (ret) {
> > >   		pr_err("Timed out waiting for PLL_U to lock\n");
> > >   		return -ETIMEDOUT;
> > >   	}
> > > @@ -2890,12 +2897,12 @@ static int tegra210_init_pllu(void)
> > >   		reg = readl_relaxed(clk_base + XUSB_PLL_CFG0);
> > >   		reg &= ~XUSB_PLL_CFG0_PLLU_LOCK_DLY_MASK;
> > >   		writel_relaxed(reg, clk_base + XUSB_PLL_CFG0);
> > > -		udelay(1);
> > > +		fence_udelay(1, clk_base);
> > >   		reg = readl_relaxed(clk_base + PLLU_HW_PWRDN_CFG0);
> > >   		reg |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
> > >   		writel_relaxed(reg, clk_base + PLLU_HW_PWRDN_CFG0);
> > > -		udelay(1);
> > > +		fence_udelay(1, clk_base);
> > >   		reg = readl_relaxed(clk_base + PLLU_BASE);
> > >   		reg &= ~PLLU_BASE_CLKENABLE_USB;
> > > @@ -3282,6 +3289,188 @@ static void tegra210_disable_cpu_clock(u32 cpu)
> > >   }
> > >   #ifdef CONFIG_PM_SLEEP
> > > +static u32 cpu_softrst_ctx[3];
> > > +static struct platform_device *dfll_pdev;
> > > +static u32 *periph_clk_src_ctx;
> > > +struct periph_source_bank {
> > Blank line between the above two.
> > 
> > > +	u32 start;
> > > +	u32 end;
> > > +};
> > > +
> > > +static struct periph_source_bank periph_srcs[] = {
> > > +	[0] = {
> > > +		.start = 0x100,
> > > +		.end = 0x198,
> > > +	},
> > > +	[1] = {
> > > +		.start = 0x1a0,
> > > +		.end = 0x1f8,
> > > +	},
> > > +	[2] = {
> > > +		.start = 0x3b4,
> > > +		.end = 0x42c,
> > > +	},
> > > +	[3] = {
> > > +		.start = 0x49c,
> > > +		.end = 0x4b4,
> > > +	},
> > > +	[4] = {
> > > +		.start = 0x560,
> > > +		.end = 0x564,
> > > +	},
> > > +	[5] = {
> > > +		.start = 0x600,
> > > +		.end = 0x678,
> > > +	},
> > > +	[6] = {
> > > +		.start = 0x694,
> > > +		.end = 0x6a0,
> > > +	},
> > > +	[7] = {
> > > +		.start = 0x6b8,
> > > +		.end = 0x718,
> > > +	},
> > > +};
> > > +
> > > +/* This array lists the valid clocks for each periph clk bank */
> > > +static u32 periph_clks_on[] = {
> > > +	0xdcd7dff9,
> > > +	0x87d1f3e7,
> > > +	0xf3fed3fa,
> > > +	0xffc18cfb,
> > > +	0x793fb7ff,
> > > +	0x3fe66fff,
> > > +	0xfc1fc7ff,
> > > +};
> > Hm... this is a bunch of magic. Perhaps replace this by a list of the
> > clock IDs? That's perhaps a little more verbose, but if we ever need to
> > tweak the list of IDs in that periph_clks_on array, that'll be quite the
> > challenge.
> > 
> > Also, is this list a "guess" or are these all guaranteed to be always
> > on? What if some of these ended up getting disabled as part of suspend
> > already (by their users). If we force them on, won't their references
> > become unbalanced if the driver later enables them again on resume?
> 
> Yes, will replace with list of peripheral clock names..
> 
> This list is not a guess. Each entry of this list maps to CLK_ENB set
> register.
> 
> Total 7 registers are available and each bit of these registers is for
> enable/disable clock to corresponding peripheral.
> 
> Some of the bits are off as those peripheral clocks don't need to be enabled
> as we are not changing source or not using them like MIPIBIF, PLLG_REF..
> 
> This list of peripheral clocks are enabled during resume before changing
> clock sources and after clock source update, they are restored back to the
> state they were before suspend. So their references don't become unbalanced.

Okay, good. Can you maybe put a version of that explanation in a comment
on top of the periph_clks_on declaration? And perhaps also describe this
in the commit message.

Or maybe even better, add some comments in the main suspend/resume paths
to sort of "guide" through what's happening.

> > > +
> > > +static struct platform_device *dfll_pdev;
> > I think you already predeclared this one above.
> > 
> > > +#define car_readl(_base, _off) readl_relaxed(clk_base + (_base) + ((_off) * 4))
> > > +#define car_writel(_val, _base, _off) \
> > > +		writel_relaxed(_val, clk_base + (_base) + ((_off) * 4))
> > > +
> > > +static u32 * __init tegra210_init_suspend_ctx(void)
> > > +{
> > > +	int i, size = 0;
> > Can both be unsigned int.
> > 
> > > +
> > > +	for (i = 0; i < ARRAY_SIZE(periph_srcs); i++)
> > > +		size += periph_srcs[i].end - periph_srcs[i].start + 4;
> > > +
> > > +	periph_clk_src_ctx = kmalloc(size, GFP_KERNEL);
> > > +
> > > +	return periph_clk_src_ctx;
> > It's somewhat wasteful to return a global variable since you can access
> > it anyway. Perhaps it'd be more useful to make the function return a
> > boolean?
> > 
> > > +}
> > > +
> > > +static int tegra210_clk_suspend(void)
> > > +{
> > > +	int i;
> > unsigned int.
> > 
> > > +	unsigned long off;
> > > +	struct device_node *node;
> > > +	u32 *clk_rst_ctx = periph_clk_src_ctx;
> > > +	u32 val;
> > > +
> > > +	tegra_cclkg_burst_policy_save_context();
> > > +
> > > +	if (!dfll_pdev) {
> > > +		node = of_find_compatible_node(NULL, NULL,
> > > +					       "nvidia,tegra210-dfll");
> > > +		if (node)
> > > +			dfll_pdev = of_find_device_by_node(node);
> > > +		of_node_put(node);
> > > +		if (!dfll_pdev)
> > > +			pr_err("dfll node not found. no suspend for dfll\n");
> > > +	}
> > Wouldn't it make sense to run this only once, perhaps as part of
> > tegra210_init_suspend_ctx()?
> > 
> > > +
> > > +	if (dfll_pdev)
> > > +		tegra_dfll_suspend(dfll_pdev);
> > > +
> > > +	/* Enable PLLP_OUT_CPU after dfll suspend */
> > > +	val = car_readl(CLK_OUT_ENB_Y, 0);
> > > +	val |= CLK_ENB_PLLP_OUT_CPU;
> > > +	car_writel(val, CLK_OUT_ENB_Y, 0);
> > > +
> > > +	tegra_clk_periph_suspend(clk_base);
> > > +
> > > +	for (i = 0; i < ARRAY_SIZE(periph_srcs); i++)
> > > +		for (off = periph_srcs[i].start; off <= periph_srcs[i].end;
> > > +		     off += 4)
> > > +			*clk_rst_ctx++ = car_readl(off, 0);
> > > +
> > > +	tegra_sclk_cclklp_burst_policy_save_context();
> > > +
> > > +	for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
> > > +		cpu_softrst_ctx[i] = car_readl(CPU_SOFTRST_CTRL, i);
> > > +
> > > +	clk_save_context();
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static void tegra210_clk_resume(void)
> > > +{
> > > +	int i;
> > > +	unsigned long off;
> > > +	u32 val;
> > > +	u32 *clk_rst_ctx = periph_clk_src_ctx;
> > > +	struct clk_hw *parent;
> > > +	struct clk *clk;
> > > +
> > > +	for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
> > > +		car_writel(cpu_softrst_ctx[i], CPU_SOFTRST_CTRL, i);
> > > +
> > > +	tegra_clk_osc_resume(clk_base);
> > > +
> > > +	/*
> > > +	 * restore all the plls before configuring clocks and resetting
> > > +	 * the devices.
> > > +	 */
> > > +	tegra210_init_pllu();
> > > +	tegra_sclk_cpulp_burst_policy_restore_context();
> > > +	clk_restore_context();
> > > +
> > > +	/* enable all clocks before configuring clock sources */
> > > +	tegra_clk_periph_force_on(periph_clks_on, ARRAY_SIZE(periph_clks_on),
> > > +				  clk_base);
> > > +	/* wait for all writes to happen to have all the clocks enabled */
> > > +	wmb();
> > > +	fence_udelay(2, clk_base);
> > > +
> > > +	/* restore all the devices clock sources */
> > > +	for (i = 0; i < ARRAY_SIZE(periph_srcs); i++)
> > > +		for (off = periph_srcs[i].start; off <= periph_srcs[i].end;
> > > +		     off += 4)
> > > +			car_writel(*clk_rst_ctx++, off, 0);
> > > +
> > > +	/* propagate and restore resets, restore clock state */
> > > +	fence_udelay(5, clk_base);
> > > +	tegra_clk_periph_resume(clk_base);
> > > +
> > > +	/*
> > > +	 * restore CPUG clocks:
> > > +	 * - enable DFLL in open loop mode
> > > +	 * - switch CPUG to DFLL clock source
> > > +	 * - close DFLL loop
> > > +	 * - sync PLLX state
> > > +	 */
> > > +	if (dfll_pdev)
> > > +		tegra_dfll_resume(dfll_pdev, false);
> > > +
> > > +	tegra_cclkg_burst_policy_restore_context();
> > > +	fence_udelay(2, clk_base);
> > > +
> > > +	if (dfll_pdev)
> > > +		tegra_dfll_resume(dfll_pdev, true);
> > > +
> > > +	parent = clk_hw_get_parent(__clk_get_hw(clks[TEGRA210_CLK_CCLK_G]));
> > > +	clk = clks[TEGRA210_CLK_PLL_X];
> > > +	if (parent != __clk_get_hw(clk))
> > > +		tegra_clk_sync_state_pll(__clk_get_hw(clk));
> > > +
> > > +	/* Disable PLL_OUT_CPU after DFLL resume */
> > > +	val = car_readl(CLK_OUT_ENB_Y, 0);
> > > +	val &= ~CLK_ENB_PLLP_OUT_CPU;
> > > +	car_writel(val, CLK_OUT_ENB_Y, 0);
> > > +}
> > I'm surprised by the amount of work that we need to do here. I had hoped
> > that the clock framework's save/restore infrastructure would be enough.
> > I suppose you do call clk_restore_context() somewhere in there, so maybe
> > this really is as good as it gets.
> > 
> > Thierry
> 
> Reason is there are dependencies b/w the clocks and DFLL resume and clocks
> resume order needed is not same as clock tree list.
> 
> during resume as per clock tree, CPU clock configs to use DFLL will happen
> first as its first in the clock tree but DFLL resume should be done prior to
> switching CPU to use from DFLL output.
> 
> To resume DFLL, peripheral clocks should be restored.
> 
> Considering these dependencies, performing peripheral and DFLL/CPU resume in
> Tegra210 clock driver rather than in corresponding peripheral clk_ops using
> save and restore context callback.

Okay makes sense. As mentioned above, I think it'd be great if you could
add more comments throughout the tegra210_clk_{suspend,resume}() code to
guide the reader through what you're doing, given that this is far from
obvious. You already do quite a bit of that, but it's perhaps better to
explain more what's going on and, perhaps more importantly, why. You're
currently mostly repeating the code sequence in the code. It'd be great
to have the general suspend/resume sequence detailed and highlight why
the sequence is the way it is and what the dependencies are, etc.

Thierry

> 
> > > +
> > >   static void tegra210_cpu_clock_suspend(void)
> > >   {
> > >   	/* switch coresite to clk_m, save off original source */
> > > @@ -3295,8 +3484,20 @@ static void tegra210_cpu_clock_resume(void)
> > >   	writel(tegra210_cpu_clk_sctx.clk_csite_src,
> > >   				clk_base + CLK_SOURCE_CSITE);
> > >   }
> > > +#else
> > > +#define tegra210_clk_suspend	NULL
> > > +#define tegra210_clk_resume	NULL
> > > +static inline u32 *tegra210_init_suspend_ctx(void)
> > > +{
> > > +	return NULL;
> > > +}
> > >   #endif
> > > +static struct syscore_ops tegra_clk_syscore_ops = {
> > > +	.suspend = tegra210_clk_suspend,
> > > +	.resume = tegra210_clk_resume,
> > > +};
> > > +
> > >   static struct tegra_cpu_car_ops tegra210_cpu_car_ops = {
> > >   	.wait_for_reset	= tegra210_wait_cpu_in_reset,
> > >   	.disable_clock	= tegra210_disable_cpu_clock,
> > > @@ -3580,5 +3781,8 @@ static void __init tegra210_clock_init(struct device_node *np)
> > >   	tegra210_mbist_clk_init();
> > >   	tegra_cpu_car_ops = &tegra210_cpu_car_ops;
> > > +
> > > +	if (tegra210_init_suspend_ctx())
> > > +		register_syscore_ops(&tegra_clk_syscore_ops);
> > >   }
> > >   CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);
> > > -- 
> > > 2.7.4
> > > 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 02/17] pinctrl: tegra: add suspend and resume support
  2019-06-18 20:00             ` Dmitry Osipenko
  2019-06-18 20:04               ` Sowjanya Komatineni
@ 2019-06-19  8:31               ` Thierry Reding
  2019-06-19  8:40                 ` Dmitry Osipenko
  1 sibling, 1 reply; 47+ messages in thread
From: Thierry Reding @ 2019-06-19  8:31 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Sowjanya Komatineni, Stephen Warren, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland, pdeschrijver,
	pgaikwad, sboyd, linux-clk, linux-gpio, jckuo, josephl, talho,
	linux-tegra, linux-kernel, mperttunen, spatra, robh+dt,
	devicetree

[-- Attachment #1: Type: text/plain, Size: 12890 bytes --]

On Tue, Jun 18, 2019 at 11:00:05PM +0300, Dmitry Osipenko wrote:
> 18.06.2019 20:34, Sowjanya Komatineni пишет:
> > 
> > On 6/18/19 9:50 AM, Sowjanya Komatineni wrote:
> >>
> >> On 6/18/19 8:41 AM, Stephen Warren wrote:
> >>> On 6/18/19 3:30 AM, Dmitry Osipenko wrote:
> >>>> 18.06.2019 12:22, Dmitry Osipenko пишет:
> >>>>> 18.06.2019 10:46, Sowjanya Komatineni пишет:
> >>>>>> This patch adds suspend and resume support for Tegra pinctrl driver
> >>>>>> and registers them to syscore so the pinmux settings are restored
> >>>>>> before the devices resume.
> >>>>>>
> >>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> >>>>>> ---
> >>>>>>   drivers/pinctrl/tegra/pinctrl-tegra.c    | 62 ++++++++++++++++++++++++++++++++
> >>>>>>   drivers/pinctrl/tegra/pinctrl-tegra.h    |  5 +++
> >>>>>>   drivers/pinctrl/tegra/pinctrl-tegra114.c |  1 +
> >>>>>>   drivers/pinctrl/tegra/pinctrl-tegra124.c |  1 +
> >>>>>>   drivers/pinctrl/tegra/pinctrl-tegra20.c  |  1 +
> >>>>>>   drivers/pinctrl/tegra/pinctrl-tegra210.c | 13 +++++++
> >>>>>>   drivers/pinctrl/tegra/pinctrl-tegra30.c  |  1 +
> >>>>>>   7 files changed, 84 insertions(+)
> >>>>>>
> >>>>>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c
> >>>>>> b/drivers/pinctrl/tegra/pinctrl-tegra.c
> >>>>>> index 34596b246578..ceced30d8bd1 100644
> >>>>>> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
> >>>>>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
> >>>>>> @@ -20,11 +20,16 @@
> >>>>>>   #include <linux/pinctrl/pinmux.h>
> >>>>>>   #include <linux/pinctrl/pinconf.h>
> >>>>>>   #include <linux/slab.h>
> >>>>>> +#include <linux/syscore_ops.h>
> >>>>>>     #include "../core.h"
> >>>>>>   #include "../pinctrl-utils.h"
> >>>>>>   #include "pinctrl-tegra.h"
> >>>>>>   +#define EMMC2_PAD_CFGPADCTRL_0            0x1c8
> >>>>>> +#define EMMC4_PAD_CFGPADCTRL_0            0x1e0
> >>>>>> +#define EMMC_DPD_PARKING            (0x1fff << 14)
> >>>>>> +
> >>>>>>   static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 reg)
> >>>>>>   {
> >>>>>>       return readl(pmx->regs[bank] + reg);
> >>>>>> @@ -619,6 +624,48 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
> >>>>>>               pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
> >>>>>>           }
> >>>>>>       }
> >>>>>> +
> >>>>>> +    if (pmx->soc->has_park_padcfg) {
> >>>>>> +        val = pmx_readl(pmx, 0, EMMC2_PAD_CFGPADCTRL_0);
> >>>>>> +        val &= ~EMMC_DPD_PARKING;
> >>>>>> +        pmx_writel(pmx, val, 0, EMMC2_PAD_CFGPADCTRL_0);
> >>>>>> +
> >>>>>> +        val = pmx_readl(pmx, 0, EMMC4_PAD_CFGPADCTRL_0);
> >>>>>> +        val &= ~EMMC_DPD_PARKING;
> >>>>>> +        pmx_writel(pmx, val, 0, EMMC4_PAD_CFGPADCTRL_0);
> >>>>>> +    }
> >>>>>> +}
> >>>>>
> >>>>> Is there any reason why parked_bit can't be changed to parked_bitmask like I was
> >>>>> asking in a comment to v2?
> >>>>>
> >>>>> I suppose that it's more preferable to keep pinctrl-tegra.c platform-agnostic for
> >>>>> consistency when possible, hence adding platform specifics here should be discouraged.
> >>>>> And then the parked_bitmask will also result in a proper hardware description in the code.
> >>>>>
> >>>>
> >>>> I'm now also vaguely recalling that Stephen Warren had some kind of a "code generator"
> >>>> for the pinctrl drivers. So I guess all those tables were auto-generated initially.
> >>>>
> >>>> Stephen, maybe you could adjust the generator to take into account the bitmask (of
> >>>> course if that's a part of the generated code) and then re-gen it all for Sowjanya?
> >>>
> >>> https://github.com/NVIDIA/tegra-pinmux-scripts holds the scripts that generate
> >>> tegra-pinctrlNNN.c. See soc-to-kernel-pinctrl-driver.py. IIRC, tegra-pinctrl.c (the core
> >>> file) isn't auto-generated. Sowjanya is welcome to send a patch to that repo if the code
> >>> needs to be updated.
> >>
> >>
> >> Hi Dmitry,
> >>
> >> Just want to be clear on my understanding of your request.
> >>
> >> "change parked_bit to parked_bitmask" are you requested to change parked_bit of PINGROUP
> >> and DRV_PINGROUP to use bitmask value rather than bit position inorder to have parked bit
> >> configuration for EMMC PADs as well to happen by masking rather than checking for
> >> existence of parked_bit?
> >>
> >> Trying to understand the reason/benefit for changing parked_bit to parked_bitmask.
> > Also, Park bits in CFGPAD registers are not common for all CFGPAD registers. Park bits are
> > available only for EMMC and also those bits are used for something else on other CFGPAD
> > registers so bitmask can't be common and this also need an update to DRV_PINGROUP macro args
> > just only to handle EMMC parked_bitmask. So not sure of the benefit in using bitmask rather
> 
> Hi Sowjanya,
> 
> The main motivation is to describe hardware properly in the drivers. Why to make a
> hacky-looking workaround while you can make things properly? Especially if that doesn't take
> much effort.
> 
> Stephen, thank you very much for the pointer to the script. Looks like it should be easy to
> modify the script accordingly to the required change.
> 
> Sowjanya, below is a draft of the change that I'm suggesting. I see this as two separate
> patches: first converts drivers to use parked_bitmask, second adds suspend-resume support.
> 
> Please note that in the end it's up to you and Tegra/PINCTRL maintainers to decide if this
> is a worthwhile change that I'm suggesting. In my opinion it is much better to have a
> generic solution rather than to have a special quirk solely for T210.
> 
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
> index 34596b246578..4150da74bd44 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
> @@ -613,9 +613,9 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
> 
>  	for (i = 0; i < pmx->soc->ngroups; ++i) {
>  		g = &pmx->soc->groups[i];
> -		if (g->parked_bit >= 0) {
> +		if (g->parked_bitmask != -1) {
>  			val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
> -			val &= ~(1 << g->parked_bit);
> +			val &= ~g->parked_bitmask;
>  			pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
>  		}
>  	}
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
> index 287702660783..875eb7a1d838 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra.h
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
> @@ -96,7 +96,7 @@ struct tegra_function {
>   * @tri_reg:		Tri-state register offset.
>   * @tri_bank:		Tri-state register bank.
>   * @tri_bit:		Tri-state register bit.
> - * @parked_bit:		Parked register bit. -1 if unsupported.
> + * @parked_bitmask:	Parked register bitmask. -1 if unsupported.

If we're already moving to a bitmask, wouldn't it be easier to just make
0 the case where it is unsupported?

>   * @einput_bit:		Enable-input register bit.
>   * @odrain_bit:		Open-drain register bit.
>   * @lock_bit:		Lock register bit.
> @@ -146,7 +146,7 @@ struct tegra_pingroup {
>  	s32 mux_bit:6;
>  	s32 pupd_bit:6;
>  	s32 tri_bit:6;
> -	s32 parked_bit:6;
> +	s32 parked_bitmask:26;

If we make parked_bitmask == 0 the case for "unsupported" we could make
this u32 while at it.

>  	s32 einput_bit:6;
>  	s32 odrain_bit:6;
>  	s32 lock_bit:6;
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra210.c b/drivers/pinctrl/tegra/pinctrl-tegra210.c
> index 0b56ad5c9c1c..d2ba13466e06 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra210.c
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra210.c
> @@ -1302,7 +1302,7 @@ static struct tegra_function tegra210_functions[] = {
>  		.lock_bit = 7,						\
>  		.ioreset_bit = -1,					\
>  		.rcv_sel_bit = PINGROUP_BIT_##e_io_hv(10),		\
> -		.parked_bit = 5,					\
> +		.parked_bitmask = BIT(5),				\
>  		.hsm_bit = PINGROUP_BIT_##hsm(9),			\
>  		.schmitt_bit = 12,					\
>  		.drvtype_bit = PINGROUP_BIT_##drvtype(13),		\
> @@ -1320,7 +1320,7 @@ static struct tegra_function tegra210_functions[] = {
>  	}
> 
>  #define DRV_PINGROUP(pg_name, r, drvdn_b, drvdn_w, drvup_b, drvup_w,	\
> -		     slwr_b, slwr_w, slwf_b, slwf_w)			\
> +		     slwr_b, slwr_w, slwf_b, slwf_w, prk_mask)		\
>  	{								\
>  		.name = "drive_" #pg_name,				\
>  		.pins = drive_##pg_name##_pins,				\
> @@ -1335,7 +1335,7 @@ static struct tegra_function tegra210_functions[] = {
>  		.rcv_sel_bit = -1,					\
>  		.drv_reg = DRV_PINGROUP_REG(r),				\
>  		.drv_bank = 0,						\
> -		.parked_bit = -1,					\
> +		.parked_bitmask = prk_mask,				\
>  		.hsm_bit = -1,						\
>  		.schmitt_bit = -1,					\
>  		.lpmd_bit = -1,						\
> @@ -1516,31 +1516,31 @@ static const struct tegra_pingroup tegra210_groups[] = {
>  	PINGROUP(pz5,                  SOC,        RSVD1,  RSVD2, RSVD3, 0x3290, N,   N,       N,
>      -1,    -1,      -1,      -1,      -1,      -1,     -1,     -1,     -1),
> 
>  	/* pg_name, r, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w */
> -	DRV_PINGROUP(pa6,    0x9c0, 12, 5,  20, 5,  -1, -1, -1, -1),
> -	DRV_PINGROUP(pcc7,   0x9c4, 12, 5,  20, 5,  -1, -1, -1, -1),
> -	DRV_PINGROUP(pe6,    0x9c8, 12, 5,  20, 5,  -1, -1, -1, -1),
> -	DRV_PINGROUP(pe7,    0x9cc, 12, 5,  20, 5,  -1, -1, -1, -1),
> -	DRV_PINGROUP(ph6,    0x9d0, 12, 5,  20, 5,  -1, -1, -1, -1),
> -	DRV_PINGROUP(pk0,    0x9d4, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pk1,    0x9d8, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pk2,    0x9dc, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pk3,    0x9e0, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pk4,    0x9e4, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pk5,    0x9e8, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pk6,    0x9ec, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pk7,    0x9f0, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pl0,    0x9f4, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pl1,    0x9f8, -1, -1, -1, -1, 28, 2,  30, 2),
> -	DRV_PINGROUP(pz0,    0x9fc, 12, 7,  20, 7,  -1, -1, -1, -1),
> -	DRV_PINGROUP(pz1,    0xa00, 12, 7,  20, 7,  -1, -1, -1, -1),
> -	DRV_PINGROUP(pz2,    0xa04, 12, 7,  20, 7,  -1, -1, -1, -1),
> -	DRV_PINGROUP(pz3,    0xa08, 12, 7,  20, 7,  -1, -1, -1, -1),
> -	DRV_PINGROUP(pz4,    0xa0c, 12, 7,  20, 7,  -1, -1, -1, -1),
> -	DRV_PINGROUP(pz5,    0xa10, 12, 7,  20, 7,  -1, -1, -1, -1),
> -	DRV_PINGROUP(sdmmc1, 0xa98, 12, 7,  20, 7,  28, 2,  30, 2),
> -	DRV_PINGROUP(sdmmc2, 0xa9c, 2,  6,  8,  6,  28, 2,  30, 2),
> -	DRV_PINGROUP(sdmmc3, 0xab0, 12, 7,  20, 7,  28, 2,  30, 2),
> -	DRV_PINGROUP(sdmmc4, 0xab4, 2,  6,  8,  6,  28, 2,  30, 2),
> +	DRV_PINGROUP(pa6,    0x9c0, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(pcc7,   0x9c4, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(pe6,    0x9c8, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(pe7,    0x9cc, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(ph6,    0x9d0, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(pk0,    0x9d4, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pk1,    0x9d8, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pk2,    0x9dc, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pk3,    0x9e0, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pk4,    0x9e4, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pk5,    0x9e8, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pk6,    0x9ec, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pk7,    0x9f0, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pl0,    0x9f4, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pl1,    0x9f8, -1, -1, -1, -1, 28, 2,  30, 2, -1),
> +	DRV_PINGROUP(pz0,    0x9fc, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(pz1,    0xa00, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(pz2,    0xa04, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(pz3,    0xa08, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(pz4,    0xa0c, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(pz5,    0xa10, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
> +	DRV_PINGROUP(sdmmc1, 0xa98, 12, 7,  20, 7,  28, 2,  30, 2, -1),
> +	DRV_PINGROUP(sdmmc2, 0xa9c, 2,  6,  8,  6,  28, 2,  30, 2, 0x7ffc000),
> +	DRV_PINGROUP(sdmmc3, 0xab0, 12, 7,  20, 7,  28, 2,  30, 2, -1),
> +	DRV_PINGROUP(sdmmc4, 0xab4, 2,  6,  8,  6,  28, 2,  30, 2, 0x7ffc000),

Might be worth adding a new DRV_PINGROUP_PARK (or whatever) macro that
takes the additional parameter. that way we could avoid the extra churn.

Thierry

>  };
> 
>  static const struct tegra_pinctrl_soc_data tegra210_pinctrl = {

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 02/17] pinctrl: tegra: add suspend and resume support
  2019-06-18 15:41       ` Stephen Warren
  2019-06-18 16:50         ` Sowjanya Komatineni
@ 2019-06-19  8:33         ` Thierry Reding
  2019-06-19  8:57           ` Thierry Reding
  1 sibling, 1 reply; 47+ messages in thread
From: Thierry Reding @ 2019-06-19  8:33 UTC (permalink / raw)
  To: Stephen Warren
  Cc: Dmitry Osipenko, Sowjanya Komatineni, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland, pdeschrijver,
	pgaikwad, sboyd, linux-clk, linux-gpio, jckuo, josephl, talho,
	linux-tegra, linux-kernel, mperttunen, spatra, robh+dt,
	devicetree

[-- Attachment #1: Type: text/plain, Size: 3909 bytes --]

On Tue, Jun 18, 2019 at 09:41:03AM -0600, Stephen Warren wrote:
> On 6/18/19 3:30 AM, Dmitry Osipenko wrote:
> > 18.06.2019 12:22, Dmitry Osipenko пишет:
> > > 18.06.2019 10:46, Sowjanya Komatineni пишет:
> > > > This patch adds suspend and resume support for Tegra pinctrl driver
> > > > and registers them to syscore so the pinmux settings are restored
> > > > before the devices resume.
> > > > 
> > > > Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> > > > ---
> > > >   drivers/pinctrl/tegra/pinctrl-tegra.c    | 62 ++++++++++++++++++++++++++++++++
> > > >   drivers/pinctrl/tegra/pinctrl-tegra.h    |  5 +++
> > > >   drivers/pinctrl/tegra/pinctrl-tegra114.c |  1 +
> > > >   drivers/pinctrl/tegra/pinctrl-tegra124.c |  1 +
> > > >   drivers/pinctrl/tegra/pinctrl-tegra20.c  |  1 +
> > > >   drivers/pinctrl/tegra/pinctrl-tegra210.c | 13 +++++++
> > > >   drivers/pinctrl/tegra/pinctrl-tegra30.c  |  1 +
> > > >   7 files changed, 84 insertions(+)
> > > > 
> > > > diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
> > > > index 34596b246578..ceced30d8bd1 100644
> > > > --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
> > > > +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
> > > > @@ -20,11 +20,16 @@
> > > >   #include <linux/pinctrl/pinmux.h>
> > > >   #include <linux/pinctrl/pinconf.h>
> > > >   #include <linux/slab.h>
> > > > +#include <linux/syscore_ops.h>
> > > >   #include "../core.h"
> > > >   #include "../pinctrl-utils.h"
> > > >   #include "pinctrl-tegra.h"
> > > > +#define EMMC2_PAD_CFGPADCTRL_0			0x1c8
> > > > +#define EMMC4_PAD_CFGPADCTRL_0			0x1e0
> > > > +#define EMMC_DPD_PARKING			(0x1fff << 14)
> > > > +
> > > >   static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 reg)
> > > >   {
> > > >   	return readl(pmx->regs[bank] + reg);
> > > > @@ -619,6 +624,48 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
> > > >   			pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
> > > >   		}
> > > >   	}
> > > > +
> > > > +	if (pmx->soc->has_park_padcfg) {
> > > > +		val = pmx_readl(pmx, 0, EMMC2_PAD_CFGPADCTRL_0);
> > > > +		val &= ~EMMC_DPD_PARKING;
> > > > +		pmx_writel(pmx, val, 0, EMMC2_PAD_CFGPADCTRL_0);
> > > > +
> > > > +		val = pmx_readl(pmx, 0, EMMC4_PAD_CFGPADCTRL_0);
> > > > +		val &= ~EMMC_DPD_PARKING;
> > > > +		pmx_writel(pmx, val, 0, EMMC4_PAD_CFGPADCTRL_0);
> > > > +	}
> > > > +}
> > > 
> > > Is there any reason why parked_bit can't be changed to parked_bitmask like I was
> > > asking in a comment to v2?
> > > 
> > > I suppose that it's more preferable to keep pinctrl-tegra.c platform-agnostic for
> > > consistency when possible, hence adding platform specifics here should be discouraged.
> > > And then the parked_bitmask will also result in a proper hardware description in the code.
> > > 
> > 
> > I'm now also vaguely recalling that Stephen Warren had some kind of a "code generator"
> > for the pinctrl drivers. So I guess all those tables were auto-generated initially.
> > 
> > Stephen, maybe you could adjust the generator to take into account the bitmask (of
> > course if that's a part of the generated code) and then re-gen it all for Sowjanya?
> 
> https://github.com/NVIDIA/tegra-pinmux-scripts holds the scripts that
> generate tegra-pinctrlNNN.c. See  	soc-to-kernel-pinctrl-driver.py. IIRC,
> tegra-pinctrl.c (the core file) isn't auto-generated. Sowjanya is welcome to
> send a patch to that repo if the code needs to be updated.

If we want to do that, we may need to start off by bringing the pinmux
scripts up to date with the latest version of the generated files. There
have been a number of changes in the meantime that cause the scripts to
generate a bit of diff with regards to what's currently upstream. Sounds
like something fairly trivial, though.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 02/17] pinctrl: tegra: add suspend and resume support
  2019-06-19  8:31               ` Thierry Reding
@ 2019-06-19  8:40                 ` Dmitry Osipenko
  0 siblings, 0 replies; 47+ messages in thread
From: Dmitry Osipenko @ 2019-06-19  8:40 UTC (permalink / raw)
  To: Thierry Reding, Sowjanya Komatineni
  Cc: Stephen Warren, jonathanh, tglx, jason, marc.zyngier,
	linus.walleij, stefan, mark.rutland, pdeschrijver, pgaikwad,
	sboyd, linux-clk, linux-gpio, jckuo, josephl, talho, linux-tegra,
	linux-kernel, mperttunen, spatra, robh+dt, devicetree

19.06.2019 11:31, Thierry Reding пишет:
> On Tue, Jun 18, 2019 at 11:00:05PM +0300, Dmitry Osipenko wrote:
>> 18.06.2019 20:34, Sowjanya Komatineni пишет:
>>>
>>> On 6/18/19 9:50 AM, Sowjanya Komatineni wrote:
>>>>
>>>> On 6/18/19 8:41 AM, Stephen Warren wrote:
>>>>> On 6/18/19 3:30 AM, Dmitry Osipenko wrote:
>>>>>> 18.06.2019 12:22, Dmitry Osipenko пишет:
>>>>>>> 18.06.2019 10:46, Sowjanya Komatineni пишет:
>>>>>>>> This patch adds suspend and resume support for Tegra pinctrl driver
>>>>>>>> and registers them to syscore so the pinmux settings are restored
>>>>>>>> before the devices resume.
>>>>>>>>
>>>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>>>> ---
>>>>>>>>   drivers/pinctrl/tegra/pinctrl-tegra.c    | 62 ++++++++++++++++++++++++++++++++
>>>>>>>>   drivers/pinctrl/tegra/pinctrl-tegra.h    |  5 +++
>>>>>>>>   drivers/pinctrl/tegra/pinctrl-tegra114.c |  1 +
>>>>>>>>   drivers/pinctrl/tegra/pinctrl-tegra124.c |  1 +
>>>>>>>>   drivers/pinctrl/tegra/pinctrl-tegra20.c  |  1 +
>>>>>>>>   drivers/pinctrl/tegra/pinctrl-tegra210.c | 13 +++++++
>>>>>>>>   drivers/pinctrl/tegra/pinctrl-tegra30.c  |  1 +
>>>>>>>>   7 files changed, 84 insertions(+)
>>>>>>>>
>>>>>>>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c
>>>>>>>> b/drivers/pinctrl/tegra/pinctrl-tegra.c
>>>>>>>> index 34596b246578..ceced30d8bd1 100644
>>>>>>>> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
>>>>>>>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
>>>>>>>> @@ -20,11 +20,16 @@
>>>>>>>>   #include <linux/pinctrl/pinmux.h>
>>>>>>>>   #include <linux/pinctrl/pinconf.h>
>>>>>>>>   #include <linux/slab.h>
>>>>>>>> +#include <linux/syscore_ops.h>
>>>>>>>>     #include "../core.h"
>>>>>>>>   #include "../pinctrl-utils.h"
>>>>>>>>   #include "pinctrl-tegra.h"
>>>>>>>>   +#define EMMC2_PAD_CFGPADCTRL_0            0x1c8
>>>>>>>> +#define EMMC4_PAD_CFGPADCTRL_0            0x1e0
>>>>>>>> +#define EMMC_DPD_PARKING            (0x1fff << 14)
>>>>>>>> +
>>>>>>>>   static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 reg)
>>>>>>>>   {
>>>>>>>>       return readl(pmx->regs[bank] + reg);
>>>>>>>> @@ -619,6 +624,48 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
>>>>>>>>               pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
>>>>>>>>           }
>>>>>>>>       }
>>>>>>>> +
>>>>>>>> +    if (pmx->soc->has_park_padcfg) {
>>>>>>>> +        val = pmx_readl(pmx, 0, EMMC2_PAD_CFGPADCTRL_0);
>>>>>>>> +        val &= ~EMMC_DPD_PARKING;
>>>>>>>> +        pmx_writel(pmx, val, 0, EMMC2_PAD_CFGPADCTRL_0);
>>>>>>>> +
>>>>>>>> +        val = pmx_readl(pmx, 0, EMMC4_PAD_CFGPADCTRL_0);
>>>>>>>> +        val &= ~EMMC_DPD_PARKING;
>>>>>>>> +        pmx_writel(pmx, val, 0, EMMC4_PAD_CFGPADCTRL_0);
>>>>>>>> +    }
>>>>>>>> +}
>>>>>>>
>>>>>>> Is there any reason why parked_bit can't be changed to parked_bitmask like I was
>>>>>>> asking in a comment to v2?
>>>>>>>
>>>>>>> I suppose that it's more preferable to keep pinctrl-tegra.c platform-agnostic for
>>>>>>> consistency when possible, hence adding platform specifics here should be discouraged.
>>>>>>> And then the parked_bitmask will also result in a proper hardware description in the code.
>>>>>>>
>>>>>>
>>>>>> I'm now also vaguely recalling that Stephen Warren had some kind of a "code generator"
>>>>>> for the pinctrl drivers. So I guess all those tables were auto-generated initially.
>>>>>>
>>>>>> Stephen, maybe you could adjust the generator to take into account the bitmask (of
>>>>>> course if that's a part of the generated code) and then re-gen it all for Sowjanya?
>>>>>
>>>>> https://github.com/NVIDIA/tegra-pinmux-scripts holds the scripts that generate
>>>>> tegra-pinctrlNNN.c. See soc-to-kernel-pinctrl-driver.py. IIRC, tegra-pinctrl.c (the core
>>>>> file) isn't auto-generated. Sowjanya is welcome to send a patch to that repo if the code
>>>>> needs to be updated.
>>>>
>>>>
>>>> Hi Dmitry,
>>>>
>>>> Just want to be clear on my understanding of your request.
>>>>
>>>> "change parked_bit to parked_bitmask" are you requested to change parked_bit of PINGROUP
>>>> and DRV_PINGROUP to use bitmask value rather than bit position inorder to have parked bit
>>>> configuration for EMMC PADs as well to happen by masking rather than checking for
>>>> existence of parked_bit?
>>>>
>>>> Trying to understand the reason/benefit for changing parked_bit to parked_bitmask.
>>> Also, Park bits in CFGPAD registers are not common for all CFGPAD registers. Park bits are
>>> available only for EMMC and also those bits are used for something else on other CFGPAD
>>> registers so bitmask can't be common and this also need an update to DRV_PINGROUP macro args
>>> just only to handle EMMC parked_bitmask. So not sure of the benefit in using bitmask rather
>>
>> Hi Sowjanya,
>>
>> The main motivation is to describe hardware properly in the drivers. Why to make a
>> hacky-looking workaround while you can make things properly? Especially if that doesn't take
>> much effort.
>>
>> Stephen, thank you very much for the pointer to the script. Looks like it should be easy to
>> modify the script accordingly to the required change.
>>
>> Sowjanya, below is a draft of the change that I'm suggesting. I see this as two separate
>> patches: first converts drivers to use parked_bitmask, second adds suspend-resume support.
>>
>> Please note that in the end it's up to you and Tegra/PINCTRL maintainers to decide if this
>> is a worthwhile change that I'm suggesting. In my opinion it is much better to have a
>> generic solution rather than to have a special quirk solely for T210.
>>
>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
>> index 34596b246578..4150da74bd44 100644
>> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
>> @@ -613,9 +613,9 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
>>
>>  	for (i = 0; i < pmx->soc->ngroups; ++i) {
>>  		g = &pmx->soc->groups[i];
>> -		if (g->parked_bit >= 0) {
>> +		if (g->parked_bitmask != -1) {
>>  			val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
>> -			val &= ~(1 << g->parked_bit);
>> +			val &= ~g->parked_bitmask;
>>  			pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
>>  		}
>>  	}
>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
>> index 287702660783..875eb7a1d838 100644
>> --- a/drivers/pinctrl/tegra/pinctrl-tegra.h
>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
>> @@ -96,7 +96,7 @@ struct tegra_function {
>>   * @tri_reg:		Tri-state register offset.
>>   * @tri_bank:		Tri-state register bank.
>>   * @tri_bit:		Tri-state register bit.
>> - * @parked_bit:		Parked register bit. -1 if unsupported.
>> + * @parked_bitmask:	Parked register bitmask. -1 if unsupported.
> 
> If we're already moving to a bitmask, wouldn't it be easier to just make
> 0 the case where it is unsupported?
> 
>>   * @einput_bit:		Enable-input register bit.
>>   * @odrain_bit:		Open-drain register bit.
>>   * @lock_bit:		Lock register bit.
>> @@ -146,7 +146,7 @@ struct tegra_pingroup {
>>  	s32 mux_bit:6;
>>  	s32 pupd_bit:6;
>>  	s32 tri_bit:6;
>> -	s32 parked_bit:6;
>> +	s32 parked_bitmask:26;
> 
> If we make parked_bitmask == 0 the case for "unsupported" we could make
> this u32 while at it.
> 
>>  	s32 einput_bit:6;
>>  	s32 odrain_bit:6;
>>  	s32 lock_bit:6;
>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra210.c b/drivers/pinctrl/tegra/pinctrl-tegra210.c
>> index 0b56ad5c9c1c..d2ba13466e06 100644
>> --- a/drivers/pinctrl/tegra/pinctrl-tegra210.c
>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra210.c
>> @@ -1302,7 +1302,7 @@ static struct tegra_function tegra210_functions[] = {
>>  		.lock_bit = 7,						\
>>  		.ioreset_bit = -1,					\
>>  		.rcv_sel_bit = PINGROUP_BIT_##e_io_hv(10),		\
>> -		.parked_bit = 5,					\
>> +		.parked_bitmask = BIT(5),				\
>>  		.hsm_bit = PINGROUP_BIT_##hsm(9),			\
>>  		.schmitt_bit = 12,					\
>>  		.drvtype_bit = PINGROUP_BIT_##drvtype(13),		\
>> @@ -1320,7 +1320,7 @@ static struct tegra_function tegra210_functions[] = {
>>  	}
>>
>>  #define DRV_PINGROUP(pg_name, r, drvdn_b, drvdn_w, drvup_b, drvup_w,	\
>> -		     slwr_b, slwr_w, slwf_b, slwf_w)			\
>> +		     slwr_b, slwr_w, slwf_b, slwf_w, prk_mask)		\
>>  	{								\
>>  		.name = "drive_" #pg_name,				\
>>  		.pins = drive_##pg_name##_pins,				\
>> @@ -1335,7 +1335,7 @@ static struct tegra_function tegra210_functions[] = {
>>  		.rcv_sel_bit = -1,					\
>>  		.drv_reg = DRV_PINGROUP_REG(r),				\
>>  		.drv_bank = 0,						\
>> -		.parked_bit = -1,					\
>> +		.parked_bitmask = prk_mask,				\
>>  		.hsm_bit = -1,						\
>>  		.schmitt_bit = -1,					\
>>  		.lpmd_bit = -1,						\
>> @@ -1516,31 +1516,31 @@ static const struct tegra_pingroup tegra210_groups[] = {
>>  	PINGROUP(pz5,                  SOC,        RSVD1,  RSVD2, RSVD3, 0x3290, N,   N,       N,
>>      -1,    -1,      -1,      -1,      -1,      -1,     -1,     -1,     -1),
>>
>>  	/* pg_name, r, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w */
>> -	DRV_PINGROUP(pa6,    0x9c0, 12, 5,  20, 5,  -1, -1, -1, -1),
>> -	DRV_PINGROUP(pcc7,   0x9c4, 12, 5,  20, 5,  -1, -1, -1, -1),
>> -	DRV_PINGROUP(pe6,    0x9c8, 12, 5,  20, 5,  -1, -1, -1, -1),
>> -	DRV_PINGROUP(pe7,    0x9cc, 12, 5,  20, 5,  -1, -1, -1, -1),
>> -	DRV_PINGROUP(ph6,    0x9d0, 12, 5,  20, 5,  -1, -1, -1, -1),
>> -	DRV_PINGROUP(pk0,    0x9d4, -1, -1, -1, -1, 28, 2,  30, 2),
>> -	DRV_PINGROUP(pk1,    0x9d8, -1, -1, -1, -1, 28, 2,  30, 2),
>> -	DRV_PINGROUP(pk2,    0x9dc, -1, -1, -1, -1, 28, 2,  30, 2),
>> -	DRV_PINGROUP(pk3,    0x9e0, -1, -1, -1, -1, 28, 2,  30, 2),
>> -	DRV_PINGROUP(pk4,    0x9e4, -1, -1, -1, -1, 28, 2,  30, 2),
>> -	DRV_PINGROUP(pk5,    0x9e8, -1, -1, -1, -1, 28, 2,  30, 2),
>> -	DRV_PINGROUP(pk6,    0x9ec, -1, -1, -1, -1, 28, 2,  30, 2),
>> -	DRV_PINGROUP(pk7,    0x9f0, -1, -1, -1, -1, 28, 2,  30, 2),
>> -	DRV_PINGROUP(pl0,    0x9f4, -1, -1, -1, -1, 28, 2,  30, 2),
>> -	DRV_PINGROUP(pl1,    0x9f8, -1, -1, -1, -1, 28, 2,  30, 2),
>> -	DRV_PINGROUP(pz0,    0x9fc, 12, 7,  20, 7,  -1, -1, -1, -1),
>> -	DRV_PINGROUP(pz1,    0xa00, 12, 7,  20, 7,  -1, -1, -1, -1),
>> -	DRV_PINGROUP(pz2,    0xa04, 12, 7,  20, 7,  -1, -1, -1, -1),
>> -	DRV_PINGROUP(pz3,    0xa08, 12, 7,  20, 7,  -1, -1, -1, -1),
>> -	DRV_PINGROUP(pz4,    0xa0c, 12, 7,  20, 7,  -1, -1, -1, -1),
>> -	DRV_PINGROUP(pz5,    0xa10, 12, 7,  20, 7,  -1, -1, -1, -1),
>> -	DRV_PINGROUP(sdmmc1, 0xa98, 12, 7,  20, 7,  28, 2,  30, 2),
>> -	DRV_PINGROUP(sdmmc2, 0xa9c, 2,  6,  8,  6,  28, 2,  30, 2),
>> -	DRV_PINGROUP(sdmmc3, 0xab0, 12, 7,  20, 7,  28, 2,  30, 2),
>> -	DRV_PINGROUP(sdmmc4, 0xab4, 2,  6,  8,  6,  28, 2,  30, 2),
>> +	DRV_PINGROUP(pa6,    0x9c0, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
>> +	DRV_PINGROUP(pcc7,   0x9c4, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
>> +	DRV_PINGROUP(pe6,    0x9c8, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
>> +	DRV_PINGROUP(pe7,    0x9cc, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
>> +	DRV_PINGROUP(ph6,    0x9d0, 12, 5,  20, 5,  -1, -1, -1, -1, -1),
>> +	DRV_PINGROUP(pk0,    0x9d4, -1, -1, -1, -1, 28, 2,  30, 2, -1),
>> +	DRV_PINGROUP(pk1,    0x9d8, -1, -1, -1, -1, 28, 2,  30, 2, -1),
>> +	DRV_PINGROUP(pk2,    0x9dc, -1, -1, -1, -1, 28, 2,  30, 2, -1),
>> +	DRV_PINGROUP(pk3,    0x9e0, -1, -1, -1, -1, 28, 2,  30, 2, -1),
>> +	DRV_PINGROUP(pk4,    0x9e4, -1, -1, -1, -1, 28, 2,  30, 2, -1),
>> +	DRV_PINGROUP(pk5,    0x9e8, -1, -1, -1, -1, 28, 2,  30, 2, -1),
>> +	DRV_PINGROUP(pk6,    0x9ec, -1, -1, -1, -1, 28, 2,  30, 2, -1),
>> +	DRV_PINGROUP(pk7,    0x9f0, -1, -1, -1, -1, 28, 2,  30, 2, -1),
>> +	DRV_PINGROUP(pl0,    0x9f4, -1, -1, -1, -1, 28, 2,  30, 2, -1),
>> +	DRV_PINGROUP(pl1,    0x9f8, -1, -1, -1, -1, 28, 2,  30, 2, -1),
>> +	DRV_PINGROUP(pz0,    0x9fc, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
>> +	DRV_PINGROUP(pz1,    0xa00, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
>> +	DRV_PINGROUP(pz2,    0xa04, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
>> +	DRV_PINGROUP(pz3,    0xa08, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
>> +	DRV_PINGROUP(pz4,    0xa0c, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
>> +	DRV_PINGROUP(pz5,    0xa10, 12, 7,  20, 7,  -1, -1, -1, -1, -1),
>> +	DRV_PINGROUP(sdmmc1, 0xa98, 12, 7,  20, 7,  28, 2,  30, 2, -1),
>> +	DRV_PINGROUP(sdmmc2, 0xa9c, 2,  6,  8,  6,  28, 2,  30, 2, 0x7ffc000),
>> +	DRV_PINGROUP(sdmmc3, 0xab0, 12, 7,  20, 7,  28, 2,  30, 2, -1),
>> +	DRV_PINGROUP(sdmmc4, 0xab4, 2,  6,  8,  6,  28, 2,  30, 2, 0x7ffc000),
> 
> Might be worth adding a new DRV_PINGROUP_PARK (or whatever) macro that
> takes the additional parameter. that way we could avoid the extra churn.

Sounds like a very good call! +1

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 02/17] pinctrl: tegra: add suspend and resume support
  2019-06-19  8:33         ` Thierry Reding
@ 2019-06-19  8:57           ` Thierry Reding
  0 siblings, 0 replies; 47+ messages in thread
From: Thierry Reding @ 2019-06-19  8:57 UTC (permalink / raw)
  To: Stephen Warren
  Cc: Dmitry Osipenko, Sowjanya Komatineni, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland, pdeschrijver,
	pgaikwad, sboyd, linux-clk, linux-gpio, jckuo, josephl, talho,
	linux-tegra, linux-kernel, mperttunen, spatra, robh+dt,
	devicetree

[-- Attachment #1: Type: text/plain, Size: 11250 bytes --]

On Wed, Jun 19, 2019 at 10:33:08AM +0200, Thierry Reding wrote:
> On Tue, Jun 18, 2019 at 09:41:03AM -0600, Stephen Warren wrote:
> > On 6/18/19 3:30 AM, Dmitry Osipenko wrote:
> > > 18.06.2019 12:22, Dmitry Osipenko пишет:
> > > > 18.06.2019 10:46, Sowjanya Komatineni пишет:
> > > > > This patch adds suspend and resume support for Tegra pinctrl driver
> > > > > and registers them to syscore so the pinmux settings are restored
> > > > > before the devices resume.
> > > > > 
> > > > > Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> > > > > ---
> > > > >   drivers/pinctrl/tegra/pinctrl-tegra.c    | 62 ++++++++++++++++++++++++++++++++
> > > > >   drivers/pinctrl/tegra/pinctrl-tegra.h    |  5 +++
> > > > >   drivers/pinctrl/tegra/pinctrl-tegra114.c |  1 +
> > > > >   drivers/pinctrl/tegra/pinctrl-tegra124.c |  1 +
> > > > >   drivers/pinctrl/tegra/pinctrl-tegra20.c  |  1 +
> > > > >   drivers/pinctrl/tegra/pinctrl-tegra210.c | 13 +++++++
> > > > >   drivers/pinctrl/tegra/pinctrl-tegra30.c  |  1 +
> > > > >   7 files changed, 84 insertions(+)
> > > > > 
> > > > > diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
> > > > > index 34596b246578..ceced30d8bd1 100644
> > > > > --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
> > > > > +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
> > > > > @@ -20,11 +20,16 @@
> > > > >   #include <linux/pinctrl/pinmux.h>
> > > > >   #include <linux/pinctrl/pinconf.h>
> > > > >   #include <linux/slab.h>
> > > > > +#include <linux/syscore_ops.h>
> > > > >   #include "../core.h"
> > > > >   #include "../pinctrl-utils.h"
> > > > >   #include "pinctrl-tegra.h"
> > > > > +#define EMMC2_PAD_CFGPADCTRL_0			0x1c8
> > > > > +#define EMMC4_PAD_CFGPADCTRL_0			0x1e0
> > > > > +#define EMMC_DPD_PARKING			(0x1fff << 14)
> > > > > +
> > > > >   static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 reg)
> > > > >   {
> > > > >   	return readl(pmx->regs[bank] + reg);
> > > > > @@ -619,6 +624,48 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
> > > > >   			pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
> > > > >   		}
> > > > >   	}
> > > > > +
> > > > > +	if (pmx->soc->has_park_padcfg) {
> > > > > +		val = pmx_readl(pmx, 0, EMMC2_PAD_CFGPADCTRL_0);
> > > > > +		val &= ~EMMC_DPD_PARKING;
> > > > > +		pmx_writel(pmx, val, 0, EMMC2_PAD_CFGPADCTRL_0);
> > > > > +
> > > > > +		val = pmx_readl(pmx, 0, EMMC4_PAD_CFGPADCTRL_0);
> > > > > +		val &= ~EMMC_DPD_PARKING;
> > > > > +		pmx_writel(pmx, val, 0, EMMC4_PAD_CFGPADCTRL_0);
> > > > > +	}
> > > > > +}
> > > > 
> > > > Is there any reason why parked_bit can't be changed to parked_bitmask like I was
> > > > asking in a comment to v2?
> > > > 
> > > > I suppose that it's more preferable to keep pinctrl-tegra.c platform-agnostic for
> > > > consistency when possible, hence adding platform specifics here should be discouraged.
> > > > And then the parked_bitmask will also result in a proper hardware description in the code.
> > > > 
> > > 
> > > I'm now also vaguely recalling that Stephen Warren had some kind of a "code generator"
> > > for the pinctrl drivers. So I guess all those tables were auto-generated initially.
> > > 
> > > Stephen, maybe you could adjust the generator to take into account the bitmask (of
> > > course if that's a part of the generated code) and then re-gen it all for Sowjanya?
> > 
> > https://github.com/NVIDIA/tegra-pinmux-scripts holds the scripts that
> > generate tegra-pinctrlNNN.c. See  	soc-to-kernel-pinctrl-driver.py. IIRC,
> > tegra-pinctrl.c (the core file) isn't auto-generated. Sowjanya is welcome to
> > send a patch to that repo if the code needs to be updated.
> 
> If we want to do that, we may need to start off by bringing the pinmux
> scripts up to date with the latest version of the generated files. There
> have been a number of changes in the meantime that cause the scripts to
> generate a bit of diff with regards to what's currently upstream. Sounds
> like something fairly trivial, though.

Something like the below should do the trick.

Thierry

--- >8 ---
From 9a684d2ad3c0e0c7b4dbda5904db1fda3757072b Mon Sep 17 00:00:00 2001
From: Thierry Reding <treding@nvidia.com>
Date: Wed, 19 Jun 2019 10:50:57 +0200
Subject: [pinmux scripts PATCH] Update kernel driver template

Some changes in recent years have modified the upstream kernel driver in
some ways that make it incompatible with the current template. Update
the template to take into account changes introduced by the following
commits:

	commit e3d2160f12d6aa7a87d9db09d8458b4a3492cd45
	Author: Paul Gortmaker <paul.gortmaker@windriver.com>
	Date:   Mon May 22 16:56:47 2017 -0400

	    pinctrl: tegra: clean up modular vs. non-modular distinctions

	    None of the Kconfigs for any of these drivers are tristate,
	    meaning that they currently are not being built as a module by anyone.

	    Lets remove the modular code that is essentially orphaned, so that
	    when reading the drivers there is no doubt they are builtin-only.  All
	    drivers get similar changes, so they are handled in batch.

	    We remove module.h from code that isn't doing anything modular at
	    all;  if they have __init sections, then replace it with init.h.

	    A couple drivers have module_exit() code that is essentially orphaned,
	    and so we remove that.

	    Quite a few bool drivers (hence non-modular) are converted over to
	    to builtin_platform_driver().

	    Since module_platform_driver() uses the same init level priority as
	    builtin_platform_driver() the init ordering remains unchanged with
	    this commit.

	    Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code.

	    We also delete the MODULE_LICENSE tag etc. since all that information
	    was (or is now) contained at the top of the file in the comments.

	    Cc: Linus Walleij <linus.walleij@linaro.org>
	    Cc: Stephen Warren <swarren@wwwdotorg.org>
	    Cc: Thierry Reding <thierry.reding@gmail.com>
	    Cc: Alexandre Courbot <gnurou@gmail.com>
	    Cc: Pritesh Raithatha <praithatha@nvidia.com>
	    Cc: Ashwini Ghuge <aghuge@nvidia.com>
	    Cc: linux-gpio@vger.kernel.org
	    Cc: linux-tegra@vger.kernel.org
	    Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
	    Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

	commit 3c94d2d08a032d911bbe34f2edb24cb63a63644a
	Author: Stefan Agner <stefan@agner.ch>
	Date:   Thu Jul 26 17:40:24 2018 +0200

	    pinctrl: tegra: define GPIO compatible node per SoC

	    Tegra 2 uses a different GPIO controller which uses "tegra20-gpio" as
	    compatible string.

	    Make the compatible string the GPIO node is using a SoC specific
	    property. This prevents the kernel from registering the GPIO range
	    twice in case the GPIO range is specified in the device tree.

	    Fixes: 9462510ce31e ("pinctrl: tegra: Only set the gpio range if needed")
	    Signed-off-by: Stefan Agner <stefan@agner.ch>
	    Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

	commit 1e0813ee5599932c856bda64a568895ed7a33d3a
	Author: Dmitry Osipenko <digetx@gmail.com>
	Date:   Thu Aug 2 14:11:43 2018 +0300

	    pinctrl: tegra: Move drivers registration to arch_init level

	    There is a bug in regards to deferred probing within the drivers core
	    that causes GPIO-driver to suspend after its users. The bug appears if
	    GPIO-driver probe is getting deferred, which happens after introducing
	    dependency on PINCTRL-driver for the GPIO-driver by defining "gpio-ranges"
	    property in device-tree. The bug in the drivers core is old (more than 4
	    years now) and is well known, unfortunately there is no easy fix for it.
	    The good news is that we can workaround the deferred probe issue by
	    changing GPIO / PINCTRL drivers registration order and hence by moving
	    PINCTRL driver registration to the arch_init level and GPIO to the
	    subsys_init.

	    Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
	    Acked-by: Stefan Agner <stefan@agner.ch>
	    Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

Note that the last one is something that we probably should fix
correctly by using device links rather than working around it by playing
init level tricks.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 soc-to-kernel-pinctrl-driver.py | 27 +++++++++++----------------
 1 file changed, 11 insertions(+), 16 deletions(-)

diff --git a/soc-to-kernel-pinctrl-driver.py b/soc-to-kernel-pinctrl-driver.py
index 65e4c604f1c9..37f34b15db2b 100755
--- a/soc-to-kernel-pinctrl-driver.py
+++ b/soc-to-kernel-pinctrl-driver.py
@@ -41,22 +41,16 @@ if dbg: print(args)
 soc = tegra_pmx_soc_parser.load_soc(args.soc)
 
 print('''\
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Pinctrl data for the NVIDIA %s pinmux
  *
- * Copyright (c) %s, NVIDIA CORPORATION.  All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
+ * Author: %s
  *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
+ * Copyright (c) %s, NVIDIA CORPORATION.  All rights reserved.
  */
 
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -68,7 +62,7 @@ print('''\
  * Most pins affected by the pinmux can also be GPIOs. Define these first.
  * These must match how the GPIO driver names/numbers its pins.
  */
-''' % (soc.titlename, soc.kernel_copyright_years), end='')
+''' % (soc.titlename, soc.kernel_author, soc.kernel_copyright_years), end='')
 
 # Do not add any more exceptions here; new SoCs should be formatted correctly
 if soc.name == 'tegra30':
@@ -615,6 +609,7 @@ print('''\
 
 static const struct tegra_pinctrl_soc_data %(soc)s_pinctrl = {
 	.ngpios = NUM_GPIOS,
+	.gpio_compatible = "nvidia,%(soc)s-gpio",
 	.pins = %(soc)s_pins,
 	.npins = ARRAY_SIZE(%(soc)s_pins),
 	.functions = %(soc)s_functions,
@@ -635,7 +630,6 @@ static const struct of_device_id %(soc)s_pinctrl_of_match[] = {
 	{ .compatible = "nvidia,%(soc)s-pinmux", },
 	{ },
 };
-MODULE_DEVICE_TABLE(of, %(soc)s_pinctrl_of_match);
 
 static struct platform_driver %(soc)s_pinctrl_driver = {
 	.driver = {
@@ -644,9 +638,10 @@ static struct platform_driver %(soc)s_pinctrl_driver = {
 	},
 	.probe = %(soc)s_pinctrl_probe,
 };
-module_platform_driver(%(soc)s_pinctrl_driver);
 
-MODULE_AUTHOR("%(author)s");
-MODULE_DESCRIPTION("NVIDIA %(usoc)s pinctrl driver");
-MODULE_LICENSE("GPL v2");
+static int __init %(soc)s_pinctrl_init(void)
+{
+	return platform_driver_register(&%(soc)s_pinctrl_driver);
+}
+arch_initcall(%(soc)s_pinctrl_init);
 ''' % socvars, end='')
-- 
2.21.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 11/17] clk: tegra210: support for Tegra210 clocks suspend and resume
  2019-06-19  8:15       ` Thierry Reding
@ 2019-06-21 20:44         ` Sowjanya Komatineni
  0 siblings, 0 replies; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-21 20:44 UTC (permalink / raw)
  To: Thierry Reding
  Cc: jonathanh, tglx, jason, marc.zyngier, linus.walleij, stefan,
	mark.rutland, pdeschrijver, pgaikwad, sboyd, linux-clk,
	linux-gpio, jckuo, josephl, talho, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, digetx, devicetree


On 6/19/19 1:15 AM, Thierry Reding wrote:
> On Tue, Jun 18, 2019 at 10:58:40AM -0700, Sowjanya Komatineni wrote:
>> On 6/18/19 5:16 AM, Thierry Reding wrote:
>>> On Tue, Jun 18, 2019 at 12:46:25AM -0700, Sowjanya Komatineni wrote:
>>>> This patch adds system suspend and resume support for Tegra210
>>>> clocks.
>>>>
>>>> All the CAR controller settings are lost on suspend when core power
>>>> goes off.
>>>>
>>>> This patch has implementation for saving and restoring all the PLLs
>>>> and clocks context during system suspend and resume to have the
>>>> system back to operating state.
>>>>
>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>> ---
>>>>    drivers/clk/tegra/clk-tegra210.c | 218 +++++++++++++++++++++++++++++++++++++--
>>>>    1 file changed, 211 insertions(+), 7 deletions(-)
>>>>
>>>> diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
>>>> index e1ba62d2b1a0..c34d92e871f4 100644
>>>> --- a/drivers/clk/tegra/clk-tegra210.c
>>>> +++ b/drivers/clk/tegra/clk-tegra210.c
>>>> @@ -9,10 +9,12 @@
>>>>    #include <linux/clkdev.h>
>>>>    #include <linux/of.h>
>>>>    #include <linux/of_address.h>
>>>> +#include <linux/of_platform.h>
>>>>    #include <linux/delay.h>
>>>>    #include <linux/export.h>
>>>>    #include <linux/mutex.h>
>>>>    #include <linux/clk/tegra.h>
>>>> +#include <linux/syscore_ops.h>
>>>>    #include <dt-bindings/clock/tegra210-car.h>
>>>>    #include <dt-bindings/reset/tegra210-car.h>
>>>>    #include <linux/iopoll.h>
>>>> @@ -20,6 +22,7 @@
>>>>    #include <soc/tegra/pmc.h>
>>>>    #include "clk.h"
>>>> +#include "clk-dfll.h"
>>>>    #include "clk-id.h"
>>>>    /*
>>>> @@ -36,6 +39,8 @@
>>>>    #define CLK_SOURCE_LA 0x1f8
>>>>    #define CLK_SOURCE_SDMMC2 0x154
>>>>    #define CLK_SOURCE_SDMMC4 0x164
>>>> +#define CLK_OUT_ENB_Y 0x298
>>>> +#define CLK_ENB_PLLP_OUT_CPU BIT(31)
>>>>    #define PLLC_BASE 0x80
>>>>    #define PLLC_OUT 0x84
>>>> @@ -225,6 +230,7 @@
>>>>    #define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2a8
>>>>    #define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2ac
>>>> +#define CPU_SOFTRST_CTRL 0x380
>>>>    #define LVL2_CLK_GATE_OVRA 0xf8
>>>>    #define LVL2_CLK_GATE_OVRC 0x3a0
>>>> @@ -2820,6 +2826,7 @@ static int tegra210_enable_pllu(void)
>>>>    	struct tegra_clk_pll_freq_table *fentry;
>>>>    	struct tegra_clk_pll pllu;
>>>>    	u32 reg;
>>>> +	int ret;
>>>>    	for (fentry = pll_u_freq_table; fentry->input_rate; fentry++) {
>>>>    		if (fentry->input_rate == pll_ref_freq)
>>>> @@ -2836,7 +2843,7 @@ static int tegra210_enable_pllu(void)
>>>>    	reg = readl_relaxed(clk_base + pllu.params->ext_misc_reg[0]);
>>>>    	reg &= ~BIT(pllu.params->iddq_bit_idx);
>>>>    	writel_relaxed(reg, clk_base + pllu.params->ext_misc_reg[0]);
>>>> -	udelay(5);
>>>> +	fence_udelay(5, clk_base);
>>>>    	reg = readl_relaxed(clk_base + PLLU_BASE);
>>>>    	reg &= ~GENMASK(20, 0);
>>>> @@ -2844,13 +2851,13 @@ static int tegra210_enable_pllu(void)
>>>>    	reg |= fentry->n << 8;
>>>>    	reg |= fentry->p << 16;
>>>>    	writel(reg, clk_base + PLLU_BASE);
>>>> -	udelay(1);
>>>> +	fence_udelay(1, clk_base);
>>> These udelay() -> fence_udelay() seem like they should be a separate
>>> patch.
>>>
>>>>    	reg |= PLL_ENABLE;
>>>>    	writel(reg, clk_base + PLLU_BASE);
>>>> +	fence_udelay(1, clk_base);
>>>> -	readl_relaxed_poll_timeout_atomic(clk_base + PLLU_BASE, reg,
>>>> -					  reg & PLL_BASE_LOCK, 2, 1000);
>>>> -	if (!(reg & PLL_BASE_LOCK)) {
>>>> +	ret = tegra210_wait_for_mask(&pllu, PLLU_BASE, PLL_BASE_LOCK);
>>>> +	if (ret) {
>>>>    		pr_err("Timed out waiting for PLL_U to lock\n");
>>>>    		return -ETIMEDOUT;
>>>>    	}
>>>> @@ -2890,12 +2897,12 @@ static int tegra210_init_pllu(void)
>>>>    		reg = readl_relaxed(clk_base + XUSB_PLL_CFG0);
>>>>    		reg &= ~XUSB_PLL_CFG0_PLLU_LOCK_DLY_MASK;
>>>>    		writel_relaxed(reg, clk_base + XUSB_PLL_CFG0);
>>>> -		udelay(1);
>>>> +		fence_udelay(1, clk_base);
>>>>    		reg = readl_relaxed(clk_base + PLLU_HW_PWRDN_CFG0);
>>>>    		reg |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
>>>>    		writel_relaxed(reg, clk_base + PLLU_HW_PWRDN_CFG0);
>>>> -		udelay(1);
>>>> +		fence_udelay(1, clk_base);
>>>>    		reg = readl_relaxed(clk_base + PLLU_BASE);
>>>>    		reg &= ~PLLU_BASE_CLKENABLE_USB;
>>>> @@ -3282,6 +3289,188 @@ static void tegra210_disable_cpu_clock(u32 cpu)
>>>>    }
>>>>    #ifdef CONFIG_PM_SLEEP
>>>> +static u32 cpu_softrst_ctx[3];
>>>> +static struct platform_device *dfll_pdev;
>>>> +static u32 *periph_clk_src_ctx;
>>>> +struct periph_source_bank {
>>> Blank line between the above two.
>>>
>>>> +	u32 start;
>>>> +	u32 end;
>>>> +};
>>>> +
>>>> +static struct periph_source_bank periph_srcs[] = {
>>>> +	[0] = {
>>>> +		.start = 0x100,
>>>> +		.end = 0x198,
>>>> +	},
>>>> +	[1] = {
>>>> +		.start = 0x1a0,
>>>> +		.end = 0x1f8,
>>>> +	},
>>>> +	[2] = {
>>>> +		.start = 0x3b4,
>>>> +		.end = 0x42c,
>>>> +	},
>>>> +	[3] = {
>>>> +		.start = 0x49c,
>>>> +		.end = 0x4b4,
>>>> +	},
>>>> +	[4] = {
>>>> +		.start = 0x560,
>>>> +		.end = 0x564,
>>>> +	},
>>>> +	[5] = {
>>>> +		.start = 0x600,
>>>> +		.end = 0x678,
>>>> +	},
>>>> +	[6] = {
>>>> +		.start = 0x694,
>>>> +		.end = 0x6a0,
>>>> +	},
>>>> +	[7] = {
>>>> +		.start = 0x6b8,
>>>> +		.end = 0x718,
>>>> +	},
>>>> +};
>>>> +
>>>> +/* This array lists the valid clocks for each periph clk bank */
>>>> +static u32 periph_clks_on[] = {
>>>> +	0xdcd7dff9,
>>>> +	0x87d1f3e7,
>>>> +	0xf3fed3fa,
>>>> +	0xffc18cfb,
>>>> +	0x793fb7ff,
>>>> +	0x3fe66fff,
>>>> +	0xfc1fc7ff,
>>>> +};
>>> Hm... this is a bunch of magic. Perhaps replace this by a list of the
>>> clock IDs? That's perhaps a little more verbose, but if we ever need to
>>> tweak the list of IDs in that periph_clks_on array, that'll be quite the
>>> challenge.
>>>
>>> Also, is this list a "guess" or are these all guaranteed to be always
>>> on? What if some of these ended up getting disabled as part of suspend
>>> already (by their users). If we force them on, won't their references
>>> become unbalanced if the driver later enables them again on resume?
>> Yes, will replace with list of peripheral clock names..
>>
>> This list is not a guess. Each entry of this list maps to CLK_ENB set
>> register.
>>
>> Total 7 registers are available and each bit of these registers is for
>> enable/disable clock to corresponding peripheral.
>>
>> Some of the bits are off as those peripheral clocks don't need to be enabled
>> as we are not changing source or not using them like MIPIBIF, PLLG_REF..
>>
>> This list of peripheral clocks are enabled during resume before changing
>> clock sources and after clock source update, they are restored back to the
>> state they were before suspend. So their references don't become unbalanced.
> Okay, good. Can you maybe put a version of that explanation in a comment
> on top of the periph_clks_on declaration? And perhaps also describe this
> in the commit message.
>
> Or maybe even better, add some comments in the main suspend/resume paths
> to sort of "guide" through what's happening.
>
>>>> +
>>>> +static struct platform_device *dfll_pdev;
>>> I think you already predeclared this one above.
>>>
>>>> +#define car_readl(_base, _off) readl_relaxed(clk_base + (_base) + ((_off) * 4))
>>>> +#define car_writel(_val, _base, _off) \
>>>> +		writel_relaxed(_val, clk_base + (_base) + ((_off) * 4))
>>>> +
>>>> +static u32 * __init tegra210_init_suspend_ctx(void)
>>>> +{
>>>> +	int i, size = 0;
>>> Can both be unsigned int.
>>>
>>>> +
>>>> +	for (i = 0; i < ARRAY_SIZE(periph_srcs); i++)
>>>> +		size += periph_srcs[i].end - periph_srcs[i].start + 4;
>>>> +
>>>> +	periph_clk_src_ctx = kmalloc(size, GFP_KERNEL);
>>>> +
>>>> +	return periph_clk_src_ctx;
>>> It's somewhat wasteful to return a global variable since you can access
>>> it anyway. Perhaps it'd be more useful to make the function return a
>>> boolean?
>>>
>>>> +}
>>>> +
>>>> +static int tegra210_clk_suspend(void)
>>>> +{
>>>> +	int i;
>>> unsigned int.
>>>
>>>> +	unsigned long off;
>>>> +	struct device_node *node;
>>>> +	u32 *clk_rst_ctx = periph_clk_src_ctx;
>>>> +	u32 val;
>>>> +
>>>> +	tegra_cclkg_burst_policy_save_context();
>>>> +
>>>> +	if (!dfll_pdev) {
>>>> +		node = of_find_compatible_node(NULL, NULL,
>>>> +					       "nvidia,tegra210-dfll");
>>>> +		if (node)
>>>> +			dfll_pdev = of_find_device_by_node(node);
>>>> +		of_node_put(node);
>>>> +		if (!dfll_pdev)
>>>> +			pr_err("dfll node not found. no suspend for dfll\n");
>>>> +	}
>>> Wouldn't it make sense to run this only once, perhaps as part of
>>> tegra210_init_suspend_ctx()?

tegra210_init_suspend_ctx is invoked during tegra210_clock_init and as 
clock init happens earlier than dfll probe,

dfll platform device will not be available at that time. So acquiring 
dfll pdev during 1st suspend.

>>>> +
>>>> +	if (dfll_pdev)
>>>> +		tegra_dfll_suspend(dfll_pdev);
>>>> +
>>>> +	/* Enable PLLP_OUT_CPU after dfll suspend */
>>>> +	val = car_readl(CLK_OUT_ENB_Y, 0);
>>>> +	val |= CLK_ENB_PLLP_OUT_CPU;
>>>> +	car_writel(val, CLK_OUT_ENB_Y, 0);
>>>> +
>>>> +	tegra_clk_periph_suspend(clk_base);
>>>> +
>>>> +	for (i = 0; i < ARRAY_SIZE(periph_srcs); i++)
>>>> +		for (off = periph_srcs[i].start; off <= periph_srcs[i].end;
>>>> +		     off += 4)
>>>> +			*clk_rst_ctx++ = car_readl(off, 0);
>>>> +
>>>> +	tegra_sclk_cclklp_burst_policy_save_context();
>>>> +
>>>> +	for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
>>>> +		cpu_softrst_ctx[i] = car_readl(CPU_SOFTRST_CTRL, i);
>>>> +
>>>> +	clk_save_context();
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static void tegra210_clk_resume(void)
>>>> +{
>>>> +	int i;
>>>> +	unsigned long off;
>>>> +	u32 val;
>>>> +	u32 *clk_rst_ctx = periph_clk_src_ctx;
>>>> +	struct clk_hw *parent;
>>>> +	struct clk *clk;
>>>> +
>>>> +	for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
>>>> +		car_writel(cpu_softrst_ctx[i], CPU_SOFTRST_CTRL, i);
>>>> +
>>>> +	tegra_clk_osc_resume(clk_base);
>>>> +
>>>> +	/*
>>>> +	 * restore all the plls before configuring clocks and resetting
>>>> +	 * the devices.
>>>> +	 */
>>>> +	tegra210_init_pllu();
>>>> +	tegra_sclk_cpulp_burst_policy_restore_context();
>>>> +	clk_restore_context();
>>>> +
>>>> +	/* enable all clocks before configuring clock sources */
>>>> +	tegra_clk_periph_force_on(periph_clks_on, ARRAY_SIZE(periph_clks_on),
>>>> +				  clk_base);
>>>> +	/* wait for all writes to happen to have all the clocks enabled */
>>>> +	wmb();
>>>> +	fence_udelay(2, clk_base);
>>>> +
>>>> +	/* restore all the devices clock sources */
>>>> +	for (i = 0; i < ARRAY_SIZE(periph_srcs); i++)
>>>> +		for (off = periph_srcs[i].start; off <= periph_srcs[i].end;
>>>> +		     off += 4)
>>>> +			car_writel(*clk_rst_ctx++, off, 0);
>>>> +
>>>> +	/* propagate and restore resets, restore clock state */
>>>> +	fence_udelay(5, clk_base);
>>>> +	tegra_clk_periph_resume(clk_base);
>>>> +
>>>> +	/*
>>>> +	 * restore CPUG clocks:
>>>> +	 * - enable DFLL in open loop mode
>>>> +	 * - switch CPUG to DFLL clock source
>>>> +	 * - close DFLL loop
>>>> +	 * - sync PLLX state
>>>> +	 */
>>>> +	if (dfll_pdev)
>>>> +		tegra_dfll_resume(dfll_pdev, false);
>>>> +
>>>> +	tegra_cclkg_burst_policy_restore_context();
>>>> +	fence_udelay(2, clk_base);
>>>> +
>>>> +	if (dfll_pdev)
>>>> +		tegra_dfll_resume(dfll_pdev, true);
>>>> +
>>>> +	parent = clk_hw_get_parent(__clk_get_hw(clks[TEGRA210_CLK_CCLK_G]));
>>>> +	clk = clks[TEGRA210_CLK_PLL_X];
>>>> +	if (parent != __clk_get_hw(clk))
>>>> +		tegra_clk_sync_state_pll(__clk_get_hw(clk));
>>>> +
>>>> +	/* Disable PLL_OUT_CPU after DFLL resume */
>>>> +	val = car_readl(CLK_OUT_ENB_Y, 0);
>>>> +	val &= ~CLK_ENB_PLLP_OUT_CPU;
>>>> +	car_writel(val, CLK_OUT_ENB_Y, 0);
>>>> +}
>>> I'm surprised by the amount of work that we need to do here. I had hoped
>>> that the clock framework's save/restore infrastructure would be enough.
>>> I suppose you do call clk_restore_context() somewhere in there, so maybe
>>> this really is as good as it gets.
>>>
>>> Thierry
>> Reason is there are dependencies b/w the clocks and DFLL resume and clocks
>> resume order needed is not same as clock tree list.
>>
>> during resume as per clock tree, CPU clock configs to use DFLL will happen
>> first as its first in the clock tree but DFLL resume should be done prior to
>> switching CPU to use from DFLL output.
>>
>> To resume DFLL, peripheral clocks should be restored.
>>
>> Considering these dependencies, performing peripheral and DFLL/CPU resume in
>> Tegra210 clock driver rather than in corresponding peripheral clk_ops using
>> save and restore context callback.
> Okay makes sense. As mentioned above, I think it'd be great if you could
> add more comments throughout the tegra210_clk_{suspend,resume}() code to
> guide the reader through what you're doing, given that this is far from
> obvious. You already do quite a bit of that, but it's perhaps better to
> explain more what's going on and, perhaps more importantly, why. You're
> currently mostly repeating the code sequence in the code. It'd be great
> to have the general suspend/resume sequence detailed and highlight why
> the sequence is the way it is and what the dependencies are, etc.
>
> Thierry
>
OK, Will add more comments in V4
>>>> +
>>>>    static void tegra210_cpu_clock_suspend(void)
>>>>    {
>>>>    	/* switch coresite to clk_m, save off original source */
>>>> @@ -3295,8 +3484,20 @@ static void tegra210_cpu_clock_resume(void)
>>>>    	writel(tegra210_cpu_clk_sctx.clk_csite_src,
>>>>    				clk_base + CLK_SOURCE_CSITE);
>>>>    }
>>>> +#else
>>>> +#define tegra210_clk_suspend	NULL
>>>> +#define tegra210_clk_resume	NULL
>>>> +static inline u32 *tegra210_init_suspend_ctx(void)
>>>> +{
>>>> +	return NULL;
>>>> +}
>>>>    #endif
>>>> +static struct syscore_ops tegra_clk_syscore_ops = {
>>>> +	.suspend = tegra210_clk_suspend,
>>>> +	.resume = tegra210_clk_resume,
>>>> +};
>>>> +
>>>>    static struct tegra_cpu_car_ops tegra210_cpu_car_ops = {
>>>>    	.wait_for_reset	= tegra210_wait_cpu_in_reset,
>>>>    	.disable_clock	= tegra210_disable_cpu_clock,
>>>> @@ -3580,5 +3781,8 @@ static void __init tegra210_clock_init(struct device_node *np)
>>>>    	tegra210_mbist_clk_init();
>>>>    	tegra_cpu_car_ops = &tegra210_cpu_car_ops;
>>>> +
>>>> +	if (tegra210_init_suspend_ctx())
>>>> +		register_syscore_ops(&tegra_clk_syscore_ops);
>>>>    }
>>>>    CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);
>>>> -- 
>>>> 2.7.4
>>>>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 06/17] clk: tegra: pll: save and restore pll context
  2019-06-18  7:46 ` [PATCH V3 06/17] clk: tegra: pll: save and restore pll context Sowjanya Komatineni
  2019-06-18 11:45   ` Thierry Reding
@ 2019-06-25 20:46   ` Stephen Boyd
  2019-06-25 21:22     ` Sowjanya Komatineni
  1 sibling, 1 reply; 47+ messages in thread
From: Stephen Boyd @ 2019-06-25 20:46 UTC (permalink / raw)
  To: Sowjanya Komatineni, jason, jonathanh, linus.walleij,
	marc.zyngier, mark.rutland, stefan, tglx, thierry.reding
  Cc: pdeschrijver, pgaikwad, linux-clk, linux-gpio, jckuo, josephl,
	talho, skomatineni, linux-tegra, linux-kernel, mperttunen,
	spatra, robh+dt, digetx, devicetree

Quoting Sowjanya Komatineni (2019-06-18 00:46:20)
> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
> index 1583f5fc992f..4b0ed8fc6268 100644
> --- a/drivers/clk/tegra/clk-pll.c
> +++ b/drivers/clk/tegra/clk-pll.c
> @@ -1008,6 +1008,54 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw,
>         return rate;
>  }
>  
> +void tegra_clk_sync_state_pll(struct clk_hw *hw)
> +{
> +       if (!__clk_get_enable_count(hw->clk))
> +               clk_pll_disable(hw);
> +       else
> +               clk_pll_enable(hw);
> +}
> +
> +static int tegra_clk_pll_save_context(struct clk_hw *hw)
> +{
> +       struct tegra_clk_pll *pll = to_clk_pll(hw);
> +
> +       pll->rate = clk_hw_get_rate(hw);
> +
> +       if (!strcmp(__clk_get_name(hw->clk), "pll_mb"))
> +               pll->pllbase_ctx = pll_readl_base(pll);
> +       else if (!strcmp(__clk_get_name(hw->clk), "pll_re_vco"))
> +               pll->pllbase_ctx = pll_readl_base(pll) & (0xf << 16);
> +
> +       return 0;
> +}
> +
> +static void tegra_clk_pll_restore_context(struct clk_hw *hw)
> +{
> +       struct tegra_clk_pll *pll = to_clk_pll(hw);
> +       u32 val;
> +
> +       if (clk_pll_is_enabled(hw))
> +               return;
> +
> +       if (!strcmp(__clk_get_name(hw->clk), "pll_mb")) {

Is there any way to avoid doing a string comparison here, and instead do
something like a pointer comparison? Or maybe look at some flag in the
tegra_clk_pll to figure out what to do differently? Using a string
comparison is not too nice. Or even have different clk ops for the
different clks and then do different things in this restore clk_op?

> +               pll_writel_base(pll->pllbase_ctx, pll);
> +       } else if (!strcmp(__clk_get_name(hw->clk), "pll_re_vco")) {
> +               val = pll_readl_base(pll);
> +               val &= ~(0xf << 16);
> +               pll_writel_base(pll->pllbase_ctx | val, pll);
> +       }
> +
> +       if (pll->params->set_defaults)
> +               pll->params->set_defaults(pll);
> +
> +       clk_set_rate(hw->clk, pll->rate);

Do you need to call clk_set_rate() here to change the frequency of the
clk or just the parents of the clk, or both? I'd think that when we're
restoring the clk the cached rate of the clk would match whatever we're
restoring to, so this is a NOP. So does this do anything?

I'd prefer that the restore ops just restore the clk hardware state of
the clk_hw passed in, and not try to fix up the entire tree around a
certain clk, if that's even possible.

> +
> +       /* do not sync pllx state here. pllx is sync'd after dfll resume */
> +       if (strcmp(__clk_get_name(hw->clk), "pll_x"))
> +               tegra_clk_sync_state_pll(hw);
> +}
> +
>  const struct clk_ops tegra_clk_pll_ops = {
>         .is_enabled = clk_pll_is_enabled,
>         .enable = clk_pll_enable,
> @@ -1015,6 +1063,8 @@ const struct clk_ops tegra_clk_pll_ops = {
>         .recalc_rate = clk_pll_recalc_rate,
>         .round_rate = clk_pll_round_rate,
>         .set_rate = clk_pll_set_rate,
> +       .save_context = tegra_clk_pll_save_context,
> +       .restore_context = tegra_clk_pll_restore_context,

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH V3 06/17] clk: tegra: pll: save and restore pll context
  2019-06-25 20:46   ` Stephen Boyd
@ 2019-06-25 21:22     ` Sowjanya Komatineni
  0 siblings, 0 replies; 47+ messages in thread
From: Sowjanya Komatineni @ 2019-06-25 21:22 UTC (permalink / raw)
  To: Stephen Boyd, jason, jonathanh, linus.walleij, marc.zyngier,
	mark.rutland, stefan, tglx, thierry.reding
  Cc: pdeschrijver, pgaikwad, linux-clk, linux-gpio, jckuo, josephl,
	talho, linux-tegra, linux-kernel, mperttunen, spatra, robh+dt,
	digetx, devicetree


On 6/25/19 1:46 PM, Stephen Boyd wrote:
> Quoting Sowjanya Komatineni (2019-06-18 00:46:20)
>> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
>> index 1583f5fc992f..4b0ed8fc6268 100644
>> --- a/drivers/clk/tegra/clk-pll.c
>> +++ b/drivers/clk/tegra/clk-pll.c
>> @@ -1008,6 +1008,54 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw,
>>          return rate;
>>   }
>>   
>> +void tegra_clk_sync_state_pll(struct clk_hw *hw)
>> +{
>> +       if (!__clk_get_enable_count(hw->clk))
>> +               clk_pll_disable(hw);
>> +       else
>> +               clk_pll_enable(hw);
>> +}
>> +
>> +static int tegra_clk_pll_save_context(struct clk_hw *hw)
>> +{
>> +       struct tegra_clk_pll *pll = to_clk_pll(hw);
>> +
>> +       pll->rate = clk_hw_get_rate(hw);
>> +
>> +       if (!strcmp(__clk_get_name(hw->clk), "pll_mb"))
>> +               pll->pllbase_ctx = pll_readl_base(pll);
>> +       else if (!strcmp(__clk_get_name(hw->clk), "pll_re_vco"))
>> +               pll->pllbase_ctx = pll_readl_base(pll) & (0xf << 16);
>> +
>> +       return 0;
>> +}
>> +
>> +static void tegra_clk_pll_restore_context(struct clk_hw *hw)
>> +{
>> +       struct tegra_clk_pll *pll = to_clk_pll(hw);
>> +       u32 val;
>> +
>> +       if (clk_pll_is_enabled(hw))
>> +               return;
>> +
>> +       if (!strcmp(__clk_get_name(hw->clk), "pll_mb")) {
> Is there any way to avoid doing a string comparison here, and instead do
> something like a pointer comparison? Or maybe look at some flag in the
> tegra_clk_pll to figure out what to do differently? Using a string
> comparison is not too nice. Or even have different clk ops for the
> different clks and then do different things in this restore clk_op?
OK, Will update...
>> +               pll_writel_base(pll->pllbase_ctx, pll);
>> +       } else if (!strcmp(__clk_get_name(hw->clk), "pll_re_vco")) {
>> +               val = pll_readl_base(pll);
>> +               val &= ~(0xf << 16);
>> +               pll_writel_base(pll->pllbase_ctx | val, pll);
>> +       }
>> +
>> +       if (pll->params->set_defaults)
>> +               pll->params->set_defaults(pll);
>> +
>> +       clk_set_rate(hw->clk, pll->rate);
> Do you need to call clk_set_rate() here to change the frequency of the
> clk or just the parents of the clk, or both? I'd think that when we're
> restoring the clk the cached rate of the clk would match whatever we're
> restoring to, so this is a NOP. So does this do anything?
>
> I'd prefer that the restore ops just restore the clk hardware state of
> the clk_hw passed in, and not try to fix up the entire tree around a
> certain clk, if that's even possible.

On restore, need to program tegra plls rate back to the same rate as 
they were before suspend, so I am calling clk_set_rate to program pll 
m,n,p values in hw registers.

>> +
>> +       /* do not sync pllx state here. pllx is sync'd after dfll resume */
>> +       if (strcmp(__clk_get_name(hw->clk), "pll_x"))
>> +               tegra_clk_sync_state_pll(hw);
>> +}
>> +
>>   const struct clk_ops tegra_clk_pll_ops = {
>>          .is_enabled = clk_pll_is_enabled,
>>          .enable = clk_pll_enable,
>> @@ -1015,6 +1063,8 @@ const struct clk_ops tegra_clk_pll_ops = {
>>          .recalc_rate = clk_pll_recalc_rate,
>>          .round_rate = clk_pll_round_rate,
>>          .set_rate = clk_pll_set_rate,
>> +       .save_context = tegra_clk_pll_save_context,
>> +       .restore_context = tegra_clk_pll_restore_context,

^ permalink raw reply	[flat|nested] 47+ messages in thread

end of thread, other threads:[~2019-06-25 21:22 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-18  7:46 [PATCH V3 00/17] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
2019-06-18  7:46 ` [PATCH V3 01/17] irqchip: tegra: do not disable COP IRQ during suspend Sowjanya Komatineni
2019-06-18  9:19   ` Marc Zyngier
2019-06-18 10:58   ` Thierry Reding
2019-06-18  7:46 ` [PATCH V3 02/17] pinctrl: tegra: add suspend and resume support Sowjanya Komatineni
2019-06-18  9:22   ` Dmitry Osipenko
2019-06-18  9:30     ` Dmitry Osipenko
2019-06-18 15:41       ` Stephen Warren
2019-06-18 16:50         ` Sowjanya Komatineni
2019-06-18 17:34           ` Sowjanya Komatineni
2019-06-18 20:00             ` Dmitry Osipenko
2019-06-18 20:04               ` Sowjanya Komatineni
2019-06-19  8:31               ` Thierry Reding
2019-06-19  8:40                 ` Dmitry Osipenko
2019-06-19  8:33         ` Thierry Reding
2019-06-19  8:57           ` Thierry Reding
2019-06-18 11:31   ` Thierry Reding
2019-06-18  7:46 ` [PATCH V3 03/17] gpio: tegra: use resume_noirq for tegra gpio resume Sowjanya Komatineni
2019-06-18 11:39   ` Thierry Reding
2019-06-18  7:46 ` [PATCH V3 04/17] clk: tegra: save and restore divider rate Sowjanya Komatineni
2019-06-18 11:40   ` Thierry Reding
2019-06-18  7:46 ` [PATCH V3 05/17] clk: tegra: pllout: save and restore pllout context Sowjanya Komatineni
2019-06-18 11:41   ` Thierry Reding
2019-06-18  7:46 ` [PATCH V3 06/17] clk: tegra: pll: save and restore pll context Sowjanya Komatineni
2019-06-18 11:45   ` Thierry Reding
2019-06-25 20:46   ` Stephen Boyd
2019-06-25 21:22     ` Sowjanya Komatineni
2019-06-18  7:46 ` [PATCH V3 07/17] clk: tegra: save and restore CPU and System clocks context Sowjanya Komatineni
2019-06-18 11:48   ` Thierry Reding
2019-06-18  7:46 ` [PATCH V3 08/17] clk: tegra: add support for peripheral clock suspend and resume Sowjanya Komatineni
2019-06-18 11:50   ` Thierry Reding
2019-06-18  7:46 ` [PATCH V3 09/17] clk: tegra: support for saving and restoring OSC clock context Sowjanya Komatineni
2019-06-18 11:51   ` Thierry Reding
2019-06-18  7:46 ` [PATCH V3 10/17] clk: tegra: add suspend resume support for DFLL Sowjanya Komatineni
2019-06-18 11:59   ` Thierry Reding
2019-06-18  7:46 ` [PATCH V3 11/17] clk: tegra210: support for Tegra210 clocks suspend and resume Sowjanya Komatineni
2019-06-18 12:16   ` Thierry Reding
2019-06-18 17:58     ` Sowjanya Komatineni
2019-06-19  8:15       ` Thierry Reding
2019-06-21 20:44         ` Sowjanya Komatineni
2019-06-18  7:46 ` [PATCH V3 12/17] soc/tegra: pmc: allow support for more tegra wake Sowjanya Komatineni
2019-06-18  9:26   ` Marc Zyngier
2019-06-18  7:46 ` [PATCH V3 13/17] soc/tegra: pmc: add pmc wake support for tegra210 Sowjanya Komatineni
2019-06-18  7:46 ` [PATCH V3 14/17] arm64: tegra: enable wake from deep sleep on RTC alarm Sowjanya Komatineni
2019-06-18  7:46 ` [PATCH V3 15/17] soc/tegra: pmc: configure core power request polarity Sowjanya Komatineni
2019-06-18  7:46 ` [PATCH V3 16/17] soc/tegra: pmc: configure deep sleep control settings Sowjanya Komatineni
2019-06-18  7:46 ` [PATCH V3 17/17] arm64: dts: tegra210-p2180: Jetson TX1 SC7 timings Sowjanya Komatineni

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).