]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/arm/cpufunc.c
arm: remove interrupt nesting by ipi_preempt()/ipi_hardclock()
[FreeBSD/FreeBSD.git] / sys / arm / arm / cpufunc.c
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$");
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
66 int     arm_dcache_align;
67 int     arm_dcache_align_mask;
68
69 #ifdef CPU_MV_PJ4B
70 static void pj4bv7_setup(void);
71 #endif
72 #if defined(CPU_ARM1176)
73 static void arm11x6_setup(void);
74 #endif
75 #if defined(CPU_CORTEXA) || defined(CPU_KRAIT)
76 static void cortexa_setup(void);
77 #endif
78
79 #ifdef CPU_MV_PJ4B
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,
87
88         /* Other functions */
89         .cf_sleep = (void *)cpufunc_nullop,
90
91         /* Soft functions */
92         .cf_setup = pj4bv7_setup
93 };
94 #endif /* CPU_MV_PJ4B */
95
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,
104
105         /* Other functions */
106         .cf_sleep = arm11x6_sleep, 
107
108         /* Soft functions */
109         .cf_setup = arm11x6_setup
110 };
111 #endif /*CPU_ARM1176 */
112
113 #if defined(CPU_CORTEXA) || defined(CPU_KRAIT)
114 struct cpu_functions cortexa_cpufuncs = {
115         /* Cache operations */
116
117         /*
118          * Note: For CPUs using the PL310 the L2 ops are filled in when the
119          * L2 cache controller is actually enabled.
120          */
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,
126
127         /* Other functions */
128         .cf_sleep = armv7_cpu_sleep,
129
130         /* Soft functions */
131         .cf_setup = cortexa_setup
132 };
133 #endif /* CPU_CORTEXA || CPU_KRAIT */
134
135 /*
136  * Global constants also used by locore.s
137  */
138
139 struct cpu_functions cpufuncs;
140 u_int cputype;
141
142 static void get_cachetype_cp15(void);
143
144 static void
145 get_cachetype_cp15(void)
146 {
147         u_int ctype, dsize, cpuid;
148         u_int clevel, csize, i, sel;
149         u_char type;
150
151         ctype = cp15_ctr_get();
152         cpuid = cp15_midr_get();
153         /*
154          * ...and thus spake the ARM ARM:
155          *
156          * If an <opcode2> value corresponding to an unimplemented or
157          * reserved ID register is encountered, the System Control
158          * processor returns the value of the main ID register.
159          */
160         if (ctype == cpuid)
161                 goto out;
162
163         if (CPU_CT_FORMAT(ctype) == CPU_CT_ARMV7) {
164                 __asm __volatile("mrc p15, 1, %0, c0, c0, 1"
165                     : "=r" (clevel));
166                 i = 0;
167                 while ((type = (clevel & 0x7)) && i < 7) {
168                         if (type == CACHE_DCACHE || type == CACHE_UNI_CACHE ||
169                             type == CACHE_SEP_CACHE) {
170                                 sel = i << 1;
171                                 __asm __volatile("mcr p15, 2, %0, c0, c0, 0"
172                                     : : "r" (sel));
173                                 __asm __volatile("mrc p15, 1, %0, c0, c0, 0"
174                                     : "=r" (csize));
175                                 arm_dcache_align = 1 <<
176                                     (CPUV7_CT_xSIZE_LEN(csize) + 4);
177                                 arm_dcache_align_mask = arm_dcache_align - 1;
178                         }
179                         if (type == CACHE_ICACHE || type == CACHE_SEP_CACHE) {
180                                 sel = (i << 1) | 1;
181                                 __asm __volatile("mcr p15, 2, %0, c0, c0, 0"
182                                     : : "r" (sel));
183                                 __asm __volatile("mrc p15, 1, %0, c0, c0, 0"
184                                     : "=r" (csize));
185                         }
186                         i++;
187                         clevel >>= 3;
188                 }
189         } else {
190                 /*
191                  * If you want to know how this code works, go read the ARM ARM.
192                  */
193
194                 dsize = CPU_CT_DSIZE(ctype);
195                 arm_dcache_align = 1U << (CPU_CT_xSIZE_LEN(dsize) + 3);
196                 if (CPU_CT_xSIZE_ASSOC(dsize) == 0) {
197                         if (dsize & CPU_CT_xSIZE_M)
198                                 arm_dcache_align = 0; /* not present */
199                 }
200
201         out:
202                 arm_dcache_align_mask = arm_dcache_align - 1;
203         }
204 }
205
206 /*
207  * Cannot panic here as we may not have a console yet ...
208  */
209
210 int
211 set_cpufuncs(void)
212 {
213         cputype = cp15_midr_get();
214         cputype &= CPU_ID_CPU_MASK;
215
216 #if defined(CPU_ARM1176)
217         if (cputype == CPU_ID_ARM1176JZS) {
218                 cpufuncs = arm1176_cpufuncs;
219                 get_cachetype_cp15();
220                 goto out;
221         }
222 #endif /* CPU_ARM1176 */
223 #if defined(CPU_CORTEXA) || defined(CPU_KRAIT)
224         switch(cputype & CPU_ID_SCHEME_MASK) {
225         case CPU_ID_CORTEXA5:
226         case CPU_ID_CORTEXA7:
227         case CPU_ID_CORTEXA8:
228         case CPU_ID_CORTEXA9:
229         case CPU_ID_CORTEXA12:
230         case CPU_ID_CORTEXA15:
231         case CPU_ID_CORTEXA53:
232         case CPU_ID_CORTEXA57:
233         case CPU_ID_CORTEXA72:
234         case CPU_ID_KRAIT300:
235                 cpufuncs = cortexa_cpufuncs;
236                 get_cachetype_cp15();
237                 goto out;
238         default:
239                 break;
240         }
241 #endif /* CPU_CORTEXA || CPU_KRAIT */
242
243 #if defined(CPU_MV_PJ4B)
244         if (cputype == CPU_ID_MV88SV581X_V7 ||
245             cputype == CPU_ID_MV88SV584X_V7 ||
246             cputype == CPU_ID_ARM_88SV581X_V7) {
247                 cpufuncs = pj4bv7_cpufuncs;
248                 get_cachetype_cp15();
249                 goto out;
250         }
251 #endif /* CPU_MV_PJ4B */
252
253         /*
254          * Bzzzz. And the answer was ...
255          */
256         panic("No support for this CPU type (%08x) in kernel", cputype);
257         return(ARCHITECTURE_NOT_PRESENT);
258 out:
259         uma_set_align(arm_dcache_align_mask);
260         return (0);
261 }
262
263 /*
264  * CPU Setup code
265  */
266
267
268 #if defined(CPU_ARM1176) \
269  || defined(CPU_MV_PJ4B) \
270  || defined(CPU_CORTEXA) || defined(CPU_KRAIT)
271 static __inline void
272 cpu_scc_setup_ccnt(void)
273 {
274 /* This is how you give userland access to the CCNT and PMCn
275  * registers.
276  * BEWARE! This gives write access also, which may not be what
277  * you want!
278  */
279 #ifdef _PMC_USER_READ_WRITE_
280         /* Set PMUSERENR[0] to allow userland access */
281         cp15_pmuserenr_set(1);
282 #endif
283 #if defined(CPU_ARM1176)
284         /* Set PMCR[2,0] to enable counters and reset CCNT */
285         cp15_pmcr_set(5);
286 #else
287         /* Set up the PMCCNTR register as a cyclecounter:
288          * Set PMINTENCLR to 0xFFFFFFFF to block interrupts
289          * Set PMCR[2,0] to enable counters and reset CCNT
290          * Set PMCNTENSET to 0x80000000 to enable CCNT */
291         cp15_pminten_clr(0xFFFFFFFF);
292         cp15_pmcr_set(5);
293         cp15_pmcnten_set(0x80000000);
294 #endif
295 }
296 #endif
297
298 #if defined(CPU_ARM1176)
299 static void
300 arm11x6_setup(void)
301 {
302         uint32_t auxctrl, auxctrl_wax;
303         uint32_t tmp, tmp2;
304         uint32_t cpuid;
305
306         cpuid = cp15_midr_get();
307
308         auxctrl = 0;
309         auxctrl_wax = ~0;
310
311         /*
312          * Enable an errata workaround
313          */
314         if ((cpuid & CPU_ID_CPU_MASK) == CPU_ID_ARM1176JZS) { /* ARM1176JZSr0 */
315                 auxctrl = ARM1176_AUXCTL_PHD;
316                 auxctrl_wax = ~ARM1176_AUXCTL_PHD;
317         }
318
319         tmp = cp15_actlr_get();
320         tmp2 = tmp;
321         tmp &= auxctrl_wax;
322         tmp |= auxctrl;
323         if (tmp != tmp2)
324                 cp15_actlr_set(tmp);
325
326         cpu_scc_setup_ccnt();
327 }
328 #endif  /* CPU_ARM1176 */
329
330 #ifdef CPU_MV_PJ4B
331 static void
332 pj4bv7_setup(void)
333 {
334
335         pj4b_config();
336         cpu_scc_setup_ccnt();
337 }
338 #endif /* CPU_MV_PJ4B */
339
340 #if defined(CPU_CORTEXA) || defined(CPU_KRAIT)
341 static void
342 cortexa_setup(void)
343 {
344
345         cpu_scc_setup_ccnt();
346 }
347 #endif  /* CPU_CORTEXA || CPU_KRAIT */