linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V6 00/21] SC7 entry and exit support for Tegra210
@ 2019-07-21 19:40 Sowjanya Komatineni
  2019-07-21 19:40 ` [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend Sowjanya Komatineni
                   ` (20 more replies)
  0 siblings, 21 replies; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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.

[V6]: Changes between V5 & V6 are
	- V5 feedback fixes
	- DFLL suspend and resume moved to DFLL clock driver
	- Add suspend and resume support for CPUFreq driver to explicitly
	  switch source to safe source of PLLP and disable DFLL clock.
	- Fix to super clock driver to enable PLLP branch to CPU before
	  source switch to PLLP.
	- Added save and restore support for super clock driver.

[V5]: Changes between V4 & V5 are
	- V4 feedback fixes

[V4]: Changes between V3 & V4 are
	- V3 feedback fixes
	- Removed park bits clear for EMMC pads in pinctrl-tegra driver
	  function tegra_pinctrl_clear_parked_bits as based on V3 feedback
	  parked_bit is updated to parked_bitmask to use with DRV_PINGROUP
	  as well and thierry posted patch series for this.
	- Implemented all peripheral clocks save and restore through their
	  corresponding clk_ops save_context and restore_context and removed
	  all direct registers store and restore in clk-tegra210 driver.
	- Created separate patch for fence_delay update during PLLU init based
	  on V3 feedback.
	- Added more comments in tegra210_clk_resume regarding dfll restore
	  sequence and its dependency on peripheral clocks restore.

[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 (21):
  irqchip: tegra: Do not disable COP IRQ during suspend
  pinctrl: tegra: Add suspend and resume support
  pinctrl: tegra210: Add Tegra210 pinctrl pm ops
  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: Support for OSC context save and restore
  clk: tegra: clk-periph: Add save and restore support
  clk: tegra: clk-super: Fix to enable PLLP branches to CPU
  clk: tegra: clk-super: Add save and restore support
  clk: tegra: clk-dfll: Add suspend and resume support
  cpufreq: tegra124: Add suspend and resume support
  clk: tegra210: Use fence_udelay during PLLU init
  clk: tegra210: Add suspend and resume support
  soc/tegra: pmc: Allow to support more tegras 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
  arm64: dts: tegra210-p3450: Jetson nano SC7 timings

 arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi     |   7 +
 arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts |   7 +
 arch/arm64/boot/dts/nvidia/tegra210.dtsi           |   5 +-
 drivers/clk/tegra/clk-dfll.c                       |  44 +++++++
 drivers/clk/tegra/clk-dfll.h                       |   2 +
 drivers/clk/tegra/clk-divider.c                    |  23 ++++
 drivers/clk/tegra/clk-periph-fixed.c               |  33 +++++
 drivers/clk/tegra/clk-periph-gate.c                |  34 +++++
 drivers/clk/tegra/clk-periph.c                     |  43 +++++++
 drivers/clk/tegra/clk-pll-out.c                    |  28 ++++
 drivers/clk/tegra/clk-pll.c                        | 121 +++++++++++++-----
 drivers/clk/tegra/clk-sdmmc-mux.c                  |  30 +++++
 drivers/clk/tegra/clk-super.c                      |  51 ++++++++
 drivers/clk/tegra/clk-tegra-fixed.c                |  15 +++
 drivers/clk/tegra/clk-tegra-super-gen4.c           |   4 +-
 drivers/clk/tegra/clk-tegra124-dfll-fcpu.c         |   1 +
 drivers/clk/tegra/clk-tegra210.c                   |  81 ++++++++++--
 drivers/clk/tegra/clk.c                            |  14 ++
 drivers/clk/tegra/clk.h                            |  36 +++++-
 drivers/cpufreq/tegra124-cpufreq.c                 |  46 +++++++
 drivers/irqchip/irq-tegra.c                        |  20 ++-
 drivers/pinctrl/tegra/pinctrl-tegra.c              |  59 +++++++++
 drivers/pinctrl/tegra/pinctrl-tegra.h              |   3 +
 drivers/pinctrl/tegra/pinctrl-tegra210.c           |   1 +
 drivers/soc/tegra/pmc.c                            | 142 ++++++++++++++++++++-
 25 files changed, 798 insertions(+), 52 deletions(-)

-- 
2.7.4


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

* [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-21 20:24   ` Marc Zyngier
  2019-07-22  9:54   ` Dmitry Osipenko
  2019-07-21 19:40 ` [PATCH V6 02/21] pinctrl: tegra: Add suspend and resume support Sowjanya Komatineni
                   ` (19 subsequent siblings)
  20 siblings, 2 replies; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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.

Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/irqchip/irq-tegra.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-tegra.c b/drivers/irqchip/irq-tegra.c
index e1f771c72fc4..851f88cef508 100644
--- a/drivers/irqchip/irq-tegra.c
+++ b/drivers/irqchip/irq-tegra.c
@@ -44,6 +44,7 @@ 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 = {
@@ -56,6 +57,7 @@ static const struct tegra_ictlr_soc tegra30_ictlr_soc = {
 
 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 +69,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 +150,20 @@ 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)
+			/* Disable COP interrupts if SC7 is not supported */
+			writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
 
 		/* Disable CPU interrupts */
 		writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR);
@@ -339,6 +354,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] 84+ messages in thread

* [PATCH V6 02/21] pinctrl: tegra: Add suspend and resume support
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
  2019-07-21 19:40 ` [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-21 22:03   ` Dmitry Osipenko
  2019-07-21 19:40 ` [PATCH V6 03/21] pinctrl: tegra210: Add Tegra210 pinctrl pm ops Sowjanya Komatineni
                   ` (18 subsequent siblings)
  20 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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 Tegra pinctrl driver suspend and resume.

During suspend, context of all pinctrl registers are stored and
on resume they are all restored to have all the pinmux and pad
configuration for normal operation.

Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/pinctrl/tegra/pinctrl-tegra.c | 59 +++++++++++++++++++++++++++++++++++
 drivers/pinctrl/tegra/pinctrl-tegra.h |  3 ++
 2 files changed, 62 insertions(+)

diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
index 186ef98e7b2b..e3a237534281 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
@@ -631,6 +631,58 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
 	}
 }
 
+static size_t tegra_pinctrl_get_bank_size(struct device *dev,
+					  unsigned int bank_id)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, bank_id);
+
+	return resource_size(res) / 4;
+}
+
+static int tegra_pinctrl_suspend(struct device *dev)
+{
+	struct tegra_pmx *pmx = dev_get_drvdata(dev);
+	u32 *backup_regs = pmx->backup_regs;
+	u32 *regs;
+	size_t bank_size;
+	unsigned int i, k;
+
+	for (i = 0; i < pmx->nbanks; i++) {
+		bank_size = tegra_pinctrl_get_bank_size(dev, i);
+		regs = pmx->regs[i];
+		for (k = 0; k < bank_size; k++)
+			*backup_regs++ = readl_relaxed(regs++);
+	}
+
+	return pinctrl_force_sleep(pmx->pctl);
+}
+
+static int tegra_pinctrl_resume(struct device *dev)
+{
+	struct tegra_pmx *pmx = dev_get_drvdata(dev);
+	u32 *backup_regs = pmx->backup_regs;
+	u32 *regs;
+	size_t bank_size;
+	unsigned int i, k;
+
+	for (i = 0; i < pmx->nbanks; i++) {
+		bank_size = tegra_pinctrl_get_bank_size(dev, i);
+		regs = pmx->regs[i];
+		for (k = 0; k < bank_size; k++)
+			writel_relaxed(*backup_regs++, regs++);
+	}
+
+	return 0;
+}
+
+const struct dev_pm_ops tegra_pinctrl_pm = {
+	.suspend = &tegra_pinctrl_suspend,
+	.resume = &tegra_pinctrl_resume
+};
+
 static bool gpio_node_has_range(const char *compatible)
 {
 	struct device_node *np;
@@ -655,6 +707,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)
@@ -707,6 +760,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;
 
