Instantiate the Caliptra mailbox in the AST1040 SoC and map its SRAM and CSR 
windows at the guest-visible MCI addresses.

Add the 4 KiB MCI aperture controlled by the AST1040 SCU CPTRA page register, 
switch the SoC to the AST1040 SCU model, and expose a machine option that links 
an external mailbox peer after machine initialization.

Signed-off-by: Steven Lee <[email protected]>
---
 include/hw/arm/aspeed_soc.h | 11 ++++++
 hw/arm/aspeed_ast1040.c     | 60 ++++++++++++++++++++++++++++--
 hw/arm/aspeed_ast1040_evb.c | 74 ++++++++++++++++++++++++++++++++++++-
 3 files changed, 140 insertions(+), 5 deletions(-)

diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
index 3aac144cd4..9fad3bc082 100644
--- a/include/hw/arm/aspeed_soc.h
+++ b/include/hw/arm/aspeed_soc.h
@@ -46,6 +46,7 @@
 #include "hw/intc/arm_gicv3.h"
 #include "hw/misc/aspeed_ltpi.h"
 #include "hw/arm/aspeed_ast1700.h"
+#include "hw/misc/aspeed_cptra_mbox.h"
 
 #define VBOOTROM_FILE_NAME  "ast27x0_bootrom.bin"
 
@@ -165,6 +166,16 @@ struct Aspeed10x0SoCState {
 #define TYPE_ASPEED10X0_SOC "aspeed10x0-soc"
 OBJECT_DECLARE_SIMPLE_TYPE(Aspeed10x0SoCState, ASPEED10X0_SOC)
 
+struct Aspeed1040SoCState {
+    Aspeed10x0SoCState parent;
+
+    AspeedCptraMboxState cptra_mbox;
+    MemoryRegion cptra_mci_window;
+};
+
+#define TYPE_ASPEED1040_SOC "ast1040-a0"
+OBJECT_DECLARE_SIMPLE_TYPE(Aspeed1040SoCState, ASPEED1040_SOC)
+
 struct AspeedSoCClass {
     DeviceClass parent_class;
 
diff --git a/hw/arm/aspeed_ast1040.c b/hw/arm/aspeed_ast1040.c
index 8efcdad8f6..c597982bc5 100644
--- a/hw/arm/aspeed_ast1040.c
+++ b/hw/arm/aspeed_ast1040.c
@@ -8,12 +8,17 @@
 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
-#include "system/address-spaces.h"
 #include "system/system.h"
 #include "hw/core/qdev-clock.h"
 #include "hw/misc/unimp.h"
+#include "hw/misc/aspeed_cptra_mbox.h"
 #include "hw/arm/aspeed_soc.h"
 
+#define AST1040_CPTRA_MCI_WINDOW_BASE 0x74200000
+#define AST1040_CPTRA_MCI_WINDOW_SIZE 0x1000
+#define AST1040_CPTRA_MBOX_SRAM_BASE  0x21400000
+#define AST1040_CPTRA_MBOX_CSR_BASE   0x21600000
+
 static const hwaddr aspeed_soc_ast1040_memmap[] = {
     [ASPEED_DEV_SRAM1]     = 0x00000000, /* Hyper RAM */
     [ASPEED_DEV_FMC]       = 0x74000000,
@@ -88,6 +93,7 @@ static qemu_irq aspeed_soc_ast1040_get_irq(AspeedSoCState *s, 
int dev)
 
 static void aspeed_soc_ast1040_init(Object *obj)
 {
+    Aspeed1040SoCState *a1040 = ASPEED1040_SOC(obj);
     Aspeed10x0SoCState *a = ASPEED10X0_SOC(obj);
     AspeedSoCState *s = ASPEED_SOC(obj);
     AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
@@ -96,12 +102,13 @@ static void aspeed_soc_ast1040_init(Object *obj)
 
     s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
 
-    /* AST1040 uses the AST2700 SCUIO model */
-    object_initialize_child(obj, "scu", &s->scu, TYPE_ASPEED_2700_SCUIO);
+    object_initialize_child(obj, "scu", &s->scu, TYPE_ASPEED_1040_SCU);
     qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", sc->silicon_rev);
 
     object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu), "hw-strap1");
     object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu), "hw-strap2");
+    object_initialize_child(obj, "cptra-mbox", &a1040->cptra_mbox,
+                            TYPE_ASPEED_CPTRA_MBOX);
 
     for (i = 0; i < sc->uarts_num; i++) {
         object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_SERIAL_MM);
