On Sun, 10 Jan 2021 at 08:15, Bin Meng <bmeng...@gmail.com> wrote: > > From: Bin Meng <bin.m...@windriver.com> > > The endianness of data exchange between tx and rx fifo is incorrect. > Earlier bytes are supposed to show up on MSB and later bytes on LSB, > ie: in big endian. The manual does not explicitly say this, but the > U-Boot and Linux driver codes have a swap on the data transferred > to tx fifo and from rx fifo. > > With this change, U-Boot read from / write to SPI flash tests pass. > > => sf test 1ff000 1000 > SPI flash test: > 0 erase: 0 ticks, 4096000 KiB/s 32768.000 Mbps > 1 check: 3 ticks, 1333 KiB/s 10.664 Mbps > 2 write: 235 ticks, 17 KiB/s 0.136 Mbps > 3 read: 2 ticks, 2000 KiB/s 16.000 Mbps > Test passed > 0 erase: 0 ticks, 4096000 KiB/s 32768.000 Mbps > 1 check: 3 ticks, 1333 KiB/s 10.664 Mbps > 2 write: 235 ticks, 17 KiB/s 0.136 Mbps > 3 read: 2 ticks, 2000 KiB/s 16.000 Mbps > > Fixes: c906a3a01582 ("i.MX: Add the Freescale SPI Controller") > Signed-off-by: Bin Meng <bin.m...@windriver.com> > > --- > > (no changes since v3) > > Changes in v3: > - Simplify the tx fifo endianness handling > > hw/ssi/imx_spi.c | 7 ++----- > 1 file changed, 2 insertions(+), 5 deletions(-) > > diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c > index 47c8a0f572..b5124a6426 100644 > --- a/hw/ssi/imx_spi.c > +++ b/hw/ssi/imx_spi.c > @@ -171,7 +171,6 @@ static void imx_spi_flush_txfifo(IMXSPIState *s) > > while (!fifo32_is_empty(&s->tx_fifo)) { > int tx_burst = 0; > - int index = 0; > > if (s->burst_length <= 0) { > s->burst_length = imx_spi_burst_length(s); > @@ -192,7 +191,7 @@ static void imx_spi_flush_txfifo(IMXSPIState *s) > rx = 0; > > while (tx_burst > 0) { > - uint8_t byte = tx & 0xff; > + uint8_t byte = tx >> (tx_burst - 8); > > DPRINTF("writing 0x%02x\n", (uint32_t)byte); > > @@ -201,13 +200,11 @@ static void imx_spi_flush_txfifo(IMXSPIState *s) > > DPRINTF("0x%02x read\n", (uint32_t)byte); > > - tx = tx >> 8; > - rx |= (byte << (index * 8)); > + rx = (rx << 8) | byte; > > /* Remove 8 bits from the actual burst */ > tx_burst -= 8; > s->burst_length -= 8; > - index++; > }
This version of the loop definitely looks a lot neater. However, looking at the code I don't think there's anything that forces the guest to set a burst length that's a multiple of 8, so you need to handle that somehow. Otherwise on the last time through the loop (tx_burst - 8) can be negative, which is undefined behaviour when you try to shift by it. I think just rounding tx_burst up to a multiple of 8 before the start of the loop would do the right thing ? thanks -- PMM