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 | */ | |
a0524acc TR |
14 | |
15 | #include <linux/clk/tegra.h> | |
1cea7326 CC |
16 | #include <linux/delay.h> |
17 | #include <linux/device.h> | |
a0524acc TR |
18 | #include <linux/errno.h> |
19 | #include <linux/init.h> | |
20 | #include <linux/io.h> | |
1cea7326 CC |
21 | #include <linux/jiffies.h> |
22 | #include <linux/smp.h> | |
1cea7326 | 23 | |
304664ea | 24 | #include <soc/tegra/fuse.h> |
7232398a | 25 | #include <soc/tegra/pmc.h> |
304664ea | 26 | |
1cea7326 | 27 | #include <asm/cacheflush.h> |
1cea7326 | 28 | #include <asm/mach-types.h> |
130bfed7 | 29 | #include <asm/smp_plat.h> |
a0524acc | 30 | #include <asm/smp_scu.h> |
b36ab975 | 31 | |
a1725732 | 32 | #include "common.h" |
a0524acc | 33 | #include "flowctrl.h" |
2be39c07 | 34 | #include "iomap.h" |
a0524acc | 35 | #include "reset.h" |
a1725732 | 36 | |
130bfed7 | 37 | static cpumask_t tegra_cpu_init_mask; |
1cea7326 | 38 | |
8bd26e3a | 39 | static void tegra_secondary_init(unsigned int cpu) |
1cea7326 | 40 | { |
130bfed7 | 41 | cpumask_set_cpu(cpu, &tegra_cpu_init_mask); |
1cea7326 CC |
42 | } |
43 | ||
0d1f79b0 HD |
44 | |
45 | static int tegra20_boot_secondary(unsigned int cpu, struct task_struct *idle) | |
1cea7326 | 46 | { |
0d1f79b0 | 47 | cpu = cpu_logical_map(cpu); |
1cea7326 | 48 | |
0d1f79b0 HD |
49 | /* |
50 | * Force the CPU into reset. The CPU must remain in reset when | |
51 | * the flow controller state is cleared (which will cause the | |
52 | * flow controller to stop driving reset if the CPU has been | |
53 | * power-gated via the flow controller). This will have no | |
54 | * effect on first boot of the CPU since it should already be | |
55 | * in reset. | |
56 | */ | |
57 | tegra_put_cpu_in_reset(cpu); | |
1cea7326 | 58 | |
0d1f79b0 HD |
59 | /* |
60 | * Unhalt the CPU. If the flow controller was used to | |
61 | * power-gate the CPU this will cause the flow controller to | |
62 | * stop driving reset. The CPU will remain in reset because the | |
63 | * clock and reset block is now driving reset. | |
64 | */ | |
65 | flowctrl_write_cpu_halt(cpu, 0); | |
66 | ||
67 | tegra_enable_cpu_clock(cpu); | |
68 | flowctrl_write_cpu_csr(cpu, 0); /* Clear flow controller CSR. */ | |
69 | tegra_cpu_out_of_reset(cpu); | |
b36ab975 PDS |
70 | return 0; |
71 | } | |
1cea7326 | 72 | |
0d1f79b0 | 73 | static int tegra30_boot_secondary(unsigned int cpu, struct task_struct *idle) |
86e51a2e | 74 | { |
7e564744 | 75 | int ret; |
86e51a2e PDS |
76 | unsigned long timeout; |
77 | ||
0d1f79b0 | 78 | cpu = cpu_logical_map(cpu); |
0d1f79b0 HD |
79 | tegra_put_cpu_in_reset(cpu); |
80 | flowctrl_write_cpu_halt(cpu, 0); | |
81 | ||
130bfed7 JL |
82 | /* |
83 | * The power up sequence of cold boot CPU and warm boot CPU | |
84 | * was different. | |
85 | * | |
86 | * For warm boot CPU that was resumed from CPU hotplug, the | |
87 | * power will be resumed automatically after un-halting the | |
88 | * flow controller of the warm boot CPU. We need to wait for | |
89 | * the confirmaiton that the CPU is powered then removing | |
90 | * the IO clamps. | |
91 | * For cold boot CPU, do not wait. After the cold boot CPU be | |
92 | * booted, it will run to tegra_secondary_init() and set | |
0d1f79b0 | 93 | * tegra_cpu_init_mask which influences what tegra30_boot_secondary() |
130bfed7 JL |
94 | * next time around. |
95 | */ | |
96 | if (cpumask_test_cpu(cpu, &tegra_cpu_init_mask)) { | |
1395868c | 97 | timeout = jiffies + msecs_to_jiffies(50); |
130bfed7 | 98 | do { |
7e564744 | 99 | if (tegra_pmc_cpu_is_powered(cpu)) |
130bfed7 JL |
100 | goto remove_clamps; |
101 | udelay(10); | |
102 | } while (time_before(jiffies, timeout)); | |
103 | } | |
104 | ||
105 | /* | |
106 | * The power status of the cold boot CPU is power gated as | |
107 | * default. To power up the cold boot CPU, the power should | |
108 | * be un-gated by un-toggling the power gate register | |
109 | * manually. | |
110 | */ | |
7e564744 JL |
111 | if (!tegra_pmc_cpu_is_powered(cpu)) { |
112 | ret = tegra_pmc_cpu_power_on(cpu); | |
86e51a2e PDS |
113 | if (ret) |
114 | return ret; | |
115 | ||
116 | /* Wait for the power to come up. */ | |
1395868c | 117 | timeout = jiffies + msecs_to_jiffies(100); |
5f809932 | 118 | while (!tegra_pmc_cpu_is_powered(cpu)) { |
86e51a2e PDS |
119 | if (time_after(jiffies, timeout)) |
120 | return -ETIMEDOUT; | |
121 | udelay(10); | |
122 | } | |
123 | } | |
124 | ||
130bfed7 | 125 | remove_clamps: |
86e51a2e | 126 | /* CPU partition is powered. Enable the CPU clock. */ |
bb603277 | 127 | tegra_enable_cpu_clock(cpu); |
86e51a2e PDS |
128 | udelay(10); |
129 | ||
130 | /* Remove I/O clamps. */ | |
7e564744 | 131 | ret = tegra_pmc_cpu_remove_clamping(cpu); |
b4c25cc3 HD |
132 | if (ret) |
133 | return ret; | |
134 | ||
86e51a2e PDS |
135 | udelay(10); |
136 | ||
0d1f79b0 HD |
137 | flowctrl_write_cpu_csr(cpu, 0); /* Clear flow controller CSR. */ |
138 | tegra_cpu_out_of_reset(cpu); | |
86e51a2e PDS |
139 | return 0; |
140 | } | |
141 | ||
e562b865 JL |
142 | static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle) |
143 | { | |
18901e9f JL |
144 | int ret = 0; |
145 | ||
e562b865 | 146 | cpu = cpu_logical_map(cpu); |
18901e9f JL |
147 | |
148 | if (cpumask_test_cpu(cpu, &tegra_cpu_init_mask)) { | |
149 | /* | |
150 | * Warm boot flow | |
151 | * The flow controller in charge of the power state and | |
152 | * control for each CPU. | |
153 | */ | |
154 | /* set SCLK as event trigger for flow controller */ | |
155 | flowctrl_write_cpu_csr(cpu, 1); | |
156 | flowctrl_write_cpu_halt(cpu, | |
157 | FLOW_CTRL_WAITEVENT | FLOW_CTRL_SCLK_RESUME); | |
158 | } else { | |
159 | /* | |
160 | * Cold boot flow | |
161 | * The CPU is powered up by toggling PMC directly. It will | |
162 | * also initial power state in flow controller. After that, | |
163 | * the CPU's power state is maintained by flow controller. | |
164 | */ | |
165 | ret = tegra_pmc_cpu_power_on(cpu); | |
166 | } | |
167 | ||
168 | return ret; | |
e562b865 JL |
169 | } |
170 | ||
8bd26e3a | 171 | static int tegra_boot_secondary(unsigned int cpu, |
0d1f79b0 | 172 | struct task_struct *idle) |
b36ab975 | 173 | { |
304664ea | 174 | if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_get_chip_id() == TEGRA20) |
0d1f79b0 | 175 | return tegra20_boot_secondary(cpu, idle); |
304664ea | 176 | if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_get_chip_id() == TEGRA30) |
0d1f79b0 | 177 | return tegra30_boot_secondary(cpu, idle); |
304664ea | 178 | if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_get_chip_id() == TEGRA114) |
e562b865 | 179 | return tegra114_boot_secondary(cpu, idle); |
304664ea | 180 | if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_get_chip_id() == TEGRA124) |
73944475 | 181 | return tegra114_boot_secondary(cpu, idle); |
1cea7326 | 182 | |
0d1f79b0 | 183 | return -EINVAL; |
1cea7326 CC |
184 | } |
185 | ||
a1725732 | 186 | static void __init tegra_smp_prepare_cpus(unsigned int max_cpus) |
1cea7326 | 187 | { |
130bfed7 JL |
188 | /* Always mark the boot CPU (CPU0) as initialized. */ |
189 | cpumask_set_cpu(0, &tegra_cpu_init_mask); | |
190 | ||
909444ab HD |
191 | if (scu_a9_has_base()) |
192 | scu_enable(IO_ADDRESS(scu_a9_get_base())); | |
1cea7326 | 193 | } |
a1725732 MZ |
194 | |
195 | struct smp_operations tegra_smp_ops __initdata = { | |
a1725732 MZ |
196 | .smp_prepare_cpus = tegra_smp_prepare_cpus, |
197 | .smp_secondary_init = tegra_secondary_init, | |
198 | .smp_boot_secondary = tegra_boot_secondary, | |
199 | #ifdef CONFIG_HOTPLUG_CPU | |
b8119431 | 200 | .cpu_kill = tegra_cpu_kill, |
a1725732 MZ |
201 | .cpu_die = tegra_cpu_die, |
202 | #endif | |
203 | }; |