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