blob: c5d70de9bb4e20165fb9e6181e26f8cfafe3a0cb [file] [log] [blame]
Russell King59ac59f2010-02-11 21:56:07 +00001/*
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>
Russell King59ac59f2010-02-11 21:56:07 +000013#include <linux/smp.h>
14#include <linux/io.h>
Pawel Moll95d59742012-02-24 09:18:14 +000015#include <linux/of_fdt.h>
Pawel Moll38669e02012-10-09 12:56:36 +010016#include <linux/vexpress.h>
Pawel Moll95d59742012-02-24 09:18:14 +000017
18#include <asm/smp_scu.h>
19#include <asm/hardware/gic.h>
20#include <asm/mach/map.h>
Russell King59ac59f2010-02-11 21:56:07 +000021
Russell King59ac59f2010-02-11 21:56:07 +000022#include <mach/motherboard.h>
Russell King59ac59f2010-02-11 21:56:07 +000023
Marc Zyngier3695adc2011-09-08 13:15:22 +010024#include <plat/platsmp.h>
Russell King59ac59f2010-02-11 21:56:07 +000025
Marc Zyngier3695adc2011-09-08 13:15:22 +010026#include "core.h"
Russell King3705ff62010-12-18 10:53:12 +000027
Pawel Moll95d59742012-02-24 09:18:14 +000028#if defined(CONFIG_OF)
29
30static enum {
31 GENERIC_SCU,
32 CORTEX_A9_SCU,
33} vexpress_dt_scu __initdata = GENERIC_SCU;
34
35static struct map_desc vexpress_dt_cortex_a9_scu_map __initdata = {
36 .virtual = V2T_PERIPH,
37 /* .pfn set in vexpress_dt_init_cortex_a9_scu() */
38 .length = SZ_128,
39 .type = MT_DEVICE,
40};
41
42static void *vexpress_dt_cortex_a9_scu_base __initdata;
43
44const static char *vexpress_dt_cortex_a9_match[] __initconst = {
45 "arm,cortex-a5-scu",
46 "arm,cortex-a9-scu",
47 NULL
48};
49
50static int __init vexpress_dt_find_scu(unsigned long node,
51 const char *uname, int depth, void *data)
52{
53 if (of_flat_dt_match(node, vexpress_dt_cortex_a9_match)) {
54 phys_addr_t phys_addr;
55 __be32 *reg = of_get_flat_dt_prop(node, "reg", NULL);
56
57 if (WARN_ON(!reg))
58 return -EINVAL;
59
60 phys_addr = be32_to_cpup(reg);
61 vexpress_dt_scu = CORTEX_A9_SCU;
62
63 vexpress_dt_cortex_a9_scu_map.pfn = __phys_to_pfn(phys_addr);
64 iotable_init(&vexpress_dt_cortex_a9_scu_map, 1);
65 vexpress_dt_cortex_a9_scu_base = ioremap(phys_addr, SZ_256);
66 if (WARN_ON(!vexpress_dt_cortex_a9_scu_base))
67 return -EFAULT;
68 }
69
70 return 0;
71}
72
73void __init vexpress_dt_smp_map_io(void)
74{
75 if (initial_boot_params)
76 WARN_ON(of_scan_flat_dt(vexpress_dt_find_scu, NULL));
77}
78
79static int __init vexpress_dt_cpus_num(unsigned long node, const char *uname,
80 int depth, void *data)
81{
82 static int prev_depth = -1;
83 static int nr_cpus = -1;
84
85 if (prev_depth > depth && nr_cpus > 0)
86 return nr_cpus;
87
88 if (nr_cpus < 0 && strcmp(uname, "cpus") == 0)
89 nr_cpus = 0;
90
91 if (nr_cpus >= 0) {
92 const char *device_type = of_get_flat_dt_prop(node,
93 "device_type", NULL);
94
95 if (device_type && strcmp(device_type, "cpu") == 0)
96 nr_cpus++;
97 }
98
99 prev_depth = depth;
100
101 return 0;
102}
103
104static void __init vexpress_dt_smp_init_cpus(void)
105{
106 int ncores = 0, i;
107
108 switch (vexpress_dt_scu) {
109 case GENERIC_SCU:
110 ncores = of_scan_flat_dt(vexpress_dt_cpus_num, NULL);
111 break;
112 case CORTEX_A9_SCU:
113 ncores = scu_get_core_count(vexpress_dt_cortex_a9_scu_base);
114 break;
115 default:
116 WARN_ON(1);
117 break;
118 }
119
120 if (ncores < 2)
121 return;
122
123 if (ncores > nr_cpu_ids) {
124 pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
125 ncores, nr_cpu_ids);
126 ncores = nr_cpu_ids;
127 }
128
129 for (i = 0; i < ncores; ++i)
130 set_cpu_possible(i, true);
131
132 set_smp_cross_call(gic_raise_softirq);
133}
134
135static void __init vexpress_dt_smp_prepare_cpus(unsigned int max_cpus)
136{
137 int i;
138
139 switch (vexpress_dt_scu) {
140 case GENERIC_SCU:
141 for (i = 0; i < max_cpus; i++)
142 set_cpu_present(i, true);
143 break;
144 case CORTEX_A9_SCU:
145 scu_enable(vexpress_dt_cortex_a9_scu_base);
146 break;
147 default:
148 WARN_ON(1);
149 break;
150 }
151}
152
153#else
154
155static void __init vexpress_dt_smp_init_cpus(void)
156{
157 WARN_ON(1);
158}
159
160void __init vexpress_dt_smp_prepare_cpus(unsigned int max_cpus)
161{
162 WARN_ON(1);
163}
164
165#endif
166
Russell King59ac59f2010-02-11 21:56:07 +0000167/*
168 * Initialise the CPU possible map early - this describes the CPUs
169 * which may be present or become present in the system.
170 */
Marc Zyngier3695adc2011-09-08 13:15:22 +0100171static void __init vexpress_smp_init_cpus(void)
Russell King59ac59f2010-02-11 21:56:07 +0000172{
Pawel Moll95d59742012-02-24 09:18:14 +0000173 if (ct_desc)
174 ct_desc->init_cpu_map();
175 else
176 vexpress_dt_smp_init_cpus();
177
Russell King59ac59f2010-02-11 21:56:07 +0000178}
179
Marc Zyngier3695adc2011-09-08 13:15:22 +0100180static void __init vexpress_smp_prepare_cpus(unsigned int max_cpus)
Russell King59ac59f2010-02-11 21:56:07 +0000181{
Russell King59ac59f2010-02-11 21:56:07 +0000182 /*
183 * Initialise the present map, which describes the set of CPUs
184 * actually populated at the present time.
185 */
Pawel Moll95d59742012-02-24 09:18:14 +0000186 if (ct_desc)
187 ct_desc->smp_enable(max_cpus);
188 else
189 vexpress_dt_smp_prepare_cpus(max_cpus);
Russell King05c74a62010-12-03 11:09:48 +0000190
Russell King59ac59f2010-02-11 21:56:07 +0000191 /*
Russell King05c74a62010-12-03 11:09:48 +0000192 * Write the address of secondary startup into the
193 * system-wide flags register. The boot monitor waits
194 * until it receives a soft interrupt, and then the
195 * secondary CPU branches to this address.
Russell King59ac59f2010-02-11 21:56:07 +0000196 */
Pawel Moll38669e02012-10-09 12:56:36 +0100197 vexpress_flags_set(virt_to_phys(versatile_secondary_startup));
Russell King59ac59f2010-02-11 21:56:07 +0000198}
Marc Zyngier3695adc2011-09-08 13:15:22 +0100199
200struct smp_operations __initdata vexpress_smp_ops = {
201 .smp_init_cpus = vexpress_smp_init_cpus,
202 .smp_prepare_cpus = vexpress_smp_prepare_cpus,
203 .smp_secondary_init = versatile_secondary_init,
204 .smp_boot_secondary = versatile_boot_secondary,
205#ifdef CONFIG_HOTPLUG_CPU
206 .cpu_die = vexpress_cpu_die,
207#endif
208};