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