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 <sam...@sholland.org> # Orange Pi Zero Plus > Signed-off-by: Icenowy Zheng <u...@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;