1/*
2 * Copyright (c) 2007-2021 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#include <pexpert/arm64/board_config.h>
10
11#include <machine/machine_routines.h>
12
13#include <kern/clock.h>
14#include <kern/locks.h>
15
16/* Local declarations */
17void pe_identify_machine(boot_args * bootArgs);
18
19/* External declarations */
20extern void clean_mmu_dcache(void);
21
22static char *gPESoCDeviceType;
23static char gPESoCDeviceTypeBuffer[SOC_DEVICE_TYPE_BUFFER_SIZE];
24static vm_offset_t gPESoCBasePhys;
25
26static uint32_t pe_arm_init_timer(void *args);
27
28
29/*
30 * pe_identify_machine:
31 *
32 * Sets up platform parameters. Returns: nothing
33 */
34void
35pe_identify_machine(boot_args * bootArgs)
36{
37 OpaqueDTEntryIterator iter;
38 DTEntry cpus, cpu;
39 void const *value;
40 unsigned int size;
41 int err;
42
43 (void)bootArgs;
44
45 if (pe_arm_get_soc_base_phys() == 0) {
46 return;
47 }
48
49 /* Clear the gPEClockFrequencyInfo struct */
50 bzero(s: (void *)&gPEClockFrequencyInfo, n: sizeof(clock_frequency_info_t));
51
52 /* Start with default values. */
53 gPEClockFrequencyInfo.timebase_frequency_hz = 24000000;
54 gPEClockFrequencyInfo.bus_clock_rate_hz = 100000000;
55 gPEClockFrequencyInfo.cpu_clock_rate_hz = 400000000;
56
57 err = SecureDTLookupEntry(NULL, pathName: "/cpus", foundEntry: &cpus);
58 assert(err == kSuccess);
59
60 err = SecureDTInitEntryIterator(startEntry: cpus, iter: &iter);
61 assert(err == kSuccess);
62
63 while (kSuccess == SecureDTIterateEntries(iterator: &iter, nextEntry: &cpu)) {
64 if ((kSuccess != SecureDTGetProperty(entry: cpu, propertyName: "state", propertyValue: &value, propertySize: &size)) ||
65 (strncmp(s1: (char const *)value, s2: "running", n: size) != 0)) {
66 continue;
67 }
68
69 /* Find the time base frequency first. */
70 if (SecureDTGetProperty(entry: cpu, propertyName: "timebase-frequency", propertyValue: &value, propertySize: &size) == kSuccess) {
71 /*
72 * timebase_frequency_hz is only 32 bits, and
73 * the device tree should never provide 64
74 * bits so this if should never be taken.
75 */
76 if (size == 8) {
77 gPEClockFrequencyInfo.timebase_frequency_hz = *(uint64_t const *)value;
78 } else {
79 gPEClockFrequencyInfo.timebase_frequency_hz = *(uint32_t const *)value;
80 }
81 }
82 gPEClockFrequencyInfo.dec_clock_rate_hz = gPEClockFrequencyInfo.timebase_frequency_hz;
83
84 /* Find the bus frequency next. */
85 if (SecureDTGetProperty(entry: cpu, propertyName: "bus-frequency", propertyValue: &value, propertySize: &size) == kSuccess) {
86 if (size == 8) {
87 gPEClockFrequencyInfo.bus_frequency_hz = *(uint64_t const *)value;
88 } else {
89 gPEClockFrequencyInfo.bus_frequency_hz = *(uint32_t const *)value;
90 }
91 }
92 gPEClockFrequencyInfo.bus_frequency_min_hz = gPEClockFrequencyInfo.bus_frequency_hz;
93 gPEClockFrequencyInfo.bus_frequency_max_hz = gPEClockFrequencyInfo.bus_frequency_hz;
94
95 if (gPEClockFrequencyInfo.bus_frequency_hz < 0x100000000ULL) {
96 gPEClockFrequencyInfo.bus_clock_rate_hz = gPEClockFrequencyInfo.bus_frequency_hz;
97 } else {
98 gPEClockFrequencyInfo.bus_clock_rate_hz = 0xFFFFFFFF;
99 }
100
101 /* Find the memory frequency next. */
102 if (SecureDTGetProperty(entry: cpu, propertyName: "memory-frequency", propertyValue: &value, propertySize: &size) == kSuccess) {
103 if (size == 8) {
104 gPEClockFrequencyInfo.mem_frequency_hz = *(uint64_t const *)value;
105 } else {
106 gPEClockFrequencyInfo.mem_frequency_hz = *(uint32_t const *)value;
107 }
108 }
109 gPEClockFrequencyInfo.mem_frequency_min_hz = gPEClockFrequencyInfo.mem_frequency_hz;
110 gPEClockFrequencyInfo.mem_frequency_max_hz = gPEClockFrequencyInfo.mem_frequency_hz;
111
112 /* Find the peripheral frequency next. */
113 if (SecureDTGetProperty(entry: cpu, propertyName: "peripheral-frequency", propertyValue: &value, propertySize: &size) == kSuccess) {
114 if (size == 8) {
115 gPEClockFrequencyInfo.prf_frequency_hz = *(uint64_t const *)value;
116 } else {
117 gPEClockFrequencyInfo.prf_frequency_hz = *(uint32_t const *)value;
118 }
119 }
120 gPEClockFrequencyInfo.prf_frequency_min_hz = gPEClockFrequencyInfo.prf_frequency_hz;
121 gPEClockFrequencyInfo.prf_frequency_max_hz = gPEClockFrequencyInfo.prf_frequency_hz;
122
123 /* Find the fixed frequency next. */
124 if (SecureDTGetProperty(entry: cpu, propertyName: "fixed-frequency", propertyValue: &value, propertySize: &size) == kSuccess) {
125 if (size == 8) {
126 gPEClockFrequencyInfo.fix_frequency_hz = *(uint64_t const *)value;
127 } else {
128 gPEClockFrequencyInfo.fix_frequency_hz = *(uint32_t const *)value;
129 }
130 }
131 /* Find the cpu frequency last. */
132 if (SecureDTGetProperty(entry: cpu, propertyName: "clock-frequency", propertyValue: &value, propertySize: &size) == kSuccess) {
133 if (size == 8) {
134 gPEClockFrequencyInfo.cpu_frequency_hz = *(uint64_t const *)value;
135 } else {
136 gPEClockFrequencyInfo.cpu_frequency_hz = *(uint32_t const *)value;
137 }
138 }
139 gPEClockFrequencyInfo.cpu_frequency_min_hz = gPEClockFrequencyInfo.cpu_frequency_hz;
140 gPEClockFrequencyInfo.cpu_frequency_max_hz = gPEClockFrequencyInfo.cpu_frequency_hz;
141
142 if (gPEClockFrequencyInfo.cpu_frequency_hz < 0x100000000ULL) {
143 gPEClockFrequencyInfo.cpu_clock_rate_hz = gPEClockFrequencyInfo.cpu_frequency_hz;
144 } else {
145 gPEClockFrequencyInfo.cpu_clock_rate_hz = 0xFFFFFFFF;
146 }
147 }
148
149 /* Set the num / den pairs form the hz values. */
150 gPEClockFrequencyInfo.bus_clock_rate_num = gPEClockFrequencyInfo.bus_clock_rate_hz;
151 gPEClockFrequencyInfo.bus_clock_rate_den = 1;
152
153 gPEClockFrequencyInfo.bus_to_cpu_rate_num =
154 (2 * gPEClockFrequencyInfo.cpu_clock_rate_hz) / gPEClockFrequencyInfo.bus_clock_rate_hz;
155 gPEClockFrequencyInfo.bus_to_cpu_rate_den = 2;
156
157 gPEClockFrequencyInfo.bus_to_dec_rate_num = 1;
158 gPEClockFrequencyInfo.bus_to_dec_rate_den =
159 gPEClockFrequencyInfo.bus_clock_rate_hz / gPEClockFrequencyInfo.dec_clock_rate_hz;
160}
161
162vm_offset_t
163pe_arm_get_soc_base_phys(void)
164{
165 DTEntry entryP;
166 uintptr_t const *ranges_prop;
167 uint32_t prop_size;
168 char const *tmpStr;
169
170 if (SecureDTFindEntry(propName: "name", propValue: "arm-io", entryH: &entryP) == kSuccess) {
171 if (gPESoCDeviceType == 0) {
172 SecureDTGetProperty(entry: entryP, propertyName: "device_type", propertyValue: (void const **)&tmpStr, propertySize: &prop_size);
173 strlcpy(dst: gPESoCDeviceTypeBuffer, src: tmpStr, SOC_DEVICE_TYPE_BUFFER_SIZE);
174 gPESoCDeviceType = gPESoCDeviceTypeBuffer;
175
176 SecureDTGetProperty(entry: entryP, propertyName: "ranges", propertyValue: (void const **)&ranges_prop, propertySize: &prop_size);
177 gPESoCBasePhys = *(ranges_prop + 1);
178 }
179 return gPESoCBasePhys;
180 }
181 return 0;
182}
183
184extern void fleh_fiq_generic(void);
185
186vm_offset_t gPicBase;
187vm_offset_t gTimerBase;
188vm_offset_t gSocPhys;
189
190static uint32_t
191pe_arm_map_interrupt_controller(void)
192{
193 DTEntry entryP;
194 uintptr_t const *reg_prop;
195 uint32_t prop_size;
196 vm_offset_t soc_phys = 0;
197
198 gSocPhys = pe_arm_get_soc_base_phys();
199
200 soc_phys = gSocPhys;
201 kprintf(fmt: "pe_arm_map_interrupt_controller: soc_phys: 0x%lx\n", (unsigned long)soc_phys);
202 if (soc_phys == 0) {
203 return 0;
204 }
205
206 if (SecureDTFindEntry(propName: "interrupt-controller", propValue: "master", entryH: &entryP) == kSuccess) {
207 kprintf(fmt: "pe_arm_map_interrupt_controller: found interrupt-controller\n");
208 SecureDTGetProperty(entry: entryP, propertyName: "reg", propertyValue: (void const **)&reg_prop, propertySize: &prop_size);
209 gPicBase = ml_io_map(phys_addr: soc_phys + *reg_prop, size: *(reg_prop + 1));
210 kprintf(fmt: "pe_arm_map_interrupt_controller: gPicBase: 0x%lx\n", (unsigned long)gPicBase);
211 }
212 if (gPicBase == 0) {
213 kprintf(fmt: "pe_arm_map_interrupt_controller: failed to find the interrupt-controller.\n");
214 return 0;
215 }
216
217 if (SecureDTFindEntry(propName: "device_type", propValue: "timer", entryH: &entryP) == kSuccess) {
218 kprintf(fmt: "pe_arm_map_interrupt_controller: found timer\n");
219 SecureDTGetProperty(entry: entryP, propertyName: "reg", propertyValue: (void const **)&reg_prop, propertySize: &prop_size);
220 gTimerBase = ml_io_map(phys_addr: soc_phys + *reg_prop, size: *(reg_prop + 1));
221 kprintf(fmt: "pe_arm_map_interrupt_controller: gTimerBase: 0x%lx\n", (unsigned long)gTimerBase);
222 }
223 if (gTimerBase == 0) {
224 kprintf(fmt: "pe_arm_map_interrupt_controller: failed to find the timer.\n");
225 return 0;
226 }
227
228 return 1;
229}
230
231uint32_t
232pe_arm_init_interrupts(void *args)
233{
234 kprintf(fmt: "pe_arm_init_interrupts: args: %p\n", args);
235
236 /* Set up mappings for interrupt controller and possibly timers (if they haven't been set up already) */
237 if (args != NULL) {
238 if (!pe_arm_map_interrupt_controller()) {
239 return 0;
240 }
241 }
242
243 return pe_arm_init_timer(args);
244}
245
246static uint32_t
247pe_arm_init_timer(void *args)
248{
249 vm_offset_t pic_base = 0;
250 vm_offset_t timer_base = 0;
251 vm_offset_t soc_phys;
252 vm_offset_t eoi_addr = 0;
253 uint32_t eoi_value = 0;
254 struct tbd_ops generic_funcs = {&fleh_fiq_generic, NULL, NULL};
255 struct tbd_ops empty_funcs __unused = {NULL, NULL, NULL};
256 tbd_ops_t tbd_funcs = &generic_funcs;
257
258 /* The SoC headers expect to use pic_base, timer_base, etc... */
259 pic_base = gPicBase;
260 timer_base = gTimerBase;
261 soc_phys = gSocPhys;
262
263#if defined(__arm64__)
264 tbd_funcs = &empty_funcs;
265#else
266 return 0;
267#endif
268
269 if (args != NULL) {
270 ml_init_timebase(args, tbd_funcs, int_address: eoi_addr, int_value: eoi_value);
271 }
272
273 return 1;
274}
275