Hello Kane,

On 9/18/25 11:46, Kane Chen wrote:
Hi Cédric,

Adding a bit more context here: I'll fold these details into the commit log in 
the next revision.

LTPI (LVDS Tunneling Protocol & Interface) is defined in the OCP DC-SCM 2.0 
specification (see Figure 2):
https://www.opencompute.org/documents/ocp-dc-scm-2-0-ltpi-ver-1-0-pdf

LTPI is a protocol and physical interface for tunneling various low-speed 
signals between the HPM and SCM. In Figure 2, the AST27x0 (left) integrates two 
LTPI controllers, allowing it to connect to up to two AST1700 boards. On the 
right, the AST1700 side consolidates the HPM FPGA and other interfaces 
(GPIO/UART/I2C/I3C, etc.) onto a single board.

Because the AST1700 exposes additional I/O interfaces (GPIO/I2C/I3C, etc.), we refer to 
it as an "I/O expander". Once connected over LTPI, the AST27x0 can control more 
downstream devices. Note that the AST1700 contains ROM code only and does not support 
firmware updates, so its behavior is fixed.

When using the AST1700, include the following DTS snippets to enable the 
additional interfaces:
https://github.com/AspeedTech-BMC/linux/blob/aspeed-master-v6.6/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi
https://github.com/AspeedTech-BMC/linux/blob/aspeed-master-v6.6/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi

If any information is missing, please let me know and I will do my best to 
provide further details.


Sorry, I was distracted by other topics.

Please resend, taking into account my first comments.

Each device model proposal should include a commit log that briefly
describes the hardware unit, outlines what the model implements,
and what it does not.

AFAIUI, the AST1700 IO expander is different from the AST2700 SoC
and the implementation should rely on its own set of init and realize
handlers.

Thanks,

C.




Best Regards,
Kane
-----Original Message-----
From: Cédric Le Goater <[email protected]>
Sent: Wednesday, September 17, 2025 4:22 PM
To: Kane Chen <[email protected]>; Peter Maydell
<[email protected]>; Steven Lee <[email protected]>; Troy
Lee <[email protected]>; Jamin Lin <[email protected]>; Andrew
Jeffery <[email protected]>; Joel Stanley <[email protected]>;
open list:ASPEED BMCs <[email protected]>; open list:All patches CC
here <[email protected]>
Cc: Troy Lee <[email protected]>
Subject: Re: [SPAM] [PATCH v1 1/6] hw/arm/aspeed: Add 'ioexps-num'
property for AST27x0

Hello Kane,

On 9/17/25 03:31, Kane Chen wrote:
From: Kane-Chen-AS <[email protected]>

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 <[email protected]>
---
   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