@@ -120,8 +127,31 @@ static void aspeed_soc_ast1040_init(Object *obj)
                             TYPE_UNIMPLEMENTED_DEVICE);
 }
 
+static bool aspeed_soc_ast1040_realize_cptra_mbox(Aspeed1040SoCState *a1040,
+                                                  Error **errp)
+{
+    AspeedSoCState *s = ASPEED_SOC(a1040);
+    DeviceState *mbox = DEVICE(&a1040->cptra_mbox);
+
+    /*
+     * Caliptra is an AST1040 integrated RoT IP. The external peer is
+     * optional; without a peer, the mailbox registers remain present and
+     * EXECUTE completes with CMD_FAILURE.
+     */
+    if (!sysbus_realize(SYS_BUS_DEVICE(mbox), errp)) {
+        return false;
+    }
+
+    aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(mbox), 0,
+                    AST1040_CPTRA_MBOX_SRAM_BASE);
+    aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(mbox), 1,
+                    AST1040_CPTRA_MBOX_CSR_BASE);
+    return true;
+}
+
 static void aspeed_soc_ast1040_realize(DeviceState *dev_soc, Error **errp)
 {
+    Aspeed1040SoCState *a1040 = ASPEED1040_SOC(dev_soc);
     Aspeed10x0SoCState *a = ASPEED10X0_SOC(dev_soc);
     AspeedSoCState *s = ASPEED_SOC(dev_soc);
     AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
@@ -171,6 +201,27 @@ static void aspeed_soc_ast1040_realize(DeviceState 
*dev_soc, Error **errp)
     memory_region_add_subregion(s->memory, sc->memmap[ASPEED_DEV_SRAM1],
                                 &s->sram[1]);
 
+    if (!aspeed_soc_ast1040_realize_cptra_mbox(a1040, errp)) {
+        return;
+    }
+
+    /*
+     * The Caliptra MCI aperture is a 4 KiB alias whose target is selected by
+     * AST1040_SCU_CPTRA_PAGE_REG0. Firmware commonly switches it between
+     * mailbox SRAM (0x21400000) and mailbox CSR (0x21600000), then accesses
+     * the selected page through 0x74200000.
+     */
+    memory_region_init_alias(&a1040->cptra_mci_window, OBJECT(s),
+                             "aspeed.ast1040.cptra-mci-window", s->memory,
+                             0, AST1040_CPTRA_MCI_WINDOW_SIZE);
+    memory_region_add_subregion(s->memory, AST1040_CPTRA_MCI_WINDOW_BASE,
+                                &a1040->cptra_mci_window);
+    /* The SCU drives the aperture's target offset via SCU_CPTRA_PAGE_REG0. */
+    object_property_set_link(OBJECT(&s->scu), "cptra-page-window",
+                             OBJECT(&a1040->cptra_mci_window), &error_abort);
+    object_property_set_uint(OBJECT(&s->scu), "cptra-page-window-base",
+                             AST1040_CPTRA_MCI_WINDOW_BASE, &error_abort);
+
     /* SCU */
     if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) {
         return;
@@ -244,8 +295,9 @@ static void aspeed_soc_ast1040_class_init(ObjectClass 
*klass, const void *data)
 
 static const TypeInfo aspeed_soc_ast1040_types[] = {
     {
-        .name           = "ast1040-a0",
+        .name           = TYPE_ASPEED1040_SOC,
         .parent         = TYPE_ASPEED10X0_SOC,
+        .instance_size  = sizeof(Aspeed1040SoCState),
         .instance_init  = aspeed_soc_ast1040_init,
         .class_init     = aspeed_soc_ast1040_class_init,
     }
diff --git a/hw/arm/aspeed_ast1040_evb.c b/hw/arm/aspeed_ast1040_evb.c
index 1d9b55247f..eb325a1095 100644
--- a/hw/arm/aspeed_ast1040_evb.c
+++ b/hw/arm/aspeed_ast1040_evb.c
@@ -8,17 +8,59 @@
 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
+#include "qemu/error-report.h"
 #include "hw/arm/boot.h"
 #include "hw/arm/machines-qom.h"
 #include "hw/arm/aspeed.h"
 #include "hw/arm/aspeed_soc.h"
 #include "hw/core/qdev-clock.h"
+#include "hw/misc/aspeed_cptra_mbox.h"
 #include "system/system.h"
 
 #define AST1040_INTERNAL_FLASH_SIZE (4 * MiB)
 /* Main SYSCLK frequency in Hz (400MHz) */
 #define SYSCLK_FRQ 400000000ULL
 
+#define TYPE_AST1040_EVB_MACHINE MACHINE_TYPE_NAME("ast1040-evb")
+OBJECT_DECLARE_SIMPLE_TYPE(Ast1040EvbMachineState, AST1040_EVB_MACHINE)
+
+struct Ast1040EvbMachineState {
+    AspeedMachineState parent_obj;
+
+    char *cptra_peer;
+    Notifier machine_done;
+};
+
+static void aspeed_bic_machine_done(Notifier *notifier, void *data)
+{
+    Ast1040EvbMachineState *m = container_of(notifier,
+                                             Ast1040EvbMachineState,
+                                             machine_done);
+    AspeedMachineState *bmc = ASPEED_MACHINE(m);
+    Aspeed1040SoCState *a1040 = ASPEED1040_SOC(bmc->soc);
+    bool ambiguous = false;
+    Object *peer;
+    Error *err = NULL;
+
+    if (!m->cptra_peer) {
+        return;
+    }
+
+    peer = object_resolve_path_type(m->cptra_peer, TYPE_CPTRA_MBOX_PEER,
+                                    &ambiguous);
+    if (!peer || ambiguous) {
+        error_report("cptra-peer: peer '%s' not found%s",
+                     m->cptra_peer, ambiguous ? " (ambiguous)" : "");
+        exit(1);
+    }
+
+    if (!aspeed_cptra_mbox_set_peer(&a1040->cptra_mbox,
+                                    CPTRA_MBOX_PEER(peer), &err)) {
+        error_report_err(err);
+        exit(1);
+    }
+}
+
 static void aspeed_bic_machine_init(MachineState *machine)
 {
     AspeedMachineState *bmc = ASPEED_MACHINE(machine);
@@ -38,12 +80,35 @@ static void aspeed_bic_machine_init(MachineState *machine)
     aspeed_connect_serial_hds_to_uarts(bmc);
     qdev_realize(DEVICE(bmc->soc), NULL, &error_abort);
 
+    if (AST1040_EVB_MACHINE(machine)->cptra_peer) {
+        AST1040_EVB_MACHINE(machine)->machine_done.notify =
+            aspeed_bic_machine_done;
+        qemu_add_machine_init_done_notifier(
+            &AST1040_EVB_MACHINE(machine)->machine_done);
+    }
+
     armv7m_load_kernel(ARM_CPU(first_cpu),
                        machine->kernel_filename,
                        0,
                        AST1040_INTERNAL_FLASH_SIZE);
 }
 
+static char *aspeed_bic_get_cptra_peer(Object *obj, Error **errp)
+{
+    Ast1040EvbMachineState *m = AST1040_EVB_MACHINE(obj);
+
+    return g_strdup(m->cptra_peer);
+}
+
+static void aspeed_bic_set_cptra_peer(Object *obj, const char *value,
+                                      Error **errp)
+{
+    Ast1040EvbMachineState *m = AST1040_EVB_MACHINE(obj);
+
+    g_free(m->cptra_peer);
+    m->cptra_peer = g_strdup(value);
+}
+
 static void aspeed_machine_ast1040_evb_class_init(ObjectClass *oc,
                                                   const void *data)
 {
@@ -59,12 +124,19 @@ static void 
aspeed_machine_ast1040_evb_class_init(ObjectClass *oc,
     amc->macs_mask = 0;
     amc->uart_default = ASPEED_DEV_UART12;
     aspeed_machine_class_init_cpus_defaults(mc);
+
+    object_class_property_add_str(oc, "cptra-peer",
+                                  aspeed_bic_get_cptra_peer,
+                                  aspeed_bic_set_cptra_peer);
+    object_class_property_set_description(oc, "cptra-peer",
+        "Caliptra mailbox peer object id");
 }
 
 static const TypeInfo aspeed_ast1040_evb_types[] = {
     {
-        .name           = MACHINE_TYPE_NAME("ast1040-evb"),
+        .name           = TYPE_AST1040_EVB_MACHINE,
         .parent         = TYPE_ASPEED_MACHINE,
+        .instance_size  = sizeof(Ast1040EvbMachineState),
         .class_init     = aspeed_machine_ast1040_evb_class_init,
         .interfaces     = arm_machine_interfaces,
     }
-- 
2.43.0


Reply via email to