aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/platsmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/platsmp.c')
-rw-r--r--arch/arm/mach-tegra/platsmp.c299
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
30extern void tegra_secondary_startup(void); 31#include "pm.h"
32#include "clock.h"
33#include "reset.h"
34#include "sleep.h"
31 35
32static DEFINE_SPINLOCK(boot_lock); 36bool tegra_all_cpus_booted;
33static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE); 37
38static DECLARE_BITMAP(tegra_cpu_init_bits, CONFIG_NR_CPUS) __read_mostly;
39const 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
42void __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
60static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE);
61
62static 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
58int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) 79static 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
103static 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
112static 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); 155remove_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);
164fail:
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
177void __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(); 187int 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();
242done:
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 */
114void __init smp_init_cpus(void) 250void __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
130void __init platform_smp_prepare_cpus(unsigned int max_cpus) 277void __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}