Branch data Line data Source code
1 : : /*
2 : : * linux/arch/arm/mach-vexpress/platsmp.c
3 : : *
4 : : * Copyright (C) 2002 ARM Ltd.
5 : : * All Rights Reserved
6 : : *
7 : : * This program is free software; you can redistribute it and/or modify
8 : : * it under the terms of the GNU General Public License version 2 as
9 : : * published by the Free Software Foundation.
10 : : */
11 : : #include <linux/init.h>
12 : : #include <linux/errno.h>
13 : : #include <linux/smp.h>
14 : : #include <linux/io.h>
15 : : #include <linux/of.h>
16 : : #include <linux/of_fdt.h>
17 : : #include <linux/vexpress.h>
18 : :
19 : : #include <asm/mcpm.h>
20 : : #include <asm/smp_scu.h>
21 : : #include <asm/mach/map.h>
22 : :
23 : : #include <mach/motherboard.h>
24 : :
25 : : #include <plat/platsmp.h>
26 : :
27 : : #include "core.h"
28 : :
29 : : #if defined(CONFIG_OF)
30 : :
31 : : static enum {
32 : : GENERIC_SCU,
33 : : CORTEX_A9_SCU,
34 : : } vexpress_dt_scu __initdata = GENERIC_SCU;
35 : :
36 : : static struct map_desc vexpress_dt_cortex_a9_scu_map __initdata = {
37 : : .virtual = V2T_PERIPH,
38 : : /* .pfn set in vexpress_dt_init_cortex_a9_scu() */
39 : : .length = SZ_128,
40 : : .type = MT_DEVICE,
41 : : };
42 : :
43 : : static void *vexpress_dt_cortex_a9_scu_base __initdata;
44 : :
45 : : const static char *vexpress_dt_cortex_a9_match[] __initconst = {
46 : : "arm,cortex-a5-scu",
47 : : "arm,cortex-a9-scu",
48 : : NULL
49 : : };
50 : :
51 : 0 : static int __init vexpress_dt_find_scu(unsigned long node,
52 : : const char *uname, int depth, void *data)
53 : : {
54 [ # # ]: 0 : if (of_flat_dt_match(node, vexpress_dt_cortex_a9_match)) {
55 : : phys_addr_t phys_addr;
56 : 0 : __be32 *reg = of_get_flat_dt_prop(node, "reg", NULL);
57 : :
58 [ # # ][ # # ]: 0 : if (WARN_ON(!reg))
59 : : return -EINVAL;
60 : :
61 : : phys_addr = be32_to_cpup(reg);
62 : 0 : vexpress_dt_scu = CORTEX_A9_SCU;
63 : :
64 : 0 : vexpress_dt_cortex_a9_scu_map.pfn = __phys_to_pfn(phys_addr);
65 : 0 : iotable_init(&vexpress_dt_cortex_a9_scu_map, 1);
66 : 0 : vexpress_dt_cortex_a9_scu_base = ioremap(phys_addr, SZ_256);
67 [ # # ][ # # ]: 0 : if (WARN_ON(!vexpress_dt_cortex_a9_scu_base))
68 : : return -EFAULT;
69 : : }
70 : :
71 : : return 0;
72 : : }
73 : :
74 : 0 : void __init vexpress_dt_smp_map_io(void)
75 : : {
76 [ # # ]: 0 : if (initial_boot_params)
77 [ # # ]: 0 : WARN_ON(of_scan_flat_dt(vexpress_dt_find_scu, NULL));
78 : 0 : }
79 : :
80 : 0 : static int __init vexpress_dt_cpus_num(unsigned long node, const char *uname,
81 : : int depth, void *data)
82 : : {
83 : : static int prev_depth = -1;
84 : : static int nr_cpus = -1;
85 : :
86 [ # # ][ # # ]: 0 : if (prev_depth > depth && nr_cpus > 0)
87 : : return nr_cpus;
88 : :
89 [ # # ][ # # ]: 0 : if (nr_cpus < 0 && strcmp(uname, "cpus") == 0)
90 : 0 : nr_cpus = 0;
91 : :
92 [ # # ]: 0 : if (nr_cpus >= 0) {
93 : 0 : const char *device_type = of_get_flat_dt_prop(node,
94 : : "device_type", NULL);
95 : :
96 [ # # ][ # # ]: 0 : if (device_type && strcmp(device_type, "cpu") == 0)
97 : 0 : nr_cpus++;
98 : : }
99 : :
100 : 0 : prev_depth = depth;
101 : :
102 : 0 : return 0;
103 : : }
104 : :
105 : 0 : static void __init vexpress_dt_smp_init_cpus(void)
106 : : {
107 : : int ncores = 0, i;
108 : :
109 [ # # # ]: 0 : switch (vexpress_dt_scu) {
110 : : case GENERIC_SCU:
111 : 0 : ncores = of_scan_flat_dt(vexpress_dt_cpus_num, NULL);
112 : 0 : break;
113 : : case CORTEX_A9_SCU:
114 : 0 : ncores = scu_get_core_count(vexpress_dt_cortex_a9_scu_base);
115 : 0 : break;
116 : : default:
117 : 0 : WARN_ON(1);
118 : 0 : break;
119 : : }
120 : :
121 [ # # ]: 0 : if (ncores < 2)
122 : 0 : return;
123 : :
124 [ # # ]: 0 : if (ncores > nr_cpu_ids) {
125 : 0 : pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
126 : : ncores, nr_cpu_ids);
127 : 0 : ncores = nr_cpu_ids;
128 : : }
129 : :
130 [ # # ]: 0 : for (i = 0; i < ncores; ++i)
131 : 0 : set_cpu_possible(i, true);
132 : : }
133 : :
134 : 0 : static void __init vexpress_dt_smp_prepare_cpus(unsigned int max_cpus)
135 : : {
136 : : int i;
137 : :
138 [ # # # ]: 0 : switch (vexpress_dt_scu) {
139 : : case GENERIC_SCU:
140 [ # # ]: 0 : for (i = 0; i < max_cpus; i++)
141 : 0 : set_cpu_present(i, true);
142 : : break;
143 : : case CORTEX_A9_SCU:
144 : 0 : scu_enable(vexpress_dt_cortex_a9_scu_base);
145 : 0 : break;
146 : : default:
147 : 0 : WARN_ON(1);
148 : 0 : break;
149 : : }
150 : 0 : }
151 : :
152 : : #else
153 : :
154 : : static void __init vexpress_dt_smp_init_cpus(void)
155 : : {
156 : : WARN_ON(1);
157 : : }
158 : :
159 : : void __init vexpress_dt_smp_prepare_cpus(unsigned int max_cpus)
160 : : {
161 : : WARN_ON(1);
162 : : }
163 : :
164 : : #endif
165 : :
166 : : /*
167 : : * Initialise the CPU possible map early - this describes the CPUs
168 : : * which may be present or become present in the system.
169 : : */
170 : 0 : static void __init vexpress_smp_init_cpus(void)
171 : : {
172 [ # # ]: 0 : if (ct_desc)
173 : 0 : ct_desc->init_cpu_map();
174 : : else
175 : 0 : vexpress_dt_smp_init_cpus();
176 : :
177 : 0 : }
178 : :
179 : 0 : static void __init vexpress_smp_prepare_cpus(unsigned int max_cpus)
180 : : {
181 : : /*
182 : : * Initialise the present map, which describes the set of CPUs
183 : : * actually populated at the present time.
184 : : */
185 [ # # ]: 0 : if (ct_desc)
186 : 0 : ct_desc->smp_enable(max_cpus);
187 : : else
188 : 0 : vexpress_dt_smp_prepare_cpus(max_cpus);
189 : :
190 : : /*
191 : : * Write the address of secondary startup into the
192 : : * system-wide flags register. The boot monitor waits
193 : : * until it receives a soft interrupt, and then the
194 : : * secondary CPU branches to this address.
195 : : */
196 : 0 : vexpress_flags_set(virt_to_phys(versatile_secondary_startup));
197 : 0 : }
198 : :
199 : : struct smp_operations __initdata vexpress_smp_ops = {
200 : : .smp_init_cpus = vexpress_smp_init_cpus,
201 : : .smp_prepare_cpus = vexpress_smp_prepare_cpus,
202 : : .smp_secondary_init = versatile_secondary_init,
203 : : .smp_boot_secondary = versatile_boot_secondary,
204 : : #ifdef CONFIG_HOTPLUG_CPU
205 : : .cpu_die = vexpress_cpu_die,
206 : : #endif
207 : : };
208 : :
209 : 0 : bool __init vexpress_smp_init_ops(void)
210 : : {
211 : : #ifdef CONFIG_MCPM
212 : : /*
213 : : * The best way to detect a multi-cluster configuration at the moment
214 : : * is to look for the presence of a CCI in the system.
215 : : * Override the default vexpress_smp_ops if so.
216 : : */
217 : : struct device_node *node;
218 : 0 : node = of_find_compatible_node(NULL, NULL, "arm,cci-400");
219 [ # # ][ # # ]: 0 : if (node && of_device_is_available(node)) {
220 : 0 : mcpm_smp_set_ops();
221 : 0 : return true;
222 : : }
223 : : #endif
224 : : return false;
225 : : }
|