]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/broadcom/bcm2835/bcm2836_mp.c
Fix the SMP initialization on RPi 2 (BCM2836).
[FreeBSD/FreeBSD.git] / sys / arm / broadcom / bcm2835 / bcm2836_mp.c
1 /*-
2  * Copyright (C) 2015 Daisuke Aoyama <aoyama@peach.ne.jp>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/bus.h>
38 #include <sys/smp.h>
39
40 #include <vm/vm.h>
41 #include <vm/pmap.h>
42
43 #include <machine/smp.h>
44 #include <machine/bus.h>
45 #include <machine/fdt.h>
46 #include <machine/intr.h>
47
48 #ifdef DEBUG
49 #define DPRINTF(fmt, ...) do {                  \
50         printf("%s:%u: ", __func__, __LINE__);  \
51         printf(fmt, ##__VA_ARGS__);             \
52 } while (0)
53 #else
54 #define DPRINTF(fmt, ...)
55 #endif
56
57 #define ARM_LOCAL_BASE          0x40000000
58 #define ARM_LOCAL_SIZE          0x00001000
59
60 /* mailbox registers */
61 #define MBOXINTRCTRL_CORE(n)    (0x00000050 + (0x04 * (n)))
62 #define MBOX0SET_CORE(n)        (0x00000080 + (0x10 * (n)))
63 #define MBOX1SET_CORE(n)        (0x00000084 + (0x10 * (n)))
64 #define MBOX2SET_CORE(n)        (0x00000088 + (0x10 * (n)))
65 #define MBOX3SET_CORE(n)        (0x0000008C + (0x10 * (n)))
66 #define MBOX0CLR_CORE(n)        (0x000000C0 + (0x10 * (n)))
67 #define MBOX1CLR_CORE(n)        (0x000000C4 + (0x10 * (n)))
68 #define MBOX2CLR_CORE(n)        (0x000000C8 + (0x10 * (n)))
69 #define MBOX3CLR_CORE(n)        (0x000000CC + (0x10 * (n)))
70
71 static bus_space_handle_t bs_periph;
72
73 #define BSRD4(addr) \
74         bus_space_read_4(fdtbus_bs_tag, bs_periph, (addr))
75 #define BSWR4(addr, val) \
76         bus_space_write_4(fdtbus_bs_tag, bs_periph, (addr), (val))
77
78 void
79 platform_mp_init_secondary(void)
80 {
81
82 }
83
84 void
85 platform_mp_setmaxid(void)
86 {
87
88         DPRINTF("platform_mp_setmaxid\n");
89         if (mp_ncpus != 0)
90                 return;
91
92         mp_ncpus = 4;
93         mp_maxid = mp_ncpus - 1;
94         DPRINTF("mp_maxid=%d\n", mp_maxid);
95 }
96
97 int
98 platform_mp_probe(void)
99 {
100
101         DPRINTF("platform_mp_probe\n");
102         CPU_SETOF(0, &all_cpus);
103         if (mp_ncpus == 0)
104                 platform_mp_setmaxid();
105         return (mp_ncpus > 1);
106 }
107
108 void
109 platform_mp_start_ap(void)
110 {
111         uint32_t val;
112         int i, retry;
113
114         DPRINTF("platform_mp_start_ap\n");
115
116         /* initialize */
117         if (bus_space_map(fdtbus_bs_tag, ARM_LOCAL_BASE, ARM_LOCAL_SIZE,
118             0, &bs_periph) != 0)
119                 panic("can't map local peripheral\n");
120         for (i = 0; i < mp_ncpus; i++) {
121                 /* clear mailbox 0/3 */
122                 BSWR4(MBOX0CLR_CORE(i), 0xffffffff);
123                 BSWR4(MBOX3CLR_CORE(i), 0xffffffff);
124         }
125         wmb();
126         cpu_idcache_wbinv_all();
127         cpu_l2cache_wbinv_all();
128
129         /* boot secondary CPUs */
130         for (i = 1; i < mp_ncpus; i++) {
131                 /* set entry point to mailbox 3 */
132                 BSWR4(MBOX3SET_CORE(i),
133                     (uint32_t)pmap_kextract((vm_offset_t)mpentry));
134                 wmb();
135
136                 /* wait for bootup */
137                 retry = 1000;
138                 do {
139                         /* check entry point */
140                         val = BSRD4(MBOX3CLR_CORE(i));
141                         if (val == 0)
142                                 break;
143                         DELAY(100);
144                         retry--;
145                         if (retry <= 0) {
146                                 printf("can't start for CPU%d\n", i);
147                                 break;
148                         }
149                 } while (1);
150
151                 /* dsb and sev */
152                 armv7_sev();
153
154                 /* recode AP in CPU map */
155                 CPU_SET(i, &all_cpus);
156         }
157 }
158
159 void
160 pic_ipi_send(cpuset_t cpus, u_int ipi)
161 {
162         int i;
163
164         dsb();
165         for (i = 0; i < mp_ncpus; i++) {
166                 if (CPU_ISSET(i, &cpus))
167                         BSWR4(MBOX0SET_CORE(i), 1 << ipi);
168         }
169         wmb();
170 }
171
172 int
173 pic_ipi_read(int i)
174 {
175         uint32_t val;
176         int cpu, ipi;
177
178         cpu = PCPU_GET(cpuid);
179         dsb();
180         if (i != -1) {
181                 val = BSRD4(MBOX0CLR_CORE(cpu));
182                 if (val == 0)
183                         return (0);
184                 ipi = ffs(val) - 1;
185                 return (ipi);
186         }
187         return (0x3ff);
188 }
189
190 void
191 pic_ipi_clear(int ipi)
192 {
193         int cpu;
194
195         cpu = PCPU_GET(cpuid);
196         dsb();
197         BSWR4(MBOX0CLR_CORE(cpu), 1 << ipi);
198         wmb();
199 }
200
201 void
202 platform_ipi_send(cpuset_t cpus, u_int ipi)
203 {
204
205         pic_ipi_send(cpus, ipi);
206 }