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 */ |
22 | void pe_identify_machine(boot_args * bootArgs); |
23 | |
24 | /* External declarations */ |
25 | extern void clean_mmu_dcache(void); |
26 | |
27 | static char *gPESoCDeviceType; |
28 | static char gPESoCDeviceTypeBuffer[SOC_DEVICE_TYPE_BUFFER_SIZE]; |
29 | static vm_offset_t gPESoCBasePhys; |
30 | |
31 | static uint32_t gTCFG0Value; |
32 | |
33 | static uint32_t pe_arm_init_timer(void *args); |
34 | |
35 | #if DEVELOPMENT || DEBUG |
36 | decl_simple_lock_data(, panic_trace_lock;) |
37 | #endif |
38 | /* |
39 | * pe_identify_machine: |
40 | * |
41 | * Sets up platform parameters. Returns: nothing |
42 | */ |
43 | void |
44 | pe_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 | |
229 | vm_offset_t |
230 | pe_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 | |
251 | uint32_t |
252 | pe_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 | |
269 | extern void fleh_fiq_generic(void); |
270 | |
271 | #if defined(ARM_BOARD_CLASS_S5L8960X) |
272 | static struct tbd_ops s5l8960x_funcs = {NULL, NULL, NULL}; |
273 | #endif /* defined(ARM_BOARD_CLASS_S5L8960X) */ |
274 | |
275 | #if defined(ARM_BOARD_CLASS_T7000) |
276 | static struct tbd_ops t7000_funcs = {NULL, NULL, NULL}; |
277 | #endif /* defined(ARM_BOARD_CLASS_T7000) */ |
278 | |
279 | #if defined(ARM_BOARD_CLASS_S7002) |
280 | extern void fleh_fiq_s7002(void); |
281 | extern uint32_t s7002_get_decrementer(void); |
282 | extern void s7002_set_decrementer(uint32_t); |
283 | static 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) |
287 | static struct tbd_ops s8000_funcs = {NULL, NULL, NULL}; |
288 | #endif /* defined(ARM_BOARD_CLASS_T7000) */ |
289 | |
290 | #if defined(ARM_BOARD_CLASS_T8002) |
291 | extern void fleh_fiq_t8002(void); |
292 | extern uint32_t t8002_get_decrementer(void); |
293 | extern void t8002_set_decrementer(uint32_t); |
294 | static 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) |
298 | static struct tbd_ops t8010_funcs = {NULL, NULL, NULL}; |
299 | #endif /* defined(ARM_BOARD_CLASS_T8010) */ |
300 | |
301 | #if defined(ARM_BOARD_CLASS_T8011) |
302 | static struct tbd_ops t8011_funcs = {NULL, NULL, NULL}; |
303 | #endif /* defined(ARM_BOARD_CLASS_T8011) */ |
304 | |
305 | #if defined(ARM_BOARD_CLASS_T8015) |
306 | static 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) |
315 | static struct tbd_ops bcm2837_funcs = {NULL, NULL, NULL}; |
316 | #endif /* defined(ARM_BOARD_CLASS_BCM2837) */ |
317 | |
318 | vm_offset_t gPicBase; |
319 | vm_offset_t gTimerBase; |
320 | vm_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 |
326 | typedef enum |
327 | { |
328 | panic_trace_disabled = 0, |
329 | panic_trace_unused, |
330 | panic_trace_enabled, |
331 | panic_trace_alt_enabled, |
332 | } panic_trace_t; |
333 | static 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 |
337 | typedef struct command_buffer_element{ |
338 | uintptr_t address; |
339 | uint16_t destination_cpu_selector; |
340 | uintptr_t value; |
341 | } command_buffer_element_t; |
342 | static command_buffer_element_t debug_command_buffer[DEBUG_COMMAND_BUFFER_SIZE]; // statically allocate to prevent needing alloc at runtime |
343 | static 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 | /* |
353 | 0x0000 - all cpus |
354 | 0x0001 - cpu 0 |
355 | 0x0002 - cpu 1 |
356 | 0x0004 - cpu 2 |
357 | 0x0003 - cpu 0 and 1 |
358 | since 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. |
366 | static command_buffer_element_t *cpu_halt; |
367 | static command_buffer_element_t *enable_trace; |
368 | static command_buffer_element_t *enable_alt_trace; |
369 | static 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. |
372 | static int running_debug_command_on_cpu_number = -1; |
373 | |
374 | static void |
375 | pe_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 **)®_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 | |
428 | static void |
429 | pe_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 | |
447 | void |
448 | PE_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 | |
464 | static void |
465 | PEARMDebugPanicHook(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 | |
482 | void (*PE_arm_debug_panic_hook)(const char *str) = PEARMDebugPanicHook; |
483 | |
484 | #else |
485 | |
486 | void (*PE_arm_debug_panic_hook)(const char *str) = NULL; |
487 | |
488 | #endif // DEVELOPMENT || DEBUG |
489 | |
490 | void |
491 | pe_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 **)®_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 | |
539 | static uint32_t |
540 | pe_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 **)®_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 **)®_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 | |
579 | uint32_t |
580 | pe_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 | |
594 | static uint32_t |
595 | pe_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 | |