Skip to content

Commit fd9862f

Browse files
rikka0w0broonie
authored andcommitted
spi: bcm63xx: fix premature CS deassertion on RX-only transactions
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: b17de07 ("spi/bcm63xx: work around inability to keep CS up") Signed-off-by: Hang Zhou <929513338@qq.com> Link: https://patch.msgid.link/tencent_7AC88FCB3076489A4A7E6C2163DF1ACF8D06@qq.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 10eaa4c commit fd9862f

1 file changed

Lines changed: 14 additions & 0 deletions

File tree

drivers/spi/spi-bcm63xx.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,20 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
247247

248248
if (t->rx_buf) {
249249
do_rx = true;
250+
251+
/*
252+
* In certain hardware implementations, there appears to be a
253+
* hidden accumulator that tracks the number of bytes written into
254+
* the hardware FIFO, and this accumulator overrides the length in
255+
* the SPI_MSG_CTL register.
256+
*
257+
* Therefore, for read-only transfers, we need to write some dummy
258+
* value into the FIFO to keep the accumulator tracking the correct
259+
* length.
260+
*/
261+
if (!t->tx_buf)
262+
memset_io(bs->tx_io + len, 0xFF, t->len);
263+
250264
/* prepend is half-duplex write only */
251265
if (t == first)
252266
prepend_len = 0;

0 commit comments

Comments
 (0)