]>
Commit | Line | Data |
---|---|---|
2eb5578b PM |
1 | /* |
2 | * ARM V2M MPS2 board emulation. | |
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 | * We model the following FPGA images: | |
17 | * "mps2-an385" -- Cortex-M3 as documented in ARM Application Note AN385 | |
897d2726 | 18 | * "mps2-an386" -- Cortex-M4 as documented in ARM Application Note AN386 |
6d4811c4 | 19 | * "mps2-an500" -- Cortex-M7 as documented in ARM Application Note AN500 |
2eb5578b PM |
20 | * "mps2-an511" -- Cortex-M3 'DesignStart' as documented in AN511 |
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/cortex-m-prototyping-system | |
25 | */ | |
26 | ||
27 | #include "qemu/osdep.h" | |
eba59997 | 28 | #include "qemu/units.h" |
68637c3a | 29 | #include "qemu/cutils.h" |
2eb5578b PM |
30 | #include "qapi/error.h" |
31 | #include "qemu/error-report.h" | |
12ec8bd5 | 32 | #include "hw/arm/boot.h" |
2eb5578b | 33 | #include "hw/arm/armv7m.h" |
977a15f4 | 34 | #include "hw/or-irq.h" |
2eb5578b PM |
35 | #include "hw/boards.h" |
36 | #include "exec/address-spaces.h" | |
977a15f4 | 37 | #include "sysemu/sysemu.h" |
2eb5578b | 38 | #include "hw/misc/unimp.h" |
977a15f4 | 39 | #include "hw/char/cmsdk-apb-uart.h" |
3d53904a | 40 | #include "hw/timer/cmsdk-apb-timer.h" |
595c786b | 41 | #include "hw/timer/cmsdk-apb-dualtimer.h" |
6dbdf4ec | 42 | #include "hw/misc/mps2-scc.h" |
adbb23b6 | 43 | #include "hw/misc/mps2-fpgaio.h" |
58f7f3c4 | 44 | #include "hw/ssi/pl022.h" |
ada45de9 | 45 | #include "hw/i2c/arm_sbcon_i2c.h" |
66b03dce | 46 | #include "hw/net/lan9118.h" |
35873939 | 47 | #include "net/net.h" |
adbb23b6 | 48 | #include "hw/watchdog/cmsdk-apb-watchdog.h" |
db1015e9 | 49 | #include "qom/object.h" |
2eb5578b PM |
50 | |
51 | typedef enum MPS2FPGAType { | |
52 | FPGA_AN385, | |
897d2726 | 53 | FPGA_AN386, |
6d4811c4 | 54 | FPGA_AN500, |
2eb5578b PM |
55 | FPGA_AN511, |
56 | } MPS2FPGAType; | |
57 | ||
db1015e9 | 58 | struct MPS2MachineClass { |
2eb5578b PM |
59 | MachineClass parent; |
60 | MPS2FPGAType fpga_type; | |
6dbdf4ec | 61 | uint32_t scc_id; |
6d4811c4 PM |
62 | bool has_block_ram; |
63 | hwaddr ethernet_base; | |
64 | hwaddr psram_base; | |
db1015e9 | 65 | }; |
2eb5578b | 66 | |
db1015e9 | 67 | struct MPS2MachineState { |
2eb5578b PM |
68 | MachineState parent; |
69 | ||
70 | ARMv7MState armv7m; | |
2eb5578b PM |
71 | MemoryRegion ssram1; |
72 | MemoryRegion ssram1_m; | |
73 | MemoryRegion ssram23; | |
74 | MemoryRegion ssram23_m; | |
75 | MemoryRegion blockram; | |
76 | MemoryRegion blockram_m1; | |
77 | MemoryRegion blockram_m2; | |
78 | MemoryRegion blockram_m3; | |
79 | MemoryRegion sram; | |
75ca8341 | 80 | /* FPGA APB subsystem */ |
6dbdf4ec | 81 | MPS2SCC scc; |
adbb23b6 | 82 | MPS2FPGAIO fpgaio; |
75ca8341 | 83 | /* CMSDK APB subsystem */ |
595c786b | 84 | CMSDKAPBDualTimer dualtimer; |
adbb23b6 | 85 | CMSDKAPBWatchdog watchdog; |
efc34aaa | 86 | CMSDKAPBTimer timer[2]; |
db1015e9 | 87 | }; |
2eb5578b PM |
88 | |
89 | #define TYPE_MPS2_MACHINE "mps2" | |
90 | #define TYPE_MPS2_AN385_MACHINE MACHINE_TYPE_NAME("mps2-an385") | |
897d2726 | 91 | #define TYPE_MPS2_AN386_MACHINE MACHINE_TYPE_NAME("mps2-an386") |
6d4811c4 | 92 | #define TYPE_MPS2_AN500_MACHINE MACHINE_TYPE_NAME("mps2-an500") |
2eb5578b PM |
93 | #define TYPE_MPS2_AN511_MACHINE MACHINE_TYPE_NAME("mps2-an511") |
94 | ||
a489d195 | 95 | OBJECT_DECLARE_TYPE(MPS2MachineState, MPS2MachineClass, MPS2_MACHINE) |
2eb5578b PM |
96 | |
97 | /* Main SYSCLK frequency in Hz */ | |
98 | #define SYSCLK_FRQ 25000000 | |
99 | ||
100 | /* Initialize the auxiliary RAM region @mr and map it into | |
101 | * the memory map at @base. | |
102 | */ | |
103 | static void make_ram(MemoryRegion *mr, const char *name, | |
104 | hwaddr base, hwaddr size) | |
105 | { | |
106 | memory_region_init_ram(mr, NULL, name, size, &error_fatal); | |
107 | memory_region_add_subregion(get_system_memory(), base, mr); | |
108 | } | |
109 | ||
110 | /* Create an alias of an entire original MemoryRegion @orig | |
111 | * located at @base in the memory map. | |
112 | */ | |
113 | static void make_ram_alias(MemoryRegion *mr, const char *name, | |
114 | MemoryRegion *orig, hwaddr base) | |
115 | { | |
116 | memory_region_init_alias(mr, NULL, name, orig, 0, | |
117 | memory_region_size(orig)); | |
118 | memory_region_add_subregion(get_system_memory(), base, mr); | |
119 | } | |
120 | ||
121 | static void mps2_common_init(MachineState *machine) | |
122 | { | |
123 | MPS2MachineState *mms = MPS2_MACHINE(machine); | |
124 | MPS2MachineClass *mmc = MPS2_MACHINE_GET_CLASS(machine); | |
125 | MemoryRegion *system_memory = get_system_memory(); | |
ba1ba5cc | 126 | MachineClass *mc = MACHINE_GET_CLASS(machine); |
6dbdf4ec | 127 | DeviceState *armv7m, *sccdev; |
bb8fba9c | 128 | int i; |
2eb5578b | 129 | |
ba1ba5cc IM |
130 | if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) { |
131 | error_report("This board can only be used with CPU %s", | |
132 | mc->default_cpu_type); | |
2eb5578b PM |
133 | exit(1); |
134 | } | |
135 | ||
68637c3a IM |
136 | if (machine->ram_size != mc->default_ram_size) { |
137 | char *sz = size_to_str(mc->default_ram_size); | |
138 | error_report("Invalid RAM size, should be %s", sz); | |
139 | g_free(sz); | |
140 | exit(EXIT_FAILURE); | |
141 | } | |
142 | ||
2eb5578b PM |
143 | /* The FPGA images have an odd combination of different RAMs, |
144 | * because in hardware they are different implementations and | |
145 | * connected to different buses, giving varying performance/size | |
146 | * tradeoffs. For QEMU they're all just RAM, though. We arbitrarily | |
147 | * call the 16MB our "system memory", as it's the largest lump. | |
148 | * | |
897d2726 PM |
149 | * AN385/AN386/AN511: |
150 | * 0x21000000 .. 0x21ffffff : PSRAM (16MB) | |
6d4811c4 | 151 | * AN385/AN386/AN500: |
2eb5578b PM |
152 | * 0x00000000 .. 0x003fffff : ZBT SSRAM1 |
153 | * 0x00400000 .. 0x007fffff : mirror of ZBT SSRAM1 | |
154 | * 0x20000000 .. 0x203fffff : ZBT SSRAM 2&3 | |
155 | * 0x20400000 .. 0x207fffff : mirror of ZBT SSRAM 2&3 | |
6d4811c4 | 156 | * AN385/AN386 only: |
2eb5578b PM |
157 | * 0x01000000 .. 0x01003fff : block RAM (16K) |
158 | * 0x01004000 .. 0x01007fff : mirror of above | |
159 | * 0x01008000 .. 0x0100bfff : mirror of above | |
160 | * 0x0100c000 .. 0x0100ffff : mirror of above | |
161 | * AN511 only: | |
162 | * 0x00000000 .. 0x0003ffff : FPGA block RAM | |
163 | * 0x00400000 .. 0x007fffff : ZBT SSRAM1 | |
164 | * 0x20000000 .. 0x2001ffff : SRAM | |
165 | * 0x20400000 .. 0x207fffff : ZBT SSRAM 2&3 | |
6d4811c4 PM |
166 | * AN500 only: |
167 | * 0x60000000 .. 0x60ffffff : PSRAM (16MB) | |
2eb5578b | 168 | * |
897d2726 | 169 | * The AN385/AN386 has a feature where the lowest 16K can be mapped |
2eb5578b PM |
170 | * either to the bottom of the ZBT SSRAM1 or to the block RAM. |
171 | * This is of no use for QEMU so we don't implement it (as if | |
172 | * zbt_boot_ctrl is always zero). | |
173 | */ | |
6d4811c4 PM |
174 | memory_region_add_subregion(system_memory, mmc->psram_base, machine->ram); |
175 | ||
176 | if (mmc->has_block_ram) { | |
177 | make_ram(&mms->blockram, "mps.blockram", 0x01000000, 0x4000); | |
178 | make_ram_alias(&mms->blockram_m1, "mps.blockram_m1", | |
179 | &mms->blockram, 0x01004000); | |
180 | make_ram_alias(&mms->blockram_m2, "mps.blockram_m2", | |
181 | &mms->blockram, 0x01008000); | |
182 | make_ram_alias(&mms->blockram_m3, "mps.blockram_m3", | |
183 | &mms->blockram, 0x0100c000); | |
184 | } | |
2eb5578b PM |
185 | |
186 | switch (mmc->fpga_type) { | |
187 | case FPGA_AN385: | |
897d2726 | 188 | case FPGA_AN386: |
6d4811c4 | 189 | case FPGA_AN500: |
2eb5578b PM |
190 | make_ram(&mms->ssram1, "mps.ssram1", 0x0, 0x400000); |
191 | make_ram_alias(&mms->ssram1_m, "mps.ssram1_m", &mms->ssram1, 0x400000); | |
192 | make_ram(&mms->ssram23, "mps.ssram23", 0x20000000, 0x400000); | |
193 | make_ram_alias(&mms->ssram23_m, "mps.ssram23_m", | |
194 | &mms->ssram23, 0x20400000); | |
2eb5578b PM |
195 | break; |
196 | case FPGA_AN511: | |
197 | make_ram(&mms->blockram, "mps.blockram", 0x0, 0x40000); | |
198 | make_ram(&mms->ssram1, "mps.ssram1", 0x00400000, 0x00800000); | |
199 | make_ram(&mms->sram, "mps.sram", 0x20000000, 0x20000); | |
200 | make_ram(&mms->ssram23, "mps.ssram23", 0x20400000, 0x400000); | |
201 | break; | |
202 | default: | |
203 | g_assert_not_reached(); | |
204 | } | |
205 | ||
0074fce6 | 206 | object_initialize_child(OBJECT(mms), "armv7m", &mms->armv7m, TYPE_ARMV7M); |
2eb5578b | 207 | armv7m = DEVICE(&mms->armv7m); |
2eb5578b PM |
208 | switch (mmc->fpga_type) { |
209 | case FPGA_AN385: | |
897d2726 | 210 | case FPGA_AN386: |
6d4811c4 | 211 | case FPGA_AN500: |
2eb5578b PM |
212 | qdev_prop_set_uint32(armv7m, "num-irq", 32); |
213 | break; | |
214 | case FPGA_AN511: | |
215 | qdev_prop_set_uint32(armv7m, "num-irq", 64); | |
216 | break; | |
217 | default: | |
218 | g_assert_not_reached(); | |
219 | } | |
ba1ba5cc | 220 | qdev_prop_set_string(armv7m, "cpu-type", machine->cpu_type); |
a1c5a062 | 221 | qdev_prop_set_bit(armv7m, "enable-bitband", true); |
5325cc34 MA |
222 | object_property_set_link(OBJECT(&mms->armv7m), "memory", |
223 | OBJECT(system_memory), &error_abort); | |
0074fce6 | 224 | sysbus_realize(SYS_BUS_DEVICE(&mms->armv7m), &error_fatal); |
2eb5578b PM |
225 | |
226 | create_unimplemented_device("zbtsmram mirror", 0x00400000, 0x00400000); | |
227 | create_unimplemented_device("RESERVED 1", 0x00800000, 0x00800000); | |
228 | create_unimplemented_device("Block RAM", 0x01000000, 0x00010000); | |
229 | create_unimplemented_device("RESERVED 2", 0x01010000, 0x1EFF0000); | |
230 | create_unimplemented_device("RESERVED 3", 0x20800000, 0x00800000); | |
231 | create_unimplemented_device("PSRAM", 0x21000000, 0x01000000); | |
232 | /* These three ranges all cover multiple devices; we may implement | |
233 | * some of them below (in which case the real device takes precedence | |
234 | * over the unimplemented-region mapping). | |
235 | */ | |
236 | create_unimplemented_device("CMSDK APB peripheral region @0x40000000", | |
237 | 0x40000000, 0x00010000); | |
90b1b6ef | 238 | create_unimplemented_device("CMSDK AHB peripheral region @0x40010000", |
2eb5578b PM |
239 | 0x40010000, 0x00010000); |
240 | create_unimplemented_device("Extra peripheral region @0x40020000", | |
241 | 0x40020000, 0x00010000); | |
90b1b6ef | 242 | |
2eb5578b | 243 | create_unimplemented_device("RESERVED 4", 0x40030000, 0x001D0000); |
2eb5578b PM |
244 | create_unimplemented_device("VGA", 0x41000000, 0x0200000); |
245 | ||
977a15f4 PM |
246 | switch (mmc->fpga_type) { |
247 | case FPGA_AN385: | |
897d2726 | 248 | case FPGA_AN386: |
6d4811c4 | 249 | case FPGA_AN500: |
977a15f4 PM |
250 | { |
251 | /* The overflow IRQs for UARTs 0, 1 and 2 are ORed together. | |
252 | * Overflow for UARTs 4 and 5 doesn't trigger any interrupt. | |
253 | */ | |
254 | Object *orgate; | |
255 | DeviceState *orgate_dev; | |
977a15f4 PM |
256 | |
257 | orgate = object_new(TYPE_OR_IRQ); | |
5325cc34 | 258 | object_property_set_int(orgate, "num-lines", 6, &error_fatal); |
ce189ab2 | 259 | qdev_realize(DEVICE(orgate), NULL, &error_fatal); |
977a15f4 PM |
260 | orgate_dev = DEVICE(orgate); |
261 | qdev_connect_gpio_out(orgate_dev, 0, qdev_get_gpio_in(armv7m, 12)); | |
262 | ||
263 | for (i = 0; i < 5; i++) { | |
264 | static const hwaddr uartbase[] = {0x40004000, 0x40005000, | |
265 | 0x40006000, 0x40007000, | |
266 | 0x40009000}; | |
977a15f4 PM |
267 | /* RX irq number; TX irq is always one greater */ |
268 | static const int uartirq[] = {0, 2, 4, 18, 20}; | |
269 | qemu_irq txovrint = NULL, rxovrint = NULL; | |
270 | ||
271 | if (i < 3) { | |
272 | txovrint = qdev_get_gpio_in(orgate_dev, i * 2); | |
273 | rxovrint = qdev_get_gpio_in(orgate_dev, i * 2 + 1); | |
274 | } | |
275 | ||
276 | cmsdk_apb_uart_create(uartbase[i], | |
277 | qdev_get_gpio_in(armv7m, uartirq[i] + 1), | |
278 | qdev_get_gpio_in(armv7m, uartirq[i]), | |
279 | txovrint, rxovrint, | |
280 | NULL, | |
fc38a112 | 281 | serial_hd(i), SYSCLK_FRQ); |
977a15f4 PM |
282 | } |
283 | break; | |
284 | } | |
285 | case FPGA_AN511: | |
286 | { | |
287 | /* The overflow IRQs for all UARTs are ORed together. | |
288 | * Tx and Rx IRQs for each UART are ORed together. | |
289 | */ | |
290 | Object *orgate; | |
291 | DeviceState *orgate_dev; | |
977a15f4 PM |
292 | |
293 | orgate = object_new(TYPE_OR_IRQ); | |
5325cc34 | 294 | object_property_set_int(orgate, "num-lines", 10, &error_fatal); |
ce189ab2 | 295 | qdev_realize(DEVICE(orgate), NULL, &error_fatal); |
977a15f4 PM |
296 | orgate_dev = DEVICE(orgate); |
297 | qdev_connect_gpio_out(orgate_dev, 0, qdev_get_gpio_in(armv7m, 12)); | |
298 | ||
299 | for (i = 0; i < 5; i++) { | |
300 | /* system irq numbers for the combined tx/rx for each UART */ | |
301 | static const int uart_txrx_irqno[] = {0, 2, 45, 46, 56}; | |
302 | static const hwaddr uartbase[] = {0x40004000, 0x40005000, | |
303 | 0x4002c000, 0x4002d000, | |
304 | 0x4002e000}; | |
977a15f4 PM |
305 | Object *txrx_orgate; |
306 | DeviceState *txrx_orgate_dev; | |
307 | ||
308 | txrx_orgate = object_new(TYPE_OR_IRQ); | |
5325cc34 | 309 | object_property_set_int(txrx_orgate, "num-lines", 2, &error_fatal); |
ce189ab2 | 310 | qdev_realize(DEVICE(txrx_orgate), NULL, &error_fatal); |
977a15f4 PM |
311 | txrx_orgate_dev = DEVICE(txrx_orgate); |
312 | qdev_connect_gpio_out(txrx_orgate_dev, 0, | |
313 | qdev_get_gpio_in(armv7m, uart_txrx_irqno[i])); | |
314 | cmsdk_apb_uart_create(uartbase[i], | |
315 | qdev_get_gpio_in(txrx_orgate_dev, 0), | |
316 | qdev_get_gpio_in(txrx_orgate_dev, 1), | |
ce3bc112 PM |
317 | qdev_get_gpio_in(orgate_dev, i * 2), |
318 | qdev_get_gpio_in(orgate_dev, i * 2 + 1), | |
977a15f4 | 319 | NULL, |
fc38a112 | 320 | serial_hd(i), SYSCLK_FRQ); |
977a15f4 PM |
321 | } |
322 | break; | |
323 | } | |
324 | default: | |
325 | g_assert_not_reached(); | |
326 | } | |
bb8fba9c PMD |
327 | for (i = 0; i < 4; i++) { |
328 | static const hwaddr gpiobase[] = {0x40010000, 0x40011000, | |
329 | 0x40012000, 0x40013000}; | |
330 | create_unimplemented_device("cmsdk-ahb-gpio", gpiobase[i], 0x1000); | |
331 | } | |
977a15f4 | 332 | |
75ca8341 | 333 | /* CMSDK APB subsystem */ |
efc34aaa PM |
334 | for (i = 0; i < ARRAY_SIZE(mms->timer); i++) { |
335 | g_autofree char *name = g_strdup_printf("timer%d", i); | |
336 | hwaddr base = 0x40000000 + i * 0x1000; | |
337 | int irqno = 8 + i; | |
338 | SysBusDevice *sbd; | |
339 | ||
340 | object_initialize_child(OBJECT(mms), name, &mms->timer[i], | |
341 | TYPE_CMSDK_APB_TIMER); | |
342 | sbd = SYS_BUS_DEVICE(&mms->timer[i]); | |
343 | qdev_prop_set_uint32(DEVICE(&mms->timer[i]), "pclk-frq", SYSCLK_FRQ); | |
344 | sysbus_realize_and_unref(sbd, &error_fatal); | |
345 | sysbus_mmio_map(sbd, 0, base); | |
346 | sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(armv7m, irqno)); | |
347 | } | |
348 | ||
0074fce6 MA |
349 | object_initialize_child(OBJECT(mms), "dualtimer", &mms->dualtimer, |
350 | TYPE_CMSDK_APB_DUALTIMER); | |
595c786b | 351 | qdev_prop_set_uint32(DEVICE(&mms->dualtimer), "pclk-frq", SYSCLK_FRQ); |
0074fce6 | 352 | sysbus_realize(SYS_BUS_DEVICE(&mms->dualtimer), &error_fatal); |
595c786b PM |
353 | sysbus_connect_irq(SYS_BUS_DEVICE(&mms->dualtimer), 0, |
354 | qdev_get_gpio_in(armv7m, 10)); | |
355 | sysbus_mmio_map(SYS_BUS_DEVICE(&mms->dualtimer), 0, 0x40002000); | |
ecbe51af PMD |
356 | object_initialize_child(OBJECT(mms), "watchdog", &mms->watchdog, |
357 | TYPE_CMSDK_APB_WATCHDOG); | |
358 | qdev_prop_set_uint32(DEVICE(&mms->watchdog), "wdogclk-frq", SYSCLK_FRQ); | |
359 | sysbus_realize(SYS_BUS_DEVICE(&mms->watchdog), &error_fatal); | |
360 | sysbus_connect_irq(SYS_BUS_DEVICE(&mms->watchdog), 0, | |
361 | qdev_get_gpio_in_named(armv7m, "NMI", 0)); | |
362 | sysbus_mmio_map(SYS_BUS_DEVICE(&mms->watchdog), 0, 0x40008000); | |
595c786b | 363 | |
75ca8341 | 364 | /* FPGA APB subsystem */ |
0074fce6 | 365 | object_initialize_child(OBJECT(mms), "scc", &mms->scc, TYPE_MPS2_SCC); |
6dbdf4ec | 366 | sccdev = DEVICE(&mms->scc); |
6dbdf4ec | 367 | qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2); |
239cb6fe | 368 | qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008); |
6dbdf4ec | 369 | qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id); |
0074fce6 | 370 | sysbus_realize(SYS_BUS_DEVICE(&mms->scc), &error_fatal); |
6dbdf4ec | 371 | sysbus_mmio_map(SYS_BUS_DEVICE(sccdev), 0, 0x4002f000); |
adbb23b6 PMD |
372 | object_initialize_child(OBJECT(mms), "fpgaio", |
373 | &mms->fpgaio, TYPE_MPS2_FPGAIO); | |
374 | qdev_prop_set_uint32(DEVICE(&mms->fpgaio), "prescale-clk", 25000000); | |
375 | sysbus_realize(SYS_BUS_DEVICE(&mms->fpgaio), &error_fatal); | |
376 | sysbus_mmio_map(SYS_BUS_DEVICE(&mms->fpgaio), 0, 0x40028000); | |
58f7f3c4 PMD |
377 | sysbus_create_simple(TYPE_PL022, 0x40025000, /* External ADC */ |
378 | qdev_get_gpio_in(armv7m, 22)); | |
379 | for (i = 0; i < 2; i++) { | |
380 | static const int spi_irqno[] = {11, 24}; | |
381 | static const hwaddr spibase[] = {0x40020000, /* APB */ | |
382 | 0x40021000, /* LCD */ | |
383 | 0x40026000, /* Shield0 */ | |
384 | 0x40027000}; /* Shield1 */ | |
385 | DeviceState *orgate_dev; | |
386 | Object *orgate; | |
387 | int j; | |
388 | ||
389 | orgate = object_new(TYPE_OR_IRQ); | |
5325cc34 | 390 | object_property_set_int(orgate, "num-lines", 2, &error_fatal); |
58f7f3c4 PMD |
391 | orgate_dev = DEVICE(orgate); |
392 | qdev_realize(orgate_dev, NULL, &error_fatal); | |
393 | qdev_connect_gpio_out(orgate_dev, 0, | |
394 | qdev_get_gpio_in(armv7m, spi_irqno[i])); | |
395 | for (j = 0; j < 2; j++) { | |
396 | sysbus_create_simple(TYPE_PL022, spibase[2 * i + j], | |
397 | qdev_get_gpio_in(orgate_dev, j)); | |
398 | } | |
399 | } | |
ada45de9 PMD |
400 | for (i = 0; i < 4; i++) { |
401 | static const hwaddr i2cbase[] = {0x40022000, /* Touch */ | |
402 | 0x40023000, /* Audio */ | |
403 | 0x40029000, /* Shield0 */ | |
404 | 0x4002a000}; /* Shield1 */ | |
405 | sysbus_create_simple(TYPE_ARM_SBCON_I2C, i2cbase[i], NULL); | |
406 | } | |
7b465641 | 407 | create_unimplemented_device("i2s", 0x40024000, 0x400); |
6dbdf4ec | 408 | |
35873939 PM |
409 | /* In hardware this is a LAN9220; the LAN9118 is software compatible |
410 | * except that it doesn't support the checksum-offload feature. | |
411 | */ | |
6d4811c4 | 412 | lan9118_init(&nd_table[0], mmc->ethernet_base, |
35873939 | 413 | qdev_get_gpio_in(armv7m, |
897d2726 | 414 | mmc->fpga_type == FPGA_AN511 ? 47 : 13)); |
35873939 | 415 | |
2eb5578b PM |
416 | system_clock_scale = NANOSECONDS_PER_SECOND / SYSCLK_FRQ; |
417 | ||
418 | armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, | |
419 | 0x400000); | |
420 | } | |
421 | ||
422 | static void mps2_class_init(ObjectClass *oc, void *data) | |
423 | { | |
424 | MachineClass *mc = MACHINE_CLASS(oc); | |
425 | ||
426 | mc->init = mps2_common_init; | |
427 | mc->max_cpus = 1; | |
68637c3a IM |
428 | mc->default_ram_size = 16 * MiB; |
429 | mc->default_ram_id = "mps.ram"; | |
2eb5578b PM |
430 | } |
431 | ||
432 | static void mps2_an385_class_init(ObjectClass *oc, void *data) | |
433 | { | |
434 | MachineClass *mc = MACHINE_CLASS(oc); | |
435 | MPS2MachineClass *mmc = MPS2_MACHINE_CLASS(oc); | |
436 | ||
437 | mc->desc = "ARM MPS2 with AN385 FPGA image for Cortex-M3"; | |
438 | mmc->fpga_type = FPGA_AN385; | |
ba1ba5cc | 439 | mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3"); |
239cb6fe | 440 | mmc->scc_id = 0x41043850; |
6d4811c4 PM |
441 | mmc->psram_base = 0x21000000; |
442 | mmc->ethernet_base = 0x40200000; | |
443 | mmc->has_block_ram = true; | |
2eb5578b PM |
444 | } |
445 | ||
897d2726 PM |
446 | static void mps2_an386_class_init(ObjectClass *oc, void *data) |
447 | { | |
448 | MachineClass *mc = MACHINE_CLASS(oc); | |
449 | MPS2MachineClass *mmc = MPS2_MACHINE_CLASS(oc); | |
450 | ||
451 | mc->desc = "ARM MPS2 with AN386 FPGA image for Cortex-M4"; | |
452 | mmc->fpga_type = FPGA_AN386; | |
453 | mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m4"); | |
454 | mmc->scc_id = 0x41043860; | |
6d4811c4 PM |
455 | mmc->psram_base = 0x21000000; |
456 | mmc->ethernet_base = 0x40200000; | |
457 | mmc->has_block_ram = true; | |
458 | } | |
459 | ||
460 | static void mps2_an500_class_init(ObjectClass *oc, void *data) | |
461 | { | |
462 | MachineClass *mc = MACHINE_CLASS(oc); | |
463 | MPS2MachineClass *mmc = MPS2_MACHINE_CLASS(oc); | |
464 | ||
465 | mc->desc = "ARM MPS2 with AN500 FPGA image for Cortex-M7"; | |
466 | mmc->fpga_type = FPGA_AN500; | |
467 | mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m7"); | |
468 | mmc->scc_id = 0x41045000; | |
469 | mmc->psram_base = 0x60000000; | |
470 | mmc->ethernet_base = 0xa0000000; | |
471 | mmc->has_block_ram = false; | |
897d2726 PM |
472 | } |
473 | ||
2eb5578b PM |
474 | static void mps2_an511_class_init(ObjectClass *oc, void *data) |
475 | { | |
476 | MachineClass *mc = MACHINE_CLASS(oc); | |
477 | MPS2MachineClass *mmc = MPS2_MACHINE_CLASS(oc); | |
478 | ||
479 | mc->desc = "ARM MPS2 with AN511 DesignStart FPGA image for Cortex-M3"; | |
480 | mmc->fpga_type = FPGA_AN511; | |
ba1ba5cc | 481 | mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3"); |
239cb6fe | 482 | mmc->scc_id = 0x41045110; |
6d4811c4 PM |
483 | mmc->psram_base = 0x21000000; |
484 | mmc->ethernet_base = 0x40200000; | |
485 | mmc->has_block_ram = false; | |
2eb5578b PM |
486 | } |
487 | ||
488 | static const TypeInfo mps2_info = { | |
489 | .name = TYPE_MPS2_MACHINE, | |
490 | .parent = TYPE_MACHINE, | |
491 | .abstract = true, | |
492 | .instance_size = sizeof(MPS2MachineState), | |
493 | .class_size = sizeof(MPS2MachineClass), | |
494 | .class_init = mps2_class_init, | |
495 | }; | |
496 | ||
497 | static const TypeInfo mps2_an385_info = { | |
498 | .name = TYPE_MPS2_AN385_MACHINE, | |
499 | .parent = TYPE_MPS2_MACHINE, | |
500 | .class_init = mps2_an385_class_init, | |
501 | }; | |
502 | ||
897d2726 PM |
503 | static const TypeInfo mps2_an386_info = { |
504 | .name = TYPE_MPS2_AN386_MACHINE, | |
505 | .parent = TYPE_MPS2_MACHINE, | |
506 | .class_init = mps2_an386_class_init, | |
507 | }; | |
508 | ||
6d4811c4 PM |
509 | static const TypeInfo mps2_an500_info = { |
510 | .name = TYPE_MPS2_AN500_MACHINE, | |
511 | .parent = TYPE_MPS2_MACHINE, | |
512 | .class_init = mps2_an500_class_init, | |
513 | }; | |
514 | ||
2eb5578b PM |
515 | static const TypeInfo mps2_an511_info = { |
516 | .name = TYPE_MPS2_AN511_MACHINE, | |
517 | .parent = TYPE_MPS2_MACHINE, | |
518 | .class_init = mps2_an511_class_init, | |
519 | }; | |
520 | ||
521 | static void mps2_machine_init(void) | |
522 | { | |
523 | type_register_static(&mps2_info); | |
524 | type_register_static(&mps2_an385_info); | |
897d2726 | 525 | type_register_static(&mps2_an386_info); |
6d4811c4 | 526 | type_register_static(&mps2_an500_info); |
2eb5578b PM |
527 | type_register_static(&mps2_an511_info); |
528 | } | |
529 | ||
530 | type_init(mps2_machine_init); |