xref: /haiku/src/system/boot/arch/arm/arch_cpu.cpp (revision e81a954787e50e56a7f06f72705b7859b6ab06d1)
1 /*
2  * Copyright 2012, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Ithamar R. Adema <ithamar@upgrade-android.com>
7  */
8 
9 #include "cpu.h"
10 
11 #include <OS.h>
12 #include <boot/platform.h>
13 #include <boot/stdio.h>
14 #include <boot/kernel_args.h>
15 #include <boot/stage2.h>
16 #include <arch/cpu.h>
17 #include <arch_kernel.h>
18 #include <arch_system_info.h>
19 #include <arch_cpu.h>
20 #include <string.h>
21 
22 #define TRACE_CPU
23 #ifdef TRACE_CPU
24 #	define TRACE(x) dprintf x
25 #else
26 #	define TRACE(x) ;
27 #endif
28 
29 /*! Detect ARM core version and features.
30     Please note the fact that ARM7 and ARMv7 are two different things ;)
31     ARMx is a specific ARM CPU core instance, while ARMvX refers to the
32     ARM architecture specification version....
33 
34     Most of the architecture versions we're detecting here we will probably
35     never run on, just included for completeness sake... ARMv5 and up are
36     the likely ones for us to support (as they all have some kind of MMU).
37 */
38 static status_t
39 check_cpu_features()
40 {
41 	uint32 result = 0;
42 	int arch = 0;
43 	int variant = 0;
44 	int part = 0;
45 	int revision = 0;
46 	int implementor = 0;
47 
48 	asm volatile("MRC p15, 0, %[c1out], c0, c0, 0":[c1out] "=r" (result));
49 
50 	implementor = (result >> 24) & 0xff;
51 
52 	switch ((result >> 12) & 0xf) {
53 		case 0:	/* early ARMv3 or even older */
54 			arch = ARCH_ARM_PRE_ARM7;
55 			break;
56 
57 		case 7:	/* ARM7 processor */
58 			arch = (result & (1 << 23)) ? ARCH_ARM_v4T : ARCH_ARM_v3;
59 			variant = (result >> 16) & 0x7f;
60 			part = (result >> 4) & 0xfff;
61 			revision = result & 0xf;
62 			break;
63 
64 		default:
65 			revision = result & 0xf;
66 			part = (result >> 4) & 0xfff;
67 			switch((result >> 16) & 0xf) {
68 				case 1: arch = ARCH_ARM_v4; break;
69 				case 2: arch = ARCH_ARM_v4T; break;
70 				case 3: arch = ARCH_ARM_v5; break;
71 				case 4: arch = ARCH_ARM_v5T; break;
72 				case 5: arch = ARCH_ARM_v5TE; break;
73 				case 6: arch = ARCH_ARM_v5TEJ; break;
74 				case 7: arch = ARCH_ARM_v6; break;
75 				case 0xf:
76 					arch = ARCH_ARM_v7;
77 					// TODO ... or later. We apparently need to scan the
78 					// CPUID registers to decide.
79 					break;
80 			}
81 			variant = (result >> 20) & 0xf;
82 			break;
83 	}
84 
85 	// TODO actually check for VFP support, and maybe there is a better place
86 	// to do this.
87 	if (arch >= ARCH_ARM_v7)
88 	{
89 		// Enable VFP/NEON. We HAVE to do this before the trace call below,
90 		// which is the first time we call vprintf. Otherwise, it will crash
91 		// when trying to push floating point registers on the stack.
92 		asm volatile(
93 		"	MRC p15, #0, r1, c1, c0, #2\n" // r1 = Access Control Register
94 		"	ORR r1, r1, #(0xf << 20)\n" // enable full access for p10,11
95 		"	MCR p15, #0, r1, c1, c0, #2\n" // Access Control Register = r1
96 		"	MOV r1, #0\n"
97 		"	MCR p15, #0, r1, c7, c5, #4\n" // flush prefetch buffer because of
98 			// FMXR below and CP 10 & 11 were only just enabled
99 		"	MOV r0,#0x40000000	\n" // Enable VFP itself
100 		"	FMXR FPEXC, r0" //FPEXC = r0
101 		:::"r0", "r1");
102 	}
103 
104 
105 	TRACE(("%s: implementor=0x%x('%c'), arch=%d, variant=0x%x, part=0x%x, revision=0x%x\n",
106 		__func__, implementor, implementor, arch, variant, part, revision));
107 
108 	return (arch < ARCH_ARM_v5) ? B_ERROR : B_OK;
109 }
110 
111 
112 extern "C" void
113 arch_cpu_memory_read_barrier(void)
114 {
115 	asm volatile ("" : : : "memory");
116 }
117 
118 
119 extern "C" void
120 arch_cpu_memory_write_barrier(void)
121 {
122 	asm volatile ("" : : : "memory");
123 }
124 
125 
126 extern "C" void
127 arch_spin(bigtime_t microseconds)
128 {
129 	panic("No timing support in bootloader yet!");
130 }
131 
132 
133 extern "C" status_t
134 boot_arch_cpu_init(void)
135 {
136 	status_t err = check_cpu_features();
137 	if (err != B_OK) {
138 		panic("Retire your old Acorn and get something modern to boot!\n");
139 		return err;
140 	}
141 
142 	gKernelArgs.num_cpus = 1;
143 		// this will eventually be corrected later on
144 
145 	return B_OK;
146 }
147