1 | /* |
2 | * Copyright (c) 2007-2021 Apple Inc. All rights reserved. |
3 | * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. |
4 | */ |
5 | #include <pexpert/pexpert.h> |
6 | #include <pexpert/boot.h> |
7 | #include <pexpert/protos.h> |
8 | #include <pexpert/device_tree.h> |
9 | #include <pexpert/arm64/board_config.h> |
10 | |
11 | #include <machine/machine_routines.h> |
12 | |
13 | #include <kern/clock.h> |
14 | #include <kern/locks.h> |
15 | |
16 | /* Local declarations */ |
17 | void pe_identify_machine(boot_args * bootArgs); |
18 | |
19 | /* External declarations */ |
20 | extern void clean_mmu_dcache(void); |
21 | |
22 | static char *gPESoCDeviceType; |
23 | static char gPESoCDeviceTypeBuffer[SOC_DEVICE_TYPE_BUFFER_SIZE]; |
24 | static vm_offset_t gPESoCBasePhys; |
25 | |
26 | static uint32_t pe_arm_init_timer(void *args); |
27 | |
28 | |
29 | /* |
30 | * pe_identify_machine: |
31 | * |
32 | * Sets up platform parameters. Returns: nothing |
33 | */ |
34 | void |
35 | pe_identify_machine(boot_args * bootArgs) |
36 | { |
37 | OpaqueDTEntryIterator iter; |
38 | DTEntry cpus, cpu; |
39 | void const *value; |
40 | unsigned int size; |
41 | int err; |
42 | |
43 | (void)bootArgs; |
44 | |
45 | if (pe_arm_get_soc_base_phys() == 0) { |
46 | return; |
47 | } |
48 | |
49 | /* Clear the gPEClockFrequencyInfo struct */ |
50 | bzero(s: (void *)&gPEClockFrequencyInfo, n: sizeof(clock_frequency_info_t)); |
51 | |
52 | /* Start with default values. */ |
53 | gPEClockFrequencyInfo.timebase_frequency_hz = 24000000; |
54 | gPEClockFrequencyInfo.bus_clock_rate_hz = 100000000; |
55 | gPEClockFrequencyInfo.cpu_clock_rate_hz = 400000000; |
56 | |
57 | err = SecureDTLookupEntry(NULL, pathName: "/cpus" , foundEntry: &cpus); |
58 | assert(err == kSuccess); |
59 | |
60 | err = SecureDTInitEntryIterator(startEntry: cpus, iter: &iter); |
61 | assert(err == kSuccess); |
62 | |
63 | while (kSuccess == SecureDTIterateEntries(iterator: &iter, nextEntry: &cpu)) { |
64 | if ((kSuccess != SecureDTGetProperty(entry: cpu, propertyName: "state" , propertyValue: &value, propertySize: &size)) || |
65 | (strncmp(s1: (char const *)value, s2: "running" , n: size) != 0)) { |
66 | continue; |
67 | } |
68 | |
69 | /* Find the time base frequency first. */ |
70 | if (SecureDTGetProperty(entry: cpu, propertyName: "timebase-frequency" , propertyValue: &value, propertySize: &size) == kSuccess) { |
71 | /* |
72 | * timebase_frequency_hz is only 32 bits, and |
73 | * the device tree should never provide 64 |
74 | * bits so this if should never be taken. |
75 | */ |
76 | if (size == 8) { |
77 | gPEClockFrequencyInfo.timebase_frequency_hz = *(uint64_t const *)value; |
78 | } else { |
79 | gPEClockFrequencyInfo.timebase_frequency_hz = *(uint32_t const *)value; |
80 | } |
81 | } |
82 | gPEClockFrequencyInfo.dec_clock_rate_hz = gPEClockFrequencyInfo.timebase_frequency_hz; |
83 | |
84 | /* Find the bus frequency next. */ |
85 | if (SecureDTGetProperty(entry: cpu, propertyName: "bus-frequency" , propertyValue: &value, propertySize: &size) == kSuccess) { |
86 | if (size == 8) { |
87 | gPEClockFrequencyInfo.bus_frequency_hz = *(uint64_t const *)value; |
88 | } else { |
89 | gPEClockFrequencyInfo.bus_frequency_hz = *(uint32_t const *)value; |
90 | } |
91 | } |
92 | gPEClockFrequencyInfo.bus_frequency_min_hz = gPEClockFrequencyInfo.bus_frequency_hz; |
93 | gPEClockFrequencyInfo.bus_frequency_max_hz = gPEClockFrequencyInfo.bus_frequency_hz; |
94 | |
95 | if (gPEClockFrequencyInfo.bus_frequency_hz < 0x100000000ULL) { |
96 | gPEClockFrequencyInfo.bus_clock_rate_hz = gPEClockFrequencyInfo.bus_frequency_hz; |
97 | } else { |
98 | gPEClockFrequencyInfo.bus_clock_rate_hz = 0xFFFFFFFF; |
99 | } |
100 | |
101 | /* Find the memory frequency next. */ |
102 | if (SecureDTGetProperty(entry: cpu, propertyName: "memory-frequency" , propertyValue: &value, propertySize: &size) == kSuccess) { |
103 | if (size == 8) { |
104 | gPEClockFrequencyInfo.mem_frequency_hz = *(uint64_t const *)value; |
105 | } else { |
106 | gPEClockFrequencyInfo.mem_frequency_hz = *(uint32_t const *)value; |
107 | } |
108 | } |
109 | gPEClockFrequencyInfo.mem_frequency_min_hz = gPEClockFrequencyInfo.mem_frequency_hz; |
110 | gPEClockFrequencyInfo.mem_frequency_max_hz = gPEClockFrequencyInfo.mem_frequency_hz; |
111 | |
112 | /* Find the peripheral frequency next. */ |
113 | if (SecureDTGetProperty(entry: cpu, propertyName: "peripheral-frequency" , propertyValue: &value, propertySize: &size) == kSuccess) { |
114 | if (size == 8) { |
115 | gPEClockFrequencyInfo.prf_frequency_hz = *(uint64_t const *)value; |
116 | } else { |
117 | gPEClockFrequencyInfo.prf_frequency_hz = *(uint32_t const *)value; |
118 | } |
119 | } |
120 | gPEClockFrequencyInfo.prf_frequency_min_hz = gPEClockFrequencyInfo.prf_frequency_hz; |
121 | gPEClockFrequencyInfo.prf_frequency_max_hz = gPEClockFrequencyInfo.prf_frequency_hz; |
122 | |
123 | /* Find the fixed frequency next. */ |
124 | if (SecureDTGetProperty(entry: cpu, propertyName: "fixed-frequency" , propertyValue: &value, propertySize: &size) == kSuccess) { |
125 | if (size == 8) { |
126 | gPEClockFrequencyInfo.fix_frequency_hz = *(uint64_t const *)value; |
127 | } else { |
128 | gPEClockFrequencyInfo.fix_frequency_hz = *(uint32_t const *)value; |
129 | } |
130 | } |
131 | /* Find the cpu frequency last. */ |
132 | if (SecureDTGetProperty(entry: cpu, propertyName: "clock-frequency" , propertyValue: &value, propertySize: &size) == kSuccess) { |
133 | if (size == 8) { |
134 | gPEClockFrequencyInfo.cpu_frequency_hz = *(uint64_t const *)value; |
135 | } else { |
136 | gPEClockFrequencyInfo.cpu_frequency_hz = *(uint32_t const *)value; |
137 | } |
138 | } |
139 | gPEClockFrequencyInfo.cpu_frequency_min_hz = gPEClockFrequencyInfo.cpu_frequency_hz; |
140 | gPEClockFrequencyInfo.cpu_frequency_max_hz = gPEClockFrequencyInfo.cpu_frequency_hz; |
141 | |
142 | if (gPEClockFrequencyInfo.cpu_frequency_hz < 0x100000000ULL) { |
143 | gPEClockFrequencyInfo.cpu_clock_rate_hz = gPEClockFrequencyInfo.cpu_frequency_hz; |
144 | } else { |
145 | gPEClockFrequencyInfo.cpu_clock_rate_hz = 0xFFFFFFFF; |
146 | } |
147 | } |
148 | |
149 | /* Set the num / den pairs form the hz values. */ |
150 | gPEClockFrequencyInfo.bus_clock_rate_num = gPEClockFrequencyInfo.bus_clock_rate_hz; |
151 | gPEClockFrequencyInfo.bus_clock_rate_den = 1; |
152 | |
153 | gPEClockFrequencyInfo.bus_to_cpu_rate_num = |
154 | (2 * gPEClockFrequencyInfo.cpu_clock_rate_hz) / gPEClockFrequencyInfo.bus_clock_rate_hz; |
155 | gPEClockFrequencyInfo.bus_to_cpu_rate_den = 2; |
156 | |
157 | gPEClockFrequencyInfo.bus_to_dec_rate_num = 1; |
158 | gPEClockFrequencyInfo.bus_to_dec_rate_den = |
159 | gPEClockFrequencyInfo.bus_clock_rate_hz / gPEClockFrequencyInfo.dec_clock_rate_hz; |
160 | } |
161 | |
162 | vm_offset_t |
163 | pe_arm_get_soc_base_phys(void) |
164 | { |
165 | DTEntry entryP; |
166 | uintptr_t const *ranges_prop; |
167 | uint32_t prop_size; |
168 | char const *tmpStr; |
169 | |
170 | if (SecureDTFindEntry(propName: "name" , propValue: "arm-io" , entryH: &entryP) == kSuccess) { |
171 | if (gPESoCDeviceType == 0) { |
172 | SecureDTGetProperty(entry: entryP, propertyName: "device_type" , propertyValue: (void const **)&tmpStr, propertySize: &prop_size); |
173 | strlcpy(dst: gPESoCDeviceTypeBuffer, src: tmpStr, SOC_DEVICE_TYPE_BUFFER_SIZE); |
174 | gPESoCDeviceType = gPESoCDeviceTypeBuffer; |
175 | |
176 | SecureDTGetProperty(entry: entryP, propertyName: "ranges" , propertyValue: (void const **)&ranges_prop, propertySize: &prop_size); |
177 | gPESoCBasePhys = *(ranges_prop + 1); |
178 | } |
179 | return gPESoCBasePhys; |
180 | } |
181 | return 0; |
182 | } |
183 | |
184 | extern void fleh_fiq_generic(void); |
185 | |
186 | vm_offset_t gPicBase; |
187 | vm_offset_t gTimerBase; |
188 | vm_offset_t gSocPhys; |
189 | |
190 | static uint32_t |
191 | pe_arm_map_interrupt_controller(void) |
192 | { |
193 | DTEntry entryP; |
194 | uintptr_t const *reg_prop; |
195 | uint32_t prop_size; |
196 | vm_offset_t soc_phys = 0; |
197 | |
198 | gSocPhys = pe_arm_get_soc_base_phys(); |
199 | |
200 | soc_phys = gSocPhys; |
201 | kprintf(fmt: "pe_arm_map_interrupt_controller: soc_phys: 0x%lx\n" , (unsigned long)soc_phys); |
202 | if (soc_phys == 0) { |
203 | return 0; |
204 | } |
205 | |
206 | if (SecureDTFindEntry(propName: "interrupt-controller" , propValue: "master" , entryH: &entryP) == kSuccess) { |
207 | kprintf(fmt: "pe_arm_map_interrupt_controller: found interrupt-controller\n" ); |
208 | SecureDTGetProperty(entry: entryP, propertyName: "reg" , propertyValue: (void const **)®_prop, propertySize: &prop_size); |
209 | gPicBase = ml_io_map(phys_addr: soc_phys + *reg_prop, size: *(reg_prop + 1)); |
210 | kprintf(fmt: "pe_arm_map_interrupt_controller: gPicBase: 0x%lx\n" , (unsigned long)gPicBase); |
211 | } |
212 | if (gPicBase == 0) { |
213 | kprintf(fmt: "pe_arm_map_interrupt_controller: failed to find the interrupt-controller.\n" ); |
214 | return 0; |
215 | } |
216 | |
217 | if (SecureDTFindEntry(propName: "device_type" , propValue: "timer" , entryH: &entryP) == kSuccess) { |
218 | kprintf(fmt: "pe_arm_map_interrupt_controller: found timer\n" ); |
219 | SecureDTGetProperty(entry: entryP, propertyName: "reg" , propertyValue: (void const **)®_prop, propertySize: &prop_size); |
220 | gTimerBase = ml_io_map(phys_addr: soc_phys + *reg_prop, size: *(reg_prop + 1)); |
221 | kprintf(fmt: "pe_arm_map_interrupt_controller: gTimerBase: 0x%lx\n" , (unsigned long)gTimerBase); |
222 | } |
223 | if (gTimerBase == 0) { |
224 | kprintf(fmt: "pe_arm_map_interrupt_controller: failed to find the timer.\n" ); |
225 | return 0; |
226 | } |
227 | |
228 | return 1; |
229 | } |
230 | |
231 | uint32_t |
232 | pe_arm_init_interrupts(void *args) |
233 | { |
234 | kprintf(fmt: "pe_arm_init_interrupts: args: %p\n" , args); |
235 | |
236 | /* Set up mappings for interrupt controller and possibly timers (if they haven't been set up already) */ |
237 | if (args != NULL) { |
238 | if (!pe_arm_map_interrupt_controller()) { |
239 | return 0; |
240 | } |
241 | } |
242 | |
243 | return pe_arm_init_timer(args); |
244 | } |
245 | |
246 | static uint32_t |
247 | pe_arm_init_timer(void *args) |
248 | { |
249 | vm_offset_t pic_base = 0; |
250 | vm_offset_t timer_base = 0; |
251 | vm_offset_t soc_phys; |
252 | vm_offset_t eoi_addr = 0; |
253 | uint32_t eoi_value = 0; |
254 | struct tbd_ops generic_funcs = {&fleh_fiq_generic, NULL, NULL}; |
255 | struct tbd_ops empty_funcs __unused = {NULL, NULL, NULL}; |
256 | tbd_ops_t tbd_funcs = &generic_funcs; |
257 | |
258 | /* The SoC headers expect to use pic_base, timer_base, etc... */ |
259 | pic_base = gPicBase; |
260 | timer_base = gTimerBase; |
261 | soc_phys = gSocPhys; |
262 | |
263 | #if defined(__arm64__) |
264 | tbd_funcs = &empty_funcs; |
265 | #else |
266 | return 0; |
267 | #endif |
268 | |
269 | if (args != NULL) { |
270 | ml_init_timebase(args, tbd_funcs, int_address: eoi_addr, int_value: eoi_value); |
271 | } |
272 | |
273 | return 1; |
274 | } |
275 | |