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