diff options
-rw-r--r-- | Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt | 38 | ||||
-rw-r--r-- | arch/arm/mach-tegra/pmc.c | 83 | ||||
-rw-r--r-- | arch/arm/mach-tegra/pmc.h | 8 |
3 files changed, 129 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt index ee529b17cb9f..1608a54e90e1 100644 --- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt | |||
@@ -1,5 +1,9 @@ | |||
1 | NVIDIA Tegra Power Management Controller (PMC) | 1 | NVIDIA Tegra Power Management Controller (PMC) |
2 | 2 | ||
3 | The PMC block interacts with an external Power Management Unit. The PMC | ||
4 | mostly controls the entry and exit of the system from different sleep | ||
5 | modes. It provides power-gating controllers for SoC and CPU power-islands. | ||
6 | |||
3 | Required properties: | 7 | Required properties: |
4 | - name : Should be pmc | 8 | - name : Should be pmc |
5 | - compatible : Should contain "nvidia,tegra<chip>-pmc". | 9 | - compatible : Should contain "nvidia,tegra<chip>-pmc". |
@@ -15,6 +19,32 @@ Optional properties: | |||
15 | signal is fed into the PMC. This signal is optionally inverted, and then | 19 | signal is fed into the PMC. This signal is optionally inverted, and then |
16 | fed into the ARM GIC. The PMC is not involved in the detection or | 20 | fed into the ARM GIC. The PMC is not involved in the detection or |
17 | handling of this interrupt signal, merely its inversion. | 21 | handling of this interrupt signal, merely its inversion. |
22 | - nvidia,suspend-mode : The suspend mode that the platform should use. | ||
23 | Valid values are 0, 1 and 2: | ||
24 | 0 (LP0): CPU + Core voltage off and DRAM in self-refresh | ||
25 | 1 (LP1): CPU voltage off and DRAM in self-refresh | ||
26 | 2 (LP2): CPU voltage off | ||
27 | - nvidia,core-power-req-active-high : Boolean, core power request active-high | ||
28 | - nvidia,sys-clock-req-active-high : Boolean, system clock request active-high | ||
29 | - nvidia,combined-power-req : Boolean, combined power request for CPU & Core | ||
30 | - nvidia,cpu-pwr-good-en : Boolean, CPU power good signal (from PMIC to PMC) | ||
31 | is enabled. | ||
32 | |||
33 | Required properties when nvidia,suspend-mode is specified: | ||
34 | - nvidia,cpu-pwr-good-time : CPU power good time in uS. | ||
35 | - nvidia,cpu-pwr-off-time : CPU power off time in uS. | ||
36 | - nvidia,core-pwr-good-time : <Oscillator-stable-time Power-stable-time> | ||
37 | Core power good time in uS. | ||
38 | - nvidia,core-pwr-off-time : Core power off time in uS. | ||
39 | |||
40 | Required properties when nvidia,suspend-mode=<0>: | ||
41 | - nvidia,lp0-vec : <start length> Starting address and length of LP0 vector | ||
42 | The LP0 vector contains the warm boot code that is executed by AVP when | ||
43 | resuming from the LP0 state. The AVP (Audio-Video Processor) is an ARM7 | ||
44 | processor and always being the first boot processor when chip is power on | ||
45 | or resume from deep sleep mode. When the system is resumed from the deep | ||
46 | sleep mode, the warm boot code will restore some PLLs, clocks and then | ||
47 | bring up CPU0 for resuming the system. | ||
18 | 48 | ||
19 | Example: | 49 | Example: |
20 | 50 | ||
@@ -25,6 +55,14 @@ pmc@7000f400 { | |||
25 | clocks = <&tegra_car 110>, <&clk32k_in>; | 55 | clocks = <&tegra_car 110>, <&clk32k_in>; |
26 | clock-names = "pclk", "clk32k_in"; | 56 | clock-names = "pclk", "clk32k_in"; |
27 | nvidia,invert-interrupt; | 57 | nvidia,invert-interrupt; |
58 | nvidia,suspend-mode = <1>; | ||
59 | nvidia,cpu-pwr-good-time = <2000>; | ||
60 | nvidia,cpu-pwr-off-time = <100>; | ||
61 | nvidia,core-pwr-good-time = <3845 3845>; | ||
62 | nvidia,core-pwr-off-time = <458>; | ||
63 | nvidia,core-power-req-active-high; | ||
64 | nvidia,sys-clock-req-active-high; | ||
65 | nvidia,lp0-vec = <0xbdffd000 0x2000>; | ||
28 | }; | 66 | }; |
29 | 67 | ||
30 | / Tegra board dts file | 68 | / Tegra board dts file |
diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c index faa33e8f937d..e896826d7d0f 100644 --- a/arch/arm/mach-tegra/pmc.c +++ b/arch/arm/mach-tegra/pmc.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <linux/of.h> | 21 | #include <linux/of.h> |
22 | #include <linux/of_address.h> | 22 | #include <linux/of_address.h> |
23 | 23 | ||
24 | #include "pmc.h" | ||
25 | |||
24 | #define PMC_CTRL 0x0 | 26 | #define PMC_CTRL 0x0 |
25 | #define PMC_CTRL_INTR_LOW (1 << 17) | 27 | #define PMC_CTRL_INTR_LOW (1 << 17) |
26 | #define PMC_PWRGATE_TOGGLE 0x30 | 28 | #define PMC_PWRGATE_TOGGLE 0x30 |
@@ -49,6 +51,22 @@ static void __iomem *tegra_pmc_base; | |||
49 | static bool tegra_pmc_invert_interrupt; | 51 | static bool tegra_pmc_invert_interrupt; |
50 | static struct clk *tegra_pclk; | 52 | static struct clk *tegra_pclk; |
51 | 53 | ||
54 | struct pmc_pm_data { | ||
55 | u32 cpu_good_time; /* CPU power good time in uS */ | ||
56 | u32 cpu_off_time; /* CPU power off time in uS */ | ||
57 | u32 core_osc_time; /* Core power good osc time in uS */ | ||
58 | u32 core_pmu_time; /* Core power good pmu time in uS */ | ||
59 | u32 core_off_time; /* Core power off time in uS */ | ||
60 | bool corereq_high; /* Core power request active-high */ | ||
61 | bool sysclkreq_high; /* System clock request active-high */ | ||
62 | bool combined_req; /* Combined pwr req for CPU & Core */ | ||
63 | bool cpu_pwr_good_en; /* CPU power good signal is enabled */ | ||
64 | u32 lp0_vec_phy_addr; /* The phy addr of LP0 warm boot code */ | ||
65 | u32 lp0_vec_size; /* The size of LP0 warm boot code */ | ||
66 | enum tegra_suspend_mode suspend_mode; | ||
67 | }; | ||
68 | static struct pmc_pm_data pmc_pm_data; | ||
69 | |||
52 | static inline u32 tegra_pmc_readl(u32 reg) | 70 | static inline u32 tegra_pmc_readl(u32 reg) |
53 | { | 71 | { |
54 | return readl(tegra_pmc_base + reg); | 72 | return readl(tegra_pmc_base + reg); |
@@ -176,6 +194,10 @@ static const struct of_device_id matches[] __initconst = { | |||
176 | static void tegra_pmc_parse_dt(void) | 194 | static void tegra_pmc_parse_dt(void) |
177 | { | 195 | { |
178 | struct device_node *np; | 196 | struct device_node *np; |
197 | u32 prop; | ||
198 | enum tegra_suspend_mode suspend_mode; | ||
199 | u32 core_good_time[2] = {0, 0}; | ||
200 | u32 lp0_vec[2] = {0, 0}; | ||
179 | 201 | ||
180 | np = of_find_matching_node(NULL, matches); | 202 | np = of_find_matching_node(NULL, matches); |
181 | BUG_ON(!np); | 203 | BUG_ON(!np); |
@@ -186,6 +208,67 @@ static void tegra_pmc_parse_dt(void) | |||
186 | "nvidia,invert-interrupt"); | 208 | "nvidia,invert-interrupt"); |
187 | tegra_pclk = of_clk_get_by_name(np, "pclk"); | 209 | tegra_pclk = of_clk_get_by_name(np, "pclk"); |
188 | WARN_ON(IS_ERR(tegra_pclk)); | 210 | WARN_ON(IS_ERR(tegra_pclk)); |
211 | |||
212 | /* Grabbing the power management configurations */ | ||
213 | if (of_property_read_u32(np, "nvidia,suspend-mode", &prop)) { | ||
214 | suspend_mode = TEGRA_SUSPEND_NONE; | ||
215 | } else { | ||
216 | switch (prop) { | ||
217 | case 0: | ||
218 | suspend_mode = TEGRA_SUSPEND_LP0; | ||
219 | break; | ||
220 | case 1: | ||
221 | suspend_mode = TEGRA_SUSPEND_LP1; | ||
222 | break; | ||
223 | case 2: | ||
224 | suspend_mode = TEGRA_SUSPEND_LP2; | ||
225 | break; | ||
226 | default: | ||
227 | suspend_mode = TEGRA_SUSPEND_NONE; | ||
228 | break; | ||
229 | } | ||
230 | } | ||
231 | |||
232 | if (of_property_read_u32(np, "nvidia,cpu-pwr-good-time", &prop)) | ||
233 | suspend_mode = TEGRA_SUSPEND_NONE; | ||
234 | pmc_pm_data.cpu_good_time = prop; | ||
235 | |||
236 | if (of_property_read_u32(np, "nvidia,cpu-pwr-off-time", &prop)) | ||
237 | suspend_mode = TEGRA_SUSPEND_NONE; | ||
238 | pmc_pm_data.cpu_off_time = prop; | ||
239 | |||
240 | if (of_property_read_u32_array(np, "nvidia,core-pwr-good-time", | ||
241 | core_good_time, ARRAY_SIZE(core_good_time))) | ||
242 | suspend_mode = TEGRA_SUSPEND_NONE; | ||
243 | pmc_pm_data.core_osc_time = core_good_time[0]; | ||
244 | pmc_pm_data.core_pmu_time = core_good_time[1]; | ||
245 | |||
246 | if (of_property_read_u32(np, "nvidia,core-pwr-off-time", | ||
247 | &prop)) | ||
248 | suspend_mode = TEGRA_SUSPEND_NONE; | ||
249 | pmc_pm_data.core_off_time = prop; | ||
250 | |||
251 | pmc_pm_data.corereq_high = of_property_read_bool(np, | ||
252 | "nvidia,core-power-req-active-high"); | ||
253 | |||
254 | pmc_pm_data.sysclkreq_high = of_property_read_bool(np, | ||
255 | "nvidia,sys-clock-req-active-high"); | ||
256 | |||
257 | pmc_pm_data.combined_req = of_property_read_bool(np, | ||
258 | "nvidia,combined-power-req"); | ||
259 | |||
260 | pmc_pm_data.cpu_pwr_good_en = of_property_read_bool(np, | ||
261 | "nvidia,cpu-pwr-good-en"); | ||
262 | |||
263 | if (of_property_read_u32_array(np, "nvidia,lp0-vec", lp0_vec, | ||
264 | ARRAY_SIZE(lp0_vec))) | ||
265 | if (suspend_mode == TEGRA_SUSPEND_LP0) | ||
266 | suspend_mode = TEGRA_SUSPEND_LP1; | ||
267 | |||
268 | pmc_pm_data.lp0_vec_phy_addr = lp0_vec[0]; | ||
269 | pmc_pm_data.lp0_vec_size = lp0_vec[1]; | ||
270 | |||
271 | pmc_pm_data.suspend_mode = suspend_mode; | ||
189 | } | 272 | } |
190 | 273 | ||
191 | void __init tegra_pmc_init(void) | 274 | void __init tegra_pmc_init(void) |
diff --git a/arch/arm/mach-tegra/pmc.h b/arch/arm/mach-tegra/pmc.h index 22f16c9dd44d..6bc0fc095269 100644 --- a/arch/arm/mach-tegra/pmc.h +++ b/arch/arm/mach-tegra/pmc.h | |||
@@ -18,6 +18,14 @@ | |||
18 | #ifndef __MACH_TEGRA_PMC_H | 18 | #ifndef __MACH_TEGRA_PMC_H |
19 | #define __MACH_TEGRA_PMC_H | 19 | #define __MACH_TEGRA_PMC_H |
20 | 20 | ||
21 | enum tegra_suspend_mode { | ||
22 | TEGRA_SUSPEND_NONE = 0, | ||
23 | TEGRA_SUSPEND_LP2, /* CPU voltage off */ | ||
24 | TEGRA_SUSPEND_LP1, /* CPU voltage off, DRAM self-refresh */ | ||
25 | TEGRA_SUSPEND_LP0, /* CPU + core voltage off, DRAM self-refresh */ | ||
26 | TEGRA_MAX_SUSPEND_MODE, | ||
27 | }; | ||
28 | |||
21 | #ifdef CONFIG_PM_SLEEP | 29 | #ifdef CONFIG_PM_SLEEP |
22 | void set_power_timers(unsigned long us_on, unsigned long us_off); | 30 | void set_power_timers(unsigned long us_on, unsigned long us_off); |
23 | #endif | 31 | #endif |