
On Fri, 14 Oct 2022 11:05:13 +0800 Icenowy Zheng uwu@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 uwu@icenowy.me
With that one array index change that Samuel suggested (I can fix this up myself):
Acked-by: Andre Przywara andre.przywara@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;