All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/16] Add AST2700 support
@ 2024-04-16  9:18 Jamin Lin via
  2024-04-16  9:18 ` [PATCH v3 01/16] aspeed/wdt: " Jamin Lin via
                   ` (15 more replies)
  0 siblings, 16 replies; 42+ messages in thread
From: Jamin Lin via @ 2024-04-16  9:18 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, yunlin.tang

Changes from v1:
The patch series supports WDT, SDMC, SMC, SCU, SLI and INTC for AST2700 SoC.

Changes from v2:
- replace is_aarch64 with is_bus64bit for sdmc patch review.
- fix incorrect dram size for AST2700

Changes from v3:
- Add AST2700 Evaluation board in ASPEED document
- Add avocado test cases for AST2700 Evaluation board
- Fix reviewers review issues and add reviewers suggestions
- Implement INTC model GICINT 128 to GICINT136 for AST2700

Test steps:
1. Download the latest openbmc image for AST2700 from AspeedTech-BMC/openbmc
   repository, https://github.com/AspeedTech-BMC/openbmc/releases/tag/v09.01
   link: https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.01/ast2700-default-obmc.tar.gz
2. untar ast2700-default-obmc.tar.gz
   ```
   tar -xf ast2700-default-obmc.tar.gz
   ```
3. Run and the contents of scripts as following
IMGDIR=ast2700-default
UBOOT_SIZE=$(stat --format=%s -L ${IMGDIR}/u-boot-nodtb.bin)
UBOOT_DTB_ADDR=$((0x400000000 + ${UBOOT_SIZE}))

qemu-system-aarch64 -M ast2700-evb -nographic\
 -device loader,addr=0x400000000,file=${IMGDIR}/u-boot-nodtb.bin,force-raw=on\
 -device loader,addr=${UBOOT_DTB_ADDR},file=${IMGDIR}/u-boot.dtb,force-raw=on\
 -device loader,addr=0x430000000,file=${IMGDIR}/bl31.bin,force-raw=on\
 -device loader,addr=0x430080000,file=${IMGDIR}/optee/tee-raw.bin,force-raw=on\
 -device loader,addr=0x430000000,cpu-num=0\
 -device loader,addr=0x430000000,cpu-num=1\
 -device loader,addr=0x430000000,cpu-num=2\
 -device loader,addr=0x430000000,cpu-num=3\
 -smp 4\
 -drive file=${IMGDIR}/image-bmc,format=raw,if=mtd\
 -serial mon:stdio\
 -snapshot

Jamin Lin (16):
  aspeed/wdt: Add AST2700 support
  aspeed/sli: Add AST2700 support
  aspeed/sdmc: remove redundant macros
  aspeed/sdmc: fix coding style
  aspeed/sdmc: Add AST2700 support
  aspeed/smc: correct device description
  aspeed/smc: fix dma moving incorrect data length issue
  aspeed/smc: support 64 bits dma dram address
  aspeed/smc: Add AST2700 support
  aspeed/scu: Add AST2700 support
  aspeed/intc: Add AST2700 support
  aspeed/soc: Add AST2700 support
  aspeed: Add an AST2700 eval board
  aspeed/soc: fix incorrect dram size for AST2700
  test/avocado/machine_aspeed.py: Add AST2700 test case
  docs:aspeed: Add AST2700 Evaluation board

 docs/system/arm/aspeed.rst       |  39 +-
 hw/arm/aspeed.c                  |  32 ++
 hw/arm/aspeed_ast27x0.c          | 646 +++++++++++++++++++++++++++++++
 hw/arm/meson.build               |   1 +
 hw/intc/aspeed_intc.c            | 269 +++++++++++++
 hw/intc/meson.build              |   1 +
 hw/intc/trace-events             |   6 +
 hw/misc/aspeed_scu.c             | 306 ++++++++++++++-
 hw/misc/aspeed_sdmc.c            | 216 ++++++++++-
 hw/misc/aspeed_sli.c             | 178 +++++++++
 hw/misc/meson.build              |   3 +-
 hw/misc/trace-events             |  11 +
 hw/ssi/aspeed_smc.c              | 344 +++++++++++++++-
 hw/ssi/trace-events              |   2 +-
 hw/watchdog/wdt_aspeed.c         |  24 ++
 include/hw/arm/aspeed_soc.h      |  27 +-
 include/hw/intc/aspeed_intc.h    |  35 ++
 include/hw/misc/aspeed_scu.h     |  47 ++-
 include/hw/misc/aspeed_sdmc.h    |   5 +-
 include/hw/misc/aspeed_sli.h     |  31 ++
 include/hw/ssi/aspeed_smc.h      |   1 +
 include/hw/watchdog/wdt_aspeed.h |   3 +-
 tests/avocado/machine_aspeed.py  |  62 +++
 23 files changed, 2234 insertions(+), 55 deletions(-)
 create mode 100644 hw/arm/aspeed_ast27x0.c
 create mode 100644 hw/intc/aspeed_intc.c
 create mode 100644 hw/misc/aspeed_sli.c
 create mode 100644 include/hw/intc/aspeed_intc.h
 create mode 100644 include/hw/misc/aspeed_sli.h

-- 
2.25.1



^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v3 01/16] aspeed/wdt: Add AST2700 support
  2024-04-16  9:18 [PATCH v3 00/16] Add AST2700 support Jamin Lin via
@ 2024-04-16  9:18 ` Jamin Lin via
  2024-04-16  9:18 ` [PATCH v3 02/16] aspeed/sli: " Jamin Lin via
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 42+ messages in thread
From: Jamin Lin via @ 2024-04-16  9:18 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, yunlin.tang

AST2700 wdt controller is similiar to AST2600's wdt, but
the AST2700 has 8 watchdogs, and they each have 0x80 of registers.
Introduce ast2700 object class and increase the number of regs(offset) of
ast2700 model.

Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
 hw/watchdog/wdt_aspeed.c         | 24 ++++++++++++++++++++++++
 include/hw/watchdog/wdt_aspeed.h |  3 ++-
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c
index d70b656f8e..75685c5647 100644
--- a/hw/watchdog/wdt_aspeed.c
+++ b/hw/watchdog/wdt_aspeed.c
@@ -422,12 +422,36 @@ static const TypeInfo aspeed_1030_wdt_info = {
     .class_init = aspeed_1030_wdt_class_init,
 };
 
+static void aspeed_2700_wdt_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass);
+
+    dc->desc = "ASPEED 2700 Watchdog Controller";
+    awc->iosize = 0x80;
+    awc->ext_pulse_width_mask = 0xfffff; /* TODO */
+    awc->reset_ctrl_reg = AST2600_SCU_RESET_CONTROL1;
+    awc->reset_pulse = aspeed_2500_wdt_reset_pulse;
+    awc->wdt_reload = aspeed_wdt_reload_1mhz;
+    awc->sanitize_ctrl = aspeed_2600_sanitize_ctrl;
+    awc->default_status = 0x014FB180;
+    awc->default_reload_value = 0x014FB180;
+}
+
+static const TypeInfo aspeed_2700_wdt_info = {
+    .name = TYPE_ASPEED_2700_WDT,
+    .parent = TYPE_ASPEED_WDT,
+    .instance_size = sizeof(AspeedWDTState),
+    .class_init = aspeed_2700_wdt_class_init,
+};
+
 static void wdt_aspeed_register_types(void)
 {
     type_register_static(&aspeed_wdt_info);
     type_register_static(&aspeed_2400_wdt_info);
     type_register_static(&aspeed_2500_wdt_info);
     type_register_static(&aspeed_2600_wdt_info);
+    type_register_static(&aspeed_2700_wdt_info);
     type_register_static(&aspeed_1030_wdt_info);
 }
 
diff --git a/include/hw/watchdog/wdt_aspeed.h b/include/hw/watchdog/wdt_aspeed.h
index e90ef86651..830b0a7936 100644
--- a/include/hw/watchdog/wdt_aspeed.h
+++ b/include/hw/watchdog/wdt_aspeed.h
@@ -19,9 +19,10 @@ OBJECT_DECLARE_TYPE(AspeedWDTState, AspeedWDTClass, ASPEED_WDT)
 #define TYPE_ASPEED_2400_WDT TYPE_ASPEED_WDT "-ast2400"
 #define TYPE_ASPEED_2500_WDT TYPE_ASPEED_WDT "-ast2500"
 #define TYPE_ASPEED_2600_WDT TYPE_ASPEED_WDT "-ast2600"
+#define TYPE_ASPEED_2700_WDT TYPE_ASPEED_WDT "-ast2700"
 #define TYPE_ASPEED_1030_WDT TYPE_ASPEED_WDT "-ast1030"
 
-#define ASPEED_WDT_REGS_MAX        (0x30 / 4)
+#define ASPEED_WDT_REGS_MAX        (0x80 / 4)
 
 struct AspeedWDTState {
     /*< private >*/
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 02/16] aspeed/sli: Add AST2700 support
  2024-04-16  9:18 [PATCH v3 00/16] Add AST2700 support Jamin Lin via
  2024-04-16  9:18 ` [PATCH v3 01/16] aspeed/wdt: " Jamin Lin via
@ 2024-04-16  9:18 ` Jamin Lin via
  2024-04-16 15:29   ` Cédric Le Goater
  2024-04-16  9:18 ` [PATCH v3 03/16] aspeed/sdmc: remove redundant macros Jamin Lin via
                   ` (13 subsequent siblings)
  15 siblings, 1 reply; 42+ messages in thread
From: Jamin Lin via @ 2024-04-16  9:18 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, yunlin.tang

AST2700 SLI engine is designed to accelerate the
throughput between cross-die connections.
It have CPU_SLI at CPU die and IO_SLI at IO die.

Introduce dummy AST2700 SLI and SLIIO models.

Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
 hw/misc/aspeed_sli.c         | 178 +++++++++++++++++++++++++++++++++++
 hw/misc/meson.build          |   3 +-
 hw/misc/trace-events         |   7 ++
 include/hw/misc/aspeed_sli.h |  31 ++++++
 4 files changed, 218 insertions(+), 1 deletion(-)
 create mode 100644 hw/misc/aspeed_sli.c
 create mode 100644 include/hw/misc/aspeed_sli.h

diff --git a/hw/misc/aspeed_sli.c b/hw/misc/aspeed_sli.c
new file mode 100644
index 0000000000..e84fd6a4ca
--- /dev/null
+++ b/hw/misc/aspeed_sli.c
@@ -0,0 +1,178 @@
+/*
+ * ASPEED SLI Controller
+ *
+ * Copyright (C) 2024 ASPEED Technology Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/error-report.h"
+#include "hw/qdev-properties.h"
+#include "hw/misc/aspeed_sli.h"
+#include "qapi/error.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+#define SLI_REGION_SIZE 0x500
+#define TO_REG(addr) ((addr) >> 2)
+
+static uint64_t aspeed_sli_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    AspeedSLIState *s = ASPEED_SLI(opaque);
+    int reg = TO_REG(addr);
+
+    if (reg >= ARRAY_SIZE(s->regs)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
+                      __func__, addr);
+        return 0;
+    }
+
+    trace_aspeed_sli_read(addr, size, s->regs[reg]);
+    return s->regs[reg];
+}
+
+static void aspeed_sli_write(void *opaque, hwaddr addr, uint64_t data,
+                              unsigned int size)
+{
+    AspeedSLIState *s = ASPEED_SLI(opaque);
+    int reg = TO_REG(addr);
+
+    if (reg >= ARRAY_SIZE(s->regs)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
+                      __func__, addr);
+        return;
+    }
+
+    trace_aspeed_sli_write(addr, size, data);
+    s->regs[reg] = data;
+}
+
+static uint64_t aspeed_sliio_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    AspeedSLIState *s = ASPEED_SLI(opaque);
+    int reg = TO_REG(addr);
+
+    if (reg >= ARRAY_SIZE(s->regs)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
+                      __func__, addr);
+        return 0;
+    }
+
+    trace_aspeed_sliio_read(addr, size, s->regs[reg]);
+    return s->regs[reg];
+}
+
+static void aspeed_sliio_write(void *opaque, hwaddr addr, uint64_t data,
+                              unsigned int size)
+{
+    AspeedSLIState *s = ASPEED_SLI(opaque);
+    int reg = TO_REG(addr);
+
+    if (reg >= ARRAY_SIZE(s->regs)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
+                      __func__, addr);
+        return;
+    }
+
+    trace_aspeed_sliio_write(addr, size, data);
+    s->regs[reg] = data;
+}
+
+static const MemoryRegionOps aspeed_sli_ops = {
+    .read = aspeed_sli_read,
+    .write = aspeed_sli_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps aspeed_sliio_ops = {
+    .read = aspeed_sliio_read,
+    .write = aspeed_sliio_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+};
+
+static void aspeed_sli_realize(DeviceState *dev, Error **errp)
+{
+    AspeedSLIState *s = ASPEED_SLI(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sli_ops, s,
+                          TYPE_ASPEED_SLI, SLI_REGION_SIZE);
+    sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static void aspeed_sliio_realize(DeviceState *dev, Error **errp)
+{
+    AspeedSLIState *s = ASPEED_SLI(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sliio_ops, s,
+                          TYPE_ASPEED_SLI, SLI_REGION_SIZE);
+    sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static void aspeed_sli_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc = "Aspeed SLI Controller";
+    dc->realize = aspeed_sli_realize;
+}
+
+static const TypeInfo aspeed_sli_info = {
+    .name          = TYPE_ASPEED_SLI,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(AspeedSLIState),
+    .class_init    = aspeed_sli_class_init,
+    .class_size    = sizeof(AspeedSLIClass),
+    .abstract      = true,
+};
+
+static void aspeed_2700_sli_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc = "AST2700 SLI Controller";
+}
+
+static void aspeed_2700_sliio_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc = "AST2700 I/O SLI Controller";
+    dc->realize = aspeed_sliio_realize;
+}
+
+static const TypeInfo aspeed_2700_sli_info = {
+    .name           = TYPE_ASPEED_2700_SLI,
+    .parent         = TYPE_ASPEED_SLI,
+    .class_init     = aspeed_2700_sli_class_init,
+};
+
+static const TypeInfo aspeed_2700_sliio_info = {
+    .name           = TYPE_ASPEED_2700_SLIIO,
+    .parent         = TYPE_ASPEED_SLI,
+    .class_init     = aspeed_2700_sliio_class_init,
+};
+
+static void aspeed_sli_register_types(void)
+{
+    type_register_static(&aspeed_sli_info);
+    type_register_static(&aspeed_2700_sli_info);
+    type_register_static(&aspeed_2700_sliio_info);
+}
+
+type_init(aspeed_sli_register_types);
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 86596a3888..2ca8717be2 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -136,7 +136,8 @@ system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
   'aspeed_sbc.c',
   'aspeed_sdmc.c',
   'aspeed_xdma.c',
-  'aspeed_peci.c'))
+  'aspeed_peci.c',
+  'aspeed_sli.c'))
 
 system_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-sysreg.c'))
 system_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_rng.c'))
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index 5d241cb40a..e13b648221 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -351,3 +351,10 @@ djmemc_write(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRI
 # iosb.c
 iosb_read(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u"
 iosb_write(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u"
+
+# aspeed_sli.c
+aspeed_sli_write(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+aspeed_sli_read(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+aspeed_sliio_write(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+aspeed_sliio_read(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+
diff --git a/include/hw/misc/aspeed_sli.h b/include/hw/misc/aspeed_sli.h
new file mode 100644
index 0000000000..2329002b84
--- /dev/null
+++ b/include/hw/misc/aspeed_sli.h
@@ -0,0 +1,31 @@
+/*
+ * ASPEED SLI Controller
+ *
+ * Copyright (C) 2024 ASPEED Technology Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef ASPEED_SLI_H
+#define ASPEED_SLI_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_ASPEED_SLI "aspeed.sli"
+#define TYPE_ASPEED_2700_SLI TYPE_ASPEED_SLI "-ast2700"
+#define TYPE_ASPEED_2700_SLIIO TYPE_ASPEED_SLI "io" "-ast2700"
+OBJECT_DECLARE_TYPE(AspeedSLIState, AspeedSLIClass, ASPEED_SLI)
+
+#define ASPEED_SLI_NR_REGS  (0x500 >> 2)
+
+struct AspeedSLIState {
+    SysBusDevice parent;
+    MemoryRegion iomem;
+
+    uint32_t regs[ASPEED_SLI_NR_REGS];
+};
+
+struct AspeedSLIClass {
+    SysBusDeviceClass parent_class;
+};
+
+#endif /* ASPEED_SLI_H */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 03/16] aspeed/sdmc: remove redundant macros
  2024-04-16  9:18 [PATCH v3 00/16] Add AST2700 support Jamin Lin via
  2024-04-16  9:18 ` [PATCH v3 01/16] aspeed/wdt: " Jamin Lin via
  2024-04-16  9:18 ` [PATCH v3 02/16] aspeed/sli: " Jamin Lin via
@ 2024-04-16  9:18 ` Jamin Lin via
  2024-04-16 15:30   ` Cédric Le Goater
  2024-04-16  9:18 ` [PATCH v3 04/16] aspeed/sdmc: fix coding style Jamin Lin via
                   ` (12 subsequent siblings)
  15 siblings, 1 reply; 42+ messages in thread
From: Jamin Lin via @ 2024-04-16  9:18 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, yunlin.tang

These macros are no longer used for ASPEED SOCs, so removes them.

Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
 hw/misc/aspeed_sdmc.c | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c
index 64cd1a81dc..74279bbe8e 100644
--- a/hw/misc/aspeed_sdmc.c
+++ b/hw/misc/aspeed_sdmc.c
@@ -76,10 +76,6 @@
 #define     ASPEED_SDMC_VGA_32MB            0x2
 #define     ASPEED_SDMC_VGA_64MB            0x3
 #define ASPEED_SDMC_DRAM_SIZE(x)        (x & 0x3)
-#define     ASPEED_SDMC_DRAM_64MB           0x0
-#define     ASPEED_SDMC_DRAM_128MB          0x1
-#define     ASPEED_SDMC_DRAM_256MB          0x2
-#define     ASPEED_SDMC_DRAM_512MB          0x3
 
 #define ASPEED_SDMC_READONLY_MASK                       \
     (ASPEED_SDMC_RESERVED | ASPEED_SDMC_VGA_COMPAT |    \
@@ -100,17 +96,6 @@
 #define ASPEED_SDMC_CACHE_ENABLE        (1 << 10) /* differs from AST2400 */
 #define ASPEED_SDMC_DRAM_TYPE           (1 << 4)  /* differs from AST2400 */
 
-/* DRAM size definitions differs */
-#define     ASPEED_SDMC_AST2500_128MB       0x0
-#define     ASPEED_SDMC_AST2500_256MB       0x1
-#define     ASPEED_SDMC_AST2500_512MB       0x2
-#define     ASPEED_SDMC_AST2500_1024MB      0x3
-
-#define     ASPEED_SDMC_AST2600_256MB       0x0
-#define     ASPEED_SDMC_AST2600_512MB       0x1
-#define     ASPEED_SDMC_AST2600_1024MB      0x2
-#define     ASPEED_SDMC_AST2600_2048MB      0x3
-
 #define ASPEED_SDMC_AST2500_READONLY_MASK                               \
     (ASPEED_SDMC_HW_VERSION(0xf) | ASPEED_SDMC_CACHE_INITIAL_DONE |     \
      ASPEED_SDMC_AST2500_RESERVED | ASPEED_SDMC_VGA_COMPAT |            \
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 04/16] aspeed/sdmc: fix coding style
  2024-04-16  9:18 [PATCH v3 00/16] Add AST2700 support Jamin Lin via
                   ` (2 preceding siblings ...)
  2024-04-16  9:18 ` [PATCH v3 03/16] aspeed/sdmc: remove redundant macros Jamin Lin via
@ 2024-04-16  9:18 ` Jamin Lin via
  2024-04-16 15:30   ` Cédric Le Goater
  2024-04-16  9:18 ` [PATCH v3 05/16] aspeed/sdmc: Add AST2700 support Jamin Lin via
                   ` (11 subsequent siblings)
  15 siblings, 1 reply; 42+ messages in thread
From: Jamin Lin via @ 2024-04-16  9:18 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, yunlin.tang

Fix coding style issues from checkpatch.pl

Test command:
scripts/checkpatch.pl --no-tree -f hw/misc/aspeed_sdmc.c

Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
 hw/misc/aspeed_sdmc.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c
index 74279bbe8e..873d67c592 100644
--- a/hw/misc/aspeed_sdmc.c
+++ b/hw/misc/aspeed_sdmc.c
@@ -296,7 +296,8 @@ static void aspeed_2400_sdmc_write(AspeedSDMCState *s, uint32_t reg,
                                    uint32_t data)
 {
     if (reg == R_PROT) {
-        s->regs[reg] = (data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED;
+        s->regs[reg] =
+            (data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED;
         return;
     }
 
@@ -354,7 +355,8 @@ static void aspeed_2500_sdmc_write(AspeedSDMCState *s, uint32_t reg,
                                    uint32_t data)
 {
     if (reg == R_PROT) {
-        s->regs[reg] = (data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED;
+        s->regs[reg] =
+            (data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED;
         return;
     }
 
@@ -434,8 +436,9 @@ static void aspeed_2600_sdmc_write(AspeedSDMCState *s, uint32_t reg,
     }
 
     if (s->regs[R_PROT] == PROT_HARDLOCKED) {
-        qemu_log_mask(LOG_GUEST_ERROR, "%s: SDMC is locked until system reset!\n",
-                __func__);
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: SDMC is locked until system reset!\n",
+                      __func__);
         return;
     }
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 05/16] aspeed/sdmc: Add AST2700 support
  2024-04-16  9:18 [PATCH v3 00/16] Add AST2700 support Jamin Lin via
                   ` (3 preceding siblings ...)
  2024-04-16  9:18 ` [PATCH v3 04/16] aspeed/sdmc: fix coding style Jamin Lin via
@ 2024-04-16  9:18 ` Jamin Lin via
  2024-04-16 15:34   ` Cédric Le Goater
  2024-04-16  9:18 ` [PATCH v3 06/16] aspeed/smc: correct device description Jamin Lin via
                   ` (10 subsequent siblings)
  15 siblings, 1 reply; 42+ messages in thread
From: Jamin Lin via @ 2024-04-16  9:18 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, yunlin.tang

The SDRAM memory controller(DRAMC) controls the access to external
DDR4 and DDR5 SDRAM and power up to DDR4 and DDR5 PHY.

The DRAM memory controller of AST2700 is not backward compatible
to previous chips such AST2600, AST2500 and AST2400.

Max memory is now 8GiB on the AST2700. Introduce new
aspeed_2700_sdmc and class with read/write operation and
reset handlers.

Define DRAMC necessary protected registers and
unprotected registers for AST2700 and increase
the register set to 0x1000.

Add unlocked property to change controller protected status.

Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
 hw/misc/aspeed_sdmc.c         | 190 +++++++++++++++++++++++++++++++++-
 include/hw/misc/aspeed_sdmc.h |   5 +-
 2 files changed, 193 insertions(+), 2 deletions(-)

diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c
index 873d67c592..69a34903db 100644
--- a/hw/misc/aspeed_sdmc.c
+++ b/hw/misc/aspeed_sdmc.c
@@ -27,6 +27,7 @@
 #define   PROT_SOFTLOCKED    0x00
 
 #define   PROT_KEY_UNLOCK     0xFC600309
+#define   PROT_2700_KEY_UNLOCK  0x1688A8A8
 #define   PROT_KEY_HARDLOCK   0xDEADDEAD /* AST2600 */
 
 /* Configuration Register */
@@ -54,6 +55,46 @@
 #define R_DRAM_TIME       (0x8c / 4)
 #define R_ECC_ERR_INJECT  (0xb4 / 4)
 
+/* AST2700 Register */
+#define R_2700_PROT                 (0x00 / 4)
+#define R_INT_STATUS                (0x04 / 4)
+#define R_INT_CLEAR                 (0x08 / 4)
+#define R_INT_MASK                  (0x0c / 4)
+#define R_MAIN_CONF                 (0x10 / 4)
+#define R_MAIN_CONTROL              (0x14 / 4)
+#define R_MAIN_STATUS               (0x18 / 4)
+#define R_ERR_STATUS                (0x1c / 4)
+#define R_ECC_FAIL_STATUS           (0x78 / 4)
+#define R_ECC_FAIL_ADDR             (0x7c / 4)
+#define R_ECC_TESTING_CONTROL       (0x80 / 4)
+#define R_PROT_REGION_LOCK_STATUS   (0x94 / 4)
+#define R_TEST_FAIL_ADDR            (0xd4 / 4)
+#define R_TEST_FAIL_D0              (0xd8 / 4)
+#define R_TEST_FAIL_D1              (0xdc / 4)
+#define R_TEST_FAIL_D2              (0xe0 / 4)
+#define R_TEST_FAIL_D3              (0xe4 / 4)
+#define R_DBG_STATUS                (0xf4 / 4)
+#define R_PHY_INTERFACE_STATUS      (0xf8 / 4)
+#define R_GRAPHIC_MEM_BASE_ADDR     (0x10c / 4)
+#define R_PORT0_INTERFACE_MONITOR0  (0x240 / 4)
+#define R_PORT0_INTERFACE_MONITOR1  (0x244 / 4)
+#define R_PORT0_INTERFACE_MONITOR2  (0x248 / 4)
+#define R_PORT1_INTERFACE_MONITOR0  (0x2c0 / 4)
+#define R_PORT1_INTERFACE_MONITOR1  (0x2c4 / 4)
+#define R_PORT1_INTERFACE_MONITOR2  (0x2c8 / 4)
+#define R_PORT2_INTERFACE_MONITOR0  (0x340 / 4)
+#define R_PORT2_INTERFACE_MONITOR1  (0x344 / 4)
+#define R_PORT2_INTERFACE_MONITOR2  (0x348 / 4)
+#define R_PORT3_INTERFACE_MONITOR0  (0x3c0 / 4)
+#define R_PORT3_INTERFACE_MONITOR1  (0x3c4 / 4)
+#define R_PORT3_INTERFACE_MONITOR2  (0x3c8 / 4)
+#define R_PORT4_INTERFACE_MONITOR0  (0x440 / 4)
+#define R_PORT4_INTERFACE_MONITOR1  (0x444 / 4)
+#define R_PORT4_INTERFACE_MONITOR2  (0x448 / 4)
+#define R_PORT5_INTERFACE_MONITOR0  (0x4c0 / 4)
+#define R_PORT5_INTERFACE_MONITOR1  (0x4c4 / 4)
+#define R_PORT5_INTERFACE_MONITOR2  (0x4c8 / 4)
+
 /*
  * Configuration register Ox4 (for Aspeed AST2400 SOC)
  *
@@ -101,6 +142,19 @@
      ASPEED_SDMC_AST2500_RESERVED | ASPEED_SDMC_VGA_COMPAT |            \
      ASPEED_SDMC_VGA_APERTURE(ASPEED_SDMC_VGA_64MB))
 
+/*
+ * Main Configuration register Ox10 (for Aspeed AST2700 SOC and higher)
+ *
+ */
+#define ASPEED_SDMC_AST2700_RESERVED        0xFFFF2082 /* 31:16, 13, 7, 1 */
+#define ASPEED_SDMC_AST2700_DATA_SCRAMBLE           (1 << 8)
+#define ASPEED_SDMC_AST2700_ECC_ENABLE              (1 << 6)
+#define ASPEED_SDMC_AST2700_PAGE_MATCHING_ENABLE    (1 << 5)
+#define ASPEED_SDMC_AST2700_DRAM_SIZE(x)            ((x & 0x7) << 2)
+
+#define ASPEED_SDMC_AST2700_READONLY_MASK   \
+     (ASPEED_SDMC_AST2700_RESERVED)
+
 static uint64_t aspeed_sdmc_read(void *opaque, hwaddr addr, unsigned size)
 {
     AspeedSDMCState *s = ASPEED_SDMC(opaque);
@@ -216,7 +270,7 @@ static void aspeed_sdmc_realize(DeviceState *dev, Error **errp)
     AspeedSDMCState *s = ASPEED_SDMC(dev);
     AspeedSDMCClass *asc = ASPEED_SDMC_GET_CLASS(s);
 
-    assert(asc->max_ram_size < 4 * GiB); /* 32-bit address bus */
+    assert(asc->max_ram_size < 4 * GiB || asc->is_bus64bit);
     s->max_ram_size = asc->max_ram_size;
 
     memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sdmc_ops, s,
@@ -236,6 +290,7 @@ static const VMStateDescription vmstate_aspeed_sdmc = {
 
 static Property aspeed_sdmc_properties[] = {
     DEFINE_PROP_UINT64("max-ram-size", AspeedSDMCState, max_ram_size, 0),
+    DEFINE_PROP_BOOL("unlocked", AspeedSDMCState, unlocked, false),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -500,12 +555,145 @@ static const TypeInfo aspeed_2600_sdmc_info = {
     .class_init = aspeed_2600_sdmc_class_init,
 };
 
+static void aspeed_2700_sdmc_reset(DeviceState *dev)
+{
+    AspeedSDMCState *s = ASPEED_SDMC(dev);
+    AspeedSDMCClass *asc = ASPEED_SDMC_GET_CLASS(s);
+
+    memset(s->regs, 0, sizeof(s->regs));
+
+    /* Set ram size bit and defaults values */
+    s->regs[R_MAIN_CONF] = asc->compute_conf(s, 0);
+
+    if (s->unlocked) {
+        s->regs[R_2700_PROT] = PROT_UNLOCKED;
+    }
+}
+
+static uint32_t aspeed_2700_sdmc_compute_conf(AspeedSDMCState *s, uint32_t data)
+{
+    uint32_t fixed_conf = ASPEED_SDMC_AST2700_PAGE_MATCHING_ENABLE |
+        ASPEED_SDMC_AST2700_DRAM_SIZE(aspeed_sdmc_get_ram_bits(s));
+
+    /* Make sure readonly bits are kept */
+    data &= ~ASPEED_SDMC_AST2700_READONLY_MASK;
+
+    return data | fixed_conf;
+}
+
+static void aspeed_2700_sdmc_write(AspeedSDMCState *s, uint32_t reg,
+                                   uint32_t data)
+{
+    /* Unprotected registers */
+    switch (reg) {
+    case R_INT_STATUS:
+    case R_INT_CLEAR:
+    case R_INT_MASK:
+    case R_MAIN_STATUS:
+    case R_ERR_STATUS:
+    case R_ECC_FAIL_STATUS:
+    case R_ECC_FAIL_ADDR:
+    case R_PROT_REGION_LOCK_STATUS:
+    case R_TEST_FAIL_ADDR:
+    case R_TEST_FAIL_D0:
+    case R_TEST_FAIL_D1:
+    case R_TEST_FAIL_D2:
+    case R_TEST_FAIL_D3:
+    case R_DBG_STATUS:
+    case R_PHY_INTERFACE_STATUS:
+    case R_GRAPHIC_MEM_BASE_ADDR:
+    case R_PORT0_INTERFACE_MONITOR0:
+    case R_PORT0_INTERFACE_MONITOR1:
+    case R_PORT0_INTERFACE_MONITOR2:
+    case R_PORT1_INTERFACE_MONITOR0:
+    case R_PORT1_INTERFACE_MONITOR1:
+    case R_PORT1_INTERFACE_MONITOR2:
+    case R_PORT2_INTERFACE_MONITOR0:
+    case R_PORT2_INTERFACE_MONITOR1:
+    case R_PORT2_INTERFACE_MONITOR2:
+    case R_PORT3_INTERFACE_MONITOR0:
+    case R_PORT3_INTERFACE_MONITOR1:
+    case R_PORT3_INTERFACE_MONITOR2:
+    case R_PORT4_INTERFACE_MONITOR0:
+    case R_PORT4_INTERFACE_MONITOR1:
+    case R_PORT4_INTERFACE_MONITOR2:
+    case R_PORT5_INTERFACE_MONITOR0:
+    case R_PORT5_INTERFACE_MONITOR1:
+    case R_PORT5_INTERFACE_MONITOR2:
+        s->regs[reg] = data;
+        return;
+    }
+
+    if (s->regs[R_2700_PROT] == PROT_HARDLOCKED) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: SDMC is locked until system reset!\n",
+                      __func__);
+        return;
+    }
+
+    if (reg != R_2700_PROT && s->regs[R_2700_PROT] == PROT_SOFTLOCKED) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: SDMC is locked! (write to MCR%02x blocked)\n",
+                      __func__, reg * 4);
+        return;
+    }
+
+    switch (reg) {
+    case R_2700_PROT:
+        if (data == PROT_2700_KEY_UNLOCK)  {
+            data = PROT_UNLOCKED;
+        } else if (data == PROT_KEY_HARDLOCK) {
+            data = PROT_HARDLOCKED;
+        } else {
+            data = PROT_SOFTLOCKED;
+        }
+        break;
+    case R_MAIN_CONF:
+        data = aspeed_2700_sdmc_compute_conf(s, data);
+        break;
+    case R_MAIN_STATUS:
+        /* Will never return 'busy'. */
+        data &= ~PHY_BUSY_STATE;
+        break;
+    default:
+        break;
+    }
+
+    s->regs[reg] = data;
+}
+
+static const uint64_t
+    aspeed_2700_ram_sizes[] = { 256 * MiB, 512 * MiB, 1024 * MiB,
+                                2048 * MiB, 4096 * MiB, 8192 * MiB, 0};
+
+static void aspeed_2700_sdmc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass);
+
+    dc->desc = "ASPEED 2700 SDRAM Memory Controller";
+    dc->reset = aspeed_2700_sdmc_reset;
+
+    asc->is_bus64bit = true;
+    asc->max_ram_size = 8 * GiB;
+    asc->compute_conf = aspeed_2700_sdmc_compute_conf;
+    asc->write = aspeed_2700_sdmc_write;
+    asc->valid_ram_sizes = aspeed_2700_ram_sizes;
+}
+
+static const TypeInfo aspeed_2700_sdmc_info = {
+    .name = TYPE_ASPEED_2700_SDMC,
+    .parent = TYPE_ASPEED_SDMC,
+    .class_init = aspeed_2700_sdmc_class_init,
+};
+
 static void aspeed_sdmc_register_types(void)
 {
     type_register_static(&aspeed_sdmc_info);
     type_register_static(&aspeed_2400_sdmc_info);
     type_register_static(&aspeed_2500_sdmc_info);
     type_register_static(&aspeed_2600_sdmc_info);
+    type_register_static(&aspeed_2700_sdmc_info);
 }
 
 type_init(aspeed_sdmc_register_types);
diff --git a/include/hw/misc/aspeed_sdmc.h b/include/hw/misc/aspeed_sdmc.h
index ec2d59a14f..61c979583a 100644
--- a/include/hw/misc/aspeed_sdmc.h
+++ b/include/hw/misc/aspeed_sdmc.h
@@ -17,6 +17,7 @@ OBJECT_DECLARE_TYPE(AspeedSDMCState, AspeedSDMCClass, ASPEED_SDMC)
 #define TYPE_ASPEED_2400_SDMC TYPE_ASPEED_SDMC "-ast2400"
 #define TYPE_ASPEED_2500_SDMC TYPE_ASPEED_SDMC "-ast2500"
 #define TYPE_ASPEED_2600_SDMC TYPE_ASPEED_SDMC "-ast2600"
+#define TYPE_ASPEED_2700_SDMC TYPE_ASPEED_SDMC "-ast2700"
 
 /*
  * SDMC has 174 documented registers. In addition the u-boot device tree
@@ -29,7 +30,7 @@ OBJECT_DECLARE_TYPE(AspeedSDMCState, AspeedSDMCClass, ASPEED_SDMC)
  * time, and the other is in the DDR-PHY IP which is used during DDR-PHY
  * training.
  */
-#define ASPEED_SDMC_NR_REGS (0x500 >> 2)
+#define ASPEED_SDMC_NR_REGS (0x1000 >> 2)
 
 struct AspeedSDMCState {
     /*< private >*/
@@ -41,6 +42,7 @@ struct AspeedSDMCState {
     uint32_t regs[ASPEED_SDMC_NR_REGS];
     uint64_t ram_size;
     uint64_t max_ram_size;
+    bool unlocked;
 };
 
 
@@ -51,6 +53,7 @@ struct AspeedSDMCClass {
     const uint64_t *valid_ram_sizes;
     uint32_t (*compute_conf)(AspeedSDMCState *s, uint32_t data);
     void (*write)(AspeedSDMCState *s, uint32_t reg, uint32_t data);
+    bool is_bus64bit;
 };
 
 #endif /* ASPEED_SDMC_H */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 06/16] aspeed/smc: correct device description
  2024-04-16  9:18 [PATCH v3 00/16] Add AST2700 support Jamin Lin via
                   ` (4 preceding siblings ...)
  2024-04-16  9:18 ` [PATCH v3 05/16] aspeed/sdmc: Add AST2700 support Jamin Lin via
@ 2024-04-16  9:18 ` Jamin Lin via
  2024-04-16 15:34   ` Cédric Le Goater
  2024-04-16  9:18 ` [PATCH v3 07/16] aspeed/smc: fix dma moving incorrect data length issue Jamin Lin via
                   ` (9 subsequent siblings)
  15 siblings, 1 reply; 42+ messages in thread
From: Jamin Lin via @ 2024-04-16  9:18 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, yunlin.tang

Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
 hw/ssi/aspeed_smc.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index 6e1a84c197..8a8d77b480 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -1448,7 +1448,7 @@ static void aspeed_2500_fmc_class_init(ObjectClass *klass, void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
     AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
 
-    dc->desc               = "Aspeed 2600 FMC Controller";
+    dc->desc               = "Aspeed 2500 FMC Controller";
     asc->r_conf            = R_CONF;
     asc->r_ce_ctrl         = R_CE_CTRL;
     asc->r_ctrl0           = R_CTRL0;
@@ -1486,7 +1486,7 @@ static void aspeed_2500_spi1_class_init(ObjectClass *klass, void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
     AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
 
-    dc->desc               = "Aspeed 2600 SPI1 Controller";
+    dc->desc               = "Aspeed 2500 SPI1 Controller";
     asc->r_conf            = R_CONF;
     asc->r_ce_ctrl         = R_CE_CTRL;
     asc->r_ctrl0           = R_CTRL0;
@@ -1521,7 +1521,7 @@ static void aspeed_2500_spi2_class_init(ObjectClass *klass, void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
     AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
 
-    dc->desc               = "Aspeed 2600 SPI2 Controller";
+    dc->desc               = "Aspeed 2500 SPI2 Controller";
     asc->r_conf            = R_CONF;
     asc->r_ce_ctrl         = R_CE_CTRL;
     asc->r_ctrl0           = R_CTRL0;
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 07/16] aspeed/smc: fix dma moving incorrect data length issue
  2024-04-16  9:18 [PATCH v3 00/16] Add AST2700 support Jamin Lin via
                   ` (5 preceding siblings ...)
  2024-04-16  9:18 ` [PATCH v3 06/16] aspeed/smc: correct device description Jamin Lin via
@ 2024-04-16  9:18 ` Jamin Lin via
  2024-04-19 13:41   ` Cédric Le Goater
  2024-04-16  9:18 ` [PATCH v3 08/16] aspeed/smc: support 64 bits dma dram address Jamin Lin via
                   ` (8 subsequent siblings)
  15 siblings, 1 reply; 42+ messages in thread
From: Jamin Lin via @ 2024-04-16  9:18 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, yunlin.tang

DMA length is from 1 byte to 32MB for AST2600 and AST10x0
and DMA length is from 4 bytes to 32MB for AST2500.

In other words, if "R_DMA_LEN" is 0, it should move at least 1 byte
data for AST2600 and AST10x0 and 4 bytes data for AST2500.
To support all ASPEED SOCs, adds dma_start_length parameter to store
the start length, add helper routines function to compute the dma length
and update DMA_LENGTH mask to "1FFFFFF" to fix dma moving
incorrect data length issue.

Currently, only supports dma length 4 bytes aligned.

Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
 hw/ssi/aspeed_smc.c         | 52 ++++++++++++++++++++++++++++++++-----
 include/hw/ssi/aspeed_smc.h |  1 +
 2 files changed, 46 insertions(+), 7 deletions(-)

diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index 8a8d77b480..71abc7a2d8 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -178,13 +178,17 @@
  * DMA flash addresses should be 4 bytes aligned and the valid address
  * range is 0x20000000 - 0x2FFFFFFF.
  *
- * DMA length is from 4 bytes to 32MB
+ * DMA length is from 4 bytes to 32MB (AST2500)
  *   0: 4 bytes
  *   0x7FFFFF: 32M bytes
+ *
+ * DMA length is from 1 byte to 32MB (AST2600, AST10x0)
+ *   0: 1 byte
+ *   0x1FFFFFF: 32M bytes
  */
 #define DMA_DRAM_ADDR(asc, val)   ((val) & (asc)->dma_dram_mask)
 #define DMA_FLASH_ADDR(asc, val)  ((val) & (asc)->dma_flash_mask)
-#define DMA_LENGTH(val)         ((val) & 0x01FFFFFC)
+#define DMA_LENGTH(val)         ((val) & 0x01FFFFFF)
 
 /* Flash opcodes. */
 #define SPI_OP_READ       0x03    /* Read data bytes (low frequency) */
@@ -843,6 +847,24 @@ static bool aspeed_smc_inject_read_failure(AspeedSMCState *s)
     }
 }
 
+static uint32_t aspeed_smc_dma_len(AspeedSMCState *s)
+{
+    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
+    uint32_t dma_len;
+    uint32_t extra;
+
+    dma_len = s->regs[R_DMA_LEN] + asc->dma_start_length;
+
+    /* dma length 4 bytes aligned */
+    extra = dma_len % 4;
+
+    if (extra != 0) {
+        dma_len += 4 - extra;
+    }
+
+    return dma_len;
+}
+
 /*
  * Accumulate the result of the reads to provide a checksum that will
  * be used to validate the read timing settings.
@@ -850,6 +872,7 @@ static bool aspeed_smc_inject_read_failure(AspeedSMCState *s)
 static void aspeed_smc_dma_checksum(AspeedSMCState *s)
 {
     MemTxResult result;
+    uint32_t dma_len;
     uint32_t data;
 
     if (s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE) {
@@ -861,7 +884,9 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
         aspeed_smc_dma_calibration(s);
     }
 
-    while (s->regs[R_DMA_LEN]) {
+    dma_len = aspeed_smc_dma_len(s);
+
+    while (dma_len) {
         data = address_space_ldl_le(&s->flash_as, s->regs[R_DMA_FLASH_ADDR],
                                     MEMTXATTRS_UNSPECIFIED, &result);
         if (result != MEMTX_OK) {
@@ -877,7 +902,8 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
          */
         s->regs[R_DMA_CHECKSUM] += data;
         s->regs[R_DMA_FLASH_ADDR] += 4;
-        s->regs[R_DMA_LEN] -= 4;
+        dma_len -= 4;
+        s->regs[R_DMA_LEN] = dma_len;
     }
 
     if (s->inject_failure && aspeed_smc_inject_read_failure(s)) {
@@ -889,14 +915,17 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
 static void aspeed_smc_dma_rw(AspeedSMCState *s)
 {
     MemTxResult result;
+    uint32_t dma_len;
     uint32_t data;
 
+    dma_len = aspeed_smc_dma_len(s);
+
     trace_aspeed_smc_dma_rw(s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE ?
                             "write" : "read",
                             s->regs[R_DMA_FLASH_ADDR],
                             s->regs[R_DMA_DRAM_ADDR],
-                            s->regs[R_DMA_LEN]);
-    while (s->regs[R_DMA_LEN]) {
+                            dma_len);
+    while (dma_len) {
         if (s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE) {
             data = address_space_ldl_le(&s->dram_as, s->regs[R_DMA_DRAM_ADDR],
                                         MEMTXATTRS_UNSPECIFIED, &result);
@@ -937,7 +966,8 @@ static void aspeed_smc_dma_rw(AspeedSMCState *s)
          */
         s->regs[R_DMA_FLASH_ADDR] += 4;
         s->regs[R_DMA_DRAM_ADDR] += 4;
-        s->regs[R_DMA_LEN] -= 4;
+        dma_len -= 4;
+        s->regs[R_DMA_LEN] = dma_len;
         s->regs[R_DMA_CHECKSUM] += data;
     }
 }
@@ -1381,6 +1411,7 @@ static void aspeed_2400_fmc_class_init(ObjectClass *klass, void *data)
     asc->features          = ASPEED_SMC_FEATURE_DMA;
     asc->dma_flash_mask    = 0x0FFFFFFC;
     asc->dma_dram_mask     = 0x1FFFFFFC;
+    asc->dma_start_length  = 4;
     asc->nregs             = ASPEED_SMC_R_MAX;
     asc->segment_to_reg    = aspeed_smc_segment_to_reg;
     asc->reg_to_segment    = aspeed_smc_reg_to_segment;
@@ -1464,6 +1495,7 @@ static void aspeed_2500_fmc_class_init(ObjectClass *klass, void *data)
     asc->features          = ASPEED_SMC_FEATURE_DMA;
     asc->dma_flash_mask    = 0x0FFFFFFC;
     asc->dma_dram_mask     = 0x3FFFFFFC;
+    asc->dma_start_length  = 4;
     asc->nregs             = ASPEED_SMC_R_MAX;
     asc->segment_to_reg    = aspeed_smc_segment_to_reg;
     asc->reg_to_segment    = aspeed_smc_reg_to_segment;
@@ -1620,6 +1652,7 @@ static void aspeed_2600_fmc_class_init(ObjectClass *klass, void *data)
                              ASPEED_SMC_FEATURE_WDT_CONTROL;
     asc->dma_flash_mask    = 0x0FFFFFFC;
     asc->dma_dram_mask     = 0x3FFFFFFC;
+    asc->dma_start_length  = 1;
     asc->nregs             = ASPEED_SMC_R_MAX;
     asc->segment_to_reg    = aspeed_2600_smc_segment_to_reg;
     asc->reg_to_segment    = aspeed_2600_smc_reg_to_segment;
@@ -1658,6 +1691,7 @@ static void aspeed_2600_spi1_class_init(ObjectClass *klass, void *data)
                              ASPEED_SMC_FEATURE_DMA_GRANT;
     asc->dma_flash_mask    = 0x0FFFFFFC;
     asc->dma_dram_mask     = 0x3FFFFFFC;
+    asc->dma_start_length  = 1;
     asc->nregs             = ASPEED_SMC_R_MAX;
     asc->segment_to_reg    = aspeed_2600_smc_segment_to_reg;
     asc->reg_to_segment    = aspeed_2600_smc_reg_to_segment;
@@ -1697,6 +1731,7 @@ static void aspeed_2600_spi2_class_init(ObjectClass *klass, void *data)
                              ASPEED_SMC_FEATURE_DMA_GRANT;
     asc->dma_flash_mask    = 0x0FFFFFFC;
     asc->dma_dram_mask     = 0x3FFFFFFC;
+    asc->dma_start_length  = 1;
     asc->nregs             = ASPEED_SMC_R_MAX;
     asc->segment_to_reg    = aspeed_2600_smc_segment_to_reg;
     asc->reg_to_segment    = aspeed_2600_smc_reg_to_segment;
@@ -1778,6 +1813,7 @@ static void aspeed_1030_fmc_class_init(ObjectClass *klass, void *data)
     asc->features          = ASPEED_SMC_FEATURE_DMA;
     asc->dma_flash_mask    = 0x0FFFFFFC;
     asc->dma_dram_mask     = 0x000BFFFC;
+    asc->dma_start_length  = 1;
     asc->nregs             = ASPEED_SMC_R_MAX;
     asc->segment_to_reg    = aspeed_1030_smc_segment_to_reg;
     asc->reg_to_segment    = aspeed_1030_smc_reg_to_segment;
@@ -1815,6 +1851,7 @@ static void aspeed_1030_spi1_class_init(ObjectClass *klass, void *data)
     asc->features          = ASPEED_SMC_FEATURE_DMA;
     asc->dma_flash_mask    = 0x0FFFFFFC;
     asc->dma_dram_mask     = 0x000BFFFC;
+    asc->dma_start_length  = 1;
     asc->nregs             = ASPEED_SMC_R_MAX;
     asc->segment_to_reg    = aspeed_2600_smc_segment_to_reg;
     asc->reg_to_segment    = aspeed_2600_smc_reg_to_segment;
@@ -1851,6 +1888,7 @@ static void aspeed_1030_spi2_class_init(ObjectClass *klass, void *data)
     asc->features          = ASPEED_SMC_FEATURE_DMA;
     asc->dma_flash_mask    = 0x0FFFFFFC;
     asc->dma_dram_mask     = 0x000BFFFC;
+    asc->dma_start_length  = 1;
     asc->nregs             = ASPEED_SMC_R_MAX;
     asc->segment_to_reg    = aspeed_2600_smc_segment_to_reg;
     asc->reg_to_segment    = aspeed_2600_smc_reg_to_segment;
diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h
index 8e1dda556b..f359ed22cc 100644
--- a/include/hw/ssi/aspeed_smc.h
+++ b/include/hw/ssi/aspeed_smc.h
@@ -106,6 +106,7 @@ struct AspeedSMCClass {
     uint32_t features;
     hwaddr dma_flash_mask;
     hwaddr dma_dram_mask;
+    uint32_t dma_start_length;
     uint32_t nregs;
     uint32_t (*segment_to_reg)(const AspeedSMCState *s,
                                const AspeedSegments *seg);
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 08/16] aspeed/smc: support 64 bits dma dram address
  2024-04-16  9:18 [PATCH v3 00/16] Add AST2700 support Jamin Lin via
                   ` (6 preceding siblings ...)
  2024-04-16  9:18 ` [PATCH v3 07/16] aspeed/smc: fix dma moving incorrect data length issue Jamin Lin via
@ 2024-04-16  9:18 ` Jamin Lin via
  2024-04-18 16:09   ` Cédric Le Goater
  2024-05-07 14:19   ` Cédric Le Goater
  2024-04-16  9:18 ` [PATCH v3 09/16] aspeed/smc: Add AST2700 support Jamin Lin via
                   ` (7 subsequent siblings)
  15 siblings, 2 replies; 42+ messages in thread
From: Jamin Lin via @ 2024-04-16  9:18 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, yunlin.tang

AST2700 support the maximum dram size is 8GiB
and has a "DMA DRAM Side Address High Part(0x7C)"
register to support 64 bits dma dram address.
Add helper routines functions to compute the dma dram
address, new features and update trace-event
to support 64 bits dram address.

Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
 hw/ssi/aspeed_smc.c | 66 +++++++++++++++++++++++++++++++++++++++------
 hw/ssi/trace-events |  2 +-
 2 files changed, 59 insertions(+), 9 deletions(-)

diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index 71abc7a2d8..a67cac3d0f 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -132,6 +132,9 @@
 #define   FMC_WDT2_CTRL_BOOT_SOURCE      BIT(4) /* O: primary 1: alternate */
 #define   FMC_WDT2_CTRL_EN               BIT(0)
 
+/* DMA DRAM Side Address High Part (AST2700) */
+#define R_DMA_DRAM_ADDR_HIGH   (0x7c / 4)
+
 /* DMA Control/Status Register */
 #define R_DMA_CTRL        (0x80 / 4)
 #define   DMA_CTRL_REQUEST      (1 << 31)
@@ -187,6 +190,7 @@
  *   0x1FFFFFF: 32M bytes
  */
 #define DMA_DRAM_ADDR(asc, val)   ((val) & (asc)->dma_dram_mask)
+#define DMA_DRAM_ADDR_HIGH(val)   ((val) & 0xf)
 #define DMA_FLASH_ADDR(asc, val)  ((val) & (asc)->dma_flash_mask)
 #define DMA_LENGTH(val)         ((val) & 0x01FFFFFF)
 
@@ -207,6 +211,7 @@ static const AspeedSegments aspeed_2500_spi2_segments[];
 #define ASPEED_SMC_FEATURE_DMA       0x1
 #define ASPEED_SMC_FEATURE_DMA_GRANT 0x2
 #define ASPEED_SMC_FEATURE_WDT_CONTROL 0x4
+#define ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH 0x08
 
 static inline bool aspeed_smc_has_dma(const AspeedSMCClass *asc)
 {
@@ -218,6 +223,11 @@ static inline bool aspeed_smc_has_wdt_control(const AspeedSMCClass *asc)
     return !!(asc->features & ASPEED_SMC_FEATURE_WDT_CONTROL);
 }
 
+static inline bool aspeed_smc_has_dma_dram_addr_high(const AspeedSMCClass *asc)
+{
+    return !!(asc->features & ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH);
+}
+
 #define aspeed_smc_error(fmt, ...)                                      \
     qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt "\n", __func__, ## __VA_ARGS__)
 
@@ -747,6 +757,9 @@ static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size)
         (aspeed_smc_has_dma(asc) && addr == R_DMA_CTRL) ||
         (aspeed_smc_has_dma(asc) && addr == R_DMA_FLASH_ADDR) ||
         (aspeed_smc_has_dma(asc) && addr == R_DMA_DRAM_ADDR) ||
+        (aspeed_smc_has_dma(asc) &&
+         aspeed_smc_has_dma_dram_addr_high(asc) &&
+         addr == R_DMA_DRAM_ADDR_HIGH) ||
         (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN) ||
         (aspeed_smc_has_dma(asc) && addr == R_DMA_CHECKSUM) ||
         (addr >= R_SEG_ADDR0 &&
@@ -847,6 +860,23 @@ static bool aspeed_smc_inject_read_failure(AspeedSMCState *s)
     }
 }
 
+static uint64_t aspeed_smc_dma_dram_addr(AspeedSMCState *s)
+{
+    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
+    uint64_t dram_addr_high;
+    uint64_t dma_dram_addr;
+
+    if (aspeed_smc_has_dma_dram_addr_high(asc)) {
+        dram_addr_high = s->regs[R_DMA_DRAM_ADDR_HIGH];
+        dram_addr_high <<= 32;
+        dma_dram_addr = dram_addr_high | s->regs[R_DMA_DRAM_ADDR];
+    } else {
+        dma_dram_addr = s->regs[R_DMA_DRAM_ADDR];
+    }
+
+    return dma_dram_addr;
+}
+
 static uint32_t aspeed_smc_dma_len(AspeedSMCState *s)
 {
     AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
@@ -914,24 +944,34 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
 
 static void aspeed_smc_dma_rw(AspeedSMCState *s)
 {
+    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
+    uint64_t dram_addr_high;
+    uint64_t dma_dram_addr;
+    uint64_t dram_addr;
     MemTxResult result;
     uint32_t dma_len;
     uint32_t data;
 
     dma_len = aspeed_smc_dma_len(s);
+    dma_dram_addr = aspeed_smc_dma_dram_addr(s);
+
+    if (aspeed_smc_has_dma_dram_addr_high(asc)) {
+        dram_addr = dma_dram_addr - s->dram_mr->container->addr;
+    } else {
+        dram_addr = dma_dram_addr;
+    }
 
     trace_aspeed_smc_dma_rw(s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE ?
                             "write" : "read",
                             s->regs[R_DMA_FLASH_ADDR],
-                            s->regs[R_DMA_DRAM_ADDR],
+                            dram_addr,
                             dma_len);
     while (dma_len) {
         if (s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE) {
-            data = address_space_ldl_le(&s->dram_as, s->regs[R_DMA_DRAM_ADDR],
+            data = address_space_ldl_le(&s->dram_as, dram_addr,
                                         MEMTXATTRS_UNSPECIFIED, &result);
             if (result != MEMTX_OK) {
-                aspeed_smc_error("DRAM read failed @%08x",
-                                 s->regs[R_DMA_DRAM_ADDR]);
+                aspeed_smc_error("DRAM read failed @%" PRIx64, dram_addr);
                 return;
             }
 
@@ -951,11 +991,10 @@ static void aspeed_smc_dma_rw(AspeedSMCState *s)
                 return;
             }
 
-            address_space_stl_le(&s->dram_as, s->regs[R_DMA_DRAM_ADDR],
+            address_space_stl_le(&s->dram_as, dram_addr,
                                  data, MEMTXATTRS_UNSPECIFIED, &result);
             if (result != MEMTX_OK) {
-                aspeed_smc_error("DRAM write failed @%08x",
-                                 s->regs[R_DMA_DRAM_ADDR]);
+                aspeed_smc_error("DRAM write failed @%" PRIx64, dram_addr);
                 return;
             }
         }
@@ -964,8 +1003,15 @@ static void aspeed_smc_dma_rw(AspeedSMCState *s)
          * When the DMA is on-going, the DMA registers are updated
          * with the current working addresses and length.
          */
+        dram_addr += 4;
+        dma_dram_addr += 4;
+        if (aspeed_smc_has_dma_dram_addr_high(asc)) {
+            dram_addr_high = dma_dram_addr >> 32;
+            s->regs[R_DMA_DRAM_ADDR_HIGH] = dram_addr_high;
+        }
+
+        s->regs[R_DMA_DRAM_ADDR] = dma_dram_addr & 0xffffffff;
         s->regs[R_DMA_FLASH_ADDR] += 4;
-        s->regs[R_DMA_DRAM_ADDR] += 4;
         dma_len -= 4;
         s->regs[R_DMA_LEN] = dma_len;
         s->regs[R_DMA_CHECKSUM] += data;
@@ -1118,6 +1164,10 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data,
     } else if (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN &&
                aspeed_smc_dma_granted(s)) {
         s->regs[addr] = DMA_LENGTH(value);
+    } else if (aspeed_smc_has_dma(asc) &&
+               aspeed_smc_has_dma_dram_addr_high(asc) &&
+               addr == R_DMA_DRAM_ADDR_HIGH) {
+        s->regs[addr] = DMA_DRAM_ADDR_HIGH(value);
     } else {
         qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n",
                       __func__, addr);
diff --git a/hw/ssi/trace-events b/hw/ssi/trace-events
index 2d5bd2b83d..7b5ad6a939 100644
--- a/hw/ssi/trace-events
+++ b/hw/ssi/trace-events
@@ -6,7 +6,7 @@ aspeed_smc_do_snoop(int cs, int index, int dummies, int data) "CS%d index:0x%x d
 aspeed_smc_flash_write(int cs, uint64_t addr,  uint32_t size, uint64_t data, int mode) "CS%d @0x%" PRIx64 " size %u: 0x%" PRIx64" mode:%d"
 aspeed_smc_read(uint64_t addr,  uint32_t size, uint64_t data) "@0x%" PRIx64 " size %u: 0x%" PRIx64
 aspeed_smc_dma_checksum(uint32_t addr, uint32_t data) "0x%08x: 0x%08x"
-aspeed_smc_dma_rw(const char *dir, uint32_t flash_addr, uint32_t dram_addr, uint32_t size) "%s flash:@0x%08x dram:@0x%08x size:0x%08x"
+aspeed_smc_dma_rw(const char *dir, uint32_t flash_addr, uint64_t dram_addr, uint32_t size) "%s flash:@0x%08x dram:@0x%" PRIx64 " size:0x%08x"
 aspeed_smc_write(uint64_t addr,  uint32_t size, uint64_t data) "@0x%" PRIx64 " size %u: 0x%" PRIx64
 aspeed_smc_flash_select(int cs, const char *prefix) "CS%d %sselect"
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 09/16] aspeed/smc: Add AST2700 support
  2024-04-16  9:18 [PATCH v3 00/16] Add AST2700 support Jamin Lin via
                   ` (7 preceding siblings ...)
  2024-04-16  9:18 ` [PATCH v3 08/16] aspeed/smc: support 64 bits dma dram address Jamin Lin via
@ 2024-04-16  9:18 ` Jamin Lin via
  2024-04-18 16:14   ` Cédric Le Goater
  2024-04-16  9:18 ` [PATCH v3 10/16] aspeed/scu: " Jamin Lin via
                   ` (6 subsequent siblings)
  15 siblings, 1 reply; 42+ messages in thread
From: Jamin Lin via @ 2024-04-16  9:18 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, yunlin.tang

AST2700 fmc/spi controller's address decoding unit is 64KB
and only bits [31:16] are used for decoding. Introduce seg_to_reg
and reg_to_seg handlers for ast2700 fmc/spi controller.
In addition, adds ast2700 fmc, spi0, spi1, and spi2 class init handler.

Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
 hw/ssi/aspeed_smc.c | 222 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 220 insertions(+), 2 deletions(-)

diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index a67cac3d0f..e768e5463c 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -185,7 +185,7 @@
  *   0: 4 bytes
  *   0x7FFFFF: 32M bytes
  *
- * DMA length is from 1 byte to 32MB (AST2600, AST10x0)
+ * DMA length is from 1 byte to 32MB (AST2600, AST10x0 and AST2700)
  *   0: 1 byte
  *   0x1FFFFFF: 32M bytes
  */
@@ -670,7 +670,7 @@ static const MemoryRegionOps aspeed_smc_flash_ops = {
     .endianness = DEVICE_LITTLE_ENDIAN,
     .valid = {
         .min_access_size = 1,
-        .max_access_size = 4,
+        .max_access_size = 8,
     },
 };
 
@@ -1951,6 +1951,220 @@ static const TypeInfo aspeed_1030_spi2_info = {
     .class_init = aspeed_1030_spi2_class_init,
 };
 
+/*
+ * The FMC Segment Registers of the AST2700 have a 64KB unit.
+ * Only bits [31:16] are used for decoding.
+ */
+#define AST2700_SEG_ADDR_MASK 0xffff0000
+
+static uint32_t aspeed_2700_smc_segment_to_reg(const AspeedSMCState *s,
+                                               const AspeedSegments *seg)
+{
+    uint32_t reg = 0;
+
+    /* Disabled segments have a nil register */
+    if (!seg->size) {
+        return 0;
+    }
+
+    reg |= (seg->addr & AST2700_SEG_ADDR_MASK) >> 16; /* start offset */
+    reg |= (seg->addr + seg->size - 1) & AST2700_SEG_ADDR_MASK; /* end offset */
+    return reg;
+}
+
+static void aspeed_2700_smc_reg_to_segment(const AspeedSMCState *s,
+                                           uint32_t reg, AspeedSegments *seg)
+{
+    uint32_t start_offset = (reg << 16) & AST2700_SEG_ADDR_MASK;
+    uint32_t end_offset = reg & AST2700_SEG_ADDR_MASK;
+    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
+
+    if (reg) {
+        seg->addr = asc->flash_window_base + start_offset;
+        seg->size = end_offset + (64 * KiB) - start_offset;
+    } else {
+        seg->addr = asc->flash_window_base;
+        seg->size = 0;
+    }
+}
+
+static const uint32_t aspeed_2700_fmc_resets[ASPEED_SMC_R_MAX] = {
+    [R_CONF] = (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0 |
+            CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE1),
+    [R_CE_CTRL] = 0x0000aa00,
+    [R_CTRL0] = 0x406b0641,
+    [R_CTRL1] = 0x00000400,
+    [R_CTRL2] = 0x00000400,
+    [R_CTRL3] = 0x00000400,
+    [R_SEG_ADDR0] = 0x08000000,
+    [R_SEG_ADDR1] = 0x10000800,
+    [R_SEG_ADDR2] = 0x00000000,
+    [R_SEG_ADDR3] = 0x00000000,
+    [R_DUMMY_DATA] = 0x00010000,
+    [R_DMA_DRAM_ADDR_HIGH] = 0x00000000,
+    [R_TIMINGS] = 0x007b0000,
+};
+
+static const AspeedSegments aspeed_2700_fmc_segments[] = {
+    { 0x0, 128 * MiB }, /* start address is readonly */
+    { 128 * MiB, 128 * MiB }, /* default is disabled but needed for -kernel */
+    { 256 * MiB, 128 * MiB }, /* default is disabled but needed for -kernel */
+    { 0x0, 0 }, /* disabled */
+};
+
+static void aspeed_2700_fmc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
+
+    dc->desc               = "Aspeed 2700 FMC Controller";
+    asc->r_conf            = R_CONF;
+    asc->r_ce_ctrl         = R_CE_CTRL;
+    asc->r_ctrl0           = R_CTRL0;
+    asc->r_timings         = R_TIMINGS;
+    asc->nregs_timings     = 3;
+    asc->conf_enable_w0    = CONF_ENABLE_W0;
+    asc->cs_num_max        = 3;
+    asc->segments          = aspeed_2700_fmc_segments;
+    asc->segment_addr_mask = 0xffffffff;
+    asc->resets            = aspeed_2700_fmc_resets;
+    asc->flash_window_base = 0x100000000;
+    asc->flash_window_size = 1 * GiB;
+    asc->features          = ASPEED_SMC_FEATURE_DMA |
+                             ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH;
+    asc->dma_flash_mask    = 0x2FFFFFFC;
+    asc->dma_dram_mask     = 0xFFFFFFFC;
+    asc->dma_start_length  = 1;
+    asc->nregs             = ASPEED_SMC_R_MAX;
+    asc->segment_to_reg    = aspeed_2700_smc_segment_to_reg;
+    asc->reg_to_segment    = aspeed_2700_smc_reg_to_segment;
+    asc->dma_ctrl          = aspeed_2600_smc_dma_ctrl;
+}
+
+static const TypeInfo aspeed_2700_fmc_info = {
+    .name =  "aspeed.fmc-ast2700",
+    .parent = TYPE_ASPEED_SMC,
+    .class_init = aspeed_2700_fmc_class_init,
+};
+
+static const AspeedSegments aspeed_2700_spi0_segments[] = {
+    { 0x0, 128 * MiB }, /* start address is readonly */
+    { 128 * MiB, 128 * MiB }, /* start address is readonly */
+    { 0x0, 0 }, /* disabled */
+};
+
+static void aspeed_2700_spi0_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
+
+    dc->desc               = "Aspeed 2700 SPI0 Controller";
+    asc->r_conf            = R_CONF;
+    asc->r_ce_ctrl         = R_CE_CTRL;
+    asc->r_ctrl0           = R_CTRL0;
+    asc->r_timings         = R_TIMINGS;
+    asc->nregs_timings     = 2;
+    asc->conf_enable_w0    = CONF_ENABLE_W0;
+    asc->cs_num_max        = 2;
+    asc->segments          = aspeed_2700_spi0_segments;
+    asc->segment_addr_mask = 0xffffffff;
+    asc->flash_window_base = 0x180000000;
+    asc->flash_window_size = 1 * GiB;
+    asc->features          = ASPEED_SMC_FEATURE_DMA |
+                             ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH;
+    asc->dma_flash_mask    = 0x2FFFFFFC;
+    asc->dma_dram_mask     = 0xFFFFFFFC;
+    asc->dma_start_length  = 1;
+    asc->nregs             = ASPEED_SMC_R_MAX;
+    asc->segment_to_reg    = aspeed_2700_smc_segment_to_reg;
+    asc->reg_to_segment    = aspeed_2700_smc_reg_to_segment;
+    asc->dma_ctrl          = aspeed_2600_smc_dma_ctrl;
+}
+
+static const TypeInfo aspeed_2700_spi0_info = {
+    .name =  "aspeed.spi0-ast2700",
+    .parent = TYPE_ASPEED_SMC,
+    .class_init = aspeed_2700_spi0_class_init,
+};
+
+static const AspeedSegments aspeed_2700_spi1_segments[] = {
+    { 0x0, 128 * MiB }, /* start address is readonly */
+    { 0x0, 0 }, /* disabled */
+};
+
+static void aspeed_2700_spi1_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
+
+    dc->desc               = "Aspeed 2700 SPI1 Controller";
+    asc->r_conf            = R_CONF;
+    asc->r_ce_ctrl         = R_CE_CTRL;
+    asc->r_ctrl0           = R_CTRL0;
+    asc->r_timings         = R_TIMINGS;
+    asc->nregs_timings     = 2;
+    asc->conf_enable_w0    = CONF_ENABLE_W0;
+    asc->cs_num_max        = 2;
+    asc->segments          = aspeed_2700_spi1_segments;
+    asc->segment_addr_mask = 0xffffffff;
+    asc->flash_window_base = 0x200000000;
+    asc->flash_window_size = 1 * GiB;
+    asc->features          = ASPEED_SMC_FEATURE_DMA |
+                             ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH;
+    asc->dma_flash_mask    = 0x2FFFFFFC;
+    asc->dma_dram_mask     = 0xFFFFFFFC;
+    asc->dma_start_length  = 1;
+    asc->nregs             = ASPEED_SMC_R_MAX;
+    asc->segment_to_reg    = aspeed_2700_smc_segment_to_reg;
+    asc->reg_to_segment    = aspeed_2700_smc_reg_to_segment;
+    asc->dma_ctrl          = aspeed_2600_smc_dma_ctrl;
+}
+
+static const TypeInfo aspeed_2700_spi1_info = {
+        .name =  "aspeed.spi1-ast2700",
+        .parent = TYPE_ASPEED_SMC,
+        .class_init = aspeed_2700_spi1_class_init,
+};
+
+static const AspeedSegments aspeed_2700_spi2_segments[] = {
+    { 0x0, 128 * MiB }, /* start address is readonly */
+    { 0x0, 0 }, /* disabled */
+};
+
+static void aspeed_2700_spi2_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
+
+    dc->desc               = "Aspeed 2700 SPI2 Controller";
+    asc->r_conf            = R_CONF;
+    asc->r_ce_ctrl         = R_CE_CTRL;
+    asc->r_ctrl0           = R_CTRL0;
+    asc->r_timings         = R_TIMINGS;
+    asc->nregs_timings     = 2;
+    asc->conf_enable_w0    = CONF_ENABLE_W0;
+    asc->cs_num_max        = 2;
+    asc->segments          = aspeed_2700_spi2_segments;
+    asc->segment_addr_mask = 0xffffffff;
+    asc->flash_window_base = 0x280000000;
+    asc->flash_window_size = 1 * GiB;
+    asc->features          = ASPEED_SMC_FEATURE_DMA |
+                             ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH;
+    asc->dma_flash_mask    = 0x0FFFFFFC;
+    asc->dma_dram_mask     = 0xFFFFFFFC;
+    asc->dma_start_length  = 1;
+    asc->nregs             = ASPEED_SMC_R_MAX;
+    asc->segment_to_reg    = aspeed_2700_smc_segment_to_reg;
+    asc->reg_to_segment    = aspeed_2700_smc_reg_to_segment;
+    asc->dma_ctrl          = aspeed_2600_smc_dma_ctrl;
+}
+
+static const TypeInfo aspeed_2700_spi2_info = {
+        .name =  "aspeed.spi2-ast2700",
+        .parent = TYPE_ASPEED_SMC,
+        .class_init = aspeed_2700_spi2_class_init,
+};
+
 static void aspeed_smc_register_types(void)
 {
     type_register_static(&aspeed_smc_flash_info);
@@ -1967,6 +2181,10 @@ static void aspeed_smc_register_types(void)
     type_register_static(&aspeed_1030_fmc_info);
     type_register_static(&aspeed_1030_spi1_info);
     type_register_static(&aspeed_1030_spi2_info);
+    type_register_static(&aspeed_2700_fmc_info);
+    type_register_static(&aspeed_2700_spi0_info);
+    type_register_static(&aspeed_2700_spi1_info);
+    type_register_static(&aspeed_2700_spi2_info);
 }
 
 type_init(aspeed_smc_register_types)
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 10/16] aspeed/scu: Add AST2700 support
  2024-04-16  9:18 [PATCH v3 00/16] Add AST2700 support Jamin Lin via
                   ` (8 preceding siblings ...)
  2024-04-16  9:18 ` [PATCH v3 09/16] aspeed/smc: Add AST2700 support Jamin Lin via
@ 2024-04-16  9:18 ` Jamin Lin via
  2024-04-16  9:18 ` [PATCH v3 11/16] aspeed/intc: " Jamin Lin via
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 42+ messages in thread
From: Jamin Lin via @ 2024-04-16  9:18 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, yunlin.tang

AST2700 have two SCU controllers which are SCU and SCUIO.
Both SCU and SCUIO registers are not compatible previous SOCs
, introduces new registers and adds ast2700 scu, sucio class init handler.

The pclk divider selection of SCUIO is defined in SCUIO280[20:18] and
the pclk divider selection of SCU is defined in SCU280[25:23].
Both of them are not compatible AST2600 SOCs, adds a get_apb_freq function
and trace-event for AST2700 SCU and SCUIO.

Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
 hw/misc/aspeed_scu.c         | 306 ++++++++++++++++++++++++++++++++++-
 hw/misc/trace-events         |   4 +
 include/hw/misc/aspeed_scu.h |  47 +++++-
 3 files changed, 351 insertions(+), 6 deletions(-)

diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c
index 1ac04b6cb0..eb38ea8e19 100644
--- a/hw/misc/aspeed_scu.c
+++ b/hw/misc/aspeed_scu.c
@@ -134,6 +134,48 @@
 
 #define AST2600_CLK TO_REG(0x40)
 
+#define AST2700_SILICON_REV       TO_REG(0x00)
+#define AST2700_HW_STRAP1         TO_REG(0x10)
+#define AST2700_HW_STRAP1_CLR     TO_REG(0x14)
+#define AST2700_HW_STRAP1_LOCK    TO_REG(0x20)
+#define AST2700_HW_STRAP1_SEC1    TO_REG(0x24)
+#define AST2700_HW_STRAP1_SEC2    TO_REG(0x28)
+#define AST2700_HW_STRAP1_SEC3    TO_REG(0x2C)
+
+#define AST2700_SCU_CLK_SEL_1       TO_REG(0x280)
+#define AST2700_SCU_HPLL_PARAM      TO_REG(0x300)
+#define AST2700_SCU_HPLL_EXT_PARAM  TO_REG(0x304)
+#define AST2700_SCU_DPLL_PARAM      TO_REG(0x308)
+#define AST2700_SCU_DPLL_EXT_PARAM  TO_REG(0x30c)
+#define AST2700_SCU_MPLL_PARAM      TO_REG(0x310)
+#define AST2700_SCU_MPLL_EXT_PARAM  TO_REG(0x314)
+#define AST2700_SCU_D1CLK_PARAM     TO_REG(0x320)
+#define AST2700_SCU_D2CLK_PARAM     TO_REG(0x330)
+#define AST2700_SCU_CRT1CLK_PARAM   TO_REG(0x340)
+#define AST2700_SCU_CRT2CLK_PARAM   TO_REG(0x350)
+#define AST2700_SCU_MPHYCLK_PARAM   TO_REG(0x360)
+#define AST2700_SCU_FREQ_CNTR       TO_REG(0x3b0)
+#define AST2700_SCU_CPU_SCRATCH_0   TO_REG(0x780)
+#define AST2700_SCU_CPU_SCRATCH_1   TO_REG(0x784)
+
+#define AST2700_SCUIO_CLK_STOP_CTL_1    TO_REG(0x240)
+#define AST2700_SCUIO_CLK_STOP_CLR_1    TO_REG(0x244)
+#define AST2700_SCUIO_CLK_STOP_CTL_2    TO_REG(0x260)
+#define AST2700_SCUIO_CLK_STOP_CLR_2    TO_REG(0x264)
+#define AST2700_SCUIO_CLK_SEL_1         TO_REG(0x280)
+#define AST2700_SCUIO_CLK_SEL_2         TO_REG(0x284)
+#define AST2700_SCUIO_HPLL_PARAM        TO_REG(0x300)
+#define AST2700_SCUIO_HPLL_EXT_PARAM    TO_REG(0x304)
+#define AST2700_SCUIO_APLL_PARAM        TO_REG(0x310)
+#define AST2700_SCUIO_APLL_EXT_PARAM    TO_REG(0x314)
+#define AST2700_SCUIO_DPLL_PARAM        TO_REG(0x320)
+#define AST2700_SCUIO_DPLL_EXT_PARAM    TO_REG(0x324)
+#define AST2700_SCUIO_DPLL_PARAM_READ   TO_REG(0x328)
+#define AST2700_SCUIO_DPLL_EXT_PARAM_READ TO_REG(0x32c)
+#define AST2700_SCUIO_UARTCLK_GEN       TO_REG(0x330)
+#define AST2700_SCUIO_HUARTCLK_GEN      TO_REG(0x334)
+#define AST2700_SCUIO_CLK_DUTY_MEAS_RST TO_REG(0x388)
+
 #define SCU_IO_REGION_SIZE 0x1000
 
 static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = {
@@ -244,6 +286,25 @@ static uint32_t aspeed_1030_scu_get_apb_freq(AspeedSCUState *s)
         / asc->apb_divider;
 }
 
+static uint32_t aspeed_2700_scu_get_apb_freq(AspeedSCUState *s)
+{
+    AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s);
+    uint32_t hpll = asc->calc_hpll(s, s->regs[AST2700_SCU_HPLL_PARAM]);
+
+    return hpll / (SCU_CLK_GET_PCLK_DIV(s->regs[AST2700_SCU_CLK_SEL_1]) + 1)
+           / asc->apb_divider;
+}
+
+static uint32_t aspeed_2700_scuio_get_apb_freq(AspeedSCUState *s)
+{
+    AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s);
+    uint32_t hpll = asc->calc_hpll(s, s->regs[AST2700_SCUIO_HPLL_PARAM]);
+
+    return hpll /
+        (SCUIO_AST2700_CLK_GET_PCLK_DIV(s->regs[AST2700_SCUIO_CLK_SEL_1]) + 1)
+        / asc->apb_divider;
+}
+
 static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size)
 {
     AspeedSCUState *s = ASPEED_SCU(opaque);
@@ -258,7 +319,8 @@ static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size)
 
     switch (reg) {
     case RNG_DATA:
-        /* On hardware, RNG_DATA works regardless of
+        /*
+         * On hardware, RNG_DATA works regardless of
          * the state of the enable bit in RNG_CTRL
          */
         s->regs[RNG_DATA] = aspeed_scu_get_random();
@@ -494,6 +556,9 @@ static uint32_t aspeed_silicon_revs[] = {
     AST2600_A3_SILICON_REV,
     AST1030_A0_SILICON_REV,
     AST1030_A1_SILICON_REV,
+    AST2700_A0_SILICON_REV,
+    AST2720_A0_SILICON_REV,
+    AST2750_A0_SILICON_REV,
 };
 
 bool is_supported_silicon_rev(uint32_t silicon_rev)
@@ -783,6 +848,243 @@ static const TypeInfo aspeed_2600_scu_info = {
     .class_init = aspeed_2600_scu_class_init,
 };
 
+static uint64_t aspeed_ast2700_scu_read(void *opaque, hwaddr offset,
+                                        unsigned size)
+{
+    AspeedSCUState *s = ASPEED_SCU(opaque);
+    int reg = TO_REG(offset);
+
+    if (reg >= ASPEED_AST2700_SCU_NR_REGS) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
+                __func__, offset);
+        return 0;
+    }
+
+    switch (reg) {
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Unhandled read at offset 0x%" HWADDR_PRIx "\n",
+                      __func__, offset);
+    }
+
+    trace_aspeed_ast2700_scu_read(offset, size, s->regs[reg]);
+    return s->regs[reg];
+}
+
+static void aspeed_ast2700_scu_write(void *opaque, hwaddr offset,
+                                     uint64_t data64, unsigned size)
+{
+    AspeedSCUState *s = ASPEED_SCU(opaque);
+    int reg = TO_REG(offset);
+    /* Truncate here so bitwise operations below behave as expected */
+    uint32_t data = data64;
+
+    if (reg >= ASPEED_AST2700_SCU_NR_REGS) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
+                __func__, offset);
+        return;
+    }
+
+    trace_aspeed_ast2700_scu_write(offset, size, data);
+
+    switch (reg) {
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Unhandeled write at offset 0x%" HWADDR_PRIx "\n",
+                      __func__, offset);
+        break;
+    }
+
+    s->regs[reg] = data;
+}
+
+static const MemoryRegionOps aspeed_ast2700_scu_ops = {
+    .read = aspeed_ast2700_scu_read,
+    .write = aspeed_ast2700_scu_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 8,
+    .valid.unaligned = false,
+};
+
+static const uint32_t ast2700_a0_resets[ASPEED_AST2700_SCU_NR_REGS] = {
+    [AST2700_SILICON_REV]           = AST2700_A0_SILICON_REV,
+    [AST2700_HW_STRAP1]             = 0x00000800,
+    [AST2700_HW_STRAP1_CLR]         = 0xFFF0FFF0,
+    [AST2700_HW_STRAP1_LOCK]        = 0x00000FFF,
+    [AST2700_HW_STRAP1_SEC1]        = 0x000000FF,
+    [AST2700_HW_STRAP1_SEC2]        = 0x00000000,
+    [AST2700_HW_STRAP1_SEC3]        = 0x1000408F,
+    [AST2700_SCU_HPLL_PARAM]        = 0x0000009f,
+    [AST2700_SCU_HPLL_EXT_PARAM]    = 0x8000004f,
+    [AST2700_SCU_DPLL_PARAM]        = 0x0080009f,
+    [AST2700_SCU_DPLL_EXT_PARAM]    = 0x8000004f,
+    [AST2700_SCU_MPLL_PARAM]        = 0x00000040,
+    [AST2700_SCU_MPLL_EXT_PARAM]    = 0x80000000,
+    [AST2700_SCU_D1CLK_PARAM]       = 0x00050002,
+    [AST2700_SCU_D2CLK_PARAM]       = 0x00050002,
+    [AST2700_SCU_CRT1CLK_PARAM]     = 0x00050002,
+    [AST2700_SCU_CRT2CLK_PARAM]     = 0x00050002,
+    [AST2700_SCU_MPHYCLK_PARAM]     = 0x0000004c,
+    [AST2700_SCU_FREQ_CNTR]         = 0x000375eb,
+    [AST2700_SCU_CPU_SCRATCH_0]     = 0x00000000,
+    [AST2700_SCU_CPU_SCRATCH_1]     = 0x00000004,
+};
+
+static void aspeed_ast2700_scu_reset(DeviceState *dev)
+{
+    AspeedSCUState *s = ASPEED_SCU(dev);
+    AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
+
+    memcpy(s->regs, asc->resets, asc->nr_regs * 4);
+}
+
+static void aspeed_2700_scu_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
+
+    dc->desc = "ASPEED 2700 System Control Unit";
+    dc->reset = aspeed_ast2700_scu_reset;
+    asc->resets = ast2700_a0_resets;
+    asc->calc_hpll = aspeed_2600_scu_calc_hpll;
+    asc->get_apb = aspeed_2700_scu_get_apb_freq;
+    asc->apb_divider = 4;
+    asc->nr_regs = ASPEED_AST2700_SCU_NR_REGS;
+    asc->clkin_25Mhz = true;
+    asc->ops = &aspeed_ast2700_scu_ops;
+}
+
+static uint64_t aspeed_ast2700_scuio_read(void *opaque, hwaddr offset,
+                                        unsigned size)
+{
+    AspeedSCUState *s = ASPEED_SCU(opaque);
+    int reg = TO_REG(offset);
+    if (reg >= ASPEED_AST2700_SCU_NR_REGS) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
+                __func__, offset);
+        return 0;
+    }
+
+    switch (reg) {
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Unhandled read at offset 0x%" HWADDR_PRIx "\n",
+                      __func__, offset);
+    }
+
+    trace_aspeed_ast2700_scuio_read(offset, size, s->regs[reg]);
+    return s->regs[reg];
+}
+
+static void aspeed_ast2700_scuio_write(void *opaque, hwaddr offset,
+                                     uint64_t data64, unsigned size)
+{
+    AspeedSCUState *s = ASPEED_SCU(opaque);
+    int reg = TO_REG(offset);
+    /* Truncate here so bitwise operations below behave as expected */
+    uint32_t data = data64;
+    bool updated = false;
+
+    if (reg >= ASPEED_AST2700_SCU_NR_REGS) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
+                __func__, offset);
+        return;
+    }
+
+    trace_aspeed_ast2700_scuio_write(offset, size, data);
+
+    switch (reg) {
+    case AST2700_SCUIO_CLK_STOP_CTL_1:
+    case AST2700_SCUIO_CLK_STOP_CTL_2:
+        s->regs[reg] |= data;
+        updated = true;
+        break;
+    case AST2700_SCUIO_CLK_STOP_CLR_1:
+    case AST2700_SCUIO_CLK_STOP_CLR_2:
+        s->regs[reg - 1] ^= data;
+        updated = true;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Unhandeled write at offset 0x%" HWADDR_PRIx "\n",
+                      __func__, offset);
+        break;
+    }
+
+    if (!updated) {
+        s->regs[reg] = data;
+    }
+}
+
+static const MemoryRegionOps aspeed_ast2700_scuio_ops = {
+    .read = aspeed_ast2700_scuio_read,
+    .write = aspeed_ast2700_scuio_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 8,
+    .valid.unaligned = false,
+};
+
+static const uint32_t ast2700_a0_resets_io[ASPEED_AST2700_SCU_NR_REGS] = {
+    [AST2700_SILICON_REV]               = 0x06000003,
+    [AST2700_HW_STRAP1]                 = 0x00000504,
+    [AST2700_HW_STRAP1_CLR]             = 0xFFF0FFF0,
+    [AST2700_HW_STRAP1_LOCK]            = 0x00000FFF,
+    [AST2700_HW_STRAP1_SEC1]            = 0x000000FF,
+    [AST2700_HW_STRAP1_SEC2]            = 0x00000000,
+    [AST2700_HW_STRAP1_SEC3]            = 0x1000408F,
+    [AST2700_SCUIO_CLK_STOP_CTL_1]      = 0xffff8400,
+    [AST2700_SCUIO_CLK_STOP_CTL_2]      = 0x00005f30,
+    [AST2700_SCUIO_CLK_SEL_1]           = 0x86900000,
+    [AST2700_SCUIO_CLK_SEL_2]           = 0x00400000,
+    [AST2700_SCUIO_HPLL_PARAM]          = 0x10000027,
+    [AST2700_SCUIO_HPLL_EXT_PARAM]      = 0x80000014,
+    [AST2700_SCUIO_APLL_PARAM]          = 0x1000001f,
+    [AST2700_SCUIO_APLL_EXT_PARAM]      = 0x8000000f,
+    [AST2700_SCUIO_DPLL_PARAM]          = 0x106e42ce,
+    [AST2700_SCUIO_DPLL_EXT_PARAM]      = 0x80000167,
+    [AST2700_SCUIO_DPLL_PARAM_READ]     = 0x106e42ce,
+    [AST2700_SCUIO_DPLL_EXT_PARAM_READ] = 0x80000167,
+    [AST2700_SCUIO_UARTCLK_GEN]         = 0x00014506,
+    [AST2700_SCUIO_HUARTCLK_GEN]        = 0x000145c0,
+    [AST2700_SCUIO_CLK_DUTY_MEAS_RST]   = 0x0c9100d2,
+};
+
+static void aspeed_2700_scuio_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
+
+    dc->desc = "ASPEED 2700 System Control Unit I/O";
+    dc->reset = aspeed_ast2700_scu_reset;
+    asc->resets = ast2700_a0_resets_io;
+    asc->calc_hpll = aspeed_2600_scu_calc_hpll;
+    asc->get_apb = aspeed_2700_scuio_get_apb_freq;
+    asc->apb_divider = 2;
+    asc->nr_regs = ASPEED_AST2700_SCU_NR_REGS;
+    asc->clkin_25Mhz = true;
+    asc->ops = &aspeed_ast2700_scuio_ops;
+}
+
+static const TypeInfo aspeed_2700_scu_info = {
+    .name = TYPE_ASPEED_2700_SCU,
+    .parent = TYPE_ASPEED_SCU,
+    .instance_size = sizeof(AspeedSCUState),
+    .class_init = aspeed_2700_scu_class_init,
+};
+
+static const TypeInfo aspeed_2700_scuio_info = {
+    .name = TYPE_ASPEED_2700_SCUIO,
+    .parent = TYPE_ASPEED_SCU,
+    .instance_size = sizeof(AspeedSCUState),
+    .class_init = aspeed_2700_scuio_class_init,
+};
+
 static const uint32_t ast1030_a1_resets[ASPEED_AST2600_SCU_NR_REGS] = {
     [AST2600_SYS_RST_CTRL]      = 0xFFC3FED8,
     [AST2600_SYS_RST_CTRL2]     = 0x09FFFFFC,
@@ -841,6 +1143,8 @@ static void aspeed_scu_register_types(void)
     type_register_static(&aspeed_2500_scu_info);
     type_register_static(&aspeed_2600_scu_info);
     type_register_static(&aspeed_1030_scu_info);
+    type_register_static(&aspeed_2700_scu_info);
+    type_register_static(&aspeed_2700_scuio_info);
 }
 
 type_init(aspeed_scu_register_types);
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index e13b648221..1be0717c0c 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -93,6 +93,10 @@ slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED 0x%04x"
 # aspeed_scu.c
 aspeed_scu_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
 aspeed_scu_read(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+aspeed_ast2700_scu_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+aspeed_ast2700_scu_read(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+aspeed_ast2700_scuio_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+aspeed_ast2700_scuio_read(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
 
 # mps2-scc.c
 mps2_scc_read(uint64_t offset, uint64_t data, unsigned size) "MPS2 SCC read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
diff --git a/include/hw/misc/aspeed_scu.h b/include/hw/misc/aspeed_scu.h
index 7cb6018dbc..58db28db45 100644
--- a/include/hw/misc/aspeed_scu.h
+++ b/include/hw/misc/aspeed_scu.h
@@ -19,10 +19,13 @@ OBJECT_DECLARE_TYPE(AspeedSCUState, AspeedSCUClass, ASPEED_SCU)
 #define TYPE_ASPEED_2400_SCU TYPE_ASPEED_SCU "-ast2400"
 #define TYPE_ASPEED_2500_SCU TYPE_ASPEED_SCU "-ast2500"
 #define TYPE_ASPEED_2600_SCU TYPE_ASPEED_SCU "-ast2600"
+#define TYPE_ASPEED_2700_SCU TYPE_ASPEED_SCU "-ast2700"
+#define TYPE_ASPEED_2700_SCUIO TYPE_ASPEED_SCU "io" "-ast2700"
 #define TYPE_ASPEED_1030_SCU TYPE_ASPEED_SCU "-ast1030"
 
 #define ASPEED_SCU_NR_REGS (0x1A8 >> 2)
 #define ASPEED_AST2600_SCU_NR_REGS (0xE20 >> 2)
+#define ASPEED_AST2700_SCU_NR_REGS (0xE20 >> 2)
 
 struct AspeedSCUState {
     /*< private >*/
@@ -31,7 +34,7 @@ struct AspeedSCUState {
     /*< public >*/
     MemoryRegion iomem;
 
-    uint32_t regs[ASPEED_AST2600_SCU_NR_REGS];
+    uint32_t regs[ASPEED_AST2700_SCU_NR_REGS];
     uint32_t silicon_rev;
     uint32_t hw_strap1;
     uint32_t hw_strap2;
@@ -48,6 +51,9 @@ struct AspeedSCUState {
 #define AST2600_A3_SILICON_REV   0x05030303U
 #define AST1030_A0_SILICON_REV   0x80000000U
 #define AST1030_A1_SILICON_REV   0x80010000U
+#define AST2700_A0_SILICON_REV   0x06000103U
+#define AST2720_A0_SILICON_REV   0x06000203U
+#define AST2750_A0_SILICON_REV   0x06000003U
 
 #define ASPEED_IS_AST2500(si_rev)     ((((si_rev) >> 24) & 0xff) == 0x04)
 
@@ -87,7 +93,8 @@ uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s);
  *       1. 2012/12/29 Ryan Chen Create
  */
 
-/* SCU08   Clock Selection Register
+/*
+ * SCU08   Clock Selection Register
  *
  *  31     Enable Video Engine clock dynamic slow down
  *  30:28  Video Engine clock slow down setting
@@ -109,7 +116,8 @@ uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s);
  */
 #define SCU_CLK_GET_PCLK_DIV(x)                    (((x) >> 23) & 0x7)
 
-/* SCU24   H-PLL Parameter Register (for Aspeed AST2400 SOC)
+/*
+ * SCU24   H-PLL Parameter Register (for Aspeed AST2400 SOC)
  *
  *  18     H-PLL parameter selection
  *           0: Select H-PLL by strapping resistors
@@ -127,7 +135,8 @@ uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s);
 #define SCU_AST2400_H_PLL_BYPASS_EN                (0x1 << 17)
 #define SCU_AST2400_H_PLL_OFF                      (0x1 << 16)
 
-/* SCU24   H-PLL Parameter Register (for Aspeed AST2500 SOC)
+/*
+ * SCU24   H-PLL Parameter Register (for Aspeed AST2500 SOC)
  *
  *  21     Enable H-PLL reset
  *  20     Enable H-PLL bypass mode
@@ -144,7 +153,8 @@ uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s);
 #define SCU_H_PLL_BYPASS_EN                        (0x1 << 20)
 #define SCU_H_PLL_OFF                              (0x1 << 19)
 
-/* SCU70  Hardware Strapping Register definition (for Aspeed AST2400 SOC)
+/*
+ * SCU70  Hardware Strapping Register definition (for Aspeed AST2400 SOC)
  *
  * 31:29  Software defined strapping registers
  * 28:27  DRAM size setting (for VGA driver use)
@@ -361,4 +371,31 @@ uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s);
  */
 #define SCU_AST1030_CLK_GET_PCLK_DIV(x)                    (((x) >> 8) & 0xf)
 
+/*
+ * SCU280   Clock Selection 1 Register (for Aspeed AST2700 SCUIO)
+ *
+ *  31:29  MHCLK_DIV
+ *  28     Reserved
+ *  27:25  RGMIICLK_DIV
+ *  24     Reserved
+ *  23:21  RMIICLK_DIV
+ *  20:18  PCLK_DIV
+ *  17:14  SDCLK_DIV
+ *  13     SDCLK_SEL
+ *  12     UART13CLK_SEL
+ *  11     UART12CLK_SEL
+ *  10     UART11CLK_SEL
+ *  9      UART10CLK_SEL
+ *  8      UART9CLK_SEL
+ *  7      UART8CLK_SEL
+ *  6      UART7CLK_SEL
+ *  5      UART6CLK_SEL
+ *  4      UARTDBCLK_SEL
+ *  3      UART4CLK_SEL
+ *  2      UART3CLK_SEL
+ *  1      UART2CLK_SEL
+ *  0      UART1CLK_SEL
+ */
+#define SCUIO_AST2700_CLK_GET_PCLK_DIV(x)                    (((x) >> 18) & 0x7)
+
 #endif /* ASPEED_SCU_H */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 11/16] aspeed/intc: Add AST2700 support
  2024-04-16  9:18 [PATCH v3 00/16] Add AST2700 support Jamin Lin via
                   ` (9 preceding siblings ...)
  2024-04-16  9:18 ` [PATCH v3 10/16] aspeed/scu: " Jamin Lin via
@ 2024-04-16  9:18 ` Jamin Lin via
  2024-05-07 13:33   ` Cédric Le Goater
  2024-04-16  9:18 ` [PATCH v3 12/16] aspeed/soc: " Jamin Lin via
                   ` (4 subsequent siblings)
  15 siblings, 1 reply; 42+ messages in thread
From: Jamin Lin via @ 2024-04-16  9:18 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, yunlin.tang

AST2700 interrupt controller(INTC) provides hardware interrupt interfaces
to interrupt of processors PSP, SSP and TSP. In INTC, each interrupt of
INT 128 to INT136 combines 32 interrupts.

Introduce a new aspeed_intc class with instance_init and realize handlers.

So far, this model only supports GICINT128 to GICINT136.
It creates 9 GICINT or-gates to connect 32 interrupts sources
from GICINT128 to GICINT136 as IRQ GPIO-OUTPUT pins.
Then, this model registers IRQ handler with its IRQ GPIO-INPUT pins which
connect to GICINT or-gates. And creates 9 GICINT IRQ GPIO-OUTPUT pins which
connect to GIC device with GIC IRQ 128 to 136.

If one interrupt source from GICINT128 to GICINT136
set irq, the OR-GATE irq callback function is called and set irq to INTC by
OR-GATE GPIO-OUTPUT pins. Then, the INTC irq callback function is called and
set irq to GIC by its GICINT IRQ GPIO-OUTPUT pins. Finally, the GIC irq
callback function is called and set irq to CPUs and
CPUs execute Interrupt Service Routine (ISR).

Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
 hw/intc/aspeed_intc.c         | 269 ++++++++++++++++++++++++++++++++++
 hw/intc/meson.build           |   1 +
 hw/intc/trace-events          |   6 +
 include/hw/intc/aspeed_intc.h |  35 +++++
 4 files changed, 311 insertions(+)
 create mode 100644 hw/intc/aspeed_intc.c
 create mode 100644 include/hw/intc/aspeed_intc.h

diff --git a/hw/intc/aspeed_intc.c b/hw/intc/aspeed_intc.c
new file mode 100644
index 0000000000..df31900d56
--- /dev/null
+++ b/hw/intc/aspeed_intc.c
@@ -0,0 +1,269 @@
+/*
+ * ASPEED INTC Controller
+ *
+ * Copyright (C) 2024 ASPEED Technology Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/intc/aspeed_intc.h"
+#include "hw/irq.h"
+#include "migration/vmstate.h"
+#include "qemu/bitops.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "hw/intc/arm_gicv3.h"
+#include "trace.h"
+#include "hw/registerfields.h"
+#include "qapi/error.h"
+
+/* INTC Registers */
+REG32(GICINT128_EN,         0x1000)
+REG32(GICINT128_STATUS,     0x1004)
+REG32(GICINT129_EN,         0x1100)
+REG32(GICINT129_STATUS,     0x1104)
+REG32(GICINT130_EN,         0x1200)
+REG32(GICINT130_STATUS,     0x1204)
+REG32(GICINT131_EN,         0x1300)
+REG32(GICINT131_STATUS,     0x1304)
+REG32(GICINT132_EN,         0x1400)
+REG32(GICINT132_STATUS,     0x1404)
+REG32(GICINT133_EN,         0x1500)
+REG32(GICINT133_STATUS,     0x1504)
+REG32(GICINT134_EN,         0x1600)
+REG32(GICINT134_STATUS,     0x1604)
+REG32(GICINT135_EN,         0x1700)
+REG32(GICINT135_STATUS,     0x1704)
+REG32(GICINT136_EN,         0x1800)
+REG32(GICINT136_STATUS,     0x1804)
+
+#define GICINT_EN_BASE     R_GICINT128_EN
+
+/*
+ * The address of GICINT128 to GICINT136 are from 0x1000 to 0x1804.
+ * Utilize "address & 0x0f00" to get the gicint_out index and
+ * its gic irq.
+ */
+static void aspeed_intc_update(AspeedINTCState *s, int irq, int level)
+{
+    uint32_t gicint_enable_addr = GICINT_EN_BASE + ((0x100 * irq) >> 2);
+    uint32_t gicint_status_addr = gicint_enable_addr + (0x4 >> 2);
+
+    if (s->trigger[irq]) {
+        if (!level && !s->regs[gicint_status_addr]) {
+            /* clear irq */
+            trace_aspeed_intc_update_irq(irq, 0);
+            qemu_set_irq(s->gicint_out[irq], 0);
+            s->trigger[irq] = false;
+        }
+    } else {
+        if (s->new_gicint_status[irq]) {
+            /* set irq */
+            trace_aspeed_intc_update_irq(irq, 1);
+            s->regs[gicint_status_addr] = s->new_gicint_status[irq];
+            s->new_gicint_status[irq] = 0;
+            qemu_set_irq(s->gicint_out[irq], 1);
+            s->trigger[irq] = true;
+        }
+    }
+}
+
+/*
+ * The value of irq should be 0 to ASPEED_INTC_NR_GICS.
+ * The irq 0 indicates GICINT128, irq 1 indicates GICINT129 and so on.
+ */
+static void aspeed_intc_set_irq(void *opaque, int irq, int level)
+{
+    AspeedINTCState *s = (AspeedINTCState *)opaque;
+    uint32_t gicint_enable_addr = GICINT_EN_BASE + ((0x100 * irq) >> 2);
+    uint32_t enable = s->regs[gicint_enable_addr];
+    int i;
+
+    if (irq > ASPEED_INTC_NR_GICS) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
+                      __func__, irq);
+        return;
+    }
+
+    trace_aspeed_intc_set_irq(irq, level);
+
+    for (i = 0; i < 32; i++) {
+        if (s->gicint_orgate[irq].levels[i]) {
+            if (enable & BIT(i)) {
+                s->new_gicint_status[irq] |= BIT(i);
+            }
+        }
+    }
+
+    aspeed_intc_update(s, irq, level);
+}
+
+static uint64_t aspeed_intc_read(void *opaque, hwaddr offset, unsigned int size)
+{
+    AspeedINTCState *s = ASPEED_INTC(opaque);
+    uint32_t addr = offset >> 2;
+    uint32_t value = 0;
+
+    if (addr >= ASPEED_INTC_NR_REGS) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
+                      __func__, offset);
+        return 0;
+    }
+
+    switch (addr) {
+    case R_GICINT128_EN:
+    case R_GICINT129_EN:
+    case R_GICINT130_EN:
+    case R_GICINT131_EN:
+    case R_GICINT132_EN:
+    case R_GICINT133_EN:
+    case R_GICINT134_EN:
+    case R_GICINT135_EN:
+    case R_GICINT136_EN:
+    case R_GICINT128_STATUS:
+    case R_GICINT129_STATUS:
+    case R_GICINT130_STATUS:
+    case R_GICINT131_STATUS:
+    case R_GICINT132_STATUS:
+    case R_GICINT133_STATUS:
+    case R_GICINT134_STATUS:
+    case R_GICINT135_STATUS:
+    case R_GICINT136_STATUS:
+        value = s->regs[addr];
+        break;
+    default:
+        value = s->regs[addr];
+        break;
+    }
+
+    trace_aspeed_intc_read(offset, size, value);
+
+    return value;
+}
+
+static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data,
+                                        unsigned size)
+{
+    AspeedINTCState *s = ASPEED_INTC(opaque);
+    uint32_t irq = (offset & 0x0f00) >> 8;
+    uint32_t addr = offset >> 2;
+
+
+    if (addr >= ASPEED_INTC_NR_REGS) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
+                      __func__, offset);
+        return;
+    }
+
+    trace_aspeed_intc_write(offset, size, data);
+
+    switch (addr) {
+    case R_GICINT128_EN:
+    case R_GICINT129_EN:
+    case R_GICINT130_EN:
+    case R_GICINT131_EN:
+    case R_GICINT132_EN:
+    case R_GICINT133_EN:
+    case R_GICINT134_EN:
+    case R_GICINT135_EN:
+    case R_GICINT136_EN:
+        s->regs[addr] = data;
+        break;
+    case R_GICINT128_STATUS:
+    case R_GICINT129_STATUS:
+    case R_GICINT130_STATUS:
+    case R_GICINT131_STATUS:
+    case R_GICINT132_STATUS:
+    case R_GICINT133_STATUS:
+    case R_GICINT134_STATUS:
+    case R_GICINT135_STATUS:
+    case R_GICINT136_STATUS:
+        /* clear status */
+        s->regs[addr] &= ~data;
+        if (!s->regs[addr]) {
+            aspeed_intc_update(s, irq, 0);
+        }
+        break;
+    default:
+        s->regs[addr] = data;
+        break;
+    }
+
+    return;
+}
+
+static const MemoryRegionOps aspeed_intc_ops = {
+    .read = aspeed_intc_read,
+    .write = aspeed_intc_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    }
+};
+
+static void aspeed_intc_instance_init(Object *obj)
+{
+    AspeedINTCState *s = ASPEED_INTC(obj);
+    int i;
+
+    for (i = 0; i < ASPEED_INTC_NR_GICS; i++) {
+        object_initialize_child(obj, "gic-orgate[*]", &s->gicint_orgate[i],
+                                TYPE_OR_IRQ);
+        object_property_set_int(OBJECT(&s->gicint_orgate[i]), "num-lines",
+                                32, &error_abort);
+    }
+}
+
+static void aspeed_intc_reset(DeviceState *dev)
+{
+    AspeedINTCState *s = ASPEED_INTC(dev);
+    memset(s->regs, 0, sizeof(s->regs));
+    memset(s->trigger, 0, sizeof(s->trigger));
+    memset(s->new_gicint_status, 0, sizeof(s->new_gicint_status));
+}
+
+static void aspeed_intc_realize(DeviceState *dev, Error **errp)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+    AspeedINTCState *s = ASPEED_INTC(dev);
+    int i;
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_intc_ops, s,
+                          TYPE_ASPEED_INTC ".regs", ASPEED_INTC_NR_REGS << 2);
+
+    sysbus_init_mmio(sbd, &s->iomem);
+    qdev_init_gpio_in(dev, aspeed_intc_set_irq, ASPEED_INTC_NR_GICS);
+
+    for (i = 0; i < ASPEED_INTC_NR_GICS; i++) {
+        sysbus_init_irq(sbd, &s->gicint_out[i]);
+    }
+}
+
+static void aspeed_intc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = aspeed_intc_realize;
+    dc->reset = aspeed_intc_reset;
+    dc->desc = "ASPEED INTC Controller";
+    dc->vmsd = NULL;
+}
+
+static const TypeInfo aspeed_intc_info = {
+    .name = TYPE_ASPEED_INTC,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_init = aspeed_intc_instance_init,
+    .instance_size = sizeof(AspeedINTCState),
+    .class_init = aspeed_intc_class_init,
+};
+
+static void aspeed_intc_register_types(void)
+{
+    type_register_static(&aspeed_intc_info);
+}
+
+type_init(aspeed_intc_register_types);
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index ed355941d1..f5c574f584 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -14,6 +14,7 @@ system_ss.add(when: 'CONFIG_ARM_GICV3_TCG', if_true: files(
 ))
 system_ss.add(when: 'CONFIG_ALLWINNER_A10_PIC', if_true: files('allwinner-a10-pic.c'))
 system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_vic.c'))
+system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_intc.c'))
 system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_pic.c'))
 system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_gic.c', 'exynos4210_combiner.c'))
 system_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 1ef29d0256..30b9dd2a96 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -79,6 +79,12 @@ aspeed_vic_update_fiq(int flags) "Raising FIQ: %d"
 aspeed_vic_update_irq(int flags) "Raising IRQ: %d"
 aspeed_vic_read(uint64_t offset, unsigned size, uint32_t value) "From 0x%" PRIx64 " of size %u: 0x%" PRIx32
 aspeed_vic_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+# aspeed_intc.c
+aspeed_intc_read(uint64_t offset, unsigned size, uint32_t value) "From 0x%" PRIx64 " of size %u: 0x%" PRIx32
+aspeed_intc_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+aspeed_intc_set_irq(int irq, int level) "Set IRQ %d: %d"
+aspeed_intc_update_irq(int irq, int level) "Update IRQ: %d: %d"
+aspeed_intc_debug(uint32_t offset, uint32_t value) "Debug 0x%x: 0x%x"
 
 # arm_gic.c
 gic_enable_irq(int irq) "irq %d enabled"
diff --git a/include/hw/intc/aspeed_intc.h b/include/hw/intc/aspeed_intc.h
new file mode 100644
index 0000000000..0d2fbbda8f
--- /dev/null
+++ b/include/hw/intc/aspeed_intc.h
@@ -0,0 +1,35 @@
+/*
+ * ASPEED INTC Controller
+ *
+ * Copyright (C) 2024 ASPEED Technology Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef ASPEED_INTC_H
+#define ASPEED_INTC_H
+
+#include "hw/sysbus.h"
+#include "qom/object.h"
+#include "hw/or-irq.h"
+
+#define TYPE_ASPEED_INTC "aspeed.intc"
+OBJECT_DECLARE_SIMPLE_TYPE(AspeedINTCState, ASPEED_INTC)
+
+#define ASPEED_INTC_NR_REGS (0x2000 >> 2)
+#define ASPEED_INTC_NR_GICS 9
+
+struct AspeedINTCState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+    DeviceState *gic;
+
+    /*< public >*/
+    MemoryRegion iomem;
+    uint32_t regs[ASPEED_INTC_NR_REGS];
+    OrIRQState gicint_orgate[ASPEED_INTC_NR_GICS];
+    qemu_irq gicint_out[ASPEED_INTC_NR_GICS];
+    bool trigger[ASPEED_INTC_NR_GICS];
+    uint32_t new_gicint_status[ASPEED_INTC_NR_GICS];
+};
+
+#endif /* ASPEED_INTC_H */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 12/16] aspeed/soc: Add AST2700 support
  2024-04-16  9:18 [PATCH v3 00/16] Add AST2700 support Jamin Lin via
                   ` (10 preceding siblings ...)
  2024-04-16  9:18 ` [PATCH v3 11/16] aspeed/intc: " Jamin Lin via
@ 2024-04-16  9:18 ` Jamin Lin via
  2024-04-19  7:10   ` Cédric Le Goater
  2024-05-07 13:06   ` Cédric Le Goater
  2024-04-16  9:19 ` [PATCH v3 13/16] aspeed: Add an AST2700 eval board Jamin Lin via
                   ` (3 subsequent siblings)
  15 siblings, 2 replies; 42+ messages in thread
From: Jamin Lin via @ 2024-04-16  9:18 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, yunlin.tang

Initial definitions for a simple machine using an AST2700 SOC (Cortex-a35 CPU).

AST2700 SOC and its interrupt controller are too complex to handle
in the common Aspeed SoC framework. We introduce a new ast2700
class with instance_init and realize handlers.

AST2700 is a 64 bits quad core cpus and support 8 watchdog.
Update maximum ASPEED_CPUS_NUM to 4 and ASPEED_WDTS_NUM to 8.
In addition, update AspeedSocState to support scuio, sli, sliio and intc.

Add TYPE_ASPEED27X0_SOC machine type.

The SDMC controller is unlocked at SPL stage.
At present, only supports to emulate booting
start from u-boot stage. Set SDMC controller
unlocked by default.

In INTC, each interrupt of INT 128 to INT 136 combines 32 interrupts.
It connect GICINT IRQ GPIO-OUTPUT pins to GIC device with irq 128 to 136.
And, if a device irq is 128 to 136, its irq GPIO-OUTPUT pin is connected to
GICINT or-gates instead of GIC device.

Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
 hw/arm/aspeed_ast27x0.c     | 554 ++++++++++++++++++++++++++++++++++++
 hw/arm/meson.build          |   1 +
 include/hw/arm/aspeed_soc.h |  26 +-
 3 files changed, 579 insertions(+), 2 deletions(-)
 create mode 100644 hw/arm/aspeed_ast27x0.c

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
new file mode 100644
index 0000000000..754c963230
--- /dev/null
+++ b/hw/arm/aspeed_ast27x0.c
@@ -0,0 +1,554 @@
+/*
+ * ASPEED SoC 27x0 family
+ *
+ * Copyright (C) 2024 ASPEED Technology Inc.
+ *
+ * This code is licensed under the GPL version 2 or later.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Implementation extracted from the AST2600 and adapted for AST27x0.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/misc/unimp.h"
+#include "hw/arm/aspeed_soc.h"
+#include "qemu/module.h"
+#include "qemu/error-report.h"
+#include "hw/i2c/aspeed_i2c.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "hw/intc/arm_gicv3.h"
+#include "qapi/qmp/qlist.h"
+
+static const hwaddr aspeed_soc_ast2700_memmap[] = {
+    [ASPEED_DEV_SPI_BOOT]  =  0x400000000,
+    [ASPEED_DEV_SRAM]      =  0x10000000,
+    [ASPEED_DEV_SDMC]      =  0x12C00000,
+    [ASPEED_DEV_SCU]       =  0x12C02000,
+    [ASPEED_DEV_SCUIO]     =  0x14C02000,
+    [ASPEED_DEV_UART0]     =  0X14C33000,
+    [ASPEED_DEV_UART1]     =  0X14C33100,
+    [ASPEED_DEV_UART2]     =  0X14C33200,
+    [ASPEED_DEV_UART3]     =  0X14C33300,
+    [ASPEED_DEV_UART4]     =  0X12C1A000,
+    [ASPEED_DEV_UART5]     =  0X14C33400,
+    [ASPEED_DEV_UART6]     =  0X14C33500,
+    [ASPEED_DEV_UART7]     =  0X14C33600,
+    [ASPEED_DEV_UART8]     =  0X14C33700,
+    [ASPEED_DEV_UART9]     =  0X14C33800,
+    [ASPEED_DEV_UART10]    =  0X14C33900,
+    [ASPEED_DEV_UART11]    =  0X14C33A00,
+    [ASPEED_DEV_UART12]    =  0X14C33B00,
+    [ASPEED_DEV_WDT]       =  0x14C37000,
+    [ASPEED_DEV_VUART]     =  0X14C30000,
+    [ASPEED_DEV_FMC]       =  0x14000000,
+    [ASPEED_DEV_SPI0]      =  0x14010000,
+    [ASPEED_DEV_SPI1]      =  0x14020000,
+    [ASPEED_DEV_SPI2]      =  0x14030000,
+    [ASPEED_DEV_SDRAM]     =  0x400000000,
+    [ASPEED_DEV_MII1]      =  0x14040000,
+    [ASPEED_DEV_MII2]      =  0x14040008,
+    [ASPEED_DEV_MII3]      =  0x14040010,
+    [ASPEED_DEV_ETH1]      =  0x14050000,
+    [ASPEED_DEV_ETH2]      =  0x14060000,
+    [ASPEED_DEV_ETH3]      =  0x14070000,
+    [ASPEED_DEV_EMMC]      =  0x12090000,
+    [ASPEED_DEV_INTC]      =  0x12100000,
+    [ASPEED_DEV_SLI]       =  0x12C17000,
+    [ASPEED_DEV_SLIIO]     =  0x14C1E000,
+    [ASPEED_GIC_DIST]      =  0x12200000,
+    [ASPEED_GIC_REDIST]    =  0x12280000,
+};
+
+#define AST2700_MAX_IRQ 288
+
+/* Shared Peripheral Interrupt values below are offset by -32 from datasheet */
+static const int aspeed_soc_ast2700_irqmap[] = {
+    [ASPEED_DEV_UART0]     = 132,
+    [ASPEED_DEV_UART1]     = 132,
+    [ASPEED_DEV_UART2]     = 132,
+    [ASPEED_DEV_UART3]     = 132,
+    [ASPEED_DEV_UART4]     = 8,
+    [ASPEED_DEV_UART5]     = 132,
+    [ASPEED_DEV_UART6]     = 132,
+    [ASPEED_DEV_UART7]     = 132,
+    [ASPEED_DEV_UART8]     = 132,
+    [ASPEED_DEV_UART9]     = 132,
+    [ASPEED_DEV_UART10]    = 132,
+    [ASPEED_DEV_UART11]    = 132,
+    [ASPEED_DEV_UART12]    = 132,
+    [ASPEED_DEV_FMC]       = 131,
+    [ASPEED_DEV_SDMC]      = 0,
+    [ASPEED_DEV_SCU]       = 12,
+    [ASPEED_DEV_ADC]       = 130,
+    [ASPEED_DEV_XDMA]      = 5,
+    [ASPEED_DEV_EMMC]      = 15,
+    [ASPEED_DEV_GPIO]      = 11,
+    [ASPEED_DEV_GPIO_1_8V] = 130,
+    [ASPEED_DEV_RTC]       = 13,
+    [ASPEED_DEV_TIMER1]    = 16,
+    [ASPEED_DEV_TIMER2]    = 17,
+    [ASPEED_DEV_TIMER3]    = 18,
+    [ASPEED_DEV_TIMER4]    = 19,
+    [ASPEED_DEV_TIMER5]    = 20,
+    [ASPEED_DEV_TIMER6]    = 21,
+    [ASPEED_DEV_TIMER7]    = 22,
+    [ASPEED_DEV_TIMER8]    = 23,
+    [ASPEED_DEV_WDT]       = 131,
+    [ASPEED_DEV_PWM]       = 131,
+    [ASPEED_DEV_LPC]       = 128,
+    [ASPEED_DEV_IBT]       = 128,
+    [ASPEED_DEV_I2C]       = 130,
+    [ASPEED_DEV_PECI]      = 133,
+    [ASPEED_DEV_ETH1]      = 132,
+    [ASPEED_DEV_ETH2]      = 132,
+    [ASPEED_DEV_ETH3]      = 132,
+    [ASPEED_DEV_HACE]      = 4,
+    [ASPEED_DEV_KCS]       = 128,
+    [ASPEED_DEV_DP]        = 28,
+    [ASPEED_DEV_I3C]       = 131,
+};
+
+/* GICINT 128 */
+static const int aspeed_soc_ast2700_gic128_intcmap[] = {
+    [ASPEED_DEV_LPC]       = 0,
+    [ASPEED_DEV_IBT]       = 2,
+    [ASPEED_DEV_KCS]       = 4,
+};
+
+/* GICINT 130 */
+static const int aspeed_soc_ast2700_gic130_intcmap[] = {
+    [ASPEED_DEV_I2C]        = 0,
+    [ASPEED_DEV_ADC]        = 16,
+    [ASPEED_DEV_GPIO_1_8V]  = 18,
+};
+
+/* GICINT 131 */
+static const int aspeed_soc_ast2700_gic131_intcmap[] = {
+    [ASPEED_DEV_I3C]       = 0,
+    [ASPEED_DEV_WDT]       = 16,
+    [ASPEED_DEV_FMC]       = 25,
+    [ASPEED_DEV_PWM]       = 29,
+};
+
+/* GICINT 132 */
+static const int aspeed_soc_ast2700_gic132_intcmap[] = {
+    [ASPEED_DEV_ETH1]      = 0,
+    [ASPEED_DEV_ETH2]      = 1,
+    [ASPEED_DEV_ETH3]      = 2,
+    [ASPEED_DEV_UART0]     = 7,
+    [ASPEED_DEV_UART1]     = 8,
+    [ASPEED_DEV_UART2]     = 9,
+    [ASPEED_DEV_UART3]     = 10,
+    [ASPEED_DEV_UART5]     = 11,
+    [ASPEED_DEV_UART6]     = 12,
+    [ASPEED_DEV_UART7]     = 13,
+    [ASPEED_DEV_UART8]     = 14,
+    [ASPEED_DEV_UART9]     = 15,
+    [ASPEED_DEV_UART10]    = 16,
+    [ASPEED_DEV_UART11]    = 17,
+    [ASPEED_DEV_UART12]    = 18,
+};
+
+/* GICINT 133 */
+static const int aspeed_soc_ast2700_gic133_intcmap[] = {
+    [ASPEED_DEV_PECI]      = 4,
+};
+
+/* GICINT 128 ~ 136 */
+struct gic_intc_irq_info {
+    int irq;
+    const int *ptr;
+};
+
+static const struct gic_intc_irq_info aspeed_soc_ast2700_gic_intcmap[] = {
+    {128,  aspeed_soc_ast2700_gic128_intcmap},
+    {129,  NULL},
+    {130,  aspeed_soc_ast2700_gic130_intcmap},
+    {131,  aspeed_soc_ast2700_gic131_intcmap},
+    {132,  aspeed_soc_ast2700_gic132_intcmap},
+    {133,  aspeed_soc_ast2700_gic133_intcmap},
+    {134,  NULL},
+    {135,  NULL},
+    {136,  NULL},
+};
+
+static qemu_irq aspeed_soc_ast2700_get_irq(AspeedSoCState *s, int dev)
+{
+    Aspeed27x0SoCState *a = ASPEED27X0_SOC(s);
+    AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(aspeed_soc_ast2700_gic_intcmap); i++) {
+        if (sc->irqmap[dev] == aspeed_soc_ast2700_gic_intcmap[i].irq) {
+            assert(aspeed_soc_ast2700_gic_intcmap[i].ptr);
+            return qdev_get_gpio_in(DEVICE(&a->intc.gicint_orgate[i]),
+                aspeed_soc_ast2700_gic_intcmap[i].ptr[dev]);
+        }
+    }
+
+    return qdev_get_gpio_in(a->intc.gic, sc->irqmap[dev]);
+}
+
+static void aspeed_soc_ast2700_init(Object *obj)
+{
+    Aspeed27x0SoCState *a = ASPEED27X0_SOC(obj);
+    AspeedSoCState *s = ASPEED_SOC(obj);
+    AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+    int i;
+    char socname[8];
+    char typename[64];
+
+    if (sscanf(sc->name, "%7s", socname) != 1) {
+        g_assert_not_reached();
+    }
+
+    for (i = 0; i < sc->num_cpus; i++) {
+        object_initialize_child(obj, "cpu[*]", &a->cpu[i],
+                                aspeed_soc_cpu_type(sc));
+    }
+
+    object_initialize_child(obj, "scu", &s->scu, TYPE_ASPEED_2700_SCU);
+    qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev",
+                         sc->silicon_rev);
+    object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu),
+                              "hw-strap1");
+    object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu),
+                              "hw-strap2");
+    object_property_add_alias(obj, "hw-prot-key", OBJECT(&s->scu),
+                              "hw-prot-key");
+
+    object_initialize_child(obj, "scuio", &s->scuio, TYPE_ASPEED_2700_SCUIO);
+    qdev_prop_set_uint32(DEVICE(&s->scuio), "silicon-rev",
+                         sc->silicon_rev);
+
+    snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname);
+    object_initialize_child(obj, "fmc", &s->fmc, typename);
+
+    for (i = 0; i < sc->spis_num; i++) {
+        snprintf(typename, sizeof(typename), "aspeed.spi%d-%s", i, socname);
+        object_initialize_child(obj, "spi[*]", &s->spi[i], typename);
+    }
+
+    snprintf(typename, sizeof(typename), "aspeed.sdmc-%s", socname);
+    object_initialize_child(obj, "sdmc", &s->sdmc, typename);
+    object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
+                              "ram-size");
+
+    for (i = 0; i < sc->wdts_num; i++) {
+        snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname);
+        object_initialize_child(obj, "wdt[*]", &s->wdt[i], typename);
+    }
+
+    for (i = 0; i < sc->macs_num; i++) {
+        object_initialize_child(obj, "ftgmac100[*]", &s->ftgmac100[i],
+                                TYPE_FTGMAC100);
+
+        object_initialize_child(obj, "mii[*]", &s->mii[i], TYPE_ASPEED_MII);
+    }
+
+    for (i = 0; i < sc->uarts_num; i++) {
+        object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_SERIAL_MM);
+    }
+
+    object_initialize_child(obj, "sli", &s->sli, TYPE_ASPEED_2700_SLI);
+    object_initialize_child(obj, "sliio", &s->sliio, TYPE_ASPEED_2700_SLIIO);
+    object_initialize_child(obj, "intc", &a->intc, TYPE_ASPEED_INTC);
+}
+
+/*
+ * ASPEED ast2700 has 0x0 as cluster ID
+ *
+ * https://developer.arm.com/documentation/100236/0100/register-descriptions/aarch64-system-registers/multiprocessor-affinity-register--el1
+ */
+static uint64_t aspeed_calc_affinity(int cpu)
+{
+    return (0x0 << ARM_AFF1_SHIFT) | cpu;
+}
+
+static void aspeed_soc_ast2700_gic(DeviceState *dev, Error **errp)
+{
+    Aspeed27x0SoCState *a = ASPEED27X0_SOC(dev);
+    AspeedSoCState *s = ASPEED_SOC(dev);
+    AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+    SysBusDevice *gicbusdev;
+    QList *redist_region_count;
+    int i;
+
+    a->intc.gic = qdev_new(gicv3_class_name());
+    qdev_prop_set_uint32(a->intc.gic, "revision", 3);
+    qdev_prop_set_uint32(a->intc.gic, "num-cpu", sc->num_cpus);
+    qdev_prop_set_uint32(a->intc.gic, "num-irq", AST2700_MAX_IRQ);
+
+    redist_region_count = qlist_new();
+    qlist_append_int(redist_region_count, sc->num_cpus);
+    qdev_prop_set_array(a->intc.gic, "redist-region-count",
+                            redist_region_count);
+
+    gicbusdev = SYS_BUS_DEVICE(a->intc.gic);
+    sysbus_realize_and_unref(gicbusdev, errp);
+    sysbus_mmio_map(gicbusdev, 0, sc->memmap[ASPEED_GIC_DIST]);
+    sysbus_mmio_map(gicbusdev, 1, sc->memmap[ASPEED_GIC_REDIST]);
+
+    for (i = 0; i < sc->num_cpus; i++) {
+        DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
+        int NUM_IRQS = 256, ARCH_GIC_MAINT_IRQ = 9, VIRTUAL_PMU_IRQ = 7;
+        int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
+
+        const int timer_irq[] = {
+            [GTIMER_PHYS] = 14,
+            [GTIMER_VIRT] = 11,
+            [GTIMER_HYP]  = 10,
+            [GTIMER_SEC]  = 13,
+        };
+        int j;
+
+        for (j = 0; j < ARRAY_SIZE(timer_irq); j++) {
+            qdev_connect_gpio_out(cpudev, j,
+                    qdev_get_gpio_in(a->intc.gic, ppibase + timer_irq[j]));
+        }
+
+        qemu_irq irq = qdev_get_gpio_in(a->intc.gic,
+                                        ppibase + ARCH_GIC_MAINT_IRQ);
+        qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
+                                    0, irq);
+        qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
+                qdev_get_gpio_in(a->intc.gic, ppibase + VIRTUAL_PMU_IRQ));
+
+        sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
+        sysbus_connect_irq(gicbusdev, i + sc->num_cpus,
+                           qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
+        sysbus_connect_irq(gicbusdev, i + 2 * sc->num_cpus,
+                           qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
+        sysbus_connect_irq(gicbusdev, i + 3 * sc->num_cpus,
+                           qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
+    }
+}
+
+static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
+{
+    int i;
+    Aspeed27x0SoCState *a = ASPEED27X0_SOC(dev);
+    AspeedSoCState *s = ASPEED_SOC(dev);
+    AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+    g_autofree char *sram_name = NULL;
+
+    /* Default boot region (SPI memory or ROMs) */
+    memory_region_init(&s->spi_boot_container, OBJECT(s),
+                       "aspeed.spi_boot_container", 0x400000000);
+    memory_region_add_subregion(s->memory, sc->memmap[ASPEED_DEV_SPI_BOOT],
+                                &s->spi_boot_container);
+
+    /* CPU */
+    for (i = 0; i < sc->num_cpus; i++) {
+        object_property_set_int(OBJECT(&a->cpu[i]), "mp-affinity",
+                                aspeed_calc_affinity(i), &error_abort);
+
+        object_property_set_int(OBJECT(&a->cpu[i]), "cntfrq", 1125000000,
+                                &error_abort);
+        object_property_set_link(OBJECT(&a->cpu[i]), "memory",
+                                 OBJECT(s->memory), &error_abort);
+
+        if (!qdev_realize(DEVICE(&a->cpu[i]), NULL, errp)) {
+            return;
+        }
+    }
+
+    /* GIC */
+    aspeed_soc_ast2700_gic(dev, errp);
+
+    /* INTC */
+    if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc), errp)) {
+        return;
+    }
+
+    aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc), 0,
+                    sc->memmap[ASPEED_DEV_INTC]);
+
+    /* GICINT orgate -> INTC -> GIC */
+    for (i = 0; i < ASPEED_INTC_NR_GICS; i++) {
+        if (!qdev_realize(DEVICE(&a->intc.gicint_orgate[i]), NULL, errp)) {
+            return;
+        }
+
+        qdev_connect_gpio_out(DEVICE(&a->intc.gicint_orgate[i]), 0,
+                              qdev_get_gpio_in(DEVICE(&a->intc), i));
+
+        sysbus_connect_irq(SYS_BUS_DEVICE(&a->intc), i,
+                           qdev_get_gpio_in(a->intc.gic,
+                                aspeed_soc_ast2700_gic_intcmap[i].irq));
+    }
+
+    /* SRAM */
+    sram_name = g_strdup_printf("aspeed.sram.%d", CPU(&a->cpu[0])->cpu_index);
+    if (!memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size,
+                                 errp)) {
+        return;
+    }
+    memory_region_add_subregion(s->memory,
+                                sc->memmap[ASPEED_DEV_SRAM], &s->sram);
+
+    /* SCU */
+    if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) {
+        return;
+    }
+    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]);
+
+    /* SCU1 */
+    if (!sysbus_realize(SYS_BUS_DEVICE(&s->scuio), errp)) {
+        return;
+    }
+    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scuio), 0,
+                    sc->memmap[ASPEED_DEV_SCUIO]);
+
+    /* UART */
+    if (!aspeed_soc_uart_realize(s, errp)) {
+        return;
+    }
+
+    /* FMC, The number of CS is set at the board level */
+    object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr),
+                             &error_abort);
+    if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) {
+        return;
+    }
+    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]);
+    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 1,
+                    ASPEED_SMC_GET_CLASS(&s->fmc)->flash_window_base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0,
+                       aspeed_soc_get_irq(s, ASPEED_DEV_FMC));
+
+    /* Set up an alias on the FMC CE0 region (boot default) */
+    MemoryRegion *fmc0_mmio = &s->fmc.flashes[0].mmio;
+    memory_region_init_alias(&s->spi_boot, OBJECT(s), "aspeed.spi_boot",
+                             fmc0_mmio, 0, memory_region_size(fmc0_mmio));
+    memory_region_add_subregion(&s->spi_boot_container, 0x0, &s->spi_boot);
+
+    /* SPI */
+    for (i = 0; i < sc->spis_num; i++) {
+        object_property_set_link(OBJECT(&s->spi[i]), "dram",
+                                 OBJECT(s->dram_mr), &error_abort);
+        if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) {
+            return;
+        }
+        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 0,
+                        sc->memmap[ASPEED_DEV_SPI0 + i]);
+        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 1,
+                        ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base);
+    }
+
+    /*
+     * SDMC - SDRAM Memory Controller
+     * The SDMC controller is unlocked at SPL stage.
+     * At present, only supports to emulate booting
+     * start from u-boot stage. Set SDMC controller
+     * unlocked by default. It is a temporarily solution.
+     */
+    object_property_set_bool(OBJECT(&s->sdmc), "unlocked", true,
+                                 &error_abort);
+    if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), errp)) {
+        return;
+    }
+    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdmc), 0,
+                    sc->memmap[ASPEED_DEV_SDMC]);
+
+    /* RAM */
+    if (!aspeed_soc_dram_init(s, errp)) {
+        return;
+    }
+
+    for (i = 0; i < sc->macs_num; i++) {
+        object_property_set_bool(OBJECT(&s->ftgmac100[i]), "aspeed", true,
+                                 &error_abort);
+        if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), errp)) {
+            return;
+        }
+        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
+                        sc->memmap[ASPEED_DEV_ETH1 + i]);
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
+                           aspeed_soc_get_irq(s, ASPEED_DEV_ETH1 + i));
+
+        object_property_set_link(OBJECT(&s->mii[i]), "nic",
+                                 OBJECT(&s->ftgmac100[i]), &error_abort);
+        if (!sysbus_realize(SYS_BUS_DEVICE(&s->mii[i]), errp)) {
+            return;
+        }
+
+        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->mii[i]), 0,
+                        sc->memmap[ASPEED_DEV_MII1 + i]);
+    }
+
+    /* Watch dog */
+    for (i = 0; i < sc->wdts_num; i++) {
+        AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]);
+        hwaddr wdt_offset = sc->memmap[ASPEED_DEV_WDT] + i * awc->iosize;
+
+        object_property_set_link(OBJECT(&s->wdt[i]), "scu", OBJECT(&s->scu),
+                                 &error_abort);
+        if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
+            return;
+        }
+        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0, wdt_offset);
+    }
+
+    /* SLI */
+    if (!sysbus_realize(SYS_BUS_DEVICE(&s->sli), errp)) {
+        return;
+    }
+    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sli), 0, sc->memmap[ASPEED_DEV_SLI]);
+
+    if (!sysbus_realize(SYS_BUS_DEVICE(&s->sliio), errp)) {
+        return;
+    }
+    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sliio), 0,
+                    sc->memmap[ASPEED_DEV_SLIIO]);
+
+    create_unimplemented_device("ast2700.dpmcu", 0x11000000, 0x40000);
+    create_unimplemented_device("ast2700.iomem0", 0x12000000, 0x01000000);
+    create_unimplemented_device("ast2700.iomem1", 0x14000000, 0x01000000);
+    create_unimplemented_device("ast2700.ltpi", 0x30000000, 0x1000000);
+    create_unimplemented_device("ast2700.io", 0x0, 0x4000000);
+}
+
+static void aspeed_soc_ast2700_class_init(ObjectClass *oc, void *data)
+{
+    static const char * const valid_cpu_types[] = {
+        ARM_CPU_TYPE_NAME("cortex-a35"),
+        NULL
+    };
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc);
+
+    dc->realize      = aspeed_soc_ast2700_realize;
+
+    sc->name         = "ast2700-a0";
+    sc->valid_cpu_types = valid_cpu_types;
+    sc->silicon_rev  = AST2700_A0_SILICON_REV;
+    sc->sram_size    = 0x20000;
+    sc->spis_num     = 3;
+    sc->wdts_num     = 8;
+    sc->macs_num     = 1;
+    sc->uarts_num    = 13;
+    sc->num_cpus     = 4;
+    sc->uarts_base   = ASPEED_DEV_UART0;
+    sc->irqmap       = aspeed_soc_ast2700_irqmap;
+    sc->memmap       = aspeed_soc_ast2700_memmap;
+    sc->get_irq      = aspeed_soc_ast2700_get_irq;
+}
+
+static const TypeInfo aspeed_soc_ast27x0_types[] = {
+    {
+        .name           = TYPE_ASPEED27X0_SOC,
+        .parent         = TYPE_ASPEED_SOC,
+        .instance_size  = sizeof(Aspeed27x0SoCState),
+        .abstract       = true,
+    }, {
+        .name           = "ast2700-a0",
+        .parent         = TYPE_ASPEED27X0_SOC,
+        .instance_init  = aspeed_soc_ast2700_init,
+        .class_init     = aspeed_soc_ast2700_class_init,
+    },
+};
+
+DEFINE_TYPES(aspeed_soc_ast27x0_types)
diff --git a/hw/arm/meson.build b/hw/arm/meson.build
index 6808135c1f..1e3295a423 100644
--- a/hw/arm/meson.build
+++ b/hw/arm/meson.build
@@ -46,6 +46,7 @@ arm_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
   'aspeed_soc_common.c',
   'aspeed_ast2400.c',
   'aspeed_ast2600.c',
+  'aspeed_ast27x0.c',
   'aspeed_ast10x0.c',
   'aspeed_eeprom.c',
   'fby35.c'))
diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
index c60fac900a..9f177b6037 100644
--- a/include/hw/arm/aspeed_soc.h
+++ b/include/hw/arm/aspeed_soc.h
@@ -15,6 +15,7 @@
 #include "hw/cpu/a15mpcore.h"
 #include "hw/arm/armv7m.h"
 #include "hw/intc/aspeed_vic.h"
+#include "hw/intc/aspeed_intc.h"
 #include "hw/misc/aspeed_scu.h"
 #include "hw/adc/aspeed_adc.h"
 #include "hw/misc/aspeed_sdmc.h"
@@ -26,6 +27,7 @@
 #include "hw/ssi/aspeed_smc.h"
 #include "hw/misc/aspeed_hace.h"
 #include "hw/misc/aspeed_sbc.h"
+#include "hw/misc/aspeed_sli.h"
 #include "hw/watchdog/wdt_aspeed.h"
 #include "hw/net/ftgmac100.h"
 #include "target/arm/cpu.h"
@@ -41,8 +43,8 @@
 
 #define ASPEED_SPIS_NUM  2
 #define ASPEED_EHCIS_NUM 2
-#define ASPEED_WDTS_NUM  4
-#define ASPEED_CPUS_NUM  2
+#define ASPEED_WDTS_NUM  8
+#define ASPEED_CPUS_NUM  4
 #define ASPEED_MACS_NUM  4
 #define ASPEED_UARTS_NUM 13
 #define ASPEED_JTAG_NUM  2
@@ -61,6 +63,7 @@ struct AspeedSoCState {
     AspeedI2CState i2c;
     AspeedI3CState i3c;
     AspeedSCUState scu;
+    AspeedSCUState scuio;
     AspeedHACEState hace;
     AspeedXDMAState xdma;
     AspeedADCState adc;
@@ -68,6 +71,8 @@ struct AspeedSoCState {
     AspeedSMCState spi[ASPEED_SPIS_NUM];
     EHCISysBusState ehci[ASPEED_EHCIS_NUM];
     AspeedSBCState sbc;
+    AspeedSLIState sli;
+    AspeedSLIState sliio;
     MemoryRegion secsram;
     UnimplementedDeviceState sbc_unimplemented;
     AspeedSDMCState sdmc;
@@ -117,6 +122,16 @@ struct Aspeed2600SoCState {
 #define TYPE_ASPEED2600_SOC "aspeed2600-soc"
 OBJECT_DECLARE_SIMPLE_TYPE(Aspeed2600SoCState, ASPEED2600_SOC)
 
+struct Aspeed27x0SoCState {
+    AspeedSoCState parent;
+
+    ARMCPU cpu[ASPEED_CPUS_NUM];
+    AspeedINTCState intc;
+};
+
+#define TYPE_ASPEED27X0_SOC "aspeed27x0-soc"
+OBJECT_DECLARE_SIMPLE_TYPE(Aspeed27x0SoCState, ASPEED27X0_SOC)
+
 struct Aspeed10x0SoCState {
     AspeedSoCState parent;
 
@@ -168,11 +183,13 @@ enum {
     ASPEED_DEV_UART13,
     ASPEED_DEV_VUART,
     ASPEED_DEV_FMC,
+    ASPEED_DEV_SPI0,
     ASPEED_DEV_SPI1,
     ASPEED_DEV_SPI2,
     ASPEED_DEV_EHCI1,
     ASPEED_DEV_EHCI2,
     ASPEED_DEV_VIC,
+    ASPEED_DEV_INTC,
     ASPEED_DEV_SDMC,
     ASPEED_DEV_SCU,
     ASPEED_DEV_ADC,
@@ -222,6 +239,11 @@ enum {
     ASPEED_DEV_JTAG1,
     ASPEED_DEV_FSI1,
     ASPEED_DEV_FSI2,
+    ASPEED_DEV_SCUIO,
+    ASPEED_DEV_SLI,
+    ASPEED_DEV_SLIIO,
+    ASPEED_GIC_DIST,
+    ASPEED_GIC_REDIST,
 };
 
 qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev);
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 13/16] aspeed: Add an AST2700 eval board
  2024-04-16  9:18 [PATCH v3 00/16] Add AST2700 support Jamin Lin via
                   ` (11 preceding siblings ...)
  2024-04-16  9:18 ` [PATCH v3 12/16] aspeed/soc: " Jamin Lin via
@ 2024-04-16  9:19 ` Jamin Lin via
  2024-04-16  9:19 ` [PATCH v3 14/16] aspeed/soc: fix incorrect dram size for AST2700 Jamin Lin via
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 42+ messages in thread
From: Jamin Lin via @ 2024-04-16  9:19 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, yunlin.tang

AST2700 CPU is ARM Cortex-A35 which is 64 bits.
Add TARGET_AARCH64 to build this machine.

According to the design of ast2700, it has a bootmcu(riscv-32) which
is used for executing SPL.
Then, CPUs(cortex-a35) execute u-boot, kernel and rofs.

Currently, qemu not support emulate two CPU architectures
at the same machine. Therefore, qemu will only support
to emulate CPU(cortex-a35) side for ast2700

Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
 hw/arm/aspeed.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index 93ca87fda2..40dc0e4c76 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -178,6 +178,12 @@ struct AspeedMachineState {
 #define AST2600_EVB_HW_STRAP1 0x000000C0
 #define AST2600_EVB_HW_STRAP2 0x00000003
 
+#ifdef TARGET_AARCH64
+/* AST2700 evb hardware value */
+#define AST2700_EVB_HW_STRAP1 0x000000C0
+#define AST2700_EVB_HW_STRAP2 0x00000003
+#endif
+
 /* Tacoma hardware value */
 #define TACOMA_BMC_HW_STRAP1  0x00000000
 #define TACOMA_BMC_HW_STRAP2  0x00000040
@@ -1588,6 +1594,26 @@ static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
     aspeed_machine_class_init_cpus_defaults(mc);
 }
 
+#ifdef TARGET_AARCH64
+static void aspeed_machine_ast2700_evb_class_init(ObjectClass *oc, void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+    AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
+
+    mc->desc = "Aspeed AST2700 EVB (Cortex-A35)";
+    amc->soc_name  = "ast2700-a0";
+    amc->hw_strap1 = AST2700_EVB_HW_STRAP1;
+    amc->hw_strap2 = AST2700_EVB_HW_STRAP2;
+    amc->fmc_model = "w25q01jvq";
+    amc->spi_model = "w25q512jv";
+    amc->num_cs    = 2;
+    amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON | ASPEED_MAC2_ON;
+    amc->uart_default = ASPEED_DEV_UART12;
+    mc->default_ram_size = 1 * GiB;
+    aspeed_machine_class_init_cpus_defaults(mc);
+}
+#endif
+
 static void aspeed_machine_qcom_dc_scm_v1_class_init(ObjectClass *oc,
                                                      void *data)
 {
@@ -1711,6 +1737,12 @@ static const TypeInfo aspeed_machine_types[] = {
         .name           = MACHINE_TYPE_NAME("ast1030-evb"),
         .parent         = TYPE_ASPEED_MACHINE,
         .class_init     = aspeed_minibmc_machine_ast1030_evb_class_init,
+#ifdef TARGET_AARCH64
+    }, {
+        .name          = MACHINE_TYPE_NAME("ast2700-evb"),
+        .parent        = TYPE_ASPEED_MACHINE,
+        .class_init    = aspeed_machine_ast2700_evb_class_init,
+#endif
     }, {
         .name          = TYPE_ASPEED_MACHINE,
         .parent        = TYPE_MACHINE,
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 14/16] aspeed/soc: fix incorrect dram size for AST2700
  2024-04-16  9:18 [PATCH v3 00/16] Add AST2700 support Jamin Lin via
                   ` (12 preceding siblings ...)
  2024-04-16  9:19 ` [PATCH v3 13/16] aspeed: Add an AST2700 eval board Jamin Lin via
@ 2024-04-16  9:19 ` Jamin Lin via
  2024-04-16  9:19 ` [PATCH v3 15/16] test/avocado/machine_aspeed.py: Add AST2700 test case Jamin Lin via
  2024-04-16  9:19 ` [PATCH v3 16/16] docs:aspeed: Add AST2700 Evaluation board Jamin Lin via
  15 siblings, 0 replies; 42+ messages in thread
From: Jamin Lin via @ 2024-04-16  9:19 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, yunlin.tang

AST2700 dram size calculation is not back compatible AST2600.
According to the DDR capacity hardware behavior,
if users write the data to address which is beyond the ram size,
it would write the data to address 0.
For example:
a. sdram base address "0x4 00000000"
b. sdram size is 1 GiB
The available address range is from "0x4 00000000" to "0x4 40000000".
If users write 0xdeadbeef to address "0x6 00000000",
the value of DRAM address 0 (base address 0x4 00000000) should be 0xdeadbeef.

Add aspeed_soc_ast2700_dram_init to calculate the dram size and add
memory I/O whose address range is from max_ram_size - ram_size to max_ram_size
and its read/write handler to emulate DDR capacity hardware behavior.

Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
 hw/arm/aspeed_ast27x0.c     | 94 ++++++++++++++++++++++++++++++++++++-
 include/hw/arm/aspeed_soc.h |  1 +
 2 files changed, 94 insertions(+), 1 deletion(-)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 754c963230..38858e4fde 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -20,6 +20,7 @@
 #include "sysemu/sysemu.h"
 #include "hw/intc/arm_gicv3.h"
 #include "qapi/qmp/qlist.h"
+#include "qemu/log.h"
 
 static const hwaddr aspeed_soc_ast2700_memmap[] = {
     [ASPEED_DEV_SPI_BOOT]  =  0x400000000,
@@ -191,6 +192,97 @@ static qemu_irq aspeed_soc_ast2700_get_irq(AspeedSoCState *s, int dev)
     return qdev_get_gpio_in(a->intc.gic, sc->irqmap[dev]);
 }
 
+static uint64_t aspeed_ram_capacity_read(void *opaque, hwaddr addr,
+                                                    unsigned int size)
+{
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "%s: read @%" PRIx64 " out of ram size\n",
+                   __func__, addr);
+    return 0;
+}
+
+static void aspeed_ram_capacity_write(void *opaque, hwaddr addr, uint64_t data,
+                                                unsigned int size)
+{
+    AspeedSoCState *s = ASPEED_SOC(opaque);
+    uint32_t test_pattern = 0xdeadbeef;
+    bool invalid_pattern = true;
+    uint32_t *ram_ptr;
+    int sz;
+
+    ram_ptr = memory_region_get_ram_ptr(s->dram_mr);
+
+   /*
+    * Emulate ddr capacity hardware behavior.
+    * If writes the test_pattern to address which is beyond the ram size,
+    * it would write the test_pattern to address 0.
+    */
+    for (sz = 4; sz > 0 ; sz--) {
+        test_pattern = (test_pattern << 4) + sz;
+        if (data == test_pattern) {
+            ram_ptr[0] = test_pattern;
+            invalid_pattern = false;
+            break;
+        }
+    }
+
+    if (invalid_pattern) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: write invalid pattern @%" PRIx64
+                      " to addr @%" HWADDR_PRIx "]\n",
+                      __func__, data, addr);
+    }
+}
+
+static const MemoryRegionOps aspeed_ram_capacity_ops = {
+    .read = aspeed_ram_capacity_read,
+    .write = aspeed_ram_capacity_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 8,
+    },
+};
+
+/*
+ * SDMC should be realized first to get correct RAM size and max size
+ * values
+ */
+static bool aspeed_soc_ast2700_dram_init(DeviceState *dev, Error **errp)
+{
+    ram_addr_t ram_size, max_ram_size;
+    Aspeed27x0SoCState *a = ASPEED27X0_SOC(dev);
+    AspeedSoCState *s = ASPEED_SOC(dev);
+    AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+
+    ram_size = object_property_get_uint(OBJECT(&s->sdmc), "ram-size",
+                                        &error_abort);
+    max_ram_size = object_property_get_uint(OBJECT(&s->sdmc), "max-ram-size",
+                                            &error_abort);
+
+    memory_region_init(&s->dram_container, OBJECT(s), "ram-container",
+                       ram_size);
+    memory_region_add_subregion(&s->dram_container, 0, s->dram_mr);
+
+    /*
+     * Add a memory region beyond the RAM region to emulate
+     * ddr capacity hardware behavior.
+     */
+    if (ram_size < max_ram_size) {
+        memory_region_init_io(&a->dram_empty, OBJECT(s),
+                              &aspeed_ram_capacity_ops, s,
+                              "ram-empty", max_ram_size - ram_size);
+
+        memory_region_add_subregion(s->memory,
+                                    sc->memmap[ASPEED_DEV_SDRAM] + ram_size,
+                                    &a->dram_empty);
+    }
+
+    memory_region_add_subregion(s->memory,
+                      sc->memmap[ASPEED_DEV_SDRAM], &s->dram_container);
+    return true;
+}
+
 static void aspeed_soc_ast2700_init(Object *obj)
 {
     Aspeed27x0SoCState *a = ASPEED27X0_SOC(obj);
@@ -454,7 +546,7 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
                     sc->memmap[ASPEED_DEV_SDMC]);
 
     /* RAM */
-    if (!aspeed_soc_dram_init(s, errp)) {
+    if (!aspeed_soc_ast2700_dram_init(dev, errp)) {
         return;
     }
 
diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
index 9f177b6037..9dbf48f873 100644
--- a/include/hw/arm/aspeed_soc.h
+++ b/include/hw/arm/aspeed_soc.h
@@ -127,6 +127,7 @@ struct Aspeed27x0SoCState {
 
     ARMCPU cpu[ASPEED_CPUS_NUM];
     AspeedINTCState intc;
+    MemoryRegion dram_empty;
 };
 
 #define TYPE_ASPEED27X0_SOC "aspeed27x0-soc"
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 15/16] test/avocado/machine_aspeed.py: Add AST2700 test case
  2024-04-16  9:18 [PATCH v3 00/16] Add AST2700 support Jamin Lin via
                   ` (13 preceding siblings ...)
  2024-04-16  9:19 ` [PATCH v3 14/16] aspeed/soc: fix incorrect dram size for AST2700 Jamin Lin via
@ 2024-04-16  9:19 ` Jamin Lin via
  2024-04-16 16:44   ` Cédric Le Goater
  2024-04-16  9:19 ` [PATCH v3 16/16] docs:aspeed: Add AST2700 Evaluation board Jamin Lin via
  15 siblings, 1 reply; 42+ messages in thread
From: Jamin Lin via @ 2024-04-16  9:19 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, yunlin.tang

Add a test case to test Aspeed OpenBMC SDK v09.01 on AST2700 board.

It loads u-boot-nodtb.bin, u-boot.dtb, tfa and optee-os
images to dram first which base address is 0x400000000.
Then, boot and launch 4 cpu cores.

```
qemu-system-aarch64 -machine ast2700-evb
    -device loader,force-raw=on,addr=0x400000000,file=workdir/u-boot-nodtb.bin \
    -device loader,force-raw=on,addr=uboot_dtb_load_addr,file=u-boot.dtb\
    -device loader,force-raw=on,addr=0x430000000,file=workdir/bl31.bin\
    -device loader,force-raw=on,addr=0x430080000,file=workdir/optee/tee-raw.bin\
    -device loader,cpu-num=0,addr=0x430000000 \
    -device loader,cpu-num=1,addr=0x430000000 \
    -device loader,cpu-num=2,addr=0x430000000 \
    -device loader,cpu-num=3,addr=0x430000000 \
    -smp 4 \
    -drive file=workdir/image-bmc,format=raw,if=mtd
```

A test image is downloaded from the ASPEED Forked OpenBMC GitHub release repository :
https://github.com/AspeedTech-BMC/openbmc/releases/

Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
 tests/avocado/machine_aspeed.py | 62 +++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
index cec0181424..3a20644fb2 100644
--- a/tests/avocado/machine_aspeed.py
+++ b/tests/avocado/machine_aspeed.py
@@ -311,6 +311,17 @@ def do_test_arm_aspeed_sdk_start(self, image):
             self, 'boot', '## Loading kernel from FIT Image')
         self.wait_for_console_pattern('Starting kernel ...')
 
+    def do_test_aarch64_aspeed_sdk_start(self, image):
+        self.vm.set_console()
+        self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw')
+
+        self.vm.launch()
+
+        self.wait_for_console_pattern('U-Boot 2023.10')
+        self.wait_for_console_pattern('## Loading kernel from FIT Image')
+        self.wait_for_console_pattern('Starting kernel ...')
+        self.wait_for_console_pattern("systemd[1]: Hostname set to")
+
     @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
 
     def test_arm_ast2500_evb_sdk(self):
@@ -375,3 +386,54 @@ def test_arm_ast2600_evb_sdk(self):
              'i2c i2c-5: new_device: Instantiated device ds1307 at 0x32');
         year = time.strftime("%Y")
         self.ssh_command_output_contains('/sbin/hwclock -f /dev/rtc1', year);
+
+    def test_aarch64_ast2700_evb_sdk_v09_01(self):
+        """
+        :avocado: tags=arch:aarch64
+        :avocado: tags=machine:ast2700-evb
+        """
+
+        image_url = ('https://github.com/AspeedTech-BMC/openbmc/releases/'
+                     'download/v09.01/ast2700-default-obmc.tar.gz')
+        image_hash = 'b1cc0fd73c7650d34c9c8459a243f52a91e9e27144b8608b2645ab19461d1e07'
+        image_path = self.fetch_asset(image_url, asset_hash=image_hash,
+                                      algorithm='sha256')
+        archive.extract(image_path, self.workdir)
+
+        num_cpu = 4
+        image_dir = self.workdir + '/ast2700-default/'
+        uboot_size = os.path.getsize(image_dir + 'u-boot-nodtb.bin')
+        uboot_dtb_load_addr = hex(0x400000000 + uboot_size)
+
+        load_images_list = [
+            {
+                'addr': '0x400000000',
+                'file': image_dir + 'u-boot-nodtb.bin'
+            },
+            {
+                'addr': str(uboot_dtb_load_addr),
+                'file': image_dir + 'u-boot.dtb'
+            },
+            {
+                'addr': '0x430000000',
+                'file': image_dir + 'bl31.bin'
+            },
+            {
+                'addr': '0x430080000',
+                'file': image_dir + 'optee/tee-raw.bin'
+            }
+        ]
+
+        for load_image in load_images_list:
+            addr = load_image['addr']
+            file = load_image['file']
+            self.vm.add_args('-device',
+                             f'loader,force-raw=on,addr={addr},file={file}')
+
+        for i in range(num_cpu):
+            self.vm.add_args('-device',
+                             f'loader,addr=0x430000000,cpu-num={i}')
+
+        self.vm.add_args('-smp', str(num_cpu))
+        self.do_test_aarch64_aspeed_sdk_start(image_dir + 'image-bmc')
+
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 16/16] docs:aspeed: Add AST2700 Evaluation board
  2024-04-16  9:18 [PATCH v3 00/16] Add AST2700 support Jamin Lin via
                   ` (14 preceding siblings ...)
  2024-04-16  9:19 ` [PATCH v3 15/16] test/avocado/machine_aspeed.py: Add AST2700 test case Jamin Lin via
@ 2024-04-16  9:19 ` Jamin Lin via
  2024-04-16 15:54   ` Cédric Le Goater
  15 siblings, 1 reply; 42+ messages in thread
From: Jamin Lin via @ 2024-04-16  9:19 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: jamin_lin, troy_lee, yunlin.tang

Add AST2700 Evaluation board and its boot command.

Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
 docs/system/arm/aspeed.rst | 39 ++++++++++++++++++++++++++++++++++----
 1 file changed, 35 insertions(+), 4 deletions(-)

diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst
index b2dea54eed..320ff2a4cd 100644
--- a/docs/system/arm/aspeed.rst
+++ b/docs/system/arm/aspeed.rst
@@ -1,11 +1,12 @@
-Aspeed family boards (``*-bmc``, ``ast2500-evb``, ``ast2600-evb``)
-==================================================================
+Aspeed family boards (``*-bmc``, ``ast2500-evb``, ``ast2600-evb``, ``ast2700-evb``)
+===================================================================================
 
 The QEMU Aspeed machines model BMCs of various OpenPOWER systems and
 Aspeed evaluation boards. They are based on different releases of the
 Aspeed SoC : the AST2400 integrating an ARM926EJ-S CPU (400MHz), the
-AST2500 with an ARM1176JZS CPU (800MHz) and more recently the AST2600
-with dual cores ARM Cortex-A7 CPUs (1.2GHz).
+AST2500 with an ARM1176JZS CPU (800MHz), the AST2600
+with dual cores ARM Cortex-A7 CPUs (1.2GHz) and more recently the AST2700
+with quad cores ARM Cortex-A35 64 bits CPUs (1.6GHz)
 
 The SoC comes with RAM, Gigabit ethernet, USB, SD/MMC, USB, SPI, I2C,
 etc.
@@ -38,6 +39,10 @@ AST2600 SoC based machines :
 - ``qcom-dc-scm-v1-bmc``   Qualcomm DC-SCM V1 BMC
 - ``qcom-firework-bmc``    Qualcomm Firework BMC
 
+AST2700 SoC based machines :
+
+- ``ast2700-evb``          Aspeed AST2700 Evaluation board (Cortex-A35)
+
 Supported devices
 -----------------
 
@@ -66,6 +71,7 @@ Supported devices
  * eMMC Boot Controller (dummy)
  * PECI Controller (minimal)
  * I3C Controller
+ * Internal Bridge Controller (SLI dummy)
 
 
 Missing devices
@@ -95,6 +101,10 @@ or directly from the OpenBMC GitHub release repository :
 
    https://github.com/openbmc/openbmc/releases
 
+or directly from the ASPEED Forked OpenBMC GitHub release repository :
+
+   https://github.com/AspeedTech-BMC/openbmc/releases
+
 To boot a kernel directly from a Linux build tree:
 
 .. code-block:: bash
@@ -164,6 +174,27 @@ under Linux), use :
 
   -M ast2500-evb,bmc-console=uart3
 
+
+Boot the AST2700 machine from the flash image, use an MTD drive :
+
+.. code-block:: bash
+
+  IMGDIR=ast2700-default
+  UBOOT_SIZE=$(stat --format=%s -L ${IMGDIR}/u-boot-nodtb.bin)
+
+  $ qemu-system-aarch64 -M ast2700-evb \
+       -device loader,force-raw=on,addr=0x400000000,file=${IMGDIR}/u-boot-nodtb.bin \
+       -device loader,force-raw=on,addr=$((0x400000000 + ${UBOOT_SIZE})),file=u-boot.dtb \
+       -device loader,force-raw=on,addr=0x430000000,file=${IMGDIR}/bl31.bin \
+       -device loader,force-raw=on,addr=0x430080000,file=${IMGDIR}/optee/tee-raw.bin \
+       -device loader,cpu-num=0,addr=0x430000000 \
+       -device loader,cpu-num=1,addr=0x430000000 \
+       -device loader,cpu-num=2,addr=0x430000000 \
+       -device loader,cpu-num=3,addr=0x430000000 \
+       -smp 4 \
+       -drive file=${IMGDIR}/image-bmc,format=raw,if=mtd \
+       -nographic
+
 Aspeed minibmc family boards (``ast1030-evb``)
 ==================================================================
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 02/16] aspeed/sli: Add AST2700 support
  2024-04-16  9:18 ` [PATCH v3 02/16] aspeed/sli: " Jamin Lin via
@ 2024-04-16 15:29   ` Cédric Le Goater
  0 siblings, 0 replies; 42+ messages in thread
From: Cédric Le Goater @ 2024-04-16 15:29 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	Alistair Francis, Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: troy_lee, yunlin.tang

Hello Jamin,

On 4/16/24 11:18, Jamin Lin wrote:
> AST2700 SLI engine is designed to accelerate the
> throughput between cross-die connections.
> It have CPU_SLI at CPU die and IO_SLI at IO die.
> 
> Introduce dummy AST2700 SLI and SLIIO models.
> 
> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
>   hw/misc/aspeed_sli.c         | 178 +++++++++++++++++++++++++++++++++++
>   hw/misc/meson.build          |   3 +-
>   hw/misc/trace-events         |   7 ++
>   include/hw/misc/aspeed_sli.h |  31 ++++++
>   4 files changed, 218 insertions(+), 1 deletion(-)
>   create mode 100644 hw/misc/aspeed_sli.c
>   create mode 100644 include/hw/misc/aspeed_sli.h
> 
> diff --git a/hw/misc/aspeed_sli.c b/hw/misc/aspeed_sli.c
> new file mode 100644
> index 0000000000..e84fd6a4ca
> --- /dev/null
> +++ b/hw/misc/aspeed_sli.c
> @@ -0,0 +1,178 @@
> +/*
> + * ASPEED SLI Controller
> + *
> + * Copyright (C) 2024 ASPEED Technology Inc.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "qemu/error-report.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/misc/aspeed_sli.h"
> +#include "qapi/error.h"
> +#include "migration/vmstate.h"
> +#include "trace.h"
> +
> +#define SLI_REGION_SIZE 0x500
> +#define TO_REG(addr) ((addr) >> 2)
> +
> +static uint64_t aspeed_sli_read(void *opaque, hwaddr addr, unsigned int size)
> +{
> +    AspeedSLIState *s = ASPEED_SLI(opaque);
> +    int reg = TO_REG(addr);
> +
> +    if (reg >= ARRAY_SIZE(s->regs)) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
> +                      __func__, addr);
> +        return 0;
> +    }
> +
> +    trace_aspeed_sli_read(addr, size, s->regs[reg]);
> +    return s->regs[reg];
> +}
> +
> +static void aspeed_sli_write(void *opaque, hwaddr addr, uint64_t data,
> +                              unsigned int size)
> +{
> +    AspeedSLIState *s = ASPEED_SLI(opaque);
> +    int reg = TO_REG(addr);
> +
> +    if (reg >= ARRAY_SIZE(s->regs)) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
> +                      __func__, addr);
> +        return;
> +    }
> +
> +    trace_aspeed_sli_write(addr, size, data);
> +    s->regs[reg] = data;
> +}
> +
> +static uint64_t aspeed_sliio_read(void *opaque, hwaddr addr, unsigned int size)
> +{
> +    AspeedSLIState *s = ASPEED_SLI(opaque);
> +    int reg = TO_REG(addr);
> +
> +    if (reg >= ARRAY_SIZE(s->regs)) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
> +                      __func__, addr);
> +        return 0;
> +    }
> +
> +    trace_aspeed_sliio_read(addr, size, s->regs[reg]);
> +    return s->regs[reg];
> +}
> +
> +static void aspeed_sliio_write(void *opaque, hwaddr addr, uint64_t data,
> +                              unsigned int size)
> +{
> +    AspeedSLIState *s = ASPEED_SLI(opaque);
> +    int reg = TO_REG(addr);
> +
> +    if (reg >= ARRAY_SIZE(s->regs)) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
> +                      __func__, addr);
> +        return;
> +    }
> +
> +    trace_aspeed_sliio_write(addr, size, data);
> +    s->regs[reg] = data;
> +}
> +
> +static const MemoryRegionOps aspeed_sli_ops = {
> +    .read = aspeed_sli_read,
> +    .write = aspeed_sli_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 1,
> +        .max_access_size = 4,
> +    },
> +};
> +
> +static const MemoryRegionOps aspeed_sliio_ops = {
> +    .read = aspeed_sliio_read,
> +    .write = aspeed_sliio_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 1,
> +        .max_access_size = 4,
> +    },
> +};
> +
> +static void aspeed_sli_realize(DeviceState *dev, Error **errp)
> +{
> +    AspeedSLIState *s = ASPEED_SLI(dev);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +
> +    memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sli_ops, s,
> +                          TYPE_ASPEED_SLI, SLI_REGION_SIZE);
> +    sysbus_init_mmio(sbd, &s->iomem);
> +}
> +
> +static void aspeed_sliio_realize(DeviceState *dev, Error **errp)
> +{
> +    AspeedSLIState *s = ASPEED_SLI(dev);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +
> +    memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sliio_ops, s,
> +                          TYPE_ASPEED_SLI, SLI_REGION_SIZE);
> +    sysbus_init_mmio(sbd, &s->iomem);
> +}
> +
> +static void aspeed_sli_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->desc = "Aspeed SLI Controller";
> +    dc->realize = aspeed_sli_realize;
> +}
> +
> +static const TypeInfo aspeed_sli_info = {
> +    .name          = TYPE_ASPEED_SLI,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(AspeedSLIState),
> +    .class_init    = aspeed_sli_class_init,
> +    .class_size    = sizeof(AspeedSLIClass),
> +    .abstract      = true,
> +};
> +
> +static void aspeed_2700_sli_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->desc = "AST2700 SLI Controller";
> +}
> +
> +static void aspeed_2700_sliio_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->desc = "AST2700 I/O SLI Controller";
> +    dc->realize = aspeed_sliio_realize;
> +}
> +
> +static const TypeInfo aspeed_2700_sli_info = {
> +    .name           = TYPE_ASPEED_2700_SLI,
> +    .parent         = TYPE_ASPEED_SLI,
> +    .class_init     = aspeed_2700_sli_class_init,
> +};
> +
> +static const TypeInfo aspeed_2700_sliio_info = {
> +    .name           = TYPE_ASPEED_2700_SLIIO,
> +    .parent         = TYPE_ASPEED_SLI,
> +    .class_init     = aspeed_2700_sliio_class_init,
> +};
> +
> +static void aspeed_sli_register_types(void)
> +{
> +    type_register_static(&aspeed_sli_info);
> +    type_register_static(&aspeed_2700_sli_info);
> +    type_register_static(&aspeed_2700_sliio_info);
> +}
> +
> +type_init(aspeed_sli_register_types);
> diff --git a/hw/misc/meson.build b/hw/misc/meson.build
> index 86596a3888..2ca8717be2 100644
> --- a/hw/misc/meson.build
> +++ b/hw/misc/meson.build
> @@ -136,7 +136,8 @@ system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
>     'aspeed_sbc.c',
>     'aspeed_sdmc.c',
>     'aspeed_xdma.c',
> -  'aspeed_peci.c'))
> +  'aspeed_peci.c',
> +  'aspeed_sli.c'))
>   
>   system_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-sysreg.c'))
>   system_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_rng.c'))
> diff --git a/hw/misc/trace-events b/hw/misc/trace-events
> index 5d241cb40a..e13b648221 100644
> --- a/hw/misc/trace-events
> +++ b/hw/misc/trace-events
> @@ -351,3 +351,10 @@ djmemc_write(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRI
>   # iosb.c
>   iosb_read(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u"
>   iosb_write(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u"
> +
> +# aspeed_sli.c
> +aspeed_sli_write(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
> +aspeed_sli_read(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
> +aspeed_sliio_write(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
> +aspeed_sliio_read(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
> +
> diff --git a/include/hw/misc/aspeed_sli.h b/include/hw/misc/aspeed_sli.h
> new file mode 100644
> index 0000000000..2329002b84
> --- /dev/null
> +++ b/include/hw/misc/aspeed_sli.h
> @@ -0,0 +1,31 @@
> +/*
> + * ASPEED SLI Controller
> + *
> + * Copyright (C) 2024 ASPEED Technology Inc.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +#ifndef ASPEED_SLI_H
> +#define ASPEED_SLI_H
> +
> +#include "hw/sysbus.h"
> +
> +#define TYPE_ASPEED_SLI "aspeed.sli"
> +#define TYPE_ASPEED_2700_SLI TYPE_ASPEED_SLI "-ast2700"
> +#define TYPE_ASPEED_2700_SLIIO TYPE_ASPEED_SLI "io" "-ast2700"
> +OBJECT_DECLARE_TYPE(AspeedSLIState, AspeedSLIClass, ASPEED_SLI)
> +
> +#define ASPEED_SLI_NR_REGS  (0x500 >> 2)
> +
> +struct AspeedSLIState {
> +    SysBusDevice parent;
> +    MemoryRegion iomem;
> +
> +    uint32_t regs[ASPEED_SLI_NR_REGS];
> +};
> +
> +struct AspeedSLIClass {
> +    SysBusDeviceClass parent_class;
> +};

May be use OBJECT_DECLARE_SIMPLE_TYPE() to avoid the empty class.

Anyhow,


Reviewed-by: Cédric Le Goater <clg@kaod.org>

Thanks,

C.



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 03/16] aspeed/sdmc: remove redundant macros
  2024-04-16  9:18 ` [PATCH v3 03/16] aspeed/sdmc: remove redundant macros Jamin Lin via
@ 2024-04-16 15:30   ` Cédric Le Goater
  0 siblings, 0 replies; 42+ messages in thread
From: Cédric Le Goater @ 2024-04-16 15:30 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	Alistair Francis, Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: troy_lee, yunlin.tang

On 4/16/24 11:18, Jamin Lin wrote:
> These macros are no longer used for ASPEED SOCs, so removes them.
> 
> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>


Reviewed-by: Cédric Le Goater <clg@kaod.org>

Thanks,

C.


> ---
>   hw/misc/aspeed_sdmc.c | 15 ---------------
>   1 file changed, 15 deletions(-)
> 
> diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c
> index 64cd1a81dc..74279bbe8e 100644
> --- a/hw/misc/aspeed_sdmc.c
> +++ b/hw/misc/aspeed_sdmc.c
> @@ -76,10 +76,6 @@
>   #define     ASPEED_SDMC_VGA_32MB            0x2
>   #define     ASPEED_SDMC_VGA_64MB            0x3
>   #define ASPEED_SDMC_DRAM_SIZE(x)        (x & 0x3)
> -#define     ASPEED_SDMC_DRAM_64MB           0x0
> -#define     ASPEED_SDMC_DRAM_128MB          0x1
> -#define     ASPEED_SDMC_DRAM_256MB          0x2
> -#define     ASPEED_SDMC_DRAM_512MB          0x3
>   
>   #define ASPEED_SDMC_READONLY_MASK                       \
>       (ASPEED_SDMC_RESERVED | ASPEED_SDMC_VGA_COMPAT |    \
> @@ -100,17 +96,6 @@
>   #define ASPEED_SDMC_CACHE_ENABLE        (1 << 10) /* differs from AST2400 */
>   #define ASPEED_SDMC_DRAM_TYPE           (1 << 4)  /* differs from AST2400 */
>   
> -/* DRAM size definitions differs */
> -#define     ASPEED_SDMC_AST2500_128MB       0x0
> -#define     ASPEED_SDMC_AST2500_256MB       0x1
> -#define     ASPEED_SDMC_AST2500_512MB       0x2
> -#define     ASPEED_SDMC_AST2500_1024MB      0x3
> -
> -#define     ASPEED_SDMC_AST2600_256MB       0x0
> -#define     ASPEED_SDMC_AST2600_512MB       0x1
> -#define     ASPEED_SDMC_AST2600_1024MB      0x2
> -#define     ASPEED_SDMC_AST2600_2048MB      0x3
> -
>   #define ASPEED_SDMC_AST2500_READONLY_MASK                               \
>       (ASPEED_SDMC_HW_VERSION(0xf) | ASPEED_SDMC_CACHE_INITIAL_DONE |     \
>        ASPEED_SDMC_AST2500_RESERVED | ASPEED_SDMC_VGA_COMPAT |            \



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 04/16] aspeed/sdmc: fix coding style
  2024-04-16  9:18 ` [PATCH v3 04/16] aspeed/sdmc: fix coding style Jamin Lin via
@ 2024-04-16 15:30   ` Cédric Le Goater
  0 siblings, 0 replies; 42+ messages in thread
From: Cédric Le Goater @ 2024-04-16 15:30 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	Alistair Francis, Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: troy_lee, yunlin.tang

On 4/16/24 11:18, Jamin Lin wrote:
> Fix coding style issues from checkpatch.pl
> 
> Test command:
> scripts/checkpatch.pl --no-tree -f hw/misc/aspeed_sdmc.c
> 
> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>


Reviewed-by: Cédric Le Goater <clg@kaod.org>

Thanks,

C.


> ---
>   hw/misc/aspeed_sdmc.c | 11 +++++++----
>   1 file changed, 7 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c
> index 74279bbe8e..873d67c592 100644
> --- a/hw/misc/aspeed_sdmc.c
> +++ b/hw/misc/aspeed_sdmc.c
> @@ -296,7 +296,8 @@ static void aspeed_2400_sdmc_write(AspeedSDMCState *s, uint32_t reg,
>                                      uint32_t data)
>   {
>       if (reg == R_PROT) {
> -        s->regs[reg] = (data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED;
> +        s->regs[reg] =
> +            (data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED;
>           return;
>       }
>   
> @@ -354,7 +355,8 @@ static void aspeed_2500_sdmc_write(AspeedSDMCState *s, uint32_t reg,
>                                      uint32_t data)
>   {
>       if (reg == R_PROT) {
> -        s->regs[reg] = (data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED;
> +        s->regs[reg] =
> +            (data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED;
>           return;
>       }
>   
> @@ -434,8 +436,9 @@ static void aspeed_2600_sdmc_write(AspeedSDMCState *s, uint32_t reg,
>       }
>   
>       if (s->regs[R_PROT] == PROT_HARDLOCKED) {
> -        qemu_log_mask(LOG_GUEST_ERROR, "%s: SDMC is locked until system reset!\n",
> -                __func__);
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: SDMC is locked until system reset!\n",
> +                      __func__);
>           return;
>       }
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 05/16] aspeed/sdmc: Add AST2700 support
  2024-04-16  9:18 ` [PATCH v3 05/16] aspeed/sdmc: Add AST2700 support Jamin Lin via
@ 2024-04-16 15:34   ` Cédric Le Goater
  0 siblings, 0 replies; 42+ messages in thread
From: Cédric Le Goater @ 2024-04-16 15:34 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	Alistair Francis, Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: troy_lee, yunlin.tang

On 4/16/24 11:18, Jamin Lin wrote:
> The SDRAM memory controller(DRAMC) controls the access to external
> DDR4 and DDR5 SDRAM and power up to DDR4 and DDR5 PHY.
> 
> The DRAM memory controller of AST2700 is not backward compatible
> to previous chips such AST2600, AST2500 and AST2400.
> 
> Max memory is now 8GiB on the AST2700. Introduce new
> aspeed_2700_sdmc and class with read/write operation and
> reset handlers.
> 
> Define DRAMC necessary protected registers and
> unprotected registers for AST2700 and increase
> the register set to 0x1000.
> 
> Add unlocked property to change controller protected status.
> 
> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>


Reviewed-by: Cédric Le Goater <clg@kaod.org>

Thanks,

C.


> ---
>   hw/misc/aspeed_sdmc.c         | 190 +++++++++++++++++++++++++++++++++-
>   include/hw/misc/aspeed_sdmc.h |   5 +-
>   2 files changed, 193 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c
> index 873d67c592..69a34903db 100644
> --- a/hw/misc/aspeed_sdmc.c
> +++ b/hw/misc/aspeed_sdmc.c
> @@ -27,6 +27,7 @@
>   #define   PROT_SOFTLOCKED    0x00
>   
>   #define   PROT_KEY_UNLOCK     0xFC600309
> +#define   PROT_2700_KEY_UNLOCK  0x1688A8A8
>   #define   PROT_KEY_HARDLOCK   0xDEADDEAD /* AST2600 */
>   
>   /* Configuration Register */
> @@ -54,6 +55,46 @@
>   #define R_DRAM_TIME       (0x8c / 4)
>   #define R_ECC_ERR_INJECT  (0xb4 / 4)
>   
> +/* AST2700 Register */
> +#define R_2700_PROT                 (0x00 / 4)
> +#define R_INT_STATUS                (0x04 / 4)
> +#define R_INT_CLEAR                 (0x08 / 4)
> +#define R_INT_MASK                  (0x0c / 4)
> +#define R_MAIN_CONF                 (0x10 / 4)
> +#define R_MAIN_CONTROL              (0x14 / 4)
> +#define R_MAIN_STATUS               (0x18 / 4)
> +#define R_ERR_STATUS                (0x1c / 4)
> +#define R_ECC_FAIL_STATUS           (0x78 / 4)
> +#define R_ECC_FAIL_ADDR             (0x7c / 4)
> +#define R_ECC_TESTING_CONTROL       (0x80 / 4)
> +#define R_PROT_REGION_LOCK_STATUS   (0x94 / 4)
> +#define R_TEST_FAIL_ADDR            (0xd4 / 4)
> +#define R_TEST_FAIL_D0              (0xd8 / 4)
> +#define R_TEST_FAIL_D1              (0xdc / 4)
> +#define R_TEST_FAIL_D2              (0xe0 / 4)
> +#define R_TEST_FAIL_D3              (0xe4 / 4)
> +#define R_DBG_STATUS                (0xf4 / 4)
> +#define R_PHY_INTERFACE_STATUS      (0xf8 / 4)
> +#define R_GRAPHIC_MEM_BASE_ADDR     (0x10c / 4)
> +#define R_PORT0_INTERFACE_MONITOR0  (0x240 / 4)
> +#define R_PORT0_INTERFACE_MONITOR1  (0x244 / 4)
> +#define R_PORT0_INTERFACE_MONITOR2  (0x248 / 4)
> +#define R_PORT1_INTERFACE_MONITOR0  (0x2c0 / 4)
> +#define R_PORT1_INTERFACE_MONITOR1  (0x2c4 / 4)
> +#define R_PORT1_INTERFACE_MONITOR2  (0x2c8 / 4)
> +#define R_PORT2_INTERFACE_MONITOR0  (0x340 / 4)
> +#define R_PORT2_INTERFACE_MONITOR1  (0x344 / 4)
> +#define R_PORT2_INTERFACE_MONITOR2  (0x348 / 4)
> +#define R_PORT3_INTERFACE_MONITOR0  (0x3c0 / 4)
> +#define R_PORT3_INTERFACE_MONITOR1  (0x3c4 / 4)
> +#define R_PORT3_INTERFACE_MONITOR2  (0x3c8 / 4)
> +#define R_PORT4_INTERFACE_MONITOR0  (0x440 / 4)
> +#define R_PORT4_INTERFACE_MONITOR1  (0x444 / 4)
> +#define R_PORT4_INTERFACE_MONITOR2  (0x448 / 4)
> +#define R_PORT5_INTERFACE_MONITOR0  (0x4c0 / 4)
> +#define R_PORT5_INTERFACE_MONITOR1  (0x4c4 / 4)
> +#define R_PORT5_INTERFACE_MONITOR2  (0x4c8 / 4)
> +
>   /*
>    * Configuration register Ox4 (for Aspeed AST2400 SOC)
>    *
> @@ -101,6 +142,19 @@
>        ASPEED_SDMC_AST2500_RESERVED | ASPEED_SDMC_VGA_COMPAT |            \
>        ASPEED_SDMC_VGA_APERTURE(ASPEED_SDMC_VGA_64MB))
>   
> +/*
> + * Main Configuration register Ox10 (for Aspeed AST2700 SOC and higher)
> + *
> + */
> +#define ASPEED_SDMC_AST2700_RESERVED        0xFFFF2082 /* 31:16, 13, 7, 1 */
> +#define ASPEED_SDMC_AST2700_DATA_SCRAMBLE           (1 << 8)
> +#define ASPEED_SDMC_AST2700_ECC_ENABLE              (1 << 6)
> +#define ASPEED_SDMC_AST2700_PAGE_MATCHING_ENABLE    (1 << 5)
> +#define ASPEED_SDMC_AST2700_DRAM_SIZE(x)            ((x & 0x7) << 2)
> +
> +#define ASPEED_SDMC_AST2700_READONLY_MASK   \
> +     (ASPEED_SDMC_AST2700_RESERVED)
> +
>   static uint64_t aspeed_sdmc_read(void *opaque, hwaddr addr, unsigned size)
>   {
>       AspeedSDMCState *s = ASPEED_SDMC(opaque);
> @@ -216,7 +270,7 @@ static void aspeed_sdmc_realize(DeviceState *dev, Error **errp)
>       AspeedSDMCState *s = ASPEED_SDMC(dev);
>       AspeedSDMCClass *asc = ASPEED_SDMC_GET_CLASS(s);
>   
> -    assert(asc->max_ram_size < 4 * GiB); /* 32-bit address bus */
> +    assert(asc->max_ram_size < 4 * GiB || asc->is_bus64bit);
>       s->max_ram_size = asc->max_ram_size;
>   
>       memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sdmc_ops, s,
> @@ -236,6 +290,7 @@ static const VMStateDescription vmstate_aspeed_sdmc = {
>   
>   static Property aspeed_sdmc_properties[] = {
>       DEFINE_PROP_UINT64("max-ram-size", AspeedSDMCState, max_ram_size, 0),
> +    DEFINE_PROP_BOOL("unlocked", AspeedSDMCState, unlocked, false),
>       DEFINE_PROP_END_OF_LIST(),
>   };
>   
> @@ -500,12 +555,145 @@ static const TypeInfo aspeed_2600_sdmc_info = {
>       .class_init = aspeed_2600_sdmc_class_init,
>   };
>   
> +static void aspeed_2700_sdmc_reset(DeviceState *dev)
> +{
> +    AspeedSDMCState *s = ASPEED_SDMC(dev);
> +    AspeedSDMCClass *asc = ASPEED_SDMC_GET_CLASS(s);
> +
> +    memset(s->regs, 0, sizeof(s->regs));
> +
> +    /* Set ram size bit and defaults values */
> +    s->regs[R_MAIN_CONF] = asc->compute_conf(s, 0);
> +
> +    if (s->unlocked) {
> +        s->regs[R_2700_PROT] = PROT_UNLOCKED;
> +    }
> +}
> +
> +static uint32_t aspeed_2700_sdmc_compute_conf(AspeedSDMCState *s, uint32_t data)
> +{
> +    uint32_t fixed_conf = ASPEED_SDMC_AST2700_PAGE_MATCHING_ENABLE |
> +        ASPEED_SDMC_AST2700_DRAM_SIZE(aspeed_sdmc_get_ram_bits(s));
> +
> +    /* Make sure readonly bits are kept */
> +    data &= ~ASPEED_SDMC_AST2700_READONLY_MASK;
> +
> +    return data | fixed_conf;
> +}
> +
> +static void aspeed_2700_sdmc_write(AspeedSDMCState *s, uint32_t reg,
> +                                   uint32_t data)
> +{
> +    /* Unprotected registers */
> +    switch (reg) {
> +    case R_INT_STATUS:
> +    case R_INT_CLEAR:
> +    case R_INT_MASK:
> +    case R_MAIN_STATUS:
> +    case R_ERR_STATUS:
> +    case R_ECC_FAIL_STATUS:
> +    case R_ECC_FAIL_ADDR:
> +    case R_PROT_REGION_LOCK_STATUS:
> +    case R_TEST_FAIL_ADDR:
> +    case R_TEST_FAIL_D0:
> +    case R_TEST_FAIL_D1:
> +    case R_TEST_FAIL_D2:
> +    case R_TEST_FAIL_D3:
> +    case R_DBG_STATUS:
> +    case R_PHY_INTERFACE_STATUS:
> +    case R_GRAPHIC_MEM_BASE_ADDR:
> +    case R_PORT0_INTERFACE_MONITOR0:
> +    case R_PORT0_INTERFACE_MONITOR1:
> +    case R_PORT0_INTERFACE_MONITOR2:
> +    case R_PORT1_INTERFACE_MONITOR0:
> +    case R_PORT1_INTERFACE_MONITOR1:
> +    case R_PORT1_INTERFACE_MONITOR2:
> +    case R_PORT2_INTERFACE_MONITOR0:
> +    case R_PORT2_INTERFACE_MONITOR1:
> +    case R_PORT2_INTERFACE_MONITOR2:
> +    case R_PORT3_INTERFACE_MONITOR0:
> +    case R_PORT3_INTERFACE_MONITOR1:
> +    case R_PORT3_INTERFACE_MONITOR2:
> +    case R_PORT4_INTERFACE_MONITOR0:
> +    case R_PORT4_INTERFACE_MONITOR1:
> +    case R_PORT4_INTERFACE_MONITOR2:
> +    case R_PORT5_INTERFACE_MONITOR0:
> +    case R_PORT5_INTERFACE_MONITOR1:
> +    case R_PORT5_INTERFACE_MONITOR2:
> +        s->regs[reg] = data;
> +        return;
> +    }
> +
> +    if (s->regs[R_2700_PROT] == PROT_HARDLOCKED) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: SDMC is locked until system reset!\n",
> +                      __func__);
> +        return;
> +    }
> +
> +    if (reg != R_2700_PROT && s->regs[R_2700_PROT] == PROT_SOFTLOCKED) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: SDMC is locked! (write to MCR%02x blocked)\n",
> +                      __func__, reg * 4);
> +        return;
> +    }
> +
> +    switch (reg) {
> +    case R_2700_PROT:
> +        if (data == PROT_2700_KEY_UNLOCK)  {
> +            data = PROT_UNLOCKED;
> +        } else if (data == PROT_KEY_HARDLOCK) {
> +            data = PROT_HARDLOCKED;
> +        } else {
> +            data = PROT_SOFTLOCKED;
> +        }
> +        break;
> +    case R_MAIN_CONF:
> +        data = aspeed_2700_sdmc_compute_conf(s, data);
> +        break;
> +    case R_MAIN_STATUS:
> +        /* Will never return 'busy'. */
> +        data &= ~PHY_BUSY_STATE;
> +        break;
> +    default:
> +        break;
> +    }
> +
> +    s->regs[reg] = data;
> +}
> +
> +static const uint64_t
> +    aspeed_2700_ram_sizes[] = { 256 * MiB, 512 * MiB, 1024 * MiB,
> +                                2048 * MiB, 4096 * MiB, 8192 * MiB, 0};
> +
> +static void aspeed_2700_sdmc_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass);
> +
> +    dc->desc = "ASPEED 2700 SDRAM Memory Controller";
> +    dc->reset = aspeed_2700_sdmc_reset;
> +
> +    asc->is_bus64bit = true;
> +    asc->max_ram_size = 8 * GiB;
> +    asc->compute_conf = aspeed_2700_sdmc_compute_conf;
> +    asc->write = aspeed_2700_sdmc_write;
> +    asc->valid_ram_sizes = aspeed_2700_ram_sizes;
> +}
> +
> +static const TypeInfo aspeed_2700_sdmc_info = {
> +    .name = TYPE_ASPEED_2700_SDMC,
> +    .parent = TYPE_ASPEED_SDMC,
> +    .class_init = aspeed_2700_sdmc_class_init,
> +};
> +
>   static void aspeed_sdmc_register_types(void)
>   {
>       type_register_static(&aspeed_sdmc_info);
>       type_register_static(&aspeed_2400_sdmc_info);
>       type_register_static(&aspeed_2500_sdmc_info);
>       type_register_static(&aspeed_2600_sdmc_info);
> +    type_register_static(&aspeed_2700_sdmc_info);
>   }
>   
>   type_init(aspeed_sdmc_register_types);
> diff --git a/include/hw/misc/aspeed_sdmc.h b/include/hw/misc/aspeed_sdmc.h
> index ec2d59a14f..61c979583a 100644
> --- a/include/hw/misc/aspeed_sdmc.h
> +++ b/include/hw/misc/aspeed_sdmc.h
> @@ -17,6 +17,7 @@ OBJECT_DECLARE_TYPE(AspeedSDMCState, AspeedSDMCClass, ASPEED_SDMC)
>   #define TYPE_ASPEED_2400_SDMC TYPE_ASPEED_SDMC "-ast2400"
>   #define TYPE_ASPEED_2500_SDMC TYPE_ASPEED_SDMC "-ast2500"
>   #define TYPE_ASPEED_2600_SDMC TYPE_ASPEED_SDMC "-ast2600"
> +#define TYPE_ASPEED_2700_SDMC TYPE_ASPEED_SDMC "-ast2700"
>   
>   /*
>    * SDMC has 174 documented registers. In addition the u-boot device tree
> @@ -29,7 +30,7 @@ OBJECT_DECLARE_TYPE(AspeedSDMCState, AspeedSDMCClass, ASPEED_SDMC)
>    * time, and the other is in the DDR-PHY IP which is used during DDR-PHY
>    * training.
>    */
> -#define ASPEED_SDMC_NR_REGS (0x500 >> 2)
> +#define ASPEED_SDMC_NR_REGS (0x1000 >> 2)
>   
>   struct AspeedSDMCState {
>       /*< private >*/
> @@ -41,6 +42,7 @@ struct AspeedSDMCState {
>       uint32_t regs[ASPEED_SDMC_NR_REGS];
>       uint64_t ram_size;
>       uint64_t max_ram_size;
> +    bool unlocked;
>   };
>   
>   
> @@ -51,6 +53,7 @@ struct AspeedSDMCClass {
>       const uint64_t *valid_ram_sizes;
>       uint32_t (*compute_conf)(AspeedSDMCState *s, uint32_t data);
>       void (*write)(AspeedSDMCState *s, uint32_t reg, uint32_t data);
> +    bool is_bus64bit;
>   };
>   
>   #endif /* ASPEED_SDMC_H */



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 06/16] aspeed/smc: correct device description
  2024-04-16  9:18 ` [PATCH v3 06/16] aspeed/smc: correct device description Jamin Lin via
@ 2024-04-16 15:34   ` Cédric Le Goater
  0 siblings, 0 replies; 42+ messages in thread
From: Cédric Le Goater @ 2024-04-16 15:34 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	Alistair Francis, Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: troy_lee, yunlin.tang

On 4/16/24 11:18, Jamin Lin wrote:
> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>


Reviewed-by: Cédric Le Goater <clg@kaod.org>

Thanks,

C.


> ---
>   hw/ssi/aspeed_smc.c | 6 +++---
>   1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
> index 6e1a84c197..8a8d77b480 100644
> --- a/hw/ssi/aspeed_smc.c
> +++ b/hw/ssi/aspeed_smc.c
> @@ -1448,7 +1448,7 @@ static void aspeed_2500_fmc_class_init(ObjectClass *klass, void *data)
>       DeviceClass *dc = DEVICE_CLASS(klass);
>       AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
>   
> -    dc->desc               = "Aspeed 2600 FMC Controller";
> +    dc->desc               = "Aspeed 2500 FMC Controller";
>       asc->r_conf            = R_CONF;
>       asc->r_ce_ctrl         = R_CE_CTRL;
>       asc->r_ctrl0           = R_CTRL0;
> @@ -1486,7 +1486,7 @@ static void aspeed_2500_spi1_class_init(ObjectClass *klass, void *data)
>       DeviceClass *dc = DEVICE_CLASS(klass);
>       AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
>   
> -    dc->desc               = "Aspeed 2600 SPI1 Controller";
> +    dc->desc               = "Aspeed 2500 SPI1 Controller";
>       asc->r_conf            = R_CONF;
>       asc->r_ce_ctrl         = R_CE_CTRL;
>       asc->r_ctrl0           = R_CTRL0;
> @@ -1521,7 +1521,7 @@ static void aspeed_2500_spi2_class_init(ObjectClass *klass, void *data)
>       DeviceClass *dc = DEVICE_CLASS(klass);
>       AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
>   
> -    dc->desc               = "Aspeed 2600 SPI2 Controller";
> +    dc->desc               = "Aspeed 2500 SPI2 Controller";
>       asc->r_conf            = R_CONF;
>       asc->r_ce_ctrl         = R_CE_CTRL;
>       asc->r_ctrl0           = R_CTRL0;



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 16/16] docs:aspeed: Add AST2700 Evaluation board
  2024-04-16  9:19 ` [PATCH v3 16/16] docs:aspeed: Add AST2700 Evaluation board Jamin Lin via
@ 2024-04-16 15:54   ` Cédric Le Goater
  0 siblings, 0 replies; 42+ messages in thread
From: Cédric Le Goater @ 2024-04-16 15:54 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	Alistair Francis, Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: troy_lee, yunlin.tang

On 4/16/24 11:19, Jamin Lin wrote:
> Add AST2700 Evaluation board and its boot command.
> 
> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>


Reviewed-by: Cédric Le Goater <clg@kaod.org>

Thanks,

C.


> ---
>   docs/system/arm/aspeed.rst | 39 ++++++++++++++++++++++++++++++++++----
>   1 file changed, 35 insertions(+), 4 deletions(-)
> 
> diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst
> index b2dea54eed..320ff2a4cd 100644
> --- a/docs/system/arm/aspeed.rst
> +++ b/docs/system/arm/aspeed.rst
> @@ -1,11 +1,12 @@
> -Aspeed family boards (``*-bmc``, ``ast2500-evb``, ``ast2600-evb``)
> -==================================================================
> +Aspeed family boards (``*-bmc``, ``ast2500-evb``, ``ast2600-evb``, ``ast2700-evb``)
> +===================================================================================
>   
>   The QEMU Aspeed machines model BMCs of various OpenPOWER systems and
>   Aspeed evaluation boards. They are based on different releases of the
>   Aspeed SoC : the AST2400 integrating an ARM926EJ-S CPU (400MHz), the
> -AST2500 with an ARM1176JZS CPU (800MHz) and more recently the AST2600
> -with dual cores ARM Cortex-A7 CPUs (1.2GHz).
> +AST2500 with an ARM1176JZS CPU (800MHz), the AST2600
> +with dual cores ARM Cortex-A7 CPUs (1.2GHz) and more recently the AST2700
> +with quad cores ARM Cortex-A35 64 bits CPUs (1.6GHz)
>   
>   The SoC comes with RAM, Gigabit ethernet, USB, SD/MMC, USB, SPI, I2C,
>   etc.
> @@ -38,6 +39,10 @@ AST2600 SoC based machines :
>   - ``qcom-dc-scm-v1-bmc``   Qualcomm DC-SCM V1 BMC
>   - ``qcom-firework-bmc``    Qualcomm Firework BMC
>   
> +AST2700 SoC based machines :
> +
> +- ``ast2700-evb``          Aspeed AST2700 Evaluation board (Cortex-A35)
> +
>   Supported devices
>   -----------------
>   
> @@ -66,6 +71,7 @@ Supported devices
>    * eMMC Boot Controller (dummy)
>    * PECI Controller (minimal)
>    * I3C Controller
> + * Internal Bridge Controller (SLI dummy)
>   
>   
>   Missing devices
> @@ -95,6 +101,10 @@ or directly from the OpenBMC GitHub release repository :
>   
>      https://github.com/openbmc/openbmc/releases
>   
> +or directly from the ASPEED Forked OpenBMC GitHub release repository :
> +
> +   https://github.com/AspeedTech-BMC/openbmc/releases
> +
>   To boot a kernel directly from a Linux build tree:
>   
>   .. code-block:: bash
> @@ -164,6 +174,27 @@ under Linux), use :
>   
>     -M ast2500-evb,bmc-console=uart3
>   
> +
> +Boot the AST2700 machine from the flash image, use an MTD drive :
> +
> +.. code-block:: bash
> +
> +  IMGDIR=ast2700-default
> +  UBOOT_SIZE=$(stat --format=%s -L ${IMGDIR}/u-boot-nodtb.bin)
> +
> +  $ qemu-system-aarch64 -M ast2700-evb \
> +       -device loader,force-raw=on,addr=0x400000000,file=${IMGDIR}/u-boot-nodtb.bin \
> +       -device loader,force-raw=on,addr=$((0x400000000 + ${UBOOT_SIZE})),file=u-boot.dtb \
> +       -device loader,force-raw=on,addr=0x430000000,file=${IMGDIR}/bl31.bin \
> +       -device loader,force-raw=on,addr=0x430080000,file=${IMGDIR}/optee/tee-raw.bin \
> +       -device loader,cpu-num=0,addr=0x430000000 \
> +       -device loader,cpu-num=1,addr=0x430000000 \
> +       -device loader,cpu-num=2,addr=0x430000000 \
> +       -device loader,cpu-num=3,addr=0x430000000 \
> +       -smp 4 \
> +       -drive file=${IMGDIR}/image-bmc,format=raw,if=mtd \
> +       -nographic
> +
>   Aspeed minibmc family boards (``ast1030-evb``)
>   ==================================================================
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 15/16] test/avocado/machine_aspeed.py: Add AST2700 test case
  2024-04-16  9:19 ` [PATCH v3 15/16] test/avocado/machine_aspeed.py: Add AST2700 test case Jamin Lin via
@ 2024-04-16 16:44   ` Cédric Le Goater
  0 siblings, 0 replies; 42+ messages in thread
From: Cédric Le Goater @ 2024-04-16 16:44 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	Alistair Francis, Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: troy_lee, yunlin.tang

On 4/16/24 11:19, Jamin Lin wrote:
> Add a test case to test Aspeed OpenBMC SDK v09.01 on AST2700 board.
> 
> It loads u-boot-nodtb.bin, u-boot.dtb, tfa and optee-os
> images to dram first which base address is 0x400000000.
> Then, boot and launch 4 cpu cores.
> 
> ```
> qemu-system-aarch64 -machine ast2700-evb
>      -device loader,force-raw=on,addr=0x400000000,file=workdir/u-boot-nodtb.bin \
>      -device loader,force-raw=on,addr=uboot_dtb_load_addr,file=u-boot.dtb\
>      -device loader,force-raw=on,addr=0x430000000,file=workdir/bl31.bin\
>      -device loader,force-raw=on,addr=0x430080000,file=workdir/optee/tee-raw.bin\
>      -device loader,cpu-num=0,addr=0x430000000 \
>      -device loader,cpu-num=1,addr=0x430000000 \
>      -device loader,cpu-num=2,addr=0x430000000 \
>      -device loader,cpu-num=3,addr=0x430000000 \
>      -smp 4 \
>      -drive file=workdir/image-bmc,format=raw,if=mtd
> ```
> 
> A test image is downloaded from the ASPEED Forked OpenBMC GitHub release repository :
> https://github.com/AspeedTech-BMC/openbmc/releases/
> 
> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>


Reviewed-by: Cédric Le Goater <clg@kaod.org>

Thanks,

C.


> ---
>   tests/avocado/machine_aspeed.py | 62 +++++++++++++++++++++++++++++++++
>   1 file changed, 62 insertions(+)
> 
> diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
> index cec0181424..3a20644fb2 100644
> --- a/tests/avocado/machine_aspeed.py
> +++ b/tests/avocado/machine_aspeed.py
> @@ -311,6 +311,17 @@ def do_test_arm_aspeed_sdk_start(self, image):
>               self, 'boot', '## Loading kernel from FIT Image')
>           self.wait_for_console_pattern('Starting kernel ...')
>   
> +    def do_test_aarch64_aspeed_sdk_start(self, image):
> +        self.vm.set_console()
> +        self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw')
> +
> +        self.vm.launch()
> +
> +        self.wait_for_console_pattern('U-Boot 2023.10')
> +        self.wait_for_console_pattern('## Loading kernel from FIT Image')
> +        self.wait_for_console_pattern('Starting kernel ...')
> +        self.wait_for_console_pattern("systemd[1]: Hostname set to")
> +
>       @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
>   
>       def test_arm_ast2500_evb_sdk(self):
> @@ -375,3 +386,54 @@ def test_arm_ast2600_evb_sdk(self):
>                'i2c i2c-5: new_device: Instantiated device ds1307 at 0x32');
>           year = time.strftime("%Y")
>           self.ssh_command_output_contains('/sbin/hwclock -f /dev/rtc1', year);
> +
> +    def test_aarch64_ast2700_evb_sdk_v09_01(self):
> +        """
> +        :avocado: tags=arch:aarch64
> +        :avocado: tags=machine:ast2700-evb
> +        """
> +
> +        image_url = ('https://github.com/AspeedTech-BMC/openbmc/releases/'
> +                     'download/v09.01/ast2700-default-obmc.tar.gz')
> +        image_hash = 'b1cc0fd73c7650d34c9c8459a243f52a91e9e27144b8608b2645ab19461d1e07'
> +        image_path = self.fetch_asset(image_url, asset_hash=image_hash,
> +                                      algorithm='sha256')
> +        archive.extract(image_path, self.workdir)
> +
> +        num_cpu = 4
> +        image_dir = self.workdir + '/ast2700-default/'
> +        uboot_size = os.path.getsize(image_dir + 'u-boot-nodtb.bin')
> +        uboot_dtb_load_addr = hex(0x400000000 + uboot_size)
> +
> +        load_images_list = [
> +            {
> +                'addr': '0x400000000',
> +                'file': image_dir + 'u-boot-nodtb.bin'
> +            },
> +            {
> +                'addr': str(uboot_dtb_load_addr),
> +                'file': image_dir + 'u-boot.dtb'
> +            },
> +            {
> +                'addr': '0x430000000',
> +                'file': image_dir + 'bl31.bin'
> +            },
> +            {
> +                'addr': '0x430080000',
> +                'file': image_dir + 'optee/tee-raw.bin'
> +            }
> +        ]
> +
> +        for load_image in load_images_list:
> +            addr = load_image['addr']
> +            file = load_image['file']
> +            self.vm.add_args('-device',
> +                             f'loader,force-raw=on,addr={addr},file={file}')
> +
> +        for i in range(num_cpu):
> +            self.vm.add_args('-device',
> +                             f'loader,addr=0x430000000,cpu-num={i}')
> +
> +        self.vm.add_args('-smp', str(num_cpu))
> +        self.do_test_aarch64_aspeed_sdk_start(image_dir + 'image-bmc')
> +



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 08/16] aspeed/smc: support 64 bits dma dram address
  2024-04-16  9:18 ` [PATCH v3 08/16] aspeed/smc: support 64 bits dma dram address Jamin Lin via
@ 2024-04-18 16:09   ` Cédric Le Goater
  2024-04-19  6:00     ` Jamin Lin
  2024-05-07 14:19   ` Cédric Le Goater
  1 sibling, 1 reply; 42+ messages in thread
From: Cédric Le Goater @ 2024-04-18 16:09 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	Alistair Francis, Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: troy_lee, yunlin.tang

Hello Jamin,

On 4/16/24 11:18, Jamin Lin wrote:
> AST2700 support the maximum dram size is 8GiB
> and has a "DMA DRAM Side Address High Part(0x7C)"
> register to support 64 bits dma dram address.
> Add helper routines functions to compute the dma dram
> address, new features and update trace-event
> to support 64 bits dram address.
> 
> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
>   hw/ssi/aspeed_smc.c | 66 +++++++++++++++++++++++++++++++++++++++------
>   hw/ssi/trace-events |  2 +-
>   2 files changed, 59 insertions(+), 9 deletions(-)
> 
> diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
> index 71abc7a2d8..a67cac3d0f 100644
> --- a/hw/ssi/aspeed_smc.c
> +++ b/hw/ssi/aspeed_smc.c
> @@ -132,6 +132,9 @@
>   #define   FMC_WDT2_CTRL_BOOT_SOURCE      BIT(4) /* O: primary 1: alternate */
>   #define   FMC_WDT2_CTRL_EN               BIT(0)
>   
> +/* DMA DRAM Side Address High Part (AST2700) */
> +#define R_DMA_DRAM_ADDR_HIGH   (0x7c / 4)
> +
>   /* DMA Control/Status Register */
>   #define R_DMA_CTRL        (0x80 / 4)
>   #define   DMA_CTRL_REQUEST      (1 << 31)
> @@ -187,6 +190,7 @@
>    *   0x1FFFFFF: 32M bytes
>    */
>   #define DMA_DRAM_ADDR(asc, val)   ((val) & (asc)->dma_dram_mask)
> +#define DMA_DRAM_ADDR_HIGH(val)   ((val) & 0xf)
>   #define DMA_FLASH_ADDR(asc, val)  ((val) & (asc)->dma_flash_mask)
>   #define DMA_LENGTH(val)         ((val) & 0x01FFFFFF)
>   
> @@ -207,6 +211,7 @@ static const AspeedSegments aspeed_2500_spi2_segments[];
>   #define ASPEED_SMC_FEATURE_DMA       0x1
>   #define ASPEED_SMC_FEATURE_DMA_GRANT 0x2
>   #define ASPEED_SMC_FEATURE_WDT_CONTROL 0x4
> +#define ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH 0x08
>   
>   static inline bool aspeed_smc_has_dma(const AspeedSMCClass *asc)
>   {
> @@ -218,6 +223,11 @@ static inline bool aspeed_smc_has_wdt_control(const AspeedSMCClass *asc)
>       return !!(asc->features & ASPEED_SMC_FEATURE_WDT_CONTROL);
>   }
>   
> +static inline bool aspeed_smc_has_dma_dram_addr_high(const AspeedSMCClass *asc)

To ease the reading, I would call the helper aspeed_smc_has_dma64()

> +{
> +    return !!(asc->features & ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH);
> +}
> +
>   #define aspeed_smc_error(fmt, ...)                                      \
>       qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt "\n", __func__, ## __VA_ARGS__)
>   
> @@ -747,6 +757,9 @@ static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size)
>           (aspeed_smc_has_dma(asc) && addr == R_DMA_CTRL) ||
>           (aspeed_smc_has_dma(asc) && addr == R_DMA_FLASH_ADDR) ||
>           (aspeed_smc_has_dma(asc) && addr == R_DMA_DRAM_ADDR) ||
> +        (aspeed_smc_has_dma(asc) &&
> +         aspeed_smc_has_dma_dram_addr_high(asc) &&
> +         addr == R_DMA_DRAM_ADDR_HIGH) ||
>           (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN) ||
>           (aspeed_smc_has_dma(asc) && addr == R_DMA_CHECKSUM) ||
>           (addr >= R_SEG_ADDR0 &&
> @@ -847,6 +860,23 @@ static bool aspeed_smc_inject_read_failure(AspeedSMCState *s)
>       }
>   }
>   
> +static uint64_t aspeed_smc_dma_dram_addr(AspeedSMCState *s)
> +{
> +    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
> +    uint64_t dram_addr_high;
> +    uint64_t dma_dram_addr;
> +
> +    if (aspeed_smc_has_dma_dram_addr_high(asc)) {
> +        dram_addr_high = s->regs[R_DMA_DRAM_ADDR_HIGH];
> +        dram_addr_high <<= 32;
> +        dma_dram_addr = dram_addr_high | s->regs[R_DMA_DRAM_ADDR];

Here is a proposal to shorten the routine :

         return ((uint64_t) s->regs[R_DMA_DRAM_ADDR_HIGH] << 32) |
             s->regs[R_DMA_DRAM_ADDR];


> +    } else {
> +        dma_dram_addr = s->regs[R_DMA_DRAM_ADDR];

and
         return s->regs[R_DMA_DRAM_ADDR];
	
> +    }
> +
> +    return dma_dram_addr;
> +}
> +
>   static uint32_t aspeed_smc_dma_len(AspeedSMCState *s)
>   {
>       AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
> @@ -914,24 +944,34 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
>   
>   static void aspeed_smc_dma_rw(AspeedSMCState *s)
>   {
> +    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
> +    uint64_t dram_addr_high;

This variable doesn't look very useful
  
> +    uint64_t dma_dram_addr;
> +    uint64_t dram_addr;

and dram_addr is redundant with dma_dram_addr. Please use only one.


>       MemTxResult result;
>       uint32_t dma_len;
>       uint32_t data;
>   
>       dma_len = aspeed_smc_dma_len(s);
> +    dma_dram_addr = aspeed_smc_dma_dram_addr(s);
> +
> +    if (aspeed_smc_has_dma_dram_addr_high(asc)) {
> +        dram_addr = dma_dram_addr - s->dram_mr->container->addr;

Why do you truncate the address again ? It should already be done with

#define DMA_DRAM_ADDR_HIGH(val)   ((val) & 0xf)

> +    } else {
> +        dram_addr = dma_dram_addr;
> +    }
>   
>       trace_aspeed_smc_dma_rw(s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE ?
>                               "write" : "read",
>                               s->regs[R_DMA_FLASH_ADDR],
> -                            s->regs[R_DMA_DRAM_ADDR],
> +                            dram_addr,
>                               dma_len);
>       while (dma_len) {
>           if (s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE) {
> -            data = address_space_ldl_le(&s->dram_as, s->regs[R_DMA_DRAM_ADDR],
> +            data = address_space_ldl_le(&s->dram_as, dram_addr,
>                                           MEMTXATTRS_UNSPECIFIED, &result);
>               if (result != MEMTX_OK) {
> -                aspeed_smc_error("DRAM read failed @%08x",
> -                                 s->regs[R_DMA_DRAM_ADDR]);
> +                aspeed_smc_error("DRAM read failed @%" PRIx64, dram_addr);
>                   return;
>               }
>   
> @@ -951,11 +991,10 @@ static void aspeed_smc_dma_rw(AspeedSMCState *s)
>                   return;
>               }
>   
> -            address_space_stl_le(&s->dram_as, s->regs[R_DMA_DRAM_ADDR],
> +            address_space_stl_le(&s->dram_as, dram_addr,
>                                    data, MEMTXATTRS_UNSPECIFIED, &result);
>               if (result != MEMTX_OK) {
> -                aspeed_smc_error("DRAM write failed @%08x",
> -                                 s->regs[R_DMA_DRAM_ADDR]);
> +                aspeed_smc_error("DRAM write failed @%" PRIx64, dram_addr);
>                   return;
>               }
>           }
> @@ -964,8 +1003,15 @@ static void aspeed_smc_dma_rw(AspeedSMCState *s)
>            * When the DMA is on-going, the DMA registers are updated
>            * with the current working addresses and length.
>            */
> +        dram_addr += 4;
> +        dma_dram_addr += 4;
> +        if (aspeed_smc_has_dma_dram_addr_high(asc)) {
> +            dram_addr_high = dma_dram_addr >> 32;
> +            s->regs[R_DMA_DRAM_ADDR_HIGH] = dram_addr_high;

             s->regs[R_DMA_DRAM_ADDR_HIGH] = dma_dram_addr >> 32;

> +        }
> +
> +        s->regs[R_DMA_DRAM_ADDR] = dma_dram_addr & 0xffffffff;

use DMA_DRAM_ADDR() may be instead.

>           s->regs[R_DMA_FLASH_ADDR] += 4;
> -        s->regs[R_DMA_DRAM_ADDR] += 4;
>           dma_len -= 4;
>           s->regs[R_DMA_LEN] = dma_len;
>           s->regs[R_DMA_CHECKSUM] += data;
> @@ -1118,6 +1164,10 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data,
>       } else if (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN &&
>                  aspeed_smc_dma_granted(s)) {
>           s->regs[addr] = DMA_LENGTH(value);
> +    } else if (aspeed_smc_has_dma(asc) &&
> +               aspeed_smc_has_dma_dram_addr_high(asc) &&
> +               addr == R_DMA_DRAM_ADDR_HIGH) {
> +        s->regs[addr] = DMA_DRAM_ADDR_HIGH(value);
>       } else {
>           qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n",
>                         __func__, addr);
> diff --git a/hw/ssi/trace-events b/hw/ssi/trace-events
> index 2d5bd2b83d..7b5ad6a939 100644
> --- a/hw/ssi/trace-events
> +++ b/hw/ssi/trace-events
> @@ -6,7 +6,7 @@ aspeed_smc_do_snoop(int cs, int index, int dummies, int data) "CS%d index:0x%x d
>   aspeed_smc_flash_write(int cs, uint64_t addr,  uint32_t size, uint64_t data, int mode) "CS%d @0x%" PRIx64 " size %u: 0x%" PRIx64" mode:%d"
>   aspeed_smc_read(uint64_t addr,  uint32_t size, uint64_t data) "@0x%" PRIx64 " size %u: 0x%" PRIx64
>   aspeed_smc_dma_checksum(uint32_t addr, uint32_t data) "0x%08x: 0x%08x"
> -aspeed_smc_dma_rw(const char *dir, uint32_t flash_addr, uint32_t dram_addr, uint32_t size) "%s flash:@0x%08x dram:@0x%08x size:0x%08x"
> +aspeed_smc_dma_rw(const char *dir, uint32_t flash_addr, uint64_t dram_addr, uint32_t size) "%s flash:@0x%08x dram:@0x%" PRIx64 " size:0x%08x"
>   aspeed_smc_write(uint64_t addr,  uint32_t size, uint64_t data) "@0x%" PRIx64 " size %u: 0x%" PRIx64
>   aspeed_smc_flash_select(int cs, const char *prefix) "CS%d %sselect"
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 09/16] aspeed/smc: Add AST2700 support
  2024-04-16  9:18 ` [PATCH v3 09/16] aspeed/smc: Add AST2700 support Jamin Lin via
@ 2024-04-18 16:14   ` Cédric Le Goater
  0 siblings, 0 replies; 42+ messages in thread
From: Cédric Le Goater @ 2024-04-18 16:14 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	Alistair Francis, Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: troy_lee, yunlin.tang

On 4/16/24 11:18, Jamin Lin wrote:
> AST2700 fmc/spi controller's address decoding unit is 64KB
> and only bits [31:16] are used for decoding. Introduce seg_to_reg
> and reg_to_seg handlers for ast2700 fmc/spi controller.
> In addition, adds ast2700 fmc, spi0, spi1, and spi2 class init handler.
> 
> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>


Reviewed-by: Cédric Le Goater <clg@kaod.org>

Thanks,

C.


> ---
>   hw/ssi/aspeed_smc.c | 222 +++++++++++++++++++++++++++++++++++++++++++-
>   1 file changed, 220 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
> index a67cac3d0f..e768e5463c 100644
> --- a/hw/ssi/aspeed_smc.c
> +++ b/hw/ssi/aspeed_smc.c
> @@ -185,7 +185,7 @@
>    *   0: 4 bytes
>    *   0x7FFFFF: 32M bytes
>    *
> - * DMA length is from 1 byte to 32MB (AST2600, AST10x0)
> + * DMA length is from 1 byte to 32MB (AST2600, AST10x0 and AST2700)
>    *   0: 1 byte
>    *   0x1FFFFFF: 32M bytes
>    */
> @@ -670,7 +670,7 @@ static const MemoryRegionOps aspeed_smc_flash_ops = {
>       .endianness = DEVICE_LITTLE_ENDIAN,
>       .valid = {
>           .min_access_size = 1,
> -        .max_access_size = 4,
> +        .max_access_size = 8,
>       },
>   };
>   
> @@ -1951,6 +1951,220 @@ static const TypeInfo aspeed_1030_spi2_info = {
>       .class_init = aspeed_1030_spi2_class_init,
>   };
>   
> +/*
> + * The FMC Segment Registers of the AST2700 have a 64KB unit.
> + * Only bits [31:16] are used for decoding.
> + */
> +#define AST2700_SEG_ADDR_MASK 0xffff0000
> +
> +static uint32_t aspeed_2700_smc_segment_to_reg(const AspeedSMCState *s,
> +                                               const AspeedSegments *seg)
> +{
> +    uint32_t reg = 0;
> +
> +    /* Disabled segments have a nil register */
> +    if (!seg->size) {
> +        return 0;
> +    }
> +
> +    reg |= (seg->addr & AST2700_SEG_ADDR_MASK) >> 16; /* start offset */
> +    reg |= (seg->addr + seg->size - 1) & AST2700_SEG_ADDR_MASK; /* end offset */
> +    return reg;
> +}
> +
> +static void aspeed_2700_smc_reg_to_segment(const AspeedSMCState *s,
> +                                           uint32_t reg, AspeedSegments *seg)
> +{
> +    uint32_t start_offset = (reg << 16) & AST2700_SEG_ADDR_MASK;
> +    uint32_t end_offset = reg & AST2700_SEG_ADDR_MASK;
> +    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
> +
> +    if (reg) {
> +        seg->addr = asc->flash_window_base + start_offset;
> +        seg->size = end_offset + (64 * KiB) - start_offset;
> +    } else {
> +        seg->addr = asc->flash_window_base;
> +        seg->size = 0;
> +    }
> +}
> +
> +static const uint32_t aspeed_2700_fmc_resets[ASPEED_SMC_R_MAX] = {
> +    [R_CONF] = (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0 |
> +            CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE1),
> +    [R_CE_CTRL] = 0x0000aa00,
> +    [R_CTRL0] = 0x406b0641,
> +    [R_CTRL1] = 0x00000400,
> +    [R_CTRL2] = 0x00000400,
> +    [R_CTRL3] = 0x00000400,
> +    [R_SEG_ADDR0] = 0x08000000,
> +    [R_SEG_ADDR1] = 0x10000800,
> +    [R_SEG_ADDR2] = 0x00000000,
> +    [R_SEG_ADDR3] = 0x00000000,
> +    [R_DUMMY_DATA] = 0x00010000,
> +    [R_DMA_DRAM_ADDR_HIGH] = 0x00000000,
> +    [R_TIMINGS] = 0x007b0000,
> +};
> +
> +static const AspeedSegments aspeed_2700_fmc_segments[] = {
> +    { 0x0, 128 * MiB }, /* start address is readonly */
> +    { 128 * MiB, 128 * MiB }, /* default is disabled but needed for -kernel */
> +    { 256 * MiB, 128 * MiB }, /* default is disabled but needed for -kernel */
> +    { 0x0, 0 }, /* disabled */
> +};
> +
> +static void aspeed_2700_fmc_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
> +
> +    dc->desc               = "Aspeed 2700 FMC Controller";
> +    asc->r_conf            = R_CONF;
> +    asc->r_ce_ctrl         = R_CE_CTRL;
> +    asc->r_ctrl0           = R_CTRL0;
> +    asc->r_timings         = R_TIMINGS;
> +    asc->nregs_timings     = 3;
> +    asc->conf_enable_w0    = CONF_ENABLE_W0;
> +    asc->cs_num_max        = 3;
> +    asc->segments          = aspeed_2700_fmc_segments;
> +    asc->segment_addr_mask = 0xffffffff;
> +    asc->resets            = aspeed_2700_fmc_resets;
> +    asc->flash_window_base = 0x100000000;
> +    asc->flash_window_size = 1 * GiB;
> +    asc->features          = ASPEED_SMC_FEATURE_DMA |
> +                             ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH;
> +    asc->dma_flash_mask    = 0x2FFFFFFC;
> +    asc->dma_dram_mask     = 0xFFFFFFFC;
> +    asc->dma_start_length  = 1;
> +    asc->nregs             = ASPEED_SMC_R_MAX;
> +    asc->segment_to_reg    = aspeed_2700_smc_segment_to_reg;
> +    asc->reg_to_segment    = aspeed_2700_smc_reg_to_segment;
> +    asc->dma_ctrl          = aspeed_2600_smc_dma_ctrl;
> +}
> +
> +static const TypeInfo aspeed_2700_fmc_info = {
> +    .name =  "aspeed.fmc-ast2700",
> +    .parent = TYPE_ASPEED_SMC,
> +    .class_init = aspeed_2700_fmc_class_init,
> +};
> +
> +static const AspeedSegments aspeed_2700_spi0_segments[] = {
> +    { 0x0, 128 * MiB }, /* start address is readonly */
> +    { 128 * MiB, 128 * MiB }, /* start address is readonly */
> +    { 0x0, 0 }, /* disabled */
> +};
> +
> +static void aspeed_2700_spi0_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
> +
> +    dc->desc               = "Aspeed 2700 SPI0 Controller";
> +    asc->r_conf            = R_CONF;
> +    asc->r_ce_ctrl         = R_CE_CTRL;
> +    asc->r_ctrl0           = R_CTRL0;
> +    asc->r_timings         = R_TIMINGS;
> +    asc->nregs_timings     = 2;
> +    asc->conf_enable_w0    = CONF_ENABLE_W0;
> +    asc->cs_num_max        = 2;
> +    asc->segments          = aspeed_2700_spi0_segments;
> +    asc->segment_addr_mask = 0xffffffff;
> +    asc->flash_window_base = 0x180000000;
> +    asc->flash_window_size = 1 * GiB;
> +    asc->features          = ASPEED_SMC_FEATURE_DMA |
> +                             ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH;
> +    asc->dma_flash_mask    = 0x2FFFFFFC;
> +    asc->dma_dram_mask     = 0xFFFFFFFC;
> +    asc->dma_start_length  = 1;
> +    asc->nregs             = ASPEED_SMC_R_MAX;
> +    asc->segment_to_reg    = aspeed_2700_smc_segment_to_reg;
> +    asc->reg_to_segment    = aspeed_2700_smc_reg_to_segment;
> +    asc->dma_ctrl          = aspeed_2600_smc_dma_ctrl;
> +}
> +
> +static const TypeInfo aspeed_2700_spi0_info = {
> +    .name =  "aspeed.spi0-ast2700",
> +    .parent = TYPE_ASPEED_SMC,
> +    .class_init = aspeed_2700_spi0_class_init,
> +};
> +
> +static const AspeedSegments aspeed_2700_spi1_segments[] = {
> +    { 0x0, 128 * MiB }, /* start address is readonly */
> +    { 0x0, 0 }, /* disabled */
> +};
> +
> +static void aspeed_2700_spi1_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
> +
> +    dc->desc               = "Aspeed 2700 SPI1 Controller";
> +    asc->r_conf            = R_CONF;
> +    asc->r_ce_ctrl         = R_CE_CTRL;
> +    asc->r_ctrl0           = R_CTRL0;
> +    asc->r_timings         = R_TIMINGS;
> +    asc->nregs_timings     = 2;
> +    asc->conf_enable_w0    = CONF_ENABLE_W0;
> +    asc->cs_num_max        = 2;
> +    asc->segments          = aspeed_2700_spi1_segments;
> +    asc->segment_addr_mask = 0xffffffff;
> +    asc->flash_window_base = 0x200000000;
> +    asc->flash_window_size = 1 * GiB;
> +    asc->features          = ASPEED_SMC_FEATURE_DMA |
> +                             ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH;
> +    asc->dma_flash_mask    = 0x2FFFFFFC;
> +    asc->dma_dram_mask     = 0xFFFFFFFC;
> +    asc->dma_start_length  = 1;
> +    asc->nregs             = ASPEED_SMC_R_MAX;
> +    asc->segment_to_reg    = aspeed_2700_smc_segment_to_reg;
> +    asc->reg_to_segment    = aspeed_2700_smc_reg_to_segment;
> +    asc->dma_ctrl          = aspeed_2600_smc_dma_ctrl;
> +}
> +
> +static const TypeInfo aspeed_2700_spi1_info = {
> +        .name =  "aspeed.spi1-ast2700",
> +        .parent = TYPE_ASPEED_SMC,
> +        .class_init = aspeed_2700_spi1_class_init,
> +};
> +
> +static const AspeedSegments aspeed_2700_spi2_segments[] = {
> +    { 0x0, 128 * MiB }, /* start address is readonly */
> +    { 0x0, 0 }, /* disabled */
> +};
> +
> +static void aspeed_2700_spi2_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
> +
> +    dc->desc               = "Aspeed 2700 SPI2 Controller";
> +    asc->r_conf            = R_CONF;
> +    asc->r_ce_ctrl         = R_CE_CTRL;
> +    asc->r_ctrl0           = R_CTRL0;
> +    asc->r_timings         = R_TIMINGS;
> +    asc->nregs_timings     = 2;
> +    asc->conf_enable_w0    = CONF_ENABLE_W0;
> +    asc->cs_num_max        = 2;
> +    asc->segments          = aspeed_2700_spi2_segments;
> +    asc->segment_addr_mask = 0xffffffff;
> +    asc->flash_window_base = 0x280000000;
> +    asc->flash_window_size = 1 * GiB;
> +    asc->features          = ASPEED_SMC_FEATURE_DMA |
> +                             ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH;
> +    asc->dma_flash_mask    = 0x0FFFFFFC;
> +    asc->dma_dram_mask     = 0xFFFFFFFC;
> +    asc->dma_start_length  = 1;
> +    asc->nregs             = ASPEED_SMC_R_MAX;
> +    asc->segment_to_reg    = aspeed_2700_smc_segment_to_reg;
> +    asc->reg_to_segment    = aspeed_2700_smc_reg_to_segment;
> +    asc->dma_ctrl          = aspeed_2600_smc_dma_ctrl;
> +}
> +
> +static const TypeInfo aspeed_2700_spi2_info = {
> +        .name =  "aspeed.spi2-ast2700",
> +        .parent = TYPE_ASPEED_SMC,
> +        .class_init = aspeed_2700_spi2_class_init,
> +};
> +
>   static void aspeed_smc_register_types(void)
>   {
>       type_register_static(&aspeed_smc_flash_info);
> @@ -1967,6 +2181,10 @@ static void aspeed_smc_register_types(void)
>       type_register_static(&aspeed_1030_fmc_info);
>       type_register_static(&aspeed_1030_spi1_info);
>       type_register_static(&aspeed_1030_spi2_info);
> +    type_register_static(&aspeed_2700_fmc_info);
> +    type_register_static(&aspeed_2700_spi0_info);
> +    type_register_static(&aspeed_2700_spi1_info);
> +    type_register_static(&aspeed_2700_spi2_info);
>   }
>   
>   type_init(aspeed_smc_register_types)



^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH v3 08/16] aspeed/smc: support 64 bits dma dram address
  2024-04-18 16:09   ` Cédric Le Goater
@ 2024-04-19  6:00     ` Jamin Lin
  2024-04-30  7:26       ` Cédric Le Goater
  0 siblings, 1 reply; 42+ messages in thread
From: Jamin Lin @ 2024-04-19  6:00 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: Troy Lee, Yunlin Tang

Hi Cedric,
> 
> Hello Jamin,
> 
> On 4/16/24 11:18, Jamin Lin wrote:
> > AST2700 support the maximum dram size is 8GiB and has a "DMA DRAM
> Side
> > Address High Part(0x7C)"
> > register to support 64 bits dma dram address.
> > Add helper routines functions to compute the dma dram address, new
> > features and update trace-event to support 64 bits dram address.
> >
> > Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> > Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> > ---
> >   hw/ssi/aspeed_smc.c | 66
> +++++++++++++++++++++++++++++++++++++++------
> >   hw/ssi/trace-events |  2 +-
> >   2 files changed, 59 insertions(+), 9 deletions(-)
> >
> > diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index
> > 71abc7a2d8..a67cac3d0f 100644
> > --- a/hw/ssi/aspeed_smc.c
> > +++ b/hw/ssi/aspeed_smc.c
> > @@ -132,6 +132,9 @@
> >   #define   FMC_WDT2_CTRL_BOOT_SOURCE      BIT(4) /* O: primary
> 1: alternate */
> >   #define   FMC_WDT2_CTRL_EN               BIT(0)
> >
> > +/* DMA DRAM Side Address High Part (AST2700) */
> > +#define R_DMA_DRAM_ADDR_HIGH   (0x7c / 4)
> > +
> >   /* DMA Control/Status Register */
> >   #define R_DMA_CTRL        (0x80 / 4)
> >   #define   DMA_CTRL_REQUEST      (1 << 31)
> > @@ -187,6 +190,7 @@
> >    *   0x1FFFFFF: 32M bytes
> >    */
> >   #define DMA_DRAM_ADDR(asc, val)   ((val) & (asc)->dma_dram_mask)
> > +#define DMA_DRAM_ADDR_HIGH(val)   ((val) & 0xf)
> >   #define DMA_FLASH_ADDR(asc, val)  ((val) & (asc)->dma_flash_mask)
> >   #define DMA_LENGTH(val)         ((val) & 0x01FFFFFF)
> >
> > @@ -207,6 +211,7 @@ static const AspeedSegments
> aspeed_2500_spi2_segments[];
> >   #define ASPEED_SMC_FEATURE_DMA       0x1
> >   #define ASPEED_SMC_FEATURE_DMA_GRANT 0x2
> >   #define ASPEED_SMC_FEATURE_WDT_CONTROL 0x4
> > +#define ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH 0x08
> >
> >   static inline bool aspeed_smc_has_dma(const AspeedSMCClass *asc)
> >   {
> > @@ -218,6 +223,11 @@ static inline bool
> aspeed_smc_has_wdt_control(const AspeedSMCClass *asc)
> >       return !!(asc->features & ASPEED_SMC_FEATURE_WDT_CONTROL);
> >   }
> >
> > +static inline bool aspeed_smc_has_dma_dram_addr_high(const
> > +AspeedSMCClass *asc)
> 
> To ease the reading, I would call the helper aspeed_smc_has_dma64()
Will fix it
> 
> > +{
> > +    return !!(asc->features &
> ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH);
> > +}
> > +
> >   #define aspeed_smc_error(fmt, ...)
> \
> >       qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt "\n", __func__, ##
> > __VA_ARGS__)
> >
> > @@ -747,6 +757,9 @@ static uint64_t aspeed_smc_read(void *opaque,
> hwaddr addr, unsigned int size)
> >           (aspeed_smc_has_dma(asc) && addr == R_DMA_CTRL) ||
> >           (aspeed_smc_has_dma(asc) && addr == R_DMA_FLASH_ADDR)
> ||
> >           (aspeed_smc_has_dma(asc) && addr == R_DMA_DRAM_ADDR)
> ||
> > +        (aspeed_smc_has_dma(asc) &&
> > +         aspeed_smc_has_dma_dram_addr_high(asc) &&
> > +         addr == R_DMA_DRAM_ADDR_HIGH) ||
> >           (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN) ||
> >           (aspeed_smc_has_dma(asc) && addr == R_DMA_CHECKSUM)
> ||
> >           (addr >= R_SEG_ADDR0 &&
> > @@ -847,6 +860,23 @@ static bool
> aspeed_smc_inject_read_failure(AspeedSMCState *s)
> >       }
> >   }
> >
> > +static uint64_t aspeed_smc_dma_dram_addr(AspeedSMCState *s) {
> > +    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
> > +    uint64_t dram_addr_high;
> > +    uint64_t dma_dram_addr;
> > +
> > +    if (aspeed_smc_has_dma_dram_addr_high(asc)) {
> > +        dram_addr_high = s->regs[R_DMA_DRAM_ADDR_HIGH];
> > +        dram_addr_high <<= 32;
> > +        dma_dram_addr = dram_addr_high |
> s->regs[R_DMA_DRAM_ADDR];
> 
> Here is a proposal to shorten the routine :
> 
>          return ((uint64_t) s->regs[R_DMA_DRAM_ADDR_HIGH] << 32) |
>              s->regs[R_DMA_DRAM_ADDR];
> 
> 
> > +    } else {
> > +        dma_dram_addr = s->regs[R_DMA_DRAM_ADDR];
> 
> and
>          return s->regs[R_DMA_DRAM_ADDR];
> 
> > +    }
> > +
> > +    return dma_dram_addr;
> > +}
> > +
Thanks for your suggestion. Will fix.
> >   static uint32_t aspeed_smc_dma_len(AspeedSMCState *s)
> >   {
> >       AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); @@ -914,24
> > +944,34 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
> >
> >   static void aspeed_smc_dma_rw(AspeedSMCState *s)
> >   {
> > +    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
> > +    uint64_t dram_addr_high;
> 
> This variable doesn't look very useful
Will try to remove it.
> 
> > +    uint64_t dma_dram_addr;
> > +    uint64_t dram_addr;
> 
> and dram_addr is redundant with dma_dram_addr. Please use only one.
Please see my below description and please give us any suggestion.
> 
> 
> >       MemTxResult result;
> >       uint32_t dma_len;
> >       uint32_t data;
> >
> >       dma_len = aspeed_smc_dma_len(s);
> > +    dma_dram_addr = aspeed_smc_dma_dram_addr(s);
> > +
> > +    if (aspeed_smc_has_dma_dram_addr_high(asc)) {
> > +        dram_addr = dma_dram_addr - s->dram_mr->container->addr;
> 
> Why do you truncate the address again ? It should already be done with
> 
> #define DMA_DRAM_ADDR_HIGH(val)   ((val) & 0xf)
> 
The reason is that our firmware set the real address in SMC registers.
For example: If users want to move data from flash to the DRAM at address 0,
It set R_DMA_DRAM_ADDR_HIGH 4 and R_DMA_DRAM_ADDR 0 because the
dram base address is 0x 4 00000000 for AST2700.

According to the design of QEMU, the dram container base address is 0x4 00000000(s->dram_mr).
Therefore, in the above example, the data should be moved to the dram container at address 0.

I created two variables to save the different base address.
A dma_dram_addr is used to save the real address.
A dram_addr is used to save the address for dram container(s->dram_as)

Example:
dma_dram_addr is 0x4 00000000  
(uint64) s->regs[R_DMA_DRAM_ADDR_HIGH] << 32) |s->regs[R_DMA_DRAM_ADDR]
dram_addr is 0
dram_addr = 0x400000000(real address) - 0x400000000(dram container base address) to get the address for dram contained for moving
dram_addr = dma_dram_addr - s->dram_mr->container->addr;

Finally, the following APIs could work properly.
data = address_space_ldl_le(&s->dram_as, dram_addr,
                       MEMTXATTRS_UNSPECIFIED, &result);
Thanks-Jamin
> > +    } else {
> > +        dram_addr = dma_dram_addr;
> > +    }
> >
> >       trace_aspeed_smc_dma_rw(s->regs[R_DMA_CTRL] &
> DMA_CTRL_WRITE ?
> >                               "write" : "read",
> >                               s->regs[R_DMA_FLASH_ADDR],
> > -                            s->regs[R_DMA_DRAM_ADDR],
> > +                            dram_addr,
> >                               dma_len);
> >       while (dma_len) {
> >           if (s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE) {
> > -            data = address_space_ldl_le(&s->dram_as,
> s->regs[R_DMA_DRAM_ADDR],
> > +            data = address_space_ldl_le(&s->dram_as, dram_addr,
> >
> MEMTXATTRS_UNSPECIFIED, &result);
> >               if (result != MEMTX_OK) {
> > -                aspeed_smc_error("DRAM read failed @%08x",
> > -                                 s->regs[R_DMA_DRAM_ADDR]);
> > +                aspeed_smc_error("DRAM read failed @%" PRIx64,
> > + dram_addr);
> >                   return;
> >               }
> >
> > @@ -951,11 +991,10 @@ static void aspeed_smc_dma_rw(AspeedSMCState
> *s)
> >                   return;
> >               }
> >
> > -            address_space_stl_le(&s->dram_as,
> s->regs[R_DMA_DRAM_ADDR],
> > +            address_space_stl_le(&s->dram_as, dram_addr,
> >                                    data,
> MEMTXATTRS_UNSPECIFIED, &result);
> >               if (result != MEMTX_OK) {
> > -                aspeed_smc_error("DRAM write failed @%08x",
> > -                                 s->regs[R_DMA_DRAM_ADDR]);
> > +                aspeed_smc_error("DRAM write failed @%" PRIx64,
> > + dram_addr);
> >                   return;
> >               }
> >           }
> > @@ -964,8 +1003,15 @@ static void aspeed_smc_dma_rw(AspeedSMCState
> *s)
> >            * When the DMA is on-going, the DMA registers are updated
> >            * with the current working addresses and length.
> >            */
> > +        dram_addr += 4;
> > +        dma_dram_addr += 4;
> > +        if (aspeed_smc_has_dma_dram_addr_high(asc)) {
> > +            dram_addr_high = dma_dram_addr >> 32;
> > +            s->regs[R_DMA_DRAM_ADDR_HIGH] = dram_addr_high;
> 
>              s->regs[R_DMA_DRAM_ADDR_HIGH] = dma_dram_addr >>
> 32;
> 
> > +        }
> > +
> > +        s->regs[R_DMA_DRAM_ADDR] = dma_dram_addr & 0xffffffff;
> 
> use DMA_DRAM_ADDR() may be instead.
> 
> >           s->regs[R_DMA_FLASH_ADDR] += 4;
> > -        s->regs[R_DMA_DRAM_ADDR] += 4;
> >           dma_len -= 4;
> >           s->regs[R_DMA_LEN] = dma_len;
> >           s->regs[R_DMA_CHECKSUM] += data; @@ -1118,6 +1164,10
> @@
> > static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data,
> >       } else if (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN &&
> >                  aspeed_smc_dma_granted(s)) {
> >           s->regs[addr] = DMA_LENGTH(value);
> > +    } else if (aspeed_smc_has_dma(asc) &&
> > +               aspeed_smc_has_dma_dram_addr_high(asc) &&
> > +               addr == R_DMA_DRAM_ADDR_HIGH) {
> > +        s->regs[addr] = DMA_DRAM_ADDR_HIGH(value);
> >       } else {
> >           qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%"
> HWADDR_PRIx "\n",
> >                         __func__, addr); diff --git
> > a/hw/ssi/trace-events b/hw/ssi/trace-events index
> > 2d5bd2b83d..7b5ad6a939 100644
> > --- a/hw/ssi/trace-events
> > +++ b/hw/ssi/trace-events
> > @@ -6,7 +6,7 @@ aspeed_smc_do_snoop(int cs, int index, int dummies, int
> data) "CS%d index:0x%x d
> >   aspeed_smc_flash_write(int cs, uint64_t addr,  uint32_t size, uint64_t
> data, int mode) "CS%d @0x%" PRIx64 " size %u: 0x%" PRIx64" mode:%d"
> >   aspeed_smc_read(uint64_t addr,  uint32_t size, uint64_t data) "@0x%"
> PRIx64 " size %u: 0x%" PRIx64
> >   aspeed_smc_dma_checksum(uint32_t addr, uint32_t data) "0x%08x:
> 0x%08x"
> > -aspeed_smc_dma_rw(const char *dir, uint32_t flash_addr, uint32_t
> dram_addr, uint32_t size) "%s flash:@0x%08x dram:@0x%08x size:0x%08x"
> > +aspeed_smc_dma_rw(const char *dir, uint32_t flash_addr, uint64_t
> dram_addr, uint32_t size) "%s flash:@0x%08x dram:@0x%" PRIx64 "
> size:0x%08x"
> >   aspeed_smc_write(uint64_t addr,  uint32_t size, uint64_t data) "@0x%"
> PRIx64 " size %u: 0x%" PRIx64
> >   aspeed_smc_flash_select(int cs, const char *prefix) "CS%d %sselect"
> >


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 12/16] aspeed/soc: Add AST2700 support
  2024-04-16  9:18 ` [PATCH v3 12/16] aspeed/soc: " Jamin Lin via
@ 2024-04-19  7:10   ` Cédric Le Goater
  2024-04-19  7:58     ` Jamin Lin
  2024-05-07 13:06   ` Cédric Le Goater
  1 sibling, 1 reply; 42+ messages in thread
From: Cédric Le Goater @ 2024-04-19  7:10 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	Alistair Francis, Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: troy_lee, yunlin.tang

On 4/16/24 11:18, Jamin Lin wrote:
> Initial definitions for a simple machine using an AST2700 SOC (Cortex-a35 CPU).
> 
> AST2700 SOC and its interrupt controller are too complex to handle
> in the common Aspeed SoC framework. We introduce a new ast2700
> class with instance_init and realize handlers.
> 
> AST2700 is a 64 bits quad core cpus and support 8 watchdog.
> Update maximum ASPEED_CPUS_NUM to 4 and ASPEED_WDTS_NUM to 8.
> In addition, update AspeedSocState to support scuio, sli, sliio and intc.
> 
> Add TYPE_ASPEED27X0_SOC machine type.
> 
> The SDMC controller is unlocked at SPL stage.
> At present, only supports to emulate booting
> start from u-boot stage. Set SDMC controller
> unlocked by default.
> 
> In INTC, each interrupt of INT 128 to INT 136 combines 32 interrupts.
> It connect GICINT IRQ GPIO-OUTPUT pins to GIC device with irq 128 to 136.
> And, if a device irq is 128 to 136, its irq GPIO-OUTPUT pin is connected to
> GICINT or-gates instead of GIC device.
> 
> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>

Before I forget, please see a little comment below regarding user creatable
devices.

The model looks fine. The interrupt controller part is more complex than
the previous SoCs so I will come back to it later when I have more time.

> ---
>   hw/arm/aspeed_ast27x0.c     | 554 ++++++++++++++++++++++++++++++++++++
>   hw/arm/meson.build          |   1 +
>   include/hw/arm/aspeed_soc.h |  26 +-
>   3 files changed, 579 insertions(+), 2 deletions(-)
>   create mode 100644 hw/arm/aspeed_ast27x0.c
> 
> diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
> new file mode 100644
> index 0000000000..754c963230
> --- /dev/null
> +++ b/hw/arm/aspeed_ast27x0.c
> @@ -0,0 +1,554 @@
> +/*
> + * ASPEED SoC 27x0 family
> + *
> + * Copyright (C) 2024 ASPEED Technology Inc.
> + *
> + * This code is licensed under the GPL version 2 or later.  See
> + * the COPYING file in the top-level directory.
> + *
> + * Implementation extracted from the AST2600 and adapted for AST27x0.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "hw/misc/unimp.h"
> +#include "hw/arm/aspeed_soc.h"
> +#include "qemu/module.h"
> +#include "qemu/error-report.h"
> +#include "hw/i2c/aspeed_i2c.h"
> +#include "net/net.h"
> +#include "sysemu/sysemu.h"
> +#include "hw/intc/arm_gicv3.h"
> +#include "qapi/qmp/qlist.h"
> +
> +static const hwaddr aspeed_soc_ast2700_memmap[] = {
> +    [ASPEED_DEV_SPI_BOOT]  =  0x400000000,
> +    [ASPEED_DEV_SRAM]      =  0x10000000,
> +    [ASPEED_DEV_SDMC]      =  0x12C00000,
> +    [ASPEED_DEV_SCU]       =  0x12C02000,
> +    [ASPEED_DEV_SCUIO]     =  0x14C02000,
> +    [ASPEED_DEV_UART0]     =  0X14C33000,
> +    [ASPEED_DEV_UART1]     =  0X14C33100,
> +    [ASPEED_DEV_UART2]     =  0X14C33200,
> +    [ASPEED_DEV_UART3]     =  0X14C33300,
> +    [ASPEED_DEV_UART4]     =  0X12C1A000,
> +    [ASPEED_DEV_UART5]     =  0X14C33400,
> +    [ASPEED_DEV_UART6]     =  0X14C33500,
> +    [ASPEED_DEV_UART7]     =  0X14C33600,
> +    [ASPEED_DEV_UART8]     =  0X14C33700,
> +    [ASPEED_DEV_UART9]     =  0X14C33800,
> +    [ASPEED_DEV_UART10]    =  0X14C33900,
> +    [ASPEED_DEV_UART11]    =  0X14C33A00,
> +    [ASPEED_DEV_UART12]    =  0X14C33B00,
> +    [ASPEED_DEV_WDT]       =  0x14C37000,
> +    [ASPEED_DEV_VUART]     =  0X14C30000,
> +    [ASPEED_DEV_FMC]       =  0x14000000,
> +    [ASPEED_DEV_SPI0]      =  0x14010000,
> +    [ASPEED_DEV_SPI1]      =  0x14020000,
> +    [ASPEED_DEV_SPI2]      =  0x14030000,
> +    [ASPEED_DEV_SDRAM]     =  0x400000000,
> +    [ASPEED_DEV_MII1]      =  0x14040000,
> +    [ASPEED_DEV_MII2]      =  0x14040008,
> +    [ASPEED_DEV_MII3]      =  0x14040010,
> +    [ASPEED_DEV_ETH1]      =  0x14050000,
> +    [ASPEED_DEV_ETH2]      =  0x14060000,
> +    [ASPEED_DEV_ETH3]      =  0x14070000,
> +    [ASPEED_DEV_EMMC]      =  0x12090000,
> +    [ASPEED_DEV_INTC]      =  0x12100000,
> +    [ASPEED_DEV_SLI]       =  0x12C17000,
> +    [ASPEED_DEV_SLIIO]     =  0x14C1E000,
> +    [ASPEED_GIC_DIST]      =  0x12200000,
> +    [ASPEED_GIC_REDIST]    =  0x12280000,
> +};
> +
> +#define AST2700_MAX_IRQ 288
> +
> +/* Shared Peripheral Interrupt values below are offset by -32 from datasheet */
> +static const int aspeed_soc_ast2700_irqmap[] = {
> +    [ASPEED_DEV_UART0]     = 132,
> +    [ASPEED_DEV_UART1]     = 132,
> +    [ASPEED_DEV_UART2]     = 132,
> +    [ASPEED_DEV_UART3]     = 132,
> +    [ASPEED_DEV_UART4]     = 8,
> +    [ASPEED_DEV_UART5]     = 132,
> +    [ASPEED_DEV_UART6]     = 132,
> +    [ASPEED_DEV_UART7]     = 132,
> +    [ASPEED_DEV_UART8]     = 132,
> +    [ASPEED_DEV_UART9]     = 132,
> +    [ASPEED_DEV_UART10]    = 132,
> +    [ASPEED_DEV_UART11]    = 132,
> +    [ASPEED_DEV_UART12]    = 132,
> +    [ASPEED_DEV_FMC]       = 131,
> +    [ASPEED_DEV_SDMC]      = 0,
> +    [ASPEED_DEV_SCU]       = 12,
> +    [ASPEED_DEV_ADC]       = 130,
> +    [ASPEED_DEV_XDMA]      = 5,
> +    [ASPEED_DEV_EMMC]      = 15,
> +    [ASPEED_DEV_GPIO]      = 11,
> +    [ASPEED_DEV_GPIO_1_8V] = 130,
> +    [ASPEED_DEV_RTC]       = 13,
> +    [ASPEED_DEV_TIMER1]    = 16,
> +    [ASPEED_DEV_TIMER2]    = 17,
> +    [ASPEED_DEV_TIMER3]    = 18,
> +    [ASPEED_DEV_TIMER4]    = 19,
> +    [ASPEED_DEV_TIMER5]    = 20,
> +    [ASPEED_DEV_TIMER6]    = 21,
> +    [ASPEED_DEV_TIMER7]    = 22,
> +    [ASPEED_DEV_TIMER8]    = 23,
> +    [ASPEED_DEV_WDT]       = 131,
> +    [ASPEED_DEV_PWM]       = 131,
> +    [ASPEED_DEV_LPC]       = 128,
> +    [ASPEED_DEV_IBT]       = 128,
> +    [ASPEED_DEV_I2C]       = 130,
> +    [ASPEED_DEV_PECI]      = 133,
> +    [ASPEED_DEV_ETH1]      = 132,
> +    [ASPEED_DEV_ETH2]      = 132,
> +    [ASPEED_DEV_ETH3]      = 132,
> +    [ASPEED_DEV_HACE]      = 4,
> +    [ASPEED_DEV_KCS]       = 128,
> +    [ASPEED_DEV_DP]        = 28,
> +    [ASPEED_DEV_I3C]       = 131,
> +};
> +
> +/* GICINT 128 */
> +static const int aspeed_soc_ast2700_gic128_intcmap[] = {
> +    [ASPEED_DEV_LPC]       = 0,
> +    [ASPEED_DEV_IBT]       = 2,
> +    [ASPEED_DEV_KCS]       = 4,
> +};
> +
> +/* GICINT 130 */
> +static const int aspeed_soc_ast2700_gic130_intcmap[] = {
> +    [ASPEED_DEV_I2C]        = 0,
> +    [ASPEED_DEV_ADC]        = 16,
> +    [ASPEED_DEV_GPIO_1_8V]  = 18,
> +};
> +
> +/* GICINT 131 */
> +static const int aspeed_soc_ast2700_gic131_intcmap[] = {
> +    [ASPEED_DEV_I3C]       = 0,
> +    [ASPEED_DEV_WDT]       = 16,
> +    [ASPEED_DEV_FMC]       = 25,
> +    [ASPEED_DEV_PWM]       = 29,
> +};
> +
> +/* GICINT 132 */
> +static const int aspeed_soc_ast2700_gic132_intcmap[] = {
> +    [ASPEED_DEV_ETH1]      = 0,
> +    [ASPEED_DEV_ETH2]      = 1,
> +    [ASPEED_DEV_ETH3]      = 2,
> +    [ASPEED_DEV_UART0]     = 7,
> +    [ASPEED_DEV_UART1]     = 8,
> +    [ASPEED_DEV_UART2]     = 9,
> +    [ASPEED_DEV_UART3]     = 10,
> +    [ASPEED_DEV_UART5]     = 11,
> +    [ASPEED_DEV_UART6]     = 12,
> +    [ASPEED_DEV_UART7]     = 13,
> +    [ASPEED_DEV_UART8]     = 14,
> +    [ASPEED_DEV_UART9]     = 15,
> +    [ASPEED_DEV_UART10]    = 16,
> +    [ASPEED_DEV_UART11]    = 17,
> +    [ASPEED_DEV_UART12]    = 18,
> +};
> +
> +/* GICINT 133 */
> +static const int aspeed_soc_ast2700_gic133_intcmap[] = {
> +    [ASPEED_DEV_PECI]      = 4,
> +};
> +
> +/* GICINT 128 ~ 136 */
> +struct gic_intc_irq_info {
> +    int irq;
> +    const int *ptr;
> +};
> +
> +static const struct gic_intc_irq_info aspeed_soc_ast2700_gic_intcmap[] = {
> +    {128,  aspeed_soc_ast2700_gic128_intcmap},
> +    {129,  NULL},
> +    {130,  aspeed_soc_ast2700_gic130_intcmap},
> +    {131,  aspeed_soc_ast2700_gic131_intcmap},
> +    {132,  aspeed_soc_ast2700_gic132_intcmap},
> +    {133,  aspeed_soc_ast2700_gic133_intcmap},
> +    {134,  NULL},
> +    {135,  NULL},
> +    {136,  NULL},
> +};
> +
> +static qemu_irq aspeed_soc_ast2700_get_irq(AspeedSoCState *s, int dev)
> +{
> +    Aspeed27x0SoCState *a = ASPEED27X0_SOC(s);
> +    AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
> +    int i;
> +
> +    for (i = 0; i < ARRAY_SIZE(aspeed_soc_ast2700_gic_intcmap); i++) {
> +        if (sc->irqmap[dev] == aspeed_soc_ast2700_gic_intcmap[i].irq) {
> +            assert(aspeed_soc_ast2700_gic_intcmap[i].ptr);
> +            return qdev_get_gpio_in(DEVICE(&a->intc.gicint_orgate[i]),
> +                aspeed_soc_ast2700_gic_intcmap[i].ptr[dev]);
> +        }
> +    }
> +
> +    return qdev_get_gpio_in(a->intc.gic, sc->irqmap[dev]);
> +}
> +
> +static void aspeed_soc_ast2700_init(Object *obj)
> +{
> +    Aspeed27x0SoCState *a = ASPEED27X0_SOC(obj);
> +    AspeedSoCState *s = ASPEED_SOC(obj);
> +    AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
> +    int i;
> +    char socname[8];
> +    char typename[64];
> +
> +    if (sscanf(sc->name, "%7s", socname) != 1) {
> +        g_assert_not_reached();
> +    }
> +
> +    for (i = 0; i < sc->num_cpus; i++) {
> +        object_initialize_child(obj, "cpu[*]", &a->cpu[i],
> +                                aspeed_soc_cpu_type(sc));
> +    }
> +
> +    object_initialize_child(obj, "scu", &s->scu, TYPE_ASPEED_2700_SCU);
> +    qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev",
> +                         sc->silicon_rev);
> +    object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu),
> +                              "hw-strap1");
> +    object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu),
> +                              "hw-strap2");
> +    object_property_add_alias(obj, "hw-prot-key", OBJECT(&s->scu),
> +                              "hw-prot-key");
> +
> +    object_initialize_child(obj, "scuio", &s->scuio, TYPE_ASPEED_2700_SCUIO);
> +    qdev_prop_set_uint32(DEVICE(&s->scuio), "silicon-rev",
> +                         sc->silicon_rev);
> +
> +    snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname);
> +    object_initialize_child(obj, "fmc", &s->fmc, typename);
> +
> +    for (i = 0; i < sc->spis_num; i++) {
> +        snprintf(typename, sizeof(typename), "aspeed.spi%d-%s", i, socname);
> +        object_initialize_child(obj, "spi[*]", &s->spi[i], typename);
> +    }
> +
> +    snprintf(typename, sizeof(typename), "aspeed.sdmc-%s", socname);
> +    object_initialize_child(obj, "sdmc", &s->sdmc, typename);
> +    object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
> +                              "ram-size");
> +
> +    for (i = 0; i < sc->wdts_num; i++) {
> +        snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname);
> +        object_initialize_child(obj, "wdt[*]", &s->wdt[i], typename);
> +    }
> +
> +    for (i = 0; i < sc->macs_num; i++) {
> +        object_initialize_child(obj, "ftgmac100[*]", &s->ftgmac100[i],
> +                                TYPE_FTGMAC100);
> +
> +        object_initialize_child(obj, "mii[*]", &s->mii[i], TYPE_ASPEED_MII);
> +    }
> +
> +    for (i = 0; i < sc->uarts_num; i++) {
> +        object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_SERIAL_MM);
> +    }
> +
> +    object_initialize_child(obj, "sli", &s->sli, TYPE_ASPEED_2700_SLI);
> +    object_initialize_child(obj, "sliio", &s->sliio, TYPE_ASPEED_2700_SLIIO);
> +    object_initialize_child(obj, "intc", &a->intc, TYPE_ASPEED_INTC);
> +}
> +
> +/*
> + * ASPEED ast2700 has 0x0 as cluster ID
> + *
> + * https://developer.arm.com/documentation/100236/0100/register-descriptions/aarch64-system-registers/multiprocessor-affinity-register--el1
> + */
> +static uint64_t aspeed_calc_affinity(int cpu)
> +{
> +    return (0x0 << ARM_AFF1_SHIFT) | cpu;
> +}
> +
> +static void aspeed_soc_ast2700_gic(DeviceState *dev, Error **errp)
> +{
> +    Aspeed27x0SoCState *a = ASPEED27X0_SOC(dev);
> +    AspeedSoCState *s = ASPEED_SOC(dev);
> +    AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
> +    SysBusDevice *gicbusdev;
> +    QList *redist_region_count;
> +    int i;
> +
> +    a->intc.gic = qdev_new(gicv3_class_name());
> +    qdev_prop_set_uint32(a->intc.gic, "revision", 3);
> +    qdev_prop_set_uint32(a->intc.gic, "num-cpu", sc->num_cpus);
> +    qdev_prop_set_uint32(a->intc.gic, "num-irq", AST2700_MAX_IRQ);
> +
> +    redist_region_count = qlist_new();
> +    qlist_append_int(redist_region_count, sc->num_cpus);
> +    qdev_prop_set_array(a->intc.gic, "redist-region-count",
> +                            redist_region_count);
> +
> +    gicbusdev = SYS_BUS_DEVICE(a->intc.gic);
> +    sysbus_realize_and_unref(gicbusdev, errp);
> +    sysbus_mmio_map(gicbusdev, 0, sc->memmap[ASPEED_GIC_DIST]);
> +    sysbus_mmio_map(gicbusdev, 1, sc->memmap[ASPEED_GIC_REDIST]);
> +
> +    for (i = 0; i < sc->num_cpus; i++) {
> +        DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
> +        int NUM_IRQS = 256, ARCH_GIC_MAINT_IRQ = 9, VIRTUAL_PMU_IRQ = 7;
> +        int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
> +
> +        const int timer_irq[] = {
> +            [GTIMER_PHYS] = 14,
> +            [GTIMER_VIRT] = 11,
> +            [GTIMER_HYP]  = 10,
> +            [GTIMER_SEC]  = 13,
> +        };
> +        int j;
> +
> +        for (j = 0; j < ARRAY_SIZE(timer_irq); j++) {
> +            qdev_connect_gpio_out(cpudev, j,
> +                    qdev_get_gpio_in(a->intc.gic, ppibase + timer_irq[j]));
> +        }
> +
> +        qemu_irq irq = qdev_get_gpio_in(a->intc.gic,
> +                                        ppibase + ARCH_GIC_MAINT_IRQ);
> +        qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
> +                                    0, irq);
> +        qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
> +                qdev_get_gpio_in(a->intc.gic, ppibase + VIRTUAL_PMU_IRQ));
> +
> +        sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
> +        sysbus_connect_irq(gicbusdev, i + sc->num_cpus,
> +                           qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
> +        sysbus_connect_irq(gicbusdev, i + 2 * sc->num_cpus,
> +                           qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
> +        sysbus_connect_irq(gicbusdev, i + 3 * sc->num_cpus,
> +                           qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
> +    }
> +}
> +
> +static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
> +{
> +    int i;
> +    Aspeed27x0SoCState *a = ASPEED27X0_SOC(dev);
> +    AspeedSoCState *s = ASPEED_SOC(dev);
> +    AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
> +    g_autofree char *sram_name = NULL;
> +
> +    /* Default boot region (SPI memory or ROMs) */
> +    memory_region_init(&s->spi_boot_container, OBJECT(s),
> +                       "aspeed.spi_boot_container", 0x400000000);
> +    memory_region_add_subregion(s->memory, sc->memmap[ASPEED_DEV_SPI_BOOT],
> +                                &s->spi_boot_container);
> +
> +    /* CPU */
> +    for (i = 0; i < sc->num_cpus; i++) {
> +        object_property_set_int(OBJECT(&a->cpu[i]), "mp-affinity",
> +                                aspeed_calc_affinity(i), &error_abort);
> +
> +        object_property_set_int(OBJECT(&a->cpu[i]), "cntfrq", 1125000000,
> +                                &error_abort);
> +        object_property_set_link(OBJECT(&a->cpu[i]), "memory",
> +                                 OBJECT(s->memory), &error_abort);
> +
> +        if (!qdev_realize(DEVICE(&a->cpu[i]), NULL, errp)) {
> +            return;
> +        }
> +    }
> +
> +    /* GIC */
> +    aspeed_soc_ast2700_gic(dev, errp);

Hmm, we should return.

> +
> +    /* INTC */
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc), errp)) {
> +        return;
> +    }
> +
> +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc), 0,
> +                    sc->memmap[ASPEED_DEV_INTC]);
> +
> +    /* GICINT orgate -> INTC -> GIC */
> +    for (i = 0; i < ASPEED_INTC_NR_GICS; i++) {
> +        if (!qdev_realize(DEVICE(&a->intc.gicint_orgate[i]), NULL, errp)) {
> +            return;
> +        }
> +
> +        qdev_connect_gpio_out(DEVICE(&a->intc.gicint_orgate[i]), 0,
> +                              qdev_get_gpio_in(DEVICE(&a->intc), i));
> +
> +        sysbus_connect_irq(SYS_BUS_DEVICE(&a->intc), i,
> +                           qdev_get_gpio_in(a->intc.gic,
> +                                aspeed_soc_ast2700_gic_intcmap[i].irq));
> +    }
> +
> +    /* SRAM */
> +    sram_name = g_strdup_printf("aspeed.sram.%d", CPU(&a->cpu[0])->cpu_index);
> +    if (!memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size,
> +                                 errp)) {
> +        return;
> +    }
> +    memory_region_add_subregion(s->memory,
> +                                sc->memmap[ASPEED_DEV_SRAM], &s->sram);
> +
> +    /* SCU */
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) {
> +        return;
> +    }
> +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]);
> +
> +    /* SCU1 */
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->scuio), errp)) {
> +        return;
> +    }
> +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scuio), 0,
> +                    sc->memmap[ASPEED_DEV_SCUIO]);
> +
> +    /* UART */
> +    if (!aspeed_soc_uart_realize(s, errp)) {
> +        return;
> +    }
> +
> +    /* FMC, The number of CS is set at the board level */
> +    object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr),
> +                             &error_abort);
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) {
> +        return;
> +    }
> +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]);
> +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 1,
> +                    ASPEED_SMC_GET_CLASS(&s->fmc)->flash_window_base);
> +    sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0,
> +                       aspeed_soc_get_irq(s, ASPEED_DEV_FMC));
> +
> +    /* Set up an alias on the FMC CE0 region (boot default) */
> +    MemoryRegion *fmc0_mmio = &s->fmc.flashes[0].mmio;
> +    memory_region_init_alias(&s->spi_boot, OBJECT(s), "aspeed.spi_boot",
> +                             fmc0_mmio, 0, memory_region_size(fmc0_mmio));
> +    memory_region_add_subregion(&s->spi_boot_container, 0x0, &s->spi_boot);
> +
> +    /* SPI */
> +    for (i = 0; i < sc->spis_num; i++) {
> +        object_property_set_link(OBJECT(&s->spi[i]), "dram",
> +                                 OBJECT(s->dram_mr), &error_abort);
> +        if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) {
> +            return;
> +        }
> +        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 0,
> +                        sc->memmap[ASPEED_DEV_SPI0 + i]);
> +        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 1,
> +                        ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base);
> +    }
> +
> +    /*
> +     * SDMC - SDRAM Memory Controller
> +     * The SDMC controller is unlocked at SPL stage.
> +     * At present, only supports to emulate booting
> +     * start from u-boot stage. Set SDMC controller
> +     * unlocked by default. It is a temporarily solution.
> +     */
> +    object_property_set_bool(OBJECT(&s->sdmc), "unlocked", true,
> +                                 &error_abort);
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), errp)) {
> +        return;
> +    }
> +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdmc), 0,
> +                    sc->memmap[ASPEED_DEV_SDMC]);
> +
> +    /* RAM */
> +    if (!aspeed_soc_dram_init(s, errp)) {
> +        return;
> +    }
> +
> +    for (i = 0; i < sc->macs_num; i++) {
> +        object_property_set_bool(OBJECT(&s->ftgmac100[i]), "aspeed", true,
> +                                 &error_abort);
> +        if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), errp)) {
> +            return;
> +        }
> +        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
> +                        sc->memmap[ASPEED_DEV_ETH1 + i]);
> +        sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
> +                           aspeed_soc_get_irq(s, ASPEED_DEV_ETH1 + i));
> +
> +        object_property_set_link(OBJECT(&s->mii[i]), "nic",
> +                                 OBJECT(&s->ftgmac100[i]), &error_abort);
> +        if (!sysbus_realize(SYS_BUS_DEVICE(&s->mii[i]), errp)) {
> +            return;
> +        }
> +
> +        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->mii[i]), 0,
> +                        sc->memmap[ASPEED_DEV_MII1 + i]);
> +    }
> +
> +    /* Watch dog */
> +    for (i = 0; i < sc->wdts_num; i++) {
> +        AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]);
> +        hwaddr wdt_offset = sc->memmap[ASPEED_DEV_WDT] + i * awc->iosize;
> +
> +        object_property_set_link(OBJECT(&s->wdt[i]), "scu", OBJECT(&s->scu),
> +                                 &error_abort);
> +        if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
> +            return;
> +        }
> +        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0, wdt_offset);
> +    }
> +
> +    /* SLI */
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->sli), errp)) {
> +        return;
> +    }
> +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sli), 0, sc->memmap[ASPEED_DEV_SLI]);
> +
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->sliio), errp)) {
> +        return;
> +    }
> +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sliio), 0,
> +                    sc->memmap[ASPEED_DEV_SLIIO]);
> +
> +    create_unimplemented_device("ast2700.dpmcu", 0x11000000, 0x40000);
> +    create_unimplemented_device("ast2700.iomem0", 0x12000000, 0x01000000);
> +    create_unimplemented_device("ast2700.iomem1", 0x14000000, 0x01000000);
> +    create_unimplemented_device("ast2700.ltpi", 0x30000000, 0x1000000);
> +    create_unimplemented_device("ast2700.io", 0x0, 0x4000000);
> +}
> +
> +static void aspeed_soc_ast2700_class_init(ObjectClass *oc, void *data)
> +{
> +    static const char * const valid_cpu_types[] = {
> +        ARM_CPU_TYPE_NAME("cortex-a35"),
> +        NULL
> +    };
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +    AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc);
> +
> +    dc->realize      = aspeed_soc_ast2700_realize;


Please add :

     /* Reason: The Aspeed SoC can only be instantiated from a board */
     dc->user_creatable = false;


Thanks,

C.


> +
> +    sc->name         = "ast2700-a0";
> +    sc->valid_cpu_types = valid_cpu_types;
> +    sc->silicon_rev  = AST2700_A0_SILICON_REV;
> +    sc->sram_size    = 0x20000;
> +    sc->spis_num     = 3;
> +    sc->wdts_num     = 8;
> +    sc->macs_num     = 1;
> +    sc->uarts_num    = 13;
> +    sc->num_cpus     = 4;
> +    sc->uarts_base   = ASPEED_DEV_UART0;
> +    sc->irqmap       = aspeed_soc_ast2700_irqmap;
> +    sc->memmap       = aspeed_soc_ast2700_memmap;
> +    sc->get_irq      = aspeed_soc_ast2700_get_irq;
> +}
> +
> +static const TypeInfo aspeed_soc_ast27x0_types[] = {
> +    {
> +        .name           = TYPE_ASPEED27X0_SOC,
> +        .parent         = TYPE_ASPEED_SOC,
> +        .instance_size  = sizeof(Aspeed27x0SoCState),
> +        .abstract       = true,
> +    }, {
> +        .name           = "ast2700-a0",
> +        .parent         = TYPE_ASPEED27X0_SOC,
> +        .instance_init  = aspeed_soc_ast2700_init,
> +        .class_init     = aspeed_soc_ast2700_class_init,
> +    },
> +};
> +
> +DEFINE_TYPES(aspeed_soc_ast27x0_types)
> diff --git a/hw/arm/meson.build b/hw/arm/meson.build
> index 6808135c1f..1e3295a423 100644
> --- a/hw/arm/meson.build
> +++ b/hw/arm/meson.build
> @@ -46,6 +46,7 @@ arm_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
>     'aspeed_soc_common.c',
>     'aspeed_ast2400.c',
>     'aspeed_ast2600.c',
> +  'aspeed_ast27x0.c',
>     'aspeed_ast10x0.c',
>     'aspeed_eeprom.c',
>     'fby35.c'))
> diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
> index c60fac900a..9f177b6037 100644
> --- a/include/hw/arm/aspeed_soc.h
> +++ b/include/hw/arm/aspeed_soc.h
> @@ -15,6 +15,7 @@
>   #include "hw/cpu/a15mpcore.h"
>   #include "hw/arm/armv7m.h"
>   #include "hw/intc/aspeed_vic.h"
> +#include "hw/intc/aspeed_intc.h"
>   #include "hw/misc/aspeed_scu.h"
>   #include "hw/adc/aspeed_adc.h"
>   #include "hw/misc/aspeed_sdmc.h"
> @@ -26,6 +27,7 @@
>   #include "hw/ssi/aspeed_smc.h"
>   #include "hw/misc/aspeed_hace.h"
>   #include "hw/misc/aspeed_sbc.h"
> +#include "hw/misc/aspeed_sli.h"
>   #include "hw/watchdog/wdt_aspeed.h"
>   #include "hw/net/ftgmac100.h"
>   #include "target/arm/cpu.h"
> @@ -41,8 +43,8 @@
>   
>   #define ASPEED_SPIS_NUM  2
>   #define ASPEED_EHCIS_NUM 2
> -#define ASPEED_WDTS_NUM  4
> -#define ASPEED_CPUS_NUM  2
> +#define ASPEED_WDTS_NUM  8
> +#define ASPEED_CPUS_NUM  4
>   #define ASPEED_MACS_NUM  4
>   #define ASPEED_UARTS_NUM 13
>   #define ASPEED_JTAG_NUM  2
> @@ -61,6 +63,7 @@ struct AspeedSoCState {
>       AspeedI2CState i2c;
>       AspeedI3CState i3c;
>       AspeedSCUState scu;
> +    AspeedSCUState scuio;
>       AspeedHACEState hace;
>       AspeedXDMAState xdma;
>       AspeedADCState adc;
> @@ -68,6 +71,8 @@ struct AspeedSoCState {
>       AspeedSMCState spi[ASPEED_SPIS_NUM];
>       EHCISysBusState ehci[ASPEED_EHCIS_NUM];
>       AspeedSBCState sbc;
> +    AspeedSLIState sli;
> +    AspeedSLIState sliio;
>       MemoryRegion secsram;
>       UnimplementedDeviceState sbc_unimplemented;
>       AspeedSDMCState sdmc;
> @@ -117,6 +122,16 @@ struct Aspeed2600SoCState {
>   #define TYPE_ASPEED2600_SOC "aspeed2600-soc"
>   OBJECT_DECLARE_SIMPLE_TYPE(Aspeed2600SoCState, ASPEED2600_SOC)
>   
> +struct Aspeed27x0SoCState {
> +    AspeedSoCState parent;
> +
> +    ARMCPU cpu[ASPEED_CPUS_NUM];
> +    AspeedINTCState intc;
> +};
> +
> +#define TYPE_ASPEED27X0_SOC "aspeed27x0-soc"
> +OBJECT_DECLARE_SIMPLE_TYPE(Aspeed27x0SoCState, ASPEED27X0_SOC)
> +
>   struct Aspeed10x0SoCState {
>       AspeedSoCState parent;
>   
> @@ -168,11 +183,13 @@ enum {
>       ASPEED_DEV_UART13,
>       ASPEED_DEV_VUART,
>       ASPEED_DEV_FMC,
> +    ASPEED_DEV_SPI0,
>       ASPEED_DEV_SPI1,
>       ASPEED_DEV_SPI2,
>       ASPEED_DEV_EHCI1,
>       ASPEED_DEV_EHCI2,
>       ASPEED_DEV_VIC,
> +    ASPEED_DEV_INTC,
>       ASPEED_DEV_SDMC,
>       ASPEED_DEV_SCU,
>       ASPEED_DEV_ADC,
> @@ -222,6 +239,11 @@ enum {
>       ASPEED_DEV_JTAG1,
>       ASPEED_DEV_FSI1,
>       ASPEED_DEV_FSI2,
> +    ASPEED_DEV_SCUIO,
> +    ASPEED_DEV_SLI,
> +    ASPEED_DEV_SLIIO,
> +    ASPEED_GIC_DIST,
> +    ASPEED_GIC_REDIST,
>   };
>   
>   qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev);



^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH v3 12/16] aspeed/soc: Add AST2700 support
  2024-04-19  7:10   ` Cédric Le Goater
@ 2024-04-19  7:58     ` Jamin Lin
  0 siblings, 0 replies; 42+ messages in thread
From: Jamin Lin @ 2024-04-19  7:58 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: Troy Lee, Yunlin Tang

Hi Cedric, 
> On 4/16/24 11:18, Jamin Lin wrote:
> > Initial definitions for a simple machine using an AST2700 SOC (Cortex-a35
> CPU).
> >
> > AST2700 SOC and its interrupt controller are too complex to handle in
> > the common Aspeed SoC framework. We introduce a new ast2700 class with
> > instance_init and realize handlers.
> >
> > AST2700 is a 64 bits quad core cpus and support 8 watchdog.
> > Update maximum ASPEED_CPUS_NUM to 4 and ASPEED_WDTS_NUM to 8.
> > In addition, update AspeedSocState to support scuio, sli, sliio and intc.
> >
> > Add TYPE_ASPEED27X0_SOC machine type.
> >
> > The SDMC controller is unlocked at SPL stage.
> > At present, only supports to emulate booting start from u-boot stage.
> > Set SDMC controller unlocked by default.
> >
> > In INTC, each interrupt of INT 128 to INT 136 combines 32 interrupts.
> > It connect GICINT IRQ GPIO-OUTPUT pins to GIC device with irq 128 to 136.
> > And, if a device irq is 128 to 136, its irq GPIO-OUTPUT pin is
> > connected to GICINT or-gates instead of GIC device.
> >
> > Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> > Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> 
> Before I forget, please see a little comment below regarding user creatable
> devices.
> 
> The model looks fine. The interrupt controller part is more complex than the
> previous SoCs so I will come back to it later when I have more time. 
Thanks for your kindly support.
> > ---
> >   hw/arm/aspeed_ast27x0.c     | 554
> ++++++++++++++++++++++++++++++++++++
> >   hw/arm/meson.build          |   1 +
> >   include/hw/arm/aspeed_soc.h |  26 +-
> >   3 files changed, 579 insertions(+), 2 deletions(-)
> >   create mode 100644 hw/arm/aspeed_ast27x0.c
> >
> > diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c new
> > file mode 100644 index 0000000000..754c963230
> > --- /dev/null
> > +++ b/hw/arm/aspeed_ast27x0.c
> > @@ -0,0 +1,554 @@
> > +/*
> > + * ASPEED SoC 27x0 family
> > + *
> > + * Copyright (C) 2024 ASPEED Technology Inc.
> > + *
> > + * This code is licensed under the GPL version 2 or later.  See
> > + * the COPYING file in the top-level directory.
> > + *
> > + * Implementation extracted from the AST2600 and adapted for AST27x0.
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qapi/error.h"
> > +#include "hw/misc/unimp.h"
> > +#include "hw/arm/aspeed_soc.h"
> > +#include "qemu/module.h"
> > +#include "qemu/error-report.h"
> > +#include "hw/i2c/aspeed_i2c.h"
> > +#include "net/net.h"
> > +#include "sysemu/sysemu.h"
> > +#include "hw/intc/arm_gicv3.h"
> > +#include "qapi/qmp/qlist.h"
> > +
> > +static const hwaddr aspeed_soc_ast2700_memmap[] = {
> > +    [ASPEED_DEV_SPI_BOOT]  =  0x400000000,
> > +    [ASPEED_DEV_SRAM]      =  0x10000000,
> > +    [ASPEED_DEV_SDMC]      =  0x12C00000,
> > +    [ASPEED_DEV_SCU]       =  0x12C02000,
> > +    [ASPEED_DEV_SCUIO]     =  0x14C02000,
> > +    [ASPEED_DEV_UART0]     =  0X14C33000,
> > +    [ASPEED_DEV_UART1]     =  0X14C33100,
> > +    [ASPEED_DEV_UART2]     =  0X14C33200,
> > +    [ASPEED_DEV_UART3]     =  0X14C33300,
> > +    [ASPEED_DEV_UART4]     =  0X12C1A000,
> > +    [ASPEED_DEV_UART5]     =  0X14C33400,
> > +    [ASPEED_DEV_UART6]     =  0X14C33500,
> > +    [ASPEED_DEV_UART7]     =  0X14C33600,
> > +    [ASPEED_DEV_UART8]     =  0X14C33700,
> > +    [ASPEED_DEV_UART9]     =  0X14C33800,
> > +    [ASPEED_DEV_UART10]    =  0X14C33900,
> > +    [ASPEED_DEV_UART11]    =  0X14C33A00,
> > +    [ASPEED_DEV_UART12]    =  0X14C33B00,
> > +    [ASPEED_DEV_WDT]       =  0x14C37000,
> > +    [ASPEED_DEV_VUART]     =  0X14C30000,
> > +    [ASPEED_DEV_FMC]       =  0x14000000,
> > +    [ASPEED_DEV_SPI0]      =  0x14010000,
> > +    [ASPEED_DEV_SPI1]      =  0x14020000,
> > +    [ASPEED_DEV_SPI2]      =  0x14030000,
> > +    [ASPEED_DEV_SDRAM]     =  0x400000000,
> > +    [ASPEED_DEV_MII1]      =  0x14040000,
> > +    [ASPEED_DEV_MII2]      =  0x14040008,
> > +    [ASPEED_DEV_MII3]      =  0x14040010,
> > +    [ASPEED_DEV_ETH1]      =  0x14050000,
> > +    [ASPEED_DEV_ETH2]      =  0x14060000,
> > +    [ASPEED_DEV_ETH3]      =  0x14070000,
> > +    [ASPEED_DEV_EMMC]      =  0x12090000,
> > +    [ASPEED_DEV_INTC]      =  0x12100000,
> > +    [ASPEED_DEV_SLI]       =  0x12C17000,
> > +    [ASPEED_DEV_SLIIO]     =  0x14C1E000,
> > +    [ASPEED_GIC_DIST]      =  0x12200000,
> > +    [ASPEED_GIC_REDIST]    =  0x12280000,
> > +};
> > +
> > +#define AST2700_MAX_IRQ 288
> > +
> > +/* Shared Peripheral Interrupt values below are offset by -32 from
> > +datasheet */ static const int aspeed_soc_ast2700_irqmap[] = {
> > +    [ASPEED_DEV_UART0]     = 132,
> > +    [ASPEED_DEV_UART1]     = 132,
> > +    [ASPEED_DEV_UART2]     = 132,
> > +    [ASPEED_DEV_UART3]     = 132,
> > +    [ASPEED_DEV_UART4]     = 8,
> > +    [ASPEED_DEV_UART5]     = 132,
> > +    [ASPEED_DEV_UART6]     = 132,
> > +    [ASPEED_DEV_UART7]     = 132,
> > +    [ASPEED_DEV_UART8]     = 132,
> > +    [ASPEED_DEV_UART9]     = 132,
> > +    [ASPEED_DEV_UART10]    = 132,
> > +    [ASPEED_DEV_UART11]    = 132,
> > +    [ASPEED_DEV_UART12]    = 132,
> > +    [ASPEED_DEV_FMC]       = 131,
> > +    [ASPEED_DEV_SDMC]      = 0,
> > +    [ASPEED_DEV_SCU]       = 12,
> > +    [ASPEED_DEV_ADC]       = 130,
> > +    [ASPEED_DEV_XDMA]      = 5,
> > +    [ASPEED_DEV_EMMC]      = 15,
> > +    [ASPEED_DEV_GPIO]      = 11,
> > +    [ASPEED_DEV_GPIO_1_8V] = 130,
> > +    [ASPEED_DEV_RTC]       = 13,
> > +    [ASPEED_DEV_TIMER1]    = 16,
> > +    [ASPEED_DEV_TIMER2]    = 17,
> > +    [ASPEED_DEV_TIMER3]    = 18,
> > +    [ASPEED_DEV_TIMER4]    = 19,
> > +    [ASPEED_DEV_TIMER5]    = 20,
> > +    [ASPEED_DEV_TIMER6]    = 21,
> > +    [ASPEED_DEV_TIMER7]    = 22,
> > +    [ASPEED_DEV_TIMER8]    = 23,
> > +    [ASPEED_DEV_WDT]       = 131,
> > +    [ASPEED_DEV_PWM]       = 131,
> > +    [ASPEED_DEV_LPC]       = 128,
> > +    [ASPEED_DEV_IBT]       = 128,
> > +    [ASPEED_DEV_I2C]       = 130,
> > +    [ASPEED_DEV_PECI]      = 133,
> > +    [ASPEED_DEV_ETH1]      = 132,
> > +    [ASPEED_DEV_ETH2]      = 132,
> > +    [ASPEED_DEV_ETH3]      = 132,
> > +    [ASPEED_DEV_HACE]      = 4,
> > +    [ASPEED_DEV_KCS]       = 128,
> > +    [ASPEED_DEV_DP]        = 28,
> > +    [ASPEED_DEV_I3C]       = 131,
> > +};
> > +
> > +/* GICINT 128 */
> > +static const int aspeed_soc_ast2700_gic128_intcmap[] = {
> > +    [ASPEED_DEV_LPC]       = 0,
> > +    [ASPEED_DEV_IBT]       = 2,
> > +    [ASPEED_DEV_KCS]       = 4,
> > +};
> > +
> > +/* GICINT 130 */
> > +static const int aspeed_soc_ast2700_gic130_intcmap[] = {
> > +    [ASPEED_DEV_I2C]        = 0,
> > +    [ASPEED_DEV_ADC]        = 16,
> > +    [ASPEED_DEV_GPIO_1_8V]  = 18,
> > +};
> > +
> > +/* GICINT 131 */
> > +static const int aspeed_soc_ast2700_gic131_intcmap[] = {
> > +    [ASPEED_DEV_I3C]       = 0,
> > +    [ASPEED_DEV_WDT]       = 16,
> > +    [ASPEED_DEV_FMC]       = 25,
> > +    [ASPEED_DEV_PWM]       = 29,
> > +};
> > +
> > +/* GICINT 132 */
> > +static const int aspeed_soc_ast2700_gic132_intcmap[] = {
> > +    [ASPEED_DEV_ETH1]      = 0,
> > +    [ASPEED_DEV_ETH2]      = 1,
> > +    [ASPEED_DEV_ETH3]      = 2,
> > +    [ASPEED_DEV_UART0]     = 7,
> > +    [ASPEED_DEV_UART1]     = 8,
> > +    [ASPEED_DEV_UART2]     = 9,
> > +    [ASPEED_DEV_UART3]     = 10,
> > +    [ASPEED_DEV_UART5]     = 11,
> > +    [ASPEED_DEV_UART6]     = 12,
> > +    [ASPEED_DEV_UART7]     = 13,
> > +    [ASPEED_DEV_UART8]     = 14,
> > +    [ASPEED_DEV_UART9]     = 15,
> > +    [ASPEED_DEV_UART10]    = 16,
> > +    [ASPEED_DEV_UART11]    = 17,
> > +    [ASPEED_DEV_UART12]    = 18,
> > +};
> > +
> > +/* GICINT 133 */
> > +static const int aspeed_soc_ast2700_gic133_intcmap[] = {
> > +    [ASPEED_DEV_PECI]      = 4,
> > +};
> > +
> > +/* GICINT 128 ~ 136 */
> > +struct gic_intc_irq_info {
> > +    int irq;
> > +    const int *ptr;
> > +};
> > +
> > +static const struct gic_intc_irq_info aspeed_soc_ast2700_gic_intcmap[] = {
> > +    {128,  aspeed_soc_ast2700_gic128_intcmap},
> > +    {129,  NULL},
> > +    {130,  aspeed_soc_ast2700_gic130_intcmap},
> > +    {131,  aspeed_soc_ast2700_gic131_intcmap},
> > +    {132,  aspeed_soc_ast2700_gic132_intcmap},
> > +    {133,  aspeed_soc_ast2700_gic133_intcmap},
> > +    {134,  NULL},
> > +    {135,  NULL},
> > +    {136,  NULL},
> > +};
> > +
> > +static qemu_irq aspeed_soc_ast2700_get_irq(AspeedSoCState *s, int
> > +dev) {
> > +    Aspeed27x0SoCState *a = ASPEED27X0_SOC(s);
> > +    AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
> > +    int i;
> > +
> > +    for (i = 0; i < ARRAY_SIZE(aspeed_soc_ast2700_gic_intcmap); i++) {
> > +        if (sc->irqmap[dev] == aspeed_soc_ast2700_gic_intcmap[i].irq) {
> > +            assert(aspeed_soc_ast2700_gic_intcmap[i].ptr);
> > +            return qdev_get_gpio_in(DEVICE(&a->intc.gicint_orgate[i]),
> > +                aspeed_soc_ast2700_gic_intcmap[i].ptr[dev]);
> > +        }
> > +    }
> > +
> > +    return qdev_get_gpio_in(a->intc.gic, sc->irqmap[dev]); }
> > +
> > +static void aspeed_soc_ast2700_init(Object *obj) {
> > +    Aspeed27x0SoCState *a = ASPEED27X0_SOC(obj);
> > +    AspeedSoCState *s = ASPEED_SOC(obj);
> > +    AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
> > +    int i;
> > +    char socname[8];
> > +    char typename[64];
> > +
> > +    if (sscanf(sc->name, "%7s", socname) != 1) {
> > +        g_assert_not_reached();
> > +    }
> > +
> > +    for (i = 0; i < sc->num_cpus; i++) {
> > +        object_initialize_child(obj, "cpu[*]", &a->cpu[i],
> > +                                aspeed_soc_cpu_type(sc));
> > +    }
> > +
> > +    object_initialize_child(obj, "scu", &s->scu, TYPE_ASPEED_2700_SCU);
> > +    qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev",
> > +                         sc->silicon_rev);
> > +    object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu),
> > +                              "hw-strap1");
> > +    object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu),
> > +                              "hw-strap2");
> > +    object_property_add_alias(obj, "hw-prot-key", OBJECT(&s->scu),
> > +                              "hw-prot-key");
> > +
> > +    object_initialize_child(obj, "scuio", &s->scuio,
> TYPE_ASPEED_2700_SCUIO);
> > +    qdev_prop_set_uint32(DEVICE(&s->scuio), "silicon-rev",
> > +                         sc->silicon_rev);
> > +
> > +    snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname);
> > +    object_initialize_child(obj, "fmc", &s->fmc, typename);
> > +
> > +    for (i = 0; i < sc->spis_num; i++) {
> > +        snprintf(typename, sizeof(typename), "aspeed.spi%d-%s", i,
> socname);
> > +        object_initialize_child(obj, "spi[*]", &s->spi[i], typename);
> > +    }
> > +
> > +    snprintf(typename, sizeof(typename), "aspeed.sdmc-%s", socname);
> > +    object_initialize_child(obj, "sdmc", &s->sdmc, typename);
> > +    object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
> > +                              "ram-size");
> > +
> > +    for (i = 0; i < sc->wdts_num; i++) {
> > +        snprintf(typename, sizeof(typename), "aspeed.wdt-%s",
> socname);
> > +        object_initialize_child(obj, "wdt[*]", &s->wdt[i], typename);
> > +    }
> > +
> > +    for (i = 0; i < sc->macs_num; i++) {
> > +        object_initialize_child(obj, "ftgmac100[*]", &s->ftgmac100[i],
> > +                                TYPE_FTGMAC100);
> > +
> > +        object_initialize_child(obj, "mii[*]", &s->mii[i],
> TYPE_ASPEED_MII);
> > +    }
> > +
> > +    for (i = 0; i < sc->uarts_num; i++) {
> > +        object_initialize_child(obj, "uart[*]", &s->uart[i],
> TYPE_SERIAL_MM);
> > +    }
> > +
> > +    object_initialize_child(obj, "sli", &s->sli, TYPE_ASPEED_2700_SLI);
> > +    object_initialize_child(obj, "sliio", &s->sliio,
> TYPE_ASPEED_2700_SLIIO);
> > +    object_initialize_child(obj, "intc", &a->intc, TYPE_ASPEED_INTC);
> > +}
> > +
> > +/*
> > + * ASPEED ast2700 has 0x0 as cluster ID
> > + *
> > + *
> > +https://developer.arm.com/documentation/100236/0100/register-descript
> > +ions/aarch64-system-registers/multiprocessor-affinity-register--el1
> > + */
> > +static uint64_t aspeed_calc_affinity(int cpu) {
> > +    return (0x0 << ARM_AFF1_SHIFT) | cpu; }
> > +
> > +static void aspeed_soc_ast2700_gic(DeviceState *dev, Error **errp) {
> > +    Aspeed27x0SoCState *a = ASPEED27X0_SOC(dev);
> > +    AspeedSoCState *s = ASPEED_SOC(dev);
> > +    AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
> > +    SysBusDevice *gicbusdev;
> > +    QList *redist_region_count;
> > +    int i;
> > +
> > +    a->intc.gic = qdev_new(gicv3_class_name());
> > +    qdev_prop_set_uint32(a->intc.gic, "revision", 3);
> > +    qdev_prop_set_uint32(a->intc.gic, "num-cpu", sc->num_cpus);
> > +    qdev_prop_set_uint32(a->intc.gic, "num-irq", AST2700_MAX_IRQ);
> > +
> > +    redist_region_count = qlist_new();
> > +    qlist_append_int(redist_region_count, sc->num_cpus);
> > +    qdev_prop_set_array(a->intc.gic, "redist-region-count",
> > +                            redist_region_count);
> > +
> > +    gicbusdev = SYS_BUS_DEVICE(a->intc.gic);
> > +    sysbus_realize_and_unref(gicbusdev, errp);
> > +    sysbus_mmio_map(gicbusdev, 0, sc->memmap[ASPEED_GIC_DIST]);
> > +    sysbus_mmio_map(gicbusdev, 1, sc->memmap[ASPEED_GIC_REDIST]);
> > +
> > +    for (i = 0; i < sc->num_cpus; i++) {
> > +        DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
> > +        int NUM_IRQS = 256, ARCH_GIC_MAINT_IRQ = 9,
> VIRTUAL_PMU_IRQ = 7;
> > +        int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
> > +
> > +        const int timer_irq[] = {
> > +            [GTIMER_PHYS] = 14,
> > +            [GTIMER_VIRT] = 11,
> > +            [GTIMER_HYP]  = 10,
> > +            [GTIMER_SEC]  = 13,
> > +        };
> > +        int j;
> > +
> > +        for (j = 0; j < ARRAY_SIZE(timer_irq); j++) {
> > +            qdev_connect_gpio_out(cpudev, j,
> > +                    qdev_get_gpio_in(a->intc.gic, ppibase +
> timer_irq[j]));
> > +        }
> > +
> > +        qemu_irq irq = qdev_get_gpio_in(a->intc.gic,
> > +                                        ppibase +
> ARCH_GIC_MAINT_IRQ);
> > +        qdev_connect_gpio_out_named(cpudev,
> "gicv3-maintenance-interrupt",
> > +                                    0, irq);
> > +        qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
> > +                qdev_get_gpio_in(a->intc.gic, ppibase +
> > + VIRTUAL_PMU_IRQ));
> > +
> > +        sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev,
> ARM_CPU_IRQ));
> > +        sysbus_connect_irq(gicbusdev, i + sc->num_cpus,
> > +                           qdev_get_gpio_in(cpudev,
> ARM_CPU_FIQ));
> > +        sysbus_connect_irq(gicbusdev, i + 2 * sc->num_cpus,
> > +                           qdev_get_gpio_in(cpudev,
> ARM_CPU_VIRQ));
> > +        sysbus_connect_irq(gicbusdev, i + 3 * sc->num_cpus,
> > +                           qdev_get_gpio_in(cpudev,
> ARM_CPU_VFIQ));
> > +    }
> > +}
> > +
> > +static void aspeed_soc_ast2700_realize(DeviceState *dev, Error
> > +**errp) {
> > +    int i;
> > +    Aspeed27x0SoCState *a = ASPEED27X0_SOC(dev);
> > +    AspeedSoCState *s = ASPEED_SOC(dev);
> > +    AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
> > +    g_autofree char *sram_name = NULL;
> > +
> > +    /* Default boot region (SPI memory or ROMs) */
> > +    memory_region_init(&s->spi_boot_container, OBJECT(s),
> > +                       "aspeed.spi_boot_container", 0x400000000);
> > +    memory_region_add_subregion(s->memory,
> sc->memmap[ASPEED_DEV_SPI_BOOT],
> > +                                &s->spi_boot_container);
> > +
> > +    /* CPU */
> > +    for (i = 0; i < sc->num_cpus; i++) {
> > +        object_property_set_int(OBJECT(&a->cpu[i]), "mp-affinity",
> > +                                aspeed_calc_affinity(i),
> > + &error_abort);
> > +
> > +        object_property_set_int(OBJECT(&a->cpu[i]), "cntfrq",
> 1125000000,
> > +                                &error_abort);
> > +        object_property_set_link(OBJECT(&a->cpu[i]), "memory",
> > +                                 OBJECT(s->memory),
> &error_abort);
> > +
> > +        if (!qdev_realize(DEVICE(&a->cpu[i]), NULL, errp)) {
> > +            return;
> > +        }
> > +    }
> > +
> > +    /* GIC */
> > +    aspeed_soc_ast2700_gic(dev, errp);
> 
> Hmm, we should return.
This function return type is void.
If I understand your request, do you mean do the following changes?

static bool aspeed_soc_ast2700_gic(DeviceState *dev, Error **errp) --> change return type bool
{
    ---
    gicbusdev = SYS_BUS_DEVICE(a->intc.gic); 
    if(!sysbus_realize(gicbusdev, errp)) {
        return false;
    }
    ---
    return true;
}

Then, 
/* GIC */
if(!aspeed_soc_ast2700_gic(dev, errp)) {
    return;
    }

Thanks-Jamin
> 
> > +
> > +    /* INTC */
> > +    if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc), errp)) {
> > +        return;
> > +    }
> > +
> > +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc), 0,
> > +                    sc->memmap[ASPEED_DEV_INTC]);
> > +
> > +    /* GICINT orgate -> INTC -> GIC */
> > +    for (i = 0; i < ASPEED_INTC_NR_GICS; i++) {
> > +        if (!qdev_realize(DEVICE(&a->intc.gicint_orgate[i]), NULL, errp)) {
> > +            return;
> > +        }
> > +
> > +        qdev_connect_gpio_out(DEVICE(&a->intc.gicint_orgate[i]), 0,
> > +                              qdev_get_gpio_in(DEVICE(&a->intc),
> i));
> > +
> > +        sysbus_connect_irq(SYS_BUS_DEVICE(&a->intc), i,
> > +                           qdev_get_gpio_in(a->intc.gic,
> > +
> aspeed_soc_ast2700_gic_intcmap[i].irq));
> > +    }
> > +
> > +    /* SRAM */
> > +    sram_name = g_strdup_printf("aspeed.sram.%d",
> CPU(&a->cpu[0])->cpu_index);
> > +    if (!memory_region_init_ram(&s->sram, OBJECT(s), sram_name,
> sc->sram_size,
> > +                                 errp)) {
> > +        return;
> > +    }
> > +    memory_region_add_subregion(s->memory,
> > +                                sc->memmap[ASPEED_DEV_SRAM],
> > + &s->sram);
> > +
> > +    /* SCU */
> > +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) {
> > +        return;
> > +    }
> > +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0,
> > + sc->memmap[ASPEED_DEV_SCU]);
> > +
> > +    /* SCU1 */
> > +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->scuio), errp)) {
> > +        return;
> > +    }
> > +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scuio), 0,
> > +                    sc->memmap[ASPEED_DEV_SCUIO]);
> > +
> > +    /* UART */
> > +    if (!aspeed_soc_uart_realize(s, errp)) {
> > +        return;
> > +    }
> > +
> > +    /* FMC, The number of CS is set at the board level */
> > +    object_property_set_link(OBJECT(&s->fmc), "dram",
> OBJECT(s->dram_mr),
> > +                             &error_abort);
> > +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) {
> > +        return;
> > +    }
> > +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 0,
> sc->memmap[ASPEED_DEV_FMC]);
> > +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 1,
> > +
> ASPEED_SMC_GET_CLASS(&s->fmc)->flash_window_base);
> > +    sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0,
> > +                       aspeed_soc_get_irq(s, ASPEED_DEV_FMC));
> > +
> > +    /* Set up an alias on the FMC CE0 region (boot default) */
> > +    MemoryRegion *fmc0_mmio = &s->fmc.flashes[0].mmio;
> > +    memory_region_init_alias(&s->spi_boot, OBJECT(s),
> "aspeed.spi_boot",
> > +                             fmc0_mmio, 0,
> memory_region_size(fmc0_mmio));
> > +    memory_region_add_subregion(&s->spi_boot_container, 0x0,
> > + &s->spi_boot);
> > +
> > +    /* SPI */
> > +    for (i = 0; i < sc->spis_num; i++) {
> > +        object_property_set_link(OBJECT(&s->spi[i]), "dram",
> > +                                 OBJECT(s->dram_mr),
> &error_abort);
> > +        if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) {
> > +            return;
> > +        }
> > +        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 0,
> > +                        sc->memmap[ASPEED_DEV_SPI0 + i]);
> > +        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 1,
> > +
> ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base);
> > +    }
> > +
> > +    /*
> > +     * SDMC - SDRAM Memory Controller
> > +     * The SDMC controller is unlocked at SPL stage.
> > +     * At present, only supports to emulate booting
> > +     * start from u-boot stage. Set SDMC controller
> > +     * unlocked by default. It is a temporarily solution.
> > +     */
> > +    object_property_set_bool(OBJECT(&s->sdmc), "unlocked", true,
> > +                                 &error_abort);
> > +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), errp)) {
> > +        return;
> > +    }
> > +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdmc), 0,
> > +                    sc->memmap[ASPEED_DEV_SDMC]);
> > +
> > +    /* RAM */
> > +    if (!aspeed_soc_dram_init(s, errp)) {
> > +        return;
> > +    }
> > +
> > +    for (i = 0; i < sc->macs_num; i++) {
> > +        object_property_set_bool(OBJECT(&s->ftgmac100[i]), "aspeed",
> true,
> > +                                 &error_abort);
> > +        if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), errp)) {
> > +            return;
> > +        }
> > +        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
> > +                        sc->memmap[ASPEED_DEV_ETH1 + i]);
> > +        sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
> > +                           aspeed_soc_get_irq(s, ASPEED_DEV_ETH1
> +
> > + i));
> > +
> > +        object_property_set_link(OBJECT(&s->mii[i]), "nic",
> > +                                 OBJECT(&s->ftgmac100[i]),
> &error_abort);
> > +        if (!sysbus_realize(SYS_BUS_DEVICE(&s->mii[i]), errp)) {
> > +            return;
> > +        }
> > +
> > +        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->mii[i]), 0,
> > +                        sc->memmap[ASPEED_DEV_MII1 + i]);
> > +    }
> > +
> > +    /* Watch dog */
> > +    for (i = 0; i < sc->wdts_num; i++) {
> > +        AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]);
> > +        hwaddr wdt_offset = sc->memmap[ASPEED_DEV_WDT] + i *
> > + awc->iosize;
> > +
> > +        object_property_set_link(OBJECT(&s->wdt[i]), "scu",
> OBJECT(&s->scu),
> > +                                 &error_abort);
> > +        if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
> > +            return;
> > +        }
> > +        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0,
> wdt_offset);
> > +    }
> > +
> > +    /* SLI */
> > +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->sli), errp)) {
> > +        return;
> > +    }
> > +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sli), 0,
> > + sc->memmap[ASPEED_DEV_SLI]);
> > +
> > +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->sliio), errp)) {
> > +        return;
> > +    }
> > +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sliio), 0,
> > +                    sc->memmap[ASPEED_DEV_SLIIO]);
> > +
> > +    create_unimplemented_device("ast2700.dpmcu", 0x11000000,
> 0x40000);
> > +    create_unimplemented_device("ast2700.iomem0", 0x12000000,
> 0x01000000);
> > +    create_unimplemented_device("ast2700.iomem1", 0x14000000,
> 0x01000000);
> > +    create_unimplemented_device("ast2700.ltpi", 0x30000000,
> 0x1000000);
> > +    create_unimplemented_device("ast2700.io", 0x0, 0x4000000); }
> > +
> > +static void aspeed_soc_ast2700_class_init(ObjectClass *oc, void
> > +*data) {
> > +    static const char * const valid_cpu_types[] = {
> > +        ARM_CPU_TYPE_NAME("cortex-a35"),
> > +        NULL
> > +    };
> > +    DeviceClass *dc = DEVICE_CLASS(oc);
> > +    AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc);
> > +
> > +    dc->realize      = aspeed_soc_ast2700_realize;
> 
> 
> Please add :
> 
>      /* Reason: The Aspeed SoC can only be instantiated from a board */
>      dc->user_creatable = false;
> 
> 
Will add.
> Thanks,
> 
> C.
> 
> 
> > +
> > +    sc->name         = "ast2700-a0";
> > +    sc->valid_cpu_types = valid_cpu_types;
> > +    sc->silicon_rev  = AST2700_A0_SILICON_REV;
> > +    sc->sram_size    = 0x20000;
> > +    sc->spis_num     = 3;
> > +    sc->wdts_num     = 8;
> > +    sc->macs_num     = 1;
> > +    sc->uarts_num    = 13;
> > +    sc->num_cpus     = 4;
> > +    sc->uarts_base   = ASPEED_DEV_UART0;
> > +    sc->irqmap       = aspeed_soc_ast2700_irqmap;
> > +    sc->memmap       = aspeed_soc_ast2700_memmap;
> > +    sc->get_irq      = aspeed_soc_ast2700_get_irq;
> > +}
> > +
> > +static const TypeInfo aspeed_soc_ast27x0_types[] = {
> > +    {
> > +        .name           = TYPE_ASPEED27X0_SOC,
> > +        .parent         = TYPE_ASPEED_SOC,
> > +        .instance_size  = sizeof(Aspeed27x0SoCState),
> > +        .abstract       = true,
> > +    }, {
> > +        .name           = "ast2700-a0",
> > +        .parent         = TYPE_ASPEED27X0_SOC,
> > +        .instance_init  = aspeed_soc_ast2700_init,
> > +        .class_init     = aspeed_soc_ast2700_class_init,
> > +    },
> > +};
> > +
> > +DEFINE_TYPES(aspeed_soc_ast27x0_types)
> > diff --git a/hw/arm/meson.build b/hw/arm/meson.build index
> > 6808135c1f..1e3295a423 100644
> > --- a/hw/arm/meson.build
> > +++ b/hw/arm/meson.build
> > @@ -46,6 +46,7 @@ arm_ss.add(when: 'CONFIG_ASPEED_SOC', if_true:
> files(
> >     'aspeed_soc_common.c',
> >     'aspeed_ast2400.c',
> >     'aspeed_ast2600.c',
> > +  'aspeed_ast27x0.c',
> >     'aspeed_ast10x0.c',
> >     'aspeed_eeprom.c',
> >     'fby35.c'))
> > diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
> > index c60fac900a..9f177b6037 100644
> > --- a/include/hw/arm/aspeed_soc.h
> > +++ b/include/hw/arm/aspeed_soc.h
> > @@ -15,6 +15,7 @@
> >   #include "hw/cpu/a15mpcore.h"
> >   #include "hw/arm/armv7m.h"
> >   #include "hw/intc/aspeed_vic.h"
> > +#include "hw/intc/aspeed_intc.h"
> >   #include "hw/misc/aspeed_scu.h"
> >   #include "hw/adc/aspeed_adc.h"
> >   #include "hw/misc/aspeed_sdmc.h"
> > @@ -26,6 +27,7 @@
> >   #include "hw/ssi/aspeed_smc.h"
> >   #include "hw/misc/aspeed_hace.h"
> >   #include "hw/misc/aspeed_sbc.h"
> > +#include "hw/misc/aspeed_sli.h"
> >   #include "hw/watchdog/wdt_aspeed.h"
> >   #include "hw/net/ftgmac100.h"
> >   #include "target/arm/cpu.h"
> > @@ -41,8 +43,8 @@
> >
> >   #define ASPEED_SPIS_NUM  2
> >   #define ASPEED_EHCIS_NUM 2
> > -#define ASPEED_WDTS_NUM  4
> > -#define ASPEED_CPUS_NUM  2
> > +#define ASPEED_WDTS_NUM  8
> > +#define ASPEED_CPUS_NUM  4
> >   #define ASPEED_MACS_NUM  4
> >   #define ASPEED_UARTS_NUM 13
> >   #define ASPEED_JTAG_NUM  2
> > @@ -61,6 +63,7 @@ struct AspeedSoCState {
> >       AspeedI2CState i2c;
> >       AspeedI3CState i3c;
> >       AspeedSCUState scu;
> > +    AspeedSCUState scuio;
> >       AspeedHACEState hace;
> >       AspeedXDMAState xdma;
> >       AspeedADCState adc;
> > @@ -68,6 +71,8 @@ struct AspeedSoCState {
> >       AspeedSMCState spi[ASPEED_SPIS_NUM];
> >       EHCISysBusState ehci[ASPEED_EHCIS_NUM];
> >       AspeedSBCState sbc;
> > +    AspeedSLIState sli;
> > +    AspeedSLIState sliio;
> >       MemoryRegion secsram;
> >       UnimplementedDeviceState sbc_unimplemented;
> >       AspeedSDMCState sdmc;
> > @@ -117,6 +122,16 @@ struct Aspeed2600SoCState {
> >   #define TYPE_ASPEED2600_SOC "aspeed2600-soc"
> >   OBJECT_DECLARE_SIMPLE_TYPE(Aspeed2600SoCState,
> ASPEED2600_SOC)
> >
> > +struct Aspeed27x0SoCState {
> > +    AspeedSoCState parent;
> > +
> > +    ARMCPU cpu[ASPEED_CPUS_NUM];
> > +    AspeedINTCState intc;
> > +};
> > +
> > +#define TYPE_ASPEED27X0_SOC "aspeed27x0-soc"
> > +OBJECT_DECLARE_SIMPLE_TYPE(Aspeed27x0SoCState, ASPEED27X0_SOC)
> > +
> >   struct Aspeed10x0SoCState {
> >       AspeedSoCState parent;
> >
> > @@ -168,11 +183,13 @@ enum {
> >       ASPEED_DEV_UART13,
> >       ASPEED_DEV_VUART,
> >       ASPEED_DEV_FMC,
> > +    ASPEED_DEV_SPI0,
> >       ASPEED_DEV_SPI1,
> >       ASPEED_DEV_SPI2,
> >       ASPEED_DEV_EHCI1,
> >       ASPEED_DEV_EHCI2,
> >       ASPEED_DEV_VIC,
> > +    ASPEED_DEV_INTC,
> >       ASPEED_DEV_SDMC,
> >       ASPEED_DEV_SCU,
> >       ASPEED_DEV_ADC,
> > @@ -222,6 +239,11 @@ enum {
> >       ASPEED_DEV_JTAG1,
> >       ASPEED_DEV_FSI1,
> >       ASPEED_DEV_FSI2,
> > +    ASPEED_DEV_SCUIO,
> > +    ASPEED_DEV_SLI,
> > +    ASPEED_DEV_SLIIO,
> > +    ASPEED_GIC_DIST,
> > +    ASPEED_GIC_REDIST,
> >   };
> >
> >   qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev);


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 07/16] aspeed/smc: fix dma moving incorrect data length issue
  2024-04-16  9:18 ` [PATCH v3 07/16] aspeed/smc: fix dma moving incorrect data length issue Jamin Lin via
@ 2024-04-19 13:41   ` Cédric Le Goater
  2024-04-30  7:22     ` Cédric Le Goater
  0 siblings, 1 reply; 42+ messages in thread
From: Cédric Le Goater @ 2024-04-19 13:41 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	Alistair Francis, Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: troy_lee, yunlin.tang

On 4/16/24 11:18, Jamin Lin wrote:
> DMA length is from 1 byte to 32MB for AST2600 and AST10x0
> and DMA length is from 4 bytes to 32MB for AST2500.
> 
> In other words, if "R_DMA_LEN" is 0, it should move at least 1 byte
> data for AST2600 and AST10x0 and 4 bytes data for AST2500.
>> To support all ASPEED SOCs, adds dma_start_length parameter to store
> the start length, add helper routines function to compute the dma length
> and update DMA_LENGTH mask to "1FFFFFF" to fix dma moving
> incorrect data length issue.

OK. There are two problems to address, the "zero" length transfer and
the DMA length unit, which is missing today. Newer SoC use a 1 bit / byte
and older ones, AST2400 and AST2500, use 1 bit / 4 bytes.

We can introduce a AspeedSMCClass::dma_len_unit and rework the loop to :

     do {

       ....

        if (s->regs[R_DMA_LEN]) {
             s->regs[R_DMA_LEN] -= 4 / asc->dma_len_unit;
         }
     } while (s->regs[R_DMA_LEN]);

It should fix the current implementation.

I don't think this is necessary to add a Fixes tag because the problem
has been there for ages and no one reported it. Probably because the
only place DMA transfers are used is in U-Boot and transfers have a
non-zero length.

> Currently, only supports dma length 4 bytes aligned.

this looks like a third topic. So the minimum value R_DMA_LEN should
have on the AST2600 SoC and above is '3'. I would opt to replace the
DMA_LENGTH macro with a dma_length_sanitize() helper to fix the software
input of R_DMA_LEN.


Thanks,

C.


  
> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
>   hw/ssi/aspeed_smc.c         | 52 ++++++++++++++++++++++++++++++++-----
>   include/hw/ssi/aspeed_smc.h |  1 +
>   2 files changed, 46 insertions(+), 7 deletions(-)
> 
> diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
> index 8a8d77b480..71abc7a2d8 100644
> --- a/hw/ssi/aspeed_smc.c
> +++ b/hw/ssi/aspeed_smc.c
> @@ -178,13 +178,17 @@
>    * DMA flash addresses should be 4 bytes aligned and the valid address
>    * range is 0x20000000 - 0x2FFFFFFF.
>    *
> - * DMA length is from 4 bytes to 32MB
> + * DMA length is from 4 bytes to 32MB (AST2500)
>    *   0: 4 bytes
>    *   0x7FFFFF: 32M bytes
> + *
> + * DMA length is from 1 byte to 32MB (AST2600, AST10x0)
> + *   0: 1 byte
> + *   0x1FFFFFF: 32M bytes
>    */
>   #define DMA_DRAM_ADDR(asc, val)   ((val) & (asc)->dma_dram_mask)
>   #define DMA_FLASH_ADDR(asc, val)  ((val) & (asc)->dma_flash_mask)
> -#define DMA_LENGTH(val)         ((val) & 0x01FFFFFC)
> +#define DMA_LENGTH(val)         ((val) & 0x01FFFFFF)
>   
>   /* Flash opcodes. */
>   #define SPI_OP_READ       0x03    /* Read data bytes (low frequency) */
> @@ -843,6 +847,24 @@ static bool aspeed_smc_inject_read_failure(AspeedSMCState *s)
>       }
>   }
>   
> +static uint32_t aspeed_smc_dma_len(AspeedSMCState *s)
> +{
> +    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
> +    uint32_t dma_len;
> +    uint32_t extra;
> +
> +    dma_len = s->regs[R_DMA_LEN] + asc->dma_start_length;
> +
> +    /* dma length 4 bytes aligned */
> +    extra = dma_len % 4;
> +
> +    if (extra != 0) {
> +        dma_len += 4 - extra;
> +    }
> +
> +    return dma_len;
> +}
> +
>   /*
>    * Accumulate the result of the reads to provide a checksum that will
>    * be used to validate the read timing settings.
> @@ -850,6 +872,7 @@ static bool aspeed_smc_inject_read_failure(AspeedSMCState *s)
>   static void aspeed_smc_dma_checksum(AspeedSMCState *s)
>   {
>       MemTxResult result;
> +    uint32_t dma_len;
>       uint32_t data;
>   
>       if (s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE) {
> @@ -861,7 +884,9 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
>           aspeed_smc_dma_calibration(s);
>       }
>   
> -    while (s->regs[R_DMA_LEN]) {
> +    dma_len = aspeed_smc_dma_len(s);
> +
> +    while (dma_len) {
>           data = address_space_ldl_le(&s->flash_as, s->regs[R_DMA_FLASH_ADDR],
>                                       MEMTXATTRS_UNSPECIFIED, &result);
>           if (result != MEMTX_OK) {
> @@ -877,7 +902,8 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
>            */
>           s->regs[R_DMA_CHECKSUM] += data;
>           s->regs[R_DMA_FLASH_ADDR] += 4;
> -        s->regs[R_DMA_LEN] -= 4;
> +        dma_len -= 4;
> +        s->regs[R_DMA_LEN] = dma_len;
>       }
>   
>       if (s->inject_failure && aspeed_smc_inject_read_failure(s)) {
> @@ -889,14 +915,17 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
>   static void aspeed_smc_dma_rw(AspeedSMCState *s)
>   {
>       MemTxResult result;
> +    uint32_t dma_len;
>       uint32_t data;
>   
> +    dma_len = aspeed_smc_dma_len(s);
> +
>       trace_aspeed_smc_dma_rw(s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE ?
>                               "write" : "read",
>                               s->regs[R_DMA_FLASH_ADDR],
>                               s->regs[R_DMA_DRAM_ADDR],
> -                            s->regs[R_DMA_LEN]);
> -    while (s->regs[R_DMA_LEN]) {
> +                            dma_len);
> +    while (dma_len) {
>           if (s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE) {
>               data = address_space_ldl_le(&s->dram_as, s->regs[R_DMA_DRAM_ADDR],
>                                           MEMTXATTRS_UNSPECIFIED, &result);
> @@ -937,7 +966,8 @@ static void aspeed_smc_dma_rw(AspeedSMCState *s)
>            */
>           s->regs[R_DMA_FLASH_ADDR] += 4;
>           s->regs[R_DMA_DRAM_ADDR] += 4;
> -        s->regs[R_DMA_LEN] -= 4;
> +        dma_len -= 4;
> +        s->regs[R_DMA_LEN] = dma_len;
>           s->regs[R_DMA_CHECKSUM] += data;
>       }
>   }
> @@ -1381,6 +1411,7 @@ static void aspeed_2400_fmc_class_init(ObjectClass *klass, void *data)
>       asc->features          = ASPEED_SMC_FEATURE_DMA;
>       asc->dma_flash_mask    = 0x0FFFFFFC;
>       asc->dma_dram_mask     = 0x1FFFFFFC;
> +    asc->dma_start_length  = 4;
>       asc->nregs             = ASPEED_SMC_R_MAX;
>       asc->segment_to_reg    = aspeed_smc_segment_to_reg;
>       asc->reg_to_segment    = aspeed_smc_reg_to_segment;
> @@ -1464,6 +1495,7 @@ static void aspeed_2500_fmc_class_init(ObjectClass *klass, void *data)
>       asc->features          = ASPEED_SMC_FEATURE_DMA;
>       asc->dma_flash_mask    = 0x0FFFFFFC;
>       asc->dma_dram_mask     = 0x3FFFFFFC;
> +    asc->dma_start_length  = 4;
>       asc->nregs             = ASPEED_SMC_R_MAX;
>       asc->segment_to_reg    = aspeed_smc_segment_to_reg;
>       asc->reg_to_segment    = aspeed_smc_reg_to_segment;
> @@ -1620,6 +1652,7 @@ static void aspeed_2600_fmc_class_init(ObjectClass *klass, void *data)
>                                ASPEED_SMC_FEATURE_WDT_CONTROL;
>       asc->dma_flash_mask    = 0x0FFFFFFC;
>       asc->dma_dram_mask     = 0x3FFFFFFC;
> +    asc->dma_start_length  = 1;
>       asc->nregs             = ASPEED_SMC_R_MAX;
>       asc->segment_to_reg    = aspeed_2600_smc_segment_to_reg;
>       asc->reg_to_segment    = aspeed_2600_smc_reg_to_segment;
> @@ -1658,6 +1691,7 @@ static void aspeed_2600_spi1_class_init(ObjectClass *klass, void *data)
>                                ASPEED_SMC_FEATURE_DMA_GRANT;
>       asc->dma_flash_mask    = 0x0FFFFFFC;
>       asc->dma_dram_mask     = 0x3FFFFFFC;
> +    asc->dma_start_length  = 1;
>       asc->nregs             = ASPEED_SMC_R_MAX;
>       asc->segment_to_reg    = aspeed_2600_smc_segment_to_reg;
>       asc->reg_to_segment    = aspeed_2600_smc_reg_to_segment;
> @@ -1697,6 +1731,7 @@ static void aspeed_2600_spi2_class_init(ObjectClass *klass, void *data)
>                                ASPEED_SMC_FEATURE_DMA_GRANT;
>       asc->dma_flash_mask    = 0x0FFFFFFC;
>       asc->dma_dram_mask     = 0x3FFFFFFC;
> +    asc->dma_start_length  = 1;
>       asc->nregs             = ASPEED_SMC_R_MAX;
>       asc->segment_to_reg    = aspeed_2600_smc_segment_to_reg;
>       asc->reg_to_segment    = aspeed_2600_smc_reg_to_segment;
> @@ -1778,6 +1813,7 @@ static void aspeed_1030_fmc_class_init(ObjectClass *klass, void *data)
>       asc->features          = ASPEED_SMC_FEATURE_DMA;
>       asc->dma_flash_mask    = 0x0FFFFFFC;
>       asc->dma_dram_mask     = 0x000BFFFC;
> +    asc->dma_start_length  = 1;
>       asc->nregs             = ASPEED_SMC_R_MAX;
>       asc->segment_to_reg    = aspeed_1030_smc_segment_to_reg;
>       asc->reg_to_segment    = aspeed_1030_smc_reg_to_segment;
> @@ -1815,6 +1851,7 @@ static void aspeed_1030_spi1_class_init(ObjectClass *klass, void *data)
>       asc->features          = ASPEED_SMC_FEATURE_DMA;
>       asc->dma_flash_mask    = 0x0FFFFFFC;
>       asc->dma_dram_mask     = 0x000BFFFC;
> +    asc->dma_start_length  = 1;
>       asc->nregs             = ASPEED_SMC_R_MAX;
>       asc->segment_to_reg    = aspeed_2600_smc_segment_to_reg;
>       asc->reg_to_segment    = aspeed_2600_smc_reg_to_segment;
> @@ -1851,6 +1888,7 @@ static void aspeed_1030_spi2_class_init(ObjectClass *klass, void *data)
>       asc->features          = ASPEED_SMC_FEATURE_DMA;
>       asc->dma_flash_mask    = 0x0FFFFFFC;
>       asc->dma_dram_mask     = 0x000BFFFC;
> +    asc->dma_start_length  = 1;
>       asc->nregs             = ASPEED_SMC_R_MAX;
>       asc->segment_to_reg    = aspeed_2600_smc_segment_to_reg;
>       asc->reg_to_segment    = aspeed_2600_smc_reg_to_segment;
> diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h
> index 8e1dda556b..f359ed22cc 100644
> --- a/include/hw/ssi/aspeed_smc.h
> +++ b/include/hw/ssi/aspeed_smc.h
> @@ -106,6 +106,7 @@ struct AspeedSMCClass {
>       uint32_t features;
>       hwaddr dma_flash_mask;
>       hwaddr dma_dram_mask;
> +    uint32_t dma_start_length;
>       uint32_t nregs;
>       uint32_t (*segment_to_reg)(const AspeedSMCState *s,
>                                  const AspeedSegments *seg);



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 07/16] aspeed/smc: fix dma moving incorrect data length issue
  2024-04-19 13:41   ` Cédric Le Goater
@ 2024-04-30  7:22     ` Cédric Le Goater
  2024-04-30  8:51       ` Jamin Lin
  0 siblings, 1 reply; 42+ messages in thread
From: Cédric Le Goater @ 2024-04-30  7:22 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	Alistair Francis, Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: troy_lee, yunlin.tang

On 4/19/24 15:41, Cédric Le Goater wrote:
> On 4/16/24 11:18, Jamin Lin wrote:
>> DMA length is from 1 byte to 32MB for AST2600 and AST10x0
>> and DMA length is from 4 bytes to 32MB for AST2500.
>>
>> In other words, if "R_DMA_LEN" is 0, it should move at least 1 byte
>> data for AST2600 and AST10x0 and 4 bytes data for AST2500.
>>> To support all ASPEED SOCs, adds dma_start_length parameter to store
>> the start length, add helper routines function to compute the dma length
>> and update DMA_LENGTH mask to "1FFFFFF" to fix dma moving
>> incorrect data length issue.
> 
> OK. There are two problems to address, the "zero" length transfer and
> the DMA length unit, which is missing today. Newer SoC use a 1 bit / byte
> and older ones, AST2400 and AST2500, use 1 bit / 4 bytes.
> 
> We can introduce a AspeedSMCClass::dma_len_unit and rework the loop to :
> 
>      do {
> 
>        ....
> 
>         if (s->regs[R_DMA_LEN]) {
>              s->regs[R_DMA_LEN] -= 4 / asc->dma_len_unit;
>          }
>      } while (s->regs[R_DMA_LEN]);
> 
> It should fix the current implementation.


I checked what FW is doing on a QEMU ast2500-evb machine :
  
     U-Boot 2019.04-v00.04.12 (Sep 29 2022 - 10:40:37 +0000)
     ...
     
        Loading Kernel Image ... aspeed_smc_write @0x88 size 4: 0x80001000
     aspeed_smc_write @0x84 size 4: 0x20100130
     aspeed_smc_write @0x8c size 4: 0x3c6770
     aspeed_smc_write @0x80 size 4: 0x1
     aspeed_smc_dma_rw read flash:@0x00100130 dram:@0x1000 size:0x003c6774
     aspeed_smc_read @0x8 size 4: 0x800
     aspeed_smc_write @0x80 size 4: 0x0
     OK
        Loading Ramdisk to 8fef2000, end 8ffff604 ... aspeed_smc_write @0x88 size 4: 0x8fef2000
     aspeed_smc_write @0x84 size 4: 0x204cdde0
     aspeed_smc_write @0x8c size 4: 0x10d604
     aspeed_smc_write @0x80 size 4: 0x1
     aspeed_smc_dma_rw read flash:@0x004cdde0 dram:@0xfef2000 size:0x0010d608
     aspeed_smc_read @0x8 size 4: 0x800
     aspeed_smc_write @0x80 size 4: 0x0
     OK
        Loading Device Tree to 8fee7000, end 8fef135e ... aspeed_smc_write @0x88 size 4: 0x8fee7000
     aspeed_smc_write @0x84 size 4: 0x204c69b4
     aspeed_smc_write @0x8c size 4: 0x7360
     aspeed_smc_write @0x80 size 4: 0x1
     aspeed_smc_dma_rw read flash:@0x004c69b4 dram:@0xfee7000 size:0x00007364
     aspeed_smc_read @0x8 size 4: 0x800
     aspeed_smc_write @0x80 size 4: 0x0
     OK
     
     Starting kernel ...
     
It seems that the R_DMA_LEN register is set by FW without taking
into account the length unit ( bit / 4 bytes). Would you know why ?

If I change the model to match 1 bit / 4 bytes unit of the R_DMA_LEN
register. Linux fails to boot. I didn't dig further and this is
something we need to understand before committing.

> I don't think this is necessary to add a Fixes tag because the problem
> has been there for ages and no one reported it. Probably because the
> only place DMA transfers are used is in U-Boot and transfers have a
> non-zero length.
> 
>> Currently, only supports dma length 4 bytes aligned.

Is this 4 bytes alignment new for the AST2700 or is this something
you added because the mask of DMA_LENGTH is now relaxed to match
all addresses ?

#define DMA_LENGTH(val)         ((val) & 0x01FFFFFF)

Thanks,

C.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 08/16] aspeed/smc: support 64 bits dma dram address
  2024-04-19  6:00     ` Jamin Lin
@ 2024-04-30  7:26       ` Cédric Le Goater
  2024-04-30  7:56         ` Jamin Lin
  0 siblings, 1 reply; 42+ messages in thread
From: Cédric Le Goater @ 2024-04-30  7:26 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	Alistair Francis, Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: Troy Lee, Yunlin Tang

On 4/19/24 08:00, Jamin Lin wrote:
> Hi Cedric,
>>
>> Hello Jamin,
>>
>> On 4/16/24 11:18, Jamin Lin wrote:
>>> AST2700 support the maximum dram size is 8GiB and has a "DMA DRAM
>> Side
>>> Address High Part(0x7C)"
>>> register to support 64 bits dma dram address.
>>> Add helper routines functions to compute the dma dram address, new
>>> features and update trace-event to support 64 bits dram address.
>>>
>>> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
>>> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
>>> ---
>>>    hw/ssi/aspeed_smc.c | 66
>> +++++++++++++++++++++++++++++++++++++++------
>>>    hw/ssi/trace-events |  2 +-
>>>    2 files changed, 59 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index
>>> 71abc7a2d8..a67cac3d0f 100644
>>> --- a/hw/ssi/aspeed_smc.c
>>> +++ b/hw/ssi/aspeed_smc.c
>>> @@ -132,6 +132,9 @@
>>>    #define   FMC_WDT2_CTRL_BOOT_SOURCE      BIT(4) /* O: primary
>> 1: alternate */
>>>    #define   FMC_WDT2_CTRL_EN               BIT(0)
>>>
>>> +/* DMA DRAM Side Address High Part (AST2700) */
>>> +#define R_DMA_DRAM_ADDR_HIGH   (0x7c / 4)
>>> +
>>>    /* DMA Control/Status Register */
>>>    #define R_DMA_CTRL        (0x80 / 4)
>>>    #define   DMA_CTRL_REQUEST      (1 << 31)
>>> @@ -187,6 +190,7 @@
>>>     *   0x1FFFFFF: 32M bytes
>>>     */
>>>    #define DMA_DRAM_ADDR(asc, val)   ((val) & (asc)->dma_dram_mask)
>>> +#define DMA_DRAM_ADDR_HIGH(val)   ((val) & 0xf)
>>>    #define DMA_FLASH_ADDR(asc, val)  ((val) & (asc)->dma_flash_mask)
>>>    #define DMA_LENGTH(val)         ((val) & 0x01FFFFFF)
>>>
>>> @@ -207,6 +211,7 @@ static const AspeedSegments
>> aspeed_2500_spi2_segments[];
>>>    #define ASPEED_SMC_FEATURE_DMA       0x1
>>>    #define ASPEED_SMC_FEATURE_DMA_GRANT 0x2
>>>    #define ASPEED_SMC_FEATURE_WDT_CONTROL 0x4
>>> +#define ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH 0x08
>>>
>>>    static inline bool aspeed_smc_has_dma(const AspeedSMCClass *asc)
>>>    {
>>> @@ -218,6 +223,11 @@ static inline bool
>> aspeed_smc_has_wdt_control(const AspeedSMCClass *asc)
>>>        return !!(asc->features & ASPEED_SMC_FEATURE_WDT_CONTROL);
>>>    }
>>>
>>> +static inline bool aspeed_smc_has_dma_dram_addr_high(const
>>> +AspeedSMCClass *asc)
>>
>> To ease the reading, I would call the helper aspeed_smc_has_dma64()
> Will fix it
>>
>>> +{
>>> +    return !!(asc->features &
>> ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH);
>>> +}
>>> +
>>>    #define aspeed_smc_error(fmt, ...)
>> \
>>>        qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt "\n", __func__, ##
>>> __VA_ARGS__)
>>>
>>> @@ -747,6 +757,9 @@ static uint64_t aspeed_smc_read(void *opaque,
>> hwaddr addr, unsigned int size)
>>>            (aspeed_smc_has_dma(asc) && addr == R_DMA_CTRL) ||
>>>            (aspeed_smc_has_dma(asc) && addr == R_DMA_FLASH_ADDR)
>> ||
>>>            (aspeed_smc_has_dma(asc) && addr == R_DMA_DRAM_ADDR)
>> ||
>>> +        (aspeed_smc_has_dma(asc) &&
>>> +         aspeed_smc_has_dma_dram_addr_high(asc) &&
>>> +         addr == R_DMA_DRAM_ADDR_HIGH) ||
>>>            (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN) ||
>>>            (aspeed_smc_has_dma(asc) && addr == R_DMA_CHECKSUM)
>> ||
>>>            (addr >= R_SEG_ADDR0 &&
>>> @@ -847,6 +860,23 @@ static bool
>> aspeed_smc_inject_read_failure(AspeedSMCState *s)
>>>        }
>>>    }
>>>
>>> +static uint64_t aspeed_smc_dma_dram_addr(AspeedSMCState *s) {
>>> +    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
>>> +    uint64_t dram_addr_high;
>>> +    uint64_t dma_dram_addr;
>>> +
>>> +    if (aspeed_smc_has_dma_dram_addr_high(asc)) {
>>> +        dram_addr_high = s->regs[R_DMA_DRAM_ADDR_HIGH];
>>> +        dram_addr_high <<= 32;
>>> +        dma_dram_addr = dram_addr_high |
>> s->regs[R_DMA_DRAM_ADDR];
>>
>> Here is a proposal to shorten the routine :
>>
>>           return ((uint64_t) s->regs[R_DMA_DRAM_ADDR_HIGH] << 32) |
>>               s->regs[R_DMA_DRAM_ADDR];
>>
>>
>>> +    } else {
>>> +        dma_dram_addr = s->regs[R_DMA_DRAM_ADDR];
>>
>> and
>>           return s->regs[R_DMA_DRAM_ADDR];
>>
>>> +    }
>>> +
>>> +    return dma_dram_addr;
>>> +}
>>> +
> Thanks for your suggestion. Will fix.
>>>    static uint32_t aspeed_smc_dma_len(AspeedSMCState *s)
>>>    {
>>>        AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); @@ -914,24
>>> +944,34 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
>>>
>>>    static void aspeed_smc_dma_rw(AspeedSMCState *s)
>>>    {
>>> +    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
>>> +    uint64_t dram_addr_high;
>>
>> This variable doesn't look very useful
> Will try to remove it.
>>
>>> +    uint64_t dma_dram_addr;
>>> +    uint64_t dram_addr;
>>
>> and dram_addr is redundant with dma_dram_addr. Please use only one.
> Please see my below description and please give us any suggestion.
>>
>>
>>>        MemTxResult result;
>>>        uint32_t dma_len;
>>>        uint32_t data;
>>>
>>>        dma_len = aspeed_smc_dma_len(s);
>>> +    dma_dram_addr = aspeed_smc_dma_dram_addr(s);
>>> +
>>> +    if (aspeed_smc_has_dma_dram_addr_high(asc)) {
>>> +        dram_addr = dma_dram_addr - s->dram_mr->container->addr;
>>
>> Why do you truncate the address again ? It should already be done with
>>
>> #define DMA_DRAM_ADDR_HIGH(val)   ((val) & 0xf)
>>
> The reason is that our firmware set the real address in SMC registers.
> For example: If users want to move data from flash to the DRAM at address 0,
> It set R_DMA_DRAM_ADDR_HIGH 4 and R_DMA_DRAM_ADDR 0 because the
> dram base address is 0x 4 00000000 for AST2700.


Could you please share the specs of the R_DMA_DRAM_ADDR and
R_DMA_DRAM_ADDR_HIGH registers to see what are the init values,
how these registers should be set, their alignment constraints
if any, how the values evolve while the HW does the DMA transactions,
etc.

Thanks,

C.





^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH v3 08/16] aspeed/smc: support 64 bits dma dram address
  2024-04-30  7:26       ` Cédric Le Goater
@ 2024-04-30  7:56         ` Jamin Lin
  2024-05-03 14:20           ` Cédric Le Goater
  0 siblings, 1 reply; 42+ messages in thread
From: Jamin Lin @ 2024-04-30  7:56 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: Troy Lee, Yunlin Tang

Hi Cedric,

> -----Original Message-----
> From: Cédric Le Goater <clg@kaod.org>
> Sent: Tuesday, April 30, 2024 3:26 PM
> To: Jamin Lin <jamin_lin@aspeedtech.com>; Peter Maydell
> <peter.maydell@linaro.org>; Andrew Jeffery <andrew@codeconstruct.com.au>;
> Joel Stanley <joel@jms.id.au>; Alistair Francis <alistair@alistair23.me>; Cleber
> Rosa <crosa@redhat.com>; Philippe Mathieu-Daudé <philmd@linaro.org>;
> Wainer dos Santos Moschetta <wainersm@redhat.com>; Beraldo Leal
> <bleal@redhat.com>; 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>; Yunlin Tang
> <yunlin.tang@aspeedtech.com>
> Subject: Re: [PATCH v3 08/16] aspeed/smc: support 64 bits dma dram address
> 
> On 4/19/24 08:00, Jamin Lin wrote:
> > Hi Cedric,
> >>
> >> Hello Jamin,
> >>
> >> On 4/16/24 11:18, Jamin Lin wrote:
> >>> AST2700 support the maximum dram size is 8GiB and has a "DMA DRAM
> >> Side
> >>> Address High Part(0x7C)"
> >>> register to support 64 bits dma dram address.
> >>> Add helper routines functions to compute the dma dram address, new
> >>> features and update trace-event to support 64 bits dram address.
> >>>
> >>> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> >>> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> >>> ---
> >>>    hw/ssi/aspeed_smc.c | 66
> >> +++++++++++++++++++++++++++++++++++++++------
> >>>    hw/ssi/trace-events |  2 +-
> >>>    2 files changed, 59 insertions(+), 9 deletions(-)
> >>>
> >>> diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index
> >>> 71abc7a2d8..a67cac3d0f 100644
> >>> --- a/hw/ssi/aspeed_smc.c
> >>> +++ b/hw/ssi/aspeed_smc.c
> >>> @@ -132,6 +132,9 @@
> >>>    #define   FMC_WDT2_CTRL_BOOT_SOURCE      BIT(4) /* O:
> primary
> >> 1: alternate */
> >>>    #define   FMC_WDT2_CTRL_EN               BIT(0)
> >>>
> >>> +/* DMA DRAM Side Address High Part (AST2700) */
> >>> +#define R_DMA_DRAM_ADDR_HIGH   (0x7c / 4)
> >>> +
> >>>    /* DMA Control/Status Register */
> >>>    #define R_DMA_CTRL        (0x80 / 4)
> >>>    #define   DMA_CTRL_REQUEST      (1 << 31)
> >>> @@ -187,6 +190,7 @@
> >>>     *   0x1FFFFFF: 32M bytes
> >>>     */
> >>>    #define DMA_DRAM_ADDR(asc, val)   ((val) &
> (asc)->dma_dram_mask)
> >>> +#define DMA_DRAM_ADDR_HIGH(val)   ((val) & 0xf)
> >>>    #define DMA_FLASH_ADDR(asc, val)  ((val) &
> (asc)->dma_flash_mask)
> >>>    #define DMA_LENGTH(val)         ((val) & 0x01FFFFFF)
> >>>
> >>> @@ -207,6 +211,7 @@ static const AspeedSegments
> >> aspeed_2500_spi2_segments[];
> >>>    #define ASPEED_SMC_FEATURE_DMA       0x1
> >>>    #define ASPEED_SMC_FEATURE_DMA_GRANT 0x2
> >>>    #define ASPEED_SMC_FEATURE_WDT_CONTROL 0x4
> >>> +#define ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH 0x08
> >>>
> >>>    static inline bool aspeed_smc_has_dma(const AspeedSMCClass *asc)
> >>>    {
> >>> @@ -218,6 +223,11 @@ static inline bool
> >> aspeed_smc_has_wdt_control(const AspeedSMCClass *asc)
> >>>        return !!(asc->features &
> ASPEED_SMC_FEATURE_WDT_CONTROL);
> >>>    }
> >>>
> >>> +static inline bool aspeed_smc_has_dma_dram_addr_high(const
> >>> +AspeedSMCClass *asc)
> >>
> >> To ease the reading, I would call the helper aspeed_smc_has_dma64()
> > Will fix it
> >>
> >>> +{
> >>> +    return !!(asc->features &
> >> ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH);
> >>> +}
> >>> +
> >>>    #define aspeed_smc_error(fmt, ...)
> >> \
> >>>        qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt "\n", __func__,
> ##
> >>> __VA_ARGS__)
> >>>
> >>> @@ -747,6 +757,9 @@ static uint64_t aspeed_smc_read(void *opaque,
> >> hwaddr addr, unsigned int size)
> >>>            (aspeed_smc_has_dma(asc) && addr == R_DMA_CTRL) ||
> >>>            (aspeed_smc_has_dma(asc) && addr ==
> R_DMA_FLASH_ADDR)
> >> ||
> >>>            (aspeed_smc_has_dma(asc) && addr ==
> R_DMA_DRAM_ADDR)
> >> ||
> >>> +        (aspeed_smc_has_dma(asc) &&
> >>> +         aspeed_smc_has_dma_dram_addr_high(asc) &&
> >>> +         addr == R_DMA_DRAM_ADDR_HIGH) ||
> >>>            (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN) ||
> >>>            (aspeed_smc_has_dma(asc) && addr ==
> R_DMA_CHECKSUM)
> >> ||
> >>>            (addr >= R_SEG_ADDR0 &&
> >>> @@ -847,6 +860,23 @@ static bool
> >> aspeed_smc_inject_read_failure(AspeedSMCState *s)
> >>>        }
> >>>    }
> >>>
> >>> +static uint64_t aspeed_smc_dma_dram_addr(AspeedSMCState *s) {
> >>> +    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
> >>> +    uint64_t dram_addr_high;
> >>> +    uint64_t dma_dram_addr;
> >>> +
> >>> +    if (aspeed_smc_has_dma_dram_addr_high(asc)) {
> >>> +        dram_addr_high = s->regs[R_DMA_DRAM_ADDR_HIGH];
> >>> +        dram_addr_high <<= 32;
> >>> +        dma_dram_addr = dram_addr_high |
> >> s->regs[R_DMA_DRAM_ADDR];
> >>
> >> Here is a proposal to shorten the routine :
> >>
> >>           return ((uint64_t) s->regs[R_DMA_DRAM_ADDR_HIGH] << 32)
> |
> >>               s->regs[R_DMA_DRAM_ADDR];
> >>
> >>
> >>> +    } else {
> >>> +        dma_dram_addr = s->regs[R_DMA_DRAM_ADDR];
> >>
> >> and
> >>           return s->regs[R_DMA_DRAM_ADDR];
> >>
> >>> +    }
> >>> +
> >>> +    return dma_dram_addr;
> >>> +}
> >>> +
> > Thanks for your suggestion. Will fix.
> >>>    static uint32_t aspeed_smc_dma_len(AspeedSMCState *s)
> >>>    {
> >>>        AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); @@
> -914,24
> >>> +944,34 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
> >>>
> >>>    static void aspeed_smc_dma_rw(AspeedSMCState *s)
> >>>    {
> >>> +    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
> >>> +    uint64_t dram_addr_high;
> >>
> >> This variable doesn't look very useful
> > Will try to remove it.
> >>
> >>> +    uint64_t dma_dram_addr;
> >>> +    uint64_t dram_addr;
> >>
> >> and dram_addr is redundant with dma_dram_addr. Please use only one.
> > Please see my below description and please give us any suggestion.
> >>
> >>
> >>>        MemTxResult result;
> >>>        uint32_t dma_len;
> >>>        uint32_t data;
> >>>
> >>>        dma_len = aspeed_smc_dma_len(s);
> >>> +    dma_dram_addr = aspeed_smc_dma_dram_addr(s);
> >>> +
> >>> +    if (aspeed_smc_has_dma_dram_addr_high(asc)) {
> >>> +        dram_addr = dma_dram_addr - s->dram_mr->container->addr;
> >>
> >> Why do you truncate the address again ? It should already be done
> >> with
> >>
> >> #define DMA_DRAM_ADDR_HIGH(val)   ((val) & 0xf)
> >>
> > The reason is that our firmware set the real address in SMC registers.
> > For example: If users want to move data from flash to the DRAM at
> > address 0, It set R_DMA_DRAM_ADDR_HIGH 4 and R_DMA_DRAM_ADDR 0
> because
> > the dram base address is 0x 4 00000000 for AST2700.
> 
> 
> Could you please share the specs of the R_DMA_DRAM_ADDR and
> R_DMA_DRAM_ADDR_HIGH registers to see what are the init values, how
> these registers should be set, their alignment constraints if any, how the values
> evolve while the HW does the DMA transactions, etc.
> 
DMA_DRAM_SIDE_ADDRESS 0x088 Init=0x00000000
31:0 RW DMA_RO
DRAM side start address
For DMA Read flash, this the destination address.
For DMA Write flash, the is the source address
DMA only execute on 4 bytes boundary
When read, it shows the current working address

DMA DRAM Side Address High Part 0x07c Init=0x00000000
32:8 RO reserved
7:0 RW DMA_RO_HI
      dma_ro[39:32]

Therefore, DMA address is dma_ro[39:0]

Our FW settings, 
In u-boot shell, execute the following command
cp.b 100220000 403000000 100
100220000 flash address for kernel fit image
403000000 dram address at offset 3000000
https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2023.10/lib/string.c#L553C8-L553C29
https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2023.10/arch/arm/mach-aspeed/ast2700/spi.c#L156 
https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2023.10/arch/arm/mach-aspeed/ast2700/spi.c#L179-L183 
Thanks-Jamin

> Thanks,
> 
> C.
> 
> 


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH v3 07/16] aspeed/smc: fix dma moving incorrect data length issue
  2024-04-30  7:22     ` Cédric Le Goater
@ 2024-04-30  8:51       ` Jamin Lin
  2024-05-03 14:35         ` Cédric Le Goater
  0 siblings, 1 reply; 42+ messages in thread
From: Jamin Lin @ 2024-04-30  8:51 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: Troy Lee, Yunlin Tang

Hi Cedric,
> On 4/19/24 15:41, Cédric Le Goater wrote:
> > On 4/16/24 11:18, Jamin Lin wrote:
> >> DMA length is from 1 byte to 32MB for AST2600 and AST10x0 and DMA
> >> length is from 4 bytes to 32MB for AST2500.
> >>
> >> In other words, if "R_DMA_LEN" is 0, it should move at least 1 byte
> >> data for AST2600 and AST10x0 and 4 bytes data for AST2500.
> >>> To support all ASPEED SOCs, adds dma_start_length parameter to store
> >> the start length, add helper routines function to compute the dma
> >> length and update DMA_LENGTH mask to "1FFFFFF" to fix dma moving
> >> incorrect data length issue.
> >
> > OK. There are two problems to address, the "zero" length transfer and
> > the DMA length unit, which is missing today. Newer SoC use a 1 bit /
> > byte and older ones, AST2400 and AST2500, use 1 bit / 4 bytes.
> >
> > We can introduce a AspeedSMCClass::dma_len_unit and rework the loop to :
> >
> >      do {
> >
> >        ....
> >
> >         if (s->regs[R_DMA_LEN]) {
> >              s->regs[R_DMA_LEN] -= 4 / asc->dma_len_unit;
> >          }
> >      } while (s->regs[R_DMA_LEN]);
> >
> > It should fix the current implementation.
> 
> 
> I checked what FW is doing on a QEMU ast2500-evb machine :
> 
>      U-Boot 2019.04-v00.04.12 (Sep 29 2022 - 10:40:37 +0000)
>      ...
> 
>         Loading Kernel Image ... aspeed_smc_write @0x88 size 4:
> 0x80001000
>      aspeed_smc_write @0x84 size 4: 0x20100130
>      aspeed_smc_write @0x8c size 4: 0x3c6770
>      aspeed_smc_write @0x80 size 4: 0x1
>      aspeed_smc_dma_rw read flash:@0x00100130 dram:@0x1000
> size:0x003c6774
>      aspeed_smc_read @0x8 size 4: 0x800
>      aspeed_smc_write @0x80 size 4: 0x0
>      OK
>         Loading Ramdisk to 8fef2000, end 8ffff604 ... aspeed_smc_write
> @0x88 size 4: 0x8fef2000
>      aspeed_smc_write @0x84 size 4: 0x204cdde0
>      aspeed_smc_write @0x8c size 4: 0x10d604
>      aspeed_smc_write @0x80 size 4: 0x1
>      aspeed_smc_dma_rw read flash:@0x004cdde0 dram:@0xfef2000
> size:0x0010d608
>      aspeed_smc_read @0x8 size 4: 0x800
>      aspeed_smc_write @0x80 size 4: 0x0
>      OK
>         Loading Device Tree to 8fee7000, end 8fef135e ... aspeed_smc_write
> @0x88 size 4: 0x8fee7000
>      aspeed_smc_write @0x84 size 4: 0x204c69b4
>      aspeed_smc_write @0x8c size 4: 0x7360
>      aspeed_smc_write @0x80 size 4: 0x1
>      aspeed_smc_dma_rw read flash:@0x004c69b4 dram:@0xfee7000
> size:0x00007364
>      aspeed_smc_read @0x8 size 4: 0x800
>      aspeed_smc_write @0x80 size 4: 0x0
>      OK
> 
>      Starting kernel ...
> 
> It seems that the R_DMA_LEN register is set by FW without taking into account
> the length unit ( bit / 4 bytes). Would you know why ?
> 
https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2019.04/lib/string.c#L559
This line make user input data length 4 bytes alignment.
https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2019.04/arch/arm/mach-aspeed/ast2500/utils.S#L35
This line set the value of count parameter to AST_FMC_DNA_LENGTH.
AST_FMC_DMA_LENGTH is 4 bytes alignment value.
Example: input 4
((4+3)/4) * 4 --> (7/4) *4 ---> 4
If AST_FMC_DMA_LENGTH is 0, it means it should move 4 bytes data and AST_FMC_DMA_LENGTH do not need to be divided by 4. 

> If I change the model to match 1 bit / 4 bytes unit of the R_DMA_LEN register.
> Linux fails to boot. I didn't dig further and this is something we need to
> understand before committing.
> 
> > I don't think this is necessary to add a Fixes tag because the problem
> > has been there for ages and no one reported it. Probably because the
> > only place DMA transfers are used is in U-Boot and transfers have a
> > non-zero length.
> >
> >> Currently, only supports dma length 4 bytes aligned.
> 
> Is this 4 bytes alignment new for the AST2700 or is this something you added
> because the mask of DMA_LENGTH is now relaxed to match all addresses ?
> 
> #define DMA_LENGTH(val)         ((val) & 0x01FFFFFF)
AST2700, AST2600 and AST1030 is from 1 byte to 1FFFFFF, so I change this Micro to fix data lost.
https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2023.10/arch/arm/mach-aspeed/ast2700/spi.c#L186
Please see this line, it decrease dma_len 1 byte first then, set to DMA_LEN register because DMA_LEN is 0 which means should move 1 byte data if DMA enables for AST2600, AST1030 and AST2700. 
> 
> Thanks,
> 
> C.

Only AST2500 need 4 bytes alignment for DMA Length. However, according to the design of sapped_smc_dma_rw function,
it utilizes address_space_stl_le API and it only works data 4 bytes alignment. https://github.com/qemu/qemu/blob/master/hw/ssi/aspeed_smc.c#L889 
For example,
If users want to move 0x101 data_length, after 0x100 data has been moved and remains 1 byte data need to be moved.
Please see this line program, https://github.com/qemu/qemu/blob/master/hw/ssi/aspeed_smc.c#L940
```
s->regs[R_DMA_LEN] -= 4;
```
The value of s->regs[R_DMA_LEN] becomes 0xffffffffXX because it is uint32_t data type and this while loop run in the unexpected behavior, https://github.com/qemu/qemu/blob/master/hw/ssi/aspeed_smc.c#L864
That was, why I set 4bytes alignment for all models.



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 08/16] aspeed/smc: support 64 bits dma dram address
  2024-04-30  7:56         ` Jamin Lin
@ 2024-05-03 14:20           ` Cédric Le Goater
  2024-05-15  8:56             ` Jamin Lin
  0 siblings, 1 reply; 42+ messages in thread
From: Cédric Le Goater @ 2024-05-03 14:20 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	Alistair Francis, Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: Troy Lee, Yunlin Tang

Hello Jamin,

On 4/30/24 09:56, Jamin Lin wrote:
> Hi Cedric,
> 
>> -----Original Message-----
>> From: Cédric Le Goater <clg@kaod.org>
>> Sent: Tuesday, April 30, 2024 3:26 PM
>> To: Jamin Lin <jamin_lin@aspeedtech.com>; Peter Maydell
>> <peter.maydell@linaro.org>; Andrew Jeffery <andrew@codeconstruct.com.au>;
>> Joel Stanley <joel@jms.id.au>; Alistair Francis <alistair@alistair23.me>; Cleber
>> Rosa <crosa@redhat.com>; Philippe Mathieu-Daudé <philmd@linaro.org>;
>> Wainer dos Santos Moschetta <wainersm@redhat.com>; Beraldo Leal
>> <bleal@redhat.com>; 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>; Yunlin Tang
>> <yunlin.tang@aspeedtech.com>
>> Subject: Re: [PATCH v3 08/16] aspeed/smc: support 64 bits dma dram address
>>
>> On 4/19/24 08:00, Jamin Lin wrote:
>>> Hi Cedric,
>>>>
>>>> Hello Jamin,
>>>>
>>>> On 4/16/24 11:18, Jamin Lin wrote:
>>>>> AST2700 support the maximum dram size is 8GiB and has a "DMA DRAM
>>>> Side
>>>>> Address High Part(0x7C)"
>>>>> register to support 64 bits dma dram address.
>>>>> Add helper routines functions to compute the dma dram address, new
>>>>> features and update trace-event to support 64 bits dram address.
>>>>>
>>>>> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
>>>>> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
>>>>> ---
>>>>>     hw/ssi/aspeed_smc.c | 66
>>>> +++++++++++++++++++++++++++++++++++++++------
>>>>>     hw/ssi/trace-events |  2 +-
>>>>>     2 files changed, 59 insertions(+), 9 deletions(-)
>>>>>
>>>>> diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index
>>>>> 71abc7a2d8..a67cac3d0f 100644
>>>>> --- a/hw/ssi/aspeed_smc.c
>>>>> +++ b/hw/ssi/aspeed_smc.c
>>>>> @@ -132,6 +132,9 @@
>>>>>     #define   FMC_WDT2_CTRL_BOOT_SOURCE      BIT(4) /* O:
>> primary
>>>> 1: alternate */
>>>>>     #define   FMC_WDT2_CTRL_EN               BIT(0)
>>>>>
>>>>> +/* DMA DRAM Side Address High Part (AST2700) */
>>>>> +#define R_DMA_DRAM_ADDR_HIGH   (0x7c / 4)
>>>>> +
>>>>>     /* DMA Control/Status Register */
>>>>>     #define R_DMA_CTRL        (0x80 / 4)
>>>>>     #define   DMA_CTRL_REQUEST      (1 << 31)
>>>>> @@ -187,6 +190,7 @@
>>>>>      *   0x1FFFFFF: 32M bytes
>>>>>      */
>>>>>     #define DMA_DRAM_ADDR(asc, val)   ((val) &
>> (asc)->dma_dram_mask)
>>>>> +#define DMA_DRAM_ADDR_HIGH(val)   ((val) & 0xf)
>>>>>     #define DMA_FLASH_ADDR(asc, val)  ((val) &
>> (asc)->dma_flash_mask)
>>>>>     #define DMA_LENGTH(val)         ((val) & 0x01FFFFFF)
>>>>>
>>>>> @@ -207,6 +211,7 @@ static const AspeedSegments
>>>> aspeed_2500_spi2_segments[];
>>>>>     #define ASPEED_SMC_FEATURE_DMA       0x1
>>>>>     #define ASPEED_SMC_FEATURE_DMA_GRANT 0x2
>>>>>     #define ASPEED_SMC_FEATURE_WDT_CONTROL 0x4
>>>>> +#define ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH 0x08
>>>>>
>>>>>     static inline bool aspeed_smc_has_dma(const AspeedSMCClass *asc)
>>>>>     {
>>>>> @@ -218,6 +223,11 @@ static inline bool
>>>> aspeed_smc_has_wdt_control(const AspeedSMCClass *asc)
>>>>>         return !!(asc->features &
>> ASPEED_SMC_FEATURE_WDT_CONTROL);
>>>>>     }
>>>>>
>>>>> +static inline bool aspeed_smc_has_dma_dram_addr_high(const
>>>>> +AspeedSMCClass *asc)
>>>>
>>>> To ease the reading, I would call the helper aspeed_smc_has_dma64()
>>> Will fix it
>>>>
>>>>> +{
>>>>> +    return !!(asc->features &
>>>> ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH);
>>>>> +}
>>>>> +
>>>>>     #define aspeed_smc_error(fmt, ...)
>>>> \
>>>>>         qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt "\n", __func__,
>> ##
>>>>> __VA_ARGS__)
>>>>>
>>>>> @@ -747,6 +757,9 @@ static uint64_t aspeed_smc_read(void *opaque,
>>>> hwaddr addr, unsigned int size)
>>>>>             (aspeed_smc_has_dma(asc) && addr == R_DMA_CTRL) ||
>>>>>             (aspeed_smc_has_dma(asc) && addr ==
>> R_DMA_FLASH_ADDR)
>>>> ||
>>>>>             (aspeed_smc_has_dma(asc) && addr ==
>> R_DMA_DRAM_ADDR)
>>>> ||
>>>>> +        (aspeed_smc_has_dma(asc) &&
>>>>> +         aspeed_smc_has_dma_dram_addr_high(asc) &&
>>>>> +         addr == R_DMA_DRAM_ADDR_HIGH) ||
>>>>>             (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN) ||
>>>>>             (aspeed_smc_has_dma(asc) && addr ==
>> R_DMA_CHECKSUM)
>>>> ||
>>>>>             (addr >= R_SEG_ADDR0 &&
>>>>> @@ -847,6 +860,23 @@ static bool
>>>> aspeed_smc_inject_read_failure(AspeedSMCState *s)
>>>>>         }
>>>>>     }
>>>>>
>>>>> +static uint64_t aspeed_smc_dma_dram_addr(AspeedSMCState *s) {
>>>>> +    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
>>>>> +    uint64_t dram_addr_high;
>>>>> +    uint64_t dma_dram_addr;
>>>>> +
>>>>> +    if (aspeed_smc_has_dma_dram_addr_high(asc)) {
>>>>> +        dram_addr_high = s->regs[R_DMA_DRAM_ADDR_HIGH];
>>>>> +        dram_addr_high <<= 32;
>>>>> +        dma_dram_addr = dram_addr_high |
>>>> s->regs[R_DMA_DRAM_ADDR];
>>>>
>>>> Here is a proposal to shorten the routine :
>>>>
>>>>            return ((uint64_t) s->regs[R_DMA_DRAM_ADDR_HIGH] << 32)
>> |
>>>>                s->regs[R_DMA_DRAM_ADDR];
>>>>
>>>>
>>>>> +    } else {
>>>>> +        dma_dram_addr = s->regs[R_DMA_DRAM_ADDR];
>>>>
>>>> and
>>>>            return s->regs[R_DMA_DRAM_ADDR];
>>>>
>>>>> +    }
>>>>> +
>>>>> +    return dma_dram_addr;
>>>>> +}
>>>>> +
>>> Thanks for your suggestion. Will fix.
>>>>>     static uint32_t aspeed_smc_dma_len(AspeedSMCState *s)
>>>>>     {
>>>>>         AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); @@
>> -914,24
>>>>> +944,34 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
>>>>>
>>>>>     static void aspeed_smc_dma_rw(AspeedSMCState *s)
>>>>>     {
>>>>> +    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
>>>>> +    uint64_t dram_addr_high;
>>>>
>>>> This variable doesn't look very useful
>>> Will try to remove it.
>>>>
>>>>> +    uint64_t dma_dram_addr;
>>>>> +    uint64_t dram_addr;
>>>>
>>>> and dram_addr is redundant with dma_dram_addr. Please use only one.
>>> Please see my below description and please give us any suggestion.
>>>>
>>>>
>>>>>         MemTxResult result;
>>>>>         uint32_t dma_len;
>>>>>         uint32_t data;
>>>>>
>>>>>         dma_len = aspeed_smc_dma_len(s);
>>>>> +    dma_dram_addr = aspeed_smc_dma_dram_addr(s);
>>>>> +
>>>>> +    if (aspeed_smc_has_dma_dram_addr_high(asc)) {
>>>>> +        dram_addr = dma_dram_addr - s->dram_mr->container->addr;
>>>>
>>>> Why do you truncate the address again ? It should already be done
>>>> with
>>>>
>>>> #define DMA_DRAM_ADDR_HIGH(val)   ((val) & 0xf)
>>>>
>>> The reason is that our firmware set the real address in SMC registers.
>>> For example: If users want to move data from flash to the DRAM at
>>> address 0, It set R_DMA_DRAM_ADDR_HIGH 4 and R_DMA_DRAM_ADDR 0
>> because
>>> the dram base address is 0x 4 00000000 for AST2700.
>>
>>
>> Could you please share the specs of the R_DMA_DRAM_ADDR and
>> R_DMA_DRAM_ADDR_HIGH registers to see what are the init values, how
>> these registers should be set, their alignment constraints if any, how the values
>> evolve while the HW does the DMA transactions, etc.
>>
> DMA_DRAM_SIDE_ADDRESS 0x088 Init=0x00000000
> 31:0 RW DMA_RO
> DRAM side start address
> For DMA Read flash, this the destination address.
> For DMA Write flash, the is the source address
> DMA only execute on 4 bytes boundary
> When read, it shows the current working address
> 
> DMA DRAM Side Address High Part 0x07c Init=0x00000000
> 32:8 RO reserved
> 7:0 RW DMA_RO_HI
>        dma_ro[39:32]
> 
> Therefore, DMA address is dma_ro[39:0]

Thanks for the info. It seems that there are no alignment constraints.
I am surprised that there are no limits for the length in the specs.
It's 32MB right ?
  
Previous SoCs hardwire the high bits of the address where DRAM is mapped
in the DMA DRAM address reg. This is why the DRAM container was introduced,
so that HW units doing DMAs, like SMC, didn't have to manipulate real
physical addresses and offsets could be used instead. AST2700 HW interface
is different.

We can't use 's->dram_mr->container->addr' directly and I would like to
avoid passing 'sc->memmap[ASPEED_DEV_SDRAM]' as a property to the model.
Also, I was hoping that we didn't have to update the high part of the
address in the 0x07c reg. It seems we have to.

  
> 
> Our FW settings,
> In u-boot shell, execute the following command
> cp.b 100220000 403000000 100
> 100220000 flash address for kernel fit image
> 403000000 dram address at offset 3000000
> https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2023.10/lib/string.c#L553C8-L553C29
> https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2023.10/arch/arm/mach-aspeed/ast2700/spi.c#L156

So, U-Boot simply hardcodes the DRAM high bits

			if (dma_dest >= ASPEED_DRAM_BASE)
				writel(0x4, (void *)DRAM_HI_ADDR);

The fallback plan would simply be to ignore the high bits of the DMA
DRAM address. It should work today. Let me think about it more.

Thanks,

C.




> https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2023.10/arch/arm/mach-aspeed/ast2700/spi.c#L179-L183
> Thanks-Jamin
> 
>> Thanks,
>>
>> C.
>>
>>
> 



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 07/16] aspeed/smc: fix dma moving incorrect data length issue
  2024-04-30  8:51       ` Jamin Lin
@ 2024-05-03 14:35         ` Cédric Le Goater
  2024-05-15  4:05           ` Jamin Lin
  0 siblings, 1 reply; 42+ messages in thread
From: Cédric Le Goater @ 2024-05-03 14:35 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	Alistair Francis, Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: Troy Lee, Yunlin Tang

On 4/30/24 10:51, Jamin Lin wrote:
> Hi Cedric,
>> On 4/19/24 15:41, Cédric Le Goater wrote:
>>> On 4/16/24 11:18, Jamin Lin wrote:
>>>> DMA length is from 1 byte to 32MB for AST2600 and AST10x0 and DMA
>>>> length is from 4 bytes to 32MB for AST2500.
>>>>
>>>> In other words, if "R_DMA_LEN" is 0, it should move at least 1 byte
>>>> data for AST2600 and AST10x0 and 4 bytes data for AST2500.
>>>>> To support all ASPEED SOCs, adds dma_start_length parameter to store
>>>> the start length, add helper routines function to compute the dma
>>>> length and update DMA_LENGTH mask to "1FFFFFF" to fix dma moving
>>>> incorrect data length issue.
>>>
>>> OK. There are two problems to address, the "zero" length transfer and
>>> the DMA length unit, which is missing today. Newer SoC use a 1 bit /
>>> byte and older ones, AST2400 and AST2500, use 1 bit / 4 bytes.
>>>
>>> We can introduce a AspeedSMCClass::dma_len_unit and rework the loop to :
>>>
>>>       do {
>>>
>>>         ....
>>>
>>>          if (s->regs[R_DMA_LEN]) {
>>>               s->regs[R_DMA_LEN] -= 4 / asc->dma_len_unit;
>>>           }
>>>       } while (s->regs[R_DMA_LEN]);
>>>
>>> It should fix the current implementation.
>>
>>
>> I checked what FW is doing on a QEMU ast2500-evb machine :
>>
>>       U-Boot 2019.04-v00.04.12 (Sep 29 2022 - 10:40:37 +0000)
>>       ...
>>
>>          Loading Kernel Image ... aspeed_smc_write @0x88 size 4:
>> 0x80001000
>>       aspeed_smc_write @0x84 size 4: 0x20100130
>>       aspeed_smc_write @0x8c size 4: 0x3c6770
>>       aspeed_smc_write @0x80 size 4: 0x1
>>       aspeed_smc_dma_rw read flash:@0x00100130 dram:@0x1000
>> size:0x003c6774
>>       aspeed_smc_read @0x8 size 4: 0x800
>>       aspeed_smc_write @0x80 size 4: 0x0
>>       OK
>>          Loading Ramdisk to 8fef2000, end 8ffff604 ... aspeed_smc_write
>> @0x88 size 4: 0x8fef2000
>>       aspeed_smc_write @0x84 size 4: 0x204cdde0
>>       aspeed_smc_write @0x8c size 4: 0x10d604
>>       aspeed_smc_write @0x80 size 4: 0x1
>>       aspeed_smc_dma_rw read flash:@0x004cdde0 dram:@0xfef2000
>> size:0x0010d608
>>       aspeed_smc_read @0x8 size 4: 0x800
>>       aspeed_smc_write @0x80 size 4: 0x0
>>       OK
>>          Loading Device Tree to 8fee7000, end 8fef135e ... aspeed_smc_write
>> @0x88 size 4: 0x8fee7000
>>       aspeed_smc_write @0x84 size 4: 0x204c69b4
>>       aspeed_smc_write @0x8c size 4: 0x7360
>>       aspeed_smc_write @0x80 size 4: 0x1
>>       aspeed_smc_dma_rw read flash:@0x004c69b4 dram:@0xfee7000
>> size:0x00007364
>>       aspeed_smc_read @0x8 size 4: 0x800
>>       aspeed_smc_write @0x80 size 4: 0x0
>>       OK
>>
>>       Starting kernel ...
>>
>> It seems that the R_DMA_LEN register is set by FW without taking into account
>> the length unit ( bit / 4 bytes). Would you know why ?
>>
> https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2019.04/lib/string.c#L559
> This line make user input data length 4 bytes alignment.
> https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2019.04/arch/arm/mach-aspeed/ast2500/utils.S#L35

yes. I don't see any 1bit / 4bytes conversion when setting the DMA_LEN
register. Am I mistaking ? That's not what the specs says.

> This line set the value of count parameter to AST_FMC_DNA_LENGTH.
> AST_FMC_DMA_LENGTH is 4 bytes alignment value.
> Example: input 4
> ((4+3)/4) * 4 --> (7/4) *4 ---> 4
> If AST_FMC_DMA_LENGTH is 0, it means it should move 4 bytes data and AST_FMC_DMA_LENGTH do not need to be divided by 4.

ok. For that, I think you could replace aspeed_smc_dma_len() with

    return QEMU_ALIGN_UP(s->regs[R_DMA_LEN] + asc->dma_start_length, 4);

Thanks,

C.



> 
>> If I change the model to match 1 bit / 4 bytes unit of the R_DMA_LEN register.
>> Linux fails to boot. I didn't dig further and this is something we need to
>> understand before committing.
>>
>>> I don't think this is necessary to add a Fixes tag because the problem
>>> has been there for ages and no one reported it. Probably because the
>>> only place DMA transfers are used is in U-Boot and transfers have a
>>> non-zero length.
>>>
>>>> Currently, only supports dma length 4 bytes aligned.
>>
>> Is this 4 bytes alignment new for the AST2700 or is this something you added
>> because the mask of DMA_LENGTH is now relaxed to match all addresses ?
>>
>> #define DMA_LENGTH(val)         ((val) & 0x01FFFFFF)
> AST2700, AST2600 and AST1030 is from 1 byte to 1FFFFFF, so I change this Micro to fix data lost.
> https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2023.10/arch/arm/mach-aspeed/ast2700/spi.c#L186
> Please see this line, it decrease dma_len 1 byte first then, set to DMA_LEN register because DMA_LEN is 0 which means should move 1 byte data if DMA enables for AST2600, AST1030 and AST2700.
>>
>> Thanks,
>>
>> C.
> 
> Only AST2500 need 4 bytes alignment for DMA Length. However, according to the design of sapped_smc_dma_rw function,
> it utilizes address_space_stl_le API and it only works data 4 bytes alignment. https://github.com/qemu/qemu/blob/master/hw/ssi/aspeed_smc.c#L889
> For example,
> If users want to move 0x101 data_length, after 0x100 data has been moved and remains 1 byte data need to be moved.
> Please see this line program, https://github.com/qemu/qemu/blob/master/hw/ssi/aspeed_smc.c#L940
> ```
> s->regs[R_DMA_LEN] -= 4;
> ```
> The value of s->regs[R_DMA_LEN] becomes 0xffffffffXX because it is uint32_t data type and this while loop run in the unexpected behavior, https://github.com/qemu/qemu/blob/master/hw/ssi/aspeed_smc.c#L864
> That was, why I set 4bytes alignment for all models.
> 
> 



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 12/16] aspeed/soc: Add AST2700 support
  2024-04-16  9:18 ` [PATCH v3 12/16] aspeed/soc: " Jamin Lin via
  2024-04-19  7:10   ` Cédric Le Goater
@ 2024-05-07 13:06   ` Cédric Le Goater
  1 sibling, 0 replies; 42+ messages in thread
From: Cédric Le Goater @ 2024-05-07 13:06 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	Alistair Francis, Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: troy_lee, yunlin.tang

Peter,

Could you please look at aspeed_soc_ast2700_gic() when you have some time ?
My GIC knowledge is a bit limited and I would feel more confortable with
your feedback.

The rest looks good to me.

Thanks,

C.



On 4/16/24 11:18, Jamin Lin wrote:
> Initial definitions for a simple machine using an AST2700 SOC (Cortex-a35 CPU).
> 
> AST2700 SOC and its interrupt controller are too complex to handle
> in the common Aspeed SoC framework. We introduce a new ast2700
> class with instance_init and realize handlers.
> 
> AST2700 is a 64 bits quad core cpus and support 8 watchdog.
> Update maximum ASPEED_CPUS_NUM to 4 and ASPEED_WDTS_NUM to 8.
> In addition, update AspeedSocState to support scuio, sli, sliio and intc.
> 
> Add TYPE_ASPEED27X0_SOC machine type.
> 
> The SDMC controller is unlocked at SPL stage.
> At present, only supports to emulate booting
> start from u-boot stage. Set SDMC controller
> unlocked by default.
> 
> In INTC, each interrupt of INT 128 to INT 136 combines 32 interrupts.
> It connect GICINT IRQ GPIO-OUTPUT pins to GIC device with irq 128 to 136.
> And, if a device irq is 128 to 136, its irq GPIO-OUTPUT pin is connected to
> GICINT or-gates instead of GIC device.
> 
> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
>   hw/arm/aspeed_ast27x0.c     | 554 ++++++++++++++++++++++++++++++++++++
>   hw/arm/meson.build          |   1 +
>   include/hw/arm/aspeed_soc.h |  26 +-
>   3 files changed, 579 insertions(+), 2 deletions(-)
>   create mode 100644 hw/arm/aspeed_ast27x0.c
> 
> diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
> new file mode 100644
> index 0000000000..754c963230
> --- /dev/null
> +++ b/hw/arm/aspeed_ast27x0.c
> @@ -0,0 +1,554 @@
> +/*
> + * ASPEED SoC 27x0 family
> + *
> + * Copyright (C) 2024 ASPEED Technology Inc.
> + *
> + * This code is licensed under the GPL version 2 or later.  See
> + * the COPYING file in the top-level directory.
> + *
> + * Implementation extracted from the AST2600 and adapted for AST27x0.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "hw/misc/unimp.h"
> +#include "hw/arm/aspeed_soc.h"
> +#include "qemu/module.h"
> +#include "qemu/error-report.h"
> +#include "hw/i2c/aspeed_i2c.h"
> +#include "net/net.h"
> +#include "sysemu/sysemu.h"
> +#include "hw/intc/arm_gicv3.h"
> +#include "qapi/qmp/qlist.h"
> +
> +static const hwaddr aspeed_soc_ast2700_memmap[] = {
> +    [ASPEED_DEV_SPI_BOOT]  =  0x400000000,
> +    [ASPEED_DEV_SRAM]      =  0x10000000,
> +    [ASPEED_DEV_SDMC]      =  0x12C00000,
> +    [ASPEED_DEV_SCU]       =  0x12C02000,
> +    [ASPEED_DEV_SCUIO]     =  0x14C02000,
> +    [ASPEED_DEV_UART0]     =  0X14C33000,
> +    [ASPEED_DEV_UART1]     =  0X14C33100,
> +    [ASPEED_DEV_UART2]     =  0X14C33200,
> +    [ASPEED_DEV_UART3]     =  0X14C33300,
> +    [ASPEED_DEV_UART4]     =  0X12C1A000,
> +    [ASPEED_DEV_UART5]     =  0X14C33400,
> +    [ASPEED_DEV_UART6]     =  0X14C33500,
> +    [ASPEED_DEV_UART7]     =  0X14C33600,
> +    [ASPEED_DEV_UART8]     =  0X14C33700,
> +    [ASPEED_DEV_UART9]     =  0X14C33800,
> +    [ASPEED_DEV_UART10]    =  0X14C33900,
> +    [ASPEED_DEV_UART11]    =  0X14C33A00,
> +    [ASPEED_DEV_UART12]    =  0X14C33B00,
> +    [ASPEED_DEV_WDT]       =  0x14C37000,
> +    [ASPEED_DEV_VUART]     =  0X14C30000,
> +    [ASPEED_DEV_FMC]       =  0x14000000,
> +    [ASPEED_DEV_SPI0]      =  0x14010000,
> +    [ASPEED_DEV_SPI1]      =  0x14020000,
> +    [ASPEED_DEV_SPI2]      =  0x14030000,
> +    [ASPEED_DEV_SDRAM]     =  0x400000000,
> +    [ASPEED_DEV_MII1]      =  0x14040000,
> +    [ASPEED_DEV_MII2]      =  0x14040008,
> +    [ASPEED_DEV_MII3]      =  0x14040010,
> +    [ASPEED_DEV_ETH1]      =  0x14050000,
> +    [ASPEED_DEV_ETH2]      =  0x14060000,
> +    [ASPEED_DEV_ETH3]      =  0x14070000,
> +    [ASPEED_DEV_EMMC]      =  0x12090000,
> +    [ASPEED_DEV_INTC]      =  0x12100000,
> +    [ASPEED_DEV_SLI]       =  0x12C17000,
> +    [ASPEED_DEV_SLIIO]     =  0x14C1E000,
> +    [ASPEED_GIC_DIST]      =  0x12200000,
> +    [ASPEED_GIC_REDIST]    =  0x12280000,
> +};
> +
> +#define AST2700_MAX_IRQ 288
> +
> +/* Shared Peripheral Interrupt values below are offset by -32 from datasheet */
> +static const int aspeed_soc_ast2700_irqmap[] = {
> +    [ASPEED_DEV_UART0]     = 132,
> +    [ASPEED_DEV_UART1]     = 132,
> +    [ASPEED_DEV_UART2]     = 132,
> +    [ASPEED_DEV_UART3]     = 132,
> +    [ASPEED_DEV_UART4]     = 8,
> +    [ASPEED_DEV_UART5]     = 132,
> +    [ASPEED_DEV_UART6]     = 132,
> +    [ASPEED_DEV_UART7]     = 132,
> +    [ASPEED_DEV_UART8]     = 132,
> +    [ASPEED_DEV_UART9]     = 132,
> +    [ASPEED_DEV_UART10]    = 132,
> +    [ASPEED_DEV_UART11]    = 132,
> +    [ASPEED_DEV_UART12]    = 132,
> +    [ASPEED_DEV_FMC]       = 131,
> +    [ASPEED_DEV_SDMC]      = 0,
> +    [ASPEED_DEV_SCU]       = 12,
> +    [ASPEED_DEV_ADC]       = 130,
> +    [ASPEED_DEV_XDMA]      = 5,
> +    [ASPEED_DEV_EMMC]      = 15,
> +    [ASPEED_DEV_GPIO]      = 11,
> +    [ASPEED_DEV_GPIO_1_8V] = 130,
> +    [ASPEED_DEV_RTC]       = 13,
> +    [ASPEED_DEV_TIMER1]    = 16,
> +    [ASPEED_DEV_TIMER2]    = 17,
> +    [ASPEED_DEV_TIMER3]    = 18,
> +    [ASPEED_DEV_TIMER4]    = 19,
> +    [ASPEED_DEV_TIMER5]    = 20,
> +    [ASPEED_DEV_TIMER6]    = 21,
> +    [ASPEED_DEV_TIMER7]    = 22,
> +    [ASPEED_DEV_TIMER8]    = 23,
> +    [ASPEED_DEV_WDT]       = 131,
> +    [ASPEED_DEV_PWM]       = 131,
> +    [ASPEED_DEV_LPC]       = 128,
> +    [ASPEED_DEV_IBT]       = 128,
> +    [ASPEED_DEV_I2C]       = 130,
> +    [ASPEED_DEV_PECI]      = 133,
> +    [ASPEED_DEV_ETH1]      = 132,
> +    [ASPEED_DEV_ETH2]      = 132,
> +    [ASPEED_DEV_ETH3]      = 132,
> +    [ASPEED_DEV_HACE]      = 4,
> +    [ASPEED_DEV_KCS]       = 128,
> +    [ASPEED_DEV_DP]        = 28,
> +    [ASPEED_DEV_I3C]       = 131,
> +};
> +
> +/* GICINT 128 */
> +static const int aspeed_soc_ast2700_gic128_intcmap[] = {
> +    [ASPEED_DEV_LPC]       = 0,
> +    [ASPEED_DEV_IBT]       = 2,
> +    [ASPEED_DEV_KCS]       = 4,
> +};
> +
> +/* GICINT 130 */
> +static const int aspeed_soc_ast2700_gic130_intcmap[] = {
> +    [ASPEED_DEV_I2C]        = 0,
> +    [ASPEED_DEV_ADC]        = 16,
> +    [ASPEED_DEV_GPIO_1_8V]  = 18,
> +};
> +
> +/* GICINT 131 */
> +static const int aspeed_soc_ast2700_gic131_intcmap[] = {
> +    [ASPEED_DEV_I3C]       = 0,
> +    [ASPEED_DEV_WDT]       = 16,
> +    [ASPEED_DEV_FMC]       = 25,
> +    [ASPEED_DEV_PWM]       = 29,
> +};
> +
> +/* GICINT 132 */
> +static const int aspeed_soc_ast2700_gic132_intcmap[] = {
> +    [ASPEED_DEV_ETH1]      = 0,
> +    [ASPEED_DEV_ETH2]      = 1,
> +    [ASPEED_DEV_ETH3]      = 2,
> +    [ASPEED_DEV_UART0]     = 7,
> +    [ASPEED_DEV_UART1]     = 8,
> +    [ASPEED_DEV_UART2]     = 9,
> +    [ASPEED_DEV_UART3]     = 10,
> +    [ASPEED_DEV_UART5]     = 11,
> +    [ASPEED_DEV_UART6]     = 12,
> +    [ASPEED_DEV_UART7]     = 13,
> +    [ASPEED_DEV_UART8]     = 14,
> +    [ASPEED_DEV_UART9]     = 15,
> +    [ASPEED_DEV_UART10]    = 16,
> +    [ASPEED_DEV_UART11]    = 17,
> +    [ASPEED_DEV_UART12]    = 18,
> +};
> +
> +/* GICINT 133 */
> +static const int aspeed_soc_ast2700_gic133_intcmap[] = {
> +    [ASPEED_DEV_PECI]      = 4,
> +};
> +
> +/* GICINT 128 ~ 136 */
> +struct gic_intc_irq_info {
> +    int irq;
> +    const int *ptr;
> +};
> +
> +static const struct gic_intc_irq_info aspeed_soc_ast2700_gic_intcmap[] = {
> +    {128,  aspeed_soc_ast2700_gic128_intcmap},
> +    {129,  NULL},
> +    {130,  aspeed_soc_ast2700_gic130_intcmap},
> +    {131,  aspeed_soc_ast2700_gic131_intcmap},
> +    {132,  aspeed_soc_ast2700_gic132_intcmap},
> +    {133,  aspeed_soc_ast2700_gic133_intcmap},
> +    {134,  NULL},
> +    {135,  NULL},
> +    {136,  NULL},
> +};
> +
> +static qemu_irq aspeed_soc_ast2700_get_irq(AspeedSoCState *s, int dev)
> +{
> +    Aspeed27x0SoCState *a = ASPEED27X0_SOC(s);
> +    AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
> +    int i;
> +
> +    for (i = 0; i < ARRAY_SIZE(aspeed_soc_ast2700_gic_intcmap); i++) {
> +        if (sc->irqmap[dev] == aspeed_soc_ast2700_gic_intcmap[i].irq) {
> +            assert(aspeed_soc_ast2700_gic_intcmap[i].ptr);
> +            return qdev_get_gpio_in(DEVICE(&a->intc.gicint_orgate[i]),
> +                aspeed_soc_ast2700_gic_intcmap[i].ptr[dev]);
> +        }
> +    }
> +
> +    return qdev_get_gpio_in(a->intc.gic, sc->irqmap[dev]);
> +}
> +
> +static void aspeed_soc_ast2700_init(Object *obj)
> +{
> +    Aspeed27x0SoCState *a = ASPEED27X0_SOC(obj);
> +    AspeedSoCState *s = ASPEED_SOC(obj);
> +    AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
> +    int i;
> +    char socname[8];
> +    char typename[64];
> +
> +    if (sscanf(sc->name, "%7s", socname) != 1) {
> +        g_assert_not_reached();
> +    }
> +
> +    for (i = 0; i < sc->num_cpus; i++) {
> +        object_initialize_child(obj, "cpu[*]", &a->cpu[i],
> +                                aspeed_soc_cpu_type(sc));
> +    }
> +
> +    object_initialize_child(obj, "scu", &s->scu, TYPE_ASPEED_2700_SCU);
> +    qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev",
> +                         sc->silicon_rev);
> +    object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu),
> +                              "hw-strap1");
> +    object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu),
> +                              "hw-strap2");
> +    object_property_add_alias(obj, "hw-prot-key", OBJECT(&s->scu),
> +                              "hw-prot-key");
> +
> +    object_initialize_child(obj, "scuio", &s->scuio, TYPE_ASPEED_2700_SCUIO);
> +    qdev_prop_set_uint32(DEVICE(&s->scuio), "silicon-rev",
> +                         sc->silicon_rev);
> +
> +    snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname);
> +    object_initialize_child(obj, "fmc", &s->fmc, typename);
> +
> +    for (i = 0; i < sc->spis_num; i++) {
> +        snprintf(typename, sizeof(typename), "aspeed.spi%d-%s", i, socname);
> +        object_initialize_child(obj, "spi[*]", &s->spi[i], typename);
> +    }
> +
> +    snprintf(typename, sizeof(typename), "aspeed.sdmc-%s", socname);
> +    object_initialize_child(obj, "sdmc", &s->sdmc, typename);
> +    object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
> +                              "ram-size");
> +
> +    for (i = 0; i < sc->wdts_num; i++) {
> +        snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname);
> +        object_initialize_child(obj, "wdt[*]", &s->wdt[i], typename);
> +    }
> +
> +    for (i = 0; i < sc->macs_num; i++) {
> +        object_initialize_child(obj, "ftgmac100[*]", &s->ftgmac100[i],
> +                                TYPE_FTGMAC100);
> +
> +        object_initialize_child(obj, "mii[*]", &s->mii[i], TYPE_ASPEED_MII);
> +    }
> +
> +    for (i = 0; i < sc->uarts_num; i++) {
> +        object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_SERIAL_MM);
> +    }
> +
> +    object_initialize_child(obj, "sli", &s->sli, TYPE_ASPEED_2700_SLI);
> +    object_initialize_child(obj, "sliio", &s->sliio, TYPE_ASPEED_2700_SLIIO);
> +    object_initialize_child(obj, "intc", &a->intc, TYPE_ASPEED_INTC);
> +}
> +
> +/*
> + * ASPEED ast2700 has 0x0 as cluster ID
> + *
> + * https://developer.arm.com/documentation/100236/0100/register-descriptions/aarch64-system-registers/multiprocessor-affinity-register--el1
> + */
> +static uint64_t aspeed_calc_affinity(int cpu)
> +{
> +    return (0x0 << ARM_AFF1_SHIFT) | cpu;
> +}
> +
> +static void aspeed_soc_ast2700_gic(DeviceState *dev, Error **errp)
> +{
> +    Aspeed27x0SoCState *a = ASPEED27X0_SOC(dev);
> +    AspeedSoCState *s = ASPEED_SOC(dev);
> +    AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
> +    SysBusDevice *gicbusdev;
> +    QList *redist_region_count;
> +    int i;
> +
> +    a->intc.gic = qdev_new(gicv3_class_name());
> +    qdev_prop_set_uint32(a->intc.gic, "revision", 3);
> +    qdev_prop_set_uint32(a->intc.gic, "num-cpu", sc->num_cpus);
> +    qdev_prop_set_uint32(a->intc.gic, "num-irq", AST2700_MAX_IRQ);
> +
> +    redist_region_count = qlist_new();
> +    qlist_append_int(redist_region_count, sc->num_cpus);
> +    qdev_prop_set_array(a->intc.gic, "redist-region-count",
> +                            redist_region_count);
> +
> +    gicbusdev = SYS_BUS_DEVICE(a->intc.gic);
> +    sysbus_realize_and_unref(gicbusdev, errp);
> +    sysbus_mmio_map(gicbusdev, 0, sc->memmap[ASPEED_GIC_DIST]);
> +    sysbus_mmio_map(gicbusdev, 1, sc->memmap[ASPEED_GIC_REDIST]);
> +
> +    for (i = 0; i < sc->num_cpus; i++) {
> +        DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
> +        int NUM_IRQS = 256, ARCH_GIC_MAINT_IRQ = 9, VIRTUAL_PMU_IRQ = 7;
> +        int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
> +
> +        const int timer_irq[] = {
> +            [GTIMER_PHYS] = 14,
> +            [GTIMER_VIRT] = 11,
> +            [GTIMER_HYP]  = 10,
> +            [GTIMER_SEC]  = 13,
> +        };
> +        int j;
> +
> +        for (j = 0; j < ARRAY_SIZE(timer_irq); j++) {
> +            qdev_connect_gpio_out(cpudev, j,
> +                    qdev_get_gpio_in(a->intc.gic, ppibase + timer_irq[j]));
> +        }
> +
> +        qemu_irq irq = qdev_get_gpio_in(a->intc.gic,
> +                                        ppibase + ARCH_GIC_MAINT_IRQ);
> +        qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
> +                                    0, irq);
> +        qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
> +                qdev_get_gpio_in(a->intc.gic, ppibase + VIRTUAL_PMU_IRQ));
> +
> +        sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
> +        sysbus_connect_irq(gicbusdev, i + sc->num_cpus,
> +                           qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
> +        sysbus_connect_irq(gicbusdev, i + 2 * sc->num_cpus,
> +                           qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
> +        sysbus_connect_irq(gicbusdev, i + 3 * sc->num_cpus,
> +                           qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
> +    }
> +}
> +
> +static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
> +{
> +    int i;
> +    Aspeed27x0SoCState *a = ASPEED27X0_SOC(dev);
> +    AspeedSoCState *s = ASPEED_SOC(dev);
> +    AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
> +    g_autofree char *sram_name = NULL;
> +
> +    /* Default boot region (SPI memory or ROMs) */
> +    memory_region_init(&s->spi_boot_container, OBJECT(s),
> +                       "aspeed.spi_boot_container", 0x400000000);
> +    memory_region_add_subregion(s->memory, sc->memmap[ASPEED_DEV_SPI_BOOT],
> +                                &s->spi_boot_container);
> +
> +    /* CPU */
> +    for (i = 0; i < sc->num_cpus; i++) {
> +        object_property_set_int(OBJECT(&a->cpu[i]), "mp-affinity",
> +                                aspeed_calc_affinity(i), &error_abort);
> +
> +        object_property_set_int(OBJECT(&a->cpu[i]), "cntfrq", 1125000000,
> +                                &error_abort);
> +        object_property_set_link(OBJECT(&a->cpu[i]), "memory",
> +                                 OBJECT(s->memory), &error_abort);
> +
> +        if (!qdev_realize(DEVICE(&a->cpu[i]), NULL, errp)) {
> +            return;
> +        }
> +    }
> +
> +    /* GIC */
> +    aspeed_soc_ast2700_gic(dev, errp);
> +
> +    /* INTC */
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc), errp)) {
> +        return;
> +    }
> +
> +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc), 0,
> +                    sc->memmap[ASPEED_DEV_INTC]);
> +
> +    /* GICINT orgate -> INTC -> GIC */
> +    for (i = 0; i < ASPEED_INTC_NR_GICS; i++) {
> +        if (!qdev_realize(DEVICE(&a->intc.gicint_orgate[i]), NULL, errp)) {
> +            return;
> +        }
> +
> +        qdev_connect_gpio_out(DEVICE(&a->intc.gicint_orgate[i]), 0,
> +                              qdev_get_gpio_in(DEVICE(&a->intc), i));
> +
> +        sysbus_connect_irq(SYS_BUS_DEVICE(&a->intc), i,
> +                           qdev_get_gpio_in(a->intc.gic,
> +                                aspeed_soc_ast2700_gic_intcmap[i].irq));
> +    }
> +
> +    /* SRAM */
> +    sram_name = g_strdup_printf("aspeed.sram.%d", CPU(&a->cpu[0])->cpu_index);
> +    if (!memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size,
> +                                 errp)) {
> +        return;
> +    }
> +    memory_region_add_subregion(s->memory,
> +                                sc->memmap[ASPEED_DEV_SRAM], &s->sram);
> +
> +    /* SCU */
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) {
> +        return;
> +    }
> +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]);
> +
> +    /* SCU1 */
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->scuio), errp)) {
> +        return;
> +    }
> +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scuio), 0,
> +                    sc->memmap[ASPEED_DEV_SCUIO]);
> +
> +    /* UART */
> +    if (!aspeed_soc_uart_realize(s, errp)) {
> +        return;
> +    }
> +
> +    /* FMC, The number of CS is set at the board level */
> +    object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr),
> +                             &error_abort);
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) {
> +        return;
> +    }
> +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]);
> +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 1,
> +                    ASPEED_SMC_GET_CLASS(&s->fmc)->flash_window_base);
> +    sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0,
> +                       aspeed_soc_get_irq(s, ASPEED_DEV_FMC));
> +
> +    /* Set up an alias on the FMC CE0 region (boot default) */
> +    MemoryRegion *fmc0_mmio = &s->fmc.flashes[0].mmio;
> +    memory_region_init_alias(&s->spi_boot, OBJECT(s), "aspeed.spi_boot",
> +                             fmc0_mmio, 0, memory_region_size(fmc0_mmio));
> +    memory_region_add_subregion(&s->spi_boot_container, 0x0, &s->spi_boot);
> +
> +    /* SPI */
> +    for (i = 0; i < sc->spis_num; i++) {
> +        object_property_set_link(OBJECT(&s->spi[i]), "dram",
> +                                 OBJECT(s->dram_mr), &error_abort);
> +        if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) {
> +            return;
> +        }
> +        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 0,
> +                        sc->memmap[ASPEED_DEV_SPI0 + i]);
> +        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 1,
> +                        ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base);
> +    }
> +
> +    /*
> +     * SDMC - SDRAM Memory Controller
> +     * The SDMC controller is unlocked at SPL stage.
> +     * At present, only supports to emulate booting
> +     * start from u-boot stage. Set SDMC controller
> +     * unlocked by default. It is a temporarily solution.
> +     */
> +    object_property_set_bool(OBJECT(&s->sdmc), "unlocked", true,
> +                                 &error_abort);
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), errp)) {
> +        return;
> +    }
> +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdmc), 0,
> +                    sc->memmap[ASPEED_DEV_SDMC]);
> +
> +    /* RAM */
> +    if (!aspeed_soc_dram_init(s, errp)) {
> +        return;
> +    }
> +
> +    for (i = 0; i < sc->macs_num; i++) {
> +        object_property_set_bool(OBJECT(&s->ftgmac100[i]), "aspeed", true,
> +                                 &error_abort);
> +        if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), errp)) {
> +            return;
> +        }
> +        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
> +                        sc->memmap[ASPEED_DEV_ETH1 + i]);
> +        sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
> +                           aspeed_soc_get_irq(s, ASPEED_DEV_ETH1 + i));
> +
> +        object_property_set_link(OBJECT(&s->mii[i]), "nic",
> +                                 OBJECT(&s->ftgmac100[i]), &error_abort);
> +        if (!sysbus_realize(SYS_BUS_DEVICE(&s->mii[i]), errp)) {
> +            return;
> +        }
> +
> +        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->mii[i]), 0,
> +                        sc->memmap[ASPEED_DEV_MII1 + i]);
> +    }
> +
> +    /* Watch dog */
> +    for (i = 0; i < sc->wdts_num; i++) {
> +        AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]);
> +        hwaddr wdt_offset = sc->memmap[ASPEED_DEV_WDT] + i * awc->iosize;
> +
> +        object_property_set_link(OBJECT(&s->wdt[i]), "scu", OBJECT(&s->scu),
> +                                 &error_abort);
> +        if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
> +            return;
> +        }
> +        aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0, wdt_offset);
> +    }
> +
> +    /* SLI */
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->sli), errp)) {
> +        return;
> +    }
> +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sli), 0, sc->memmap[ASPEED_DEV_SLI]);
> +
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->sliio), errp)) {
> +        return;
> +    }
> +    aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sliio), 0,
> +                    sc->memmap[ASPEED_DEV_SLIIO]);
> +
> +    create_unimplemented_device("ast2700.dpmcu", 0x11000000, 0x40000);
> +    create_unimplemented_device("ast2700.iomem0", 0x12000000, 0x01000000);
> +    create_unimplemented_device("ast2700.iomem1", 0x14000000, 0x01000000);
> +    create_unimplemented_device("ast2700.ltpi", 0x30000000, 0x1000000);
> +    create_unimplemented_device("ast2700.io", 0x0, 0x4000000);
> +}
> +
> +static void aspeed_soc_ast2700_class_init(ObjectClass *oc, void *data)
> +{
> +    static const char * const valid_cpu_types[] = {
> +        ARM_CPU_TYPE_NAME("cortex-a35"),
> +        NULL
> +    };
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +    AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc);
> +
> +    dc->realize      = aspeed_soc_ast2700_realize;
> +
> +    sc->name         = "ast2700-a0";
> +    sc->valid_cpu_types = valid_cpu_types;
> +    sc->silicon_rev  = AST2700_A0_SILICON_REV;
> +    sc->sram_size    = 0x20000;
> +    sc->spis_num     = 3;
> +    sc->wdts_num     = 8;
> +    sc->macs_num     = 1;
> +    sc->uarts_num    = 13;
> +    sc->num_cpus     = 4;
> +    sc->uarts_base   = ASPEED_DEV_UART0;
> +    sc->irqmap       = aspeed_soc_ast2700_irqmap;
> +    sc->memmap       = aspeed_soc_ast2700_memmap;
> +    sc->get_irq      = aspeed_soc_ast2700_get_irq;
> +}
> +
> +static const TypeInfo aspeed_soc_ast27x0_types[] = {
> +    {
> +        .name           = TYPE_ASPEED27X0_SOC,
> +        .parent         = TYPE_ASPEED_SOC,
> +        .instance_size  = sizeof(Aspeed27x0SoCState),
> +        .abstract       = true,
> +    }, {
> +        .name           = "ast2700-a0",
> +        .parent         = TYPE_ASPEED27X0_SOC,
> +        .instance_init  = aspeed_soc_ast2700_init,
> +        .class_init     = aspeed_soc_ast2700_class_init,
> +    },
> +};
> +
> +DEFINE_TYPES(aspeed_soc_ast27x0_types)
> diff --git a/hw/arm/meson.build b/hw/arm/meson.build
> index 6808135c1f..1e3295a423 100644
> --- a/hw/arm/meson.build
> +++ b/hw/arm/meson.build
> @@ -46,6 +46,7 @@ arm_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
>     'aspeed_soc_common.c',
>     'aspeed_ast2400.c',
>     'aspeed_ast2600.c',
> +  'aspeed_ast27x0.c',
>     'aspeed_ast10x0.c',
>     'aspeed_eeprom.c',
>     'fby35.c'))
> diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
> index c60fac900a..9f177b6037 100644
> --- a/include/hw/arm/aspeed_soc.h
> +++ b/include/hw/arm/aspeed_soc.h
> @@ -15,6 +15,7 @@
>   #include "hw/cpu/a15mpcore.h"
>   #include "hw/arm/armv7m.h"
>   #include "hw/intc/aspeed_vic.h"
> +#include "hw/intc/aspeed_intc.h"
>   #include "hw/misc/aspeed_scu.h"
>   #include "hw/adc/aspeed_adc.h"
>   #include "hw/misc/aspeed_sdmc.h"
> @@ -26,6 +27,7 @@
>   #include "hw/ssi/aspeed_smc.h"
>   #include "hw/misc/aspeed_hace.h"
>   #include "hw/misc/aspeed_sbc.h"
> +#include "hw/misc/aspeed_sli.h"
>   #include "hw/watchdog/wdt_aspeed.h"
>   #include "hw/net/ftgmac100.h"
>   #include "target/arm/cpu.h"
> @@ -41,8 +43,8 @@
>   
>   #define ASPEED_SPIS_NUM  2
>   #define ASPEED_EHCIS_NUM 2
> -#define ASPEED_WDTS_NUM  4
> -#define ASPEED_CPUS_NUM  2
> +#define ASPEED_WDTS_NUM  8
> +#define ASPEED_CPUS_NUM  4
>   #define ASPEED_MACS_NUM  4
>   #define ASPEED_UARTS_NUM 13
>   #define ASPEED_JTAG_NUM  2
> @@ -61,6 +63,7 @@ struct AspeedSoCState {
>       AspeedI2CState i2c;
>       AspeedI3CState i3c;
>       AspeedSCUState scu;
> +    AspeedSCUState scuio;
>       AspeedHACEState hace;
>       AspeedXDMAState xdma;
>       AspeedADCState adc;
> @@ -68,6 +71,8 @@ struct AspeedSoCState {
>       AspeedSMCState spi[ASPEED_SPIS_NUM];
>       EHCISysBusState ehci[ASPEED_EHCIS_NUM];
>       AspeedSBCState sbc;
> +    AspeedSLIState sli;
> +    AspeedSLIState sliio;
>       MemoryRegion secsram;
>       UnimplementedDeviceState sbc_unimplemented;
>       AspeedSDMCState sdmc;
> @@ -117,6 +122,16 @@ struct Aspeed2600SoCState {
>   #define TYPE_ASPEED2600_SOC "aspeed2600-soc"
>   OBJECT_DECLARE_SIMPLE_TYPE(Aspeed2600SoCState, ASPEED2600_SOC)
>   
> +struct Aspeed27x0SoCState {
> +    AspeedSoCState parent;
> +
> +    ARMCPU cpu[ASPEED_CPUS_NUM];
> +    AspeedINTCState intc;
> +};
> +
> +#define TYPE_ASPEED27X0_SOC "aspeed27x0-soc"
> +OBJECT_DECLARE_SIMPLE_TYPE(Aspeed27x0SoCState, ASPEED27X0_SOC)
> +
>   struct Aspeed10x0SoCState {
>       AspeedSoCState parent;
>   
> @@ -168,11 +183,13 @@ enum {
>       ASPEED_DEV_UART13,
>       ASPEED_DEV_VUART,
>       ASPEED_DEV_FMC,
> +    ASPEED_DEV_SPI0,
>       ASPEED_DEV_SPI1,
>       ASPEED_DEV_SPI2,
>       ASPEED_DEV_EHCI1,
>       ASPEED_DEV_EHCI2,
>       ASPEED_DEV_VIC,
> +    ASPEED_DEV_INTC,
>       ASPEED_DEV_SDMC,
>       ASPEED_DEV_SCU,
>       ASPEED_DEV_ADC,
> @@ -222,6 +239,11 @@ enum {
>       ASPEED_DEV_JTAG1,
>       ASPEED_DEV_FSI1,
>       ASPEED_DEV_FSI2,
> +    ASPEED_DEV_SCUIO,
> +    ASPEED_DEV_SLI,
> +    ASPEED_DEV_SLIIO,
> +    ASPEED_GIC_DIST,
> +    ASPEED_GIC_REDIST,
>   };
>   
>   qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev);



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 11/16] aspeed/intc: Add AST2700 support
  2024-04-16  9:18 ` [PATCH v3 11/16] aspeed/intc: " Jamin Lin via
@ 2024-05-07 13:33   ` Cédric Le Goater
  0 siblings, 0 replies; 42+ messages in thread
From: Cédric Le Goater @ 2024-05-07 13:33 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	Alistair Francis, Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: troy_lee, yunlin.tang

Hello Jamin

On 4/16/24 11:18, Jamin Lin wrote:
> AST2700 interrupt controller(INTC) provides hardware interrupt interfaces
> to interrupt of processors PSP, SSP and TSP. In INTC, each interrupt of
> INT 128 to INT136 combines 32 interrupts.
> 
> Introduce a new aspeed_intc class with instance_init and realize handlers.
> 
> So far, this model only supports GICINT128 to GICINT136.
> It creates 9 GICINT or-gates to connect 32 interrupts sources
> from GICINT128 to GICINT136 as IRQ GPIO-OUTPUT pins.
> Then, this model registers IRQ handler with its IRQ GPIO-INPUT pins which
> connect to GICINT or-gates. And creates 9 GICINT IRQ GPIO-OUTPUT pins which
> connect to GIC device with GIC IRQ 128 to 136.
> 
> If one interrupt source from GICINT128 to GICINT136
> set irq, the OR-GATE irq callback function is called and set irq to INTC by
> OR-GATE GPIO-OUTPUT pins. Then, the INTC irq callback function is called and
> set irq to GIC by its GICINT IRQ GPIO-OUTPUT pins. Finally, the GIC irq
> callback function is called and set irq to CPUs and
> CPUs execute Interrupt Service Routine (ISR).

It is difficult to understand what the model does :/

> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
>   hw/intc/aspeed_intc.c         | 269 ++++++++++++++++++++++++++++++++++
>   hw/intc/meson.build           |   1 +
>   hw/intc/trace-events          |   6 +
>   include/hw/intc/aspeed_intc.h |  35 +++++
>   4 files changed, 311 insertions(+)
>   create mode 100644 hw/intc/aspeed_intc.c
>   create mode 100644 include/hw/intc/aspeed_intc.h
> 
> diff --git a/hw/intc/aspeed_intc.c b/hw/intc/aspeed_intc.c
> new file mode 100644
> index 0000000000..df31900d56
> --- /dev/null
> +++ b/hw/intc/aspeed_intc.c
> @@ -0,0 +1,269 @@
> +/*
> + * ASPEED INTC Controller
> + *
> + * Copyright (C) 2024 ASPEED Technology Inc.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/intc/aspeed_intc.h"
> +#include "hw/irq.h"
> +#include "migration/vmstate.h"
> +#include "qemu/bitops.h"
> +#include "qemu/log.h"
> +#include "qemu/module.h"
> +#include "hw/intc/arm_gicv3.h"
> +#include "trace.h"
> +#include "hw/registerfields.h"
> +#include "qapi/error.h"
> +
> +/* INTC Registers */
> +REG32(GICINT128_EN,         0x1000)
> +REG32(GICINT128_STATUS,     0x1004)
> +REG32(GICINT129_EN,         0x1100)
> +REG32(GICINT129_STATUS,     0x1104)
> +REG32(GICINT130_EN,         0x1200)
> +REG32(GICINT130_STATUS,     0x1204)
> +REG32(GICINT131_EN,         0x1300)
> +REG32(GICINT131_STATUS,     0x1304)
> +REG32(GICINT132_EN,         0x1400)
> +REG32(GICINT132_STATUS,     0x1404)
> +REG32(GICINT133_EN,         0x1500)
> +REG32(GICINT133_STATUS,     0x1504)
> +REG32(GICINT134_EN,         0x1600)
> +REG32(GICINT134_STATUS,     0x1604)
> +REG32(GICINT135_EN,         0x1700)
> +REG32(GICINT135_STATUS,     0x1704)
> +REG32(GICINT136_EN,         0x1800)
> +REG32(GICINT136_STATUS,     0x1804)
> +
> +#define GICINT_EN_BASE     R_GICINT128_EN
> +
> +/*
> + * The address of GICINT128 to GICINT136 are from 0x1000 to 0x1804.
> + * Utilize "address & 0x0f00" to get the gicint_out index and
> + * its gic irq.
> + */
> +static void aspeed_intc_update(AspeedINTCState *s, int irq, int level)
> +{
> +    uint32_t gicint_enable_addr = GICINT_EN_BASE + ((0x100 * irq) >> 2);
> +    uint32_t gicint_status_addr = gicint_enable_addr + (0x4 >> 2);
> +
> +    if (s->trigger[irq]) {
> +        if (!level && !s->regs[gicint_status_addr]) {
> +            /* clear irq */
> +            trace_aspeed_intc_update_irq(irq, 0);
> +            qemu_set_irq(s->gicint_out[irq], 0);
> +            s->trigger[irq] = false;
> +        }
> +    } else {
> +        if (s->new_gicint_status[irq]) {
> +            /* set irq */
> +            trace_aspeed_intc_update_irq(irq, 1);
> +            s->regs[gicint_status_addr] = s->new_gicint_status[irq];
> +            s->new_gicint_status[irq] = 0;
> +            qemu_set_irq(s->gicint_out[irq], 1);
> +            s->trigger[irq] = true;
> +        }
> +    }

I will trust you on this as I don't understand.


> +}
> +
> +/*
> + * The value of irq should be 0 to ASPEED_INTC_NR_GICS.
> + * The irq 0 indicates GICINT128, irq 1 indicates GICINT129 and so on.
> + */
> +static void aspeed_intc_set_irq(void *opaque, int irq, int level)
> +{
> +    AspeedINTCState *s = (AspeedINTCState *)opaque;
> +    uint32_t gicint_enable_addr = GICINT_EN_BASE + ((0x100 * irq) >> 2);
> +    uint32_t enable = s->regs[gicint_enable_addr];
> +    int i;
> +
> +    if (irq > ASPEED_INTC_NR_GICS) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
> +                      __func__, irq);
> +        return;
> +    }
> +
> +    trace_aspeed_intc_set_irq(irq, level);
> +
> +    for (i = 0; i < 32; i++) {
> +        if (s->gicint_orgate[irq].levels[i]) {
> +            if (enable & BIT(i)) {
> +                s->new_gicint_status[irq] |= BIT(i);
> +            }
> +        }
> +    }
> +
> +    aspeed_intc_update(s, irq, level);
> +}
> +
> +static uint64_t aspeed_intc_read(void *opaque, hwaddr offset, unsigned int size)
> +{
> +    AspeedINTCState *s = ASPEED_INTC(opaque);
> +    uint32_t addr = offset >> 2;
> +    uint32_t value = 0;
> +
> +    if (addr >= ASPEED_INTC_NR_REGS) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
> +                      __func__, offset);
> +        return 0;
> +    }
> +
> +    switch (addr) {
> +    case R_GICINT128_EN:
> +    case R_GICINT129_EN:
> +    case R_GICINT130_EN:
> +    case R_GICINT131_EN:
> +    case R_GICINT132_EN:
> +    case R_GICINT133_EN:
> +    case R_GICINT134_EN:
> +    case R_GICINT135_EN:
> +    case R_GICINT136_EN:
> +    case R_GICINT128_STATUS:
> +    case R_GICINT129_STATUS:
> +    case R_GICINT130_STATUS:
> +    case R_GICINT131_STATUS:
> +    case R_GICINT132_STATUS:
> +    case R_GICINT133_STATUS:
> +    case R_GICINT134_STATUS:
> +    case R_GICINT135_STATUS:
> +    case R_GICINT136_STATUS:
> +        value = s->regs[addr];
> +        break;
> +    default:
> +        value = s->regs[addr];
> +        break;
> +    }
> +
> +    trace_aspeed_intc_read(offset, size, value);
> +
> +    return value;
> +}
> +
> +static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data,
> +                                        unsigned size)
> +{
> +    AspeedINTCState *s = ASPEED_INTC(opaque);
> +    uint32_t irq = (offset & 0x0f00) >> 8;
> +    uint32_t addr = offset >> 2;
> +
> +
> +    if (addr >= ASPEED_INTC_NR_REGS) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
> +                      __func__, offset);
> +        return;
> +    }
> +
> +    trace_aspeed_intc_write(offset, size, data);
> +
> +    switch (addr) {
> +    case R_GICINT128_EN:
> +    case R_GICINT129_EN:
> +    case R_GICINT130_EN:
> +    case R_GICINT131_EN:
> +    case R_GICINT132_EN:
> +    case R_GICINT133_EN:
> +    case R_GICINT134_EN:
> +    case R_GICINT135_EN:
> +    case R_GICINT136_EN:
> +        s->regs[addr] = data;
> +        break;
> +    case R_GICINT128_STATUS:
> +    case R_GICINT129_STATUS:
> +    case R_GICINT130_STATUS:
> +    case R_GICINT131_STATUS:
> +    case R_GICINT132_STATUS:
> +    case R_GICINT133_STATUS:
> +    case R_GICINT134_STATUS:
> +    case R_GICINT135_STATUS:
> +    case R_GICINT136_STATUS:
> +        /* clear status */
> +        s->regs[addr] &= ~data;
> +        if (!s->regs[addr]) {
> +            aspeed_intc_update(s, irq, 0);
> +        }
> +        break;
> +    default:
> +        s->regs[addr] = data;
> +        break;
> +    }
> +
> +    return;
> +}
> +
> +static const MemoryRegionOps aspeed_intc_ops = {
> +    .read = aspeed_intc_read,
> +    .write = aspeed_intc_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 4,
> +    }
> +};
> +
> +static void aspeed_intc_instance_init(Object *obj)
> +{
> +    AspeedINTCState *s = ASPEED_INTC(obj);
> +    int i;
> +
> +    for (i = 0; i < ASPEED_INTC_NR_GICS; i++) {
> +        object_initialize_child(obj, "gic-orgate[*]", &s->gicint_orgate[i],
> +                                TYPE_OR_IRQ);
> +        object_property_set_int(OBJECT(&s->gicint_orgate[i]), "num-lines",
> +                                32, &error_abort);
> +    }
> +}
> +
> +static void aspeed_intc_reset(DeviceState *dev)
> +{
> +    AspeedINTCState *s = ASPEED_INTC(dev);
> +    memset(s->regs, 0, sizeof(s->regs));
> +    memset(s->trigger, 0, sizeof(s->trigger));
> +    memset(s->new_gicint_status, 0, sizeof(s->new_gicint_status));
> +}
> +
> +static void aspeed_intc_realize(DeviceState *dev, Error **errp)
> +{
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +    AspeedINTCState *s = ASPEED_INTC(dev);
> +    int i;
> +
> +    memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_intc_ops, s,
> +                          TYPE_ASPEED_INTC ".regs", ASPEED_INTC_NR_REGS << 2);
> +
> +    sysbus_init_mmio(sbd, &s->iomem);
> +    qdev_init_gpio_in(dev, aspeed_intc_set_irq, ASPEED_INTC_NR_GICS);
> +
> +    for (i = 0; i < ASPEED_INTC_NR_GICS; i++) {
> +        sysbus_init_irq(sbd, &s->gicint_out[i]);
> +    }

Why aren't the orgates realized here ?

> +}
> +
> +static void aspeed_intc_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->realize = aspeed_intc_realize;
> +    dc->reset = aspeed_intc_reset;
> +    dc->desc = "ASPEED INTC Controller";
> +    dc->vmsd = NULL;
> +}
> +
> +static const TypeInfo aspeed_intc_info = {
> +    .name = TYPE_ASPEED_INTC,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_init = aspeed_intc_instance_init,
> +    .instance_size = sizeof(AspeedINTCState),
> +    .class_init = aspeed_intc_class_init,
> +};
> +
> +static void aspeed_intc_register_types(void)
> +{
> +    type_register_static(&aspeed_intc_info);
> +}
> +
> +type_init(aspeed_intc_register_types);
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index ed355941d1..f5c574f584 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -14,6 +14,7 @@ system_ss.add(when: 'CONFIG_ARM_GICV3_TCG', if_true: files(
>   ))
>   system_ss.add(when: 'CONFIG_ALLWINNER_A10_PIC', if_true: files('allwinner-a10-pic.c'))
>   system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_vic.c'))
> +system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_intc.c'))
>   system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_pic.c'))
>   system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_gic.c', 'exynos4210_combiner.c'))
>   system_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
> diff --git a/hw/intc/trace-events b/hw/intc/trace-events
> index 1ef29d0256..30b9dd2a96 100644
> --- a/hw/intc/trace-events
> +++ b/hw/intc/trace-events
> @@ -79,6 +79,12 @@ aspeed_vic_update_fiq(int flags) "Raising FIQ: %d"
>   aspeed_vic_update_irq(int flags) "Raising IRQ: %d"
>   aspeed_vic_read(uint64_t offset, unsigned size, uint32_t value) "From 0x%" PRIx64 " of size %u: 0x%" PRIx32
>   aspeed_vic_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
> +# aspeed_intc.c
> +aspeed_intc_read(uint64_t offset, unsigned size, uint32_t value) "From 0x%" PRIx64 " of size %u: 0x%" PRIx32
> +aspeed_intc_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
> +aspeed_intc_set_irq(int irq, int level) "Set IRQ %d: %d"
> +aspeed_intc_update_irq(int irq, int level) "Update IRQ: %d: %d"
> +aspeed_intc_debug(uint32_t offset, uint32_t value) "Debug 0x%x: 0x%x"
>   
>   # arm_gic.c
>   gic_enable_irq(int irq) "irq %d enabled"
> diff --git a/include/hw/intc/aspeed_intc.h b/include/hw/intc/aspeed_intc.h
> new file mode 100644
> index 0000000000..0d2fbbda8f
> --- /dev/null
> +++ b/include/hw/intc/aspeed_intc.h
> @@ -0,0 +1,35 @@
> +/*
> + * ASPEED INTC Controller
> + *
> + * Copyright (C) 2024 ASPEED Technology Inc.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +#ifndef ASPEED_INTC_H
> +#define ASPEED_INTC_H
> +
> +#include "hw/sysbus.h"
> +#include "qom/object.h"
> +#include "hw/or-irq.h"
> +
> +#define TYPE_ASPEED_INTC "aspeed.intc"
> +OBJECT_DECLARE_SIMPLE_TYPE(AspeedINTCState, ASPEED_INTC)
> +
> +#define ASPEED_INTC_NR_REGS (0x2000 >> 2)
> +#define ASPEED_INTC_NR_GICS 9
> +
> +struct AspeedINTCState {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +    DeviceState *gic;
> +
> +    /*< public >*/
> +    MemoryRegion iomem;
> +    uint32_t regs[ASPEED_INTC_NR_REGS];
> +    OrIRQState gicint_orgate[ASPEED_INTC_NR_GICS];
> +    qemu_irq gicint_out[ASPEED_INTC_NR_GICS];
> +    bool trigger[ASPEED_INTC_NR_GICS];
> +    uint32_t new_gicint_status[ASPEED_INTC_NR_GICS];

I don't think the gicint prefix is useful in the names. I am struggling to
catch what new_gicint_status and trigger really do.


Thanks,

C.




> +};
> +
> +#endif /* ASPEED_INTC_H */



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 08/16] aspeed/smc: support 64 bits dma dram address
  2024-04-16  9:18 ` [PATCH v3 08/16] aspeed/smc: support 64 bits dma dram address Jamin Lin via
  2024-04-18 16:09   ` Cédric Le Goater
@ 2024-05-07 14:19   ` Cédric Le Goater
  2024-05-15  9:01     ` Jamin Lin
  1 sibling, 1 reply; 42+ messages in thread
From: Cédric Le Goater @ 2024-05-07 14:19 UTC (permalink / raw)
  To: Jamin Lin, Peter Maydell, Andrew Jeffery, Joel Stanley,
	Alistair Francis, Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: troy_lee, yunlin.tang


Hello Jamin,

To handle the DMA DRAM Side Address High register, we should reintroduce
an "dram-base" property which I removed a while ago. Something like :



diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h
index 7f32e43ff6f3..6d8ef6bc968f 100644
--- a/include/hw/ssi/aspeed_smc.h
+++ b/include/hw/ssi/aspeed_smc.h
@@ -76,6 +76,7 @@ struct AspeedSMCState {
      AddressSpace flash_as;
      MemoryRegion *dram_mr;
      AddressSpace dram_as;
+    uint64_t     dram_base;
  
      AddressSpace wdt2_as;
      MemoryRegion *wdt2_mr;
diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 38858e4fdec1..3417949ad8a3 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -500,6 +500,8 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
      }
  
      /* FMC, The number of CS is set at the board level */
+    object_property_set_int(OBJECT(&s->fmc), "dram-base",
+                            sc->memmap[ASPEED_DEV_SDRAM], &error_abort);
      object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr),
                               &error_abort);
      if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) {
diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index 3fa783578e9e..29ebfc0fd8c8 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -1372,6 +1372,7 @@ static const VMStateDescription vmstate_aspeed_smc = {
  
  static Property aspeed_smc_properties[] = {
      DEFINE_PROP_BOOL("inject-failure", AspeedSMCState, inject_failure, false),
+    DEFINE_PROP_UINT64("dram-base", AspeedSMCState, dram_base, 0),
      DEFINE_PROP_LINK("dram", AspeedSMCState, dram_mr,
                       TYPE_MEMORY_REGION, MemoryRegion *),
      DEFINE_PROP_LINK("wdt2", AspeedSMCState, wdt2_mr,



With that, see below for more comments,

On 4/16/24 11:18, Jamin Lin wrote:
> AST2700 support the maximum dram size is 8GiB
> and has a "DMA DRAM Side Address High Part(0x7C)"
> register to support 64 bits dma dram address.
> Add helper routines functions to compute the dma dram
> address, new features and update trace-event
> to support 64 bits dram address.
> 
> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
>   hw/ssi/aspeed_smc.c | 66 +++++++++++++++++++++++++++++++++++++++------
>   hw/ssi/trace-events |  2 +-
>   2 files changed, 59 insertions(+), 9 deletions(-)
> 
> diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
> index 71abc7a2d8..a67cac3d0f 100644
> --- a/hw/ssi/aspeed_smc.c
> +++ b/hw/ssi/aspeed_smc.c
> @@ -132,6 +132,9 @@
>   #define   FMC_WDT2_CTRL_BOOT_SOURCE      BIT(4) /* O: primary 1: alternate */
>   #define   FMC_WDT2_CTRL_EN               BIT(0)
>   
> +/* DMA DRAM Side Address High Part (AST2700) */
> +#define R_DMA_DRAM_ADDR_HIGH   (0x7c / 4)
> +
>   /* DMA Control/Status Register */
>   #define R_DMA_CTRL        (0x80 / 4)
>   #define   DMA_CTRL_REQUEST      (1 << 31)
> @@ -187,6 +190,7 @@
>    *   0x1FFFFFF: 32M bytes
>    */
>   #define DMA_DRAM_ADDR(asc, val)   ((val) & (asc)->dma_dram_mask)
> +#define DMA_DRAM_ADDR_HIGH(val)   ((val) & 0xf)
>   #define DMA_FLASH_ADDR(asc, val)  ((val) & (asc)->dma_flash_mask)
>   #define DMA_LENGTH(val)         ((val) & 0x01FFFFFF)
>   
> @@ -207,6 +211,7 @@ static const AspeedSegments aspeed_2500_spi2_segments[];
>   #define ASPEED_SMC_FEATURE_DMA       0x1
>   #define ASPEED_SMC_FEATURE_DMA_GRANT 0x2
>   #define ASPEED_SMC_FEATURE_WDT_CONTROL 0x4
> +#define ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH 0x08
>   
>   static inline bool aspeed_smc_has_dma(const AspeedSMCClass *asc)
>   {
> @@ -218,6 +223,11 @@ static inline bool aspeed_smc_has_wdt_control(const AspeedSMCClass *asc)
>       return !!(asc->features & ASPEED_SMC_FEATURE_WDT_CONTROL);
>   }
>   
> +static inline bool aspeed_smc_has_dma_dram_addr_high(const AspeedSMCClass *asc)
> +{
> +    return !!(asc->features & ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH);
> +}
> +
>   #define aspeed_smc_error(fmt, ...)                                      \
>       qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt "\n", __func__, ## __VA_ARGS__)
>   
> @@ -747,6 +757,9 @@ static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size)
>           (aspeed_smc_has_dma(asc) && addr == R_DMA_CTRL) ||
>           (aspeed_smc_has_dma(asc) && addr == R_DMA_FLASH_ADDR) ||
>           (aspeed_smc_has_dma(asc) && addr == R_DMA_DRAM_ADDR) ||
> +        (aspeed_smc_has_dma(asc) &&
> +         aspeed_smc_has_dma_dram_addr_high(asc) &&
> +         addr == R_DMA_DRAM_ADDR_HIGH) ||
>           (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN) ||
>           (aspeed_smc_has_dma(asc) && addr == R_DMA_CHECKSUM) ||
>           (addr >= R_SEG_ADDR0 &&
> @@ -847,6 +860,23 @@ static bool aspeed_smc_inject_read_failure(AspeedSMCState *s)
>       }
>   }
>   
> +static uint64_t aspeed_smc_dma_dram_addr(AspeedSMCState *s)
> +{
> +    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
> +    uint64_t dram_addr_high;
> +    uint64_t dma_dram_addr;
> +
> +    if (aspeed_smc_has_dma_dram_addr_high(asc)) {
> +        dram_addr_high = s->regs[R_DMA_DRAM_ADDR_HIGH];
> +        dram_addr_high <<= 32;
> +        dma_dram_addr = dram_addr_high | s->regs[R_DMA_DRAM_ADDR];
> +    } else {
> +        dma_dram_addr = s->regs[R_DMA_DRAM_ADDR];
> +    }
> +
> +    return dma_dram_addr;
> +}
> +
>   static uint32_t aspeed_smc_dma_len(AspeedSMCState *s)
>   {
>       AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
> @@ -914,24 +944,34 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
>   
>   static void aspeed_smc_dma_rw(AspeedSMCState *s)
>   {
> +    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
> +    uint64_t dram_addr_high;

dram_addr_high can be removed

> +    uint64_t dma_dram_addr;
> +    uint64_t dram_addr;

please call this variable dma_dram_offset, I found it less confusing.

>       MemTxResult result;
>       uint32_t dma_len;
>       uint32_t data;
>   
>       dma_len = aspeed_smc_dma_len(s);
> +    dma_dram_addr = aspeed_smc_dma_dram_addr(s);
> +
> +    if (aspeed_smc_has_dma_dram_addr_high(asc)) {
> +        dram_addr = dma_dram_addr - s->dram_mr->container->addr;
> +    } else {
> +        dram_addr = dma_dram_addr;
> +    }
>

With the new "dram-base" property, the above if can be replaced by :

     dma_dram_offset = dma_dram_addr - s->dram_base;


Thanks,

C.


>       trace_aspeed_smc_dma_rw(s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE ?
>                               "write" : "read",
>                               s->regs[R_DMA_FLASH_ADDR],
> -                            s->regs[R_DMA_DRAM_ADDR],
> +                            dram_addr,
>                               dma_len);
>       while (dma_len) {
>           if (s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE) {
> -            data = address_space_ldl_le(&s->dram_as, s->regs[R_DMA_DRAM_ADDR],
> +            data = address_space_ldl_le(&s->dram_as, dram_addr,
>                                           MEMTXATTRS_UNSPECIFIED, &result);
>               if (result != MEMTX_OK) {
> -                aspeed_smc_error("DRAM read failed @%08x",
> -                                 s->regs[R_DMA_DRAM_ADDR]);
> +                aspeed_smc_error("DRAM read failed @%" PRIx64, dram_addr);
>                   return;
>               }
>   
> @@ -951,11 +991,10 @@ static void aspeed_smc_dma_rw(AspeedSMCState *s)
>                   return;
>               }
>   
> -            address_space_stl_le(&s->dram_as, s->regs[R_DMA_DRAM_ADDR],
> +            address_space_stl_le(&s->dram_as, dram_addr,
>                                    data, MEMTXATTRS_UNSPECIFIED, &result);
>               if (result != MEMTX_OK) {
> -                aspeed_smc_error("DRAM write failed @%08x",
> -                                 s->regs[R_DMA_DRAM_ADDR]);
> +                aspeed_smc_error("DRAM write failed @%" PRIx64, dram_addr);
>                   return;
>               }
>           }
> @@ -964,8 +1003,15 @@ static void aspeed_smc_dma_rw(AspeedSMCState *s)
>            * When the DMA is on-going, the DMA registers are updated
>            * with the current working addresses and length.
>            */
> +        dram_addr += 4;
> +        dma_dram_addr += 4;
> +        if (aspeed_smc_has_dma_dram_addr_high(asc)) {
> +            dram_addr_high = dma_dram_addr >> 32;
> +            s->regs[R_DMA_DRAM_ADDR_HIGH] = dram_addr_high;
> +        }
> +
> +        s->regs[R_DMA_DRAM_ADDR] = dma_dram_addr & 0xffffffff;
>           s->regs[R_DMA_FLASH_ADDR] += 4;
> -        s->regs[R_DMA_DRAM_ADDR] += 4;
>           dma_len -= 4;
>           s->regs[R_DMA_LEN] = dma_len;
>           s->regs[R_DMA_CHECKSUM] += data;
> @@ -1118,6 +1164,10 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data,
>       } else if (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN &&
>                  aspeed_smc_dma_granted(s)) {
>           s->regs[addr] = DMA_LENGTH(value);
> +    } else if (aspeed_smc_has_dma(asc) &&
> +               aspeed_smc_has_dma_dram_addr_high(asc) &&
> +               addr == R_DMA_DRAM_ADDR_HIGH) {
> +        s->regs[addr] = DMA_DRAM_ADDR_HIGH(value);
>       } else {
>           qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n",
>                         __func__, addr);
> diff --git a/hw/ssi/trace-events b/hw/ssi/trace-events
> index 2d5bd2b83d..7b5ad6a939 100644
> --- a/hw/ssi/trace-events
> +++ b/hw/ssi/trace-events
> @@ -6,7 +6,7 @@ aspeed_smc_do_snoop(int cs, int index, int dummies, int data) "CS%d index:0x%x d
>   aspeed_smc_flash_write(int cs, uint64_t addr,  uint32_t size, uint64_t data, int mode) "CS%d @0x%" PRIx64 " size %u: 0x%" PRIx64" mode:%d"
>   aspeed_smc_read(uint64_t addr,  uint32_t size, uint64_t data) "@0x%" PRIx64 " size %u: 0x%" PRIx64
>   aspeed_smc_dma_checksum(uint32_t addr, uint32_t data) "0x%08x: 0x%08x"
> -aspeed_smc_dma_rw(const char *dir, uint32_t flash_addr, uint32_t dram_addr, uint32_t size) "%s flash:@0x%08x dram:@0x%08x size:0x%08x"
> +aspeed_smc_dma_rw(const char *dir, uint32_t flash_addr, uint64_t dram_addr, uint32_t size) "%s flash:@0x%08x dram:@0x%" PRIx64 " size:0x%08x"
>   aspeed_smc_write(uint64_t addr,  uint32_t size, uint64_t data) "@0x%" PRIx64 " size %u: 0x%" PRIx64
>   aspeed_smc_flash_select(int cs, const char *prefix) "CS%d %sselect"
>   



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* RE: [PATCH v3 07/16] aspeed/smc: fix dma moving incorrect data length issue
  2024-05-03 14:35         ` Cédric Le Goater
@ 2024-05-15  4:05           ` Jamin Lin
  0 siblings, 0 replies; 42+ messages in thread
From: Jamin Lin @ 2024-05-15  4:05 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: Troy Lee, Yunlin Tang

Hi Cedric,

Sorry reply you late.
> On 4/30/24 10:51, Jamin Lin wrote:
> > Hi Cedric,
> >> On 4/19/24 15:41, Cédric Le Goater wrote:
> >>> On 4/16/24 11:18, Jamin Lin wrote:
> >>>> DMA length is from 1 byte to 32MB for AST2600 and AST10x0 and DMA
> >>>> length is from 4 bytes to 32MB for AST2500.
> >>>>
> >>>> In other words, if "R_DMA_LEN" is 0, it should move at least 1 byte
> >>>> data for AST2600 and AST10x0 and 4 bytes data for AST2500.
> >>>>> To support all ASPEED SOCs, adds dma_start_length parameter to
> >>>>> store
> >>>> the start length, add helper routines function to compute the dma
> >>>> length and update DMA_LENGTH mask to "1FFFFFF" to fix dma moving
> >>>> incorrect data length issue.
> >>>
> >>> OK. There are two problems to address, the "zero" length transfer
> >>> and the DMA length unit, which is missing today. Newer SoC use a 1
> >>> bit / byte and older ones, AST2400 and AST2500, use 1 bit / 4 bytes.
> >>>
> >>> We can introduce a AspeedSMCClass::dma_len_unit and rework the loop
> to :
> >>>
> >>>       do {
> >>>
> >>>         ....
> >>>
> >>>          if (s->regs[R_DMA_LEN]) {
> >>>               s->regs[R_DMA_LEN] -= 4 / asc->dma_len_unit;
> >>>           }
> >>>       } while (s->regs[R_DMA_LEN]);
> >>>
> >>> It should fix the current implementation.
> >>
> >>
> >> I checked what FW is doing on a QEMU ast2500-evb machine :
> >>
> >>       U-Boot 2019.04-v00.04.12 (Sep 29 2022 - 10:40:37 +0000)
> >>       ...
> >>
> >>          Loading Kernel Image ... aspeed_smc_write @0x88 size 4:
> >> 0x80001000
> >>       aspeed_smc_write @0x84 size 4: 0x20100130
> >>       aspeed_smc_write @0x8c size 4: 0x3c6770
> >>       aspeed_smc_write @0x80 size 4: 0x1
> >>       aspeed_smc_dma_rw read flash:@0x00100130 dram:@0x1000
> >> size:0x003c6774
> >>       aspeed_smc_read @0x8 size 4: 0x800
> >>       aspeed_smc_write @0x80 size 4: 0x0
> >>       OK
> >>          Loading Ramdisk to 8fef2000, end 8ffff604 ...
> >> aspeed_smc_write
> >> @0x88 size 4: 0x8fef2000
> >>       aspeed_smc_write @0x84 size 4: 0x204cdde0
> >>       aspeed_smc_write @0x8c size 4: 0x10d604
> >>       aspeed_smc_write @0x80 size 4: 0x1
> >>       aspeed_smc_dma_rw read flash:@0x004cdde0 dram:@0xfef2000
> >> size:0x0010d608
> >>       aspeed_smc_read @0x8 size 4: 0x800
> >>       aspeed_smc_write @0x80 size 4: 0x0
> >>       OK
> >>          Loading Device Tree to 8fee7000, end 8fef135e ...
> >> aspeed_smc_write
> >> @0x88 size 4: 0x8fee7000
> >>       aspeed_smc_write @0x84 size 4: 0x204c69b4
> >>       aspeed_smc_write @0x8c size 4: 0x7360
> >>       aspeed_smc_write @0x80 size 4: 0x1
> >>       aspeed_smc_dma_rw read flash:@0x004c69b4 dram:@0xfee7000
> >> size:0x00007364
> >>       aspeed_smc_read @0x8 size 4: 0x800
> >>       aspeed_smc_write @0x80 size 4: 0x0
> >>       OK
> >>
> >>       Starting kernel ...
> >>
> >> It seems that the R_DMA_LEN register is set by FW without taking into
> >> account the length unit ( bit / 4 bytes). Would you know why ?
> >>
After I discussed with designers, my explanation as below.
AST2500 datasheet description:
FMC8C: DMA Length Register
31:25      Reserved(0)
24:2  RW  DMA_LENGTH
          From 4bytes to 32MB
          0: 4bytes
          0x7FFFFF: 32MB
1:0       Reserved

If users set this register 0, SPI DMA controller would move 4 bytes data.
If users set this register bits[24:2] 0x7FFFFF, SPI DMC controller would move 32MB data because this register includes reserved bits [1:0].
Ex: bits 24:2 --> 0x7fffff
   bits 1:0 --> 0 Reserved  
bits[24:0] is (0x1FFFFFC + start length 4) --> 2000000 --> 32MB  
           111 1111 1111 1111 1111 1111  00
LENGTH[24:2] 7   F    F   F   F    F    Reserved [1:0]

That was why AST2500 DMA length should 4 bytes alignment and you do not see handling length units because it includes reserved bits 1 and 0.
If user want to move 3 bytes data, our firmware set this register 4 ensure it 4bytes alignment and the value of register as following
bits[2:0] = "b100" Finally, SPI DMA controller move 8 bytes data(4bytes input count + start length 4bytes) 

And that was why it set DMA_LENGTH 0x01FFFFFC
https://github.com/qemu/qemu/blob/master/hw/ssi/aspeed_smc.c#L187
#define DMA_LENGTH(val)         ((val) & 0x01FFFFFC)

I want to change it to 0x01FFFFFF to support all ASPEED SOCs because AST2600, AST2700 and AST1030 use this register bit 0 and 1 whose unit is 1byte rather than 4 bytes.

> > https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2019.04/l
> > ib/string.c#L559 This line make user input data length 4 bytes
> > alignment.
> >
> https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2019.04/a
> > rch/arm/mach-aspeed/ast2500/utils.S#L35
> 
> yes. I don't see any 1bit / 4bytes conversion when setting the DMA_LEN
> register. Am I mistaking ? That's not what the specs says.
> 
> > This line set the value of count parameter to AST_FMC_DNA_LENGTH.
> > AST_FMC_DMA_LENGTH is 4 bytes alignment value.
> > Example: input 4
> > ((4+3)/4) * 4 --> (7/4) *4 ---> 4
> > If AST_FMC_DMA_LENGTH is 0, it means it should move 4 bytes data and
> AST_FMC_DMA_LENGTH do not need to be divided by 4.
> 
> ok. For that, I think you could replace aspeed_smc_dma_len() with
> 
>     return QEMU_ALIGN_UP(s->regs[R_DMA_LEN] + asc->dma_start_length,
> 4);
> 
Thanks for your suggestion and will fix it.

> Thanks,
> 
> C.
> 
> 
> 
> >
> >> If I change the model to match 1 bit / 4 bytes unit of the R_DMA_LEN
> register.
> >> Linux fails to boot. I didn't dig further and this is something we
> >> need to understand before committing.
> >>
> >>> I don't think this is necessary to add a Fixes tag because the
> >>> problem has been there for ages and no one reported it. Probably
> >>> because the only place DMA transfers are used is in U-Boot and
> >>> transfers have a non-zero length.
> >>>
> >>>> Currently, only supports dma length 4 bytes aligned.
> >>
> >> Is this 4 bytes alignment new for the AST2700 or is this something
> >> you added because the mask of DMA_LENGTH is now relaxed to match all
> addresses ?
> >>
> >> #define DMA_LENGTH(val)         ((val) & 0x01FFFFFF)
> > AST2700, AST2600 and AST1030 is from 1 byte to 1FFFFFF, so I change this
> Micro to fix data lost.
> >
> https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2023.10/a
> > rch/arm/mach-aspeed/ast2700/spi.c#L186
> > Please see this line, it decrease dma_len 1 byte first then, set to DMA_LEN
> register because DMA_LEN is 0 which means should move 1 byte data if DMA
> enables for AST2600, AST1030 and AST2700.
> >>
> >> Thanks,
> >>
> >> C.
> >
> > Only AST2500 need 4 bytes alignment for DMA Length. However, according
> > to the design of sapped_smc_dma_rw function, it utilizes
> > address_space_stl_le API and it only works data 4 bytes alignment.
> > https://github.com/qemu/qemu/blob/master/hw/ssi/aspeed_smc.c#L889
> > For example,
> > If users want to move 0x101 data_length, after 0x100 data has been moved
> and remains 1 byte data need to be moved.
> > Please see this line program,
> > https://github.com/qemu/qemu/blob/master/hw/ssi/aspeed_smc.c#L940
> > ```
> > s->regs[R_DMA_LEN] -= 4;
> > ```
> > The value of s->regs[R_DMA_LEN] becomes 0xffffffffXX because it is
> > uint32_t data type and this while loop run in the unexpected behavior,
> > https://github.com/qemu/qemu/blob/master/hw/ssi/aspeed_smc.c#L864
> > That was, why I set 4bytes alignment for all models.
> >
> >


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH v3 08/16] aspeed/smc: support 64 bits dma dram address
  2024-05-03 14:20           ` Cédric Le Goater
@ 2024-05-15  8:56             ` Jamin Lin
  0 siblings, 0 replies; 42+ messages in thread
From: Jamin Lin @ 2024-05-15  8:56 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: Troy Lee, Yunlin Tang

Hi Cedric,

Sorry reply you late.
> Hello Jamin,
> 
> On 4/30/24 09:56, Jamin Lin wrote:
> > Hi Cedric,
> >
> >> -----Original Message-----
> >> From: Cédric Le Goater <clg@kaod.org>
> >> Sent: Tuesday, April 30, 2024 3:26 PM
> >> To: Jamin Lin <jamin_lin@aspeedtech.com>; Peter Maydell
> >> <peter.maydell@linaro.org>; Andrew Jeffery
> >> <andrew@codeconstruct.com.au>; Joel Stanley <joel@jms.id.au>;
> >> Alistair Francis <alistair@alistair23.me>; Cleber Rosa
> >> <crosa@redhat.com>; Philippe Mathieu-Daudé <philmd@linaro.org>;
> >> Wainer dos Santos Moschetta <wainersm@redhat.com>; Beraldo Leal
> >> <bleal@redhat.com>; 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>; Yunlin Tang
> >> <yunlin.tang@aspeedtech.com>
> >> Subject: Re: [PATCH v3 08/16] aspeed/smc: support 64 bits dma dram
> >> address
> >>
> >> On 4/19/24 08:00, Jamin Lin wrote:
> >>> Hi Cedric,
> >>>>
> >>>> Hello Jamin,
> >>>>
> >>>> On 4/16/24 11:18, Jamin Lin wrote:
> >>>>> AST2700 support the maximum dram size is 8GiB and has a "DMA
> DRAM
> >>>> Side
> >>>>> Address High Part(0x7C)"
> >>>>> register to support 64 bits dma dram address.
> >>>>> Add helper routines functions to compute the dma dram address, new
> >>>>> features and update trace-event to support 64 bits dram address.
> >>>>>
> >>>>> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> >>>>> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> >>>>> ---
> >>>>>     hw/ssi/aspeed_smc.c | 66
> >>>> +++++++++++++++++++++++++++++++++++++++------
> >>>>>     hw/ssi/trace-events |  2 +-
> >>>>>     2 files changed, 59 insertions(+), 9 deletions(-)
> >>>>>
> >>>>> diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index
> >>>>> 71abc7a2d8..a67cac3d0f 100644
> >>>>> --- a/hw/ssi/aspeed_smc.c
> >>>>> +++ b/hw/ssi/aspeed_smc.c
> >>>>> @@ -132,6 +132,9 @@
> >>>>>     #define   FMC_WDT2_CTRL_BOOT_SOURCE      BIT(4) /* O:
> >> primary
> >>>> 1: alternate */
> >>>>>     #define   FMC_WDT2_CTRL_EN               BIT(0)
> >>>>>
> >>>>> +/* DMA DRAM Side Address High Part (AST2700) */
> >>>>> +#define R_DMA_DRAM_ADDR_HIGH   (0x7c / 4)
> >>>>> +
> >>>>>     /* DMA Control/Status Register */
> >>>>>     #define R_DMA_CTRL        (0x80 / 4)
> >>>>>     #define   DMA_CTRL_REQUEST      (1 << 31)
> >>>>> @@ -187,6 +190,7 @@
> >>>>>      *   0x1FFFFFF: 32M bytes
> >>>>>      */
> >>>>>     #define DMA_DRAM_ADDR(asc, val)   ((val) &
> >> (asc)->dma_dram_mask)
> >>>>> +#define DMA_DRAM_ADDR_HIGH(val)   ((val) & 0xf)
> >>>>>     #define DMA_FLASH_ADDR(asc, val)  ((val) &
> >> (asc)->dma_flash_mask)
> >>>>>     #define DMA_LENGTH(val)         ((val) & 0x01FFFFFF)
> >>>>>
> >>>>> @@ -207,6 +211,7 @@ static const AspeedSegments
> >>>> aspeed_2500_spi2_segments[];
> >>>>>     #define ASPEED_SMC_FEATURE_DMA       0x1
> >>>>>     #define ASPEED_SMC_FEATURE_DMA_GRANT 0x2
> >>>>>     #define ASPEED_SMC_FEATURE_WDT_CONTROL 0x4
> >>>>> +#define ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH 0x08
> >>>>>
> >>>>>     static inline bool aspeed_smc_has_dma(const AspeedSMCClass
> *asc)
> >>>>>     {
> >>>>> @@ -218,6 +223,11 @@ static inline bool
> >>>> aspeed_smc_has_wdt_control(const AspeedSMCClass *asc)
> >>>>>         return !!(asc->features &
> >> ASPEED_SMC_FEATURE_WDT_CONTROL);
> >>>>>     }
> >>>>>
> >>>>> +static inline bool aspeed_smc_has_dma_dram_addr_high(const
> >>>>> +AspeedSMCClass *asc)
> >>>>
> >>>> To ease the reading, I would call the helper aspeed_smc_has_dma64()
> >>> Will fix it
> >>>>
> >>>>> +{
> >>>>> +    return !!(asc->features &
> >>>> ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH);
> >>>>> +}
> >>>>> +
> >>>>>     #define aspeed_smc_error(fmt, ...)
> >>>> \
> >>>>>         qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt "\n",
> __func__,
> >> ##
> >>>>> __VA_ARGS__)
> >>>>>
> >>>>> @@ -747,6 +757,9 @@ static uint64_t aspeed_smc_read(void *opaque,
> >>>> hwaddr addr, unsigned int size)
> >>>>>             (aspeed_smc_has_dma(asc) && addr == R_DMA_CTRL)
> ||
> >>>>>             (aspeed_smc_has_dma(asc) && addr ==
> >> R_DMA_FLASH_ADDR)
> >>>> ||
> >>>>>             (aspeed_smc_has_dma(asc) && addr ==
> >> R_DMA_DRAM_ADDR)
> >>>> ||
> >>>>> +        (aspeed_smc_has_dma(asc) &&
> >>>>> +         aspeed_smc_has_dma_dram_addr_high(asc) &&
> >>>>> +         addr == R_DMA_DRAM_ADDR_HIGH) ||
> >>>>>             (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN)
> ||
> >>>>>             (aspeed_smc_has_dma(asc) && addr ==
> >> R_DMA_CHECKSUM)
> >>>> ||
> >>>>>             (addr >= R_SEG_ADDR0 && @@ -847,6 +860,23 @@
> static
> >>>>> bool
> >>>> aspeed_smc_inject_read_failure(AspeedSMCState *s)
> >>>>>         }
> >>>>>     }
> >>>>>
> >>>>> +static uint64_t aspeed_smc_dma_dram_addr(AspeedSMCState *s) {
> >>>>> +    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
> >>>>> +    uint64_t dram_addr_high;
> >>>>> +    uint64_t dma_dram_addr;
> >>>>> +
> >>>>> +    if (aspeed_smc_has_dma_dram_addr_high(asc)) {
> >>>>> +        dram_addr_high = s->regs[R_DMA_DRAM_ADDR_HIGH];
> >>>>> +        dram_addr_high <<= 32;
> >>>>> +        dma_dram_addr = dram_addr_high |
> >>>> s->regs[R_DMA_DRAM_ADDR];
> >>>>
> >>>> Here is a proposal to shorten the routine :
> >>>>
> >>>>            return ((uint64_t) s->regs[R_DMA_DRAM_ADDR_HIGH] <<
> 32)
> >> |
> >>>>                s->regs[R_DMA_DRAM_ADDR];
> >>>>
> >>>>
> >>>>> +    } else {
> >>>>> +        dma_dram_addr = s->regs[R_DMA_DRAM_ADDR];
> >>>>
> >>>> and
> >>>>            return s->regs[R_DMA_DRAM_ADDR];
> >>>>
> >>>>> +    }
> >>>>> +
> >>>>> +    return dma_dram_addr;
> >>>>> +}
> >>>>> +
> >>> Thanks for your suggestion. Will fix.
> >>>>>     static uint32_t aspeed_smc_dma_len(AspeedSMCState *s)
> >>>>>     {
> >>>>>         AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); @@
> >> -914,24
> >>>>> +944,34 @@ static void aspeed_smc_dma_checksum(AspeedSMCState
> *s)
> >>>>>
> >>>>>     static void aspeed_smc_dma_rw(AspeedSMCState *s)
> >>>>>     {
> >>>>> +    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
> >>>>> +    uint64_t dram_addr_high;
> >>>>
> >>>> This variable doesn't look very useful
> >>> Will try to remove it.
> >>>>
> >>>>> +    uint64_t dma_dram_addr;
> >>>>> +    uint64_t dram_addr;
> >>>>
> >>>> and dram_addr is redundant with dma_dram_addr. Please use only one.
> >>> Please see my below description and please give us any suggestion.
> >>>>
> >>>>
> >>>>>         MemTxResult result;
> >>>>>         uint32_t dma_len;
> >>>>>         uint32_t data;
> >>>>>
> >>>>>         dma_len = aspeed_smc_dma_len(s);
> >>>>> +    dma_dram_addr = aspeed_smc_dma_dram_addr(s);
> >>>>> +
> >>>>> +    if (aspeed_smc_has_dma_dram_addr_high(asc)) {
> >>>>> +        dram_addr = dma_dram_addr -
> s->dram_mr->container->addr;
> >>>>
> >>>> Why do you truncate the address again ? It should already be done
> >>>> with
> >>>>
> >>>> #define DMA_DRAM_ADDR_HIGH(val)   ((val) & 0xf)
> >>>>
> >>> The reason is that our firmware set the real address in SMC registers.
> >>> For example: If users want to move data from flash to the DRAM at
> >>> address 0, It set R_DMA_DRAM_ADDR_HIGH 4 and R_DMA_DRAM_ADDR
> 0
> >> because
> >>> the dram base address is 0x 4 00000000 for AST2700.
> >>
> >>
> >> Could you please share the specs of the R_DMA_DRAM_ADDR and
> >> R_DMA_DRAM_ADDR_HIGH registers to see what are the init values, how
> >> these registers should be set, their alignment constraints if any,
> >> how the values evolve while the HW does the DMA transactions, etc.
> >>
> > DMA_DRAM_SIDE_ADDRESS 0x088 Init=0x00000000
> > 31:0 RW DMA_RO
> > DRAM side start address
> > For DMA Read flash, this the destination address.
> > For DMA Write flash, the is the source address DMA only execute on 4
> > bytes boundary When read, it shows the current working address
> >
> > DMA DRAM Side Address High Part 0x07c Init=0x00000000
> > 32:8 RO reserved
> > 7:0 RW DMA_RO_HI
> >        dma_ro[39:32]
> >
> > Therefore, DMA address is dma_ro[39:0]
> 
> Thanks for the info. It seems that there are no alignment constraints.
> I am surprised that there are no limits for the length in the specs.
> It's 32MB right ?
> 
This register is used to set the dram address. AST2700 support the maximum dram size is 8GiB.
If dram base address is 0x400000000, the address range of 8GiB size would be 0x400000000 - 0x600000000
32bits only support dram size 4GiB. That was why we need this High Part register to support 8GIB size.
Yes, the maximum moving data length for flash is 32MB and is set by SPI8C DMA LENGTH Register.

> Previous SoCs hardwire the high bits of the address where DRAM is mapped in
> the DMA DRAM address reg. This is why the DRAM container was introduced,
> so that HW units doing DMAs, like SMC, didn't have to manipulate real physical
> addresses and offsets could be used instead. AST2700 HW interface is
> different.
> 
> We can't use 's->dram_mr->container->addr' directly and I would like to avoid
> passing 'sc->memmap[ASPEED_DEV_SDRAM]' as a property to the model.
> Also, I was hoping that we didn't have to update the high part of the address in
> the 0x07c reg. It seems we have to.
> 
> 
> >
> > Our FW settings,
> > In u-boot shell, execute the following command cp.b 100220000
> > 403000000 100
> > 100220000 flash address for kernel fit image
> > 403000000 dram address at offset 3000000
> > https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2023.10/l
> > ib/string.c#L553C8-L553C29
> >
> https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2023.10/a
> > rch/arm/mach-aspeed/ast2700/spi.c#L156
> 
> So, U-Boot simply hardcodes the DRAM high bits
> 
> 			if (dma_dest >= ASPEED_DRAM_BASE)
> 				writel(0x4, (void *)DRAM_HI_ADDR);
> 
After I checked with our SPI deriver designers, we confirmed it was a bug.
Example: If users use 8GIB dram size, the address range of 8GiB size would be 0x400000000 - 0x600000000
cp.b 100220000 503000000 101 --> This command would move the date at dram address 403000000 rather than 503000000
Our u-boot firmware will fix it. Thanks for report it.
Jamin

> The fallback plan would simply be to ignore the high bits of the DMA DRAM
> address. It should work today. Let me think about it more.
> 
> Thanks,
> 
> C.
> 
> 
> 
> 
> >
> https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2023.10/a
> > rch/arm/mach-aspeed/ast2700/spi.c#L179-L183
> > Thanks-Jamin
> >
> >> Thanks,
> >>
> >> C.
> >>
> >>
> >


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH v3 08/16] aspeed/smc: support 64 bits dma dram address
  2024-05-07 14:19   ` Cédric Le Goater
@ 2024-05-15  9:01     ` Jamin Lin
  0 siblings, 0 replies; 42+ messages in thread
From: Jamin Lin @ 2024-05-15  9:01 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Andrew Jeffery,
	Joel Stanley, Alistair Francis, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: Troy Lee, Yunlin Tang

Hi Cedric,

Sorry reply you late.
> Hello Jamin,
> 
> To handle the DMA DRAM Side Address High register, we should reintroduce an
> "dram-base" property which I removed a while ago. Something like :
> 
> 
> 
> diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h index
> 7f32e43ff6f3..6d8ef6bc968f 100644
> --- a/include/hw/ssi/aspeed_smc.h
> +++ b/include/hw/ssi/aspeed_smc.h
> @@ -76,6 +76,7 @@ struct AspeedSMCState {
>       AddressSpace flash_as;
>       MemoryRegion *dram_mr;
>       AddressSpace dram_as;
> +    uint64_t     dram_base;
> 
>       AddressSpace wdt2_as;
>       MemoryRegion *wdt2_mr;
> diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c index
> 38858e4fdec1..3417949ad8a3 100644
> --- a/hw/arm/aspeed_ast27x0.c
> +++ b/hw/arm/aspeed_ast27x0.c
> @@ -500,6 +500,8 @@ static void aspeed_soc_ast2700_realize(DeviceState
> *dev, Error **errp)
>       }
> 
>       /* FMC, The number of CS is set at the board level */
> +    object_property_set_int(OBJECT(&s->fmc), "dram-base",
> +                            sc->memmap[ASPEED_DEV_SDRAM],
> + &error_abort);
>       object_property_set_link(OBJECT(&s->fmc), "dram",
> OBJECT(s->dram_mr),
>                                &error_abort);
>       if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) { diff --git
> a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index
> 3fa783578e9e..29ebfc0fd8c8 100644
> --- a/hw/ssi/aspeed_smc.c
> +++ b/hw/ssi/aspeed_smc.c
> @@ -1372,6 +1372,7 @@ static const VMStateDescription
> vmstate_aspeed_smc = {
> 
>   static Property aspeed_smc_properties[] = {
>       DEFINE_PROP_BOOL("inject-failure", AspeedSMCState, inject_failure,
> false),
> +    DEFINE_PROP_UINT64("dram-base", AspeedSMCState, dram_base, 0),
>       DEFINE_PROP_LINK("dram", AspeedSMCState, dram_mr,
>                        TYPE_MEMORY_REGION, MemoryRegion *),
>       DEFINE_PROP_LINK("wdt2", AspeedSMCState, wdt2_mr,
> 
> 
I appreciate your kindly support and thanks for your suggestion.
Will add it. 

> 
> With that, see below for more comments,
> 
> On 4/16/24 11:18, Jamin Lin wrote:
> > AST2700 support the maximum dram size is 8GiB and has a "DMA DRAM
> Side
> > Address High Part(0x7C)"
> > register to support 64 bits dma dram address.
> > Add helper routines functions to compute the dma dram address, new
> > features and update trace-event to support 64 bits dram address.
> >
> > Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> > Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> > ---
> >   hw/ssi/aspeed_smc.c | 66
> +++++++++++++++++++++++++++++++++++++++------
> >   hw/ssi/trace-events |  2 +-
> >   2 files changed, 59 insertions(+), 9 deletions(-)
> >
> > diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index
> > 71abc7a2d8..a67cac3d0f 100644
> > --- a/hw/ssi/aspeed_smc.c
> > +++ b/hw/ssi/aspeed_smc.c
> > @@ -132,6 +132,9 @@
> >   #define   FMC_WDT2_CTRL_BOOT_SOURCE      BIT(4) /* O: primary
> 1: alternate */
> >   #define   FMC_WDT2_CTRL_EN               BIT(0)
> >
> > +/* DMA DRAM Side Address High Part (AST2700) */
> > +#define R_DMA_DRAM_ADDR_HIGH   (0x7c / 4)
> > +
> >   /* DMA Control/Status Register */
> >   #define R_DMA_CTRL        (0x80 / 4)
> >   #define   DMA_CTRL_REQUEST      (1 << 31)
> > @@ -187,6 +190,7 @@
> >    *   0x1FFFFFF: 32M bytes
> >    */
> >   #define DMA_DRAM_ADDR(asc, val)   ((val) & (asc)->dma_dram_mask)
> > +#define DMA_DRAM_ADDR_HIGH(val)   ((val) & 0xf)
> >   #define DMA_FLASH_ADDR(asc, val)  ((val) & (asc)->dma_flash_mask)
> >   #define DMA_LENGTH(val)         ((val) & 0x01FFFFFF)
> >
> > @@ -207,6 +211,7 @@ static const AspeedSegments
> aspeed_2500_spi2_segments[];
> >   #define ASPEED_SMC_FEATURE_DMA       0x1
> >   #define ASPEED_SMC_FEATURE_DMA_GRANT 0x2
> >   #define ASPEED_SMC_FEATURE_WDT_CONTROL 0x4
> > +#define ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH 0x08
> >
> >   static inline bool aspeed_smc_has_dma(const AspeedSMCClass *asc)
> >   {
> > @@ -218,6 +223,11 @@ static inline bool
> aspeed_smc_has_wdt_control(const AspeedSMCClass *asc)
> >       return !!(asc->features & ASPEED_SMC_FEATURE_WDT_CONTROL);
> >   }
> >
> > +static inline bool aspeed_smc_has_dma_dram_addr_high(const
> > +AspeedSMCClass *asc) {
> > +    return !!(asc->features &
> ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH);
> > +}
> > +
> >   #define aspeed_smc_error(fmt, ...)
> \
> >       qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt "\n", __func__, ##
> > __VA_ARGS__)
> >
> > @@ -747,6 +757,9 @@ static uint64_t aspeed_smc_read(void *opaque,
> hwaddr addr, unsigned int size)
> >           (aspeed_smc_has_dma(asc) && addr == R_DMA_CTRL) ||
> >           (aspeed_smc_has_dma(asc) && addr == R_DMA_FLASH_ADDR)
> ||
> >           (aspeed_smc_has_dma(asc) && addr == R_DMA_DRAM_ADDR)
> ||
> > +        (aspeed_smc_has_dma(asc) &&
> > +         aspeed_smc_has_dma_dram_addr_high(asc) &&
> > +         addr == R_DMA_DRAM_ADDR_HIGH) ||
> >           (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN) ||
> >           (aspeed_smc_has_dma(asc) && addr == R_DMA_CHECKSUM)
> ||
> >           (addr >= R_SEG_ADDR0 &&
> > @@ -847,6 +860,23 @@ static bool
> aspeed_smc_inject_read_failure(AspeedSMCState *s)
> >       }
> >   }
> >
> > +static uint64_t aspeed_smc_dma_dram_addr(AspeedSMCState *s) {
> > +    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
> > +    uint64_t dram_addr_high;
> > +    uint64_t dma_dram_addr;
> > +
> > +    if (aspeed_smc_has_dma_dram_addr_high(asc)) {
> > +        dram_addr_high = s->regs[R_DMA_DRAM_ADDR_HIGH];
> > +        dram_addr_high <<= 32;
> > +        dma_dram_addr = dram_addr_high |
> s->regs[R_DMA_DRAM_ADDR];
> > +    } else {
> > +        dma_dram_addr = s->regs[R_DMA_DRAM_ADDR];
> > +    }
> > +
> > +    return dma_dram_addr;
> > +}
> > +
> >   static uint32_t aspeed_smc_dma_len(AspeedSMCState *s)
> >   {
> >       AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); @@ -914,24
> > +944,34 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
> >
> >   static void aspeed_smc_dma_rw(AspeedSMCState *s)
> >   {
> > +    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
> > +    uint64_t dram_addr_high;
> 
> dram_addr_high can be removed
> 
> > +    uint64_t dma_dram_addr;
> > +    uint64_t dram_addr;
> 
> please call this variable dma_dram_offset, I found it less confusing.
> 
> >       MemTxResult result;
> >       uint32_t dma_len;
> >       uint32_t data;
> >
> >       dma_len = aspeed_smc_dma_len(s);
> > +    dma_dram_addr = aspeed_smc_dma_dram_addr(s);
> > +
> > +    if (aspeed_smc_has_dma_dram_addr_high(asc)) {
> > +        dram_addr = dma_dram_addr - s->dram_mr->container->addr;
> > +    } else {
> > +        dram_addr = dma_dram_addr;
> > +    }
> >
> 
> With the new "dram-base" property, the above if can be replaced by :
> 
>      dma_dram_offset = dma_dram_addr - s->dram_base;
> 
> 
Again, I appreciate your kindly support and thanks for your suggestion.
Will update them.

> Thanks,
> 
> C.
> 
> 
> >       trace_aspeed_smc_dma_rw(s->regs[R_DMA_CTRL] &
> DMA_CTRL_WRITE ?
> >                               "write" : "read",
> >                               s->regs[R_DMA_FLASH_ADDR],
> > -                            s->regs[R_DMA_DRAM_ADDR],
> > +                            dram_addr,
> >                               dma_len);
> >       while (dma_len) {
> >           if (s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE) {
> > -            data = address_space_ldl_le(&s->dram_as,
> s->regs[R_DMA_DRAM_ADDR],
> > +            data = address_space_ldl_le(&s->dram_as, dram_addr,
> >
> MEMTXATTRS_UNSPECIFIED, &result);
> >               if (result != MEMTX_OK) {
> > -                aspeed_smc_error("DRAM read failed @%08x",
> > -                                 s->regs[R_DMA_DRAM_ADDR]);
> > +                aspeed_smc_error("DRAM read failed @%" PRIx64,
> > + dram_addr);
> >                   return;
> >               }
> >
> > @@ -951,11 +991,10 @@ static void aspeed_smc_dma_rw(AspeedSMCState
> *s)
> >                   return;
> >               }
> >
> > -            address_space_stl_le(&s->dram_as,
> s->regs[R_DMA_DRAM_ADDR],
> > +            address_space_stl_le(&s->dram_as, dram_addr,
> >                                    data,
> MEMTXATTRS_UNSPECIFIED, &result);
> >               if (result != MEMTX_OK) {
> > -                aspeed_smc_error("DRAM write failed @%08x",
> > -                                 s->regs[R_DMA_DRAM_ADDR]);
> > +                aspeed_smc_error("DRAM write failed @%" PRIx64,
> > + dram_addr);
> >                   return;
> >               }
> >           }
> > @@ -964,8 +1003,15 @@ static void aspeed_smc_dma_rw(AspeedSMCState
> *s)
> >            * When the DMA is on-going, the DMA registers are updated
> >            * with the current working addresses and length.
> >            */
> > +        dram_addr += 4;
> > +        dma_dram_addr += 4;
> > +        if (aspeed_smc_has_dma_dram_addr_high(asc)) {
> > +            dram_addr_high = dma_dram_addr >> 32;
> > +            s->regs[R_DMA_DRAM_ADDR_HIGH] = dram_addr_high;
> > +        }
> > +
> > +        s->regs[R_DMA_DRAM_ADDR] = dma_dram_addr & 0xffffffff;
> >           s->regs[R_DMA_FLASH_ADDR] += 4;
> > -        s->regs[R_DMA_DRAM_ADDR] += 4;
> >           dma_len -= 4;
> >           s->regs[R_DMA_LEN] = dma_len;
> >           s->regs[R_DMA_CHECKSUM] += data; @@ -1118,6 +1164,10
> @@
> > static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data,
> >       } else if (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN &&
> >                  aspeed_smc_dma_granted(s)) {
> >           s->regs[addr] = DMA_LENGTH(value);
> > +    } else if (aspeed_smc_has_dma(asc) &&
> > +               aspeed_smc_has_dma_dram_addr_high(asc) &&
> > +               addr == R_DMA_DRAM_ADDR_HIGH) {
> > +        s->regs[addr] = DMA_DRAM_ADDR_HIGH(value);
> >       } else {
> >           qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%"
> HWADDR_PRIx "\n",
> >                         __func__, addr); diff --git
> > a/hw/ssi/trace-events b/hw/ssi/trace-events index
> > 2d5bd2b83d..7b5ad6a939 100644
> > --- a/hw/ssi/trace-events
> > +++ b/hw/ssi/trace-events
> > @@ -6,7 +6,7 @@ aspeed_smc_do_snoop(int cs, int index, int dummies, int
> data) "CS%d index:0x%x d
> >   aspeed_smc_flash_write(int cs, uint64_t addr,  uint32_t size, uint64_t
> data, int mode) "CS%d @0x%" PRIx64 " size %u: 0x%" PRIx64" mode:%d"
> >   aspeed_smc_read(uint64_t addr,  uint32_t size, uint64_t data) "@0x%"
> PRIx64 " size %u: 0x%" PRIx64
> >   aspeed_smc_dma_checksum(uint32_t addr, uint32_t data) "0x%08x:
> 0x%08x"
> > -aspeed_smc_dma_rw(const char *dir, uint32_t flash_addr, uint32_t
> dram_addr, uint32_t size) "%s flash:@0x%08x dram:@0x%08x size:0x%08x"
> > +aspeed_smc_dma_rw(const char *dir, uint32_t flash_addr, uint64_t
> dram_addr, uint32_t size) "%s flash:@0x%08x dram:@0x%" PRIx64 "
> size:0x%08x"
> >   aspeed_smc_write(uint64_t addr,  uint32_t size, uint64_t data) "@0x%"
> PRIx64 " size %u: 0x%" PRIx64
> >   aspeed_smc_flash_select(int cs, const char *prefix) "CS%d %sselect"
> >


^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2024-05-15  9:02 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-04-16  9:18 [PATCH v3 00/16] Add AST2700 support Jamin Lin via
2024-04-16  9:18 ` [PATCH v3 01/16] aspeed/wdt: " Jamin Lin via
2024-04-16  9:18 ` [PATCH v3 02/16] aspeed/sli: " Jamin Lin via
2024-04-16 15:29   ` Cédric Le Goater
2024-04-16  9:18 ` [PATCH v3 03/16] aspeed/sdmc: remove redundant macros Jamin Lin via
2024-04-16 15:30   ` Cédric Le Goater
2024-04-16  9:18 ` [PATCH v3 04/16] aspeed/sdmc: fix coding style Jamin Lin via
2024-04-16 15:30   ` Cédric Le Goater
2024-04-16  9:18 ` [PATCH v3 05/16] aspeed/sdmc: Add AST2700 support Jamin Lin via
2024-04-16 15:34   ` Cédric Le Goater
2024-04-16  9:18 ` [PATCH v3 06/16] aspeed/smc: correct device description Jamin Lin via
2024-04-16 15:34   ` Cédric Le Goater
2024-04-16  9:18 ` [PATCH v3 07/16] aspeed/smc: fix dma moving incorrect data length issue Jamin Lin via
2024-04-19 13:41   ` Cédric Le Goater
2024-04-30  7:22     ` Cédric Le Goater
2024-04-30  8:51       ` Jamin Lin
2024-05-03 14:35         ` Cédric Le Goater
2024-05-15  4:05           ` Jamin Lin
2024-04-16  9:18 ` [PATCH v3 08/16] aspeed/smc: support 64 bits dma dram address Jamin Lin via
2024-04-18 16:09   ` Cédric Le Goater
2024-04-19  6:00     ` Jamin Lin
2024-04-30  7:26       ` Cédric Le Goater
2024-04-30  7:56         ` Jamin Lin
2024-05-03 14:20           ` Cédric Le Goater
2024-05-15  8:56             ` Jamin Lin
2024-05-07 14:19   ` Cédric Le Goater
2024-05-15  9:01     ` Jamin Lin
2024-04-16  9:18 ` [PATCH v3 09/16] aspeed/smc: Add AST2700 support Jamin Lin via
2024-04-18 16:14   ` Cédric Le Goater
2024-04-16  9:18 ` [PATCH v3 10/16] aspeed/scu: " Jamin Lin via
2024-04-16  9:18 ` [PATCH v3 11/16] aspeed/intc: " Jamin Lin via
2024-05-07 13:33   ` Cédric Le Goater
2024-04-16  9:18 ` [PATCH v3 12/16] aspeed/soc: " Jamin Lin via
2024-04-19  7:10   ` Cédric Le Goater
2024-04-19  7:58     ` Jamin Lin
2024-05-07 13:06   ` Cédric Le Goater
2024-04-16  9:19 ` [PATCH v3 13/16] aspeed: Add an AST2700 eval board Jamin Lin via
2024-04-16  9:19 ` [PATCH v3 14/16] aspeed/soc: fix incorrect dram size for AST2700 Jamin Lin via
2024-04-16  9:19 ` [PATCH v3 15/16] test/avocado/machine_aspeed.py: Add AST2700 test case Jamin Lin via
2024-04-16 16:44   ` Cédric Le Goater
2024-04-16  9:19 ` [PATCH v3 16/16] docs:aspeed: Add AST2700 Evaluation board Jamin Lin via
2024-04-16 15:54   ` Cédric Le Goater

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.