Skip to contentSkip to conversation

ARM: tegra: support LP1 suspend mode

PATCH New Joseph Lo 4 participants 44 messages Jul 26, 2013 – Aug 9, 2013

Subsystems (6)
lore
Share & tools
lore

Joseph Lo

author
#0 lore raw

cover ARM: tegra: support LP1 suspend mode

This series adds the support of LP1 suspend mode for Tegra.

Verified on Seaboard, Cardhu and Dalmore.
And tested with THUMB2_KERNEL as well.

P.S.
A known issue on Dalmore, the LP1 resume may take 10 ~ 15 seconds due to the 792MHz BCT. It can't be reproduced on Seaboard or Cardhu. And the root cause of this is about the default settings of EMC registers that cause the DRAM can't leave self-refresh mode immediately. If you want to test with quick LP1 resume on Dalmore, I can provide another HACK for this.

Joseph Lo (8):
ARM: tegra: add common resume handling code for LP1 resuming
ARM: tegra: config the polarity of the request of sys clock
clk: tegra114: add LP1 suspend/resume support
ARM: tegra: add common LP1 suspend support
ARM: tegra30: add LP1 suspend support
ARM: tegra20: add LP1 suspend support
ARM: tegra114: add LP1 suspend support
ARM: dts: tegra: enable LP1 suspend mode

 arch/arm/boot/dts/tegra114-dalmore.dts     |   2 +-
 arch/arm/boot/dts/tegra20-colibri-512.dtsi |   2 +-
 arch/arm/boot/dts/tegra20-harmony.dts      |   2 +-
 arch/arm/boot/dts/tegra20-paz00.dts        |   2 +-
 arch/arm/boot/dts/tegra20-seaboard.dts     |   2 +-
 arch/arm/boot/dts/tegra20-tamonten.dtsi    |   2 +-
 arch/arm/boot/dts/tegra20-trimslice.dts    |   2 +-
 arch/arm/boot/dts/tegra20-ventana.dts      |   2 +-
 arch/arm/boot/dts/tegra20-whistler.dts     |   2 +-
 arch/arm/boot/dts/tegra30-beaver.dts       |   2 +-
 arch/arm/boot/dts/tegra30-cardhu.dtsi      |   2 +-
 arch/arm/mach-tegra/Makefile               |   3 +
 arch/arm/mach-tegra/iomap.h                |   6 +
 arch/arm/mach-tegra/pm-tegra20.c           |  37 ++
 arch/arm/mach-tegra/pm-tegra30.c           |  37 ++
 arch/arm/mach-tegra/pm.c                   | 121 +++++-
 arch/arm/mach-tegra/pm.h                   |  23 ++
 arch/arm/mach-tegra/pmc.c                  |  36 +-
 arch/arm/mach-tegra/pmc.h                  |   3 +
 arch/arm/mach-tegra/reset-handler.S        |  13 +
 arch/arm/mach-tegra/reset.c                |   2 +
 arch/arm/mach-tegra/reset.h                |   4 +
 arch/arm/mach-tegra/sleep-tegra20.S        | 300 ++++++++++++++
 arch/arm/mach-tegra/sleep-tegra30.S        | 615 +++++++++++++++++++++++++++++
 arch/arm/mach-tegra/sleep.S                |   8 +-
 arch/arm/mach-tegra/sleep.h                |  18 +
 drivers/clk/tegra/clk-tegra114.c           |  32 ++
 27 files changed, 1259 insertions(+), 21 deletions(-)
 create mode 100644 arch/arm/mach-tegra/pm-tegra20.c
 create mode 100644 arch/arm/mach-tegra/pm-tegra30.c
Signature · 1 line
1.8.3.4
author
#1 lore raw

PATCH 1/8 ARM: tegra: add common resume handling code for LP1 resuming

The common LP1 resuming procedures of LP1 on Tegra was checking the LP1 mask first. The LP1 mask indicated that the Tegra device was in LP1 then we need to resume the Tegra from the LP1 reset handler.

And the LP1 was putting the SDRAM to self-refresh mode, the SDRAM wasn't accessible when resuming from LP1. We need to copy the LP1 reset handler to IRAM before suspending. That's why you can see the address of LP1 reset handler was located in IRAM.

---
 arch/arm/mach-tegra/reset-handler.S | 13 +++++++++++++
 arch/arm/mach-tegra/reset.c         |  2 ++
 arch/arm/mach-tegra/sleep.h         |  2 ++
 3 files changed, 17 insertions(+)
arch/arm/mach-tegra/reset-handler.S +13 -0
index 34614bd..492b10f 100644
@@ -182,6 +182,19 @@ after_errata:
 1:
 #endif
 
