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 | */ | |
0a2d87e0 JH |
111 | ret = tegra_pmc_cpu_power_on(cpu); |
112 | if (ret) | |
113 | return ret; | |
86e51a2e | 114 | |
130bfed7 | 115 | remove_clamps: |
86e51a2e | 116 | /* CPU partition is powered. Enable the CPU clock. */ |
bb603277 | 117 | tegra_enable_cpu_clock(cpu); |
86e51a2e PDS |
118 | udelay(10); |
119 | ||
120 | /* Remove I/O clamps. */ | |
7e564744 | 121 | ret = tegra_pmc_cpu_remove_clamping(cpu); |
b4c25cc3 HD |
122 | if (ret) |
123 | return ret; | |
124 | ||
86e51a2e PDS |
125 | udelay(10); |
126 | ||
0d1f79b0 HD |
127 | flowctrl_write_cpu_csr(cpu, 0); /* Clear flow controller CSR. */ |
128 | tegra_cpu_out_of_reset(cpu); | |
86e51a2e PDS |
129 | return 0; |
130 | } | |
131 | ||
e562b865 JL |
132 | static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle) |
133 | { | |
18901e9f JL |
134 | int ret = 0; |
135 | ||
e562b865 | 136 | cpu = cpu_logical_map(cpu); |
18901e9f JL |
137 | |
138 | if (cpumask_test_cpu(cpu, &tegra_cpu_init_mask)) { | |
139 | /* | |
140 | * Warm boot flow | |
141 | * The flow controller in charge of the power state and | |
142 | * control for each CPU. | |
143 | */ | |
144 | /* set SCLK as event trigger for flow controller */ | |
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 | * Cold boot flow | |
151 | * The CPU is powered up by toggling PMC directly. It will | |
152 | * also initial power state in flow controller. After that, | |
153 | * the CPU's power state is maintained by flow controller. | |
154 | */ | |
155 | ret = tegra_pmc_cpu_power_on(cpu); | |
156 | } | |
157 | ||
158 | return ret; | |
e562b865 JL |
159 | } |
160 | ||
8bd26e3a | 161 | static int tegra_boot_secondary(unsigned int cpu, |
0d1f79b0 | 162 | struct task_struct *idle) |
b36ab975 | 163 | { |
304664ea | 164 | if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_get_chip_id() == TEGRA20) |
0d1f79b0 | 165 | return tegra20_boot_secondary(cpu, idle); |
304664ea | 166 | if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_get_chip_id() == TEGRA30) |
0d1f79b0 | 167 | return tegra30_boot_secondary(cpu, idle); |
304664ea | 168 | if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_get_chip_id() == TEGRA114) |
e562b865 | 169 | return tegra114_boot_secondary(cpu, idle); |
304664ea | 170 | if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_get_chip_id() == TEGRA124) |
73944475 | 171 | return tegra114_boot_secondary(cpu, idle); |
1cea7326 | 172 | |
0d1f79b0 | 173 | return -EINVAL; |
1cea7326 CC |
174 | } |
175 | ||
a1725732 | 176 | static void __init tegra_smp_prepare_cpus(unsigned int max_cpus) |
1cea7326 | 177 | { |
130bfed7 JL |
178 | /* Always mark the boot CPU (CPU0) as initialized. */ |
179 | cpumask_set_cpu(0, &tegra_cpu_init_mask); | |
180 | ||
909444ab HD |
181 | if (scu_a9_has_base()) |
182 | scu_enable(IO_ADDRESS(scu_a9_get_base())); | |
1cea7326 | 183 | } |
a1725732 | 184 | |
75305275 | 185 | const struct smp_operations tegra_smp_ops __initconst = { |
a1725732 MZ |
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 | |
b8119431 | 190 | .cpu_kill = tegra_cpu_kill, |
a1725732 MZ |
191 | .cpu_die = tegra_cpu_die, |
192 | #endif | |
193 | }; |