[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