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