All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jamin Lin <jamin_lin@aspeedtech.com>
To: "Cédric Le Goater" <clg@kaod.org>,
	"Peter Maydell" <peter.maydell@linaro.org>,
	"Steven Lee" <steven_lee@aspeedtech.com>,
	"Troy Lee" <leetroy@gmail.com>,
	"Kane Chen" <kane_chen@aspeedtech.com>,
	"Andrew Jeffery" <andrew@codeconstruct.com.au>,
	"Joel Stanley" <joel@jms.id.au>,
	"Pierrick Bouvier" <pierrick.bouvier@linaro.org>,
	"Alistair Francis" <alistair@alistair23.me>,
	"Kevin Wolf" <kwolf@redhat.com>,
	"Hanna Reitz" <hreitz@redhat.com>,
	"open list:ASPEED BMCs" <qemu-arm@nongnu.org>,
	"open list:All patches CC here" <qemu-devel@nongnu.org>,
	"open list:Block layer core" <qemu-block@nongnu.org>
Cc: Jamin Lin <jamin_lin@aspeedtech.com>, Troy Lee <troy_lee@aspeedtech.com>
Subject: [PATCH v4 15/21] hw/ssi/aspeed_smc: Add Data FIFO-based flash access support for AST2700
Date: Fri, 17 Apr 2026 03:28:58 +0000	[thread overview]
Message-ID: <20260417032837.2664122-16-jamin_lin@aspeedtech.com> (raw)
In-Reply-To: <20260417032837.2664122-1-jamin_lin@aspeedtech.com>

AST2700 supports a Data FIFO mode where flash accesses can be performed
directly through Data FIFO MMIO offsets. The Data FIFO start offset
increments by one for every 16MB of flash address space, allowing the
chip select (CS) to be decoded from the Data FIFO offset.

This change adds Data FIFO support to the Aspeed SMC model and introduces
a class callback to translate Data FIFO offsets into CS indices. For
AST2700, the Data FIFO offset is matched against the segment start address
of each CS to determine the target flash device.

The SMC register region size (nregs) is also extended dynamically
based on the number of supported chip selects to cover all possible
Data FIFO regions.

Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
 include/hw/ssi/aspeed_smc.h |   3 +-
 hw/ssi/aspeed_smc.c         | 113 +++++++++++++++++++++++++++++++++---
 2 files changed, 107 insertions(+), 9 deletions(-)

diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h
index 76831422c6..640efade94 100644
--- a/include/hw/ssi/aspeed_smc.h
+++ b/include/hw/ssi/aspeed_smc.h
@@ -47,7 +47,7 @@ struct AspeedSMCFlash {
 #define TYPE_ASPEED_SMC "aspeed.smc"
 OBJECT_DECLARE_TYPE(AspeedSMCState, AspeedSMCClass, ASPEED_SMC)
 
-#define ASPEED_SMC_R_MAX        (0x100 / 4)
+#define ASPEED_SMC_R_MAX        (0x300 / 4)
 #define ASPEED_SMC_CS_MAX       5
 
 struct AspeedSMCState {
@@ -116,6 +116,7 @@ struct AspeedSMCClass {
                            AspeedSegments *seg);
     void (*dma_ctrl)(AspeedSMCState *s, uint32_t value);
     int (*addr_width)(const AspeedSMCState *s);
+    int (*data_fifo_offset_to_cs)(const AspeedSMCState *s, uint32_t offset);
     const MemoryRegionOps *reg_ops;
 };
 
diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index f0deeea996..186446c1ec 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -163,6 +163,9 @@
 /* Read Timing Compensation Register */
 #define R_TIMINGS         (0x94 / 4)
 
+/* Data fifo */
+#define R_DATA_FIFO       (0x200 / 4)
+
 /* SPI controller registers and bits (AST2400) */
 #define R_SPI_CONF        (0x00 / 4)
 #define   SPI_CONF_ENABLE_W0   0
@@ -212,6 +215,7 @@ static const AspeedSegments aspeed_2500_spi2_segments[];
 #define ASPEED_SMC_FEATURE_DMA_GRANT 0x2
 #define ASPEED_SMC_FEATURE_WDT_CONTROL 0x4
 #define ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH 0x08
+#define ASPEED_SMC_FEATURE_DATA_FIFO 0x10
 
 static inline bool aspeed_smc_has_dma(const AspeedSMCClass *asc)
 {
@@ -228,6 +232,11 @@ static inline bool aspeed_smc_has_dma64(const AspeedSMCClass *asc)
     return !!(asc->features & ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH);
 }
 
+static inline bool aspeed_smc_has_data_fifo(const AspeedSMCClass *asc)
+{
+    return !!(asc->features & ASPEED_SMC_FEATURE_DATA_FIFO);
+}
+
 #define aspeed_smc_error(fmt, ...)                                      \
     qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt "\n", __func__, ## __VA_ARGS__)
 
@@ -764,6 +773,7 @@ static MemTxResult aspeed_smc_read(void *opaque, hwaddr addr, uint64_t *data,
 {
     AspeedSMCState *s = ASPEED_SMC(opaque);
     AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(opaque);
+    int cs;
 
     addr >>= 2;
 
@@ -789,6 +799,18 @@ static MemTxResult aspeed_smc_read(void *opaque, hwaddr addr, uint64_t *data,
         trace_aspeed_smc_read(addr << 2, size, s->regs[addr]);
 
         *data = s->regs[addr];
+    } else if (aspeed_smc_has_data_fifo(asc) && addr >= R_DATA_FIFO) {
+        cs = asc->data_fifo_offset_to_cs(s, addr << 2);
+        if (cs >= 0) {
+            /*
+             * Data fifo mode only supports SPI user mode.
+             * The flash address is provided by the SPI command/address cycles,
+             * the MMIO addr parameter is ignored.
+             */
+            return aspeed_smc_flash_read(&s->flashes[cs], 0, data, size, attrs);
+        }
+        aspeed_smc_error("Invalid data fifo offset %" HWADDR_PRIx, addr << 2);
+        return MEMTX_ERROR;
     } else {
         qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n",
                       __func__, addr);
@@ -1163,6 +1185,19 @@ static MemTxResult aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data,
     } else if (aspeed_smc_has_dma(asc) && aspeed_smc_has_dma64(asc) &&
                addr == R_DMA_DRAM_ADDR_HIGH) {
         s->regs[addr] = DMA_DRAM_ADDR_HIGH(value);
+    } else if (aspeed_smc_has_data_fifo(asc) && addr >= R_DATA_FIFO) {
+        int cs = asc->data_fifo_offset_to_cs(s, addr << 2);
+        if (cs >= 0) {
+            /*
+             * Data fifo mode only supports SPI user mode.
+             * The flash address is provided by the SPI command/address cycles,
+             * the MMIO addr parameter is ignored.
+             */
+            return aspeed_smc_flash_write(&s->flashes[cs], 0, data, size,
+                                          attrs);
+        }
+        aspeed_smc_error("Invalid data fifo offset %" HWADDR_PRIx, addr << 2);
+        return MEMTX_ERROR;
     } else {
         qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n",
                       __func__, addr);
@@ -1996,6 +2031,39 @@ static void aspeed_2700_smc_reg_to_segment(const AspeedSMCState *s,
     }
 }
 
+/*
+ * Convert a data fifo offset to a chip select (CS).
+ *
+ * Data fifo access starts at 0x200. The data fifo offset index is
+ * calculated by subtracting the data fifo base offset from the MMIO address.
+ *
+ * The data fifo offset index increments by 1 for every 16MB of flash address
+ * space. Each offset step therefore represents a 16MB address decode range.
+ *
+ * The CS is determined by matching the data fifo offset index against the
+ * segment start address of each CS.
+ *
+ * Returns the CS index on success, or -1 if the offset is invalid.
+ */
+static int aspeed_2700_smc_data_fifo_offset_to_cs(const AspeedSMCState *s,
+                                                  uint32_t offset)
+{
+    AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
+    uint32_t start_offset;
+    uint32_t fifo_offset;
+    int i;
+
+    for (i = 0; i < asc->cs_num_max; i++) {
+        start_offset = (s->regs[R_SEG_ADDR0 + i] & 0x0000ffff) << 16;
+        fifo_offset = start_offset / 0x1000000;
+        if (fifo_offset == offset - (R_DATA_FIFO << 2)) {
+            return i;
+        }
+    }
+
+    return -1;
+}
+
 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),
@@ -2030,6 +2098,27 @@ static const AspeedSegments aspeed_2700_fmc_segments[] = {
     { 0x0, 0 }, /* disabled */
 };
 
