]>
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; | |
5ba3f43e | 50 | unsigned long *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 | ||
110 | err = DTLookupEntry(NULL, "/cpus", &cpus); | |
111 | assert(err == kSuccess); | |
112 | ||
113 | err = DTInitEntryIterator(cpus, &iter); | |
114 | assert(err == kSuccess); | |
115 | ||
116 | while (kSuccess == DTIterateEntries(&iter, &cpu)) { | |
117 | if ((kSuccess != DTGetProperty(cpu, "state", (void **)&value, &size)) || | |
0a7de745 | 118 | (strncmp((char*)value, "running", size) != 0)) { |
5ba3f43e | 119 | continue; |
0a7de745 | 120 | } |
5ba3f43e A |
121 | |
122 | /* Find the time base frequency first. */ | |
123 | if (DTGetProperty(cpu, "timebase-frequency", (void **)&value, &size) == kSuccess) { | |
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) { |
5ba3f43e | 130 | gPEClockFrequencyInfo.timebase_frequency_hz = *(unsigned long long *)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. */ | |
138 | if (DTGetProperty(cpu, "bus-frequency", (void **)&value, &size) == kSuccess) { | |
0a7de745 | 139 | if (size == 8) { |
5ba3f43e | 140 | gPEClockFrequencyInfo.bus_frequency_hz = *(unsigned long long *)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. */ | |
155 | if (DTGetProperty(cpu, "memory-frequency", (void **)&value, &size) == kSuccess) { | |
0a7de745 | 156 | if (size == 8) { |
5ba3f43e | 157 | gPEClockFrequencyInfo.mem_frequency_hz = *(unsigned long long *)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. */ | |
166 | if (DTGetProperty(cpu, "peripheral-frequency", (void **)&value, &size) == kSuccess) { | |
0a7de745 | 167 | if (size == 8) { |
5ba3f43e | 168 | gPEClockFrequencyInfo.prf_frequency_hz = *(unsigned long long *)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. */ | |
177 | if (DTGetProperty(cpu, "fixed-frequency", (void **)&value, &size) == kSuccess) { | |
0a7de745 | 178 | if (size == 8) { |
5ba3f43e | 179 | gPEClockFrequencyInfo.fix_frequency_hz = *(unsigned long long *)value; |
0a7de745 | 180 | } else { |
5ba3f43e | 181 | gPEClockFrequencyInfo.fix_frequency_hz = *value; |
0a7de745 | 182 | } |
5ba3f43e A |
183 | } |
184 | /* Find the cpu frequency last. */ | |
185 | if (DTGetProperty(cpu, "clock-frequency", (void **)&value, &size) == kSuccess) { | |
0a7de745 | 186 | if (size == 8) { |
5ba3f43e | 187 | gPEClockFrequencyInfo.cpu_frequency_hz = *(unsigned long long *)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 A |
237 | DTEntry entryP; |
238 | uintptr_t *ranges_prop; | |
239 | uint32_t prop_size; | |
5ba3f43e A |
240 | char *tmpStr; |
241 | ||
242 | if (DTFindEntry("name", "arm-io", &entryP) == kSuccess) { | |
243 | if (gPESoCDeviceType == 0) { | |
244 | DTGetProperty(entryP, "device_type", (void **)&tmpStr, &prop_size); | |
245 | strlcpy(gPESoCDeviceTypeBuffer, tmpStr, SOC_DEVICE_TYPE_BUFFER_SIZE); | |
246 | gPESoCDeviceType = gPESoCDeviceTypeBuffer; | |
247 | ||
248 | DTGetProperty(entryP, "ranges", (void **)&ranges_prop, &prop_size); | |
249 | gPESoCBasePhys = *(ranges_prop + 1); | |
250 | } | |
251 | return gPESoCBasePhys; | |
252 | } | |
253 | return 0; | |
254 | } | |
255 | ||
256 | uint32_t | |
257 | pe_arm_get_soc_revision(void) | |
258 | { | |
0a7de745 A |
259 | DTEntry entryP; |
260 | uint32_t *value; | |
261 | uint32_t size; | |
5ba3f43e | 262 | |
0a7de745 | 263 | if ((DTFindEntry("name", "arm-io", &entryP) == kSuccess) |
5ba3f43e | 264 | && (DTGetProperty(entryP, "chip-revision", (void **)&value, &size) == kSuccess)) { |
0a7de745 A |
265 | if (size == 8) { |
266 | return (uint32_t)*(unsigned long long *)value; | |
267 | } else { | |
268 | return *value; | |
269 | } | |
5ba3f43e A |
270 | } |
271 | return 0; | |
272 | } | |
273 | ||
274 | ||
0a7de745 | 275 | extern void fleh_fiq_generic(void); |
5ba3f43e | 276 | |
5ba3f43e A |
277 | |
278 | #if defined(ARM_BOARD_CLASS_T7000) | |
279 | static struct tbd_ops t7000_funcs = {NULL, NULL, NULL}; | |
280 | #endif /* defined(ARM_BOARD_CLASS_T7000) */ | |
281 | ||
282 | #if defined(ARM_BOARD_CLASS_S7002) | |
283 | extern void fleh_fiq_s7002(void); | |
0a7de745 A |
284 | extern uint32_t s7002_get_decrementer(void); |
285 | extern void s7002_set_decrementer(uint32_t); | |
5ba3f43e A |
286 | static struct tbd_ops s7002_funcs = {&fleh_fiq_s7002, &s7002_get_decrementer, &s7002_set_decrementer}; |
287 | #endif /* defined(ARM_BOARD_CLASS_S7002) */ | |
288 | ||
289 | #if defined(ARM_BOARD_CLASS_S8000) | |
290 | static struct tbd_ops s8000_funcs = {NULL, NULL, NULL}; | |
291 | #endif /* defined(ARM_BOARD_CLASS_T7000) */ | |
292 | ||
293 | #if defined(ARM_BOARD_CLASS_T8002) | |
294 | extern void fleh_fiq_t8002(void); | |
0a7de745 A |
295 | extern uint32_t t8002_get_decrementer(void); |
296 | extern void t8002_set_decrementer(uint32_t); | |
5ba3f43e A |
297 | static struct tbd_ops t8002_funcs = {&fleh_fiq_t8002, &t8002_get_decrementer, &t8002_set_decrementer}; |
298 | #endif /* defined(ARM_BOARD_CLASS_T8002) */ | |
299 | ||
300 | #if defined(ARM_BOARD_CLASS_T8010) | |
301 | static struct tbd_ops t8010_funcs = {NULL, NULL, NULL}; | |
302 | #endif /* defined(ARM_BOARD_CLASS_T8010) */ | |
303 | ||
304 | #if defined(ARM_BOARD_CLASS_T8011) | |
305 | static struct tbd_ops t8011_funcs = {NULL, NULL, NULL}; | |
306 | #endif /* defined(ARM_BOARD_CLASS_T8011) */ | |
307 | ||
d9a64523 A |
308 | #if defined(ARM_BOARD_CLASS_T8015) |
309 | static struct tbd_ops t8015_funcs = {NULL, NULL, NULL}; | |
310 | #endif /* defined(ARM_BOARD_CLASS_T8015) */ | |
311 | ||
c6bf4f31 A |
312 | #if defined(ARM_BOARD_CLASS_T8020) |
313 | static struct tbd_ops t8020_funcs = {NULL, NULL, NULL}; | |
314 | #endif /* defined(ARM_BOARD_CLASS_T8020) */ | |
d9a64523 | 315 | |
c6bf4f31 A |
316 | #if defined(ARM_BOARD_CLASS_T8006) |
317 | static struct tbd_ops t8006_funcs = {NULL, NULL, NULL}; | |
318 | #endif /* defined(ARM_BOARD_CLASS_T8006) */ | |
5ba3f43e | 319 | |
c6bf4f31 A |
320 | #if defined(ARM_BOARD_CLASS_T8027) |
321 | static struct tbd_ops t8027_funcs = {NULL, NULL, NULL}; | |
322 | #endif /* defined(ARM_BOARD_CLASS_T8027) */ | |
5ba3f43e | 323 | |
c6bf4f31 A |
324 | #if defined(ARM_BOARD_CLASS_T8028) |
325 | static struct tbd_ops t8028_funcs = {NULL, NULL, NULL}; | |
326 | #endif /* defined(ARM_BOARD_CLASS_T8028) */ | |
5ba3f43e | 327 | |
c6bf4f31 A |
328 | #if defined(ARM_BOARD_CLASS_T8030) |
329 | static struct tbd_ops t8030_funcs = {NULL, NULL, NULL}; | |
330 | #endif /* defined(ARM_BOARD_CLASS_T8030) */ | |
5ba3f43e | 331 | |
cb323159 A |
332 | |
333 | ||
334 | ||
d9a64523 A |
335 | #if defined(ARM_BOARD_CLASS_BCM2837) |
336 | static struct tbd_ops bcm2837_funcs = {NULL, NULL, NULL}; | |
337 | #endif /* defined(ARM_BOARD_CLASS_BCM2837) */ | |
5ba3f43e | 338 | |
0a7de745 A |
339 | vm_offset_t gPicBase; |
340 | vm_offset_t gTimerBase; | |
341 | vm_offset_t gSocPhys; | |
5ba3f43e A |
342 | |
343 | #if DEVELOPMENT || DEBUG | |
344 | // This block contains the panic trace implementation | |
345 | ||
346 | // These variables are local to this file, and contain the panic trace configuration information | |
0a7de745 A |
347 | typedef enum{ |
348 | panic_trace_disabled = 0, | |
349 | panic_trace_unused, | |
350 | panic_trace_enabled, | |
351 | panic_trace_alt_enabled, | |
5ba3f43e A |
352 | } panic_trace_t; |
353 | static panic_trace_t bootarg_panic_trace; | |
354 | ||
cb323159 A |
355 | static int bootarg_stop_clocks; |
356 | ||
5ba3f43e | 357 | // The command buffer contains the converted commands from the device tree for commanding cpu_halt, enable_trace, etc. |
d9a64523 | 358 | #define DEBUG_COMMAND_BUFFER_SIZE 256 |
0a7de745 | 359 | typedef struct command_buffer_element { |
5ba3f43e | 360 | uintptr_t address; |
5ba3f43e | 361 | uintptr_t value; |
cb323159 A |
362 | uint16_t destination_cpu_selector; |
363 | uint16_t delay_us; | |
364 | bool is_32bit; | |
5ba3f43e | 365 | } command_buffer_element_t; |
0a7de745 | 366 | static command_buffer_element_t debug_command_buffer[DEBUG_COMMAND_BUFFER_SIZE]; // statically allocate to prevent needing alloc at runtime |
cb323159 | 367 | static uint32_t next_command_buffer_entry = 0; // index of next unused slot in debug_command_buffer |
0a7de745 | 368 | |
cb323159 A |
369 | #define CPU_SELECTOR_SHIFT (16) |
370 | #define CPU_SELECTOR_MASK (0xFFFF << CPU_SELECTOR_SHIFT) | |
371 | #define REGISTER_OFFSET_MASK ((1 << CPU_SELECTOR_SHIFT) - 1) | |
0a7de745 | 372 | #define REGISTER_OFFSET(register_prop) (register_prop & REGISTER_OFFSET_MASK) |
cb323159 A |
373 | #define CPU_SELECTOR(register_offset) ((register_offset & CPU_SELECTOR_MASK) >> CPU_SELECTOR_SHIFT) // Upper 16bits holds the cpu selector |
374 | #define MAX_WINDOW_SIZE 0xFFFF | |
375 | #define PE_ISSPACE(c) (c == ' ' || c == '\t' || c == '\n' || c == '\12') | |
376 | #define DELAY_SHIFT (32) | |
377 | #define DELAY_MASK (0xFFFFULL << DELAY_SHIFT) | |
378 | #define DELAY_US(register_offset) ((register_offset & DELAY_MASK) >> DELAY_SHIFT) | |
379 | #define REGISTER_32BIT_MASK (1ULL << 63) | |
5ba3f43e | 380 | /* |
0a7de745 A |
381 | * 0x0000 - all cpus |
382 | * 0x0001 - cpu 0 | |
383 | * 0x0002 - cpu 1 | |
384 | * 0x0004 - cpu 2 | |
385 | * 0x0003 - cpu 0 and 1 | |
386 | * since it's 16bits, we can have up to 16 cpus | |
387 | */ | |
5ba3f43e A |
388 | #define ALL_CPUS 0x0000 |
389 | #define IS_CPU_SELECTED(cpu_number, cpu_selector) (cpu_selector == ALL_CPUS || (cpu_selector & (1<<cpu_number) ) != 0 ) | |
390 | ||
0a7de745 | 391 | #define RESET_VIRTUAL_ADDRESS_WINDOW 0xFFFFFFFF |
5ba3f43e A |
392 | |
393 | // Pointers into debug_command_buffer for each operation. Assumes runtime will init them to zero. | |
394 | static command_buffer_element_t *cpu_halt; | |
395 | static command_buffer_element_t *enable_trace; | |
396 | static command_buffer_element_t *enable_alt_trace; | |
397 | static command_buffer_element_t *trace_halt; | |
cb323159 A |
398 | static command_buffer_element_t *enable_stop_clocks; |
399 | static command_buffer_element_t *stop_clocks; | |
5ba3f43e A |
400 | |
401 | // Record which CPU is currently running one of our debug commands, so we can trap panic reentrancy to PE_arm_debug_panic_hook. | |
402 | static int running_debug_command_on_cpu_number = -1; | |
403 | ||
404 | static void | |
405 | pe_init_debug_command(DTEntry entryP, command_buffer_element_t **command_buffer, const char* entry_name) | |
406 | { | |
0a7de745 A |
407 | uintptr_t *reg_prop; |
408 | uint32_t prop_size, reg_window_size = 0, command_starting_index; | |
409 | uintptr_t debug_reg_window = 0; | |
5ba3f43e A |
410 | |
411 | if (command_buffer == 0) { | |
412 | return; | |
413 | } | |
414 | ||
415 | if (DTGetProperty(entryP, entry_name, (void **)®_prop, &prop_size) != kSuccess) { | |
416 | panic("pe_init_debug_command: failed to read property %s\n", entry_name); | |
417 | } | |
418 | ||
419 | // make sure command will fit | |
cb323159 | 420 | if (next_command_buffer_entry + prop_size / sizeof(uintptr_t) > DEBUG_COMMAND_BUFFER_SIZE - 1) { |
5ba3f43e | 421 | panic("pe_init_debug_command: property %s is %u bytes, command buffer only has %lu bytes remaining\n", |
cb323159 | 422 | entry_name, prop_size, ((DEBUG_COMMAND_BUFFER_SIZE - 1) - next_command_buffer_entry) * sizeof(uintptr_t)); |
5ba3f43e A |
423 | } |
424 | ||
425 | // Hold the pointer in a temp variable and later assign it to command buffer, in case we panic while half-initialized | |
cb323159 | 426 | command_starting_index = next_command_buffer_entry; |
5ba3f43e A |
427 | |
428 | // convert to real virt addresses and stuff commands into debug_command_buffer | |
0a7de745 | 429 | for (; prop_size; reg_prop += 2, prop_size -= 2 * sizeof(uintptr_t)) { |
5ba3f43e A |
430 | if (*reg_prop == RESET_VIRTUAL_ADDRESS_WINDOW) { |
431 | debug_reg_window = 0; // Create a new window | |
0a7de745 | 432 | } else if (debug_reg_window == 0) { |
5ba3f43e A |
433 | // create a window from virtual address to the specified physical address |
434 | reg_window_size = ((uint32_t)*(reg_prop + 1)); | |
435 | if (reg_window_size > MAX_WINDOW_SIZE) { | |
436 | 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 ); | |
437 | } | |
438 | debug_reg_window = ml_io_map(gSocPhys + *reg_prop, reg_window_size); | |
439 | // for debug -- kprintf("pe_init_debug_command: %s registers @ 0x%08lX for 0x%08lX\n", entry_name, debug_reg_window, *(reg_prop + 1) ); | |
440 | } else { | |
0a7de745 A |
441 | if ((REGISTER_OFFSET(*reg_prop) + sizeof(uintptr_t)) >= reg_window_size) { |
442 | panic("pe_init_debug_command: Command Offset is %lx, exceeds allocated size of %x\n", REGISTER_OFFSET(*reg_prop), reg_window_size ); | |
5ba3f43e | 443 | } |
cb323159 A |
444 | debug_command_buffer[next_command_buffer_entry].address = debug_reg_window + REGISTER_OFFSET(*reg_prop); |
445 | debug_command_buffer[next_command_buffer_entry].destination_cpu_selector = CPU_SELECTOR(*reg_prop); | |
446 | #if defined(__arm64__) | |
447 | debug_command_buffer[next_command_buffer_entry].delay_us = DELAY_US(*reg_prop); | |
448 | debug_command_buffer[next_command_buffer_entry].is_32bit = ((*reg_prop & REGISTER_32BIT_MASK) != 0); | |
449 | #else | |
450 | debug_command_buffer[next_command_buffer_entry].delay_us = 0; | |
451 | debug_command_buffer[next_command_buffer_entry].is_32bit = false; | |
452 | #endif | |
453 | debug_command_buffer[next_command_buffer_entry++].value = *(reg_prop + 1); | |
5ba3f43e A |
454 | } |
455 | } | |
456 | ||
457 | // null terminate the address field of the command to end it | |
cb323159 | 458 | debug_command_buffer[next_command_buffer_entry++].address = 0; |
5ba3f43e | 459 | |
0a7de745 | 460 | // save pointer into table for this command |
5ba3f43e A |
461 | *command_buffer = &debug_command_buffer[command_starting_index]; |
462 | } | |
463 | ||
464 | static void | |
465 | pe_run_debug_command(command_buffer_element_t *command_buffer) | |
466 | { | |
467 | // 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 |
468 | simple_lock(&panic_hook_lock, LCK_GRP_NULL); |
469 | ||
5ba3f43e A |
470 | running_debug_command_on_cpu_number = cpu_number(); |
471 | ||
0a7de745 | 472 | while (command_buffer && command_buffer->address) { |
5ba3f43e | 473 | if (IS_CPU_SELECTED(running_debug_command_on_cpu_number, command_buffer->destination_cpu_selector)) { |
cb323159 A |
474 | if (command_buffer->is_32bit) { |
475 | *((volatile uint32_t*)(command_buffer->address)) = (uint32_t)(command_buffer->value); | |
476 | } else { | |
477 | *((volatile uintptr_t*)(command_buffer->address)) = command_buffer->value; // register = value; | |
478 | } | |
479 | if (command_buffer->delay_us != 0) { | |
480 | uint64_t deadline; | |
481 | nanoseconds_to_absolutetime(command_buffer->delay_us * NSEC_PER_USEC, &deadline); | |
482 | deadline += ml_get_timebase(); | |
483 | while (ml_get_timebase() < deadline) { | |
484 | ; | |
485 | } | |
486 | } | |
5ba3f43e A |
487 | } |
488 | command_buffer++; | |
489 | } | |
490 | ||
491 | running_debug_command_on_cpu_number = -1; | |
cb323159 | 492 | simple_unlock(&panic_hook_lock); |
5ba3f43e A |
493 | } |
494 | ||
495 | ||
496 | void | |
497 | PE_arm_debug_enable_trace(void) | |
498 | { | |
0a7de745 A |
499 | switch (bootarg_panic_trace) { |
500 | case panic_trace_enabled: | |
501 | pe_run_debug_command(enable_trace); | |
502 | break; | |
503 | ||
504 | case panic_trace_alt_enabled: | |
505 | pe_run_debug_command(enable_alt_trace); | |
506 | break; | |
507 | ||
508 | default: | |
509 | break; | |
510 | } | |
5ba3f43e A |
511 | } |
512 | ||
513 | static void | |
cb323159 | 514 | PE_arm_panic_hook(const char *str __unused) |
5ba3f43e | 515 | { |
0a7de745 | 516 | (void)str; // not used |
cb323159 A |
517 | if (bootarg_stop_clocks != 0) { |
518 | pe_run_debug_command(stop_clocks); | |
519 | } | |
5ba3f43e A |
520 | // if panic trace is enabled |
521 | if (bootarg_panic_trace != 0) { | |
522 | if (running_debug_command_on_cpu_number == cpu_number()) { | |
523 | // This is going to end badly if we don't trap, since we'd be panic-ing during our own code | |
524 | kprintf("## Panic Trace code caused the panic ##\n"); | |
525 | return; // allow the normal panic operation to occur. | |
526 | } | |
527 | ||
cb323159 | 528 | // Stop tracing to freeze the buffer and return to normal panic processing. |
5ba3f43e A |
529 | pe_run_debug_command(trace_halt); |
530 | } | |
531 | } | |
532 | ||
cb323159 A |
533 | void (*PE_arm_debug_panic_hook)(const char *str) = PE_arm_panic_hook; |
534 | ||
535 | void | |
536 | PE_init_cpu(void) | |
537 | { | |
538 | if (bootarg_stop_clocks != 0) { | |
539 | pe_run_debug_command(enable_stop_clocks); | |
540 | } | |
541 | } | |
5ba3f43e A |
542 | |
543 | #else | |
544 | ||
cb323159 A |
545 | void(*const PE_arm_debug_panic_hook)(const char *str) = NULL; |
546 | ||
547 | void | |
548 | PE_init_cpu(void) | |
549 | { | |
550 | } | |
5ba3f43e A |
551 | |
552 | #endif // DEVELOPMENT || DEBUG | |
553 | ||
cb323159 A |
554 | void |
555 | PE_panic_hook(const char *str __unused) | |
556 | { | |
557 | if (PE_arm_debug_panic_hook != NULL) { | |
558 | PE_arm_debug_panic_hook(str); | |
559 | } | |
560 | } | |
561 | ||
5ba3f43e A |
562 | void |
563 | pe_arm_init_debug(void *args) | |
564 | { | |
0a7de745 A |
565 | DTEntry entryP; |
566 | uintptr_t *reg_prop; | |
567 | uint32_t prop_size; | |
5ba3f43e | 568 | |
0a7de745 | 569 | if (gSocPhys == 0) { |
5ba3f43e | 570 | kprintf("pe_arm_init_debug: failed to initialize gSocPhys == 0\n"); |
0a7de745 | 571 | return; |
5ba3f43e | 572 | } |
0a7de745 A |
573 | |
574 | if (DTFindEntry("device_type", "cpu-debug-interface", &entryP) == kSuccess) { | |
5ba3f43e A |
575 | if (args != NULL) { |
576 | if (DTGetProperty(entryP, "reg", (void **)®_prop, &prop_size) == kSuccess) { | |
577 | ml_init_arm_debug_interface(args, ml_io_map(gSocPhys + *reg_prop, *(reg_prop + 1))); | |
578 | } | |
579 | #if DEVELOPMENT || DEBUG | |
580 | // When args != NULL, this means we're being called from arm_init on the boot CPU. | |
581 | // This controls one-time initialization of the Panic Trace infrastructure | |
582 | ||
cb323159 | 583 | simple_lock_init(&panic_hook_lock, 0); //assuming single threaded mode |
0a7de745 | 584 | |
5ba3f43e A |
585 | // Panic_halt is deprecated. Please use panic_trace istead. |
586 | unsigned int temp_bootarg_panic_trace; | |
587 | if (PE_parse_boot_argn("panic_trace", &temp_bootarg_panic_trace, sizeof(temp_bootarg_panic_trace)) || | |
588 | PE_parse_boot_argn("panic_halt", &temp_bootarg_panic_trace, sizeof(temp_bootarg_panic_trace))) { | |
5ba3f43e A |
589 | kprintf("pe_arm_init_debug: panic_trace=%d\n", temp_bootarg_panic_trace); |
590 | ||
0a7de745 | 591 | // Prepare debug command buffers. |
5ba3f43e A |
592 | pe_init_debug_command(entryP, &cpu_halt, "cpu_halt"); |
593 | pe_init_debug_command(entryP, &enable_trace, "enable_trace"); | |
594 | pe_init_debug_command(entryP, &enable_alt_trace, "enable_alt_trace"); | |
595 | pe_init_debug_command(entryP, &trace_halt, "trace_halt"); | |
0a7de745 | 596 | |
5ba3f43e A |
597 | // now that init's are done, enable the panic halt capture (allows pe_init_debug_command to panic normally if necessary) |
598 | bootarg_panic_trace = temp_bootarg_panic_trace; | |
599 | ||
600 | // start tracing now if enabled | |
601 | PE_arm_debug_enable_trace(); | |
602 | } | |
cb323159 A |
603 | unsigned int temp_bootarg_stop_clocks; |
604 | if (PE_parse_boot_argn("stop_clocks", &temp_bootarg_stop_clocks, sizeof(temp_bootarg_stop_clocks))) { | |
605 | pe_init_debug_command(entryP, &enable_stop_clocks, "enable_stop_clocks"); | |
606 | pe_init_debug_command(entryP, &stop_clocks, "stop_clocks"); | |
607 | bootarg_stop_clocks = temp_bootarg_stop_clocks; | |
608 | } | |
5ba3f43e A |
609 | #endif |
610 | } | |
611 | } else { | |
612 | kprintf("pe_arm_init_debug: failed to find cpu-debug-interface\n"); | |
613 | } | |
614 | } | |
615 | ||
616 | static uint32_t | |
617 | pe_arm_map_interrupt_controller(void) | |
618 | { | |
0a7de745 A |
619 | DTEntry entryP; |
620 | uintptr_t *reg_prop; | |
621 | uint32_t prop_size; | |
622 | vm_offset_t soc_phys = 0; | |
5ba3f43e A |
623 | |
624 | gSocPhys = pe_arm_get_soc_base_phys(); | |
625 | ||
626 | soc_phys = gSocPhys; | |
627 | kprintf("pe_arm_map_interrupt_controller: soc_phys: 0x%lx\n", (unsigned long)soc_phys); | |
0a7de745 | 628 | if (soc_phys == 0) { |
5ba3f43e | 629 | return 0; |
0a7de745 | 630 | } |
5ba3f43e A |
631 | |
632 | if (DTFindEntry("interrupt-controller", "master", &entryP) == kSuccess) { | |
633 | kprintf("pe_arm_map_interrupt_controller: found interrupt-controller\n"); | |
634 | DTGetProperty(entryP, "reg", (void **)®_prop, &prop_size); | |
635 | gPicBase = ml_io_map(soc_phys + *reg_prop, *(reg_prop + 1)); | |
636 | kprintf("pe_arm_map_interrupt_controller: gPicBase: 0x%lx\n", (unsigned long)gPicBase); | |
637 | } | |
638 | if (gPicBase == 0) { | |
639 | kprintf("pe_arm_map_interrupt_controller: failed to find the interrupt-controller.\n"); | |
640 | return 0; | |
641 | } | |
642 | ||
643 | if (DTFindEntry("device_type", "timer", &entryP) == kSuccess) { | |
644 | kprintf("pe_arm_map_interrupt_controller: found timer\n"); | |
645 | DTGetProperty(entryP, "reg", (void **)®_prop, &prop_size); | |
646 | gTimerBase = ml_io_map(soc_phys + *reg_prop, *(reg_prop + 1)); | |
647 | kprintf("pe_arm_map_interrupt_controller: gTimerBase: 0x%lx\n", (unsigned long)gTimerBase); | |
648 | } | |
649 | if (gTimerBase == 0) { | |
650 | kprintf("pe_arm_map_interrupt_controller: failed to find the timer.\n"); | |
651 | return 0; | |
652 | } | |
653 | ||
654 | return 1; | |
655 | } | |
656 | ||
657 | uint32_t | |
658 | pe_arm_init_interrupts(void *args) | |
659 | { | |
660 | kprintf("pe_arm_init_interrupts: args: %p\n", args); | |
661 | ||
662 | /* Set up mappings for interrupt controller and possibly timers (if they haven't been set up already) */ | |
663 | if (args != NULL) { | |
664 | if (!pe_arm_map_interrupt_controller()) { | |
665 | return 0; | |
666 | } | |
667 | } | |
668 | ||
669 | return pe_arm_init_timer(args); | |
670 | } | |
671 | ||
0a7de745 | 672 | static uint32_t |
5ba3f43e A |
673 | pe_arm_init_timer(void *args) |
674 | { | |
0a7de745 A |
675 | vm_offset_t pic_base = 0; |
676 | vm_offset_t timer_base = 0; | |
677 | vm_offset_t soc_phys; | |
678 | vm_offset_t eoi_addr = 0; | |
679 | uint32_t eoi_value = 0; | |
5ba3f43e | 680 | struct tbd_ops generic_funcs = {&fleh_fiq_generic, NULL, NULL}; |
0a7de745 | 681 | tbd_ops_t tbd_funcs = &generic_funcs; |
5ba3f43e A |
682 | |
683 | /* The SoC headers expect to use pic_base, timer_base, etc... */ | |
684 | pic_base = gPicBase; | |
685 | timer_base = gTimerBase; | |
686 | soc_phys = gSocPhys; | |
687 | ||
5ba3f43e A |
688 | #if defined(ARM_BOARD_CLASS_T7000) |
689 | if (!strcmp(gPESoCDeviceType, "t7000-io") || | |
0a7de745 | 690 | !strcmp(gPESoCDeviceType, "t7001-io")) { |
5ba3f43e A |
691 | tbd_funcs = &t7000_funcs; |
692 | } else | |
693 | #endif | |
694 | #if defined(ARM_BOARD_CLASS_S7002) | |
695 | if (!strcmp(gPESoCDeviceType, "s7002-io")) { | |
5ba3f43e A |
696 | #ifdef ARM_BOARD_WFE_TIMEOUT_NS |
697 | // Enable the WFE Timer | |
0a7de745 | 698 | rPMGR_EVENT_TMR_PERIOD = ((uint64_t)(ARM_BOARD_WFE_TIMEOUT_NS) *gPEClockFrequencyInfo.timebase_frequency_hz) / NSEC_PER_SEC; |
5ba3f43e A |
699 | rPMGR_EVENT_TMR = rPMGR_EVENT_TMR_PERIOD; |
700 | rPMGR_EVENT_TMR_CTL = PMGR_EVENT_TMR_CTL_EN; | |
701 | #endif /* ARM_BOARD_WFE_TIMEOUT_NS */ | |
702 | ||
703 | rPMGR_INTERVAL_TMR = 0x7FFFFFFF; | |
704 | rPMGR_INTERVAL_TMR_CTL = PMGR_INTERVAL_TMR_CTL_EN | PMGR_INTERVAL_TMR_CTL_CLR_INT; | |
705 | ||
706 | eoi_addr = timer_base; | |
707 | eoi_value = PMGR_INTERVAL_TMR_CTL_EN | PMGR_INTERVAL_TMR_CTL_CLR_INT; | |
708 | tbd_funcs = &s7002_funcs; | |
709 | } else | |
710 | #endif | |
711 | #if defined(ARM_BOARD_CLASS_S8000) | |
712 | if (!strcmp(gPESoCDeviceType, "s8000-io") || | |
713 | !strcmp(gPESoCDeviceType, "s8001-io")) { | |
714 | tbd_funcs = &s8000_funcs; | |
715 | } else | |
716 | #endif | |
717 | #if defined(ARM_BOARD_CLASS_T8002) | |
718 | if (!strcmp(gPESoCDeviceType, "t8002-io") || | |
719 | !strcmp(gPESoCDeviceType, "t8004-io")) { | |
5ba3f43e A |
720 | /* Enable the Decrementer */ |
721 | aic_write32(kAICTmrCnt, 0x7FFFFFFF); | |
722 | aic_write32(kAICTmrCfg, kAICTmrCfgEn); | |
723 | aic_write32(kAICTmrIntStat, kAICTmrIntStatPct); | |
724 | #ifdef ARM_BOARD_WFE_TIMEOUT_NS | |
725 | // Enable the WFE Timer | |
0a7de745 | 726 | rPMGR_EVENT_TMR_PERIOD = ((uint64_t)(ARM_BOARD_WFE_TIMEOUT_NS) *gPEClockFrequencyInfo.timebase_frequency_hz) / NSEC_PER_SEC; |
5ba3f43e A |
727 | rPMGR_EVENT_TMR = rPMGR_EVENT_TMR_PERIOD; |
728 | rPMGR_EVENT_TMR_CTL = PMGR_EVENT_TMR_CTL_EN; | |
729 | #endif /* ARM_BOARD_WFE_TIMEOUT_NS */ | |
730 | ||
731 | eoi_addr = pic_base; | |
732 | eoi_value = kAICTmrIntStatPct; | |
733 | tbd_funcs = &t8002_funcs; | |
734 | } else | |
735 | #endif | |
736 | #if defined(ARM_BOARD_CLASS_T8010) | |
737 | if (!strcmp(gPESoCDeviceType, "t8010-io")) { | |
738 | tbd_funcs = &t8010_funcs; | |
739 | } else | |
740 | #endif | |
741 | #if defined(ARM_BOARD_CLASS_T8011) | |
742 | if (!strcmp(gPESoCDeviceType, "t8011-io")) { | |
743 | tbd_funcs = &t8011_funcs; | |
744 | } else | |
d9a64523 A |
745 | #endif |
746 | #if defined(ARM_BOARD_CLASS_T8015) | |
747 | if (!strcmp(gPESoCDeviceType, "t8015-io")) { | |
748 | tbd_funcs = &t8015_funcs; | |
749 | } else | |
750 | #endif | |
c6bf4f31 A |
751 | #if defined(ARM_BOARD_CLASS_T8020) |
752 | if (!strcmp(gPESoCDeviceType, "t8020-io")) { | |
753 | tbd_funcs = &t8020_funcs; | |
754 | } else | |
755 | #endif | |
756 | #if defined(ARM_BOARD_CLASS_T8006) | |
757 | if (!strcmp(gPESoCDeviceType, "t8006-io")) { | |
758 | tbd_funcs = &t8006_funcs; | |
759 | } else | |
760 | #endif | |
761 | #if defined(ARM_BOARD_CLASS_T8027) | |
762 | if (!strcmp(gPESoCDeviceType, "t8027-io")) { | |
763 | tbd_funcs = &t8027_funcs; | |
764 | } else | |
765 | #endif | |
766 | #if defined(ARM_BOARD_CLASS_T8028) | |
767 | if (!strcmp(gPESoCDeviceType, "t8028-io")) { | |
768 | tbd_funcs = &t8028_funcs; | |
769 | } else | |
770 | #endif | |
771 | #if defined(ARM_BOARD_CLASS_T8030) | |
772 | if (!strcmp(gPESoCDeviceType, "t8030-io")) { | |
773 | tbd_funcs = &t8030_funcs; | |
774 | } else | |
775 | #endif | |
d9a64523 A |
776 | #if defined(ARM_BOARD_CLASS_BCM2837) |
777 | if (!strcmp(gPESoCDeviceType, "bcm2837-io")) { | |
778 | tbd_funcs = &bcm2837_funcs; | |
779 | } else | |
5ba3f43e | 780 | #endif |
0a7de745 | 781 | return 0; |
5ba3f43e | 782 | |
0a7de745 | 783 | if (args != NULL) { |
5ba3f43e | 784 | ml_init_timebase(args, tbd_funcs, eoi_addr, eoi_value); |
0a7de745 | 785 | } |
5ba3f43e A |
786 | |
787 | return 1; | |
788 | } |