@@ -715,6 +769,11 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
 	if (!pmx->regs)
 		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);
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
index 105309774079..0fc82eea9cf1 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra.h
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
@@ -17,6 +17,7 @@ struct tegra_pmx {
 
 	int nbanks;
 	void __iomem **regs;
+	u32 *backup_regs;
 };
 
 enum tegra_pinconf_param {
@@ -193,6 +194,8 @@ struct tegra_pinctrl_soc_data {
 	bool drvtype_in_mux;
 };
 
+extern const struct dev_pm_ops tegra_pinctrl_pm;
+
 int tegra_pinctrl_probe(struct platform_device *pdev,
 			const struct tegra_pinctrl_soc_data *soc_data);
 #endif
-- 
2.7.4


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

* [PATCH V6 03/21] pinctrl: tegra210: Add Tegra210 pinctrl pm ops
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
  2019-07-21 19:40 ` [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend Sowjanya Komatineni
  2019-07-21 19:40 ` [PATCH V6 02/21] pinctrl: tegra: Add suspend and resume support Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-21 19:40 ` [PATCH V6 04/21] clk: tegra: Save and restore divider rate Sowjanya Komatineni
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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 functionality to Tegra210 pinctrl.

Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/pinctrl/tegra/pinctrl-tegra210.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/pinctrl/tegra/pinctrl-tegra210.c b/drivers/pinctrl/tegra/pinctrl-tegra210.c
index 39ab6480a941..fc072a36deb3 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra210.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra210.c
@@ -1571,6 +1571,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,
 };
-- 
2.7.4


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

* [PATCH V6 04/21] clk: tegra: Save and restore divider rate
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (2 preceding siblings ...)
  2019-07-21 19:40 ` [PATCH V6 03/21] pinctrl: tegra210: Add Tegra210 pinctrl pm ops Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-21 22:14   ` Dmitry Osipenko
  2019-07-21 19:40 ` [PATCH V6 05/21] clk: tegra: pllout: Save and restore pllout context Sowjanya Komatineni
                   ` (16 subsequent siblings)
  20 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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.

Acked-by: Thierry Reding <treding@nvidia.com>
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] 84+ messages in thread

* [PATCH V6 05/21] clk: tegra: pllout: Save and restore pllout context
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (3 preceding siblings ...)
  2019-07-21 19:40 ` [PATCH V6 04/21] clk: tegra: Save and restore divider rate Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-21 22:18   ` Dmitry Osipenko
  2019-07-21 19:40 ` [PATCH V6 06/21] clk: tegra: pll: Save and restore pll context Sowjanya Komatineni
                   ` (15 subsequent siblings)
  20 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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.

Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/clk/tegra/clk-pll-out.c  | 28 ++++++++++++++++++++++++++++
 drivers/clk/tegra/clk-tegra210.c |  3 ++-
 drivers/clk/tegra/clk.h          |  9 +++++++++
 3 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/tegra/clk-pll-out.c b/drivers/clk/tegra/clk-pll-out.c
index 35f2bf00e1e6..8f26a7e3e579 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 (pll_out->flags & TEGRA_PLLRE_OUT)
+		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 (pll_out->flags & TEGRA_PLLRE_OUT) {
+		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-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index df172d5772d7..4721ee030d1c 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -3200,7 +3200,8 @@ static void __init tegra210_pll_init(void __iomem *clk_base,
 					 8, 8, 1, NULL);
 	clk = tegra_clk_register_pll_out("pll_re_out1", "pll_re_out1_div",
 					 clk_base + PLLRE_OUT1, 1, 0,
-					 CLK_SET_RATE_PARENT, 0, NULL);
+					 CLK_SET_RATE_PARENT, TEGRA_PLLRE_OUT,
+					 NULL);
 	clks[TEGRA210_CLK_PLL_RE_OUT1] = clk;
 
 	/* PLLE */
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 83623f5f55f3..fb29a8c27873 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -439,6 +439,12 @@ 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
+ *
+ * Flags:
+ * TEGRA_PLLRE_OUT - This flag indicates that it is PLLRE_OUT and is used to
+ *		     identify PLLRE_OUT during clk_pll_out save and restore.
  */
 struct tegra_clk_pll_out {
 	struct clk_hw	hw;
@@ -447,8 +453,11 @@ struct tegra_clk_pll_out {
 	u8		rst_bit_idx;
 	spinlock_t	*lock;
 	u8		flags;
+	unsigned int	pllout_ctx;
 };
 
+#define TEGRA_PLLRE_OUT BIT(0)
+
 #define to_clk_pll_out(_hw) container_of(_hw, struct tegra_clk_pll_out, hw)
 
 extern const struct clk_ops tegra_clk_pll_out_ops;
-- 
2.7.4


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

* [PATCH V6 06/21] clk: tegra: pll: Save and restore pll context
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (4 preceding siblings ...)
  2019-07-21 19:40 ` [PATCH V6 05/21] clk: tegra: pllout: Save and restore pllout context Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-21 21:44   ` Dmitry Osipenko
  2019-07-21 22:21   ` Dmitry Osipenko
  2019-07-21 19:40 ` [PATCH V6 07/21] clk: tegra: Support for OSC context save and restore Sowjanya Komatineni
                   ` (14 subsequent siblings)
  20 siblings, 2 replies; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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.

Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/clk/tegra/clk-pll.c      | 121 ++++++++++++++++++++++++++++-----------
 drivers/clk/tegra/clk-tegra210.c |   2 +-
 drivers/clk/tegra/clk.h          |  10 +++-
 3 files changed, 99 insertions(+), 34 deletions(-)

diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 1583f5fc992f..f136964e6c44 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -1008,6 +1008,59 @@ 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);
+	u32 val = 0;
+
+	pll->rate = clk_hw_get_rate(hw);
+
+	if (pll->params->flags & TEGRA_PLLMB)
+		val = pll_readl_base(pll);
+	else if (pll->params->flags & TEGRA_PLLRE)
+		val = pll_readl_base(pll) & divp_mask_shifted(pll);
+
+	pll->pllbase_ctx = val;
+
+	return 0;
+}
+
+static void tegra_clk_pll_restore_context(struct clk_hw *hw)
+{
+	struct tegra_clk_pll *pll = to_clk_pll(hw);
+	struct clk_hw *parent = clk_hw_get_parent(hw);
+	unsigned long parent_rate = clk_hw_get_rate(parent);
+	u32 val;
+
+	if (clk_pll_is_enabled(hw))
+		return;
+
+	if (pll->params->flags & TEGRA_PLLMB) {
+		pll_writel_base(pll->pllbase_ctx, pll);
+	} else if (pll->params->flags & TEGRA_PLLRE) {
+		val = pll_readl_base(pll);
+		val &= ~(divp_mask_shifted(pll));
+		pll_writel_base(pll->pllbase_ctx | val, pll);
+	}
+
+	if (pll->params->set_defaults)
+		pll->params->set_defaults(pll);
+
+	clk_pll_set_rate(hw, pll->rate, parent_rate);
+
+	/* do not sync pllx state here. pllx is sync'd after dfll resume */
+	if (!(pll->params->flags & TEGRA_PLLX))
+		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 +1068,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 +1857,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 +2290,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 +2337,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,
@@ -2375,6 +2438,7 @@ struct clk *tegra_clk_register_pllre_tegra210(const char *name,
 		pll_params->vco_min = pll_params->adjust_vco(pll_params,
 							     parent_rate);
 
+	pll_params->flags |= TEGRA_PLLRE;
 	pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
 	if (IS_ERR(pll))
 		return ERR_CAST(pll);
@@ -2520,11 +2584,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 +2607,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-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index 4721ee030d1c..58397f93166c 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -1602,7 +1602,7 @@ static struct tegra_clk_pll_params pll_x_params = {
 	.pdiv_tohw = pll_qlin_pdiv_to_hw,
 	.div_nmp = &pllx_nmp,
 	.freq_table = pll_x_freq_table,
-	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLLX,
 	.dyn_ramp = tegra210_pllx_dyn_ramp,
 	.set_defaults = tegra210_pllx_set_defaults,
 	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index fb29a8c27873..8532f5150091 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -235,6 +235,8 @@ struct tegra_clk_pll;
  * TEGRA_PLLMB - PLLMB has should be treated similar to PLLM. This
  *     flag indicated that it is PLLMB.
  * TEGRA_PLL_VCO_OUT - Used to indicate that the PLL has a VCO output
+ * TEGRA_PLLRE - Used to indicate that it is PLLRE.
+ * TEGRA_PLLX - Used to indicate that it is PLLX.
  */
 struct tegra_clk_pll_params {
 	unsigned long	input_min;
@@ -301,6 +303,8 @@ struct tegra_clk_pll_params {
 #define TEGRA_MDIV_NEW BIT(11)
 #define TEGRA_PLLMB BIT(12)
 #define TEGRA_PLL_VCO_OUT BIT(13)
+#define TEGRA_PLLRE BIT(14)
+#define TEGRA_PLLX BIT(15)
 
 /**
  * struct tegra_clk_pll - Tegra PLL clock
@@ -310,6 +314,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 +323,8 @@ struct tegra_clk_pll {
 	void __iomem	*pmc;
 	spinlock_t	*lock;
 	struct tegra_clk_pll_params	*params;
+	unsigned long	rate;
+	u32	pllbase_ctx;
 };
 
 #define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw)
@@ -840,7 +848,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] 84+ messages in thread

* [PATCH V6 07/21] clk: tegra: Support for OSC context save and restore
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (5 preceding siblings ...)
  2019-07-21 19:40 ` [PATCH V6 06/21] clk: tegra: pll: Save and restore pll context Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-22 10:12   ` Dmitry Osipenko
  2019-07-21 19:40 ` [PATCH V6 08/21] clk: tegra: clk-periph: Add save and restore support Sowjanya Komatineni
                   ` (13 subsequent siblings)
  20 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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

X-NVConfidentiality: public

This patch adds support for saving 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.

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

diff --git a/drivers/clk/tegra/clk-tegra-fixed.c b/drivers/clk/tegra/clk-tegra-fixed.c
index 8d91b2b191cf..7c6c8abfcde6 100644
--- a/drivers/clk/tegra/clk-tegra-fixed.c
+++ b/drivers/clk/tegra/clk-tegra-fixed.c
@@ -17,6 +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,
@@ -29,6 +33,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 +101,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 8532f5150091..3cd003b7512a 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -849,6 +849,7 @@ 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_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] 84+ messages in thread

* [PATCH V6 08/21] clk: tegra: clk-periph: Add save and restore support
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (6 preceding siblings ...)
  2019-07-21 19:40 ` [PATCH V6 07/21] clk: tegra: Support for OSC context save and restore Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-21 19:40 ` [PATCH V6 09/21] clk: tegra: clk-super: Fix to enable PLLP branches to CPU Sowjanya Komatineni
                   ` (12 subsequent siblings)
  20 siblings, 0 replies; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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 context for peripheral fixed
clock ops, peripheral gate clock ops, sdmmc mux clock ops, and
peripheral clock ops.

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

So during suspend entry clock and reset state of peripherals is saved
and on resume they are restored to have clocks back to same rate and
state as before suspend.

Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/clk/tegra/clk-periph-fixed.c | 33 +++++++++++++++++++++++++++
 drivers/clk/tegra/clk-periph-gate.c  | 34 ++++++++++++++++++++++++++++
 drivers/clk/tegra/clk-periph.c       | 43 ++++++++++++++++++++++++++++++++++++
 drivers/clk/tegra/clk-sdmmc-mux.c    | 30 +++++++++++++++++++++++++
 drivers/clk/tegra/clk.h              |  8 +++++++
 5 files changed, 148 insertions(+)

diff --git a/drivers/clk/tegra/clk-periph-fixed.c b/drivers/clk/tegra/clk-periph-fixed.c
index c088e7a280df..21b24530fa00 100644
--- a/drivers/clk/tegra/clk-periph-fixed.c
+++ b/drivers/clk/tegra/clk-periph-fixed.c
@@ -60,11 +60,44 @@ tegra_clk_periph_fixed_recalc_rate(struct clk_hw *hw,
 	return (unsigned long)rate;
 }
 
+static int tegra_clk_periph_fixed_save_context(struct clk_hw *hw)
+{
+	struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
+	u32 mask = 1 << (fixed->num % 32);
+
+	fixed->enb_ctx = readl_relaxed(fixed->base + fixed->regs->enb_reg) &
+			 mask;
+	fixed->rst_ctx = readl_relaxed(fixed->base + fixed->regs->rst_reg) &
+			 mask;
+
+	return 0;
+}
+
+static void tegra_clk_periph_fixed_restore_context(struct clk_hw *hw)
+{
+	struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
+	u32 mask = 1 << (fixed->num % 32);
+
+	if (fixed->enb_ctx)
+		writel_relaxed(mask, fixed->base + fixed->regs->enb_set_reg);
+	else
+		writel_relaxed(mask, fixed->base + fixed->regs->enb_clr_reg);
+
+	udelay(2);
+
+	if (!fixed->rst_ctx) {
+		udelay(5); /* reset propogation delay */
+		writel_relaxed(mask, fixed->base + fixed->regs->rst_reg);
+	}
+}
+
 static const struct clk_ops tegra_clk_periph_fixed_ops = {
 	.is_enabled = tegra_clk_periph_fixed_is_enabled,
 	.enable = tegra_clk_periph_fixed_enable,
 	.disable = tegra_clk_periph_fixed_disable,
 	.recalc_rate = tegra_clk_periph_fixed_recalc_rate,
+	.save_context = tegra_clk_periph_fixed_save_context,
+	.restore_context = tegra_clk_periph_fixed_restore_context,
 };
 
 struct clk *tegra_clk_register_periph_fixed(const char *name,
diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c
index 4b31beefc9fc..6ba5b08e0787 100644
--- a/drivers/clk/tegra/clk-periph-gate.c
+++ b/drivers/clk/tegra/clk-periph-gate.c
@@ -25,6 +25,8 @@ static DEFINE_SPINLOCK(periph_ref_lock);
 
 #define read_rst(gate) \
 	readl_relaxed(gate->clk_base + (gate->regs->rst_reg))
+#define write_rst_set(val, gate) \
+	writel_relaxed(val, gate->clk_base + (gate->regs->rst_set_reg))
 #define write_rst_clr(val, gate) \
 	writel_relaxed(val, gate->clk_base + (gate->regs->rst_clr_reg))
 
@@ -110,10 +112,42 @@ static void clk_periph_disable(struct clk_hw *hw)
 	spin_unlock_irqrestore(&periph_ref_lock, flags);
 }
 
+static int clk_periph_gate_save_context(struct clk_hw *hw)
+{
+	struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
+
+	gate->clk_state_ctx = read_enb(gate) & periph_clk_to_bit(gate);
+	gate->rst_state_ctx = read_rst(gate) & periph_clk_to_bit(gate);
+
+	return 0;
+}
+
+static void clk_periph_gate_restore_context(struct clk_hw *hw)
+{
+	struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
+
+	if (gate->clk_state_ctx)
+		write_enb_set(periph_clk_to_bit(gate), gate);
+	else
+		write_enb_clr(periph_clk_to_bit(gate), gate);
+
+	udelay(5);
+
+	if (!(gate->flags & TEGRA_PERIPH_NO_RESET) &&
+	    !(gate->flags & TEGRA_PERIPH_MANUAL_RESET)) {
+		if (gate->rst_state_ctx)
+			write_rst_set(periph_clk_to_bit(gate), gate);
+		else
+			write_rst_clr(periph_clk_to_bit(gate), gate);
+	}
+}
+
 const struct clk_ops tegra_clk_periph_gate_ops = {
 	.is_enabled = clk_periph_is_enabled,
 	.enable = clk_periph_enable,
 	.disable = clk_periph_disable,
+	.save_context = clk_periph_gate_save_context,
+	.restore_context = clk_periph_gate_restore_context,
 };
 
 struct clk *tegra_clk_register_periph_gate(const char *name,
diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c
index 58437da25156..b29a1ed2ec08 100644
--- a/drivers/clk/tegra/clk-periph.c
+++ b/drivers/clk/tegra/clk-periph.c
@@ -5,6 +5,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/export.h>
+#include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 
@@ -99,6 +100,42 @@ static void clk_periph_disable(struct clk_hw *hw)
 	gate_ops->disable(gate_hw);
 }
 
+static int clk_periph_save_context(struct clk_hw *hw)
+{
+	struct tegra_clk_periph *periph = to_clk_periph(hw);
+	const struct clk_ops *gate_ops = periph->gate_ops;
+	struct clk_hw *gate_hw = &periph->gate.hw;
+	struct clk_hw *parent = clk_hw_get_parent(hw);
+	unsigned long parent_rate = clk_hw_get_rate(parent);
+
+	if (!(periph->gate.flags & TEGRA_PERIPH_NO_GATE))
+		gate_ops->save_context(gate_hw);
+
+	if (!(periph->gate.flags & TEGRA_PERIPH_NO_DIV))
+		periph->rate_ctx = clk_periph_recalc_rate(hw, parent_rate);
+
+	periph->parent_ctx = clk_periph_get_parent(hw);
+
+	return 0;
+}
+
+static void clk_periph_restore_context(struct clk_hw *hw)
+{
+	struct tegra_clk_periph *periph = to_clk_periph(hw);
+	const struct clk_ops *gate_ops = periph->gate_ops;
+	struct clk_hw *gate_hw = &periph->gate.hw;
+	struct clk_hw *parent = clk_hw_get_parent(hw);
+	unsigned long parent_rate = clk_hw_get_rate(parent);
+
+	clk_periph_set_parent(hw, periph->parent_ctx);
+
+	if (!(periph->gate.flags & TEGRA_PERIPH_NO_DIV))
+		clk_periph_set_rate(hw, periph->rate_ctx, parent_rate);
+
+	if (!(periph->gate.flags & TEGRA_PERIPH_NO_GATE))
+		gate_ops->restore_context(gate_hw);
+}
+
 const struct clk_ops tegra_clk_periph_ops = {
 	.get_parent = clk_periph_get_parent,
 	.set_parent = clk_periph_set_parent,
@@ -108,6 +145,8 @@ const struct clk_ops tegra_clk_periph_ops = {
 	.is_enabled = clk_periph_is_enabled,
 	.enable = clk_periph_enable,
 	.disable = clk_periph_disable,
+	.save_context = clk_periph_save_context,
+	.restore_context = clk_periph_restore_context,
 };
 
 static const struct clk_ops tegra_clk_periph_nodiv_ops = {
@@ -116,6 +155,8 @@ static const struct clk_ops tegra_clk_periph_nodiv_ops = {
 	.is_enabled = clk_periph_is_enabled,
 	.enable = clk_periph_enable,
 	.disable = clk_periph_disable,
+	.save_context = clk_periph_save_context,
+	.restore_context = clk_periph_restore_context,
 };
 
 static const struct clk_ops tegra_clk_periph_no_gate_ops = {
@@ -124,6 +165,8 @@ static const struct clk_ops tegra_clk_periph_no_gate_ops = {
 	.recalc_rate = clk_periph_recalc_rate,
 	.round_rate = clk_periph_round_rate,
 	.set_rate = clk_periph_set_rate,
+	.save_context = clk_periph_save_context,
+	.restore_context = clk_periph_restore_context,
 };
 
 static struct clk *_tegra_clk_register_periph(const char *name,
diff --git a/drivers/clk/tegra/clk-sdmmc-mux.c b/drivers/clk/tegra/clk-sdmmc-mux.c
index a5cd3e31dbae..fffe08e02c10 100644
--- a/drivers/clk/tegra/clk-sdmmc-mux.c
+++ b/drivers/clk/tegra/clk-sdmmc-mux.c
@@ -194,6 +194,34 @@ static void clk_sdmmc_mux_disable(struct clk_hw *hw)
 	gate_ops->disable(gate_hw);
 }
 
+static int clk_sdmmc_mux_save_context(struct clk_hw *hw)
+{
+	struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw);
+	const struct clk_ops *gate_ops = sdmmc_mux->gate_ops;
+	struct clk_hw *gate_hw = &sdmmc_mux->gate.hw;
+	struct clk_hw *parent = clk_hw_get_parent(hw);
+	unsigned long parent_rate = clk_hw_get_rate(parent);
+
+	sdmmc_mux->rate_ctx = clk_sdmmc_mux_recalc_rate(hw, parent_rate);
+	sdmmc_mux->parent_ctx = clk_sdmmc_mux_get_parent(hw);
+	gate_ops->save_context(gate_hw);
+
+	return 0;
+}
+
+static void clk_sdmmc_mux_restore_context(struct clk_hw *hw)
+{
+	struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw);
+	const struct clk_ops *gate_ops = sdmmc_mux->gate_ops;
+	struct clk_hw *gate_hw = &sdmmc_mux->gate.hw;
+	struct clk_hw *parent = clk_hw_get_parent(hw);
+	unsigned long parent_rate = clk_hw_get_rate(parent);
+
+	clk_sdmmc_mux_set_parent(hw, sdmmc_mux->parent_ctx);
+	clk_sdmmc_mux_set_rate(hw, sdmmc_mux->rate_ctx, parent_rate);
+	gate_ops->restore_context(gate_hw);
+}
+
 static const struct clk_ops tegra_clk_sdmmc_mux_ops = {
 	.get_parent = clk_sdmmc_mux_get_parent,
 	.set_parent = clk_sdmmc_mux_set_parent,
@@ -203,6 +231,8 @@ static const struct clk_ops tegra_clk_sdmmc_mux_ops = {
 	.is_enabled = clk_sdmmc_mux_is_enabled,
 	.enable = clk_sdmmc_mux_enable,
 	.disable = clk_sdmmc_mux_disable,
+	.save_context = clk_sdmmc_mux_save_context,
+	.restore_context = clk_sdmmc_mux_restore_context,
 };
 
 struct clk *tegra_clk_register_sdmmc_mux_div(const char *name,
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 3cd003b7512a..ac6de3a0b91f 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -523,6 +523,8 @@ struct tegra_clk_periph_gate {
 	int			clk_num;
 	int			*enable_refcnt;
 	const struct tegra_clk_periph_regs *regs;
+	bool			clk_state_ctx;
+	bool			rst_state_ctx;
 };
 
 #define to_clk_periph_gate(_hw)					\
@@ -549,6 +551,8 @@ struct tegra_clk_periph_fixed {
 	unsigned int mul;
 	unsigned int div;
 	unsigned int num;
+	bool enb_ctx;
+	bool rst_ctx;
 };
 
 struct clk *tegra_clk_register_periph_fixed(const char *name,
@@ -581,6 +585,8 @@ struct tegra_clk_periph {
 	const struct clk_ops	*mux_ops;
 	const struct clk_ops	*div_ops;
 	const struct clk_ops	*gate_ops;
+	unsigned long		rate_ctx;
+	u8			parent_ctx;
 };
 
 #define to_clk_periph(_hw) container_of(_hw, struct tegra_clk_periph, hw)
@@ -732,6 +738,8 @@ struct tegra_sdmmc_mux {
 	const struct clk_ops	*gate_ops;
 	struct tegra_clk_periph_gate	gate;
 	u8			div_flags;
+	unsigned long		rate_ctx;
+	u8			parent_ctx;
 };
 
 #define to_clk_sdmmc_mux(_hw) container_of(_hw, struct tegra_sdmmc_mux, hw)
-- 
2.7.4


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

* [PATCH V6 09/21] clk: tegra: clk-super: Fix to enable PLLP branches to CPU
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (7 preceding siblings ...)
  2019-07-21 19:40 ` [PATCH V6 08/21] clk: tegra: clk-periph: Add save and restore support Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-21 21:16   ` Dmitry Osipenko
  2019-07-21 19:40 ` [PATCH V6 10/21] clk: tegra: clk-super: Add save and restore support Sowjanya Komatineni
                   ` (11 subsequent siblings)
  20 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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 a fix to enable PLLP branches to CPU before changing
the CPU clusters clock source to PLLP for Gen5 Super clock.

During system suspend entry and exit, CPU source will be switched
to PLLP and this needs PLLP branches to be enabled to CPU prior to
the switch.

On system resume, warmboot code enables PLLP branches to CPU and
powers up the CPU with PLLP clock source.

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

diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c
index 39ef31b46df5..d73c587e4853 100644
--- a/drivers/clk/tegra/clk-super.c
+++ b/drivers/clk/tegra/clk-super.c
@@ -28,6 +28,9 @@
 #define super_state_to_src_shift(m, s) ((m->width * s))
 #define super_state_to_src_mask(m) (((1 << m->width) - 1))
 
+#define CCLK_SRC_PLLP_OUT0 4
+#define CCLK_SRC_PLLP_OUT4 5
+
 static u8 clk_super_get_parent(struct clk_hw *hw)
 {
 	struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
@@ -97,6 +100,14 @@ static int clk_super_set_parent(struct clk_hw *hw, u8 index)
 		if (index == mux->div2_index)
 			index = mux->pllx_index;
 	}
+
+	/*
+	 * Enable PLLP branches to CPU before selecting PLLP source
+	 */
+	if ((mux->flags & TEGRA_CPU_CLK) &&
+	    ((index == CCLK_SRC_PLLP_OUT0) || (index == CCLK_SRC_PLLP_OUT4)))
+		tegra_clk_set_pllp_out_cpu(true);
+
 	val &= ~((super_state_to_src_mask(mux)) << shift);
 	val |= (index & (super_state_to_src_mask(mux))) << shift;
 
diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c
index cdfe7c9697e1..cd208d0eca2a 100644
--- a/drivers/clk/tegra/clk-tegra-super-gen4.c
+++ b/drivers/clk/tegra/clk-tegra-super-gen4.c
@@ -180,7 +180,7 @@ static void __init tegra_super_clk_init(void __iomem *clk_base,
 					gen_info->num_cclk_g_parents,
 					CLK_SET_RATE_PARENT,
 					clk_base + CCLKG_BURST_POLICY,
-					0, 4, 8, 0, NULL);
+					TEGRA_CPU_CLK, 4, 8, 0, NULL);
 		} else {
 			clk = tegra_clk_register_super_mux("cclk_g",
 					gen_info->cclk_g_parents,
@@ -201,7 +201,7 @@ static void __init tegra_super_clk_init(void __iomem *clk_base,
 					gen_info->num_cclk_lp_parents,
 					CLK_SET_RATE_PARENT,
 					clk_base + CCLKLP_BURST_POLICY,
-					0, 4, 8, 0, NULL);
+					TEGRA_CPU_CLK, 4, 8, 0, NULL);
 		} else {
 			clk = tegra_clk_register_super_mux("cclk_lp",
 					gen_info->cclk_lp_parents,
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index ac6de3a0b91f..c357b49e49b0 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -694,6 +694,9 @@ struct clk *tegra_clk_register_periph_data(void __iomem *clk_base,
  * Flags:
  * TEGRA_DIVIDER_2 - LP cluster has additional divider. This flag indicates
  *     that this is LP cluster clock.
+ * TEGRA_CPU_CLK - This flag indicates this is CPU cluster clock. To use PLLP
+ * for CPU clock source, need to enable PLLP branches to CPU by setting the
+ * additional bit PLLP_OUT_CPU for gen5 super clock.
  */
 struct tegra_clk_super_mux {
 	struct clk_hw	hw;
@@ -710,6 +713,7 @@ struct tegra_clk_super_mux {
 #define to_clk_super_mux(_hw) container_of(_hw, struct tegra_clk_super_mux, hw)
 
 #define TEGRA_DIVIDER_2 BIT(0)
+#define TEGRA_CPU_CLK	BIT(1)
 
 extern const struct clk_ops tegra_clk_super_ops;
 struct clk *tegra_clk_register_super_mux(const char *name,
-- 
2.7.4


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

* [PATCH V6 10/21] clk: tegra: clk-super: Add save and restore support
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (8 preceding siblings ...)
  2019-07-21 19:40 ` [PATCH V6 09/21] clk: tegra: clk-super: Fix to enable PLLP branches to CPU Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-21 19:40 ` [PATCH V6 11/21] clk: tegra: clk-dfll: Add suspend and resume support Sowjanya Komatineni
                   ` (10 subsequent siblings)
  20 siblings, 0 replies; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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 context for clk_super_mux
and clk_super.

During system supend, core power goes off the and context of Tegra
CAR registers is lost.

So during suspend entry, context of super clock registers are saved
through save_context clk_ops and are restored through restore_context
clk_ops to have them in same state as before suspend.

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

diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c
index d73c587e4853..84492afd3f1d 100644
--- a/drivers/clk/tegra/clk-super.c
+++ b/drivers/clk/tegra/clk-super.c
@@ -121,9 +121,27 @@ static int clk_super_set_parent(struct clk_hw *hw, u8 index)
 	return err;
 }
 
+static int clk_super_mux_save_context(struct clk_hw *hw)
+{
+	struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
+
+	mux->parent_index_ctx = clk_super_get_parent(hw);
+
+	return 0;
+}
+
+static void clk_super_mux_restore_context(struct clk_hw *hw)
+{
+	struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
+
+	clk_super_set_parent(hw, mux->parent_index_ctx);
+}
+
 static const struct clk_ops tegra_clk_super_mux_ops = {
 	.get_parent = clk_super_get_parent,
 	.set_parent = clk_super_set_parent,
+	.save_context = clk_super_mux_save_context,
+	.restore_context = clk_super_mux_restore_context,
 };
 
 static long clk_super_round_rate(struct clk_hw *hw, unsigned long rate,
@@ -159,12 +177,34 @@ static int clk_super_set_rate(struct clk_hw *hw, unsigned long rate,
 	return super->div_ops->set_rate(div_hw, rate, parent_rate);
 }
 
+static int clk_super_save_context(struct clk_hw *hw)
+{
+	struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
+	struct clk_hw *div_hw = &super->frac_div.hw;
+
+	super->parent_index_ctx = clk_super_get_parent(hw);
+
+	return super->div_ops->save_context(div_hw);
+}
+
+static void clk_super_restore_context(struct clk_hw *hw)
+{
+	struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
+	struct clk_hw *div_hw = &super->frac_div.hw;
+
+	clk_super_set_parent(hw, super->parent_index_ctx);
+
+	super->div_ops->restore_context(div_hw);
+}
+
 const struct clk_ops tegra_clk_super_ops = {
 	.get_parent = clk_super_get_parent,
 	.set_parent = clk_super_set_parent,
 	.set_rate = clk_super_set_rate,
 	.round_rate = clk_super_round_rate,
 	.recalc_rate = clk_super_recalc_rate,
+	.save_context = clk_super_save_context,
+	.restore_context = clk_super_restore_context,
 };
 
 struct clk *tegra_clk_register_super_mux(const char *name,
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index c357b49e49b0..562a3ee2d537 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -708,6 +708,7 @@ struct tegra_clk_super_mux {
 	u8		div2_index;
 	u8		pllx_index;
 	spinlock_t	*lock;
+	u8		parent_index_ctx;
 };
 
 #define to_clk_super_mux(_hw) container_of(_hw, struct tegra_clk_super_mux, hw)
-- 
2.7.4


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

* [PATCH V6 11/21] clk: tegra: clk-dfll: Add suspend and resume support
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (9 preceding siblings ...)
  2019-07-21 19:40 ` [PATCH V6 10/21] clk: tegra: clk-super: Add save and restore support Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-21 21:32   ` Dmitry Osipenko
  2019-07-21 19:40 ` [PATCH V6 12/21] cpufreq: tegra124: " Sowjanya Komatineni
                   ` (9 subsequent siblings)
  20 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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 DFLL suspend and resume operation.

During system suspend entry, CPU clock will switch CPU to safe
clock source of PLLP and disables DFLL clock output.

DFLL driver suspend confirms DFLL disable state and errors out on
being active.

DFLL is re-initialized during the DFLL driver resume as it goes
through complete reset during suspend entry.

Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/clk/tegra/clk-dfll.c               | 44 ++++++++++++++++++++++++++++++
 drivers/clk/tegra/clk-dfll.h               |  2 ++
 drivers/clk/tegra/clk-tegra124-dfll-fcpu.c |  1 +
 3 files changed, 47 insertions(+)

diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c
index f8688c2ddf1a..7dcad4ccd0ae 100644
--- a/drivers/clk/tegra/clk-dfll.c
+++ b/drivers/clk/tegra/clk-dfll.c
@@ -1513,6 +1513,50 @@ static int dfll_init(struct tegra_dfll *td)
 	return ret;
 }
 
+/**
+ * tegra_dfll_suspend - check DFLL is disabled
+ * @dev: DFLL device *
+ *
+ * DFLL clock should be disabled by the CPUFreq driver. So, make
+ * sure it is disabled and disable all clocks needed by the DFLL.
+ */
+int tegra_dfll_suspend(struct device *dev)
+{
+	struct tegra_dfll *td = dev_get_drvdata(dev);
+
+	if (dfll_is_running(td)) {
+		dev_warn(td->dev, "failed disabling the dfll\n");
+		return -EBUSY;
+	}
+
+	pm_runtime_disable(dev);
+
+	clk_unprepare(td->ref_clk);
+	clk_unprepare(td->soc_clk);
+	clk_unprepare(td->i2c_clk);
+
+	reset_control_assert(td->dvco_rst);
+
+	return 0;
+}
+EXPORT_SYMBOL(tegra_dfll_suspend);
+
+/**
+ * tegra_dfll_resume - reinitialize DFLL on resume
+ * @pdev: DFLL instance
+ *
+ * Re-initialize DFLL on resume as it gets disabled and reset during
+ * suspend entry. DFLL clock is enabled in closed loop mode later
+ * and CPU frequency will be switched to DFLL output.
+ */
+int tegra_dfll_resume(struct device *dev)
+{
+	struct tegra_dfll *td = dev_get_drvdata(dev);
+
+	return dfll_init(td);
+}
+EXPORT_SYMBOL(tegra_dfll_resume);
+
 /*
  * DT data fetch
  */
diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h
index 1b14ebe7268b..fb209eb5f365 100644
--- a/drivers/clk/tegra/clk-dfll.h
+++ b/drivers/clk/tegra/clk-dfll.h
@@ -42,5 +42,7 @@ int tegra_dfll_register(struct platform_device *pdev,
 struct tegra_dfll_soc_data *tegra_dfll_unregister(struct platform_device *pdev);
 int tegra_dfll_runtime_suspend(struct device *dev);
 int tegra_dfll_runtime_resume(struct device *dev);
+int tegra_dfll_suspend(struct device *dev);
+int tegra_dfll_resume(struct device *dev);
 
 #endif /* __DRIVERS_CLK_TEGRA_CLK_DFLL_H */
diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
index e84b6d52cbbd..2ac2679d696d 100644
--- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
+++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
@@ -631,6 +631,7 @@ static int tegra124_dfll_fcpu_remove(struct platform_device *pdev)
 static const struct dev_pm_ops tegra124_dfll_pm_ops = {
 	SET_RUNTIME_PM_OPS(tegra_dfll_runtime_suspend,
 			   tegra_dfll_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(tegra_dfll_suspend, tegra_dfll_resume)
 };
 
 static struct platform_driver tegra124_dfll_fcpu_driver = {
-- 
2.7.4


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

* [PATCH V6 12/21] cpufreq: tegra124: Add suspend and resume support
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (10 preceding siblings ...)
  2019-07-21 19:40 ` [PATCH V6 11/21] clk: tegra: clk-dfll: Add suspend and resume support Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-21 21:04   ` Dmitry Osipenko
  2019-07-21 19:40 ` [PATCH V6 13/21] clk: tegra210: Use fence_udelay during PLLU init Sowjanya Komatineni
                   ` (8 subsequent siblings)
  20 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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 pm ops for cpufreq driver.

PLLP is the safe clock source for CPU during system suspend and
resume as PLLP rate is below the CPU Fmax at Vmin.

CPUFreq driver suspend switches the CPU clock source to PLLP and
disables the DFLL clock.

During system resume, warmboot code powers up the CPU with PLLP
clock source. So CPUFreq driver resume enabled DFLL clock and
switches CPU back to DFLL clock source.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/cpufreq/tegra124-cpufreq.c | 46 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/drivers/cpufreq/tegra124-cpufreq.c b/drivers/cpufreq/tegra124-cpufreq.c
index 4f0c637b3b49..4eff63379b0f 100644
--- a/drivers/cpufreq/tegra124-cpufreq.c
+++ b/drivers/cpufreq/tegra124-cpufreq.c
@@ -6,6 +6,7 @@
 #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
 
 #include <linux/clk.h>
+#include <linux/cpufreq.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -128,8 +129,53 @@ static int tegra124_cpufreq_probe(struct platform_device *pdev)
 	return ret;
 }
 
+static int tegra124_cpufreq_suspend(struct device *dev)
+{
+	struct tegra124_cpufreq_priv *priv = dev_get_drvdata(dev);
+
+	/*
+	 * PLLP rate 408Mhz is below the CPU Fmax at Vmin and is safe to
+	 * use during suspend and resume. So, switch the CPU clock source
+	 * to PLLP and disable DFLL.
+	 */
+	clk_set_parent(priv->cpu_clk, priv->pllp_clk);
+
+	/* disable DFLL clock */
+	clk_disable_unprepare(priv->dfll_clk);
+
+	return 0;
+}
+
+static int tegra124_cpufreq_resume(struct device *dev)
+{
+	struct tegra124_cpufreq_priv *priv = dev_get_drvdata(dev);
+	int ret = 0;
+
+	/*
+	 * Warmboot code powers up the CPU with PLLP clock source.
+	 * Enable DFLL clock and switch CPU clock source back to DFLL.
+	 */
+	ret = clk_prepare_enable(priv->dfll_clk);
+	if (ret) {
+		dev_warn(dev, "failed to enable DFLL clock for CPU\n");
+		clk_set_parent(priv->cpu_clk, priv->pllp_clk);
+		disable_cpufreq();
+		return ret;
+	}
+
+	clk_set_parent(priv->cpu_clk, priv->dfll_clk);
+
+	return ret;
+}
+
+static const struct dev_pm_ops tegra124_cpufreq_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(tegra124_cpufreq_suspend,
+				tegra124_cpufreq_resume)
+};
+
 static struct platform_driver tegra124_cpufreq_platdrv = {
 	.driver.name	= "cpufreq-tegra124",
+	.driver.pm	= &tegra124_cpufreq_pm_ops,
 	.probe		= tegra124_cpufreq_probe,
 };
 
-- 
2.7.4


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

* [PATCH V6 13/21] clk: tegra210: Use fence_udelay during PLLU init
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (11 preceding siblings ...)
  2019-07-21 19:40 ` [PATCH V6 12/21] cpufreq: tegra124: " Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-21 19:40 ` [PATCH V6 14/21] clk: tegra210: Add suspend and resume support Sowjanya Komatineni
                   ` (7 subsequent siblings)
  20 siblings, 0 replies; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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 uses fence_udelay rather than udelay during PLLU
initialization to ensure writes to clock registers happens before
waiting for specified delay.

Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/clk/tegra/clk-tegra210.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index 58397f93166c..55a88c0824a5 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -2841,7 +2841,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);
@@ -2849,7 +2849,7 @@ 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);
 
@@ -2895,12 +2895,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;
-- 
2.7.4


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

* [PATCH V6 14/21] clk: tegra210: Add suspend and resume support
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (12 preceding siblings ...)
  2019-07-21 19:40 ` [PATCH V6 13/21] clk: tegra210: Use fence_udelay during PLLU init Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-21 21:38   ` Dmitry Osipenko
  2019-07-21 19:40 ` [PATCH V6 15/21] soc/tegra: pmc: Allow to support more tegras wake Sowjanya Komatineni
                   ` (6 subsequent siblings)
  20 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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 clk: tegra210: suspend-resume.

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

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

Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/clk/tegra/clk-tegra210.c | 68 ++++++++++++++++++++++++++++++++++++++--
 drivers/clk/tegra/clk.c          | 14 +++++++++
 drivers/clk/tegra/clk.h          |  1 +
 3 files changed, 80 insertions(+), 3 deletions(-)

diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index 55a88c0824a5..68271873acc1 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -9,6 +9,7 @@
 #include <linux/clkdev.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/syscore_ops.h>
 #include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/mutex.h>
@@ -220,11 +221,15 @@
 #define CLK_M_DIVISOR_SHIFT 2
 #define CLK_M_DIVISOR_MASK 0x3
 
+#define CLK_MASK_ARM	0x44
+#define MISC_CLK_ENB	0x48
+
 #define RST_DFLL_DVCO 0x2f4
 #define DVFS_DFLL_RESET_SHIFT 0
 
 #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
@@ -2825,6 +2830,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)
@@ -2853,9 +2859,8 @@ static int tegra210_enable_pllu(void)
 	reg |= PLL_ENABLE;
 	writel(reg, clk_base + PLLU_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;
 	}
@@ -3288,6 +3293,56 @@ static void tegra210_disable_cpu_clock(u32 cpu)
 }
 
 #ifdef CONFIG_PM_SLEEP
+#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 spare_reg_ctx, misc_clk_enb_ctx, clk_msk_arm_ctx;
+static u32 cpu_softrst_ctx[3];
+
+static int tegra210_clk_suspend(void)
+{
+	unsigned int i;
+
+	clk_save_context();
+
+	/*
+	 * save the bootloader configured clock registers SPARE_REG0,
+	 * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL
+	 */
+	spare_reg_ctx = readl_relaxed(clk_base + SPARE_REG0);
+	misc_clk_enb_ctx = readl_relaxed(clk_base + MISC_CLK_ENB);
+	clk_msk_arm_ctx = readl_relaxed(clk_base + CLK_MASK_ARM);
+
+	for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
+		cpu_softrst_ctx[i] = car_readl(CPU_SOFTRST_CTRL, i);
+
+	return 0;
+}
+
+static void tegra210_clk_resume(void)
+{
+	unsigned int i;
+
+	tegra_clk_osc_resume(clk_base);
+
+	/*
+	 * restore the bootloader configured clock registers SPARE_REG0,
+	 * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL from saved context.
+	 */
+	writel_relaxed(spare_reg_ctx, clk_base + SPARE_REG0);
+	writel_relaxed(misc_clk_enb_ctx, clk_base + MISC_CLK_ENB);
+	writel_relaxed(clk_msk_arm_ctx, clk_base + CLK_MASK_ARM);
+
+	for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
+		car_writel(cpu_softrst_ctx[i], CPU_SOFTRST_CTRL, i);
+
+	fence_udelay(5, clk_base);
+
+	tegra210_init_pllu();
+	clk_restore_context();
+}
+
 static void tegra210_cpu_clock_suspend(void)
 {
 	/* switch coresite to clk_m, save off original source */
@@ -3303,6 +3358,11 @@ static void tegra210_cpu_clock_resume(void)
 }
 #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,
@@ -3587,5 +3647,7 @@ static void __init tegra210_clock_init(struct device_node *np)
 	tegra210_mbist_clk_init();
 
 	tegra_cpu_car_ops = &tegra210_cpu_car_ops;
+
+	register_syscore_ops(&tegra_clk_syscore_ops);
 }
 CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);
diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
index 573e3c967ae1..eb08047fd02f 100644
--- a/drivers/clk/tegra/clk.c
+++ b/drivers/clk/tegra/clk.c
@@ -23,6 +23,7 @@
 #define CLK_OUT_ENB_W			0x364
 #define CLK_OUT_ENB_X			0x280
 #define CLK_OUT_ENB_Y			0x298
+#define CLK_ENB_PLLP_OUT_CPU		BIT(31)
 #define CLK_OUT_ENB_SET_L		0x320
 #define CLK_OUT_ENB_CLR_L		0x324
 #define CLK_OUT_ENB_SET_H		0x328
@@ -199,6 +200,19 @@ const struct tegra_clk_periph_regs *get_reg_bank(int clkid)
 	}
 }
 
+void tegra_clk_set_pllp_out_cpu(bool enable)
+{
+	u32 val;
+
+	val = readl_relaxed(clk_base + CLK_OUT_ENB_Y);
+	if (enable)
+		val |= CLK_ENB_PLLP_OUT_CPU;
+	else
+		val &= ~CLK_ENB_PLLP_OUT_CPU;
+
+	writel_relaxed(val, clk_base + CLK_OUT_ENB_Y);
+}
+
 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 562a3ee2d537..0ffa763c755b 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -863,6 +863,7 @@ 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_clk_osc_resume(void __iomem *clk_base);
+void tegra_clk_set_pllp_out_cpu(bool enable);
 
 /* Combined read fence with delay */
 #define fence_udelay(delay, reg)	\
-- 
2.7.4


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

* [PATCH V6 15/21] soc/tegra: pmc: Allow to support more tegras wake
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (13 preceding siblings ...)
  2019-07-21 19:40 ` [PATCH V6 14/21] clk: tegra210: Add suspend and resume support Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-21 19:40 ` [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210 Sowjanya Komatineni
                   ` (5 subsequent siblings)
  20 siblings, 0 replies; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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 | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 9f9c1c677cf4..91c84d0e66ae 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;
@@ -1920,7 +1922,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;
@@ -1952,7 +1954,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;
@@ -2006,8 +2008,8 @@ 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;
+	pmc->irq.irq_set_type = pmc->soc->irq_set_type;
+	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);
@@ -2680,6 +2682,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] 84+ messages in thread

* [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (14 preceding siblings ...)
  2019-07-21 19:40 ` [PATCH V6 15/21] soc/tegra: pmc: Allow to support more tegras wake Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-23  0:58   ` Dmitry Osipenko
  2019-07-21 19:40 ` [PATCH V6 17/21] arm64: tegra: Enable wake from deep sleep on RTC alarm Sowjanya Komatineni
                   ` (4 subsequent siblings)
  20 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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 91c84d0e66ae..c556f38874e1 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)
@@ -1922,6 +1933,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);
@@ -1954,6 +2014,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);
@@ -2540,6 +2643,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,
@@ -2557,10 +2664,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] 84+ messages in thread

* [PATCH V6 17/21] arm64: tegra: Enable wake from deep sleep on RTC alarm.
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (15 preceding siblings ...)
  2019-07-21 19:40 ` [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210 Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-26  6:30   ` Dmitry Osipenko
  2019-07-21 19:40 ` [PATCH V6 18/21] soc/tegra: pmc: Configure core power request polarity Sowjanya Komatineni
                   ` (3 subsequent siblings)
  20 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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 659753118e96..30a7c48385a2 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -768,7 +768,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";
 	};
@@ -778,6 +779,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] 84+ messages in thread

* [PATCH V6 18/21] soc/tegra: pmc: Configure core power request polarity
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (16 preceding siblings ...)
  2019-07-21 19:40 ` [PATCH V6 17/21] arm64: tegra: Enable wake from deep sleep on RTC alarm Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-21 19:40 ` [PATCH V6 19/21] soc/tegra: pmc: Configure deep sleep control settings Sowjanya Komatineni
                   ` (2 subsequent siblings)
  20 siblings, 0 replies; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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 c556f38874e1..7521394b94ab 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)
 
@@ -2303,6 +2304,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] 84+ messages in thread

* [PATCH V6 19/21] soc/tegra: pmc: Configure deep sleep control settings
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (17 preceding siblings ...)
  2019-07-21 19:40 ` [PATCH V6 18/21] soc/tegra: pmc: Configure core power request polarity Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-21 19:40 ` [PATCH V6 20/21] arm64: dts: tegra210-p2180: Jetson TX1 SC7 timings Sowjanya Komatineni
  2019-07-21 19:41 ` [PATCH V6 21/21] arm64: dts: tegra210-p3450: Jetson nano " Sowjanya Komatineni
  20 siblings, 0 replies; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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 | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 7521394b94ab..16df35bdbd4b 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
 
@@ -2290,7 +2292,7 @@ static const struct tegra_pmc_regs tegra20_pmc_regs = {
 
 static void tegra20_pmc_init(struct tegra_pmc *pmc)
 {
-	u32 value;
+	u32 value, osc, pmu, off;
 
 	/* Always enable CPU power request */
 	value = tegra_pmc_readl(pmc, PMC_CNTRL);
@@ -2316,6 +2318,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(pmc->core_osc_time * 8192, 1000000);
+	pmu = DIV_ROUND_UP(pmc->core_pmu_time * 32768, 1000000);
+	off = DIV_ROUND_UP(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] 84+ messages in thread

* [PATCH V6 20/21] arm64: dts: tegra210-p2180: Jetson TX1 SC7 timings
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (18 preceding siblings ...)
  2019-07-21 19:40 ` [PATCH V6 19/21] soc/tegra: pmc: Configure deep sleep control settings Sowjanya Komatineni
@ 2019-07-21 19:40 ` Sowjanya Komatineni
  2019-07-21 19:41 ` [PATCH V6 21/21] arm64: dts: tegra210-p3450: Jetson nano " Sowjanya Komatineni
  20 siblings, 0 replies; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:40 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 27723829d033..cb58f79deb48 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] 84+ messages in thread

* [PATCH V6 21/21] arm64: dts: tegra210-p3450: Jetson nano SC7 timings
  2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
                   ` (19 preceding siblings ...)
  2019-07-21 19:40 ` [PATCH V6 20/21] arm64: dts: tegra210-p2180: Jetson TX1 SC7 timings Sowjanya Komatineni
@ 2019-07-21 19:41 ` Sowjanya Komatineni
  2019-07-21 22:25   ` Dmitry Osipenko
  20 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 19:41 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 Jetson nano platform specific SC7 timing configuration
in the device tree.

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

diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
index 9d17ec707bce..b525e69c172a 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
@@ -382,6 +382,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;
 	};
 
 	hda@70030000 {
-- 
2.7.4


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

* Re: [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend
  2019-07-21 19:40 ` [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend Sowjanya Komatineni
@ 2019-07-21 20:24   ` Marc Zyngier
  2019-07-22  9:54   ` Dmitry Osipenko
  1 sibling, 0 replies; 84+ messages in thread
From: Marc Zyngier @ 2019-07-21 20:24 UTC (permalink / raw)
  To: Sowjanya Komatineni
  Cc: thierry.reding, jonathanh, tglx, jason, 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 Sun, 21 Jul 2019 12:40:40 -0700
Sowjanya Komatineni <skomatineni@nvidia.com> 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.
> 
> Acked-by: Thierry Reding <treding@nvidia.com>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>

Acked-by: Marc Zyngier <maz@kernel.org>

Please let me know how you want this to be merged (either via the
irqchip tree as a standalone patch, or as part of the series via
another tree).

Thanks,

	M.
-- 
Without deviation from the norm, progress is not possible.

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

* Re: [PATCH V6 12/21] cpufreq: tegra124: Add suspend and resume support
  2019-07-21 19:40 ` [PATCH V6 12/21] cpufreq: tegra124: " Sowjanya Komatineni
@ 2019-07-21 21:04   ` Dmitry Osipenko
  0 siblings, 0 replies; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-21 21:04 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

21.07.2019 22:40, Sowjanya Komatineni пишет:
> This patch adds suspend and resume pm ops for cpufreq driver.
> 
> PLLP is the safe clock source for CPU during system suspend and
> resume as PLLP rate is below the CPU Fmax at Vmin.
> 
> CPUFreq driver suspend switches the CPU clock source to PLLP and
> disables the DFLL clock.
> 
> During system resume, warmboot code powers up the CPU with PLLP
> clock source. So CPUFreq driver resume enabled DFLL clock and
> switches CPU back to DFLL clock source.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/cpufreq/tegra124-cpufreq.c | 46 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 46 insertions(+)
> 
> diff --git a/drivers/cpufreq/tegra124-cpufreq.c b/drivers/cpufreq/tegra124-cpufreq.c
> index 4f0c637b3b49..4eff63379b0f 100644
> --- a/drivers/cpufreq/tegra124-cpufreq.c
> +++ b/drivers/cpufreq/tegra124-cpufreq.c
> @@ -6,6 +6,7 @@
>  #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
>  
>  #include <linux/clk.h>
> +#include <linux/cpufreq.h>>  #include <linux/err.h>
>  #include <linux/init.h>
>  #include <linux/kernel.h>
> @@ -128,8 +129,53 @@ static int tegra124_cpufreq_probe(struct platform_device *pdev)
>  	return ret;
>  }
>  
> +static int tegra124_cpufreq_suspend(struct device *dev)

__maybe_unused

> +{
> +	struct tegra124_cpufreq_priv *priv = dev_get_drvdata(dev);
> +
> +	/*
> +	 * PLLP rate 408Mhz is below the CPU Fmax at Vmin and is safe to
> +	 * use during suspend and resume. So, switch the CPU clock source
> +	 * to PLLP and disable DFLL.
> +	 */
> +	clk_set_parent(priv->cpu_clk, priv->pllp_clk);

Error check?

> +
> +	/* disable DFLL clock */
> +	clk_disable_unprepare(priv->dfll_clk);
> +
> +	return 0;
> +}
> +
> +static int tegra124_cpufreq_resume(struct device *dev)

__maybe_unused

> +{
> +	struct tegra124_cpufreq_priv *priv = dev_get_drvdata(dev);
> +	int ret = 0;
> +
> +	/*
> +	 * Warmboot code powers up the CPU with PLLP clock source.
> +	 * Enable DFLL clock and switch CPU clock source back to DFLL.
> +	 */
> +	ret = clk_prepare_enable(priv->dfll_clk);
> +	if (ret) {
> +		dev_warn(dev, "failed to enable DFLL clock for CPU\n");

dev_err("..: %d\n", err);

> +		clk_set_parent(priv->cpu_clk, priv->pllp_clk);

This is not needed because CPU is already on PLLP.

> +		disable_cpufreq();
> +		return ret;
> +	}
> +
> +	clk_set_parent(priv->cpu_clk, priv->dfll_clk);

Error check?

> +
> +	return ret;
> +}
> +
> +static const struct dev_pm_ops tegra124_cpufreq_pm_ops = {
> +	SET_SYSTEM_SLEEP_PM_OPS(tegra124_cpufreq_suspend,
> +				tegra124_cpufreq_resume)
> +};
> +
>  static struct platform_driver tegra124_cpufreq_platdrv = {
>  	.driver.name	= "cpufreq-tegra124",
> +	.driver.pm	= &tegra124_cpufreq_pm_ops,
>  	.probe		= tegra124_cpufreq_probe,
>  };
>  
> 


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

* Re: [PATCH V6 09/21] clk: tegra: clk-super: Fix to enable PLLP branches to CPU
  2019-07-21 19:40 ` [PATCH V6 09/21] clk: tegra: clk-super: Fix to enable PLLP branches to CPU Sowjanya Komatineni
@ 2019-07-21 21:16   ` Dmitry Osipenko
  2019-07-21 22:39     ` Sowjanya Komatineni
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-21 21:16 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

21.07.2019 22:40, Sowjanya Komatineni пишет:
> This patch has a fix to enable PLLP branches to CPU before changing
> the CPU clusters clock source to PLLP for Gen5 Super clock.
> 
> During system suspend entry and exit, CPU source will be switched
> to PLLP and this needs PLLP branches to be enabled to CPU prior to
> the switch.
> 
> On system resume, warmboot code enables PLLP branches to CPU and
> powers up the CPU with PLLP clock source.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk-super.c            | 11 +++++++++++
>  drivers/clk/tegra/clk-tegra-super-gen4.c |  4 ++--
>  drivers/clk/tegra/clk.h                  |  4 ++++
>  3 files changed, 17 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c
> index 39ef31b46df5..d73c587e4853 100644
> --- a/drivers/clk/tegra/clk-super.c
> +++ b/drivers/clk/tegra/clk-super.c
> @@ -28,6 +28,9 @@
>  #define super_state_to_src_shift(m, s) ((m->width * s))
>  #define super_state_to_src_mask(m) (((1 << m->width) - 1))
>  
> +#define CCLK_SRC_PLLP_OUT0 4
> +#define CCLK_SRC_PLLP_OUT4 5
> +
>  static u8 clk_super_get_parent(struct clk_hw *hw)
>  {
>  	struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
> @@ -97,6 +100,14 @@ static int clk_super_set_parent(struct clk_hw *hw, u8 index)
>  		if (index == mux->div2_index)
>  			index = mux->pllx_index;
>  	}
> +
> +	/*
> +	 * Enable PLLP branches to CPU before selecting PLLP source
> +	 */
> +	if ((mux->flags & TEGRA_CPU_CLK) &&
> +	    ((index == CCLK_SRC_PLLP_OUT0) || (index == CCLK_SRC_PLLP_OUT4)))
> +		tegra_clk_set_pllp_out_cpu(true);

Should somewhere here be tegra_clk_set_pllp_out_cpu(false) when
switching from PLLP?

>  	val &= ~((super_state_to_src_mask(mux)) << shift);
>  	val |= (index & (super_state_to_src_mask(mux))) << shift;
>  
> diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c
> index cdfe7c9697e1..cd208d0eca2a 100644
> --- a/drivers/clk/tegra/clk-tegra-super-gen4.c
> +++ b/drivers/clk/tegra/clk-tegra-super-gen4.c
> @@ -180,7 +180,7 @@ static void __init tegra_super_clk_init(void __iomem *clk_base,
>  					gen_info->num_cclk_g_parents,
>  					CLK_SET_RATE_PARENT,
>  					clk_base + CCLKG_BURST_POLICY,
> -					0, 4, 8, 0, NULL);
> +					TEGRA_CPU_CLK, 4, 8, 0, NULL);
>  		} else {
>  			clk = tegra_clk_register_super_mux("cclk_g",
>  					gen_info->cclk_g_parents,
> @@ -201,7 +201,7 @@ static void __init tegra_super_clk_init(void __iomem *clk_base,
>  					gen_info->num_cclk_lp_parents,
>  					CLK_SET_RATE_PARENT,
>  					clk_base + CCLKLP_BURST_POLICY,
> -					0, 4, 8, 0, NULL);
> +					TEGRA_CPU_CLK, 4, 8, 0, NULL);
>  		} else {
>  			clk = tegra_clk_register_super_mux("cclk_lp",
>  					gen_info->cclk_lp_parents,
> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
> index ac6de3a0b91f..c357b49e49b0 100644
> --- a/drivers/clk/tegra/clk.h
> +++ b/drivers/clk/tegra/clk.h
> @@ -694,6 +694,9 @@ struct clk *tegra_clk_register_periph_data(void __iomem *clk_base,
>   * Flags:
>   * TEGRA_DIVIDER_2 - LP cluster has additional divider. This flag indicates
>   *     that this is LP cluster clock.
> + * TEGRA_CPU_CLK - This flag indicates this is CPU cluster clock. To use PLLP
> + * for CPU clock source, need to enable PLLP branches to CPU by setting the
> + * additional bit PLLP_OUT_CPU for gen5 super clock.
>   */
>  struct tegra_clk_super_mux {
>  	struct clk_hw	hw;
> @@ -710,6 +713,7 @@ struct tegra_clk_super_mux {
>  #define to_clk_super_mux(_hw) container_of(_hw, struct tegra_clk_super_mux, hw)
>  
>  #define TEGRA_DIVIDER_2 BIT(0)
> +#define TEGRA_CPU_CLK	BIT(1)

I'd name this TEGRA210_CPU_CLK for clarity.

>  extern const struct clk_ops tegra_clk_super_ops;
>  struct clk *tegra_clk_register_super_mux(const char *name,
> 

Will be better to move the tegra_clk_set_pllp_out_cpu() definition into
this patch, otherwise this looks inconsistent for reviewer.

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

* Re: [PATCH V6 11/21] clk: tegra: clk-dfll: Add suspend and resume support
  2019-07-21 19:40 ` [PATCH V6 11/21] clk: tegra: clk-dfll: Add suspend and resume support Sowjanya Komatineni
@ 2019-07-21 21:32   ` Dmitry Osipenko
  2019-07-21 22:42     ` Sowjanya Komatineni
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-21 21:32 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

21.07.2019 22:40, Sowjanya Komatineni пишет:
> This patch implements DFLL suspend and resume operation.
> 
> During system suspend entry, CPU clock will switch CPU to safe
> clock source of PLLP and disables DFLL clock output.
> 
> DFLL driver suspend confirms DFLL disable state and errors out on
> being active.
> 
> DFLL is re-initialized during the DFLL driver resume as it goes
> through complete reset during suspend entry.
> 
> Acked-by: Thierry Reding <treding@nvidia.com>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk-dfll.c               | 44 ++++++++++++++++++++++++++++++
>  drivers/clk/tegra/clk-dfll.h               |  2 ++
>  drivers/clk/tegra/clk-tegra124-dfll-fcpu.c |  1 +
>  3 files changed, 47 insertions(+)
> 
> diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c
> index f8688c2ddf1a..7dcad4ccd0ae 100644
> --- a/drivers/clk/tegra/clk-dfll.c
> +++ b/drivers/clk/tegra/clk-dfll.c
> @@ -1513,6 +1513,50 @@ static int dfll_init(struct tegra_dfll *td)
>  	return ret;
>  }
>  
> +/**
> + * tegra_dfll_suspend - check DFLL is disabled
> + * @dev: DFLL device *
> + *
> + * DFLL clock should be disabled by the CPUFreq driver. So, make
> + * sure it is disabled and disable all clocks needed by the DFLL.
> + */
> +int tegra_dfll_suspend(struct device *dev)
> +{
> +	struct tegra_dfll *td = dev_get_drvdata(dev);
> +
> +	if (dfll_is_running(td)) {
> +		dev_warn(td->dev, "failed disabling the dfll\n");

Something like "dfll is enabled while shouldn't be\n" will be more
informative.

This is a error, hence dev_err().

> +		return -EBUSY;
> +	}
> +
> +	pm_runtime_disable(dev);
> +
> +	clk_unprepare(td->ref_clk);
> +	clk_unprepare(td->soc_clk);
> +	clk_unprepare(td->i2c_clk);

Please don't do this, DFLL is already disabled if not running.

> +	reset_control_assert(td->dvco_rst);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(tegra_dfll_suspend);
> +
> +/**
> + * tegra_dfll_resume - reinitialize DFLL on resume
> + * @pdev: DFLL instance
> + *
> + * Re-initialize DFLL on resume as it gets disabled and reset during
> + * suspend entry. DFLL clock is enabled in closed loop mode later
> + * and CPU frequency will be switched to DFLL output.
> + */
> +int tegra_dfll_resume(struct device *dev)
> +{
> +	struct tegra_dfll *td = dev_get_drvdata(dev);
> +
> +	return dfll_init(td);

Just create dfll_reinit() variant.

> +}
> +EXPORT_SYMBOL(tegra_dfll_resume);
> +
>  /*
>   * DT data fetch
>   */
> diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h
> index 1b14ebe7268b..fb209eb5f365 100644
> --- a/drivers/clk/tegra/clk-dfll.h
> +++ b/drivers/clk/tegra/clk-dfll.h
> @@ -42,5 +42,7 @@ int tegra_dfll_register(struct platform_device *pdev,
>  struct tegra_dfll_soc_data *tegra_dfll_unregister(struct platform_device *pdev);
>  int tegra_dfll_runtime_suspend(struct device *dev);
>  int tegra_dfll_runtime_resume(struct device *dev);
> +int tegra_dfll_suspend(struct device *dev);
> +int tegra_dfll_resume(struct device *dev);
>  
>  #endif /* __DRIVERS_CLK_TEGRA_CLK_DFLL_H */
> diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
> index e84b6d52cbbd..2ac2679d696d 100644
> --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
> +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
> @@ -631,6 +631,7 @@ static int tegra124_dfll_fcpu_remove(struct platform_device *pdev)
>  static const struct dev_pm_ops tegra124_dfll_pm_ops = {
>  	SET_RUNTIME_PM_OPS(tegra_dfll_runtime_suspend,
>  			   tegra_dfll_runtime_resume, NULL)
> +	SET_SYSTEM_SLEEP_PM_OPS(tegra_dfll_suspend, tegra_dfll_resume)
>  };
>  
>  static struct platform_driver tegra124_dfll_fcpu_driver = {
> 


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

* Re: [PATCH V6 14/21] clk: tegra210: Add suspend and resume support
  2019-07-21 19:40 ` [PATCH V6 14/21] clk: tegra210: Add suspend and resume support Sowjanya Komatineni
@ 2019-07-21 21:38   ` Dmitry Osipenko
  2019-07-21 22:45     ` Sowjanya Komatineni
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-21 21:38 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

21.07.2019 22:40, Sowjanya Komatineni пишет:
> This patch adds support for clk: tegra210: suspend-resume.
> 
> All the CAR controller settings are lost on suspend when core
> power goes off.
> 
> This patch has implementation for saving and restoring all PLLs
> and clocks context during system suspend and resume to have the
> clocks back to same state for normal operation.
> 
> Acked-by: Thierry Reding <treding@nvidia.com>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk-tegra210.c | 68 ++++++++++++++++++++++++++++++++++++++--
>  drivers/clk/tegra/clk.c          | 14 +++++++++
>  drivers/clk/tegra/clk.h          |  1 +
>  3 files changed, 80 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
> index 55a88c0824a5..68271873acc1 100644
> --- a/drivers/clk/tegra/clk-tegra210.c
> +++ b/drivers/clk/tegra/clk-tegra210.c
> @@ -9,6 +9,7 @@
>  #include <linux/clkdev.h>
>  #include <linux/of.h>
>  #include <linux/of_address.h>
> +#include <linux/syscore_ops.h>
>  #include <linux/delay.h>
>  #include <linux/export.h>
>  #include <linux/mutex.h>
> @@ -220,11 +221,15 @@
>  #define CLK_M_DIVISOR_SHIFT 2
>  #define CLK_M_DIVISOR_MASK 0x3
>  
> +#define CLK_MASK_ARM	0x44
> +#define MISC_CLK_ENB	0x48
> +
>  #define RST_DFLL_DVCO 0x2f4
>  #define DVFS_DFLL_RESET_SHIFT 0
>  
>  #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
> @@ -2825,6 +2830,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)
> @@ -2853,9 +2859,8 @@ static int tegra210_enable_pllu(void)
>  	reg |= PLL_ENABLE;
>  	writel(reg, clk_base + PLLU_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) {

Why this is needed? Was there a bug?

>  		pr_err("Timed out waiting for PLL_U to lock\n");
>  		return -ETIMEDOUT;
>  	}
> @@ -3288,6 +3293,56 @@ static void tegra210_disable_cpu_clock(u32 cpu)
>  }
>  
>  #ifdef CONFIG_PM_SLEEP
> +#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 spare_reg_ctx, misc_clk_enb_ctx, clk_msk_arm_ctx;
> +static u32 cpu_softrst_ctx[3];
> +
> +static int tegra210_clk_suspend(void)
> +{
> +	unsigned int i;
> +
> +	clk_save_context();
> +
> +	/*
> +	 * save the bootloader configured clock registers SPARE_REG0,
> +	 * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL

Nit: Start all multi-line comments with a capital letter and put dot in
the end of sentence.

> +	 */
> +	spare_reg_ctx = readl_relaxed(clk_base + SPARE_REG0);
> +	misc_clk_enb_ctx = readl_relaxed(clk_base + MISC_CLK_ENB);
> +	clk_msk_arm_ctx = readl_relaxed(clk_base + CLK_MASK_ARM);
> +
> +	for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
> +		cpu_softrst_ctx[i] = car_readl(CPU_SOFTRST_CTRL, i);
> +
> +	return 0;
> +}
> +
> +static void tegra210_clk_resume(void)
> +{
> +	unsigned int i;
> +
> +	tegra_clk_osc_resume(clk_base);
> +
> +	/*
> +	 * restore the bootloader configured clock registers SPARE_REG0,
> +	 * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL from saved context.

Same here.

> +	 */
> +	writel_relaxed(spare_reg_ctx, clk_base + SPARE_REG0);
> +	writel_relaxed(misc_clk_enb_ctx, clk_base + MISC_CLK_ENB);
> +	writel_relaxed(clk_msk_arm_ctx, clk_base + CLK_MASK_ARM);
> +
> +	for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
> +		car_writel(cpu_softrst_ctx[i], CPU_SOFTRST_CTRL, i);
> +
> +	fence_udelay(5, clk_base);
> +
> +	tegra210_init_pllu();
> +	clk_restore_context();
> +}
> +
>  static void tegra210_cpu_clock_suspend(void)
>  {
>  	/* switch coresite to clk_m, save off original source */
> @@ -3303,6 +3358,11 @@ static void tegra210_cpu_clock_resume(void)
>  }
>  #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,
> @@ -3587,5 +3647,7 @@ static void __init tegra210_clock_init(struct device_node *np)
>  	tegra210_mbist_clk_init();
>  
>  	tegra_cpu_car_ops = &tegra210_cpu_car_ops;
> +
> +	register_syscore_ops(&tegra_clk_syscore_ops);
>  }
>  CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);
> diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
> index 573e3c967ae1..eb08047fd02f 100644
> --- a/drivers/clk/tegra/clk.c
> +++ b/drivers/clk/tegra/clk.c
> @@ -23,6 +23,7 @@
>  #define CLK_OUT_ENB_W			0x364
>  #define CLK_OUT_ENB_X			0x280
>  #define CLK_OUT_ENB_Y			0x298
> +#define CLK_ENB_PLLP_OUT_CPU		BIT(31)
>  #define CLK_OUT_ENB_SET_L		0x320
>  #define CLK_OUT_ENB_CLR_L		0x324
>  #define CLK_OUT_ENB_SET_H		0x328
> @@ -199,6 +200,19 @@ const struct tegra_clk_periph_regs *get_reg_bank(int clkid)
>  	}
>  }
>  
> +void tegra_clk_set_pllp_out_cpu(bool enable)
> +{
> +	u32 val;
> +
> +	val = readl_relaxed(clk_base + CLK_OUT_ENB_Y);
> +	if (enable)
> +		val |= CLK_ENB_PLLP_OUT_CPU;
> +	else
> +		val &= ~CLK_ENB_PLLP_OUT_CPU;
> +
> +	writel_relaxed(val, clk_base + CLK_OUT_ENB_Y);
> +}
> +
>  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 562a3ee2d537..0ffa763c755b 100644
> --- a/drivers/clk/tegra/clk.h
> +++ b/drivers/clk/tegra/clk.h
> @@ -863,6 +863,7 @@ 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_clk_osc_resume(void __iomem *clk_base);
> +void tegra_clk_set_pllp_out_cpu(bool enable);
>  
>  /* Combined read fence with delay */
>  #define fence_udelay(delay, reg)	\
> 


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

* Re: [PATCH V6 06/21] clk: tegra: pll: Save and restore pll context
  2019-07-21 19:40 ` [PATCH V6 06/21] clk: tegra: pll: Save and restore pll context Sowjanya Komatineni
@ 2019-07-21 21:44   ` Dmitry Osipenko
  2019-07-21 22:47     ` Sowjanya Komatineni
  2019-07-21 22:21   ` Dmitry Osipenko
  1 sibling, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-21 21:44 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

21.07.2019 22:40, Sowjanya Komatineni пишет:
> 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.
> 
> Acked-by: Thierry Reding <treding@nvidia.com>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk-pll.c      | 121 ++++++++++++++++++++++++++++-----------
>  drivers/clk/tegra/clk-tegra210.c |   2 +-
>  drivers/clk/tegra/clk.h          |  10 +++-
>  3 files changed, 99 insertions(+), 34 deletions(-)
> 
> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
> index 1583f5fc992f..f136964e6c44 100644
> --- a/drivers/clk/tegra/clk-pll.c
> +++ b/drivers/clk/tegra/clk-pll.c
> @@ -1008,6 +1008,59 @@ 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);
> +	u32 val = 0;
> +
> +	pll->rate = clk_hw_get_rate(hw);
> +
> +	if (pll->params->flags & TEGRA_PLLMB)
> +		val = pll_readl_base(pll);
> +	else if (pll->params->flags & TEGRA_PLLRE)
> +		val = pll_readl_base(pll) & divp_mask_shifted(pll);
> +
> +	pll->pllbase_ctx = val;
> +
> +	return 0;
> +}
> +
> +static void tegra_clk_pll_restore_context(struct clk_hw *hw)
> +{
> +	struct tegra_clk_pll *pll = to_clk_pll(hw);
> +	struct clk_hw *parent = clk_hw_get_parent(hw);
> +	unsigned long parent_rate = clk_hw_get_rate(parent);
> +	u32 val;
> +
> +	if (clk_pll_is_enabled(hw))
> +		return;
> +
> +	if (pll->params->flags & TEGRA_PLLMB) {
> +		pll_writel_base(pll->pllbase_ctx, pll);
> +	} else if (pll->params->flags & TEGRA_PLLRE) {
> +		val = pll_readl_base(pll);
> +		val &= ~(divp_mask_shifted(pll));
> +		pll_writel_base(pll->pllbase_ctx | val, pll);
> +	}
> +
> +	if (pll->params->set_defaults)
> +		pll->params->set_defaults(pll);
> +
> +	clk_pll_set_rate(hw, pll->rate, parent_rate);
> +
> +	/* do not sync pllx state here. pllx is sync'd after dfll resume */
> +	if (!(pll->params->flags & TEGRA_PLLX))
> +		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 +1068,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 +1857,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 +2290,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 +2337,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,
> @@ -2375,6 +2438,7 @@ struct clk *tegra_clk_register_pllre_tegra210(const char *name,
>  		pll_params->vco_min = pll_params->adjust_vco(pll_params,
>  							     parent_rate);
>  
> +	pll_params->flags |= TEGRA_PLLRE;
>  	pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
>  	if (IS_ERR(pll))
>  		return ERR_CAST(pll);
> @@ -2520,11 +2584,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 +2607,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-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
> index 4721ee030d1c..58397f93166c 100644
> --- a/drivers/clk/tegra/clk-tegra210.c
> +++ b/drivers/clk/tegra/clk-tegra210.c
> @@ -1602,7 +1602,7 @@ static struct tegra_clk_pll_params pll_x_params = {
>  	.pdiv_tohw = pll_qlin_pdiv_to_hw,
>  	.div_nmp = &pllx_nmp,
>  	.freq_table = pll_x_freq_table,
> -	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
> +	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLLX,
>  	.dyn_ramp = tegra210_pllx_dyn_ramp,
>  	.set_defaults = tegra210_pllx_set_defaults,
>  	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
> index fb29a8c27873..8532f5150091 100644
> --- a/drivers/clk/tegra/clk.h
> +++ b/drivers/clk/tegra/clk.h
> @@ -235,6 +235,8 @@ struct tegra_clk_pll;
>   * TEGRA_PLLMB - PLLMB has should be treated similar to PLLM. This
>   *     flag indicated that it is PLLMB.
>   * TEGRA_PLL_VCO_OUT - Used to indicate that the PLL has a VCO output
> + * TEGRA_PLLRE - Used to indicate that it is PLLRE.
> + * TEGRA_PLLX - Used to indicate that it is PLLX.
>   */
>  struct tegra_clk_pll_params {
>  	unsigned long	input_min;
> @@ -301,6 +303,8 @@ struct tegra_clk_pll_params {
>  #define TEGRA_MDIV_NEW BIT(11)
>  #define TEGRA_PLLMB BIT(12)
>  #define TEGRA_PLL_VCO_OUT BIT(13)
> +#define TEGRA_PLLRE BIT(14)
> +#define TEGRA_PLLX BIT(15)
>  
>  /**
>   * struct tegra_clk_pll - Tegra PLL clock
> @@ -310,6 +314,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 +323,8 @@ struct tegra_clk_pll {
>  	void __iomem	*pmc;
>  	spinlock_t	*lock;
>  	struct tegra_clk_pll_params	*params;
> +	unsigned long	rate;
> +	u32	pllbase_ctx;
>  };
>  
>  #define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw)
> @@ -840,7 +848,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);

Looks like this function isn't used anywhere other than this patch. Bug?

>  /* Combined read fence with delay */
>  #define fence_udelay(delay, reg)	\
> 


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

* Re: [PATCH V6 02/21] pinctrl: tegra: Add suspend and resume support
  2019-07-21 19:40 ` [PATCH V6 02/21] pinctrl: tegra: Add suspend and resume support Sowjanya Komatineni
@ 2019-07-21 22:03   ` Dmitry Osipenko
  2019-07-21 22:09     ` Dmitry Osipenko
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-21 22:03 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

21.07.2019 22:40, Sowjanya Komatineni пишет:
> This patch adds support for Tegra pinctrl driver suspend and resume.
> 
> During suspend, context of all pinctrl registers are stored and
> on resume they are all restored to have all the pinmux and pad
> configuration for normal operation.
> 
> Acked-by: Thierry Reding <treding@nvidia.com>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/pinctrl/tegra/pinctrl-tegra.c | 59 +++++++++++++++++++++++++++++++++++
>  drivers/pinctrl/tegra/pinctrl-tegra.h |  3 ++
>  2 files changed, 62 insertions(+)
> 
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
> index 186ef98e7b2b..e3a237534281 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
> @@ -631,6 +631,58 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
>  	}
>  }
>  
> +static size_t tegra_pinctrl_get_bank_size(struct device *dev,
> +					  unsigned int bank_id)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct resource *res;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, bank_id);
> +
> +	return resource_size(res) / 4;
> +}
> +
> +static int tegra_pinctrl_suspend(struct device *dev)
> +{
> +	struct tegra_pmx *pmx = dev_get_drvdata(dev);
> +	u32 *backup_regs = pmx->backup_regs;
> +	u32 *regs;
> +	size_t bank_size;
> +	unsigned int i, k;
> +
> +	for (i = 0; i < pmx->nbanks; i++) {
> +		bank_size = tegra_pinctrl_get_bank_size(dev, i);
> +		regs = pmx->regs[i];
> +		for (k = 0; k < bank_size; k++)
> +			*backup_regs++ = readl_relaxed(regs++);
> +	}
> +
> +	return pinctrl_force_sleep(pmx->pctl);
> +}
> +
> +static int tegra_pinctrl_resume(struct device *dev)
> +{
> +	struct tegra_pmx *pmx = dev_get_drvdata(dev);
> +	u32 *backup_regs = pmx->backup_regs;
> +	u32 *regs;
> +	size_t bank_size;
> +	unsigned int i, k;
> +
> +	for (i = 0; i < pmx->nbanks; i++) {
> +		bank_size = tegra_pinctrl_get_bank_size(dev, i);
> +		regs = pmx->regs[i];
> +		for (k = 0; k < bank_size; k++)
> +			writel_relaxed(*backup_regs++, regs++);
> +	}
> +
> +	return 0;
> +}
> +
> +const struct dev_pm_ops tegra_pinctrl_pm = {
> +	.suspend = &tegra_pinctrl_suspend,
> +	.resume = &tegra_pinctrl_resume
> +};
> +
>  static bool gpio_node_has_range(const char *compatible)
>  {
>  	struct device_node *np;
> @@ -655,6 +707,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)
> @@ -707,6 +760,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;
>  
> @@ -715,6 +769,11 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
>  	if (!pmx->regs)
>  		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);
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
> index 105309774079..0fc82eea9cf1 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra.h
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
> @@ -17,6 +17,7 @@ struct tegra_pmx {
>  
>  	int nbanks;
>  	void __iomem **regs;
> +	u32 *backup_regs;
>  };
>  
>  enum tegra_pinconf_param {
> @@ -193,6 +194,8 @@ struct tegra_pinctrl_soc_data {
>  	bool drvtype_in_mux;
>  };
>  
> +extern const struct dev_pm_ops tegra_pinctrl_pm;
> +
>  int tegra_pinctrl_probe(struct platform_device *pdev,
>  			const struct tegra_pinctrl_soc_data *soc_data);
>  #endif
> 

Reviewed-by: Dmitry Osipenko <digetx@gmail.com>

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

* Re: [PATCH V6 02/21] pinctrl: tegra: Add suspend and resume support
  2019-07-21 22:03   ` Dmitry Osipenko
@ 2019-07-21 22:09     ` Dmitry Osipenko
  2019-07-21 22:48       ` Sowjanya Komatineni
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-21 22:09 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

22.07.2019 1:03, Dmitry Osipenko пишет:
> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>> This patch adds support for Tegra pinctrl driver suspend and resume.
>>
>> During suspend, context of all pinctrl registers are stored and
>> on resume they are all restored to have all the pinmux and pad
>> configuration for normal operation.
>>
>> Acked-by: Thierry Reding <treding@nvidia.com>
>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>> ---
>>  drivers/pinctrl/tegra/pinctrl-tegra.c | 59 +++++++++++++++++++++++++++++++++++
>>  drivers/pinctrl/tegra/pinctrl-tegra.h |  3 ++
>>  2 files changed, 62 insertions(+)
>>
>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
>> index 186ef98e7b2b..e3a237534281 100644
>> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
>> @@ -631,6 +631,58 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
>>  	}
>>  }
>>  
>> +static size_t tegra_pinctrl_get_bank_size(struct device *dev,
>> +					  unsigned int bank_id)
>> +{
>> +	struct platform_device *pdev = to_platform_device(dev);
>> +	struct resource *res;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, bank_id);
>> +
>> +	return resource_size(res) / 4;
>> +}
>> +
>> +static int tegra_pinctrl_suspend(struct device *dev)
>> +{
>> +	struct tegra_pmx *pmx = dev_get_drvdata(dev);
>> +	u32 *backup_regs = pmx->backup_regs;
>> +	u32 *regs;
>> +	size_t bank_size;
>> +	unsigned int i, k;
>> +
>> +	for (i = 0; i < pmx->nbanks; i++) {
>> +		bank_size = tegra_pinctrl_get_bank_size(dev, i);
>> +		regs = pmx->regs[i];
>> +		for (k = 0; k < bank_size; k++)
>> +			*backup_regs++ = readl_relaxed(regs++);
>> +	}
>> +
>> +	return pinctrl_force_sleep(pmx->pctl);
>> +}
>> +
>> +static int tegra_pinctrl_resume(struct device *dev)
>> +{
>> +	struct tegra_pmx *pmx = dev_get_drvdata(dev);
>> +	u32 *backup_regs = pmx->backup_regs;
>> +	u32 *regs;
>> +	size_t bank_size;
>> +	unsigned int i, k;
>> +
>> +	for (i = 0; i < pmx->nbanks; i++) {
>> +		bank_size = tegra_pinctrl_get_bank_size(dev, i);
>> +		regs = pmx->regs[i];
>> +		for (k = 0; k < bank_size; k++)
>> +			writel_relaxed(*backup_regs++, regs++);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +const struct dev_pm_ops tegra_pinctrl_pm = {
>> +	.suspend = &tegra_pinctrl_suspend,
>> +	.resume = &tegra_pinctrl_resume
>> +};
>> +
>>  static bool gpio_node_has_range(const char *compatible)
>>  {
>>  	struct device_node *np;
>> @@ -655,6 +707,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)
>> @@ -707,6 +760,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;
>>  
>> @@ -715,6 +769,11 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
>>  	if (!pmx->regs)
>>  		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);
>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
>> index 105309774079..0fc82eea9cf1 100644
>> --- a/drivers/pinctrl/tegra/pinctrl-tegra.h
>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
>> @@ -17,6 +17,7 @@ struct tegra_pmx {
>>  
>>  	int nbanks;
>>  	void __iomem **regs;
>> +	u32 *backup_regs;
>>  };
>>  
>>  enum tegra_pinconf_param {
>> @@ -193,6 +194,8 @@ struct tegra_pinctrl_soc_data {
>>  	bool drvtype_in_mux;
>>  };
>>  
>> +extern const struct dev_pm_ops tegra_pinctrl_pm;
>> +
>>  int tegra_pinctrl_probe(struct platform_device *pdev,
>>  			const struct tegra_pinctrl_soc_data *soc_data);
>>  #endif
>>
> 
> Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
> 

BTW, you should remove Thierry's ACK from all patches that were modified
if he didn't re-ACK the new version.

Also, it looks to me that you're manually adding versioning to the
patches because git usually uses lowercase for 'v'. You could use "git
format-patch -v6 ..".

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

* Re: [PATCH V6 04/21] clk: tegra: Save and restore divider rate
  2019-07-21 19:40 ` [PATCH V6 04/21] clk: tegra: Save and restore divider rate Sowjanya Komatineni
@ 2019-07-21 22:14   ` Dmitry Osipenko
  0 siblings, 0 replies; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-21 22:14 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

21.07.2019 22:40, Sowjanya Komatineni пишет:
> 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.
> 
> Acked-by: Thierry Reding <treding@nvidia.com>
> 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);

I'm not sure what's the point of this, because clk_hw_get_rate() returns
cached value.

> +	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);

Hence this could be:

	unsigned long parent_rate = clk_hw_get_rate(parent);
	unsigned long rate = clk_hw_get_rate(hw);

	if (clk_frac_div_set_rate(hw, 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)
> 


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

* Re: [PATCH V6 05/21] clk: tegra: pllout: Save and restore pllout context
  2019-07-21 19:40 ` [PATCH V6 05/21] clk: tegra: pllout: Save and restore pllout context Sowjanya Komatineni
@ 2019-07-21 22:18   ` Dmitry Osipenko
  0 siblings, 0 replies; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-21 22:18 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

21.07.2019 22:40, Sowjanya Komatineni пишет:
> 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.
> 
> Acked-by: Thierry Reding <treding@nvidia.com>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk-pll-out.c  | 28 ++++++++++++++++++++++++++++
>  drivers/clk/tegra/clk-tegra210.c |  3 ++-
>  drivers/clk/tegra/clk.h          |  9 +++++++++
>  3 files changed, 39 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/clk/tegra/clk-pll-out.c b/drivers/clk/tegra/clk-pll-out.c
> index 35f2bf00e1e6..8f26a7e3e579 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 (pll_out->flags & TEGRA_PLLRE_OUT)
> +		pll_out->pllout_ctx = readl_relaxed(pll_out->reg);


> +	else
> +		pll_out->pllout_ctx = clk_hw_get_rate(hw);

This is unused?

> +	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 (pll_out->flags & TEGRA_PLLRE_OUT) {
> +		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-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
> index df172d5772d7..4721ee030d1c 100644
> --- a/drivers/clk/tegra/clk-tegra210.c
> +++ b/drivers/clk/tegra/clk-tegra210.c
> @@ -3200,7 +3200,8 @@ static void __init tegra210_pll_init(void __iomem *clk_base,
>  					 8, 8, 1, NULL);
>  	clk = tegra_clk_register_pll_out("pll_re_out1", "pll_re_out1_div",
>  					 clk_base + PLLRE_OUT1, 1, 0,
> -					 CLK_SET_RATE_PARENT, 0, NULL);
> +					 CLK_SET_RATE_PARENT, TEGRA_PLLRE_OUT,
> +					 NULL);
>  	clks[TEGRA210_CLK_PLL_RE_OUT1] = clk;
>  
>  	/* PLLE */
> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
> index 83623f5f55f3..fb29a8c27873 100644
> --- a/drivers/clk/tegra/clk.h
> +++ b/drivers/clk/tegra/clk.h
> @@ -439,6 +439,12 @@ 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
> + *
> + * Flags:
> + * TEGRA_PLLRE_OUT - This flag indicates that it is PLLRE_OUT and is used to
> + *		     identify PLLRE_OUT during clk_pll_out save and restore.
>   */
>  struct tegra_clk_pll_out {
>  	struct clk_hw	hw;
> @@ -447,8 +453,11 @@ struct tegra_clk_pll_out {
>  	u8		rst_bit_idx;
>  	spinlock_t	*lock;
>  	u8		flags;
> +	unsigned int	pllout_ctx;

u32

>  };
>  
> +#define TEGRA_PLLRE_OUT BIT(0)
> +
>  #define to_clk_pll_out(_hw) container_of(_hw, struct tegra_clk_pll_out, hw)
>  
>  extern const struct clk_ops tegra_clk_pll_out_ops;
> 


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

* Re: [PATCH V6 06/21] clk: tegra: pll: Save and restore pll context
  2019-07-21 19:40 ` [PATCH V6 06/21] clk: tegra: pll: Save and restore pll context Sowjanya Komatineni
  2019-07-21 21:44   ` Dmitry Osipenko
@ 2019-07-21 22:21   ` Dmitry Osipenko
  2019-07-22  3:22     ` Sowjanya Komatineni
  1 sibling, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-21 22:21 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

21.07.2019 22:40, Sowjanya Komatineni пишет:
> 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.
> 
> Acked-by: Thierry Reding <treding@nvidia.com>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk-pll.c      | 121 ++++++++++++++++++++++++++++-----------
>  drivers/clk/tegra/clk-tegra210.c |   2 +-
>  drivers/clk/tegra/clk.h          |  10 +++-
>  3 files changed, 99 insertions(+), 34 deletions(-)
> 
> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
> index 1583f5fc992f..f136964e6c44 100644
> --- a/drivers/clk/tegra/clk-pll.c
> +++ b/drivers/clk/tegra/clk-pll.c
> @@ -1008,6 +1008,59 @@ 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);
> +	u32 val = 0;
> +
> +	pll->rate = clk_hw_get_rate(hw);

Again, clk_hw_get_rate() returns cached value. Why do you need to
duplicate it?

> +	if (pll->params->flags & TEGRA_PLLMB)
> +		val = pll_readl_base(pll);
> +	else if (pll->params->flags & TEGRA_PLLRE)
> +		val = pll_readl_base(pll) & divp_mask_shifted(pll);
> +
> +	pll->pllbase_ctx = val;
> +
> +	return 0;
> +}
> +
> +static void tegra_clk_pll_restore_context(struct clk_hw *hw)
> +{
> +	struct tegra_clk_pll *pll = to_clk_pll(hw);
> +	struct clk_hw *parent = clk_hw_get_parent(hw);
> +	unsigned long parent_rate = clk_hw_get_rate(parent);
> +	u32 val;
> +
> +	if (clk_pll_is_enabled(hw))
> +		return;
> +
> +	if (pll->params->flags & TEGRA_PLLMB) {
> +		pll_writel_base(pll->pllbase_ctx, pll);
> +	} else if (pll->params->flags & TEGRA_PLLRE) {
> +		val = pll_readl_base(pll);
> +		val &= ~(divp_mask_shifted(pll));
> +		pll_writel_base(pll->pllbase_ctx | val, pll);
> +	}
> +
> +	if (pll->params->set_defaults)
> +		pll->params->set_defaults(pll);
> +
> +	clk_pll_set_rate(hw, pll->rate, parent_rate);
> +
> +	/* do not sync pllx state here. pllx is sync'd after dfll resume */
> +	if (!(pll->params->flags & TEGRA_PLLX))
> +		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 +1068,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 +1857,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 +2290,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 +2337,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,
> @@ -2375,6 +2438,7 @@ struct clk *tegra_clk_register_pllre_tegra210(const char *name,
>  		pll_params->vco_min = pll_params->adjust_vco(pll_params,
>  							     parent_rate);
>  
> +	pll_params->flags |= TEGRA_PLLRE;
>  	pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
>  	if (IS_ERR(pll))
>  		return ERR_CAST(pll);
> @@ -2520,11 +2584,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 +2607,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-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
> index 4721ee030d1c..58397f93166c 100644
> --- a/drivers/clk/tegra/clk-tegra210.c
> +++ b/drivers/clk/tegra/clk-tegra210.c
> @@ -1602,7 +1602,7 @@ static struct tegra_clk_pll_params pll_x_params = {
>  	.pdiv_tohw = pll_qlin_pdiv_to_hw,
>  	.div_nmp = &pllx_nmp,
>  	.freq_table = pll_x_freq_table,
> -	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
> +	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLLX,
>  	.dyn_ramp = tegra210_pllx_dyn_ramp,
>  	.set_defaults = tegra210_pllx_set_defaults,
>  	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
> index fb29a8c27873..8532f5150091 100644
> --- a/drivers/clk/tegra/clk.h
> +++ b/drivers/clk/tegra/clk.h
> @@ -235,6 +235,8 @@ struct tegra_clk_pll;
>   * TEGRA_PLLMB - PLLMB has should be treated similar to PLLM. This
>   *     flag indicated that it is PLLMB.
>   * TEGRA_PLL_VCO_OUT - Used to indicate that the PLL has a VCO output
> + * TEGRA_PLLRE - Used to indicate that it is PLLRE.
> + * TEGRA_PLLX - Used to indicate that it is PLLX.
>   */
>  struct tegra_clk_pll_params {
>  	unsigned long	input_min;
> @@ -301,6 +303,8 @@ struct tegra_clk_pll_params {
>  #define TEGRA_MDIV_NEW BIT(11)
>  #define TEGRA_PLLMB BIT(12)
>  #define TEGRA_PLL_VCO_OUT BIT(13)
> +#define TEGRA_PLLRE BIT(14)
> +#define TEGRA_PLLX BIT(15)
>  
>  /**
>   * struct tegra_clk_pll - Tegra PLL clock
> @@ -310,6 +314,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 +323,8 @@ struct tegra_clk_pll {
>  	void __iomem	*pmc;
>  	spinlock_t	*lock;
>  	struct tegra_clk_pll_params	*params;
> +	unsigned long	rate;
> +	u32	pllbase_ctx;
>  };
>  
>  #define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw)
> @@ -840,7 +848,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)	\
> 


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

* Re: [PATCH V6 21/21] arm64: dts: tegra210-p3450: Jetson nano SC7 timings
  2019-07-21 19:41 ` [PATCH V6 21/21] arm64: dts: tegra210-p3450: Jetson nano " Sowjanya Komatineni
@ 2019-07-21 22:25   ` Dmitry Osipenko
  0 siblings, 0 replies; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-21 22:25 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

21.07.2019 22:41, Sowjanya Komatineni пишет:
> This patch adds Jetson nano platform specific SC7 timing configuration
> in the device tree.

You should stat all names with a capital letter, hence "Jetson Nano" and
"Tegra" in all patches (commit title/message and code comments). When
unsure, just go to google and find how official name looks like.

> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
> index 9d17ec707bce..b525e69c172a 100644
> --- a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
> +++ b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
> @@ -382,6 +382,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;
>  	};
>  
>  	hda@70030000 {
> 


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

* Re: [PATCH V6 09/21] clk: tegra: clk-super: Fix to enable PLLP branches to CPU
  2019-07-21 21:16   ` Dmitry Osipenko
@ 2019-07-21 22:39     ` Sowjanya Komatineni
  2019-07-22  3:17       ` Sowjanya Komatineni
  0 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 22:39 UTC (permalink / raw)
  To: Dmitry Osipenko, 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


On 7/21/19 2:16 PM, Dmitry Osipenko wrote:
> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>> This patch has a fix to enable PLLP branches to CPU before changing
>> the CPU clusters clock source to PLLP for Gen5 Super clock.
>>
>> During system suspend entry and exit, CPU source will be switched
>> to PLLP and this needs PLLP branches to be enabled to CPU prior to
>> the switch.
>>
>> On system resume, warmboot code enables PLLP branches to CPU and
>> powers up the CPU with PLLP clock source.
>>
>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>> ---
>>   drivers/clk/tegra/clk-super.c            | 11 +++++++++++
>>   drivers/clk/tegra/clk-tegra-super-gen4.c |  4 ++--
>>   drivers/clk/tegra/clk.h                  |  4 ++++
>>   3 files changed, 17 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c
>> index 39ef31b46df5..d73c587e4853 100644
>> --- a/drivers/clk/tegra/clk-super.c
>> +++ b/drivers/clk/tegra/clk-super.c
>> @@ -28,6 +28,9 @@
>>   #define super_state_to_src_shift(m, s) ((m->width * s))
>>   #define super_state_to_src_mask(m) (((1 << m->width) - 1))
>>   
>> +#define CCLK_SRC_PLLP_OUT0 4
>> +#define CCLK_SRC_PLLP_OUT4 5
>> +
>>   static u8 clk_super_get_parent(struct clk_hw *hw)
>>   {
>>   	struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
>> @@ -97,6 +100,14 @@ static int clk_super_set_parent(struct clk_hw *hw, u8 index)
>>   		if (index == mux->div2_index)
>>   			index = mux->pllx_index;
>>   	}
>> +
>> +	/*
>> +	 * Enable PLLP branches to CPU before selecting PLLP source
>> +	 */
>> +	if ((mux->flags & TEGRA_CPU_CLK) &&
>> +	    ((index == CCLK_SRC_PLLP_OUT0) || (index == CCLK_SRC_PLLP_OUT4)))
>> +		tegra_clk_set_pllp_out_cpu(true);
> Should somewhere here be tegra_clk_set_pllp_out_cpu(false) when
> switching from PLLP?
PLLP may be used for other CPU clusters.
>>   	val &= ~((super_state_to_src_mask(mux)) << shift);
>>   	val |= (index & (super_state_to_src_mask(mux))) << shift;
>>   
>> diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c
>> index cdfe7c9697e1..cd208d0eca2a 100644
>> --- a/drivers/clk/tegra/clk-tegra-super-gen4.c
>> +++ b/drivers/clk/tegra/clk-tegra-super-gen4.c
>> @@ -180,7 +180,7 @@ static void __init tegra_super_clk_init(void __iomem *clk_base,
>>   					gen_info->num_cclk_g_parents,
>>   					CLK_SET_RATE_PARENT,
>>   					clk_base + CCLKG_BURST_POLICY,
>> -					0, 4, 8, 0, NULL);
>> +					TEGRA_CPU_CLK, 4, 8, 0, NULL);
>>   		} else {
>>   			clk = tegra_clk_register_super_mux("cclk_g",
>>   					gen_info->cclk_g_parents,
>> @@ -201,7 +201,7 @@ static void __init tegra_super_clk_init(void __iomem *clk_base,
>>   					gen_info->num_cclk_lp_parents,
>>   					CLK_SET_RATE_PARENT,
>>   					clk_base + CCLKLP_BURST_POLICY,
>> -					0, 4, 8, 0, NULL);
>> +					TEGRA_CPU_CLK, 4, 8, 0, NULL);
>>   		} else {
>>   			clk = tegra_clk_register_super_mux("cclk_lp",
>>   					gen_info->cclk_lp_parents,
>> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
>> index ac6de3a0b91f..c357b49e49b0 100644
>> --- a/drivers/clk/tegra/clk.h
>> +++ b/drivers/clk/tegra/clk.h
>> @@ -694,6 +694,9 @@ struct clk *tegra_clk_register_periph_data(void __iomem *clk_base,
>>    * Flags:
>>    * TEGRA_DIVIDER_2 - LP cluster has additional divider. This flag indicates
>>    *     that this is LP cluster clock.
>> + * TEGRA_CPU_CLK - This flag indicates this is CPU cluster clock. To use PLLP
>> + * for CPU clock source, need to enable PLLP branches to CPU by setting the
>> + * additional bit PLLP_OUT_CPU for gen5 super clock.
>>    */
>>   struct tegra_clk_super_mux {
>>   	struct clk_hw	hw;
>> @@ -710,6 +713,7 @@ struct tegra_clk_super_mux {
>>   #define to_clk_super_mux(_hw) container_of(_hw, struct tegra_clk_super_mux, hw)
>>   
>>   #define TEGRA_DIVIDER_2 BIT(0)
>> +#define TEGRA_CPU_CLK	BIT(1)
> I'd name this TEGRA210_CPU_CLK for clarity.
>
>>   extern const struct clk_ops tegra_clk_super_ops;
>>   struct clk *tegra_clk_register_super_mux(const char *name,
>>
> Will be better to move the tegra_clk_set_pllp_out_cpu() definition into
> this patch, otherwise this looks inconsistent for reviewer.
ok, Will move to this patch

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

* Re: [PATCH V6 11/21] clk: tegra: clk-dfll: Add suspend and resume support
  2019-07-21 21:32   ` Dmitry Osipenko
@ 2019-07-21 22:42     ` Sowjanya Komatineni
  0 siblings, 0 replies; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 22:42 UTC (permalink / raw)
  To: Dmitry Osipenko, 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


On 7/21/19 2:32 PM, Dmitry Osipenko wrote:
> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>> This patch implements DFLL suspend and resume operation.
>>
>> During system suspend entry, CPU clock will switch CPU to safe
>> clock source of PLLP and disables DFLL clock output.
>>
>> DFLL driver suspend confirms DFLL disable state and errors out on
>> being active.
>>
>> DFLL is re-initialized during the DFLL driver resume as it goes
>> through complete reset during suspend entry.
>>
>> Acked-by: Thierry Reding <treding@nvidia.com>
>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>> ---
>>   drivers/clk/tegra/clk-dfll.c               | 44 ++++++++++++++++++++++++++++++
>>   drivers/clk/tegra/clk-dfll.h               |  2 ++
>>   drivers/clk/tegra/clk-tegra124-dfll-fcpu.c |  1 +
>>   3 files changed, 47 insertions(+)
>>
>> diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c
>> index f8688c2ddf1a..7dcad4ccd0ae 100644
>> --- a/drivers/clk/tegra/clk-dfll.c
>> +++ b/drivers/clk/tegra/clk-dfll.c
>> @@ -1513,6 +1513,50 @@ static int dfll_init(struct tegra_dfll *td)
>>   	return ret;
>>   }
>>   
>> +/**
>> + * tegra_dfll_suspend - check DFLL is disabled
>> + * @dev: DFLL device *
>> + *
>> + * DFLL clock should be disabled by the CPUFreq driver. So, make
>> + * sure it is disabled and disable all clocks needed by the DFLL.
>> + */
>> +int tegra_dfll_suspend(struct device *dev)
>> +{
>> +	struct tegra_dfll *td = dev_get_drvdata(dev);
>> +
>> +	if (dfll_is_running(td)) {
>> +		dev_warn(td->dev, "failed disabling the dfll\n");
> Something like "dfll is enabled while shouldn't be\n" will be more
> informative.
>
> This is a error, hence dev_err().
>
>> +		return -EBUSY;
>> +	}
>> +
>> +	pm_runtime_disable(dev);
>> +
>> +	clk_unprepare(td->ref_clk);
>> +	clk_unprepare(td->soc_clk);
>> +	clk_unprepare(td->i2c_clk);
> Please don't do this, DFLL is already disabled if not running.

during resume dfll re-init sequence is same as dfll init so I am using 
existing dfll_init

which includes runtime_enable and clk_prepare.


Will create separate dfll_reinit then...

>> +	reset_control_assert(td->dvco_rst);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(tegra_dfll_suspend);
>> +
>> +/**
>> + * tegra_dfll_resume - reinitialize DFLL on resume
>> + * @pdev: DFLL instance
>> + *
>> + * Re-initialize DFLL on resume as it gets disabled and reset during
>> + * suspend entry. DFLL clock is enabled in closed loop mode later
>> + * and CPU frequency will be switched to DFLL output.
>> + */
>> +int tegra_dfll_resume(struct device *dev)
>> +{
>> +	struct tegra_dfll *td = dev_get_drvdata(dev);
>> +
>> +	return dfll_init(td);
> Just create dfll_reinit() variant.
>
>> +}
>> +EXPORT_SYMBOL(tegra_dfll_resume);
>> +
>>   /*
>>    * DT data fetch
>>    */
>> diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h
>> index 1b14ebe7268b..fb209eb5f365 100644
>> --- a/drivers/clk/tegra/clk-dfll.h
>> +++ b/drivers/clk/tegra/clk-dfll.h
>> @@ -42,5 +42,7 @@ int tegra_dfll_register(struct platform_device *pdev,
>>   struct tegra_dfll_soc_data *tegra_dfll_unregister(struct platform_device *pdev);
>>   int tegra_dfll_runtime_suspend(struct device *dev);
>>   int tegra_dfll_runtime_resume(struct device *dev);
>> +int tegra_dfll_suspend(struct device *dev);
>> +int tegra_dfll_resume(struct device *dev);
>>   
>>   #endif /* __DRIVERS_CLK_TEGRA_CLK_DFLL_H */
>> diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
>> index e84b6d52cbbd..2ac2679d696d 100644
>> --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
>> +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
>> @@ -631,6 +631,7 @@ static int tegra124_dfll_fcpu_remove(struct platform_device *pdev)
>>   static const struct dev_pm_ops tegra124_dfll_pm_ops = {
>>   	SET_RUNTIME_PM_OPS(tegra_dfll_runtime_suspend,
>>   			   tegra_dfll_runtime_resume, NULL)
>> +	SET_SYSTEM_SLEEP_PM_OPS(tegra_dfll_suspend, tegra_dfll_resume)
>>   };
>>   
>>   static struct platform_driver tegra124_dfll_fcpu_driver = {
>>

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

* Re: [PATCH V6 14/21] clk: tegra210: Add suspend and resume support
  2019-07-21 21:38   ` Dmitry Osipenko
@ 2019-07-21 22:45     ` Sowjanya Komatineni
  2019-07-22  6:10       ` Dmitry Osipenko
  0 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 22:45 UTC (permalink / raw)
  To: Dmitry Osipenko, 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


On 7/21/19 2:38 PM, Dmitry Osipenko wrote:
> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>> This patch adds support for clk: tegra210: suspend-resume.
>>
>> All the CAR controller settings are lost on suspend when core
>> power goes off.
>>
>> This patch has implementation for saving and restoring all PLLs
>> and clocks context during system suspend and resume to have the
>> clocks back to same state for normal operation.
>>
>> Acked-by: Thierry Reding <treding@nvidia.com>
>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>> ---
>>   drivers/clk/tegra/clk-tegra210.c | 68 ++++++++++++++++++++++++++++++++++++++--
>>   drivers/clk/tegra/clk.c          | 14 +++++++++
>>   drivers/clk/tegra/clk.h          |  1 +
>>   3 files changed, 80 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
>> index 55a88c0824a5..68271873acc1 100644
>> --- a/drivers/clk/tegra/clk-tegra210.c
>> +++ b/drivers/clk/tegra/clk-tegra210.c
>> @@ -9,6 +9,7 @@
>>   #include <linux/clkdev.h>
>>   #include <linux/of.h>
>>   #include <linux/of_address.h>
>> +#include <linux/syscore_ops.h>
>>   #include <linux/delay.h>
>>   #include <linux/export.h>
>>   #include <linux/mutex.h>
>> @@ -220,11 +221,15 @@
>>   #define CLK_M_DIVISOR_SHIFT 2
>>   #define CLK_M_DIVISOR_MASK 0x3
>>   
>> +#define CLK_MASK_ARM	0x44
>> +#define MISC_CLK_ENB	0x48
>> +
>>   #define RST_DFLL_DVCO 0x2f4
>>   #define DVFS_DFLL_RESET_SHIFT 0
>>   
>>   #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
>> @@ -2825,6 +2830,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)
>> @@ -2853,9 +2859,8 @@ static int tegra210_enable_pllu(void)
>>   	reg |= PLL_ENABLE;
>>   	writel(reg, clk_base + PLLU_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) {
> Why this is needed? Was there a bug?
>
during resume pllu init is needed and to use same terga210_init_pllu, 
poll_timeout_atomic can't be used as its ony for atomic context.

So changed to use wait_for_mask which should work in both cases.

>>   		pr_err("Timed out waiting for PLL_U to lock\n");
>>   		return -ETIMEDOUT;
>>   	}
>> @@ -3288,6 +3293,56 @@ static void tegra210_disable_cpu_clock(u32 cpu)
>>   }
>>   
>>   #ifdef CONFIG_PM_SLEEP
>> +#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 spare_reg_ctx, misc_clk_enb_ctx, clk_msk_arm_ctx;
>> +static u32 cpu_softrst_ctx[3];
>> +
>> +static int tegra210_clk_suspend(void)
>> +{
>> +	unsigned int i;
>> +
>> +	clk_save_context();
>> +
>> +	/*
>> +	 * save the bootloader configured clock registers SPARE_REG0,
>> +	 * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL
> Nit: Start all multi-line comments with a capital letter and put dot in
> the end of sentence.
>
>> +	 */
>> +	spare_reg_ctx = readl_relaxed(clk_base + SPARE_REG0);
>> +	misc_clk_enb_ctx = readl_relaxed(clk_base + MISC_CLK_ENB);
>> +	clk_msk_arm_ctx = readl_relaxed(clk_base + CLK_MASK_ARM);
>> +
>> +	for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
>> +		cpu_softrst_ctx[i] = car_readl(CPU_SOFTRST_CTRL, i);
>> +
>> +	return 0;
>> +}
>> +
>> +static void tegra210_clk_resume(void)
>> +{
>> +	unsigned int i;
>> +
>> +	tegra_clk_osc_resume(clk_base);
>> +
>> +	/*
>> +	 * restore the bootloader configured clock registers SPARE_REG0,
>> +	 * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL from saved context.
> Same here.
>
>> +	 */
>> +	writel_relaxed(spare_reg_ctx, clk_base + SPARE_REG0);
>> +	writel_relaxed(misc_clk_enb_ctx, clk_base + MISC_CLK_ENB);
>> +	writel_relaxed(clk_msk_arm_ctx, clk_base + CLK_MASK_ARM);
>> +
>> +	for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
>> +		car_writel(cpu_softrst_ctx[i], CPU_SOFTRST_CTRL, i);
>> +
>> +	fence_udelay(5, clk_base);
>> +
>> +	tegra210_init_pllu();
>> +	clk_restore_context();
>> +}
>> +
>>   static void tegra210_cpu_clock_suspend(void)
>>   {
>>   	/* switch coresite to clk_m, save off original source */
>> @@ -3303,6 +3358,11 @@ static void tegra210_cpu_clock_resume(void)
>>   }
>>   #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,
>> @@ -3587,5 +3647,7 @@ static void __init tegra210_clock_init(struct device_node *np)
>>   	tegra210_mbist_clk_init();
>>   
>>   	tegra_cpu_car_ops = &tegra210_cpu_car_ops;
>> +
>> +	register_syscore_ops(&tegra_clk_syscore_ops);
>>   }
>>   CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);
>> diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
>> index 573e3c967ae1..eb08047fd02f 100644
>> --- a/drivers/clk/tegra/clk.c
>> +++ b/drivers/clk/tegra/clk.c
>> @@ -23,6 +23,7 @@
>>   #define CLK_OUT_ENB_W			0x364
>>   #define CLK_OUT_ENB_X			0x280
>>   #define CLK_OUT_ENB_Y			0x298
>> +#define CLK_ENB_PLLP_OUT_CPU		BIT(31)
>>   #define CLK_OUT_ENB_SET_L		0x320
>>   #define CLK_OUT_ENB_CLR_L		0x324
>>   #define CLK_OUT_ENB_SET_H		0x328
>> @@ -199,6 +200,19 @@ const struct tegra_clk_periph_regs *get_reg_bank(int clkid)
>>   	}
>>   }
>>   
>> +void tegra_clk_set_pllp_out_cpu(bool enable)
>> +{
>> +	u32 val;
>> +
>> +	val = readl_relaxed(clk_base + CLK_OUT_ENB_Y);
>> +	if (enable)
>> +		val |= CLK_ENB_PLLP_OUT_CPU;
>> +	else
>> +		val &= ~CLK_ENB_PLLP_OUT_CPU;
>> +
>> +	writel_relaxed(val, clk_base + CLK_OUT_ENB_Y);
>> +}
>> +
>>   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 562a3ee2d537..0ffa763c755b 100644
>> --- a/drivers/clk/tegra/clk.h
>> +++ b/drivers/clk/tegra/clk.h
>> @@ -863,6 +863,7 @@ 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_clk_osc_resume(void __iomem *clk_base);
>> +void tegra_clk_set_pllp_out_cpu(bool enable);
>>   
>>   /* Combined read fence with delay */
>>   #define fence_udelay(delay, reg)	\
>>

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

* Re: [PATCH V6 06/21] clk: tegra: pll: Save and restore pll context
  2019-07-21 21:44   ` Dmitry Osipenko
@ 2019-07-21 22:47     ` Sowjanya Komatineni
  0 siblings, 0 replies; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 22:47 UTC (permalink / raw)
  To: Dmitry Osipenko, 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


On 7/21/19 2:44 PM, Dmitry Osipenko wrote:
> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>> 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.
>>
>> Acked-by: Thierry Reding <treding@nvidia.com>
>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>> ---
>>   drivers/clk/tegra/clk-pll.c      | 121 ++++++++++++++++++++++++++++-----------
>>   drivers/clk/tegra/clk-tegra210.c |   2 +-
>>   drivers/clk/tegra/clk.h          |  10 +++-
>>   3 files changed, 99 insertions(+), 34 deletions(-)
>>
>> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
>> index 1583f5fc992f..f136964e6c44 100644
>> --- a/drivers/clk/tegra/clk-pll.c
>> +++ b/drivers/clk/tegra/clk-pll.c
>> @@ -1008,6 +1008,59 @@ 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);
>> +	u32 val = 0;
>> +
>> +	pll->rate = clk_hw_get_rate(hw);
>> +
>> +	if (pll->params->flags & TEGRA_PLLMB)
>> +		val = pll_readl_base(pll);
>> +	else if (pll->params->flags & TEGRA_PLLRE)
>> +		val = pll_readl_base(pll) & divp_mask_shifted(pll);
>> +
>> +	pll->pllbase_ctx = val;
>> +
>> +	return 0;
>> +}
>> +
>> +static void tegra_clk_pll_restore_context(struct clk_hw *hw)
>> +{
>> +	struct tegra_clk_pll *pll = to_clk_pll(hw);
>> +	struct clk_hw *parent = clk_hw_get_parent(hw);
>> +	unsigned long parent_rate = clk_hw_get_rate(parent);
>> +	u32 val;
>> +
>> +	if (clk_pll_is_enabled(hw))
>> +		return;
>> +
>> +	if (pll->params->flags & TEGRA_PLLMB) {
>> +		pll_writel_base(pll->pllbase_ctx, pll);
>> +	} else if (pll->params->flags & TEGRA_PLLRE) {
>> +		val = pll_readl_base(pll);
>> +		val &= ~(divp_mask_shifted(pll));
>> +		pll_writel_base(pll->pllbase_ctx | val, pll);
>> +	}
>> +
>> +	if (pll->params->set_defaults)
>> +		pll->params->set_defaults(pll);
>> +
>> +	clk_pll_set_rate(hw, pll->rate, parent_rate);
>> +
>> +	/* do not sync pllx state here. pllx is sync'd after dfll resume */
>> +	if (!(pll->params->flags & TEGRA_PLLX))
>> +		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 +1068,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 +1857,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 +2290,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 +2337,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,
>> @@ -2375,6 +2438,7 @@ struct clk *tegra_clk_register_pllre_tegra210(const char *name,
>>   		pll_params->vco_min = pll_params->adjust_vco(pll_params,
>>   							     parent_rate);
>>   
>> +	pll_params->flags |= TEGRA_PLLRE;
>>   	pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
>>   	if (IS_ERR(pll))
>>   		return ERR_CAST(pll);
>> @@ -2520,11 +2584,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 +2607,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-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
>> index 4721ee030d1c..58397f93166c 100644
>> --- a/drivers/clk/tegra/clk-tegra210.c
>> +++ b/drivers/clk/tegra/clk-tegra210.c
>> @@ -1602,7 +1602,7 @@ static struct tegra_clk_pll_params pll_x_params = {
>>   	.pdiv_tohw = pll_qlin_pdiv_to_hw,
>>   	.div_nmp = &pllx_nmp,
>>   	.freq_table = pll_x_freq_table,
>> -	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
>> +	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLLX,
>>   	.dyn_ramp = tegra210_pllx_dyn_ramp,
>>   	.set_defaults = tegra210_pllx_set_defaults,
>>   	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
>> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
>> index fb29a8c27873..8532f5150091 100644
>> --- a/drivers/clk/tegra/clk.h
>> +++ b/drivers/clk/tegra/clk.h
>> @@ -235,6 +235,8 @@ struct tegra_clk_pll;
>>    * TEGRA_PLLMB - PLLMB has should be treated similar to PLLM. This
>>    *     flag indicated that it is PLLMB.
>>    * TEGRA_PLL_VCO_OUT - Used to indicate that the PLL has a VCO output
>> + * TEGRA_PLLRE - Used to indicate that it is PLLRE.
>> + * TEGRA_PLLX - Used to indicate that it is PLLX.
>>    */
>>   struct tegra_clk_pll_params {
>>   	unsigned long	input_min;
>> @@ -301,6 +303,8 @@ struct tegra_clk_pll_params {
>>   #define TEGRA_MDIV_NEW BIT(11)
>>   #define TEGRA_PLLMB BIT(12)
>>   #define TEGRA_PLL_VCO_OUT BIT(13)
>> +#define TEGRA_PLLRE BIT(14)
>> +#define TEGRA_PLLX BIT(15)
>>   
>>   /**
>>    * struct tegra_clk_pll - Tegra PLL clock
>> @@ -310,6 +314,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 +323,8 @@ struct tegra_clk_pll {
>>   	void __iomem	*pmc;
>>   	spinlock_t	*lock;
>>   	struct tegra_clk_pll_params	*params;
>> +	unsigned long	rate;
>> +	u32	pllbase_ctx;
>>   };
>>   
>>   #define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw)
>> @@ -840,7 +848,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);
> Looks like this function isn't used anywhere other than this patch. Bug?

With all dfll sequence moved to right places in this patch, yes this can 
be collapsed within restore context itself.

Will change in next version

>>   /* Combined read fence with delay */
>>   #define fence_udelay(delay, reg)	\
>>

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

* Re: [PATCH V6 02/21] pinctrl: tegra: Add suspend and resume support
  2019-07-21 22:09     ` Dmitry Osipenko
@ 2019-07-21 22:48       ` Sowjanya Komatineni
  0 siblings, 0 replies; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-21 22:48 UTC (permalink / raw)
  To: Dmitry Osipenko, 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


On 7/21/19 3:09 PM, Dmitry Osipenko wrote:
> 22.07.2019 1:03, Dmitry Osipenko пишет:
>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>> This patch adds support for Tegra pinctrl driver suspend and resume.
>>>
>>> During suspend, context of all pinctrl registers are stored and
>>> on resume they are all restored to have all the pinmux and pad
>>> configuration for normal operation.
>>>
>>> Acked-by: Thierry Reding <treding@nvidia.com>
>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>> ---
>>>   drivers/pinctrl/tegra/pinctrl-tegra.c | 59 +++++++++++++++++++++++++++++++++++
>>>   drivers/pinctrl/tegra/pinctrl-tegra.h |  3 ++
>>>   2 files changed, 62 insertions(+)
>>>
>>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
>>> index 186ef98e7b2b..e3a237534281 100644
>>> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
>>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
>>> @@ -631,6 +631,58 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
>>>   	}
>>>   }
>>>   
>>> +static size_t tegra_pinctrl_get_bank_size(struct device *dev,
>>> +					  unsigned int bank_id)
>>> +{
>>> +	struct platform_device *pdev = to_platform_device(dev);
>>> +	struct resource *res;
>>> +
>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, bank_id);
>>> +
>>> +	return resource_size(res) / 4;
>>> +}
>>> +
>>> +static int tegra_pinctrl_suspend(struct device *dev)
>>> +{
>>> +	struct tegra_pmx *pmx = dev_get_drvdata(dev);
>>> +	u32 *backup_regs = pmx->backup_regs;
>>> +	u32 *regs;
>>> +	size_t bank_size;
>>> +	unsigned int i, k;
>>> +
>>> +	for (i = 0; i < pmx->nbanks; i++) {
>>> +		bank_size = tegra_pinctrl_get_bank_size(dev, i);
>>> +		regs = pmx->regs[i];
>>> +		for (k = 0; k < bank_size; k++)
>>> +			*backup_regs++ = readl_relaxed(regs++);
>>> +	}
>>> +
>>> +	return pinctrl_force_sleep(pmx->pctl);
>>> +}
>>> +
>>> +static int tegra_pinctrl_resume(struct device *dev)
>>> +{
>>> +	struct tegra_pmx *pmx = dev_get_drvdata(dev);
>>> +	u32 *backup_regs = pmx->backup_regs;
>>> +	u32 *regs;
>>> +	size_t bank_size;
>>> +	unsigned int i, k;
>>> +
>>> +	for (i = 0; i < pmx->nbanks; i++) {
>>> +		bank_size = tegra_pinctrl_get_bank_size(dev, i);
>>> +		regs = pmx->regs[i];
>>> +		for (k = 0; k < bank_size; k++)
>>> +			writel_relaxed(*backup_regs++, regs++);
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +const struct dev_pm_ops tegra_pinctrl_pm = {
>>> +	.suspend = &tegra_pinctrl_suspend,
>>> +	.resume = &tegra_pinctrl_resume
>>> +};
>>> +
>>>   static bool gpio_node_has_range(const char *compatible)
>>>   {
>>>   	struct device_node *np;
>>> @@ -655,6 +707,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)
>>> @@ -707,6 +760,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;
>>>   
>>> @@ -715,6 +769,11 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
>>>   	if (!pmx->regs)
>>>   		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);
>>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
>>> index 105309774079..0fc82eea9cf1 100644
>>> --- a/drivers/pinctrl/tegra/pinctrl-tegra.h
>>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
>>> @@ -17,6 +17,7 @@ struct tegra_pmx {
>>>   
>>>   	int nbanks;
>>>   	void __iomem **regs;
>>> +	u32 *backup_regs;
>>>   };
>>>   
>>>   enum tegra_pinconf_param {
>>> @@ -193,6 +194,8 @@ struct tegra_pinctrl_soc_data {
>>>   	bool drvtype_in_mux;
>>>   };
>>>   
>>> +extern const struct dev_pm_ops tegra_pinctrl_pm;
>>> +
>>>   int tegra_pinctrl_probe(struct platform_device *pdev,
>>>   			const struct tegra_pinctrl_soc_data *soc_data);
>>>   #endif
>>>
>> Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
>>
> BTW, you should remove Thierry's ACK from all patches that were modified
> if he didn't re-ACK the new version.
>
> Also, it looks to me that you're manually adding versioning to the
> patches because git usually uses lowercase for 'v'. You could use "git
> format-patch -v6 ..".


ok, Reg. version I am using git format-patch --subject-prefix='PATCH V6'

will change to lower case v


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

* Re: [PATCH V6 09/21] clk: tegra: clk-super: Fix to enable PLLP branches to CPU
  2019-07-21 22:39     ` Sowjanya Komatineni
@ 2019-07-22  3:17       ` Sowjanya Komatineni
  2019-07-22  6:32         ` Dmitry Osipenko
  0 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-22  3:17 UTC (permalink / raw)
  To: Dmitry Osipenko, 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


On 7/21/19 3:39 PM, Sowjanya Komatineni wrote:
>
> On 7/21/19 2:16 PM, Dmitry Osipenko wrote:
>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>> This patch has a fix to enable PLLP branches to CPU before changing
>>> the CPU clusters clock source to PLLP for Gen5 Super clock.
>>>
>>> During system suspend entry and exit, CPU source will be switched
>>> to PLLP and this needs PLLP branches to be enabled to CPU prior to
>>> the switch.
>>>
>>> On system resume, warmboot code enables PLLP branches to CPU and
>>> powers up the CPU with PLLP clock source.
>>>
>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>> ---
>>>   drivers/clk/tegra/clk-super.c            | 11 +++++++++++
>>>   drivers/clk/tegra/clk-tegra-super-gen4.c |  4 ++--
>>>   drivers/clk/tegra/clk.h                  |  4 ++++
>>>   3 files changed, 17 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/clk/tegra/clk-super.c 
>>> b/drivers/clk/tegra/clk-super.c
>>> index 39ef31b46df5..d73c587e4853 100644
>>> --- a/drivers/clk/tegra/clk-super.c
>>> +++ b/drivers/clk/tegra/clk-super.c
>>> @@ -28,6 +28,9 @@
>>>   #define super_state_to_src_shift(m, s) ((m->width * s))
>>>   #define super_state_to_src_mask(m) (((1 << m->width) - 1))
>>>   +#define CCLK_SRC_PLLP_OUT0 4
>>> +#define CCLK_SRC_PLLP_OUT4 5
>>> +
>>>   static u8 clk_super_get_parent(struct clk_hw *hw)
>>>   {
>>>       struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
>>> @@ -97,6 +100,14 @@ static int clk_super_set_parent(struct clk_hw 
>>> *hw, u8 index)
>>>           if (index == mux->div2_index)
>>>               index = mux->pllx_index;
>>>       }
>>> +
>>> +    /*
>>> +     * Enable PLLP branches to CPU before selecting PLLP source
>>> +     */
>>> +    if ((mux->flags & TEGRA_CPU_CLK) &&
>>> +        ((index == CCLK_SRC_PLLP_OUT0) || (index == 
>>> CCLK_SRC_PLLP_OUT4)))
>>> +        tegra_clk_set_pllp_out_cpu(true);
>> Should somewhere here be tegra_clk_set_pllp_out_cpu(false) when
>> switching from PLLP?
> PLLP may be used for other CPU clusters.

Though to avoid flag and check needed to make sure other CPU is not 
using before disabling PLLP branch to CPU.

But leaving it enabled shouldn't impact much as clock source mux is 
after this in design anyway.

But can add as well if its clear that way.

>>>       val &= ~((super_state_to_src_mask(mux)) << shift);
>>>       val |= (index & (super_state_to_src_mask(mux))) << shift;
>>>   diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c 
>>> b/drivers/clk/tegra/clk-tegra-super-gen4.c
>>> index cdfe7c9697e1..cd208d0eca2a 100644
>>> --- a/drivers/clk/tegra/clk-tegra-super-gen4.c
>>> +++ b/drivers/clk/tegra/clk-tegra-super-gen4.c
>>> @@ -180,7 +180,7 @@ static void __init tegra_super_clk_init(void 
>>> __iomem *clk_base,
>>>                       gen_info->num_cclk_g_parents,
>>>                       CLK_SET_RATE_PARENT,
>>>                       clk_base + CCLKG_BURST_POLICY,
>>> -                    0, 4, 8, 0, NULL);
>>> +                    TEGRA_CPU_CLK, 4, 8, 0, NULL);
>>>           } else {
>>>               clk = tegra_clk_register_super_mux("cclk_g",
>>>                       gen_info->cclk_g_parents,
>>> @@ -201,7 +201,7 @@ static void __init tegra_super_clk_init(void 
>>> __iomem *clk_base,
>>>                       gen_info->num_cclk_lp_parents,
>>>                       CLK_SET_RATE_PARENT,
>>>                       clk_base + CCLKLP_BURST_POLICY,
>>> -                    0, 4, 8, 0, NULL);
>>> +                    TEGRA_CPU_CLK, 4, 8, 0, NULL);
>>>           } else {
>>>               clk = tegra_clk_register_super_mux("cclk_lp",
>>>                       gen_info->cclk_lp_parents,
>>> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
>>> index ac6de3a0b91f..c357b49e49b0 100644
>>> --- a/drivers/clk/tegra/clk.h
>>> +++ b/drivers/clk/tegra/clk.h
>>> @@ -694,6 +694,9 @@ struct clk *tegra_clk_register_periph_data(void 
>>> __iomem *clk_base,
>>>    * Flags:
>>>    * TEGRA_DIVIDER_2 - LP cluster has additional divider. This flag 
>>> indicates
>>>    *     that this is LP cluster clock.
>>> + * TEGRA_CPU_CLK - This flag indicates this is CPU cluster clock. 
>>> To use PLLP
>>> + * for CPU clock source, need to enable PLLP branches to CPU by 
>>> setting the
>>> + * additional bit PLLP_OUT_CPU for gen5 super clock.
>>>    */
>>>   struct tegra_clk_super_mux {
>>>       struct clk_hw    hw;
>>> @@ -710,6 +713,7 @@ struct tegra_clk_super_mux {
>>>   #define to_clk_super_mux(_hw) container_of(_hw, struct 
>>> tegra_clk_super_mux, hw)
>>>     #define TEGRA_DIVIDER_2 BIT(0)
>>> +#define TEGRA_CPU_CLK    BIT(1)
>> I'd name this TEGRA210_CPU_CLK for clarity.
>>
>>>   extern const struct clk_ops tegra_clk_super_ops;
>>>   struct clk *tegra_clk_register_super_mux(const char *name,
>>>
>> Will be better to move the tegra_clk_set_pllp_out_cpu() definition into
>> this patch, otherwise this looks inconsistent for reviewer.
> ok, Will move to this patch

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

* Re: [PATCH V6 06/21] clk: tegra: pll: Save and restore pll context
  2019-07-21 22:21   ` Dmitry Osipenko
@ 2019-07-22  3:22     ` Sowjanya Komatineni
  0 siblings, 0 replies; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-22  3:22 UTC (permalink / raw)
  To: Dmitry Osipenko, 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


On 7/21/19 3:21 PM, Dmitry Osipenko wrote:
> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>> 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.
>>
>> Acked-by: Thierry Reding <treding@nvidia.com>
>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>> ---
>>   drivers/clk/tegra/clk-pll.c      | 121 ++++++++++++++++++++++++++++-----------
>>   drivers/clk/tegra/clk-tegra210.c |   2 +-
>>   drivers/clk/tegra/clk.h          |  10 +++-
>>   3 files changed, 99 insertions(+), 34 deletions(-)
>>
>> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
>> index 1583f5fc992f..f136964e6c44 100644
>> --- a/drivers/clk/tegra/clk-pll.c
>> +++ b/drivers/clk/tegra/clk-pll.c
>> @@ -1008,6 +1008,59 @@ 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);
>> +	u32 val = 0;
>> +
>> +	pll->rate = clk_hw_get_rate(hw);
> Again, clk_hw_get_rate() returns cached value. Why do you need to
> duplicate it?
true, will remove storing in next version. thanks.
>> +	if (pll->params->flags & TEGRA_PLLMB)
>> +		val = pll_readl_base(pll);
>> +	else if (pll->params->flags & TEGRA_PLLRE)
>> +		val = pll_readl_base(pll) & divp_mask_shifted(pll);
>> +
>> +	pll->pllbase_ctx = val;
>> +
>> +	return 0;
>> +}
>> +
>> +static void tegra_clk_pll_restore_context(struct clk_hw *hw)
>> +{
>> +	struct tegra_clk_pll *pll = to_clk_pll(hw);
>> +	struct clk_hw *parent = clk_hw_get_parent(hw);
>> +	unsigned long parent_rate = clk_hw_get_rate(parent);
>> +	u32 val;
>> +
>> +	if (clk_pll_is_enabled(hw))
>> +		return;
>> +
>> +	if (pll->params->flags & TEGRA_PLLMB) {
>> +		pll_writel_base(pll->pllbase_ctx, pll);
>> +	} else if (pll->params->flags & TEGRA_PLLRE) {
>> +		val = pll_readl_base(pll);
>> +		val &= ~(divp_mask_shifted(pll));
>> +		pll_writel_base(pll->pllbase_ctx | val, pll);
>> +	}
>> +
>> +	if (pll->params->set_defaults)
>> +		pll->params->set_defaults(pll);
>> +
>> +	clk_pll_set_rate(hw, pll->rate, parent_rate);
>> +
>> +	/* do not sync pllx state here. pllx is sync'd after dfll resume */
>> +	if (!(pll->params->flags & TEGRA_PLLX))
>> +		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 +1068,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 +1857,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 +2290,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 +2337,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,
>> @@ -2375,6 +2438,7 @@ struct clk *tegra_clk_register_pllre_tegra210(const char *name,
>>   		pll_params->vco_min = pll_params->adjust_vco(pll_params,
>>   							     parent_rate);
>>   
>> +	pll_params->flags |= TEGRA_PLLRE;
>>   	pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
>>   	if (IS_ERR(pll))
>>   		return ERR_CAST(pll);
>> @@ -2520,11 +2584,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 +2607,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-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
>> index 4721ee030d1c..58397f93166c 100644
>> --- a/drivers/clk/tegra/clk-tegra210.c
>> +++ b/drivers/clk/tegra/clk-tegra210.c
>> @@ -1602,7 +1602,7 @@ static struct tegra_clk_pll_params pll_x_params = {
>>   	.pdiv_tohw = pll_qlin_pdiv_to_hw,
>>   	.div_nmp = &pllx_nmp,
>>   	.freq_table = pll_x_freq_table,
>> -	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
>> +	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLLX,
>>   	.dyn_ramp = tegra210_pllx_dyn_ramp,
>>   	.set_defaults = tegra210_pllx_set_defaults,
>>   	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
>> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
>> index fb29a8c27873..8532f5150091 100644
>> --- a/drivers/clk/tegra/clk.h
>> +++ b/drivers/clk/tegra/clk.h
>> @@ -235,6 +235,8 @@ struct tegra_clk_pll;
>>    * TEGRA_PLLMB - PLLMB has should be treated similar to PLLM. This
>>    *     flag indicated that it is PLLMB.
>>    * TEGRA_PLL_VCO_OUT - Used to indicate that the PLL has a VCO output
>> + * TEGRA_PLLRE - Used to indicate that it is PLLRE.
>> + * TEGRA_PLLX - Used to indicate that it is PLLX.
>>    */
>>   struct tegra_clk_pll_params {
>>   	unsigned long	input_min;
>> @@ -301,6 +303,8 @@ struct tegra_clk_pll_params {
>>   #define TEGRA_MDIV_NEW BIT(11)
>>   #define TEGRA_PLLMB BIT(12)
>>   #define TEGRA_PLL_VCO_OUT BIT(13)
>> +#define TEGRA_PLLRE BIT(14)
>> +#define TEGRA_PLLX BIT(15)
>>   
>>   /**
>>    * struct tegra_clk_pll - Tegra PLL clock
>> @@ -310,6 +314,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 +323,8 @@ struct tegra_clk_pll {
>>   	void __iomem	*pmc;
>>   	spinlock_t	*lock;
>>   	struct tegra_clk_pll_params	*params;
>> +	unsigned long	rate;
>> +	u32	pllbase_ctx;
>>   };
>>   
>>   #define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw)
>> @@ -840,7 +848,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)	\
>>

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

* Re: [PATCH V6 14/21] clk: tegra210: Add suspend and resume support
  2019-07-21 22:45     ` Sowjanya Komatineni
@ 2019-07-22  6:10       ` Dmitry Osipenko
  2019-07-22  6:52         ` Sowjanya Komatineni
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-22  6:10 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

22.07.2019 1:45, Sowjanya Komatineni пишет:
> 
> On 7/21/19 2:38 PM, Dmitry Osipenko wrote:
>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>> This patch adds support for clk: tegra210: suspend-resume.
>>>
>>> All the CAR controller settings are lost on suspend when core
>>> power goes off.
>>>
>>> This patch has implementation for saving and restoring all PLLs
>>> and clocks context during system suspend and resume to have the
>>> clocks back to same state for normal operation.
>>>
>>> Acked-by: Thierry Reding <treding@nvidia.com>
>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>> ---
>>>   drivers/clk/tegra/clk-tegra210.c | 68
>>> ++++++++++++++++++++++++++++++++++++++--
>>>   drivers/clk/tegra/clk.c          | 14 +++++++++
>>>   drivers/clk/tegra/clk.h          |  1 +
>>>   3 files changed, 80 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/clk/tegra/clk-tegra210.c
>>> b/drivers/clk/tegra/clk-tegra210.c
>>> index 55a88c0824a5..68271873acc1 100644
>>> --- a/drivers/clk/tegra/clk-tegra210.c
>>> +++ b/drivers/clk/tegra/clk-tegra210.c
>>> @@ -9,6 +9,7 @@
>>>   #include <linux/clkdev.h>
>>>   #include <linux/of.h>
>>>   #include <linux/of_address.h>
>>> +#include <linux/syscore_ops.h>
>>>   #include <linux/delay.h>
>>>   #include <linux/export.h>
>>>   #include <linux/mutex.h>
>>> @@ -220,11 +221,15 @@
>>>   #define CLK_M_DIVISOR_SHIFT 2
>>>   #define CLK_M_DIVISOR_MASK 0x3
>>>   +#define CLK_MASK_ARM    0x44
>>> +#define MISC_CLK_ENB    0x48
>>> +
>>>   #define RST_DFLL_DVCO 0x2f4
>>>   #define DVFS_DFLL_RESET_SHIFT 0
>>>     #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
>>> @@ -2825,6 +2830,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)
>>> @@ -2853,9 +2859,8 @@ static int tegra210_enable_pllu(void)
>>>       reg |= PLL_ENABLE;
>>>       writel(reg, clk_base + PLLU_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) {
>> Why this is needed? Was there a bug?
>>
> during resume pllu init is needed and to use same terga210_init_pllu,
> poll_timeout_atomic can't be used as its ony for atomic context.
> 
> So changed to use wait_for_mask which should work in both cases.

Atomic variant could be used from any context, not sure what do you
mean. The 'atomic' part only means that function won't cause scheduling
and that's it.

>>>           pr_err("Timed out waiting for PLL_U to lock\n");
>>>           return -ETIMEDOUT;
>>>       }
>>> @@ -3288,6 +3293,56 @@ static void tegra210_disable_cpu_clock(u32 cpu)
>>>   }
>>>     #ifdef CONFIG_PM_SLEEP
>>> +#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 spare_reg_ctx, misc_clk_enb_ctx, clk_msk_arm_ctx;
>>> +static u32 cpu_softrst_ctx[3];
>>> +
>>> +static int tegra210_clk_suspend(void)
>>> +{
>>> +    unsigned int i;
>>> +
>>> +    clk_save_context();
>>> +
>>> +    /*
>>> +     * save the bootloader configured clock registers SPARE_REG0,
>>> +     * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL
>> Nit: Start all multi-line comments with a capital letter and put dot in
>> the end of sentence.
>>
>>> +     */
>>> +    spare_reg_ctx = readl_relaxed(clk_base + SPARE_REG0);
>>> +    misc_clk_enb_ctx = readl_relaxed(clk_base + MISC_CLK_ENB);
>>> +    clk_msk_arm_ctx = readl_relaxed(clk_base + CLK_MASK_ARM);
>>> +
>>> +    for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
>>> +        cpu_softrst_ctx[i] = car_readl(CPU_SOFTRST_CTRL, i);
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static void tegra210_clk_resume(void)
>>> +{
>>> +    unsigned int i;
>>> +
>>> +    tegra_clk_osc_resume(clk_base);
>>> +
>>> +    /*
>>> +     * restore the bootloader configured clock registers SPARE_REG0,
>>> +     * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL from saved context.
>> Same here.
>>
>>> +     */
>>> +    writel_relaxed(spare_reg_ctx, clk_base + SPARE_REG0);
>>> +    writel_relaxed(misc_clk_enb_ctx, clk_base + MISC_CLK_ENB);
>>> +    writel_relaxed(clk_msk_arm_ctx, clk_base + CLK_MASK_ARM);
>>> +
>>> +    for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
>>> +        car_writel(cpu_softrst_ctx[i], CPU_SOFTRST_CTRL, i);
>>> +
>>> +    fence_udelay(5, clk_base);
>>> +
>>> +    tegra210_init_pllu();
>>> +    clk_restore_context();
>>> +}
>>> +
>>>   static void tegra210_cpu_clock_suspend(void)
>>>   {
>>>       /* switch coresite to clk_m, save off original source */
>>> @@ -3303,6 +3358,11 @@ static void tegra210_cpu_clock_resume(void)
>>>   }
>>>   #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,
>>> @@ -3587,5 +3647,7 @@ static void __init tegra210_clock_init(struct
>>> device_node *np)
>>>       tegra210_mbist_clk_init();
>>>         tegra_cpu_car_ops = &tegra210_cpu_car_ops;
>>> +
>>> +    register_syscore_ops(&tegra_clk_syscore_ops);
>>>   }
>>>   CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);
>>> diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
>>> index 573e3c967ae1..eb08047fd02f 100644
>>> --- a/drivers/clk/tegra/clk.c
>>> +++ b/drivers/clk/tegra/clk.c
>>> @@ -23,6 +23,7 @@
>>>   #define CLK_OUT_ENB_W            0x364
>>>   #define CLK_OUT_ENB_X            0x280
>>>   #define CLK_OUT_ENB_Y            0x298
>>> +#define CLK_ENB_PLLP_OUT_CPU        BIT(31)
>>>   #define CLK_OUT_ENB_SET_L        0x320
>>>   #define CLK_OUT_ENB_CLR_L        0x324
>>>   #define CLK_OUT_ENB_SET_H        0x328
>>> @@ -199,6 +200,19 @@ const struct tegra_clk_periph_regs
>>> *get_reg_bank(int clkid)
>>>       }
>>>   }
>>>   +void tegra_clk_set_pllp_out_cpu(bool enable)
>>> +{
>>> +    u32 val;
>>> +
>>> +    val = readl_relaxed(clk_base + CLK_OUT_ENB_Y);
>>> +    if (enable)
>>> +        val |= CLK_ENB_PLLP_OUT_CPU;
>>> +    else
>>> +        val &= ~CLK_ENB_PLLP_OUT_CPU;
>>> +
>>> +    writel_relaxed(val, clk_base + CLK_OUT_ENB_Y);
>>> +}
>>> +
>>>   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 562a3ee2d537..0ffa763c755b 100644
>>> --- a/drivers/clk/tegra/clk.h
>>> +++ b/drivers/clk/tegra/clk.h
>>> @@ -863,6 +863,7 @@ 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_clk_osc_resume(void __iomem *clk_base);
>>> +void tegra_clk_set_pllp_out_cpu(bool enable);
>>>     /* Combined read fence with delay */
>>>   #define fence_udelay(delay, reg)    \
>>>


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

* Re: [PATCH V6 09/21] clk: tegra: clk-super: Fix to enable PLLP branches to CPU
  2019-07-22  3:17       ` Sowjanya Komatineni
@ 2019-07-22  6:32         ` Dmitry Osipenko
  2019-07-22  7:12           ` Sowjanya Komatineni
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-22  6:32 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

22.07.2019 6:17, Sowjanya Komatineni пишет:
> 
> On 7/21/19 3:39 PM, Sowjanya Komatineni wrote:
>>
>> On 7/21/19 2:16 PM, Dmitry Osipenko wrote:
>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>> This patch has a fix to enable PLLP branches to CPU before changing
>>>> the CPU clusters clock source to PLLP for Gen5 Super clock.
>>>>
>>>> During system suspend entry and exit, CPU source will be switched
>>>> to PLLP and this needs PLLP branches to be enabled to CPU prior to
>>>> the switch.
>>>>
>>>> On system resume, warmboot code enables PLLP branches to CPU and
>>>> powers up the CPU with PLLP clock source.
>>>>
>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>> ---
>>>>   drivers/clk/tegra/clk-super.c            | 11 +++++++++++
>>>>   drivers/clk/tegra/clk-tegra-super-gen4.c |  4 ++--
>>>>   drivers/clk/tegra/clk.h                  |  4 ++++
>>>>   3 files changed, 17 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/drivers/clk/tegra/clk-super.c
>>>> b/drivers/clk/tegra/clk-super.c
>>>> index 39ef31b46df5..d73c587e4853 100644
>>>> --- a/drivers/clk/tegra/clk-super.c
>>>> +++ b/drivers/clk/tegra/clk-super.c
>>>> @@ -28,6 +28,9 @@
>>>>   #define super_state_to_src_shift(m, s) ((m->width * s))
>>>>   #define super_state_to_src_mask(m) (((1 << m->width) - 1))
>>>>   +#define CCLK_SRC_PLLP_OUT0 4
>>>> +#define CCLK_SRC_PLLP_OUT4 5
>>>> +
>>>>   static u8 clk_super_get_parent(struct clk_hw *hw)
>>>>   {
>>>>       struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
>>>> @@ -97,6 +100,14 @@ static int clk_super_set_parent(struct clk_hw
>>>> *hw, u8 index)
>>>>           if (index == mux->div2_index)
>>>>               index = mux->pllx_index;
>>>>       }
>>>> +
>>>> +    /*
>>>> +     * Enable PLLP branches to CPU before selecting PLLP source
>>>> +     */
>>>> +    if ((mux->flags & TEGRA_CPU_CLK) &&
>>>> +        ((index == CCLK_SRC_PLLP_OUT0) || (index ==
>>>> CCLK_SRC_PLLP_OUT4)))
>>>> +        tegra_clk_set_pllp_out_cpu(true);
>>> Should somewhere here be tegra_clk_set_pllp_out_cpu(false) when
>>> switching from PLLP?
>> PLLP may be used for other CPU clusters.
> 
> Though to avoid flag and check needed to make sure other CPU is not
> using before disabling PLLP branch to CPU.
> 
> But leaving it enabled shouldn't impact much as clock source mux is
> after this in design anyway.
> 
> But can add as well if its clear that way.

The TRM doc says "The CPU subsystem supports a switch-cluster mode
meaning that only one of the clusters can be active at any given time".

Given that cluster-switching isn't supported in upstream, I don't think
that you need to care about the other cluster at all, at least for now.

The cluster-switching implementation in upstream is very complicated
because it requires a special "hotplugging" CPU governor, which
apparently no other platform needs.

[snip]

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

* Re: [PATCH V6 14/21] clk: tegra210: Add suspend and resume support
  2019-07-22  6:10       ` Dmitry Osipenko
@ 2019-07-22  6:52         ` Sowjanya Komatineni
  2019-07-22  7:09           ` Dmitry Osipenko
  0 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-22  6:52 UTC (permalink / raw)
  To: Dmitry Osipenko, 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


On 7/21/19 11:10 PM, Dmitry Osipenko wrote:
> 22.07.2019 1:45, Sowjanya Komatineni пишет:
>> On 7/21/19 2:38 PM, Dmitry Osipenko wrote:
>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>> This patch adds support for clk: tegra210: suspend-resume.
>>>>
>>>> All the CAR controller settings are lost on suspend when core
>>>> power goes off.
>>>>
>>>> This patch has implementation for saving and restoring all PLLs
>>>> and clocks context during system suspend and resume to have the
>>>> clocks back to same state for normal operation.
>>>>
>>>> Acked-by: Thierry Reding <treding@nvidia.com>
>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>> ---
>>>>    drivers/clk/tegra/clk-tegra210.c | 68
>>>> ++++++++++++++++++++++++++++++++++++++--
>>>>    drivers/clk/tegra/clk.c          | 14 +++++++++
>>>>    drivers/clk/tegra/clk.h          |  1 +
>>>>    3 files changed, 80 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/drivers/clk/tegra/clk-tegra210.c
>>>> b/drivers/clk/tegra/clk-tegra210.c
>>>> index 55a88c0824a5..68271873acc1 100644
>>>> --- a/drivers/clk/tegra/clk-tegra210.c
>>>> +++ b/drivers/clk/tegra/clk-tegra210.c
>>>> @@ -9,6 +9,7 @@
>>>>    #include <linux/clkdev.h>
>>>>    #include <linux/of.h>
>>>>    #include <linux/of_address.h>
>>>> +#include <linux/syscore_ops.h>
>>>>    #include <linux/delay.h>
>>>>    #include <linux/export.h>
>>>>    #include <linux/mutex.h>
>>>> @@ -220,11 +221,15 @@
>>>>    #define CLK_M_DIVISOR_SHIFT 2
>>>>    #define CLK_M_DIVISOR_MASK 0x3
>>>>    +#define CLK_MASK_ARM    0x44
>>>> +#define MISC_CLK_ENB    0x48
>>>> +
>>>>    #define RST_DFLL_DVCO 0x2f4
>>>>    #define DVFS_DFLL_RESET_SHIFT 0
>>>>      #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
>>>> @@ -2825,6 +2830,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)
>>>> @@ -2853,9 +2859,8 @@ static int tegra210_enable_pllu(void)
>>>>        reg |= PLL_ENABLE;
>>>>        writel(reg, clk_base + PLLU_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) {
>>> Why this is needed? Was there a bug?
>>>
>> during resume pllu init is needed and to use same terga210_init_pllu,
>> poll_timeout_atomic can't be used as its ony for atomic context.
>>
>> So changed to use wait_for_mask which should work in both cases.
> Atomic variant could be used from any context, not sure what do you
> mean. The 'atomic' part only means that function won't cause scheduling
> and that's it.

Sorry, replied incorrect. readx_poll_timeout_atomic uses ktime_get() and 
during resume timekeeping suspend/resume happens later than clock 
suspend/resume. So using tegra210_wait_for_mask.

both timekeeping and clk-tegra210 drivers are registered as syscore but 
not ordered.

>>>>            pr_err("Timed out waiting for PLL_U to lock\n");
>>>>            return -ETIMEDOUT;
>>>>        }
>>>> @@ -3288,6 +3293,56 @@ static void tegra210_disable_cpu_clock(u32 cpu)
>>>>    }
>>>>      #ifdef CONFIG_PM_SLEEP
>>>> +#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 spare_reg_ctx, misc_clk_enb_ctx, clk_msk_arm_ctx;
>>>> +static u32 cpu_softrst_ctx[3];
>>>> +
>>>> +static int tegra210_clk_suspend(void)
>>>> +{
>>>> +    unsigned int i;
>>>> +
>>>> +    clk_save_context();
>>>> +
>>>> +    /*
>>>> +     * save the bootloader configured clock registers SPARE_REG0,
>>>> +     * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL
>>> Nit: Start all multi-line comments with a capital letter and put dot in
>>> the end of sentence.
>>>
>>>> +     */
>>>> +    spare_reg_ctx = readl_relaxed(clk_base + SPARE_REG0);
>>>> +    misc_clk_enb_ctx = readl_relaxed(clk_base + MISC_CLK_ENB);
>>>> +    clk_msk_arm_ctx = readl_relaxed(clk_base + CLK_MASK_ARM);
>>>> +
>>>> +    for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
>>>> +        cpu_softrst_ctx[i] = car_readl(CPU_SOFTRST_CTRL, i);
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static void tegra210_clk_resume(void)
>>>> +{
>>>> +    unsigned int i;
>>>> +
>>>> +    tegra_clk_osc_resume(clk_base);
>>>> +
>>>> +    /*
>>>> +     * restore the bootloader configured clock registers SPARE_REG0,
>>>> +     * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL from saved context.
>>> Same here.
>>>
>>>> +     */
>>>> +    writel_relaxed(spare_reg_ctx, clk_base + SPARE_REG0);
>>>> +    writel_relaxed(misc_clk_enb_ctx, clk_base + MISC_CLK_ENB);
>>>> +    writel_relaxed(clk_msk_arm_ctx, clk_base + CLK_MASK_ARM);
>>>> +
>>>> +    for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
>>>> +        car_writel(cpu_softrst_ctx[i], CPU_SOFTRST_CTRL, i);
>>>> +
>>>> +    fence_udelay(5, clk_base);
>>>> +
>>>> +    tegra210_init_pllu();
>>>> +    clk_restore_context();
>>>> +}
>>>> +
>>>>    static void tegra210_cpu_clock_suspend(void)
>>>>    {
>>>>        /* switch coresite to clk_m, save off original source */
>>>> @@ -3303,6 +3358,11 @@ static void tegra210_cpu_clock_resume(void)
>>>>    }
>>>>    #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,
>>>> @@ -3587,5 +3647,7 @@ static void __init tegra210_clock_init(struct
>>>> device_node *np)
>>>>        tegra210_mbist_clk_init();
>>>>          tegra_cpu_car_ops = &tegra210_cpu_car_ops;
>>>> +
>>>> +    register_syscore_ops(&tegra_clk_syscore_ops);
>>>>    }
>>>>    CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);
>>>> diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
>>>> index 573e3c967ae1..eb08047fd02f 100644
>>>> --- a/drivers/clk/tegra/clk.c
>>>> +++ b/drivers/clk/tegra/clk.c
>>>> @@ -23,6 +23,7 @@
>>>>    #define CLK_OUT_ENB_W            0x364
>>>>    #define CLK_OUT_ENB_X            0x280
>>>>    #define CLK_OUT_ENB_Y            0x298
>>>> +#define CLK_ENB_PLLP_OUT_CPU        BIT(31)
>>>>    #define CLK_OUT_ENB_SET_L        0x320
>>>>    #define CLK_OUT_ENB_CLR_L        0x324
>>>>    #define CLK_OUT_ENB_SET_H        0x328
>>>> @@ -199,6 +200,19 @@ const struct tegra_clk_periph_regs
>>>> *get_reg_bank(int clkid)
>>>>        }
>>>>    }
>>>>    +void tegra_clk_set_pllp_out_cpu(bool enable)
>>>> +{
>>>> +    u32 val;
>>>> +
>>>> +    val = readl_relaxed(clk_base + CLK_OUT_ENB_Y);
>>>> +    if (enable)
>>>> +        val |= CLK_ENB_PLLP_OUT_CPU;
>>>> +    else
>>>> +        val &= ~CLK_ENB_PLLP_OUT_CPU;
>>>> +
>>>> +    writel_relaxed(val, clk_base + CLK_OUT_ENB_Y);
>>>> +}
>>>> +
>>>>    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 562a3ee2d537..0ffa763c755b 100644
>>>> --- a/drivers/clk/tegra/clk.h
>>>> +++ b/drivers/clk/tegra/clk.h
>>>> @@ -863,6 +863,7 @@ 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_clk_osc_resume(void __iomem *clk_base);
>>>> +void tegra_clk_set_pllp_out_cpu(bool enable);
>>>>      /* Combined read fence with delay */
>>>>    #define fence_udelay(delay, reg)    \
>>>>

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

* Re: [PATCH V6 14/21] clk: tegra210: Add suspend and resume support
  2019-07-22  6:52         ` Sowjanya Komatineni
@ 2019-07-22  7:09           ` Dmitry Osipenko
  2019-07-22  7:12             ` Dmitry Osipenko
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-22  7:09 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

22.07.2019 9:52, Sowjanya Komatineni пишет:
> 
> On 7/21/19 11:10 PM, Dmitry Osipenko wrote:
>> 22.07.2019 1:45, Sowjanya Komatineni пишет:
>>> On 7/21/19 2:38 PM, Dmitry Osipenko wrote:
>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>>> This patch adds support for clk: tegra210: suspend-resume.
>>>>>
>>>>> All the CAR controller settings are lost on suspend when core
>>>>> power goes off.
>>>>>
>>>>> This patch has implementation for saving and restoring all PLLs
>>>>> and clocks context during system suspend and resume to have the
>>>>> clocks back to same state for normal operation.
>>>>>
>>>>> Acked-by: Thierry Reding <treding@nvidia.com>
>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>> ---
>>>>>    drivers/clk/tegra/clk-tegra210.c | 68
>>>>> ++++++++++++++++++++++++++++++++++++++--
>>>>>    drivers/clk/tegra/clk.c          | 14 +++++++++
>>>>>    drivers/clk/tegra/clk.h          |  1 +
>>>>>    3 files changed, 80 insertions(+), 3 deletions(-)
>>>>>
>>>>> diff --git a/drivers/clk/tegra/clk-tegra210.c
>>>>> b/drivers/clk/tegra/clk-tegra210.c
>>>>> index 55a88c0824a5..68271873acc1 100644
>>>>> --- a/drivers/clk/tegra/clk-tegra210.c
>>>>> +++ b/drivers/clk/tegra/clk-tegra210.c
>>>>> @@ -9,6 +9,7 @@
>>>>>    #include <linux/clkdev.h>
>>>>>    #include <linux/of.h>
>>>>>    #include <linux/of_address.h>
>>>>> +#include <linux/syscore_ops.h>
>>>>>    #include <linux/delay.h>
>>>>>    #include <linux/export.h>
>>>>>    #include <linux/mutex.h>
>>>>> @@ -220,11 +221,15 @@
>>>>>    #define CLK_M_DIVISOR_SHIFT 2
>>>>>    #define CLK_M_DIVISOR_MASK 0x3
>>>>>    +#define CLK_MASK_ARM    0x44
>>>>> +#define MISC_CLK_ENB    0x48
>>>>> +
>>>>>    #define RST_DFLL_DVCO 0x2f4
>>>>>    #define DVFS_DFLL_RESET_SHIFT 0
>>>>>      #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
>>>>> @@ -2825,6 +2830,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)
>>>>> @@ -2853,9 +2859,8 @@ static int tegra210_enable_pllu(void)
>>>>>        reg |= PLL_ENABLE;
>>>>>        writel(reg, clk_base + PLLU_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) {
>>>> Why this is needed? Was there a bug?
>>>>
>>> during resume pllu init is needed and to use same terga210_init_pllu,
>>> poll_timeout_atomic can't be used as its ony for atomic context.
>>>
>>> So changed to use wait_for_mask which should work in both cases.
>> Atomic variant could be used from any context, not sure what do you
>> mean. The 'atomic' part only means that function won't cause scheduling
>> and that's it.
> 
> Sorry, replied incorrect. readx_poll_timeout_atomic uses ktime_get() and
> during resume timekeeping suspend/resume happens later than clock
> suspend/resume. So using tegra210_wait_for_mask.
> 
> both timekeeping and clk-tegra210 drivers are registered as syscore but
> not ordered.

Okay, thank you for the clarification.

[snip]

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

* Re: [PATCH V6 14/21] clk: tegra210: Add suspend and resume support
  2019-07-22  7:09           ` Dmitry Osipenko
@ 2019-07-22  7:12             ` Dmitry Osipenko
  2019-08-02 17:51               ` Stephen Boyd
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-22  7:12 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

22.07.2019 10:09, Dmitry Osipenko пишет:
> 22.07.2019 9:52, Sowjanya Komatineni пишет:
>>
>> On 7/21/19 11:10 PM, Dmitry Osipenko wrote:
>>> 22.07.2019 1:45, Sowjanya Komatineni пишет:
>>>> On 7/21/19 2:38 PM, Dmitry Osipenko wrote:
>>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>>>> This patch adds support for clk: tegra210: suspend-resume.
>>>>>>
>>>>>> All the CAR controller settings are lost on suspend when core
>>>>>> power goes off.
>>>>>>
>>>>>> This patch has implementation for saving and restoring all PLLs
>>>>>> and clocks context during system suspend and resume to have the
>>>>>> clocks back to same state for normal operation.
>>>>>>
>>>>>> Acked-by: Thierry Reding <treding@nvidia.com>
>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>> ---
>>>>>>    drivers/clk/tegra/clk-tegra210.c | 68
>>>>>> ++++++++++++++++++++++++++++++++++++++--
>>>>>>    drivers/clk/tegra/clk.c          | 14 +++++++++
>>>>>>    drivers/clk/tegra/clk.h          |  1 +
>>>>>>    3 files changed, 80 insertions(+), 3 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/clk/tegra/clk-tegra210.c
>>>>>> b/drivers/clk/tegra/clk-tegra210.c
>>>>>> index 55a88c0824a5..68271873acc1 100644
>>>>>> --- a/drivers/clk/tegra/clk-tegra210.c
>>>>>> +++ b/drivers/clk/tegra/clk-tegra210.c
>>>>>> @@ -9,6 +9,7 @@
>>>>>>    #include <linux/clkdev.h>
>>>>>>    #include <linux/of.h>
>>>>>>    #include <linux/of_address.h>
>>>>>> +#include <linux/syscore_ops.h>
>>>>>>    #include <linux/delay.h>
>>>>>>    #include <linux/export.h>
>>>>>>    #include <linux/mutex.h>
>>>>>> @@ -220,11 +221,15 @@
>>>>>>    #define CLK_M_DIVISOR_SHIFT 2
>>>>>>    #define CLK_M_DIVISOR_MASK 0x3
>>>>>>    +#define CLK_MASK_ARM    0x44
>>>>>> +#define MISC_CLK_ENB    0x48
>>>>>> +
>>>>>>    #define RST_DFLL_DVCO 0x2f4
>>>>>>    #define DVFS_DFLL_RESET_SHIFT 0
>>>>>>      #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
>>>>>> @@ -2825,6 +2830,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)
>>>>>> @@ -2853,9 +2859,8 @@ static int tegra210_enable_pllu(void)
>>>>>>        reg |= PLL_ENABLE;
>>>>>>        writel(reg, clk_base + PLLU_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) {
>>>>> Why this is needed? Was there a bug?
>>>>>
>>>> during resume pllu init is needed and to use same terga210_init_pllu,
>>>> poll_timeout_atomic can't be used as its ony for atomic context.
>>>>
>>>> So changed to use wait_for_mask which should work in both cases.
>>> Atomic variant could be used from any context, not sure what do you
>>> mean. The 'atomic' part only means that function won't cause scheduling
>>> and that's it.
>>
>> Sorry, replied incorrect. readx_poll_timeout_atomic uses ktime_get() and
>> during resume timekeeping suspend/resume happens later than clock
>> suspend/resume. So using tegra210_wait_for_mask.
>>
>> both timekeeping and clk-tegra210 drivers are registered as syscore but
>> not ordered.
> 
> Okay, thank you for the clarification.
> 
> [snip]
> 

You should remove the 'iopoll.h' then, since it's not used anymore.

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

* Re: [PATCH V6 09/21] clk: tegra: clk-super: Fix to enable PLLP branches to CPU
  2019-07-22  6:32         ` Dmitry Osipenko
@ 2019-07-22  7:12           ` Sowjanya Komatineni
  2019-07-22  7:17             ` Dmitry Osipenko
  0 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-22  7:12 UTC (permalink / raw)
  To: Dmitry Osipenko, 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


On 7/21/19 11:32 PM, Dmitry Osipenko wrote:
> 22.07.2019 6:17, Sowjanya Komatineni пишет:
>> On 7/21/19 3:39 PM, Sowjanya Komatineni wrote:
>>> On 7/21/19 2:16 PM, Dmitry Osipenko wrote:
>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>>> This patch has a fix to enable PLLP branches to CPU before changing
>>>>> the CPU clusters clock source to PLLP for Gen5 Super clock.
>>>>>
>>>>> During system suspend entry and exit, CPU source will be switched
>>>>> to PLLP and this needs PLLP branches to be enabled to CPU prior to
>>>>> the switch.
>>>>>
>>>>> On system resume, warmboot code enables PLLP branches to CPU and
>>>>> powers up the CPU with PLLP clock source.
>>>>>
>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>> ---
>>>>>    drivers/clk/tegra/clk-super.c            | 11 +++++++++++
>>>>>    drivers/clk/tegra/clk-tegra-super-gen4.c |  4 ++--
>>>>>    drivers/clk/tegra/clk.h                  |  4 ++++
>>>>>    3 files changed, 17 insertions(+), 2 deletions(-)
>>>>>
>>>>> diff --git a/drivers/clk/tegra/clk-super.c
>>>>> b/drivers/clk/tegra/clk-super.c
>>>>> index 39ef31b46df5..d73c587e4853 100644
>>>>> --- a/drivers/clk/tegra/clk-super.c
>>>>> +++ b/drivers/clk/tegra/clk-super.c
>>>>> @@ -28,6 +28,9 @@
>>>>>    #define super_state_to_src_shift(m, s) ((m->width * s))
>>>>>    #define super_state_to_src_mask(m) (((1 << m->width) - 1))
>>>>>    +#define CCLK_SRC_PLLP_OUT0 4
>>>>> +#define CCLK_SRC_PLLP_OUT4 5
>>>>> +
>>>>>    static u8 clk_super_get_parent(struct clk_hw *hw)
>>>>>    {
>>>>>        struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
>>>>> @@ -97,6 +100,14 @@ static int clk_super_set_parent(struct clk_hw
>>>>> *hw, u8 index)
>>>>>            if (index == mux->div2_index)
>>>>>                index = mux->pllx_index;
>>>>>        }
>>>>> +
>>>>> +    /*
>>>>> +     * Enable PLLP branches to CPU before selecting PLLP source
>>>>> +     */
>>>>> +    if ((mux->flags & TEGRA_CPU_CLK) &&
>>>>> +        ((index == CCLK_SRC_PLLP_OUT0) || (index ==
>>>>> CCLK_SRC_PLLP_OUT4)))
>>>>> +        tegra_clk_set_pllp_out_cpu(true);
>>>> Should somewhere here be tegra_clk_set_pllp_out_cpu(false) when
>>>> switching from PLLP?
>>> PLLP may be used for other CPU clusters.
>> Though to avoid flag and check needed to make sure other CPU is not
>> using before disabling PLLP branch to CPU.
>>
>> But leaving it enabled shouldn't impact much as clock source mux is
>> after this in design anyway.
>>
>> But can add as well if its clear that way.
> The TRM doc says "The CPU subsystem supports a switch-cluster mode
> meaning that only one of the clusters can be active at any given time".
>
> Given that cluster-switching isn't supported in upstream, I don't think
> that you need to care about the other cluster at all, at least for now.
>
> The cluster-switching implementation in upstream is very complicated
> because it requires a special "hotplugging" CPU governor, which
> apparently no other platform needs.
>
> [snip]

This patch enables PLLP branches to CPU for both CPUG & CPULP if they 
use PLLP source.

So, to disable PLLP out CPU when not in use, we still need check for 
other cluster because during resume both LP CPU and G CPU gets restored. 
CPUG runs from PLLP on resume and when it does super clk restore for LP 
CPU which may not be using PLLP, but as both uses same super mux 
clk_ops, without check (for PLLP branch to CPU in use) disabling PLLP 
branch to CPU during LP CPU restore looses clock to CPU G as well which 
is running from PLLP.

Will add check and disable PLLP if not in use in next version... this 
need extern flag as well to mark PLLP usage with either of CPU's.



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

* Re: [PATCH V6 09/21] clk: tegra: clk-super: Fix to enable PLLP branches to CPU
  2019-07-22  7:12           ` Sowjanya Komatineni
@ 2019-07-22  7:17             ` Dmitry Osipenko
  2019-07-22  7:24               ` Sowjanya Komatineni
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-22  7:17 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

22.07.2019 10:12, Sowjanya Komatineni пишет:
> 
> On 7/21/19 11:32 PM, Dmitry Osipenko wrote:
>> 22.07.2019 6:17, Sowjanya Komatineni пишет:
>>> On 7/21/19 3:39 PM, Sowjanya Komatineni wrote:
>>>> On 7/21/19 2:16 PM, Dmitry Osipenko wrote:
>>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>>>> This patch has a fix to enable PLLP branches to CPU before changing
>>>>>> the CPU clusters clock source to PLLP for Gen5 Super clock.
>>>>>>
>>>>>> During system suspend entry and exit, CPU source will be switched
>>>>>> to PLLP and this needs PLLP branches to be enabled to CPU prior to
>>>>>> the switch.
>>>>>>
>>>>>> On system resume, warmboot code enables PLLP branches to CPU and
>>>>>> powers up the CPU with PLLP clock source.
>>>>>>
>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>> ---
>>>>>>    drivers/clk/tegra/clk-super.c            | 11 +++++++++++
>>>>>>    drivers/clk/tegra/clk-tegra-super-gen4.c |  4 ++--
>>>>>>    drivers/clk/tegra/clk.h                  |  4 ++++
>>>>>>    3 files changed, 17 insertions(+), 2 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/clk/tegra/clk-super.c
>>>>>> b/drivers/clk/tegra/clk-super.c
>>>>>> index 39ef31b46df5..d73c587e4853 100644
>>>>>> --- a/drivers/clk/tegra/clk-super.c
>>>>>> +++ b/drivers/clk/tegra/clk-super.c
>>>>>> @@ -28,6 +28,9 @@
>>>>>>    #define super_state_to_src_shift(m, s) ((m->width * s))
>>>>>>    #define super_state_to_src_mask(m) (((1 << m->width) - 1))
>>>>>>    +#define CCLK_SRC_PLLP_OUT0 4
>>>>>> +#define CCLK_SRC_PLLP_OUT4 5
>>>>>> +
>>>>>>    static u8 clk_super_get_parent(struct clk_hw *hw)
>>>>>>    {
>>>>>>        struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
>>>>>> @@ -97,6 +100,14 @@ static int clk_super_set_parent(struct clk_hw
>>>>>> *hw, u8 index)
>>>>>>            if (index == mux->div2_index)
>>>>>>                index = mux->pllx_index;
>>>>>>        }
>>>>>> +
>>>>>> +    /*
>>>>>> +     * Enable PLLP branches to CPU before selecting PLLP source
>>>>>> +     */
>>>>>> +    if ((mux->flags & TEGRA_CPU_CLK) &&
>>>>>> +        ((index == CCLK_SRC_PLLP_OUT0) || (index ==
>>>>>> CCLK_SRC_PLLP_OUT4)))
>>>>>> +        tegra_clk_set_pllp_out_cpu(true);
>>>>> Should somewhere here be tegra_clk_set_pllp_out_cpu(false) when
>>>>> switching from PLLP?
>>>> PLLP may be used for other CPU clusters.
>>> Though to avoid flag and check needed to make sure other CPU is not
>>> using before disabling PLLP branch to CPU.
>>>
>>> But leaving it enabled shouldn't impact much as clock source mux is
>>> after this in design anyway.
>>>
>>> But can add as well if its clear that way.
>> The TRM doc says "The CPU subsystem supports a switch-cluster mode
>> meaning that only one of the clusters can be active at any given time".
>>
>> Given that cluster-switching isn't supported in upstream, I don't think
>> that you need to care about the other cluster at all, at least for now.
>>
>> The cluster-switching implementation in upstream is very complicated
>> because it requires a special "hotplugging" CPU governor, which
>> apparently no other platform needs.
>>
>> [snip]
> 
> This patch enables PLLP branches to CPU for both CPUG & CPULP if they
> use PLLP source.
> 
> So, to disable PLLP out CPU when not in use, we still need check for
> other cluster because during resume both LP CPU and G CPU gets restored.
> CPUG runs from PLLP on resume and when it does super clk restore for LP
> CPU which may not be using PLLP, but as both uses same super mux
> clk_ops, without check (for PLLP branch to CPU in use) disabling PLLP
> branch to CPU during LP CPU restore looses clock to CPU G as well which
> is running from PLLP.
> 
> Will add check and disable PLLP if not in use in next version... this
> need extern flag as well to mark PLLP usage with either of CPU's.

I still don't understand why do you need to care about LP cluster at
all, given that it's always in a power-gated state.

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

* Re: [PATCH V6 09/21] clk: tegra: clk-super: Fix to enable PLLP branches to CPU
  2019-07-22  7:17             ` Dmitry Osipenko
@ 2019-07-22  7:24               ` Sowjanya Komatineni
  2019-07-22  7:30                 ` Dmitry Osipenko
  0 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-22  7:24 UTC (permalink / raw)
  To: Dmitry Osipenko, 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


On 7/22/19 12:17 AM, Dmitry Osipenko wrote:
> 22.07.2019 10:12, Sowjanya Komatineni пишет:
>> On 7/21/19 11:32 PM, Dmitry Osipenko wrote:
>>> 22.07.2019 6:17, Sowjanya Komatineni пишет:
>>>> On 7/21/19 3:39 PM, Sowjanya Komatineni wrote:
>>>>> On 7/21/19 2:16 PM, Dmitry Osipenko wrote:
>>>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>>>>> This patch has a fix to enable PLLP branches to CPU before changing
>>>>>>> the CPU clusters clock source to PLLP for Gen5 Super clock.
>>>>>>>
>>>>>>> During system suspend entry and exit, CPU source will be switched
>>>>>>> to PLLP and this needs PLLP branches to be enabled to CPU prior to
>>>>>>> the switch.
>>>>>>>
>>>>>>> On system resume, warmboot code enables PLLP branches to CPU and
>>>>>>> powers up the CPU with PLLP clock source.
>>>>>>>
>>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>>> ---
>>>>>>>     drivers/clk/tegra/clk-super.c            | 11 +++++++++++
>>>>>>>     drivers/clk/tegra/clk-tegra-super-gen4.c |  4 ++--
>>>>>>>     drivers/clk/tegra/clk.h                  |  4 ++++
>>>>>>>     3 files changed, 17 insertions(+), 2 deletions(-)
>>>>>>>
>>>>>>> diff --git a/drivers/clk/tegra/clk-super.c
>>>>>>> b/drivers/clk/tegra/clk-super.c
>>>>>>> index 39ef31b46df5..d73c587e4853 100644
>>>>>>> --- a/drivers/clk/tegra/clk-super.c
>>>>>>> +++ b/drivers/clk/tegra/clk-super.c
>>>>>>> @@ -28,6 +28,9 @@
>>>>>>>     #define super_state_to_src_shift(m, s) ((m->width * s))
>>>>>>>     #define super_state_to_src_mask(m) (((1 << m->width) - 1))
>>>>>>>     +#define CCLK_SRC_PLLP_OUT0 4
>>>>>>> +#define CCLK_SRC_PLLP_OUT4 5
>>>>>>> +
>>>>>>>     static u8 clk_super_get_parent(struct clk_hw *hw)
>>>>>>>     {
>>>>>>>         struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
>>>>>>> @@ -97,6 +100,14 @@ static int clk_super_set_parent(struct clk_hw
>>>>>>> *hw, u8 index)
>>>>>>>             if (index == mux->div2_index)
>>>>>>>                 index = mux->pllx_index;
>>>>>>>         }
>>>>>>> +
>>>>>>> +    /*
>>>>>>> +     * Enable PLLP branches to CPU before selecting PLLP source
>>>>>>> +     */
>>>>>>> +    if ((mux->flags & TEGRA_CPU_CLK) &&
>>>>>>> +        ((index == CCLK_SRC_PLLP_OUT0) || (index ==
>>>>>>> CCLK_SRC_PLLP_OUT4)))
>>>>>>> +        tegra_clk_set_pllp_out_cpu(true);
>>>>>> Should somewhere here be tegra_clk_set_pllp_out_cpu(false) when
>>>>>> switching from PLLP?
>>>>> PLLP may be used for other CPU clusters.
>>>> Though to avoid flag and check needed to make sure other CPU is not
>>>> using before disabling PLLP branch to CPU.
>>>>
>>>> But leaving it enabled shouldn't impact much as clock source mux is
>>>> after this in design anyway.
>>>>
>>>> But can add as well if its clear that way.
>>> The TRM doc says "The CPU subsystem supports a switch-cluster mode
>>> meaning that only one of the clusters can be active at any given time".
>>>
>>> Given that cluster-switching isn't supported in upstream, I don't think
>>> that you need to care about the other cluster at all, at least for now.
>>>
>>> The cluster-switching implementation in upstream is very complicated
>>> because it requires a special "hotplugging" CPU governor, which
>>> apparently no other platform needs.
>>>
>>> [snip]
>> This patch enables PLLP branches to CPU for both CPUG & CPULP if they
>> use PLLP source.
>>
>> So, to disable PLLP out CPU when not in use, we still need check for
>> other cluster because during resume both LP CPU and G CPU gets restored.
>> CPUG runs from PLLP on resume and when it does super clk restore for LP
>> CPU which may not be using PLLP, but as both uses same super mux
>> clk_ops, without check (for PLLP branch to CPU in use) disabling PLLP
>> branch to CPU during LP CPU restore looses clock to CPU G as well which
>> is running from PLLP.
>>
>> Will add check and disable PLLP if not in use in next version... this
>> need extern flag as well to mark PLLP usage with either of CPU's.
> I still don't understand why do you need to care about LP cluster at
> all, given that it's always in a power-gated state.

cclk_lp is registered thru super clk mux which uses same clk_ops as cclk_g.

during restore, cclk_lp also gets restored. So both cclk_lp & cclk_g 
goes thru same clk_ops

In this patch, I marked super flags with TEGRA_CPU_CLK for both cclk_lp 
& cclk_g.

So when cclk_lp restore happens, it goes thru same set_parent clk_ops 
and as its source is not PLLP, it tries to disable PLLP_OUT_CPU if its 
disabled without adding check for PLLP being in use by other cluster.

So either I should not mark cclk_lp as TEGRA_CPU_CLK and mark cclk_g 
only as TEGRA_CPU_CLK so PLLP out to CPU can be disabled without check 
if its not the source.

OR

With TEGRA_CPU_CLK used for both cclk_lp & cclk_g, need to add check if 
PLLP is in use so during cclk_lp restore it doesnt disable PLLP out to CPU.


To simplify without check, will just mark cclk_g super clock flag only 
as TEGRA_CPU_CLK so PLLP_OUT_CPU enable or disable happens only for CPUG



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

* Re: [PATCH V6 09/21] clk: tegra: clk-super: Fix to enable PLLP branches to CPU
  2019-07-22  7:24               ` Sowjanya Komatineni
@ 2019-07-22  7:30                 ` Dmitry Osipenko
  2019-07-22  7:36                   ` Sowjanya Komatineni
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-22  7:30 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

22.07.2019 10:24, Sowjanya Komatineni пишет:
> 
> On 7/22/19 12:17 AM, Dmitry Osipenko wrote:
>> 22.07.2019 10:12, Sowjanya Komatineni пишет:
>>> On 7/21/19 11:32 PM, Dmitry Osipenko wrote:
>>>> 22.07.2019 6:17, Sowjanya Komatineni пишет:
>>>>> On 7/21/19 3:39 PM, Sowjanya Komatineni wrote:
>>>>>> On 7/21/19 2:16 PM, Dmitry Osipenko wrote:
>>>>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>>>>>> This patch has a fix to enable PLLP branches to CPU before changing
>>>>>>>> the CPU clusters clock source to PLLP for Gen5 Super clock.
>>>>>>>>
>>>>>>>> During system suspend entry and exit, CPU source will be switched
>>>>>>>> to PLLP and this needs PLLP branches to be enabled to CPU prior to
>>>>>>>> the switch.
>>>>>>>>
>>>>>>>> On system resume, warmboot code enables PLLP branches to CPU and
>>>>>>>> powers up the CPU with PLLP clock source.
>>>>>>>>
>>>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>>>> ---
>>>>>>>>     drivers/clk/tegra/clk-super.c            | 11 +++++++++++
>>>>>>>>     drivers/clk/tegra/clk-tegra-super-gen4.c |  4 ++--
>>>>>>>>     drivers/clk/tegra/clk.h                  |  4 ++++
>>>>>>>>     3 files changed, 17 insertions(+), 2 deletions(-)
>>>>>>>>
>>>>>>>> diff --git a/drivers/clk/tegra/clk-super.c
>>>>>>>> b/drivers/clk/tegra/clk-super.c
>>>>>>>> index 39ef31b46df5..d73c587e4853 100644
>>>>>>>> --- a/drivers/clk/tegra/clk-super.c
>>>>>>>> +++ b/drivers/clk/tegra/clk-super.c
>>>>>>>> @@ -28,6 +28,9 @@
>>>>>>>>     #define super_state_to_src_shift(m, s) ((m->width * s))
>>>>>>>>     #define super_state_to_src_mask(m) (((1 << m->width) - 1))
>>>>>>>>     +#define CCLK_SRC_PLLP_OUT0 4
>>>>>>>> +#define CCLK_SRC_PLLP_OUT4 5
>>>>>>>> +
>>>>>>>>     static u8 clk_super_get_parent(struct clk_hw *hw)
>>>>>>>>     {
>>>>>>>>         struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
>>>>>>>> @@ -97,6 +100,14 @@ static int clk_super_set_parent(struct clk_hw
>>>>>>>> *hw, u8 index)
>>>>>>>>             if (index == mux->div2_index)
>>>>>>>>                 index = mux->pllx_index;
>>>>>>>>         }
>>>>>>>> +
>>>>>>>> +    /*
>>>>>>>> +     * Enable PLLP branches to CPU before selecting PLLP source
>>>>>>>> +     */
>>>>>>>> +    if ((mux->flags & TEGRA_CPU_CLK) &&
>>>>>>>> +        ((index == CCLK_SRC_PLLP_OUT0) || (index ==
>>>>>>>> CCLK_SRC_PLLP_OUT4)))
>>>>>>>> +        tegra_clk_set_pllp_out_cpu(true);
>>>>>>> Should somewhere here be tegra_clk_set_pllp_out_cpu(false) when
>>>>>>> switching from PLLP?
>>>>>> PLLP may be used for other CPU clusters.
>>>>> Though to avoid flag and check needed to make sure other CPU is not
>>>>> using before disabling PLLP branch to CPU.
>>>>>
>>>>> But leaving it enabled shouldn't impact much as clock source mux is
>>>>> after this in design anyway.
>>>>>
>>>>> But can add as well if its clear that way.
>>>> The TRM doc says "The CPU subsystem supports a switch-cluster mode
>>>> meaning that only one of the clusters can be active at any given time".
>>>>
>>>> Given that cluster-switching isn't supported in upstream, I don't think
>>>> that you need to care about the other cluster at all, at least for now.
>>>>
>>>> The cluster-switching implementation in upstream is very complicated
>>>> because it requires a special "hotplugging" CPU governor, which
>>>> apparently no other platform needs.
>>>>
>>>> [snip]
>>> This patch enables PLLP branches to CPU for both CPUG & CPULP if they
>>> use PLLP source.
>>>
>>> So, to disable PLLP out CPU when not in use, we still need check for
>>> other cluster because during resume both LP CPU and G CPU gets restored.
>>> CPUG runs from PLLP on resume and when it does super clk restore for LP
>>> CPU which may not be using PLLP, but as both uses same super mux
>>> clk_ops, without check (for PLLP branch to CPU in use) disabling PLLP
>>> branch to CPU during LP CPU restore looses clock to CPU G as well which
>>> is running from PLLP.
>>>
>>> Will add check and disable PLLP if not in use in next version... this
>>> need extern flag as well to mark PLLP usage with either of CPU's.
>> I still don't understand why do you need to care about LP cluster at
>> all, given that it's always in a power-gated state.
> 
> cclk_lp is registered thru super clk mux which uses same clk_ops as cclk_g.
> 
> during restore, cclk_lp also gets restored. So both cclk_lp & cclk_g
> goes thru same clk_ops
> 
> In this patch, I marked super flags with TEGRA_CPU_CLK for both cclk_lp
> & cclk_g.
> 
> So when cclk_lp restore happens, it goes thru same set_parent clk_ops
> and as its source is not PLLP, it tries to disable PLLP_OUT_CPU if its
> disabled without adding check for PLLP being in use by other cluster.

Ah, okay.

> So either I should not mark cclk_lp as TEGRA_CPU_CLK and mark cclk_g
> only as TEGRA_CPU_CLK so PLLP out to CPU can be disabled without check
> if its not the source.
> 
> OR
> 
> With TEGRA_CPU_CLK used for both cclk_lp & cclk_g, need to add check if
> PLLP is in use so during cclk_lp restore it doesnt disable PLLP out to CPU.
> 
> 
> To simplify without check, will just mark cclk_g super clock flag only
> as TEGRA_CPU_CLK so PLLP_OUT_CPU enable or disable happens only for CPUG

Sounds good. Then please add a brief comment to the CPULP, telling why
it misses the flag, for the record.

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

* Re: [PATCH V6 09/21] clk: tegra: clk-super: Fix to enable PLLP branches to CPU
  2019-07-22  7:30                 ` Dmitry Osipenko
@ 2019-07-22  7:36                   ` Sowjanya Komatineni
  0 siblings, 0 replies; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-22  7:36 UTC (permalink / raw)
  To: Dmitry Osipenko, 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


On 7/22/19 12:30 AM, Dmitry Osipenko wrote:
> 22.07.2019 10:24, Sowjanya Komatineni пишет:
>> On 7/22/19 12:17 AM, Dmitry Osipenko wrote:
>>> 22.07.2019 10:12, Sowjanya Komatineni пишет:
>>>> On 7/21/19 11:32 PM, Dmitry Osipenko wrote:
>>>>> 22.07.2019 6:17, Sowjanya Komatineni пишет:
>>>>>> On 7/21/19 3:39 PM, Sowjanya Komatineni wrote:
>>>>>>> On 7/21/19 2:16 PM, Dmitry Osipenko wrote:
>>>>>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>>>>>>> This patch has a fix to enable PLLP branches to CPU before changing
>>>>>>>>> the CPU clusters clock source to PLLP for Gen5 Super clock.
>>>>>>>>>
>>>>>>>>> During system suspend entry and exit, CPU source will be switched
>>>>>>>>> to PLLP and this needs PLLP branches to be enabled to CPU prior to
>>>>>>>>> the switch.
>>>>>>>>>
>>>>>>>>> On system resume, warmboot code enables PLLP branches to CPU and
>>>>>>>>> powers up the CPU with PLLP clock source.
>>>>>>>>>
>>>>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>>>>> ---
>>>>>>>>>      drivers/clk/tegra/clk-super.c            | 11 +++++++++++
>>>>>>>>>      drivers/clk/tegra/clk-tegra-super-gen4.c |  4 ++--
>>>>>>>>>      drivers/clk/tegra/clk.h                  |  4 ++++
>>>>>>>>>      3 files changed, 17 insertions(+), 2 deletions(-)
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/clk/tegra/clk-super.c
>>>>>>>>> b/drivers/clk/tegra/clk-super.c
>>>>>>>>> index 39ef31b46df5..d73c587e4853 100644
>>>>>>>>> --- a/drivers/clk/tegra/clk-super.c
>>>>>>>>> +++ b/drivers/clk/tegra/clk-super.c
>>>>>>>>> @@ -28,6 +28,9 @@
>>>>>>>>>      #define super_state_to_src_shift(m, s) ((m->width * s))
>>>>>>>>>      #define super_state_to_src_mask(m) (((1 << m->width) - 1))
>>>>>>>>>      +#define CCLK_SRC_PLLP_OUT0 4
>>>>>>>>> +#define CCLK_SRC_PLLP_OUT4 5
>>>>>>>>> +
>>>>>>>>>      static u8 clk_super_get_parent(struct clk_hw *hw)
>>>>>>>>>      {
>>>>>>>>>          struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
>>>>>>>>> @@ -97,6 +100,14 @@ static int clk_super_set_parent(struct clk_hw
>>>>>>>>> *hw, u8 index)
>>>>>>>>>              if (index == mux->div2_index)
>>>>>>>>>                  index = mux->pllx_index;
>>>>>>>>>          }
>>>>>>>>> +
>>>>>>>>> +    /*
>>>>>>>>> +     * Enable PLLP branches to CPU before selecting PLLP source
>>>>>>>>> +     */
>>>>>>>>> +    if ((mux->flags & TEGRA_CPU_CLK) &&
>>>>>>>>> +        ((index == CCLK_SRC_PLLP_OUT0) || (index ==
>>>>>>>>> CCLK_SRC_PLLP_OUT4)))
>>>>>>>>> +        tegra_clk_set_pllp_out_cpu(true);
>>>>>>>> Should somewhere here be tegra_clk_set_pllp_out_cpu(false) when
>>>>>>>> switching from PLLP?
>>>>>>> PLLP may be used for other CPU clusters.
>>>>>> Though to avoid flag and check needed to make sure other CPU is not
>>>>>> using before disabling PLLP branch to CPU.
>>>>>>
>>>>>> But leaving it enabled shouldn't impact much as clock source mux is
>>>>>> after this in design anyway.
>>>>>>
>>>>>> But can add as well if its clear that way.
>>>>> The TRM doc says "The CPU subsystem supports a switch-cluster mode
>>>>> meaning that only one of the clusters can be active at any given time".
>>>>>
>>>>> Given that cluster-switching isn't supported in upstream, I don't think
>>>>> that you need to care about the other cluster at all, at least for now.
>>>>>
>>>>> The cluster-switching implementation in upstream is very complicated
>>>>> because it requires a special "hotplugging" CPU governor, which
>>>>> apparently no other platform needs.
>>>>>
>>>>> [snip]
>>>> This patch enables PLLP branches to CPU for both CPUG & CPULP if they
>>>> use PLLP source.
>>>>
>>>> So, to disable PLLP out CPU when not in use, we still need check for
>>>> other cluster because during resume both LP CPU and G CPU gets restored.
>>>> CPUG runs from PLLP on resume and when it does super clk restore for LP
>>>> CPU which may not be using PLLP, but as both uses same super mux
>>>> clk_ops, without check (for PLLP branch to CPU in use) disabling PLLP
>>>> branch to CPU during LP CPU restore looses clock to CPU G as well which
>>>> is running from PLLP.
>>>>
>>>> Will add check and disable PLLP if not in use in next version... this
>>>> need extern flag as well to mark PLLP usage with either of CPU's.
>>> I still don't understand why do you need to care about LP cluster at
>>> all, given that it's always in a power-gated state.
>> cclk_lp is registered thru super clk mux which uses same clk_ops as cclk_g.
>>
>> during restore, cclk_lp also gets restored. So both cclk_lp & cclk_g
>> goes thru same clk_ops
>>
>> In this patch, I marked super flags with TEGRA_CPU_CLK for both cclk_lp
>> & cclk_g.
>>
>> So when cclk_lp restore happens, it goes thru same set_parent clk_ops
>> and as its source is not PLLP, it tries to disable PLLP_OUT_CPU if its
>> disabled without adding check for PLLP being in use by other cluster.
> Ah, okay.
>
>> So either I should not mark cclk_lp as TEGRA_CPU_CLK and mark cclk_g
>> only as TEGRA_CPU_CLK so PLLP out to CPU can be disabled without check
>> if its not the source.
>>
>> OR
>>
>> With TEGRA_CPU_CLK used for both cclk_lp & cclk_g, need to add check if
>> PLLP is in use so during cclk_lp restore it doesnt disable PLLP out to CPU.
>>
>>
>> To simplify without check, will just mark cclk_g super clock flag only
>> as TEGRA_CPU_CLK so PLLP_OUT_CPU enable or disable happens only for CPUG
> Sounds good. Then please add a brief comment to the CPULP, telling why
> it misses the flag, for the record.

Sure, will add comment.


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

* Re: [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend
  2019-07-21 19:40 ` [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend Sowjanya Komatineni
  2019-07-21 20:24   ` Marc Zyngier
@ 2019-07-22  9:54   ` Dmitry Osipenko
  2019-07-22 10:13     ` Marc Zyngier
  2019-07-25  9:55     ` Peter De Schrijver
  1 sibling, 2 replies; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-22  9:54 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

21.07.2019 22:40, Sowjanya Komatineni пишет:
> 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.
> 
> Acked-by: Thierry Reding <treding@nvidia.com>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/irqchip/irq-tegra.c | 20 ++++++++++++++++++--
>  1 file changed, 18 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-tegra.c b/drivers/irqchip/irq-tegra.c
> index e1f771c72fc4..851f88cef508 100644
> --- a/drivers/irqchip/irq-tegra.c
> +++ b/drivers/irqchip/irq-tegra.c
> @@ -44,6 +44,7 @@ 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 = {
> @@ -56,6 +57,7 @@ static const struct tegra_ictlr_soc tegra30_ictlr_soc = {
>  
>  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 +69,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 +150,20 @@ 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)
> +			/* Disable COP interrupts if SC7 is not supported */

All Tegra SoCs support SC7, hence the 'supports_sc7' and the comment
doesn't sound correct to me. Something like 'firmware_sc7' should suit
better here.

> +			writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);

Secondly, I'm also not sure why COP interrupts need to be disabled for
pre-T210 at all, since COP is unused. This looks to me like it was
cut-n-pasted from downstream kernel without a good reason and could be
simply removed.

>  		/* Disable CPU interrupts */
>  		writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR);
> @@ -339,6 +354,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",
> 


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

* Re: [PATCH V6 07/21] clk: tegra: Support for OSC context save and restore
  2019-07-21 19:40 ` [PATCH V6 07/21] clk: tegra: Support for OSC context save and restore Sowjanya Komatineni
@ 2019-07-22 10:12   ` Dmitry Osipenko
  0 siblings, 0 replies; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-22 10:12 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

21.07.2019 22:40, Sowjanya Komatineni пишет:
> X-NVConfidentiality: public

What's that?

> This patch adds support for saving 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.
> 
> Acked-by: Thierry Reding <treding@nvidia.com>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk-tegra-fixed.c | 15 +++++++++++++++
>  drivers/clk/tegra/clk.h             |  1 +
>  2 files changed, 16 insertions(+)
> 
> diff --git a/drivers/clk/tegra/clk-tegra-fixed.c b/drivers/clk/tegra/clk-tegra-fixed.c
> index 8d91b2b191cf..7c6c8abfcde6 100644
> --- a/drivers/clk/tegra/clk-tegra-fixed.c
> +++ b/drivers/clk/tegra/clk-tegra-fixed.c
> @@ -17,6 +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,
> @@ -29,6 +33,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 +101,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 8532f5150091..3cd003b7512a 100644
> --- a/drivers/clk/tegra/clk.h
> +++ b/drivers/clk/tegra/clk.h
> @@ -849,6 +849,7 @@ 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_clk_osc_resume(void __iomem *clk_base);
>  
>  /* Combined read fence with delay */
>  #define fence_udelay(delay, reg)	\
> 


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

* Re: [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend
  2019-07-22  9:54   ` Dmitry Osipenko
@ 2019-07-22 10:13     ` Marc Zyngier
  2019-07-22 10:57       ` Dmitry Osipenko
  2019-07-25  9:55     ` Peter De Schrijver
  1 sibling, 1 reply; 84+ messages in thread
From: Marc Zyngier @ 2019-07-22 10:13 UTC (permalink / raw)
  To: Dmitry Osipenko, 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, devicetree

On 22/07/2019 10:54, Dmitry Osipenko wrote:
> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>> 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.
>>
>> Acked-by: Thierry Reding <treding@nvidia.com>
>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>> ---
>>  drivers/irqchip/irq-tegra.c | 20 ++++++++++++++++++--
>>  1 file changed, 18 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-tegra.c b/drivers/irqchip/irq-tegra.c
>> index e1f771c72fc4..851f88cef508 100644
>> --- a/drivers/irqchip/irq-tegra.c
>> +++ b/drivers/irqchip/irq-tegra.c
>> @@ -44,6 +44,7 @@ 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 = {
>> @@ -56,6 +57,7 @@ static const struct tegra_ictlr_soc tegra30_ictlr_soc = {
>>  
>>  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 +69,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 +150,20 @@ 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)
>> +			/* Disable COP interrupts if SC7 is not supported */
> 
> All Tegra SoCs support SC7, hence the 'supports_sc7' and the comment
> doesn't sound correct to me. Something like 'firmware_sc7' should suit
> better here.

If what you're saying is true, then the whole patch is wrong, and the
SC7 property should come from DT.

> 
>> +			writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
> 
> Secondly, I'm also not sure why COP interrupts need to be disabled for
> pre-T210 at all, since COP is unused. This looks to me like it was
> cut-n-pasted from downstream kernel without a good reason and could be
> simply removed.

Please verify that this is actually the case. Tegra-2 definitely needed
some level of poking, and I'm not keen on changing anything there until
you (or someone else) has verified it on actual HW (see e307cc8941fc).

Joseph, can you please shed some light here?

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

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

* Re: [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend
  2019-07-22 10:13     ` Marc Zyngier
@ 2019-07-22 10:57       ` Dmitry Osipenko
  2019-07-22 16:21         ` Sowjanya Komatineni
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-22 10:57 UTC (permalink / raw)
  To: Marc Zyngier, 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, devicetree

22.07.2019 13:13, Marc Zyngier пишет:
> On 22/07/2019 10:54, Dmitry Osipenko wrote:
>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>> 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.
>>>
>>> Acked-by: Thierry Reding <treding@nvidia.com>
>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>> ---
>>>  drivers/irqchip/irq-tegra.c | 20 ++++++++++++++++++--
>>>  1 file changed, 18 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/irqchip/irq-tegra.c b/drivers/irqchip/irq-tegra.c
>>> index e1f771c72fc4..851f88cef508 100644
>>> --- a/drivers/irqchip/irq-tegra.c
>>> +++ b/drivers/irqchip/irq-tegra.c
>>> @@ -44,6 +44,7 @@ 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 = {
>>> @@ -56,6 +57,7 @@ static const struct tegra_ictlr_soc tegra30_ictlr_soc = {
>>>  
>>>  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 +69,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 +150,20 @@ 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)
>>> +			/* Disable COP interrupts if SC7 is not supported */
>>
>> All Tegra SoCs support SC7, hence the 'supports_sc7' and the comment
>> doesn't sound correct to me. Something like 'firmware_sc7' should suit
>> better here.
> 
> If what you're saying is true, then the whole patch is wrong, and the
> SC7 property should come from DT.

It should be safe to assume that all of existing Tegra210 devices use
the firmware for SC7, hence I wouldn't say that the patch is entirely
wrong. To me it's not entirely correct.

>>
>>> +			writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
>>
>> Secondly, I'm also not sure why COP interrupts need to be disabled for
>> pre-T210 at all, since COP is unused. This looks to me like it was
>> cut-n-pasted from downstream kernel without a good reason and could be
>> simply removed.
> 
> Please verify that this is actually the case. Tegra-2 definitely needed
> some level of poking, and I'm not keen on changing anything there until
> you (or someone else) has verified it on actual HW (see e307cc8941fc).

Tested on Tegra20 and Tegra30, LP1 suspend-resume works perfectly fine
with all COP bits removed from the driver.

AFAIK, the reason why downstream needed that disabling is that it uses
proprietary firmware which is running on the COP and that firmware is
usually a BLOB audio/video DEC-ENC driver which doesn't cleanup
interrupts after itself. That firmware is not applicable for the
upstream kernel, hence there is no need to care about it.

> Joseph, can you please shed some light here?


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

* Re: [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend
  2019-07-22 10:57       ` Dmitry Osipenko
@ 2019-07-22 16:21         ` Sowjanya Komatineni
  2019-07-22 18:38           ` Marc Zyngier
  0 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-22 16:21 UTC (permalink / raw)
  To: Dmitry Osipenko, Marc Zyngier, 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, devicetree


On 7/22/19 3:57 AM, Dmitry Osipenko wrote:
> 22.07.2019 13:13, Marc Zyngier пишет:
>> On 22/07/2019 10:54, Dmitry Osipenko wrote:
>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>> 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.
>>>>
>>>> Acked-by: Thierry Reding <treding@nvidia.com>
>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>> ---
>>>>   drivers/irqchip/irq-tegra.c | 20 ++++++++++++++++++--
>>>>   1 file changed, 18 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/drivers/irqchip/irq-tegra.c b/drivers/irqchip/irq-tegra.c
>>>> index e1f771c72fc4..851f88cef508 100644
>>>> --- a/drivers/irqchip/irq-tegra.c
>>>> +++ b/drivers/irqchip/irq-tegra.c
>>>> @@ -44,6 +44,7 @@ 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 = {
>>>> @@ -56,6 +57,7 @@ static const struct tegra_ictlr_soc tegra30_ictlr_soc = {
>>>>   
>>>>   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 +69,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 +150,20 @@ 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)
>>>> +			/* Disable COP interrupts if SC7 is not supported */
>>> All Tegra SoCs support SC7, hence the 'supports_sc7' and the comment
>>> doesn't sound correct to me. Something like 'firmware_sc7' should suit
>>> better here.
>> If what you're saying is true, then the whole patch is wrong, and the
>> SC7 property should come from DT.
> It should be safe to assume that all of existing Tegra210 devices use
> the firmware for SC7, hence I wouldn't say that the patch is entirely
> wrong. To me it's not entirely correct.

Yes, all existing Tegra210 platforms uses sc7 entry firmware for SC7 and 
AVP/COP IRQ need to be kept enabled as during suspend ATF triggers IRQ 
to COP for SC7 entry fw execution.


>>>> +			writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
>>> Secondly, I'm also not sure why COP interrupts need to be disabled for
>>> pre-T210 at all, since COP is unused. This looks to me like it was
>>> cut-n-pasted from downstream kernel without a good reason and could be
>>> simply removed.
>> Please verify that this is actually the case. Tegra-2 definitely needed
>> some level of poking, and I'm not keen on changing anything there until
>> you (or someone else) has verified it on actual HW (see e307cc8941fc).
> Tested on Tegra20 and Tegra30, LP1 suspend-resume works perfectly fine
> with all COP bits removed from the driver.
>
> AFAIK, the reason why downstream needed that disabling is that it uses
> proprietary firmware which is running on the COP and that firmware is
> usually a BLOB audio/video DEC-ENC driver which doesn't cleanup
> interrupts after itself. That firmware is not applicable for the
> upstream kernel, hence there is no need to care about it.
>
>> Joseph, can you please shed some light here?

SC7 entry flow uses 3rd party ATF (arm-trusted FW) blob which is the one that actually loads SC7 entry firmware and triggers IRQ to AVP/COP which causes COP to wakeup and run SC7 entry FW.

So when SC7 support is enabled, IRQ need to be kept enabled and when SC7 FW starts execution, it will disable COP IRQ.



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

* Re: [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend
  2019-07-22 16:21         ` Sowjanya Komatineni
@ 2019-07-22 18:38           ` Marc Zyngier
  2019-07-22 23:35             ` Dmitry Osipenko
  0 siblings, 1 reply; 84+ messages in thread
From: Marc Zyngier @ 2019-07-22 18:38 UTC (permalink / raw)
  To: Sowjanya Komatineni
  Cc: Dmitry Osipenko, thierry.reding, jonathanh, tglx, jason,
	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 Mon, 22 Jul 2019 09:21:21 -0700
Sowjanya Komatineni <skomatineni@nvidia.com> wrote:

> On 7/22/19 3:57 AM, Dmitry Osipenko wrote:
> > 22.07.2019 13:13, Marc Zyngier пишет:  
> >> On 22/07/2019 10:54, Dmitry Osipenko wrote:  
> >>> 21.07.2019 22:40, Sowjanya Komatineni пишет:  
> >>>> 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.
> >>>>
> >>>> Acked-by: Thierry Reding <treding@nvidia.com>
> >>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> >>>> ---
> >>>>   drivers/irqchip/irq-tegra.c | 20 ++++++++++++++++++--
> >>>>   1 file changed, 18 insertions(+), 2 deletions(-)
> >>>>
> >>>> diff --git a/drivers/irqchip/irq-tegra.c b/drivers/irqchip/irq-tegra.c
> >>>> index e1f771c72fc4..851f88cef508 100644
> >>>> --- a/drivers/irqchip/irq-tegra.c
> >>>> +++ b/drivers/irqchip/irq-tegra.c
> >>>> @@ -44,6 +44,7 @@ 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 = {
> >>>> @@ -56,6 +57,7 @@ static const struct tegra_ictlr_soc tegra30_ictlr_soc = {
> >>>>   
> >>>>   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 +69,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 +150,20 @@ 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)
> >>>> +			/* Disable COP interrupts if SC7 is not supported */  
> >>> All Tegra SoCs support SC7, hence the 'supports_sc7' and the comment
> >>> doesn't sound correct to me. Something like 'firmware_sc7' should suit
> >>> better here.  
> >> If what you're saying is true, then the whole patch is wrong, and the
> >> SC7 property should come from DT.  
> > It should be safe to assume that all of existing Tegra210 devices use
> > the firmware for SC7, hence I wouldn't say that the patch is entirely
> > wrong. To me it's not entirely correct.  
> 
> Yes, all existing Tegra210 platforms uses sc7 entry firmware for SC7 and 
> AVP/COP IRQ need to be kept enabled as during suspend ATF triggers IRQ 
> to COP for SC7 entry fw execution.

That's not the question. Dmitry says that the SC7 support is not a
property of the SoC, but mostly a platform decision on whether the
firmware supports SC7 or not.

To me, that's a clear indication that this should not be hardcoded in
the driver, but instead obtained dynamically, via DT or otherwise.

> 
> 
> >>>> +			writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);  
> >>> Secondly, I'm also not sure why COP interrupts need to be disabled for
> >>> pre-T210 at all, since COP is unused. This looks to me like it was
> >>> cut-n-pasted from downstream kernel without a good reason and could be
> >>> simply removed.  
> >> Please verify that this is actually the case. Tegra-2 definitely needed
> >> some level of poking, and I'm not keen on changing anything there until
> >> you (or someone else) has verified it on actual HW (see e307cc8941fc).  
> > Tested on Tegra20 and Tegra30, LP1 suspend-resume works perfectly fine
> > with all COP bits removed from the driver.
> >
> > AFAIK, the reason why downstream needed that disabling is that it uses
> > proprietary firmware which is running on the COP and that firmware is
> > usually a BLOB audio/video DEC-ENC driver which doesn't cleanup
> > interrupts after itself. That firmware is not applicable for the
> > upstream kernel, hence there is no need to care about it.
> >  
> >> Joseph, can you please shed some light here?  
> 
> SC7 entry flow uses 3rd party ATF (arm-trusted FW) blob which is the
> one that actually loads SC7 entry firmware and triggers IRQ to
> AVP/COP which causes COP to wakeup and run SC7 entry FW.
> 
> So when SC7 support is enabled, IRQ need to be kept enabled and when
> SC7 FW starts execution, it will disable COP IRQ.

This looks like a lot of undocumented assumptions on what firmware
does, as well as what firmware *is*. What I gather from this thread is
that there is at least two versions of firmware (a "proprietary
firmware" for "downstream kernels", and another one for mainline), and
that they do different things.

Given that we cannot know what people actually run, I don't think we
can safely remove anything unless this gets tested on the full spectrum
of HW/FW combination.

Thanks,

	M.
-- 
Without deviation from the norm, progress is not possible.

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

* Re: [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend
  2019-07-22 18:38           ` Marc Zyngier
@ 2019-07-22 23:35             ` Dmitry Osipenko
  2019-07-24 23:09               ` Sowjanya Komatineni
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-22 23:35 UTC (permalink / raw)
  To: Marc Zyngier, Sowjanya Komatineni
  Cc: thierry.reding, jonathanh, tglx, jason, linus.walleij, stefan,
	mark.rutland, pdeschrijver, pgaikwad, sboyd, linux-clk,
	linux-gpio, jckuo, josephl, talho, linux-tegra, linux-kernel,
	mperttunen, spatra, robh+dt, devicetree

22.07.2019 21:38, Marc Zyngier пишет:
> On Mon, 22 Jul 2019 09:21:21 -0700
> Sowjanya Komatineni <skomatineni@nvidia.com> wrote:
> 
>> On 7/22/19 3:57 AM, Dmitry Osipenko wrote:
>>> 22.07.2019 13:13, Marc Zyngier пишет:  
>>>> On 22/07/2019 10:54, Dmitry Osipenko wrote:  
>>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:  
>>>>>> 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.
>>>>>>
>>>>>> Acked-by: Thierry Reding <treding@nvidia.com>
>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>> ---
>>>>>>   drivers/irqchip/irq-tegra.c | 20 ++++++++++++++++++--
>>>>>>   1 file changed, 18 insertions(+), 2 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/irqchip/irq-tegra.c b/drivers/irqchip/irq-tegra.c
>>>>>> index e1f771c72fc4..851f88cef508 100644
>>>>>> --- a/drivers/irqchip/irq-tegra.c
>>>>>> +++ b/drivers/irqchip/irq-tegra.c
>>>>>> @@ -44,6 +44,7 @@ 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 = {
>>>>>> @@ -56,6 +57,7 @@ static const struct tegra_ictlr_soc tegra30_ictlr_soc = {
>>>>>>   
>>>>>>   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 +69,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 +150,20 @@ 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)
>>>>>> +			/* Disable COP interrupts if SC7 is not supported */  
>>>>> All Tegra SoCs support SC7, hence the 'supports_sc7' and the comment
>>>>> doesn't sound correct to me. Something like 'firmware_sc7' should suit
>>>>> better here.  
>>>> If what you're saying is true, then the whole patch is wrong, and the
>>>> SC7 property should come from DT.  
>>> It should be safe to assume that all of existing Tegra210 devices use
>>> the firmware for SC7, hence I wouldn't say that the patch is entirely
>>> wrong. To me it's not entirely correct.  
>>
>> Yes, all existing Tegra210 platforms uses sc7 entry firmware for SC7 and 
>> AVP/COP IRQ need to be kept enabled as during suspend ATF triggers IRQ 
>> to COP for SC7 entry fw execution.

Okay, as I already wrote before, it looks to me that a more proper
solution should be to just remove everything related to COP from this
driver instead of adding custom quirks for T210.

The disabling / restoring of COP interrupts should be relevant only for
the multimedia firmware on older Tegra SoCs. That firmware won't be ever
supported in the upstream simply because NVIDIA abandoned the support
for older hardware in the downstream and because it is not possible due
to some legal weirdness (IIUC). The only variant for upstream is
reverse-engineering of hardware (not the firmware BLOB) and writing
proper opensource drivers for the upstream kernel, which we're already
doing and have success to a some extent.

> That's not the question. Dmitry says that the SC7 support is not a
> property of the SoC, but mostly a platform decision on whether the
> firmware supports SC7 or not.
> 
> To me, that's a clear indication that this should not be hardcoded in
> the driver, but instead obtained dynamically, via DT or otherwise.

We already have an nvidia,suspend-mode property in the device-tree of
the Power Management Controller node (all Tegra SoCs) which defines what
suspending type is supported by a particular board.

>>>>>> +			writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);  
>>>>> Secondly, I'm also not sure why COP interrupts need to be disabled for
>>>>> pre-T210 at all, since COP is unused. This looks to me like it was
>>>>> cut-n-pasted from downstream kernel without a good reason and could be
>>>>> simply removed.  
>>>> Please verify that this is actually the case. Tegra-2 definitely needed
>>>> some level of poking, and I'm not keen on changing anything there until
>>>> you (or someone else) has verified it on actual HW (see e307cc8941fc).  
>>> Tested on Tegra20 and Tegra30, LP1 suspend-resume works perfectly fine
>>> with all COP bits removed from the driver.
>>>
>>> AFAIK, the reason why downstream needed that disabling is that it uses
>>> proprietary firmware which is running on the COP and that firmware is
>>> usually a BLOB audio/video DEC-ENC driver which doesn't cleanup
>>> interrupts after itself. That firmware is not applicable for the
>>> upstream kernel, hence there is no need to care about it.
>>>  
>>>> Joseph, can you please shed some light here?  
>>
>> SC7 entry flow uses 3rd party ATF (arm-trusted FW) blob which is the
>> one that actually loads SC7 entry firmware and triggers IRQ to
>> AVP/COP which causes COP to wakeup and run SC7 entry FW.
>>
>> So when SC7 support is enabled, IRQ need to be kept enabled and when
>> SC7 FW starts execution, it will disable COP IRQ.
> 
> This looks like a lot of undocumented assumptions on what firmware
> does, as well as what firmware *is*. What I gather from this thread is
> that there is at least two versions of firmware (a "proprietary
> firmware" for "downstream kernels", and another one for mainline), and
> that they do different things.
> 
> Given that we cannot know what people actually run, I don't think we
> can safely remove anything unless this gets tested on the full spectrum
> of HW/FW combination.

I'm not sure whether multiple firmware variations exist in the wild for
Tegra210. Maybe Sowjanya or somebody else from NVIDIA could clarify. I
think there should be some efforts in regards to a fully opensource
firmware on Tegra210, but I'm not following it and have no idea about
the status.

You're right that there are multiple variants of suspend-resuming flow
on Tegra SoCs. The older 32bit Tegra SoC generations have a variety of
options in regards to suspend-resuming, including firmware-less variants
on platforms that are having kernel running in secure mode (dev boards,
most of Tegra20 consumer devices) and Trusted-Foundations firmware
variant for insecure platforms (consumer devices). And yes, vendor
firmware creates a lot of headache in regards to bringing support into
upstream because it usually does a lot of odd undocumented things which
may also vary depending on a firmware version (bootloader, etc) and it
also usually difficult to replace it with an opensource alternative due
to a crypto signing.

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

* Re: [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210
  2019-07-21 19:40 ` [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210 Sowjanya Komatineni
@ 2019-07-23  0:58   ` Dmitry Osipenko
  2019-07-23  1:08     ` Dmitry Osipenko
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-23  0:58 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

21.07.2019 22:40, Sowjanya Komatineni пишет:
> 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 91c84d0e66ae..c556f38874e1 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)
> @@ -1922,6 +1933,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);

Why it takes so much time to latch the values? Shouldn't some status-bit
be polled for the completion of latching?

Is this register-write really getting buffered in the PMC?

> +	value &= ~PMC_CNTRL_LATCH_WAKEUPS;
> +	tegra_pmc_writel(pmc, value, PMC_CNTRL);
> +	udelay(120);

120 usecs to remove latching, really?

> +	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);

Why the latching is done *before* writing into the WAKE registers? What
it is latching then?

> +	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);
> @@ -1954,6 +2014,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);

Shouldn't the WAKE_LEVEL be latched as well?

> +	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);
> @@ -2540,6 +2643,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,
> @@ -2557,10 +2664,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)					     \
> 


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

* Re: [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210
  2019-07-23  0:58   ` Dmitry Osipenko
@ 2019-07-23  1:08     ` Dmitry Osipenko
  2019-07-23  1:41       ` Dmitry Osipenko
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-23  1:08 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

23.07.2019 3:58, Dmitry Osipenko пишет:
> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>> 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 91c84d0e66ae..c556f38874e1 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)

Please follow the TRM's bits naming.

PMC_CNTRL_LATCHWAKE_EN

>> +#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)
>> @@ -1922,6 +1933,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);
> 
> Why it takes so much time to latch the values? Shouldn't some status-bit
> be polled for the completion of latching?
> 
> Is this register-write really getting buffered in the PMC?
> 
>> +	value &= ~PMC_CNTRL_LATCH_WAKEUPS;
>> +	tegra_pmc_writel(pmc, value, PMC_CNTRL);
>> +	udelay(120);
> 
> 120 usecs to remove latching, really?
> 
>> +	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);
> 
> Why the latching is done *before* writing into the WAKE registers? What
> it is latching then?

I'm looking at the TRM doc and it says that latching should be done
*after* writing to the WAKE_MASK / LEVEL registers.

Secondly it says that it's enough to do:

value = tegra_pmc_readl(pmc, PMC_CNTRL);
value |= PMC_CNTRL_LATCH_WAKEUPS;
tegra_pmc_writel(pmc, value, PMC_CNTRL);

in order to latch. There is no need for the delay and to remove the
"LATCHWAKE_EN" bit, it should be a oneshot action.

>> +	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);
>> @@ -1954,6 +2014,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);
> 
> Shouldn't the WAKE_LEVEL be latched as well?
> 
>> +	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);
>> @@ -2540,6 +2643,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,
>> @@ -2557,10 +2664,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)					     \
>>
> 


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

* Re: [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210
  2019-07-23  1:08     ` Dmitry Osipenko
@ 2019-07-23  1:41       ` Dmitry Osipenko
  2019-07-23  1:52         ` Dmitry Osipenko
       [not found]         ` <71a88a9c-a542-557a-0eaa-3c90112dee0e@nvidia.com>
  0 siblings, 2 replies; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-23  1:41 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

23.07.2019 4:08, Dmitry Osipenko пишет:
> 23.07.2019 3:58, Dmitry Osipenko пишет:
>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>> 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 91c84d0e66ae..c556f38874e1 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)
> 
> Please follow the TRM's bits naming.
> 
> PMC_CNTRL_LATCHWAKE_EN
> 
>>> +#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)
>>> @@ -1922,6 +1933,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);
>>
>> Why it takes so much time to latch the values? Shouldn't some status-bit
>> be polled for the completion of latching?
>>
>> Is this register-write really getting buffered in the PMC?
>>
>>> +	value &= ~PMC_CNTRL_LATCH_WAKEUPS;
>>> +	tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>> +	udelay(120);
>>
>> 120 usecs to remove latching, really?
>>
>>> +	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);
>>
>> Why the latching is done *before* writing into the WAKE registers? What
>> it is latching then?
> 
> I'm looking at the TRM doc and it says that latching should be done
> *after* writing to the WAKE_MASK / LEVEL registers.
> 
> Secondly it says that it's enough to do:
> 
> value = tegra_pmc_readl(pmc, PMC_CNTRL);
> value |= PMC_CNTRL_LATCH_WAKEUPS;
> tegra_pmc_writel(pmc, value, PMC_CNTRL);
> 
> in order to latch. There is no need for the delay and to remove the
> "LATCHWAKE_EN" bit, it should be a oneshot action.

Although, no. TRM says "stops latching on transition from 1
to 0 (sequence - set to 1,set to 0)", so it's not a oneshot action.

Have you tested this code at all? I'm wondering how it happens to work
without a proper latching.

>>> +	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);
>>> @@ -1954,6 +2014,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);
>>
>> Shouldn't the WAKE_LEVEL be latched as well?
>>
>>> +	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);
>>> @@ -2540,6 +2643,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,
>>> @@ -2557,10 +2664,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)					     \
>>>
>>
> 


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

* Re: [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210
  2019-07-23  1:41       ` Dmitry Osipenko
@ 2019-07-23  1:52         ` Dmitry Osipenko
  2019-07-23  2:10           ` Dmitry Osipenko
       [not found]         ` <71a88a9c-a542-557a-0eaa-3c90112dee0e@nvidia.com>
  1 sibling, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-23  1:52 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

23.07.2019 4:41, Dmitry Osipenko пишет:
> 23.07.2019 4:08, Dmitry Osipenko пишет:
>> 23.07.2019 3:58, Dmitry Osipenko пишет:
>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>> 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 91c84d0e66ae..c556f38874e1 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)
>>
>> Please follow the TRM's bits naming.
>>
>> PMC_CNTRL_LATCHWAKE_EN
>>
>>>> +#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)
>>>> @@ -1922,6 +1933,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);
>>>
>>> Why it takes so much time to latch the values? Shouldn't some status-bit
>>> be polled for the completion of latching?
>>>
>>> Is this register-write really getting buffered in the PMC?
>>>
>>>> +	value &= ~PMC_CNTRL_LATCH_WAKEUPS;
>>>> +	tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>> +	udelay(120);
>>>
>>> 120 usecs to remove latching, really?
>>>
>>>> +	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);
>>>
>>> Why the latching is done *before* writing into the WAKE registers? What
>>> it is latching then?
>>
>> I'm looking at the TRM doc and it says that latching should be done
>> *after* writing to the WAKE_MASK / LEVEL registers.
>>
>> Secondly it says that it's enough to do:
>>
>> value = tegra_pmc_readl(pmc, PMC_CNTRL);
>> value |= PMC_CNTRL_LATCH_WAKEUPS;
>> tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>
>> in order to latch. There is no need for the delay and to remove the
>> "LATCHWAKE_EN" bit, it should be a oneshot action.
> 
> Although, no. TRM says "stops latching on transition from 1
> to 0 (sequence - set to 1,set to 0)", so it's not a oneshot action.
> 
> Have you tested this code at all? I'm wondering how it happens to work
> without a proper latching.

Okay, I re-read the TRM and apparently "latching" just means storing of
WAKE-event bit in the WAKE-status register if latching is enabled. Hence
the PMC_CNTRL_LATCHWAKE_EN should be enabled in tegra_pmc_suspend() and
unset in tegra_pmc_resume().

Also, apparently, on resume from suspend the interrupt should be
re-triggered in accordance to the WAKE-status, then the WAKE-status need
to be cleared.

>>>> +	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);
>>>> @@ -1954,6 +2014,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);
>>>
>>> Shouldn't the WAKE_LEVEL be latched as well?
>>>
>>>> +	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);
>>>> @@ -2540,6 +2643,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,
>>>> @@ -2557,10 +2664,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)					     \
>>>>
>>>
>>
> 


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

* Re: [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210
  2019-07-23  1:52         ` Dmitry Osipenko
@ 2019-07-23  2:10           ` Dmitry Osipenko
  0 siblings, 0 replies; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-23  2:10 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

23.07.2019 4:52, Dmitry Osipenko пишет:
> 23.07.2019 4:41, Dmitry Osipenko пишет:
>> 23.07.2019 4:08, Dmitry Osipenko пишет:
>>> 23.07.2019 3:58, Dmitry Osipenko пишет:
>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>>> 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 91c84d0e66ae..c556f38874e1 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)
>>>
>>> Please follow the TRM's bits naming.
>>>
>>> PMC_CNTRL_LATCHWAKE_EN
>>>
>>>>> +#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)
>>>>> @@ -1922,6 +1933,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);
>>>>
>>>> Why it takes so much time to latch the values? Shouldn't some status-bit
>>>> be polled for the completion of latching?
>>>>
>>>> Is this register-write really getting buffered in the PMC?
>>>>
>>>>> +	value &= ~PMC_CNTRL_LATCH_WAKEUPS;
>>>>> +	tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>>> +	udelay(120);
>>>>
>>>> 120 usecs to remove latching, really?
>>>>
>>>>> +	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);
>>>>
>>>> Why the latching is done *before* writing into the WAKE registers? What
>>>> it is latching then?
>>>
>>> I'm looking at the TRM doc and it says that latching should be done
>>> *after* writing to the WAKE_MASK / LEVEL registers.
>>>
>>> Secondly it says that it's enough to do:
>>>
>>> value = tegra_pmc_readl(pmc, PMC_CNTRL);
>>> value |= PMC_CNTRL_LATCH_WAKEUPS;
>>> tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>
>>> in order to latch. There is no need for the delay and to remove the
>>> "LATCHWAKE_EN" bit, it should be a oneshot action.
>>
>> Although, no. TRM says "stops latching on transition from 1
>> to 0 (sequence - set to 1,set to 0)", so it's not a oneshot action.
>>
>> Have you tested this code at all? I'm wondering how it happens to work
>> without a proper latching.
> 
> Okay, I re-read the TRM and apparently "latching" just means storing of
> WAKE-event bit in the WAKE-status register if latching is enabled. Hence
> the PMC_CNTRL_LATCHWAKE_EN should be enabled in tegra_pmc_suspend() and
> unset in tegra_pmc_resume().
> 
> Also, apparently, on resume from suspend the interrupt should be
> re-triggered in accordance to the WAKE-status, then the WAKE-status need
> to be cleared.

I'm now also recalling that downstream kernel had some problems in
regards to missing power-button presses on resume from suspend because
input driver reads the GPIO-key state in order to determine the press
status and the GPIO state in already unset at the time when input driver
resumes. Hence it happened sometime that after pressing power button,
device waked up from LP0 and then immediately went into suspend (due to
android's wakelocks).

>>>>> +	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);
>>>>> @@ -1954,6 +2014,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);
>>>>
>>>> Shouldn't the WAKE_LEVEL be latched as well?
>>>>
>>>>> +	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);
>>>>> @@ -2540,6 +2643,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,
>>>>> @@ -2557,10 +2664,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)					     \
>>>>>
>>>>
>>>
>>
> 


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

* Re: [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210
       [not found]         ` <71a88a9c-a542-557a-0eaa-3c90112dee0e@nvidia.com>
@ 2019-07-23  3:03           ` Dmitry Osipenko
  2019-07-23  3:09             ` Sowjanya Komatineni
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-23  3:03 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

23.07.2019 4:52, Sowjanya Komatineni пишет:
> 
> On 7/22/19 6:41 PM, Dmitry Osipenko wrote:
>> 23.07.2019 4:08, Dmitry Osipenko пишет:
>>> 23.07.2019 3:58, Dmitry Osipenko пишет:
>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>>> 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 91c84d0e66ae..c556f38874e1 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)
>>> Please follow the TRM's bits naming.
>>>
>>> PMC_CNTRL_LATCHWAKE_EN
>>>
>>>>> +#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)
>>>>> @@ -1922,6 +1933,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);
>>>> Why it takes so much time to latch the values? Shouldn't some status-bit
>>>> be polled for the completion of latching?
>>>>
>>>> Is this register-write really getting buffered in the PMC?
>>>>
>>>>> +	value &= ~PMC_CNTRL_LATCH_WAKEUPS;
>>>>> +	tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>>> +	udelay(120);
>>>> 120 usecs to remove latching, really?
>>>>
>>>>> +	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);
>>>> Why the latching is done *before* writing into the WAKE registers? What
>>>> it is latching then?
>>> I'm looking at the TRM doc and it says that latching should be done
>>> *after* writing to the WAKE_MASK / LEVEL registers.
>>>
>>> Secondly it says that it's enough to do:
>>>
>>> value = tegra_pmc_readl(pmc, PMC_CNTRL);
>>> value |= PMC_CNTRL_LATCH_WAKEUPS;
>>> tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>
>>> in order to latch. There is no need for the delay and to remove the
>>> "LATCHWAKE_EN" bit, it should be a oneshot action.
>> Although, no. TRM says "stops latching on transition from 1
>> to 0 (sequence - set to 1,set to 0)", so it's not a oneshot action.
>>
>> Have you tested this code at all? I'm wondering how it happens to work
>> without a proper latching.
> Yes, ofcourse its tested and this sequence to do transition is
> recommendation from Tegra designer.
> Will check if TRM doesn't have update properly or will re-confirm
> internally on delay time...
> 
> On any of the wake event PMC wakeup happens and WAKE_STATUS register
> will have bits set for all events that triggered wake.
> After wakeup PMC doesn't update SW_WAKE_STATUS register as per PMC design.
> SW latch register added in design helps to provide a way to capture
> those events that happen right during wakeup time and didnt make it to
> SW_WAKE_STATUS register.
> So before next suspend entry, latching all prior wake events into SW
> WAKE_STATUS and then clearing them.

I'm now wondering whether the latching cold be turned ON permanently
during of the PMC's probe, for simplicity.

> LATCHWAKE_EN - When set, enables latching and stops latching on
> transition from 1 to 0
> There is recommendation of min 120uSec for this transition to stop
> latching. Will double-check why 120uSec

Yes, please check.

>>>>> +	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);
>>>>> @@ -1954,6 +2014,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);
>>>> Shouldn't the WAKE_LEVEL be latched as well?
> WAKE_LEVELs dont need any latch as they are the levels SW sets for wake
> trigger and they are not status

Okay.

[snip]

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

* Re: [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210
  2019-07-23  3:03           ` Dmitry Osipenko
@ 2019-07-23  3:09             ` Sowjanya Komatineni
  2019-07-23  3:25               ` Dmitry Osipenko
  0 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-23  3:09 UTC (permalink / raw)
  To: Dmitry Osipenko, 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


On 7/22/19 8:03 PM, Dmitry Osipenko wrote:
> 23.07.2019 4:52, Sowjanya Komatineni пишет:
>> On 7/22/19 6:41 PM, Dmitry Osipenko wrote:
>>> 23.07.2019 4:08, Dmitry Osipenko пишет:
>>>> 23.07.2019 3:58, Dmitry Osipenko пишет:
>>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>>>> 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 91c84d0e66ae..c556f38874e1 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)
>>>> Please follow the TRM's bits naming.
>>>>
>>>> PMC_CNTRL_LATCHWAKE_EN
>>>>
>>>>>> +#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)
>>>>>> @@ -1922,6 +1933,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);
>>>>> Why it takes so much time to latch the values? Shouldn't some status-bit
>>>>> be polled for the completion of latching?
>>>>>
>>>>> Is this register-write really getting buffered in the PMC?
>>>>>
>>>>>> +	value &= ~PMC_CNTRL_LATCH_WAKEUPS;
>>>>>> +	tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>>>> +	udelay(120);
>>>>> 120 usecs to remove latching, really?
>>>>>
>>>>>> +	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);
>>>>> Why the latching is done *before* writing into the WAKE registers? What
>>>>> it is latching then?
>>>> I'm looking at the TRM doc and it says that latching should be done
>>>> *after* writing to the WAKE_MASK / LEVEL registers.
>>>>
>>>> Secondly it says that it's enough to do:
>>>>
>>>> value = tegra_pmc_readl(pmc, PMC_CNTRL);
>>>> value |= PMC_CNTRL_LATCH_WAKEUPS;
>>>> tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>>
>>>> in order to latch. There is no need for the delay and to remove the
>>>> "LATCHWAKE_EN" bit, it should be a oneshot action.
>>> Although, no. TRM says "stops latching on transition from 1
>>> to 0 (sequence - set to 1,set to 0)", so it's not a oneshot action.
>>>
>>> Have you tested this code at all? I'm wondering how it happens to work
>>> without a proper latching.
>> Yes, ofcourse its tested and this sequence to do transition is
>> recommendation from Tegra designer.
>> Will check if TRM doesn't have update properly or will re-confirm
>> internally on delay time...
>>
>> On any of the wake event PMC wakeup happens and WAKE_STATUS register
>> will have bits set for all events that triggered wake.
>> After wakeup PMC doesn't update SW_WAKE_STATUS register as per PMC design.
>> SW latch register added in design helps to provide a way to capture
>> those events that happen right during wakeup time and didnt make it to
>> SW_WAKE_STATUS register.
>> So before next suspend entry, latching all prior wake events into SW
>> WAKE_STATUS and then clearing them.
> I'm now wondering whether the latching cold be turned ON permanently
> during of the PMC's probe, for simplicity.
latching should be done on suspend-resume cycle as wake events gets 
generates on every suspend-resume cycle.
>> LATCHWAKE_EN - When set, enables latching and stops latching on
>> transition from 1 to 0
>> There is recommendation of min 120uSec for this transition to stop
>> latching. Will double-check why 120uSec
> Yes, please check.
>
>>>>>> +	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);
>>>>>> @@ -1954,6 +2014,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);
>>>>> Shouldn't the WAKE_LEVEL be latched as well?
>> WAKE_LEVELs dont need any latch as they are the levels SW sets for wake
>> trigger and they are not status
> Okay.
>
> [snip]

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

* Re: [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210
  2019-07-23  3:09             ` Sowjanya Komatineni
@ 2019-07-23  3:25               ` Dmitry Osipenko
  2019-07-23  3:31                 ` Sowjanya Komatineni
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-23  3:25 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

23.07.2019 6:09, Sowjanya Komatineni пишет:
> 
> On 7/22/19 8:03 PM, Dmitry Osipenko wrote:
>> 23.07.2019 4:52, Sowjanya Komatineni пишет:
>>> On 7/22/19 6:41 PM, Dmitry Osipenko wrote:
>>>> 23.07.2019 4:08, Dmitry Osipenko пишет:
>>>>> 23.07.2019 3:58, Dmitry Osipenko пишет:
>>>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>>>>> 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 91c84d0e66ae..c556f38874e1 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)
>>>>> Please follow the TRM's bits naming.
>>>>>
>>>>> PMC_CNTRL_LATCHWAKE_EN
>>>>>
>>>>>>> +#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)
>>>>>>> @@ -1922,6 +1933,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);
>>>>>> Why it takes so much time to latch the values? Shouldn't some
>>>>>> status-bit
>>>>>> be polled for the completion of latching?
>>>>>>
>>>>>> Is this register-write really getting buffered in the PMC?
>>>>>>
>>>>>>> +    value &= ~PMC_CNTRL_LATCH_WAKEUPS;
>>>>>>> +    tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>>>>> +    udelay(120);
>>>>>> 120 usecs to remove latching, really?
>>>>>>
>>>>>>> +    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);
>>>>>> Why the latching is done *before* writing into the WAKE registers?
>>>>>> What
>>>>>> it is latching then?
>>>>> I'm looking at the TRM doc and it says that latching should be done
>>>>> *after* writing to the WAKE_MASK / LEVEL registers.
>>>>>
>>>>> Secondly it says that it's enough to do:
>>>>>
>>>>> value = tegra_pmc_readl(pmc, PMC_CNTRL);
>>>>> value |= PMC_CNTRL_LATCH_WAKEUPS;
>>>>> tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>>>
>>>>> in order to latch. There is no need for the delay and to remove the
>>>>> "LATCHWAKE_EN" bit, it should be a oneshot action.
>>>> Although, no. TRM says "stops latching on transition from 1
>>>> to 0 (sequence - set to 1,set to 0)", so it's not a oneshot action.
>>>>
>>>> Have you tested this code at all? I'm wondering how it happens to work
>>>> without a proper latching.
>>> Yes, ofcourse its tested and this sequence to do transition is
>>> recommendation from Tegra designer.
>>> Will check if TRM doesn't have update properly or will re-confirm
>>> internally on delay time...
>>>
>>> On any of the wake event PMC wakeup happens and WAKE_STATUS register
>>> will have bits set for all events that triggered wake.
>>> After wakeup PMC doesn't update SW_WAKE_STATUS register as per PMC
>>> design.
>>> SW latch register added in design helps to provide a way to capture
>>> those events that happen right during wakeup time and didnt make it to
>>> SW_WAKE_STATUS register.
>>> So before next suspend entry, latching all prior wake events into SW
>>> WAKE_STATUS and then clearing them.
>> I'm now wondering whether the latching cold be turned ON permanently
>> during of the PMC's probe, for simplicity.
> latching should be done on suspend-resume cycle as wake events gets
> generates on every suspend-resume cycle.