+/*
+ * AST2700 supports data fifo mode with a base data fifo start offset of 0x200.
+ *
+ * The data fifo start offset increments by 1 for every 16MB of flash address
+ * space. Each offset step therefore represents a 16MB address decode range.
+ *
+ * Assuming each chip select (CS) can use the maximum flash size of 256MB:
+ *   256MB / 16MB = 0x10 offset steps per CS.
+ *
+ * Data fifo start offset for CSn:
+ *   0x200 + (n * 0x10)
+ *
+ * Examples:
+ *   CS0: 0x200
+ *   CS1: 0x210
+ *   CS2: 0x220
+ *   CS3: 0x230
+ *
+ * asc->nregs should be set to: 0x200 + (asc->cs_num_max * 0x10)
+ * to cover all possible data fifo regions.
+ */
 static void aspeed_2700_fmc_class_init(ObjectClass *klass, const void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -2049,14 +2138,16 @@ static void aspeed_2700_fmc_class_init(ObjectClass *klass, const void *data)
     asc->flash_window_base = 0x100000000;
     asc->flash_window_size = 1 * GiB;
     asc->features          = ASPEED_SMC_FEATURE_DMA |
-                             ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH;
+                             ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH |
+                             ASPEED_SMC_FEATURE_DATA_FIFO;
     asc->dma_flash_mask    = 0x2FFFFFFC;
     asc->dma_dram_mask     = 0xFFFFFFFC;
     asc->dma_start_length  = 1;
-    asc->nregs             = ASPEED_SMC_R_MAX;
+    asc->nregs             = 0x200 + (asc->cs_num_max * 0x10);
     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;
+    asc->data_fifo_offset_to_cs = aspeed_2700_smc_data_fifo_offset_to_cs;
     asc->reg_ops           = &aspeed_2700_smc_flash_ops;
 }
 
@@ -2090,14 +2181,16 @@ static void aspeed_2700_spi0_class_init(ObjectClass *klass, const void *data)
     asc->flash_window_base = 0x180000000;
     asc->flash_window_size = 1 * GiB;
     asc->features          = ASPEED_SMC_FEATURE_DMA |
-                             ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH;
+                             ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH |
+                             ASPEED_SMC_FEATURE_DATA_FIFO;
     asc->dma_flash_mask    = 0x2FFFFFFC;
     asc->dma_dram_mask     = 0xFFFFFFFC;
     asc->dma_start_length  = 1;
-    asc->nregs             = ASPEED_SMC_R_MAX;
+    asc->nregs             = 0x200 + (asc->cs_num_max * 0x10);
     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;
+    asc->data_fifo_offset_to_cs = aspeed_2700_smc_data_fifo_offset_to_cs;
     asc->reg_ops           = &aspeed_2700_smc_flash_ops;
 }
 
@@ -2130,14 +2223,16 @@ static void aspeed_2700_spi1_class_init(ObjectClass *klass, const void *data)
     asc->flash_window_base = 0x200000000;
     asc->flash_window_size = 1 * GiB;
     asc->features          = ASPEED_SMC_FEATURE_DMA |
-                             ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH;
+                             ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH |
+                             ASPEED_SMC_FEATURE_DATA_FIFO;
     asc->dma_flash_mask    = 0x2FFFFFFC;
     asc->dma_dram_mask     = 0xFFFFFFFC;
     asc->dma_start_length  = 1;
-    asc->nregs             = ASPEED_SMC_R_MAX;
+    asc->nregs             = 0x200 + (asc->cs_num_max * 0x10);
     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;
+    asc->data_fifo_offset_to_cs = aspeed_2700_smc_data_fifo_offset_to_cs;
     asc->reg_ops           = &aspeed_2700_smc_flash_ops;
 }
 
@@ -2170,14 +2265,16 @@ static void aspeed_2700_spi2_class_init(ObjectClass *klass, const void *data)
     asc->flash_window_base = 0x280000000;
     asc->flash_window_size = 1 * GiB;
     asc->features          = ASPEED_SMC_FEATURE_DMA |
-                             ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH;
+                             ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH |
+                             ASPEED_SMC_FEATURE_DATA_FIFO;
     asc->dma_flash_mask    = 0x0FFFFFFC;
     asc->dma_dram_mask     = 0xFFFFFFFC;
     asc->dma_start_length  = 1;
-    asc->nregs             = ASPEED_SMC_R_MAX;
+    asc->nregs             = 0x200 + (asc->cs_num_max * 0x10);
     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;
+    asc->data_fifo_offset_to_cs = aspeed_2700_smc_data_fifo_offset_to_cs;
     asc->reg_ops           = &aspeed_2700_smc_flash_ops;
 }
 
