]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2007-2019 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 | ||
10 | #if defined(__arm__) | |
11 | #include <pexpert/arm/board_config.h> | |
12 | #elif defined(__arm64__) | |
13 | #include <pexpert/arm64/board_config.h> | |
14 | #endif | |
15 | ||
16 | #include <kern/clock.h> | |
17 | #include <machine/machine_routines.h> | |
18 | #if DEVELOPMENT || DEBUG | |
19 | #include <kern/simple_lock.h> | |
20 | #include <kern/cpu_number.h> | |
21 | #endif | |
22 | /* Local declarations */ | |
23 | void pe_identify_machine(boot_args * bootArgs); | |
24 | ||
25 | /* External declarations */ | |
26 | extern void clean_mmu_dcache(void); | |
27 | ||
28 | static char *gPESoCDeviceType; | |
29 | static char gPESoCDeviceTypeBuffer[SOC_DEVICE_TYPE_BUFFER_SIZE]; | |
30 | static vm_offset_t gPESoCBasePhys; | |
31 | ||
32 | static uint32_t gTCFG0Value; | |
33 | ||
34 | static uint32_t pe_arm_init_timer(void *args); | |
35 | ||
36 | #if DEVELOPMENT || DEBUG | |
37 | decl_simple_lock_data(, panic_hook_lock); | |
38 | #endif | |
39 | /* | |
40 | * pe_identify_machine: | |
41 | * | |
42 | * Sets up platform parameters. Returns: nothing | |
43 | */ | |
44 | void | |
45 | pe_identify_machine(boot_args * bootArgs) | |
46 | { | |
47 | OpaqueDTEntryIterator iter; | |
48 | DTEntry cpus, cpu; | |
49 | uint32_t mclk = 0, hclk = 0, pclk = 0, tclk = 0, use_dt = 0; | |
50 | unsigned long const *value; | |
51 | unsigned int size; | |
52 | int err; | |
53 | ||
54 | (void)bootArgs; | |
55 | ||
56 | if (pe_arm_get_soc_base_phys() == 0) { | |
57 | return; | |
58 | } | |
59 | ||
60 | /* Clear the gPEClockFrequencyInfo struct */ | |
61 | bzero((void *)&gPEClockFrequencyInfo, sizeof(clock_frequency_info_t)); | |
62 | ||
63 | if (!strcmp(gPESoCDeviceType, "s3c2410-io")) { | |
64 | mclk = 192 << 23; | |
65 | hclk = mclk / 2; | |
66 | pclk = hclk / 2; | |
67 | tclk = (1 << (23 + 2)) / 10; | |
68 | tclk = pclk / tclk; | |
69 | ||
70 | gTCFG0Value = tclk - 1; | |
71 | ||
72 | tclk = pclk / (4 * tclk); /* Calculate the "actual" | |
73 | * Timer0 frequency in fixed | |
74 | * point. */ | |
75 | ||
76 | mclk = (mclk >> 17) * (125 * 125); | |
77 | hclk = (hclk >> 17) * (125 * 125); | |
78 | pclk = (pclk >> 17) * (125 * 125); | |
79 | tclk = (((((tclk * 125) + 2) >> 2) * 125) + (1 << 14)) >> 15; | |
80 | } else if (!strcmp(gPESoCDeviceType, "integratorcp-io")) { | |
81 | mclk = 200000000; | |
82 | hclk = mclk / 2; | |
83 | pclk = hclk / 2; | |
84 | tclk = 100000; | |
85 | } else if (!strcmp(gPESoCDeviceType, "olocreek-io")) { | |
86 | mclk = 1000000000; | |
87 | hclk = mclk / 8; | |
88 | pclk = hclk / 2; | |
89 | tclk = pclk; | |
90 | } else if (!strcmp(gPESoCDeviceType, "omap3430sdp-io")) { | |
91 | mclk = 332000000; | |
92 | hclk = 19200000; | |
93 | pclk = hclk; | |
94 | tclk = pclk; | |
95 | } else if (!strcmp(gPESoCDeviceType, "s5i3000-io")) { | |
96 | mclk = 400000000; | |
97 | hclk = mclk / 4; | |
98 | pclk = hclk / 2; | |
99 | tclk = 100000; /* timer is at 100khz */ | |
100 | } else { | |
101 | use_dt = 1; | |
102 | } | |
103 | ||
104 | if (use_dt) { | |
105 | /* Start with default values. */ | |
106 | gPEClockFrequencyInfo.timebase_frequency_hz = 24000000; | |
107 | gPEClockFrequencyInfo.bus_clock_rate_hz = 100000000; | |
108 | gPEClockFrequencyInfo.cpu_clock_rate_hz = 400000000; | |
109 | ||
110 | err = SecureDTLookupEntry(NULL, "/cpus", &cpus); | |
111 | assert(err == kSuccess); | |
112 | ||
113 | err = SecureDTInitEntryIterator(cpus, &iter); | |
114 | assert(err == kSuccess); | |
115 | ||
116 | while (kSuccess == SecureDTIterateEntries(&iter, &cpu)) { | |
117 | if ((kSuccess != SecureDTGetProperty(cpu, "state", (void const **)&value, &size)) || | |
118 | (strncmp((char const *)value, "running", size) != 0)) { | |
119 | continue; | |
120 | } | |
121 | ||
122 | /* Find the time base frequency first. */ | |
123 | if (SecureDTGetProperty(cpu, "timebase-frequency", (void const **)&value, &size) == kSuccess) { | |
124 | /* | |
125 | * timebase_frequency_hz is only 32 bits, and | |
126 | * the device tree should never provide 64 | |
127 | * bits so this if should never be taken. | |
128 | */ | |
129 | if (size == 8) { | |
130 | gPEClockFrequencyInfo.timebase_frequency_hz = *(unsigned long long const *)value; | |
131 | } else { | |
132 | gPEClockFrequencyInfo.timebase_frequency_hz = *value; | |
133 | } | |
134 | } | |
135 | gPEClockFrequencyInfo.dec_clock_rate_hz = gPEClockFrequencyInfo.timebase_frequency_hz; | |
136 | ||
137 | /* Find the bus frequency next. */ | |
138 | if (SecureDTGetProperty(cpu, "bus-frequency", (void const **)&value, &size) == kSuccess) { | |
139 | if (size == 8) { | |
140 | gPEClockFrequencyInfo.bus_frequency_hz = *(unsigned long long const *)value; | |
141 | } else { | |
142 | gPEClockFrequencyInfo.bus_frequency_hz = *value; | |
143 | } | |
144 | } | |
145 | gPEClockFrequencyInfo.bus_frequency_min_hz = gPEClockFrequencyInfo.bus_frequency_hz; | |
146 | gPEClockFrequencyInfo.bus_frequency_max_hz = gPEClockFrequencyInfo.bus_frequency_hz; | |
147 | ||
148 | if (gPEClockFrequencyInfo.bus_frequency_hz < 0x100000000ULL) { | |
149 | gPEClockFrequencyInfo.bus_clock_rate_hz = gPEClockFrequencyInfo.bus_frequency_hz; | |
150 | } else { | |
151 | gPEClockFrequencyInfo.bus_clock_rate_hz = 0xFFFFFFFF; | |
152 | } | |
153 | ||
154 | /* Find the memory frequency next. */ | |
155 | if (SecureDTGetProperty(cpu, "memory-frequency", (void const **)&value, &size) == kSuccess) { | |
156 | if (size == 8) { | |
157 | gPEClockFrequencyInfo.mem_frequency_hz = *(unsigned long long const *)value; | |
158 | } else { | |
159 | gPEClockFrequencyInfo.mem_frequency_hz = *value; | |
160 | } | |
161 | } | |
162 | gPEClockFrequencyInfo.mem_frequency_min_hz = gPEClockFrequencyInfo.mem_frequency_hz; | |
163 | gPEClockFrequencyInfo.mem_frequency_max_hz = gPEClockFrequencyInfo.mem_frequency_hz; | |
164 | ||
165 | /* Find the peripheral frequency next. */ | |
166 | if (SecureDTGetProperty(cpu, "peripheral-frequency", (void const **)&value, &size) == kSuccess) { | |
167 | if (size == 8) { | |
168 | gPEClockFrequencyInfo.prf_frequency_hz = *(unsigned long long const *)value; | |
169 | } else { | |
170 | gPEClockFrequencyInfo.prf_frequency_hz = *value; | |
171 | } | |
172 | } | |
173 | gPEClockFrequencyInfo.prf_frequency_min_hz = gPEClockFrequencyInfo.prf_frequency_hz; | |
174 | gPEClockFrequencyInfo.prf_frequency_max_hz = gPEClockFrequencyInfo.prf_frequency_hz; | |
175 | ||
176 | /* Find the fixed frequency next. */ | |
177 | if (SecureDTGetProperty(cpu, "fixed-frequency", (void const **)&value, &size) == kSuccess) { | |
178 | if (size == 8) { | |
179 | gPEClockFrequencyInfo.fix_frequency_hz = *(unsigned long long const *)value; | |
180 | } else { | |
181 | gPEClockFrequencyInfo.fix_frequency_hz = *value; | |
182 | } | |
183 | } | |
184 | /* Find the cpu frequency last. */ | |
185 | if (SecureDTGetProperty(cpu, "clock-frequency", (void const **)&value, &size) == kSuccess) { | |
186 | if (size == 8) { | |
187 | gPEClockFrequencyInfo.cpu_frequency_hz = *(unsigned long long const *)value; | |
188 | } else { | |
189 | gPEClockFrequencyInfo.cpu_frequency_hz = *value; | |
190 | } | |
191 | } | |
192 | gPEClockFrequencyInfo.cpu_frequency_min_hz = gPEClockFrequencyInfo.cpu_frequency_hz; | |
193 | gPEClockFrequencyInfo.cpu_frequency_max_hz = gPEClockFrequencyInfo.cpu_frequency_hz; | |
194 | ||
195 | if (gPEClockFrequencyInfo.cpu_frequency_hz < 0x100000000ULL) { | |
196 | gPEClockFrequencyInfo.cpu_clock_rate_hz = gPEClockFrequencyInfo.cpu_frequency_hz; | |
197 | } else { | |
198 | gPEClockFrequencyInfo.cpu_clock_rate_hz = 0xFFFFFFFF; | |
199 | } | |
200 | } | |
201 | } else { | |
202 | /* Use the canned values. */ | |
203 | gPEClockFrequencyInfo.timebase_frequency_hz = tclk; | |
204 | gPEClockFrequencyInfo.fix_frequency_hz = tclk; | |
205 | gPEClockFrequencyInfo.bus_frequency_hz = hclk; | |
206 | gPEClockFrequencyInfo.cpu_frequency_hz = mclk; | |
207 | gPEClockFrequencyInfo.prf_frequency_hz = pclk; | |
208 | ||
209 | gPEClockFrequencyInfo.bus_frequency_min_hz = gPEClockFrequencyInfo.bus_frequency_hz; | |
210 | gPEClockFrequencyInfo.bus_frequency_max_hz = gPEClockFrequencyInfo.bus_frequency_hz; | |
211 | gPEClockFrequencyInfo.cpu_frequency_min_hz = gPEClockFrequencyInfo.cpu_frequency_hz; | |
212 | gPEClockFrequencyInfo.cpu_frequency_max_hz = gPEClockFrequencyInfo.cpu_frequency_hz; | |
213 | gPEClockFrequencyInfo.prf_frequency_min_hz = gPEClockFrequencyInfo.prf_frequency_hz; | |
214 | gPEClockFrequencyInfo.prf_frequency_max_hz = gPEClockFrequencyInfo.prf_frequency_hz; | |
215 | ||
216 | gPEClockFrequencyInfo.dec_clock_rate_hz = gPEClockFrequencyInfo.timebase_frequency_hz; | |
217 | gPEClockFrequencyInfo.bus_clock_rate_hz = gPEClockFrequencyInfo.bus_frequency_hz; | |
218 | gPEClockFrequencyInfo.cpu_clock_rate_hz = gPEClockFrequencyInfo.cpu_frequency_hz; | |
219 | } | |
220 | ||
221 | /* Set the num / den pairs form the hz values. */ | |
222 | gPEClockFrequencyInfo.bus_clock_rate_num = gPEClockFrequencyInfo.bus_clock_rate_hz; | |
223 | gPEClockFrequencyInfo.bus_clock_rate_den = 1; | |
224 | ||
225 | gPEClockFrequencyInfo.bus_to_cpu_rate_num = | |
226 | (2 * gPEClockFrequencyInfo.cpu_clock_rate_hz) / gPEClockFrequencyInfo.bus_clock_rate_hz; | |
227 | gPEClockFrequencyInfo.bus_to_cpu_rate_den = 2; | |
228 | ||
229 | gPEClockFrequencyInfo.bus_to_dec_rate_num = 1; | |
230 | gPEClockFrequencyInfo.bus_to_dec_rate_den = | |
231 | gPEClockFrequencyInfo.bus_clock_rate_hz / gPEClockFrequencyInfo.dec_clock_rate_hz; | |
232 | } | |
233 | ||
234 | vm_offset_t | |
235 | pe_arm_get_soc_base_phys(void) | |
236 | { | |
237 | DTEntry entryP; | |
238 | uintptr_t const *ranges_prop; | |
239 | uint32_t prop_size; | |
240 | char const *tmpStr; | |
241 | ||
242 | if (SecureDTFindEntry("name", "arm-io", &entryP) == kSuccess) { | |
243 | if (gPESoCDeviceType == 0) { | |
244 | SecureDTGetProperty(entryP, "device_type", (void const **)&tmpStr, &prop_size); | |
245 | strlcpy(gPESoCDeviceTypeBuffer, tmpStr, SOC_DEVICE_TYPE_BUFFER_SIZE); | |
246 | gPESoCDeviceType = gPESoCDeviceTypeBuffer; | |
247 | ||
248 | SecureDTGetProperty(entryP, "ranges", (void const **)&ranges_prop, &prop_size); | |
249 | gPESoCBasePhys = *(ranges_prop + 1); | |
250 | } | |
251 | return gPESoCBasePhys; | |
252 | } | |
253 | return 0; | |
254 | } | |
255 | ||
256 | extern void fleh_fiq_generic(void); | |
257 | ||
258 | #if defined(ARM_BOARD_CLASS_T8002) | |
259 | extern void fleh_fiq_t8002(void); | |
260 | extern uint32_t t8002_get_decrementer(void); | |
261 | extern void t8002_set_decrementer(uint32_t); | |
262 | static struct tbd_ops t8002_funcs = {&fleh_fiq_t8002, &t8002_get_decrementer, &t8002_set_decrementer}; | |
263 | #endif /* defined(ARM_BOARD_CLASS_T8002) */ | |
264 | ||
265 | vm_offset_t gPicBase; | |
266 | vm_offset_t gTimerBase; | |
267 | vm_offset_t gSocPhys; | |
268 | ||
269 | #if DEVELOPMENT || DEBUG | |
270 | // This block contains the panic trace implementation | |
271 | ||
272 | // These variables are local to this file, and contain the panic trace configuration information | |
273 | typedef enum{ | |
274 | panic_trace_disabled = 0, | |
275 | panic_trace_unused, | |
276 | panic_trace_enabled, | |
277 | panic_trace_alt_enabled, | |
278 | } panic_trace_t; | |
279 | static panic_trace_t bootarg_panic_trace; | |
280 | ||
281 | static int bootarg_stop_clocks; | |
282 | ||
283 | // The command buffer contains the converted commands from the device tree for commanding cpu_halt, enable_trace, etc. | |
284 | #define DEBUG_COMMAND_BUFFER_SIZE 256 | |
285 | typedef struct command_buffer_element { | |
286 | uintptr_t address; | |
287 | uintptr_t value; | |
288 | uint16_t destination_cpu_selector; | |
289 | uint16_t delay_us; | |
290 | bool is_32bit; | |
291 | } command_buffer_element_t; | |
292 | static command_buffer_element_t debug_command_buffer[DEBUG_COMMAND_BUFFER_SIZE]; // statically allocate to prevent needing alloc at runtime | |
293 | static uint32_t next_command_buffer_entry = 0; // index of next unused slot in debug_command_buffer | |
294 | ||
295 | #define CPU_SELECTOR_SHIFT (16) | |
296 | #define CPU_SELECTOR_MASK (0xFFFF << CPU_SELECTOR_SHIFT) | |
297 | #define REGISTER_OFFSET_MASK ((1 << CPU_SELECTOR_SHIFT) - 1) | |
298 | #define REGISTER_OFFSET(register_prop) (register_prop & REGISTER_OFFSET_MASK) | |
299 | #define CPU_SELECTOR(register_offset) ((register_offset & CPU_SELECTOR_MASK) >> CPU_SELECTOR_SHIFT) // Upper 16bits holds the cpu selector | |
300 | #define MAX_WINDOW_SIZE 0xFFFF | |
301 | #define PE_ISSPACE(c) (c == ' ' || c == '\t' || c == '\n' || c == '\12') | |
302 | #define DELAY_SHIFT (32) | |
303 | #define DELAY_MASK (0xFFFFULL << DELAY_SHIFT) | |
304 | #define DELAY_US(register_offset) ((register_offset & DELAY_MASK) >> DELAY_SHIFT) | |
305 | #define REGISTER_32BIT_MASK (1ULL << 63) | |
306 | /* | |
307 | * 0x0000 - all cpus | |
308 | * 0x0001 - cpu 0 | |
309 | * 0x0002 - cpu 1 | |
310 | * 0x0004 - cpu 2 | |
311 | * 0x0003 - cpu 0 and 1 | |
312 | * since it's 16bits, we can have up to 16 cpus | |
313 | */ | |
314 | #define ALL_CPUS 0x0000 | |
315 | #define IS_CPU_SELECTED(cpu_number, cpu_selector) (cpu_selector == ALL_CPUS || (cpu_selector & (1<<cpu_number) ) != 0 ) | |
316 | ||
317 | #define RESET_VIRTUAL_ADDRESS_WINDOW 0xFFFFFFFF | |
318 | ||
319 | // Pointers into debug_command_buffer for each operation. Assumes runtime will init them to zero. | |
320 | static command_buffer_element_t *cpu_halt; | |
321 | static command_buffer_element_t *enable_trace; | |
322 | static command_buffer_element_t *enable_alt_trace; | |
323 | static command_buffer_element_t *trace_halt; | |
324 | static command_buffer_element_t *enable_stop_clocks; | |
325 | static command_buffer_element_t *stop_clocks; | |
326 | ||
327 | // Record which CPU is currently running one of our debug commands, so we can trap panic reentrancy to PE_arm_debug_panic_hook. | |
328 | static int running_debug_command_on_cpu_number = -1; | |
329 | ||
330 | static void | |
331 | pe_init_debug_command(DTEntry entryP, command_buffer_element_t **command_buffer, const char* entry_name) | |
332 | { | |
333 | uintptr_t const *reg_prop; | |
334 | uint32_t prop_size, reg_window_size = 0, command_starting_index; | |
335 | uintptr_t debug_reg_window = 0; | |
336 | ||
337 | if (command_buffer == 0) { | |
338 | return; | |
339 | } | |
340 | ||
341 | if (SecureDTGetProperty(entryP, entry_name, (void const **)®_prop, &prop_size) != kSuccess) { | |
342 | panic("pe_init_debug_command: failed to read property %s\n", entry_name); | |
343 | } | |
344 | ||
345 | // make sure command will fit | |
346 | if (next_command_buffer_entry + prop_size / sizeof(uintptr_t) > DEBUG_COMMAND_BUFFER_SIZE - 1) { | |
347 | panic("pe_init_debug_command: property %s is %u bytes, command buffer only has %lu bytes remaining\n", | |
348 | entry_name, prop_size, ((DEBUG_COMMAND_BUFFER_SIZE - 1) - next_command_buffer_entry) * sizeof(uintptr_t)); | |
349 | } | |
350 | ||
351 | // Hold the pointer in a temp variable and later assign it to command buffer, in case we panic while half-initialized | |
352 | command_starting_index = next_command_buffer_entry; | |
353 | ||
354 | // convert to real virt addresses and stuff commands into debug_command_buffer | |
355 | for (; prop_size; reg_prop += 2, prop_size -= 2 * sizeof(uintptr_t)) { | |
356 | if (*reg_prop == RESET_VIRTUAL_ADDRESS_WINDOW) { | |
357 | debug_reg_window = 0; // Create a new window | |
358 | } else if (debug_reg_window == 0) { | |
359 | // create a window from virtual address to the specified physical address | |
360 | reg_window_size = ((uint32_t)*(reg_prop + 1)); | |
361 | if (reg_window_size > MAX_WINDOW_SIZE) { | |
362 | panic("pe_init_debug_command: Command page size is %0x, exceeds the Maximum allowed page size 0f 0%x\n", reg_window_size, MAX_WINDOW_SIZE ); | |
363 | } | |
364 | debug_reg_window = ml_io_map(gSocPhys + *reg_prop, reg_window_size); | |
365 | // for debug -- kprintf("pe_init_debug_command: %s registers @ 0x%08lX for 0x%08lX\n", entry_name, debug_reg_window, *(reg_prop + 1) ); | |
366 | } else { | |
367 | if ((REGISTER_OFFSET(*reg_prop) + sizeof(uintptr_t)) >= reg_window_size) { | |
368 | panic("pe_init_debug_command: Command Offset is %lx, exceeds allocated size of %x\n", REGISTER_OFFSET(*reg_prop), reg_window_size ); | |
369 | } | |
370 | debug_command_buffer[next_command_buffer_entry].address = debug_reg_window + REGISTER_OFFSET(*reg_prop); | |
371 | debug_command_buffer[next_command_buffer_entry].destination_cpu_selector = (uint16_t)CPU_SELECTOR(*reg_prop); | |
372 | #if defined(__arm64__) | |
373 | debug_command_buffer[next_command_buffer_entry].delay_us = DELAY_US(*reg_prop); | |
374 | debug_command_buffer[next_command_buffer_entry].is_32bit = ((*reg_prop & REGISTER_32BIT_MASK) != 0); | |
375 | #else | |
376 | debug_command_buffer[next_command_buffer_entry].delay_us = 0; | |
377 | debug_command_buffer[next_command_buffer_entry].is_32bit = false; | |
378 | #endif | |
379 | debug_command_buffer[next_command_buffer_entry++].value = *(reg_prop + 1); | |
380 | } | |
381 | } | |
382 | ||
383 | // null terminate the address field of the command to end it | |
384 | debug_command_buffer[next_command_buffer_entry++].address = 0; | |
385 | ||
386 | // save pointer into table for this command | |
387 | *command_buffer = &debug_command_buffer[command_starting_index]; | |
388 | } | |
389 | ||
390 | static void | |
391 | pe_run_debug_command(command_buffer_element_t *command_buffer) | |
392 | { | |
393 | // When both the CPUs panic, one will get stuck on the lock and the other CPU will be halted when the first executes the debug command | |
394 | simple_lock(&panic_hook_lock, LCK_GRP_NULL); | |
395 | ||
396 | running_debug_command_on_cpu_number = cpu_number(); | |
397 | ||
398 | while (command_buffer && command_buffer->address) { | |
399 | if (IS_CPU_SELECTED(running_debug_command_on_cpu_number, command_buffer->destination_cpu_selector)) { | |
400 | if (command_buffer->is_32bit) { | |
401 | *((volatile uint32_t*)(command_buffer->address)) = (uint32_t)(command_buffer->value); | |
402 | } else { | |
403 | *((volatile uintptr_t*)(command_buffer->address)) = command_buffer->value; // register = value; | |
404 | } | |
405 | if (command_buffer->delay_us != 0) { | |
406 | uint64_t deadline; | |
407 | nanoseconds_to_absolutetime(command_buffer->delay_us * NSEC_PER_USEC, &deadline); | |
408 | deadline += ml_get_timebase(); | |
409 | while (ml_get_timebase() < deadline) { | |
410 | os_compiler_barrier(); | |
411 | } | |
412 | } | |
413 | } | |
414 | command_buffer++; | |
415 | } | |
416 | ||
417 | running_debug_command_on_cpu_number = -1; | |
418 | simple_unlock(&panic_hook_lock); | |
419 | } | |
420 | ||
421 | ||
422 | void | |
423 | PE_arm_debug_enable_trace(void) | |
424 | { | |
425 | switch (bootarg_panic_trace) { | |
426 | case panic_trace_enabled: | |
427 | pe_run_debug_command(enable_trace); | |
428 | break; | |
429 | ||
430 | case panic_trace_alt_enabled: | |
431 | pe_run_debug_command(enable_alt_trace); | |
432 | break; | |
433 | ||
434 | default: | |
435 | break; | |
436 | } | |
437 | } | |
438 | ||
439 | static void | |
440 | PE_arm_panic_hook(const char *str __unused) | |
441 | { | |
442 | (void)str; // not used | |
443 | if (bootarg_stop_clocks != 0) { | |
444 | pe_run_debug_command(stop_clocks); | |
445 | } | |
446 | // if panic trace is enabled | |
447 | if (bootarg_panic_trace != 0) { | |
448 | if (running_debug_command_on_cpu_number == cpu_number()) { | |
449 | // This is going to end badly if we don't trap, since we'd be panic-ing during our own code | |
450 | kprintf("## Panic Trace code caused the panic ##\n"); | |
451 | return; // allow the normal panic operation to occur. | |
452 | } | |
453 | ||
454 | // Stop tracing to freeze the buffer and return to normal panic processing. | |
455 | pe_run_debug_command(trace_halt); | |
456 | } | |
457 | } | |
458 | ||
459 | void (*PE_arm_debug_panic_hook)(const char *str) = PE_arm_panic_hook; | |
460 | ||
461 | void | |
462 | PE_init_cpu(void) | |
463 | { | |
464 | if (bootarg_stop_clocks != 0) { | |
465 | pe_run_debug_command(enable_stop_clocks); | |
466 | } | |
467 | } | |
468 | ||
469 | #else | |
470 | ||
471 | void(*const PE_arm_debug_panic_hook)(const char *str) = NULL; | |
472 | ||
473 | void | |
474 | PE_init_cpu(void) | |
475 | { | |
476 | } | |
477 | ||
478 | #endif // DEVELOPMENT || DEBUG | |
479 | ||
480 | void | |
481 | PE_panic_hook(const char *str __unused) | |
482 | { | |
483 | if (PE_arm_debug_panic_hook != NULL) { | |
484 | PE_arm_debug_panic_hook(str); | |
485 | } | |
486 | } | |
487 | ||
488 | void | |
489 | pe_arm_init_debug(void *args) | |
490 | { | |
491 | DTEntry entryP; | |
492 | uintptr_t const *reg_prop; | |
493 | uint32_t prop_size; | |
494 | ||
495 | if (gSocPhys == 0) { | |
496 | kprintf("pe_arm_init_debug: failed to initialize gSocPhys == 0\n"); | |
497 | return; | |
498 | } | |
499 | ||
500 | if (SecureDTFindEntry("device_type", "cpu-debug-interface", &entryP) == kSuccess) { | |
501 | if (args != NULL) { | |
502 | if (SecureDTGetProperty(entryP, "reg", (void const **)®_prop, &prop_size) == kSuccess) { | |
503 | ml_init_arm_debug_interface(args, ml_io_map(gSocPhys + *reg_prop, *(reg_prop + 1))); | |
504 | } | |
505 | #if DEVELOPMENT || DEBUG | |
506 | // When args != NULL, this means we're being called from arm_init on the boot CPU. | |
507 | // This controls one-time initialization of the Panic Trace infrastructure | |
508 | ||
509 | simple_lock_init(&panic_hook_lock, 0); //assuming single threaded mode | |
510 | ||
511 | // Panic_halt is deprecated. Please use panic_trace istead. | |
512 | unsigned int temp_bootarg_panic_trace; | |
513 | if (PE_parse_boot_argn("panic_trace", &temp_bootarg_panic_trace, sizeof(temp_bootarg_panic_trace)) || | |
514 | PE_parse_boot_argn("panic_halt", &temp_bootarg_panic_trace, sizeof(temp_bootarg_panic_trace))) { | |
515 | kprintf("pe_arm_init_debug: panic_trace=%d\n", temp_bootarg_panic_trace); | |
516 | ||
517 | // Prepare debug command buffers. | |
518 | pe_init_debug_command(entryP, &cpu_halt, "cpu_halt"); | |
519 | pe_init_debug_command(entryP, &enable_trace, "enable_trace"); | |
520 | pe_init_debug_command(entryP, &enable_alt_trace, "enable_alt_trace"); | |
521 | pe_init_debug_command(entryP, &trace_halt, "trace_halt"); | |
522 | ||
523 | // now that init's are done, enable the panic halt capture (allows pe_init_debug_command to panic normally if necessary) | |
524 | bootarg_panic_trace = temp_bootarg_panic_trace; | |
525 | ||
526 | // start tracing now if enabled | |
527 | PE_arm_debug_enable_trace(); | |
528 | } | |
529 | unsigned int temp_bootarg_stop_clocks; | |
530 | if (PE_parse_boot_argn("stop_clocks", &temp_bootarg_stop_clocks, sizeof(temp_bootarg_stop_clocks))) { | |
531 | pe_init_debug_command(entryP, &enable_stop_clocks, "enable_stop_clocks"); | |
532 | pe_init_debug_command(entryP, &stop_clocks, "stop_clocks"); | |
533 | bootarg_stop_clocks = temp_bootarg_stop_clocks; | |
534 | } | |
535 | #endif | |
536 | } | |
537 | } else { | |
538 | kprintf("pe_arm_init_debug: failed to find cpu-debug-interface\n"); | |
539 | } | |
540 | } | |
541 | ||
542 | static uint32_t | |
543 | pe_arm_map_interrupt_controller(void) | |
544 | { | |
545 | DTEntry entryP; | |
546 | uintptr_t const *reg_prop; | |
547 | uint32_t prop_size; | |
548 | vm_offset_t soc_phys = 0; | |
549 | ||
550 | gSocPhys = pe_arm_get_soc_base_phys(); | |
551 | ||
552 | soc_phys = gSocPhys; | |
553 | kprintf("pe_arm_map_interrupt_controller: soc_phys: 0x%lx\n", (unsigned long)soc_phys); | |
554 | if (soc_phys == 0) { | |
555 | return 0; | |
556 | } | |
557 | ||
558 | if (SecureDTFindEntry("interrupt-controller", "master", &entryP) == kSuccess) { | |
559 | kprintf("pe_arm_map_interrupt_controller: found interrupt-controller\n"); | |
560 | SecureDTGetProperty(entryP, "reg", (void const **)®_prop, &prop_size); | |
561 | gPicBase = ml_io_map(soc_phys + *reg_prop, *(reg_prop + 1)); | |
562 | kprintf("pe_arm_map_interrupt_controller: gPicBase: 0x%lx\n", (unsigned long)gPicBase); | |
563 | } | |
564 | if (gPicBase == 0) { | |
565 | kprintf("pe_arm_map_interrupt_controller: failed to find the interrupt-controller.\n"); | |
566 | return 0; | |
567 | } | |
568 | ||
569 | if (SecureDTFindEntry("device_type", "timer", &entryP) == kSuccess) { | |
570 | kprintf("pe_arm_map_interrupt_controller: found timer\n"); | |
571 | SecureDTGetProperty(entryP, "reg", (void const **)®_prop, &prop_size); | |
572 | gTimerBase = ml_io_map(soc_phys + *reg_prop, *(reg_prop + 1)); | |
573 | kprintf("pe_arm_map_interrupt_controller: gTimerBase: 0x%lx\n", (unsigned long)gTimerBase); | |
574 | } | |
575 | if (gTimerBase == 0) { | |
576 | kprintf("pe_arm_map_interrupt_controller: failed to find the timer.\n"); | |
577 | return 0; | |
578 | } | |
579 | ||
580 | return 1; | |
581 | } | |
582 | ||
583 | uint32_t | |
584 | pe_arm_init_interrupts(void *args) | |
585 | { | |
586 | kprintf("pe_arm_init_interrupts: args: %p\n", args); | |
587 | ||
588 | /* Set up mappings for interrupt controller and possibly timers (if they haven't been set up already) */ | |
589 | if (args != NULL) { | |
590 | if (!pe_arm_map_interrupt_controller()) { | |
591 | return 0; | |
592 | } | |
593 | } | |
594 | ||
595 | return pe_arm_init_timer(args); | |
596 | } | |
597 | ||
598 | static uint32_t | |
599 | pe_arm_init_timer(void *args) | |
600 | { | |
601 | vm_offset_t pic_base = 0; | |
602 | vm_offset_t timer_base = 0; | |
603 | vm_offset_t soc_phys; | |
604 | vm_offset_t eoi_addr = 0; | |
605 | uint32_t eoi_value = 0; | |
606 | struct tbd_ops generic_funcs = {&fleh_fiq_generic, NULL, NULL}; | |
607 | struct tbd_ops empty_funcs __unused = {NULL, NULL, NULL}; | |
608 | tbd_ops_t tbd_funcs = &generic_funcs; | |
609 | ||
610 | /* The SoC headers expect to use pic_base, timer_base, etc... */ | |
611 | pic_base = gPicBase; | |
612 | timer_base = gTimerBase; | |
613 | soc_phys = gSocPhys; | |
614 | ||
615 | #if defined(ARM_BOARD_CLASS_T8002) | |
616 | if (!strcmp(gPESoCDeviceType, "t8002-io") || | |
617 | !strcmp(gPESoCDeviceType, "t8004-io")) { | |
618 | /* Enable the Decrementer */ | |
619 | aic_write32(kAICTmrCnt, 0x7FFFFFFF); | |
620 | aic_write32(kAICTmrCfg, kAICTmrCfgEn); | |
621 | aic_write32(kAICTmrIntStat, kAICTmrIntStatPct); | |
622 | #ifdef ARM_BOARD_WFE_TIMEOUT_NS | |
623 | // Enable the WFE Timer | |
624 | rPMGR_EVENT_TMR_PERIOD = ((uint64_t)(ARM_BOARD_WFE_TIMEOUT_NS) *gPEClockFrequencyInfo.timebase_frequency_hz) / NSEC_PER_SEC; | |
625 | rPMGR_EVENT_TMR = rPMGR_EVENT_TMR_PERIOD; | |
626 | rPMGR_EVENT_TMR_CTL = PMGR_EVENT_TMR_CTL_EN; | |
627 | #endif /* ARM_BOARD_WFE_TIMEOUT_NS */ | |
628 | ||
629 | eoi_addr = pic_base; | |
630 | eoi_value = kAICTmrIntStatPct; | |
631 | tbd_funcs = &t8002_funcs; | |
632 | } else | |
633 | #endif | |
634 | #if defined(__arm64__) | |
635 | tbd_funcs = &empty_funcs; | |
636 | #else | |
637 | return 0; | |
638 | #endif | |
639 | ||
640 | if (args != NULL) { | |
641 | ml_init_timebase(args, tbd_funcs, eoi_addr, eoi_value); | |
642 | } | |
643 | ||
644 | return 1; | |
645 | } |