Re: [PATCH v3 01/18] hw/misc: Add LTPI controller

2025-12-10 Thread Nabih Estefan
On Sun, Dec 7, 2025 at 11:46 PM Kane Chen via  wrote:
>
> From: Kane-Chen-AS 
>
> 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 
> ---
>  include/hw/misc/aspeed_ltpi.h |  32 ++
>  hw/misc/aspeed_ltpi.c | 194 ++
>  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 00..cb1a9f4bd8
> --- /dev/null
> +++ b/include/hw/misc/aspeed_ltpi.h
> @@ -0,0 +1,32 @@
> +/*
> + * 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_CTRL_SIZE   0x200
> +#define ASPEED_LTPI_PHY_SIZE0x100
> +#define ASPEED_LTPI_TOP_SIZE0x100

Is there any specific reason to has ASPEED_LTPI_TOTAL_SIZE declared in
the header, but the rest of the sizes in the main file? More of a nit,
but we should group them all together (probably in the header)

> +
> +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 00..a94ed804a3
> --- /dev/null
> +++ b/hw/misc/aspeed_ltpi.c
> @@ -0,0 +1,194 @@
> +/*
> + * 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_TOTAL_SIZE  0x900
> +#define ASPEED_LTPI_CTRL_BASE   0x000
> +#define ASPEED_LTPI_PHY_BASE0x200
> +#define ASPEED_LTPI_TOP_BASE0x800
> +
> +#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, 

[PATCH v3 01/18] hw/misc: Add LTPI controller

2025-12-07 Thread Kane Chen via
From: Kane-Chen-AS 

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 
---
 include/hw/misc/aspeed_ltpi.h |  32 ++
 hw/misc/aspeed_ltpi.c | 194 ++
 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 00..cb1a9f4bd8
--- /dev/null
+++ b/include/hw/misc/aspeed_ltpi.h
@@ -0,0 +1,32 @@
+/*
+ * 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_CTRL_SIZE   0x200
+#define ASPEED_LTPI_PHY_SIZE0x100
+#define ASPEED_LTPI_TOP_SIZE0x100
+
+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 00..a94ed804a3
--- /dev/null
+++ b/hw/misc/aspeed_ltpi.c
@@ -0,0 +1,194 @@
+/*
+ * 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_TOTAL_SIZE  0x900
+#define ASPEED_LTPI_CTRL_BASE   0x000
+#define ASPEED_LTPI_PHY_BASE0x200
+#define ASPEED_LTPI_TOP_BASE0x800
+
+#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