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

Icenowy Zheng uwu at icenowy.me
Fri Oct 14 05:05:16 CEST 2022


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).

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:
 	spi0_deinit();
 
 	return ret;
-- 
2.37.1



More information about the U-Boot mailing list