aboutsummaryrefslogtreecommitdiffstats
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
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>
-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
-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/Makefile3
-rw-r--r--drivers/soc/tegra/common.c30
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra.c11
-rw-r--r--drivers/soc/tegra/fuse/tegra-apbmisc.c7
-rw-r--r--drivers/soc/tegra/pmc.c957
-rw-r--r--include/soc/tegra/common.h14
-rw-r--r--include/soc/tegra/fuse.h1
-rw-r--r--include/soc/tegra/pm.h38
-rw-r--r--include/soc/tegra/pmc.h (renamed from include/soc/tegra/powergate.h)31
25 files changed, 1132 insertions, 1038 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)) {
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 236600f91bb3..cdaad9d53a05 100644
--- a/drivers/soc/tegra/Makefile
+++ b/drivers/soc/tegra/Makefile
@@ -1 +1,4 @@
1obj-$(CONFIG_ARCH_TEGRA) += fuse/ 1obj-$(CONFIG_ARCH_TEGRA) += fuse/
2
3obj-$(CONFIG_ARCH_TEGRA) += common.o
4obj-$(CONFIG_ARCH_TEGRA) += pmc.o
diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c
new file mode 100644
index 000000000000..a71cb74f3674
--- /dev/null
+++ b/drivers/soc/tegra/common.c
@@ -0,0 +1,30 @@
1/*
2 * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
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#include <linux/of.h>
10
11#include <soc/tegra/common.h>
12
13static const struct of_device_id tegra_machine_match[] = {
14 { .compatible = "nvidia,tegra20", },
15 { .compatible = "nvidia,tegra30", },
16 { .compatible = "nvidia,tegra114", },
17 { .compatible = "nvidia,tegra124", },
18 { }
19};
20
21bool soc_is_tegra(void)
22{
23 struct device_node *root;
24
25 root = of_find_node_by_path("/");
26 if (!root)
27 return false;
28
29 return of_match_node(tegra_machine_match, root) != NULL;
30}
diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c
index 03742edcfe83..11a5043959dc 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra.c
@@ -23,6 +23,7 @@
23#include <linux/of_address.h> 23#include <linux/of_address.h>
24#include <linux/io.h> 24#include <linux/io.h>
25 25
26#include <soc/tegra/common.h>
26#include <soc/tegra/fuse.h> 27#include <soc/tegra/fuse.h>
27 28
28#include "fuse.h" 29#include "fuse.h"
@@ -125,11 +126,14 @@ int tegra_fuse_create_sysfs(struct device *dev, int size,
125 return device_create_bin_file(dev, &fuse_bin_attr); 126 return device_create_bin_file(dev, &fuse_bin_attr);
126} 127}
127 128
128void __init tegra_init_fuse(void) 129static int __init tegra_init_fuse(void)
129{ 130{
130 struct device_node *np; 131 struct device_node *np;
131 void __iomem *car_base; 132 void __iomem *car_base;
132 133
134 if (!soc_is_tegra())
135 return 0;
136
133 tegra_init_apbmisc(); 137 tegra_init_apbmisc();
134 138
135 np = of_find_matching_node(NULL, car_match); 139 np = of_find_matching_node(NULL, car_match);
@@ -139,7 +143,7 @@ void __init tegra_init_fuse(void)
139 iounmap(car_base); 143 iounmap(car_base);
140 } else { 144 } else {
141 pr_err("Could not enable fuse clk. ioremap tegra car failed.\n"); 145 pr_err("Could not enable fuse clk. ioremap tegra car failed.\n");
142 return; 146 return -ENXIO;
143 } 147 }
144 148
145 if (tegra_get_chip_id() == TEGRA20) 149 if (tegra_get_chip_id() == TEGRA20)
@@ -153,4 +157,7 @@ void __init tegra_init_fuse(void)
153 tegra_sku_info.core_process_id); 157 tegra_sku_info.core_process_id);
154 pr_debug("Tegra CPU Speedo ID %d, Soc Speedo ID %d\n", 158 pr_debug("Tegra CPU Speedo ID %d, Soc Speedo ID %d\n",
155 tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id); 159 tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id);
160
161 return 0;
156} 162}
163early_initcall(tegra_init_fuse);
diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c
index bfc1d54ac4ad..3bf5aba4caaa 100644
--- a/drivers/soc/tegra/fuse/tegra-apbmisc.c
+++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c
@@ -38,9 +38,12 @@ u32 tegra_read_chipid(void)
38 38
39u8 tegra_get_chip_id(void) 39u8 tegra_get_chip_id(void)
40{ 40{
41 u32 id = tegra_read_chipid(); 41 if (!apbmisc_base) {
42 WARN(1, "Tegra Chip ID not yet available\n");
43 return 0;
44 }
42 45
43 return (id >> 8) & 0xff; 46 return (tegra_read_chipid() >> 8) & 0xff;
44} 47}
45 48
46u32 tegra_read_straps(void) 49u32 tegra_read_straps(void)
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/common.h b/include/soc/tegra/common.h
new file mode 100644
index 000000000000..fc13a9a134e9
--- /dev/null
+++ b/include/soc/tegra/common.h
@@ -0,0 +1,14 @@
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_COMMON_H__
10#define __SOC_TEGRA_COMMON_H__
11
12bool soc_is_tegra(void);
13
14#endif /* __SOC_TEGRA_COMMON_H__ */
diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h
index 738712d75cfe..8e1249474e84 100644
--- a/include/soc/tegra/fuse.h
+++ b/include/soc/tegra/fuse.h
@@ -56,7 +56,6 @@ struct tegra_sku_info {
56 56
57u32 tegra_read_straps(void); 57u32 tegra_read_straps(void);
58u32 tegra_read_chipid(void); 58u32 tegra_read_chipid(void);
59void tegra_init_fuse(void);
60int tegra_fuse_readl(unsigned long offset, u32 *value); 59int tegra_fuse_readl(unsigned long offset, u32 *value);
61 60
62extern struct tegra_sku_info tegra_sku_info; 61extern struct tegra_sku_info tegra_sku_info;
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__ */