You're saying that PMC "doesn't update SW_WAKE_STATUS" after wake-up,
then I don't quite understand what's the point of disabling the latching
at all.

>>> LATCHWAKE_EN - When set, enables latching and stops latching on
>>> transition from 1 to 0
>>> There is recommendation of min 120uSec for this transition to stop
>>> latching. Will double-check why 120uSec
>> Yes, please check.
>>
>>>>>>> +    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);
>>>>>>> @@ -1954,6 +2014,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);
>>>>>> Shouldn't the WAKE_LEVEL be latched as well?
>>> WAKE_LEVELs dont need any latch as they are the levels SW sets for wake
>>> trigger and they are not status
>> Okay.
>>
>> [snip]


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

* Re: [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210
  2019-07-23  3:25               ` Dmitry Osipenko
@ 2019-07-23  3:31                 ` Sowjanya Komatineni
  2019-07-23  3:43                   ` Dmitry Osipenko
  0 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-23  3:31 UTC (permalink / raw)
  To: Dmitry Osipenko, 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


On 7/22/19 8:25 PM, Dmitry Osipenko wrote:
> 23.07.2019 6:09, Sowjanya Komatineni пишет:
>> On 7/22/19 8:03 PM, Dmitry Osipenko wrote:
>>> 23.07.2019 4:52, Sowjanya Komatineni пишет:
>>>> On 7/22/19 6:41 PM, Dmitry Osipenko wrote:
>>>>> 23.07.2019 4:08, Dmitry Osipenko пишет:
>>>>>> 23.07.2019 3:58, Dmitry Osipenko пишет:
>>>>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>>>>>> 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 91c84d0e66ae..c556f38874e1 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)
>>>>>> Please follow the TRM's bits naming.
>>>>>>
>>>>>> PMC_CNTRL_LATCHWAKE_EN
>>>>>>
>>>>>>>> +#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)
>>>>>>>> @@ -1922,6 +1933,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);
>>>>>>> Why it takes so much time to latch the values? Shouldn't some
>>>>>>> status-bit
>>>>>>> be polled for the completion of latching?
>>>>>>>
>>>>>>> Is this register-write really getting buffered in the PMC?
>>>>>>>
>>>>>>>> +    value &= ~PMC_CNTRL_LATCH_WAKEUPS;
>>>>>>>> +    tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>>>>>> +    udelay(120);
>>>>>>> 120 usecs to remove latching, really?
>>>>>>>
>>>>>>>> +    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);
>>>>>>> Why the latching is done *before* writing into the WAKE registers?
>>>>>>> What
>>>>>>> it is latching then?
>>>>>> I'm looking at the TRM doc and it says that latching should be done
>>>>>> *after* writing to the WAKE_MASK / LEVEL registers.
>>>>>>
>>>>>> Secondly it says that it's enough to do:
>>>>>>
>>>>>> value = tegra_pmc_readl(pmc, PMC_CNTRL);
>>>>>> value |= PMC_CNTRL_LATCH_WAKEUPS;
>>>>>> tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>>>>
>>>>>> in order to latch. There is no need for the delay and to remove the
>>>>>> "LATCHWAKE_EN" bit, it should be a oneshot action.
>>>>> Although, no. TRM says "stops latching on transition from 1
>>>>> to 0 (sequence - set to 1,set to 0)", so it's not a oneshot action.
>>>>>
>>>>> Have you tested this code at all? I'm wondering how it happens to work
>>>>> without a proper latching.
>>>> Yes, ofcourse its tested and this sequence to do transition is
>>>> recommendation from Tegra designer.
>>>> Will check if TRM doesn't have update properly or will re-confirm
>>>> internally on delay time...
>>>>
>>>> On any of the wake event PMC wakeup happens and WAKE_STATUS register
>>>> will have bits set for all events that triggered wake.
>>>> After wakeup PMC doesn't update SW_WAKE_STATUS register as per PMC
>>>> design.
>>>> SW latch register added in design helps to provide a way to capture
>>>> those events that happen right during wakeup time and didnt make it to
>>>> SW_WAKE_STATUS register.
>>>> So before next suspend entry, latching all prior wake events into SW
>>>> WAKE_STATUS and then clearing them.
>>> I'm now wondering whether the latching cold be turned ON permanently
>>> during of the PMC's probe, for simplicity.
>> latching should be done on suspend-resume cycle as wake events gets
>> generates on every suspend-resume cycle.
> You're saying that PMC "doesn't update SW_WAKE_STATUS" after wake-up,
> then I don't quite understand what's the point of disabling the latching
> at all.
When latch wake enable is set, events are latched and during 1 to 0 
transition latching is disabled.

This is to avoid sw_wake_status and wake_status showing diff events.

Currently driver is not relying on SW_WAKE_STATUS but its good to latch 
and clear so even at some point for some reason when SW_WAKE_STATUS is 
used, this wlil not cause mismatch with wake_status.

>>>> LATCHWAKE_EN - When set, enables latching and stops latching on
>>>> transition from 1 to 0
>>>> There is recommendation of min 120uSec for this transition to stop
>>>> latching. Will double-check why 120uSec
>>> Yes, please check.
>>>
>>>>>>>> +    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);
>>>>>>>> @@ -1954,6 +2014,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);
>>>>>>> Shouldn't the WAKE_LEVEL be latched as well?
>>>> WAKE_LEVELs dont need any latch as they are the levels SW sets for wake
>>>> trigger and they are not status
>>> Okay.
>>>
>>> [snip]

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

* Re: [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210
  2019-07-23  3:31                 ` Sowjanya Komatineni
@ 2019-07-23  3:43                   ` Dmitry Osipenko
  2019-07-23 14:27                     ` Dmitry Osipenko
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-23  3:43 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

23.07.2019 6:31, Sowjanya Komatineni пишет:
> 
> On 7/22/19 8:25 PM, Dmitry Osipenko wrote:
>> 23.07.2019 6:09, Sowjanya Komatineni пишет:
>>> On 7/22/19 8:03 PM, Dmitry Osipenko wrote:
>>>> 23.07.2019 4:52, Sowjanya Komatineni пишет:
>>>>> On 7/22/19 6:41 PM, Dmitry Osipenko wrote:
>>>>>> 23.07.2019 4:08, Dmitry Osipenko пишет:
>>>>>>> 23.07.2019 3:58, Dmitry Osipenko пишет:
>>>>>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>>>>>>> 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 91c84d0e66ae..c556f38874e1 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)
>>>>>>> Please follow the TRM's bits naming.
>>>>>>>
>>>>>>> PMC_CNTRL_LATCHWAKE_EN
>>>>>>>
>>>>>>>>> +#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)
>>>>>>>>> @@ -1922,6 +1933,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);
>>>>>>>> Why it takes so much time to latch the values? Shouldn't some
>>>>>>>> status-bit
>>>>>>>> be polled for the completion of latching?
>>>>>>>>
>>>>>>>> Is this register-write really getting buffered in the PMC?
>>>>>>>>
>>>>>>>>> +    value &= ~PMC_CNTRL_LATCH_WAKEUPS;
>>>>>>>>> +    tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>>>>>>> +    udelay(120);
>>>>>>>> 120 usecs to remove latching, really?
>>>>>>>>
>>>>>>>>> +    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);
>>>>>>>> Why the latching is done *before* writing into the WAKE registers?
>>>>>>>> What
>>>>>>>> it is latching then?
>>>>>>> I'm looking at the TRM doc and it says that latching should be done
>>>>>>> *after* writing to the WAKE_MASK / LEVEL registers.
>>>>>>>
>>>>>>> Secondly it says that it's enough to do:
>>>>>>>
>>>>>>> value = tegra_pmc_readl(pmc, PMC_CNTRL);
>>>>>>> value |= PMC_CNTRL_LATCH_WAKEUPS;
>>>>>>> tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>>>>>
>>>>>>> in order to latch. There is no need for the delay and to remove the
>>>>>>> "LATCHWAKE_EN" bit, it should be a oneshot action.
>>>>>> Although, no. TRM says "stops latching on transition from 1
>>>>>> to 0 (sequence - set to 1,set to 0)", so it's not a oneshot action.
>>>>>>
>>>>>> Have you tested this code at all? I'm wondering how it happens to
>>>>>> work
>>>>>> without a proper latching.
>>>>> Yes, ofcourse its tested and this sequence to do transition is
>>>>> recommendation from Tegra designer.
>>>>> Will check if TRM doesn't have update properly or will re-confirm
>>>>> internally on delay time...
>>>>>
>>>>> On any of the wake event PMC wakeup happens and WAKE_STATUS register
>>>>> will have bits set for all events that triggered wake.
>>>>> After wakeup PMC doesn't update SW_WAKE_STATUS register as per PMC
>>>>> design.
>>>>> SW latch register added in design helps to provide a way to capture
>>>>> those events that happen right during wakeup time and didnt make it to
>>>>> SW_WAKE_STATUS register.
>>>>> So before next suspend entry, latching all prior wake events into SW
>>>>> WAKE_STATUS and then clearing them.
>>>> I'm now wondering whether the latching cold be turned ON permanently
>>>> during of the PMC's probe, for simplicity.
>>> latching should be done on suspend-resume cycle as wake events gets
>>> generates on every suspend-resume cycle.
>> You're saying that PMC "doesn't update SW_WAKE_STATUS" after wake-up,
>> then I don't quite understand what's the point of disabling the latching
>> at all.
> When latch wake enable is set, events are latched and during 1 to 0
> transition latching is disabled.
> 
> This is to avoid sw_wake_status and wake_status showing diff events.

