Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/annapurna/alpine/alpine_machdep_mp.c
39536 views
1
/*-
2
* Copyright (c) 2013 Ruslan Bukin <[email protected]>
3
* Copyright (c) 2015 Semihalf
4
* All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*
27
*/
28
29
#include <sys/param.h>
30
#include <sys/systm.h>
31
#include <sys/bus.h>
32
#include <sys/lock.h>
33
#include <sys/mutex.h>
34
#include <sys/smp.h>
35
#include <sys/cpuset.h>
36
37
#include <vm/vm.h>
38
#include <vm/pmap.h>
39
40
#include <machine/smp.h>
41
#include <machine/fdt.h>
42
#include <machine/intr.h>
43
#include <machine/cpu.h>
44
#include <machine/platformvar.h>
45
46
#include <dev/fdt/fdt_common.h>
47
#include <dev/ofw/openfirm.h>
48
#include <dev/ofw/ofw_cpu.h>
49
#include <dev/ofw/ofw_bus_subr.h>
50
51
#include <arm/annapurna/alpine/alpine_mp.h>
52
53
#define AL_CPU_RESUME_WATERMARK_REG 0x00
54
#define AL_CPU_RESUME_FLAGS_REG 0x04
55
#define AL_CPU_RESUME_PCPU_RADDR_REG(cpu) (0x08 + 0x04 + 8*(cpu))
56
#define AL_CPU_RESUME_PCPU_FLAGS(cpu) (0x08 + 8*(cpu))
57
58
/* Per-CPU flags */
59
#define AL_CPU_RESUME_FLG_PERCPU_DONT_RESUME (1 << 2)
60
61
/* The expected magic number for validating the resume addresses */
62
#define AL_CPU_RESUME_MAGIC_NUM 0xf0e1d200
63
#define AL_CPU_RESUME_MAGIC_NUM_MASK 0xffffff00
64
65
/* The expected minimal version number for validating the capabilities */
66
#define AL_CPU_RESUME_MIN_VER 0x000000c3
67
#define AL_CPU_RESUME_MIN_VER_MASK 0x000000ff
68
69
/* Field controlling the boot-up of companion cores */
70
#define AL_NB_INIT_CONTROL (0x8)
71
#define AL_NB_CONFIG_STATUS_PWR_CTRL(cpu) (0x2020 + (cpu)*0x100)
72
73
extern bus_addr_t al_devmap_pa;
74
extern bus_addr_t al_devmap_size;
75
76
extern void mpentry(void);
77
78
static int platform_mp_get_core_cnt(void);
79
static int alpine_get_cpu_resume_base(u_long *pbase, u_long *psize);
80
static int alpine_get_nb_base(u_long *pbase, u_long *psize);
81
static bool alpine_validate_cpu(u_int, phandle_t, u_int, pcell_t *);
82
83
static bool
84
alpine_validate_cpu(u_int id, phandle_t child, u_int addr_cell, pcell_t *reg)
85
{
86
return ofw_bus_node_is_compatible(child, "arm,cortex-a15");
87
}
88
89
static int
90
platform_mp_get_core_cnt(void)
91
{
92
static int ncores = 0;
93
int nchilds;
94
uint32_t reg;
95
96
/* Calculate ncores value only once */
97
if (ncores)
98
return (ncores);
99
100
reg = cp15_l2ctlr_get();
101
ncores = CPUV7_L2CTLR_NPROC(reg);
102
103
nchilds = ofw_cpu_early_foreach(alpine_validate_cpu, false);
104
105
/* Limit CPUs if DTS has configured less than available */
106
if ((nchilds > 0) && (nchilds < ncores)) {
107
printf("SMP: limiting number of active CPUs to %d out of %d\n",
108
nchilds, ncores);
109
ncores = nchilds;
110
}
111
112
return (ncores);
113
}
114
115
void
116
alpine_mp_setmaxid(platform_t plat)
117
{
118
119
mp_ncpus = platform_mp_get_core_cnt();
120
mp_maxid = mp_ncpus - 1;
121
}
122
123
static int
124
alpine_get_cpu_resume_base(u_long *pbase, u_long *psize)
125
{
126
phandle_t node;
127
u_long base = 0;
128
u_long size = 0;
129
130
if (pbase == NULL || psize == NULL)
131
return (EINVAL);
132
133
if ((node = OF_finddevice("/")) == -1)
134
return (EFAULT);
135
136
if ((node =
137
ofw_bus_find_compatible(node, "annapurna-labs,al-cpu-resume")) == 0)
138
return (EFAULT);
139
140
if (fdt_regsize(node, &base, &size))
141
return (EFAULT);
142
143
*pbase = base;
144
*psize = size;
145
146
return (0);
147
}
148
149
static int
150
alpine_get_nb_base(u_long *pbase, u_long *psize)
151
{
152
phandle_t node;
153
u_long base = 0;
154
u_long size = 0;
155
156
if (pbase == NULL || psize == NULL)
157
return (EINVAL);
158
159
if ((node = OF_finddevice("/")) == -1)
160
return (EFAULT);
161
162
if ((node =
163
ofw_bus_find_compatible(node, "annapurna-labs,al-nb-service")) == 0)
164
return (EFAULT);
165
166
if (fdt_regsize(node, &base, &size))
167
return (EFAULT);
168
169
*pbase = base;
170
*psize = size;
171
172
return (0);
173
}
174
175
void
176
alpine_mp_start_ap(platform_t plat)
177
{
178
uint32_t physaddr;
179
vm_offset_t vaddr;
180
uint32_t val;
181
uint32_t start_mask;
182
u_long cpu_resume_base;
183
u_long nb_base;
184
u_long cpu_resume_size;
185
u_long nb_size;
186
bus_addr_t cpu_resume_baddr;
187
bus_addr_t nb_baddr;
188
int a;
189
190
if (alpine_get_cpu_resume_base(&cpu_resume_base, &cpu_resume_size))
191
panic("Couldn't resolve cpu_resume_base address\n");
192
193
if (alpine_get_nb_base(&nb_base, &nb_size))
194
panic("Couldn't resolve_nb_base address\n");
195
196
/* Proceed with start addresses for additional CPUs */
197
if (bus_space_map(fdtbus_bs_tag, al_devmap_pa + cpu_resume_base,
198
cpu_resume_size, 0, &cpu_resume_baddr))
199
panic("Couldn't map CPU-resume area");
200
if (bus_space_map(fdtbus_bs_tag, al_devmap_pa + nb_base,
201
nb_size, 0, &nb_baddr))
202
panic("Couldn't map NB-service area");
203
204
/* Proceed with start addresses for additional CPUs */
205
val = bus_space_read_4(fdtbus_bs_tag, cpu_resume_baddr,
206
AL_CPU_RESUME_WATERMARK_REG);
207
if (((val & AL_CPU_RESUME_MAGIC_NUM_MASK) != AL_CPU_RESUME_MAGIC_NUM) ||
208
((val & AL_CPU_RESUME_MIN_VER_MASK) < AL_CPU_RESUME_MIN_VER)) {
209
panic("CPU-resume device is not compatible");
210
}
211
212
vaddr = (vm_offset_t)mpentry;
213
physaddr = pmap_kextract(vaddr);
214
215
for (a = 1; a < platform_mp_get_core_cnt(); a++) {
216
/* Power up the core */
217
bus_space_write_4(fdtbus_bs_tag, nb_baddr,
218
AL_NB_CONFIG_STATUS_PWR_CTRL(a), 0);
219
mb();
220
221
/* Enable resume */
222
val = bus_space_read_4(fdtbus_bs_tag, cpu_resume_baddr,
223
AL_CPU_RESUME_PCPU_FLAGS(a));
224
val &= ~AL_CPU_RESUME_FLG_PERCPU_DONT_RESUME;
225
bus_space_write_4(fdtbus_bs_tag, cpu_resume_baddr,
226
AL_CPU_RESUME_PCPU_FLAGS(a), val);
227
mb();
228
229
/* Set resume physical address */
230
bus_space_write_4(fdtbus_bs_tag, cpu_resume_baddr,
231
AL_CPU_RESUME_PCPU_RADDR_REG(a), physaddr);
232
mb();
233
}
234
235
/* Release cores from reset */
236
if (bus_space_map(fdtbus_bs_tag, al_devmap_pa + nb_base,
237
nb_size, 0, &nb_baddr))
238
panic("Couldn't map NB-service area");
239
240
start_mask = (1 << platform_mp_get_core_cnt()) - 1;
241
242
/* Release cores from reset */
243
val = bus_space_read_4(fdtbus_bs_tag, nb_baddr, AL_NB_INIT_CONTROL);
244
val |= start_mask;
245
bus_space_write_4(fdtbus_bs_tag, nb_baddr, AL_NB_INIT_CONTROL, val);
246
dsb();
247
248
bus_space_unmap(fdtbus_bs_tag, nb_baddr, nb_size);
249
bus_space_unmap(fdtbus_bs_tag, cpu_resume_baddr, cpu_resume_size);
250
}
251
252