On Wed, Dec 24, 2025 at 2:36 AM Cédric Le Goater <[email protected]> wrote: > > On 12/24/25 02:41, Kane Chen via wrote: > > From: Kane-Chen-AS <[email protected]> > > > > LTPI (LVDS Tunneling Protocol & Interface) is defined in the OCP DC-SCM > > 2.0 specification: > > 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. As shown in Figure 2, the AST27x0 (left) > > integrates two LTPI controllers, allowing it to connect to up to two > > extended boards. > > > > This commit introduces a simple device model for the ASPEED LTPI > > controller in QEMU. > > > > The model includes basic MMIO read/write operations and sets default > > register values during reset to emulate a link-up state. > > > > Implements register space with read/write callbacks. > > > > Signed-off-by: Kane-Chen-AS <[email protected]> > > Reviewed-by: Cédric Le Goater <[email protected]> >
Reviewed-by: Nabih Estefan <[email protected]> Tested-by: Nabih Estefan <[email protected]> > > --- > > include/hw/misc/aspeed_ltpi.h | 33 ++++++ > > hw/misc/aspeed_ltpi.c | 193 ++++++++++++++++++++++++++++++++++ > > hw/misc/meson.build | 1 + > > 3 files changed, 227 insertions(+) > > create mode 100644 include/hw/misc/aspeed_ltpi.h > > create mode 100644 hw/misc/aspeed_ltpi.c > > > > diff --git a/include/hw/misc/aspeed_ltpi.h b/include/hw/misc/aspeed_ltpi.h > > new file mode 100644 > > index 0000000000..e991afc666 > > --- /dev/null > > +++ b/include/hw/misc/aspeed_ltpi.h > > @@ -0,0 +1,33 @@ > > +/* > > + * ASPEED LTPI Controller > > + * > > + * Copyright (C) 2025 ASPEED Technology Inc. > > + * > > + * SPDX-License-Identifier: GPL-2.0-or-later > > + */ > > +#ifndef ASPEED_LTPI_H > > +#define ASPEED_LTPI_H > > + > > +#include "hw/sysbus.h" > > + > > +#define TYPE_ASPEED_LTPI "aspeed.ltpi-ctrl" > > +OBJECT_DECLARE_SIMPLE_TYPE(AspeedLTPIState, ASPEED_LTPI) > > + > > +#define ASPEED_LTPI_TOTAL_SIZE 0x900 > > +#define ASPEED_LTPI_CTRL_SIZE 0x200 > > +#define ASPEED_LTPI_PHY_SIZE 0x100 > > +#define ASPEED_LTPI_TOP_SIZE 0x100 > > + > > +struct AspeedLTPIState { > > + SysBusDevice parent; > > + MemoryRegion mmio; > > + MemoryRegion mmio_ctrl; > > + MemoryRegion mmio_phy; > > + MemoryRegion mmio_top; > > + > > + uint32_t ctrl_regs[ASPEED_LTPI_CTRL_SIZE >> 2]; > > + uint32_t phy_regs[ASPEED_LTPI_PHY_SIZE >> 2]; > > + uint32_t top_regs[ASPEED_LTPI_TOP_SIZE >> 2]; > > +}; > > + > > +#endif /* ASPEED_LTPI_H */ > > diff --git a/hw/misc/aspeed_ltpi.c b/hw/misc/aspeed_ltpi.c > > new file mode 100644 > > index 0000000000..131cea9c6b > > --- /dev/null > > +++ b/hw/misc/aspeed_ltpi.c > > @@ -0,0 +1,193 @@ > > +/* > > + * ASPEED LTPI Controller > > + * > > + * Copyright (C) 2025 ASPEED Technology Inc. > > + * > > + * SPDX-License-Identifier: GPL-2.0-or-later > > + */ > > + > > +#include "qemu/osdep.h" > > +#include "qemu/log.h" > > +#include "migration/vmstate.h" > > +#include "hw/misc/aspeed_ltpi.h" > > + > > +#define ASPEED_LTPI_CTRL_BASE 0x000 > > +#define ASPEED_LTPI_PHY_BASE 0x200 > > +#define ASPEED_LTPI_TOP_BASE 0x800 > > + > > +#define LTPI_CTRL_LINK_MNG 0x42 > > +#define LTPI_PHY_MODE 0x0 > > + > > +static uint64_t aspeed_ltpi_top_read(void *opaque, hwaddr offset, unsigned > > size) > > +{ > > + AspeedLTPIState *s = opaque; > > + uint32_t idx = offset >> 2; > > + > > + return s->top_regs[idx]; > > +} > > + > > +static void aspeed_ltpi_top_write(void *opaque, hwaddr offset, > > + uint64_t val, unsigned size) > > +{ > > + AspeedLTPIState *s = opaque; > > + uint32_t idx = offset >> 2; > > + > > + switch (offset) { > > + default: > > + s->top_regs[idx] = (uint32_t)val; > > + break; > > + } > > +} > > + > > +static const MemoryRegionOps aspeed_ltpi_top_ops = { > > + .read = aspeed_ltpi_top_read, > > + .write = aspeed_ltpi_top_write, > > + .endianness = DEVICE_LITTLE_ENDIAN, > > + .valid = { > > + .min_access_size = 1, > > + .max_access_size = 4, > > + }, > > +}; > > + > > +static uint64_t aspeed_ltpi_phy_read(void *opaque, hwaddr offset, unsigned > > size) > > +{ > > + AspeedLTPIState *s = opaque; > > + uint32_t idx = offset >> 2; > > + > > + return s->phy_regs[idx]; > > +} > > + > > +static void aspeed_ltpi_phy_write(void *opaque, hwaddr offset, > > + uint64_t val, unsigned size) > > +{ > > + AspeedLTPIState *s = opaque; > > + uint32_t idx = offset >> 2; > > + > > + switch (offset) { > > + default: > > + s->phy_regs[idx] = (uint32_t)val; > > + break; > > + } > > +} > > + > > +static const MemoryRegionOps aspeed_ltpi_phy_ops = { > > + .read = aspeed_ltpi_phy_read, > > + .write = aspeed_ltpi_phy_write, > > + .endianness = DEVICE_LITTLE_ENDIAN, > > + .valid = { > > + .min_access_size = 1, > > + .max_access_size = 4, > > + }, > > +}; > > + > > +static uint64_t aspeed_ltpi_ctrl_read(void *opaque, > > + hwaddr offset, unsigned size) > > +{ > > + AspeedLTPIState *s = opaque; > > + uint32_t idx = offset >> 2; > > + > > + return s->ctrl_regs[idx]; > > +} > > + > > +static void aspeed_ltpi_ctrl_write(void *opaque, hwaddr offset, > > + uint64_t val, unsigned size) > > +{ > > + AspeedLTPIState *s = opaque; > > + uint32_t idx = offset >> 2; > > + > > + switch (offset) { > > + default: > > + s->ctrl_regs[idx] = (uint32_t)val; > > + break; > > + } > > +} > > + > > +static const MemoryRegionOps aspeed_ltpi_ctrl_ops = { > > + .read = aspeed_ltpi_ctrl_read, > > + .write = aspeed_ltpi_ctrl_write, > > + .endianness = DEVICE_LITTLE_ENDIAN, > > + .valid = { > > + .min_access_size = 1, > > + .max_access_size = 4, > > + }, > > +}; > > + > > +static void aspeed_ltpi_reset(DeviceState *dev) > > +{ > > + AspeedLTPIState *s = ASPEED_LTPI(dev); > > + > > + memset(s->ctrl_regs, 0, sizeof(s->ctrl_regs)); > > + memset(s->phy_regs, 0, sizeof(s->phy_regs)); > > + memset(s->top_regs, 0, sizeof(s->top_regs)); > > + /* set default values */ > > + s->ctrl_regs[LTPI_CTRL_LINK_MNG] = 0x11900007; > > + s->phy_regs[LTPI_PHY_MODE] = 0x2; > > +} > > + > > + > > +static const VMStateDescription vmstate_aspeed_ltpi = { > > + .name = TYPE_ASPEED_LTPI, > > + .version_id = 1, > > + .minimum_version_id = 1, > > + .fields = (VMStateField[]) { > > + VMSTATE_UINT32_ARRAY(ctrl_regs, AspeedLTPIState, > > + ASPEED_LTPI_CTRL_SIZE >> 2), > > + VMSTATE_UINT32_ARRAY(phy_regs, AspeedLTPIState, > > + ASPEED_LTPI_PHY_SIZE >> 2), > > + VMSTATE_UINT32_ARRAY(top_regs, AspeedLTPIState, > > + ASPEED_LTPI_TOP_SIZE >> 2), > > + > > + VMSTATE_END_OF_LIST() > > + } > > +}; > > + > > +static void aspeed_ltpi_realize(DeviceState *dev, Error **errp) > > +{ > > + AspeedLTPIState *s = ASPEED_LTPI(dev); > > + > > + memory_region_init(&s->mmio, OBJECT(s), TYPE_ASPEED_LTPI, > > + ASPEED_LTPI_TOTAL_SIZE); > > + > > + memory_region_init_io(&s->mmio_ctrl, OBJECT(s), > > + &aspeed_ltpi_ctrl_ops, s, > > + "aspeed-ltpi-ctrl", ASPEED_LTPI_CTRL_SIZE); > > + > > + memory_region_init_io(&s->mmio_phy, OBJECT(s), > > + &aspeed_ltpi_phy_ops, s, > > + "aspeed-ltpi-phy", ASPEED_LTPI_PHY_SIZE); > > + > > + memory_region_init_io(&s->mmio_top, OBJECT(s), > > + &aspeed_ltpi_top_ops, s, > > + "aspeed-ltpi-top", ASPEED_LTPI_TOP_SIZE); > > + > > + memory_region_add_subregion(&s->mmio, > > + ASPEED_LTPI_CTRL_BASE, &s->mmio_ctrl); > > + memory_region_add_subregion(&s->mmio, > > + ASPEED_LTPI_PHY_BASE, &s->mmio_phy); > > + memory_region_add_subregion(&s->mmio, > > + ASPEED_LTPI_TOP_BASE, &s->mmio_top); > > + > > + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); > > +} > > + > > +static void aspeed_ltpi_class_init(ObjectClass *klass, const void *data) > > +{ > > + DeviceClass *dc = DEVICE_CLASS(klass); > > + dc->realize = aspeed_ltpi_realize; > > + dc->vmsd = &vmstate_aspeed_ltpi; > > + device_class_set_legacy_reset(dc, aspeed_ltpi_reset); > > +} > > + > > +static const TypeInfo aspeed_ltpi_info = { > > + .name = TYPE_ASPEED_LTPI, > > + .parent = TYPE_SYS_BUS_DEVICE, > > + .instance_size = sizeof(AspeedLTPIState), > > + .class_init = aspeed_ltpi_class_init, > > +}; > > + > > +static void aspeed_ltpi_register_types(void) > > +{ > > + type_register_static(&aspeed_ltpi_info); > > +} > > + > > +type_init(aspeed_ltpi_register_types); > > diff --git a/hw/misc/meson.build b/hw/misc/meson.build > > index b1d8d8e5d2..45b16e7797 100644 > > --- a/hw/misc/meson.build > > +++ b/hw/misc/meson.build > > @@ -136,6 +136,7 @@ system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files( > > 'aspeed_hace.c', > > 'aspeed_i3c.c', > > 'aspeed_lpc.c', > > + 'aspeed_ltpi.c', > > 'aspeed_scu.c', > > 'aspeed_sbc.c', > > 'aspeed_sdmc.c', >
