Commit | Line | Data |
---|---|---|
9a5a110e AE |
1 | /* |
2 | * Copyright (C) 2014 Broadcom Corporation | |
3 | * Copyright 2014 Linaro Limited | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or | |
6 | * modify it under the terms of the GNU General Public License as | |
7 | * published by the Free Software Foundation version 2. | |
8 | * | |
9 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | |
10 | * kind, whether express or implied; without even the implied warranty | |
11 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | */ | |
14 | ||
15 | #include <linux/init.h> | |
16 | #include <linux/errno.h> | |
17 | #include <linux/io.h> | |
18 | #include <linux/of.h> | |
19 | #include <linux/sched.h> | |
20 | ||
21 | #include <asm/smp.h> | |
22 | #include <asm/smp_plat.h> | |
23 | #include <asm/smp_scu.h> | |
24 | ||
25 | /* Size of mapped Cortex A9 SCU address space */ | |
26 | #define CORTEX_A9_SCU_SIZE 0x58 | |
27 | ||
28 | #define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */ | |
29 | #define BOOT_ADDR_CPUID_MASK 0x3 | |
30 | ||
31 | /* Name of device node property defining secondary boot register location */ | |
32 | #define OF_SECONDARY_BOOT "secondary-boot-reg" | |
33 | ||
34 | /* I/O address of register used to coordinate secondary core startup */ | |
35 | static u32 secondary_boot; | |
36 | ||
37 | /* | |
38 | * Enable the Cortex A9 Snoop Control Unit | |
39 | * | |
40 | * By the time this is called we already know there are multiple | |
41 | * cores present. We assume we're running on a Cortex A9 processor, | |
42 | * so any trouble getting the base address register or getting the | |
43 | * SCU base is a problem. | |
44 | * | |
45 | * Return 0 if successful or an error code otherwise. | |
46 | */ | |
47 | static int __init scu_a9_enable(void) | |
48 | { | |
49 | unsigned long config_base; | |
50 | void __iomem *scu_base; | |
51 | ||
52 | if (!scu_a9_has_base()) { | |
53 | pr_err("no configuration base address register!\n"); | |
54 | return -ENXIO; | |
55 | } | |
56 | ||
57 | /* Config base address register value is zero for uniprocessor */ | |
58 | config_base = scu_a9_get_base(); | |
59 | if (!config_base) { | |
60 | pr_err("hardware reports only one core\n"); | |
61 | return -ENOENT; | |
62 | } | |
63 | ||
64 | scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE); | |
65 | if (!scu_base) { | |
66 | pr_err("failed to remap config base (%lu/%u) for SCU\n", | |
67 | config_base, CORTEX_A9_SCU_SIZE); | |
68 | return -ENOMEM; | |
69 | } | |
70 | ||
71 | scu_enable(scu_base); | |
72 | ||
73 | iounmap(scu_base); /* That's the last we'll need of this */ | |
74 | ||
75 | return 0; | |
76 | } | |
77 | ||
78 | static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) | |
79 | { | |
80 | static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; | |
81 | struct device_node *node; | |
82 | int ret; | |
83 | ||
84 | BUG_ON(secondary_boot); /* We're called only once */ | |
85 | ||
86 | /* | |
87 | * This function is only called via smp_ops->smp_prepare_cpu(). | |
88 | * That only happens if a "/cpus" device tree node exists | |
89 | * and has an "enable-method" property that selects the SMP | |
90 | * operations defined herein. | |
91 | */ | |
92 | node = of_find_node_by_path("/cpus"); | |
93 | BUG_ON(!node); | |
94 | ||
95 | /* | |
96 | * Our secondary enable method requires a "secondary-boot-reg" | |
97 | * property to specify a register address used to request the | |
98 | * ROM code boot a secondary code. If we have any trouble | |
99 | * getting this we fall back to uniprocessor mode. | |
100 | */ | |
101 | if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) { | |
102 | pr_err("%s: missing/invalid " OF_SECONDARY_BOOT " property\n", | |
103 | node->name); | |
104 | ret = -ENOENT; /* Arrange to disable SMP */ | |
105 | goto out; | |
106 | } | |
107 | ||
108 | /* | |
109 | * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is | |
110 | * returned, the SoC reported a uniprocessor configuration. | |
111 | * We bail on any other error. | |
112 | */ | |
113 | ret = scu_a9_enable(); | |
114 | out: | |
115 | of_node_put(node); | |
116 | if (ret) { | |
117 | /* Update the CPU present map to reflect uniprocessor mode */ | |
118 | BUG_ON(ret != -ENOENT); | |
119 | pr_warn("disabling SMP\n"); | |
120 | init_cpu_present(&only_cpu_0); | |
121 | } | |
122 | } | |
123 | ||
124 | /* | |
125 | * The ROM code has the secondary cores looping, waiting for an event. | |
126 | * When an event occurs each core examines the bottom two bits of the | |
127 | * secondary boot register. When a core finds those bits contain its | |
128 | * own core id, it performs initialization, including computing its boot | |
129 | * address by clearing the boot register value's bottom two bits. The | |
130 | * core signals that it is beginning its execution by writing its boot | |
131 | * address back to the secondary boot register, and finally jumps to | |
132 | * that address. | |
133 | * | |
134 | * So to start a core executing we need to: | |
135 | * - Encode the (hardware) CPU id with the bottom bits of the secondary | |
136 | * start address. | |
137 | * - Write that value into the secondary boot register. | |
138 | * - Generate an event to wake up the secondary CPU(s). | |
139 | * - Wait for the secondary boot register to be re-written, which | |
140 | * indicates the secondary core has started. | |
141 | */ | |
142 | static int bcm_boot_secondary(unsigned int cpu, struct task_struct *idle) | |
143 | { | |
144 | void __iomem *boot_reg; | |
145 | phys_addr_t boot_func; | |
146 | u64 start_clock; | |
147 | u32 cpu_id; | |
148 | u32 boot_val; | |
149 | bool timeout = false; | |
150 | ||
151 | cpu_id = cpu_logical_map(cpu); | |
152 | if (cpu_id & ~BOOT_ADDR_CPUID_MASK) { | |
153 | pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK); | |
154 | return -EINVAL; | |
155 | } | |
156 | ||
157 | if (!secondary_boot) { | |
158 | pr_err("required secondary boot register not specified\n"); | |
159 | return -EINVAL; | |
160 | } | |
161 | ||
162 | boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32)); | |
163 | if (!boot_reg) { | |
164 | pr_err("unable to map boot register for cpu %u\n", cpu_id); | |
165 | return -ENOSYS; | |
166 | } | |
167 | ||
168 | /* | |
169 | * Secondary cores will start in secondary_startup(), | |
170 | * defined in "arch/arm/kernel/head.S" | |
171 | */ | |
172 | boot_func = virt_to_phys(secondary_startup); | |
173 | BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK); | |
174 | BUG_ON(boot_func > (phys_addr_t)U32_MAX); | |
175 | ||
176 | /* The core to start is encoded in the low bits */ | |
177 | boot_val = (u32)boot_func | cpu_id; | |
178 | writel_relaxed(boot_val, boot_reg); | |
179 | ||
180 | sev(); | |
181 | ||
182 | /* The low bits will be cleared once the core has started */ | |
183 | start_clock = local_clock(); | |
184 | while (!timeout && readl_relaxed(boot_reg) == boot_val) | |
185 | timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS; | |
186 | ||
187 | iounmap(boot_reg); | |
188 | ||
189 | if (!timeout) | |
190 | return 0; | |
191 | ||
192 | pr_err("timeout waiting for cpu %u to start\n", cpu_id); | |
193 | ||
194 | return -ENOSYS; | |
195 | } | |
196 | ||
197 | static struct smp_operations bcm_smp_ops __initdata = { | |
198 | .smp_prepare_cpus = bcm_smp_prepare_cpus, | |
199 | .smp_boot_secondary = bcm_boot_secondary, | |
200 | }; | |
201 | CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", | |
202 | &bcm_smp_ops); |