xref: /qemu/hw/arm/mps3r.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
1273a70aeSPeter Maydell /*
2273a70aeSPeter Maydell  * Arm MPS3 board emulation for Cortex-R-based FPGA images.
3273a70aeSPeter Maydell  * (For M-profile images see mps2.c and mps2tz.c.)
4273a70aeSPeter Maydell  *
5273a70aeSPeter Maydell  * Copyright (c) 2017 Linaro Limited
6273a70aeSPeter Maydell  * Written by Peter Maydell
7273a70aeSPeter Maydell  *
8273a70aeSPeter Maydell  *  This program is free software; you can redistribute it and/or modify
9273a70aeSPeter Maydell  *  it under the terms of the GNU General Public License version 2 or
10273a70aeSPeter Maydell  *  (at your option) any later version.
11273a70aeSPeter Maydell  */
12273a70aeSPeter Maydell 
13273a70aeSPeter Maydell /*
14273a70aeSPeter Maydell  * The MPS3 is an FPGA based dev board. This file handles FPGA images
15273a70aeSPeter Maydell  * which use the Cortex-R CPUs. We model these separately from the
16273a70aeSPeter Maydell  * M-profile images, because on M-profile the FPGA image is based on
17273a70aeSPeter Maydell  * a "Subsystem for Embedded" which is similar to an SoC, whereas
18273a70aeSPeter Maydell  * the R-profile FPGA images don't have that abstraction layer.
19273a70aeSPeter Maydell  *
20273a70aeSPeter Maydell  * We model the following FPGA images here:
21273a70aeSPeter Maydell  *  "mps3-an536" -- dual Cortex-R52 as documented in Arm Application Note AN536
22273a70aeSPeter Maydell  *
23273a70aeSPeter Maydell  * Application Note AN536:
24273a70aeSPeter Maydell  * https://developer.arm.com/documentation/dai0536/latest/
25273a70aeSPeter Maydell  */
26273a70aeSPeter Maydell 
27273a70aeSPeter Maydell #include "qemu/osdep.h"
28273a70aeSPeter Maydell #include "qemu/units.h"
29273a70aeSPeter Maydell #include "qapi/error.h"
30407bc4bfSDaniel P. Berrangé #include "qobject/qlist.h"
31dfc56946SRichard Henderson #include "system/address-spaces.h"
32273a70aeSPeter Maydell #include "cpu.h"
3332cad1ffSPhilippe Mathieu-Daudé #include "system/system.h"
34273a70aeSPeter Maydell #include "hw/boards.h"
35a71e2646SPeter Maydell #include "hw/or-irq.h"
360482e762SPeter Maydell #include "hw/qdev-clock.h"
379220b09dSPeter Maydell #include "hw/qdev-properties.h"
38273a70aeSPeter Maydell #include "hw/arm/boot.h"
399220b09dSPeter Maydell #include "hw/arm/bsa.h"
40a71e2646SPeter Maydell #include "hw/char/cmsdk-apb-uart.h"
410482e762SPeter Maydell #include "hw/i2c/arm_sbcon_i2c.h"
429220b09dSPeter Maydell #include "hw/intc/arm_gicv3.h"
4382e2b7e3SPeter Maydell #include "hw/misc/mps2-scc.h"
4482e2b7e3SPeter Maydell #include "hw/misc/mps2-fpgaio.h"
450482e762SPeter Maydell #include "hw/misc/unimp.h"
4682e2b7e3SPeter Maydell #include "hw/net/lan9118.h"
4782e2b7e3SPeter Maydell #include "hw/rtc/pl031.h"
4882e2b7e3SPeter Maydell #include "hw/ssi/pl022.h"
490482e762SPeter Maydell #include "hw/timer/cmsdk-apb-dualtimer.h"
500482e762SPeter Maydell #include "hw/watchdog/cmsdk-apb-watchdog.h"
51273a70aeSPeter Maydell 
52273a70aeSPeter Maydell /* Define the layout of RAM and ROM in a board */
53273a70aeSPeter Maydell typedef struct RAMInfo {
54273a70aeSPeter Maydell     const char *name;
55273a70aeSPeter Maydell     hwaddr base;
56273a70aeSPeter Maydell     hwaddr size;
57273a70aeSPeter Maydell     int mrindex; /* index into rams[]; -1 for the system RAM block */
58273a70aeSPeter Maydell     int flags;
59273a70aeSPeter Maydell } RAMInfo;
60273a70aeSPeter Maydell 
61273a70aeSPeter Maydell /*
62273a70aeSPeter Maydell  * The MPS3 DDR is 3GiB, but on a 32-bit host QEMU doesn't permit
63273a70aeSPeter Maydell  * emulation of that much guest RAM, so artificially make it smaller.
64273a70aeSPeter Maydell  */
65273a70aeSPeter Maydell #if HOST_LONG_BITS == 32
66273a70aeSPeter Maydell #define MPS3_DDR_SIZE (1 * GiB)
67273a70aeSPeter Maydell #else
68273a70aeSPeter Maydell #define MPS3_DDR_SIZE (3 * GiB)
69273a70aeSPeter Maydell #endif
70273a70aeSPeter Maydell 
71273a70aeSPeter Maydell /*
72273a70aeSPeter Maydell  * Flag values:
73273a70aeSPeter Maydell  * IS_MAIN: this is the main machine RAM
74273a70aeSPeter Maydell  * IS_ROM: this area is read-only
75273a70aeSPeter Maydell  */
76273a70aeSPeter Maydell #define IS_MAIN 1
77273a70aeSPeter Maydell #define IS_ROM 2
78273a70aeSPeter Maydell 
79273a70aeSPeter Maydell #define MPS3R_RAM_MAX 9
809220b09dSPeter Maydell #define MPS3R_CPU_MAX 2
81a71e2646SPeter Maydell #define MPS3R_UART_MAX 4 /* shared UART count */
829220b09dSPeter Maydell 
839220b09dSPeter Maydell #define PERIPHBASE 0xf0000000
849220b09dSPeter Maydell #define NUM_SPIS 96
85273a70aeSPeter Maydell 
86273a70aeSPeter Maydell typedef enum MPS3RFPGAType {
87273a70aeSPeter Maydell     FPGA_AN536,
88273a70aeSPeter Maydell } MPS3RFPGAType;
89273a70aeSPeter Maydell 
90273a70aeSPeter Maydell struct MPS3RMachineClass {
91273a70aeSPeter Maydell     MachineClass parent;
92273a70aeSPeter Maydell     MPS3RFPGAType fpga_type;
93273a70aeSPeter Maydell     const RAMInfo *raminfo;
949220b09dSPeter Maydell     hwaddr loader_start;
95273a70aeSPeter Maydell };
96273a70aeSPeter Maydell 
97273a70aeSPeter Maydell struct MPS3RMachineState {
98273a70aeSPeter Maydell     MachineState parent;
999220b09dSPeter Maydell     struct arm_boot_info bootinfo;
100273a70aeSPeter Maydell     MemoryRegion ram[MPS3R_RAM_MAX];
1019220b09dSPeter Maydell     Object *cpu[MPS3R_CPU_MAX];
1029220b09dSPeter Maydell     MemoryRegion cpu_sysmem[MPS3R_CPU_MAX];
1039220b09dSPeter Maydell     MemoryRegion sysmem_alias[MPS3R_CPU_MAX];
1049220b09dSPeter Maydell     MemoryRegion cpu_ram[MPS3R_CPU_MAX];
1059220b09dSPeter Maydell     GICv3State gic;
106a71e2646SPeter Maydell     /* per-CPU UARTs followed by the shared UARTs */
107a71e2646SPeter Maydell     CMSDKAPBUART uart[MPS3R_CPU_MAX + MPS3R_UART_MAX];
108a71e2646SPeter Maydell     OrIRQState cpu_uart_oflow[MPS3R_CPU_MAX];
109a71e2646SPeter Maydell     OrIRQState uart_oflow;
1100482e762SPeter Maydell     CMSDKAPBWatchdog watchdog;
1110482e762SPeter Maydell     CMSDKAPBDualTimer dualtimer;
1120482e762SPeter Maydell     ArmSbconI2CState i2c[5];
11382e2b7e3SPeter Maydell     PL022State spi[3];
11482e2b7e3SPeter Maydell     MPS2SCC scc;
11582e2b7e3SPeter Maydell     MPS2FPGAIO fpgaio;
11682e2b7e3SPeter Maydell     UnimplementedDeviceState i2s_audio;
11782e2b7e3SPeter Maydell     PL031State rtc;
1180482e762SPeter Maydell     Clock *clk;
119273a70aeSPeter Maydell };
120273a70aeSPeter Maydell 
121273a70aeSPeter Maydell #define TYPE_MPS3R_MACHINE "mps3r"
122273a70aeSPeter Maydell #define TYPE_MPS3R_AN536_MACHINE MACHINE_TYPE_NAME("mps3-an536")
123273a70aeSPeter Maydell 
124273a70aeSPeter Maydell OBJECT_DECLARE_TYPE(MPS3RMachineState, MPS3RMachineClass, MPS3R_MACHINE)
125273a70aeSPeter Maydell 
126a71e2646SPeter Maydell /*
127a71e2646SPeter Maydell  * Main clock frequency CLK in Hz (50MHz). In the image there are also
128a71e2646SPeter Maydell  * ACLK, MCLK, GPUCLK and PERIPHCLK at the same frequency; for our
129a71e2646SPeter Maydell  * model we just roll them all into one.
130a71e2646SPeter Maydell  */
131a71e2646SPeter Maydell #define CLK_FRQ 50000000
132a71e2646SPeter Maydell 
133273a70aeSPeter Maydell static const RAMInfo an536_raminfo[] = {
134273a70aeSPeter Maydell     {
135273a70aeSPeter Maydell         .name = "ATCM",
136273a70aeSPeter Maydell         .base = 0x00000000,
137273a70aeSPeter Maydell         .size = 0x00008000,
138273a70aeSPeter Maydell         .mrindex = 0,
139273a70aeSPeter Maydell     }, {
140273a70aeSPeter Maydell         /* We model the QSPI flash as simple ROM for now */
141273a70aeSPeter Maydell         .name = "QSPI",
142273a70aeSPeter Maydell         .base = 0x08000000,
143273a70aeSPeter Maydell         .size = 0x00800000,
144273a70aeSPeter Maydell         .flags = IS_ROM,
145273a70aeSPeter Maydell         .mrindex = 1,
146273a70aeSPeter Maydell     }, {
147273a70aeSPeter Maydell         .name = "BRAM",
148273a70aeSPeter Maydell         .base = 0x10000000,
149273a70aeSPeter Maydell         .size = 0x00080000,
150273a70aeSPeter Maydell         .mrindex = 2,
151273a70aeSPeter Maydell     }, {
152273a70aeSPeter Maydell         .name = "DDR",
153273a70aeSPeter Maydell         .base = 0x20000000,
154273a70aeSPeter Maydell         .size = MPS3_DDR_SIZE,
155273a70aeSPeter Maydell         .mrindex = -1,
156273a70aeSPeter Maydell     }, {
157273a70aeSPeter Maydell         .name = "ATCM0",
158273a70aeSPeter Maydell         .base = 0xee000000,
159273a70aeSPeter Maydell         .size = 0x00008000,
160273a70aeSPeter Maydell         .mrindex = 3,
161273a70aeSPeter Maydell     }, {
162273a70aeSPeter Maydell         .name = "BTCM0",
163273a70aeSPeter Maydell         .base = 0xee100000,
164273a70aeSPeter Maydell         .size = 0x00008000,
165273a70aeSPeter Maydell         .mrindex = 4,
166273a70aeSPeter Maydell     }, {
167273a70aeSPeter Maydell         .name = "CTCM0",
168273a70aeSPeter Maydell         .base = 0xee200000,
169273a70aeSPeter Maydell         .size = 0x00008000,
170273a70aeSPeter Maydell         .mrindex = 5,
171273a70aeSPeter Maydell     }, {
172273a70aeSPeter Maydell         .name = "ATCM1",
173273a70aeSPeter Maydell         .base = 0xee400000,
174273a70aeSPeter Maydell         .size = 0x00008000,
175273a70aeSPeter Maydell         .mrindex = 6,
176273a70aeSPeter Maydell     }, {
177273a70aeSPeter Maydell         .name = "BTCM1",
178273a70aeSPeter Maydell         .base = 0xee500000,
179273a70aeSPeter Maydell         .size = 0x00008000,
180273a70aeSPeter Maydell         .mrindex = 7,
181273a70aeSPeter Maydell     }, {
182273a70aeSPeter Maydell         .name = "CTCM1",
183273a70aeSPeter Maydell         .base = 0xee600000,
184273a70aeSPeter Maydell         .size = 0x00008000,
185273a70aeSPeter Maydell         .mrindex = 8,
186273a70aeSPeter Maydell     }, {
187273a70aeSPeter Maydell         .name = NULL,
188273a70aeSPeter Maydell     }
189273a70aeSPeter Maydell };
190273a70aeSPeter Maydell 
19182e2b7e3SPeter Maydell static const int an536_oscclk[] = {
19282e2b7e3SPeter Maydell     24000000, /* 24MHz reference for RTC and timers */
19382e2b7e3SPeter Maydell     50000000, /* 50MHz ACLK */
19482e2b7e3SPeter Maydell     50000000, /* 50MHz MCLK */
19582e2b7e3SPeter Maydell     50000000, /* 50MHz GPUCLK */
19682e2b7e3SPeter Maydell     24576000, /* 24.576MHz AUDCLK */
19782e2b7e3SPeter Maydell     23750000, /* 23.75MHz HDLCDCLK */
19882e2b7e3SPeter Maydell     100000000, /* 100MHz DDR4_REF_CLK */
19982e2b7e3SPeter Maydell };
20082e2b7e3SPeter Maydell 
mr_for_raminfo(MPS3RMachineState * mms,const RAMInfo * raminfo)201273a70aeSPeter Maydell static MemoryRegion *mr_for_raminfo(MPS3RMachineState *mms,
202273a70aeSPeter Maydell                                     const RAMInfo *raminfo)
203273a70aeSPeter Maydell {
204273a70aeSPeter Maydell     /* Return an initialized MemoryRegion for the RAMInfo. */
205273a70aeSPeter Maydell     MemoryRegion *ram;
206273a70aeSPeter Maydell 
207273a70aeSPeter Maydell     if (raminfo->mrindex < 0) {
208273a70aeSPeter Maydell         /* Means this RAMInfo is for QEMU's "system memory" */
209273a70aeSPeter Maydell         MachineState *machine = MACHINE(mms);
210273a70aeSPeter Maydell         assert(!(raminfo->flags & IS_ROM));
211273a70aeSPeter Maydell         return machine->ram;
212273a70aeSPeter Maydell     }
213273a70aeSPeter Maydell 
214273a70aeSPeter Maydell     assert(raminfo->mrindex < MPS3R_RAM_MAX);
215273a70aeSPeter Maydell     ram = &mms->ram[raminfo->mrindex];
216273a70aeSPeter Maydell 
217273a70aeSPeter Maydell     memory_region_init_ram(ram, NULL, raminfo->name,
218273a70aeSPeter Maydell                            raminfo->size, &error_fatal);
219273a70aeSPeter Maydell     if (raminfo->flags & IS_ROM) {
220273a70aeSPeter Maydell         memory_region_set_readonly(ram, true);
221273a70aeSPeter Maydell     }
222273a70aeSPeter Maydell     return ram;
223273a70aeSPeter Maydell }
224273a70aeSPeter Maydell 
2259220b09dSPeter Maydell /*
2269220b09dSPeter Maydell  * There is no defined secondary boot protocol for Linux for the AN536,
2279220b09dSPeter Maydell  * because real hardware has a restriction that atomic operations between
2289220b09dSPeter Maydell  * the two CPUs do not function correctly, and so true SMP is not
2299220b09dSPeter Maydell  * possible. Therefore for cases where the user is directly booting
2309220b09dSPeter Maydell  * a kernel, we treat the system as essentially uniprocessor, and
2319220b09dSPeter Maydell  * put the secondary CPU into power-off state (as if the user on the
2329220b09dSPeter Maydell  * real hardware had configured the secondary to be halted via the
2339220b09dSPeter Maydell  * SCC config registers).
2349220b09dSPeter Maydell  *
2359220b09dSPeter Maydell  * Note that the default secondary boot code would not work here anyway
2369220b09dSPeter Maydell  * as it assumes a GICv2, and we have a GICv3.
2379220b09dSPeter Maydell  */
mps3r_write_secondary_boot(ARMCPU * cpu,const struct arm_boot_info * info)2389220b09dSPeter Maydell static void mps3r_write_secondary_boot(ARMCPU *cpu,
2399220b09dSPeter Maydell                                        const struct arm_boot_info *info)
2409220b09dSPeter Maydell {
2419220b09dSPeter Maydell     /*
2429220b09dSPeter Maydell      * Power the secondary CPU off. This means we don't need to write any
2439220b09dSPeter Maydell      * boot code into guest memory. Note that the 'cpu' argument to this
2449220b09dSPeter Maydell      * function is the primary CPU we passed to arm_load_kernel(), not
2459220b09dSPeter Maydell      * the secondary. Loop around all the other CPUs, as the boot.c
2469220b09dSPeter Maydell      * code does for the "disable secondaries if PSCI is enabled" case.
2479220b09dSPeter Maydell      */
2489220b09dSPeter Maydell     for (CPUState *cs = first_cpu; cs; cs = CPU_NEXT(cs)) {
2499220b09dSPeter Maydell         if (cs != first_cpu) {
2509220b09dSPeter Maydell             object_property_set_bool(OBJECT(cs), "start-powered-off", true,
2519220b09dSPeter Maydell                                      &error_abort);
2529220b09dSPeter Maydell         }
2539220b09dSPeter Maydell     }
2549220b09dSPeter Maydell }
2559220b09dSPeter Maydell 
mps3r_secondary_cpu_reset(ARMCPU * cpu,const struct arm_boot_info * info)2569220b09dSPeter Maydell static void mps3r_secondary_cpu_reset(ARMCPU *cpu,
2579220b09dSPeter Maydell                                       const struct arm_boot_info *info)
2589220b09dSPeter Maydell {
2599220b09dSPeter Maydell     /* We don't need to do anything here because the CPU will be off */
2609220b09dSPeter Maydell }
2619220b09dSPeter Maydell 
create_gic(MPS3RMachineState * mms,MemoryRegion * sysmem)2629220b09dSPeter Maydell static void create_gic(MPS3RMachineState *mms, MemoryRegion *sysmem)
2639220b09dSPeter Maydell {
2649220b09dSPeter Maydell     MachineState *machine = MACHINE(mms);
2659220b09dSPeter Maydell     DeviceState *gicdev;
2669220b09dSPeter Maydell     QList *redist_region_count;
2679220b09dSPeter Maydell 
2689220b09dSPeter Maydell     object_initialize_child(OBJECT(mms), "gic", &mms->gic, TYPE_ARM_GICV3);
2699220b09dSPeter Maydell     gicdev = DEVICE(&mms->gic);
2709220b09dSPeter Maydell     qdev_prop_set_uint32(gicdev, "num-cpu", machine->smp.cpus);
2719220b09dSPeter Maydell     qdev_prop_set_uint32(gicdev, "num-irq", NUM_SPIS + GIC_INTERNAL);
2729220b09dSPeter Maydell     redist_region_count = qlist_new();
2739220b09dSPeter Maydell     qlist_append_int(redist_region_count, machine->smp.cpus);
2749220b09dSPeter Maydell     qdev_prop_set_array(gicdev, "redist-region-count", redist_region_count);
2759220b09dSPeter Maydell     object_property_set_link(OBJECT(&mms->gic), "sysmem",
2769220b09dSPeter Maydell                              OBJECT(sysmem), &error_fatal);
2779220b09dSPeter Maydell     sysbus_realize(SYS_BUS_DEVICE(&mms->gic), &error_fatal);
2789220b09dSPeter Maydell     sysbus_mmio_map(SYS_BUS_DEVICE(&mms->gic), 0, PERIPHBASE);
2799220b09dSPeter Maydell     sysbus_mmio_map(SYS_BUS_DEVICE(&mms->gic), 1, PERIPHBASE + 0x100000);
2809220b09dSPeter Maydell     /*
2819220b09dSPeter Maydell      * Wire the outputs from each CPU's generic timer and the GICv3
2829220b09dSPeter Maydell      * maintenance interrupt signal to the appropriate GIC PPI inputs,
2839220b09dSPeter Maydell      * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs.
2849220b09dSPeter Maydell      */
2859220b09dSPeter Maydell     for (int i = 0; i < machine->smp.cpus; i++) {
2869220b09dSPeter Maydell         DeviceState *cpudev = DEVICE(mms->cpu[i]);
2879220b09dSPeter Maydell         SysBusDevice *gicsbd = SYS_BUS_DEVICE(&mms->gic);
2889220b09dSPeter Maydell         int intidbase = NUM_SPIS + i * GIC_INTERNAL;
2899220b09dSPeter Maydell         int irq;
2909220b09dSPeter Maydell         /*
2919220b09dSPeter Maydell          * Mapping from the output timer irq lines from the CPU to the
2929220b09dSPeter Maydell          * GIC PPI inputs used for this board. This isn't a BSA board,
2939220b09dSPeter Maydell          * but it uses the standard convention for the PPI numbers.
2949220b09dSPeter Maydell          */
2959220b09dSPeter Maydell         const int timer_irq[] = {
2969220b09dSPeter Maydell             [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
2979220b09dSPeter Maydell             [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
2989220b09dSPeter Maydell             [GTIMER_HYP]  = ARCH_TIMER_NS_EL2_IRQ,
2999220b09dSPeter Maydell         };
3009220b09dSPeter Maydell 
3019220b09dSPeter Maydell         for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
3029220b09dSPeter Maydell             qdev_connect_gpio_out(cpudev, irq,
3039220b09dSPeter Maydell                                   qdev_get_gpio_in(gicdev,
3049220b09dSPeter Maydell                                                    intidbase + timer_irq[irq]));
3059220b09dSPeter Maydell         }
3069220b09dSPeter Maydell 
3079220b09dSPeter Maydell         qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", 0,
3089220b09dSPeter Maydell                                     qdev_get_gpio_in(gicdev,
3099220b09dSPeter Maydell                                                      intidbase + ARCH_GIC_MAINT_IRQ));
3109220b09dSPeter Maydell 
3119220b09dSPeter Maydell         qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
3129220b09dSPeter Maydell                                     qdev_get_gpio_in(gicdev,
3139220b09dSPeter Maydell                                                      intidbase + VIRTUAL_PMU_IRQ));
3149220b09dSPeter Maydell 
3159220b09dSPeter Maydell         sysbus_connect_irq(gicsbd, i,
3169220b09dSPeter Maydell                            qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
3179220b09dSPeter Maydell         sysbus_connect_irq(gicsbd, i + machine->smp.cpus,
3189220b09dSPeter Maydell                            qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
3199220b09dSPeter Maydell         sysbus_connect_irq(gicsbd, i + 2 * machine->smp.cpus,
3209220b09dSPeter Maydell                            qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
3219220b09dSPeter Maydell         sysbus_connect_irq(gicsbd, i + 3 * machine->smp.cpus,
3229220b09dSPeter Maydell                            qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
3239220b09dSPeter Maydell     }
3249220b09dSPeter Maydell }
3259220b09dSPeter Maydell 
326a71e2646SPeter Maydell /*
327a71e2646SPeter Maydell  * Create UART uartno, and map it into the MemoryRegion mem at address baseaddr.
328a71e2646SPeter Maydell  * The qemu_irq arguments are where we connect the various IRQs from the UART.
329a71e2646SPeter Maydell  */
create_uart(MPS3RMachineState * mms,int uartno,MemoryRegion * mem,hwaddr baseaddr,qemu_irq txirq,qemu_irq rxirq,qemu_irq txoverirq,qemu_irq rxoverirq,qemu_irq combirq)330a71e2646SPeter Maydell static void create_uart(MPS3RMachineState *mms, int uartno, MemoryRegion *mem,
331a71e2646SPeter Maydell                         hwaddr baseaddr, qemu_irq txirq, qemu_irq rxirq,
332a71e2646SPeter Maydell                         qemu_irq txoverirq, qemu_irq rxoverirq,
333a71e2646SPeter Maydell                         qemu_irq combirq)
334a71e2646SPeter Maydell {
335a71e2646SPeter Maydell     g_autofree char *s = g_strdup_printf("uart%d", uartno);
336a71e2646SPeter Maydell     SysBusDevice *sbd;
337a71e2646SPeter Maydell 
338a71e2646SPeter Maydell     assert(uartno < ARRAY_SIZE(mms->uart));
339a71e2646SPeter Maydell     object_initialize_child(OBJECT(mms), s, &mms->uart[uartno],
340a71e2646SPeter Maydell                             TYPE_CMSDK_APB_UART);
341a71e2646SPeter Maydell     qdev_prop_set_uint32(DEVICE(&mms->uart[uartno]), "pclk-frq", CLK_FRQ);
342a71e2646SPeter Maydell     qdev_prop_set_chr(DEVICE(&mms->uart[uartno]), "chardev", serial_hd(uartno));
343a71e2646SPeter Maydell     sbd = SYS_BUS_DEVICE(&mms->uart[uartno]);
344a71e2646SPeter Maydell     sysbus_realize(sbd, &error_fatal);
345a71e2646SPeter Maydell     memory_region_add_subregion(mem, baseaddr,
346a71e2646SPeter Maydell                                 sysbus_mmio_get_region(sbd, 0));
347a71e2646SPeter Maydell     sysbus_connect_irq(sbd, 0, txirq);
348a71e2646SPeter Maydell     sysbus_connect_irq(sbd, 1, rxirq);
349a71e2646SPeter Maydell     sysbus_connect_irq(sbd, 2, txoverirq);
350a71e2646SPeter Maydell     sysbus_connect_irq(sbd, 3, rxoverirq);
351a71e2646SPeter Maydell     sysbus_connect_irq(sbd, 4, combirq);
352a71e2646SPeter Maydell }
353a71e2646SPeter Maydell 
mps3r_common_init(MachineState * machine)354273a70aeSPeter Maydell static void mps3r_common_init(MachineState *machine)
355273a70aeSPeter Maydell {
356273a70aeSPeter Maydell     MPS3RMachineState *mms = MPS3R_MACHINE(machine);
357273a70aeSPeter Maydell     MPS3RMachineClass *mmc = MPS3R_MACHINE_GET_CLASS(mms);
358273a70aeSPeter Maydell     MemoryRegion *sysmem = get_system_memory();
359a71e2646SPeter Maydell     DeviceState *gicdev;
36082e2b7e3SPeter Maydell     QList *oscclk;
361273a70aeSPeter Maydell 
3620482e762SPeter Maydell     mms->clk = clock_new(OBJECT(machine), "CLK");
3630482e762SPeter Maydell     clock_set_hz(mms->clk, CLK_FRQ);
3640482e762SPeter Maydell 
365273a70aeSPeter Maydell     for (const RAMInfo *ri = mmc->raminfo; ri->name; ri++) {
366273a70aeSPeter Maydell         MemoryRegion *mr = mr_for_raminfo(mms, ri);
367273a70aeSPeter Maydell         memory_region_add_subregion(sysmem, ri->base, mr);
368273a70aeSPeter Maydell     }
3699220b09dSPeter Maydell 
3709220b09dSPeter Maydell     assert(machine->smp.cpus <= MPS3R_CPU_MAX);
3719220b09dSPeter Maydell     for (int i = 0; i < machine->smp.cpus; i++) {
3729220b09dSPeter Maydell         g_autofree char *sysmem_name = g_strdup_printf("cpu-%d-memory", i);
3739220b09dSPeter Maydell         g_autofree char *ramname = g_strdup_printf("cpu-%d-memory", i);
3749220b09dSPeter Maydell         g_autofree char *alias_name = g_strdup_printf("sysmem-alias-%d", i);
3759220b09dSPeter Maydell 
3769220b09dSPeter Maydell         /*
3779220b09dSPeter Maydell          * Each CPU has some private RAM/peripherals, so create the container
3789220b09dSPeter Maydell          * which will house those, with the whole-machine system memory being
3799220b09dSPeter Maydell          * used where there's no CPU-specific device. Note that we need the
3809220b09dSPeter Maydell          * sysmem_alias aliases because we can't put one MR (the original
3819220b09dSPeter Maydell          * 'sysmem') into more than one other MR.
3829220b09dSPeter Maydell          */
3839220b09dSPeter Maydell         memory_region_init(&mms->cpu_sysmem[i], OBJECT(machine),
3849220b09dSPeter Maydell                            sysmem_name, UINT64_MAX);
3859220b09dSPeter Maydell         memory_region_init_alias(&mms->sysmem_alias[i], OBJECT(machine),
3869220b09dSPeter Maydell                                  alias_name, sysmem, 0, UINT64_MAX);
3879220b09dSPeter Maydell         memory_region_add_subregion_overlap(&mms->cpu_sysmem[i], 0,
3889220b09dSPeter Maydell                                             &mms->sysmem_alias[i], -1);
3899220b09dSPeter Maydell 
3909220b09dSPeter Maydell         mms->cpu[i] = object_new(machine->cpu_type);
3919220b09dSPeter Maydell         object_property_set_link(mms->cpu[i], "memory",
3929220b09dSPeter Maydell                                  OBJECT(&mms->cpu_sysmem[i]), &error_abort);
3939220b09dSPeter Maydell         object_property_set_int(mms->cpu[i], "reset-cbar",
3949220b09dSPeter Maydell                                 PERIPHBASE, &error_abort);
3959220b09dSPeter Maydell         qdev_realize(DEVICE(mms->cpu[i]), NULL, &error_fatal);
3969220b09dSPeter Maydell         object_unref(mms->cpu[i]);
3979220b09dSPeter Maydell 
3989220b09dSPeter Maydell         /* Per-CPU RAM */
3999220b09dSPeter Maydell         memory_region_init_ram(&mms->cpu_ram[i], NULL, ramname,
4009220b09dSPeter Maydell                                0x1000, &error_fatal);
4019220b09dSPeter Maydell         memory_region_add_subregion(&mms->cpu_sysmem[i], 0xe7c01000,
4029220b09dSPeter Maydell                                     &mms->cpu_ram[i]);
4039220b09dSPeter Maydell     }
4049220b09dSPeter Maydell 
4059220b09dSPeter Maydell     create_gic(mms, sysmem);
406a71e2646SPeter Maydell     gicdev = DEVICE(&mms->gic);
407a71e2646SPeter Maydell 
408a71e2646SPeter Maydell     /*
409a71e2646SPeter Maydell      * UARTs 0 and 1 are per-CPU; their interrupts are wired to
410a71e2646SPeter Maydell      * the relevant CPU's PPI 0..3, aka INTID 16..19
411a71e2646SPeter Maydell      */
412a71e2646SPeter Maydell     for (int i = 0; i < machine->smp.cpus; i++) {
413a71e2646SPeter Maydell         int intidbase = NUM_SPIS + i * GIC_INTERNAL;
414a71e2646SPeter Maydell         g_autofree char *s = g_strdup_printf("cpu-uart-oflow-orgate%d", i);
415a71e2646SPeter Maydell         DeviceState *orgate;
416a71e2646SPeter Maydell 
417a71e2646SPeter Maydell         /* The two overflow IRQs from the UART are ORed together into PPI 3 */
418a71e2646SPeter Maydell         object_initialize_child(OBJECT(mms), s, &mms->cpu_uart_oflow[i],
419a71e2646SPeter Maydell                                 TYPE_OR_IRQ);
420a71e2646SPeter Maydell         orgate = DEVICE(&mms->cpu_uart_oflow[i]);
421a71e2646SPeter Maydell         qdev_prop_set_uint32(orgate, "num-lines", 2);
422a71e2646SPeter Maydell         qdev_realize(orgate, NULL, &error_fatal);
423a71e2646SPeter Maydell         qdev_connect_gpio_out(orgate, 0,
424a71e2646SPeter Maydell                               qdev_get_gpio_in(gicdev, intidbase + 19));
425a71e2646SPeter Maydell 
426a71e2646SPeter Maydell         create_uart(mms, i, &mms->cpu_sysmem[i], 0xe7c00000,
427a71e2646SPeter Maydell                     qdev_get_gpio_in(gicdev, intidbase + 17), /* tx */
428a71e2646SPeter Maydell                     qdev_get_gpio_in(gicdev, intidbase + 16), /* rx */
429a71e2646SPeter Maydell                     qdev_get_gpio_in(orgate, 0), /* txover */
430a71e2646SPeter Maydell                     qdev_get_gpio_in(orgate, 1), /* rxover */
431a71e2646SPeter Maydell                     qdev_get_gpio_in(gicdev, intidbase + 18) /* combined */);
432a71e2646SPeter Maydell     }
433a71e2646SPeter Maydell     /*
434a71e2646SPeter Maydell      * UARTs 2 to 5 are whole-system; all overflow IRQs are ORed
435a71e2646SPeter Maydell      * together into IRQ 17
436a71e2646SPeter Maydell      */
437a71e2646SPeter Maydell     object_initialize_child(OBJECT(mms), "uart-oflow-orgate",
438a71e2646SPeter Maydell                             &mms->uart_oflow, TYPE_OR_IRQ);
439a71e2646SPeter Maydell     qdev_prop_set_uint32(DEVICE(&mms->uart_oflow), "num-lines",
440a71e2646SPeter Maydell                          MPS3R_UART_MAX * 2);
441a71e2646SPeter Maydell     qdev_realize(DEVICE(&mms->uart_oflow), NULL, &error_fatal);
442a71e2646SPeter Maydell     qdev_connect_gpio_out(DEVICE(&mms->uart_oflow), 0,
443a71e2646SPeter Maydell                           qdev_get_gpio_in(gicdev, 17));
444a71e2646SPeter Maydell 
445a71e2646SPeter Maydell     for (int i = 0; i < MPS3R_UART_MAX; i++) {
446a71e2646SPeter Maydell         hwaddr baseaddr = 0xe0205000 + i * 0x1000;
447a71e2646SPeter Maydell         int rxirq = 5 + i * 2, txirq = 6 + i * 2, combirq = 13 + i;
448a71e2646SPeter Maydell 
449a71e2646SPeter Maydell         create_uart(mms, i + MPS3R_CPU_MAX, sysmem, baseaddr,
450a71e2646SPeter Maydell                     qdev_get_gpio_in(gicdev, txirq),
451a71e2646SPeter Maydell                     qdev_get_gpio_in(gicdev, rxirq),
452a71e2646SPeter Maydell                     qdev_get_gpio_in(DEVICE(&mms->uart_oflow), i * 2),
453a71e2646SPeter Maydell                     qdev_get_gpio_in(DEVICE(&mms->uart_oflow), i * 2 + 1),
454a71e2646SPeter Maydell                     qdev_get_gpio_in(gicdev, combirq));
455a71e2646SPeter Maydell     }
4569220b09dSPeter Maydell 
4570482e762SPeter Maydell     for (int i = 0; i < 4; i++) {
4580482e762SPeter Maydell         /* CMSDK GPIO controllers */
4590482e762SPeter Maydell         g_autofree char *s = g_strdup_printf("gpio%d", i);
4600482e762SPeter Maydell         create_unimplemented_device(s, 0xe0000000 + i * 0x1000, 0x1000);
4610482e762SPeter Maydell     }
4620482e762SPeter Maydell 
4630482e762SPeter Maydell     object_initialize_child(OBJECT(mms), "watchdog", &mms->watchdog,
4640482e762SPeter Maydell                             TYPE_CMSDK_APB_WATCHDOG);
4650482e762SPeter Maydell     qdev_connect_clock_in(DEVICE(&mms->watchdog), "WDOGCLK", mms->clk);
4660482e762SPeter Maydell     sysbus_realize(SYS_BUS_DEVICE(&mms->watchdog), &error_fatal);
4670482e762SPeter Maydell     sysbus_connect_irq(SYS_BUS_DEVICE(&mms->watchdog), 0,
4680482e762SPeter Maydell                        qdev_get_gpio_in(gicdev, 0));
4690482e762SPeter Maydell     sysbus_mmio_map(SYS_BUS_DEVICE(&mms->watchdog), 0, 0xe0100000);
4700482e762SPeter Maydell 
4710482e762SPeter Maydell     object_initialize_child(OBJECT(mms), "dualtimer", &mms->dualtimer,
4720482e762SPeter Maydell                             TYPE_CMSDK_APB_DUALTIMER);
4730482e762SPeter Maydell     qdev_connect_clock_in(DEVICE(&mms->dualtimer), "TIMCLK", mms->clk);
4740482e762SPeter Maydell     sysbus_realize(SYS_BUS_DEVICE(&mms->dualtimer), &error_fatal);
4750482e762SPeter Maydell     sysbus_connect_irq(SYS_BUS_DEVICE(&mms->dualtimer), 0,
4760482e762SPeter Maydell                        qdev_get_gpio_in(gicdev, 3));
4770482e762SPeter Maydell     sysbus_connect_irq(SYS_BUS_DEVICE(&mms->dualtimer), 1,
4780482e762SPeter Maydell                        qdev_get_gpio_in(gicdev, 1));
4790482e762SPeter Maydell     sysbus_connect_irq(SYS_BUS_DEVICE(&mms->dualtimer), 2,
4800482e762SPeter Maydell                        qdev_get_gpio_in(gicdev, 2));
4810482e762SPeter Maydell     sysbus_mmio_map(SYS_BUS_DEVICE(&mms->dualtimer), 0, 0xe0101000);
4820482e762SPeter Maydell 
4830482e762SPeter Maydell     for (int i = 0; i < ARRAY_SIZE(mms->i2c); i++) {
4840482e762SPeter Maydell         static const hwaddr i2cbase[] = {0xe0102000,    /* Touch */
4850482e762SPeter Maydell                                          0xe0103000,    /* Audio */
4860482e762SPeter Maydell                                          0xe0107000,    /* Shield0 */
4870482e762SPeter Maydell                                          0xe0108000,    /* Shield1 */
4880482e762SPeter Maydell                                          0xe0109000};   /* DDR4 EEPROM */
4890482e762SPeter Maydell         g_autofree char *s = g_strdup_printf("i2c%d", i);
4900482e762SPeter Maydell 
4910482e762SPeter Maydell         object_initialize_child(OBJECT(mms), s, &mms->i2c[i],
4920482e762SPeter Maydell                                 TYPE_ARM_SBCON_I2C);
4930482e762SPeter Maydell         sysbus_realize(SYS_BUS_DEVICE(&mms->i2c[i]), &error_fatal);
4940482e762SPeter Maydell         sysbus_mmio_map(SYS_BUS_DEVICE(&mms->i2c[i]), 0, i2cbase[i]);
4950482e762SPeter Maydell         if (i != 2 && i != 3) {
4960482e762SPeter Maydell             /*
4970482e762SPeter Maydell              * internal-only bus: mark it full to avoid user-created
4980482e762SPeter Maydell              * i2c devices being plugged into it.
4990482e762SPeter Maydell              */
5000482e762SPeter Maydell             qbus_mark_full(qdev_get_child_bus(DEVICE(&mms->i2c[i]), "i2c"));
5010482e762SPeter Maydell         }
5020482e762SPeter Maydell     }
5030482e762SPeter Maydell 
50482e2b7e3SPeter Maydell     for (int i = 0; i < ARRAY_SIZE(mms->spi); i++) {
50582e2b7e3SPeter Maydell         g_autofree char *s = g_strdup_printf("spi%d", i);
50682e2b7e3SPeter Maydell         hwaddr baseaddr = 0xe0104000 + i * 0x1000;
50782e2b7e3SPeter Maydell 
50882e2b7e3SPeter Maydell         object_initialize_child(OBJECT(mms), s, &mms->spi[i], TYPE_PL022);
50982e2b7e3SPeter Maydell         sysbus_realize(SYS_BUS_DEVICE(&mms->spi[i]), &error_fatal);
51082e2b7e3SPeter Maydell         sysbus_mmio_map(SYS_BUS_DEVICE(&mms->spi[i]), 0, baseaddr);
51182e2b7e3SPeter Maydell         sysbus_connect_irq(SYS_BUS_DEVICE(&mms->spi[i]), 0,
51282e2b7e3SPeter Maydell                            qdev_get_gpio_in(gicdev, 22 + i));
51382e2b7e3SPeter Maydell     }
51482e2b7e3SPeter Maydell 
51582e2b7e3SPeter Maydell     object_initialize_child(OBJECT(mms), "scc", &mms->scc, TYPE_MPS2_SCC);
51682e2b7e3SPeter Maydell     qdev_prop_set_uint32(DEVICE(&mms->scc), "scc-cfg0", 0);
51782e2b7e3SPeter Maydell     qdev_prop_set_uint32(DEVICE(&mms->scc), "scc-cfg4", 0x2);
51882e2b7e3SPeter Maydell     qdev_prop_set_uint32(DEVICE(&mms->scc), "scc-aid", 0x00200008);
51982e2b7e3SPeter Maydell     qdev_prop_set_uint32(DEVICE(&mms->scc), "scc-id", 0x41055360);
52082e2b7e3SPeter Maydell     oscclk = qlist_new();
52182e2b7e3SPeter Maydell     for (int i = 0; i < ARRAY_SIZE(an536_oscclk); i++) {
52282e2b7e3SPeter Maydell         qlist_append_int(oscclk, an536_oscclk[i]);
52382e2b7e3SPeter Maydell     }
52482e2b7e3SPeter Maydell     qdev_prop_set_array(DEVICE(&mms->scc), "oscclk", oscclk);
52582e2b7e3SPeter Maydell     sysbus_realize(SYS_BUS_DEVICE(&mms->scc), &error_fatal);
52682e2b7e3SPeter Maydell     sysbus_mmio_map(SYS_BUS_DEVICE(&mms->scc), 0, 0xe0200000);
52782e2b7e3SPeter Maydell 
52882e2b7e3SPeter Maydell     create_unimplemented_device("i2s-audio", 0xe0201000, 0x1000);
52982e2b7e3SPeter Maydell 
53082e2b7e3SPeter Maydell     object_initialize_child(OBJECT(mms), "fpgaio", &mms->fpgaio,
53182e2b7e3SPeter Maydell                             TYPE_MPS2_FPGAIO);
53282e2b7e3SPeter Maydell     qdev_prop_set_uint32(DEVICE(&mms->fpgaio), "prescale-clk", an536_oscclk[1]);
53382e2b7e3SPeter Maydell     qdev_prop_set_uint32(DEVICE(&mms->fpgaio), "num-leds", 10);
53482e2b7e3SPeter Maydell     qdev_prop_set_bit(DEVICE(&mms->fpgaio), "has-switches", true);
53582e2b7e3SPeter Maydell     qdev_prop_set_bit(DEVICE(&mms->fpgaio), "has-dbgctrl", false);
53682e2b7e3SPeter Maydell     sysbus_realize(SYS_BUS_DEVICE(&mms->fpgaio), &error_fatal);
53782e2b7e3SPeter Maydell     sysbus_mmio_map(SYS_BUS_DEVICE(&mms->fpgaio), 0, 0xe0202000);
53882e2b7e3SPeter Maydell 
53982e2b7e3SPeter Maydell     create_unimplemented_device("clcd", 0xe0209000, 0x1000);
54082e2b7e3SPeter Maydell 
54182e2b7e3SPeter Maydell     object_initialize_child(OBJECT(mms), "rtc", &mms->rtc, TYPE_PL031);
54282e2b7e3SPeter Maydell     sysbus_realize(SYS_BUS_DEVICE(&mms->rtc), &error_fatal);
54382e2b7e3SPeter Maydell     sysbus_mmio_map(SYS_BUS_DEVICE(&mms->rtc), 0, 0xe020a000);
54482e2b7e3SPeter Maydell     sysbus_connect_irq(SYS_BUS_DEVICE(&mms->rtc), 0,
54582e2b7e3SPeter Maydell                        qdev_get_gpio_in(gicdev, 4));
54682e2b7e3SPeter Maydell 
54782e2b7e3SPeter Maydell     /*
54882e2b7e3SPeter Maydell      * In hardware this is a LAN9220; the LAN9118 is software compatible
54982e2b7e3SPeter Maydell      * except that it doesn't support the checksum-offload feature.
55082e2b7e3SPeter Maydell      */
55182e2b7e3SPeter Maydell     lan9118_init(0xe0300000,
55282e2b7e3SPeter Maydell                  qdev_get_gpio_in(gicdev, 18));
55382e2b7e3SPeter Maydell 
55482e2b7e3SPeter Maydell     create_unimplemented_device("usb", 0xe0301000, 0x1000);
55582e2b7e3SPeter Maydell     create_unimplemented_device("qspi-write-config", 0xe0600000, 0x1000);
55682e2b7e3SPeter Maydell 
5579220b09dSPeter Maydell     mms->bootinfo.ram_size = machine->ram_size;
5589220b09dSPeter Maydell     mms->bootinfo.board_id = -1;
5599220b09dSPeter Maydell     mms->bootinfo.loader_start = mmc->loader_start;
5609220b09dSPeter Maydell     mms->bootinfo.write_secondary_boot = mps3r_write_secondary_boot;
5619220b09dSPeter Maydell     mms->bootinfo.secondary_cpu_reset_hook = mps3r_secondary_cpu_reset;
5629220b09dSPeter Maydell     arm_load_kernel(ARM_CPU(mms->cpu[0]), machine, &mms->bootinfo);
563273a70aeSPeter Maydell }
564273a70aeSPeter Maydell 
mps3r_set_default_ram_info(MPS3RMachineClass * mmc)565273a70aeSPeter Maydell static void mps3r_set_default_ram_info(MPS3RMachineClass *mmc)
566273a70aeSPeter Maydell {
567273a70aeSPeter Maydell     /*
568273a70aeSPeter Maydell      * Set mc->default_ram_size and default_ram_id from the
569273a70aeSPeter Maydell      * information in mmc->raminfo.
570273a70aeSPeter Maydell      */
571273a70aeSPeter Maydell     MachineClass *mc = MACHINE_CLASS(mmc);
572273a70aeSPeter Maydell     const RAMInfo *p;
573273a70aeSPeter Maydell 
574273a70aeSPeter Maydell     for (p = mmc->raminfo; p->name; p++) {
575273a70aeSPeter Maydell         if (p->mrindex < 0) {
576273a70aeSPeter Maydell             /* Found the entry for "system memory" */
577273a70aeSPeter Maydell             mc->default_ram_size = p->size;
578273a70aeSPeter Maydell             mc->default_ram_id = p->name;
5799220b09dSPeter Maydell             mmc->loader_start = p->base;
580273a70aeSPeter Maydell             return;
581273a70aeSPeter Maydell         }
582273a70aeSPeter Maydell     }
583273a70aeSPeter Maydell     g_assert_not_reached();
584273a70aeSPeter Maydell }
585273a70aeSPeter Maydell 
mps3r_class_init(ObjectClass * oc,const void * data)586*12d1a768SPhilippe Mathieu-Daudé static void mps3r_class_init(ObjectClass *oc, const void *data)
587273a70aeSPeter Maydell {
588273a70aeSPeter Maydell     MachineClass *mc = MACHINE_CLASS(oc);
589273a70aeSPeter Maydell 
590273a70aeSPeter Maydell     mc->init = mps3r_common_init;
591273a70aeSPeter Maydell }
592273a70aeSPeter Maydell 
mps3r_an536_class_init(ObjectClass * oc,const void * data)593*12d1a768SPhilippe Mathieu-Daudé static void mps3r_an536_class_init(ObjectClass *oc, const void *data)
594273a70aeSPeter Maydell {
595273a70aeSPeter Maydell     MachineClass *mc = MACHINE_CLASS(oc);
596273a70aeSPeter Maydell     MPS3RMachineClass *mmc = MPS3R_MACHINE_CLASS(oc);
597273a70aeSPeter Maydell     static const char * const valid_cpu_types[] = {
598273a70aeSPeter Maydell         ARM_CPU_TYPE_NAME("cortex-r52"),
599273a70aeSPeter Maydell         NULL
600273a70aeSPeter Maydell     };
601273a70aeSPeter Maydell 
602273a70aeSPeter Maydell     mc->desc = "ARM MPS3 with AN536 FPGA image for Cortex-R52";
6039220b09dSPeter Maydell     /*
6049220b09dSPeter Maydell      * In the real FPGA image there are always two cores, but the standard
6059220b09dSPeter Maydell      * initial setting for the SCC SYSCON 0x000 register is 0x21, meaning
6069220b09dSPeter Maydell      * that the second core is held in reset and halted. Many images built for
6079220b09dSPeter Maydell      * the board do not expect the second core to run at startup (especially
6089220b09dSPeter Maydell      * since on the real FPGA image it is not possible to use LDREX/STREX
6099220b09dSPeter Maydell      * in RAM between the two cores, so a true SMP setup isn't supported).
6109220b09dSPeter Maydell      *
6119220b09dSPeter Maydell      * As QEMU's equivalent of this, we support both -smp 1 and -smp 2,
6129220b09dSPeter Maydell      * with the default being -smp 1. This seems a more intuitive UI for
6139220b09dSPeter Maydell      * QEMU users than, for instance, having a machine property to allow
6149220b09dSPeter Maydell      * the user to set the initial value of the SYSCON 0x000 register.
6159220b09dSPeter Maydell      */
6169220b09dSPeter Maydell     mc->default_cpus = 1;
6179220b09dSPeter Maydell     mc->min_cpus = 1;
6189220b09dSPeter Maydell     mc->max_cpus = 2;
619273a70aeSPeter Maydell     mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-r52");
620273a70aeSPeter Maydell     mc->valid_cpu_types = valid_cpu_types;
621273a70aeSPeter Maydell     mmc->raminfo = an536_raminfo;
622273a70aeSPeter Maydell     mps3r_set_default_ram_info(mmc);
623273a70aeSPeter Maydell }
624273a70aeSPeter Maydell 
625273a70aeSPeter Maydell static const TypeInfo mps3r_machine_types[] = {
626273a70aeSPeter Maydell     {
627273a70aeSPeter Maydell         .name = TYPE_MPS3R_MACHINE,
628273a70aeSPeter Maydell         .parent = TYPE_MACHINE,
629273a70aeSPeter Maydell         .abstract = true,
630273a70aeSPeter Maydell         .instance_size = sizeof(MPS3RMachineState),
631273a70aeSPeter Maydell         .class_size = sizeof(MPS3RMachineClass),
632273a70aeSPeter Maydell         .class_init = mps3r_class_init,
633273a70aeSPeter Maydell     }, {
634273a70aeSPeter Maydell         .name = TYPE_MPS3R_AN536_MACHINE,
635273a70aeSPeter Maydell         .parent = TYPE_MPS3R_MACHINE,
636273a70aeSPeter Maydell         .class_init = mps3r_an536_class_init,
637273a70aeSPeter Maydell     },
638273a70aeSPeter Maydell };
639273a70aeSPeter Maydell 
640273a70aeSPeter Maydell DEFINE_TYPES(mps3r_machine_types);
641