diff mbox

[V3,3/5] ARM: tegra20: clocks: add CPU low-power function into tegra_cpu_car_ops

Message ID 1355797861-12759-4-git-send-email-josephl@nvidia.com (mailing list archive)
State New, archived
Headers show

Commit Message

Joseph Lo Dec. 18, 2012, 2:30 a.m. UTC
Add suspend, resume and rail_off_ready API into tegra_cpu_car_ops. These
functions were used for CPU powered-down state maintenance.

Signed-off-by: Joseph Lo <josephl@nvidia.com>
---
V3:
* no change
V2:
* refine the code sequence in "tegra20_cpu_rail_off_ready"
---
 arch/arm/mach-tegra/tegra20_clocks.c |   99 ++++++++++++++++++++++++++++++++++
 1 files changed, 99 insertions(+), 0 deletions(-)

Comments

Stephen Warren Dec. 20, 2012, 5:46 p.m. UTC | #1
On 12/17/2012 07:30 PM, Joseph Lo wrote:
> Add suspend, resume and rail_off_ready API into tegra_cpu_car_ops. These
> functions were used for CPU powered-down state maintenance.

I think this isn't adding those functions into tegra_cpu_car_ops, but
rather implementing the already existing function pointers for Tegra20,
right?

This patch touches the clock driver and Prashant will soon be posting
patches that significantly rework the clock driver. Those will conflict.
How have you worked with Prashant to resolve the conflicts? Will
Prashant's patches be based on top of this series? Please explicitly
describe the dependencies and resolution of conflicts when you post the
next version. (below the ---, along with the changelog)
Joseph Lo Dec. 21, 2012, 5:02 a.m. UTC | #2
On Fri, 2012-12-21 at 01:46 +0800, Stephen Warren wrote:
> On 12/17/2012 07:30 PM, Joseph Lo wrote:
> > Add suspend, resume and rail_off_ready API into tegra_cpu_car_ops. These
> > functions were used for CPU powered-down state maintenance.
> 
> I think this isn't adding those functions into tegra_cpu_car_ops, but
> rather implementing the already existing function pointers for Tegra20,
> right?
> 
Yes, exactly.

> This patch touches the clock driver and Prashant will soon be posting
> patches that significantly rework the clock driver. Those will conflict.
> How have you worked with Prashant to resolve the conflicts? Will
> Prashant's patches be based on top of this series? Please explicitly
> describe the dependencies and resolution of conflicts when you post the
> next version. (below the ---, along with the changelog)
> 
Yes, there are many patch series may have dependency each other
recently. We also want to know what the sequence you expect to merge the
patch series to your tree. Evan my own patch series had dependency too.
For ex, hotplug enhancement, cpuidle, SMP works on UP and
suspend/resume. Currently, I think we are all work the the top of
linux-next tree. If we can't expect the sequence of the patch series to
be merged, we will always have some conflicts with each other.

Depend on the timing, I think it should be better to know which patch
series should be going first or recently and which should go later and
depend on which series. Then we can rearrange our patches on top of it.
And reducing the job to fix conflict on your side.

What do you think, Prashant? If your rework of clock driver will show up
soon and Stephen also expect that will be merged first, I am fine to
re-base on it and re-send my next version after new clock driver be
done.

Thanks,
Joseph
Stephen Warren Dec. 21, 2012, 9:10 p.m. UTC | #3
On 12/20/2012 10:02 PM, Joseph Lo wrote:
> On Fri, 2012-12-21 at 01:46 +0800, Stephen Warren wrote:
>> On 12/17/2012 07:30 PM, Joseph Lo wrote:
>>> Add suspend, resume and rail_off_ready API into tegra_cpu_car_ops. These
>>> functions were used for CPU powered-down state maintenance.
>>
>> I think this isn't adding those functions into tegra_cpu_car_ops, but
>> rather implementing the already existing function pointers for Tegra20,
>> right?
>>
> Yes, exactly.
> 
>> This patch touches the clock driver and Prashant will soon be posting
>> patches that significantly rework the clock driver. Those will conflict.
>> How have you worked with Prashant to resolve the conflicts? Will
>> Prashant's patches be based on top of this series? Please explicitly
>> describe the dependencies and resolution of conflicts when you post the
>> next version. (below the ---, along with the changelog)
>>
> Yes, there are many patch series may have dependency each other
> recently. We also want to know what the sequence you expect to merge the
> patch series to your tree.

To be honest, I don't know what order I'd like to merge things yet.
There are so many conflicting/dependant patches for 3.9 flying around
I'd need to re-read them all and think it through in quite some detail...

The common clock rework is something quite important. I'd certainly like
to get that in early. That most likely implies everything else should be
rebased on top of it.

The best thing would be if all patch authors take a look at Prashant's
clock patches (and all other patches) and work out what has dependencies
on what, and co-ordinate with each-other which order is the easiest to
merge things in. Once 3.8-rc1 is out and I can actually start merging
things, I'd like to see a list of outstanding patches from each person,
with all dependencies explicitly listed. I'll use that information to
decide which order to merge in.

Of course I just realized that Prashant hasn't posted his clock patches
upstream yet, so it's a little difficult for anyone to rebase on top of
them yet, but hopefully that will be resolved very soon now...
diff mbox

Patch

diff --git a/arch/arm/mach-tegra/tegra20_clocks.c b/arch/arm/mach-tegra/tegra20_clocks.c
index 4eb6bc8..1780268 100644
--- a/arch/arm/mach-tegra/tegra20_clocks.c
+++ b/arch/arm/mach-tegra/tegra20_clocks.c
@@ -159,6 +159,31 @@ 
 #define CPU_CLOCK(cpu)	(0x1 << (8 + cpu))
 #define CPU_RESET(cpu)	(0x1111ul << (cpu))
 
