@@ -25,7 +25,14 @@ struct RP2040State {
ARMv7MState armv7m[RP2040_NCPUS];
- MemoryRegion container;
+ /* RP2040 regions */
+ MemoryRegion *memory; /* from board */
+ MemoryRegion memory_alias[RP2040_NCPUS - 1];
+
+ MemoryRegion rom; /* internal mask rom */
+ MemoryRegion sram03; /* shared SRAM0-3 banks */
+ MemoryRegion sram4; /* non-stripped SRAM4 */
+ MemoryRegion sram5; /* non-stripped SRAM5 */
};
@@ -22,6 +22,7 @@ struct PiPicoMachineState {
MachineState parent_obj;
/*< public >*/
RP2040State soc;
+ MemoryRegion flash;
};
typedef struct PiPicoMachineState PiPicoMachineState;
@@ -37,14 +38,33 @@ typedef struct PiPicoMachineClass PiPicoMachineClass;
DECLARE_OBJ_CHECKERS(PiPicoMachineState, PiPicoMachineClass,
PIPICO_MACHINE, TYPE_PIPICO_MACHINE)
+#define RP2040_XIP_BASE 0x10000000
static void pipico_machine_init(MachineState *machine)
{
PiPicoMachineState *s = PIPICO_MACHINE(machine);
+ MemoryRegion *sysmem = get_system_memory();
+ Error **errp = &error_fatal;
/* Setup the SOC */
object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RP2040);
+ object_property_set_link(OBJECT(&s->soc), "memory", OBJECT(sysmem), errp);
+
+ /*
+ * The flash device it external to the SoC and mounted on the
+ * PiPico board itself. We will "load" the actual contents with
+ * armv7_load_kernel later although we still rely on the SoC's
+ * mask ROM to get to it.
+ */
+ const uint32_t flash_size = 256 * KiB;
+ memory_region_init_rom(&s->flash, NULL, "pico.flash0", flash_size, errp);
+ memory_region_add_subregion(sysmem, RP2040_XIP_BASE, &s->flash);
+
+
sysbus_realize(SYS_BUS_DEVICE(&s->soc), &error_fatal);
+
+ /* This assumes the "kernel" is positioned in the XIP Flash block */
+ armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, RP2040_XIP_BASE);
}
static void pipico_machine_class_init(ObjectClass *oc, void *data)
@@ -7,10 +7,11 @@
*/
#include "qemu/osdep.h"
+#include "qemu/units.h"
#include "qapi/error.h"
-#include "qemu/module.h"
#include "hw/arm/armv7m.h"
#include "hw/arm/rp2040.h"
+#include "hw/misc/unimp.h"
#include "hw/sysbus.h"
#include "hw/qdev-properties.h"
@@ -27,6 +28,11 @@ typedef struct RP2040Class {
#define RP2040_GET_CLASS(obj) \
OBJECT_GET_CLASS(RP2040Class, (obj), TYPE_RP2040)
+/* See Table 2.2.2 in the RP2040 Datasheet */
+#define RP2040_SRAM_BASE 0x20000000
+#define RP2040_SRAM4_BASE 0x20040000
+#define RP2040_SRAM5_BASE 0x20041000
+
static void rp2040_init(Object *obj)
{
RP2040State *s = RP2040(obj);
@@ -37,6 +43,16 @@ static void rp2040_init(Object *obj)
object_initialize_child(obj, name, &s->armv7m[n], TYPE_ARMV7M);
qdev_prop_set_string(DEVICE(&s->armv7m[n]), "cpu-type",
ARM_CPU_TYPE_NAME("cortex-m0"));
+ /*
+ * Confusingly ARMv7M creates it's own per-core container so
+ * we need to alias additional regions to avoid trying to give
+ * a region two parents.
+ */
+ if (n > 0) {
+ memory_region_init_alias(&s->memory_alias[n - 1], obj,
+ "system-memory.alias", s->memory,
+ 0, -1);
+ }
}
}
@@ -46,14 +62,104 @@ static void rp2040_realize(DeviceState *dev, Error **errp)
Object *obj = OBJECT(dev);
int n;
+ if (!s->memory) {
+ error_setg(errp, "%s: memory property was not set", __func__);
+ return;
+ }
+
+ /* initialize internal 16 KB internal ROM */
+ memory_region_init_rom(&s->rom, obj, "rp2040.rom0", 16 * KiB, errp);
+ memory_region_add_subregion(s->memory, 0, &s->rom);
+
+ /* SRAM (Main 256k bank + two 4k banks)*/
+ memory_region_init_ram(&s->sram03, obj, "rp2040.sram03", 256 * KiB, errp);
+ memory_region_add_subregion(s->memory, RP2040_SRAM_BASE, &s->sram03);
+
+ memory_region_init_ram(&s->sram4, obj, "rp2040.sram4", 4 * KiB, errp);
+ memory_region_add_subregion(s->memory, RP2040_SRAM4_BASE, &s->sram4);
+
+ memory_region_init_ram(&s->sram5, obj, "rp2040.sram5", 4 * KiB, errp);
+ memory_region_add_subregion(s->memory, RP2040_SRAM5_BASE, &s->sram5);
+
+ /* Map all the devices - see table 2.2.2 from the datasheet */
+
+ /* APB Peripherals */
+ create_unimplemented_device("rp2040.sysinfo", 0x40000000, 0x4000);
+ create_unimplemented_device("rp2040.syscfg", 0x40004000, 0x4000);
+ create_unimplemented_device("rp2040.clocks", 0x40008000, 0x4000);
+ create_unimplemented_device("rp2040.resets", 0x4000c000, 0x4000);
+ create_unimplemented_device("rp2040.psm", 0x40010000, 0x4000);
+ create_unimplemented_device("rp2040.iobnk0", 0x40014000, 0x4000);
+ create_unimplemented_device("rp2040.ioqspi", 0x40018000, 0x4000);
+ create_unimplemented_device("rp2040.padsbnk0", 0x4001c000, 0x4000);
+ create_unimplemented_device("rp2040.padsqspi", 0x40020000, 0x4000);
+ create_unimplemented_device("rp2040.xosc", 0x40024000, 0x4000);
+
+ create_unimplemented_device("rp2040.pllsys", 0x40028000, 0x4000);
+ create_unimplemented_device("rp2040.pllusb", 0x4002c000, 0x4000);
+ create_unimplemented_device("rp2040.busctrl", 0x40030000, 0x4000);
+ create_unimplemented_device("rp2040.uart0", 0x40034000, 0x4000);
+ create_unimplemented_device("rp2040.uart1", 0x40038000, 0x4000);
+ create_unimplemented_device("rp2040.spi0", 0x4003c000, 0x4000);
+ create_unimplemented_device("rp2040.spi1", 0x40040000, 0x4000);
+ create_unimplemented_device("rp2040.i2c0", 0x40044000, 0x4000);
+ create_unimplemented_device("rp2040.i2c1", 0x40048000, 0x4000);
+ create_unimplemented_device("rp2040.adc", 0x4004c000, 0x4000);
+ create_unimplemented_device("rp2040.pwm", 0x40050000, 0x4000);
+ create_unimplemented_device("rp2040.timer", 0x40054000, 0x4000);
+ create_unimplemented_device("rp2040.watchdog", 0x40058000, 0x4000);
+ create_unimplemented_device("rp2040.rtc", 0x4005c000, 0x4000);
+ create_unimplemented_device("rp2040.rosc", 0x40060000, 0x4000);
+ create_unimplemented_device("rp2040.vreg&reset", 0x40064000, 0x4000);
+ create_unimplemented_device("rp2040.tbman", 0x4006c000, 0x4000);
+
+ /* AHB-Lite Peripherals */
+ create_unimplemented_device("rp2040.dmabase", 0x50000000, 0x1000);
+
+ /* USB */
+ create_unimplemented_device("rp2040.usbram", 0x50100000, 0x10000);
+ create_unimplemented_device("rp2040.usbregs", 0x50110000, 0x10000);
+
+ /* Remaining AHB-Lite peripherals */
+ create_unimplemented_device("rp2040.pi00", 0x50200000, 0x10000);
+ create_unimplemented_device("rp2040.pi01", 0x50300000, 0x10000);
+
+ /* IOPORT Peripherals */
+ create_unimplemented_device("rp2040.sio", 0xd0000000, 0x10000000);
+
+ /*
+ * Cortex-M0+ internal peripherals (PPB_BASE) are handled by
+ * the v7m model and live at 0xe0000000.
+ */
+
+ /* TODO: deal with stripped aliases */
+
for (n = 0; n < RP2040_NCPUS; n++) {
Object *cpuobj = OBJECT(&s->armv7m[n]);
+ MemoryRegion *mr = n == 0 ? s->memory : &s->memory_alias[n - 1];
+ object_property_set_link(cpuobj, "memory", OBJECT(mr), errp);
+
+ /*
+ * FIXME: temp hack - until more of the logic is emulated we
+ * can't let the second CPU run off into the wild.
+ */
+ if (n > 0) {
+ object_property_set_bool(cpuobj, "start-powered-off",
+ true, &error_fatal);
+ }
+
if (!sysbus_realize(SYS_BUS_DEVICE(cpuobj), errp)) {
return;
}
}
}
+static Property rp2040_soc_properties[] = {
+ DEFINE_PROP_LINK("memory", RP2040State, memory, TYPE_MEMORY_REGION,
+ MemoryRegion *),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void rp2040_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -61,14 +167,13 @@ static void rp2040_class_init(ObjectClass *oc, void *data)
bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-m0");
dc->realize = rp2040_realize;
- /* any props? */
+ device_class_set_props(dc, rp2040_soc_properties);
};
static const TypeInfo rp2040_types[] = {
{
.name = TYPE_RP2040,
- /* .parent = TYPE_SYS_BUS_DEVICE, */
- .parent = TYPE_DEVICE,
+ .parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(RP2040State),
.instance_init = rp2040_init,
.class_size = sizeof(RP2040Class),
All the memory aside from the external flash is a feature of the SoC itself. However the flash is part of the board and different RP2040 boards can choose to wire up different amounts of it. For now add unimplemented devices for all the rp2040 peripheral blocks. Before we can boot more of the ROM we will need to model at least the SIO and CLOCKS blocks. For now CPU#1 starts disabled as it needs a working CPUID register so it can identify itself before sleeping. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- include/hw/arm/rp2040.h | 9 +++- hw/arm/raspi_pico.c | 20 +++++++ hw/arm/rp2040.c | 113 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 137 insertions(+), 5 deletions(-)