+	/* Waking up from LP1? */
+	ldr	r8, [r12, #RESET_DATA(MASK_LP1)]
+	tst	r8, r11				@ if in_lp1
+	beq	__is_not_lp1
+	cmp	r10, #0
+	bne	__die				@ only CPU0 can be here
+	ldr	lr, [r12, #RESET_DATA(STARTUP_LP1)]
+ THUMB(	add	lr, lr, #1 )			@ switch to Thumb mode
+	cmp	lr, #0
+	bleq	__die				@ no LP1 startup handler
+	bx	lr
+__is_not_lp1:
+
 	/* Waking up from LP2? */
 	ldr	r9, [r12, #RESET_DATA(MASK_LP2)]
 	tst	r9, r11				@ if in_lp2
arch/arm/mach-tegra/reset.c +2 -0
index 1ac434e..fd0bbf8 100644
@@ -81,6 +81,8 @@ void __init tegra_cpu_reset_handler_init(void)
 #endif
 
 #ifdef CONFIG_PM_SLEEP
+	__tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_LP1] =
+		TEGRA_IRAM_CODE_AREA;
 	__tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_LP2] =
 		virt_to_phys((void *)tegra_resume);
 #endif
arch/arm/mach-tegra/sleep.h +2 -0
index e907e40..e7f8b6f 100644
@@ -29,6 +29,8 @@
 					+ IO_APB_VIRT)
 #define TEGRA_PMC_VIRT	(TEGRA_PMC_BASE - IO_APB_PHYS + IO_APB_VIRT)
 
+#define TEGRA_IRAM_CODE_AREA	(TEGRA_IRAM_BASE + SZ_4K)
+
 /* PMC_SCRATCH37-39 and 41 are used for tegra_pen_lock and idle */
 #define PMC_SCRATCH37	0x130
 #define PMC_SCRATCH38	0x134
Signature · 1 line
1.8.3.4
#2 lore raw

PATCH 1/8 ARM: tegra: add common resume handling code for LP1 resuming

Quoted 8 lines · Joseph Lo

The common LP1 resuming procedures of LP1 on Tegra was checking the LP1 mask first. The LP1 mask indicated that the Tegra device was in LP1 then we need to resume the Tegra from the LP1 reset handler.

And the LP1 was putting the SDRAM to self-refresh mode, the SDRAM wasn't accessible when resuming from LP1. We need to copy the LP1 reset handler to IRAM before suspending. That's why you can see the address of LP1 reset handler was located in IRAM.

That's rather hard to understand. How about:

==========
Add support to the Tegra CPU reset vector to detect whether the CPU is resuming from LP1 suspend state. If it is, branch to the LP1-specific resume code.

When Tegra enters the LP1 suspend state, the SDRAM controller is placed into a self-refresh state. For this reason, we must place the LP1 resume code into IRAM, so that it is accessible before SDRAM access has been re-enabled.
==========

Talking about *copying* the LP1 resume code to IRAM isn't appropriate here, since nothing in this patch performs any copying of the resume code.

Quoted 6 lines
arch/arm/mach-tegra/reset-handler.S +0 -0
@@ -182,6 +182,19 @@ after_errata:
 1:
 #endif
 

arch/arm/mach-tegra/reset-handler.S after_errata: · line 194

Quoted 10 lines
arch/arm/mach-tegra/reset-handler.S +10 -0
+	/* Waking up from LP1? */
+	ldr	r8, [r12, #RESET_DATA(MASK_LP1)]
+	tst	r8, r11				@ if in_lp1
+	beq	__is_not_lp1
+	cmp	r10, #0
+	bne	__die				@ only CPU0 can be here
+	ldr	lr, [r12, #RESET_DATA(STARTUP_LP1)]
+ THUMB(	add	lr, lr, #1 )			@ switch to Thumb mode
+	cmp	lr, #0
+	bleq	__die				@ no LP1 startup handler

On thumb, lr==#1 at this point. I think you want to move the THUMB() instruction after the bleq.

arch/arm/mach-tegra/sleep.h line 32

Quoted 3 lines
arch/arm/mach-tegra/sleep.h +1 -0
 
+#define TEGRA_IRAM_CODE_AREA	(TEGRA_IRAM_BASE + SZ_4K)

The layout of IRAM should be described in irammap.h not sleep.h.

author
#3 lore raw

PATCH 2/8 ARM: tegra: config the polarity of the request of sys clock

In reply to Joseph Lo

When suspending to LP1 mode, the SYSCLK will be clock gated. And different board may have different polarity of the request of SYSCLK, this patch configure the polarity from the DT for the board.

---
 arch/arm/mach-tegra/pmc.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
arch/arm/mach-tegra/pmc.c +16 -0
index 8345fcd..018bc87 100644
@@ -27,6 +27,8 @@
 #include "pmc.h"
 #include "sleep.h"
 
+#define TEGRA_POWER_SYSCLK_POLARITY	(1 << 10)  /* sys clk polarity */
+#define TEGRA_POWER_SYSCLK_OE		(1 << 11)  /* system clock enable */
 #define TEGRA_POWER_EFFECT_LP0		(1 << 14)  /* LP0 when CPU pwr gated */
 #define TEGRA_POWER_CPU_PWRREQ_POLARITY	(1 << 15)  /* CPU pwr req polarity */
 #define TEGRA_POWER_CPU_PWRREQ_OE	(1 << 16)  /* CPU pwr req enable */
@@ -238,6 +240,20 @@ void tegra_pmc_suspend_init(void)
 	reg = tegra_pmc_readl(PMC_CTRL);
 	reg |= TEGRA_POWER_CPU_PWRREQ_OE;
 	tegra_pmc_writel(reg, PMC_CTRL);
+
+	reg = tegra_pmc_readl(PMC_CTRL);
+
+	if (!pmc_pm_data.sysclkreq_high)
+		reg |= TEGRA_POWER_SYSCLK_POLARITY;
+	else
+		reg &= ~TEGRA_POWER_SYSCLK_POLARITY;
+
+	/* configure the output inverts while the request is tristated */
+	tegra_pmc_writel(reg, PMC_CTRL);
+
+	/* now enable the request */
+	reg |= TEGRA_POWER_SYSCLK_OE;
+	tegra_pmc_writel(reg, PMC_CTRL);
 }
 #endif
 
Signature · 1 line
1.8.3.4
#4 lore raw

PATCH 2/8 ARM: tegra: config the polarity of the request of sys clock

Quoted 10 lines · Joseph Lo

When suspending to LP1 mode, the SYSCLK will be clock gated. And different board may have different polarity of the request of SYSCLK, this patch configure the polarity from the DT for the board.

arch/arm/mach-tegra/pmc.c +0 -0
@@ -238,6 +240,20 @@ void tegra_pmc_suspend_init(void)
 	reg = tegra_pmc_readl(PMC_CTRL);
 	reg |= TEGRA_POWER_CPU_PWRREQ_OE;
 	tegra_pmc_writel(reg, PMC_CTRL);

arch/arm/mach-tegra/pmc.c void tegra_pmc_suspend_init(void) · line 252

Quoted 10 lines
arch/arm/mach-tegra/pmc.c +10 -0
+
+	reg = tegra_pmc_readl(PMC_CTRL);
+
+	if (!pmc_pm_data.sysclkreq_high)
+		reg |= TEGRA_POWER_SYSCLK_POLARITY;
+	else
+		reg &= ~TEGRA_POWER_SYSCLK_POLARITY;
+
+	/* configure the output inverts while the request is tristated */
+	tegra_pmc_writel(reg, PMC_CTRL);

I think s/inverts/polarity/ in that comment would make a lot more sense.

Must _OE be disabled for the code to work correctly? If so, should the code explicitly clear _OE first, since who knows what state it was originally in? Can't we just set the new polarity and enable _OE in a single register write?

Quoted 3 lines
arch/arm/mach-tegra/pmc.c +3 -0
+	/* now enable the request */
+	reg |= TEGRA_POWER_SYSCLK_OE;
+	tegra_pmc_writel(reg, PMC_CTRL);
author
#5 lore raw

PATCH 2/8 ARM: tegra: config the polarity of the request of sys clock

Quoted 7 lines · Stephen Warren
Quoted 5 lines · Joseph Lo

When suspending to LP1 mode, the SYSCLK will be clock gated. And different board may have different polarity of the request of SYSCLK, this patch configure the polarity from the DT for the board.

arch/arm/mach-tegra/pmc.c +0 -0
Quoted 17 lines
Quoted 4 lines
arch/arm/mach-tegra/pmc.c +0 -0
@@ -238,6 +240,20 @@ void tegra_pmc_suspend_init(void)
 	reg = tegra_pmc_readl(PMC_CTRL);
 	reg |= TEGRA_POWER_CPU_PWRREQ_OE;
 	tegra_pmc_writel(reg, PMC_CTRL);

arch/arm/mach-tegra/pmc.c void tegra_pmc_suspend_init(void) · line 252

Quoted 10 lines
arch/arm/mach-tegra/pmc.c +10 -0
+
+	reg = tegra_pmc_readl(PMC_CTRL);
+
+	if (!pmc_pm_data.sysclkreq_high)
+		reg |= TEGRA_POWER_SYSCLK_POLARITY;
+	else
+		reg &= ~TEGRA_POWER_SYSCLK_POLARITY;
+
+	/* configure the output inverts while the request is tristated */
+	tegra_pmc_writel(reg, PMC_CTRL);

I think s/inverts/polarity/ in that comment would make a lot more sense.

Yes, thanks.

Quoted 5 lines

Must _OE be disabled for the code to work correctly? If so, should the code explicitly clear _OE first, since who knows what state it was originally in? Can't we just set the new polarity and enable _OE in a single register write?

The SYSCLK is super clock that was connected to COP subsystem. It can't be disabled when system is running. The boot loader had initialized it and brought it to kernel. We follow the HW description in DT of the polarity of SCLK to re-configure and re-init again. Then the PMC can clock gate it when system go into suspend state.

And it can't be set it up by a single register write. It's a HW control sequence. (Actually lots of PMC code have similar sequence.)

Quoted 4 lines
Quoted 3 lines
arch/arm/mach-tegra/pmc.c +3 -0
+	/* now enable the request */
+	reg |= TEGRA_POWER_SYSCLK_OE;
+	tegra_pmc_writel(reg, PMC_CTRL);
#6 lore raw

PATCH 2/8 ARM: tegra: config the polarity of the request of sys clock

Quoted 32 lines · Joseph Lo
Quoted 7 lines · Stephen Warren
Quoted 5 lines · Joseph Lo

When suspending to LP1 mode, the SYSCLK will be clock gated. And different board may have different polarity of the request of SYSCLK, this patch configure the polarity from the DT for the board.

arch/arm/mach-tegra/pmc.c +0 -0
Quoted 17 lines
Quoted 4 lines
arch/arm/mach-tegra/pmc.c +0 -0
@@ -238,6 +240,20 @@ void tegra_pmc_suspend_init(void)
 	reg = tegra_pmc_readl(PMC_CTRL);
 	reg |= TEGRA_POWER_CPU_PWRREQ_OE;
 	tegra_pmc_writel(reg, PMC_CTRL);

arch/arm/mach-tegra/pmc.c void tegra_pmc_suspend_init(void) · line 252

Quoted 10 lines
arch/arm/mach-tegra/pmc.c +10 -0
+
+	reg = tegra_pmc_readl(PMC_CTRL);
+
+	if (!pmc_pm_data.sysclkreq_high)
+		reg |= TEGRA_POWER_SYSCLK_POLARITY;
+	else
+		reg &= ~TEGRA_POWER_SYSCLK_POLARITY;
+
+	/* configure the output inverts while the request is tristated */
+	tegra_pmc_writel(reg, PMC_CTRL);

I think s/inverts/polarity/ in that comment would make a lot more sense.

Yes, thanks.

Quoted 5 lines

Must _OE be disabled for the code to work correctly? If so, should the code explicitly clear _OE first, since who knows what state it was originally in? Can't we just set the new polarity and enable _OE in a single register write?

Quoted 5 lines

The SYSCLK is super clock that was connected to COP subsystem. It can't be disabled when system is running. The boot loader had initialized it and brought it to kernel. We follow the HW description in DT of the polarity of SCLK to re-configure and re-init again. Then the PMC can clock gate it when system go into suspend state.

So it sounds like the bootloader has already configured the clock to a certain polarity. If so, why do we need to reconfigure it again?

Or, is this code not duplicating something the bootloader must have done, but simply informing some HW in the PMC that's receiving SYSCLK how the clock is configured elsewhere?

author
#7 lore raw

PATCH 2/8 ARM: tegra: config the polarity of the request of sys clock

Quoted 39 lines · Stephen Warren
Quoted 32 lines · Joseph Lo
Quoted 7 lines · Stephen Warren
Quoted 5 lines · Joseph Lo

When suspending to LP1 mode, the SYSCLK will be clock gated. And different board may have different polarity of the request of SYSCLK, this patch configure the polarity from the DT for the board.

arch/arm/mach-tegra/pmc.c +0 -0
Quoted 17 lines
Quoted 4 lines
arch/arm/mach-tegra/pmc.c +0 -0
@@ -238,6 +240,20 @@ void tegra_pmc_suspend_init(void)
 	reg = tegra_pmc_readl(PMC_CTRL);
 	reg |= TEGRA_POWER_CPU_PWRREQ_OE;
 	tegra_pmc_writel(reg, PMC_CTRL);

arch/arm/mach-tegra/pmc.c void tegra_pmc_suspend_init(void) · line 252

Quoted 10 lines
arch/arm/mach-tegra/pmc.c +10 -0
+
+	reg = tegra_pmc_readl(PMC_CTRL);
+
+	if (!pmc_pm_data.sysclkreq_high)
+		reg |= TEGRA_POWER_SYSCLK_POLARITY;
+	else
+		reg &= ~TEGRA_POWER_SYSCLK_POLARITY;
+
+	/* configure the output inverts while the request is tristated */
+	tegra_pmc_writel(reg, PMC_CTRL);

I think s/inverts/polarity/ in that comment would make a lot more sense.

Yes, thanks.

Quoted 5 lines

Must _OE be disabled for the code to work correctly? If so, should the code explicitly clear _OE first, since who knows what state it was originally in? Can't we just set the new polarity and enable _OE in a single register write?

Quoted 5 lines

The SYSCLK is super clock that was connected to COP subsystem. It can't be disabled when system is running. The boot loader had initialized it and brought it to kernel. We follow the HW description in DT of the polarity of SCLK to re-configure and re-init again. Then the PMC can clock gate it when system go into suspend state.

Quoted 6 lines

So it sounds like the bootloader has already configured the clock to a certain polarity. If so, why do we need to reconfigure it again?

Or, is this code not duplicating something the bootloader must have done, but simply informing some HW in the PMC that's receiving SYSCLK how the clock is configured elsewhere?

I can't always guarantee the bootloader does the stuffs that kernel needs. For this reason, it's better to do what the kernel needs in the kernel.

author
#8 lore raw

PATCH 3/8 clk: tegra114: add LP1 suspend/resume support

In reply to Joseph Lo

When the system suspends to LP1, the clock of the CPU would be switched to CLK_M (12MHz Oscillator) during suspend/resume flow. The clock driver needs to restore the clock of CPU after LP1 resume.

Cc Mike Turquette <[email protected]>
---
 drivers/clk/tegra/clk-tegra114.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
drivers/clk/tegra/clk-tegra114.c +32 -0
index f74ed19..b0e745a 100644
@@ -22,6 +22,7 @@
 #include <linux/of_address.h>
 #include <linux/delay.h>
 #include <linux/export.h>
+#include <linux/syscore_ops.h>
 #include <linux/clk/tegra.h>
 
 #include "clk.h"
@@ -2332,6 +2333,33 @@ void tegra114_clock_deassert_dfll_dvco_reset(void)
 }
 EXPORT_SYMBOL(tegra114_clock_deassert_dfll_dvco_reset);
 
+#ifdef CONFIG_PM_SLEEP
+static u32 clk_rst_suspend[2];
+
+static int tegra114_clk_suspend(void)
+{
+	u32 *ctx = clk_rst_suspend;
+
+	*ctx++ = readl_relaxed(clk_base + CCLKG_BURST_POLICY);
+	*ctx++ = readl_relaxed(clk_base + CCLKG_BURST_POLICY + 4);
+
+	return 0;
+}
+
+static void tegra114_clk_resume(void)
+{
+	u32 *ctx = clk_rst_suspend;
+
+	writel_relaxed(*ctx++, clk_base + CCLKG_BURST_POLICY);
+	writel_relaxed(*ctx++, clk_base + CCLKG_BURST_POLICY + 4);
+}
+
+static struct syscore_ops tegra114_clk_syscore_ops = {
+	.suspend = tegra114_clk_suspend,
+	.resume = tegra114_clk_resume,
+};
+#endif
+
 static void __init tegra114_clock_init(struct device_node *np)
 {
 	struct device_node *node;
@@ -2384,5 +2412,9 @@ static void __init tegra114_clock_init(struct device_node *np)
 	tegra_clk_apply_init_table = tegra114_clock_apply_init_table;
 
 	tegra_cpu_car_ops = &tegra114_cpu_car_ops;
+
+#ifdef CONFIG_PM_SLEEP
+	register_syscore_ops(&tegra114_clk_syscore_ops);
+#endif
 }
 CLK_OF_DECLARE(tegra114, "nvidia,tegra114-car", tegra114_clock_init);
Signature · 1 line
1.8.3.4
#9 lore raw

PATCH 3/8 clk: tegra114: add LP1 suspend/resume support

Quoted 3 lines · Joseph Lo

When the system suspends to LP1, the clock of the CPU would be switched to CLK_M (12MHz Oscillator) during suspend/resume flow. The clock driver needs to restore the clock of CPU after LP1 resume.

It's unclear to me how the code change implements "restore the clock of the CPU". A register name of CCLKG_BURST_POLICY doesn't sound like it's anything to do with enabled/disabling the CPU clock, nor configuring its rate. What exactly does this register do, and hence what does this new code actually restore?

Why don't Tegra20/30 need a similar change?

author
#10 lore raw

PATCH 3/8 clk: tegra114: add LP1 suspend/resume support

Quoted 11 lines · Stephen Warren
Quoted 3 lines · Joseph Lo

When the system suspends to LP1, the clock of the CPU would be switched to CLK_M (12MHz Oscillator) during suspend/resume flow. The clock driver needs to restore the clock of CPU after LP1 resume.

It's unclear to me how the code change implements "restore the clock of the CPU". A register name of CCLKG_BURST_POLICY doesn't sound like it's anything to do with enabled/disabling the CPU clock, nor configuring its rate. What exactly does this register do, and hence what does this new code actually restore?

When system suspend to LP1, most of the PLLs was clock gated. Because we didn't cut off the core power, the settings of PLL still keep there. But we switch the clock source of CPU to CLK_M before shut off PLLs by CCLKG_BURSY_POLICY register. So we need to resume it back to original clock source by CCLKG_BURST_POLICY register. Or it would be keep in low rate (CLK_M) after resume.

Quoted 1 line

Why don't Tegra20/30 need a similar change?

For Tegra20/30, the same code had been implemented in the suspend/resume function of tegra_cpu_car_ops. It restores the CPU clock ASAP when CPU resume from a suspend state to get quick performance I believe.

For Tegra114, the resume performance is cool (although we can't see it in upstream kernel now, it still need some other functions.). We can implement all the clock related suspend/resume function in the clock driver.

#11 lore raw

PATCH 3/8 clk: tegra114: add LP1 suspend/resume support

Quoted 12 lines · Joseph Lo
Quoted 11 lines · Stephen Warren
Quoted 3 lines · Joseph Lo

When the system suspends to LP1, the clock of the CPU would be switched to CLK_M (12MHz Oscillator) during suspend/resume flow. The clock driver needs to restore the clock of CPU after LP1 resume.

It's unclear to me how the code change implements "restore the clock of the CPU". A register name of CCLKG_BURST_POLICY doesn't sound like it's anything to do with enabled/disabling the CPU clock, nor configuring its rate. What exactly does this register do, and hence what does this new code actually restore?

Quoted 6 lines

When system suspend to LP1, most of the PLLs was clock gated. Because we didn't cut off the core power, the settings of PLL still keep there. But we switch the clock source of CPU to CLK_M before shut off PLLs by CCLKG_BURSY_POLICY register. So we need to resume it back to original clock source by CCLKG_BURST_POLICY register. Or it would be keep in low rate (CLK_M) after resume.

OK, I guess the register name was badly chosen by HW. I'd like to see part of your description above in the patch description. How about replacing the patch description with:

----------
When the system suspends to LP1, the CPU clock source is switched to CLK_M (12MHz Oscillator) during suspend/resume flow[1]. The CPU clock source is controlled by the CCLKG_BURST_POLICY register, and hence this register must be restored during LP1 resume.
----------

[1] Question: where does this happen? This patch doesn't make that change. I wonder why the suspend path can't save this register, rather than implementing a separate suspend syscore op in the clock driver. Does the HW auto-switch the value in the register itself?

Quoted 10 lines
Quoted 1 line

Why don't Tegra20/30 need a similar change?

For Tegra20/30, the same code had been implemented in the suspend/resume function of tegra_cpu_car_ops. It restores the CPU clock ASAP when CPU resume from a suspend state to get quick performance I believe.

For Tegra114, the resume performance is cool (although we can't see it in upstream kernel now, it still need some other functions.). We can implement all the clock related suspend/resume function in the clock driver.

OK, I do see something similar in tegra20/30_cpu_clock_suspend/resume. Why can't this new code be part of the equivalent functions; does the Tegra114 suspend/resume code in mach-tegra/ not call tegra_cpu_car_ops.suspend/resume() in the same way it does on Tegra20/30?

author
#12 lore raw

PATCH 3/8 clk: tegra114: add LP1 suspend/resume support

Quoted 31 lines · Stephen Warren
Quoted 12 lines · Joseph Lo
Quoted 11 lines · Stephen Warren
Quoted 3 lines · Joseph Lo

When the system suspends to LP1, the clock of the CPU would be switched to CLK_M (12MHz Oscillator) during suspend/resume flow. The clock driver needs to restore the clock of CPU after LP1 resume.

It's unclear to me how the code change implements "restore the clock of the CPU". A register name of CCLKG_BURST_POLICY doesn't sound like it's anything to do with enabled/disabling the CPU clock, nor configuring its rate. What exactly does this register do, and hence what does this new code actually restore?

Quoted 6 lines

When system suspend to LP1, most of the PLLs was clock gated. Because we didn't cut off the core power, the settings of PLL still keep there. But we switch the clock source of CPU to CLK_M before shut off PLLs by CCLKG_BURSY_POLICY register. So we need to resume it back to original clock source by CCLKG_BURST_POLICY register. Or it would be keep in low rate (CLK_M) after resume.

OK, I guess the register name was badly chosen by HW. I'd like to see part of your description above in the patch description. How about replacing the patch description with:

----------
When the system suspends to LP1, the CPU clock source is switched to CLK_M (12MHz Oscillator) during suspend/resume flow[1]. The CPU clock source is controlled by the CCLKG_BURST_POLICY register, and hence this register must be restored during LP1 resume.
----------

Quoted 5 lines

[1] Question: where does this happen? This patch doesn't make that change. I wonder why the suspend path can't save this register, rather than implementing a separate suspend syscore op in the clock driver. Does the HW auto-switch the value in the register itself?

If we switch CPU to CLK_M in clock driver, the system will become slowly during the middle of suspending flow. We do this at the very end of the LP1 suspending flow before the CPU disable all the PLL clocks.

Quoted 11 lines
Quoted 10 lines
Quoted 1 line

Why don't Tegra20/30 need a similar change?

For Tegra20/30, the same code had been implemented in the suspend/resume function of tegra_cpu_car_ops. It restores the CPU clock ASAP when CPU resume from a suspend state to get quick performance I believe.

For Tegra114, the resume performance is cool (although we can't see it in upstream kernel now, it still need some other functions.). We can implement all the clock related suspend/resume function in the clock driver.

Quoted 4 lines

OK, I do see something similar in tegra20/30_cpu_clock_suspend/resume. Why can't this new code be part of the equivalent functions; does the Tegra114 suspend/resume code in mach-tegra/ not call tegra_cpu_car_ops.suspend/resume() in the same way it does on Tegra20/30?

One of the main reasons is due to DFLL clock. The CPU clock of Tegra114 is going to switch to DFLL to a get higher clock rate. But it depends some other HW (i.e. I2C), we can't resume it so early when the CPU just resume like we did in tegra_cpu_car_ops.suspend/resume for Tegra20/30.

#13 lore raw

PATCH 3/8 clk: tegra114: add LP1 suspend/resume support

Quoted 32 lines · Joseph Lo
Quoted 31 lines · Stephen Warren
Quoted 12 lines · Joseph Lo
Quoted 11 lines · Stephen Warren
Quoted 3 lines · Joseph Lo

When the system suspends to LP1, the clock of the CPU would be switched to CLK_M (12MHz Oscillator) during suspend/resume flow. The clock driver needs to restore the clock of CPU after LP1 resume.

It's unclear to me how the code change implements "restore the clock of the CPU". A register name of CCLKG_BURST_POLICY doesn't sound like it's anything to do with enabled/disabling the CPU clock, nor configuring its rate. What exactly does this register do, and hence what does this new code actually restore?

Quoted 6 lines

When system suspend to LP1, most of the PLLs was clock gated. Because we didn't cut off the core power, the settings of PLL still keep there. But we switch the clock source of CPU to CLK_M before shut off PLLs by CCLKG_BURSY_POLICY register. So we need to resume it back to original clock source by CCLKG_BURST_POLICY register. Or it would be keep in low rate (CLK_M) after resume.

OK, I guess the register name was badly chosen by HW. I'd like to see part of your description above in the patch description. How about replacing the patch description with:

----------
When the system suspends to LP1, the CPU clock source is switched to CLK_M (12MHz Oscillator) during suspend/resume flow[1]. The CPU clock source is controlled by the CCLKG_BURST_POLICY register, and hence this register must be restored during LP1 resume.
----------

Quoted 8 lines
Quoted 4 lines

[1] Question: where does this happen? This patch doesn't make that change. I wonder why the suspend path can't save this register, rather than implementing a separate suspend syscore op in the clock driver. Does the HW auto-switch the value in the register itself?

If we switch CPU to CLK_M in clock driver, the system will become slowly during the middle of suspending flow. We do this at the very end of the LP1 suspending flow before the CPU disable all the PLL clocks.

I think you answered "why is the switch to CLK_M performed very late", whereas I asked "where is the code that performs the switch to CLK_M".

Quoted 16 lines
Quoted 11 lines
Quoted 10 lines
Quoted 1 line

Why don't Tegra20/30 need a similar change?

For Tegra20/30, the same code had been implemented in the suspend/resume function of tegra_cpu_car_ops. It restores the CPU clock ASAP when CPU resume from a suspend state to get quick performance I believe.

For Tegra114, the resume performance is cool (although we can't see it in upstream kernel now, it still need some other functions.). We can implement all the clock related suspend/resume function in the clock driver.

Quoted 4 lines

OK, I do see something similar in tegra20/30_cpu_clock_suspend/resume. Why can't this new code be part of the equivalent functions; does the Tegra114 suspend/resume code in mach-tegra/ not call tegra_cpu_car_ops.suspend/resume() in the same way it does on Tegra20/30?

Quoted 4 lines

One of the main reasons is due to DFLL clock. The CPU clock of Tegra114 is going to switch to DFLL to a get higher clock rate. But it depends some other HW (i.e. I2C), we can't resume it so early when the CPU just resume like we did in tegra_cpu_car_ops.suspend/resume for Tegra20/30.

Is there a guarantee that the syscore_ops are run after the call to tegar_cpu_car_ops.resume() would be? Perhaps the mach-tegra/ code should simply call tegra_cpu_car_ops.resume() later on Tegra114 than it does on earlier chips, so it's run at a suitable time?

#14 lore raw

PATCH 3/8 clk: tegra114: add LP1 suspend/resume support

Quoted 38 lines · Stephen Warren
Quoted 37 lines · Joseph Lo
Quoted 35 lines · Stephen Warren
Quoted 12 lines · Joseph Lo
Quoted 11 lines · Stephen Warren
Quoted 3 lines · Joseph Lo

When the system suspends to LP1, the clock of the CPU would be switched to CLK_M (12MHz Oscillator) during suspend/resume flow. The clock driver needs to restore the clock of CPU after LP1 resume.

It's unclear to me how the code change implements "restore the clock of the CPU". A register name of CCLKG_BURST_POLICY doesn't sound like it's anything to do with enabled/disabling the CPU clock, nor configuring its rate. What exactly does this register do, and hence what does this new code actually restore?

Quoted 6 lines

When system suspend to LP1, most of the PLLs was clock gated. Because we didn't cut off the core power, the settings of PLL still keep there. But we switch the clock source of CPU to CLK_M before shut off PLLs by CCLKG_BURSY_POLICY register. So we need to resume it back to original clock source by CCLKG_BURST_POLICY register. Or it would be keep in low rate (CLK_M) after resume.

OK, I guess the register name was badly chosen by HW. I'd like to see part of your description above in the patch description. How about replacing the patch description with:

----------
When the system suspends to LP1, the CPU clock source is switched to CLK_M (12MHz Oscillator) during suspend/resume flow[1]. The CPU clock source is controlled by the CCLKG_BURST_POLICY register, and hence this register must be restored during LP1 resume.
----------

[1] Question: where does this happen? This patch doesn't make that change. I wonder why the suspend path can't save this register, rather than implementing a separate suspend syscore op in the clock driver. Does the HW auto-switch the value in the register itself?

Quoted 6 lines
Quoted 3 lines

If we switch CPU to CLK_M in clock driver, the system will become slowly during the middle of suspending flow. We do this at the very end of the LP1 suspending flow before the CPU disable all the PLL clocks.

I think you answered "why is the switch to CLK_M performed very late", whereas I asked "where is the code that performs the switch to CLK_M".

To expand on this a bit more, I can't find any reference to register CCLKG_BURST_POLICY in arch/arm/mach-tegra/ or drivers/clk/tegra/ except for the definition of clock cclk_g, nor any reference to that clock in those two directories. And that CCLKG_BURST_POLICY register is what this patch saves/restores.

I do see function tegra30_switch_cpu_to_clk32k in patch 5/8 appears to do something related to switching to clk_m and touches some other burst-related registers, but not CCLKG_BURST_POLICY...

So, if this syscore_op is attempting to undo some change that happens to CCLKG_BURST_POLICY during suspend, I still can't see what change is happening to that register during suspemd, nor which piece of code causes it.

If the issue is that the value in this register is simply lost during LP1 because the power is turned off, then I wonder what sets up this register during the original boot path?

author
#15 lore raw

PATCH 3/8 clk: tegra114: add LP1 suspend/resume support

Quoted 39 lines · Stephen Warren
Quoted 38 lines · Stephen Warren
Quoted 37 lines · Joseph Lo
Quoted 35 lines · Stephen Warren
Quoted 12 lines · Joseph Lo
Quoted 11 lines · Stephen Warren
Quoted 3 lines · Joseph Lo

When the system suspends to LP1, the clock of the CPU would be switched to CLK_M (12MHz Oscillator) during suspend/resume flow. The clock driver needs to restore the clock of CPU after LP1 resume.

It's unclear to me how the code change implements "restore the clock of the CPU". A register name of CCLKG_BURST_POLICY doesn't sound like it's anything to do with enabled/disabling the CPU clock, nor configuring its rate. What exactly does this register do, and hence what does this new code actually restore?

Quoted 6 lines

When system suspend to LP1, most of the PLLs was clock gated. Because we didn't cut off the core power, the settings of PLL still keep there. But we switch the clock source of CPU to CLK_M before shut off PLLs by CCLKG_BURSY_POLICY register. So we need to resume it back to original clock source by CCLKG_BURST_POLICY register. Or it would be keep in low rate (CLK_M) after resume.

OK, I guess the register name was badly chosen by HW. I'd like to see part of your description above in the patch description. How about replacing the patch description with:

----------
When the system suspends to LP1, the CPU clock source is switched to CLK_M (12MHz Oscillator) during suspend/resume flow[1]. The CPU clock source is controlled by the CCLKG_BURST_POLICY register, and hence this register must be restored during LP1 resume.
----------

[1] Question: where does this happen? This patch doesn't make that change. I wonder why the suspend path can't save this register, rather than implementing a separate suspend syscore op in the clock driver. Does the HW auto-switch the value in the register itself?

Quoted 6 lines
Quoted 6 lines
Quoted 3 lines

If we switch CPU to CLK_M in clock driver, the system will become slowly during the middle of suspending flow. We do this at the very end of the LP1 suspending flow before the CPU disable all the PLL clocks.

I think you answered "why is the switch to CLK_M performed very late", whereas I asked "where is the code that performs the switch to CLK_M".

You can find to code in the function tegraXX_switch_cpu_to_clk32k of the patch 5/8 and 6/8. It switches the SCLK and CCLK to CLKM before disabling the PLLs.

Quoted 11 lines

To expand on this a bit more, I can't find any reference to register CCLKG_BURST_POLICY in arch/arm/mach-tegra/ or drivers/clk/tegra/ except for the definition of clock cclk_g, nor any reference to that clock in those two directories. And that CCLKG_BURST_POLICY register is what this patch saves/restores.

I do see function tegra30_switch_cpu_to_clk32k in patch 5/8 appears to do something related to switching to clk_m and touches some other burst-related registers, but not CCLKG_BURST_POLICY...

OK. It's a little difference we do in clock driver side and low level code side.

As you knew, we have two CPU clusters (CCLKG & CCLKLP) in Tegra chips. And they have exactly the same clock source for Tegra20/30, but Tegra114. From the low level side, it should be supported when the system going to suspend with CPU_G or CPU_LP. So we switched the clock source of CPU to CLK_M by CCLK_BURST_POLICY. This register can support the running CPU switch to the clock source they want.

On the clock driver side, because the clock source of CCLKG and CCLKLP is not exactly the same for the Tegra114. The CCLKG supports DFLL clock but CCLKLP. We need to restore it separately to avoid the CPU restore to the wrong clock source.

The CPU clock suspend/resume function in the tegra_cpu_car_ops of Tegra20/30 is also using CCLK_BURST_POLICY register, because the definition of the clock source of CCLKG and CCLKLP is the same. We can simply the code for just using CCLK_BURST_POLICY.

I think the code should OK when CPU_G or CPU_LP running with it.

Quoted 8 lines

So, if this syscore_op is attempting to undo some change that happens to CCLKG_BURST_POLICY during suspend, I still can't see what change is happening to that register during suspemd, nor which piece of code causes it.

If the issue is that the value in this register is simply lost during LP1 because the power is turned off, then I wonder what sets up this register during the original boot path?

#16 lore raw

PATCH 3/8 clk: tegra114: add LP1 suspend/resume support

Quoted 75 lines · Joseph Lo
Quoted 39 lines · Stephen Warren
Quoted 38 lines · Stephen Warren
Quoted 37 lines · Joseph Lo
Quoted 35 lines · Stephen Warren
Quoted 12 lines · Joseph Lo
Quoted 11 lines · Stephen Warren
Quoted 3 lines · Joseph Lo

When the system suspends to LP1, the clock of the CPU would be switched to CLK_M (12MHz Oscillator) during suspend/resume flow. The clock driver needs to restore the clock of CPU after LP1 resume.

It's unclear to me how the code change implements "restore the clock of the CPU". A register name of CCLKG_BURST_POLICY doesn't sound like it's anything to do with enabled/disabling the CPU clock, nor configuring its rate. What exactly does this register do, and hence what does this new code actually restore?

Quoted 6 lines

When system suspend to LP1, most of the PLLs was clock gated. Because we didn't cut off the core power, the settings of PLL still keep there. But we switch the clock source of CPU to CLK_M before shut off PLLs by CCLKG_BURSY_POLICY register. So we need to resume it back to original clock source by CCLKG_BURST_POLICY register. Or it would be keep in low rate (CLK_M) after resume.

OK, I guess the register name was badly chosen by HW. I'd like to see part of your description above in the patch description. How about replacing the patch description with:

----------
When the system suspends to LP1, the CPU clock source is switched to CLK_M (12MHz Oscillator) during suspend/resume flow[1]. The CPU clock source is controlled by the CCLKG_BURST_POLICY register, and hence this register must be restored during LP1 resume.
----------

[1] Question: where does this happen? This patch doesn't make that change. I wonder why the suspend path can't save this register, rather than implementing a separate suspend syscore op in the clock driver. Does the HW auto-switch the value in the register itself?

Quoted 6 lines
Quoted 6 lines
Quoted 3 lines

If we switch CPU to CLK_M in clock driver, the system will become slowly during the middle of suspending flow. We do this at the very end of the LP1 suspending flow before the CPU disable all the PLL clocks.

I think you answered "why is the switch to CLK_M performed very late", whereas I asked "where is the code that performs the switch to CLK_M".

You can find to code in the function tegraXX_switch_cpu_to_clk32k of the patch 5/8 and 6/8. It switches the SCLK and CCLK to CLKM before disabling the PLLs.

Quoted 11 lines

To expand on this a bit more, I can't find any reference to register CCLKG_BURST_POLICY in arch/arm/mach-tegra/ or drivers/clk/tegra/ except for the definition of clock cclk_g, nor any reference to that clock in those two directories. And that CCLKG_BURST_POLICY register is what this patch saves/restores.

I do see function tegra30_switch_cpu_to_clk32k in patch 5/8 appears to do something related to switching to clk_m and touches some other burst-related registers, but not CCLKG_BURST_POLICY...

OK. It's a little difference we do in clock driver side and low level code side.

As you knew, we have two CPU clusters (CCLKG & CCLKLP) in Tegra chips. And they have exactly the same clock source for Tegra20/30, but Tegra114. From the low level side, it should be supported when the system going to suspend with CPU_G or CPU_LP. So we switched the clock source of CPU to CLK_M by CCLK_BURST_POLICY. This register can support the running CPU switch to the clock source they want.

On the clock driver side, because the clock source of CCLKG and CCLKLP is not exactly the same for the Tegra114. The CCLKG supports DFLL clock but CCLKLP. We need to restore it separately to avoid the CPU restore to the wrong clock source.

Quoted 6 lines

The CPU clock suspend/resume function in the tegra_cpu_car_ops of Tegra20/30 is also using CCLK_BURST_POLICY register, because the definition of the clock source of CCLKG and CCLKLP is the same. We can simply the code for just using CCLK_BURST_POLICY.

I think the code should OK when CPU_G or CPU_LP running with it.

OK, so just to paraphrase what you've said, to make sure I understand it:

On Tegra114, there are 3 registers:

1) Controls just the clock source of the G cluster.
2) Controls just the clock source of the LP cluster.
3) Controls both at the same time, simulating a write to both (1) and (2)

In tegra30_switch_cpu_to_clk32k(), we use register (3) above to switch to clk_m then clk_s. This is possible, because in both registers (1) and (2), the values for clk_m and clk_s are identical.

In tegra30_lp1_reset(), we can't use the same technique (a write to register 3) to restore the clock source for both G and LP clusters, since the values we need to write to those registers to re-select their clock source is different.

however, on Tegra30, there really is only one register, so we can use that to both switch to clk_m/clk_s, /and/ to switch back.

That all explains the following part of patch 7/8, which disables the clock register restore path except on Tegra30 where it will work:

Review

Quoted 6 lines
(quoted diff) +4 -2
-	mov32	r4, ((1 << 28) | (0x8))	@ burst policy is PLLX
-	str	r4, [r0, #CLK_RESET_CCLK_BURST]
+	cmp	r10, #TEGRA30
+	movweq	r4, #:lower16:((1 << 28) | (0x8))	@ burst policy is PLLX
+	movteq	r4, #:upper16:((1 << 28) | (0x8))
+	streq	r4, [r0, #CLK_RESET_CCLK_BURST]

However, none of this explains why the CPU clock restore logic on Tegra114 needs to be a syscore_op, rather than simply having tegra30_lp1_reset() execute some Tegra114-specific code.

Re-writing the part of the patch I quoted above in C, it looks like:

if (soc is tegra30)
write to CLK_RESET_CCLK_BURST to select pllx

Instead of making that code do nothing on Tegra114, why can't that code be:

if (soc is tegra30)
write to CLK_RESET_CCLK_BURST to re-select pllx
else
write to G-cluster-specific register to restore saved value write to LP-cluster-specific register to restore saved value

or:

if (soc is tegra30)
write to CLK_RESET_CCLK_BURST to re-select pllx
else
write to G-cluster-specific register to re-select pllx/dfll/... write to LP-cluster-specific register to restore ...

Plenty of other registers are saved/restored by tegra30_lp1_reset(), so surely you just need to have save two more registers in the suspend path, and restore them as I showed above.

That way, we don't have to have some special-case syscore_op to do this; all chips will restore the clock sources at the exact same place in the code, and everything will be consistent.

author
#17 lore raw

PATCH 3/8 clk: tegra114: add LP1 suspend/resume support

Quoted 8 lines · Stephen Warren
Quoted 7 lines · Joseph Lo
Quoted 6 lines · Stephen Warren
Quoted 5 lines · Stephen Warren
Quoted 4 lines · Joseph Lo
Quoted 3 lines · Stephen Warren
Quoted 2 lines · Joseph Lo
Quoted 1 line · Stephen Warren

On 07/26/2013 03:15 AM, Joseph Lo wrote:

[snip]

Quoted 20 lines
Quoted 20 lines

OK. It's a little difference we do in clock driver side and low level code side.

As you knew, we have two CPU clusters (CCLKG & CCLKLP) in Tegra chips. And they have exactly the same clock source for Tegra20/30, but Tegra114. From the low level side, it should be supported when the system going to suspend with CPU_G or CPU_LP. So we switched the clock source of CPU to CLK_M by CCLK_BURST_POLICY. This register can support the running CPU switch to the clock source they want.

On the clock driver side, because the clock source of CCLKG and CCLKLP is not exactly the same for the Tegra114. The CCLKG supports DFLL clock but CCLKLP. We need to restore it separately to avoid the CPU restore to the wrong clock source.

The CPU clock suspend/resume function in the tegra_cpu_car_ops of Tegra20/30 is also using CCLK_BURST_POLICY register, because the definition of the clock source of CCLKG and CCLKLP is the same. We can simply the code for just using CCLK_BURST_POLICY.

Quoted 5 lines
Quoted 1 line

I think the code should OK when CPU_G or CPU_LP running with it.

OK, so just to paraphrase what you've said, to make sure I understand it:

On Tegra114, there are 3 registers:

It's on Tegra30 too.

Quoted 2 lines

1) Controls just the clock source of the G cluster.

CCLKG_BURST_POLICY at offset 0x368.

Quoted 1 line

2) Controls just the clock source of the LP cluster.

CCLKLP_BURST_POLICY at offset 0x370.

Quoted 1 line

3) Controls both at the same time, simulating a write to both (1) and (2)

CCLK_BURST_POLICY at offset 0x20.
Yes, exactly. And I double confirm the item 3 again with a downstream kernel that support cluster switch today. It's true.

Quoted 4 lines

In tegra30_switch_cpu_to_clk32k(), we use register (3) above to switch to clk_m then clk_s. This is possible, because in both registers (1) and (2), the values for clk_m and clk_s are identical.

Yes.

Quoted 12 lines

In tegra30_lp1_reset(), we can't use the same technique (a write to register 3) to restore the clock source for both G and LP clusters, since the values we need to write to those registers to re-select their clock source is different.

however, on Tegra30, there really is only one register, so we can use that to both switch to clk_m/clk_s, /and/ to switch back.

That all explains the following part of patch 7/8, which disables the clock register restore path except on Tegra30 where it will work:

Quoted 6 lines

Review

Quoted 6 lines
(quoted diff) +4 -2
-	mov32	r4, ((1 << 28) | (0x8))	@ burst policy is PLLX
-	str	r4, [r0, #CLK_RESET_CCLK_BURST]
+	cmp	r10, #TEGRA30
+	movweq	r4, #:lower16:((1 << 28) | (0x8))	@ burst policy is PLLX
+	movteq	r4, #:upper16:((1 << 28) | (0x8))
+	streq	r4, [r0, #CLK_RESET_CCLK_BURST]

OK. The burst policy of CPU clock has 5 different states (STDBY, IDLE, RUN, IRQ and FIQ). The SW only can set up the clock source of each state. The switching to different state was controlled by HW.

So the Tegra30 code here was set up the clock source of IDLE state only (the CPU runs in this state after resume) to make the performance better. But It had no idea about the clock sources of the other states. It still needs clock driver to take care of that.

The clock source id (0x8) means PLLX_OUT0 in Tegra30. In Tegra114, it means PLLX_OUT0_LJ (low jitter). It's not available at this moment. I can switch it to PLLX_OUT0 (0xe) for Tegra114 too. The code may like below.

Review

Quoted 8 lines
(quoted diff) +6 -2
-     mov32   r4, ((1 << 28) | (0x8)) @ burst policy is PLLX
-     str     r4, [r0, #CLK_RESET_CCLK_BURST]
+     cmp     r10, #TEGRA30
+     movweq  r4, #:lower16:((1 << 28) | (0x8))
+     movteq  r4, #:upper16:((1 << 28) | (0x8))
+	movwne  r4, #:lower16:((1 << 28) | (0xe))
+	movteq  r4, #:upper16:((1 << 28) | (0xe))
+     str	r4, [r0, #CLK_RESET_CCLK_BURST]

I had tested this code before I sent this series. It didn't impact or improve the resuming performance. So I removed them.
Do you want me to add them back?

Quoted 18 lines

However, none of this explains why the CPU clock restore logic on Tegra114 needs to be a syscore_op, rather than simply having tegra30_lp1_reset() execute some Tegra114-specific code.

Re-writing the part of the patch I quoted above in C, it looks like:

if (soc is tegra30)
write to CLK_RESET_CCLK_BURST to select pllx

Instead of making that code do nothing on Tegra114, why can't that code be:

if (soc is tegra30)
write to CLK_RESET_CCLK_BURST to re-select pllx
else
write to G-cluster-specific register to restore saved value write to LP-cluster-specific register to restore saved value

Quoted 8 lines

or:

if (soc is tegra30)
write to CLK_RESET_CCLK_BURST to re-select pllx
else
write to G-cluster-specific register to re-select pllx/dfll/... write to LP-cluster-specific register to restore ...

Hope the explanation above is enough for you. The low level code had no idea of clock source of each CPU state in BURST_POLICY register. It needs to be done by clk driver itself.

#18 lore raw

PATCH 3/8 clk: tegra114: add LP1 suspend/resume support

Quoted 83 lines · Joseph Lo
Quoted 8 lines · Stephen Warren
Quoted 7 lines · Joseph Lo
Quoted 6 lines · Stephen Warren
Quoted 5 lines · Stephen Warren
Quoted 4 lines · Joseph Lo
Quoted 3 lines · Stephen Warren
Quoted 2 lines · Joseph Lo
Quoted 1 line · Stephen Warren

On 07/26/2013 03:15 AM, Joseph Lo wrote:

[snip]

Quoted 20 lines
Quoted 20 lines

OK. It's a little difference we do in clock driver side and low level code side.

As you knew, we have two CPU clusters (CCLKG & CCLKLP) in Tegra chips. And they have exactly the same clock source for Tegra20/30, but Tegra114. From the low level side, it should be supported when the system going to suspend with CPU_G or CPU_LP. So we switched the clock source of CPU to CLK_M by CCLK_BURST_POLICY. This register can support the running CPU switch to the clock source they want.

On the clock driver side, because the clock source of CCLKG and CCLKLP is not exactly the same for the Tegra114. The CCLKG supports DFLL clock but CCLKLP. We need to restore it separately to avoid the CPU restore to the wrong clock source.

The CPU clock suspend/resume function in the tegra_cpu_car_ops of Tegra20/30 is also using CCLK_BURST_POLICY register, because the definition of the clock source of CCLKG and CCLKLP is the same. We can simply the code for just using CCLK_BURST_POLICY.

Quoted 5 lines
Quoted 1 line

I think the code should OK when CPU_G or CPU_LP running with it.

OK, so just to paraphrase what you've said, to make sure I understand it:

On Tegra114, there are 3 registers:

It's on Tegra30 too.

Quoted 2 lines

1) Controls just the clock source of the G cluster.

CCLKG_BURST_POLICY at offset 0x368.

Quoted 1 line

2) Controls just the clock source of the LP cluster.

CCLKLP_BURST_POLICY at offset 0x370.

Quoted 1 line

3) Controls both at the same time, simulating a write to both (1) and (2)

CCLK_BURST_POLICY at offset 0x20.
Yes, exactly. And I double confirm the item 3 again with a downstream kernel that support cluster switch today. It's true.

Quoted 4 lines

In tegra30_switch_cpu_to_clk32k(), we use register (3) above to switch to clk_m then clk_s. This is possible, because in both registers (1) and (2), the values for clk_m and clk_s are identical.

Yes.

Quoted 12 lines

In tegra30_lp1_reset(), we can't use the same technique (a write to register 3) to restore the clock source for both G and LP clusters, since the values we need to write to those registers to re-select their clock source is different.

however, on Tegra30, there really is only one register, so we can use that to both switch to clk_m/clk_s, /and/ to switch back.

That all explains the following part of patch 7/8, which disables the clock register restore path except on Tegra30 where it will work:

Quoted 6 lines

Review

Quoted 6 lines
(quoted diff) +4 -2
-	mov32	r4, ((1 << 28) | (0x8))	@ burst policy is PLLX
-	str	r4, [r0, #CLK_RESET_CCLK_BURST]
+	cmp	r10, #TEGRA30
+	movweq	r4, #:lower16:((1 << 28) | (0x8))	@ burst policy is PLLX
+	movteq	r4, #:upper16:((1 << 28) | (0x8))
+	streq	r4, [r0, #CLK_RESET_CCLK_BURST]

OK. The burst policy of CPU clock has 5 different states (STDBY, IDLE, RUN, IRQ and FIQ). The SW only can set up the clock source of each state. The switching to different state was controlled by HW.

So the Tegra30 code here was set up the clock source of IDLE state only (the CPU runs in this state after resume) to make the performance better. But It had no idea about the clock sources of the other states. It still needs clock driver to take care of that.

The clock source id (0x8) means PLLX_OUT0 in Tegra30. In Tegra114, it means PLLX_OUT0_LJ (low jitter). It's not available at this moment. I can switch it to PLLX_OUT0 (0xe) for Tegra114 too. The code may like below.

Quoted 7 lines

Review

Quoted 7 lines
(quoted diff) +5 -2
-     mov32   r4, ((1 << 28) | (0x8)) @ burst policy is PLLX
-     str     r4, [r0, #CLK_RESET_CCLK_BURST]
+     cmp     r10, #TEGRA30
+     movweq  r4, #:lower16:((1 << 28) | (0x8))
+     movteq  r4, #:upper16:((1 << 28) | (0x8))
+	movwne  r4, #:lower16:((1 << 28) | (0xe))
+	movteq  r4, #:upper16:((1 << 28) | (0xe))

I assume that should be movtne.

Quoted 5 lines
Quoted 1 line

+ str r4, [r0, #CLK_RESET_CCLK_BURST]

I had tested this code before I sent this series. It didn't impact or improve the resuming performance. So I removed them.
Do you want me to add them back?

I think adding that code back would make sense. It would mean the code works fundamentally the same way for all SoCs.

BTW, you mentioned that LP1 resume takes 10-15 seconds on Dalmore. Are you sure this isn't because the above code is missing, and hence the CPU keeps running at 32KHz or the crystal speed, since nothing restores the CPU clock source until much later, when the syscore op runs?

Quoted 25 lines
Quoted 17 lines

However, none of this explains why the CPU clock restore logic on Tegra114 needs to be a syscore_op, rather than simply having tegra30_lp1_reset() execute some Tegra114-specific code.

Re-writing the part of the patch I quoted above in C, it looks like:

if (soc is tegra30)
write to CLK_RESET_CCLK_BURST to select pllx

Instead of making that code do nothing on Tegra114, why can't that code be:

if (soc is tegra30)
write to CLK_RESET_CCLK_BURST to re-select pllx
else
write to G-cluster-specific register to restore saved value write to LP-cluster-specific register to restore saved value

Quoted 8 lines

or:

if (soc is tegra30)
write to CLK_RESET_CCLK_BURST to re-select pllx
else
write to G-cluster-specific register to re-select pllx/dfll/... write to LP-cluster-specific register to restore ...

Quoted 3 lines

Hope the explanation above is enough for you. The low level code had no idea of clock source of each CPU state in BURST_POLICY register. It needs to be done by clk driver itself.

I still have absolutely no idea why Tegra30 and Tegra114 are different.

You mentioned something about this low-level code only manipulating the IDLE state, and the clock driver needing to restore the other 4 states. This raises yet more questions:

1) Do we not need to restore the other 4 states on Tegra30? If not, why not? If we do, presumably Tegra30 (and Tegra20?) need to the syscore_op this patch series adds to Tegra114 only? If we don't, then why does Tegra114 have to restore them?

2) What triggers the HW to switch from IDLE to RUN state? In other words, I think you're saying that the existing Tegra30 code:

	mov32	r4, ((1 << 28) | (0x8))	@ burst policy is PLLX
	str	r4, [r0, #CLK_RESET_CCLK_BURST]

doesn't change the clock rate right away. When does it change?

Related, when tegra30_switch_cpu_to_clk32k() sets the CPU clock source for the IDLE state to clk_s, when does that switch actually take place? That function appears to assume it happens immediately, since it immediately disables the PLLs that might have been the previous CPU clock source. Perhaps this is what the MSELECT register writes do? I guess not since there's only 1 MSELECT write in tegra_lp1_reset() and two changes of CPU clock source.

author
#19 lore raw

PATCH 3/8 clk: tegra114: add LP1 suspend/resume support

Quoted 11 lines · Stephen Warren
Quoted 10 lines · Joseph Lo
Quoted 8 lines · Stephen Warren
Quoted 7 lines · Joseph Lo
Quoted 6 lines · Stephen Warren
Quoted 5 lines · Stephen Warren
Quoted 4 lines · Joseph Lo
Quoted 3 lines · Stephen Warren
Quoted 2 lines · Joseph Lo
Quoted 1 line · Stephen Warren

On 07/26/2013 03:15 AM, Joseph Lo wrote:

[snip]

[snip]

Quoted 32 lines
Quoted 32 lines
Quoted 11 lines

In tegra30_lp1_reset(), we can't use the same technique (a write to register 3) to restore the clock source for both G and LP clusters, since the values we need to write to those registers to re-select their clock source is different.

however, on Tegra30, there really is only one register, so we can use that to both switch to clk_m/clk_s, /and/ to switch back.

That all explains the following part of patch 7/8, which disables the clock register restore path except on Tegra30 where it will work:

Quoted 6 lines

Review

Quoted 6 lines
(quoted diff) +4 -2
-	mov32	r4, ((1 << 28) | (0x8))	@ burst policy is PLLX
-	str	r4, [r0, #CLK_RESET_CCLK_BURST]
+	cmp	r10, #TEGRA30
+	movweq	r4, #:lower16:((1 << 28) | (0x8))	@ burst policy is PLLX
+	movteq	r4, #:upper16:((1 << 28) | (0x8))
+	streq	r4, [r0, #CLK_RESET_CCLK_BURST]

OK. The burst policy of CPU clock has 5 different states (STDBY, IDLE, RUN, IRQ and FIQ). The SW only can set up the clock source of each state. The switching to different state was controlled by HW.

So the Tegra30 code here was set up the clock source of IDLE state only (the CPU runs in this state after resume) to make the performance better. But It had no idea about the clock sources of the other states. It still needs clock driver to take care of that.

The clock source id (0x8) means PLLX_OUT0 in Tegra30. In Tegra114, it means PLLX_OUT0_LJ (low jitter). It's not available at this moment. I can switch it to PLLX_OUT0 (0xe) for Tegra114 too. The code may like below.

Quoted 9 lines
Quoted 7 lines

Review

Quoted 7 lines
(quoted diff) +5 -2
-     mov32   r4, ((1 << 28) | (0x8)) @ burst policy is PLLX
-     str     r4, [r0, #CLK_RESET_CCLK_BURST]
+     cmp     r10, #TEGRA30
+     movweq  r4, #:lower16:((1 << 28) | (0x8))
+     movteq  r4, #:upper16:((1 << 28) | (0x8))
+	movwne  r4, #:lower16:((1 << 28) | (0xe))
+	movteq  r4, #:upper16:((1 << 28) | (0xe))

I assume that should be movtne.

Ah, yes.

Quoted 9 lines
Quoted 6 lines
Quoted 2 lines

+ str r4, [r0, #CLK_RESET_CCLK_BURST]

I had tested this code before I sent this series. It didn't impact or improve the resuming performance. So I removed them.
Do you want me to add them back?

I think adding that code back would make sense. It would mean the code works fundamentally the same way for all SoCs.

OK.

Quoted 5 lines

BTW, you mentioned that LP1 resume takes 10-15 seconds on Dalmore. Are you sure this isn't because the above code is missing, and hence the CPU keeps running at 32KHz or the crystal speed, since nothing restores the CPU clock source until much later, when the syscore op runs?

It's due to the long time that SDRAM leaves self-refresh. Looks something that related to BCT not be flashed during the flashing process. Please also check the internal bug 1314918.

Quoted 32 lines
Quoted 26 lines
Quoted 18 lines

However, none of this explains why the CPU clock restore logic on Tegra114 needs to be a syscore_op, rather than simply having tegra30_lp1_reset() execute some Tegra114-specific code.

Re-writing the part of the patch I quoted above in C, it looks like:

if (soc is tegra30)
write to CLK_RESET_CCLK_BURST to select pllx

Instead of making that code do nothing on Tegra114, why can't that code be:

if (soc is tegra30)
write to CLK_RESET_CCLK_BURST to re-select pllx
else
write to G-cluster-specific register to restore saved value write to LP-cluster-specific register to restore saved value

Quoted 8 lines

or:

if (soc is tegra30)
write to CLK_RESET_CCLK_BURST to re-select pllx
else
write to G-cluster-specific register to re-select pllx/dfll/... write to LP-cluster-specific register to restore ...

Quoted 3 lines

Hope the explanation above is enough for you. The low level code had no idea of clock source of each CPU state in BURST_POLICY register. It needs to be done by clk driver itself.

I still have absolutely no idea why Tegra30 and Tegra114 are different.

Quoted 8 lines

You mentioned something about this low-level code only manipulating the IDLE state, and the clock driver needing to restore the other 4 states. This raises yet more questions:

1) Do we not need to restore the other 4 states on Tegra30? If not, why not? If we do, presumably Tegra30 (and Tegra20?) need to the syscore_op this patch series adds to Tegra114 only? If we don't, then why does Tegra114 have to restore them?

We need to restore all of them for all Tegra chips. For Tegra20/30, we had done it in the tegra_cpu_car_ops.suspend/resume. For Tegra114, the patch was here.

The other reason is:
1) The PLLX is the main CPU clock source in Tegra20/30. We can restore it ASAP to get a better performance.
2) For Tegra114, the PLLX is the CPU clock source when CPU runs at low rates. When CPU in high rate, it uses DFLL as clock source. So it depends on what the clock source of the CPU when it goes into suspend. And the DFLL has its own resume code, it needs to be restored before the CPU uses it as clock source again. It makes the CPU clock restore sequence like this.

Quoted 2 lines

2) What triggers the HW to switch from IDLE to RUN state?

I also want to know more detail about it. The TRM only said it decided by HW and gave an example about when switching to IRQ or FIQ state.

Quoted 7 lines

In other
words, I think you're saying that the existing Tegra30 code:

	mov32	r4, ((1 << 28) | (0x8))	@ burst policy is PLLX
	str	r4, [r0, #CLK_RESET_CCLK_BURST]

doesn't change the clock rate right away. When does it change?

The code before this is the PLLX re-enable code. Then it switches to PLLX. The rate is still kept the same when it suspended. The next rate change after resume would be happened in the CPUfreq driver.

Quoted 3 lines

Related, when tegra30_switch_cpu_to_clk32k() sets the CPU clock source for the IDLE state to clk_s, when does that switch actually take place?

After the PLLs was disabled, only SCLK switched to CLK_S, the CPU and MSELECT still keep in CLK_M. Because the CPU would be powered off immediately.

Quoted 3 lines

That function appears to assume it happens immediately, since it immediately disables the PLLs that might have been the previous CPU clock source. Perhaps this is what the MSELECT register writes do?

Yes, switching them to the Oscillator before disabling the PLLs.

Quoted 3 lines

I
guess not since there's only 1 MSELECT write in tegra_lp1_reset() and two changes of CPU clock source.

#20 lore raw

PATCH 3/8 clk: tegra114: add LP1 suspend/resume support

Quoted 1 line · Joseph Lo

On Thu, 2013-08-08 at 00:46 +0800, Stephen Warren wrote:

..

Quoted 15 lines
Quoted 10 lines

I still have absolutely no idea why Tegra30 and Tegra114 are different.

You mentioned something about this low-level code only manipulating the IDLE state, and the clock driver needing to restore the other 4 states. This raises yet more questions:

1) Do we not need to restore the other 4 states on Tegra30? If not, why not? If we do, presumably Tegra30 (and Tegra20?) need to the syscore_op this patch series adds to Tegra114 only? If we don't, then why does Tegra114 have to restore them?

We need to restore all of them for all Tegra chips. For Tegra20/30, we had done it in the tegra_cpu_car_ops.suspend/resume. For Tegra114, the patch was here.

Quoted 9 lines

The other reason is:
1) The PLLX is the main CPU clock source in Tegra20/30. We can restore it ASAP to get a better performance.
2) For Tegra114, the PLLX is the CPU clock source when CPU runs at low rates. When CPU in high rate, it uses DFLL as clock source. So it depends on what the clock source of the CPU when it goes into suspend. And the DFLL has its own resume code, it needs to be restored before the CPU uses it as clock source again. It makes the CPU clock restore sequence like this.

So, we don't yet support the DFLL upstream. Presumably, the CPU is always running off PLLX on Tegra114 upstream right now. As such, we can hard-code that into the resume path just like we do on earlier chips, i.e. using tegra_cpu_car_ops.resume().

Once we do get DFLL support, presumably the DFLL resume path can switch the register from PLLX to DFLL, and we still won't need a custom syscore_ops.

Will that work?

Quoted 8 lines
Quoted 1 line

2) What triggers the HW to switch from IDLE to RUN state?

I also want to know more detail about it. The TRM only said it decided by HW and gave an example about when switching to IRQ or FIQ state.

Quoted 3 lines

In other
words, I think you're saying that the existing Tegra30 code:

Quoted 8 lines
Quoted 4 lines
	mov32	r4, ((1 << 28) | (0x8))	@ burst policy is PLLX
	str	r4, [r0, #CLK_RESET_CCLK_BURST]

doesn't change the clock rate right away. When does it change?

The code before this is the PLLX re-enable code. Then it switches to PLLX. The rate is still kept the same when it suspended. The next rate change after resume would be happened in the CPUfreq driver.

Sorry, when I wrote "doesn't change the clock rate right away", I really meant "doesn't change the clock *source* right away".

author
#21 lore raw

PATCH 3/8 clk: tegra114: add LP1 suspend/resume support

Quoted 33 lines · Stephen Warren
Quoted 1 line · Joseph Lo

On Thu, 2013-08-08 at 00:46 +0800, Stephen Warren wrote:

..

Quoted 15 lines
Quoted 10 lines

I still have absolutely no idea why Tegra30 and Tegra114 are different.

You mentioned something about this low-level code only manipulating the IDLE state, and the clock driver needing to restore the other 4 states. This raises yet more questions:

1) Do we not need to restore the other 4 states on Tegra30? If not, why not? If we do, presumably Tegra30 (and Tegra20?) need to the syscore_op this patch series adds to Tegra114 only? If we don't, then why does Tegra114 have to restore them?

We need to restore all of them for all Tegra chips. For Tegra20/30, we had done it in the tegra_cpu_car_ops.suspend/resume. For Tegra114, the patch was here.

Quoted 9 lines

The other reason is:
1) The PLLX is the main CPU clock source in Tegra20/30. We can restore it ASAP to get a better performance.
2) For Tegra114, the PLLX is the CPU clock source when CPU runs at low rates. When CPU in high rate, it uses DFLL as clock source. So it depends on what the clock source of the CPU when it goes into suspend. And the DFLL has its own resume code, it needs to be restored before the CPU uses it as clock source again. It makes the CPU clock restore sequence like this.

So, we don't yet support the DFLL upstream. Presumably, the CPU is always running off PLLX on Tegra114 upstream right now. As such, we can hard-code that into the resume path just like we do on earlier chips, i.e. using tegra_cpu_car_ops.resume().

Quoted 5 lines

Once we do get DFLL support, presumably the DFLL resume path can switch the register from PLLX to DFLL, and we still won't need a custom syscore_ops.

Will that work?

Hmm. If we can implement DFLL resume code there, that may be work. But I can't confirm right now. I can move them to tegra_cpu_car_ops for now. We can re-visit this later when we get more function to support.

Thanks,
Joseph

author
#22 lore raw

PATCH 3/8 clk: tegra114: add LP1 suspend/resume support

In reply to Stephen Warren
Quoted 9 lines · Stephen Warren
Quoted 8 lines · Joseph Lo
Quoted 7 lines · Stephen Warren
Quoted 6 lines · Joseph Lo
Quoted 5 lines · Stephen Warren
Quoted 3 lines · Joseph Lo

When the system suspends to LP1, the clock of the CPU would be switched to CLK_M (12MHz Oscillator) during suspend/resume flow. The clock driver needs to restore the clock of CPU after LP1 resume.

[snip]

Quoted 21 lines
Quoted 16 lines
Quoted 11 lines
Quoted 10 lines
Quoted 1 line

Why don't Tegra20/30 need a similar change?

For Tegra20/30, the same code had been implemented in the suspend/resume function of tegra_cpu_car_ops. It restores the CPU clock ASAP when CPU resume from a suspend state to get quick performance I believe.

For Tegra114, the resume performance is cool (although we can't see it in upstream kernel now, it still need some other functions.). We can implement all the clock related suspend/resume function in the clock driver.

Quoted 4 lines

OK, I do see something similar in tegra20/30_cpu_clock_suspend/resume. Why can't this new code be part of the equivalent functions; does the Tegra114 suspend/resume code in mach-tegra/ not call tegra_cpu_car_ops.suspend/resume() in the same way it does on Tegra20/30?

Quoted 4 lines

One of the main reasons is due to DFLL clock. The CPU clock of Tegra114 is going to switch to DFLL to a get higher clock rate. But it depends some other HW (i.e. I2C), we can't resume it so early when the CPU just resume like we did in tegra_cpu_car_ops.suspend/resume for Tegra20/30.

Quoted 4 lines

Is there a guarantee that the syscore_ops are run after the call to tegar_cpu_car_ops.resume() would be? Perhaps the mach-tegra/ code should simply call tegra_cpu_car_ops.resume() later on Tegra114 than it does on earlier chips, so it's run at a suitable time?

Yes, the tegra_cpu_car_ops.suspend/resume() is hooked to suspend_cpu_complex()/resuem_cpu_complex() that in the "pm.c" file. It would be the final/first function be invoked when system suspend/resume.

author
#23 lore raw

PATCH 4/8 ARM: tegra: add common LP1 suspend support

In reply to Joseph Lo

The LP1 suspending mode on Tegra means CPU rail off, devices and PLLs are clock gated and SDRAM in self-refresh mode. That means the low level LP1 suspending and resuming code couldn't be run on DRAM and the CPU must switch to the always on clock domain (a.k.a. CLK_M 12MHz oscillator). And the system clock (SCLK) would be switched to CLK_S, a 32KHz oscillator. The LP1 low level handling code need to be moved to IRAM area first. And marking the LP1 mask for indicating the Tegra device is in LP1. The CPU power timer needs to be re-calculated based on 32KHz that was originally based on PCLK.

When resuming from LP1, the LP1 reset handler will resume PLLs and then put DRAM to normal mode. Then jumping to the "tegra_resume" that will restore full context before back to kernel. The "tegra_resume" handler was expected to be found in PMC_SCRATCH41 register.

This is common LP1 procedures for Tegra, so we do these jobs mainly in this patch:
* moving LP1 low level handling code to IRAM
* marking LP1 mask
* copying the physical address of "tegra_resume" to PMC_SCRATCH41
* re-calculate the CPU power timer based on 32KHz

---
 arch/arm/mach-tegra/pm.c    | 97 ++++++++++++++++++++++++++++++++++++++++++---
 arch/arm/mach-tegra/pm.h    |  7 ++++
 arch/arm/mach-tegra/pmc.c   | 20 +++++++++-
 arch/arm/mach-tegra/pmc.h   |  3 ++
 arch/arm/mach-tegra/reset.h |  4 ++
 5 files changed, 125 insertions(+), 6 deletions(-)
arch/arm/mach-tegra/pm.c +92 -5
index 5792872..45c9516 100644
@@ -37,12 +37,18 @@
 #include "reset.h"
 #include "flowctrl.h"
 #include "fuse.h"
+#include "pm.h"
 #include "pmc.h"
 #include "sleep.h"
 
 #ifdef CONFIG_PM_SLEEP
 static DEFINE_SPINLOCK(tegra_lp2_lock);
+static void __iomem *iram_code = IO_ADDRESS(TEGRA_IRAM_CODE_AREA);
+static u32 iram_save_size;
+static void *iram_save_addr;
+struct tegra_lp1_iram *tegra_lp1_iram;
 void (*tegra_tear_down_cpu)(void);
+void (*tegra_sleep_core_finish)(unsigned long v2p);
 
 static void tegra_tear_down_cpu_init(void)
 {
@@ -174,14 +180,75 @@ enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
 				enum tegra_suspend_mode mode)
 {
 	/*
-	 * The Tegra devices only support suspending to LP2 currently.
+	 * The Tegra devices only support suspending to LP1 currently.
 	 */
-	if (mode > TEGRA_SUSPEND_LP2)
-		return TEGRA_SUSPEND_LP2;
+	if (mode > TEGRA_SUSPEND_LP1)
+		return TEGRA_SUSPEND_LP1;
 
 	return mode;
 }
 
+static int tegra_sleep_core(unsigned long v2p)
+{
+	setup_mm_for_reboot();
+	tegra_sleep_core_finish(v2p);
+
+	/* should never here */
+	BUG();
+
+	return 0;
+}
+
+/*
+ * tegra_lp1_iram_hook
+ *
+ * Hooking the address of LP1 reset vector and SDRAM self-refresh code in
+ * SDRAM. These codes not be copied to IRAM in this fuction. We need to
+ * copy these code to IRAM before LP0/LP1 suspend and restore the content
+ * of IRAM after resume.
+ */
+static bool tegra_lp1_iram_hook(void)
+{
+	if (!tegra_lp1_iram)
+		return false;
+
+	iram_save_size = tegra_lp1_iram->end_addr - tegra_lp1_iram->start_addr;
+	iram_save_addr = kmalloc(iram_save_size, GFP_KERNEL);
+	if (!iram_save_addr)
+		return false;
+
+	return true;
+}
+
+static bool tegra_sleep_core_init(void)
+{
+	if (!tegra_sleep_core_finish)
+		return false;
+
+	return true;
+}
+
+static void tegra_suspend_enter_lp1(void)
+{
+	tegra_pmc_suspend();
+
+	/* copy the reset vector & SDRAM shutdown code into IRAM */
+	memcpy(iram_save_addr, iram_code, iram_save_size);
+	memcpy(iram_code, tegra_lp1_iram->start_addr, iram_save_size);
+
+	*((u32 *)tegra_cpu_lp1_mask) = 1;
+}
+
+static void tegra_suspend_exit_lp1(void)
+{
+	tegra_pmc_resume();
+
+	/* restore IRAM */
+	memcpy(iram_code, iram_save_addr, iram_save_size);
+
+	*(u32 *)tegra_cpu_lp1_mask = 0;
+}
+
 static const char *lp_state[TEGRA_MAX_SUSPEND_MODE] = {
 	[TEGRA_SUSPEND_NONE] = "none",
 	[TEGRA_SUSPEND_LP2] = "LP2",
@@ -205,6 +272,9 @@ static int tegra_suspend_enter(suspend_state_t state)
 
 	suspend_cpu_complex();
 	switch (mode) {
+	case TEGRA_SUSPEND_LP1:
+		tegra_suspend_enter_lp1();
+		break;
 	case TEGRA_SUSPEND_LP2:
 		tegra_set_cpu_in_lp2();
 		break;
@@ -212,9 +282,15 @@ static int tegra_suspend_enter(suspend_state_t state)
 		break;
 	}
 
-	cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
+	if (mode == TEGRA_SUSPEND_LP2)
+		cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
+	else
+		cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_core);
 
 	switch (mode) {
+	case TEGRA_SUSPEND_LP1:
+		tegra_suspend_exit_lp1();
+		break;
 	case TEGRA_SUSPEND_LP2:
 		tegra_clear_cpu_in_lp2();
 		break;
@@ -235,12 +311,23 @@ static const struct platform_suspend_ops tegra_suspend_ops = {
 
 void __init tegra_init_suspend(void)
 {
-	if (tegra_pmc_get_suspend_mode() == TEGRA_SUSPEND_NONE)
+	enum tegra_suspend_mode mode = tegra_pmc_get_suspend_mode();
+
+	if (mode == TEGRA_SUSPEND_NONE)
 		return;
 
 	tegra_tear_down_cpu_init();
 	tegra_pmc_suspend_init();
 
+	if (mode >= TEGRA_SUSPEND_LP1) {
+		if (!tegra_lp1_iram_hook() || !tegra_sleep_core_init()) {
+			pr_err("%s: unable to allocate memory for SDRAM"
+			       "self-refresh -- LP0/LP1 unavailable\n",
+			       __func__);
+			tegra_pmc_set_suspend_mode(TEGRA_SUSPEND_LP2);
+		}
+	}
+
 	suspend_set_ops(&tegra_suspend_ops);
 }
 #endif
arch/arm/mach-tegra/pm.h +7 -0
index 94c4b9d..3cb9309 100644
@@ -23,6 +23,13 @@
 
 #include "pmc.h"
 
+struct tegra_lp1_iram {
+	void	*start_addr;
+	void	*end_addr;
+};
+extern struct tegra_lp1_iram *tegra_lp1_iram;
+extern void (*tegra_sleep_core_finish)(unsigned long v2p);
+
 extern unsigned long l2x0_saved_regs_addr;
 
 void save_cpu_arch_register(void);
arch/arm/mach-tegra/pmc.c +19 -1
index 018bc87..dff239f 100644
@@ -196,10 +196,28 @@ enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
 	return pmc_pm_data.suspend_mode;
 }
 
+void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
+{
+	if (mode < TEGRA_SUSPEND_NONE || mode >= TEGRA_MAX_SUSPEND_MODE)
+		return;
+
+	pmc_pm_data.suspend_mode = mode;
+}
+
+void tegra_pmc_suspend(void)
+{
+	tegra_pmc_writel(virt_to_phys(tegra_resume), PMC_SCRATCH41);
+}
+
+void tegra_pmc_resume(void)
+{
+	tegra_pmc_writel(0x0, PMC_SCRATCH41);
+}
+
 void tegra_pmc_pm_set(enum tegra_suspend_mode mode)
 {
 	u32 reg, csr_reg;
-	unsigned long rate = 0;
+	unsigned long rate = 32768;
 
 	reg = tegra_pmc_readl(PMC_CTRL);
 	reg |= TEGRA_POWER_CPU_PWRREQ_OE;
arch/arm/mach-tegra/pmc.h +3 -0
index e1c2df2..549f8c7 100644
@@ -28,6 +28,9 @@ enum tegra_suspend_mode {
 
 #ifdef CONFIG_PM_SLEEP
 enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void);
+void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode);
+void tegra_pmc_suspend(void);
+void tegra_pmc_resume(void);
 void tegra_pmc_pm_set(enum tegra_suspend_mode mode);
 void tegra_pmc_suspend_init(void);
 #endif
arch/arm/mach-tegra/reset.h +4 -0
index c90d8e9..76a9343 100644
@@ -39,6 +39,10 @@ void __tegra_cpu_reset_handler_end(void);
 void tegra_secondary_startup(void);
 
 #ifdef CONFIG_PM_SLEEP
+#define tegra_cpu_lp1_mask \
+	(IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
+	((u32)&__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_LP1] - \
+	 (u32)__tegra_cpu_reset_handler_start)))
 #define tegra_cpu_lp2_mask \
 	(IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
 	((u32)&__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_LP2] - \
Signature · 1 line
1.8.3.4
#24 lore raw

PATCH 4/8 ARM: tegra: add common LP1 suspend support

Quoted 11 lines · Joseph Lo

The LP1 suspending mode on Tegra means CPU rail off, devices and PLLs are clock gated and SDRAM in self-refresh mode. That means the low level LP1 suspending and resuming code couldn't be run on DRAM and the CPU must switch to the always on clock domain (a.k.a. CLK_M 12MHz oscillator). And the system clock (SCLK) would be switched to CLK_S, a 32KHz oscillator. The LP1 low level handling code need to be moved to IRAM area first. And marking the LP1 mask for indicating the Tegra device is in LP1. The CPU power timer needs to be re-calculated based on 32KHz that was originally based on PCLK.

arch/arm/mach-tegra/pm.c line 51

Quoted 9 lines
arch/arm/mach-tegra/pm.c +5 -0
 
 #ifdef CONFIG_PM_SLEEP
 static DEFINE_SPINLOCK(tegra_lp2_lock);
+static void __iomem *iram_code = IO_ADDRESS(TEGRA_IRAM_CODE_AREA);
+static u32 iram_save_size;
+static void *iram_save_addr;
+struct tegra_lp1_iram *tegra_lp1_iram;
 void (*tegra_tear_down_cpu)(void);
+void (*tegra_sleep_core_finish)(unsigned long v2p);

I'm not sure all of those are required to be global variables. For example, iram_code is just a constant, so you could easily just use it directly in code.

arch/arm/mach-tegra/pm.c enum tegra_suspend_mode tegra_pm_validate_suspend_mode( · line 183

Quoted 6 lines
arch/arm/mach-tegra/pm.c +1 -1
@@ -174,14 +180,75 @@ enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
 				enum tegra_suspend_mode mode)
 {
 	/*
-	 * The Tegra devices only support suspending to LP2 currently.
+	 * The Tegra devices only support suspending to LP1 currently.

That now says that only LP1 is supported. That's not true; both LP1 and LP2 are supported. How about s/LP1/LP1 or lower/ or s:LP1:LP1/LP2: ?

arch/arm/mach-tegra/pm.c enum tegra_suspend_mode tegra_pm_validate_suspend_mode( · line 229

Quoted 7 lines
arch/arm/mach-tegra/pm.c +7 -0
+static bool tegra_sleep_core_init(void)
+{
+	if (!tegra_sleep_core_finish)
+		return false;
+
+	return true;
+}

That function seems a little pointless. Why not just check the value of tegra_sleep_core_finish directly in tegra_init_suspend()?

Quoted 10 lines
arch/arm/mach-tegra/pm.c +10 -0
+static void tegra_suspend_enter_lp1(void)
+{
+	tegra_pmc_suspend();
+
+	/* copy the reset vector & SDRAM shutdown code into IRAM */
+	memcpy(iram_save_addr, iram_code, iram_save_size);
+	memcpy(iram_code, tegra_lp1_iram->start_addr, iram_save_size);
+
+	*((u32 *)tegra_cpu_lp1_mask) = 1;
+}

arch/arm/mach-tegra/pm.c enum tegra_suspend_mode tegra_pm_validate_suspend_mode( · line 250

Quoted 10 lines
arch/arm/mach-tegra/pm.c +10 -0
+
+static void tegra_suspend_exit_lp1(void)
+{
+	tegra_pmc_resume();
+
+	/* restore IRAM */
+	memcpy(iram_code, iram_save_addr, iram_save_size);
+
+	*(u32 *)tegra_cpu_lp1_mask = 0;
+}

I'm not really sure I like that, but I suppose it's OK. It sure seems like a performance limiter, but I suppose LP1 is so slow it doesn't matter, due to the need to ramp power rails, PLLs, SDRAM controller, etc.

It'd be nice to simply reserve more IRAM for the kernel's use. Right now, only 1K is reserved, and presumably the code running on the AVP can't use the rest of that page anyway, or can it?

arch/arm/mach-tegra/pm.c static int tegra_suspend_enter(suspend_state_t state) · line 288

Quoted 9 lines
arch/arm/mach-tegra/pm.c +4 -1
@@ -212,9 +282,15 @@ static int tegra_suspend_enter(suspend_state_t state)
 		break;
 	}
 
-	cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
+	if (mode == TEGRA_SUSPEND_LP2)
+		cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
+	else
+		cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_core);

Nit: It might be slightly simpler to simply calculate the parameter to cpu_suspend(), but then take the same code-path:

if (mode == TEGRA_SUSPEND_LP2)

	sleep_func = tegra_sleep_cpu;
else
	sleep_func = tegra_sleep_core;

cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, sleep_func);

