diff options
Diffstat (limited to 'arch/arm/mach-tegra/platsmp.c')
-rw-r--r-- | arch/arm/mach-tegra/platsmp.c | 299 |
1 files changed, 228 insertions, 71 deletions
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index b8ae3c978de..ed6c01fe854 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c | |||
@@ -7,104 +7,240 @@ | |||
7 | * Copyright (C) 2009 Palm | 7 | * Copyright (C) 2009 Palm |
8 | * All Rights Reserved | 8 | * All Rights Reserved |
9 | * | 9 | * |
10 | * Copyright (C) 2010-2011 NVIDIA Corporation | ||
11 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License version 2 as | 13 | * it under the terms of the GNU General Public License version 2 as |
12 | * published by the Free Software Foundation. | 14 | * published by the Free Software Foundation. |
13 | */ | 15 | */ |
16 | |||
17 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | 18 | #include <linux/init.h> |
15 | #include <linux/errno.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <linux/jiffies.h> | ||
19 | #include <linux/smp.h> | ||
20 | #include <linux/io.h> | 19 | #include <linux/io.h> |
20 | #include <linux/smp.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/clk.h> | ||
23 | #include <linux/cpumask.h> | ||
21 | 24 | ||
22 | #include <asm/cacheflush.h> | ||
23 | #include <asm/hardware/gic.h> | 25 | #include <asm/hardware/gic.h> |
24 | #include <mach/hardware.h> | ||
25 | #include <asm/mach-types.h> | ||
26 | #include <asm/smp_scu.h> | 26 | #include <asm/smp_scu.h> |
27 | 27 | ||
28 | #include <mach/iomap.h> | 28 | #include <mach/iomap.h> |
29 | #include <mach/powergate.h> | ||
29 | 30 | ||
30 | extern void tegra_secondary_startup(void); | 31 | #include "pm.h" |
32 | #include "clock.h" | ||
33 | #include "reset.h" | ||
34 | #include "sleep.h" | ||
31 | 35 | ||
32 | static DEFINE_SPINLOCK(boot_lock); | 36 | bool tegra_all_cpus_booted; |
33 | static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE); | 37 | |
38 | static DECLARE_BITMAP(tegra_cpu_init_bits, CONFIG_NR_CPUS) __read_mostly; | ||
39 | const struct cpumask *const tegra_cpu_init_mask = to_cpumask(tegra_cpu_init_bits); | ||
40 | #define tegra_cpu_init_map (*(cpumask_t *)tegra_cpu_init_mask) | ||
34 | 41 | ||
35 | #define EVP_CPU_RESET_VECTOR \ | ||
36 | (IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100) | ||
37 | #define CLK_RST_CONTROLLER_CLK_CPU_CMPLX \ | 42 | #define CLK_RST_CONTROLLER_CLK_CPU_CMPLX \ |
38 | (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x4c) | 43 | (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x4c) |
44 | #define CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET \ | ||
45 | (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x340) | ||
39 | #define CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR \ | 46 | #define CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR \ |
40 | (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x344) | 47 | (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x344) |
41 | 48 | ||
42 | void __cpuinit platform_secondary_init(unsigned int cpu) | 49 | #define CPU_CLOCK(cpu) (0x1<<(8+cpu)) |
50 | #define CPU_RESET(cpu) (0x1111ul<<(cpu)) | ||
51 | |||
52 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
53 | #define CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR \ | ||
54 | (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x34c) | ||
55 | #define CAR_BOND_OUT_V \ | ||
56 | (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x390) | ||
57 | #define CAR_BOND_OUT_V_CPU_G (1<<0) | ||
58 | #endif | ||
59 | |||
60 | static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE); | ||
61 | |||
62 | static unsigned int available_cpus(void) | ||
43 | { | 63 | { |
44 | /* | 64 | static unsigned int ncores; |
45 | * if any interrupts are already enabled for the primary | ||
46 | * core (e.g. timer irq), then they will not have been enabled | ||
47 | * for us: do so | ||
48 | */ | ||
49 | gic_secondary_init(0); | ||
50 | 65 | ||
51 | /* | 66 | if (ncores == 0) { |
52 | * Synchronise with the boot thread. | 67 | ncores = scu_get_core_count(scu_base); |
53 | */ | 68 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC |
54 | spin_lock(&boot_lock); | 69 | if (ncores > 1) { |
55 | spin_unlock(&boot_lock); | 70 | u32 fuse_sku = readl(FUSE_SKU_DIRECT_CONFIG); |
71 | ncores -= FUSE_SKU_NUM_DISABLED_CPUS(fuse_sku); | ||
72 | BUG_ON((int)ncores <= 0); | ||
73 | } | ||
74 | #endif | ||
75 | } | ||
76 | return ncores; | ||
56 | } | 77 | } |
57 | 78 | ||
58 | int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) | 79 | static int is_g_cluster_available(unsigned int cpu) |
80 | { | ||
81 | #ifdef CONFIG_TEGRA_CLUSTER_CONTROL | ||
82 | u32 fuse_sku = readl(FUSE_SKU_DIRECT_CONFIG); | ||
83 | u32 bond_out = readl(CAR_BOND_OUT_V); | ||
84 | |||
85 | /* Does the G CPU complex exist at all? */ | ||
86 | if ((fuse_sku & FUSE_SKU_DISABLE_ALL_CPUS) || | ||
87 | (bond_out & CAR_BOND_OUT_V_CPU_G)) | ||
88 | return -EPERM; | ||
89 | |||
90 | if (cpu >= available_cpus()) | ||
91 | return -EPERM; | ||
92 | |||
93 | /* FIXME: The G CPU can be unavailable for a number of reasons | ||
94 | * (e.g., low battery, over temperature, etc.). Add checks for | ||
95 | * these conditions. */ | ||
96 | return 0; | ||
97 | #else | ||
98 | return -EPERM; | ||
99 | #endif | ||
100 | } | ||
101 | |||
102 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
103 | static bool is_cpu_powered(unsigned int cpu) | ||
104 | { | ||
105 | if (is_lp_cluster()) | ||
106 | return true; | ||
107 | else | ||
108 | return tegra_powergate_is_powered(TEGRA_CPU_POWERGATE_ID(cpu)); | ||
109 | } | ||
110 | #endif | ||
111 | |||
112 | static int power_up_cpu(unsigned int cpu) | ||
59 | { | 113 | { |
60 | unsigned long old_boot_vector; | ||
61 | unsigned long boot_vector; | ||
62 | unsigned long timeout; | ||
63 | u32 reg; | 114 | u32 reg; |
115 | int ret = 0; | ||
116 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
117 | unsigned long timeout; | ||
64 | 118 | ||
65 | /* | 119 | BUG_ON(cpu == smp_processor_id()); |
66 | * set synchronisation state between this boot processor | 120 | BUG_ON(is_lp_cluster()); |
67 | * and the secondary one | 121 | |
122 | /* If this cpu has booted this function is entered after | ||
123 | * CPU has been already un-gated by flow controller. Wait | ||
124 | * for confirmation that cpu is powered and remove clamps. | ||
125 | * On first boot entry do not wait - go to direct ungate. | ||
68 | */ | 126 | */ |
69 | spin_lock(&boot_lock); | 127 | if (cpu_isset(cpu, tegra_cpu_init_map)) { |
128 | timeout = jiffies + 5; | ||
129 | do { | ||
130 | if (is_cpu_powered(cpu)) | ||
131 | goto remove_clamps; | ||
132 | udelay(10); | ||
133 | } while (time_before(jiffies, timeout)); | ||
134 | } | ||
70 | 135 | ||
136 | /* First boot or Flow controller did not work as expected. Try to | ||
137 | directly toggle power gates. Error if direct power on also fails. */ | ||
138 | if (!is_cpu_powered(cpu)) { | ||
139 | ret = tegra_unpowergate_partition(TEGRA_CPU_POWERGATE_ID(cpu)); | ||
140 | if (ret) | ||
141 | goto fail; | ||
71 | 142 | ||
72 | /* set the reset vector to point to the secondary_startup routine */ | 143 | /* Wait for the power to come up. */ |
144 | timeout = jiffies + 10*HZ; | ||
145 | |||
146 | do { | ||
147 | if (is_cpu_powered(cpu)) | ||
148 | goto remove_clamps; | ||
149 | udelay(10); | ||
150 | } while (time_before(jiffies, timeout)); | ||
151 | ret = -ETIMEDOUT; | ||
152 | goto fail; | ||
153 | } | ||
73 | 154 | ||
74 | boot_vector = virt_to_phys(tegra_secondary_startup); | 155 | remove_clamps: |
75 | old_boot_vector = readl(EVP_CPU_RESET_VECTOR); | 156 | /* CPU partition is powered. Enable the CPU clock. */ |
76 | writel(boot_vector, EVP_CPU_RESET_VECTOR); | 157 | writel(CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR); |
158 | reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR); | ||
159 | udelay(10); | ||
77 | 160 | ||
78 | /* enable cpu clock on cpu1 */ | 161 | /* Remove I/O clamps. */ |
162 | ret = tegra_powergate_remove_clamping(TEGRA_CPU_POWERGATE_ID(cpu)); | ||
163 | udelay(10); | ||
164 | fail: | ||
165 | #else | ||
166 | /* Enable the CPU clock. */ | ||
79 | reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX); | 167 | reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX); |
80 | writel(reg & ~(1<<9), CLK_RST_CONTROLLER_CLK_CPU_CMPLX); | 168 | writel(reg & ~CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX); |
169 | barrier(); | ||
170 | reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX); | ||
171 | #endif | ||
172 | /* Clear flow controller CSR. */ | ||
173 | flowctrl_writel(0, FLOW_CTRL_CPU_CSR(cpu)); | ||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | void __cpuinit platform_secondary_init(unsigned int cpu) | ||
178 | { | ||
179 | gic_secondary_init(0); | ||
81 | 180 | ||
82 | reg = (1<<13) | (1<<9) | (1<<5) | (1<<1); | 181 | cpumask_set_cpu(cpu, to_cpumask(tegra_cpu_init_bits)); |
83 | writel(reg, CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR); | 182 | if (!tegra_all_cpus_booted) |
183 | if (cpumask_equal(tegra_cpu_init_mask, cpu_present_mask)) | ||
184 | tegra_all_cpus_booted = true; | ||
185 | } | ||
84 | 186 | ||
85 | smp_wmb(); | 187 | int boot_secondary(unsigned int cpu, struct task_struct *idle) |
86 | flush_cache_all(); | 188 | { |
189 | int status; | ||
190 | |||
191 | /* Avoid timer calibration on slave cpus. Use the value calibrated | ||
192 | * on master cpu. This reduces the bringup time for each slave cpu | ||
193 | * by around 260ms. | ||
194 | */ | ||
195 | preset_lpj = loops_per_jiffy; | ||
196 | if (is_lp_cluster()) { | ||
197 | struct clk *cpu_clk, *cpu_g_clk; | ||
198 | |||
199 | /* The G CPU may not be available for a variety of reasons. */ | ||
200 | status = is_g_cluster_available(cpu); | ||
201 | if (status) | ||
202 | goto done; | ||
87 | 203 | ||
88 | /* unhalt the cpu */ | 204 | cpu_clk = tegra_get_clock_by_name("cpu"); |
89 | writel(0, IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + 0x14); | 205 | cpu_g_clk = tegra_get_clock_by_name("cpu_g"); |
90 | 206 | ||
91 | timeout = jiffies + (1 * HZ); | 207 | /* Switch to G CPU before continuing. */ |
92 | while (time_before(jiffies, timeout)) { | 208 | if (!cpu_clk || !cpu_g_clk) { |
93 | if (readl(EVP_CPU_RESET_VECTOR) != boot_vector) | 209 | /* Early boot, clock infrastructure is not initialized |
94 | break; | 210 | - CPU mode switch is not allowed */ |
95 | udelay(10); | 211 | status = -EINVAL; |
212 | } else | ||
213 | status = clk_set_parent(cpu_clk, cpu_g_clk); | ||
214 | |||
215 | if (status) | ||
216 | goto done; | ||
96 | } | 217 | } |
97 | 218 | ||
98 | /* put the old boot vector back */ | 219 | smp_wmb(); |
99 | writel(old_boot_vector, EVP_CPU_RESET_VECTOR); | ||
100 | 220 | ||
101 | /* | 221 | /* Force the CPU into reset. The CPU must remain in reset when the |
102 | * now the secondary core is starting up let it run its | 222 | flow controller state is cleared (which will cause the flow |
103 | * calibrations, then wait for it to finish | 223 | controller to stop driving reset if the CPU has been power-gated |
104 | */ | 224 | via the flow controller). This will have no effect on first boot |
105 | spin_unlock(&boot_lock); | 225 | of the CPU since it should already be in reset. */ |
226 | writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); | ||
227 | dmb(); | ||
106 | 228 | ||
107 | return 0; | 229 | /* Unhalt the CPU. If the flow controller was used to power-gate the |
230 | CPU this will cause the flow controller to stop driving reset. | ||
231 | The CPU will remain in reset because the clock and reset block | ||
232 | is now driving reset. */ | ||
233 | flowctrl_writel(0, FLOW_CTRL_HALT_CPU(cpu)); | ||
234 | |||
235 | status = power_up_cpu(cpu); | ||
236 | if (status) | ||
237 | goto done; | ||
238 | |||
239 | /* Take the CPU out of reset. */ | ||
240 | writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR); | ||
241 | wmb(); | ||
242 | done: | ||
243 | return status; | ||
108 | } | 244 | } |
109 | 245 | ||
110 | /* | 246 | /* |
@@ -113,30 +249,51 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) | |||
113 | */ | 249 | */ |
114 | void __init smp_init_cpus(void) | 250 | void __init smp_init_cpus(void) |
115 | { | 251 | { |
116 | unsigned int i, ncores = scu_get_core_count(scu_base); | 252 | unsigned int ncores = available_cpus(); |
253 | unsigned int i; | ||
117 | 254 | ||
118 | if (ncores > NR_CPUS) { | 255 | if (ncores > nr_cpu_ids) { |
119 | printk(KERN_ERR "Tegra: no. of cores (%u) greater than configured (%u), clipping\n", | 256 | pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", |
120 | ncores, NR_CPUS); | 257 | ncores, nr_cpu_ids); |
121 | ncores = NR_CPUS; | 258 | ncores = nr_cpu_ids; |
122 | } | 259 | } |
123 | 260 | ||
124 | for (i = 0; i < ncores; i++) | 261 | for (i = 0; i < ncores; i++) |
125 | cpu_set(i, cpu_possible_map); | 262 | set_cpu_possible(i, true); |
263 | |||
264 | /* If only one CPU is possible, platform_smp_prepare_cpus() will | ||
265 | never get called. We must therefore initialize the reset handler | ||
266 | here. If there is more than one CPU, we must wait until after | ||
267 | the cpu_present_mask has been updated with all present CPUs in | ||
268 | platform_smp_prepare_cpus() before initializing the reset handler. */ | ||
269 | if (ncores == 1) { | ||
270 | tegra_cpu_reset_handler_init(); | ||
271 | tegra_all_cpus_booted = true; | ||
272 | } | ||
126 | 273 | ||
127 | set_smp_cross_call(gic_raise_softirq); | 274 | set_smp_cross_call(gic_raise_softirq); |
128 | } | 275 | } |
129 | 276 | ||
130 | void __init platform_smp_prepare_cpus(unsigned int max_cpus) | 277 | void __init platform_smp_prepare_cpus(unsigned int max_cpus) |
131 | { | 278 | { |
132 | int i; | ||
133 | 279 | ||
134 | /* | 280 | /* Always mark the boot CPU as initialized. */ |
135 | * Initialise the present map, which describes the set of CPUs | 281 | cpumask_set_cpu(0, to_cpumask(tegra_cpu_init_bits)); |
136 | * actually populated at the present time. | ||
137 | */ | ||
138 | for (i = 0; i < max_cpus; i++) | ||
139 | set_cpu_present(i, true); | ||
140 | 282 | ||
283 | if (max_cpus == 1) | ||
284 | tegra_all_cpus_booted = true; | ||
285 | |||
286 | /* If we're here, it means that more than one CPU was found by | ||
287 | smp_init_cpus() which also means that it did not initialize the | ||
288 | reset handler. Do it now before the secondary CPUs are started. */ | ||
289 | tegra_cpu_reset_handler_init(); | ||
290 | |||
291 | #if defined(CONFIG_HAVE_ARM_SCU) | ||
292 | { | ||
293 | u32 scu_ctrl = __raw_readl(scu_base) | 1 << 3; | ||
294 | if (!(scu_ctrl & 1)) | ||
295 | __raw_writel(scu_ctrl, scu_base); | ||
296 | } | ||
297 | #endif | ||
141 | scu_enable(scu_base); | 298 | scu_enable(scu_base); |
142 | } | 299 | } |