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