That way, it's a little more obvious that the code always calls cpu_suspend() in the same way, but simply passes a different function to it to power things down at the end.

arch/arm/mach-tegra/pmc.c enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void) · line 220

Quoted 7 lines
arch/arm/mach-tegra/pmc.c +1 -1
 
 void tegra_pmc_pm_set(enum tegra_suspend_mode mode)
 {
 	u32 reg, csr_reg;
-	unsigned long rate = 0;
+	unsigned long rate = 32768;

That's LP1-specific. You should add a "case TEGRA_SUSPEND_LP1:" to the switch statement that calculates rate instead; after all, that's the whole point of having that switch statement.

author
#25 lore raw

PATCH 4/8 ARM: tegra: add common LP1 suspend support

Quoted 13 lines · Stephen Warren
Quoted 11 lines · Joseph Lo

The LP1 suspending mode on Tegra means CPU rail off, devices and PLLs are clock gated and SDRAM in self-refresh mode. That means the low level LP1 suspending and resuming code couldn't be run on DRAM and the CPU must switch to the always on clock domain (a.k.a. CLK_M 12MHz oscillator). And the system clock (SCLK) would be switched to CLK_S, a 32KHz oscillator. The LP1 low level handling code need to be moved to IRAM area first. And marking the LP1 mask for indicating the Tegra device is in LP1. The CPU power timer needs to be re-calculated based on 32KHz that was originally based on PCLK.

arch/arm/mach-tegra/pm.c +0 -0
Quoted 13 lines

arch/arm/mach-tegra/pm.c line 51

Quoted 8 lines

#ifdef CONFIG_PM_SLEEP
static DEFINE_SPINLOCK(tegra_lp2_lock);

arch/arm/mach-tegra/pm.c +5 -0
+static void __iomem *iram_code = IO_ADDRESS(TEGRA_IRAM_CODE_AREA);
+static u32 iram_save_size;
+static void *iram_save_addr;
+struct tegra_lp1_iram *tegra_lp1_iram;
 void (*tegra_tear_down_cpu)(void);
+void (*tegra_sleep_core_finish)(unsigned long v2p);

I'm not sure all of those are required to be global variables. For example, iram_code is just a constant, so you could easily just use it directly in code.

All of them does not mean the same thing. The LP1 resume code was built in kernel image and store in RAM.
The tegra_lp1_iram hooks the LP1 resume code for different chips. Before LP1 suspend, the original stuffs that in the area of IRAM would be store in the iram_save_addr (RAM). Then copy the LP1 resume code to iram_code area (IRAM).

Quoted 11 lines

arch/arm/mach-tegra/pm.c enum tegra_suspend_mode tegra_pm_validate_suspend_mode( · line 229

Quoted 7 lines
arch/arm/mach-tegra/pm.c +7 -0
+static bool tegra_sleep_core_init(void)
+{
+	if (!tegra_sleep_core_finish)
+		return false;
+
+	return true;
+}

That function seems a little pointless. Why not just check the value of tegra_sleep_core_finish directly in tegra_init_suspend()?

I will add some code that wraps to different SoC later. We add some common code for LP1 support here, but it didn't support by the chip yet. Does that OK or should I move it to the next patch?

Quoted 16 lines
Quoted 16 lines
arch/arm/mach-tegra/pm.c +16 -0
+static void tegra_suspend_enter_lp1(void)
+{
+	tegra_pmc_suspend();
+
+	/* copy the reset vector & SDRAM shutdown code into IRAM */
+	memcpy(iram_save_addr, iram_code, iram_save_size);
+	memcpy(iram_code, tegra_lp1_iram->start_addr, iram_save_size);
+
+	*((u32 *)tegra_cpu_lp1_mask) = 1;
+}
+
+static void tegra_suspend_exit_lp1(void)
+{
+	tegra_pmc_resume();
+
+	/* restore IRAM */
Quoted 9 lines

arch/arm/mach-tegra/pm.c enum tegra_suspend_mode tegra_pm_validate_suspend_mode( · line 250

Quoted 4 lines
arch/arm/mach-tegra/pm.c +4 -0
+	memcpy(iram_code, iram_save_addr, iram_save_size);
+
+	*(u32 *)tegra_cpu_lp1_mask = 0;
+}

I'm not really sure I like that, but I suppose it's OK. It sure seems like a performance limiter, but I suppose LP1 is so slow it doesn't matter, due to the need to ramp power rails, PLLs, SDRAM controller, etc.

That's why we only back up the code size that exactly same with the LP1 resume code of the SoC.

Quoted 3 lines

It'd be nice to simply reserve more IRAM for the kernel's use. Right now, only 1K is reserved, and presumably the code running on the AVP can't use the rest of that page anyway, or can it?

The LP1 resume code still running on the CPU (The LP0 would resume from AVP).

Quoted 15 lines

arch/arm/mach-tegra/pm.c static int tegra_suspend_enter(suspend_state_t state) · line 288

Quoted 10 lines
arch/arm/mach-tegra/pm.c +4 -1
@@ -212,9 +282,15 @@ static int tegra_suspend_enter(suspend_state_t state)
 		break;
 	}
 
-	cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
+	if (mode == TEGRA_SUSPEND_LP2)
+		cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
+	else
+		cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_core);

Nit: It might be slightly simpler to simply calculate the parameter to cpu_suspend(), but then take the same code-path:

if (mode == TEGRA_SUSPEND_LP2)

Quoted 8 lines
	sleep_func = tegra_sleep_cpu;
else
	sleep_func = tegra_sleep_core;

cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, sleep_func);

