]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
spi: stm32-qspi: Optimize FIFO accesses using u16 or u32
authorPatrice Chotard <patrice.chotard@foss.st.com>
Tue, 16 Dec 2025 15:31:54 +0000 (16:31 +0100)
committerPatrice Chotard <patrice.chotard@foss.st.com>
Thu, 29 Jan 2026 09:47:57 +0000 (10:47 +0100)
FIFO accesses uses u8 only for read/write.
In order to optimize throughput, add u16 or u32 read/write
accesses when possible.
Set FIFO threshold level value accordingly.

Test performed by writing and reading 64MB on sNOR on
stm32mp157c-ev1 board:

          before      after    ratio
Write :  428 KB/s   719 KB/s    +68%
Read  :  520 KB/s  3200 KB/s   +615%

Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
drivers/spi/stm32_qspi.c

index 1778f8c145861f71797c54b0371630a0deb307af..a02e0999ccbf96600665f7a82fc6b5e8c9ae8bf6 100644 (file)
@@ -50,6 +50,7 @@ struct stm32_qspi_regs {
 #define STM32_QSPI_CR_SSHIFT           BIT(4)
 #define STM32_QSPI_CR_DFM              BIT(6)
 #define STM32_QSPI_CR_FSEL             BIT(7)
+#define STM32_QSPI_CR_FTHRES_MASK      GENMASK(4, 0)
 #define STM32_QSPI_CR_FTHRES_SHIFT     8
 #define STM32_QSPI_CR_TEIE             BIT(16)
 #define STM32_QSPI_CR_TCIE             BIT(17)
@@ -162,23 +163,42 @@ static int _stm32_qspi_wait_cmd(struct stm32_qspi_priv *priv,
        return ret;
 }
 
-static void _stm32_qspi_read_fifo(u8 *val, void __iomem *addr)
+static void _stm32_qspi_read_fifo(void *val, void __iomem *addr, u8 len)
 {
-       *val = readb(addr);
+       switch (len) {
+       case sizeof(u32):
+               *((u32 *)val) = readl_relaxed(addr);
+               break;
+       case sizeof(u16):
+               *((u16 *)val) = readw_relaxed(addr);
+               break;
+       case sizeof(u8):
+               *((u8 *)val) = readb_relaxed(addr);
+       };
 }
 
-static void _stm32_qspi_write_fifo(u8 *val, void __iomem *addr)
+static void _stm32_qspi_write_fifo(void *val, void __iomem *addr, u8 len)
 {
-       writeb(*val, addr);
+       switch (len) {
+       case sizeof(u32):
+               writel_relaxed(*((u32 *)val), addr);
+               break;
+       case sizeof(u16):
+               writew_relaxed(*((u16 *)val), addr);
+               break;
+       case sizeof(u8):
+               writeb_relaxed(*((u8 *)val), addr);
+       };
 }
 
 static int _stm32_qspi_poll(struct stm32_qspi_priv *priv,
                            const struct spi_mem_op *op)
 {
-       void (*fifo)(u8 *val, void __iomem *addr);
+       void (*fifo)(void *val, void __iomem *addr, u8 len);
        u32 len = op->data.nbytes, sr;
-       u8 *buf;
+       void *buf;
        int ret;
+       u8 step = 0;
 
        if (op->data.dir == SPI_MEM_DATA_IN) {
                fifo = _stm32_qspi_read_fifo;
@@ -186,10 +206,10 @@ static int _stm32_qspi_poll(struct stm32_qspi_priv *priv,
 
        } else {
                fifo = _stm32_qspi_write_fifo;
-               buf = (u8 *)op->data.buf.out;
+               buf = (void *)op->data.buf.out;
        }
 
-       while (len--) {
+       while (len) {
                ret = readl_poll_timeout(&priv->regs->sr, sr,
                                         sr & STM32_QSPI_SR_FTF,
                                         STM32_QSPI_FIFO_TIMEOUT_US);
@@ -198,7 +218,23 @@ static int _stm32_qspi_poll(struct stm32_qspi_priv *priv,
                        return ret;
                }
 
-               fifo(buf++, &priv->regs->dr);
+               if (!IS_ALIGNED((uintptr_t)buf, sizeof(u32))) {
+                       if (!IS_ALIGNED((uintptr_t)buf, sizeof(u16)))
+                               step = sizeof(u8);
+                       else
+                               step = min((u32)len, (u32)sizeof(u16));
+               }
+               /* Buf is aligned */
+               else if (len >= sizeof(u32))
+                       step = sizeof(u32);
+               else if (len >= sizeof(u16))
+                       step = sizeof(u16);
+               else if (len)
+                       step = sizeof(u8);
+
+               fifo(buf, &priv->regs->dr, step);
+               len -= step;
+               buf += step;
 
                if (!(len % SZ_1M))
                        schedule();
@@ -383,6 +419,11 @@ static int stm32_qspi_probe(struct udevice *bus)
 
        priv->cs_used = -1;
 
+       clrsetbits_le32(&priv->regs->cr,
+                       STM32_QSPI_CR_FTHRES_MASK <<
+                       STM32_QSPI_CR_FTHRES_SHIFT,
+                       3 << STM32_QSPI_CR_FTHRES_SHIFT);
+
        setbits_le32(&priv->regs->cr, STM32_QSPI_CR_SSHIFT);
 
        /* Set dcr fsize to max address */