]>
Commit | Line | Data |
---|---|---|
5aff1c07 PM |
1 | /* |
2 | * ARM V2M MPS2 board emulation, trustzone aware FPGA images | |
3 | * | |
4 | * Copyright (c) 2017 Linaro Limited | |
5 | * Written by Peter Maydell | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 or | |
9 | * (at your option) any later version. | |
10 | */ | |
11 | ||
12 | /* The MPS2 and MPS2+ dev boards are FPGA based (the 2+ has a bigger | |
13 | * FPGA but is otherwise the same as the 2). Since the CPU itself | |
14 | * and most of the devices are in the FPGA, the details of the board | |
15 | * as seen by the guest depend significantly on the FPGA image. | |
16 | * This source file covers the following FPGA images, for TrustZone cores: | |
17 | * "mps2-an505" -- Cortex-M33 as documented in ARM Application Note AN505 | |
23f92423 | 18 | * "mps2-an521" -- Dual Cortex-M33 as documented in Application Note AN521 |
25ff112a | 19 | * "mps2-an524" -- Dual Cortex-M33 as documented in Application Note AN524 |
eb09d533 | 20 | * "mps2-an547" -- Single Cortex-M55 as documented in Application Note AN547 |
5aff1c07 PM |
21 | * |
22 | * Links to the TRM for the board itself and to the various Application | |
23 | * Notes which document the FPGA images can be found here: | |
24 | * https://developer.arm.com/products/system-design/development-boards/fpga-prototyping-boards/mps2 | |
25 | * | |
26 | * Board TRM: | |
50b52b18 | 27 | * https://developer.arm.com/documentation/100112/latest/ |
5aff1c07 | 28 | * Application Note AN505: |
50b52b18 | 29 | * https://developer.arm.com/documentation/dai0505/latest/ |
23f92423 | 30 | * Application Note AN521: |
50b52b18 | 31 | * https://developer.arm.com/documentation/dai0521/latest/ |
25ff112a PM |
32 | * Application Note AN524: |
33 | * https://developer.arm.com/documentation/dai0524/latest/ | |
eb09d533 | 34 | * Application Note AN547: |
e212fb05 | 35 | * https://developer.arm.com/documentation/dai0547/latest/ |
5aff1c07 PM |
36 | * |
37 | * The AN505 defers to the Cortex-M33 processor ARMv8M IoT Kit FVP User Guide | |
38 | * (ARM ECM0601256) for the details of some of the device layout: | |
50b52b18 | 39 | * https://developer.arm.com/documentation/ecm0601256/latest |
25ff112a | 40 | * Similarly, the AN521 and AN524 use the SSE-200, and the SSE-200 TRM defines |
23f92423 | 41 | * most of the device layout: |
50b52b18 | 42 | * https://developer.arm.com/documentation/101104/latest/ |
eb09d533 PM |
43 | * and the AN547 uses the SSE-300, whose layout is in the SSE-300 TRM: |
44 | * https://developer.arm.com/documentation/101773/latest/ | |
5aff1c07 PM |
45 | */ |
46 | ||
47 | #include "qemu/osdep.h" | |
eba59997 | 48 | #include "qemu/units.h" |
70a2cb8e | 49 | #include "qemu/cutils.h" |
5aff1c07 | 50 | #include "qapi/error.h" |
31805a0a | 51 | #include "qapi/qmp/qlist.h" |
5aff1c07 | 52 | #include "qemu/error-report.h" |
12ec8bd5 | 53 | #include "hw/arm/boot.h" |
5aff1c07 PM |
54 | #include "hw/arm/armv7m.h" |
55 | #include "hw/or-irq.h" | |
56 | #include "hw/boards.h" | |
57 | #include "exec/address-spaces.h" | |
58 | #include "sysemu/sysemu.h" | |
f1dfab0d | 59 | #include "sysemu/reset.h" |
5aff1c07 PM |
60 | #include "hw/misc/unimp.h" |
61 | #include "hw/char/cmsdk-apb-uart.h" | |
62 | #include "hw/timer/cmsdk-apb-timer.h" | |
63 | #include "hw/misc/mps2-scc.h" | |
64 | #include "hw/misc/mps2-fpgaio.h" | |
665670aa | 65 | #include "hw/misc/tz-mpc.h" |
28e56f05 | 66 | #include "hw/misc/tz-msc.h" |
6eee5d24 | 67 | #include "hw/arm/armsse.h" |
28e56f05 | 68 | #include "hw/dma/pl080.h" |
41745d20 | 69 | #include "hw/rtc/pl031.h" |
0d49759b | 70 | #include "hw/ssi/pl022.h" |
2e34818f | 71 | #include "hw/i2c/arm_sbcon_i2c.h" |
94630665 | 72 | #include "hw/net/lan9118.h" |
5aff1c07 PM |
73 | #include "net/net.h" |
74 | #include "hw/core/split-irq.h" | |
dee1515b | 75 | #include "hw/qdev-clock.h" |
db1015e9 | 76 | #include "qom/object.h" |
f1dfab0d | 77 | #include "hw/irq.h" |
5aff1c07 | 78 | |
eb09d533 PM |
79 | #define MPS2TZ_NUMIRQ_MAX 96 |
80 | #define MPS2TZ_RAM_MAX 5 | |
4a30dc1c | 81 | |
5aff1c07 PM |
82 | typedef enum MPS2TZFPGAType { |
83 | FPGA_AN505, | |
4a30dc1c | 84 | FPGA_AN521, |
25ff112a | 85 | FPGA_AN524, |
eb09d533 | 86 | FPGA_AN547, |
5aff1c07 PM |
87 | } MPS2TZFPGAType; |
88 | ||
4fec32db PM |
89 | /* |
90 | * Define the layout of RAM in a board, including which parts are | |
91 | * behind which MPCs. | |
92 | * mrindex specifies the index into mms->ram[] to use for the backing RAM; | |
93 | * -1 means "use the system RAM". | |
94 | */ | |
95 | typedef struct RAMInfo { | |
96 | const char *name; | |
97 | uint32_t base; | |
98 | uint32_t size; | |
99 | int mpc; /* MPC number, -1 for "not behind an MPC" */ | |
100 | int mrindex; | |
101 | int flags; | |
102 | } RAMInfo; | |
103 | ||
104 | /* | |
105 | * Flag values: | |
106 | * IS_ALIAS: this RAM area is an alias to the upstream end of the | |
107 | * MPC specified by its .mpc value | |
b89918fc | 108 | * IS_ROM: this RAM area is read-only |
4fec32db PM |
109 | */ |
110 | #define IS_ALIAS 1 | |
b89918fc | 111 | #define IS_ROM 2 |
4fec32db | 112 | |
db1015e9 | 113 | struct MPS2TZMachineClass { |
5aff1c07 PM |
114 | MachineClass parent; |
115 | MPS2TZFPGAType fpga_type; | |
116 | uint32_t scc_id; | |
a3e24690 | 117 | uint32_t sysclk_frq; /* Main SYSCLK frequency in Hz */ |
ad28ca7e | 118 | uint32_t apb_periph_frq; /* APB peripheral frequency in Hz */ |
f7c71b21 PM |
119 | uint32_t len_oscclk; |
120 | const uint32_t *oscclk; | |
de77e8f4 PM |
121 | uint32_t fpgaio_num_leds; /* Number of LEDs in FPGAIO LED0 register */ |
122 | bool fpgaio_has_switches; /* Does FPGAIO have SWITCH register? */ | |
39901aea | 123 | bool fpgaio_has_dbgctrl; /* Does FPGAIO have DBGCTRL register? */ |
11e1d412 | 124 | int numirq; /* Number of external interrupts */ |
8b4b5c23 | 125 | int uart_overflow_irq; /* number of the combined UART overflow IRQ */ |
9fe1ea11 | 126 | uint32_t init_svtor; /* init-svtor setting for SSE */ |
902b28ae | 127 | uint32_t sram_addr_width; /* SRAM_ADDR_WIDTH setting for SSE */ |
e73b8bb8 PM |
128 | uint32_t cpu0_mpu_ns; /* CPU0_MPU_NS setting for SSE */ |
129 | uint32_t cpu0_mpu_s; /* CPU0_MPU_S setting for SSE */ | |
130 | uint32_t cpu1_mpu_ns; /* CPU1_MPU_NS setting for SSE */ | |
131 | uint32_t cpu1_mpu_s; /* CPU1_MPU_S setting for SSE */ | |
4fec32db | 132 | const RAMInfo *raminfo; |
23f92423 | 133 | const char *armsse_type; |
2f12dca0 | 134 | uint32_t boot_ram_size; /* size of ram at address 0; 0 == find in raminfo */ |
db1015e9 | 135 | }; |
5aff1c07 | 136 | |
db1015e9 | 137 | struct MPS2TZMachineState { |
5aff1c07 PM |
138 | MachineState parent; |
139 | ||
93dbd103 | 140 | ARMSSE iotkit; |
4fec32db | 141 | MemoryRegion ram[MPS2TZ_RAM_MAX]; |
a9597753 PM |
142 | MemoryRegion eth_usb_container; |
143 | ||
5aff1c07 PM |
144 | MPS2SCC scc; |
145 | MPS2FPGAIO fpgaio; | |
146 | TZPPC ppc[5]; | |
4fec32db | 147 | TZMPC mpc[3]; |
0d49759b | 148 | PL022State spi[5]; |
25ff112a | 149 | ArmSbconI2CState i2c[5]; |
5aff1c07 | 150 | UnimplementedDeviceState i2s_audio; |
519655e6 | 151 | UnimplementedDeviceState gpio[4]; |
5aff1c07 | 152 | UnimplementedDeviceState gfx; |
25ff112a | 153 | UnimplementedDeviceState cldc; |
a9597753 | 154 | UnimplementedDeviceState usb; |
41745d20 | 155 | PL031State rtc; |
28e56f05 PM |
156 | PL080State dma[4]; |
157 | TZMSC msc[4]; | |
25ff112a | 158 | CMSDKAPBUART uart[6]; |
5aff1c07 | 159 | SplitIRQ sec_resp_splitter; |
e844f0c5 | 160 | OrIRQState uart_irq_orgate; |
519655e6 | 161 | DeviceState *lan9118; |
11e1d412 | 162 | SplitIRQ cpu_irq_splitter[MPS2TZ_NUMIRQ_MAX]; |
dee1515b PM |
163 | Clock *sysclk; |
164 | Clock *s32kclk; | |
f1dfab0d PM |
165 | |
166 | bool remap; | |
167 | qemu_irq remap_irq; | |
db1015e9 | 168 | }; |
5aff1c07 PM |
169 | |
170 | #define TYPE_MPS2TZ_MACHINE "mps2tz" | |
171 | #define TYPE_MPS2TZ_AN505_MACHINE MACHINE_TYPE_NAME("mps2-an505") | |
23f92423 | 172 | #define TYPE_MPS2TZ_AN521_MACHINE MACHINE_TYPE_NAME("mps2-an521") |
25ff112a | 173 | #define TYPE_MPS3TZ_AN524_MACHINE MACHINE_TYPE_NAME("mps3-an524") |
eb09d533 | 174 | #define TYPE_MPS3TZ_AN547_MACHINE MACHINE_TYPE_NAME("mps3-an547") |
5aff1c07 | 175 | |
a489d195 | 176 | OBJECT_DECLARE_TYPE(MPS2TZMachineState, MPS2TZMachineClass, MPS2TZ_MACHINE) |
5aff1c07 | 177 | |
dee1515b PM |
178 | /* Slow 32Khz S32KCLK frequency in Hz */ |
179 | #define S32KCLK_FRQ (32 * 1000) | |
5aff1c07 | 180 | |
25ff112a PM |
181 | /* |
182 | * The MPS3 DDR is 2GiB, but on a 32-bit host QEMU doesn't permit | |
183 | * emulation of that much guest RAM, so artificially make it smaller. | |
184 | */ | |
185 | #if HOST_LONG_BITS == 32 | |
186 | #define MPS3_DDR_SIZE (1 * GiB) | |
187 | #else | |
188 | #define MPS3_DDR_SIZE (2 * GiB) | |
189 | #endif | |
190 | ||
e73b8bb8 PM |
191 | /* For cpu{0,1}_mpu_{ns,s}, means "leave at SSE's default value" */ |
192 | #define MPU_REGION_DEFAULT UINT32_MAX | |
193 | ||
f7c71b21 PM |
194 | static const uint32_t an505_oscclk[] = { |
195 | 40000000, | |
196 | 24580000, | |
197 | 25000000, | |
198 | }; | |
199 | ||
25ff112a PM |
200 | static const uint32_t an524_oscclk[] = { |
201 | 24000000, | |
202 | 32000000, | |
203 | 50000000, | |
204 | 50000000, | |
205 | 24576000, | |
206 | 23750000, | |
207 | }; | |
208 | ||
4fec32db PM |
209 | static const RAMInfo an505_raminfo[] = { { |
210 | .name = "ssram-0", | |
211 | .base = 0x00000000, | |
212 | .size = 0x00400000, | |
213 | .mpc = 0, | |
214 | .mrindex = 0, | |
215 | }, { | |
216 | .name = "ssram-1", | |
217 | .base = 0x28000000, | |
218 | .size = 0x00200000, | |
219 | .mpc = 1, | |
220 | .mrindex = 1, | |
221 | }, { | |
222 | .name = "ssram-2", | |
223 | .base = 0x28200000, | |
224 | .size = 0x00200000, | |
225 | .mpc = 2, | |
226 | .mrindex = 2, | |
227 | }, { | |
228 | .name = "ssram-0-alias", | |
229 | .base = 0x00400000, | |
230 | .size = 0x00400000, | |
231 | .mpc = 0, | |
232 | .mrindex = 3, | |
233 | .flags = IS_ALIAS, | |
234 | }, { | |
235 | /* Use the largest bit of contiguous RAM as our "system memory" */ | |
236 | .name = "mps.ram", | |
237 | .base = 0x80000000, | |
238 | .size = 16 * MiB, | |
239 | .mpc = -1, | |
240 | .mrindex = -1, | |
241 | }, { | |
242 | .name = NULL, | |
243 | }, | |
244 | }; | |
245 | ||
f1dfab0d PM |
246 | /* |
247 | * Note that the addresses and MPC numbering here should match up | |
248 | * with those used in remap_memory(), which can swap the BRAM and QSPI. | |
249 | */ | |
25ff112a PM |
250 | static const RAMInfo an524_raminfo[] = { { |
251 | .name = "bram", | |
252 | .base = 0x00000000, | |
253 | .size = 512 * KiB, | |
254 | .mpc = 0, | |
255 | .mrindex = 0, | |
25ff112a PM |
256 | }, { |
257 | /* We don't model QSPI flash yet; for now expose it as simple ROM */ | |
258 | .name = "QSPI", | |
259 | .base = 0x28000000, | |
260 | .size = 8 * MiB, | |
261 | .mpc = 1, | |
b6889c5a | 262 | .mrindex = 1, |
25ff112a PM |
263 | .flags = IS_ROM, |
264 | }, { | |
265 | .name = "DDR", | |
266 | .base = 0x60000000, | |
267 | .size = MPS3_DDR_SIZE, | |
268 | .mpc = 2, | |
269 | .mrindex = -1, | |
270 | }, { | |
271 | .name = NULL, | |
272 | }, | |
273 | }; | |
274 | ||
eb09d533 | 275 | static const RAMInfo an547_raminfo[] = { { |
eb09d533 PM |
276 | .name = "sram", |
277 | .base = 0x01000000, | |
278 | .size = 2 * MiB, | |
279 | .mpc = 0, | |
280 | .mrindex = 1, | |
eb09d533 PM |
281 | }, { |
282 | .name = "sram 2", | |
283 | .base = 0x21000000, | |
284 | .size = 4 * MiB, | |
285 | .mpc = -1, | |
286 | .mrindex = 3, | |
287 | }, { | |
288 | /* We don't model QSPI flash yet; for now expose it as simple ROM */ | |
289 | .name = "QSPI", | |
290 | .base = 0x28000000, | |
291 | .size = 8 * MiB, | |
292 | .mpc = 1, | |
293 | .mrindex = 4, | |
294 | .flags = IS_ROM, | |
295 | }, { | |
296 | .name = "DDR", | |
297 | .base = 0x60000000, | |
298 | .size = MPS3_DDR_SIZE, | |
299 | .mpc = 2, | |
300 | .mrindex = -1, | |
301 | }, { | |
302 | .name = NULL, | |
303 | }, | |
304 | }; | |
305 | ||
4fec32db PM |
306 | static const RAMInfo *find_raminfo_for_mpc(MPS2TZMachineState *mms, int mpc) |
307 | { | |
308 | MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); | |
309 | const RAMInfo *p; | |
91c0a798 | 310 | const RAMInfo *found = NULL; |
4fec32db PM |
311 | |
312 | for (p = mmc->raminfo; p->name; p++) { | |
313 | if (p->mpc == mpc && !(p->flags & IS_ALIAS)) { | |
91c0a798 PM |
314 | /* There should only be one entry in the array for this MPC */ |
315 | g_assert(!found); | |
316 | found = p; | |
4fec32db PM |
317 | } |
318 | } | |
319 | /* if raminfo array doesn't have an entry for each MPC this is a bug */ | |
91c0a798 PM |
320 | assert(found); |
321 | return found; | |
4fec32db PM |
322 | } |
323 | ||
324 | static MemoryRegion *mr_for_raminfo(MPS2TZMachineState *mms, | |
325 | const RAMInfo *raminfo) | |
326 | { | |
327 | /* Return an initialized MemoryRegion for the RAMInfo. */ | |
328 | MemoryRegion *ram; | |
329 | ||
330 | if (raminfo->mrindex < 0) { | |
331 | /* Means this RAMInfo is for QEMU's "system memory" */ | |
332 | MachineState *machine = MACHINE(mms); | |
b89918fc | 333 | assert(!(raminfo->flags & IS_ROM)); |
4fec32db PM |
334 | return machine->ram; |
335 | } | |
336 | ||
337 | assert(raminfo->mrindex < MPS2TZ_RAM_MAX); | |
338 | ram = &mms->ram[raminfo->mrindex]; | |
339 | ||
340 | memory_region_init_ram(ram, NULL, raminfo->name, | |
341 | raminfo->size, &error_fatal); | |
b89918fc PM |
342 | if (raminfo->flags & IS_ROM) { |
343 | memory_region_set_readonly(ram, true); | |
344 | } | |
4fec32db PM |
345 | return ram; |
346 | } | |
347 | ||
5aff1c07 PM |
348 | /* Create an alias of an entire original MemoryRegion @orig |
349 | * located at @base in the memory map. | |
350 | */ | |
351 | static void make_ram_alias(MemoryRegion *mr, const char *name, | |
352 | MemoryRegion *orig, hwaddr base) | |
353 | { | |
354 | memory_region_init_alias(mr, NULL, name, orig, 0, | |
355 | memory_region_size(orig)); | |
356 | memory_region_add_subregion(get_system_memory(), base, mr); | |
357 | } | |
358 | ||
4a30dc1c PM |
359 | static qemu_irq get_sse_irq_in(MPS2TZMachineState *mms, int irqno) |
360 | { | |
fee887a7 PM |
361 | /* |
362 | * Return a qemu_irq which will signal IRQ n to all CPUs in the | |
363 | * SSE. The irqno should be as the CPU sees it, so the first | |
364 | * external-to-the-SSE interrupt is 32. | |
365 | */ | |
ba94ffd7 | 366 | MachineClass *mc = MACHINE_GET_CLASS(mms); |
11e1d412 | 367 | MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); |
4a30dc1c | 368 | |
fee887a7 PM |
369 | assert(irqno >= 32 && irqno < (mmc->numirq + 32)); |
370 | ||
371 | /* | |
372 | * Convert from "CPU irq number" (as listed in the FPGA image | |
373 | * documentation) to the SSE external-interrupt number. | |
374 | */ | |
375 | irqno -= 32; | |
4a30dc1c | 376 | |
ba94ffd7 | 377 | if (mc->max_cpus > 1) { |
4a30dc1c | 378 | return qdev_get_gpio_in(DEVICE(&mms->cpu_irq_splitter[irqno]), 0); |
ba94ffd7 PM |
379 | } else { |
380 | return qdev_get_gpio_in_named(DEVICE(&mms->iotkit), "EXP_IRQ", irqno); | |
4a30dc1c PM |
381 | } |
382 | } | |
383 | ||
e6f79acd PM |
384 | /* Union describing the device-specific extra data we pass to the devfn. */ |
385 | typedef union PPCExtraData { | |
68e57951 | 386 | bool i2c_internal; |
e6f79acd PM |
387 | } PPCExtraData; |
388 | ||
5aff1c07 PM |
389 | /* Most of the devices in the AN505 FPGA image sit behind |
390 | * Peripheral Protection Controllers. These data structures | |
391 | * define the layout of which devices sit behind which PPCs. | |
392 | * The devfn for each port is a function which creates, configures | |
393 | * and initializes the device, returning the MemoryRegion which | |
394 | * needs to be plugged into the downstream end of the PPC port. | |
395 | */ | |
396 | typedef MemoryRegion *MakeDevFn(MPS2TZMachineState *mms, void *opaque, | |
42418279 | 397 | const char *name, hwaddr size, |
e6f79acd PM |
398 | const int *irqs, |
399 | const PPCExtraData *extradata); | |
5aff1c07 PM |
400 | |
401 | typedef struct PPCPortInfo { | |
402 | const char *name; | |
403 | MakeDevFn *devfn; | |
404 | void *opaque; | |
405 | hwaddr addr; | |
406 | hwaddr size; | |
42418279 | 407 | int irqs[3]; /* currently no device needs more IRQ lines than this */ |
e6f79acd | 408 | PPCExtraData extradata; /* to pass device-specific info to the devfn */ |
5aff1c07 PM |
409 | } PPCPortInfo; |
410 | ||
411 | typedef struct PPCInfo { | |
412 | const char *name; | |
413 | PPCPortInfo ports[TZ_NUM_PORTS]; | |
414 | } PPCInfo; | |
415 | ||
416 | static MemoryRegion *make_unimp_dev(MPS2TZMachineState *mms, | |
42418279 PM |
417 | void *opaque, |
418 | const char *name, hwaddr size, | |
e6f79acd PM |
419 | const int *irqs, |
420 | const PPCExtraData *extradata) | |
5aff1c07 PM |
421 | { |
422 | /* Initialize, configure and realize a TYPE_UNIMPLEMENTED_DEVICE, | |
423 | * and return a pointer to its MemoryRegion. | |
424 | */ | |
425 | UnimplementedDeviceState *uds = opaque; | |
426 | ||
0074fce6 | 427 | object_initialize_child(OBJECT(mms), name, uds, TYPE_UNIMPLEMENTED_DEVICE); |
5aff1c07 PM |
428 | qdev_prop_set_string(DEVICE(uds), "name", name); |
429 | qdev_prop_set_uint64(DEVICE(uds), "size", size); | |
0074fce6 | 430 | sysbus_realize(SYS_BUS_DEVICE(uds), &error_fatal); |
5aff1c07 PM |
431 | return sysbus_mmio_get_region(SYS_BUS_DEVICE(uds), 0); |
432 | } | |
433 | ||
434 | static MemoryRegion *make_uart(MPS2TZMachineState *mms, void *opaque, | |
42418279 | 435 | const char *name, hwaddr size, |
e6f79acd | 436 | const int *irqs, const PPCExtraData *extradata) |
5aff1c07 | 437 | { |
b22c4e8b | 438 | /* The irq[] array is tx, rx, combined, in that order */ |
a3e24690 | 439 | MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); |
5aff1c07 PM |
440 | CMSDKAPBUART *uart = opaque; |
441 | int i = uart - &mms->uart[0]; | |
5aff1c07 | 442 | SysBusDevice *s; |
5aff1c07 PM |
443 | DeviceState *orgate_dev = DEVICE(&mms->uart_irq_orgate); |
444 | ||
0074fce6 | 445 | object_initialize_child(OBJECT(mms), name, uart, TYPE_CMSDK_APB_UART); |
fc38a112 | 446 | qdev_prop_set_chr(DEVICE(uart), "chardev", serial_hd(i)); |
ad28ca7e | 447 | qdev_prop_set_uint32(DEVICE(uart), "pclk-frq", mmc->apb_periph_frq); |
0074fce6 | 448 | sysbus_realize(SYS_BUS_DEVICE(uart), &error_fatal); |
5aff1c07 | 449 | s = SYS_BUS_DEVICE(uart); |
b22c4e8b PM |
450 | sysbus_connect_irq(s, 0, get_sse_irq_in(mms, irqs[0])); |
451 | sysbus_connect_irq(s, 1, get_sse_irq_in(mms, irqs[1])); | |
5aff1c07 PM |
452 | sysbus_connect_irq(s, 2, qdev_get_gpio_in(orgate_dev, i * 2)); |
453 | sysbus_connect_irq(s, 3, qdev_get_gpio_in(orgate_dev, i * 2 + 1)); | |
b22c4e8b | 454 | sysbus_connect_irq(s, 4, get_sse_irq_in(mms, irqs[2])); |
5aff1c07 PM |
455 | return sysbus_mmio_get_region(SYS_BUS_DEVICE(uart), 0); |
456 | } | |
457 | ||
458 | static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque, | |
42418279 | 459 | const char *name, hwaddr size, |
e6f79acd | 460 | const int *irqs, const PPCExtraData *extradata) |
5aff1c07 PM |
461 | { |
462 | MPS2SCC *scc = opaque; | |
463 | DeviceState *sccdev; | |
464 | MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); | |
31805a0a | 465 | QList *oscclk; |
f7c71b21 | 466 | uint32_t i; |
5aff1c07 | 467 | |
0074fce6 | 468 | object_initialize_child(OBJECT(mms), "scc", scc, TYPE_MPS2_SCC); |
5aff1c07 | 469 | sccdev = DEVICE(scc); |
f1dfab0d | 470 | qdev_prop_set_uint32(sccdev, "scc-cfg0", mms->remap ? 1 : 0); |
5aff1c07 | 471 | qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2); |
cb159db9 | 472 | qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008); |
5aff1c07 | 473 | qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id); |
31805a0a KW |
474 | |
475 | oscclk = qlist_new(); | |
f7c71b21 | 476 | for (i = 0; i < mmc->len_oscclk; i++) { |
31805a0a | 477 | qlist_append_int(oscclk, mmc->oscclk[i]); |
f7c71b21 | 478 | } |
31805a0a KW |
479 | qdev_prop_set_array(sccdev, "oscclk", oscclk); |
480 | ||
0074fce6 | 481 | sysbus_realize(SYS_BUS_DEVICE(scc), &error_fatal); |
5aff1c07 PM |
482 | return sysbus_mmio_get_region(SYS_BUS_DEVICE(sccdev), 0); |
483 | } | |
484 | ||
485 | static MemoryRegion *make_fpgaio(MPS2TZMachineState *mms, void *opaque, | |
42418279 | 486 | const char *name, hwaddr size, |
e6f79acd | 487 | const int *irqs, const PPCExtraData *extradata) |
5aff1c07 PM |
488 | { |
489 | MPS2FPGAIO *fpgaio = opaque; | |
de77e8f4 | 490 | MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); |
5aff1c07 | 491 | |
0074fce6 | 492 | object_initialize_child(OBJECT(mms), "fpgaio", fpgaio, TYPE_MPS2_FPGAIO); |
de77e8f4 PM |
493 | qdev_prop_set_uint32(DEVICE(fpgaio), "num-leds", mmc->fpgaio_num_leds); |
494 | qdev_prop_set_bit(DEVICE(fpgaio), "has-switches", mmc->fpgaio_has_switches); | |
39901aea | 495 | qdev_prop_set_bit(DEVICE(fpgaio), "has-dbgctrl", mmc->fpgaio_has_dbgctrl); |
0074fce6 | 496 | sysbus_realize(SYS_BUS_DEVICE(fpgaio), &error_fatal); |
5aff1c07 PM |
497 | return sysbus_mmio_get_region(SYS_BUS_DEVICE(fpgaio), 0); |
498 | } | |
499 | ||
519655e6 | 500 | static MemoryRegion *make_eth_dev(MPS2TZMachineState *mms, void *opaque, |
42418279 | 501 | const char *name, hwaddr size, |
e6f79acd PM |
502 | const int *irqs, |
503 | const PPCExtraData *extradata) | |
519655e6 PM |
504 | { |
505 | SysBusDevice *s; | |
519655e6 PM |
506 | NICInfo *nd = &nd_table[0]; |
507 | ||
508 | /* In hardware this is a LAN9220; the LAN9118 is software compatible | |
509 | * except that it doesn't support the checksum-offload feature. | |
510 | */ | |
511 | qemu_check_nic_model(nd, "lan9118"); | |
3e80f690 | 512 | mms->lan9118 = qdev_new(TYPE_LAN9118); |
519655e6 | 513 | qdev_set_nic_properties(mms->lan9118, nd); |
519655e6 PM |
514 | |
515 | s = SYS_BUS_DEVICE(mms->lan9118); | |
3c6ef471 | 516 | sysbus_realize_and_unref(s, &error_fatal); |
b22c4e8b | 517 | sysbus_connect_irq(s, 0, get_sse_irq_in(mms, irqs[0])); |
519655e6 PM |
518 | return sysbus_mmio_get_region(s, 0); |
519 | } | |
520 | ||
a9597753 PM |
521 | static MemoryRegion *make_eth_usb(MPS2TZMachineState *mms, void *opaque, |
522 | const char *name, hwaddr size, | |
e6f79acd PM |
523 | const int *irqs, |
524 | const PPCExtraData *extradata) | |
a9597753 PM |
525 | { |
526 | /* | |
527 | * The AN524 makes the ethernet and USB share a PPC port. | |
528 | * irqs[] is the ethernet IRQ. | |
529 | */ | |
530 | SysBusDevice *s; | |
531 | NICInfo *nd = &nd_table[0]; | |
532 | ||
533 | memory_region_init(&mms->eth_usb_container, OBJECT(mms), | |
534 | "mps2-tz-eth-usb-container", 0x200000); | |
535 | ||
536 | /* | |
537 | * In hardware this is a LAN9220; the LAN9118 is software compatible | |
538 | * except that it doesn't support the checksum-offload feature. | |
539 | */ | |
540 | qemu_check_nic_model(nd, "lan9118"); | |
541 | mms->lan9118 = qdev_new(TYPE_LAN9118); | |
542 | qdev_set_nic_properties(mms->lan9118, nd); | |
543 | ||
544 | s = SYS_BUS_DEVICE(mms->lan9118); | |
545 | sysbus_realize_and_unref(s, &error_fatal); | |
546 | sysbus_connect_irq(s, 0, get_sse_irq_in(mms, irqs[0])); | |
547 | ||
548 | memory_region_add_subregion(&mms->eth_usb_container, | |
549 | 0, sysbus_mmio_get_region(s, 0)); | |
550 | ||
551 | /* The USB OTG controller is an ISP1763; we don't have a model of it. */ | |
552 | object_initialize_child(OBJECT(mms), "usb-otg", | |
553 | &mms->usb, TYPE_UNIMPLEMENTED_DEVICE); | |
554 | qdev_prop_set_string(DEVICE(&mms->usb), "name", "usb-otg"); | |
555 | qdev_prop_set_uint64(DEVICE(&mms->usb), "size", 0x100000); | |
556 | s = SYS_BUS_DEVICE(&mms->usb); | |
557 | sysbus_realize(s, &error_fatal); | |
558 | ||
559 | memory_region_add_subregion(&mms->eth_usb_container, | |
560 | 0x100000, sysbus_mmio_get_region(s, 0)); | |
561 | ||
562 | return &mms->eth_usb_container; | |
563 | } | |
564 | ||
665670aa | 565 | static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque, |
42418279 | 566 | const char *name, hwaddr size, |
e6f79acd | 567 | const int *irqs, const PPCExtraData *extradata) |
665670aa PM |
568 | { |
569 | TZMPC *mpc = opaque; | |
4fec32db | 570 | int i = mpc - &mms->mpc[0]; |
665670aa | 571 | MemoryRegion *upstream; |
4fec32db PM |
572 | const RAMInfo *raminfo = find_raminfo_for_mpc(mms, i); |
573 | MemoryRegion *ram = mr_for_raminfo(mms, raminfo); | |
665670aa | 574 | |
4fec32db PM |
575 | object_initialize_child(OBJECT(mms), name, mpc, TYPE_TZ_MPC); |
576 | object_property_set_link(OBJECT(mpc), "downstream", OBJECT(ram), | |
5325cc34 | 577 | &error_fatal); |
0074fce6 | 578 | sysbus_realize(SYS_BUS_DEVICE(mpc), &error_fatal); |
665670aa PM |
579 | /* Map the upstream end of the MPC into system memory */ |
580 | upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 1); | |
4fec32db | 581 | memory_region_add_subregion(get_system_memory(), raminfo->base, upstream); |
665670aa PM |
582 | /* and connect its interrupt to the IoTKit */ |
583 | qdev_connect_gpio_out_named(DEVICE(mpc), "irq", 0, | |
584 | qdev_get_gpio_in_named(DEVICE(&mms->iotkit), | |
585 | "mpcexp_status", i)); | |
586 | ||
665670aa PM |
587 | /* Return the register interface MR for our caller to map behind the PPC */ |
588 | return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0); | |
589 | } | |
590 | ||
f1dfab0d PM |
591 | static hwaddr boot_mem_base(MPS2TZMachineState *mms) |
592 | { | |
593 | /* | |
594 | * Return the canonical address of the block which will be mapped | |
595 | * at address 0x0 (i.e. where the vector table is). | |
596 | * This is usually 0, but if the AN524 alternate memory map is | |
597 | * enabled it will be the base address of the QSPI block. | |
598 | */ | |
599 | return mms->remap ? 0x28000000 : 0; | |
600 | } | |
601 | ||
602 | static void remap_memory(MPS2TZMachineState *mms, int map) | |
603 | { | |
604 | /* | |
605 | * Remap the memory for the AN524. 'map' is the value of | |
606 | * SCC CFG_REG0 bit 0, i.e. 0 for the default map and 1 | |
607 | * for the "option 1" mapping where QSPI is at address 0. | |
608 | * | |
609 | * Effectively we need to swap around the "upstream" ends of | |
610 | * MPC 0 and MPC 1. | |
611 | */ | |
612 | MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); | |
613 | int i; | |
614 | ||
615 | if (mmc->fpga_type != FPGA_AN524) { | |
616 | return; | |
617 | } | |
618 | ||
619 | memory_region_transaction_begin(); | |
620 | for (i = 0; i < 2; i++) { | |
621 | TZMPC *mpc = &mms->mpc[i]; | |
622 | MemoryRegion *upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 1); | |
623 | hwaddr addr = (i ^ map) ? 0x28000000 : 0; | |
624 | ||
625 | memory_region_set_address(upstream, addr); | |
626 | } | |
627 | memory_region_transaction_commit(); | |
628 | } | |
629 | ||
630 | static void remap_irq_fn(void *opaque, int n, int level) | |
631 | { | |
632 | MPS2TZMachineState *mms = opaque; | |
633 | ||
634 | remap_memory(mms, level); | |
635 | } | |
636 | ||
28e56f05 | 637 | static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque, |
42418279 | 638 | const char *name, hwaddr size, |
e6f79acd | 639 | const int *irqs, const PPCExtraData *extradata) |
28e56f05 | 640 | { |
b22c4e8b | 641 | /* The irq[] array is DMACINTR, DMACINTERR, DMACINTTC, in that order */ |
28e56f05 PM |
642 | PL080State *dma = opaque; |
643 | int i = dma - &mms->dma[0]; | |
644 | SysBusDevice *s; | |
645 | char *mscname = g_strdup_printf("%s-msc", name); | |
646 | TZMSC *msc = &mms->msc[i]; | |
647 | DeviceState *iotkitdev = DEVICE(&mms->iotkit); | |
648 | MemoryRegion *msc_upstream; | |
649 | MemoryRegion *msc_downstream; | |
650 | ||
651 | /* | |
652 | * Each DMA device is a PL081 whose transaction master interface | |
653 | * is guarded by a Master Security Controller. The downstream end of | |
654 | * the MSC connects to the IoTKit AHB Slave Expansion port, so the | |
655 | * DMA devices can see all devices and memory that the CPU does. | |
656 | */ | |
0074fce6 | 657 | object_initialize_child(OBJECT(mms), mscname, msc, TYPE_TZ_MSC); |
28e56f05 | 658 | msc_downstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(&mms->iotkit), 0); |
5325cc34 MA |
659 | object_property_set_link(OBJECT(msc), "downstream", |
660 | OBJECT(msc_downstream), &error_fatal); | |
661 | object_property_set_link(OBJECT(msc), "idau", OBJECT(mms), &error_fatal); | |
0074fce6 | 662 | sysbus_realize(SYS_BUS_DEVICE(msc), &error_fatal); |
28e56f05 PM |
663 | |
664 | qdev_connect_gpio_out_named(DEVICE(msc), "irq", 0, | |
665 | qdev_get_gpio_in_named(iotkitdev, | |
666 | "mscexp_status", i)); | |
667 | qdev_connect_gpio_out_named(iotkitdev, "mscexp_clear", i, | |
668 | qdev_get_gpio_in_named(DEVICE(msc), | |
669 | "irq_clear", 0)); | |
670 | qdev_connect_gpio_out_named(iotkitdev, "mscexp_ns", i, | |
671 | qdev_get_gpio_in_named(DEVICE(msc), | |
672 | "cfg_nonsec", 0)); | |
673 | qdev_connect_gpio_out(DEVICE(&mms->sec_resp_splitter), | |
674 | ARRAY_SIZE(mms->ppc) + i, | |
675 | qdev_get_gpio_in_named(DEVICE(msc), | |
676 | "cfg_sec_resp", 0)); | |
677 | msc_upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(msc), 0); | |
678 | ||
0074fce6 | 679 | object_initialize_child(OBJECT(mms), name, dma, TYPE_PL081); |
5325cc34 MA |
680 | object_property_set_link(OBJECT(dma), "downstream", OBJECT(msc_upstream), |
681 | &error_fatal); | |
0074fce6 | 682 | sysbus_realize(SYS_BUS_DEVICE(dma), &error_fatal); |
28e56f05 PM |
683 | |
684 | s = SYS_BUS_DEVICE(dma); | |
685 | /* Wire up DMACINTR, DMACINTERR, DMACINTTC */ | |
b22c4e8b PM |
686 | sysbus_connect_irq(s, 0, get_sse_irq_in(mms, irqs[0])); |
687 | sysbus_connect_irq(s, 1, get_sse_irq_in(mms, irqs[1])); | |
688 | sysbus_connect_irq(s, 2, get_sse_irq_in(mms, irqs[2])); | |
28e56f05 | 689 | |
7081e9b6 | 690 | g_free(mscname); |
28e56f05 PM |
691 | return sysbus_mmio_get_region(s, 0); |
692 | } | |
693 | ||
0d49759b | 694 | static MemoryRegion *make_spi(MPS2TZMachineState *mms, void *opaque, |
42418279 | 695 | const char *name, hwaddr size, |
e6f79acd | 696 | const int *irqs, const PPCExtraData *extradata) |
0d49759b PM |
697 | { |
698 | /* | |
699 | * The AN505 has five PL022 SPI controllers. | |
700 | * One of these should have the LCD controller behind it; the others | |
701 | * are connected only to the FPGA's "general purpose SPI connector" | |
702 | * or "shield" expansion connectors. | |
703 | * Note that if we do implement devices behind SPI, the chip select | |
704 | * lines are set via the "MISC" register in the MPS2 FPGAIO device. | |
705 | */ | |
706 | PL022State *spi = opaque; | |
0d49759b PM |
707 | SysBusDevice *s; |
708 | ||
0074fce6 MA |
709 | object_initialize_child(OBJECT(mms), name, spi, TYPE_PL022); |
710 | sysbus_realize(SYS_BUS_DEVICE(spi), &error_fatal); | |
0d49759b | 711 | s = SYS_BUS_DEVICE(spi); |
b22c4e8b | 712 | sysbus_connect_irq(s, 0, get_sse_irq_in(mms, irqs[0])); |
0d49759b PM |
713 | return sysbus_mmio_get_region(s, 0); |
714 | } | |
715 | ||
2e34818f | 716 | static MemoryRegion *make_i2c(MPS2TZMachineState *mms, void *opaque, |
42418279 | 717 | const char *name, hwaddr size, |
e6f79acd | 718 | const int *irqs, const PPCExtraData *extradata) |
2e34818f PMD |
719 | { |
720 | ArmSbconI2CState *i2c = opaque; | |
721 | SysBusDevice *s; | |
722 | ||
723 | object_initialize_child(OBJECT(mms), name, i2c, TYPE_ARM_SBCON_I2C); | |
724 | s = SYS_BUS_DEVICE(i2c); | |
725 | sysbus_realize(s, &error_fatal); | |
68e57951 PM |
726 | |
727 | /* | |
728 | * If this is an internal-use-only i2c bus, mark it full | |
729 | * so that user-created i2c devices are not plugged into it. | |
730 | * If we implement models of any on-board i2c devices that | |
731 | * plug in to one of the internal-use-only buses, then we will | |
732 | * need to create and plugging those in here before we mark the | |
733 | * bus as full. | |
734 | */ | |
735 | if (extradata->i2c_internal) { | |
736 | BusState *qbus = qdev_get_child_bus(DEVICE(i2c), "i2c"); | |
737 | qbus_mark_full(qbus); | |
738 | } | |
739 | ||
2e34818f PMD |
740 | return sysbus_mmio_get_region(s, 0); |
741 | } | |
742 | ||
41745d20 PM |
743 | static MemoryRegion *make_rtc(MPS2TZMachineState *mms, void *opaque, |
744 | const char *name, hwaddr size, | |
e6f79acd | 745 | const int *irqs, const PPCExtraData *extradata) |
41745d20 PM |
746 | { |
747 | PL031State *pl031 = opaque; | |
748 | SysBusDevice *s; | |
749 | ||
750 | object_initialize_child(OBJECT(mms), name, pl031, TYPE_PL031); | |
751 | s = SYS_BUS_DEVICE(pl031); | |
752 | sysbus_realize(s, &error_fatal); | |
753 | /* | |
754 | * The board docs don't give an IRQ number for the PL031, so | |
755 | * presumably it is not connected. | |
756 | */ | |
757 | return sysbus_mmio_get_region(s, 0); | |
758 | } | |
759 | ||
4fec32db PM |
760 | static void create_non_mpc_ram(MPS2TZMachineState *mms) |
761 | { | |
762 | /* | |
763 | * Handle the RAMs which are either not behind MPCs or which are | |
764 | * aliases to another MPC. | |
765 | */ | |
766 | const RAMInfo *p; | |
767 | MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); | |
768 | ||
769 | for (p = mmc->raminfo; p->name; p++) { | |
770 | if (p->flags & IS_ALIAS) { | |
771 | SysBusDevice *mpc_sbd = SYS_BUS_DEVICE(&mms->mpc[p->mpc]); | |
772 | MemoryRegion *upstream = sysbus_mmio_get_region(mpc_sbd, 1); | |
773 | make_ram_alias(&mms->ram[p->mrindex], p->name, upstream, p->base); | |
774 | } else if (p->mpc == -1) { | |
775 | /* RAM not behind an MPC */ | |
776 | MemoryRegion *mr = mr_for_raminfo(mms, p); | |
777 | memory_region_add_subregion(get_system_memory(), p->base, mr); | |
778 | } | |
779 | } | |
780 | } | |
781 | ||
a113aef9 PM |
782 | static uint32_t boot_ram_size(MPS2TZMachineState *mms) |
783 | { | |
784 | /* Return the size of the RAM block at guest address zero */ | |
785 | const RAMInfo *p; | |
786 | MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); | |
787 | ||
2f12dca0 PM |
788 | /* |
789 | * Use a per-board specification (for when the boot RAM is in | |
790 | * the SSE and so doesn't have a RAMInfo list entry) | |
791 | */ | |
792 | if (mmc->boot_ram_size) { | |
793 | return mmc->boot_ram_size; | |
794 | } | |
795 | ||
a113aef9 | 796 | for (p = mmc->raminfo; p->name; p++) { |
f1dfab0d | 797 | if (p->base == boot_mem_base(mms)) { |
a113aef9 PM |
798 | return p->size; |
799 | } | |
800 | } | |
801 | g_assert_not_reached(); | |
802 | } | |
803 | ||
5aff1c07 PM |
804 | static void mps2tz_common_init(MachineState *machine) |
805 | { | |
806 | MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine); | |
4a30dc1c | 807 | MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); |
5aff1c07 PM |
808 | MachineClass *mc = MACHINE_GET_CLASS(machine); |
809 | MemoryRegion *system_memory = get_system_memory(); | |
810 | DeviceState *iotkitdev; | |
811 | DeviceState *dev_splitter; | |
ef29e382 PM |
812 | const PPCInfo *ppcs; |
813 | int num_ppcs; | |
5aff1c07 PM |
814 | int i; |
815 | ||
70a2cb8e IM |
816 | if (machine->ram_size != mc->default_ram_size) { |
817 | char *sz = size_to_str(mc->default_ram_size); | |
818 | error_report("Invalid RAM size, should be %s", sz); | |
819 | g_free(sz); | |
820 | exit(EXIT_FAILURE); | |
821 | } | |
822 | ||
dee1515b PM |
823 | /* These clocks don't need migration because they are fixed-frequency */ |
824 | mms->sysclk = clock_new(OBJECT(machine), "SYSCLK"); | |
a3e24690 | 825 | clock_set_hz(mms->sysclk, mmc->sysclk_frq); |
dee1515b PM |
826 | mms->s32kclk = clock_new(OBJECT(machine), "S32KCLK"); |
827 | clock_set_hz(mms->s32kclk, S32KCLK_FRQ); | |
828 | ||
0074fce6 MA |
829 | object_initialize_child(OBJECT(machine), TYPE_IOTKIT, &mms->iotkit, |
830 | mmc->armsse_type); | |
5aff1c07 | 831 | iotkitdev = DEVICE(&mms->iotkit); |
5325cc34 MA |
832 | object_property_set_link(OBJECT(&mms->iotkit), "memory", |
833 | OBJECT(system_memory), &error_abort); | |
11e1d412 | 834 | qdev_prop_set_uint32(iotkitdev, "EXP_NUMIRQ", mmc->numirq); |
9fe1ea11 | 835 | qdev_prop_set_uint32(iotkitdev, "init-svtor", mmc->init_svtor); |
e73b8bb8 PM |
836 | if (mmc->cpu0_mpu_ns != MPU_REGION_DEFAULT) { |
837 | qdev_prop_set_uint32(iotkitdev, "CPU0_MPU_NS", mmc->cpu0_mpu_ns); | |
838 | } | |
839 | if (mmc->cpu0_mpu_s != MPU_REGION_DEFAULT) { | |
840 | qdev_prop_set_uint32(iotkitdev, "CPU0_MPU_S", mmc->cpu0_mpu_s); | |
841 | } | |
842 | if (object_property_find(OBJECT(iotkitdev), "CPU1_MPU_NS")) { | |
843 | if (mmc->cpu1_mpu_ns != MPU_REGION_DEFAULT) { | |
844 | qdev_prop_set_uint32(iotkitdev, "CPU1_MPU_NS", mmc->cpu1_mpu_ns); | |
845 | } | |
846 | if (mmc->cpu1_mpu_s != MPU_REGION_DEFAULT) { | |
847 | qdev_prop_set_uint32(iotkitdev, "CPU1_MPU_S", mmc->cpu1_mpu_s); | |
848 | } | |
849 | } | |
902b28ae | 850 | qdev_prop_set_uint32(iotkitdev, "SRAM_ADDR_WIDTH", mmc->sram_addr_width); |
dee1515b PM |
851 | qdev_connect_clock_in(iotkitdev, "MAINCLK", mms->sysclk); |
852 | qdev_connect_clock_in(iotkitdev, "S32KCLK", mms->s32kclk); | |
0074fce6 | 853 | sysbus_realize(SYS_BUS_DEVICE(&mms->iotkit), &error_fatal); |
5aff1c07 | 854 | |
4a30dc1c | 855 | /* |
ba94ffd7 PM |
856 | * If this board has more than one CPU, then we need to create splitters |
857 | * to feed the IRQ inputs for each CPU in the SSE from each device in the | |
858 | * board. If there is only one CPU, we can just wire the device IRQ | |
859 | * directly to the SSE's IRQ input. | |
4a30dc1c | 860 | */ |
11e1d412 | 861 | assert(mmc->numirq <= MPS2TZ_NUMIRQ_MAX); |
ba94ffd7 | 862 | if (mc->max_cpus > 1) { |
11e1d412 | 863 | for (i = 0; i < mmc->numirq; i++) { |
4a30dc1c PM |
864 | char *name = g_strdup_printf("mps2-irq-splitter%d", i); |
865 | SplitIRQ *splitter = &mms->cpu_irq_splitter[i]; | |
866 | ||
9fc7fc4d MA |
867 | object_initialize_child_with_props(OBJECT(machine), name, |
868 | splitter, sizeof(*splitter), | |
869 | TYPE_SPLIT_IRQ, &error_fatal, | |
870 | NULL); | |
4a30dc1c PM |
871 | g_free(name); |
872 | ||
5325cc34 | 873 | object_property_set_int(OBJECT(splitter), "num-lines", 2, |
4a30dc1c | 874 | &error_fatal); |
ce189ab2 | 875 | qdev_realize(DEVICE(splitter), NULL, &error_fatal); |
4a30dc1c PM |
876 | qdev_connect_gpio_out(DEVICE(splitter), 0, |
877 | qdev_get_gpio_in_named(DEVICE(&mms->iotkit), | |
878 | "EXP_IRQ", i)); | |
879 | qdev_connect_gpio_out(DEVICE(splitter), 1, | |
880 | qdev_get_gpio_in_named(DEVICE(&mms->iotkit), | |
881 | "EXP_CPU1_IRQ", i)); | |
882 | } | |
883 | } | |
884 | ||
5aff1c07 | 885 | /* The sec_resp_cfg output from the IoTKit must be split into multiple |
28e56f05 | 886 | * lines, one for each of the PPCs we create here, plus one per MSC. |
5aff1c07 | 887 | */ |
7840938e | 888 | object_initialize_child(OBJECT(machine), "sec-resp-splitter", |
9fc7fc4d | 889 | &mms->sec_resp_splitter, TYPE_SPLIT_IRQ); |
5325cc34 | 890 | object_property_set_int(OBJECT(&mms->sec_resp_splitter), "num-lines", |
28e56f05 | 891 | ARRAY_SIZE(mms->ppc) + ARRAY_SIZE(mms->msc), |
5325cc34 | 892 | &error_fatal); |
ce189ab2 | 893 | qdev_realize(DEVICE(&mms->sec_resp_splitter), NULL, &error_fatal); |
5aff1c07 PM |
894 | dev_splitter = DEVICE(&mms->sec_resp_splitter); |
895 | qdev_connect_gpio_out_named(iotkitdev, "sec_resp_cfg", 0, | |
896 | qdev_get_gpio_in(dev_splitter, 0)); | |
897 | ||
4fec32db PM |
898 | /* |
899 | * The IoTKit sets up much of the memory layout, including | |
5aff1c07 | 900 | * the aliases between secure and non-secure regions in the |
4fec32db PM |
901 | * address space, and also most of the devices in the system. |
902 | * The FPGA itself contains various RAMs and some additional devices. | |
903 | * The FPGA images have an odd combination of different RAMs, | |
5aff1c07 PM |
904 | * because in hardware they are different implementations and |
905 | * connected to different buses, giving varying performance/size | |
906 | * tradeoffs. For QEMU they're all just RAM, though. We arbitrarily | |
4fec32db | 907 | * call the largest lump our "system memory". |
5aff1c07 | 908 | */ |
5aff1c07 | 909 | |
8cf68ed9 PM |
910 | /* |
911 | * The overflow IRQs for all UARTs are ORed together. | |
5aff1c07 | 912 | * Tx, Rx and "combined" IRQs are sent to the NVIC separately. |
8cf68ed9 PM |
913 | * Create the OR gate for this: it has one input for the TX overflow |
914 | * and one for the RX overflow for each UART we might have. | |
915 | * (If the board has fewer than the maximum possible number of UARTs | |
916 | * those inputs are never wired up and are treated as always-zero.) | |
5aff1c07 | 917 | */ |
7840938e | 918 | object_initialize_child(OBJECT(mms), "uart-irq-orgate", |
9fc7fc4d | 919 | &mms->uart_irq_orgate, TYPE_OR_IRQ); |
8cf68ed9 PM |
920 | object_property_set_int(OBJECT(&mms->uart_irq_orgate), "num-lines", |
921 | 2 * ARRAY_SIZE(mms->uart), | |
5aff1c07 | 922 | &error_fatal); |
ce189ab2 | 923 | qdev_realize(DEVICE(&mms->uart_irq_orgate), NULL, &error_fatal); |
5aff1c07 | 924 | qdev_connect_gpio_out(DEVICE(&mms->uart_irq_orgate), 0, |
8b4b5c23 | 925 | get_sse_irq_in(mms, mmc->uart_overflow_irq)); |
5aff1c07 PM |
926 | |
927 | /* Most of the devices in the FPGA are behind Peripheral Protection | |
928 | * Controllers. The required order for initializing things is: | |
929 | * + initialize the PPC | |
930 | * + initialize, configure and realize downstream devices | |
931 | * + connect downstream device MemoryRegions to the PPC | |
932 | * + realize the PPC | |
933 | * + map the PPC's MemoryRegions to the places in the address map | |
934 | * where the downstream devices should appear | |
935 | * + wire up the PPC's control lines to the IoTKit object | |
936 | */ | |
937 | ||
ef29e382 | 938 | const PPCInfo an505_ppcs[] = { { |
5aff1c07 PM |
939 | .name = "apb_ppcexp0", |
940 | .ports = { | |
4fec32db PM |
941 | { "ssram-0-mpc", make_mpc, &mms->mpc[0], 0x58007000, 0x1000 }, |
942 | { "ssram-1-mpc", make_mpc, &mms->mpc[1], 0x58008000, 0x1000 }, | |
943 | { "ssram-2-mpc", make_mpc, &mms->mpc[2], 0x58009000, 0x1000 }, | |
5aff1c07 PM |
944 | }, |
945 | }, { | |
946 | .name = "apb_ppcexp1", | |
947 | .ports = { | |
b22c4e8b PM |
948 | { "spi0", make_spi, &mms->spi[0], 0x40205000, 0x1000, { 51 } }, |
949 | { "spi1", make_spi, &mms->spi[1], 0x40206000, 0x1000, { 52 } }, | |
950 | { "spi2", make_spi, &mms->spi[2], 0x40209000, 0x1000, { 53 } }, | |
951 | { "spi3", make_spi, &mms->spi[3], 0x4020a000, 0x1000, { 54 } }, | |
952 | { "spi4", make_spi, &mms->spi[4], 0x4020b000, 0x1000, { 55 } }, | |
953 | { "uart0", make_uart, &mms->uart[0], 0x40200000, 0x1000, { 32, 33, 42 } }, | |
954 | { "uart1", make_uart, &mms->uart[1], 0x40201000, 0x1000, { 34, 35, 43 } }, | |
955 | { "uart2", make_uart, &mms->uart[2], 0x40202000, 0x1000, { 36, 37, 44 } }, | |
956 | { "uart3", make_uart, &mms->uart[3], 0x40203000, 0x1000, { 38, 39, 45 } }, | |
957 | { "uart4", make_uart, &mms->uart[4], 0x40204000, 0x1000, { 40, 41, 46 } }, | |
68e57951 PM |
958 | { "i2c0", make_i2c, &mms->i2c[0], 0x40207000, 0x1000, {}, |
959 | { .i2c_internal = true /* touchscreen */ } }, | |
960 | { "i2c1", make_i2c, &mms->i2c[1], 0x40208000, 0x1000, {}, | |
961 | { .i2c_internal = true /* audio conf */ } }, | |
962 | { "i2c2", make_i2c, &mms->i2c[2], 0x4020c000, 0x1000, {}, | |
963 | { .i2c_internal = false /* shield 0 */ } }, | |
964 | { "i2c3", make_i2c, &mms->i2c[3], 0x4020d000, 0x1000, {}, | |
965 | { .i2c_internal = false /* shield 1 */ } }, | |
5aff1c07 PM |
966 | }, |
967 | }, { | |
968 | .name = "apb_ppcexp2", | |
969 | .ports = { | |
970 | { "scc", make_scc, &mms->scc, 0x40300000, 0x1000 }, | |
971 | { "i2s-audio", make_unimp_dev, &mms->i2s_audio, | |
972 | 0x40301000, 0x1000 }, | |
973 | { "fpgaio", make_fpgaio, &mms->fpgaio, 0x40302000, 0x1000 }, | |
974 | }, | |
975 | }, { | |
976 | .name = "ahb_ppcexp0", | |
977 | .ports = { | |
978 | { "gfx", make_unimp_dev, &mms->gfx, 0x41000000, 0x140000 }, | |
979 | { "gpio0", make_unimp_dev, &mms->gpio[0], 0x40100000, 0x1000 }, | |
980 | { "gpio1", make_unimp_dev, &mms->gpio[1], 0x40101000, 0x1000 }, | |
981 | { "gpio2", make_unimp_dev, &mms->gpio[2], 0x40102000, 0x1000 }, | |
982 | { "gpio3", make_unimp_dev, &mms->gpio[3], 0x40103000, 0x1000 }, | |
b22c4e8b | 983 | { "eth", make_eth_dev, NULL, 0x42000000, 0x100000, { 48 } }, |
5aff1c07 PM |
984 | }, |
985 | }, { | |
986 | .name = "ahb_ppcexp1", | |
987 | .ports = { | |
b22c4e8b PM |
988 | { "dma0", make_dma, &mms->dma[0], 0x40110000, 0x1000, { 58, 56, 57 } }, |
989 | { "dma1", make_dma, &mms->dma[1], 0x40111000, 0x1000, { 61, 59, 60 } }, | |
990 | { "dma2", make_dma, &mms->dma[2], 0x40112000, 0x1000, { 64, 62, 63 } }, | |
991 | { "dma3", make_dma, &mms->dma[3], 0x40113000, 0x1000, { 67, 65, 66 } }, | |
5aff1c07 PM |
992 | }, |
993 | }, | |
994 | }; | |
995 | ||
25ff112a PM |
996 | const PPCInfo an524_ppcs[] = { { |
997 | .name = "apb_ppcexp0", | |
998 | .ports = { | |
999 | { "bram-mpc", make_mpc, &mms->mpc[0], 0x58007000, 0x1000 }, | |
1000 | { "qspi-mpc", make_mpc, &mms->mpc[1], 0x58008000, 0x1000 }, | |
1001 | { "ddr-mpc", make_mpc, &mms->mpc[2], 0x58009000, 0x1000 }, | |
1002 | }, | |
1003 | }, { | |
1004 | .name = "apb_ppcexp1", | |
1005 | .ports = { | |
68e57951 PM |
1006 | { "i2c0", make_i2c, &mms->i2c[0], 0x41200000, 0x1000, {}, |
1007 | { .i2c_internal = true /* touchscreen */ } }, | |
1008 | { "i2c1", make_i2c, &mms->i2c[1], 0x41201000, 0x1000, {}, | |
1009 | { .i2c_internal = true /* audio conf */ } }, | |
25ff112a PM |
1010 | { "spi0", make_spi, &mms->spi[0], 0x41202000, 0x1000, { 52 } }, |
1011 | { "spi1", make_spi, &mms->spi[1], 0x41203000, 0x1000, { 53 } }, | |
1012 | { "spi2", make_spi, &mms->spi[2], 0x41204000, 0x1000, { 54 } }, | |
68e57951 PM |
1013 | { "i2c2", make_i2c, &mms->i2c[2], 0x41205000, 0x1000, {}, |
1014 | { .i2c_internal = false /* shield 0 */ } }, | |
1015 | { "i2c3", make_i2c, &mms->i2c[3], 0x41206000, 0x1000, {}, | |
1016 | { .i2c_internal = false /* shield 1 */ } }, | |
25ff112a | 1017 | { /* port 7 reserved */ }, |
68e57951 PM |
1018 | { "i2c4", make_i2c, &mms->i2c[4], 0x41208000, 0x1000, {}, |
1019 | { .i2c_internal = true /* DDR4 EEPROM */ } }, | |
25ff112a PM |
1020 | }, |
1021 | }, { | |
1022 | .name = "apb_ppcexp2", | |
1023 | .ports = { | |
1024 | { "scc", make_scc, &mms->scc, 0x41300000, 0x1000 }, | |
1025 | { "i2s-audio", make_unimp_dev, &mms->i2s_audio, | |
1026 | 0x41301000, 0x1000 }, | |
1027 | { "fpgaio", make_fpgaio, &mms->fpgaio, 0x41302000, 0x1000 }, | |
1028 | { "uart0", make_uart, &mms->uart[0], 0x41303000, 0x1000, { 32, 33, 42 } }, | |
1029 | { "uart1", make_uart, &mms->uart[1], 0x41304000, 0x1000, { 34, 35, 43 } }, | |
1030 | { "uart2", make_uart, &mms->uart[2], 0x41305000, 0x1000, { 36, 37, 44 } }, | |
1031 | { "uart3", make_uart, &mms->uart[3], 0x41306000, 0x1000, { 38, 39, 45 } }, | |
1032 | { "uart4", make_uart, &mms->uart[4], 0x41307000, 0x1000, { 40, 41, 46 } }, | |
1033 | { "uart5", make_uart, &mms->uart[5], 0x41308000, 0x1000, { 124, 125, 126 } }, | |
1034 | ||
1035 | { /* port 9 reserved */ }, | |
1036 | { "clcd", make_unimp_dev, &mms->cldc, 0x4130a000, 0x1000 }, | |
41745d20 | 1037 | { "rtc", make_rtc, &mms->rtc, 0x4130b000, 0x1000 }, |
25ff112a PM |
1038 | }, |
1039 | }, { | |
1040 | .name = "ahb_ppcexp0", | |
1041 | .ports = { | |
1042 | { "gpio0", make_unimp_dev, &mms->gpio[0], 0x41100000, 0x1000 }, | |
1043 | { "gpio1", make_unimp_dev, &mms->gpio[1], 0x41101000, 0x1000 }, | |
1044 | { "gpio2", make_unimp_dev, &mms->gpio[2], 0x41102000, 0x1000 }, | |
1045 | { "gpio3", make_unimp_dev, &mms->gpio[3], 0x41103000, 0x1000 }, | |
a9597753 | 1046 | { "eth-usb", make_eth_usb, NULL, 0x41400000, 0x200000, { 48 } }, |
25ff112a PM |
1047 | }, |
1048 | }, | |
1049 | }; | |
1050 | ||
eb09d533 PM |
1051 | const PPCInfo an547_ppcs[] = { { |
1052 | .name = "apb_ppcexp0", | |
1053 | .ports = { | |
1054 | { "ssram-mpc", make_mpc, &mms->mpc[0], 0x57000000, 0x1000 }, | |
1055 | { "qspi-mpc", make_mpc, &mms->mpc[1], 0x57001000, 0x1000 }, | |
1056 | { "ddr-mpc", make_mpc, &mms->mpc[2], 0x57002000, 0x1000 }, | |
1057 | }, | |
1058 | }, { | |
1059 | .name = "apb_ppcexp1", | |
1060 | .ports = { | |
68e57951 PM |
1061 | { "i2c0", make_i2c, &mms->i2c[0], 0x49200000, 0x1000, {}, |
1062 | { .i2c_internal = true /* touchscreen */ } }, | |
1063 | { "i2c1", make_i2c, &mms->i2c[1], 0x49201000, 0x1000, {}, | |
1064 | { .i2c_internal = true /* audio conf */ } }, | |
eb09d533 PM |
1065 | { "spi0", make_spi, &mms->spi[0], 0x49202000, 0x1000, { 53 } }, |
1066 | { "spi1", make_spi, &mms->spi[1], 0x49203000, 0x1000, { 54 } }, | |
1067 | { "spi2", make_spi, &mms->spi[2], 0x49204000, 0x1000, { 55 } }, | |
68e57951 PM |
1068 | { "i2c2", make_i2c, &mms->i2c[2], 0x49205000, 0x1000, {}, |
1069 | { .i2c_internal = false /* shield 0 */ } }, | |
1070 | { "i2c3", make_i2c, &mms->i2c[3], 0x49206000, 0x1000, {}, | |
1071 | { .i2c_internal = false /* shield 1 */ } }, | |
eb09d533 | 1072 | { /* port 7 reserved */ }, |
68e57951 PM |
1073 | { "i2c4", make_i2c, &mms->i2c[4], 0x49208000, 0x1000, {}, |
1074 | { .i2c_internal = true /* DDR4 EEPROM */ } }, | |
eb09d533 PM |
1075 | }, |
1076 | }, { | |
1077 | .name = "apb_ppcexp2", | |
1078 | .ports = { | |
1079 | { "scc", make_scc, &mms->scc, 0x49300000, 0x1000 }, | |
1080 | { "i2s-audio", make_unimp_dev, &mms->i2s_audio, 0x49301000, 0x1000 }, | |
1081 | { "fpgaio", make_fpgaio, &mms->fpgaio, 0x49302000, 0x1000 }, | |
1082 | { "uart0", make_uart, &mms->uart[0], 0x49303000, 0x1000, { 33, 34, 43 } }, | |
1083 | { "uart1", make_uart, &mms->uart[1], 0x49304000, 0x1000, { 35, 36, 44 } }, | |
1084 | { "uart2", make_uart, &mms->uart[2], 0x49305000, 0x1000, { 37, 38, 45 } }, | |
1085 | { "uart3", make_uart, &mms->uart[3], 0x49306000, 0x1000, { 39, 40, 46 } }, | |
1086 | { "uart4", make_uart, &mms->uart[4], 0x49307000, 0x1000, { 41, 42, 47 } }, | |
1087 | { "uart5", make_uart, &mms->uart[5], 0x49308000, 0x1000, { 125, 126, 127 } }, | |
1088 | ||
1089 | { /* port 9 reserved */ }, | |
1090 | { "clcd", make_unimp_dev, &mms->cldc, 0x4930a000, 0x1000 }, | |
1091 | { "rtc", make_rtc, &mms->rtc, 0x4930b000, 0x1000 }, | |
1092 | }, | |
1093 | }, { | |
1094 | .name = "ahb_ppcexp0", | |
1095 | .ports = { | |
1096 | { "gpio0", make_unimp_dev, &mms->gpio[0], 0x41100000, 0x1000 }, | |
1097 | { "gpio1", make_unimp_dev, &mms->gpio[1], 0x41101000, 0x1000 }, | |
1098 | { "gpio2", make_unimp_dev, &mms->gpio[2], 0x41102000, 0x1000 }, | |
1099 | { "gpio3", make_unimp_dev, &mms->gpio[3], 0x41103000, 0x1000 }, | |
cc3b66ac JB |
1100 | { /* port 4 USER AHB interface 0 */ }, |
1101 | { /* port 5 USER AHB interface 1 */ }, | |
1102 | { /* port 6 USER AHB interface 2 */ }, | |
1103 | { /* port 7 USER AHB interface 3 */ }, | |
eb09d533 PM |
1104 | { "eth-usb", make_eth_usb, NULL, 0x41400000, 0x200000, { 49 } }, |
1105 | }, | |
1106 | }, | |
1107 | }; | |
1108 | ||
ef29e382 PM |
1109 | switch (mmc->fpga_type) { |
1110 | case FPGA_AN505: | |
1111 | case FPGA_AN521: | |
1112 | ppcs = an505_ppcs; | |
1113 | num_ppcs = ARRAY_SIZE(an505_ppcs); | |
1114 | break; | |
25ff112a PM |
1115 | case FPGA_AN524: |
1116 | ppcs = an524_ppcs; | |
1117 | num_ppcs = ARRAY_SIZE(an524_ppcs); | |
1118 | break; | |
eb09d533 PM |
1119 | case FPGA_AN547: |
1120 | ppcs = an547_ppcs; | |
1121 | num_ppcs = ARRAY_SIZE(an547_ppcs); | |
1122 | break; | |
ef29e382 PM |
1123 | default: |
1124 | g_assert_not_reached(); | |
1125 | } | |
1126 | ||
1127 | for (i = 0; i < num_ppcs; i++) { | |
5aff1c07 PM |
1128 | const PPCInfo *ppcinfo = &ppcs[i]; |
1129 | TZPPC *ppc = &mms->ppc[i]; | |
1130 | DeviceState *ppcdev; | |
1131 | int port; | |
1132 | char *gpioname; | |
1133 | ||
0074fce6 MA |
1134 | object_initialize_child(OBJECT(machine), ppcinfo->name, ppc, |
1135 | TYPE_TZ_PPC); | |
5aff1c07 PM |
1136 | ppcdev = DEVICE(ppc); |
1137 | ||
1138 | for (port = 0; port < TZ_NUM_PORTS; port++) { | |
1139 | const PPCPortInfo *pinfo = &ppcinfo->ports[port]; | |
1140 | MemoryRegion *mr; | |
1141 | char *portname; | |
1142 | ||
1143 | if (!pinfo->devfn) { | |
1144 | continue; | |
1145 | } | |
1146 | ||
42418279 | 1147 | mr = pinfo->devfn(mms, pinfo->opaque, pinfo->name, pinfo->size, |
e6f79acd | 1148 | pinfo->irqs, &pinfo->extradata); |
5aff1c07 | 1149 | portname = g_strdup_printf("port[%d]", port); |
5325cc34 MA |
1150 | object_property_set_link(OBJECT(ppc), portname, OBJECT(mr), |
1151 | &error_fatal); | |
5aff1c07 PM |
1152 | g_free(portname); |
1153 | } | |
1154 | ||
0074fce6 | 1155 | sysbus_realize(SYS_BUS_DEVICE(ppc), &error_fatal); |
5aff1c07 PM |
1156 | |
1157 | for (port = 0; port < TZ_NUM_PORTS; port++) { | |
1158 | const PPCPortInfo *pinfo = &ppcinfo->ports[port]; | |
1159 | ||
1160 | if (!pinfo->devfn) { | |
1161 | continue; | |
1162 | } | |
1163 | sysbus_mmio_map(SYS_BUS_DEVICE(ppc), port, pinfo->addr); | |
1164 | ||
1165 | gpioname = g_strdup_printf("%s_nonsec", ppcinfo->name); | |
1166 | qdev_connect_gpio_out_named(iotkitdev, gpioname, port, | |
1167 | qdev_get_gpio_in_named(ppcdev, | |
1168 | "cfg_nonsec", | |
1169 | port)); | |
1170 | g_free(gpioname); | |
1171 | gpioname = g_strdup_printf("%s_ap", ppcinfo->name); | |
1172 | qdev_connect_gpio_out_named(iotkitdev, gpioname, port, | |
1173 | qdev_get_gpio_in_named(ppcdev, | |
1174 | "cfg_ap", port)); | |
1175 | g_free(gpioname); | |
1176 | } | |
1177 | ||
1178 | gpioname = g_strdup_printf("%s_irq_enable", ppcinfo->name); | |
1179 | qdev_connect_gpio_out_named(iotkitdev, gpioname, 0, | |
1180 | qdev_get_gpio_in_named(ppcdev, | |
1181 | "irq_enable", 0)); | |
1182 | g_free(gpioname); | |
1183 | gpioname = g_strdup_printf("%s_irq_clear", ppcinfo->name); | |
1184 | qdev_connect_gpio_out_named(iotkitdev, gpioname, 0, | |
1185 | qdev_get_gpio_in_named(ppcdev, | |
1186 | "irq_clear", 0)); | |
1187 | g_free(gpioname); | |
1188 | gpioname = g_strdup_printf("%s_irq_status", ppcinfo->name); | |
1189 | qdev_connect_gpio_out_named(ppcdev, "irq", 0, | |
1190 | qdev_get_gpio_in_named(iotkitdev, | |
1191 | gpioname, 0)); | |
1192 | g_free(gpioname); | |
1193 | ||
1194 | qdev_connect_gpio_out(dev_splitter, i, | |
1195 | qdev_get_gpio_in_named(ppcdev, | |
1196 | "cfg_sec_resp", 0)); | |
1197 | } | |
1198 | ||
5aff1c07 PM |
1199 | create_unimplemented_device("FPGA NS PC", 0x48007000, 0x1000); |
1200 | ||
eb09d533 PM |
1201 | if (mmc->fpga_type == FPGA_AN547) { |
1202 | create_unimplemented_device("U55 timing adapter 0", 0x48102000, 0x1000); | |
1203 | create_unimplemented_device("U55 timing adapter 1", 0x48103000, 0x1000); | |
1204 | } | |
1205 | ||
4fec32db PM |
1206 | create_non_mpc_ram(mms); |
1207 | ||
f1dfab0d PM |
1208 | if (mmc->fpga_type == FPGA_AN524) { |
1209 | /* | |
1210 | * Connect the line from the SCC so that we can remap when the | |
1211 | * guest updates that register. | |
1212 | */ | |
1213 | mms->remap_irq = qemu_allocate_irq(remap_irq_fn, mms, 0); | |
1214 | qdev_connect_gpio_out_named(DEVICE(&mms->scc), "remap", 0, | |
1215 | mms->remap_irq); | |
1216 | } | |
1217 | ||
a113aef9 | 1218 | armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, |
761c532a | 1219 | 0, boot_ram_size(mms)); |
5aff1c07 PM |
1220 | } |
1221 | ||
28e56f05 PM |
1222 | static void mps2_tz_idau_check(IDAUInterface *ii, uint32_t address, |
1223 | int *iregion, bool *exempt, bool *ns, bool *nsc) | |
1224 | { | |
1225 | /* | |
1226 | * The MPS2 TZ FPGA images have IDAUs in them which are connected to | |
673d8215 | 1227 | * the Master Security Controllers. These have the same logic as |
28e56f05 PM |
1228 | * is used by the IoTKit for the IDAU connected to the CPU, except |
1229 | * that MSCs don't care about the NSC attribute. | |
1230 | */ | |
1231 | int region = extract32(address, 28, 4); | |
1232 | ||
1233 | *ns = !(region & 1); | |
1234 | *nsc = false; | |
1235 | /* 0xe0000000..0xe00fffff and 0xf0000000..0xf00fffff are exempt */ | |
1236 | *exempt = (address & 0xeff00000) == 0xe0000000; | |
1237 | *iregion = region; | |
1238 | } | |
1239 | ||
f1dfab0d PM |
1240 | static char *mps2_get_remap(Object *obj, Error **errp) |
1241 | { | |
1242 | MPS2TZMachineState *mms = MPS2TZ_MACHINE(obj); | |
1243 | const char *val = mms->remap ? "QSPI" : "BRAM"; | |
1244 | return g_strdup(val); | |
1245 | } | |
1246 | ||
1247 | static void mps2_set_remap(Object *obj, const char *value, Error **errp) | |
1248 | { | |
1249 | MPS2TZMachineState *mms = MPS2TZ_MACHINE(obj); | |
1250 | ||
1251 | if (!strcmp(value, "BRAM")) { | |
1252 | mms->remap = false; | |
1253 | } else if (!strcmp(value, "QSPI")) { | |
1254 | mms->remap = true; | |
1255 | } else { | |
1256 | error_setg(errp, "Invalid remap value"); | |
1257 | error_append_hint(errp, "Valid values are BRAM and QSPI.\n"); | |
1258 | } | |
1259 | } | |
1260 | ||
7966d70f | 1261 | static void mps2_machine_reset(MachineState *machine, ShutdownCause reason) |
f1dfab0d PM |
1262 | { |
1263 | MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine); | |
1264 | ||
1265 | /* | |
1266 | * Set the initial memory mapping before triggering the reset of | |
1267 | * the rest of the system, so that the guest image loader and CPU | |
1268 | * reset see the correct mapping. | |
1269 | */ | |
1270 | remap_memory(mms, mms->remap); | |
7966d70f | 1271 | qemu_devices_reset(reason); |
f1dfab0d PM |
1272 | } |
1273 | ||
5aff1c07 PM |
1274 | static void mps2tz_class_init(ObjectClass *oc, void *data) |
1275 | { | |
1276 | MachineClass *mc = MACHINE_CLASS(oc); | |
28e56f05 | 1277 | IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(oc); |
e73b8bb8 | 1278 | MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc); |
5aff1c07 PM |
1279 | |
1280 | mc->init = mps2tz_common_init; | |
f1dfab0d | 1281 | mc->reset = mps2_machine_reset; |
28e56f05 | 1282 | iic->check = mps2_tz_idau_check; |
e73b8bb8 PM |
1283 | |
1284 | /* Most machines leave these at the SSE defaults */ | |
1285 | mmc->cpu0_mpu_ns = MPU_REGION_DEFAULT; | |
1286 | mmc->cpu0_mpu_s = MPU_REGION_DEFAULT; | |
1287 | mmc->cpu1_mpu_ns = MPU_REGION_DEFAULT; | |
1288 | mmc->cpu1_mpu_s = MPU_REGION_DEFAULT; | |
18a8c3b3 PM |
1289 | } |
1290 | ||
1291 | static void mps2tz_set_default_ram_info(MPS2TZMachineClass *mmc) | |
1292 | { | |
1293 | /* | |
1294 | * Set mc->default_ram_size and default_ram_id from the | |
1295 | * information in mmc->raminfo. | |
1296 | */ | |
1297 | MachineClass *mc = MACHINE_CLASS(mmc); | |
1298 | const RAMInfo *p; | |
1299 | ||
1300 | for (p = mmc->raminfo; p->name; p++) { | |
1301 | if (p->mrindex < 0) { | |
1302 | /* Found the entry for "system memory" */ | |
1303 | mc->default_ram_size = p->size; | |
1304 | mc->default_ram_id = p->name; | |
1305 | return; | |
1306 | } | |
1307 | } | |
1308 | g_assert_not_reached(); | |
5aff1c07 PM |
1309 | } |
1310 | ||
1311 | static void mps2tz_an505_class_init(ObjectClass *oc, void *data) | |
1312 | { | |
1313 | MachineClass *mc = MACHINE_CLASS(oc); | |
1314 | MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc); | |
3e71f4a7 GS |
1315 | static const char * const valid_cpu_types[] = { |
1316 | ARM_CPU_TYPE_NAME("cortex-m33"), | |
1317 | NULL | |
1318 | }; | |
5aff1c07 PM |
1319 | |
1320 | mc->desc = "ARM MPS2 with AN505 FPGA image for Cortex-M33"; | |
23f92423 PM |
1321 | mc->default_cpus = 1; |
1322 | mc->min_cpus = mc->default_cpus; | |
1323 | mc->max_cpus = mc->default_cpus; | |
5aff1c07 PM |
1324 | mmc->fpga_type = FPGA_AN505; |
1325 | mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33"); | |
3e71f4a7 | 1326 | mc->valid_cpu_types = valid_cpu_types; |
cb159db9 | 1327 | mmc->scc_id = 0x41045050; |
a3e24690 | 1328 | mmc->sysclk_frq = 20 * 1000 * 1000; /* 20MHz */ |
ad28ca7e | 1329 | mmc->apb_periph_frq = mmc->sysclk_frq; |
f7c71b21 PM |
1330 | mmc->oscclk = an505_oscclk; |
1331 | mmc->len_oscclk = ARRAY_SIZE(an505_oscclk); | |
de77e8f4 PM |
1332 | mmc->fpgaio_num_leds = 2; |
1333 | mmc->fpgaio_has_switches = false; | |
39901aea | 1334 | mmc->fpgaio_has_dbgctrl = false; |
11e1d412 | 1335 | mmc->numirq = 92; |
8b4b5c23 | 1336 | mmc->uart_overflow_irq = 47; |
9fe1ea11 | 1337 | mmc->init_svtor = 0x10000000; |
902b28ae | 1338 | mmc->sram_addr_width = 15; |
4fec32db | 1339 | mmc->raminfo = an505_raminfo; |
23f92423 | 1340 | mmc->armsse_type = TYPE_IOTKIT; |
2f12dca0 | 1341 | mmc->boot_ram_size = 0; |
18a8c3b3 | 1342 | mps2tz_set_default_ram_info(mmc); |
23f92423 PM |
1343 | } |
1344 | ||
1345 | static void mps2tz_an521_class_init(ObjectClass *oc, void *data) | |
1346 | { | |
1347 | MachineClass *mc = MACHINE_CLASS(oc); | |
1348 | MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc); | |
3e71f4a7 GS |
1349 | static const char * const valid_cpu_types[] = { |
1350 | ARM_CPU_TYPE_NAME("cortex-m33"), | |
1351 | NULL | |
1352 | }; | |
23f92423 PM |
1353 | |
1354 | mc->desc = "ARM MPS2 with AN521 FPGA image for dual Cortex-M33"; | |
1355 | mc->default_cpus = 2; | |
1356 | mc->min_cpus = mc->default_cpus; | |
1357 | mc->max_cpus = mc->default_cpus; | |
1358 | mmc->fpga_type = FPGA_AN521; | |
1359 | mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33"); | |
3e71f4a7 | 1360 | mc->valid_cpu_types = valid_cpu_types; |
23f92423 | 1361 | mmc->scc_id = 0x41045210; |
a3e24690 | 1362 | mmc->sysclk_frq = 20 * 1000 * 1000; /* 20MHz */ |
ad28ca7e | 1363 | mmc->apb_periph_frq = mmc->sysclk_frq; |
f7c71b21 PM |
1364 | mmc->oscclk = an505_oscclk; /* AN521 is the same as AN505 here */ |
1365 | mmc->len_oscclk = ARRAY_SIZE(an505_oscclk); | |
de77e8f4 PM |
1366 | mmc->fpgaio_num_leds = 2; |
1367 | mmc->fpgaio_has_switches = false; | |
39901aea | 1368 | mmc->fpgaio_has_dbgctrl = false; |
11e1d412 | 1369 | mmc->numirq = 92; |
8b4b5c23 | 1370 | mmc->uart_overflow_irq = 47; |
9fe1ea11 | 1371 | mmc->init_svtor = 0x10000000; |
902b28ae | 1372 | mmc->sram_addr_width = 15; |
4fec32db | 1373 | mmc->raminfo = an505_raminfo; /* AN521 is the same as AN505 here */ |
23f92423 | 1374 | mmc->armsse_type = TYPE_SSE200; |
2f12dca0 | 1375 | mmc->boot_ram_size = 0; |
18a8c3b3 | 1376 | mps2tz_set_default_ram_info(mmc); |
5aff1c07 PM |
1377 | } |
1378 | ||
25ff112a PM |
1379 | static void mps3tz_an524_class_init(ObjectClass *oc, void *data) |
1380 | { | |
1381 | MachineClass *mc = MACHINE_CLASS(oc); | |
1382 | MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc); | |
3e71f4a7 GS |
1383 | static const char * const valid_cpu_types[] = { |
1384 | ARM_CPU_TYPE_NAME("cortex-m33"), | |
1385 | NULL | |
1386 | }; | |
25ff112a PM |
1387 | |
1388 | mc->desc = "ARM MPS3 with AN524 FPGA image for dual Cortex-M33"; | |
1389 | mc->default_cpus = 2; | |
1390 | mc->min_cpus = mc->default_cpus; | |
1391 | mc->max_cpus = mc->default_cpus; | |
1392 | mmc->fpga_type = FPGA_AN524; | |
1393 | mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33"); | |
3e71f4a7 | 1394 | mc->valid_cpu_types = valid_cpu_types; |
25ff112a PM |
1395 | mmc->scc_id = 0x41045240; |
1396 | mmc->sysclk_frq = 32 * 1000 * 1000; /* 32MHz */ | |
ad28ca7e | 1397 | mmc->apb_periph_frq = mmc->sysclk_frq; |
25ff112a PM |
1398 | mmc->oscclk = an524_oscclk; |
1399 | mmc->len_oscclk = ARRAY_SIZE(an524_oscclk); | |
1400 | mmc->fpgaio_num_leds = 10; | |
1401 | mmc->fpgaio_has_switches = true; | |
39901aea | 1402 | mmc->fpgaio_has_dbgctrl = false; |
25ff112a | 1403 | mmc->numirq = 95; |
8b4b5c23 | 1404 | mmc->uart_overflow_irq = 47; |
9fe1ea11 | 1405 | mmc->init_svtor = 0x10000000; |
902b28ae | 1406 | mmc->sram_addr_width = 15; |
25ff112a PM |
1407 | mmc->raminfo = an524_raminfo; |
1408 | mmc->armsse_type = TYPE_SSE200; | |
2f12dca0 | 1409 | mmc->boot_ram_size = 0; |
25ff112a | 1410 | mps2tz_set_default_ram_info(mmc); |
f1dfab0d PM |
1411 | |
1412 | object_class_property_add_str(oc, "remap", mps2_get_remap, mps2_set_remap); | |
1413 | object_class_property_set_description(oc, "remap", | |
1414 | "Set memory mapping. Valid values " | |
1415 | "are BRAM (default) and QSPI."); | |
25ff112a PM |
1416 | } |
1417 | ||
eb09d533 PM |
1418 | static void mps3tz_an547_class_init(ObjectClass *oc, void *data) |
1419 | { | |
1420 | MachineClass *mc = MACHINE_CLASS(oc); | |
1421 | MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc); | |
3e71f4a7 GS |
1422 | static const char * const valid_cpu_types[] = { |
1423 | ARM_CPU_TYPE_NAME("cortex-m55"), | |
1424 | NULL | |
1425 | }; | |
eb09d533 PM |
1426 | |
1427 | mc->desc = "ARM MPS3 with AN547 FPGA image for Cortex-M55"; | |
1428 | mc->default_cpus = 1; | |
1429 | mc->min_cpus = mc->default_cpus; | |
1430 | mc->max_cpus = mc->default_cpus; | |
1431 | mmc->fpga_type = FPGA_AN547; | |
1432 | mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m55"); | |
3e71f4a7 | 1433 | mc->valid_cpu_types = valid_cpu_types; |
eb09d533 PM |
1434 | mmc->scc_id = 0x41055470; |
1435 | mmc->sysclk_frq = 32 * 1000 * 1000; /* 32MHz */ | |
1436 | mmc->apb_periph_frq = 25 * 1000 * 1000; /* 25MHz */ | |
1437 | mmc->oscclk = an524_oscclk; /* same as AN524 */ | |
1438 | mmc->len_oscclk = ARRAY_SIZE(an524_oscclk); | |
1439 | mmc->fpgaio_num_leds = 10; | |
1440 | mmc->fpgaio_has_switches = true; | |
1441 | mmc->fpgaio_has_dbgctrl = true; | |
1442 | mmc->numirq = 96; | |
1443 | mmc->uart_overflow_irq = 48; | |
1444 | mmc->init_svtor = 0x00000000; | |
e73b8bb8 | 1445 | mmc->cpu0_mpu_s = mmc->cpu0_mpu_ns = 16; |
902b28ae | 1446 | mmc->sram_addr_width = 21; |
eb09d533 PM |
1447 | mmc->raminfo = an547_raminfo; |
1448 | mmc->armsse_type = TYPE_SSE300; | |
2f12dca0 | 1449 | mmc->boot_ram_size = 512 * KiB; |
eb09d533 PM |
1450 | mps2tz_set_default_ram_info(mmc); |
1451 | } | |
1452 | ||
5aff1c07 PM |
1453 | static const TypeInfo mps2tz_info = { |
1454 | .name = TYPE_MPS2TZ_MACHINE, | |
1455 | .parent = TYPE_MACHINE, | |
1456 | .abstract = true, | |
1457 | .instance_size = sizeof(MPS2TZMachineState), | |
1458 | .class_size = sizeof(MPS2TZMachineClass), | |
1459 | .class_init = mps2tz_class_init, | |
28e56f05 PM |
1460 | .interfaces = (InterfaceInfo[]) { |
1461 | { TYPE_IDAU_INTERFACE }, | |
1462 | { } | |
1463 | }, | |
5aff1c07 PM |
1464 | }; |
1465 | ||
1466 | static const TypeInfo mps2tz_an505_info = { | |
1467 | .name = TYPE_MPS2TZ_AN505_MACHINE, | |
1468 | .parent = TYPE_MPS2TZ_MACHINE, | |
1469 | .class_init = mps2tz_an505_class_init, | |
1470 | }; | |
1471 | ||
23f92423 PM |
1472 | static const TypeInfo mps2tz_an521_info = { |
1473 | .name = TYPE_MPS2TZ_AN521_MACHINE, | |
1474 | .parent = TYPE_MPS2TZ_MACHINE, | |
1475 | .class_init = mps2tz_an521_class_init, | |
1476 | }; | |
1477 | ||
25ff112a PM |
1478 | static const TypeInfo mps3tz_an524_info = { |
1479 | .name = TYPE_MPS3TZ_AN524_MACHINE, | |
1480 | .parent = TYPE_MPS2TZ_MACHINE, | |
1481 | .class_init = mps3tz_an524_class_init, | |
1482 | }; | |
1483 | ||
eb09d533 PM |
1484 | static const TypeInfo mps3tz_an547_info = { |
1485 | .name = TYPE_MPS3TZ_AN547_MACHINE, | |
1486 | .parent = TYPE_MPS2TZ_MACHINE, | |
1487 | .class_init = mps3tz_an547_class_init, | |
1488 | }; | |
1489 | ||
5aff1c07 PM |
1490 | static void mps2tz_machine_init(void) |
1491 | { | |
1492 | type_register_static(&mps2tz_info); | |
1493 | type_register_static(&mps2tz_an505_info); | |
23f92423 | 1494 | type_register_static(&mps2tz_an521_info); |
25ff112a | 1495 | type_register_static(&mps3tz_an524_info); |
eb09d533 | 1496 | type_register_static(&mps3tz_an547_info); |
5aff1c07 PM |
1497 | } |
1498 | ||
1499 | type_init(mps2tz_machine_init); |