Okay.

> Currently driver is not relying on SW_WAKE_STATUS but its good to latch
> and clear so even at some point for some reason when SW_WAKE_STATUS is
> used, this wlil not cause mismatch with wake_status.

Then the latching need to be enabled on suspend and disabled early on
resume to get a proper WAKE status.

[snip]


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

* Re: [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210
  2019-07-23  3:43                   ` Dmitry Osipenko
@ 2019-07-23 14:27                     ` Dmitry Osipenko
  2019-07-23 23:39                       ` Sowjanya Komatineni
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-23 14:27 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

23.07.2019 6:43, Dmitry Osipenko пишет:
> 23.07.2019 6:31, Sowjanya Komatineni пишет:
>>
>> On 7/22/19 8:25 PM, Dmitry Osipenko wrote:
>>> 23.07.2019 6:09, Sowjanya Komatineni пишет:
>>>> On 7/22/19 8:03 PM, Dmitry Osipenko wrote:
>>>>> 23.07.2019 4:52, Sowjanya Komatineni пишет:
>>>>>> On 7/22/19 6:41 PM, Dmitry Osipenko wrote:
>>>>>>> 23.07.2019 4:08, Dmitry Osipenko пишет:
>>>>>>>> 23.07.2019 3:58, Dmitry Osipenko пишет:
>>>>>>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>>>>>>>> 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 91c84d0e66ae..c556f38874e1 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)
>>>>>>>> Please follow the TRM's bits naming.
>>>>>>>>
>>>>>>>> PMC_CNTRL_LATCHWAKE_EN
>>>>>>>>
>>>>>>>>>> +#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)
>>>>>>>>>> @@ -1922,6 +1933,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);
>>>>>>>>> Why it takes so much time to latch the values? Shouldn't some
>>>>>>>>> status-bit
>>>>>>>>> be polled for the completion of latching?
>>>>>>>>>
>>>>>>>>> Is this register-write really getting buffered in the PMC?
>>>>>>>>>
>>>>>>>>>> +    value &= ~PMC_CNTRL_LATCH_WAKEUPS;
>>>>>>>>>> +    tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>>>>>>>> +    udelay(120);
>>>>>>>>> 120 usecs to remove latching, really?
>>>>>>>>>
>>>>>>>>>> +    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);
>>>>>>>>> Why the latching is done *before* writing into the WAKE registers?
>>>>>>>>> What
>>>>>>>>> it is latching then?
>>>>>>>> I'm looking at the TRM doc and it says that latching should be done
>>>>>>>> *after* writing to the WAKE_MASK / LEVEL registers.
>>>>>>>>
>>>>>>>> Secondly it says that it's enough to do:
>>>>>>>>
>>>>>>>> value = tegra_pmc_readl(pmc, PMC_CNTRL);
>>>>>>>> value |= PMC_CNTRL_LATCH_WAKEUPS;
>>>>>>>> tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>>>>>>
>>>>>>>> in order to latch. There is no need for the delay and to remove the
>>>>>>>> "LATCHWAKE_EN" bit, it should be a oneshot action.
>>>>>>> Although, no. TRM says "stops latching on transition from 1
>>>>>>> to 0 (sequence - set to 1,set to 0)", so it's not a oneshot action.
>>>>>>>
>>>>>>> Have you tested this code at all? I'm wondering how it happens to
>>>>>>> work
>>>>>>> without a proper latching.
>>>>>> Yes, ofcourse its tested and this sequence to do transition is
>>>>>> recommendation from Tegra designer.
>>>>>> Will check if TRM doesn't have update properly or will re-confirm
>>>>>> internally on delay time...
>>>>>>
>>>>>> On any of the wake event PMC wakeup happens and WAKE_STATUS register
>>>>>> will have bits set for all events that triggered wake.
>>>>>> After wakeup PMC doesn't update SW_WAKE_STATUS register as per PMC
>>>>>> design.
>>>>>> SW latch register added in design helps to provide a way to capture
>>>>>> those events that happen right during wakeup time and didnt make it to
>>>>>> SW_WAKE_STATUS register.
>>>>>> So before next suspend entry, latching all prior wake events into SW
>>>>>> WAKE_STATUS and then clearing them.
>>>>> I'm now wondering whether the latching cold be turned ON permanently
>>>>> during of the PMC's probe, for simplicity.
>>>> latching should be done on suspend-resume cycle as wake events gets
>>>> generates on every suspend-resume cycle.
>>> You're saying that PMC "doesn't update SW_WAKE_STATUS" after wake-up,
>>> then I don't quite understand what's the point of disabling the latching
>>> at all.
>> When latch wake enable is set, events are latched and during 1 to 0
>> transition latching is disabled.
>>
>> This is to avoid sw_wake_status and wake_status showing diff events.
> 
> Okay.
> 
>> Currently driver is not relying on SW_WAKE_STATUS but its good to latch
>> and clear so even at some point for some reason when SW_WAKE_STATUS is
>> used, this wlil not cause mismatch with wake_status.
> 
> Then the latching need to be enabled on suspend and disabled early on
> resume to get a proper WAKE status.

Actually, it will be better to simply not implement the latching until
it will become really needed. In general you shouldn't add into the
patchset anything that is unused.

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

* Re: [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210
  2019-07-23 14:27                     ` Dmitry Osipenko
@ 2019-07-23 23:39                       ` Sowjanya Komatineni
  2019-07-24  9:31                         ` Dmitry Osipenko
  0 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-23 23:39 UTC (permalink / raw)
  To: Dmitry Osipenko, 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


On 7/23/19 7:27 AM, Dmitry Osipenko wrote:
> 23.07.2019 6:43, Dmitry Osipenko пишет:
>> 23.07.2019 6:31, Sowjanya Komatineni пишет:
>>> On 7/22/19 8:25 PM, Dmitry Osipenko wrote:
>>>> 23.07.2019 6:09, Sowjanya Komatineni пишет:
>>>>> On 7/22/19 8:03 PM, Dmitry Osipenko wrote:
>>>>>> 23.07.2019 4:52, Sowjanya Komatineni пишет:
>>>>>>> On 7/22/19 6:41 PM, Dmitry Osipenko wrote:
>>>>>>>> 23.07.2019 4:08, Dmitry Osipenko пишет:
>>>>>>>>> 23.07.2019 3:58, Dmitry Osipenko пишет:
>>>>>>>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>>>>>>>>> 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 91c84d0e66ae..c556f38874e1 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)
>>>>>>>>> Please follow the TRM's bits naming.
>>>>>>>>>
>>>>>>>>> PMC_CNTRL_LATCHWAKE_EN
>>>>>>>>>
>>>>>>>>>>> +#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)
>>>>>>>>>>> @@ -1922,6 +1933,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);
>>>>>>>>>> Why it takes so much time to latch the values? Shouldn't some
>>>>>>>>>> status-bit
>>>>>>>>>> be polled for the completion of latching?
>>>>>>>>>>
>>>>>>>>>> Is this register-write really getting buffered in the PMC?
>>>>>>>>>>
>>>>>>>>>>> +    value &= ~PMC_CNTRL_LATCH_WAKEUPS;
>>>>>>>>>>> +    tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>>>>>>>>> +    udelay(120);
>>>>>>>>>> 120 usecs to remove latching, really?
>>>>>>>>>>
>>>>>>>>>>> +    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);
>>>>>>>>>> Why the latching is done *before* writing into the WAKE registers?
>>>>>>>>>> What
>>>>>>>>>> it is latching then?
>>>>>>>>> I'm looking at the TRM doc and it says that latching should be done
>>>>>>>>> *after* writing to the WAKE_MASK / LEVEL registers.
>>>>>>>>>
>>>>>>>>> Secondly it says that it's enough to do:
>>>>>>>>>
>>>>>>>>> value = tegra_pmc_readl(pmc, PMC_CNTRL);
>>>>>>>>> value |= PMC_CNTRL_LATCH_WAKEUPS;
>>>>>>>>> tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>>>>>>>
>>>>>>>>> in order to latch. There is no need for the delay and to remove the
>>>>>>>>> "LATCHWAKE_EN" bit, it should be a oneshot action.
>>>>>>>> Although, no. TRM says "stops latching on transition from 1
>>>>>>>> to 0 (sequence - set to 1,set to 0)", so it's not a oneshot action.
>>>>>>>>
>>>>>>>> Have you tested this code at all? I'm wondering how it happens to
>>>>>>>> work
>>>>>>>> without a proper latching.
>>>>>>> Yes, ofcourse its tested and this sequence to do transition is
>>>>>>> recommendation from Tegra designer.
>>>>>>> Will check if TRM doesn't have update properly or will re-confirm
>>>>>>> internally on delay time...
>>>>>>>
>>>>>>> On any of the wake event PMC wakeup happens and WAKE_STATUS register
>>>>>>> will have bits set for all events that triggered wake.
>>>>>>> After wakeup PMC doesn't update SW_WAKE_STATUS register as per PMC
>>>>>>> design.
>>>>>>> SW latch register added in design helps to provide a way to capture
>>>>>>> those events that happen right during wakeup time and didnt make it to
>>>>>>> SW_WAKE_STATUS register.
>>>>>>> So before next suspend entry, latching all prior wake events into SW
>>>>>>> WAKE_STATUS and then clearing them.
>>>>>> I'm now wondering whether the latching cold be turned ON permanently
>>>>>> during of the PMC's probe, for simplicity.
>>>>> latching should be done on suspend-resume cycle as wake events gets
>>>>> generates on every suspend-resume cycle.
>>>> You're saying that PMC "doesn't update SW_WAKE_STATUS" after wake-up,
>>>> then I don't quite understand what's the point of disabling the latching
>>>> at all.
>>> When latch wake enable is set, events are latched and during 1 to 0
>>> transition latching is disabled.
>>>
>>> This is to avoid sw_wake_status and wake_status showing diff events.
>> Okay.
>>
>>> Currently driver is not relying on SW_WAKE_STATUS but its good to latch
>>> and clear so even at some point for some reason when SW_WAKE_STATUS is
>>> used, this wlil not cause mismatch with wake_status.
>> Then the latching need to be enabled on suspend and disabled early on
>> resume to get a proper WAKE status.
> Actually, it will be better to simply not implement the latching until
> it will become really needed. In general you shouldn't add into the
> patchset anything that is unused.

