]>
Commit | Line | Data |
---|---|---|
1cea7326 CC |
1 | /* |
2 | * linux/arch/arm/mach-tegra/platsmp.c | |
3 | * | |
4 | * Copyright (C) 2002 ARM Ltd. | |
5 | * All Rights Reserved | |
6 | * | |
7 | * Copyright (C) 2009 Palm | |
8 | * All Rights Reserved | |
9 | * | |
10 | * 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 | |
12 | * published by the Free Software Foundation. | |
13 | */ | |
14 | #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> | |
520f7bd7 | 21 | #include <linux/irqchip/arm-gic.h> |
89572c77 | 22 | #include <linux/clk/tegra.h> |
1cea7326 CC |
23 | |
24 | #include <asm/cacheflush.h> | |
1cea7326 | 25 | #include <asm/mach-types.h> |
1cea7326 | 26 | #include <asm/smp_scu.h> |
130bfed7 | 27 | #include <asm/smp_plat.h> |
1cea7326 | 28 | |
86e51a2e | 29 | #include <mach/powergate.h> |
1cea7326 | 30 | |
b36ab975 PDS |
31 | #include "fuse.h" |
32 | #include "flowctrl.h" | |
33 | #include "reset.h" | |
34 | ||
a1725732 | 35 | #include "common.h" |
2be39c07 | 36 | #include "iomap.h" |
a1725732 | 37 | |
130bfed7 | 38 | static cpumask_t tegra_cpu_init_mask; |
1cea7326 | 39 | |
a1725732 | 40 | static void __cpuinit tegra_secondary_init(unsigned int cpu) |
1cea7326 | 41 | { |
1cea7326 CC |
42 | /* |
43 | * if any interrupts are already enabled for the primary | |
44 | * core (e.g. timer irq), then they will not have been enabled | |
45 | * for us: do so | |
46 | */ | |
38489533 | 47 | gic_secondary_init(0); |
1cea7326 | 48 | |
130bfed7 | 49 | cpumask_set_cpu(cpu, &tegra_cpu_init_mask); |
1cea7326 CC |
50 | } |
51 | ||
0d1f79b0 HD |
52 | |
53 | static int tegra20_boot_secondary(unsigned int cpu, struct task_struct *idle) | |
1cea7326 | 54 | { |
0d1f79b0 | 55 | cpu = cpu_logical_map(cpu); |
1cea7326 | 56 | |
0d1f79b0 HD |
57 | /* |
58 | * Force the CPU into reset. The CPU must remain in reset when | |
59 | * the flow controller state is cleared (which will cause the | |
60 | * flow controller to stop driving reset if the CPU has been | |
61 | * power-gated via the flow controller). This will have no | |
62 | * effect on first boot of the CPU since it should already be | |
63 | * in reset. | |
64 | */ | |
65 | tegra_put_cpu_in_reset(cpu); | |
1cea7326 | 66 | |
0d1f79b0 HD |
67 | /* |
68 | * Unhalt the CPU. If the flow controller was used to | |
69 | * power-gate the CPU this will cause the flow controller to | |
70 | * stop driving reset. The CPU will remain in reset because the | |
71 | * clock and reset block is now driving reset. | |
72 | */ | |
73 | flowctrl_write_cpu_halt(cpu, 0); | |
74 | ||
75 | tegra_enable_cpu_clock(cpu); | |
76 | flowctrl_write_cpu_csr(cpu, 0); /* Clear flow controller CSR. */ | |
77 | tegra_cpu_out_of_reset(cpu); | |
b36ab975 PDS |
78 | return 0; |
79 | } | |
1cea7326 | 80 | |
0d1f79b0 | 81 | static int tegra30_boot_secondary(unsigned int cpu, struct task_struct *idle) |
86e51a2e | 82 | { |
86e51a2e PDS |
83 | int ret, pwrgateid; |
84 | unsigned long timeout; | |
85 | ||
0d1f79b0 | 86 | cpu = cpu_logical_map(cpu); |
86e51a2e PDS |
87 | pwrgateid = tegra_cpu_powergate_id(cpu); |
88 | if (pwrgateid < 0) | |
89 | return pwrgateid; | |
90 | ||
0d1f79b0 HD |
91 | tegra_put_cpu_in_reset(cpu); |
92 | flowctrl_write_cpu_halt(cpu, 0); | |
93 | ||
130bfed7 JL |
94 | /* |
95 | * The power up sequence of cold boot CPU and warm boot CPU | |
96 | * was different. | |
97 | * | |
98 | * For warm boot CPU that was resumed from CPU hotplug, the | |
99 | * power will be resumed automatically after un-halting the | |
100 | * flow controller of the warm boot CPU. We need to wait for | |
101 | * the confirmaiton that the CPU is powered then removing | |
102 | * the IO clamps. | |
103 | * For cold boot CPU, do not wait. After the cold boot CPU be | |
104 | * booted, it will run to tegra_secondary_init() and set | |
0d1f79b0 | 105 | * tegra_cpu_init_mask which influences what tegra30_boot_secondary() |
130bfed7 JL |
106 | * next time around. |
107 | */ | |
108 | if (cpumask_test_cpu(cpu, &tegra_cpu_init_mask)) { | |
1395868c | 109 | timeout = jiffies + msecs_to_jiffies(50); |
130bfed7 | 110 | do { |
2be8951e | 111 | if (tegra_powergate_is_powered(pwrgateid)) |
130bfed7 JL |
112 | goto remove_clamps; |
113 | udelay(10); | |
114 | } while (time_before(jiffies, timeout)); | |
115 | } | |
116 | ||
117 | /* | |
118 | * The power status of the cold boot CPU is power gated as | |
119 | * default. To power up the cold boot CPU, the power should | |
120 | * be un-gated by un-toggling the power gate register | |
121 | * manually. | |
122 | */ | |
86e51a2e PDS |
123 | if (!tegra_powergate_is_powered(pwrgateid)) { |
124 | ret = tegra_powergate_power_on(pwrgateid); | |
125 | if (ret) | |
126 | return ret; | |
127 | ||
128 | /* Wait for the power to come up. */ | |
1395868c | 129 | timeout = jiffies + msecs_to_jiffies(100); |
86e51a2e PDS |
130 | while (tegra_powergate_is_powered(pwrgateid)) { |
131 | if (time_after(jiffies, timeout)) | |
132 | return -ETIMEDOUT; | |
133 | udelay(10); | |
134 | } | |
135 | } | |
136 | ||
130bfed7 | 137 | remove_clamps: |
86e51a2e | 138 | /* CPU partition is powered. Enable the CPU clock. */ |
bb603277 | 139 | tegra_enable_cpu_clock(cpu); |
86e51a2e PDS |
140 | udelay(10); |
141 | ||
142 | /* Remove I/O clamps. */ | |
143 | ret = tegra_powergate_remove_clamping(pwrgateid); | |
b4c25cc3 HD |
144 | if (ret) |
145 | return ret; | |
146 | ||
86e51a2e PDS |
147 | udelay(10); |
148 | ||
0d1f79b0 HD |
149 | flowctrl_write_cpu_csr(cpu, 0); /* Clear flow controller CSR. */ |
150 | tegra_cpu_out_of_reset(cpu); | |
86e51a2e PDS |
151 | return 0; |
152 | } | |
153 | ||
0d1f79b0 HD |
154 | static int __cpuinit tegra_boot_secondary(unsigned int cpu, |
155 | struct task_struct *idle) | |
b36ab975 | 156 | { |
0d1f79b0 HD |
157 | if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_chip_id == TEGRA20) |
158 | return tegra20_boot_secondary(cpu, idle); | |
159 | if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_chip_id == TEGRA30) | |
160 | return tegra30_boot_secondary(cpu, idle); | |
1cea7326 | 161 | |
0d1f79b0 | 162 | return -EINVAL; |
1cea7326 CC |
163 | } |
164 | ||
a1725732 | 165 | static void __init tegra_smp_prepare_cpus(unsigned int max_cpus) |
1cea7326 | 166 | { |
130bfed7 JL |
167 | /* Always mark the boot CPU (CPU0) as initialized. */ |
168 | cpumask_set_cpu(0, &tegra_cpu_init_mask); | |
169 | ||
909444ab HD |
170 | if (scu_a9_has_base()) |
171 | scu_enable(IO_ADDRESS(scu_a9_get_base())); | |
1cea7326 | 172 | } |
a1725732 MZ |
173 | |
174 | struct smp_operations tegra_smp_ops __initdata = { | |
a1725732 MZ |
175 | .smp_prepare_cpus = tegra_smp_prepare_cpus, |
176 | .smp_secondary_init = tegra_secondary_init, | |
177 | .smp_boot_secondary = tegra_boot_secondary, | |
178 | #ifdef CONFIG_HOTPLUG_CPU | |
b8119431 | 179 | .cpu_kill = tegra_cpu_kill, |
a1725732 | 180 | .cpu_die = tegra_cpu_die, |
25468fe8 | 181 | .cpu_disable = tegra_cpu_disable, |
a1725732 MZ |
182 | #endif |
183 | }; |