[PATCH v2] spi: bcm63xx: fix premature CS deassertion on RX-only transactions

Hang Zhou
2025-11-16T14:09:36Z

On BCM6358 (and also observed on BCM6368) the controller appears to
only generate as many SPI clocks as bytes that have been written into
the TX FIFO. For RX-only transfers the driver programs the transfer
length in SPI_MSG_CTL but does not write anything into the FIFO, so
chip select is deasserted early and the RX transfer segment is never
fully clocked in.

A concrete failing case is a three-transfer MAC address read from
SPI-NOR:
- TX 0x03 (read command)
- TX 3-byte address
- RX 6 bytes (MAC)

In contrast, a two-transfer JEDEC-ID read (0x9f + 6-byte RX) works
because the driver uses prepend_len and writes dummy bytes into the
TX FIFO for the RX part.

Fix this by writing 0xff dummy bytes into the TX FIFO for RX-only
segments so that the number of bytes written to the FIFO matches the
total message length seen by the controller.

Fixes: b17de076062a ("spi/bcm63xx: work around inability to keep CS up")

Signed-off-by: Hang Zhou <929513338@qq.com>
---
drivers/spi/spi-bcm63xx.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)

diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index 8510400e7867..76ccd0f62c2e 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -154,6 +154,20 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,

if (t->rx_buf) {
do_rx = true;
+
+ /*
+ * In certain hardware implementations, there appears to be a
+ * hidden accumulator that tracks the number of bytes written into
+ * the hardware FIFO, and this accumulator overrides the length in
+ * the SPI_MSG_CTL register.
+ *
+ * Therefore, for read-only transfers, we need to write some dummy
+ * value into the FIFO to keep the accumulator tracking the correct
+ * length.
+ */
+ if (!t->tx_buf)
+ memset_io(bs->tx_io + len, 0xFF, t->len);
+
/* prepend is half-duplex write only */
if (t == first)
prepend_len = 0;
--
2.34.1