OK, will remove latch_wake for now.

Will send next version once I get all the review feedback ..


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

* Re: [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210
  2019-07-23 23:39                       ` Sowjanya Komatineni
@ 2019-07-24  9:31                         ` Dmitry Osipenko
  0 siblings, 0 replies; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-24  9:31 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

24.07.2019 2:39, Sowjanya Komatineni пишет:
> 
> On 7/23/19 7:27 AM, Dmitry Osipenko wrote:
>> 23.07.2019 6:43, Dmitry Osipenko пишет:
>>> 23.07.2019 6:31, Sowjanya Komatineni пишет:
>>>> On 7/22/19 8:25 PM, Dmitry Osipenko wrote:
>>>>> 23.07.2019 6:09, Sowjanya Komatineni пишет:
>>>>>> On 7/22/19 8:03 PM, Dmitry Osipenko wrote:
>>>>>>> 23.07.2019 4:52, Sowjanya Komatineni пишет:
>>>>>>>> On 7/22/19 6:41 PM, Dmitry Osipenko wrote:
>>>>>>>>> 23.07.2019 4:08, Dmitry Osipenko пишет:
>>>>>>>>>> 23.07.2019 3:58, Dmitry Osipenko пишет:
>>>>>>>>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>>>>>>>>>> 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 91c84d0e66ae..c556f38874e1 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)
>>>>>>>>>> Please follow the TRM's bits naming.
>>>>>>>>>>
>>>>>>>>>> PMC_CNTRL_LATCHWAKE_EN
>>>>>>>>>>
>>>>>>>>>>>> +#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)
>>>>>>>>>>>> @@ -1922,6 +1933,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);
>>>>>>>>>>> Why it takes so much time to latch the values? Shouldn't some
>>>>>>>>>>> status-bit
>>>>>>>>>>> be polled for the completion of latching?
>>>>>>>>>>>
>>>>>>>>>>> Is this register-write really getting buffered in the PMC?
>>>>>>>>>>>
>>>>>>>>>>>> +    value &= ~PMC_CNTRL_LATCH_WAKEUPS;
>>>>>>>>>>>> +    tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>>>>>>>>>> +    udelay(120);
>>>>>>>>>>> 120 usecs to remove latching, really?
>>>>>>>>>>>
>>>>>>>>>>>> +    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);
>>>>>>>>>>> Why the latching is done *before* writing into the WAKE
>>>>>>>>>>> registers?
>>>>>>>>>>> What
>>>>>>>>>>> it is latching then?
>>>>>>>>>> I'm looking at the TRM doc and it says that latching should be
>>>>>>>>>> done
>>>>>>>>>> *after* writing to the WAKE_MASK / LEVEL registers.
>>>>>>>>>>
>>>>>>>>>> Secondly it says that it's enough to do:
>>>>>>>>>>
>>>>>>>>>> value = tegra_pmc_readl(pmc, PMC_CNTRL);
>>>>>>>>>> value |= PMC_CNTRL_LATCH_WAKEUPS;
>>>>>>>>>> tegra_pmc_writel(pmc, value, PMC_CNTRL);
>>>>>>>>>>
>>>>>>>>>> in order to latch. There is no need for the delay and to
>>>>>>>>>> remove the
>>>>>>>>>> "LATCHWAKE_EN" bit, it should be a oneshot action.
>>>>>>>>> Although, no. TRM says "stops latching on transition from 1
>>>>>>>>> to 0 (sequence - set to 1,set to 0)", so it's not a oneshot
>>>>>>>>> action.
>>>>>>>>>
>>>>>>>>> Have you tested this code at all? I'm wondering how it happens to
>>>>>>>>> work
>>>>>>>>> without a proper latching.
>>>>>>>> Yes, ofcourse its tested and this sequence to do transition is
>>>>>>>> recommendation from Tegra designer.
>>>>>>>> Will check if TRM doesn't have update properly or will re-confirm
>>>>>>>> internally on delay time...
>>>>>>>>
>>>>>>>> On any of the wake event PMC wakeup happens and WAKE_STATUS
>>>>>>>> register
>>>>>>>> will have bits set for all events that triggered wake.
>>>>>>>> After wakeup PMC doesn't update SW_WAKE_STATUS register as per PMC
>>>>>>>> design.
>>>>>>>> SW latch register added in design helps to provide a way to capture
>>>>>>>> those events that happen right during wakeup time and didnt make
>>>>>>>> it to
>>>>>>>> SW_WAKE_STATUS register.
>>>>>>>> So before next suspend entry, latching all prior wake events
>>>>>>>> into SW
>>>>>>>> WAKE_STATUS and then clearing them.
>>>>>>> I'm now wondering whether the latching cold be turned ON permanently
>>>>>>> during of the PMC's probe, for simplicity.
>>>>>> latching should be done on suspend-resume cycle as wake events gets
>>>>>> generates on every suspend-resume cycle.
>>>>> You're saying that PMC "doesn't update SW_WAKE_STATUS" after wake-up,
>>>>> then I don't quite understand what's the point of disabling the
>>>>> latching
>>>>> at all.
>>>> When latch wake enable is set, events are latched and during 1 to 0
>>>> transition latching is disabled.
>>>>
>>>> This is to avoid sw_wake_status and wake_status showing diff events.
>>> Okay.
>>>
>>>> Currently driver is not relying on SW_WAKE_STATUS but its good to latch
>>>> and clear so even at some point for some reason when SW_WAKE_STATUS is
>>>> used, this wlil not cause mismatch with wake_status.
>>> Then the latching need to be enabled on suspend and disabled early on
>>> resume to get a proper WAKE status.
>> Actually, it will be better to simply not implement the latching until
>> it will become really needed. In general you shouldn't add into the
>> patchset anything that is unused.
> 
> OK, will remove latch_wake for now.
> 
> Will send next version once I get all the review feedback ..
> 

