1 /* $NetBSD: cpufunc.c,v 1.65 2003/11/05 12:53:15 scw Exp $ */
2
3 /*-
4 * SPDX-License-Identifier: BSD-4-Clause
5 *
6 * arm9 support code Copyright (C) 2001 ARM Ltd
7 * Copyright (c) 1997 Mark Brinicombe.
8 * Copyright (c) 1997 Causality Limited
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by Causality Limited.
22 * 4. The name of Causality Limited may not be used to endorse or promote
23 * products derived from this software without specific prior written
24 * permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY CAUSALITY LIMITED ``AS IS'' AND ANY EXPRESS
27 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29 * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED BE LIABLE FOR ANY DIRECT,
30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * RiscBSD kernel project
39 *
40 * cpufuncs.c
41 *
42 * C functions for supporting CPU / MMU / TLB specific operations.
43 *
44 * Created : 30/01/97
45 */
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/lock.h>
50 #include <sys/mutex.h>
51 #include <sys/bus.h>
52 #include <machine/bus.h>
53 #include <machine/cpu.h>
54 #include <machine/disassem.h>
55
56 #include <vm/vm.h>
57 #include <vm/pmap.h>
58 #include <vm/uma.h>
59
60 #include <machine/cpufunc.h>
61
62 /* PRIMARY CACHE VARIABLES */
63
64 unsigned int arm_dcache_align;
65 unsigned int arm_dcache_align_mask;
66
67 #ifdef CPU_MV_PJ4B
68 static void pj4bv7_setup(void);
69 #endif
70 #if defined(CPU_ARM1176)
71 static void arm11x6_setup(void);
72 #endif
73 #if defined(CPU_CORTEXA) || defined(CPU_KRAIT)
74 static void cortexa_setup(void);
75 #endif
76
77 #ifdef CPU_MV_PJ4B
78 struct cpu_functions pj4bv7_cpufuncs = {
79 /* Cache operations */
80 .cf_l2cache_wbinv_all = (void *)cpufunc_nullop,
81 .cf_l2cache_wbinv_range = (void *)cpufunc_nullop,
82 .cf_l2cache_inv_range = (void *)cpufunc_nullop,
83 .cf_l2cache_wb_range = (void *)cpufunc_nullop,
84 .cf_l2cache_drain_writebuf = (void *)cpufunc_nullop,
85
86 /* Other functions */
87 .cf_sleep = (void *)cpufunc_nullop,
88
89 /* Soft functions */
90 .cf_setup = pj4bv7_setup
91 };
92 #endif /* CPU_MV_PJ4B */
93
94 #if defined(CPU_ARM1176)
95 struct cpu_functions arm1176_cpufuncs = {
96 /* Cache operations */
97 .cf_l2cache_wbinv_all = (void *)cpufunc_nullop,
98 .cf_l2cache_wbinv_range = (void *)cpufunc_nullop,
99 .cf_l2cache_inv_range = (void *)cpufunc_nullop,
100 .cf_l2cache_wb_range = (void *)cpufunc_nullop,
101 .cf_l2cache_drain_writebuf = (void *)cpufunc_nullop,
102
103 /* Other functions */
104 .cf_sleep = arm11x6_sleep,
105
106 /* Soft functions */
107 .cf_setup = arm11x6_setup
108 };
109 #endif /*CPU_ARM1176 */
110
111 #if defined(CPU_CORTEXA) || defined(CPU_KRAIT)
112 struct cpu_functions cortexa_cpufuncs = {
113 /* Cache operations */
114
115 /*
116 * Note: For CPUs using the PL310 the L2 ops are filled in when the
117 * L2 cache controller is actually enabled.
118 */
119 .cf_l2cache_wbinv_all = cpufunc_nullop,
120 .cf_l2cache_wbinv_range = (void *)cpufunc_nullop,
121 .cf_l2cache_inv_range = (void *)cpufunc_nullop,
122 .cf_l2cache_wb_range = (void *)cpufunc_nullop,
123 .cf_l2cache_drain_writebuf = (void *)cpufunc_nullop,
124
125 /* Other functions */
126 .cf_sleep = armv7_cpu_sleep,
127
128 /* Soft functions */
129 .cf_setup = cortexa_setup
130 };
131 #endif /* CPU_CORTEXA || CPU_KRAIT */
132
133 /*
134 * Global constants also used by locore.s
135 */
136
137 struct cpu_functions cpufuncs;
138 u_int cputype;
139
140 static void get_cachetype_cp15(void);
141
142 static void
get_cachetype_cp15(void)143 get_cachetype_cp15(void)
144 {
145 u_int ctype, dsize, cpuid;
146 u_int clevel, csize, i, sel;
147 u_char type;
148
149 ctype = cp15_ctr_get();
150 cpuid = cp15_midr_get();
151 /*
152 * ...and thus spake the ARM ARM:
153 *
154 * If an <opcode2> value corresponding to an unimplemented or
155 * reserved ID register is encountered, the System Control
156 * processor returns the value of the main ID register.
157 */
158 if (ctype == cpuid)
159 goto out;
160
161 if (CPU_CT_FORMAT(ctype) == CPU_CT_ARMV7) {
162 __asm __volatile("mrc p15, 1, %0, c0, c0, 1"
163 : "=r" (clevel));
164 i = 0;
165 while ((type = (clevel & 0x7)) && i < 7) {
166 if (type == CACHE_DCACHE || type == CACHE_UNI_CACHE ||
167 type == CACHE_SEP_CACHE) {
168 sel = i << 1;
169 __asm __volatile("mcr p15, 2, %0, c0, c0, 0"
170 : : "r" (sel));
171 __asm __volatile("mrc p15, 1, %0, c0, c0, 0"
172 : "=r" (csize));
173 arm_dcache_align = 1U <<
174 (CPUV7_CT_xSIZE_LEN(csize) + 4);
175 }
176 if (type == CACHE_ICACHE || type == CACHE_SEP_CACHE) {
177 sel = (i << 1) | 1;
178 __asm __volatile("mcr p15, 2, %0, c0, c0, 0"
179 : : "r" (sel));
180 __asm __volatile("mrc p15, 1, %0, c0, c0, 0"
181 : "=r" (csize));
182 }
183 i++;
184 clevel >>= 3;
185 }
186 } else {
187 /*
188 * If you want to know how this code works, go read the ARM ARM.
189 */
190
191 dsize = CPU_CT_DSIZE(ctype);
192 arm_dcache_align = 1U << (CPU_CT_xSIZE_LEN(dsize) + 3);
193 if (CPU_CT_xSIZE_ASSOC(dsize) == 0) {
194 if (dsize & CPU_CT_xSIZE_M)
195 arm_dcache_align = 0; /* not present */
196 }
197 }
198
199 out:
200 arm_dcache_align_mask = arm_dcache_align - 1;
201 }
202
203 /*
204 * Cannot panic here as we may not have a console yet ...
205 */
206
207 int
set_cpufuncs(void)208 set_cpufuncs(void)
209 {
210 cputype = cp15_midr_get();
211 cputype &= CPU_ID_CPU_MASK;
212
213 #if defined(CPU_ARM1176)
214 if (cputype == CPU_ID_ARM1176JZS) {
215 cpufuncs = arm1176_cpufuncs;
216 get_cachetype_cp15();
217 goto out;
218 }
219 #endif /* CPU_ARM1176 */
220 #if defined(CPU_CORTEXA) || defined(CPU_KRAIT)
221 switch(cputype & CPU_ID_SCHEME_MASK) {
222 case CPU_ID_CORTEXA5:
223 case CPU_ID_CORTEXA7:
224 case CPU_ID_CORTEXA8:
225 case CPU_ID_CORTEXA9:
226 case CPU_ID_CORTEXA12:
227 case CPU_ID_CORTEXA15:
228 case CPU_ID_CORTEXA53:
229 case CPU_ID_CORTEXA57:
230 case CPU_ID_CORTEXA72:
231 case CPU_ID_KRAIT300:
232 cpufuncs = cortexa_cpufuncs;
233 get_cachetype_cp15();
234 goto out;
235 default:
236 break;
237 }
238 #endif /* CPU_CORTEXA || CPU_KRAIT */
239
240 #if defined(CPU_MV_PJ4B)
241 if (cputype == CPU_ID_MV88SV581X_V7 ||
242 cputype == CPU_ID_MV88SV584X_V7 ||
243 cputype == CPU_ID_ARM_88SV581X_V7) {
244 cpufuncs = pj4bv7_cpufuncs;
245 get_cachetype_cp15();
246 goto out;
247 }
248 #endif /* CPU_MV_PJ4B */
249
250 /*
251 * Bzzzz. And the answer was ...
252 */
253 panic("No support for this CPU type (%08x) in kernel", cputype);
254 return(ARCHITECTURE_NOT_PRESENT);
255 out:
256 uma_set_cache_align_mask(arm_dcache_align_mask);
257 return (0);
258 }
259
260 /*
261 * CPU Setup code
262 */
263
264
265 #if defined(CPU_ARM1176) \
266 || defined(CPU_MV_PJ4B) \
267 || defined(CPU_CORTEXA) || defined(CPU_KRAIT)
268 static __inline void
cpu_scc_setup_ccnt(void)269 cpu_scc_setup_ccnt(void)
270 {
271 /* This is how you give userland access to the CCNT and PMCn
272 * registers.
273 * BEWARE! This gives write access also, which may not be what
274 * you want!
275 */
276 #ifdef _PMC_USER_READ_WRITE_
277 /* Set PMUSERENR[0] to allow userland access */
278 cp15_pmuserenr_set(1);
279 #endif
280 #if defined(CPU_ARM1176)
281 /* Set PMCR[2,0] to enable counters and reset CCNT */
282 cp15_pmcr_set(5);
283 #else
284 /* Set up the PMCCNTR register as a cyclecounter:
285 * Set PMINTENCLR to 0xFFFFFFFF to block interrupts
286 * Set PMCR[2,0] to enable counters and reset CCNT
287 * Set PMCNTENSET to 0x80000000 to enable CCNT */
288 cp15_pminten_clr(0xFFFFFFFF);
289 cp15_pmcr_set(5);
290 cp15_pmcnten_set(0x80000000);
291 #endif
292 }
293 #endif
294
295 #if defined(CPU_ARM1176)
296 static void
arm11x6_setup(void)297 arm11x6_setup(void)
298 {
299 uint32_t auxctrl, auxctrl_wax;
300 uint32_t tmp, tmp2;
301 uint32_t cpuid;
302
303 cpuid = cp15_midr_get();
304
305 auxctrl = 0;
306 auxctrl_wax = ~0;
307
308 /*
309 * Enable an errata workaround
310 */
311 if ((cpuid & CPU_ID_CPU_MASK) == CPU_ID_ARM1176JZS) { /* ARM1176JZSr0 */
312 auxctrl = ARM1176_AUXCTL_PHD;
313 auxctrl_wax = ~ARM1176_AUXCTL_PHD;
314 }
315
316 tmp = cp15_actlr_get();
317 tmp2 = tmp;
318 tmp &= auxctrl_wax;
319 tmp |= auxctrl;
320 if (tmp != tmp2)
321 cp15_actlr_set(tmp);
322
323 cpu_scc_setup_ccnt();
324 }
325 #endif /* CPU_ARM1176 */
326
327 #ifdef CPU_MV_PJ4B
328 static void
pj4bv7_setup(void)329 pj4bv7_setup(void)
330 {
331
332 pj4b_config();
333 cpu_scc_setup_ccnt();
334 }
335 #endif /* CPU_MV_PJ4B */
336
337 #if defined(CPU_CORTEXA) || defined(CPU_KRAIT)
338 static void
cortexa_setup(void)339 cortexa_setup(void)
340 {
341
342 cpu_scc_setup_ccnt();
343 }
344 #endif /* CPU_CORTEXA || CPU_KRAIT */
345