[PATCH 1/8] sunxi: SPL SPI: extract code for doing SPI transfer

Andre Przywara andre.przywara at arm.com
Tue Dec 12 19:12:16 CET 2023


On Fri, 14 Oct 2022 11:05:13 +0800
Icenowy Zheng <uwu at 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 at icenowy.me>

With that one array index change that Samuel suggested (I can fix this up
myself):

Acked-by: Andre Przywara <andre.przywara at 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;



More information about the U-Boot mailing list