-- 
2.43.0


  parent reply	other threads:[~2026-04-17  3:32 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-17  3:28 [PATCH v4 00/21] Add SSP/TSP power control and DRAM remap support for AST2700 Jamin Lin
2026-04-17  3:28 ` [PATCH v4 01/21] hw/misc/aspeed_scu: Introduce Aspeed2700SCU subclass and separate from generic SCU Jamin Lin
2026-06-01 17:05   ` Cédric Le Goater
2026-04-17  3:28 ` [PATCH v4 02/21] hw/misc/aspeed_scu: Add separate reset handler for AST2700 SCUIO Jamin Lin
2026-04-17  3:28 ` [PATCH v4 03/21] hw/arm/ast27x0: Start SSP in powered-off state to match hardware behavior Jamin Lin
2026-04-17  3:28 ` [PATCH v4 04/21] hw/arm/ast27x0: Start TSP " Jamin Lin
2026-04-17  3:28 ` [PATCH v4 05/21] hw/arm/ast27x0: Add DRAM alias for SSP SDRAM remap Jamin Lin
2026-06-01 17:07   ` Cédric Le Goater
2026-04-17  3:28 ` [PATCH v4 06/21] hw/arm/ast27x0: Add DRAM alias for TSP " Jamin Lin
2026-04-17  3:28 ` [PATCH v4 07/21] hw/misc/aspeed_scu: Implement SSP reset and power-on control via SCU registers Jamin Lin
2026-04-17  3:28 ` [PATCH v4 08/21] hw/misc/aspeed_scu: Implement TSP " Jamin Lin
2026-04-17  3:28 ` [PATCH v4 09/21] hw/misc/aspeed_scu: Add SCU support for SSP SDRAM remap Jamin Lin
2026-06-01 17:28   ` Cédric Le Goater
2026-04-17  3:28 ` [PATCH v4 10/21] hw/misc/aspeed_scu: Add SCU support for TSP " Jamin Lin
2026-04-17  3:28 ` [PATCH v4 11/21] hw/arm/ast27x0: Share FMC controller with SSP and TSP Jamin Lin
2026-06-01 17:18   ` Cédric Le Goater
2026-04-17  3:28 ` [PATCH v4 12/21] hw/arm/aspeed_ast27x0: Add unimplemented Privilege Controller MMIO regions for SSP/TSP Jamin Lin
2026-06-01 17:19   ` Cédric Le Goater
2026-04-17  3:28 ` [PATCH v4 13/21] hw/arm/aspeed_ast27x0: Add unimplemented OTP controller " Jamin Lin
2026-06-01 17:19   ` Cédric Le Goater
2026-04-17  3:28 ` [PATCH v4 14/21] hw/block/m25p80: Implement volatile status register write enable for Winbond Jamin Lin
2026-06-01 17:31   ` Cédric Le Goater
2026-04-17  3:28 ` Jamin Lin [this message]
2026-04-17  3:28 ` [PATCH v4 16/21] hw/misc/aspeed_scu: Drop noisy unhandled read logs for AST2700 SCU/SCUIO Jamin Lin
2026-06-01 17:20   ` Cédric Le Goater
2026-04-17  3:29 ` [PATCH v4 17/21] hw/misc/aspeed_scu: Add AST2700 SCUIO RNG control and data registers Jamin Lin
2026-06-01 17:21   ` Cédric Le Goater
2026-04-17  3:29 ` [PATCH v4 18/21] hw/arm/ast27x0: Share single SCUIO instance across PSP, SSP, and TSP Jamin Lin
2026-06-01 17:23   ` Cédric Le Goater
2026-04-17  3:29 ` [PATCH v4 19/21] hw/arm/aspeed_ast27x0-fc: Fix hardware strap settings Jamin Lin
2026-06-01 17:23   ` Cédric Le Goater
2026-04-17  3:29 ` [PATCH v4 20/21] tests/functional/aarch64/test_aspeed_ast2700fc: Boot SSP/TSP via PSP and load binaries from DRAM Jamin Lin
2026-04-17  3:29 ` [PATCH v4 21/21] docs: Add support vbootrom and update Manual boot for ast2700fc Jamin Lin
2026-05-21  6:42 ` [PATCH v4 00/21] Add SSP/TSP power control and DRAM remap support for AST2700 Cédric Le Goater
2026-05-21  6:47   ` Jamin Lin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260417032837.2664122-16-jamin_lin@aspeedtech.com \
    --to=jamin_lin@aspeedtech.com \
    --cc=alistair@alistair23.me \
    --cc=andrew@codeconstruct.com.au \
    --cc=clg@kaod.org \
    --cc=hreitz@redhat.com \
    --cc=joel@jms.id.au \
    --cc=kane_chen@aspeedtech.com \
    --cc=kwolf@redhat.com \
    --cc=leetroy@gmail.com \
    --cc=peter.maydell@linaro.org \
    --cc=pierrick.bouvier@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=steven_lee@aspeedtech.com \
    --cc=troy_lee@aspeedtech.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.