diff mbox

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

Message ID 1354503607-13707-3-git-send-email-josephl@nvidia.com (mailing list archive)
State New, archived
Headers show

Commit Message

Joseph Lo Dec. 3, 2012, 3 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>
---
 arch/arm/mach-tegra/tegra20_clocks.c |  102 ++++++++++++++++++++++++++++++++++
 1 files changed, 102 insertions(+), 0 deletions(-)

Comments

Stephen Warren Dec. 3, 2012, 6:20 p.m. UTC | #1
On 12/02/2012 08:00 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.

> diff --git a/arch/arm/mach-tegra/tegra20_clocks.c b/arch/arm/mach-tegra/tegra20_clocks.c

> +static bool tegra20_cpu_rail_off_ready(void)

> +	if ((cpu_rst_status & 0x2) != 0x2)
> +		return false;
> +
> +	return true;
> +}

Perhaps simplify that to:

return cpu_rst_status & 2;

or perhaps if that generates an int->bool performance warning:

return !!(cpu_rst_status & 2);

or:

return (cpu_rst_status >> 1) & 1;
Joseph Lo Dec. 4, 2012, 4:28 a.m. UTC | #2
On Tue, 2012-12-04 at 02:20 +0800, Stephen Warren wrote:
> On 12/02/2012 08:00 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.
> 
> > diff --git a/arch/arm/mach-tegra/tegra20_clocks.c b/arch/arm/mach-tegra/tegra20_clocks.c
> 
> > +static bool tegra20_cpu_rail_off_ready(void)
> 
> > +	if ((cpu_rst_status & 0x2) != 0x2)
> > +		return false;
> > +
> > +	return true;
> > +}
> 
> Perhaps simplify that to:
> 
> return cpu_rst_status & 2;
> 
> or perhaps if that generates an int->bool performance warning:
> 
> return !!(cpu_rst_status & 2);

OK. Will do this.

Thanks,
Joseph
Prashant Gaikwad Dec. 4, 2012, 5:12 a.m. UTC | #3
On Monday 03 December 2012 08:30 AM, 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.
>
> Signed-off-by: Joseph Lo <josephl@nvidia.com>
> ---
>   arch/arm/mach-tegra/tegra20_clocks.c |  102 ++++++++++++++++++++++++++++++++++
>   1 files changed, 102 insertions(+), 0 deletions(-)

I have a concern here, I am working on removing these ops and replacing 
it with clock.
Adding suspend/resume to these will make it more difficult to remove.

Any other way to implement this?

> diff --git a/arch/arm/mach-tegra/tegra20_clocks.c b/arch/arm/mach-tegra/tegra20_clocks.c
> index 4eb6bc8..05968d7 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))
>
Joseph Lo Dec. 4, 2012, 5:25 a.m. UTC | #4
On Tue, 2012-12-04 at 13:12 +0800, Prashant Gaikwad wrote:
> On Monday 03 December 2012 08:30 AM, 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.
> >
> > Signed-off-by: Joseph Lo <josephl@nvidia.com>
> > ---
> >   arch/arm/mach-tegra/tegra20_clocks.c |  102 ++++++++++++++++++++++++++++++++++
> >   1 files changed, 102 insertions(+), 0 deletions(-)
> 
> I have a concern here, I am working on removing these ops and replacing 
> it with clock.
> Adding suspend/resume to these will make it more difficult to remove.
> 
> Any other way to implement this?
> 

Prashant,

Thanks for remind.
Actually the "tegra_cpu_car_ops" is more like reset & suspend/resume
handling, it's not really related to clock framework. So it's more like
some functions for CPU power management control. Maybe I can move them
(Tegra20 & Tegra30) to another pm related file later.

How do you think, Stephen?

Thanks,
Joseph
Stephen Warren Dec. 5, 2012, 6:34 p.m. UTC | #5
On 12/03/2012 10:25 PM, Joseph Lo wrote:
> On Tue, 2012-12-04 at 13:12 +0800, Prashant Gaikwad wrote:
>> On Monday 03 December 2012 08:30 AM, 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.
>>>
>>> Signed-off-by: Joseph Lo <josephl@nvidia.com>
>>> ---
>>>   arch/arm/mach-tegra/tegra20_clocks.c |  102 ++++++++++++++++++++++++++++++++++
>>>   1 files changed, 102 insertions(+), 0 deletions(-)
>>
>> I have a concern here, I am working on removing these ops and replacing 
>> it with clock.
>> Adding suspend/resume to these will make it more difficult to remove.
>>
>> Any other way to implement this?
>>
> 
> Prashant,
> 
> Thanks for remind.
> Actually the "tegra_cpu_car_ops" is more like reset & suspend/resume
> handling, it's not really related to clock framework. So it's more like
> some functions for CPU power management control. Maybe I can move them
> (Tegra20 & Tegra30) to another pm related file later.
> 
> How do you think, Stephen?

Well, the CAR (Clock And Reset) HW module implements this functionality,
right? As such, the code should be part of the clock driver. The whole
reason we have the car_ops in the first place is so that only the clock
driver touches the clock HW module. I hope we'll eventually do the same
for all HW modules.
diff mbox

Patch

diff --git a/arch/arm/mach-tegra/tegra20_clocks.c b/arch/arm/mach-tegra/tegra20_clocks.c
index 4eb6bc8..05968d7 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,89 @@  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);
+
+	if ((cpu_rst_status & 0x2) != 0x2)
+		return false;
+
+	return true;
+}
+
+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)