Message ID | 20221014030520.3067228-2-uwu@icenowy.me |
---|---|
State | Deferred |
Delegated to: | Tom Rini |
Headers | show |
Series | SUNIV SPI NAND support in SPL | expand |
On 10/13/22 22:05, Icenowy Zheng wrote: > 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. > > Signed-off-by: Icenowy Zheng <uwu@icenowy.me> One comment below. Reviewed-by: Samuel Holland <samuel@sholland.org> Tested-by: Samuel Holland <samuel@sholland.org> # Orange Pi Zero Plus > --- > 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); I think txbuf[i] would be a bit clearer here. Regards, Samuel > > /* 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;
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;
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;
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. Signed-off-by: Icenowy Zheng <uwu@icenowy.me> --- arch/arm/mach-sunxi/spl_spi_sunxi.c | 105 ++++++++++++++++------------ 1 file changed, 59 insertions(+), 46 deletions(-)