diff mbox series

[RFC,3/6] hw/arm: wire-up memory from the Pico board and the SoC

Message ID 20220110175104.2908956-4-alex.bennee@linaro.org (mailing list archive)
State New, archived
Headers show
Series Basic skeleton of RP2040 Raspbery Pi Pico | expand

Commit Message

Alex Bennée Jan. 10, 2022, 5:51 p.m. UTC
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(-)

Comments

Philippe Mathieu-Daudé Jan. 17, 2022, 12:27 p.m. UTC | #1
On 1/10/22 18:51, Alex Bennée wrote:
> 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(-)

> +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),

Squash that in patch #1 without any MemoryRegion property?
diff mbox series

Patch

diff --git a/include/hw/arm/rp2040.h b/include/hw/arm/rp2040.h
index 6bf4a4e57e..760cef98fc 100644
--- a/include/hw/arm/rp2040.h
+++ b/include/hw/arm/rp2040.h
@@ -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 */
 };
 
 
diff --git a/hw/arm/raspi_pico.c b/hw/arm/raspi_pico.c
index 9826f4d608..76839e93bf 100644
--- a/hw/arm/raspi_pico.c
+++ b/hw/arm/raspi_pico.c
@@ -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)
diff --git a/hw/arm/rp2040.c b/hw/arm/rp2040.c
index 2feedc0da8..c6cc9b7165 100644
--- a/hw/arm/rp2040.c
+++ b/hw/arm/rp2040.c
@@ -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),