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