aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2014-07-19 15:31:22 -0400
committerOlof Johansson <olof@lixom.net>2014-07-19 15:31:22 -0400
commitc6b659c0050429c36e3e805529d68d8680956e1a (patch)
tree288581d67495844edd17a7be4a7caae273ff6efb /arch/arm/mach-tegra
parent23e892929e7ccee8b5977a673a147dec96ac1351 (diff)
parent7232398abc6a7186e315425638c367d50c674718 (diff)
Merge tag 'tegra-for-3.17-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into next/cleanup
Merge "ARM: tegra: core code changes for 3.17" from Thierry Reding: Some of the code that's currently called from the Tegra machine setup code is moved to regular initcalls. To catch dependency violations, the various code paths now WARN if they're called to early. Not all of the potential candidates are converted yet, but those that were have been verified to work across all supported Tegra generations. A new function, soc_is_tegra(), is also provided to make sure that the initcalls can abort early if they aren't run on Tegra, which can happen for multi-platform builds. Finally this also moves out the PMC driver to drivers/soc/tegra so that it can be shared with 64-bit ARM. This is based on the for-3.17/fuse-move branch. The split is somewhat arbitrary but allows the dependents of the for-3.17/fuse-move to pull in as little code as necessary. * tag 'tegra-for-3.17-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux: ARM: tegra: Convert PMC to a driver soc/tegra: fuse: Set up in early initcall ARM: tegra: Always lock the CPU reset vector ARM: tegra: Setup CPU hotplug in a pure initcall soc/tegra: Implement runtime check for Tegra SoCs Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r--arch/arm/mach-tegra/Makefile2
-rw-r--r--arch/arm/mach-tegra/board.h7
-rw-r--r--arch/arm/mach-tegra/hotplug.c16
-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/reset.c10
-rw-r--r--arch/arm/mach-tegra/sleep.h3
-rw-r--r--arch/arm/mach-tegra/tegra.c9
12 files changed, 45 insertions, 1025 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/hotplug.c b/arch/arm/mach-tegra/hotplug.c
index d60339c996cb..6fc71f1534b0 100644
--- a/arch/arm/mach-tegra/hotplug.c
+++ b/arch/arm/mach-tegra/hotplug.c
@@ -12,6 +12,7 @@
12#include <linux/kernel.h> 12#include <linux/kernel.h>
13#include <linux/smp.h> 13#include <linux/smp.h>
14 14
15#include <soc/tegra/common.h>
15#include <soc/tegra/fuse.h> 16#include <soc/tegra/fuse.h>
16 17
17#include <asm/smp_plat.h> 18#include <asm/smp_plat.h>
@@ -38,6 +39,11 @@ int tegra_cpu_kill(unsigned cpu)
38 */ 39 */
39void __ref tegra_cpu_die(unsigned int cpu) 40void __ref tegra_cpu_die(unsigned int cpu)
40{ 41{
42 if (!tegra_hotplug_shutdown) {
43 WARN(1, "hotplug is not yet initialized\n");
44 return;
45 }
46
41 /* Clean L1 data cache */ 47 /* Clean L1 data cache */
42 tegra_disable_clean_inv_dcache(TEGRA_FLUSH_CACHE_LOUIS); 48 tegra_disable_clean_inv_dcache(TEGRA_FLUSH_CACHE_LOUIS);
43 49
@@ -48,10 +54,13 @@ void __ref tegra_cpu_die(unsigned int cpu)
48 BUG(); 54 BUG();
49} 55}
50 56
51void __init tegra_hotplug_init(void) 57static int __init tegra_hotplug_init(void)
52{ 58{
53 if (!IS_ENABLED(CONFIG_HOTPLUG_CPU)) 59 if (!IS_ENABLED(CONFIG_HOTPLUG_CPU))
54 return; 60 return 0;
61
62 if (!soc_is_tegra())
63 return 0;
55 64
56 if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_get_chip_id() == TEGRA20) 65 if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_get_chip_id() == TEGRA20)
57 tegra_hotplug_shutdown = tegra20_hotplug_shutdown; 66 tegra_hotplug_shutdown = tegra20_hotplug_shutdown;
@@ -61,4 +70,7 @@ void __init tegra_hotplug_init(void)
61 tegra_hotplug_shutdown = tegra30_hotplug_shutdown; 70 tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
62 if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_get_chip_id() == TEGRA124) 71 if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_get_chip_id() == TEGRA124)
63 tegra_hotplug_shutdown = tegra30_hotplug_shutdown; 72 tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
73
74 return 0;
64} 75}
76pure_initcall(tegra_hotplug_init);
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/reset.c b/arch/arm/mach-tegra/reset.c
index 5377495d41b8..894c5c472184 100644
--- a/arch/arm/mach-tegra/reset.c
+++ b/arch/arm/mach-tegra/reset.c
@@ -54,12 +54,10 @@ static void __init tegra_cpu_reset_handler_set(const u32 reset_address)
54 * Prevent further modifications to the physical reset vector. 54 * Prevent further modifications to the physical reset vector.
55 * NOTE: Has no effect on chips prior to Tegra30. 55 * NOTE: Has no effect on chips prior to Tegra30.
56 */ 56 */
57 if (tegra_get_chip_id() != TEGRA20) { 57 reg = readl(sb_ctrl);
58 reg = readl(sb_ctrl); 58 reg |= 2;
59 reg |= 2; 59 writel(reg, sb_ctrl);
60 writel(reg, sb_ctrl); 60 wmb();
61 wmb();
62 }
63} 61}
64 62
65static void __init tegra_cpu_reset_handler_enable(void) 63static void __init tegra_cpu_reset_handler_enable(void)
diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h
index 339fe42cd6fb..92d46ec1361a 100644
--- a/arch/arm/mach-tegra/sleep.h
+++ b/arch/arm/mach-tegra/sleep.h
@@ -130,9 +130,6 @@ void tegra_disable_clean_inv_dcache(u32 flag);
130#ifdef CONFIG_HOTPLUG_CPU 130#ifdef CONFIG_HOTPLUG_CPU
131void tegra20_hotplug_shutdown(void); 131void tegra20_hotplug_shutdown(void);
132void tegra30_hotplug_shutdown(void); 132void tegra30_hotplug_shutdown(void);
133void tegra_hotplug_init(void);
134#else
135static inline void tegra_hotplug_init(void) {}
136#endif 133#endif
137 134
138void tegra20_cpu_shutdown(int cpu); 135void tegra20_cpu_shutdown(int cpu);
diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index 6ccbc8ca1db5..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"
@@ -73,15 +73,11 @@ u32 tegra_uart_config[3] = {
73static void __init tegra_init_early(void) 73static void __init tegra_init_early(void)
74{ 74{
75 of_register_trusted_foundations(); 75 of_register_trusted_foundations();
76 tegra_init_fuse();
77 tegra_cpu_reset_handler_init(); 76 tegra_cpu_reset_handler_init();
78 tegra_powergate_init();
79 tegra_hotplug_init();
80} 77}
81 78
82static void __init tegra_dt_init_irq(void) 79static void __init tegra_dt_init_irq(void)
83{ 80{
84 tegra_pmc_init_irq();
85 tegra_init_irq(); 81 tegra_init_irq();
86 irqchip_init(); 82 irqchip_init();
87 tegra_legacy_irq_syscore_init(); 83 tegra_legacy_irq_syscore_init();
@@ -93,8 +89,6 @@ static void __init tegra_dt_init(void)
93 struct soc_device *soc_dev; 89 struct soc_device *soc_dev;
94 struct device *parent = NULL; 90 struct device *parent = NULL;
95 91
96 tegra_pmc_init();
97
98 tegra_clocks_apply_init_table(); 92 tegra_clocks_apply_init_table();
99 93
100 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 94 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
@@ -144,7 +138,6 @@ static void __init tegra_dt_init_late(void)
144 138
145 tegra_init_suspend(); 139 tegra_init_suspend();
146 tegra_cpuidle_init(); 140 tegra_cpuidle_init();
147 tegra_powergate_debugfs_init();
148 141
149 for (i = 0; i < ARRAY_SIZE(board_init_funcs); i++) { 142 for (i = 0; i < ARRAY_SIZE(board_init_funcs); i++) {
150 if (of_machine_is_compatible(board_init_funcs[i].machine)) { 143 if (of_machine_is_compatible(board_init_funcs[i].machine)) {