aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2014-07-11 07:19:06 -0400
committerThierry Reding <treding@nvidia.com>2014-07-17 08:58:43 -0400
commit7232398abc6a7186e315425638c367d50c674718 (patch)
tree874b08603b104c3b42a07cb7c1402a8f3bcf5ec0
parent24fa5af81059af90c723bec6aacc3cd2b2809d14 (diff)
ARM: tegra: Convert PMC to a driver
This commit converts the PMC support code to a platform driver. Because the boot process needs to call into this driver very early, also set up a minimal environment via an early initcall. Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/Makefile2
-rw-r--r--arch/arm/mach-tegra/board.h7
-rw-r--r--arch/arm/mach-tegra/platsmp.c2
-rw-r--r--arch/arm/mach-tegra/pm.c32
-rw-r--r--arch/arm/mach-tegra/pm.h10
-rw-r--r--arch/arm/mach-tegra/pmc.c414
-rw-r--r--arch/arm/mach-tegra/pmc.h49
-rw-r--r--arch/arm/mach-tegra/powergate.c516
-rw-r--r--arch/arm/mach-tegra/tegra.c7
-rw-r--r--drivers/clk/tegra/clk-tegra30.c2
-rw-r--r--drivers/gpu/drm/tegra/gr3d.c2
-rw-r--r--drivers/gpu/drm/tegra/sor.c2
-rw-r--r--drivers/pci/host/pci-tegra.c2
-rw-r--r--drivers/soc/tegra/Makefile1
-rw-r--r--drivers/soc/tegra/pmc.c957
-rw-r--r--include/soc/tegra/pm.h38
-rw-r--r--include/soc/tegra/pmc.h (renamed from include/soc/tegra/powergate.h)31
17 files changed, 1054 insertions, 1020 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index c303b55de22e..e48a74458c25 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -2,9 +2,7 @@ asflags-y += -march=armv7-a
2 2
3obj-y += io.o 3obj-y += io.o
4obj-y += irq.o 4obj-y += irq.o
5obj-y += pmc.o
6obj-y += flowctrl.o 5obj-y += flowctrl.o
7obj-y += powergate.o
8obj-y += pm.o 6obj-y += pm.o
9obj-y += reset.o 7obj-y += reset.o
10obj-y += reset-handler.o 8obj-y += reset-handler.o
diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h
index bcf5dbf69d58..da90c89296b9 100644
--- a/arch/arm/mach-tegra/board.h
+++ b/arch/arm/mach-tegra/board.h
@@ -28,13 +28,6 @@
28void __init tegra_map_common_io(void); 28void __init tegra_map_common_io(void);
29void __init tegra_init_irq(void); 29void __init tegra_init_irq(void);
30 30
31int __init tegra_powergate_init(void);
32#if defined(CONFIG_ARCH_TEGRA_2x_SOC) && defined(CONFIG_DEBUG_FS)
33int __init tegra_powergate_debugfs_init(void);
34#else
35static inline int tegra_powergate_debugfs_init(void) { return 0; }
36#endif
37
38void __init tegra_paz00_wifikill_init(void); 31void __init tegra_paz00_wifikill_init(void);
39 32
40#endif 33#endif
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index 0466a145b500..b45086666648 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -22,6 +22,7 @@
22#include <linux/smp.h> 22#include <linux/smp.h>
23 23
24#include <soc/tegra/fuse.h> 24#include <soc/tegra/fuse.h>
25#include <soc/tegra/pmc.h>
25 26
26#include <asm/cacheflush.h> 27#include <asm/cacheflush.h>
27#include <asm/mach-types.h> 28#include <asm/mach-types.h>
@@ -31,7 +32,6 @@
31#include "common.h" 32#include "common.h"
32#include "flowctrl.h" 33#include "flowctrl.h"
33#include "iomap.h" 34#include "iomap.h"
34#include "pmc.h"
35#include "reset.h" 35#include "reset.h"
36 36
37static cpumask_t tegra_cpu_init_mask; 37static cpumask_t tegra_cpu_init_mask;
diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c
index 94db3b6664df..b0f48a3946fa 100644
--- a/arch/arm/mach-tegra/pm.c
+++ b/arch/arm/mach-tegra/pm.c
@@ -28,6 +28,8 @@
28#include <linux/suspend.h> 28#include <linux/suspend.h>
29 29
30#include <soc/tegra/fuse.h> 30#include <soc/tegra/fuse.h>
31#include <soc/tegra/pm.h>
32#include <soc/tegra/pmc.h>
31 33
32#include <asm/cacheflush.h> 34#include <asm/cacheflush.h>
33#include <asm/idmap.h> 35#include <asm/idmap.h>
@@ -38,7 +40,6 @@
38 40
39#include "flowctrl.h" 41#include "flowctrl.h"
40#include "iomap.h" 42#include "iomap.h"
41#include "pmc.h"
42#include "pm.h" 43#include "pm.h"
43#include "reset.h" 44#include "reset.h"
44#include "sleep.h" 45#include "sleep.h"
@@ -167,9 +168,29 @@ static int tegra_sleep_cpu(unsigned long v2p)
167 return 0; 168 return 0;
168} 169}
169 170
171static void tegra_pm_set(enum tegra_suspend_mode mode)
172{
173 u32 value;
174
175 switch (tegra_get_chip_id()) {
176 case TEGRA20:
177 case TEGRA30:
178 break;
179 default:
180 /* Turn off CRAIL */
181 value = flowctrl_read_cpu_csr(0);
182 value &= ~FLOW_CTRL_CSR_ENABLE_EXT_MASK;
183 value |= FLOW_CTRL_CSR_ENABLE_EXT_CRAIL;
184 flowctrl_write_cpu_csr(0, value);
185 break;
186 }
187
188 tegra_pmc_enter_suspend_mode(mode);
189}
190
170void tegra_idle_lp2_last(void) 191void tegra_idle_lp2_last(void)
171{ 192{
172 tegra_pmc_pm_set(TEGRA_SUSPEND_LP2); 193 tegra_pm_set(TEGRA_SUSPEND_LP2);
173 194
174 cpu_cluster_pm_enter(); 195 cpu_cluster_pm_enter();
175 suspend_cpu_complex(); 196 suspend_cpu_complex();
@@ -268,8 +289,6 @@ static bool tegra_sleep_core_init(void)
268 289
269static void tegra_suspend_enter_lp1(void) 290static void tegra_suspend_enter_lp1(void)
270{ 291{
271 tegra_pmc_suspend();
272
273 /* copy the reset vector & SDRAM shutdown code into IRAM */ 292 /* copy the reset vector & SDRAM shutdown code into IRAM */
274 memcpy(iram_save_addr, IO_ADDRESS(TEGRA_IRAM_LPx_RESUME_AREA), 293 memcpy(iram_save_addr, IO_ADDRESS(TEGRA_IRAM_LPx_RESUME_AREA),
275 iram_save_size); 294 iram_save_size);
@@ -281,8 +300,6 @@ static void tegra_suspend_enter_lp1(void)
281 300
282static void tegra_suspend_exit_lp1(void) 301static void tegra_suspend_exit_lp1(void)
283{ 302{
284 tegra_pmc_resume();
285
286 /* restore IRAM */ 303 /* restore IRAM */
287 memcpy(IO_ADDRESS(TEGRA_IRAM_LPx_RESUME_AREA), iram_save_addr, 304 memcpy(IO_ADDRESS(TEGRA_IRAM_LPx_RESUME_AREA), iram_save_addr,
288 iram_save_size); 305 iram_save_size);
@@ -307,7 +324,7 @@ static int tegra_suspend_enter(suspend_state_t state)
307 324
308 pr_info("Entering suspend state %s\n", lp_state[mode]); 325 pr_info("Entering suspend state %s\n", lp_state[mode]);
309 326
310 tegra_pmc_pm_set(mode); 327 tegra_pm_set(mode);
311 328
312 local_fiq_disable(); 329 local_fiq_disable();
313 330
@@ -355,7 +372,6 @@ void __init tegra_init_suspend(void)
355 return; 372 return;
356 373
357 tegra_tear_down_cpu_init(); 374 tegra_tear_down_cpu_init();
358 tegra_pmc_suspend_init();
359 375
360 if (mode >= TEGRA_SUSPEND_LP1) { 376 if (mode >= TEGRA_SUSPEND_LP1) {
361 if (!tegra_lp1_iram_hook() || !tegra_sleep_core_init()) { 377 if (!tegra_lp1_iram_hook() || !tegra_sleep_core_init()) {
diff --git a/arch/arm/mach-tegra/pm.h b/arch/arm/mach-tegra/pm.h
index f4a89698e5b0..83bc87583446 100644
--- a/arch/arm/mach-tegra/pm.h
+++ b/arch/arm/mach-tegra/pm.h
@@ -21,12 +21,11 @@
21#ifndef _MACH_TEGRA_PM_H_ 21#ifndef _MACH_TEGRA_PM_H_
22#define _MACH_TEGRA_PM_H_ 22#define _MACH_TEGRA_PM_H_
23 23
24#include "pmc.h"
25
26struct tegra_lp1_iram { 24struct tegra_lp1_iram {
27 void *start_addr; 25 void *start_addr;
28 void *end_addr; 26 void *end_addr;
29}; 27};
28
30extern struct tegra_lp1_iram tegra_lp1_iram; 29extern struct tegra_lp1_iram tegra_lp1_iram;
31extern void (*tegra_sleep_core_finish)(unsigned long v2p); 30extern void (*tegra_sleep_core_finish)(unsigned long v2p);
32 31
@@ -42,15 +41,8 @@ void tegra_idle_lp2_last(void);
42extern void (*tegra_tear_down_cpu)(void); 41extern void (*tegra_tear_down_cpu)(void);
43 42
44#ifdef CONFIG_PM_SLEEP 43#ifdef CONFIG_PM_SLEEP
45enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
46 enum tegra_suspend_mode mode);
47void tegra_init_suspend(void); 44void tegra_init_suspend(void);
48#else 45#else
49static inline enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
50 enum tegra_suspend_mode mode)
51{
52 return TEGRA_SUSPEND_NONE;
53}
54static inline void tegra_init_suspend(void) {} 46static inline void tegra_init_suspend(void) {}
55#endif 47#endif
56 48
diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c
deleted file mode 100644
index 69df18090c8b..000000000000
--- a/arch/arm/mach-tegra/pmc.c
+++ /dev/null
@@ -1,414 +0,0 @@
1/*
2 * Copyright (C) 2012,2013 NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#include <linux/clk.h>
19#include <linux/io.h>
20#include <linux/kernel.h>
21#include <linux/of.h>
22#include <linux/of_address.h>
23
24#include <soc/tegra/fuse.h>
25#include <soc/tegra/powergate.h>
26
27#include "flowctrl.h"
28#include "pm.h"
29#include "pmc.h"
30#include "sleep.h"
31
32#define TEGRA_POWER_SYSCLK_POLARITY (1 << 10) /* sys clk polarity */
33#define TEGRA_POWER_SYSCLK_OE (1 << 11) /* system clock enable */
34#define TEGRA_POWER_EFFECT_LP0 (1 << 14) /* LP0 when CPU pwr gated */
35#define TEGRA_POWER_CPU_PWRREQ_POLARITY (1 << 15) /* CPU pwr req polarity */
36#define TEGRA_POWER_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */
37
38#define PMC_CTRL 0x0
39#define PMC_CTRL_INTR_LOW (1 << 17)
40#define PMC_PWRGATE_TOGGLE 0x30
41#define PMC_PWRGATE_TOGGLE_START (1 << 8)
42#define PMC_REMOVE_CLAMPING 0x34
43#define PMC_PWRGATE_STATUS 0x38
44
45#define PMC_SCRATCH0 0x50
46#define PMC_SCRATCH0_MODE_RECOVERY (1 << 31)
47#define PMC_SCRATCH0_MODE_BOOTLOADER (1 << 30)
48#define PMC_SCRATCH0_MODE_RCM (1 << 1)
49#define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \
50 PMC_SCRATCH0_MODE_BOOTLOADER | \
51 PMC_SCRATCH0_MODE_RCM)
52
53#define PMC_CPUPWRGOOD_TIMER 0xc8
54#define PMC_CPUPWROFF_TIMER 0xcc
55
56static u8 tegra_cpu_domains[] = {
57 0xFF, /* not available for CPU0 */
58 TEGRA_POWERGATE_CPU1,
59 TEGRA_POWERGATE_CPU2,
60 TEGRA_POWERGATE_CPU3,
61};
62static DEFINE_SPINLOCK(tegra_powergate_lock);
63
64static void __iomem *tegra_pmc_base;
65static bool tegra_pmc_invert_interrupt;
66static struct clk *tegra_pclk;
67
68struct pmc_pm_data {
69 u32 cpu_good_time; /* CPU power good time in uS */
70 u32 cpu_off_time; /* CPU power off time in uS */
71 u32 core_osc_time; /* Core power good osc time in uS */
72 u32 core_pmu_time; /* Core power good pmu time in uS */
73 u32 core_off_time; /* Core power off time in uS */
74 bool corereq_high; /* Core power request active-high */
75 bool sysclkreq_high; /* System clock request active-high */
76 bool combined_req; /* Combined pwr req for CPU & Core */
77 bool cpu_pwr_good_en; /* CPU power good signal is enabled */
78 u32 lp0_vec_phy_addr; /* The phy addr of LP0 warm boot code */
79 u32 lp0_vec_size; /* The size of LP0 warm boot code */
80 enum tegra_suspend_mode suspend_mode;
81};
82static struct pmc_pm_data pmc_pm_data;
83
84static inline u32 tegra_pmc_readl(u32 reg)
85{
86 return readl(tegra_pmc_base + reg);
87}
88
89static inline void tegra_pmc_writel(u32 val, u32 reg)
90{
91 writel(val, tegra_pmc_base + reg);
92}
93
94static int tegra_pmc_get_cpu_powerdomain_id(int cpuid)
95{
96 if (cpuid <= 0 || cpuid >= num_possible_cpus())
97 return -EINVAL;
98 return tegra_cpu_domains[cpuid];
99}
100
101static bool tegra_pmc_powergate_is_powered(int id)
102{
103 return (tegra_pmc_readl(PMC_PWRGATE_STATUS) >> id) & 1;
104}
105
106static int tegra_pmc_powergate_set(int id, bool new_state)
107{
108 bool old_state;
109 unsigned long flags;
110
111 spin_lock_irqsave(&tegra_powergate_lock, flags);
112
113 old_state = tegra_pmc_powergate_is_powered(id);
114 WARN_ON(old_state == new_state);
115
116 tegra_pmc_writel(PMC_PWRGATE_TOGGLE_START | id, PMC_PWRGATE_TOGGLE);
117
118 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
119
120 return 0;
121}
122
123static int tegra_pmc_powergate_remove_clamping(int id)
124{
125 u32 mask;
126
127 /*
128 * Tegra has a bug where PCIE and VDE clamping masks are
129 * swapped relatively to the partition ids.
130 */
131 if (id == TEGRA_POWERGATE_VDEC)
132 mask = (1 << TEGRA_POWERGATE_PCIE);
133 else if (id == TEGRA_POWERGATE_PCIE)
134 mask = (1 << TEGRA_POWERGATE_VDEC);
135 else
136 mask = (1 << id);
137
138 tegra_pmc_writel(mask, PMC_REMOVE_CLAMPING);
139
140 return 0;
141}
142
143bool tegra_pmc_cpu_is_powered(int cpuid)
144{
145 int id;
146
147 id = tegra_pmc_get_cpu_powerdomain_id(cpuid);
148 if (id < 0)
149 return false;
150 return tegra_pmc_powergate_is_powered(id);
151}
152
153int tegra_pmc_cpu_power_on(int cpuid)
154{
155 int id;
156
157 id = tegra_pmc_get_cpu_powerdomain_id(cpuid);
158 if (id < 0)
159 return id;
160 return tegra_pmc_powergate_set(id, true);
161}
162
163int tegra_pmc_cpu_remove_clamping(int cpuid)
164{
165 int id;
166
167 id = tegra_pmc_get_cpu_powerdomain_id(cpuid);
168 if (id < 0)
169 return id;
170 return tegra_pmc_powergate_remove_clamping(id);
171}
172
173void tegra_pmc_restart(enum reboot_mode mode, const char *cmd)
174{
175 u32 val;
176
177 val = tegra_pmc_readl(PMC_SCRATCH0);
178 val &= ~PMC_SCRATCH0_MODE_MASK;
179
180 if (cmd) {
181 if (strcmp(cmd, "recovery") == 0)
182 val |= PMC_SCRATCH0_MODE_RECOVERY;
183
184 if (strcmp(cmd, "bootloader") == 0)
185 val |= PMC_SCRATCH0_MODE_BOOTLOADER;
186
187 if (strcmp(cmd, "forced-recovery") == 0)
188 val |= PMC_SCRATCH0_MODE_RCM;
189 }
190
191 tegra_pmc_writel(val, PMC_SCRATCH0);
192
193 val = tegra_pmc_readl(0);
194 val |= 0x10;
195 tegra_pmc_writel(val, 0);
196}
197
198#ifdef CONFIG_PM_SLEEP
199static void set_power_timers(u32 us_on, u32 us_off, unsigned long rate)
200{
201 unsigned long long ticks;
202 unsigned long long pclk;
203 static unsigned long tegra_last_pclk;
204
205 if (WARN_ON_ONCE(rate <= 0))
206 pclk = 100000000;
207 else
208 pclk = rate;
209
210 if ((rate != tegra_last_pclk)) {
211 ticks = (us_on * pclk) + 999999ull;
212 do_div(ticks, 1000000);
213 tegra_pmc_writel((unsigned long)ticks, PMC_CPUPWRGOOD_TIMER);
214
215 ticks = (us_off * pclk) + 999999ull;
216 do_div(ticks, 1000000);
217 tegra_pmc_writel((unsigned long)ticks, PMC_CPUPWROFF_TIMER);
218 wmb();
219 }
220 tegra_last_pclk = pclk;
221}
222
223enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
224{
225 return pmc_pm_data.suspend_mode;
226}
227
228void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
229{
230 if (mode < TEGRA_SUSPEND_NONE || mode >= TEGRA_MAX_SUSPEND_MODE)
231 return;
232
233 pmc_pm_data.suspend_mode = mode;
234}
235
236void tegra_pmc_suspend(void)
237{
238 tegra_pmc_writel(virt_to_phys(tegra_resume), PMC_SCRATCH41);
239}
240
241void tegra_pmc_resume(void)
242{
243 tegra_pmc_writel(0x0, PMC_SCRATCH41);
244}
245
246void tegra_pmc_pm_set(enum tegra_suspend_mode mode)
247{
248 u32 reg, csr_reg;
249 unsigned long rate = 0;
250
251 reg = tegra_pmc_readl(PMC_CTRL);
252 reg |= TEGRA_POWER_CPU_PWRREQ_OE;
253 reg &= ~TEGRA_POWER_EFFECT_LP0;
254
255 switch (tegra_get_chip_id()) {
256 case TEGRA20:
257 case TEGRA30:
258 break;
259 default:
260 /* Turn off CRAIL */
261 csr_reg = flowctrl_read_cpu_csr(0);
262 csr_reg &= ~FLOW_CTRL_CSR_ENABLE_EXT_MASK;
263 csr_reg |= FLOW_CTRL_CSR_ENABLE_EXT_CRAIL;
264 flowctrl_write_cpu_csr(0, csr_reg);
265 break;
266 }
267
268 switch (mode) {
269 case TEGRA_SUSPEND_LP1:
270 rate = 32768;
271 break;
272 case TEGRA_SUSPEND_LP2:
273 rate = clk_get_rate(tegra_pclk);
274 break;
275 default:
276 break;
277 }
278
279 set_power_timers(pmc_pm_data.cpu_good_time, pmc_pm_data.cpu_off_time,
280 rate);
281
282 tegra_pmc_writel(reg, PMC_CTRL);
283}
284
285void tegra_pmc_suspend_init(void)
286{
287 u32 reg;
288
289 /* Always enable CPU power request */
290 reg = tegra_pmc_readl(PMC_CTRL);
291 reg |= TEGRA_POWER_CPU_PWRREQ_OE;
292 tegra_pmc_writel(reg, PMC_CTRL);
293
294 reg = tegra_pmc_readl(PMC_CTRL);
295
296 if (!pmc_pm_data.sysclkreq_high)
297 reg |= TEGRA_POWER_SYSCLK_POLARITY;
298 else
299 reg &= ~TEGRA_POWER_SYSCLK_POLARITY;
300
301 /* configure the output polarity while the request is tristated */
302 tegra_pmc_writel(reg, PMC_CTRL);
303
304 /* now enable the request */
305 reg |= TEGRA_POWER_SYSCLK_OE;
306 tegra_pmc_writel(reg, PMC_CTRL);
307}
308#endif
309
310static const struct of_device_id matches[] __initconst = {
311 { .compatible = "nvidia,tegra124-pmc" },
312 { .compatible = "nvidia,tegra114-pmc" },
313 { .compatible = "nvidia,tegra30-pmc" },
314 { .compatible = "nvidia,tegra20-pmc" },
315 { }
316};
317
318void __init tegra_pmc_init_irq(void)
319{
320 struct device_node *np;
321 u32 val;
322
323 np = of_find_matching_node(NULL, matches);
324 BUG_ON(!np);
325
326 tegra_pmc_base = of_iomap(np, 0);
327
328 tegra_pmc_invert_interrupt = of_property_read_bool(np,
329 "nvidia,invert-interrupt");
330
331 val = tegra_pmc_readl(PMC_CTRL);
332 if (tegra_pmc_invert_interrupt)
333 val |= PMC_CTRL_INTR_LOW;
334 else
335 val &= ~PMC_CTRL_INTR_LOW;
336 tegra_pmc_writel(val, PMC_CTRL);
337}
338
339void __init tegra_pmc_init(void)
340{
341 struct device_node *np;
342 u32 prop;
343 enum tegra_suspend_mode suspend_mode;
344 u32 core_good_time[2] = {0, 0};
345 u32 lp0_vec[2] = {0, 0};
346
347 np = of_find_matching_node(NULL, matches);
348 BUG_ON(!np);
349
350 tegra_pclk = of_clk_get_by_name(np, "pclk");
351 WARN_ON(IS_ERR(tegra_pclk));
352
353 /* Grabbing the power management configurations */
354 if (of_property_read_u32(np, "nvidia,suspend-mode", &prop)) {
355 suspend_mode = TEGRA_SUSPEND_NONE;
356 } else {
357 switch (prop) {
358 case 0:
359 suspend_mode = TEGRA_SUSPEND_LP0;
360 break;
361 case 1:
362 suspend_mode = TEGRA_SUSPEND_LP1;
363 break;
364 case 2:
365 suspend_mode = TEGRA_SUSPEND_LP2;
366 break;
367 default:
368 suspend_mode = TEGRA_SUSPEND_NONE;
369 break;
370 }
371 }
372 suspend_mode = tegra_pm_validate_suspend_mode(suspend_mode);
373
374 if (of_property_read_u32(np, "nvidia,cpu-pwr-good-time", &prop))
375 suspend_mode = TEGRA_SUSPEND_NONE;
376 pmc_pm_data.cpu_good_time = prop;
377
378 if (of_property_read_u32(np, "nvidia,cpu-pwr-off-time", &prop))
379 suspend_mode = TEGRA_SUSPEND_NONE;
380 pmc_pm_data.cpu_off_time = prop;
381
382 if (of_property_read_u32_array(np, "nvidia,core-pwr-good-time",
383 core_good_time, ARRAY_SIZE(core_good_time)))
384 suspend_mode = TEGRA_SUSPEND_NONE;
385 pmc_pm_data.core_osc_time = core_good_time[0];
386 pmc_pm_data.core_pmu_time = core_good_time[1];
387
388 if (of_property_read_u32(np, "nvidia,core-pwr-off-time",
389 &prop))
390 suspend_mode = TEGRA_SUSPEND_NONE;
391 pmc_pm_data.core_off_time = prop;
392
393 pmc_pm_data.corereq_high = of_property_read_bool(np,
394 "nvidia,core-power-req-active-high");
395
396 pmc_pm_data.sysclkreq_high = of_property_read_bool(np,
397 "nvidia,sys-clock-req-active-high");
398
399 pmc_pm_data.combined_req = of_property_read_bool(np,
400 "nvidia,combined-power-req");
401
402 pmc_pm_data.cpu_pwr_good_en = of_property_read_bool(np,
403 "nvidia,cpu-pwr-good-en");
404
405 if (of_property_read_u32_array(np, "nvidia,lp0-vec", lp0_vec,
406 ARRAY_SIZE(lp0_vec)))
407 if (suspend_mode == TEGRA_SUSPEND_LP0)
408 suspend_mode = TEGRA_SUSPEND_LP1;
409
410 pmc_pm_data.lp0_vec_phy_addr = lp0_vec[0];
411 pmc_pm_data.lp0_vec_size = lp0_vec[1];
412
413 pmc_pm_data.suspend_mode = suspend_mode;
414}
diff --git a/arch/arm/mach-tegra/pmc.h b/arch/arm/mach-tegra/pmc.h
deleted file mode 100644
index 59e19c344298..000000000000
--- a/arch/arm/mach-tegra/pmc.h
+++ /dev/null
@@ -1,49 +0,0 @@
1/*
2 * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#ifndef __MACH_TEGRA_PMC_H
19#define __MACH_TEGRA_PMC_H
20
21#include <linux/reboot.h>
22
23enum tegra_suspend_mode {
24 TEGRA_SUSPEND_NONE = 0,
25 TEGRA_SUSPEND_LP2, /* CPU voltage off */
26 TEGRA_SUSPEND_LP1, /* CPU voltage off, DRAM self-refresh */
27 TEGRA_SUSPEND_LP0, /* CPU + core voltage off, DRAM self-refresh */
28 TEGRA_MAX_SUSPEND_MODE,
29};
30
31#ifdef CONFIG_PM_SLEEP
32enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void);
33void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode);
34void tegra_pmc_suspend(void);
35void tegra_pmc_resume(void);
36void tegra_pmc_pm_set(enum tegra_suspend_mode mode);
37void tegra_pmc_suspend_init(void);
38#endif
39
40bool tegra_pmc_cpu_is_powered(int cpuid);
41int tegra_pmc_cpu_power_on(int cpuid);
42int tegra_pmc_cpu_remove_clamping(int cpuid);
43
44void tegra_pmc_restart(enum reboot_mode mode, const char *cmd);
45
46void tegra_pmc_init_irq(void);
47void tegra_pmc_init(void);
48
49#endif
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
deleted file mode 100644
index 0a14b8638437..000000000000
--- a/arch/arm/mach-tegra/powergate.c
+++ /dev/null
@@ -1,516 +0,0 @@
1/*
2 * drivers/powergate/tegra-powergate.c
3 *
4 * Copyright (c) 2010 Google, Inc
5 *
6 * Author:
7 * Colin Cross <ccross@google.com>
8 *
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20#include <linux/clk.h>
21#include <linux/clk/tegra.h>
22#include <linux/debugfs.h>
23#include <linux/delay.h>
24#include <linux/err.h>
25#include <linux/export.h>
26#include <linux/init.h>
27#include <linux/io.h>
28#include <linux/kernel.h>
29#include <linux/reset.h>
30#include <linux/seq_file.h>
31#include <linux/spinlock.h>
32
33#include <soc/tegra/fuse.h>
34#include <soc/tegra/powergate.h>
35
36#include "iomap.h"
37
38#define DPD_SAMPLE 0x020
39#define DPD_SAMPLE_ENABLE (1 << 0)
40#define DPD_SAMPLE_DISABLE (0 << 0)
41
42#define PWRGATE_TOGGLE 0x30
43#define PWRGATE_TOGGLE_START (1 << 8)
44
45#define REMOVE_CLAMPING 0x34
46
47#define PWRGATE_STATUS 0x38
48
49#define IO_DPD_REQ 0x1b8
50#define IO_DPD_REQ_CODE_IDLE (0 << 30)
51#define IO_DPD_REQ_CODE_OFF (1 << 30)
52#define IO_DPD_REQ_CODE_ON (2 << 30)
53#define IO_DPD_REQ_CODE_MASK (3 << 30)
54
55#define IO_DPD_STATUS 0x1bc
56#define IO_DPD2_REQ 0x1c0
57#define IO_DPD2_STATUS 0x1c4
58#define SEL_DPD_TIM 0x1c8
59
60#define GPU_RG_CNTRL 0x2d4
61
62static int tegra_num_powerdomains;
63static int tegra_num_cpu_domains;
64static const u8 *tegra_cpu_domains;
65
66static const u8 tegra30_cpu_domains[] = {
67 TEGRA_POWERGATE_CPU,
68 TEGRA_POWERGATE_CPU1,
69 TEGRA_POWERGATE_CPU2,
70 TEGRA_POWERGATE_CPU3,
71};
72
73static const u8 tegra114_cpu_domains[] = {
74 TEGRA_POWERGATE_CPU0,
75 TEGRA_POWERGATE_CPU1,
76 TEGRA_POWERGATE_CPU2,
77 TEGRA_POWERGATE_CPU3,
78};
79
80static const u8 tegra124_cpu_domains[] = {
81 TEGRA_POWERGATE_CPU0,
82 TEGRA_POWERGATE_CPU1,
83 TEGRA_POWERGATE_CPU2,
84 TEGRA_POWERGATE_CPU3,
85};
86
87static DEFINE_SPINLOCK(tegra_powergate_lock);
88
89static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
90
91static u32 pmc_read(unsigned long reg)
92{
93 return readl(pmc + reg);
94}
95
96static void pmc_write(u32 val, unsigned long reg)
97{
98 writel(val, pmc + reg);
99}
100
101static int tegra_powergate_set(int id, bool new_state)
102{
103 bool status;
104 unsigned long flags;
105
106 spin_lock_irqsave(&tegra_powergate_lock, flags);
107
108 status = pmc_read(PWRGATE_STATUS) & (1 << id);
109
110 if (status == new_state) {
111 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
112 return 0;
113 }
114
115 pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
116
117 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
118
119 return 0;
120}
121
122int tegra_powergate_power_on(int id)
123{
124 if (id < 0 || id >= tegra_num_powerdomains)
125 return -EINVAL;
126
127 return tegra_powergate_set(id, true);
128}
129
130int tegra_powergate_power_off(int id)
131{
132 if (id < 0 || id >= tegra_num_powerdomains)
133 return -EINVAL;
134
135 return tegra_powergate_set(id, false);
136}
137EXPORT_SYMBOL(tegra_powergate_power_off);
138
139int tegra_powergate_is_powered(int id)
140{
141 u32 status;
142
143 if (id < 0 || id >= tegra_num_powerdomains)
144 return -EINVAL;
145
146 status = pmc_read(PWRGATE_STATUS) & (1 << id);
147 return !!status;
148}
149
150int tegra_powergate_remove_clamping(int id)
151{
152 u32 mask;
153
154 if (id < 0 || id >= tegra_num_powerdomains)
155 return -EINVAL;
156
157 /*
158 * The Tegra124 GPU has a separate register (with different semantics)
159 * to remove clamps.
160 */
161 if (tegra_get_chip_id() == TEGRA124) {
162 if (id == TEGRA_POWERGATE_3D) {
163 pmc_write(0, GPU_RG_CNTRL);
164 return 0;
165 }
166 }
167
168 /*
169 * Tegra 2 has a bug where PCIE and VDE clamping masks are
170 * swapped relatively to the partition ids
171 */
172 if (id == TEGRA_POWERGATE_VDEC)
173 mask = (1 << TEGRA_POWERGATE_PCIE);
174 else if (id == TEGRA_POWERGATE_PCIE)
175 mask = (1 << TEGRA_POWERGATE_VDEC);
176 else
177 mask = (1 << id);
178
179 pmc_write(mask, REMOVE_CLAMPING);
180
181 return 0;
182}
183EXPORT_SYMBOL(tegra_powergate_remove_clamping);
184
185/* Must be called with clk disabled, and returns with clk enabled */
186int tegra_powergate_sequence_power_up(int id, struct clk *clk,
187 struct reset_control *rst)
188{
189 int ret;
190
191 reset_control_assert(rst);
192
193 ret = tegra_powergate_power_on(id);
194 if (ret)
195 goto err_power;
196
197 ret = clk_prepare_enable(clk);
198 if (ret)
199 goto err_clk;
200
201 udelay(10);
202
203 ret = tegra_powergate_remove_clamping(id);
204 if (ret)
205 goto err_clamp;
206
207 udelay(10);
208 reset_control_deassert(rst);
209
210 return 0;
211
212err_clamp:
213 clk_disable_unprepare(clk);
214err_clk:
215 tegra_powergate_power_off(id);
216err_power:
217 return ret;
218}
219EXPORT_SYMBOL(tegra_powergate_sequence_power_up);
220
221int tegra_cpu_powergate_id(int cpuid)
222{
223 if (cpuid > 0 && cpuid < tegra_num_cpu_domains)
224 return tegra_cpu_domains[cpuid];
225
226 return -EINVAL;
227}
228
229int __init tegra_powergate_init(void)
230{
231 switch (tegra_get_chip_id()) {
232 case TEGRA20:
233 tegra_num_powerdomains = 7;
234 break;
235 case TEGRA30:
236 tegra_num_powerdomains = 14;
237 tegra_num_cpu_domains = 4;
238 tegra_cpu_domains = tegra30_cpu_domains;
239 break;
240 case TEGRA114:
241 tegra_num_powerdomains = 23;
242 tegra_num_cpu_domains = 4;
243 tegra_cpu_domains = tegra114_cpu_domains;
244 break;
245 case TEGRA124:
246 tegra_num_powerdomains = 25;
247 tegra_num_cpu_domains = 4;
248 tegra_cpu_domains = tegra124_cpu_domains;
249 break;
250 default:
251 /* Unknown Tegra variant. Disable powergating */
252 tegra_num_powerdomains = 0;
253 break;
254 }
255
256 return 0;
257}
258
259#ifdef CONFIG_DEBUG_FS
260
261static const char * const *powergate_name;
262
263static const char * const powergate_name_t20[] = {
264 [TEGRA_POWERGATE_CPU] = "cpu",
265 [TEGRA_POWERGATE_3D] = "3d",
266 [TEGRA_POWERGATE_VENC] = "venc",
267 [TEGRA_POWERGATE_VDEC] = "vdec",
268 [TEGRA_POWERGATE_PCIE] = "pcie",
269 [TEGRA_POWERGATE_L2] = "l2",
270 [TEGRA_POWERGATE_MPE] = "mpe",
271};
272
273static const char * const powergate_name_t30[] = {
274 [TEGRA_POWERGATE_CPU] = "cpu0",
275 [TEGRA_POWERGATE_3D] = "3d0",
276 [TEGRA_POWERGATE_VENC] = "venc",
277 [TEGRA_POWERGATE_VDEC] = "vdec",
278 [TEGRA_POWERGATE_PCIE] = "pcie",
279 [TEGRA_POWERGATE_L2] = "l2",
280 [TEGRA_POWERGATE_MPE] = "mpe",
281 [TEGRA_POWERGATE_HEG] = "heg",
282 [TEGRA_POWERGATE_SATA] = "sata",
283 [TEGRA_POWERGATE_CPU1] = "cpu1",
284 [TEGRA_POWERGATE_CPU2] = "cpu2",
285 [TEGRA_POWERGATE_CPU3] = "cpu3",
286 [TEGRA_POWERGATE_CELP] = "celp",
287 [TEGRA_POWERGATE_3D1] = "3d1",
288};
289
290static const char * const powergate_name_t114[] = {
291 [TEGRA_POWERGATE_CPU] = "crail",
292 [TEGRA_POWERGATE_3D] = "3d",
293 [TEGRA_POWERGATE_VENC] = "venc",
294 [TEGRA_POWERGATE_VDEC] = "vdec",
295 [TEGRA_POWERGATE_MPE] = "mpe",
296 [TEGRA_POWERGATE_HEG] = "heg",
297 [TEGRA_POWERGATE_CPU1] = "cpu1",
298 [TEGRA_POWERGATE_CPU2] = "cpu2",
299 [TEGRA_POWERGATE_CPU3] = "cpu3",
300 [TEGRA_POWERGATE_CELP] = "celp",
301 [TEGRA_POWERGATE_CPU0] = "cpu0",
302 [TEGRA_POWERGATE_C0NC] = "c0nc",
303 [TEGRA_POWERGATE_C1NC] = "c1nc",
304 [TEGRA_POWERGATE_DIS] = "dis",
305 [TEGRA_POWERGATE_DISB] = "disb",
306 [TEGRA_POWERGATE_XUSBA] = "xusba",
307 [TEGRA_POWERGATE_XUSBB] = "xusbb",
308 [TEGRA_POWERGATE_XUSBC] = "xusbc",
309};
310
311static const char * const powergate_name_t124[] = {
312 [TEGRA_POWERGATE_CPU] = "crail",
313 [TEGRA_POWERGATE_3D] = "3d",
314 [TEGRA_POWERGATE_VENC] = "venc",
315 [TEGRA_POWERGATE_PCIE] = "pcie",
316 [TEGRA_POWERGATE_VDEC] = "vdec",
317 [TEGRA_POWERGATE_L2] = "l2",
318 [TEGRA_POWERGATE_MPE] = "mpe",
319 [TEGRA_POWERGATE_HEG] = "heg",
320 [TEGRA_POWERGATE_SATA] = "sata",
321 [TEGRA_POWERGATE_CPU1] = "cpu1",
322 [TEGRA_POWERGATE_CPU2] = "cpu2",
323 [TEGRA_POWERGATE_CPU3] = "cpu3",
324 [TEGRA_POWERGATE_CELP] = "celp",
325 [TEGRA_POWERGATE_CPU0] = "cpu0",
326 [TEGRA_POWERGATE_C0NC] = "c0nc",
327 [TEGRA_POWERGATE_C1NC] = "c1nc",
328 [TEGRA_POWERGATE_SOR] = "sor",
329 [TEGRA_POWERGATE_DIS] = "dis",
330 [TEGRA_POWERGATE_DISB] = "disb",
331 [TEGRA_POWERGATE_XUSBA] = "xusba",
332 [TEGRA_POWERGATE_XUSBB] = "xusbb",
333 [TEGRA_POWERGATE_XUSBC] = "xusbc",
334 [TEGRA_POWERGATE_VIC] = "vic",
335 [TEGRA_POWERGATE_IRAM] = "iram",
336};
337
338static int powergate_show(struct seq_file *s, void *data)
339{
340 int i;
341
342 seq_printf(s, " powergate powered\n");
343 seq_printf(s, "------------------\n");
344
345 for (i = 0; i < tegra_num_powerdomains; i++) {
346 if (!powergate_name[i])
347 continue;
348
349 seq_printf(s, " %9s %7s\n", powergate_name[i],
350 tegra_powergate_is_powered(i) ? "yes" : "no");
351 }
352
353 return 0;
354}
355
356static int powergate_open(struct inode *inode, struct file *file)
357{
358 return single_open(file, powergate_show, inode->i_private);
359}
360
361static const struct file_operations powergate_fops = {
362 .open = powergate_open,
363 .read = seq_read,
364 .llseek = seq_lseek,
365 .release = single_release,
366};
367
368int __init tegra_powergate_debugfs_init(void)
369{
370 struct dentry *d;
371
372 switch (tegra_get_chip_id()) {
373 case TEGRA20:
374 powergate_name = powergate_name_t20;
375 break;
376 case TEGRA30:
377 powergate_name = powergate_name_t30;
378 break;
379 case TEGRA114:
380 powergate_name = powergate_name_t114;
381 break;
382 case TEGRA124:
383 powergate_name = powergate_name_t124;
384 break;
385 }
386
387 if (powergate_name) {
388 d = debugfs_create_file("powergate", S_IRUGO, NULL, NULL,
389 &powergate_fops);
390 if (!d)
391 return -ENOMEM;
392 }
393
394 return 0;
395}
396
397#endif
398
399static int tegra_io_rail_prepare(int id, unsigned long *request,
400 unsigned long *status, unsigned int *bit)
401{
402 unsigned long rate, value;
403 struct clk *clk;
404
405 *bit = id % 32;
406
407 /*
408 * There are two sets of 30 bits to select IO rails, but bits 30 and
409 * 31 are control bits rather than IO rail selection bits.
410 */
411 if (id > 63 || *bit == 30 || *bit == 31)
412 return -EINVAL;
413
414 if (id < 32) {
415 *status = IO_DPD_STATUS;
416 *request = IO_DPD_REQ;
417 } else {
418 *status = IO_DPD2_STATUS;
419 *request = IO_DPD2_REQ;
420 }
421
422 clk = clk_get_sys(NULL, "pclk");
423 if (IS_ERR(clk))
424 return PTR_ERR(clk);
425
426 rate = clk_get_rate(clk);
427 clk_put(clk);
428
429 pmc_write(DPD_SAMPLE_ENABLE, DPD_SAMPLE);
430
431 /* must be at least 200 ns, in APB (PCLK) clock cycles */
432 value = DIV_ROUND_UP(1000000000, rate);
433 value = DIV_ROUND_UP(200, value);
434 pmc_write(value, SEL_DPD_TIM);
435
436 return 0;
437}
438
439static int tegra_io_rail_poll(unsigned long offset, unsigned long mask,
440 unsigned long val, unsigned long timeout)
441{
442 unsigned long value;
443
444 timeout = jiffies + msecs_to_jiffies(timeout);
445
446 while (time_after(timeout, jiffies)) {
447 value = pmc_read(offset);
448 if ((value & mask) == val)
449 return 0;
450
451 usleep_range(250, 1000);
452 }
453
454 return -ETIMEDOUT;
455}
456
457static void tegra_io_rail_unprepare(void)
458{
459 pmc_write(DPD_SAMPLE_DISABLE, DPD_SAMPLE);
460}
461
462int tegra_io_rail_power_on(int id)
463{
464 unsigned long request, status, value;
465 unsigned int bit, mask;
466 int err;
467
468 err = tegra_io_rail_prepare(id, &request, &status, &bit);
469 if (err < 0)
470 return err;
471
472 mask = 1 << bit;
473
474 value = pmc_read(request);
475 value |= mask;
476 value &= ~IO_DPD_REQ_CODE_MASK;
477 value |= IO_DPD_REQ_CODE_OFF;
478 pmc_write(value, request);
479
480 err = tegra_io_rail_poll(status, mask, 0, 250);
481 if (err < 0)
482 return err;
483
484 tegra_io_rail_unprepare();
485
486 return 0;
487}
488EXPORT_SYMBOL(tegra_io_rail_power_on);
489
490int tegra_io_rail_power_off(int id)
491{
492 unsigned long request, status, value;
493 unsigned int bit, mask;
494 int err;
495
496 err = tegra_io_rail_prepare(id, &request, &status, &bit);
497 if (err < 0)
498 return err;
499
500 mask = 1 << bit;
501
502 value = pmc_read(request);
503 value |= mask;
504 value &= ~IO_DPD_REQ_CODE_MASK;
505 value |= IO_DPD_REQ_CODE_ON;
506 pmc_write(value, request);
507
508 err = tegra_io_rail_poll(status, mask, mask, 250);
509 if (err < 0)
510 return err;
511
512 tegra_io_rail_unprepare();
513
514 return 0;
515}
516EXPORT_SYMBOL(tegra_io_rail_power_off);
diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index c9176db0b9c0..5ef5173dec83 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -36,6 +36,7 @@
36#include <linux/usb/tegra_usb_phy.h> 36#include <linux/usb/tegra_usb_phy.h>
37 37
38#include <soc/tegra/fuse.h> 38#include <soc/tegra/fuse.h>
39#include <soc/tegra/pmc.h>
39 40
40#include <asm/hardware/cache-l2x0.h> 41#include <asm/hardware/cache-l2x0.h>
41#include <asm/mach/arch.h> 42#include <asm/mach/arch.h>
@@ -49,7 +50,6 @@
49#include "cpuidle.h" 50#include "cpuidle.h"
50#include "iomap.h" 51#include "iomap.h"
51#include "irq.h" 52#include "irq.h"
52#include "pmc.h"
53#include "pm.h" 53#include "pm.h"
54#include "reset.h" 54#include "reset.h"
55#include "sleep.h" 55#include "sleep.h"
@@ -74,12 +74,10 @@ static void __init tegra_init_early(void)
74{ 74{
75 of_register_trusted_foundations(); 75 of_register_trusted_foundations();
76 tegra_cpu_reset_handler_init(); 76 tegra_cpu_reset_handler_init();
77 tegra_powergate_init();
78} 77}
79 78
80static void __init tegra_dt_init_irq(void) 79static void __init tegra_dt_init_irq(void)
81{ 80{
82 tegra_pmc_init_irq();
83 tegra_init_irq(); 81 tegra_init_irq();
84 irqchip_init(); 82 irqchip_init();
85 tegra_legacy_irq_syscore_init(); 83 tegra_legacy_irq_syscore_init();
@@ -91,8 +89,6 @@ static void __init tegra_dt_init(void)
91 struct soc_device *soc_dev; 89 struct soc_device *soc_dev;
92 struct device *parent = NULL; 90 struct device *parent = NULL;
93 91
94 tegra_pmc_init();
95
96 tegra_clocks_apply_init_table(); 92 tegra_clocks_apply_init_table();
97 93
98 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 94 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
@@ -142,7 +138,6 @@ static void __init tegra_dt_init_late(void)
142 138
143 tegra_init_suspend(); 139 tegra_init_suspend();
144 tegra_cpuidle_init(); 140 tegra_cpuidle_init();
145 tegra_powergate_debugfs_init();
146 141
147 for (i = 0; i < ARRAY_SIZE(board_init_funcs); i++) { 142 for (i = 0; i < ARRAY_SIZE(board_init_funcs); i++) {
148 if (of_machine_is_compatible(board_init_funcs[i].machine)) { 143 if (of_machine_is_compatible(board_init_funcs[i].machine)) {
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index 5679ffdb3f8c..5bbacd01094f 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -23,7 +23,7 @@
23#include <linux/of_address.h> 23#include <linux/of_address.h>
24#include <linux/clk/tegra.h> 24#include <linux/clk/tegra.h>
25 25
26#include <soc/tegra/powergate.h> 26#include <soc/tegra/pmc.h>
27 27
28#include <dt-bindings/clock/tegra30-car.h> 28#include <dt-bindings/clock/tegra30-car.h>
29 29
diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c
index 69974851e564..2d07616a7d80 100644
--- a/drivers/gpu/drm/tegra/gr3d.c
+++ b/drivers/gpu/drm/tegra/gr3d.c
@@ -13,7 +13,7 @@
13#include <linux/platform_device.h> 13#include <linux/platform_device.h>
14#include <linux/reset.h> 14#include <linux/reset.h>
15 15
16#include <soc/tegra/powergate.h> 16#include <soc/tegra/pmc.h>
17 17
18#include "drm.h" 18#include "drm.h"
19#include "gem.h" 19#include "gem.h"
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
index eafd0b8a71d2..7f8ca5d4718f 100644
--- a/drivers/gpu/drm/tegra/sor.c
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -12,7 +12,7 @@
12#include <linux/platform_device.h> 12#include <linux/platform_device.h>
13#include <linux/reset.h> 13#include <linux/reset.h>
14 14
15#include <soc/tegra/powergate.h> 15#include <soc/tegra/pmc.h>
16 16
17#include <drm/drm_dp_helper.h> 17#include <drm/drm_dp_helper.h>
18 18
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index a2f0f88be382..acbfee0d7947 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -45,7 +45,7 @@
45#include <linux/regulator/consumer.h> 45#include <linux/regulator/consumer.h>
46 46
47#include <soc/tegra/cpuidle.h> 47#include <soc/tegra/cpuidle.h>
48#include <soc/tegra/powergate.h> 48#include <soc/tegra/pmc.h>
49 49
50#include <asm/mach/irq.h> 50#include <asm/mach/irq.h>
51#include <asm/mach/map.h> 51#include <asm/mach/map.h>
diff --git a/drivers/soc/tegra/Makefile b/drivers/soc/tegra/Makefile
index db34987ed9dc..cdaad9d53a05 100644
--- a/drivers/soc/tegra/Makefile
+++ b/drivers/soc/tegra/Makefile
@@ -1,3 +1,4 @@
1obj-$(CONFIG_ARCH_TEGRA) += fuse/ 1obj-$(CONFIG_ARCH_TEGRA) += fuse/
2 2
3obj-$(CONFIG_ARCH_TEGRA) += common.o 3obj-$(CONFIG_ARCH_TEGRA) += common.o
4obj-$(CONFIG_ARCH_TEGRA) += pmc.o
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
new file mode 100644
index 000000000000..a2c0ceb95f8f
--- /dev/null
+++ b/drivers/soc/tegra/pmc.c
@@ -0,0 +1,957 @@
1/*
2 * drivers/soc/tegra/pmc.c
3 *
4 * Copyright (c) 2010 Google, Inc
5 *
6 * Author:
7 * Colin Cross <ccross@google.com>
8 *
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20#include <linux/kernel.h>
21#include <linux/clk.h>
22#include <linux/clk/tegra.h>
23#include <linux/debugfs.h>
24#include <linux/delay.h>
25#include <linux/err.h>
26#include <linux/export.h>
27#include <linux/init.h>
28#include <linux/io.h>
29#include <linux/of.h>
30#include <linux/of_address.h>
31#include <linux/platform_device.h>
32#include <linux/reboot.h>
33#include <linux/reset.h>
34#include <linux/seq_file.h>
35#include <linux/spinlock.h>
36
37#include <soc/tegra/common.h>
38#include <soc/tegra/fuse.h>
39#include <soc/tegra/pmc.h>
40
41#define PMC_CNTRL 0x0
42#define PMC_CNTRL_SYSCLK_POLARITY (1 << 10) /* sys clk polarity */
43#define PMC_CNTRL_SYSCLK_OE (1 << 11) /* system clock enable */
44#define PMC_CNTRL_SIDE_EFFECT_LP0 (1 << 14) /* LP0 when CPU pwr gated */
45#define PMC_CNTRL_CPU_PWRREQ_POLARITY (1 << 15) /* CPU pwr req polarity */
46#define PMC_CNTRL_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */
47#define PMC_CNTRL_INTR_POLARITY (1 << 17) /* inverts INTR polarity */
48
49#define DPD_SAMPLE 0x020
50#define DPD_SAMPLE_ENABLE (1 << 0)
51#define DPD_SAMPLE_DISABLE (0 << 0)
52
53#define PWRGATE_TOGGLE 0x30
54#define PWRGATE_TOGGLE_START (1 << 8)
55
56#define REMOVE_CLAMPING 0x34
57
58#define PWRGATE_STATUS 0x38
59
60#define PMC_SCRATCH0 0x50
61#define PMC_SCRATCH0_MODE_RECOVERY (1 << 31)
62#define PMC_SCRATCH0_MODE_BOOTLOADER (1 << 30)
63#define PMC_SCRATCH0_MODE_RCM (1 << 1)
64#define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \
65 PMC_SCRATCH0_MODE_BOOTLOADER | \
66 PMC_SCRATCH0_MODE_RCM)
67
68#define PMC_CPUPWRGOOD_TIMER 0xc8
69#define PMC_CPUPWROFF_TIMER 0xcc
70
71#define PMC_SCRATCH41 0x140
72
73#define IO_DPD_REQ 0x1b8
74#define IO_DPD_REQ_CODE_IDLE (0 << 30)
75#define IO_DPD_REQ_CODE_OFF (1 << 30)
76#define IO_DPD_REQ_CODE_ON (2 << 30)
77#define IO_DPD_REQ_CODE_MASK (3 << 30)
78
79#define IO_DPD_STATUS 0x1bc
80#define IO_DPD2_REQ 0x1c0
81#define IO_DPD2_STATUS 0x1c4
82#define SEL_DPD_TIM 0x1c8
83
84#define GPU_RG_CNTRL 0x2d4
85
86struct tegra_pmc_soc {
87 unsigned int num_powergates;
88 const char *const *powergates;
89 unsigned int num_cpu_powergates;
90 const u8 *cpu_powergates;
91};
92
93/**
94 * struct tegra_pmc - NVIDIA Tegra PMC
95 * @base: pointer to I/O remapped register region
96 * @clk: pointer to pclk clock
97 * @rate: currently configured rate of pclk
98 * @suspend_mode: lowest suspend mode available
99 * @cpu_good_time: CPU power good time (in microseconds)
100 * @cpu_off_time: CPU power off time (in microsecends)
101 * @core_osc_time: core power good OSC time (in microseconds)
102 * @core_pmu_time: core power good PMU time (in microseconds)
103 * @core_off_time: core power off time (in microseconds)
104 * @corereq_high: core power request is active-high
105 * @sysclkreq_high: system clock request is active-high
106 * @combined_req: combined power request for CPU & core
107 * @cpu_pwr_good_en: CPU power good signal is enabled
108 * @lp0_vec_phys: physical base address of the LP0 warm boot code
109 * @lp0_vec_size: size of the LP0 warm boot code
110 * @powergates_lock: mutex for power gate register access
111 */
112struct tegra_pmc {
113 void __iomem *base;
114 struct clk *clk;
115
116 const struct tegra_pmc_soc *soc;
117
118 unsigned long rate;
119
120 enum tegra_suspend_mode suspend_mode;
121 u32 cpu_good_time;
122 u32 cpu_off_time;
123 u32 core_osc_time;
124 u32 core_pmu_time;
125 u32 core_off_time;
126 bool corereq_high;
127 bool sysclkreq_high;
128 bool combined_req;
129 bool cpu_pwr_good_en;
130 u32 lp0_vec_phys;
131 u32 lp0_vec_size;
132
133 struct mutex powergates_lock;
134};
135
136static struct tegra_pmc *pmc = &(struct tegra_pmc) {
137 .base = NULL,
138 .suspend_mode = TEGRA_SUSPEND_NONE,
139};
140
141static u32 tegra_pmc_readl(unsigned long offset)
142{
143 return readl(pmc->base + offset);
144}
145
146static void tegra_pmc_writel(u32 value, unsigned long offset)
147{
148 writel(value, pmc->base + offset);
149}
150
151/**
152 * tegra_powergate_set() - set the state of a partition
153 * @id: partition ID
154 * @new_state: new state of the partition
155 */
156static int tegra_powergate_set(int id, bool new_state)
157{
158 bool status;
159
160 mutex_lock(&pmc->powergates_lock);
161
162 status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
163
164 if (status == new_state) {
165 mutex_unlock(&pmc->powergates_lock);
166 return 0;
167 }
168
169 tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
170
171 mutex_unlock(&pmc->powergates_lock);
172
173 return 0;
174}
175
176/**
177 * tegra_powergate_power_on() - power on partition
178 * @id: partition ID
179 */
180int tegra_powergate_power_on(int id)
181{
182 if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
183 return -EINVAL;
184
185 return tegra_powergate_set(id, true);
186}
187
188/**
189 * tegra_powergate_power_off() - power off partition
190 * @id: partition ID
191 */
192int tegra_powergate_power_off(int id)
193{
194 if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
195 return -EINVAL;
196
197 return tegra_powergate_set(id, false);
198}
199EXPORT_SYMBOL(tegra_powergate_power_off);
200
201/**
202 * tegra_powergate_is_powered() - check if partition is powered
203 * @id: partition ID
204 */
205int tegra_powergate_is_powered(int id)
206{
207 u32 status;
208
209 if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
210 return -EINVAL;
211
212 status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
213 return !!status;
214}
215
216/**
217 * tegra_powergate_remove_clamping() - remove power clamps for partition
218 * @id: partition ID
219 */
220int tegra_powergate_remove_clamping(int id)
221{
222 u32 mask;
223
224 if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
225 return -EINVAL;
226
227 /*
228 * The Tegra124 GPU has a separate register (with different semantics)
229 * to remove clamps.
230 */
231 if (tegra_get_chip_id() == TEGRA124) {
232 if (id == TEGRA_POWERGATE_3D) {
233 tegra_pmc_writel(0, GPU_RG_CNTRL);
234 return 0;
235 }
236 }
237
238 /*
239 * Tegra 2 has a bug where PCIE and VDE clamping masks are
240 * swapped relatively to the partition ids
241 */
242 if (id == TEGRA_POWERGATE_VDEC)
243 mask = (1 << TEGRA_POWERGATE_PCIE);
244 else if (id == TEGRA_POWERGATE_PCIE)
245 mask = (1 << TEGRA_POWERGATE_VDEC);
246 else
247 mask = (1 << id);
248
249 tegra_pmc_writel(mask, REMOVE_CLAMPING);
250
251 return 0;
252}
253EXPORT_SYMBOL(tegra_powergate_remove_clamping);
254
255/**
256 * tegra_powergate_sequence_power_up() - power up partition
257 * @id: partition ID
258 * @clk: clock for partition
259 * @rst: reset for partition
260 *
261 * Must be called with clk disabled, and returns with clk enabled.
262 */
263int tegra_powergate_sequence_power_up(int id, struct clk *clk,
264 struct reset_control *rst)
265{
266 int ret;
267
268 reset_control_assert(rst);
269
270 ret = tegra_powergate_power_on(id);
271 if (ret)
272 goto err_power;
273
274 ret = clk_prepare_enable(clk);
275 if (ret)
276 goto err_clk;
277
278 usleep_range(10, 20);
279
280 ret = tegra_powergate_remove_clamping(id);
281 if (ret)
282 goto err_clamp;
283
284 usleep_range(10, 20);
285 reset_control_deassert(rst);
286
287 return 0;
288
289err_clamp:
290 clk_disable_unprepare(clk);
291err_clk:
292 tegra_powergate_power_off(id);
293err_power:
294 return ret;
295}
296EXPORT_SYMBOL(tegra_powergate_sequence_power_up);
297
298#ifdef CONFIG_SMP
299/**
300 * tegra_get_cpu_powergate_id() - convert from CPU ID to partition ID
301 * @cpuid: CPU partition ID
302 *
303 * Returns the partition ID corresponding to the CPU partition ID or a
304 * negative error code on failure.
305 */
306static int tegra_get_cpu_powergate_id(int cpuid)
307{
308 if (pmc->soc && cpuid > 0 && cpuid < pmc->soc->num_cpu_powergates)
309 return pmc->soc->cpu_powergates[cpuid];
310
311 return -EINVAL;
312}
313
314/**
315 * tegra_pmc_cpu_is_powered() - check if CPU partition is powered
316 * @cpuid: CPU partition ID
317 */
318bool tegra_pmc_cpu_is_powered(int cpuid)
319{
320 int id;
321
322 id = tegra_get_cpu_powergate_id(cpuid);
323 if (id < 0)
324 return false;
325
326 return tegra_powergate_is_powered(id);
327}
328
329/**
330 * tegra_pmc_cpu_power_on() - power on CPU partition
331 * @cpuid: CPU partition ID
332 */
333int tegra_pmc_cpu_power_on(int cpuid)
334{
335 int id;
336
337 id = tegra_get_cpu_powergate_id(cpuid);
338 if (id < 0)
339 return id;
340
341 return tegra_powergate_set(id, true);
342}
343
344/**
345 * tegra_pmc_cpu_remove_clamping() - remove power clamps for CPU partition
346 * @cpuid: CPU partition ID
347 */
348int tegra_pmc_cpu_remove_clamping(int cpuid)
349{
350 int id;
351
352 id = tegra_get_cpu_powergate_id(cpuid);
353 if (id < 0)
354 return id;
355
356 return tegra_powergate_remove_clamping(id);
357}
358#endif /* CONFIG_SMP */
359
360/**
361 * tegra_pmc_restart() - reboot the system
362 * @mode: which mode to reboot in
363 * @cmd: reboot command
364 */
365void tegra_pmc_restart(enum reboot_mode mode, const char *cmd)
366{
367 u32 value;
368
369 value = tegra_pmc_readl(PMC_SCRATCH0);
370 value &= ~PMC_SCRATCH0_MODE_MASK;
371
372 if (cmd) {
373 if (strcmp(cmd, "recovery") == 0)
374 value |= PMC_SCRATCH0_MODE_RECOVERY;
375
376 if (strcmp(cmd, "bootloader") == 0)
377 value |= PMC_SCRATCH0_MODE_BOOTLOADER;
378
379 if (strcmp(cmd, "forced-recovery") == 0)
380 value |= PMC_SCRATCH0_MODE_RCM;
381 }
382
383 tegra_pmc_writel(value, PMC_SCRATCH0);
384
385 value = tegra_pmc_readl(0);
386 value |= 0x10;
387 tegra_pmc_writel(value, 0);
388}
389
390static int powergate_show(struct seq_file *s, void *data)
391{
392 unsigned int i;
393
394 seq_printf(s, " powergate powered\n");
395 seq_printf(s, "------------------\n");
396
397 for (i = 0; i < pmc->soc->num_powergates; i++) {
398 if (!pmc->soc->powergates[i])
399 continue;
400
401 seq_printf(s, " %9s %7s\n", pmc->soc->powergates[i],
402 tegra_powergate_is_powered(i) ? "yes" : "no");
403 }
404
405 return 0;
406}
407
408static int powergate_open(struct inode *inode, struct file *file)
409{
410 return single_open(file, powergate_show, inode->i_private);
411}
412
413static const struct file_operations powergate_fops = {
414 .open = powergate_open,
415 .read = seq_read,
416 .llseek = seq_lseek,
417 .release = single_release,
418};
419
420static int tegra_powergate_debugfs_init(void)
421{
422 struct dentry *d;
423
424 d = debugfs_create_file("powergate", S_IRUGO, NULL, NULL,
425 &powergate_fops);
426 if (!d)
427 return -ENOMEM;
428
429 return 0;
430}
431
432static int tegra_io_rail_prepare(int id, unsigned long *request,
433 unsigned long *status, unsigned int *bit)
434{
435 unsigned long rate, value;
436 struct clk *clk;
437
438 *bit = id % 32;
439
440 /*
441 * There are two sets of 30 bits to select IO rails, but bits 30 and
442 * 31 are control bits rather than IO rail selection bits.
443 */
444 if (id > 63 || *bit == 30 || *bit == 31)
445 return -EINVAL;
446
447 if (id < 32) {
448 *status = IO_DPD_STATUS;
449 *request = IO_DPD_REQ;
450 } else {
451 *status = IO_DPD2_STATUS;
452 *request = IO_DPD2_REQ;
453 }
454
455 clk = clk_get_sys(NULL, "pclk");
456 if (IS_ERR(clk))
457 return PTR_ERR(clk);
458
459 rate = clk_get_rate(clk);
460 clk_put(clk);
461
462 tegra_pmc_writel(DPD_SAMPLE_ENABLE, DPD_SAMPLE);
463
464 /* must be at least 200 ns, in APB (PCLK) clock cycles */
465 value = DIV_ROUND_UP(1000000000, rate);
466 value = DIV_ROUND_UP(200, value);
467 tegra_pmc_writel(value, SEL_DPD_TIM);
468
469 return 0;
470}
471
472static int tegra_io_rail_poll(unsigned long offset, unsigned long mask,
473 unsigned long val, unsigned long timeout)
474{
475 unsigned long value;
476
477 timeout = jiffies + msecs_to_jiffies(timeout);
478
479 while (time_after(timeout, jiffies)) {
480 value = tegra_pmc_readl(offset);
481 if ((value & mask) == val)
482 return 0;
483
484 usleep_range(250, 1000);
485 }
486
487 return -ETIMEDOUT;
488}
489
490static void tegra_io_rail_unprepare(void)
491{
492 tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE);
493}
494
495int tegra_io_rail_power_on(int id)
496{
497 unsigned long request, status, value;
498 unsigned int bit, mask;
499 int err;
500
501 err = tegra_io_rail_prepare(id, &request, &status, &bit);
502 if (err < 0)
503 return err;
504
505 mask = 1 << bit;
506
507 value = tegra_pmc_readl(request);
508 value |= mask;
509 value &= ~IO_DPD_REQ_CODE_MASK;
510 value |= IO_DPD_REQ_CODE_OFF;
511 tegra_pmc_writel(value, request);
512
513 err = tegra_io_rail_poll(status, mask, 0, 250);
514 if (err < 0)
515 return err;
516
517 tegra_io_rail_unprepare();
518
519 return 0;
520}
521EXPORT_SYMBOL(tegra_io_rail_power_on);
522
523int tegra_io_rail_power_off(int id)
524{
525 unsigned long request, status, value;
526 unsigned int bit, mask;
527 int err;
528
529 err = tegra_io_rail_prepare(id, &request, &status, &bit);
530 if (err < 0)
531 return err;
532
533 mask = 1 << bit;
534
535 value = tegra_pmc_readl(request);
536 value |= mask;
537 value &= ~IO_DPD_REQ_CODE_MASK;
538 value |= IO_DPD_REQ_CODE_ON;
539 tegra_pmc_writel(value, request);
540
541 err = tegra_io_rail_poll(status, mask, mask, 250);
542 if (err < 0)
543 return err;
544
545 tegra_io_rail_unprepare();
546
547 return 0;
548}
549EXPORT_SYMBOL(tegra_io_rail_power_off);
550
551#ifdef CONFIG_PM_SLEEP
552enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
553{
554 return pmc->suspend_mode;
555}
556
557void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
558{
559 if (mode < TEGRA_SUSPEND_NONE || mode >= TEGRA_MAX_SUSPEND_MODE)
560 return;
561
562 pmc->suspend_mode = mode;
563}
564
565void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode)
566{
567 unsigned long long rate = 0;
568 u32 value;
569
570 switch (mode) {
571 case TEGRA_SUSPEND_LP1:
572 rate = 32768;
573 break;
574
575 case TEGRA_SUSPEND_LP2:
576 rate = clk_get_rate(pmc->clk);
577 break;
578
579 default:
580 break;
581 }
582
583 if (WARN_ON_ONCE(rate == 0))
584 rate = 100000000;
585
586 if (rate != pmc->rate) {
587 u64 ticks;
588
589 ticks = pmc->cpu_good_time * rate + USEC_PER_SEC - 1;
590 do_div(ticks, USEC_PER_SEC);
591 tegra_pmc_writel(ticks, PMC_CPUPWRGOOD_TIMER);
592
593 ticks = pmc->cpu_off_time * rate + USEC_PER_SEC - 1;
594 do_div(ticks, USEC_PER_SEC);
595 tegra_pmc_writel(ticks, PMC_CPUPWROFF_TIMER);
596
597 wmb();
598
599 pmc->rate = rate;
600 }
601
602 value = tegra_pmc_readl(PMC_CNTRL);
603 value &= ~PMC_CNTRL_SIDE_EFFECT_LP0;
604 value |= PMC_CNTRL_CPU_PWRREQ_OE;
605 tegra_pmc_writel(value, PMC_CNTRL);
606}
607#endif
608
609static int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np)
610{
611 u32 value, values[2];
612
613 if (of_property_read_u32(np, "nvidia,suspend-mode", &value)) {
614 } else {
615 switch (value) {
616 case 0:
617 pmc->suspend_mode = TEGRA_SUSPEND_LP0;
618 break;
619
620 case 1:
621 pmc->suspend_mode = TEGRA_SUSPEND_LP1;
622 break;
623
624 case 2:
625 pmc->suspend_mode = TEGRA_SUSPEND_LP2;
626 break;
627
628 default:
629 pmc->suspend_mode = TEGRA_SUSPEND_NONE;
630 break;
631 }
632 }
633
634 pmc->suspend_mode = tegra_pm_validate_suspend_mode(pmc->suspend_mode);
635
636 if (of_property_read_u32(np, "nvidia,cpu-pwr-good-time", &value))
637 pmc->suspend_mode = TEGRA_SUSPEND_NONE;
638
639 pmc->cpu_good_time = value;
640
641 if (of_property_read_u32(np, "nvidia,cpu-pwr-off-time", &value))
642 pmc->suspend_mode = TEGRA_SUSPEND_NONE;
643
644 pmc->cpu_off_time = value;
645
646 if (of_property_read_u32_array(np, "nvidia,core-pwr-good-time",
647 values, ARRAY_SIZE(values)))
648 pmc->suspend_mode = TEGRA_SUSPEND_NONE;
649
650 pmc->core_osc_time = values[0];
651 pmc->core_pmu_time = values[1];
652
653 if (of_property_read_u32(np, "nvidia,core-pwr-off-time", &value))
654 pmc->suspend_mode = TEGRA_SUSPEND_NONE;
655
656 pmc->core_off_time = value;
657
658 pmc->corereq_high = of_property_read_bool(np,
659 "nvidia,core-power-req-active-high");
660
661 pmc->sysclkreq_high = of_property_read_bool(np,
662 "nvidia,sys-clock-req-active-high");
663
664 pmc->combined_req = of_property_read_bool(np,
665 "nvidia,combined-power-req");
666
667 pmc->cpu_pwr_good_en = of_property_read_bool(np,
668 "nvidia,cpu-pwr-good-en");
669
670 if (of_property_read_u32_array(np, "nvidia,lp0-vec", values,
671 ARRAY_SIZE(values)))
672 if (pmc->suspend_mode == TEGRA_SUSPEND_LP0)
673 pmc->suspend_mode = TEGRA_SUSPEND_LP1;
674
675 pmc->lp0_vec_phys = values[0];
676 pmc->lp0_vec_size = values[1];
677
678 return 0;
679}
680
681static void tegra_pmc_init(struct tegra_pmc *pmc)
682{
683 u32 value;
684
685 /* Always enable CPU power request */
686 value = tegra_pmc_readl(PMC_CNTRL);
687 value |= PMC_CNTRL_CPU_PWRREQ_OE;
688 tegra_pmc_writel(value, PMC_CNTRL);
689
690 value = tegra_pmc_readl(PMC_CNTRL);
691
692 if (pmc->sysclkreq_high)
693 value &= ~PMC_CNTRL_SYSCLK_POLARITY;
694 else
695 value |= PMC_CNTRL_SYSCLK_POLARITY;
696
697 /* configure the output polarity while the request is tristated */
698 tegra_pmc_writel(value, PMC_CNTRL);
699
700 /* now enable the request */
701 value = tegra_pmc_readl(PMC_CNTRL);
702 value |= PMC_CNTRL_SYSCLK_OE;
703 tegra_pmc_writel(value, PMC_CNTRL);
704}
705
706static int tegra_pmc_probe(struct platform_device *pdev)
707{
708 void __iomem *base = pmc->base;
709 struct resource *res;
710 int err;
711
712 err = tegra_pmc_parse_dt(pmc, pdev->dev.of_node);
713 if (err < 0)
714 return err;
715
716 /* take over the memory region from the early initialization */
717 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
718 pmc->base = devm_ioremap_resource(&pdev->dev, res);
719 if (IS_ERR(pmc->base))
720 return PTR_ERR(pmc->base);
721
722 iounmap(base);
723
724 pmc->clk = devm_clk_get(&pdev->dev, "pclk");
725 if (IS_ERR(pmc->clk)) {
726 err = PTR_ERR(pmc->clk);
727 dev_err(&pdev->dev, "failed to get pclk: %d\n", err);
728 return err;
729 }
730
731 tegra_pmc_init(pmc);
732
733 if (IS_ENABLED(CONFIG_DEBUG_FS)) {
734 err = tegra_powergate_debugfs_init();
735 if (err < 0)
736 return err;
737 }
738
739 return 0;
740}
741
742#ifdef CONFIG_PM_SLEEP
743static int tegra_pmc_suspend(struct device *dev)
744{
745 tegra_pmc_writel(virt_to_phys(tegra_resume), PMC_SCRATCH41);
746
747 return 0;
748}
749
750static int tegra_pmc_resume(struct device *dev)
751{
752 tegra_pmc_writel(0x0, PMC_SCRATCH41);
753
754 return 0;
755}
756#endif
757
758static SIMPLE_DEV_PM_OPS(tegra_pmc_pm_ops, tegra_pmc_suspend, tegra_pmc_resume);
759
760static const char * const tegra20_powergates[] = {
761 [TEGRA_POWERGATE_CPU] = "cpu",
762 [TEGRA_POWERGATE_3D] = "3d",
763 [TEGRA_POWERGATE_VENC] = "venc",
764 [TEGRA_POWERGATE_VDEC] = "vdec",
765 [TEGRA_POWERGATE_PCIE] = "pcie",
766 [TEGRA_POWERGATE_L2] = "l2",
767 [TEGRA_POWERGATE_MPE] = "mpe",
768};
769
770static const struct tegra_pmc_soc tegra20_pmc_soc = {
771 .num_powergates = ARRAY_SIZE(tegra20_powergates),
772 .powergates = tegra20_powergates,
773 .num_cpu_powergates = 0,
774 .cpu_powergates = NULL,
775};
776
777static const char * const tegra30_powergates[] = {
778 [TEGRA_POWERGATE_CPU] = "cpu0",
779 [TEGRA_POWERGATE_3D] = "3d0",
780 [TEGRA_POWERGATE_VENC] = "venc",
781 [TEGRA_POWERGATE_VDEC] = "vdec",
782 [TEGRA_POWERGATE_PCIE] = "pcie",
783 [TEGRA_POWERGATE_L2] = "l2",
784 [TEGRA_POWERGATE_MPE] = "mpe",
785 [TEGRA_POWERGATE_HEG] = "heg",
786 [TEGRA_POWERGATE_SATA] = "sata",
787 [TEGRA_POWERGATE_CPU1] = "cpu1",
788 [TEGRA_POWERGATE_CPU2] = "cpu2",
789 [TEGRA_POWERGATE_CPU3] = "cpu3",
790 [TEGRA_POWERGATE_CELP] = "celp",
791 [TEGRA_POWERGATE_3D1] = "3d1",
792};
793
794static const u8 tegra30_cpu_powergates[] = {
795 TEGRA_POWERGATE_CPU,
796 TEGRA_POWERGATE_CPU1,
797 TEGRA_POWERGATE_CPU2,
798 TEGRA_POWERGATE_CPU3,
799};
800
801static const struct tegra_pmc_soc tegra30_pmc_soc = {
802 .num_powergates = ARRAY_SIZE(tegra30_powergates),
803 .powergates = tegra30_powergates,
804 .num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates),
805 .cpu_powergates = tegra30_cpu_powergates,
806};
807
808static const char * const tegra114_powergates[] = {
809 [TEGRA_POWERGATE_CPU] = "crail",
810 [TEGRA_POWERGATE_3D] = "3d",
811 [TEGRA_POWERGATE_VENC] = "venc",
812 [TEGRA_POWERGATE_VDEC] = "vdec",
813 [TEGRA_POWERGATE_MPE] = "mpe",
814 [TEGRA_POWERGATE_HEG] = "heg",
815 [TEGRA_POWERGATE_CPU1] = "cpu1",
816 [TEGRA_POWERGATE_CPU2] = "cpu2",
817 [TEGRA_POWERGATE_CPU3] = "cpu3",
818 [TEGRA_POWERGATE_CELP] = "celp",
819 [TEGRA_POWERGATE_CPU0] = "cpu0",
820 [TEGRA_POWERGATE_C0NC] = "c0nc",
821 [TEGRA_POWERGATE_C1NC] = "c1nc",
822 [TEGRA_POWERGATE_DIS] = "dis",
823 [TEGRA_POWERGATE_DISB] = "disb",
824 [TEGRA_POWERGATE_XUSBA] = "xusba",
825 [TEGRA_POWERGATE_XUSBB] = "xusbb",
826 [TEGRA_POWERGATE_XUSBC] = "xusbc",
827};
828
829static const u8 tegra114_cpu_powergates[] = {
830 TEGRA_POWERGATE_CPU0,
831 TEGRA_POWERGATE_CPU1,
832 TEGRA_POWERGATE_CPU2,
833 TEGRA_POWERGATE_CPU3,
834};
835
836static const struct tegra_pmc_soc tegra114_pmc_soc = {
837 .num_powergates = ARRAY_SIZE(tegra114_powergates),
838 .powergates = tegra114_powergates,
839 .num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates),
840 .cpu_powergates = tegra114_cpu_powergates,
841};
842
843static const char * const tegra124_powergates[] = {
844 [TEGRA_POWERGATE_CPU] = "crail",
845 [TEGRA_POWERGATE_3D] = "3d",
846 [TEGRA_POWERGATE_VENC] = "venc",
847 [TEGRA_POWERGATE_PCIE] = "pcie",
848 [TEGRA_POWERGATE_VDEC] = "vdec",
849 [TEGRA_POWERGATE_L2] = "l2",
850 [TEGRA_POWERGATE_MPE] = "mpe",
851 [TEGRA_POWERGATE_HEG] = "heg",
852 [TEGRA_POWERGATE_SATA] = "sata",
853 [TEGRA_POWERGATE_CPU1] = "cpu1",
854 [TEGRA_POWERGATE_CPU2] = "cpu2",
855 [TEGRA_POWERGATE_CPU3] = "cpu3",
856 [TEGRA_POWERGATE_CELP] = "celp",
857 [TEGRA_POWERGATE_CPU0] = "cpu0",
858 [TEGRA_POWERGATE_C0NC] = "c0nc",
859 [TEGRA_POWERGATE_C1NC] = "c1nc",
860 [TEGRA_POWERGATE_SOR] = "sor",
861 [TEGRA_POWERGATE_DIS] = "dis",
862 [TEGRA_POWERGATE_DISB] = "disb",
863 [TEGRA_POWERGATE_XUSBA] = "xusba",
864 [TEGRA_POWERGATE_XUSBB] = "xusbb",
865 [TEGRA_POWERGATE_XUSBC] = "xusbc",
866 [TEGRA_POWERGATE_VIC] = "vic",
867 [TEGRA_POWERGATE_IRAM] = "iram",
868};
869
870static const u8 tegra124_cpu_powergates[] = {
871 TEGRA_POWERGATE_CPU0,
872 TEGRA_POWERGATE_CPU1,
873 TEGRA_POWERGATE_CPU2,
874 TEGRA_POWERGATE_CPU3,
875};
876
877static const struct tegra_pmc_soc tegra124_pmc_soc = {
878 .num_powergates = ARRAY_SIZE(tegra124_powergates),
879 .powergates = tegra124_powergates,
880 .num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates),
881 .cpu_powergates = tegra124_cpu_powergates,
882};
883
884static const struct of_device_id tegra_pmc_match[] = {
885 { .compatible = "nvidia,tegra124-pmc", .data = &tegra124_pmc_soc },
886 { .compatible = "nvidia,tegra114-pmc", .data = &tegra114_pmc_soc },
887 { .compatible = "nvidia,tegra30-pmc", .data = &tegra30_pmc_soc },
888 { .compatible = "nvidia,tegra20-pmc", .data = &tegra20_pmc_soc },
889 { }
890};
891
892static struct platform_driver tegra_pmc_driver = {
893 .driver = {
894 .name = "tegra-pmc",
895 .suppress_bind_attrs = true,
896 .of_match_table = tegra_pmc_match,
897 .pm = &tegra_pmc_pm_ops,
898 },
899 .probe = tegra_pmc_probe,
900};
901module_platform_driver(tegra_pmc_driver);
902
903/*
904 * Early initialization to allow access to registers in the very early boot
905 * process.
906 */
907static int __init tegra_pmc_early_init(void)
908{
909 const struct of_device_id *match;
910 struct device_node *np;
911 struct resource regs;
912 bool invert;
913 u32 value;
914
915 if (!soc_is_tegra())
916 return 0;
917
918 np = of_find_matching_node_and_match(NULL, tegra_pmc_match, &match);
919 if (!np) {
920 pr_warn("PMC device node not found, disabling powergating\n");
921
922 regs.start = 0x7000e400;
923 regs.end = 0x7000e7ff;
924 regs.flags = IORESOURCE_MEM;
925
926 pr_warn("Using memory region %pR\n", &regs);
927 } else {
928 pmc->soc = match->data;
929 }
930
931 if (of_address_to_resource(np, 0, &regs) < 0) {
932 pr_err("failed to get PMC registers\n");
933 return -ENXIO;
934 }
935
936 pmc->base = ioremap_nocache(regs.start, resource_size(&regs));
937 if (!pmc->base) {
938 pr_err("failed to map PMC registers\n");
939 return -ENXIO;
940 }
941
942 mutex_init(&pmc->powergates_lock);
943
944 invert = of_property_read_bool(np, "nvidia,invert-interrupt");
945
946 value = tegra_pmc_readl(PMC_CNTRL);
947
948 if (invert)
949 value |= PMC_CNTRL_INTR_POLARITY;
950 else
951 value &= ~PMC_CNTRL_INTR_POLARITY;
952
953 tegra_pmc_writel(value, PMC_CNTRL);
954
955 return 0;
956}
957early_initcall(tegra_pmc_early_init);
diff --git a/include/soc/tegra/pm.h b/include/soc/tegra/pm.h
new file mode 100644
index 000000000000..30fe2078a547
--- /dev/null
+++ b/include/soc/tegra/pm.h
@@ -0,0 +1,38 @@
1/*
2 * Copyright (C) 2014 NVIDIA Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef __SOC_TEGRA_PM_H__
10#define __SOC_TEGRA_PM_H__
11
12enum tegra_suspend_mode {
13 TEGRA_SUSPEND_NONE = 0,
14 TEGRA_SUSPEND_LP2, /* CPU voltage off */
15 TEGRA_SUSPEND_LP1, /* CPU voltage off, DRAM self-refresh */
16 TEGRA_SUSPEND_LP0, /* CPU + core voltage off, DRAM self-refresh */
17 TEGRA_MAX_SUSPEND_MODE,
18};
19
20#ifdef CONFIG_PM_SLEEP
21enum tegra_suspend_mode
22tegra_pm_validate_suspend_mode(enum tegra_suspend_mode mode);
23
24/* low-level resume entry point */
25void tegra_resume(void);
26#else
27static inline enum tegra_suspend_mode
28tegra_pm_validate_suspend_mode(enum tegra_suspend_mode mode)
29{
30 return TEGRA_SUSPEND_NONE;
31}
32
33static inline void tegra_resume(void)
34{
35}
36#endif /* CONFIG_PM_SLEEP */
37
38#endif /* __SOC_TEGRA_PM_H__ */
diff --git a/include/soc/tegra/powergate.h b/include/soc/tegra/pmc.h
index c16912ed1a8d..65a93273e72f 100644
--- a/include/soc/tegra/powergate.h
+++ b/include/soc/tegra/pmc.h
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (c) 2010 Google, Inc 2 * Copyright (c) 2010 Google, Inc
3 * Copyright (c) 2014 NVIDIA Corporation
3 * 4 *
4 * Author: 5 * Author:
5 * Colin Cross <ccross@google.com> 6 * Colin Cross <ccross@google.com>
@@ -15,12 +16,34 @@
15 * 16 *
16 */ 17 */
17 18
18#ifndef __SOC_TEGRA_POWERGATE_H__ 19#ifndef __SOC_TEGRA_PMC_H__
19#define __SOC_TEGRA_POWERGATE_H__ 20#define __SOC_TEGRA_PMC_H__
21
22#include <linux/reboot.h>
23
24#include <soc/tegra/pm.h>
20 25
21struct clk; 26struct clk;
22struct reset_control; 27struct reset_control;
23 28
29void tegra_pmc_restart(enum reboot_mode mode, const char *cmd);
30
31#ifdef CONFIG_PM_SLEEP
32enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void);
33void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode);
34void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode);
35#endif /* CONFIG_PM_SLEEP */
36
37#ifdef CONFIG_SMP
38bool tegra_pmc_cpu_is_powered(int cpuid);
39int tegra_pmc_cpu_power_on(int cpuid);
40int tegra_pmc_cpu_remove_clamping(int cpuid);
41#endif /* CONFIG_SMP */
42
43/*
44 * powergate and I/O rail APIs
45 */
46
24#define TEGRA_POWERGATE_CPU 0 47#define TEGRA_POWERGATE_CPU 0
25#define TEGRA_POWERGATE_3D 1 48#define TEGRA_POWERGATE_3D 1
26#define TEGRA_POWERGATE_VENC 2 49#define TEGRA_POWERGATE_VENC 2
@@ -129,6 +152,6 @@ static inline int tegra_io_rail_power_off(int id)
129{ 152{
130 return -ENOSYS; 153 return -ENOSYS;
131} 154}
132#endif 155#endif /* CONFIG_ARCH_TEGRA */
133 156
134#endif /* __SOC_TEGRA_POWERGATE_H__ */ 157#endif /* __SOC_TEGRA_PMC_H__ */