]> git.saurik.com Git - apple/xnu.git/blame_incremental - pexpert/arm/pe_identify_machine.c
xnu-6153.141.1.tar.gz
[apple/xnu.git] / pexpert / arm / pe_identify_machine.c
... / ...
CommitLineData
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 */
23void pe_identify_machine(boot_args * bootArgs);
24
25/* External declarations */
26extern void clean_mmu_dcache(void);
27
28static char *gPESoCDeviceType;
29static char gPESoCDeviceTypeBuffer[SOC_DEVICE_TYPE_BUFFER_SIZE];
30static vm_offset_t gPESoCBasePhys;
31
32static uint32_t gTCFG0Value;
33
34static uint32_t pe_arm_init_timer(void *args);
35
36#if DEVELOPMENT || DEBUG
37decl_simple_lock_data(, panic_hook_lock);
38#endif
39/*
40 * pe_identify_machine:
41 *
42 * Sets up platform parameters. Returns: nothing
43 */
44void
45pe_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 *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 = DTLookupEntry(NULL, "/cpus", &cpus);
111 assert(err == kSuccess);
112
113 err = DTInitEntryIterator(cpus, &iter);
114 assert(err == kSuccess);
115
116 while (kSuccess == DTIterateEntries(&iter, &cpu)) {
117 if ((kSuccess != DTGetProperty(cpu, "state", (void **)&value, &size)) ||
118 (strncmp((char*)value, "running", size) != 0)) {
119 continue;
120 }
121
122 /* Find the time base frequency first. */
123 if (DTGetProperty(cpu, "timebase-frequency", (void **)&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 *)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 (DTGetProperty(cpu, "bus-frequency", (void **)&value, &size) == kSuccess) {
139 if (size == 8) {
140 gPEClockFrequencyInfo.bus_frequency_hz = *(unsigned long long *)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 (DTGetProperty(cpu, "memory-frequency", (void **)&value, &size) == kSuccess) {
156 if (size == 8) {
157 gPEClockFrequencyInfo.mem_frequency_hz = *(unsigned long long *)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 (DTGetProperty(cpu, "peripheral-frequency", (void **)&value, &size) == kSuccess) {
167 if (size == 8) {
168 gPEClockFrequencyInfo.prf_frequency_hz = *(unsigned long long *)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 (DTGetProperty(cpu, "fixed-frequency", (void **)&value, &size) == kSuccess) {
178 if (size == 8) {
179 gPEClockFrequencyInfo.fix_frequency_hz = *(unsigned long long *)value;
180 } else {
181 gPEClockFrequencyInfo.fix_frequency_hz = *value;
182 }
183 }
184 /* Find the cpu frequency last. */
185 if (DTGetProperty(cpu, "clock-frequency", (void **)&value, &size) == kSuccess) {
186 if (size == 8) {
187 gPEClockFrequencyInfo.cpu_frequency_hz = *(unsigned long long *)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
234vm_offset_t
235pe_arm_get_soc_base_phys(void)
236{
237 DTEntry entryP;
238 uintptr_t *ranges_prop;
239 uint32_t prop_size;
240 char *tmpStr;
241
242 if (DTFindEntry("name", "arm-io", &entryP) == kSuccess) {
243 if (gPESoCDeviceType == 0) {
244 DTGetProperty(entryP, "device_type", (void **)&tmpStr, &prop_size);
245 strlcpy(gPESoCDeviceTypeBuffer, tmpStr, SOC_DEVICE_TYPE_BUFFER_SIZE);
246 gPESoCDeviceType = gPESoCDeviceTypeBuffer;
247
248 DTGetProperty(entryP, "ranges", (void **)&ranges_prop, &prop_size);
249 gPESoCBasePhys = *(ranges_prop + 1);
250 }
251 return gPESoCBasePhys;
252 }
253 return 0;
254}
255
256uint32_t
257pe_arm_get_soc_revision(void)
258{
259 DTEntry entryP;
260 uint32_t *value;
261 uint32_t size;
262
263 if ((DTFindEntry("name", "arm-io", &entryP) == kSuccess)
264 && (DTGetProperty(entryP, "chip-revision", (void **)&value, &size) == kSuccess)) {
265 if (size == 8) {
266 return (uint32_t)*(unsigned long long *)value;
267 } else {
268 return *value;
269 }
270 }
271 return 0;
272}
273
274
275extern void fleh_fiq_generic(void);
276
277
278#if defined(ARM_BOARD_CLASS_T7000)
279static struct tbd_ops t7000_funcs = {NULL, NULL, NULL};
280#endif /* defined(ARM_BOARD_CLASS_T7000) */
281
282#if defined(ARM_BOARD_CLASS_S7002)
283extern void fleh_fiq_s7002(void);
284extern uint32_t s7002_get_decrementer(void);
285extern void s7002_set_decrementer(uint32_t);
286static struct tbd_ops s7002_funcs = {&fleh_fiq_s7002, &s7002_get_decrementer, &s7002_set_decrementer};
287#endif /* defined(ARM_BOARD_CLASS_S7002) */
288
289#if defined(ARM_BOARD_CLASS_S8000)
290static struct tbd_ops s8000_funcs = {NULL, NULL, NULL};
291#endif /* defined(ARM_BOARD_CLASS_T7000) */
292
293#if defined(ARM_BOARD_CLASS_T8002)
294extern void fleh_fiq_t8002(void);
295extern uint32_t t8002_get_decrementer(void);
296extern void t8002_set_decrementer(uint32_t);
297static struct tbd_ops t8002_funcs = {&fleh_fiq_t8002, &t8002_get_decrementer, &t8002_set_decrementer};
298#endif /* defined(ARM_BOARD_CLASS_T8002) */
299
300#if defined(ARM_BOARD_CLASS_T8010)
301static struct tbd_ops t8010_funcs = {NULL, NULL, NULL};
302#endif /* defined(ARM_BOARD_CLASS_T8010) */
303
304#if defined(ARM_BOARD_CLASS_T8011)
305static struct tbd_ops t8011_funcs = {NULL, NULL, NULL};
306#endif /* defined(ARM_BOARD_CLASS_T8011) */
307
308#if defined(ARM_BOARD_CLASS_T8015)
309static struct tbd_ops t8015_funcs = {NULL, NULL, NULL};
310#endif /* defined(ARM_BOARD_CLASS_T8015) */
311
312#if defined(ARM_BOARD_CLASS_T8020)
313static struct tbd_ops t8020_funcs = {NULL, NULL, NULL};
314#endif /* defined(ARM_BOARD_CLASS_T8020) */
315
316#if defined(ARM_BOARD_CLASS_T8006)
317static struct tbd_ops t8006_funcs = {NULL, NULL, NULL};
318#endif /* defined(ARM_BOARD_CLASS_T8006) */
319
320#if defined(ARM_BOARD_CLASS_T8027)
321static struct tbd_ops t8027_funcs = {NULL, NULL, NULL};
322#endif /* defined(ARM_BOARD_CLASS_T8027) */
323
324#if defined(ARM_BOARD_CLASS_T8028)
325static struct tbd_ops t8028_funcs = {NULL, NULL, NULL};
326#endif /* defined(ARM_BOARD_CLASS_T8028) */
327
328#if defined(ARM_BOARD_CLASS_T8030)
329static struct tbd_ops t8030_funcs = {NULL, NULL, NULL};
330#endif /* defined(ARM_BOARD_CLASS_T8030) */
331
332
333
334
335#if defined(ARM_BOARD_CLASS_BCM2837)
336static struct tbd_ops bcm2837_funcs = {NULL, NULL, NULL};
337#endif /* defined(ARM_BOARD_CLASS_BCM2837) */
338
339vm_offset_t gPicBase;
340vm_offset_t gTimerBase;
341vm_offset_t gSocPhys;
342
343#if DEVELOPMENT || DEBUG
344// This block contains the panic trace implementation
345
346// These variables are local to this file, and contain the panic trace configuration information
347typedef enum{
348 panic_trace_disabled = 0,
349 panic_trace_unused,
350 panic_trace_enabled,
351 panic_trace_alt_enabled,
352} panic_trace_t;
353static panic_trace_t bootarg_panic_trace;
354
355static int bootarg_stop_clocks;
356
357// The command buffer contains the converted commands from the device tree for commanding cpu_halt, enable_trace, etc.
358#define DEBUG_COMMAND_BUFFER_SIZE 256
359typedef struct command_buffer_element {
360 uintptr_t address;
361 uintptr_t value;
362 uint16_t destination_cpu_selector;
363 uint16_t delay_us;
364 bool is_32bit;
365} command_buffer_element_t;
366static command_buffer_element_t debug_command_buffer[DEBUG_COMMAND_BUFFER_SIZE]; // statically allocate to prevent needing alloc at runtime
367static uint32_t next_command_buffer_entry = 0; // index of next unused slot in debug_command_buffer
368
369#define CPU_SELECTOR_SHIFT (16)
370#define CPU_SELECTOR_MASK (0xFFFF << CPU_SELECTOR_SHIFT)
371#define REGISTER_OFFSET_MASK ((1 << CPU_SELECTOR_SHIFT) - 1)
372#define REGISTER_OFFSET(register_prop) (register_prop & REGISTER_OFFSET_MASK)
373#define CPU_SELECTOR(register_offset) ((register_offset & CPU_SELECTOR_MASK) >> CPU_SELECTOR_SHIFT) // Upper 16bits holds the cpu selector
374#define MAX_WINDOW_SIZE 0xFFFF
375#define PE_ISSPACE(c) (c == ' ' || c == '\t' || c == '\n' || c == '\12')
376#define DELAY_SHIFT (32)
377#define DELAY_MASK (0xFFFFULL << DELAY_SHIFT)
378#define DELAY_US(register_offset) ((register_offset & DELAY_MASK) >> DELAY_SHIFT)
379#define REGISTER_32BIT_MASK (1ULL << 63)
380/*
381 * 0x0000 - all cpus
382 * 0x0001 - cpu 0
383 * 0x0002 - cpu 1
384 * 0x0004 - cpu 2
385 * 0x0003 - cpu 0 and 1
386 * since it's 16bits, we can have up to 16 cpus
387 */
388#define ALL_CPUS 0x0000
389#define IS_CPU_SELECTED(cpu_number, cpu_selector) (cpu_selector == ALL_CPUS || (cpu_selector & (1<<cpu_number) ) != 0 )
390
391#define RESET_VIRTUAL_ADDRESS_WINDOW 0xFFFFFFFF
392
393// Pointers into debug_command_buffer for each operation. Assumes runtime will init them to zero.
394static command_buffer_element_t *cpu_halt;
395static command_buffer_element_t *enable_trace;
396static command_buffer_element_t *enable_alt_trace;
397static command_buffer_element_t *trace_halt;
398static command_buffer_element_t *enable_stop_clocks;
399static command_buffer_element_t *stop_clocks;
400
401// Record which CPU is currently running one of our debug commands, so we can trap panic reentrancy to PE_arm_debug_panic_hook.
402static int running_debug_command_on_cpu_number = -1;
403
404static void
405pe_init_debug_command(DTEntry entryP, command_buffer_element_t **command_buffer, const char* entry_name)
406{
407 uintptr_t *reg_prop;
408 uint32_t prop_size, reg_window_size = 0, command_starting_index;
409 uintptr_t debug_reg_window = 0;
410
411 if (command_buffer == 0) {
412 return;
413 }
414
415 if (DTGetProperty(entryP, entry_name, (void **)&reg_prop, &prop_size) != kSuccess) {
416 panic("pe_init_debug_command: failed to read property %s\n", entry_name);
417 }
418
419 // make sure command will fit
420 if (next_command_buffer_entry + prop_size / sizeof(uintptr_t) > DEBUG_COMMAND_BUFFER_SIZE - 1) {
421 panic("pe_init_debug_command: property %s is %u bytes, command buffer only has %lu bytes remaining\n",
422 entry_name, prop_size, ((DEBUG_COMMAND_BUFFER_SIZE - 1) - next_command_buffer_entry) * sizeof(uintptr_t));
423 }
424
425 // Hold the pointer in a temp variable and later assign it to command buffer, in case we panic while half-initialized
426 command_starting_index = next_command_buffer_entry;
427
428 // convert to real virt addresses and stuff commands into debug_command_buffer
429 for (; prop_size; reg_prop += 2, prop_size -= 2 * sizeof(uintptr_t)) {
430 if (*reg_prop == RESET_VIRTUAL_ADDRESS_WINDOW) {
431 debug_reg_window = 0; // Create a new window
432 } else if (debug_reg_window == 0) {
433 // create a window from virtual address to the specified physical address
434 reg_window_size = ((uint32_t)*(reg_prop + 1));
435 if (reg_window_size > MAX_WINDOW_SIZE) {
436 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 );
437 }
438 debug_reg_window = ml_io_map(gSocPhys + *reg_prop, reg_window_size);
439 // for debug -- kprintf("pe_init_debug_command: %s registers @ 0x%08lX for 0x%08lX\n", entry_name, debug_reg_window, *(reg_prop + 1) );
440 } else {
441 if ((REGISTER_OFFSET(*reg_prop) + sizeof(uintptr_t)) >= reg_window_size) {
442 panic("pe_init_debug_command: Command Offset is %lx, exceeds allocated size of %x\n", REGISTER_OFFSET(*reg_prop), reg_window_size );
443 }
444 debug_command_buffer[next_command_buffer_entry].address = debug_reg_window + REGISTER_OFFSET(*reg_prop);
445 debug_command_buffer[next_command_buffer_entry].destination_cpu_selector = CPU_SELECTOR(*reg_prop);
446#if defined(__arm64__)
447 debug_command_buffer[next_command_buffer_entry].delay_us = DELAY_US(*reg_prop);
448 debug_command_buffer[next_command_buffer_entry].is_32bit = ((*reg_prop & REGISTER_32BIT_MASK) != 0);
449#else
450 debug_command_buffer[next_command_buffer_entry].delay_us = 0;
451 debug_command_buffer[next_command_buffer_entry].is_32bit = false;
452#endif
453 debug_command_buffer[next_command_buffer_entry++].value = *(reg_prop + 1);
454 }
455 }
456
457 // null terminate the address field of the command to end it
458 debug_command_buffer[next_command_buffer_entry++].address = 0;
459
460 // save pointer into table for this command
461 *command_buffer = &debug_command_buffer[command_starting_index];
462}
463
464static void
465pe_run_debug_command(command_buffer_element_t *command_buffer)
466{
467 // 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
468 simple_lock(&panic_hook_lock, LCK_GRP_NULL);
469
470 running_debug_command_on_cpu_number = cpu_number();
471
472 while (command_buffer && command_buffer->address) {
473 if (IS_CPU_SELECTED(running_debug_command_on_cpu_number, command_buffer->destination_cpu_selector)) {
474 if (command_buffer->is_32bit) {
475 *((volatile uint32_t*)(command_buffer->address)) = (uint32_t)(command_buffer->value);
476 } else {
477 *((volatile uintptr_t*)(command_buffer->address)) = command_buffer->value; // register = value;
478 }
479 if (command_buffer->delay_us != 0) {
480 uint64_t deadline;
481 nanoseconds_to_absolutetime(command_buffer->delay_us * NSEC_PER_USEC, &deadline);
482 deadline += ml_get_timebase();
483 while (ml_get_timebase() < deadline) {
484 ;
485 }
486 }
487 }
488 command_buffer++;
489 }
490
491 running_debug_command_on_cpu_number = -1;
492 simple_unlock(&panic_hook_lock);
493}
494
495
496void
497PE_arm_debug_enable_trace(void)
498{
499 switch (bootarg_panic_trace) {
500 case panic_trace_enabled:
501 pe_run_debug_command(enable_trace);
502 break;
503
504 case panic_trace_alt_enabled:
505 pe_run_debug_command(enable_alt_trace);
506 break;
507
508 default:
509 break;
510 }
511}
512
513static void
514PE_arm_panic_hook(const char *str __unused)
515{
516 (void)str; // not used
517 if (bootarg_stop_clocks != 0) {
518 pe_run_debug_command(stop_clocks);
519 }
520 // if panic trace is enabled
521 if (bootarg_panic_trace != 0) {
522 if (running_debug_command_on_cpu_number == cpu_number()) {
523 // This is going to end badly if we don't trap, since we'd be panic-ing during our own code
524 kprintf("## Panic Trace code caused the panic ##\n");
525 return; // allow the normal panic operation to occur.
526 }
527
528 // Stop tracing to freeze the buffer and return to normal panic processing.
529 pe_run_debug_command(trace_halt);
530 }
531}
532
533void (*PE_arm_debug_panic_hook)(const char *str) = PE_arm_panic_hook;
534
535void
536PE_init_cpu(void)
537{
538 if (bootarg_stop_clocks != 0) {
539 pe_run_debug_command(enable_stop_clocks);
540 }
541}
542
543#else
544
545void(*const PE_arm_debug_panic_hook)(const char *str) = NULL;
546
547void
548PE_init_cpu(void)
549{
550}
551
552#endif // DEVELOPMENT || DEBUG
553
554void
555PE_panic_hook(const char *str __unused)
556{
557 if (PE_arm_debug_panic_hook != NULL) {
558 PE_arm_debug_panic_hook(str);
559 }
560}
561
562void
563pe_arm_init_debug(void *args)
564{
565 DTEntry entryP;
566 uintptr_t *reg_prop;
567 uint32_t prop_size;
568
569 if (gSocPhys == 0) {
570 kprintf("pe_arm_init_debug: failed to initialize gSocPhys == 0\n");
571 return;
572 }
573
574 if (DTFindEntry("device_type", "cpu-debug-interface", &entryP) == kSuccess) {
575 if (args != NULL) {
576 if (DTGetProperty(entryP, "reg", (void **)&reg_prop, &prop_size) == kSuccess) {
577 ml_init_arm_debug_interface(args, ml_io_map(gSocPhys + *reg_prop, *(reg_prop + 1)));
578 }
579#if DEVELOPMENT || DEBUG
580 // When args != NULL, this means we're being called from arm_init on the boot CPU.
581 // This controls one-time initialization of the Panic Trace infrastructure
582
583 simple_lock_init(&panic_hook_lock, 0); //assuming single threaded mode
584
585 // Panic_halt is deprecated. Please use panic_trace istead.
586 unsigned int temp_bootarg_panic_trace;
587 if (PE_parse_boot_argn("panic_trace", &temp_bootarg_panic_trace, sizeof(temp_bootarg_panic_trace)) ||
588 PE_parse_boot_argn("panic_halt", &temp_bootarg_panic_trace, sizeof(temp_bootarg_panic_trace))) {
589 kprintf("pe_arm_init_debug: panic_trace=%d\n", temp_bootarg_panic_trace);
590
591 // Prepare debug command buffers.
592 pe_init_debug_command(entryP, &cpu_halt, "cpu_halt");
593 pe_init_debug_command(entryP, &enable_trace, "enable_trace");
594 pe_init_debug_command(entryP, &enable_alt_trace, "enable_alt_trace");
595 pe_init_debug_command(entryP, &trace_halt, "trace_halt");
596
597 // now that init's are done, enable the panic halt capture (allows pe_init_debug_command to panic normally if necessary)
598 bootarg_panic_trace = temp_bootarg_panic_trace;
599
600 // start tracing now if enabled
601 PE_arm_debug_enable_trace();
602 }
603 unsigned int temp_bootarg_stop_clocks;
604 if (PE_parse_boot_argn("stop_clocks", &temp_bootarg_stop_clocks, sizeof(temp_bootarg_stop_clocks))) {
605 pe_init_debug_command(entryP, &enable_stop_clocks, "enable_stop_clocks");
606 pe_init_debug_command(entryP, &stop_clocks, "stop_clocks");
607 bootarg_stop_clocks = temp_bootarg_stop_clocks;
608 }
609#endif
610 }
611 } else {
612 kprintf("pe_arm_init_debug: failed to find cpu-debug-interface\n");
613 }
614}
615
616static uint32_t
617pe_arm_map_interrupt_controller(void)
618{
619 DTEntry entryP;
620 uintptr_t *reg_prop;
621 uint32_t prop_size;
622 vm_offset_t soc_phys = 0;
623
624 gSocPhys = pe_arm_get_soc_base_phys();
625
626 soc_phys = gSocPhys;
627 kprintf("pe_arm_map_interrupt_controller: soc_phys: 0x%lx\n", (unsigned long)soc_phys);
628 if (soc_phys == 0) {
629 return 0;
630 }
631
632 if (DTFindEntry("interrupt-controller", "master", &entryP) == kSuccess) {
633 kprintf("pe_arm_map_interrupt_controller: found interrupt-controller\n");
634 DTGetProperty(entryP, "reg", (void **)&reg_prop, &prop_size);
635 gPicBase = ml_io_map(soc_phys + *reg_prop, *(reg_prop + 1));
636 kprintf("pe_arm_map_interrupt_controller: gPicBase: 0x%lx\n", (unsigned long)gPicBase);
637 }
638 if (gPicBase == 0) {
639 kprintf("pe_arm_map_interrupt_controller: failed to find the interrupt-controller.\n");
640 return 0;
641 }
642
643 if (DTFindEntry("device_type", "timer", &entryP) == kSuccess) {
644 kprintf("pe_arm_map_interrupt_controller: found timer\n");
645 DTGetProperty(entryP, "reg", (void **)&reg_prop, &prop_size);
646 gTimerBase = ml_io_map(soc_phys + *reg_prop, *(reg_prop + 1));
647 kprintf("pe_arm_map_interrupt_controller: gTimerBase: 0x%lx\n", (unsigned long)gTimerBase);
648 }
649 if (gTimerBase == 0) {
650 kprintf("pe_arm_map_interrupt_controller: failed to find the timer.\n");
651 return 0;
652 }
653
654 return 1;
655}
656
657uint32_t
658pe_arm_init_interrupts(void *args)
659{
660 kprintf("pe_arm_init_interrupts: args: %p\n", args);
661
662 /* Set up mappings for interrupt controller and possibly timers (if they haven't been set up already) */
663 if (args != NULL) {
664 if (!pe_arm_map_interrupt_controller()) {
665 return 0;
666 }
667 }
668
669 return pe_arm_init_timer(args);
670}
671
672static uint32_t
673pe_arm_init_timer(void *args)
674{
675 vm_offset_t pic_base = 0;
676 vm_offset_t timer_base = 0;
677 vm_offset_t soc_phys;
678 vm_offset_t eoi_addr = 0;
679 uint32_t eoi_value = 0;
680 struct tbd_ops generic_funcs = {&fleh_fiq_generic, NULL, NULL};
681 tbd_ops_t tbd_funcs = &generic_funcs;
682
683 /* The SoC headers expect to use pic_base, timer_base, etc... */
684 pic_base = gPicBase;
685 timer_base = gTimerBase;
686 soc_phys = gSocPhys;
687
688#if defined(ARM_BOARD_CLASS_T7000)
689 if (!strcmp(gPESoCDeviceType, "t7000-io") ||
690 !strcmp(gPESoCDeviceType, "t7001-io")) {
691 tbd_funcs = &t7000_funcs;
692 } else
693#endif
694#if defined(ARM_BOARD_CLASS_S7002)
695 if (!strcmp(gPESoCDeviceType, "s7002-io")) {
696#ifdef ARM_BOARD_WFE_TIMEOUT_NS
697 // Enable the WFE Timer
698 rPMGR_EVENT_TMR_PERIOD = ((uint64_t)(ARM_BOARD_WFE_TIMEOUT_NS) *gPEClockFrequencyInfo.timebase_frequency_hz) / NSEC_PER_SEC;
699 rPMGR_EVENT_TMR = rPMGR_EVENT_TMR_PERIOD;
700 rPMGR_EVENT_TMR_CTL = PMGR_EVENT_TMR_CTL_EN;
701#endif /* ARM_BOARD_WFE_TIMEOUT_NS */
702
703 rPMGR_INTERVAL_TMR = 0x7FFFFFFF;
704 rPMGR_INTERVAL_TMR_CTL = PMGR_INTERVAL_TMR_CTL_EN | PMGR_INTERVAL_TMR_CTL_CLR_INT;
705
706 eoi_addr = timer_base;
707 eoi_value = PMGR_INTERVAL_TMR_CTL_EN | PMGR_INTERVAL_TMR_CTL_CLR_INT;
708 tbd_funcs = &s7002_funcs;
709 } else
710#endif
711#if defined(ARM_BOARD_CLASS_S8000)
712 if (!strcmp(gPESoCDeviceType, "s8000-io") ||
713 !strcmp(gPESoCDeviceType, "s8001-io")) {
714 tbd_funcs = &s8000_funcs;
715 } else
716#endif
717#if defined(ARM_BOARD_CLASS_T8002)
718 if (!strcmp(gPESoCDeviceType, "t8002-io") ||
719 !strcmp(gPESoCDeviceType, "t8004-io")) {
720 /* Enable the Decrementer */
721 aic_write32(kAICTmrCnt, 0x7FFFFFFF);
722 aic_write32(kAICTmrCfg, kAICTmrCfgEn);
723 aic_write32(kAICTmrIntStat, kAICTmrIntStatPct);
724#ifdef ARM_BOARD_WFE_TIMEOUT_NS
725 // Enable the WFE Timer
726 rPMGR_EVENT_TMR_PERIOD = ((uint64_t)(ARM_BOARD_WFE_TIMEOUT_NS) *gPEClockFrequencyInfo.timebase_frequency_hz) / NSEC_PER_SEC;
727 rPMGR_EVENT_TMR = rPMGR_EVENT_TMR_PERIOD;
728 rPMGR_EVENT_TMR_CTL = PMGR_EVENT_TMR_CTL_EN;
729#endif /* ARM_BOARD_WFE_TIMEOUT_NS */
730
731 eoi_addr = pic_base;
732 eoi_value = kAICTmrIntStatPct;
733 tbd_funcs = &t8002_funcs;
734 } else
735#endif
736#if defined(ARM_BOARD_CLASS_T8010)
737 if (!strcmp(gPESoCDeviceType, "t8010-io")) {
738 tbd_funcs = &t8010_funcs;
739 } else
740#endif
741#if defined(ARM_BOARD_CLASS_T8011)
742 if (!strcmp(gPESoCDeviceType, "t8011-io")) {
743 tbd_funcs = &t8011_funcs;
744 } else
745#endif
746#if defined(ARM_BOARD_CLASS_T8015)
747 if (!strcmp(gPESoCDeviceType, "t8015-io")) {
748 tbd_funcs = &t8015_funcs;
749 } else
750#endif
751#if defined(ARM_BOARD_CLASS_T8020)
752 if (!strcmp(gPESoCDeviceType, "t8020-io")) {
753 tbd_funcs = &t8020_funcs;
754 } else
755#endif
756#if defined(ARM_BOARD_CLASS_T8006)
757 if (!strcmp(gPESoCDeviceType, "t8006-io")) {
758 tbd_funcs = &t8006_funcs;
759 } else
760#endif
761#if defined(ARM_BOARD_CLASS_T8027)
762 if (!strcmp(gPESoCDeviceType, "t8027-io")) {
763 tbd_funcs = &t8027_funcs;
764 } else
765#endif
766#if defined(ARM_BOARD_CLASS_T8028)
767 if (!strcmp(gPESoCDeviceType, "t8028-io")) {
768 tbd_funcs = &t8028_funcs;
769 } else
770#endif
771#if defined(ARM_BOARD_CLASS_T8030)
772 if (!strcmp(gPESoCDeviceType, "t8030-io")) {
773 tbd_funcs = &t8030_funcs;
774 } else
775#endif
776#if defined(ARM_BOARD_CLASS_BCM2837)
777 if (!strcmp(gPESoCDeviceType, "bcm2837-io")) {
778 tbd_funcs = &bcm2837_funcs;
779 } else
780#endif
781 return 0;
782
783 if (args != NULL) {
784 ml_init_timebase(args, tbd_funcs, eoi_addr, eoi_value);
785 }
786
787 return 1;
788}