[PATCH 4/8] sunxi: SPL SPI: add initial support for booting from SPI NAND

Samuel Holland samuel at sholland.org
Sat Jan 14 21:08:50 CET 2023


On 10/13/22 22:05, Icenowy Zheng wrote:
> This commit adds support for booting from SPI NAND to SPL SPI code by
> mimicing the behavior of boot ROM (use fixed page size and sequentially
> try SPI NOR and NAND).

One warning generated when SPL_SPI_SUNXI_NAND is disabled. Otherwise, it
looks fine to me. I verified that NOR booting still works when
SPL_SPI_SUNXI_NAND is enabled, so:

Tested-by: Samuel Holland <samuel at sholland.org> # Orange Pi Zero Plus

> Signed-off-by: Icenowy Zheng <uwu at icenowy.me>
> ---
>  arch/arm/mach-sunxi/Kconfig         | 16 +++++++
>  arch/arm/mach-sunxi/spl_spi_sunxi.c | 74 +++++++++++++++++++++++++++++
>  2 files changed, 90 insertions(+)
> 
> diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
> index 840bbc19b3..6afbb4acb5 100644
> --- a/arch/arm/mach-sunxi/Kconfig
> +++ b/arch/arm/mach-sunxi/Kconfig
> @@ -1018,6 +1018,22 @@ config SPL_SPI_SUNXI
>  	  sunxi SPI Flash. It uses the same method as the boot ROM, so does
>  	  not need any extra configuration.
>  
> +config SPL_SPI_SUNXI_NAND
> +	bool "Support for SPI NAND Flash on Allwinner SoCs in SPL"
> +	depends on SPL_SPI_SUNXI
> +	help
> +	  Enable support for SPI NAND Flash. This option allows SPL to mimic
> +	  Allwinner boot ROM's behavior to gain support for SPI NAND Flash;
> +	  a fixed page size needs to be assumed when building the SPL image.
> +
> +config SPL_SPI_SUNXI_NAND_ASSUMED_PAGESIZE
> +	hex "Assumed pagesize for SPI NAND Flash in SPL"
> +	depends on SPL_SPI_SUNXI_NAND
> +	default 0x400 if MACH_SUNIV
> +	help
> +	  Set the page size assumed by the SPL SPI NAND code, the default
> +	  value is the same with the boot ROM.
> +
>  config PINE64_DT_SELECTION
>  	bool "Enable Pine64 device tree selection code"
>  	depends on MACH_SUN50I
> diff --git a/arch/arm/mach-sunxi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c
> index 21be33a23f..5178908327 100644
> --- a/arch/arm/mach-sunxi/spl_spi_sunxi.c
> +++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c
> @@ -305,6 +305,49 @@ static void spi0_xfer(const u8 *txbuf, u32 txlen, u8 *rxbuf, u32 rxlen)
>  	}
>  }
>  
> +#if defined(CONFIG_SPL_SPI_SUNXI_NAND)
> +static int spi0_nand_switch_page(u32 page)
> +{
> +	unsigned count;
> +	u8 buf[4];
> +
> +	/* Configure the Page Data Read (13h) command header */
> +	buf[0] = 0x13;
> +	buf[1] = (u8)(page >> 16);
> +	buf[2] = (u8)(page >> 8);
> +	buf[3] = (u8)(page);
> +
> +	spi0_xfer(buf, 4, NULL, 0);
> +
> +	/* Wait for NAND chip to exit busy state */
> +	buf[0] = 0x0f;
> +	buf[1] = 0xc0;
> +
> +	/* Load a NAND page can take up to 2-decimal-digit microseconds */
> +	for (count = 0; count < 100; count ++) {
> +		udelay(1);
> +		spi0_xfer(buf, 2, buf+2, 1);
> +		if (!(buf[2] & 0x1))
> +			return 0;
> +	}
> +
> +	return -ETIMEDOUT;
> +}
> +
> +static void spi0_nand_reset(void)
> +{
> +	u8 buf[1];
> +
> +	/* Configure the Device RESET (ffh) command */
> +	buf[0] = 0xff;
> +
> +	spi0_xfer(buf, 1, NULL, 0);
> +
> +	/* Wait for the NAND to finish resetting */
> +	udelay(10);
> +}
> +#endif
> +
>  static void spi0_read_data(void *buf, u32 addr, u32 len, u32 addr_len)
>  {
>  	u8 *buf8 = buf;
> @@ -348,6 +391,28 @@ static ulong spi_load_read_nor(struct spl_load_info *load, ulong sector,
>  	return count;
>  }
>  
> +#if defined(CONFIG_SPL_SPI_SUNXI_NAND)
> +static ulong spi_load_read_nand(struct spl_load_info *load, ulong sector,
> +			       ulong count, void *buf)
> +{
> +	const ulong pagesize = CONFIG_SPL_SPI_SUNXI_NAND_ASSUMED_PAGESIZE;
> +	ulong remain = count;
> +
> +	while (remain) {
> +		ulong count_in_page = min(remain, pagesize - (sector % pagesize));
> +		ulong current_page = sector / pagesize;
> +		if (spi0_nand_switch_page(current_page) != 0)
> +			return 0;
> +		spi0_read_data(buf, sector % pagesize, count_in_page, 2);
> +		remain -= count_in_page;
> +		sector += count_in_page;
> +		buf += count_in_page;
> +	}
> +
> +	return count;
> +}
> +#endif
> +
>  /*****************************************************************************/
>  
>  static int spl_spi_try_load(struct spl_image_info *spl_image,
> @@ -400,9 +465,18 @@ static int spl_spi_load_image(struct spl_image_info *spl_image,
>  
>  	spi0_init();
>  
> +#if defined(CONFIG_SPL_SPI_SUNXI_NAND)
> +	spi0_nand_reset();
> +	load.read = spi_load_read_nand;
> +	ret = spl_spi_try_load(spl_image, bootdev, &load, load_offset, false);
> +	if (!ret)
> +		goto out;
> +#endif
> +
>  	load.read = spi_load_read_nor;
>  	ret = spl_spi_try_load(spl_image, bootdev, &load, load_offset, true);
>  
> +out:

arch/arm/mach-sunxi/spl_spi_sunxi.c: In function 'spl_spi_load_image':
arch/arm/mach-sunxi/spl_spi_sunxi.c:482:1: warning: label 'out' defined
but not used [-Wunused-label]
  482 | out:
      | ^~~

>  	spi0_deinit();
>  
>  	return ret;



More information about the U-Boot mailing list