Hello Kane,

On 9/17/25 03:31, Kane Chen wrote:
From: Kane-Chen-AS <kane_c...@aspeedtech.com>

AST27x0 platforms can attach up to two AST1700 IO expander boards.

what are AST1700 IO expanders ? How are they attached to the main
board ? on which bus ?

Introduce the 'ioexps-num' property to let users specify how many
IO expanders to instantiate for a given machine.
> This enables modeling board variants that ship with 0-2 expanders.

Note: AST2500 and AST2600 do not support IO expanders; this property
is only available on AST27x0 machines.

Command usage:
```
./qemu-system-aarch64 -M ast2700a1-evb,ioexps-num=2 \
   -drive image-bmc,format=raw,if=mtd \
   ...
```

I would prefer these changes modifying the uapi to come at the end
when the modeling is done.


Thanks,

C.




Signed-off-by: Kane-Chen-AS <kane_c...@aspeedtech.com>
---
  include/hw/arm/aspeed_soc.h |  2 ++
  hw/arm/aspeed.c             | 49 +++++++++++++++++++++++++++++++++++++
  2 files changed, 51 insertions(+)

diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
index 217ef0eafd..77263cc6ec 100644
--- a/include/hw/arm/aspeed_soc.h
+++ b/include/hw/arm/aspeed_soc.h
@@ -49,6 +49,7 @@
  #define ASPEED_MACS_NUM  4
  #define ASPEED_UARTS_NUM 13
  #define ASPEED_JTAG_NUM  2
+#define ASPEED_IOEXP_NUM 2
struct AspeedSoCState {
      DeviceState parent;
@@ -103,6 +104,7 @@ struct AspeedSoCState {
      UnimplementedDeviceState ltpi;
      UnimplementedDeviceState jtag[ASPEED_JTAG_NUM];
      AspeedAPB2OPBState fsi[2];
+    uint8_t ioexp_num;
  };
#define TYPE_ASPEED_SOC "aspeed-soc"
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index c31bbe7701..593cb87bfe 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -32,6 +32,7 @@
  #include "qemu/units.h"
  #include "hw/qdev-clock.h"
  #include "system/system.h"
+#include "qapi/visitor.h"
static struct arm_boot_info aspeed_board_binfo = {
      .board_id = -1, /* device-tree-only board */
@@ -49,6 +50,7 @@ struct AspeedMachineState {
      char *fmc_model;
      char *spi_model;
      uint32_t hw_strap1;
+    uint32_t ioexp_num;
  };
/* On 32-bit hosts, lower RAM to 1G because of the 2047 MB limit */
@@ -444,6 +446,9 @@ static void aspeed_machine_init(MachineState *machine)
                               OBJECT(get_system_memory()), &error_abort);
      object_property_set_link(OBJECT(bmc->soc), "dram",
                               OBJECT(machine->ram), &error_abort);
+
+    bmc->soc->ioexp_num = bmc->ioexp_num;
+
      if (amc->sdhci_wp_inverted) {
          for (i = 0; i < bmc->soc->sdhci.num_slots; i++) {
              object_property_set_bool(OBJECT(&bmc->soc->sdhci.slots[i]),
@@ -1486,6 +1491,49 @@ static void 
aspeed_machine_ast2600_class_emmc_init(ObjectClass *oc)
                                            "Set or unset boot from EMMC");
  }
+#ifdef TARGET_AARCH64
+static void aspeed_get_ioexps_num(Object *obj,
+                                  Visitor *v,
+                                  const char *name,
+                                  void *opaque,
+                                  Error **errp)
+{
+    AspeedMachineState *bmc = ASPEED_MACHINE(obj);
+
+    visit_type_uint32(v, name, &bmc->ioexp_num, errp);
+}
+
+static void aspeed_set_ioexps_num(Object *obj,
+                                  Visitor *v,
+                                  const char *name,
+                                  void *opaque,
+                                  Error **errp)
+{
+    uint32_t val;
+    AspeedMachineState *bmc = ASPEED_MACHINE(obj);
+
+    if (!visit_type_uint32(v, name, &val, errp)) {
+        return;
+    }
+
+    if (val > ASPEED_IOEXP_NUM) {
+        error_setg(errp, "IOEXP number is exceeded: %d", val);
+        return;
+    }
+
+    bmc->ioexp_num = val;
+}
+
+
+static void aspeed_machine_ast1700_class_init(ObjectClass *oc)
+{
+    object_class_property_add(oc, "ioexps-num", "uint32",
+                              aspeed_get_ioexps_num,
+                              aspeed_set_ioexps_num,
+                              NULL, NULL);
+}
+#endif
+
  static void aspeed_machine_class_init(ObjectClass *oc, const void *data)
  {
      MachineClass *mc = MACHINE_CLASS(oc);
@@ -2032,6 +2080,7 @@ static void 
aspeed_machine_ast2700a1_evb_class_init(ObjectClass *oc,
      mc->auto_create_sdcard = true;
      mc->default_ram_size = 1 * GiB;
      aspeed_machine_class_init_cpus_defaults(mc);
+    aspeed_machine_ast1700_class_init(oc);
  }
  #endif


Reply via email to