1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/clk/tegra.h>
16#include <linux/delay.h>
17#include <linux/device.h>
18#include <linux/errno.h>
19#include <linux/init.h>
20#include <linux/io.h>
21#include <linux/jiffies.h>
22#include <linux/smp.h>
23
24#include <soc/tegra/fuse.h>
25#include <soc/tegra/pmc.h>
26
27#include <asm/cacheflush.h>
28#include <asm/mach-types.h>
29#include <asm/smp_plat.h>
30#include <asm/smp_scu.h>
31
32#include "common.h"
33#include "flowctrl.h"
34#include "iomap.h"
35#include "reset.h"
36
37static cpumask_t tegra_cpu_init_mask;
38
39static void tegra_secondary_init(unsigned int cpu)
40{
41 cpumask_set_cpu(cpu, &tegra_cpu_init_mask);
42}
43
44
45static int tegra20_boot_secondary(unsigned int cpu, struct task_struct *idle)
46{
47 cpu = cpu_logical_map(cpu);
48
49
50
51
52
53
54
55
56
57 tegra_put_cpu_in_reset(cpu);
58
59
60
61
62
63
64
65 flowctrl_write_cpu_halt(cpu, 0);
66
67 tegra_enable_cpu_clock(cpu);
68 flowctrl_write_cpu_csr(cpu, 0);
69 tegra_cpu_out_of_reset(cpu);
70 return 0;
71}
72
73static int tegra30_boot_secondary(unsigned int cpu, struct task_struct *idle)
74{
75 int ret;
76 unsigned long timeout;
77
78 cpu = cpu_logical_map(cpu);
79 tegra_put_cpu_in_reset(cpu);
80 flowctrl_write_cpu_halt(cpu, 0);
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96 if (cpumask_test_cpu(cpu, &tegra_cpu_init_mask)) {
97 timeout = jiffies + msecs_to_jiffies(50);
98 do {
99 if (tegra_pmc_cpu_is_powered(cpu))
100 goto remove_clamps;
101 udelay(10);
102 } while (time_before(jiffies, timeout));
103 }
104
105
106
107
108
109
110
111 ret = tegra_pmc_cpu_power_on(cpu);
112 if (ret)
113 return ret;
114
115remove_clamps:
116
117 tegra_enable_cpu_clock(cpu);
118 udelay(10);
119
120
121 ret = tegra_pmc_cpu_remove_clamping(cpu);
122 if (ret)
123 return ret;
124
125 udelay(10);
126
127 flowctrl_write_cpu_csr(cpu, 0);
128 tegra_cpu_out_of_reset(cpu);
129 return 0;
130}
131
132static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle)
133{
134 int ret = 0;
135
136 cpu = cpu_logical_map(cpu);
137
138 if (cpumask_test_cpu(cpu, &tegra_cpu_init_mask)) {
139
140
141
142
143
144
145 flowctrl_write_cpu_csr(cpu, 1);
146 flowctrl_write_cpu_halt(cpu,
147 FLOW_CTRL_WAITEVENT | FLOW_CTRL_SCLK_RESUME);
148 } else {
149
150
151
152
153
154
155 ret = tegra_pmc_cpu_power_on(cpu);
156 }
157
158 return ret;
159}
160
161static int tegra_boot_secondary(unsigned int cpu,
162 struct task_struct *idle)
163{
164 if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_get_chip_id() == TEGRA20)
165 return tegra20_boot_secondary(cpu, idle);
166 if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_get_chip_id() == TEGRA30)
167 return tegra30_boot_secondary(cpu, idle);
168 if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_get_chip_id() == TEGRA114)
169 return tegra114_boot_secondary(cpu, idle);
170 if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_get_chip_id() == TEGRA124)
171 return tegra114_boot_secondary(cpu, idle);
172
173 return -EINVAL;
174}
175
176static void __init tegra_smp_prepare_cpus(unsigned int max_cpus)
177{
178
179 cpumask_set_cpu(0, &tegra_cpu_init_mask);
180
181 if (scu_a9_has_base())
182 scu_enable(IO_ADDRESS(scu_a9_get_base()));
183}
184
185const struct smp_operations tegra_smp_ops __initconst = {
186 .smp_prepare_cpus = tegra_smp_prepare_cpus,
187 .smp_secondary_init = tegra_secondary_init,
188 .smp_boot_secondary = tegra_boot_secondary,
189#ifdef CONFIG_HOTPLUG_CPU
190 .cpu_kill = tegra_cpu_kill,
191 .cpu_die = tegra_cpu_die,
192#endif
193};
194