That's not a bad idea. Wait for one-two weeks and if it will happen that
nobody is replying, then just issue a new version.

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

* Re: [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend
  2019-07-22 23:35             ` Dmitry Osipenko
@ 2019-07-24 23:09               ` Sowjanya Komatineni
  2019-07-26  4:48                 ` Dmitry Osipenko
  0 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-07-24 23:09 UTC (permalink / raw)
  To: Dmitry Osipenko, Marc Zyngier
  Cc: thierry.reding, jonathanh, tglx, jason, 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 7/22/19 4:35 PM, Dmitry Osipenko wrote:
> 22.07.2019 21:38, Marc Zyngier пишет:
>> On Mon, 22 Jul 2019 09:21:21 -0700
>> Sowjanya Komatineni <skomatineni@nvidia.com> wrote:
>>
>>> On 7/22/19 3:57 AM, Dmitry Osipenko wrote:
>>>> 22.07.2019 13:13, Marc Zyngier пишет:
>>>>> On 22/07/2019 10:54, Dmitry Osipenko wrote:
>>>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>>>>> 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.
>>>>>>>
>>>>>>> Acked-by: Thierry Reding <treding@nvidia.com>
>>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>>> ---
>>>>>>>    drivers/irqchip/irq-tegra.c | 20 ++++++++++++++++++--
>>>>>>>    1 file changed, 18 insertions(+), 2 deletions(-)
>>>>>>>
>>>>>>> diff --git a/drivers/irqchip/irq-tegra.c b/drivers/irqchip/irq-tegra.c
>>>>>>> index e1f771c72fc4..851f88cef508 100644
>>>>>>> --- a/drivers/irqchip/irq-tegra.c
>>>>>>> +++ b/drivers/irqchip/irq-tegra.c
>>>>>>> @@ -44,6 +44,7 @@ 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 = {
>>>>>>> @@ -56,6 +57,7 @@ static const struct tegra_ictlr_soc tegra30_ictlr_soc = {
>>>>>>>    
>>>>>>>    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 +69,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 +150,20 @@ 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)
>>>>>>> +			/* Disable COP interrupts if SC7 is not supported */
>>>>>> All Tegra SoCs support SC7, hence the 'supports_sc7' and the comment
>>>>>> doesn't sound correct to me. Something like 'firmware_sc7' should suit
>>>>>> better here.
>>>>> If what you're saying is true, then the whole patch is wrong, and the
>>>>> SC7 property should come from DT.
>>>> It should be safe to assume that all of existing Tegra210 devices use
>>>> the firmware for SC7, hence I wouldn't say that the patch is entirely
>>>> wrong. To me it's not entirely correct.
>>> Yes, all existing Tegra210 platforms uses sc7 entry firmware for SC7 and
>>> AVP/COP IRQ need to be kept enabled as during suspend ATF triggers IRQ
>>> to COP for SC7 entry fw execution.
> Okay, as I already wrote before, it looks to me that a more proper
> solution should be to just remove everything related to COP from this
> driver instead of adding custom quirks for T210.
>
> The disabling / restoring of COP interrupts should be relevant only for
> the multimedia firmware on older Tegra SoCs. That firmware won't be ever
> supported in the upstream simply because NVIDIA abandoned the support
> for older hardware in the downstream and because it is not possible due
> to some legal weirdness (IIUC). The only variant for upstream is
> reverse-engineering of hardware (not the firmware BLOB) and writing
> proper opensource drivers for the upstream kernel, which we're already
> doing and have success to a some extent.
>
>> That's not the question. Dmitry says that the SC7 support is not a
>> property of the SoC, but mostly a platform decision on whether the
>> firmware supports SC7 or not.
>>
>> To me, that's a clear indication that this should not be hardcoded in
>> the driver, but instead obtained dynamically, via DT or otherwise.
> We already have an nvidia,suspend-mode property in the device-tree of
> the Power Management Controller node (all Tegra SoCs) which defines what
> suspending type is supported by a particular board.
>
>>>>>>> +			writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
>>>>>> Secondly, I'm also not sure why COP interrupts need to be disabled for
>>>>>> pre-T210 at all, since COP is unused. This looks to me like it was
>>>>>> cut-n-pasted from downstream kernel without a good reason and could be
>>>>>> simply removed.
>>>>> Please verify that this is actually the case. Tegra-2 definitely needed
>>>>> some level of poking, and I'm not keen on changing anything there until
>>>>> you (or someone else) has verified it on actual HW (see e307cc8941fc).
>>>> Tested on Tegra20 and Tegra30, LP1 suspend-resume works perfectly fine
>>>> with all COP bits removed from the driver.
>>>>
>>>> AFAIK, the reason why downstream needed that disabling is that it uses
>>>> proprietary firmware which is running on the COP and that firmware is
>>>> usually a BLOB audio/video DEC-ENC driver which doesn't cleanup
>>>> interrupts after itself. That firmware is not applicable for the
>>>> upstream kernel, hence there is no need to care about it.
>>>>   
>>>>> Joseph, can you please shed some light here?
>>> SC7 entry flow uses 3rd party ATF (arm-trusted FW) blob which is the
>>> one that actually loads SC7 entry firmware and triggers IRQ to
>>> AVP/COP which causes COP to wakeup and run SC7 entry FW.
>>>
>>> So when SC7 support is enabled, IRQ need to be kept enabled and when
>>> SC7 FW starts execution, it will disable COP IRQ.
>> This looks like a lot of undocumented assumptions on what firmware
>> does, as well as what firmware *is*. What I gather from this thread is
>> that there is at least two versions of firmware (a "proprietary
>> firmware" for "downstream kernels", and another one for mainline), and
>> that they do different things.
>>
>> Given that we cannot know what people actually run, I don't think we
>> can safely remove anything unless this gets tested on the full spectrum
>> of HW/FW combination.
> I'm not sure whether multiple firmware variations exist in the wild for
> Tegra210. Maybe Sowjanya or somebody else from NVIDIA could clarify. I
> think there should be some efforts in regards to a fully opensource
> firmware on Tegra210, but I'm not following it and have no idea about
> the status.
>
> You're right that there are multiple variants of suspend-resuming flow
> on Tegra SoCs. The older 32bit Tegra SoC generations have a variety of
> options in regards to suspend-resuming, including firmware-less variants
> on platforms that are having kernel running in secure mode (dev boards,
> most of Tegra20 consumer devices) and Trusted-Foundations firmware
> variant for insecure platforms (consumer devices). And yes, vendor
> firmware creates a lot of headache in regards to bringing support into
> upstream because it usually does a lot of odd undocumented things which
> may also vary depending on a firmware version (bootloader, etc) and it
> also usually difficult to replace it with an opensource alternative due
> to a crypto signing.

Tried without this patch which keeps COP IRQ disabled and I see SC7 
entry FW execution happens still.

Digging through the ATF FW code, I see on SC7 entry firmware loading 
into IRAM, COP processor is reset with RESET VECTOR set to SC7 entry 
firmware location in IRAM and on reset de-assert & unhalt COP, SC7 
firmware starts execution.

Will remove this patch in next version...


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

* Re: [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend
  2019-07-22  9:54   ` Dmitry Osipenko
  2019-07-22 10:13     ` Marc Zyngier
@ 2019-07-25  9:55     ` Peter De Schrijver
  2019-07-25 10:05       ` Dmitry Osipenko
  1 sibling, 1 reply; 84+ messages in thread
From: Peter De Schrijver @ 2019-07-25  9:55 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland, pgaikwad,
	sboyd, linux-clk, linux-gpio, jckuo, josephl, talho, linux-tegra,
	linux-kernel, mperttunen, spatra, robh+dt, devicetree

On Mon, Jul 22, 2019 at 12:54:51PM +0300, Dmitry Osipenko wrote:
> 
> All Tegra SoCs support SC7, hence the 'supports_sc7' and the comment
> doesn't sound correct to me. Something like 'firmware_sc7' should suit
> better here.
> 
> > +			writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
> 
> Secondly, I'm also not sure why COP interrupts need to be disabled for
> pre-T210 at all, since COP is unused. This looks to me like it was
> cut-n-pasted from downstream kernel without a good reason and could be
> simply removed.

I don't think we can rely on the fact that COP is unused. People can
write their own code to run on COP.

Peter.

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

* Re: [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend
  2019-07-25  9:55     ` Peter De Schrijver
@ 2019-07-25 10:05       ` Dmitry Osipenko
  2019-07-25 10:33         ` Peter De Schrijver
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-25 10:05 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland, pgaikwad,
	sboyd, linux-clk, linux-gpio, jckuo, josephl, talho, linux-tegra,
	linux-kernel, mperttunen, spatra, robh+dt, devicetree

25.07.2019 12:55, Peter De Schrijver пишет:
> On Mon, Jul 22, 2019 at 12:54:51PM +0300, Dmitry Osipenko wrote:
>>
>> All Tegra SoCs support SC7, hence the 'supports_sc7' and the comment
>> doesn't sound correct to me. Something like 'firmware_sc7' should suit
>> better here.
>>
>>> +			writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
>>
>> Secondly, I'm also not sure why COP interrupts need to be disabled for
>> pre-T210 at all, since COP is unused. This looks to me like it was
>> cut-n-pasted from downstream kernel without a good reason and could be
>> simply removed.
> 
> I don't think we can rely on the fact that COP is unused. People can
> write their own code to run on COP.

1. Not upstream - doesn't matter.

2. That's not very good if something unknown is running on COP and then
kernel suddenly intervenes, don't you think so?

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

* Re: [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend
  2019-07-25 10:05       ` Dmitry Osipenko
@ 2019-07-25 10:33         ` Peter De Schrijver
  2019-07-25 10:38           ` Peter De Schrijver
  0 siblings, 1 reply; 84+ messages in thread
From: Peter De Schrijver @ 2019-07-25 10:33 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland, pgaikwad,
	sboyd, linux-clk, linux-gpio, jckuo, josephl, talho, linux-tegra,
	linux-kernel, mperttunen, spatra, robh+dt, devicetree

On Thu, Jul 25, 2019 at 01:05:13PM +0300, Dmitry Osipenko wrote:
> 25.07.2019 12:55, Peter De Schrijver пишет:
> > On Mon, Jul 22, 2019 at 12:54:51PM +0300, Dmitry Osipenko wrote:
> >>
> >> All Tegra SoCs support SC7, hence the 'supports_sc7' and the comment
> >> doesn't sound correct to me. Something like 'firmware_sc7' should suit
> >> better here.
> >>
> >>> +			writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
> >>
> >> Secondly, I'm also not sure why COP interrupts need to be disabled for
> >> pre-T210 at all, since COP is unused. This looks to me like it was
> >> cut-n-pasted from downstream kernel without a good reason and could be
> >> simply removed.
> > 
> > I don't think we can rely on the fact that COP is unused. People can
> > write their own code to run on COP.
> 
> 1. Not upstream - doesn't matter.
> 

The code is not part of the kernel, so obviously it's not upstream?

> 2. That's not very good if something unknown is running on COP and then
> kernel suddenly intervenes, don't you think so?

Unless the code was written with this in mind.

Peter.

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

* Re: [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend
  2019-07-25 10:33         ` Peter De Schrijver
@ 2019-07-25 10:38           ` Peter De Schrijver
  2019-07-25 10:59             ` Dmitry Osipenko
  0 siblings, 1 reply; 84+ messages in thread
From: Peter De Schrijver @ 2019-07-25 10:38 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland, pgaikwad,
	sboyd, linux-clk, linux-gpio, jckuo, josephl, talho, linux-tegra,
	linux-kernel, mperttunen, spatra, robh+dt, devicetree

On Thu, Jul 25, 2019 at 01:33:48PM +0300, Peter De Schrijver wrote:
> On Thu, Jul 25, 2019 at 01:05:13PM +0300, Dmitry Osipenko wrote:
> > 25.07.2019 12:55, Peter De Schrijver пишет:
> > > On Mon, Jul 22, 2019 at 12:54:51PM +0300, Dmitry Osipenko wrote:
> > >>
> > >> All Tegra SoCs support SC7, hence the 'supports_sc7' and the comment
> > >> doesn't sound correct to me. Something like 'firmware_sc7' should suit
> > >> better here.
> > >>
> > >>> +			writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
> > >>
> > >> Secondly, I'm also not sure why COP interrupts need to be disabled for
> > >> pre-T210 at all, since COP is unused. This looks to me like it was
> > >> cut-n-pasted from downstream kernel without a good reason and could be
> > >> simply removed.
> > > 
> > > I don't think we can rely on the fact that COP is unused. People can
> > > write their own code to run on COP.
> > 
> > 1. Not upstream - doesn't matter.
> > 
> 
> The code is not part of the kernel, so obviously it's not upstream?
> 
> > 2. That's not very good if something unknown is running on COP and then
> > kernel suddenly intervenes, don't you think so?
> 
> Unless the code was written with this in mind.
> 

Looking at this again, I don't think we need to enable the IRQ at all.

Peter.

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

* Re: [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend
  2019-07-25 10:38           ` Peter De Schrijver
@ 2019-07-25 10:59             ` Dmitry Osipenko
  2019-08-02 13:05               ` Peter De Schrijver
  0 siblings, 1 reply; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-25 10:59 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland, pgaikwad,
	sboyd, linux-clk, linux-gpio, jckuo, josephl, talho, linux-tegra,
	linux-kernel, mperttunen, spatra, robh+dt, devicetree

25.07.2019 13:38, Peter De Schrijver пишет:
> On Thu, Jul 25, 2019 at 01:33:48PM +0300, Peter De Schrijver wrote:
>> On Thu, Jul 25, 2019 at 01:05:13PM +0300, Dmitry Osipenko wrote:
>>> 25.07.2019 12:55, Peter De Schrijver пишет:
>>>> On Mon, Jul 22, 2019 at 12:54:51PM +0300, Dmitry Osipenko wrote:
>>>>>
>>>>> All Tegra SoCs support SC7, hence the 'supports_sc7' and the comment
>>>>> doesn't sound correct to me. Something like 'firmware_sc7' should suit
>>>>> better here.
>>>>>
>>>>>> +			writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
>>>>>
>>>>> Secondly, I'm also not sure why COP interrupts need to be disabled for
>>>>> pre-T210 at all, since COP is unused. This looks to me like it was
>>>>> cut-n-pasted from downstream kernel without a good reason and could be
>>>>> simply removed.
>>>>
>>>> I don't think we can rely on the fact that COP is unused. People can
>>>> write their own code to run on COP.
>>>
>>> 1. Not upstream - doesn't matter.
>>>
>>
>> The code is not part of the kernel, so obviously it's not upstream?
>>
>>> 2. That's not very good if something unknown is running on COP and then
>>> kernel suddenly intervenes, don't you think so?
>>
>> Unless the code was written with this in mind.
>>

In that case, please see 1. ;)

> 
> Looking at this again, I don't think we need to enable the IRQ at all.

Could you please clarify? The code only saves/restores COP's interrupts
context across suspend-resume.

Again, that's absolutely useless code for the upstream kernel which
could be removed safely to avoid the confusion, IMHO. I can type a patch
if you're agreeing.

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

* Re: [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend
  2019-07-24 23:09               ` Sowjanya Komatineni
@ 2019-07-26  4:48                 ` Dmitry Osipenko
  0 siblings, 0 replies; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-26  4:48 UTC (permalink / raw)
  To: Sowjanya Komatineni
  Cc: Marc Zyngier, thierry.reding, jonathanh, tglx, jason,
	linus.walleij, stefan, mark.rutland, pdeschrijver, pgaikwad,
	sboyd, linux-clk, linux-gpio, jckuo, josephl, talho, linux-tegra,
	linux-kernel, mperttunen, spatra, robh+dt, devicetree

В Wed, 24 Jul 2019 16:09:53 -0700
Sowjanya Komatineni <skomatineni@nvidia.com> пишет:

> On 7/22/19 4:35 PM, Dmitry Osipenko wrote:
> > 22.07.2019 21:38, Marc Zyngier пишет:  
> >> On Mon, 22 Jul 2019 09:21:21 -0700
> >> Sowjanya Komatineni <skomatineni@nvidia.com> wrote:
> >>  
> >>> On 7/22/19 3:57 AM, Dmitry Osipenko wrote:  
> >>>> 22.07.2019 13:13, Marc Zyngier пишет:  
> >>>>> On 22/07/2019 10:54, Dmitry Osipenko wrote:  
> >>>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:  
> >>>>>>> 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.
> >>>>>>>
> >>>>>>> Acked-by: Thierry Reding <treding@nvidia.com>
> >>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> >>>>>>> ---
> >>>>>>>    drivers/irqchip/irq-tegra.c | 20 ++++++++++++++++++--
> >>>>>>>    1 file changed, 18 insertions(+), 2 deletions(-)
> >>>>>>>
> >>>>>>> diff --git a/drivers/irqchip/irq-tegra.c
> >>>>>>> b/drivers/irqchip/irq-tegra.c index
> >>>>>>> e1f771c72fc4..851f88cef508 100644 ---
> >>>>>>> a/drivers/irqchip/irq-tegra.c +++
> >>>>>>> b/drivers/irqchip/irq-tegra.c @@ -44,6 +44,7 @@ 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 = {
> >>>>>>> @@ -56,6 +57,7 @@ static const struct tegra_ictlr_soc
> >>>>>>> tegra30_ictlr_soc = { 
> >>>>>>>    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 +69,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 +150,20 @@ 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)
> >>>>>>> +			/* Disable COP interrupts if SC7 is
> >>>>>>> not supported */  
> >>>>>> All Tegra SoCs support SC7, hence the 'supports_sc7' and the
> >>>>>> comment doesn't sound correct to me. Something like
> >>>>>> 'firmware_sc7' should suit better here.  
> >>>>> If what you're saying is true, then the whole patch is wrong,
> >>>>> and the SC7 property should come from DT.  
> >>>> It should be safe to assume that all of existing Tegra210
> >>>> devices use the firmware for SC7, hence I wouldn't say that the
> >>>> patch is entirely wrong. To me it's not entirely correct.  
> >>> Yes, all existing Tegra210 platforms uses sc7 entry firmware for
> >>> SC7 and AVP/COP IRQ need to be kept enabled as during suspend ATF
> >>> triggers IRQ to COP for SC7 entry fw execution.  
> > Okay, as I already wrote before, it looks to me that a more proper
> > solution should be to just remove everything related to COP from
> > this driver instead of adding custom quirks for T210.
> >
> > The disabling / restoring of COP interrupts should be relevant only
> > for the multimedia firmware on older Tegra SoCs. That firmware
> > won't be ever supported in the upstream simply because NVIDIA
> > abandoned the support for older hardware in the downstream and
> > because it is not possible due to some legal weirdness (IIUC). The
> > only variant for upstream is reverse-engineering of hardware (not
> > the firmware BLOB) and writing proper opensource drivers for the
> > upstream kernel, which we're already doing and have success to a
> > some extent. 
> >> That's not the question. Dmitry says that the SC7 support is not a
> >> property of the SoC, but mostly a platform decision on whether the
> >> firmware supports SC7 or not.
> >>
> >> To me, that's a clear indication that this should not be hardcoded
> >> in the driver, but instead obtained dynamically, via DT or
> >> otherwise.  
> > We already have an nvidia,suspend-mode property in the device-tree
> > of the Power Management Controller node (all Tegra SoCs) which
> > defines what suspending type is supported by a particular board.
> >  
> >>>>>>> +			writel_relaxed(~0ul, ictlr +
> >>>>>>> ICTLR_COP_IER_CLR);  
> >>>>>> Secondly, I'm also not sure why COP interrupts need to be
> >>>>>> disabled for pre-T210 at all, since COP is unused. This looks
> >>>>>> to me like it was cut-n-pasted from downstream kernel without
> >>>>>> a good reason and could be simply removed.  
> >>>>> Please verify that this is actually the case. Tegra-2
> >>>>> definitely needed some level of poking, and I'm not keen on
> >>>>> changing anything there until you (or someone else) has
> >>>>> verified it on actual HW (see e307cc8941fc).  
> >>>> Tested on Tegra20 and Tegra30, LP1 suspend-resume works
> >>>> perfectly fine with all COP bits removed from the driver.
> >>>>
> >>>> AFAIK, the reason why downstream needed that disabling is that
> >>>> it uses proprietary firmware which is running on the COP and
> >>>> that firmware is usually a BLOB audio/video DEC-ENC driver which
> >>>> doesn't cleanup interrupts after itself. That firmware is not
> >>>> applicable for the upstream kernel, hence there is no need to
> >>>> care about it. 
> >>>>> Joseph, can you please shed some light here?  
> >>> SC7 entry flow uses 3rd party ATF (arm-trusted FW) blob which is
> >>> the one that actually loads SC7 entry firmware and triggers IRQ to
> >>> AVP/COP which causes COP to wakeup and run SC7 entry FW.
> >>>
> >>> So when SC7 support is enabled, IRQ need to be kept enabled and
> >>> when SC7 FW starts execution, it will disable COP IRQ.  
> >> This looks like a lot of undocumented assumptions on what firmware
> >> does, as well as what firmware *is*. What I gather from this
> >> thread is that there is at least two versions of firmware (a
> >> "proprietary firmware" for "downstream kernels", and another one
> >> for mainline), and that they do different things.
> >>
> >> Given that we cannot know what people actually run, I don't think
> >> we can safely remove anything unless this gets tested on the full
> >> spectrum of HW/FW combination.  
> > I'm not sure whether multiple firmware variations exist in the wild
> > for Tegra210. Maybe Sowjanya or somebody else from NVIDIA could
> > clarify. I think there should be some efforts in regards to a fully
> > opensource firmware on Tegra210, but I'm not following it and have
> > no idea about the status.
> >
> > You're right that there are multiple variants of suspend-resuming
> > flow on Tegra SoCs. The older 32bit Tegra SoC generations have a
> > variety of options in regards to suspend-resuming, including
> > firmware-less variants on platforms that are having kernel running
> > in secure mode (dev boards, most of Tegra20 consumer devices) and
> > Trusted-Foundations firmware variant for insecure platforms
> > (consumer devices). And yes, vendor firmware creates a lot of
> > headache in regards to bringing support into upstream because it
> > usually does a lot of odd undocumented things which may also vary
> > depending on a firmware version (bootloader, etc) and it also
> > usually difficult to replace it with an opensource alternative due
> > to a crypto signing.  
> 
> Tried without this patch which keeps COP IRQ disabled and I see SC7 
> entry FW execution happens still.
> 
> Digging through the ATF FW code, I see on SC7 entry firmware loading 
> into IRAM, COP processor is reset with RESET VECTOR set to SC7 entry 
> firmware location in IRAM and on reset de-assert & unhalt COP, SC7 
> firmware starts execution.
> 
> Will remove this patch in next version...
> 

Good, sounds like you also verified that SC7 COP firmware doesn't use
interrupts.

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

* Re: [PATCH V6 17/21] arm64: tegra: Enable wake from deep sleep on RTC alarm.
  2019-07-21 19:40 ` [PATCH V6 17/21] arm64: tegra: Enable wake from deep sleep on RTC alarm Sowjanya Komatineni
@ 2019-07-26  6:30   ` Dmitry Osipenko
  0 siblings, 0 replies; 84+ messages in thread
From: Dmitry Osipenko @ 2019-07-26  6:30 UTC (permalink / raw)
  To: 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

В Sun, 21 Jul 2019 12:40:56 -0700
Sowjanya Komatineni <skomatineni@nvidia.com> пишет:

> 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>

The dot in the end of the commit's title is unnecessary.

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

* Re: [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend
  2019-07-25 10:59             ` Dmitry Osipenko
@ 2019-08-02 13:05               ` Peter De Schrijver
  2019-08-02 17:35                 ` Dmitry Osipenko
  0 siblings, 1 reply; 84+ messages in thread
From: Peter De Schrijver @ 2019-08-02 13:05 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland, pgaikwad,
	sboyd, linux-clk, linux-gpio, jckuo, josephl, talho, linux-tegra,
	linux-kernel, mperttunen, spatra, robh+dt, devicetree

On Thu, Jul 25, 2019 at 01:59:09PM +0300, Dmitry Osipenko wrote:
> 25.07.2019 13:38, Peter De Schrijver пишет:
> > On Thu, Jul 25, 2019 at 01:33:48PM +0300, Peter De Schrijver wrote:
> >> On Thu, Jul 25, 2019 at 01:05:13PM +0300, Dmitry Osipenko wrote:
> >>> 25.07.2019 12:55, Peter De Schrijver пишет:
> >>>> On Mon, Jul 22, 2019 at 12:54:51PM +0300, Dmitry Osipenko wrote:
> >>>>>
> >>>>> All Tegra SoCs support SC7, hence the 'supports_sc7' and the comment
> >>>>> doesn't sound correct to me. Something like 'firmware_sc7' should suit
> >>>>> better here.
> >>>>>
> >>>>>> +			writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
> >>>>>
> >>>>> Secondly, I'm also not sure why COP interrupts need to be disabled for
> >>>>> pre-T210 at all, since COP is unused. This looks to me like it was
> >>>>> cut-n-pasted from downstream kernel without a good reason and could be
> >>>>> simply removed.
> >>>>
> >>>> I don't think we can rely on the fact that COP is unused. People can
> >>>> write their own code to run on COP.
> >>>
> >>> 1. Not upstream - doesn't matter.
> >>>
> >>
> >> The code is not part of the kernel, so obviously it's not upstream?
> >>
> >>> 2. That's not very good if something unknown is running on COP and then
> >>> kernel suddenly intervenes, don't you think so?
> >>
> >> Unless the code was written with this in mind.
> >>
> 
> In that case, please see 1. ;)
> 

In general the kernel should not touch the COP interrupts I think.

> > 
> > Looking at this again, I don't think we need to enable the IRQ at all.
> 
> Could you please clarify? The code only saves/restores COP's interrupts
> context across suspend-resume.

The sc7 entry firmware doesn't use interrupts.

Peter.

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

* Re: [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend
  2019-08-02 13:05               ` Peter De Schrijver
@ 2019-08-02 17:35                 ` Dmitry Osipenko
  0 siblings, 0 replies; 84+ messages in thread
From: Dmitry Osipenko @ 2019-08-02 17:35 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland, pgaikwad,
	sboyd, linux-clk, linux-gpio, jckuo, josephl, talho, linux-tegra,
	linux-kernel, mperttunen, spatra, robh+dt, devicetree

02.08.2019 16:05, Peter De Schrijver пишет:
> On Thu, Jul 25, 2019 at 01:59:09PM +0300, Dmitry Osipenko wrote:
>> 25.07.2019 13:38, Peter De Schrijver пишет:
>>> On Thu, Jul 25, 2019 at 01:33:48PM +0300, Peter De Schrijver wrote:
>>>> On Thu, Jul 25, 2019 at 01:05:13PM +0300, Dmitry Osipenko wrote:
>>>>> 25.07.2019 12:55, Peter De Schrijver пишет:
>>>>>> On Mon, Jul 22, 2019 at 12:54:51PM +0300, Dmitry Osipenko wrote:
>>>>>>>
>>>>>>> All Tegra SoCs support SC7, hence the 'supports_sc7' and the comment
>>>>>>> doesn't sound correct to me. Something like 'firmware_sc7' should suit
>>>>>>> better here.
>>>>>>>
>>>>>>>> +			writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
>>>>>>>
>>>>>>> Secondly, I'm also not sure why COP interrupts need to be disabled for
>>>>>>> pre-T210 at all, since COP is unused. This looks to me like it was
>>>>>>> cut-n-pasted from downstream kernel without a good reason and could be
>>>>>>> simply removed.
>>>>>>
>>>>>> I don't think we can rely on the fact that COP is unused. People can
>>>>>> write their own code to run on COP.
>>>>>
>>>>> 1. Not upstream - doesn't matter.
>>>>>
>>>>
>>>> The code is not part of the kernel, so obviously it's not upstream?
>>>>
>>>>> 2. That's not very good if something unknown is running on COP and then
>>>>> kernel suddenly intervenes, don't you think so?
>>>>
>>>> Unless the code was written with this in mind.
>>>>
>>
>> In that case, please see 1. ;)
>>
> 
> In general the kernel should not touch the COP interrupts I think.
> 
>>>
>>> Looking at this again, I don't think we need to enable the IRQ at all.
>>
>> Could you please clarify? The code only saves/restores COP's interrupts
>> context across suspend-resume.
> 
> The sc7 entry firmware doesn't use interrupts.

Okay, it shouldn't hurt to clean up the LIC's code a tad by removing the
COP's bits, will make a patch.

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

* Re: [PATCH V6 14/21] clk: tegra210: Add suspend and resume support
  2019-07-22  7:12             ` Dmitry Osipenko
@ 2019-08-02 17:51               ` Stephen Boyd
  2019-08-02 20:39                 ` Sowjanya Komatineni
  0 siblings, 1 reply; 84+ messages in thread
From: Stephen Boyd @ 2019-08-02 17:51 UTC (permalink / raw)
  To: Dmitry Osipenko, Sowjanya Komatineni, 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,
	devicetree

Quoting Dmitry Osipenko (2019-07-22 00:12:17)
> 22.07.2019 10:09, Dmitry Osipenko пишет:
> > 22.07.2019 9:52, Sowjanya Komatineni пишет:
> >>
> >> On 7/21/19 11:10 PM, Dmitry Osipenko wrote:
> >>> 22.07.2019 1:45, Sowjanya Komatineni пишет:
> >>>> On 7/21/19 2:38 PM, Dmitry Osipenko wrote:
> >>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
> >>>>>> @@ -2853,9 +2859,8 @@ static int tegra210_enable_pllu(void)
> >>>>>>        reg |= PLL_ENABLE;
> >>>>>>        writel(reg, clk_base + PLLU_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) {
> >>>>> Why this is needed? Was there a bug?
> >>>>>
> >>>> during resume pllu init is needed and to use same terga210_init_pllu,
> >>>> poll_timeout_atomic can't be used as its ony for atomic context.
> >>>>
> >>>> So changed to use wait_for_mask which should work in both cases.
> >>> Atomic variant could be used from any context, not sure what do you
> >>> mean. The 'atomic' part only means that function won't cause scheduling
> >>> and that's it.
> >>
> >> Sorry, replied incorrect. readx_poll_timeout_atomic uses ktime_get() and
> >> during resume timekeeping suspend/resume happens later than clock
> >> suspend/resume. So using tegra210_wait_for_mask.
> >>
> >> both timekeeping and clk-tegra210 drivers are registered as syscore but
> >> not ordered.
> > 
> > Okay, thank you for the clarification.
> > 
> > [snip]
> > 
> 
> You should remove the 'iopoll.h' then, since it's not used anymore.

And also add a comment to this location in the code because it's
non-obvious that we can't use iopoll here.


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

* Re: [PATCH V6 14/21] clk: tegra210: Add suspend and resume support
  2019-08-02 17:51               ` Stephen Boyd
@ 2019-08-02 20:39                 ` Sowjanya Komatineni
  2019-08-07 21:22                   ` Stephen Boyd
  0 siblings, 1 reply; 84+ messages in thread
From: Sowjanya Komatineni @ 2019-08-02 20:39 UTC (permalink / raw)
  To: Stephen Boyd, Dmitry Osipenko, 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,
	devicetree


On 8/2/19 10:51 AM, Stephen Boyd wrote:
> Quoting Dmitry Osipenko (2019-07-22 00:12:17)
>> 22.07.2019 10:09, Dmitry Osipenko пишет:
>>> 22.07.2019 9:52, Sowjanya Komatineni пишет:
>>>> On 7/21/19 11:10 PM, Dmitry Osipenko wrote:
>>>>> 22.07.2019 1:45, Sowjanya Komatineni пишет:
>>>>>> On 7/21/19 2:38 PM, Dmitry Osipenko wrote:
>>>>>>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>>>>>>> @@ -2853,9 +2859,8 @@ static int tegra210_enable_pllu(void)
>>>>>>>>         reg |= PLL_ENABLE;
>>>>>>>>         writel(reg, clk_base + PLLU_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) {
>>>>>>> Why this is needed? Was there a bug?
>>>>>>>
>>>>>> during resume pllu init is needed and to use same terga210_init_pllu,
>>>>>> poll_timeout_atomic can't be used as its ony for atomic context.
>>>>>>
>>>>>> So changed to use wait_for_mask which should work in both cases.
>>>>> Atomic variant could be used from any context, not sure what do you
>>>>> mean. The 'atomic' part only means that function won't cause scheduling
>>>>> and that's it.
>>>> Sorry, replied incorrect. readx_poll_timeout_atomic uses ktime_get() and
>>>> during resume timekeeping suspend/resume happens later than clock
>>>> suspend/resume. So using tegra210_wait_for_mask.
>>>>
>>>> both timekeeping and clk-tegra210 drivers are registered as syscore but
>>>> not ordered.
>>> Okay, thank you for the clarification.
>>>
>>> [snip]
>>>
>> You should remove the 'iopoll.h' then, since it's not used anymore.
> And also add a comment to this location in the code because it's
> non-obvious that we can't use iopoll here.
>
Actually added comment during function usage instead of during include 
as iopoll.h is removed.

Will add additional comment in include section as well highlighting 
reason for removal of iopoll.h


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

* Re: [PATCH V6 14/21] clk: tegra210: Add suspend and resume support
  2019-08-02 20:39                 ` Sowjanya Komatineni
@ 2019-08-07 21:22                   ` Stephen Boyd
  0 siblings, 0 replies; 84+ messages in thread
From: Stephen Boyd @ 2019-08-07 21:22 UTC (permalink / raw)
  To: Dmitry Osipenko, Sowjanya Komatineni, 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,
	devicetree

Quoting Sowjanya Komatineni (2019-08-02 13:39:57)
> 
> On 8/2/19 10:51 AM, Stephen Boyd wrote:
> > And also add a comment to this location in the code because it's
> > non-obvious that we can't use iopoll here.
> >
> Actually added comment during function usage instead of during include 
> as iopoll.h is removed.
> 
> Will add additional comment in include section as well highlighting 
> reason for removal of iopoll.h
> 

No I wasn't saying to add a comment to the include section, just add a
comment in the place where you would have called iopoll but don't. Sorry
that it wasn't clear.


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

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

Thread overview: 84+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend Sowjanya Komatineni
2019-07-21 20:24   ` Marc Zyngier
2019-07-22  9:54   ` Dmitry Osipenko
2019-07-22 10:13     ` Marc Zyngier
2019-07-22 10:57       ` Dmitry Osipenko
2019-07-22 16:21         ` Sowjanya Komatineni
2019-07-22 18:38           ` Marc Zyngier
2019-07-22 23:35             ` Dmitry Osipenko
2019-07-24 23:09               ` Sowjanya Komatineni
2019-07-26  4:48                 ` Dmitry Osipenko
2019-07-25  9:55     ` Peter De Schrijver
2019-07-25 10:05       ` Dmitry Osipenko
2019-07-25 10:33         ` Peter De Schrijver
2019-07-25 10:38           ` Peter De Schrijver
2019-07-25 10:59             ` Dmitry Osipenko
2019-08-02 13:05               ` Peter De Schrijver
2019-08-02 17:35                 ` Dmitry Osipenko
2019-07-21 19:40 ` [PATCH V6 02/21] pinctrl: tegra: Add suspend and resume support Sowjanya Komatineni
2019-07-21 22:03   ` Dmitry Osipenko
2019-07-21 22:09     ` Dmitry Osipenko
2019-07-21 22:48       ` Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 03/21] pinctrl: tegra210: Add Tegra210 pinctrl pm ops Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 04/21] clk: tegra: Save and restore divider rate Sowjanya Komatineni
2019-07-21 22:14   ` Dmitry Osipenko
2019-07-21 19:40 ` [PATCH V6 05/21] clk: tegra: pllout: Save and restore pllout context Sowjanya Komatineni
2019-07-21 22:18   ` Dmitry Osipenko
2019-07-21 19:40 ` [PATCH V6 06/21] clk: tegra: pll: Save and restore pll context Sowjanya Komatineni
2019-07-21 21:44   ` Dmitry Osipenko
2019-07-21 22:47     ` Sowjanya Komatineni
2019-07-21 22:21   ` Dmitry Osipenko
2019-07-22  3:22     ` Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 07/21] clk: tegra: Support for OSC context save and restore Sowjanya Komatineni
2019-07-22 10:12   ` Dmitry Osipenko
2019-07-21 19:40 ` [PATCH V6 08/21] clk: tegra: clk-periph: Add save and restore support Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 09/21] clk: tegra: clk-super: Fix to enable PLLP branches to CPU Sowjanya Komatineni
2019-07-21 21:16   ` Dmitry Osipenko
2019-07-21 22:39     ` Sowjanya Komatineni
2019-07-22  3:17       ` Sowjanya Komatineni
2019-07-22  6:32         ` Dmitry Osipenko
2019-07-22  7:12           ` Sowjanya Komatineni
2019-07-22  7:17             ` Dmitry Osipenko
2019-07-22  7:24               ` Sowjanya Komatineni
2019-07-22  7:30                 ` Dmitry Osipenko
2019-07-22  7:36                   ` Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 10/21] clk: tegra: clk-super: Add save and restore support Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 11/21] clk: tegra: clk-dfll: Add suspend and resume support Sowjanya Komatineni
2019-07-21 21:32   ` Dmitry Osipenko
2019-07-21 22:42     ` Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 12/21] cpufreq: tegra124: " Sowjanya Komatineni
2019-07-21 21:04   ` Dmitry Osipenko
2019-07-21 19:40 ` [PATCH V6 13/21] clk: tegra210: Use fence_udelay during PLLU init Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 14/21] clk: tegra210: Add suspend and resume support Sowjanya Komatineni
2019-07-21 21:38   ` Dmitry Osipenko
2019-07-21 22:45     ` Sowjanya Komatineni
2019-07-22  6:10       ` Dmitry Osipenko
2019-07-22  6:52         ` Sowjanya Komatineni
2019-07-22  7:09           ` Dmitry Osipenko
2019-07-22  7:12             ` Dmitry Osipenko
2019-08-02 17:51               ` Stephen Boyd
2019-08-02 20:39                 ` Sowjanya Komatineni
2019-08-07 21:22                   ` Stephen Boyd
2019-07-21 19:40 ` [PATCH V6 15/21] soc/tegra: pmc: Allow to support more tegras wake Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210 Sowjanya Komatineni
2019-07-23  0:58   ` Dmitry Osipenko
2019-07-23  1:08     ` Dmitry Osipenko
2019-07-23  1:41       ` Dmitry Osipenko
2019-07-23  1:52         ` Dmitry Osipenko
2019-07-23  2:10           ` Dmitry Osipenko
     [not found]         ` <71a88a9c-a542-557a-0eaa-3c90112dee0e@nvidia.com>
2019-07-23  3:03           ` Dmitry Osipenko
2019-07-23  3:09             ` Sowjanya Komatineni
2019-07-23  3:25               ` Dmitry Osipenko
2019-07-23  3:31                 ` Sowjanya Komatineni
2019-07-23  3:43                   ` Dmitry Osipenko
2019-07-23 14:27                     ` Dmitry Osipenko
2019-07-23 23:39                       ` Sowjanya Komatineni
2019-07-24  9:31                         ` Dmitry Osipenko
2019-07-21 19:40 ` [PATCH V6 17/21] arm64: tegra: Enable wake from deep sleep on RTC alarm Sowjanya Komatineni
2019-07-26  6:30   ` Dmitry Osipenko
2019-07-21 19:40 ` [PATCH V6 18/21] soc/tegra: pmc: Configure core power request polarity Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 19/21] soc/tegra: pmc: Configure deep sleep control settings Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 20/21] arm64: dts: tegra210-p2180: Jetson TX1 SC7 timings Sowjanya Komatineni
2019-07-21 19:41 ` [PATCH V6 21/21] arm64: dts: tegra210-p3450: Jetson nano " Sowjanya Komatineni
2019-07-21 22:25   ` Dmitry Osipenko

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).