From a88df1d92fcf23d848e5fa6d7d2a1c38fd0174ed Mon Sep 17 00:00:00 2001 From: Zhengyu He Date: Wed, 15 Jul 2026 20:52:15 +0800 Subject: [PATCH 1/6] spi: spacemit: Correct TX FIFO slot calculation In k1_spi_write, the count variable is intended to represent the number of slots available for writing into the TX FIFO. The current implementation uses FIELD_GET(SSP_STATUS_TFL, val) in an attempt to determine this count, but this register field returns the number of occupied slots, not the available space. The previous implementation attempted to handle this via a ternary operator (? : K1_SPI_FIFO_SIZE), which incorrectly assumed that the hardware returned 0 when the FIFO was empty (meaning all slots were available), leading to incorrect accounting of the buffer space. Fix this by calculating the free slots: count = K1_SPI_FIFO_SIZE - FIELD_GET(SSP_STATUS_TFL, val); The associated comment has been updated to reflect the logic change: The old comment reflected an incorrect assumption about the hardware behavior, which was the root cause of the previous buggy logic. This patch accurately and concisely describes the purpose of the new calculation. Signed-off-by: Peixin Xie Signed-off-by: Zhengyu He Link: https://patch.msgid.link/20260715-k1-spi-tx-fifo-fix-v1-for-next-v1-1-02024223b08a@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-spacemit-k1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-spacemit-k1.c b/drivers/spi/spi-spacemit-k1.c index 215fe66d27b4..0faf7ffed676 100644 --- a/drivers/spi/spi-spacemit-k1.c +++ b/drivers/spi/spi-spacemit-k1.c @@ -494,8 +494,8 @@ static bool k1_spi_write(struct k1_spi_driver_data *drv_data, u32 val) { unsigned int count; - /* Get the number of open slots in the FIFO; zero means all */ - count = FIELD_GET(SSP_STATUS_TFL, val) ? : K1_SPI_FIFO_SIZE; + /* Get the number of free slots in the FIFO */ + count = K1_SPI_FIFO_SIZE - FIELD_GET(SSP_STATUS_TFL, val); /* * Limit how much we try to send at a time, to reduce the From 6389eaf11d6cd3a66d10d0a5ea9cd91f242ccba2 Mon Sep 17 00:00:00 2001 From: Zhengyu He Date: Fri, 17 Jul 2026 07:45:26 -0700 Subject: [PATCH 2/6] spi: dt-bindings: spacemit: add K3 SPI compatible The K3 SPI controller is compatible with K1, so allow K3 device trees to use "spacemit,k1-spi" as fallback. Signed-off-by: Cody Kang Signed-off-by: Zhengyu He Link: https://patch.msgid.link/20260717-k3-com260-spi-v7-2-rc2-b4-preview-20260716-v1-2-969a1b0f783f@gmail.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spacemit,k1-spi.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spi/spacemit,k1-spi.yaml b/Documentation/devicetree/bindings/spi/spacemit,k1-spi.yaml index e82c7f8d0b98..5d86cc87e4fb 100644 --- a/Documentation/devicetree/bindings/spi/spacemit,k1-spi.yaml +++ b/Documentation/devicetree/bindings/spi/spacemit,k1-spi.yaml @@ -24,7 +24,11 @@ allOf: properties: compatible: - const: spacemit,k1-spi + oneOf: + - const: spacemit,k1-spi + - items: + - const: spacemit,k3-spi + - const: spacemit,k1-spi reg: maxItems: 1 From d3c87e71539cb183ea6173a99dc0e6f84fa0bc4f Mon Sep 17 00:00:00 2001 From: Surendra Singh Chouhan Date: Wed, 22 Jul 2026 21:54:44 +0530 Subject: [PATCH 3/6] spi: spacemit: prepare both DMA descriptors before submitting k1_spi_dma_one() currently submits the TX DMA descriptor to the DMA engine before preparing the RX DMA descriptor. If preparing the RX descriptor subsequently fails, the function jumps to the fallback error path without canceling or aborting the already submitted TX DMA descriptor. Fix this by preparing both the TX and RX descriptors before submitting either of them to the DMA engine. Fixes: efcd8b9d1111 ("spi: spacemit: introduce SpacemiT K1 SPI controller driver") Reviewed-by: Alex Elder Signed-off-by: Surendra Singh Chouhan Link: https://patch.msgid.link/20260722162444.11415-1-kr494167@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-spacemit-k1.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/spi/spi-spacemit-k1.c b/drivers/spi/spi-spacemit-k1.c index 0faf7ffed676..fd5893a92e59 100644 --- a/drivers/spi/spi-spacemit-k1.c +++ b/drivers/spi/spi-spacemit-k1.c @@ -278,25 +278,25 @@ static int k1_spi_dma_one(struct spi_controller *host, struct spi_device *spi, struct spi_transfer *transfer) { struct k1_spi_driver_data *drv_data = spi_controller_get_devdata(host); - struct dma_async_tx_descriptor *desc; + struct dma_async_tx_descriptor *txdesc, *rxdesc; u32 val; - /* Prepare the TX descriptor and submit it */ - desc = k1_spi_dma_prep(drv_data, transfer, true); - if (!desc) + /* Prepare the TX descriptor */ + txdesc = k1_spi_dma_prep(drv_data, transfer, true); + if (!txdesc) goto fallback; - dmaengine_submit(desc); - /* Prepare the RX descriptor and submit it */ - desc = k1_spi_dma_prep(drv_data, transfer, false); - if (!desc) + /* Prepare the RX descriptor */ + rxdesc = k1_spi_dma_prep(drv_data, transfer, false); + if (!rxdesc) goto fallback; /* When RX is complete we also know TX has completed */ - desc->callback = k1_spi_dma_callback; - desc->callback_param = drv_data; + rxdesc->callback = k1_spi_dma_callback; + rxdesc->callback_param = drv_data; - dmaengine_submit(desc); + dmaengine_submit(txdesc); + dmaengine_submit(rxdesc); val = readl(drv_data->base + SSP_TOP_CTRL); val |= TOP_TRAIL; /* Trailing bytes handled by DMA */ From 90ef2f2961c2dc55957dafe2f53b3efdb4675efc Mon Sep 17 00:00:00 2001 From: Vijaya Krishna Nivarthi Date: Wed, 22 Jul 2026 14:53:58 +0530 Subject: [PATCH 4/6] spi: qcom-qspi: Correct max DMA length to avoid 64K boundary failure The maximum size for a DMA data descriptor is 64KB-1 because the size field in HW is 16 bits wide. For this reason, transfers fail at 64KB and beyond. Lower max_dma_len to 60KB so larger transfers are split into multiple DMA blocks and do not hit the failing 64KB boundary. 60KB is chosen as a safe round number below the 64KB-1 hardware limit while satisfying alignment requirements. Tested on x1e80100 (Hamoa) with SPI-NOR flash (/dev/mtd0): Without patch: dd if=/dev/mtd0 of=/tmp/spi_dump.bin bs=32768 count=2 # works dd if=/dev/mtd0 of=/tmp/spi_dump.bin bs=65536 count=1 # fails With patch: dd if=/dev/mtd0 of=/tmp/spi_dump.bin bs=65536 count=1 # works Fixes: b5762d95607e ("spi: spi-qcom-qspi: Add DMA mode support") Cc: stable@vger.kernel.org Signed-off-by: Vijaya Krishna Nivarthi Link: https://patch.msgid.link/20260722092358.459943-1-vnivarth@qti.qualcomm.com Signed-off-by: Mark Brown --- drivers/spi/spi-qcom-qspi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c index caf55a6f70b3..e9fdefa9d65d 100644 --- a/drivers/spi/spi-qcom-qspi.c +++ b/drivers/spi/spi-qcom-qspi.c @@ -775,7 +775,8 @@ static int qcom_qspi_probe(struct platform_device *pdev) return dev_err_probe(dev, ret, "could not set DMA mask\n"); host->max_speed_hz = 300000000; - host->max_dma_len = 65536; /* as per HPG */ + /* as per HPG, it is 64KB, limit to 60KB to avoid boundary condition failures */ + host->max_dma_len = 0xf000; host->dma_alignment = QSPI_ALIGN_REQ; host->num_chipselect = QSPI_NUM_CS; host->bus_num = -1; From d9eadfce2fac49445db40808fe4d8259f20a9d2b Mon Sep 17 00:00:00 2001 From: Srikanth Boyapally Date: Mon, 20 Jul 2026 18:25:10 +0530 Subject: [PATCH 5/6] spi: spi-cadence: Move TX FIFO full busy-wait into FIFO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SPI host transfers could intermittently stall with spi_transfer timeouts. The TXFULL condition was checked only once in cdns_transfer_one() before cdns_spi_process_fifo(), so if the FIFO became full again during refill, writes could be dropped and the transfer would never complete. Move the TXFULL busy-wait into the TX path of cdns_spi_process_fifo() so the 10µs back-off is applied per FIFO entry during filling, ensuring forward progress and eliminating spurious timeouts. Restrict the delay to host mode using spi_controller_is_target(), the controller is passed into cdns_spi_process_fifo() so the check is made at the point of use. In target mode this delay must not run as it causes the target to miss its transfer window and corrupt data. Fixes: 49530e641178 ("spi: cadence: Add usleep_range() for cdns_spi_fill_tx_fifo()") Signed-off-by: Srikanth Boyapally Reviewed-by: Radhey Shyam Pandey Link: https://patch.msgid.link/20260720125510.60166-1-srikanth.boyapally@amd.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 9b4e5b7013ae..af1a05e78492 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -388,11 +388,13 @@ static inline void cdns_spi_writer(struct cdns_spi *xspi) /** * cdns_spi_process_fifo - Fills the TX FIFO, and drain the RX FIFO + * @ctlr: Pointer to the spi_controller structure * @xspi: Pointer to the cdns_spi structure * @ntx: Number of bytes to pack into the TX FIFO * @nrx: Number of bytes to drain from the RX FIFO */ -static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx) +static void cdns_spi_process_fifo(struct spi_controller *ctlr, + struct cdns_spi *xspi, int ntx, int nrx) { ntx = clamp(ntx, 0, xspi->tx_bytes); nrx = clamp(nrx, 0, xspi->rx_bytes); @@ -407,6 +409,16 @@ static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx) } if (ntx) { + /* When xspi in busy condition, bytes may send failed, + * then spi control didn't work thoroughly, add one byte + * delay. Only in host mode; in target mode this delay + * causes data corruption as the target fails to prepare + * data in time. + */ + if (!spi_controller_is_target(ctlr) && + (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL)) + udelay(10); + cdns_spi_writer(xspi); ntx--; } @@ -460,14 +472,14 @@ static irqreturn_t cdns_spi_irq(int irq, void *dev_id) cdns_spi_write(xspi, CDNS_SPI_THLD, 1); if (xspi->tx_bytes) { - cdns_spi_process_fifo(xspi, trans_cnt, trans_cnt); + cdns_spi_process_fifo(ctlr, xspi, trans_cnt, trans_cnt); } else { /* Fixed delay due to controller limitation with * RX_NEMPTY incorrect status * Xilinx AR:65885 contains more details */ udelay(10); - cdns_spi_process_fifo(xspi, 0, trans_cnt); + cdns_spi_process_fifo(ctlr, xspi, 0, trans_cnt); cdns_spi_write(xspi, CDNS_SPI_IDR, CDNS_SPI_IXR_DEFAULT); spi_finalize_current_transfer(ctlr); @@ -520,17 +532,11 @@ static int cdns_transfer_one(struct spi_controller *ctlr, cdns_spi_write(xspi, CDNS_SPI_THLD, xspi->tx_fifo_depth >> 1); } - /* When xspi in busy condition, bytes may send failed, - * then spi control didn't work thoroughly, add one byte delay - */ - if (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL) - udelay(10); - xspi->n_bytes = cdns_spi_n_bytes(transfer); xspi->tx_bytes = DIV_ROUND_UP(xspi->tx_bytes, xspi->n_bytes); xspi->rx_bytes = DIV_ROUND_UP(xspi->rx_bytes, xspi->n_bytes); - cdns_spi_process_fifo(xspi, xspi->tx_fifo_depth, 0); + cdns_spi_process_fifo(ctlr, xspi, xspi->tx_fifo_depth, 0); cdns_spi_write(xspi, CDNS_SPI_IER, CDNS_SPI_IXR_DEFAULT); return transfer->len; From 8fd62901d6bf03f274a49dd0060793cc07dd51b0 Mon Sep 17 00:00:00 2001 From: Stanislaw Pal Date: Mon, 27 Jul 2026 18:32:16 +0200 Subject: [PATCH 6/6] spi: spi-qpic-snand: write the feature value before executing SET_FEATURE qcom_spi_send_cmdaddr() programs NAND_FLASH_CMD/NAND_EXEC_CMD and submits the descriptors, which makes the controller execute the command immediately. For SPINAND_SET_FEATURE the value to be written is only placed into NAND_FLASH_FEATURES afterwards, by qcom_spi_io_op(), in a second submission - so the chip is programmed with whatever that register happened to hold from a previous operation, and the intended value is only applied by the *next* SET_FEATURE. Measured on a TP-Link Archer AX55 v1 (IPQ5018, ESMT F50L1G41LB): writing 0x40 to the configuration register (0xb0) leaves the chip at 0x00, and the subsequent write of 0x00 leaves it at 0x40 - every write lands one operation late. This stayed unnoticed until v6.18 added SPI-NAND OTP support together with OTP entries for ESMT chips. spinand_otp_rw() enables OTP mode, reads, and disables it again, and mtd_otp_nvmem_add() does this during MTD registration. With the off-by-one, the "disable" write actually applies the previously requested value, so CFG_OTP_ENABLE ends up set: the chip stays in OTP mode, every subsequent array read returns the OTP area instead of the array (UBI reports an empty device) and all writes fail with -EIO because the OTP area is write protected. On this board that makes the whole flash unusable and the device unbootable. Write the feature value into NAND_FLASH_FEATURES as part of the same transaction, before NAND_EXEC_CMD. While at it, copy only the bytes the operation actually carries - the previous code dereferenced a 4-byte pointer on a one-byte buffer (spinand->scratchbuf). With this patch the flash contents read back bit-identical to a known-good dump of the same board taken under the vendor firmware (md5-verified across partitions), and writes work. Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface") Cc: stable@vger.kernel.org Signed-off-by: Stanislaw Pal Reviewed-by: Md Sadre Alam Link: https://patch.msgid.link/20260727163216.109938-1-kuncy7@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-qpic-snand.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 66f2d1b78ade..b6c58d9cfe14 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -1358,6 +1358,22 @@ static int qcom_spi_send_cmdaddr(struct qcom_nand_controller *snandc, snandc->regs->addr0 = cpu_to_le32(op->addr.val); snandc->regs->addr1 = cpu_to_le32(0); + /* + * The feature value has to reach NAND_FLASH_FEATURES before the + * command is executed, otherwise the controller programs the chip + * with whatever the register happened to hold from a previous + * operation. + */ + if (opcode == SPINAND_SET_FEATURE) { + u32 ftr = 0; + + memcpy(&ftr, op->data.buf.out, + min_t(size_t, op->data.nbytes, sizeof(ftr))); + snandc->regs->flash_feature = cpu_to_le32(ftr); + qcom_write_reg_dma(snandc, &snandc->regs->flash_feature, + NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL); + } + qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL); qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); @@ -1395,10 +1411,8 @@ static int qcom_spi_io_op(struct qcom_nand_controller *snandc, const struct spi_ copy_ftr = true; break; case SPINAND_SET_FEATURE: - snandc->regs->flash_feature = cpu_to_le32(*(u32 *)op->data.buf.out); - qcom_write_reg_dma(snandc, &snandc->regs->flash_feature, - NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL); - break; + /* fully handled by qcom_spi_send_cmdaddr() */ + return 0; case SPINAND_PROGRAM_EXECUTE: case SPINAND_WRITE_EN: case SPINAND_RESET: