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 #include <sys/cdefs.h>
47 __FBSDID("$FreeBSD: stable/12/sys/arm/arm/cpufunc.c 336834 2018-07-28 17:21:34Z andrew $");
48
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/lock.h>
52 #include <sys/mutex.h>
53 #include <sys/bus.h>
54 #include <machine/bus.h>
55 #include <machine/cpu.h>
56 #include <machine/disassem.h>
57
58 #include <vm/vm.h>
59 #include <vm/pmap.h>
60 #include <vm/uma.h>
61
62 #include <machine/cpufunc.h>
63
64 /* PRIMARY CACHE VARIABLES */
65 int arm_picache_size;
66 int arm_picache_line_size;
67 int arm_picache_ways;
68
69 int arm_pdcache_size; /* and unified */
70 int arm_pdcache_line_size;
71 int arm_pdcache_ways;
72
73 int arm_pcache_type;
74 int arm_pcache_unified;
75
76 int arm_dcache_align;
77 int arm_dcache_align_mask;
78
79 u_int arm_cache_level;
80 u_int arm_cache_type[14];
81 u_int arm_cache_loc;
82
83 #if defined(CPU_ARM9E)
84 static void arm10_setup(void);
85 #endif
86 #ifdef CPU_MV_PJ4B
87 static void pj4bv7_setup(void);
88 #endif
89 #if defined(CPU_ARM1176)
90 static void arm11x6_setup(void);
91 #endif
92 #if defined(CPU_CORTEXA) || defined(CPU_KRAIT)
93 static void cortexa_setup(void);
94 #endif
95
96 #if defined(CPU_ARM9E)
97 struct cpu_functions armv5_ec_cpufuncs = {
98 /* CPU functions */
99
100 cpufunc_nullop, /* cpwait */
101
102 /* MMU functions */
103
104 cpufunc_control, /* control */
105 armv5_ec_setttb, /* Setttb */
106
107 /* TLB functions */
108
109 armv4_tlb_flushID, /* tlb_flushID */
110 arm9_tlb_flushID_SE, /* tlb_flushID_SE */
111 armv4_tlb_flushD, /* tlb_flushD */
112 armv4_tlb_flushD_SE, /* tlb_flushD_SE */
113
114 /* Cache operations */
115
116 armv5_ec_icache_sync_range, /* icache_sync_range */
117
118 armv5_ec_dcache_wbinv_all, /* dcache_wbinv_all */
119 armv5_ec_dcache_wbinv_range, /* dcache_wbinv_range */
120 armv5_ec_dcache_inv_range, /* dcache_inv_range */
121 armv5_ec_dcache_wb_range, /* dcache_wb_range */
122
123 armv4_idcache_inv_all, /* idcache_inv_all */
124 armv5_ec_idcache_wbinv_all, /* idcache_wbinv_all */
125 armv5_ec_idcache_wbinv_range, /* idcache_wbinv_range */
126
127 cpufunc_nullop, /* l2cache_wbinv_all */
128 (void *)cpufunc_nullop, /* l2cache_wbinv_range */
129 (void *)cpufunc_nullop, /* l2cache_inv_range */
130 (void *)cpufunc_nullop, /* l2cache_wb_range */
131 (void *)cpufunc_nullop, /* l2cache_drain_writebuf */
132
133 /* Other functions */
134
135 armv4_drain_writebuf, /* drain_writebuf */
136
137 (void *)cpufunc_nullop, /* sleep */
138
139 /* Soft functions */
140
141 arm9_context_switch, /* context_switch */
142
143 arm10_setup /* cpu setup */
144
145 };
146
147 struct cpu_functions sheeva_cpufuncs = {
148 /* CPU functions */
149
150 cpufunc_nullop, /* cpwait */
151
152 /* MMU functions */
153
154 cpufunc_control, /* control */
155 sheeva_setttb, /* Setttb */
156
157 /* TLB functions */
158
159 armv4_tlb_flushID, /* tlb_flushID */
160 arm9_tlb_flushID_SE, /* tlb_flushID_SE */
161 armv4_tlb_flushD, /* tlb_flushD */
162 armv4_tlb_flushD_SE, /* tlb_flushD_SE */
163
164 /* Cache operations */
165
166 armv5_ec_icache_sync_range, /* icache_sync_range */
167
168 armv5_ec_dcache_wbinv_all, /* dcache_wbinv_all */
169 sheeva_dcache_wbinv_range, /* dcache_wbinv_range */
170 sheeva_dcache_inv_range, /* dcache_inv_range */
171 sheeva_dcache_wb_range, /* dcache_wb_range */
172
173 armv4_idcache_inv_all, /* idcache_inv_all */
174 armv5_ec_idcache_wbinv_all, /* idcache_wbinv_all */
175 sheeva_idcache_wbinv_range, /* idcache_wbinv_all */
176
177 sheeva_l2cache_wbinv_all, /* l2cache_wbinv_all */
178 sheeva_l2cache_wbinv_range, /* l2cache_wbinv_range */
179 sheeva_l2cache_inv_range, /* l2cache_inv_range */
180 sheeva_l2cache_wb_range, /* l2cache_wb_range */
181 (void *)cpufunc_nullop, /* l2cache_drain_writebuf */
182
183 /* Other functions */
184
185 armv4_drain_writebuf, /* drain_writebuf */
186
187 sheeva_cpu_sleep, /* sleep */
188
189 /* Soft functions */
190
191 arm9_context_switch, /* context_switch */
192
193 arm10_setup /* cpu setup */
194 };
195 #endif /* CPU_ARM9E */
196
197 #ifdef CPU_MV_PJ4B
198 struct cpu_functions pj4bv7_cpufuncs = {
199
200 /* Cache operations */
201 .cf_l2cache_wbinv_all = (void *)cpufunc_nullop,
202 .cf_l2cache_wbinv_range = (void *)cpufunc_nullop,
203 .cf_l2cache_inv_range = (void *)cpufunc_nullop,
204 .cf_l2cache_wb_range = (void *)cpufunc_nullop,
205 .cf_l2cache_drain_writebuf = (void *)cpufunc_nullop,
206
207 /* Other functions */
208 .cf_sleep = (void *)cpufunc_nullop,
209
210 /* Soft functions */
211 .cf_setup = pj4bv7_setup
212 };
213 #endif /* CPU_MV_PJ4B */
214
215 #if defined(CPU_ARM1176)
216 struct cpu_functions arm1176_cpufuncs = {
217
218 /* Cache operations */
219 .cf_l2cache_wbinv_all = (void *)cpufunc_nullop,
220 .cf_l2cache_wbinv_range = (void *)cpufunc_nullop,
221 .cf_l2cache_inv_range = (void *)cpufunc_nullop,
222 .cf_l2cache_wb_range = (void *)cpufunc_nullop,
223 .cf_l2cache_drain_writebuf = (void *)cpufunc_nullop,
224
225 /* Other functions */
226 .cf_sleep = arm11x6_sleep,
227
228 /* Soft functions */
229 .cf_setup = arm11x6_setup
230 };
231 #endif /*CPU_ARM1176 */
232
233 #if defined(CPU_CORTEXA) || defined(CPU_KRAIT)
234 struct cpu_functions cortexa_cpufuncs = {
235
236 /* Cache operations */
237
238 /*
239 * Note: For CPUs using the PL310 the L2 ops are filled in when the
240 * L2 cache controller is actually enabled.
241 */
242 .cf_l2cache_wbinv_all = cpufunc_nullop,
243 .cf_l2cache_wbinv_range = (void *)cpufunc_nullop,
244 .cf_l2cache_inv_range = (void *)cpufunc_nullop,
245 .cf_l2cache_wb_range = (void *)cpufunc_nullop,
246 .cf_l2cache_drain_writebuf = (void *)cpufunc_nullop,
247
248 /* Other functions */
249 .cf_sleep = armv7_cpu_sleep,
250
251 /* Soft functions */
252 .cf_setup = cortexa_setup
253 };
254 #endif /* CPU_CORTEXA || CPU_KRAIT */
255
256 /*
257 * Global constants also used by locore.s
258 */
259
260 struct cpu_functions cpufuncs;
261 u_int cputype;
262 #if __ARM_ARCH <= 5
263 u_int cpu_reset_needs_v4_MMU_disable; /* flag used in locore-v4.s */
264 #endif
265
266 #if defined (CPU_ARM9E) || \
267 defined(CPU_ARM1176) || \
268 defined(CPU_MV_PJ4B) || \
269 defined(CPU_CORTEXA) || defined(CPU_KRAIT)
270
271 static void get_cachetype_cp15(void);
272
273 /* Additional cache information local to this file. Log2 of some of the
274 above numbers. */
275 static int arm_dcache_l2_nsets;
276 static int arm_dcache_l2_assoc;
277 static int arm_dcache_l2_linesize;
278
279 static void
get_cachetype_cp15(void)280 get_cachetype_cp15(void)
281 {
282 u_int ctype, isize, dsize, cpuid;
283 u_int clevel, csize, i, sel;
284 u_int multiplier;
285 u_char type;
286
287 ctype = cp15_ctr_get();
288 cpuid = cp15_midr_get();
289 /*
290 * ...and thus spake the ARM ARM:
291 *
292 * If an <opcode2> value corresponding to an unimplemented or
293 * reserved ID register is encountered, the System Control
294 * processor returns the value of the main ID register.
295 */
296 if (ctype == cpuid)
297 goto out;
298
299 if (CPU_CT_FORMAT(ctype) == CPU_CT_ARMV7) {
300 __asm __volatile("mrc p15, 1, %0, c0, c0, 1"
301 : "=r" (clevel));
302 arm_cache_level = clevel;
303 arm_cache_loc = CPU_CLIDR_LOC(arm_cache_level);
304 i = 0;
305 while ((type = (clevel & 0x7)) && i < 7) {
306 if (type == CACHE_DCACHE || type == CACHE_UNI_CACHE ||
307 type == CACHE_SEP_CACHE) {
308 sel = i << 1;
309 __asm __volatile("mcr p15, 2, %0, c0, c0, 0"
310 : : "r" (sel));
311 __asm __volatile("mrc p15, 1, %0, c0, c0, 0"
312 : "=r" (csize));
313 arm_cache_type[sel] = csize;
314 arm_dcache_align = 1 <<
315 (CPUV7_CT_xSIZE_LEN(csize) + 4);
316 arm_dcache_align_mask = arm_dcache_align - 1;
317 }
318 if (type == CACHE_ICACHE || type == CACHE_SEP_CACHE) {
319 sel = (i << 1) | 1;
320 __asm __volatile("mcr p15, 2, %0, c0, c0, 0"
321 : : "r" (sel));
322 __asm __volatile("mrc p15, 1, %0, c0, c0, 0"
323 : "=r" (csize));
324 arm_cache_type[sel] = csize;
325 }
326 i++;
327 clevel >>= 3;
328 }
329 } else {
330 if ((ctype & CPU_CT_S) == 0)
331 arm_pcache_unified = 1;
332
333 /*
334 * If you want to know how this code works, go read the ARM ARM.
335 */
336
337 arm_pcache_type = CPU_CT_CTYPE(ctype);
338
339 if (arm_pcache_unified == 0) {
340 isize = CPU_CT_ISIZE(ctype);
341 multiplier = (isize & CPU_CT_xSIZE_M) ? 3 : 2;
342 arm_picache_line_size = 1U << (CPU_CT_xSIZE_LEN(isize) + 3);
343 if (CPU_CT_xSIZE_ASSOC(isize) == 0) {
344 if (isize & CPU_CT_xSIZE_M)
345 arm_picache_line_size = 0; /* not present */
346 else
347 arm_picache_ways = 1;
348 } else {
349 arm_picache_ways = multiplier <<
350 (CPU_CT_xSIZE_ASSOC(isize) - 1);
351 }
352 arm_picache_size = multiplier << (CPU_CT_xSIZE_SIZE(isize) + 8);
353 }
354
355 dsize = CPU_CT_DSIZE(ctype);
356 multiplier = (dsize & CPU_CT_xSIZE_M) ? 3 : 2;
357 arm_pdcache_line_size = 1U << (CPU_CT_xSIZE_LEN(dsize) + 3);
358 if (CPU_CT_xSIZE_ASSOC(dsize) == 0) {
359 if (dsize & CPU_CT_xSIZE_M)
360 arm_pdcache_line_size = 0; /* not present */
361 else
362 arm_pdcache_ways = 1;
363 } else {
364 arm_pdcache_ways = multiplier <<
365 (CPU_CT_xSIZE_ASSOC(dsize) - 1);
366 }
367 arm_pdcache_size = multiplier << (CPU_CT_xSIZE_SIZE(dsize) + 8);
368
369 arm_dcache_align = arm_pdcache_line_size;
370
371 arm_dcache_l2_assoc = CPU_CT_xSIZE_ASSOC(dsize) + multiplier - 2;
372 arm_dcache_l2_linesize = CPU_CT_xSIZE_LEN(dsize) + 3;
373 arm_dcache_l2_nsets = 6 + CPU_CT_xSIZE_SIZE(dsize) -
374 CPU_CT_xSIZE_ASSOC(dsize) - CPU_CT_xSIZE_LEN(dsize);
375
376 out:
377 arm_dcache_align_mask = arm_dcache_align - 1;
378 }
379 }
380 #endif /* ARM9 || XSCALE */
381
382 /*
383 * Cannot panic here as we may not have a console yet ...
384 */
385
386 int
set_cpufuncs(void)387 set_cpufuncs(void)
388 {
389 cputype = cp15_midr_get();
390 cputype &= CPU_ID_CPU_MASK;
391
392 #if defined(CPU_ARM9E)
393 if (cputype == CPU_ID_MV88FR131 || cputype == CPU_ID_MV88FR571_VD ||
394 cputype == CPU_ID_MV88FR571_41) {
395 uint32_t sheeva_ctrl;
396
397 sheeva_ctrl = (MV_DC_STREAM_ENABLE | MV_BTB_DISABLE |
398 MV_L2_ENABLE);
399 /*
400 * Workaround for Marvell MV78100 CPU: Cache prefetch
401 * mechanism may affect the cache coherency validity,
402 * so it needs to be disabled.
403 *
404 * Refer to errata document MV-S501058-00C.pdf (p. 3.1
405 * L2 Prefetching Mechanism) for details.
406 */
407 if (cputype == CPU_ID_MV88FR571_VD ||
408 cputype == CPU_ID_MV88FR571_41)
409 sheeva_ctrl |= MV_L2_PREFETCH_DISABLE;
410
411 sheeva_control_ext(0xffffffff & ~MV_WA_ENABLE, sheeva_ctrl);
412
413 cpufuncs = sheeva_cpufuncs;
414 get_cachetype_cp15();
415 pmap_pte_init_generic();
416 goto out;
417 } else if (cputype == CPU_ID_ARM926EJS) {
418 cpufuncs = armv5_ec_cpufuncs;
419 get_cachetype_cp15();
420 pmap_pte_init_generic();
421 goto out;
422 }
423 #endif /* CPU_ARM9E */
424 #if defined(CPU_ARM1176)
425 if (cputype == CPU_ID_ARM1176JZS) {
426 cpufuncs = arm1176_cpufuncs;
427 get_cachetype_cp15();
428 goto out;
429 }
430 #endif /* CPU_ARM1176 */
431 #if defined(CPU_CORTEXA) || defined(CPU_KRAIT)
432 switch(cputype & CPU_ID_SCHEME_MASK) {
433 case CPU_ID_CORTEXA5:
434 case CPU_ID_CORTEXA7:
435 case CPU_ID_CORTEXA8:
436 case CPU_ID_CORTEXA9:
437 case CPU_ID_CORTEXA12:
438 case CPU_ID_CORTEXA15:
439 case CPU_ID_CORTEXA53:
440 case CPU_ID_CORTEXA57:
441 case CPU_ID_CORTEXA72:
442 case CPU_ID_KRAIT300:
443 cpufuncs = cortexa_cpufuncs;
444 get_cachetype_cp15();
445 goto out;
446 default:
447 break;
448 }
449 #endif /* CPU_CORTEXA || CPU_KRAIT */
450
451 #if defined(CPU_MV_PJ4B)
452 if (cputype == CPU_ID_MV88SV581X_V7 ||
453 cputype == CPU_ID_MV88SV584X_V7 ||
454 cputype == CPU_ID_ARM_88SV581X_V7) {
455 cpufuncs = pj4bv7_cpufuncs;
456 get_cachetype_cp15();
457 goto out;
458 }
459 #endif /* CPU_MV_PJ4B */
460
461 /*
462 * Bzzzz. And the answer was ...
463 */
464 panic("No support for this CPU type (%08x) in kernel", cputype);
465 return(ARCHITECTURE_NOT_PRESENT);
466 out:
467 uma_set_align(arm_dcache_align_mask);
468 return (0);
469 }
470
471 /*
472 * CPU Setup code
473 */
474
475 #if defined(CPU_ARM9E)
476 static void
arm10_setup(void)477 arm10_setup(void)
478 {
479 int cpuctrl, cpuctrlmask;
480
481 cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_SYST_ENABLE
482 | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE
483 | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_BPRD_ENABLE;
484 cpuctrlmask = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_SYST_ENABLE
485 | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE
486 | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_ROM_ENABLE
487 | CPU_CONTROL_BEND_ENABLE | CPU_CONTROL_AFLT_ENABLE
488 | CPU_CONTROL_BPRD_ENABLE
489 | CPU_CONTROL_ROUNDROBIN | CPU_CONTROL_CPCLK;
490
491 #ifndef ARM32_DISABLE_ALIGNMENT_FAULTS
492 cpuctrl |= CPU_CONTROL_AFLT_ENABLE;
493 #endif
494
495 #ifdef __ARMEB__
496 cpuctrl |= CPU_CONTROL_BEND_ENABLE;
497 #endif
498
499 /* Clear out the cache */
500 cpu_idcache_wbinv_all();
501
502 /* Now really make sure they are clean. */
503 __asm __volatile ("mcr\tp15, 0, r0, c7, c7, 0" : : );
504
505 if (vector_page == ARM_VECTORS_HIGH)
506 cpuctrl |= CPU_CONTROL_VECRELOC;
507
508 /* Set the control register */
509 cpu_control(0xffffffff, cpuctrl);
510
511 /* And again. */
512 cpu_idcache_wbinv_all();
513 }
514 #endif /* CPU_ARM9E || CPU_ARM10 */
515
516 #if defined(CPU_ARM1176) \
517 || defined(CPU_MV_PJ4B) \
518 || defined(CPU_CORTEXA) || defined(CPU_KRAIT)
519 static __inline void
cpu_scc_setup_ccnt(void)520 cpu_scc_setup_ccnt(void)
521 {
522 /* This is how you give userland access to the CCNT and PMCn
523 * registers.
524 * BEWARE! This gives write access also, which may not be what
525 * you want!
526 */
527 #ifdef _PMC_USER_READ_WRITE_
528 /* Set PMUSERENR[0] to allow userland access */
529 cp15_pmuserenr_set(1);
530 #endif
531 #if defined(CPU_ARM1176)
532 /* Set PMCR[2,0] to enable counters and reset CCNT */
533 cp15_pmcr_set(5);
534 #else
535 /* Set up the PMCCNTR register as a cyclecounter:
536 * Set PMINTENCLR to 0xFFFFFFFF to block interrupts
537 * Set PMCR[2,0] to enable counters and reset CCNT
538 * Set PMCNTENSET to 0x80000000 to enable CCNT */
539 cp15_pminten_clr(0xFFFFFFFF);
540 cp15_pmcr_set(5);
541 cp15_pmcnten_set(0x80000000);
542 #endif
543 }
544 #endif
545
546 #if defined(CPU_ARM1176)
547 static void
arm11x6_setup(void)548 arm11x6_setup(void)
549 {
550 uint32_t auxctrl, auxctrl_wax;
551 uint32_t tmp, tmp2;
552 uint32_t cpuid;
553
554 cpuid = cp15_midr_get();
555
556 auxctrl = 0;
557 auxctrl_wax = ~0;
558
559 /*
560 * Enable an errata workaround
561 */
562 if ((cpuid & CPU_ID_CPU_MASK) == CPU_ID_ARM1176JZS) { /* ARM1176JZSr0 */
563 auxctrl = ARM1176_AUXCTL_PHD;
564 auxctrl_wax = ~ARM1176_AUXCTL_PHD;
565 }
566
567 tmp = cp15_actlr_get();
568 tmp2 = tmp;
569 tmp &= auxctrl_wax;
570 tmp |= auxctrl;
571 if (tmp != tmp2)
572 cp15_actlr_set(tmp);
573
574 cpu_scc_setup_ccnt();
575 }
576 #endif /* CPU_ARM1176 */
577
578 #ifdef CPU_MV_PJ4B
579 static void
pj4bv7_setup(void)580 pj4bv7_setup(void)
581 {
582
583 pj4b_config();
584 cpu_scc_setup_ccnt();
585 }
586 #endif /* CPU_MV_PJ4B */
587
588 #if defined(CPU_CORTEXA) || defined(CPU_KRAIT)
589 static void
cortexa_setup(void)590 cortexa_setup(void)
591 {
592
593 cpu_scc_setup_ccnt();
594 }
595 #endif /* CPU_CORTEXA || CPU_KRAIT */
596