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