1 | // SPDX-License-Identifier: GPL-2.0-only |
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 |
10 | */ |
11 | |
12 | #include <linux/clk/tegra.h> |
13 | #include <linux/delay.h> |
14 | #include <linux/device.h> |
15 | #include <linux/errno.h> |
16 | #include <linux/init.h> |
17 | #include <linux/io.h> |
18 | #include <linux/jiffies.h> |
19 | #include <linux/smp.h> |
20 | |
21 | #include <soc/tegra/flowctrl.h> |
22 | #include <soc/tegra/fuse.h> |
23 | #include <soc/tegra/pmc.h> |
24 | |
25 | #include <asm/cacheflush.h> |
26 | #include <asm/mach-types.h> |
27 | #include <asm/smp_plat.h> |
28 | #include <asm/smp_scu.h> |
29 | |
30 | #include "common.h" |
31 | #include "iomap.h" |
32 | #include "reset.h" |
33 | |
34 | static cpumask_t tegra_cpu_init_mask; |
35 | |
36 | static void tegra_secondary_init(unsigned int cpu) |
37 | { |
38 | cpumask_set_cpu(cpu, dstp: &tegra_cpu_init_mask); |
39 | } |
40 | |
41 | |
42 | static int tegra20_boot_secondary(unsigned int cpu, struct task_struct *idle) |
43 | { |
44 | cpu = cpu_logical_map(cpu); |
45 | |
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); |
55 | |
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(cpuid: cpu, value: 0); |
63 | |
64 | tegra_enable_cpu_clock(cpu); |
65 | flowctrl_write_cpu_csr(cpuid: cpu, value: 0); /* Clear flow controller CSR. */ |
66 | tegra_cpu_out_of_reset(cpu); |
67 | return 0; |
68 | } |
69 | |
70 | static int tegra30_boot_secondary(unsigned int cpu, struct task_struct *idle) |
71 | { |
72 | int ret; |
73 | unsigned long timeout; |
74 | |
75 | cpu = cpu_logical_map(cpu); |
76 | tegra_put_cpu_in_reset(cpu); |
77 | flowctrl_write_cpu_halt(cpuid: cpu, value: 0); |
78 | |
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 confirmation 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 |
90 | * tegra_cpu_init_mask which influences what tegra30_boot_secondary() |
91 | * next time around. |
92 | */ |
93 | if (cpumask_test_cpu(cpu, cpumask: &tegra_cpu_init_mask)) { |
94 | timeout = jiffies + msecs_to_jiffies(m: 50); |
95 | do { |
96 | if (tegra_pmc_cpu_is_powered(cpuid: cpu)) |
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 | */ |
108 | ret = tegra_pmc_cpu_power_on(cpuid: cpu); |
109 | if (ret) |
110 | return ret; |
111 | |
112 | remove_clamps: |
113 | /* CPU partition is powered. Enable the CPU clock. */ |
114 | tegra_enable_cpu_clock(cpu); |
115 | udelay(10); |
116 | |
117 | /* Remove I/O clamps. */ |
118 | ret = tegra_pmc_cpu_remove_clamping(cpuid: cpu); |
119 | if (ret) |
120 | return ret; |
121 | |
122 | udelay(10); |
123 | |
124 | flowctrl_write_cpu_csr(cpuid: cpu, value: 0); /* Clear flow controller CSR. */ |
125 | tegra_cpu_out_of_reset(cpu); |
126 | return 0; |
127 | } |
128 | |
129 | static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle) |
130 | { |
131 | int ret = 0; |
132 | |
133 | cpu = cpu_logical_map(cpu); |
134 | |
135 | if (cpumask_test_cpu(cpu, cpumask: &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(cpuid: cpu, value: 1); |
143 | flowctrl_write_cpu_halt(cpuid: 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(cpuid: cpu); |
153 | } |
154 | |
155 | return ret; |
156 | } |
157 | |
158 | static int tegra_boot_secondary(unsigned int cpu, |
159 | struct task_struct *idle) |
160 | { |
161 | if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_get_chip_id() == TEGRA20) |
162 | return tegra20_boot_secondary(cpu, idle); |
163 | if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_get_chip_id() == TEGRA30) |
164 | return tegra30_boot_secondary(cpu, idle); |
165 | if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_get_chip_id() == TEGRA114) |
166 | return tegra114_boot_secondary(cpu, idle); |
167 | if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_get_chip_id() == TEGRA124) |
168 | return tegra114_boot_secondary(cpu, idle); |
169 | |
170 | return -EINVAL; |
171 | } |
172 | |
173 | static void __init tegra_smp_prepare_cpus(unsigned int max_cpus) |
174 | { |
175 | /* Always mark the boot CPU (CPU0) as initialized. */ |
176 | cpumask_set_cpu(cpu: 0, dstp: &tegra_cpu_init_mask); |
177 | |
178 | if (scu_a9_has_base()) |
179 | scu_enable(IO_ADDRESS(scu_a9_get_base())); |
180 | } |
181 | |
182 | const struct smp_operations tegra_smp_ops __initconst = { |
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 |
187 | .cpu_kill = tegra_cpu_kill, |
188 | .cpu_die = tegra_cpu_die, |
189 | #endif |
190 | }; |
191 | |