1 /* $NetBSD: cpufunc.c,v 1.65 2003/11/05 12:53:15 scw Exp $ */
4 * SPDX-License-Identifier: BSD-4-Clause
6 * arm9 support code Copyright (C) 2001 ARM Ltd
7 * Copyright (c) 1997 Mark Brinicombe.
8 * Copyright (c) 1997 Causality Limited
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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
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
38 * RiscBSD kernel project
42 * C functions for supporting CPU / MMU / TLB specific operations.
46 #include <sys/cdefs.h>
47 __FBSDID("$FreeBSD$");
49 #include <sys/param.h>
50 #include <sys/systm.h>
52 #include <sys/mutex.h>
54 #include <machine/bus.h>
55 #include <machine/cpu.h>
56 #include <machine/disassem.h>
62 #include <machine/cpufunc.h>
64 /* PRIMARY CACHE VARIABLES */
67 int arm_dcache_align_mask;
70 static void pj4bv7_setup(void);
72 #if defined(CPU_ARM1176)
73 static void arm11x6_setup(void);
75 #if defined(CPU_CORTEXA) || defined(CPU_KRAIT)
76 static void cortexa_setup(void);
80 struct cpu_functions pj4bv7_cpufuncs = {
81 /* Cache operations */
82 .cf_l2cache_wbinv_all = (void *)cpufunc_nullop,
83 .cf_l2cache_wbinv_range = (void *)cpufunc_nullop,
84 .cf_l2cache_inv_range = (void *)cpufunc_nullop,
85 .cf_l2cache_wb_range = (void *)cpufunc_nullop,
86 .cf_l2cache_drain_writebuf = (void *)cpufunc_nullop,
89 .cf_sleep = (void *)cpufunc_nullop,
92 .cf_setup = pj4bv7_setup
94 #endif /* CPU_MV_PJ4B */
96 #if defined(CPU_ARM1176)
97 struct cpu_functions arm1176_cpufuncs = {
98 /* Cache operations */
99 .cf_l2cache_wbinv_all = (void *)cpufunc_nullop,
100 .cf_l2cache_wbinv_range = (void *)cpufunc_nullop,
101 .cf_l2cache_inv_range = (void *)cpufunc_nullop,
102 .cf_l2cache_wb_range = (void *)cpufunc_nullop,
103 .cf_l2cache_drain_writebuf = (void *)cpufunc_nullop,
105 /* Other functions */
106 .cf_sleep = arm11x6_sleep,
109 .cf_setup = arm11x6_setup
111 #endif /*CPU_ARM1176 */
113 #if defined(CPU_CORTEXA) || defined(CPU_KRAIT)
114 struct cpu_functions cortexa_cpufuncs = {
115 /* Cache operations */
118 * Note: For CPUs using the PL310 the L2 ops are filled in when the
119 * L2 cache controller is actually enabled.
121 .cf_l2cache_wbinv_all = cpufunc_nullop,
122 .cf_l2cache_wbinv_range = (void *)cpufunc_nullop,
123 .cf_l2cache_inv_range = (void *)cpufunc_nullop,
124 .cf_l2cache_wb_range = (void *)cpufunc_nullop,
125 .cf_l2cache_drain_writebuf = (void *)cpufunc_nullop,
127 /* Other functions */
128 .cf_sleep = armv7_cpu_sleep,
131 .cf_setup = cortexa_setup
133 #endif /* CPU_CORTEXA || CPU_KRAIT */
136 * Global constants also used by locore.s
139 struct cpu_functions cpufuncs;
142 static void get_cachetype_cp15(void);
145 get_cachetype_cp15(void)
147 u_int ctype, dsize, cpuid;
148 u_int clevel, csize, i, sel;
152 ctype = cp15_ctr_get();
153 cpuid = cp15_midr_get();
155 * ...and thus spake the ARM ARM:
157 * If an <opcode2> value corresponding to an unimplemented or
158 * reserved ID register is encountered, the System Control
159 * processor returns the value of the main ID register.
164 if (CPU_CT_FORMAT(ctype) == CPU_CT_ARMV7) {
165 __asm __volatile("mrc p15, 1, %0, c0, c0, 1"
168 while ((type = (clevel & 0x7)) && i < 7) {
169 if (type == CACHE_DCACHE || type == CACHE_UNI_CACHE ||
170 type == CACHE_SEP_CACHE) {
172 __asm __volatile("mcr p15, 2, %0, c0, c0, 0"
174 __asm __volatile("mrc p15, 1, %0, c0, c0, 0"
176 arm_dcache_align = 1 <<
177 (CPUV7_CT_xSIZE_LEN(csize) + 4);
178 arm_dcache_align_mask = arm_dcache_align - 1;
180 if (type == CACHE_ICACHE || type == CACHE_SEP_CACHE) {
182 __asm __volatile("mcr p15, 2, %0, c0, c0, 0"
184 __asm __volatile("mrc p15, 1, %0, c0, c0, 0"
192 * If you want to know how this code works, go read the ARM ARM.
195 dsize = CPU_CT_DSIZE(ctype);
196 multiplier = (dsize & CPU_CT_xSIZE_M) ? 3 : 2;
197 arm_dcache_align = 1U << (CPU_CT_xSIZE_LEN(dsize) + 3);
198 if (CPU_CT_xSIZE_ASSOC(dsize) == 0) {
199 if (dsize & CPU_CT_xSIZE_M)
200 arm_dcache_align = 0; /* not present */
204 arm_dcache_align_mask = arm_dcache_align - 1;
209 * Cannot panic here as we may not have a console yet ...
215 cputype = cp15_midr_get();
216 cputype &= CPU_ID_CPU_MASK;
218 #if defined(CPU_ARM1176)
219 if (cputype == CPU_ID_ARM1176JZS) {
220 cpufuncs = arm1176_cpufuncs;
221 get_cachetype_cp15();
224 #endif /* CPU_ARM1176 */
225 #if defined(CPU_CORTEXA) || defined(CPU_KRAIT)
226 switch(cputype & CPU_ID_SCHEME_MASK) {
227 case CPU_ID_CORTEXA5:
228 case CPU_ID_CORTEXA7:
229 case CPU_ID_CORTEXA8:
230 case CPU_ID_CORTEXA9:
231 case CPU_ID_CORTEXA12:
232 case CPU_ID_CORTEXA15:
233 case CPU_ID_CORTEXA53:
234 case CPU_ID_CORTEXA57:
235 case CPU_ID_CORTEXA72:
236 case CPU_ID_KRAIT300:
237 cpufuncs = cortexa_cpufuncs;
238 get_cachetype_cp15();
243 #endif /* CPU_CORTEXA || CPU_KRAIT */
245 #if defined(CPU_MV_PJ4B)
246 if (cputype == CPU_ID_MV88SV581X_V7 ||
247 cputype == CPU_ID_MV88SV584X_V7 ||
248 cputype == CPU_ID_ARM_88SV581X_V7) {
249 cpufuncs = pj4bv7_cpufuncs;
250 get_cachetype_cp15();
253 #endif /* CPU_MV_PJ4B */
256 * Bzzzz. And the answer was ...
258 panic("No support for this CPU type (%08x) in kernel", cputype);
259 return(ARCHITECTURE_NOT_PRESENT);
261 uma_set_align(arm_dcache_align_mask);
270 #if defined(CPU_ARM1176) \
271 || defined(CPU_MV_PJ4B) \
272 || defined(CPU_CORTEXA) || defined(CPU_KRAIT)
274 cpu_scc_setup_ccnt(void)
276 /* This is how you give userland access to the CCNT and PMCn
278 * BEWARE! This gives write access also, which may not be what
281 #ifdef _PMC_USER_READ_WRITE_
282 /* Set PMUSERENR[0] to allow userland access */
283 cp15_pmuserenr_set(1);
285 #if defined(CPU_ARM1176)
286 /* Set PMCR[2,0] to enable counters and reset CCNT */
289 /* Set up the PMCCNTR register as a cyclecounter:
290 * Set PMINTENCLR to 0xFFFFFFFF to block interrupts
291 * Set PMCR[2,0] to enable counters and reset CCNT
292 * Set PMCNTENSET to 0x80000000 to enable CCNT */
293 cp15_pminten_clr(0xFFFFFFFF);
295 cp15_pmcnten_set(0x80000000);
300 #if defined(CPU_ARM1176)
304 uint32_t auxctrl, auxctrl_wax;
308 cpuid = cp15_midr_get();
314 * Enable an errata workaround
316 if ((cpuid & CPU_ID_CPU_MASK) == CPU_ID_ARM1176JZS) { /* ARM1176JZSr0 */
317 auxctrl = ARM1176_AUXCTL_PHD;
318 auxctrl_wax = ~ARM1176_AUXCTL_PHD;
321 tmp = cp15_actlr_get();
328 cpu_scc_setup_ccnt();
330 #endif /* CPU_ARM1176 */
338 cpu_scc_setup_ccnt();
340 #endif /* CPU_MV_PJ4B */
342 #if defined(CPU_CORTEXA) || defined(CPU_KRAIT)
347 cpu_scc_setup_ccnt();
349 #endif /* CPU_CORTEXA || CPU_KRAIT */