On Fri, 14 Oct 2022 11:05:13 +0800 Icenowy Zheng <u...@icenowy.me> wrote:
Hi, > To support SPI NAND flashes, more commands than Read (03h) are needed. > > Extract the code for doing SPI transfer from the reading code for code > reuse. I was looking for a better solution than this inflated function parameter list, but everything I came up with is actually worse. So it's fine like you wrote it here. I think it now even looks a bit better, since that long list is now wrapped completely by the spi0_xfer() function. It increases the code size by 20 (Thumb2) and 28 bytes (AArch64), that's not great, but acceptable. > Signed-off-by: Icenowy Zheng <u...@icenowy.me> With that one array index change that Samuel suggested (I can fix this up myself): Acked-by: Andre Przywara <andre.przyw...@arm.com> Cheers, Andre > --- > arch/arm/mach-sunxi/spl_spi_sunxi.c | 105 ++++++++++++++++------------ > 1 file changed, 59 insertions(+), 46 deletions(-) > > diff --git a/arch/arm/mach-sunxi/spl_spi_sunxi.c > b/arch/arm/mach-sunxi/spl_spi_sunxi.c > index 925bf85f2d..7975457758 100644 > --- a/arch/arm/mach-sunxi/spl_spi_sunxi.c > +++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c > @@ -243,77 +243,90 @@ static void spi0_deinit(void) > > #define SPI_READ_MAX_SIZE 60 /* FIFO size, minus 4 bytes of the header */ > > -static void sunxi_spi0_read_data(u8 *buf, u32 addr, u32 bufsize, > - ulong spi_ctl_reg, > - ulong spi_ctl_xch_bitmask, > - ulong spi_fifo_reg, > - ulong spi_tx_reg, > - ulong spi_rx_reg, > - ulong spi_bc_reg, > - ulong spi_tc_reg, > - ulong spi_bcc_reg) > +static void sunxi_spi0_xfer(const u8 *txbuf, u32 txlen, > + u8 *rxbuf, u32 rxlen, > + ulong spi_ctl_reg, > + ulong spi_ctl_xch_bitmask, > + ulong spi_fifo_reg, > + ulong spi_tx_reg, > + ulong spi_rx_reg, > + ulong spi_bc_reg, > + ulong spi_tc_reg, > + ulong spi_bcc_reg) > { > - writel(4 + bufsize, spi_bc_reg); /* Burst counter (total bytes) */ > - writel(4, spi_tc_reg); /* Transfer counter (bytes to send) */ > + writel(txlen + rxlen, spi_bc_reg); /* Burst counter (total bytes) */ > + writel(txlen, spi_tc_reg); /* Transfer counter (bytes to send) > */ > if (spi_bcc_reg) > - writel(4, spi_bcc_reg); /* SUN6I also needs this */ > + writel(txlen, spi_bcc_reg); /* SUN6I also needs this */ > > - /* Send the Read Data Bytes (03h) command header */ > - writeb(0x03, spi_tx_reg); > - writeb((u8)(addr >> 16), spi_tx_reg); > - writeb((u8)(addr >> 8), spi_tx_reg); > - writeb((u8)(addr), spi_tx_reg); > + for (u32 i = 0; i < txlen; i++) > + writeb(*(txbuf++), spi_tx_reg); > > /* Start the data transfer */ > setbits_le32(spi_ctl_reg, spi_ctl_xch_bitmask); > > /* Wait until everything is received in the RX FIFO */ > - while ((readl(spi_fifo_reg) & 0x7F) < 4 + bufsize) > + while ((readl(spi_fifo_reg) & 0x7F) < txlen + rxlen) > ; > > - /* Skip 4 bytes */ > - readl(spi_rx_reg); > + /* Skip txlen bytes */ > + for (u32 i = 0; i < txlen; i++) > + readb(spi_rx_reg); > > /* Read the data */ > - while (bufsize-- > 0) > - *buf++ = readb(spi_rx_reg); > + while (rxlen-- > 0) > + *rxbuf++ = readb(spi_rx_reg); > +} > + > +static void spi0_xfer(const u8 *txbuf, u32 txlen, u8 *rxbuf, u32 rxlen) > +{ > + uintptr_t base = spi0_base_address(); > > - /* tSHSL time is up to 100 ns in various SPI flash datasheets */ > - udelay(1); > + if (is_sun6i_gen_spi()) { > + sunxi_spi0_xfer(txbuf, txlen, rxbuf, rxlen, > + base + SUN6I_SPI0_TCR, > + SUN6I_TCR_XCH, > + base + SUN6I_SPI0_FIFO_STA, > + base + SUN6I_SPI0_TXD, > + base + SUN6I_SPI0_RXD, > + base + SUN6I_SPI0_MBC, > + base + SUN6I_SPI0_MTC, > + base + SUN6I_SPI0_BCC); > + } else { > + sunxi_spi0_xfer(txbuf, txlen, rxbuf, rxlen, > + base + SUN4I_SPI0_CTL, > + SUN4I_CTL_XCH, > + base + SUN4I_SPI0_FIFO_STA, > + base + SUN4I_SPI0_TX, > + base + SUN4I_SPI0_RX, > + base + SUN4I_SPI0_BC, > + base + SUN4I_SPI0_TC, > + 0); > + } > } > > static void spi0_read_data(void *buf, u32 addr, u32 len) > { > u8 *buf8 = buf; > u32 chunk_len; > - uintptr_t base = spi0_base_address(); > + u8 txbuf[4]; > > while (len > 0) { > chunk_len = len; > + > + /* Configure the Read Data Bytes (03h) command header */ > + txbuf[0] = 0x03; > + txbuf[1] = (u8)(addr >> 16); > + txbuf[2] = (u8)(addr >> 8); > + txbuf[3] = (u8)(addr); > + > if (chunk_len > SPI_READ_MAX_SIZE) > chunk_len = SPI_READ_MAX_SIZE; > > - if (is_sun6i_gen_spi()) { > - sunxi_spi0_read_data(buf8, addr, chunk_len, > - base + SUN6I_SPI0_TCR, > - SUN6I_TCR_XCH, > - base + SUN6I_SPI0_FIFO_STA, > - base + SUN6I_SPI0_TXD, > - base + SUN6I_SPI0_RXD, > - base + SUN6I_SPI0_MBC, > - base + SUN6I_SPI0_MTC, > - base + SUN6I_SPI0_BCC); > - } else { > - sunxi_spi0_read_data(buf8, addr, chunk_len, > - base + SUN4I_SPI0_CTL, > - SUN4I_CTL_XCH, > - base + SUN4I_SPI0_FIFO_STA, > - base + SUN4I_SPI0_TX, > - base + SUN4I_SPI0_RX, > - base + SUN4I_SPI0_BC, > - base + SUN4I_SPI0_TC, > - 0); > - } > + spi0_xfer(txbuf, 4, buf8, chunk_len); > + > + /* tSHSL time is up to 100 ns in various SPI flash datasheets */ > + udelay(1); > > len -= chunk_len; > buf8 += chunk_len;