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;

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
To view this discussion on the web, visit 
https://groups.google.com/d/msgid/linux-sunxi/a1117875-ec9b-4fee-9477-644787f65325%40sholland.org.

Reply via email to