]>
Commit | Line | Data |
---|---|---|
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 | 23 | void pe_identify_machine(boot_args * bootArgs); |
5ba3f43e A |
24 | |
25 | /* External declarations */ | |
26 | extern void clean_mmu_dcache(void); | |
27 | ||
28 | static char *gPESoCDeviceType; | |
0a7de745 | 29 | static char gPESoCDeviceTypeBuffer[SOC_DEVICE_TYPE_BUFFER_SIZE]; |
5ba3f43e A |
30 | static vm_offset_t gPESoCBasePhys; |
31 | ||
0a7de745 | 32 | static uint32_t gTCFG0Value; |
5ba3f43e A |
33 | |
34 | static uint32_t pe_arm_init_timer(void *args); | |
35 | ||
36 | #if DEVELOPMENT || DEBUG | |
cb323159 | 37 | decl_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 | */ | |
44 | void | |
45 | pe_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 | ||
234 | vm_offset_t | |
235 | pe_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 | 256 | extern void fleh_fiq_generic(void); |
5ba3f43e | 257 | |
5ba3f43e A |
258 | #if defined(ARM_BOARD_CLASS_T8002) |
259 | extern void fleh_fiq_t8002(void); | |
0a7de745 A |
260 | extern uint32_t t8002_get_decrementer(void); |
261 | extern void t8002_set_decrementer(uint32_t); | |
5ba3f43e A |
262 | static struct tbd_ops t8002_funcs = {&fleh_fiq_t8002, &t8002_get_decrementer, &t8002_set_decrementer}; |
263 | #endif /* defined(ARM_BOARD_CLASS_T8002) */ | |
264 | ||
0a7de745 A |
265 | vm_offset_t gPicBase; |
266 | vm_offset_t gTimerBase; | |
267 | vm_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 |
273 | typedef 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; |
279 | static panic_trace_t bootarg_panic_trace; | |
280 | ||
cb323159 A |
281 | static 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 | 285 | typedef 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 | 292 | static command_buffer_element_t debug_command_buffer[DEBUG_COMMAND_BUFFER_SIZE]; // statically allocate to prevent needing alloc at runtime |
cb323159 | 293 | static 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. | |
320 | static command_buffer_element_t *cpu_halt; | |
321 | static command_buffer_element_t *enable_trace; | |
322 | static command_buffer_element_t *enable_alt_trace; | |
323 | static command_buffer_element_t *trace_halt; | |
cb323159 A |
324 | static command_buffer_element_t *enable_stop_clocks; |
325 | static 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. | |
328 | static int running_debug_command_on_cpu_number = -1; | |
329 | ||
330 | static void | |
331 | pe_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 **)®_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 | ||
390 | static void | |
391 | pe_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 | ||
422 | void | |
423 | PE_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 | ||
439 | static void | |
cb323159 | 440 | PE_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 |
459 | void (*PE_arm_debug_panic_hook)(const char *str) = PE_arm_panic_hook; |
460 | ||
461 | void | |
462 | PE_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 |
471 | void(*const PE_arm_debug_panic_hook)(const char *str) = NULL; |
472 | ||
473 | void | |
474 | PE_init_cpu(void) | |
475 | { | |
476 | } | |
5ba3f43e A |
477 | |
478 | #endif // DEVELOPMENT || DEBUG | |
479 | ||
cb323159 A |
480 | void |
481 | PE_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 |
488 | void |
489 | pe_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 **)®_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 | ||
542 | static uint32_t | |
543 | pe_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 **)®_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 **)®_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 | ||
583 | uint32_t | |
584 | pe_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 | 598 | static uint32_t |
5ba3f43e A |
599 | pe_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 | } |