+#define CLK_RESET_CCLK_BURST	0x20
+#define CLK_RESET_CCLK_DIVIDER  0x24
+#define CLK_RESET_PLLX_BASE	0xe0
+#define CLK_RESET_PLLX_MISC	0xe4
+
+#define CLK_RESET_SOURCE_CSITE	0x1d4
+
+#define CLK_RESET_CCLK_BURST_POLICY_SHIFT	28
+#define CLK_RESET_CCLK_RUN_POLICY_SHIFT		4
+#define CLK_RESET_CCLK_IDLE_POLICY_SHIFT	0
+#define CLK_RESET_CCLK_IDLE_POLICY		1
+#define CLK_RESET_CCLK_RUN_POLICY		2
+#define CLK_RESET_CCLK_BURST_POLICY_PLLX	8
+
+#ifdef CONFIG_PM_SLEEP
+static struct cpu_clk_suspend_context {
+	u32 pllx_misc;
+	u32 pllx_base;
+
+	u32 cpu_burst;
+	u32 clk_csite_src;
+	u32 cclk_divider;
+} tegra20_cpu_clk_sctx;
+#endif
+
 static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
 static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
 
@@ -1609,12 +1634,86 @@  static void tegra20_disable_cpu_clock(u32 cpu)
 	       reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
 }
 
+#ifdef CONFIG_PM_SLEEP
+static bool tegra20_cpu_rail_off_ready(void)
+{
+	unsigned int cpu_rst_status;
+
+	cpu_rst_status = readl(reg_clk_base +
+			       TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
+
+	return !!(cpu_rst_status & 0x2);
+}
+
+static void tegra20_cpu_clock_suspend(void)
+{
+	/* switch coresite to clk_m, save off original source */
+	tegra20_cpu_clk_sctx.clk_csite_src =
+				readl(reg_clk_base + CLK_RESET_SOURCE_CSITE);
+	writel(3<<30, reg_clk_base + CLK_RESET_SOURCE_CSITE);
+
+	tegra20_cpu_clk_sctx.cpu_burst =
+				readl(reg_clk_base + CLK_RESET_CCLK_BURST);
+	tegra20_cpu_clk_sctx.pllx_base =
+				readl(reg_clk_base + CLK_RESET_PLLX_BASE);
+	tegra20_cpu_clk_sctx.pllx_misc =
+				readl(reg_clk_base + CLK_RESET_PLLX_MISC);
+	tegra20_cpu_clk_sctx.cclk_divider =
+				readl(reg_clk_base + CLK_RESET_CCLK_DIVIDER);
+}
+
+static void tegra20_cpu_clock_resume(void)
+{
+	unsigned int reg, policy;
+
+	/* Is CPU complex already running on PLLX? */
+	reg = readl(reg_clk_base + CLK_RESET_CCLK_BURST);
+	policy = (reg >> CLK_RESET_CCLK_BURST_POLICY_SHIFT) & 0xF;
+
+	if (policy == CLK_RESET_CCLK_IDLE_POLICY)
+		reg = (reg >> CLK_RESET_CCLK_IDLE_POLICY_SHIFT) & 0xF;
+	else if (policy == CLK_RESET_CCLK_RUN_POLICY)
+		reg = (reg >> CLK_RESET_CCLK_RUN_POLICY_SHIFT) & 0xF;
+	else
+		BUG();
+
+	if (reg != CLK_RESET_CCLK_BURST_POLICY_PLLX) {
+		/* restore PLLX settings if CPU is on different PLL */
+		writel(tegra20_cpu_clk_sctx.pllx_misc,
+					reg_clk_base + CLK_RESET_PLLX_MISC);
+		writel(tegra20_cpu_clk_sctx.pllx_base,
+					reg_clk_base + CLK_RESET_PLLX_BASE);
+
+		/* wait for PLL stabilization if PLLX was enabled */
+		if (tegra20_cpu_clk_sctx.pllx_base & (1 << 30))
+			udelay(300);
+	}
+
+	/*
+	 * Restore original burst policy setting for calls resulting from CPU
+	 * LP2 in idle or system suspend.
+	 */
+	writel(tegra20_cpu_clk_sctx.cclk_divider,
+					reg_clk_base + CLK_RESET_CCLK_DIVIDER);
+	writel(tegra20_cpu_clk_sctx.cpu_burst,
+					reg_clk_base + CLK_RESET_CCLK_BURST);
+
+	writel(tegra20_cpu_clk_sctx.clk_csite_src,
+					reg_clk_base + CLK_RESET_SOURCE_CSITE);
+}
+#endif
+
 static struct tegra_cpu_car_ops tegra20_cpu_car_ops = {
 	.wait_for_reset	= tegra20_wait_cpu_in_reset,
 	.put_in_reset	= tegra20_put_cpu_in_reset,
 	.out_of_reset	= tegra20_cpu_out_of_reset,
 	.enable_clock	= tegra20_enable_cpu_clock,
 	.disable_clock	= tegra20_disable_cpu_clock,
+#ifdef CONFIG_PM_SLEEP
+	.rail_off_ready = tegra20_cpu_rail_off_ready,
+	.suspend	= tegra20_cpu_clock_suspend,
+	.resume		= tegra20_cpu_clock_resume,
+#endif
 };
 
 void __init tegra20_cpu_car_ops_init(void)