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