[PATCH v1 1/6] hw/arm/aspeed: Add 'ioexps-num' property for AST27x0

Kane Chen via posted 6 patches 1 month, 4 weeks ago
Maintainers: "Cédric Le Goater" <clg@kaod.org>, Peter Maydell <peter.maydell@linaro.org>, Steven Lee <steven_lee@aspeedtech.com>, Troy Lee <leetroy@gmail.com>, Jamin Lin <jamin_lin@aspeedtech.com>, Andrew Jeffery <andrew@codeconstruct.com.au>, Joel Stanley <joel@jms.id.au>
[PATCH v1 1/6] hw/arm/aspeed: Add 'ioexps-num' property for AST27x0
Posted by Kane Chen via 1 month, 4 weeks ago
From: Kane-Chen-AS <kane_chen@aspeedtech.com>

AST27x0 platforms can attach up to two AST1700 IO expander boards.
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 \
  ...
```

Signed-off-by: Kane-Chen-AS <kane_chen@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
 
-- 
2.43.0
Re: [SPAM] [PATCH v1 1/6] hw/arm/aspeed: Add 'ioexps-num' property for AST27x0
Posted by Cédric Le Goater 1 month, 4 weeks ago
Hello Kane,

On 9/17/25 03:31, Kane Chen wrote:
> From: Kane-Chen-AS <kane_chen@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_chen@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
>
RE: [SPAM] [PATCH v1 1/6] hw/arm/aspeed: Add 'ioexps-num' property for AST27x0
Posted by Kane Chen 1 month, 3 weeks ago
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.

Best Regards,
Kane
> -----Original Message-----
> From: Cédric Le Goater <clg@kaod.org>
> Sent: Wednesday, September 17, 2025 4:22 PM
> To: Kane Chen <kane_chen@aspeedtech.com>; Peter Maydell
> <peter.maydell@linaro.org>; Steven Lee <steven_lee@aspeedtech.com>; Troy
> Lee <leetroy@gmail.com>; Jamin Lin <jamin_lin@aspeedtech.com>; Andrew
> Jeffery <andrew@codeconstruct.com.au>; Joel Stanley <joel@jms.id.au>;
> open list:ASPEED BMCs <qemu-arm@nongnu.org>; open list:All patches CC
> here <qemu-devel@nongnu.org>
> Cc: Troy Lee <troy_lee@aspeedtech.com>
> 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 <kane_chen@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_chen@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
> >

Re: [SPAM] [PATCH v1 1/6] hw/arm/aspeed: Add 'ioexps-num' property for AST27x0
Posted by Cédric Le Goater 1 month, 1 week ago
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 <clg@kaod.org>
>> Sent: Wednesday, September 17, 2025 4:22 PM
>> To: Kane Chen <kane_chen@aspeedtech.com>; Peter Maydell
>> <peter.maydell@linaro.org>; Steven Lee <steven_lee@aspeedtech.com>; Troy
>> Lee <leetroy@gmail.com>; Jamin Lin <jamin_lin@aspeedtech.com>; Andrew
>> Jeffery <andrew@codeconstruct.com.au>; Joel Stanley <joel@jms.id.au>;
>> open list:ASPEED BMCs <qemu-arm@nongnu.org>; open list:All patches CC
>> here <qemu-devel@nongnu.org>
>> Cc: Troy Lee <troy_lee@aspeedtech.com>
>> 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 <kane_chen@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_chen@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
>>>
> 


RE: [SPAM] [PATCH v1 1/6] hw/arm/aspeed: Add 'ioexps-num' property for AST27x0
Posted by Kane Chen 1 month, 1 week ago
Hi Cédric,

Thank you for your comments. I'm currently developing a dedicated set of initialization and realize handlers for AST1700. After completing this task, I will submit a new patch series for further review.

Best Regards,
Kane
> -----Original Message-----
> From: Cédric Le Goater <clg@kaod.org>
> Sent: Monday, October 6, 2025 2:52 PM
> To: Kane Chen <kane_chen@aspeedtech.com>; Peter Maydell
> <peter.maydell@linaro.org>; Steven Lee <steven_lee@aspeedtech.com>; Troy
> Lee <leetroy@gmail.com>; Jamin Lin <jamin_lin@aspeedtech.com>; Andrew
> Jeffery <andrew@codeconstruct.com.au>; Joel Stanley <joel@jms.id.au>;
> open list:ASPEED BMCs <qemu-arm@nongnu.org>; open list:All patches CC
> here <qemu-devel@nongnu.org>
> Cc: Troy Lee <troy_lee@aspeedtech.com>
> Subject: Re: [SPAM] [PATCH v1 1/6] hw/arm/aspeed: Add 'ioexps-num'
> property for AST27x0
> 
> 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/a
> > rm64/boot/dts/aspeed/aspeed-ltpi0.dtsi
> >
> https://github.com/AspeedTech-BMC/linux/blob/aspeed-master-v6.6/arch/a
> > rm64/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 <clg@kaod.org>
> >> Sent: Wednesday, September 17, 2025 4:22 PM
> >> To: Kane Chen <kane_chen@aspeedtech.com>; Peter Maydell
> >> <peter.maydell@linaro.org>; Steven Lee <steven_lee@aspeedtech.com>;
> >> Troy Lee <leetroy@gmail.com>; Jamin Lin <jamin_lin@aspeedtech.com>;
> >> Andrew Jeffery <andrew@codeconstruct.com.au>; Joel Stanley
> >> <joel@jms.id.au>; open list:ASPEED BMCs <qemu-arm@nongnu.org>; open
> >> list:All patches CC here <qemu-devel@nongnu.org>
> >> Cc: Troy Lee <troy_lee@aspeedtech.com>
> >> 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 <kane_chen@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_chen@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
> >>>
> >