[PATCH RFC 05/15] sunxi: SPL SPI: add initial support for booting from SPI NAND
John Watts
contact at jookia.org
Thu Apr 11 06:25:22 CEST 2024
From: Icenowy Zheng <uwu at icenowy.me>
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>
Tested-by: Samuel Holland <samuel at sholland.org> # Orange Pi Zero Plus
---
arch/arm/mach-sunxi/Kconfig | 16 ++++++++
arch/arm/mach-sunxi/spl_spi_sunxi.c | 75 +++++++++++++++++++++++++++++++++++++
2 files changed, 91 insertions(+)
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index ddf9414b08..cc576fc84d 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -1084,6 +1084,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 58b1422da1..7ecde2b753 100644
--- a/arch/arm/mach-sunxi/spl_spi_sunxi.c
+++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c
@@ -344,6 +344,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;
@@ -387,6 +430,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,
@@ -434,10 +499,20 @@ 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;
+ spl_set_bl_len(&load, 1);
+ ret = spl_spi_try_load(spl_image, bootdev, &load, load_offset, false);
+ if (!ret)
+ goto out;
+#endif
+
spl_set_bl_len(&load, 1);
load.read = spi_load_read_nor;
ret = spl_spi_try_load(spl_image, bootdev, &load, load_offset, true);
+out:
spi0_deinit();
return ret;
--
2.44.0
More information about the U-Boot
mailing list