That way, it's a little more obvious that the code always calls cpu_suspend() in the same way, but simply passes a different function to it to power things down at the end.

OK. Will do.

Quoted 12 lines

arch/arm/mach-tegra/pmc.c enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void) · line 220

Quoted 8 lines
arch/arm/mach-tegra/pmc.c +1 -1
 
 void tegra_pmc_pm_set(enum tegra_suspend_mode mode)
 {
 	u32 reg, csr_reg;
-	unsigned long rate = 0;
+	unsigned long rate = 32768;

That's LP1-specific. You should add a "case TEGRA_SUSPEND_LP1:" to the switch statement that calculates rate instead; after all, that's the whole point of having that switch statement.

Will fix.

#26 lore raw

PATCH 4/8 ARM: tegra: add common LP1 suspend support

Quoted 27 lines · Joseph Lo
Quoted 13 lines · Stephen Warren
Quoted 11 lines · Joseph Lo

The LP1 suspending mode on Tegra means CPU rail off, devices and PLLs are clock gated and SDRAM in self-refresh mode. That means the low level LP1 suspending and resuming code couldn't be run on DRAM and the CPU must switch to the always on clock domain (a.k.a. CLK_M 12MHz oscillator). And the system clock (SCLK) would be switched to CLK_S, a 32KHz oscillator. The LP1 low level handling code need to be moved to IRAM area first. And marking the LP1 mask for indicating the Tegra device is in LP1. The CPU power timer needs to be re-calculated based on 32KHz that was originally based on PCLK.

arch/arm/mach-tegra/pm.c +0 -0
Quoted 12 lines

arch/arm/mach-tegra/pm.c line 51

Quoted 8 lines

#ifdef CONFIG_PM_SLEEP
static DEFINE_SPINLOCK(tegra_lp2_lock);

arch/arm/mach-tegra/pm.c +5 -0
+static void __iomem *iram_code = IO_ADDRESS(TEGRA_IRAM_CODE_AREA);
+static u32 iram_save_size;
+static void *iram_save_addr;
+struct tegra_lp1_iram *tegra_lp1_iram;
 void (*tegra_tear_down_cpu)(void);
+void (*tegra_sleep_core_finish)(unsigned long v2p);

I'm not sure all of those are required to be global variables. For example, iram_code is just a constant, so you could easily just use it directly in code.

Quoted 6 lines

All of them does not mean the same thing. The LP1 resume code was built in kernel image and store in RAM.
The tegra_lp1_iram hooks the LP1 resume code for different chips. Before LP1 suspend, the original stuffs that in the area of IRAM would be store in the iram_save_addr (RAM). Then copy the LP1 resume code to iram_code area (IRAM).

Sure, some of those variable may differ based on the SoC at runtime etc.

But at least the value of iram_code never changes, right?

Quoted 11 lines
Quoted 10 lines

arch/arm/mach-tegra/pm.c enum tegra_suspend_mode tegra_pm_validate_suspend_mode( · line 229

Quoted 7 lines
arch/arm/mach-tegra/pm.c +7 -0
+static bool tegra_sleep_core_init(void)
+{
+	if (!tegra_sleep_core_finish)
+		return false;
+
+	return true;
+}

That function seems a little pointless. Why not just check the value of tegra_sleep_core_finish directly in tegra_init_suspend()?

Quoted 3 lines

I will add some code that wraps to different SoC later. We add some common code for LP1 support here, but it didn't support by the chip yet. Does that OK or should I move it to the next patch?

OK, I see this is enhanced immediately in the next patch, so it's fine.

Quoted 28 lines
Quoted 16 lines
Quoted 16 lines
arch/arm/mach-tegra/pm.c +16 -0
+static void tegra_suspend_enter_lp1(void)
+{
+	tegra_pmc_suspend();
+
+	/* copy the reset vector & SDRAM shutdown code into IRAM */
+	memcpy(iram_save_addr, iram_code, iram_save_size);
+	memcpy(iram_code, tegra_lp1_iram->start_addr, iram_save_size);
+
+	*((u32 *)tegra_cpu_lp1_mask) = 1;
+}
+
+static void tegra_suspend_exit_lp1(void)
+{
+	tegra_pmc_resume();
+
+	/* restore IRAM */
Quoted 8 lines

arch/arm/mach-tegra/pm.c enum tegra_suspend_mode tegra_pm_validate_suspend_mode( · line 250

Quoted 4 lines
arch/arm/mach-tegra/pm.c +4 -0
+	memcpy(iram_code, iram_save_addr, iram_save_size);
+
+	*(u32 *)tegra_cpu_lp1_mask = 0;
+}

I'm not really sure I like that, but I suppose it's OK. It sure seems like a performance limiter, but I suppose LP1 is so slow it doesn't matter, due to the need to ramp power rails, PLLs, SDRAM controller, etc.

That's why we only back up the code size that exactly same with the LP1 resume code of the SoC.

Quoted 6 lines
Quoted 3 lines

It'd be nice to simply reserve more IRAM for the kernel's use. Right now, only 1K is reserved, and presumably the code running on the AVP can't use the rest of that page anyway, or can it?

The LP1 resume code still running on the CPU (The LP0 would resume from AVP).

Sure. However, if the AVP never touched the IRAM region where the LP1 resume code is placed, we would only need to copy the LP1 resume code to IRAM once at kernel boot time, rather than every time we enter/leave LP1.

I guess the idea is that once we have an AVP driver, we will force the AVP to suspend first, save the IRAM that it might have been using, do the system suspend/resume, then restore the IRAM. And that changing that sequence so that the AVP never ever touched the LP1 IRAM area would require AVP firmware changes that we can't make?

author
#27 lore raw

PATCH 4/8 ARM: tegra: add common LP1 suspend support

Quoted 35 lines · Stephen Warren
Quoted 27 lines · Joseph Lo
Quoted 13 lines · Stephen Warren
Quoted 11 lines · Joseph Lo

The LP1 suspending mode on Tegra means CPU rail off, devices and PLLs are clock gated and SDRAM in self-refresh mode. That means the low level LP1 suspending and resuming code couldn't be run on DRAM and the CPU must switch to the always on clock domain (a.k.a. CLK_M 12MHz oscillator). And the system clock (SCLK) would be switched to CLK_S, a 32KHz oscillator. The LP1 low level handling code need to be moved to IRAM area first. And marking the LP1 mask for indicating the Tegra device is in LP1. The CPU power timer needs to be re-calculated based on 32KHz that was originally based on PCLK.

arch/arm/mach-tegra/pm.c +0 -0
Quoted 12 lines

arch/arm/mach-tegra/pm.c line 51

Quoted 8 lines

#ifdef CONFIG_PM_SLEEP
static DEFINE_SPINLOCK(tegra_lp2_lock);

arch/arm/mach-tegra/pm.c +5 -0
+static void __iomem *iram_code = IO_ADDRESS(TEGRA_IRAM_CODE_AREA);
+static u32 iram_save_size;
+static void *iram_save_addr;
+struct tegra_lp1_iram *tegra_lp1_iram;
 void (*tegra_tear_down_cpu)(void);
+void (*tegra_sleep_core_finish)(unsigned long v2p);

I'm not sure all of those are required to be global variables. For example, iram_code is just a constant, so you could easily just use it directly in code.

Quoted 6 lines

All of them does not mean the same thing. The LP1 resume code was built in kernel image and store in RAM.
The tegra_lp1_iram hooks the LP1 resume code for different chips. Before LP1 suspend, the original stuffs that in the area of IRAM would be store in the iram_save_addr (RAM). Then copy the LP1 resume code to iram_code area (IRAM).

Quoted 3 lines

Sure, some of those variable may differ based on the SoC at runtime etc.

But at least the value of iram_code never changes, right?

Yes.

Quoted 39 lines
Quoted 28 lines
Quoted 16 lines
Quoted 16 lines
arch/arm/mach-tegra/pm.c +16 -0
+static void tegra_suspend_enter_lp1(void)
+{
+	tegra_pmc_suspend();
+
+	/* copy the reset vector & SDRAM shutdown code into IRAM */
+	memcpy(iram_save_addr, iram_code, iram_save_size);
+	memcpy(iram_code, tegra_lp1_iram->start_addr, iram_save_size);
+
+	*((u32 *)tegra_cpu_lp1_mask) = 1;
+}
+
+static void tegra_suspend_exit_lp1(void)
+{
+	tegra_pmc_resume();
+
+	/* restore IRAM */
Quoted 8 lines

arch/arm/mach-tegra/pm.c enum tegra_suspend_mode tegra_pm_validate_suspend_mode( · line 250

Quoted 4 lines
arch/arm/mach-tegra/pm.c +4 -0
+	memcpy(iram_code, iram_save_addr, iram_save_size);
+
+	*(u32 *)tegra_cpu_lp1_mask = 0;
+}

I'm not really sure I like that, but I suppose it's OK. It sure seems like a performance limiter, but I suppose LP1 is so slow it doesn't matter, due to the need to ramp power rails, PLLs, SDRAM controller, etc.

That's why we only back up the code size that exactly same with the LP1 resume code of the SoC.

Quoted 6 lines
Quoted 3 lines

It'd be nice to simply reserve more IRAM for the kernel's use. Right now, only 1K is reserved, and presumably the code running on the AVP can't use the rest of that page anyway, or can it?

The LP1 resume code still running on the CPU (The LP0 would resume from AVP).

Sure. However, if the AVP never touched the IRAM region where the LP1 resume code is placed, we would only need to copy the LP1 resume code to IRAM once at kernel boot time, rather than every time we enter/leave LP1.

Quoted 5 lines

I guess the idea is that once we have an AVP driver, we will force the AVP to suspend first, save the IRAM that it might have been using, do the system suspend/resume, then restore the IRAM. And that changing that sequence so that the AVP never ever touched the LP1 IRAM area would require AVP firmware changes that we can't make?

Yes, exactly.

author
#28 lore raw

PATCH 5/8 ARM: tegra30: add LP1 suspend support

In reply to Joseph Lo

The LP1 suspend mode will power off the CPU, clock gated the PLLs and put SDRAM to self-refresh mode. Any interrupt can wake up device from LP1. The sequence when LP1 suspending:

* tunning off L1 data cache and the MMU
* storing some EMC registers, DPD (deep power down) status, clk source of mselect and SCLK burst policy
* putting SDRAM into self-refresh
* switching CPU to CLK_M (12MHz OSC)
* tunning off PLLM, PLLP, PLLA, PLLC and PLLX
* switching SCLK to CLK_S (32KHz OSC)
* shutting off the CPU rail

The sequence of LP1 resuming:

* re-enabling PLLM, PLLP, PLLA, PLLC and PLLX
* restoring the clk source of mselect and SCLK burst policy
* setting up CCLK burst policy to PLLX
* restoring DPD status and some EMC registers
* resuming SDRAM to normal mode
* jumping to the "tegra_resume" from PMC_SCRATCH41

Due to the SDRAM will be put into self-refresh mode, the low level procedures of LP1 suspending and resuming should be copied to TEGRA_IRAM_CODE_AREA (TEGRA_IRAM_BASE + SZ_4K) when suspending. Before restoring the CPU context when resuming, the SDRAM needs to be switched back to normal mode. And the PLLs need to be re-enabled, SCLK burst policy be restored, CCLK burst policy be set in PLLX. Then jumping to "tegra_resume" that was expected to be stored in PMC_SCRATCH41 to restore CPU context and back to kernel.

Based on the work by: Scott Williams <[email protected]>

---
 arch/arm/mach-tegra/Makefile        |   1 +
 arch/arm/mach-tegra/pm-tegra30.c    |  37 +++
 arch/arm/mach-tegra/pm.c            |  16 ++
 arch/arm/mach-tegra/pm.h            |   8 +
 arch/arm/mach-tegra/sleep-tegra30.S | 491 ++++++++++++++++++++++++++++++++++++
 arch/arm/mach-tegra/sleep.S         |   8 +-
 arch/arm/mach-tegra/sleep.h         |  16 ++
 7 files changed, 573 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm/mach-tegra/pm-tegra30.c
arch/arm/mach-tegra/Makefile +1 -0
index 98b184e..d341980 100644
@@ -22,6 +22,7 @@ obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= cpuidle-tegra20.o
 endif
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_speedo.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= sleep-tegra30.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= pm-tegra30.o
 ifeq ($(CONFIG_CPU_IDLE),y)
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= cpuidle-tegra30.o
 endif
arch/arm/mach-tegra/pm-tegra30.c new file +37 -0
new file mode 100644
index 0000000..6786955
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013, NVIDIA Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kernel.h>
+
+#include "pm.h"
+
+#ifdef CONFIG_PM_SLEEP
+static struct tegra_lp1_iram tegra30_lp1_iram;
+extern u32 tegra30_iram_start, tegra30_iram_end;
+extern void tegra30_sleep_core_finish(unsigned long);
+
+void tegra30_lp1_iram_hook(void)
+{
+	tegra30_lp1_iram.start_addr = &tegra30_iram_start;
+	tegra30_lp1_iram.end_addr = &tegra30_iram_end;
+
+	tegra_lp1_iram = &tegra30_lp1_iram;
+}
+
+void tegra30_sleep_core_init(void)
+{
+	tegra_sleep_core_finish = tegra30_sleep_core_finish;
+}
+#endif
arch/arm/mach-tegra/pm.c +16 -0
index 45c9516..77dbb22 100644
@@ -209,6 +209,14 @@ static int tegra_sleep_core(unsigned long v2p)
  */
 static bool tegra_lp1_iram_hook(void)
 {
+	switch (tegra_chip_id) {
+	case TEGRA30:
+		tegra30_lp1_iram_hook();
+		break;
+	default:
+		break;
+	}
+
 	if (!tegra_lp1_iram)
 		return false;
 
@@ -222,6 +230,14 @@ static bool tegra_lp1_iram_hook(void)
 
 static bool tegra_sleep_core_init(void)
 {
+	switch (tegra_chip_id) {
+	case TEGRA30:
+		tegra30_sleep_core_init();
+		break;
+	default:
+		break;
+	}
+
 	if (!tegra_sleep_core_finish)
 		return false;
 
arch/arm/mach-tegra/pm.h +8 -0
index 3cb9309..32d2898 100644
@@ -30,6 +30,14 @@ struct tegra_lp1_iram {
 extern struct tegra_lp1_iram *tegra_lp1_iram;
 extern void (*tegra_sleep_core_finish)(unsigned long v2p);
 
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+void tegra30_lp1_iram_hook(void);
+void tegra30_sleep_core_init(void);
+#else
+static inline void tegra30_lp1_iram_hook(void) {}
+static inline void void tegra30_sleep_core_init(void) {}
+#endif
+
 extern unsigned long l2x0_saved_regs_addr;
 
 void save_cpu_arch_register(void);
arch/arm/mach-tegra/sleep-tegra30.S +491 -0

520 lines not on this page · raw message

arch/arm/mach-tegra/sleep.S +4 -4
index 8388113..8d06213 100644
@@ -134,10 +134,10 @@ ENTRY(tegra_shut_off_mmu)
 #ifdef CONFIG_CACHE_L2X0
 	/* Disable L2 cache */
 	check_cpu_part_num 0xc09, r9, r10
-	movweq	r4, #:lower16:(TEGRA_ARM_PERIF_BASE + 0x3000)
-	movteq	r4, #:upper16:(TEGRA_ARM_PERIF_BASE + 0x3000)
-	moveq	r5, #0
-	streq	r5, [r4, #L2X0_CTRL]
+	movweq	r2, #:lower16:(TEGRA_ARM_PERIF_BASE + 0x3000)
+	movteq	r2, #:upper16:(TEGRA_ARM_PERIF_BASE + 0x3000)
+	moveq	r3, #0
+	streq	r3, [r2, #L2X0_CTRL]
 #endif
 	mov	pc, r0
 ENDPROC(tegra_shut_off_mmu)
arch/arm/mach-tegra/sleep.h +16 -0
index e7f8b6f..cfce981 100644
@@ -48,6 +48,22 @@
 #define TEGRA_FLUSH_CACHE_ALL	1
 
 #ifdef __ASSEMBLY__
+/* waits until the microsecond counter (base) ticks, for exact timing loops */
+.macro wait_for_us, rd, base, tmp
+	ldr	\rd, [\base]
+1001:	ldr	\tmp, [\base]
+	cmp	\rd, \tmp
+	beq	1001b
+.endm
+
+/* waits until the microsecond counter (base) is > rn */
+.macro wait_until, rn, base, tmp
+	add	\rn, \rn, #1
+1002:	ldr	\tmp, [\base]
+	cmp	\tmp, \rn
+	bmi	1002b
+.endm
+
 /* returns the offset of the flow controller halt register for a cpu */
 .macro cpu_to_halt_reg rd, rcpu
 	cmp	\rcpu, #0
Signature · 1 line
1.8.3.4
#29 lore raw

PATCH 5/8 ARM: tegra30: add LP1 suspend support

arch/arm/mach-tegra/pm-tegra30.c line 28

Quoted 10 lines · Joseph Lo

The LP1 suspend mode will power off the CPU, clock gated the PLLs and put SDRAM to self-refresh mode. Any interrupt can wake up device from LP1. The sequence when LP1 suspending:

arch/arm/mach-tegra/pm-tegra30.c +4 -0
 
+void tegra30_lp1_iram_hook(void)
+{
+	tegra30_lp1_iram.start_addr = &tegra30_iram_start;
+	tegra30_lp1_iram.end_addr = &tegra30_iram_end;

If you need to fill in the values in that struct dynamically anyway, why not make tegra_lp1_iram be a struct rather than a pointer, and write directly to it?

That said, aren't tegra30_iram_start constants that the linker can work out, so I think you can just initialize the structure at compile-time, and save some code.

arch/arm/mach-tegra/pm-tegra30.c line 36

Quoted 7 lines
arch/arm/mach-tegra/pm-tegra30.c +7 -0
+	tegra_lp1_iram = &tegra30_lp1_iram;
+}
+
+void tegra30_sleep_core_init(void)
+{
+	tegra_sleep_core_finish = tegra30_sleep_core_finish;
+}

Is there a need to have separate iram_hook()/sleep_core_init() functions? Perhaps they can be combined into a single function for simplicity.

arch/arm/mach-tegra/pm.h struct tegra_lp1_iram { · line 39

Quoted 9 lines
arch/arm/mach-tegra/pm.h +7 -0
 
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+void tegra30_lp1_iram_hook(void);
+void tegra30_sleep_core_init(void);
+#else
+static inline void tegra30_lp1_iram_hook(void) {}
+static inline void void tegra30_sleep_core_init(void) {}
+#endif

It'd be nice to be consistent re: whether we define dummy static inlines, or use IS_ENABLED() at the call-site. IIRC, there's lots of use of IS_ENABLED() in the Tegra PM code now, so perhaps these patches should use that instead?

arch/arm/mach-tegra/sleep.h line 57

Quoted 9 lines
arch/arm/mach-tegra/sleep.h +7 -0
 
+/* waits until the microsecond counter (base) ticks, for exact timing loops */
+.macro wait_for_us, rd, base, tmp
+	ldr	\rd, [\base]
+1001:	ldr	\tmp, [\base]
+	cmp	\rd, \tmp
+	beq	1001b
+.endm

Doesn't this wait any amount of time from 0..1uS, and hence it actually /isn't/ very exact?

arch/arm/mach-tegra/sleep.h line 65

Quoted 7 lines
arch/arm/mach-tegra/sleep.h +7 -0
+/* waits until the microsecond counter (base) is > rn */
+.macro wait_until, rn, base, tmp
+	add	\rn, \rn, #1
+1002:	ldr	\tmp, [\base]
+	cmp	\tmp, \rn
+	bmi	1002b
+.endm

Parameter "rn" could be renamed to make its purpose clear from the name. How about target_us or wait_until_this_time? "wait_until" is also rather a generic name; wait_until_us would be much better, which would require renaming wait_until_us above, which I think might be better deleted, or renamed to wait_until_next_us?

arch/arm/mach-tegra/sleep-tegra30.S ENDPROC(tegra30_cpu_shutdown) · line 229

Quoted 10 lines
arch/arm/mach-tegra/sleep-tegra30.S +7 -0
 
+ENTRY(tegra30_sleep_core_finish)
 
+	/*
+	 * Preload all the address literals that are needed for the
+	 * CPU power-gating process, to avoid loading from SDRAM which
+	 * are not supported once SDRAM is put into self-refresh.
+	 * LP0 / LP1 use physical address, since the MMU needs to be
+	 * disalbed before putting SDRAM into self-refresh to avoid

s/disalbed/disabled/

Quoted 4 lines

+/*
+ * tegra30_lp1_reset
+ *
+ * reset vector for LP1 restore; copied into IRAM during suspend.

Quoted 8 lines

+ * Brings the system back up to a safe staring point (SDRAM out of
+ * self-refresh, PLLC, PLLM and PLLP reenabled, CPU running on PLLX,
+ * system clock running on the same PLL that it suspended at), and
+ * jumps to tegra_resume to restore virtual addressing.
+ * The physical address of tegra_resume expected to be stored in
+ * PMC_SCRATCH41.
+ *
+ * NOTE: THIS *MUST* BE RELOCATED TO TEGRA_IRAM_CODE_AREA AND MUST BE FIRST.

What does "AND MUST BE FIRST" mean?

arch/arm/mach-tegra/sleep-tegra30.S ENTRY(tegra30_tear_down_cpu) · line 305

Quoted 9 lines
arch/arm/mach-tegra/sleep-tegra30.S +9 -0
+ENTRY(tegra30_lp1_reset)
+	/*
+	 * The CPU and system bus are running at 32KHz and executing from
+	 * IRAM when this code is executed; immediately switch to CLKM and
+	 * enable PLLP, PLLM, PLLC, PLLA and PLLX.
+	 */
+	mov32	r0, TEGRA_CLK_RESET_BASE
+
+	mov	r1, #(1 << 28)

Some #defines for the various magic values used in this code would be useful.

arch/arm/mach-tegra/sleep-tegra30.S ENTRY(tegra30_tear_down_cpu) · line 464

Quoted 9 lines
arch/arm/mach-tegra/sleep-tegra30.S +9 -0
+tegra30_sdram_pad_save:
+	.word	0
+	.word	0
+	.word	0
+	.word	0
+	.word	0
+	.word	0
+	.word	0
+	.word	0

This might be simpler, and easier to validate it's the right length:

.rept 8
.long 0
.endr

arch/arm/mach-tegra/sleep-tegra30.S ENTRY(tegra30_tear_down_cpu) · line 477

Quoted 12 lines
arch/arm/mach-tegra/sleep-tegra30.S +12 -0
+tegra30_sdram_pad_address:
+	.word	TEGRA_EMC_BASE + EMC_CFG				@0x0
+	.word	TEGRA_EMC_BASE + EMC_ZCAL_INTERVAL			@0x4
+	.word	TEGRA_EMC_BASE + EMC_AUTO_CAL_INTERVAL			@0x8
+	.word	TEGRA_EMC_BASE + EMC_XM2VTTGENPADCTRL			@0xc
+	.word	TEGRA_EMC_BASE + EMC_XM2VTTGENPADCTRL2			@0x10
+	.word	TEGRA_PMC_BASE + PMC_IO_DPD_STATUS			@0x14
+	.word	TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT	@0x18
+	.word	TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST		@0x1c
+
+tegra30_sdram_pad_size:
+	.word	tegra30_sdram_pad_address - tegra30_sdram_pad_save

Perhaps if you swapp the order of declaring tegra30_sdram_pad_save and tegra30_sdram_pad_address, you can even do something like:

	.rept (tegra30_sdram_pad_addr_end - tegra30_sdram_pad_addr) / 4

?

arch/arm/mach-tegra/sleep-tegra30.S ENTRY(tegra30_tear_down_cpu) · line 502

Quoted 3 lines
arch/arm/mach-tegra/sleep-tegra30.S +3 -0
+tegra30_switch_cpu_to_clk32k:
+	/*
+	 * start by jumping to CLKM to safely disable PLLs, then jump to

jumping sounds like a CPU program counter operation. s/jumping/switching/ ?

arch/arm/mach-tegra/sleep-tegra30.S ENTRY(tegra30_tear_down_cpu) · line 510

Quoted 4 lines
arch/arm/mach-tegra/sleep-tegra30.S +4 -0
+	/* 2uS delay delay between changing SCLK and CCLK */
+	wait_for_us r1, r7, r9
+	add	r1, r1, #2
+	wait_until r1, r7, r9

Ah, I see how wait_for_us is used now. Perhaps rename it wait_for_us_boundary or wait_for_us_tick? Alternatively, perhaps wait_until can just incorporate that logic itself?

author
#30 lore raw

PATCH 5/8 ARM: tegra30: add LP1 suspend support

Quoted 7 lines · Stephen Warren
Quoted 5 lines · Joseph Lo

The LP1 suspend mode will power off the CPU, clock gated the PLLs and put SDRAM to self-refresh mode. Any interrupt can wake up device from LP1. The sequence when LP1 suspending:

arch/arm/mach-tegra/pm-tegra30.c +0 -0
Quoted 9 lines

arch/arm/mach-tegra/pm-tegra30.c line 28

Quoted 4 lines
arch/arm/mach-tegra/pm-tegra30.c +4 -0
+void tegra30_lp1_iram_hook(void)
+{
+	tegra30_lp1_iram.start_addr = &tegra30_iram_start;
+	tegra30_lp1_iram.end_addr = &tegra30_iram_end;

If you need to fill in the values in that struct dynamically anyway, why not make tegra_lp1_iram be a struct rather than a pointer, and write directly to it?

OK. Will fix.

Quoted 13 lines
Quoted 4 lines

+/*
+ * tegra30_lp1_reset
+ *
+ * reset vector for LP1 restore; copied into IRAM during suspend.

Quoted 8 lines

+ * Brings the system back up to a safe staring point (SDRAM out of
+ * self-refresh, PLLC, PLLM and PLLP reenabled, CPU running on PLLX,
+ * system clock running on the same PLL that it suspended at), and
+ * jumps to tegra_resume to restore virtual addressing.
+ * The physical address of tegra_resume expected to be stored in
+ * PMC_SCRATCH41.
+ *
+ * NOTE: THIS *MUST* BE RELOCATED TO TEGRA_IRAM_CODE_AREA AND MUST BE FIRST.

Quoted 2 lines

What does "AND MUST BE FIRST" mean?

It means the LP1 reset vector needs to be copied to IRAM_CODE_AREA first before suspend to LP1. Looks no need this. Will remove it.

Quoted 4 lines
Quoted 4 lines
arch/arm/mach-tegra/pm-tegra30.c +4 -0
+ENTRY(tegra30_lp1_reset)
+	/*
+	 * The CPU and system bus are running at 32KHz and executing from
+	 * IRAM when this code is executed; immediately switch to CLKM and
Quoted 8 lines

arch/arm/mach-tegra/pm-tegra30.c

Quoted 5 lines
arch/arm/mach-tegra/pm-tegra30.c +5 -0
+	 * enable PLLP, PLLM, PLLC, PLLA and PLLX.
+	 */
+	mov32	r0, TEGRA_CLK_RESET_BASE
+
+	mov	r1, #(1 << 28)

Some #defines for the various magic values used in this code would be useful.

It may still cause some confuse if I add a #defines value for it. Because it includes a clock policy and the clock source (the value maybe just 0). I add some comments for these codes about what they are doing.

Quoted 33 lines

arch/arm/mach-tegra/pm-tegra30.c

Quoted 10 lines
arch/arm/mach-tegra/pm-tegra30.c +9 -0
+tegra30_sdram_pad_save:
+	.word	0
+	.word	0
+	.word	0
+	.word	0
+	.word	0
+	.word	0
+	.word	0
+	.word	0

This might be simpler, and easier to validate it's the right length:

.rept 8
.long 0
.endr

arch/arm/mach-tegra/pm-tegra30.c

Quoted 12 lines
arch/arm/mach-tegra/pm-tegra30.c +12 -0
+tegra30_sdram_pad_address:
+	.word	TEGRA_EMC_BASE + EMC_CFG				@0x0
+	.word	TEGRA_EMC_BASE + EMC_ZCAL_INTERVAL			@0x4
+	.word	TEGRA_EMC_BASE + EMC_AUTO_CAL_INTERVAL			@0x8
+	.word	TEGRA_EMC_BASE + EMC_XM2VTTGENPADCTRL			@0xc
+	.word	TEGRA_EMC_BASE + EMC_XM2VTTGENPADCTRL2			@0x10
+	.word	TEGRA_PMC_BASE + PMC_IO_DPD_STATUS			@0x14
+	.word	TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT	@0x18
+	.word	TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST		@0x1c
+
+tegra30_sdram_pad_size:
+	.word	tegra30_sdram_pad_address - tegra30_sdram_pad_save

Perhaps if you swapp the order of declaring tegra30_sdram_pad_save and tegra30_sdram_pad_address, you can even do something like:

Quoted 3 lines
	.rept (tegra30_sdram_pad_addr_end - tegra30_sdram_pad_addr) / 4

?

OK. Looks better. Will do this.

Quoted 9 lines

arch/arm/mach-tegra/pm-tegra30.c

Quoted 5 lines
arch/arm/mach-tegra/pm-tegra30.c +4 -0
+	/* 2uS delay delay between changing SCLK and CCLK */
+	wait_for_us r1, r7, r9
+	add	r1, r1, #2
+	wait_until r1, r7, r9

Ah, I see how wait_for_us is used now. Perhaps rename it wait_for_us_boundary or wait_for_us_tick? Alternatively, perhaps wait_until can just incorporate that logic itself?

Indeed. Will fix.

author
#31 lore raw

PATCH 6/8 ARM: tegra20: add LP1 suspend support

In reply to Joseph Lo

The LP1 suspend mode will power off the CPU, clock gated the PLLs and put SDRAM to self-refresh mode. Any interrupt can wake up device from LP1. The sequence when LP1 suspending:

* tunning off L1 data cache and the MMU
* putting SDRAM into self-refresh
* storing some EMC registers and SCLK burst policy
* switching CPU to CLK_M (12MHz OSC)
* switching SCLK to CLK_S (32KHz OSC)
* tunning off PLLM, PLLP and PLLC
* shutting off the CPU rail

The sequence of LP1 resuming:

* re-enabling PLLM, PLLP, and PLLC
* restoring some EMC registers and SCLK burst policy
* setting up CCLK burst policy to PLLP
* resuming SDRAM to normal mode
* jumping to the "tegra_resume" from PMC_SCRATCH41

Due to the SDRAM will be put into self-refresh mode, the low level procedures of LP1 suspending and resuming should be copied to TEGRA_IRAM_CODE_AREA (TEGRA_IRAM_BASE + SZ_4K) when suspending. Before restoring the CPU context when resuming, the SDRAM needs to be switched back to normal mode. And the PLLs need to be re-enabled, SCLK burst policy be restored, CCLK burst policy be set in PLLP. Then jumping to "tegra_resume" that was expected to be stored in PMC_SCRATCH41 to restore CPU context and back to kernel.

Based on the work by:
Colin Cross <[email protected]>
Gary King <[email protected]>

---
 arch/arm/mach-tegra/Makefile        |   1 +
 arch/arm/mach-tegra/pm-tegra20.c    |  37 +++++
 arch/arm/mach-tegra/pm.c            |   6 +
 arch/arm/mach-tegra/pm.h            |   8 +
 arch/arm/mach-tegra/sleep-tegra20.S | 300 ++++++++++++++++++++++++++++++++++++
 5 files changed, 352 insertions(+)
 create mode 100644 arch/arm/mach-tegra/pm-tegra20.c
arch/arm/mach-tegra/Makefile +1 -0
index d341980..a3fe22d 100644
@@ -17,6 +17,7 @@ obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= tegra20_speedo.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= tegra2_emc.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= sleep-tegra20.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= pm-tegra20.o
 ifeq ($(CONFIG_CPU_IDLE),y)
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= cpuidle-tegra20.o
 endif
arch/arm/mach-tegra/pm-tegra20.c new file +37 -0
new file mode 100644
index 0000000..47bc40b
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013, NVIDIA Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kernel.h>
+
+#include "pm.h"
+
+#ifdef CONFIG_PM_SLEEP
+static struct tegra_lp1_iram tegra20_lp1_iram;
+extern u32 tegra20_iram_start, tegra20_iram_end;
+extern void tegra20_sleep_core_finish(unsigned long);
+
+void tegra20_lp1_iram_hook(void)
+{
+	tegra20_lp1_iram.start_addr = &tegra20_iram_start;
+	tegra20_lp1_iram.end_addr = &tegra20_iram_end;
+
+	tegra_lp1_iram = &tegra20_lp1_iram;
+}
+
+void tegra20_sleep_core_init(void)
+{
+	tegra_sleep_core_finish = tegra20_sleep_core_finish;
+}
+#endif
arch/arm/mach-tegra/pm.c +6 -0
index 77dbb22..5ae7ee5 100644
@@ -210,6 +210,9 @@ static int tegra_sleep_core(unsigned long v2p)
 static bool tegra_lp1_iram_hook(void)
 {
 	switch (tegra_chip_id) {
+	case TEGRA20:
+		tegra20_lp1_iram_hook();
+		break;
 	case TEGRA30:
 		tegra30_lp1_iram_hook();
 		break;
@@ -231,6 +234,9 @@ static bool tegra_lp1_iram_hook(void)
 static bool tegra_sleep_core_init(void)
 {
 	switch (tegra_chip_id) {
+	case TEGRA20:
+		tegra20_sleep_core_init();
+		break;
 	case TEGRA30:
 		tegra30_sleep_core_init();
 		break;
arch/arm/mach-tegra/pm.h +8 -0
index 32d2898..7aef651 100644
@@ -30,6 +30,14 @@ struct tegra_lp1_iram {
 extern struct tegra_lp1_iram *tegra_lp1_iram;
 extern void (*tegra_sleep_core_finish)(unsigned long v2p);
 
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+void tegra20_lp1_iram_hook(void);
+void tegra20_sleep_core_init(void);
+#else
+static inline void tegra20_lp1_iram_hook(void) {}
+static inline void void tegra20_sleep_core_init(void) {}
+#endif
+
 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
 void tegra30_lp1_iram_hook(void);
 void tegra30_sleep_core_init(void);
arch/arm/mach-tegra/sleep-tegra20.S +300 -0

326 lines not on this page · raw message

Signature · 1 line
1.8.3.4
author
#32 lore raw

PATCH 7/8 ARM: tegra114: add LP1 suspend support

In reply to Joseph Lo

The LP1 suspend mode will power off the CPU, clock gated the PLLs and put SDRAM to self-refresh mode. Any interrupt can wake up device from LP1. The sequence when LP1 suspending:

* tunning off L1 data cache and the MMU
* storing some EMC registers, DPD (deep power down) status, clk source of mselect and SCLK burst policy
* putting SDRAM into self-refresh
* switching CPU to CLK_M (12MHz OSC)
* tunning off PLLM, PLLP, PLLA, PLLC and PLLX
* switching SCLK to CLK_S (32KHz OSC)
* shutting off the CPU rail

The sequence of LP1 resuming:

* re-enabling PLLM, PLLP, PLLA, PLLC and PLLX
* restoring the clk source of mselect and SCLK burst policy
* restoring DPD status and some EMC registers
* resuming SDRAM to normal mode
* jumping to the "tegra_resume" from PMC_SCRATCH41

Due to the SDRAM will be put into self-refresh mode, the low level procedures of LP1 suspending and resuming should be copied to TEGRA_IRAM_CODE_AREA (TEGRA_IRAM_BASE + SZ_4K) when suspending. Before restoring the CPU context when resuming, the SDRAM needs to be switched back to normal mode. And the PLLs need to be re-enabled, SCLK burst policy be restored. Then jumping to "tegra_resume" that was expected to be stored in PMC_SCRATCH41 to restore CPU context and back to kernel.

Based on the work by: Bo Yan <[email protected]>

---
 arch/arm/mach-tegra/Makefile        |   1 +
 arch/arm/mach-tegra/iomap.h         |   6 ++
 arch/arm/mach-tegra/pm.c            |   2 +
 arch/arm/mach-tegra/pm.h            |   2 +-
 arch/arm/mach-tegra/sleep-tegra30.S | 150 ++++++++++++++++++++++++++++++++----
 5 files changed, 147 insertions(+), 14 deletions(-)
arch/arm/mach-tegra/Makefile +1 -0
index a3fe22d..f4e7063 100644
@@ -33,6 +33,7 @@ obj-$(CONFIG_TEGRA_PCI)			+= pcie.o
 
 obj-$(CONFIG_ARCH_TEGRA_114_SOC)	+= tegra114_speedo.o
 obj-$(CONFIG_ARCH_TEGRA_114_SOC)	+= sleep-tegra30.o
+obj-$(CONFIG_ARCH_TEGRA_114_SOC)	+= pm-tegra30.o
 ifeq ($(CONFIG_CPU_IDLE),y)
 obj-$(CONFIG_ARCH_TEGRA_114_SOC)	+= cpuidle-tegra114.o
 endif
arch/arm/mach-tegra/iomap.h +6 -0
index 399fbca..7f463d7 100644
@@ -237,6 +237,12 @@
 #define TEGRA_KFUSE_BASE		0x7000FC00
 #define TEGRA_KFUSE_SIZE		SZ_1K
 
+#define TEGRA_EMC0_BASE			0x7001A000
+#define TEGRA_EMC0_SIZE			SZ_2K
+
+#define TEGRA_EMC1_BASE			0x7001A800
+#define TEGRA_EMC1_SIZE			SZ_2K
+
 #define TEGRA_CSITE_BASE		0x70040000
 #define TEGRA_CSITE_SIZE		SZ_256K
 
arch/arm/mach-tegra/pm.c +2 -0
index 5ae7ee5..36cadaa 100644
@@ -214,6 +214,7 @@ static bool tegra_lp1_iram_hook(void)
 		tegra20_lp1_iram_hook();
 		break;
 	case TEGRA30:
+	case TEGRA114:
 		tegra30_lp1_iram_hook();
 		break;
 	default:
@@ -238,6 +239,7 @@ static bool tegra_sleep_core_init(void)
 		tegra20_sleep_core_init();
 		break;
 	case TEGRA30:
+	case TEGRA114:
 		tegra30_sleep_core_init();
 		break;
 	default:
arch/arm/mach-tegra/pm.h +1 -1
index 7aef651..1ccc0df 100644
@@ -38,7 +38,7 @@ static inline void tegra20_lp1_iram_hook(void) {}
 static inline void void tegra20_sleep_core_init(void) {}
 #endif
 
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || defined(CONFIG_ARCH_TEGRA_114_SOC)
 void tegra30_lp1_iram_hook(void);
 void tegra30_sleep_core_init(void);
 #else
arch/arm/mach-tegra/sleep-tegra30.S +137 -13

278 lines not on this page · raw message

Signature · 1 line
1.8.3.4
#33 lore raw

PATCH 7/8 ARM: tegra114: add LP1 suspend support

Quoted 9 lines · Joseph Lo

The LP1 suspend mode will power off the CPU, clock gated the PLLs and put SDRAM to self-refresh mode. Any interrupt can wake up device from LP1. The sequence when LP1 suspending:

arch/arm/mach-tegra/pm.c +0 -0
index 5ae7ee5..36cadaa 100644

arch/arm/mach-tegra/pm.c static bool tegra_lp1_iram_hook(void) · line 218

Quoted 5 lines
arch/arm/mach-tegra/pm.c +1 -0
@@ -214,6 +214,7 @@ static bool tegra_lp1_iram_hook(void)
 		tegra20_lp1_iram_hook();
 		break;
 	case TEGRA30:
+	case TEGRA114:
 		tegra30_lp1_iram_hook();

That's in pm-tegra30.c, which is only compiled in if CONFIG_ARCH_TEGRA_3x_SOC is enabled. Similarly, this patch adds a lot of code to sleep-tegra30.S, which also isn't built/linked if !CONFIG_ARCH_TEGRA_3x_SOC.

Does this series built with all 7 combinations of Tegra20/30/114 support enabled?

Quoted 5 lines
arch/arm/mach-tegra/sleep-tegra30.S +0 -0
@@ -96,9 +100,15 @@
 	orreq	\rd, \rd, #(1 << 30)
 	streq	\rd, [\r_car_base, #\pll_base]

arch/arm/mach-tegra/sleep-tegra30.S line 111

Quoted 10 lines
arch/arm/mach-tegra/sleep-tegra30.S +6 -0
 	/* Enable lock detector */
+	.if	\pll_misc
+	ldr	\rd, [\r_car_base, #\pll_misc]
+	bic	\rd, \rd, #(1 << 18)
+	str	\rd, [\r_car_base, #\pll_misc]
+	ldr	\rd, [\r_car_base, #\pll_misc]
 	ldr	\rd, [\r_car_base, #\pll_misc]
 	orr	\rd, \rd, #(1 << 18)
 	str	\rd, [\r_car_base, #\pll_misc]
+	.endif

Hmm. Those last 3 lines that aren't touched by this patch already touched the pll_misc register even if !pll_misc. Was that a bug in a previous patch?

Is git bisect maintained for both compile and run-time across this whole patch series?

author
#34 lore raw

PATCH 7/8 ARM: tegra114: add LP1 suspend support

Quoted 5 lines · Stephen Warren
Quoted 3 lines · Joseph Lo

The LP1 suspend mode will power off the CPU, clock gated the PLLs and put SDRAM to self-refresh mode. Any interrupt can wake up device from LP1. The sequence when LP1 suspending:

Quoted 16 lines

arch/arm/mach-tegra/pm.c static bool tegra_lp1_iram_hook(void) · line 218

Quoted 10 lines
arch/arm/mach-tegra/pm.c +1 -0
index 5ae7ee5..36cadaa 100644
@@ -214,6 +214,7 @@ static bool tegra_lp1_iram_hook(void)
 		tegra20_lp1_iram_hook();
 		break;
 	case TEGRA30:
+	case TEGRA114:
 		tegra30_lp1_iram_hook();

That's in pm-tegra30.c, which is only compiled in if CONFIG_ARCH_TEGRA_3x_SOC is enabled. Similarly, this patch adds a lot of code to sleep-tegra30.S, which also isn't built/linked if !CONFIG_ARCH_TEGRA_3x_SOC.

The "pm-tegra30.c" would be build when just CONFIG_ARCH_TEGRA_3x_SOC, CONFIG_ARCH_TEGRA_114_SOC or both.

Quoted 2 lines

Does this series built with all 7 combinations of Tegra20/30/114 support enabled?

Yes, I did some test about this. But not include all 7 combination.

Quoted 12 lines
Quoted 12 lines
arch/arm/mach-tegra/sleep-tegra30.S +5 -0
@@ -96,9 +100,15 @@
 	orreq	\rd, \rd, #(1 << 30)
 	streq	\rd, [\r_car_base, #\pll_base]
 	/* Enable lock detector */
+	.if	\pll_misc
+	ldr	\rd, [\r_car_base, #\pll_misc]
+	bic	\rd, \rd, #(1 << 18)
+	str	\rd, [\r_car_base, #\pll_misc]
+	ldr	\rd, [\r_car_base, #\pll_misc]
Quoted 8 lines

arch/arm/mach-tegra/sleep-tegra30.S line 111

Quoted 4 lines
arch/arm/mach-tegra/sleep-tegra30.S +1 -0
 	ldr	\rd, [\r_car_base, #\pll_misc]
 	orr	\rd, \rd, #(1 << 18)
 	str	\rd, [\r_car_base, #\pll_misc]
+	.endif

Hmm. Those last 3 lines that aren't touched by this patch already touched the pll_misc register even if !pll_misc. Was that a bug in a previous patch?

Oops. Yes, will fix in next version.

Quoted 3 lines

Is git bisect maintained for both compile and run-time across this whole patch series?

Yes, it's OK. Will do it again before V2 sent.

Quoted 4 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

author
#35 lore raw

PATCH 8/8 ARM: dts: tegra: enable LP1 suspend mode

In reply to Joseph Lo

Enabling the LP1 suspend mode for Tegra devices.

---
 arch/arm/boot/dts/tegra114-dalmore.dts     | 2 +-
 arch/arm/boot/dts/tegra20-colibri-512.dtsi | 2 +-
 arch/arm/boot/dts/tegra20-harmony.dts      | 2 +-
 arch/arm/boot/dts/tegra20-paz00.dts        | 2 +-
 arch/arm/boot/dts/tegra20-seaboard.dts     | 2 +-
 arch/arm/boot/dts/tegra20-tamonten.dtsi    | 2 +-
 arch/arm/boot/dts/tegra20-trimslice.dts    | 2 +-
 arch/arm/boot/dts/tegra20-ventana.dts      | 2 +-
 arch/arm/boot/dts/tegra20-whistler.dts     | 2 +-
 arch/arm/boot/dts/tegra30-beaver.dts       | 2 +-
 arch/arm/boot/dts/tegra30-cardhu.dtsi      | 2 +-
 11 files changed, 11 insertions(+), 11 deletions(-)
arch/arm/boot/dts/tegra114-dalmore.dts +1 -1
index aeda147..a2a1b5f 100644
@@ -1024,7 +1024,7 @@
 
 	pmc {
 		nvidia,invert-interrupt;
-		nvidia,suspend-mode = <2>;
+		nvidia,suspend-mode = <1>;
 		nvidia,cpu-pwr-good-time = <500>;
 		nvidia,cpu-pwr-off-time = <300>;
 		nvidia,core-pwr-good-time = <641 3845>;
arch/arm/boot/dts/tegra20-colibri-512.dtsi +1 -1
index 2fcb3f2..06c5fa0 100644
@@ -363,7 +363,7 @@
 	};
 
 	pmc {
-		nvidia,suspend-mode = <2>;
+		nvidia,suspend-mode = <1>;
 		nvidia,cpu-pwr-good-time = <5000>;
 		nvidia,cpu-pwr-off-time = <5000>;
 		nvidia,core-pwr-good-time = <3845 3845>;
arch/arm/boot/dts/tegra20-harmony.dts +1 -1
index d9f89cd..d44cf90 100644
@@ -417,7 +417,7 @@
 
 	pmc {
 		nvidia,invert-interrupt;
-		nvidia,suspend-mode = <2>;
+		nvidia,suspend-mode = <1>;
 		nvidia,cpu-pwr-good-time = <5000>;
 		nvidia,cpu-pwr-off-time = <5000>;
 		nvidia,core-pwr-good-time = <3845 3845>;
arch/arm/boot/dts/tegra20-paz00.dts +1 -1
index cfd1276..8d71fc9 100644
@@ -417,7 +417,7 @@
 
 	pmc {
 		nvidia,invert-interrupt;
-		nvidia,suspend-mode = <2>;
+		nvidia,suspend-mode = <1>;
 		nvidia,cpu-pwr-good-time = <2000>;
 		nvidia,cpu-pwr-off-time = <0>;
 		nvidia,core-pwr-good-time = <3845 3845>;
arch/arm/boot/dts/tegra20-seaboard.dts +1 -1
index 365760b..152dfb7 100644
@@ -518,7 +518,7 @@
 
 	pmc {
 		nvidia,invert-interrupt;
-		nvidia,suspend-mode = <2>;
+		nvidia,suspend-mode = <1>;
 		nvidia,cpu-pwr-good-time = <5000>;
 		nvidia,cpu-pwr-off-time = <5000>;
 		nvidia,core-pwr-good-time = <3845 3845>;
arch/arm/boot/dts/tegra20-tamonten.dtsi +1 -1
index c54faae..f00febe 100644
@@ -459,7 +459,7 @@
 
 	pmc {
 		nvidia,invert-interrupt;
-		nvidia,suspend-mode = <2>;
+		nvidia,suspend-mode = <1>;
 		nvidia,cpu-pwr-good-time = <5000>;
 		nvidia,cpu-pwr-off-time = <5000>;
 		nvidia,core-pwr-good-time = <3845 3845>;
arch/arm/boot/dts/tegra20-trimslice.dts +1 -1
index ed4b901..3e4eefb 100644
@@ -302,7 +302,7 @@
 	};
 
 	pmc {
-		nvidia,suspend-mode = <2>;
+		nvidia,suspend-mode = <1>;
 		nvidia,cpu-pwr-good-time = <5000>;
 		nvidia,cpu-pwr-off-time = <5000>;
 		nvidia,core-pwr-good-time = <3845 3845>;
arch/arm/boot/dts/tegra20-ventana.dts +1 -1
index 7f8c28d..aab872c 100644
@@ -494,7 +494,7 @@
 
 	pmc {
 		nvidia,invert-interrupt;
-		nvidia,suspend-mode = <2>;
+		nvidia,suspend-mode = <1>;
 		nvidia,cpu-pwr-good-time = <2000>;
 		nvidia,cpu-pwr-off-time = <100>;
 		nvidia,core-pwr-good-time = <3845 3845>;
arch/arm/boot/dts/tegra20-whistler.dts +1 -1
index ab67c94..3899cae 100644
@@ -497,7 +497,7 @@
 
 	pmc {
 		nvidia,invert-interrupt;
-		nvidia,suspend-mode = <2>;
+		nvidia,suspend-mode = <1>;
 		nvidia,cpu-pwr-good-time = <2000>;
 		nvidia,cpu-pwr-off-time = <1000>;
 		nvidia,core-pwr-good-time = <0 3845>;
arch/arm/boot/dts/tegra30-beaver.dts +1 -1
index 87c5f7b..7378927 100644
@@ -262,7 +262,7 @@
 	pmc {
 		status = "okay";
 		nvidia,invert-interrupt;
-		nvidia,suspend-mode = <2>;
+		nvidia,suspend-mode = <1>;
 		nvidia,cpu-pwr-good-time = <2000>;
 		nvidia,cpu-pwr-off-time = <200>;
 		nvidia,core-pwr-good-time = <3845 3845>;
arch/arm/boot/dts/tegra30-cardhu.dtsi +1 -1
index c011b67..d78c90c 100644
@@ -314,7 +314,7 @@
 	pmc {
 		status = "okay";
 		nvidia,invert-interrupt;
-		nvidia,suspend-mode = <2>;
+		nvidia,suspend-mode = <1>;
 		nvidia,cpu-pwr-good-time = <2000>;
 		nvidia,cpu-pwr-off-time = <200>;
 		nvidia,core-pwr-good-time = <3845 3845>;
Signature · 1 line
1.8.3.4
#36 lore raw

cover ARM: tegra: support LP1 suspend mode

In reply to Joseph Lo
Quoted 3 lines · On Friday 26 July 2013 17:15:02 Joseph Lo wrote:

This series adds the support of LP1 suspend mode for Tegra.

Verified on Seaboard, Cardhu and Dalmore.

tested on AC100 and worked fine, except

[   68.448007] PM: Syncing filesystems ... done.
[   71.370086] Freezing user space processes ... (elapsed 0.001 seconds) done.
[   71.370088] Freezing remaining freezable tasks ... (elapsed 0.001 seconds) 
done.
[   71.371253] Suspending console(s) (use no_console_suspend to debug)
[   71.638481] PM: suspend of devices complete after 266.604 msecs
[   71.638905] PM: late suspend of devices complete after 0.417 msecs
[   71.639477] PM: noirq suspend of devices complete after 0.568 msecs
[   71.639480] Disabling non-boot CPUs ...
[   71.640242] CPU1: shutdown
[   71.641216] Entering suspend state LP1
[   71.641267] Enabling non-boot CPUs ...
[   71.643125] CPU1: Booted secondary processor
[   71.643449] CPU1 is up
[   71.643786] PM: noirq resume of devices complete after 0.331 msecs
[   71.644300] PM: early resume of devices complete after 0.364 msecs
[   71.648038] ------------[ cut here ]------------
[   71.648061] WARNING: CPU: 0 PID: 1025 at kernel/irq/manage.c:529 
irq_set_irq_wake+0xb8/0xf0()
[   71.648064] Unbalanced IRQ 384 wake disable
[   71.648068] Modules linked in:
[   71.648075] CPU: 0 PID: 1025 Comm: bash Not tainted 3.11.0-rc2-
next-20130726-00008-gef01509-dirty #6
[   71.648107] [<c001551c>] (unwind_backtrace+0x0/0xf8) from [<c001154c>] 
(show_stack+0x10/0x14)
[   71.648128] [<c001154c>] (show_stack+0x10/0x14) from [<c0515288>] 
(dump_stack+0x80/0xc4)
[   71.648142] [<c0515288>] (dump_stack+0x80/0xc4) from [<c0025340>] 
(warn_slowpath_common+0x64/0x88)
[   71.648151] [<c0025340>] (warn_slowpath_common+0x64/0x88) from [<c00253f8>] 
(warn_slowpath_fmt+0x30/0x40)
[   71.648161] [<c00253f8>] (warn_slowpath_fmt+0x30/0x40) from [<c007ff8c>] 
(irq_set_irq_wake+0xb8/0xf0)
[   71.648178] [<c007ff8c>] (irq_set_irq_wake+0xb8/0xf0) from [<c0334d00>] 
(tps6586x_rtc_resume+0x30/0x38)
[   71.648192] [<c0334d00>] (tps6586x_rtc_resume+0x30/0x38) from [<c02951d0>] 
(platform_pm_resume+0x2c/0x4c)
[   71.648202] [<c02951d0>] (platform_pm_resume+0x2c/0x4c) from [<c0299d40>] 
(dpm_run_callback.isra.5+0x18/0x38)
[   71.648211] [<c0299d40>] (dpm_run_callback.isra.5+0x18/0x38) from 
[<c029a044>] (device_resume+0xb0/0x170)
[   71.648219] [<c029a044>] (device_resume+0xb0/0x170) from [<c029aeb4>] 
(dpm_resume+0xe8/0x20c)
[   71.648227] [<c029aeb4>] (dpm_resume+0xe8/0x20c) from [<c029b174>] 
(dpm_resume_end+0xc/0x18)
[   71.648245] [<c029b174>] (dpm_resume_end+0xc/0x18) from [<c005e480>] 
(suspend_devices_and_enter+0xdc/0x2f8)
[   71.648256] [<c005e480>] (suspend_devices_and_enter+0xdc/0x2f8) from 
[<c005e810>] (pm_suspend+0x174/0x1e8)
[   71.648265] [<c005e810>] (pm_suspend+0x174/0x1e8) from [<c005d710>] 
(state_store+0x6c/0xbc)
[   71.648285] [<c005d710>] (state_store+0x6c/0xbc) from [<c01eca78>] 
(kobj_attr_store+0x14/0x20)
[   71.648298] [<c01eca78>] (kobj_attr_store+0x14/0x20) from [<c011e970>] 
(sysfs_write_file+0x168/0x198)
[   71.648312] [<c011e970>] (sysfs_write_file+0x168/0x198) from [<c00cd060>] 
(vfs_write+0xb0/0x188)
[   71.648321] [<c00cd060>] (vfs_write+0xb0/0x188) from [<c00cd410>] 
(SyS_write+0x3c/0x70)
[   71.648330] [<c00cd410>] (SyS_write+0x3c/0x70) from [<c000e560>] 
(ret_fast_syscall+0x0/0x30)
[   71.648334] ---[ end trace e5ed8212ac4db5da ]---
[   72.063578] mmc1: power class selection to bus width 8 failed
[   72.297753] usb 2-1: reset high-speed USB device number 2 using tegra-ehci
[   72.567736] usb 3-1: reset high-speed USB device number 2 using tegra-ehci
[   73.022058] usb 3-1.3: reset high-speed USB device number 4 using tegra-
ehci
[   73.216064] usb 3-1.2: reset high-speed USB device number 3 using tegra-
ehci
[   73.360225] PM: resume of devices complete after 1715.937 msecs
[   73.361008] Restarting tasks ... done.

and sdcard being offline after resume (fixed by CONFIG_MMC_UNSAFE_RESUME=y). Anyway, thanks for your great work!

Quoted 51 lines

And tested with THUMB2_KERNEL as well.

P.S.
A known issue on Dalmore, the LP1 resume may take 10 ~ 15 seconds due to the 792MHz BCT. It can't be reproduced on Seaboard or Cardhu. And the root cause of this is about the default settings of EMC registers that cause the DRAM can't leave self-refresh mode immediately. If you want to test with quick LP1 resume on Dalmore, I can provide another HACK for this.

Joseph Lo (8):
ARM: tegra: add common resume handling code for LP1 resuming
ARM: tegra: config the polarity of the request of sys clock
clk: tegra114: add LP1 suspend/resume support
ARM: tegra: add common LP1 suspend support
ARM: tegra30: add LP1 suspend support
ARM: tegra20: add LP1 suspend support
ARM: tegra114: add LP1 suspend support
ARM: dts: tegra: enable LP1 suspend mode

 arch/arm/boot/dts/tegra114-dalmore.dts     |   2 +-
 arch/arm/boot/dts/tegra20-colibri-512.dtsi |   2 +-
 arch/arm/boot/dts/tegra20-harmony.dts      |   2 +-
 arch/arm/boot/dts/tegra20-paz00.dts        |   2 +-
 arch/arm/boot/dts/tegra20-seaboard.dts     |   2 +-
 arch/arm/boot/dts/tegra20-tamonten.dtsi    |   2 +-
 arch/arm/boot/dts/tegra20-trimslice.dts    |   2 +-
 arch/arm/boot/dts/tegra20-ventana.dts      |   2 +-
 arch/arm/boot/dts/tegra20-whistler.dts     |   2 +-
 arch/arm/boot/dts/tegra30-beaver.dts       |   2 +-
 arch/arm/boot/dts/tegra30-cardhu.dtsi      |   2 +-
 arch/arm/mach-tegra/Makefile               |   3 +
 arch/arm/mach-tegra/iomap.h                |   6 +
 arch/arm/mach-tegra/pm-tegra20.c           |  37 ++
 arch/arm/mach-tegra/pm-tegra30.c           |  37 ++
 arch/arm/mach-tegra/pm.c                   | 121 +++++-
 arch/arm/mach-tegra/pm.h                   |  23 ++
 arch/arm/mach-tegra/pmc.c                  |  36 +-
 arch/arm/mach-tegra/pmc.h                  |   3 +
 arch/arm/mach-tegra/reset-handler.S        |  13 +
 arch/arm/mach-tegra/reset.c                |   2 +
 arch/arm/mach-tegra/reset.h                |   4 +
 arch/arm/mach-tegra/sleep-tegra20.S        | 300 ++++++++++++++
 arch/arm/mach-tegra/sleep-tegra30.S        | 615
+++++++++++++++++++++++++++++ arch/arm/mach-tegra/sleep.S                | 
 8 +-
 arch/arm/mach-tegra/sleep.h                |  18 +
 drivers/clk/tegra/clk-tegra114.c           |  32 ++
 27 files changed, 1259 insertions(+), 21 deletions(-)
 create mode 100644 arch/arm/mach-tegra/pm-tegra20.c
 create mode 100644 arch/arm/mach-tegra/pm-tegra30.c
#37 lore raw

cover ARM: tegra: support LP1 suspend mode

27.07.2013 20:12, Marc Dietrich ?????:

Quoted 135 lines · On Friday 26 July 2013 17:15:02 Joseph Lo wrote:
Quoted 3 lines

This series adds the support of LP1 suspend mode for Tegra.

Verified on Seaboard, Cardhu and Dalmore.

tested on AC100 and worked fine, except

[   68.448007] PM: Syncing filesystems ... done.
[   71.370086] Freezing user space processes ... (elapsed 0.001 seconds) done.
[   71.370088] Freezing remaining freezable tasks ... (elapsed 0.001 seconds) 
done.
[   71.371253] Suspending console(s) (use no_console_suspend to debug)
[   71.638481] PM: suspend of devices complete after 266.604 msecs
[   71.638905] PM: late suspend of devices complete after 0.417 msecs
[   71.639477] PM: noirq suspend of devices complete after 0.568 msecs
[   71.639480] Disabling non-boot CPUs ...
[   71.640242] CPU1: shutdown
[   71.641216] Entering suspend state LP1
[   71.641267] Enabling non-boot CPUs ...
[   71.643125] CPU1: Booted secondary processor
[   71.643449] CPU1 is up
[   71.643786] PM: noirq resume of devices complete after 0.331 msecs
[   71.644300] PM: early resume of devices complete after 0.364 msecs
[   71.648038] ------------[ cut here ]------------
[   71.648061] WARNING: CPU: 0 PID: 1025 at kernel/irq/manage.c:529 
irq_set_irq_wake+0xb8/0xf0()
[   71.648064] Unbalanced IRQ 384 wake disable
[   71.648068] Modules linked in:
[   71.648075] CPU: 0 PID: 1025 Comm: bash Not tainted 3.11.0-rc2-
next-20130726-00008-gef01509-dirty #6
[   71.648107] [<c001551c>] (unwind_backtrace+0x0/0xf8) from [<c001154c>] 
(show_stack+0x10/0x14)
[   71.648128] [<c001154c>] (show_stack+0x10/0x14) from [<c0515288>] 
(dump_stack+0x80/0xc4)
[   71.648142] [<c0515288>] (dump_stack+0x80/0xc4) from [<c0025340>] 
(warn_slowpath_common+0x64/0x88)
[   71.648151] [<c0025340>] (warn_slowpath_common+0x64/0x88) from [<c00253f8>] 
(warn_slowpath_fmt+0x30/0x40)
[   71.648161] [<c00253f8>] (warn_slowpath_fmt+0x30/0x40) from [<c007ff8c>] 
(irq_set_irq_wake+0xb8/0xf0)
[   71.648178] [<c007ff8c>] (irq_set_irq_wake+0xb8/0xf0) from [<c0334d00>] 
(tps6586x_rtc_resume+0x30/0x38)
[   71.648192] [<c0334d00>] (tps6586x_rtc_resume+0x30/0x38) from [<c02951d0>] 
(platform_pm_resume+0x2c/0x4c)
[   71.648202] [<c02951d0>] (platform_pm_resume+0x2c/0x4c) from [<c0299d40>] 
(dpm_run_callback.isra.5+0x18/0x38)
[   71.648211] [<c0299d40>] (dpm_run_callback.isra.5+0x18/0x38) from 
[<c029a044>] (device_resume+0xb0/0x170)
[   71.648219] [<c029a044>] (device_resume+0xb0/0x170) from [<c029aeb4>] 
(dpm_resume+0xe8/0x20c)
[   71.648227] [<c029aeb4>] (dpm_resume+0xe8/0x20c) from [<c029b174>] 
(dpm_resume_end+0xc/0x18)
[   71.648245] [<c029b174>] (dpm_resume_end+0xc/0x18) from [<c005e480>] 
(suspend_devices_and_enter+0xdc/0x2f8)
[   71.648256] [<c005e480>] (suspend_devices_and_enter+0xdc/0x2f8) from 
[<c005e810>] (pm_suspend+0x174/0x1e8)
[   71.648265] [<c005e810>] (pm_suspend+0x174/0x1e8) from [<c005d710>] 
(state_store+0x6c/0xbc)
[   71.648285] [<c005d710>] (state_store+0x6c/0xbc) from [<c01eca78>] 
(kobj_attr_store+0x14/0x20)
[   71.648298] [<c01eca78>] (kobj_attr_store+0x14/0x20) from [<c011e970>] 
(sysfs_write_file+0x168/0x198)
[   71.648312] [<c011e970>] (sysfs_write_file+0x168/0x198) from [<c00cd060>] 
(vfs_write+0xb0/0x188)
[   71.648321] [<c00cd060>] (vfs_write+0xb0/0x188) from [<c00cd410>] 
(SyS_write+0x3c/0x70)
[   71.648330] [<c00cd410>] (SyS_write+0x3c/0x70) from [<c000e560>] 
(ret_fast_syscall+0x0/0x30)
[   71.648334] ---[ end trace e5ed8212ac4db5da ]---
[   72.063578] mmc1: power class selection to bus width 8 failed
[   72.297753] usb 2-1: reset high-speed USB device number 2 using tegra-ehci
[   72.567736] usb 3-1: reset high-speed USB device number 2 using tegra-ehci
[   73.022058] usb 3-1.3: reset high-speed USB device number 4 using tegra-
ehci
[   73.216064] usb 3-1.2: reset high-speed USB device number 3 using tegra-
ehci
[   73.360225] PM: resume of devices complete after 1715.937 msecs
[   73.361008] Restarting tasks ... done.

and sdcard being offline after resume (fixed by CONFIG_MMC_UNSAFE_RESUME=y). Anyway, thanks for your great work!

Quoted 43 lines

And tested with THUMB2_KERNEL as well.

P.S.
A known issue on Dalmore, the LP1 resume may take 10 ~ 15 seconds due to the 792MHz BCT. It can't be reproduced on Seaboard or Cardhu. And the root cause of this is about the default settings of EMC registers that cause the DRAM can't leave self-refresh mode immediately. If you want to test with quick LP1 resume on Dalmore, I can provide another HACK for this.

Joseph Lo (8):
ARM: tegra: add common resume handling code for LP1 resuming
ARM: tegra: config the polarity of the request of sys clock
clk: tegra114: add LP1 suspend/resume support
ARM: tegra: add common LP1 suspend support
ARM: tegra30: add LP1 suspend support
ARM: tegra20: add LP1 suspend support
ARM: tegra114: add LP1 suspend support
ARM: dts: tegra: enable LP1 suspend mode

 arch/arm/boot/dts/tegra114-dalmore.dts     |   2 +-
 arch/arm/boot/dts/tegra20-colibri-512.dtsi |   2 +-
 arch/arm/boot/dts/tegra20-harmony.dts      |   2 +-
 arch/arm/boot/dts/tegra20-paz00.dts        |   2 +-
 arch/arm/boot/dts/tegra20-seaboard.dts     |   2 +-
 arch/arm/boot/dts/tegra20-tamonten.dtsi    |   2 +-
 arch/arm/boot/dts/tegra20-trimslice.dts    |   2 +-
 arch/arm/boot/dts/tegra20-ventana.dts      |   2 +-
 arch/arm/boot/dts/tegra20-whistler.dts     |   2 +-
 arch/arm/boot/dts/tegra30-beaver.dts       |   2 +-
 arch/arm/boot/dts/tegra30-cardhu.dtsi      |   2 +-
 arch/arm/mach-tegra/Makefile               |   3 +
 arch/arm/mach-tegra/iomap.h                |   6 +
 arch/arm/mach-tegra/pm-tegra20.c           |  37 ++
 arch/arm/mach-tegra/pm-tegra30.c           |  37 ++
 arch/arm/mach-tegra/pm.c                   | 121 +++++-
 arch/arm/mach-tegra/pm.h                   |  23 ++
 arch/arm/mach-tegra/pmc.c                  |  36 +-
 arch/arm/mach-tegra/pmc.h                  |   3 +
 arch/arm/mach-tegra/reset-handler.S        |  13 +
 arch/arm/mach-tegra/reset.c                |   2 +
 arch/arm/mach-tegra/reset.h                |   4 +
 arch/arm/mach-tegra/sleep-tegra20.S        | 300 ++++++++++++++
Quoted 8 lines
 arch/arm/mach-tegra/sleep-tegra30.S        | 615
+++++++++++++++++++++++++++++ arch/arm/mach-tegra/sleep.S                | 
 8 +-
 arch/arm/mach-tegra/sleep.h                |  18 +
 drivers/clk/tegra/clk-tegra114.c           |  32 ++
 27 files changed, 1259 insertions(+), 21 deletions(-)
 create mode 100644 arch/arm/mach-tegra/pm-tegra20.c
 create mode 100644 arch/arm/mach-tegra/pm-tegra30.c
Quoted 5 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

I had same warn on 3.8.
https://bitbucket.org/digetx/picasso-kernel/commits/a86dc95ab48dd77eaa0463844cdf88a5acf9d842

#38 lore raw

cover ARM: tegra: support LP1 suspend mode

Quoted 82 lines · On Saturday 27 July 2013 20:20:38 Dmitry Osipenko wrote:

27.07.2013 20:12, Marc Dietrich ?????:

Quoted 81 lines · On Friday 26 July 2013 17:15:02 Joseph Lo wrote:
Quoted 3 lines

This series adds the support of LP1 suspend mode for Tegra.

Verified on Seaboard, Cardhu and Dalmore.

tested on AC100 and worked fine, except

[   68.448007] PM: Syncing filesystems ... done.
[   71.370086] Freezing user space processes ... (elapsed 0.001 seconds)
done. [   71.370088] Freezing remaining freezable tasks ... (elapsed
0.001 seconds) done.
[   71.371253] Suspending console(s) (use no_console_suspend to debug)
[   71.638481] PM: suspend of devices complete after 266.604 msecs
[   71.638905] PM: late suspend of devices complete after 0.417 msecs
[   71.639477] PM: noirq suspend of devices complete after 0.568 msecs
[   71.639480] Disabling non-boot CPUs ...
[   71.640242] CPU1: shutdown
[   71.641216] Entering suspend state LP1
[   71.641267] Enabling non-boot CPUs ...
[   71.643125] CPU1: Booted secondary processor
[   71.643449] CPU1 is up
[   71.643786] PM: noirq resume of devices complete after 0.331 msecs
[   71.644300] PM: early resume of devices complete after 0.364 msecs
[   71.648038] ------------[ cut here ]------------
[   71.648061] WARNING: CPU: 0 PID: 1025 at kernel/irq/manage.c:529
irq_set_irq_wake+0xb8/0xf0()
[   71.648064] Unbalanced IRQ 384 wake disable
[   71.648068] Modules linked in:
[   71.648075] CPU: 0 PID: 1025 Comm: bash Not tainted 3.11.0-rc2-
next-20130726-00008-gef01509-dirty #6
[   71.648107] [<c001551c>] (unwind_backtrace+0x0/0xf8) from [<c001154c>]
(show_stack+0x10/0x14)
[   71.648128] [<c001154c>] (show_stack+0x10/0x14) from [<c0515288>]
(dump_stack+0x80/0xc4)
[   71.648142] [<c0515288>] (dump_stack+0x80/0xc4) from [<c0025340>]
(warn_slowpath_common+0x64/0x88)
[   71.648151] [<c0025340>] (warn_slowpath_common+0x64/0x88) from
[<c00253f8>] (warn_slowpath_fmt+0x30/0x40)
[   71.648161] [<c00253f8>] (warn_slowpath_fmt+0x30/0x40) from
[<c007ff8c>]
(irq_set_irq_wake+0xb8/0xf0)
[   71.648178] [<c007ff8c>] (irq_set_irq_wake+0xb8/0xf0) from [<c0334d00>]
(tps6586x_rtc_resume+0x30/0x38)
[   71.648192] [<c0334d00>] (tps6586x_rtc_resume+0x30/0x38) from
[<c02951d0>] (platform_pm_resume+0x2c/0x4c)
[   71.648202] [<c02951d0>] (platform_pm_resume+0x2c/0x4c) from
[<c0299d40>] (dpm_run_callback.isra.5+0x18/0x38)
[   71.648211] [<c0299d40>] (dpm_run_callback.isra.5+0x18/0x38) from
[<c029a044>] (device_resume+0xb0/0x170)
[   71.648219] [<c029a044>] (device_resume+0xb0/0x170) from [<c029aeb4>]
(dpm_resume+0xe8/0x20c)
[   71.648227] [<c029aeb4>] (dpm_resume+0xe8/0x20c) from [<c029b174>]
(dpm_resume_end+0xc/0x18)
[   71.648245] [<c029b174>] (dpm_resume_end+0xc/0x18) from [<c005e480>]
(suspend_devices_and_enter+0xdc/0x2f8)
[   71.648256] [<c005e480>] (suspend_devices_and_enter+0xdc/0x2f8) from
[<c005e810>] (pm_suspend+0x174/0x1e8)
[   71.648265] [<c005e810>] (pm_suspend+0x174/0x1e8) from [<c005d710>]
(state_store+0x6c/0xbc)
[   71.648285] [<c005d710>] (state_store+0x6c/0xbc) from [<c01eca78>]
(kobj_attr_store+0x14/0x20)
[   71.648298] [<c01eca78>] (kobj_attr_store+0x14/0x20) from [<c011e970>]
(sysfs_write_file+0x168/0x198)
[   71.648312] [<c011e970>] (sysfs_write_file+0x168/0x198) from
[<c00cd060>] (vfs_write+0xb0/0x188)
[   71.648321] [<c00cd060>] (vfs_write+0xb0/0x188) from [<c00cd410>]
(SyS_write+0x3c/0x70)
[   71.648330] [<c00cd410>] (SyS_write+0x3c/0x70) from [<c000e560>]
(ret_fast_syscall+0x0/0x30)
[   71.648334] ---[ end trace e5ed8212ac4db5da ]---
[   72.063578] mmc1: power class selection to bus width 8 failed
[   72.297753] usb 2-1: reset high-speed USB device number 2 using
tegra-ehci [   72.567736] usb 3-1: reset high-speed USB device number 2
using tegra-ehci [   73.022058] usb 3-1.3: reset high-speed USB device
number 4 using tegra- ehci
[   73.216064] usb 3-1.2: reset high-speed USB device number 3 using
tegra-
ehci
[   73.360225] PM: resume of devices complete after 1715.937 msecs
[   73.361008] Restarting tasks ... done.
Quoted 8 lines
Quoted 4 lines

and sdcard being offline after resume (fixed by CONFIG_MMC_UNSAFE_RESUME=y). Anyway, thanks for your great work!

I had same warn on 3.8.
https://bitbucket.org/digetx/picasso-kernel/commits/a86dc95ab48dd77eaa046384
4cdf88a5acf9d842

Stephen Warren said on IRC that this is known and on the internal bug tracker already. I just posted it so others are not surprised. Well, I should have added that it's a know problem. Sorry for that.

Marc

#39 lore raw

cover ARM: tegra: support LP1 suspend mode

27.07.2013 22:09, Marc Dietrich ?????:

Quoted 92 lines · On Saturday 27 July 2013 20:20:38 Dmitry Osipenko wrote:
Quoted 82 lines

27.07.2013 20:12, Marc Dietrich ?????:

Quoted 81 lines · On Friday 26 July 2013 17:15:02 Joseph Lo wrote:
Quoted 3 lines

This series adds the support of LP1 suspend mode for Tegra.

Verified on Seaboard, Cardhu and Dalmore.

tested on AC100 and worked fine, except

[   68.448007] PM: Syncing filesystems ... done.
[   71.370086] Freezing user space processes ... (elapsed 0.001 seconds)
done. [   71.370088] Freezing remaining freezable tasks ... (elapsed
0.001 seconds) done.
[   71.371253] Suspending console(s) (use no_console_suspend to debug)
[   71.638481] PM: suspend of devices complete after 266.604 msecs
[   71.638905] PM: late suspend of devices complete after 0.417 msecs
[   71.639477] PM: noirq suspend of devices complete after 0.568 msecs
[   71.639480] Disabling non-boot CPUs ...
[   71.640242] CPU1: shutdown
[   71.641216] Entering suspend state LP1
[   71.641267] Enabling non-boot CPUs ...
[   71.643125] CPU1: Booted secondary processor
[   71.643449] CPU1 is up
[   71.643786] PM: noirq resume of devices complete after 0.331 msecs
[   71.644300] PM: early resume of devices complete after 0.364 msecs
[   71.648038] ------------[ cut here ]------------
[   71.648061] WARNING: CPU: 0 PID: 1025 at kernel/irq/manage.c:529
irq_set_irq_wake+0xb8/0xf0()
[   71.648064] Unbalanced IRQ 384 wake disable
[   71.648068] Modules linked in:
[   71.648075] CPU: 0 PID: 1025 Comm: bash Not tainted 3.11.0-rc2-
next-20130726-00008-gef01509-dirty #6
[   71.648107] [<c001551c>] (unwind_backtrace+0x0/0xf8) from [<c001154c>]
(show_stack+0x10/0x14)
[   71.648128] [<c001154c>] (show_stack+0x10/0x14) from [<c0515288>]
(dump_stack+0x80/0xc4)
[   71.648142] [<c0515288>] (dump_stack+0x80/0xc4) from [<c0025340>]
(warn_slowpath_common+0x64/0x88)
[   71.648151] [<c0025340>] (warn_slowpath_common+0x64/0x88) from
[<c00253f8>] (warn_slowpath_fmt+0x30/0x40)
[   71.648161] [<c00253f8>] (warn_slowpath_fmt+0x30/0x40) from
[<c007ff8c>]
(irq_set_irq_wake+0xb8/0xf0)
[   71.648178] [<c007ff8c>] (irq_set_irq_wake+0xb8/0xf0) from [<c0334d00>]
(tps6586x_rtc_resume+0x30/0x38)
[   71.648192] [<c0334d00>] (tps6586x_rtc_resume+0x30/0x38) from
[<c02951d0>] (platform_pm_resume+0x2c/0x4c)
[   71.648202] [<c02951d0>] (platform_pm_resume+0x2c/0x4c) from
[<c0299d40>] (dpm_run_callback.isra.5+0x18/0x38)
[   71.648211] [<c0299d40>] (dpm_run_callback.isra.5+0x18/0x38) from
[<c029a044>] (device_resume+0xb0/0x170)
[   71.648219] [<c029a044>] (device_resume+0xb0/0x170) from [<c029aeb4>]
(dpm_resume+0xe8/0x20c)
[   71.648227] [<c029aeb4>] (dpm_resume+0xe8/0x20c) from [<c029b174>]
(dpm_resume_end+0xc/0x18)
[   71.648245] [<c029b174>] (dpm_resume_end+0xc/0x18) from [<c005e480>]
(suspend_devices_and_enter+0xdc/0x2f8)
[   71.648256] [<c005e480>] (suspend_devices_and_enter+0xdc/0x2f8) from
[<c005e810>] (pm_suspend+0x174/0x1e8)
[   71.648265] [<c005e810>] (pm_suspend+0x174/0x1e8) from [<c005d710>]
(state_store+0x6c/0xbc)
[   71.648285] [<c005d710>] (state_store+0x6c/0xbc) from [<c01eca78>]
(kobj_attr_store+0x14/0x20)
[   71.648298] [<c01eca78>] (kobj_attr_store+0x14/0x20) from [<c011e970>]
(sysfs_write_file+0x168/0x198)
[   71.648312] [<c011e970>] (sysfs_write_file+0x168/0x198) from
[<c00cd060>] (vfs_write+0xb0/0x188)
[   71.648321] [<c00cd060>] (vfs_write+0xb0/0x188) from [<c00cd410>]
(SyS_write+0x3c/0x70)
[   71.648330] [<c00cd410>] (SyS_write+0x3c/0x70) from [<c000e560>]
(ret_fast_syscall+0x0/0x30)
[   71.648334] ---[ end trace e5ed8212ac4db5da ]---
[   72.063578] mmc1: power class selection to bus width 8 failed
[   72.297753] usb 2-1: reset high-speed USB device number 2 using
tegra-ehci [   72.567736] usb 3-1: reset high-speed USB device number 2
using tegra-ehci [   73.022058] usb 3-1.3: reset high-speed USB device
number 4 using tegra- ehci
[   73.216064] usb 3-1.2: reset high-speed USB device number 3 using
tegra-
ehci
[   73.360225] PM: resume of devices complete after 1715.937 msecs
[   73.361008] Restarting tasks ... done.
Quoted 8 lines
Quoted 4 lines

and sdcard being offline after resume (fixed by CONFIG_MMC_UNSAFE_RESUME=y). Anyway, thanks for your great work!

I had same warn on 3.8.
https://bitbucket.org/digetx/picasso-kernel/commits/a86dc95ab48dd77eaa046384
4cdf88a5acf9d842

Quoted 9 lines

Stephen Warren said on IRC that this is known and on the internal bug tracker already. I just posted it so others are not surprised. Well, I should have added that it's a know problem. Sorry for that.

Marc

It might be a known problem only for those who faced with it. Since it's on their internal irc, it wasn't a known issue.

It also would be interesting to know if suspend with thumb2 works correctly. On 3.8 I've ported lp0 suspend and it works fine with arm compiled kernel, thumb2 also works but only for about 5-10 hours (resuming on each 5-30 minutes, default android behavior) and after I'm getting pmd corruption. I have no idea from where that corruption comes from without ability for hw debugging.

#40 lore raw

cover ARM: tegra: support LP1 suspend mode

27.07.2013 22:26, Dmitry Osipenko ?????:

Quoted 8 lines

It might be a known problem only for those who faced with it. Since it's on their internal irc, it wasn't a known issue.

It also would be interesting to know if suspend with thumb2 works correctly. On 3.8 I've ported lp0 suspend and it works fine with arm compiled kernel, thumb2 also works but only for about 5-10 hours (resuming on each 5-30 minutes, default android behavior) and after I'm getting pmd corruption. I have no idea from where that corruption comes from without ability for hw debugging.

s/irc/bug tracker/ :)

#41 lore raw

cover ARM: tegra: support LP1 suspend mode

In reply to Dmitry Osipenko
Quoted 41 lines · On Saturday 27 July 2013 22:26:06 Dmitry Osipenko wrote:

27.07.2013 22:09, Marc Dietrich ?????:

Quoted 33 lines · On Saturday 27 July 2013 20:20:38 Dmitry Osipenko wrote:
Quoted 31 lines

27.07.2013 20:12, Marc Dietrich ?????:

Quoted 30 lines · On Friday 26 July 2013 17:15:02 Joseph Lo wrote:
Quoted 3 lines

This series adds the support of LP1 suspend mode for Tegra.

Verified on Seaboard, Cardhu and Dalmore.

tested on AC100 and worked fine, except

[   68.448007] PM: Syncing filesystems ... done.
[   71.370086] Freezing user space processes ... (elapsed 0.001 seconds)
done. [   71.370088] Freezing remaining freezable tasks ... (elapsed
0.001 seconds) done.
[   71.371253] Suspending console(s) (use no_console_suspend to debug)
[   71.638481] PM: suspend of devices complete after 266.604 msecs
[   71.638905] PM: late suspend of devices complete after 0.417 msecs
[   71.639477] PM: noirq suspend of devices complete after 0.568 msecs
[   71.639480] Disabling non-boot CPUs ...
[   71.640242] CPU1: shutdown
[   71.641216] Entering suspend state LP1
[   71.641267] Enabling non-boot CPUs ...
[   71.643125] CPU1: Booted secondary processor
[   71.643449] CPU1 is up
[   71.643786] PM: noirq resume of devices complete after 0.331 msecs
[   71.644300] PM: early resume of devices complete after 0.364 msecs
[   71.648038] ------------[ cut here ]------------
[   71.648061] WARNING: CPU: 0 PID: 1025 at kernel/irq/manage.c:529
irq_set_irq_wake+0xb8/0xf0()
[   71.648064] Unbalanced IRQ 384 wake disable
[   71.648068] Modules linked in:
[   71.648075] CPU: 0 PID: 1025 Comm: bash Not tainted 3.11.0-rc2-

next-20130726-00008-gef01509-dirty #6

Quoted 3 lines

Stephen Warren said on IRC that this is known and on the internal bug tracker already. I just posted it so others are not surprised. Well, I should have added that it's a know problem. Sorry for that.

It might be a known problem only for those who faced with it. Since it's on their internal irc, it wasn't a known issue.

Quoted 6 lines

It also would be interesting to know if suspend with thumb2 works correctly. On 3.8 I've ported lp0 suspend and it works fine with arm compiled kernel, thumb2 also works but only for about 5-10 hours (resuming on each 5-30 minutes, default android behavior) and after I'm getting pmd corruption. I have no idea from where that corruption comes from without ability for hw debugging.

I don't think anyone can comment on this because lp0 support for mainline is not published yet. On the other hand, if you have patches for which you want some review, feel free to post them here.

Marc

#42 lore raw

cover ARM: tegra: support LP1 suspend mode

27.07.2013 23:03, Marc Dietrich ?????:

Quoted 49 lines · On Saturday 27 July 2013 22:26:06 Dmitry Osipenko wrote:
Quoted 41 lines

27.07.2013 22:09, Marc Dietrich ?????:

Quoted 33 lines · On Saturday 27 July 2013 20:20:38 Dmitry Osipenko wrote:
Quoted 31 lines

27.07.2013 20:12, Marc Dietrich ?????:

Quoted 30 lines · On Friday 26 July 2013 17:15:02 Joseph Lo wrote:
Quoted 3 lines

This series adds the support of LP1 suspend mode for Tegra.

Verified on Seaboard, Cardhu and Dalmore.

tested on AC100 and worked fine, except

[   68.448007] PM: Syncing filesystems ... done.
[   71.370086] Freezing user space processes ... (elapsed 0.001 seconds)
done. [   71.370088] Freezing remaining freezable tasks ... (elapsed
0.001 seconds) done.
[   71.371253] Suspending console(s) (use no_console_suspend to debug)
[   71.638481] PM: suspend of devices complete after 266.604 msecs
[   71.638905] PM: late suspend of devices complete after 0.417 msecs
[   71.639477] PM: noirq suspend of devices complete after 0.568 msecs
[   71.639480] Disabling non-boot CPUs ...
[   71.640242] CPU1: shutdown
[   71.641216] Entering suspend state LP1
[   71.641267] Enabling non-boot CPUs ...
[   71.643125] CPU1: Booted secondary processor
[   71.643449] CPU1 is up
[   71.643786] PM: noirq resume of devices complete after 0.331 msecs
[   71.644300] PM: early resume of devices complete after 0.364 msecs
[   71.648038] ------------[ cut here ]------------
[   71.648061] WARNING: CPU: 0 PID: 1025 at kernel/irq/manage.c:529
irq_set_irq_wake+0xb8/0xf0()
[   71.648064] Unbalanced IRQ 384 wake disable
[   71.648068] Modules linked in:
[   71.648075] CPU: 0 PID: 1025 Comm: bash Not tainted 3.11.0-rc2-

next-20130726-00008-gef01509-dirty #6

Quoted 3 lines

Stephen Warren said on IRC that this is known and on the internal bug tracker already. I just posted it so others are not surprised. Well, I should have added that it's a know problem. Sorry for that.

It might be a known problem only for those who faced with it. Since it's on their internal irc, it wasn't a known issue.

Quoted 6 lines

It also would be interesting to know if suspend with thumb2 works correctly. On 3.8 I've ported lp0 suspend and it works fine with arm compiled kernel, thumb2 also works but only for about 5-10 hours (resuming on each 5-30 minutes, default android behavior) and after I'm getting pmd corruption. I have no idea from where that corruption comes from without ability for hw debugging.

Quoted 6 lines

I don't think anyone can comment on this because lp0 support for mainline is not published yet. On the other hand, if you have patches for which you want some review, feel free to post them here.

Marc

I'm not expecting comment on it, just for notice :) I'll try this patches in some near future.

author
#43 lore raw

cover ARM: tegra: support LP1 suspend mode

In reply to Marc Dietrich
Quoted 7 lines · Marc Dietrich
Quoted 3 lines · On Friday 26 July 2013 17:15:02 Joseph Lo wrote:

This series adds the support of LP1 suspend mode for Tegra.

Verified on Seaboard, Cardhu and Dalmore.

tested on AC100 and worked fine, except

[unbalanced wake_enable/disable of rtc-6586x]

Quoted 6 lines

and sdcard being offline after resume (fixed by CONFIG_MMC_UNSAFE_RESUME=y). Anyway, thanks for your great work!

Marc,

Thanks for your testing.