diff options
| author | Joseph Lo <josephl@nvidia.com> | 2012-10-31 17:41:20 +0800 | 
|---|---|---|
| committer | Stephen Warren <swarren@nvidia.com> | 2012-11-15 15:09:21 -0700 | 
| commit | 01459c69dd48badeb7833c3293e43f7b8ae75e31 (patch) | |
| tree | 4ebe32a49b2b81560c8fb5fc94c9937360f16618 | |
| parent | a6e293eef2eafc31dbe008301182e7124bd87755 (diff) | |
| download | olio-linux-3.10-01459c69dd48badeb7833c3293e43f7b8ae75e31.tar.xz olio-linux-3.10-01459c69dd48badeb7833c3293e43f7b8ae75e31.zip  | |
ARM: tegra30: flowctrl: add cpu_suspend_exter/exit function
The flow controller can help CPU to go into suspend mode (powered-down
state). When CPU go into powered-down state, it needs some careful
settings before getting into and after leaving. The enter and exit
functions do that by configuring appropriate mode for flow controller.
Signed-off-by: Joseph Lo <josephl@nvidia.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
| -rw-r--r-- | arch/arm/mach-tegra/flowctrl.c | 47 | ||||
| -rw-r--r-- | arch/arm/mach-tegra/flowctrl.h | 8 | 
2 files changed, 55 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/flowctrl.c b/arch/arm/mach-tegra/flowctrl.c index ffaa286a71e..a2250ddae79 100644 --- a/arch/arm/mach-tegra/flowctrl.c +++ b/arch/arm/mach-tegra/flowctrl.c @@ -21,6 +21,7 @@  #include <linux/init.h>  #include <linux/kernel.h>  #include <linux/io.h> +#include <linux/cpumask.h>  #include "flowctrl.h"  #include "iomap.h" @@ -50,6 +51,14 @@ static void flowctrl_update(u8 offset, u32 value)  	readl_relaxed(addr);  } +u32 flowctrl_read_cpu_csr(unsigned int cpuid) +{ +	u8 offset = flowctrl_offset_cpu_csr[cpuid]; +	void __iomem *addr = IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + offset; + +	return readl(addr); +} +  void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value)  {  	return flowctrl_update(flowctrl_offset_cpu_csr[cpuid], value); @@ -59,3 +68,41 @@ void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value)  {  	return flowctrl_update(flowctrl_offset_halt_cpu[cpuid], value);  } + +void flowctrl_cpu_suspend_enter(unsigned int cpuid) +{ +	unsigned int reg; +	int i; + +	reg = flowctrl_read_cpu_csr(cpuid); +	reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;	/* clear wfe bitmap */ +	reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;	/* clear wfi bitmap */ +	reg |= FLOW_CTRL_CSR_INTR_FLAG;			/* clear intr flag */ +	reg |= FLOW_CTRL_CSR_EVENT_FLAG;		/* clear event flag */ +	reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid;	/* pwr gating on wfi */ +	reg |= FLOW_CTRL_CSR_ENABLE;			/* pwr gating */ +	flowctrl_write_cpu_csr(cpuid, reg); + +	for (i = 0; i < num_possible_cpus(); i++) { +		if (i == cpuid) +			continue; +		reg = flowctrl_read_cpu_csr(i); +		reg |= FLOW_CTRL_CSR_EVENT_FLAG; +		reg |= FLOW_CTRL_CSR_INTR_FLAG; +		flowctrl_write_cpu_csr(i, reg); +	} +} + +void flowctrl_cpu_suspend_exit(unsigned int cpuid) +{ +	unsigned int reg; + +	/* Disable powergating via flow controller for CPU0 */ +	reg = flowctrl_read_cpu_csr(cpuid); +	reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;	/* clear wfe bitmap */ +	reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;	/* clear wfi bitmap */ +	reg &= ~FLOW_CTRL_CSR_ENABLE;			/* clear enable */ +	reg |= FLOW_CTRL_CSR_INTR_FLAG;			/* clear intr */ +	reg |= FLOW_CTRL_CSR_EVENT_FLAG;		/* clear event */ +	flowctrl_write_cpu_csr(cpuid, reg); +} diff --git a/arch/arm/mach-tegra/flowctrl.h b/arch/arm/mach-tegra/flowctrl.h index 19428173855..0798dec1832 100644 --- a/arch/arm/mach-tegra/flowctrl.h +++ b/arch/arm/mach-tegra/flowctrl.h @@ -34,9 +34,17 @@  #define FLOW_CTRL_HALT_CPU1_EVENTS	0x14  #define FLOW_CTRL_CPU1_CSR		0x18 +#define TEGRA30_FLOW_CTRL_CSR_WFI_CPU0		(1 << 8) +#define TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP	(0xF << 4) +#define TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP	(0xF << 8) +  #ifndef __ASSEMBLY__ +u32 flowctrl_read_cpu_csr(unsigned int cpuid);  void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value);  void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value); + +void flowctrl_cpu_suspend_enter(unsigned int cpuid); +void flowctrl_cpu_suspend_exit(unsigned int cpuid);  #endif  #endif  |