
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(-)
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;