[PATCH v2 0/3] Add SPI boot to SPL on SUNIV/F1C100s

This patch adds the ability to detect the BROM's boot source, as well as the ability to boot from SPI.
Jesse Taube (3): mach-sunxi: Add boot device detection for SUNIV/F1C100s mach-sunxi: Add SPL SPI boot for SUNIV mach-sunxi: Enable SPI boot for SUNIV and licheepi nano
arch/arm/include/asm/arch-sunxi/gpio.h | 1 + arch/arm/include/asm/arch-sunxi/spl.h | 10 +++++ arch/arm/mach-sunxi/Kconfig | 2 +- arch/arm/mach-sunxi/board.c | 57 +++++++++++++------------- arch/arm/mach-sunxi/spl_spi_sunxi.c | 24 +++++++---- configs/licheepi_nano_defconfig | 1 + 6 files changed, 58 insertions(+), 37 deletions(-)

In contrast to other Allwinner SoCs the F1C100s BROM does not store a boot source indicator in the eGON header in SRAM. This leaves the SPL guessing where we were exactly booted from, and for instance trying the SD card first, even though we booted from SPI flash.
By inspecting the BROM code and by experimentation, Samuel found that the top of the BROM stack contains unique pointers for each of the boot sources, which we can use as a boot source indicator.
This patch removes the existing board_boot_order bodge and replace it with a proper boot source indication function.
Signed-off-by: Jesse Taube Mr.Bossman075@gmail.com Suggested-by: Samuel Holland samuel@sholland.org --- V1 -> V2: * Bail on NAND * Change commit description * Change sunxi_get_boot_source to u32 * Fix FEL boot by next change * Move suniv_get_boot_device call into sunxi_get_boot_source * Rename suniv_get_boot_device * Remove redundant comments --- arch/arm/include/asm/arch-sunxi/spl.h | 10 +++++ arch/arm/mach-sunxi/board.c | 57 +++++++++++++-------------- 2 files changed, 38 insertions(+), 29 deletions(-)
diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h index 58cdf806d9..9a6e8da8e1 100644 --- a/arch/arm/include/asm/arch-sunxi/spl.h +++ b/arch/arm/include/asm/arch-sunxi/spl.h @@ -19,6 +19,16 @@ #define SUNXI_BOOTED_FROM_MMC0_HIGH 0x10 #define SUNXI_BOOTED_FROM_MMC2_HIGH 0x12
+/* + * Values taken from the Bootrom's stack used + * to determine where we booted from. + */ + +#define SUNIV_BOOTED_FROM_MMC0 0xffff40f8 +#define SUNIV_BOOTED_FROM_NAND 0xffff4114 +#define SUNIV_BOOTED_FROM_SPI 0xffff4130 +#define SUNIV_BOOTED_FROM_MMC1 0xffff4150 + #define is_boot0_magic(addr) (memcmp((void *)(addr), BOOT0_MAGIC, 8) == 0)
uint32_t sunxi_get_boot_device(void); diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index 57078f7a7b..27aee1e445 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -191,12 +191,37 @@ SPL_LOAD_IMAGE_METHOD("FEL", 0, BOOT_DEVICE_BOARD, spl_board_load_image);
#define SUNXI_INVALID_BOOT_SOURCE -1
-static int sunxi_get_boot_source(void) +static uint32_t suniv_get_boot_source(void) +{ + /* Get the last function call from BootRom's stack. */ + u32 brom_call = *(u32 *)(fel_stash.sp - 4); + + /* translate SUNIV Bootrom stack to standard SUNXI boot sources */ + switch (brom_call) { + case SUNIV_BOOTED_FROM_MMC0: + return SUNXI_BOOTED_FROM_MMC0; + case SUNIV_BOOTED_FROM_SPI: + return SUNXI_BOOTED_FROM_SPI; + case SUNIV_BOOTED_FROM_MMC1: + return SUNXI_BOOTED_FROM_MMC2; + /* SPI nand is invalid try to boot from FEL*/ + case SUNIV_BOOTED_FROM_NAND: + return SUNXI_INVALID_BOOT_SOURCE; + } + /* If we get here something went wrong try to boot from FEL.*/ + printf("Unknown boot source from BROM: 0x%x\n", brom_call); + return SUNXI_INVALID_BOOT_SOURCE; +} + +static uint32_t sunxi_get_boot_source(void) { if (!is_boot0_magic(SPL_ADDR + 4)) /* eGON.BT0 */ return SUNXI_INVALID_BOOT_SOURCE;
- return readb(SPL_ADDR + 0x28); + if (IS_ENABLED(CONFIG_MACH_SUNIV)) + return suniv_get_boot_source(); + else + return readb(SPL_ADDR + 0x28); }
/* The sunxi internal brom will try to loader external bootloader @@ -204,7 +229,7 @@ static int sunxi_get_boot_source(void) */ uint32_t sunxi_get_boot_device(void) { - int boot_source = sunxi_get_boot_source(); + uint32_t boot_source = sunxi_get_boot_source();
/* * When booting from the SD card or NAND memory, the "eGON.BT0" @@ -276,36 +301,10 @@ unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc, return sector; }
-#ifdef CONFIG_MACH_SUNIV -/* - * The suniv BROM does not pass the boot media type to SPL, so we try with the - * boot sequence in BROM: mmc0->spinor->fail. - * TODO: This has the slight chance of being wrong (invalid SPL signature, - * but valid U-Boot legacy image on the SD card), but this should be rare. - * It looks like we can deduce from some BROM state upon entering the SPL - * (registers, SP, or stack itself) where the BROM was coming from and use - * that here. - */ -void board_boot_order(u32 *spl_boot_list) -{ - /* - * See the comments above in sunxi_get_boot_device() for information - * about FEL boot. - */ - if (!is_boot0_magic(SPL_ADDR + 4)) { - spl_boot_list[0] = BOOT_DEVICE_BOARD; - return; - } - - spl_boot_list[0] = BOOT_DEVICE_MMC1; - spl_boot_list[1] = BOOT_DEVICE_SPI; -} -#else u32 spl_boot_device(void) { return sunxi_get_boot_device(); } -#endif
__weak void sunxi_sram_init(void) {

On 2/11/22 19:32, Jesse Taube wrote:
In contrast to other Allwinner SoCs the F1C100s BROM does not store a boot source indicator in the eGON header in SRAM. This leaves the SPL guessing where we were exactly booted from, and for instance trying the SD card first, even though we booted from SPI flash.
By inspecting the BROM code and by experimentation, Samuel found that the top of the BROM stack contains unique pointers for each of the boot sources, which we can use as a boot source indicator.
This patch removes the existing board_boot_order bodge and replace it with a proper boot source indication function.
Signed-off-by: Jesse Taube Mr.Bossman075@gmail.com Suggested-by: Samuel Holland samuel@sholland.org
V1 -> V2:
- Bail on NAND
- Change commit description
- Change sunxi_get_boot_source to u32
- Fix FEL boot by next change
- Move suniv_get_boot_device call into sunxi_get_boot_source
- Rename suniv_get_boot_device
- Remove redundant comments
arch/arm/include/asm/arch-sunxi/spl.h | 10 +++++ arch/arm/mach-sunxi/board.c | 57 +++++++++++++-------------- 2 files changed, 38 insertions(+), 29 deletions(-)
diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h index 58cdf806d9..9a6e8da8e1 100644 --- a/arch/arm/include/asm/arch-sunxi/spl.h +++ b/arch/arm/include/asm/arch-sunxi/spl.h @@ -19,6 +19,16 @@ #define SUNXI_BOOTED_FROM_MMC0_HIGH 0x10 #define SUNXI_BOOTED_FROM_MMC2_HIGH 0x12
+/*
- Values taken from the Bootrom's stack used
- to determine where we booted from.
- */
+#define SUNIV_BOOTED_FROM_MMC0 0xffff40f8 +#define SUNIV_BOOTED_FROM_NAND 0xffff4114 +#define SUNIV_BOOTED_FROM_SPI 0xffff4130 +#define SUNIV_BOOTED_FROM_MMC1 0xffff4150
#define is_boot0_magic(addr) (memcmp((void *)(addr), BOOT0_MAGIC, 8) == 0)
uint32_t sunxi_get_boot_device(void);
diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index 57078f7a7b..27aee1e445 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -191,12 +191,37 @@ SPL_LOAD_IMAGE_METHOD("FEL", 0, BOOT_DEVICE_BOARD, spl_board_load_image);
#define SUNXI_INVALID_BOOT_SOURCE -1
-static int sunxi_get_boot_source(void)
Didn't like the implicit cast on the return statement.
+static uint32_t suniv_get_boot_source(void) +{
- /* Get the last function call from BootRom's stack. */
- u32 brom_call = *(u32 *)(fel_stash.sp - 4);
- /* translate SUNIV Bootrom stack to standard SUNXI boot sources */
- switch (brom_call) {
- case SUNIV_BOOTED_FROM_MMC0:
return SUNXI_BOOTED_FROM_MMC0;
- case SUNIV_BOOTED_FROM_SPI:
return SUNXI_BOOTED_FROM_SPI;
- case SUNIV_BOOTED_FROM_MMC1:
return SUNXI_BOOTED_FROM_MMC2;
- /* SPI nand is invalid try to boot from FEL*/
- case SUNIV_BOOTED_FROM_NAND:
return SUNXI_INVALID_BOOT_SOURCE;
- }
- /* If we get here something went wrong try to boot from FEL.*/
- printf("Unknown boot source from BROM: 0x%x\n", brom_call);
- return SUNXI_INVALID_BOOT_SOURCE;
This just trys to boot from FEL doesn't hang.
+}
+static uint32_t sunxi_get_boot_source(void) { if (!is_boot0_magic(SPL_ADDR + 4)) /* eGON.BT0 */ return SUNXI_INVALID_BOOT_SOURCE;
This will return when booting from FEL.
- return readb(SPL_ADDR + 0x28);
if (IS_ENABLED(CONFIG_MACH_SUNIV))
return suniv_get_boot_source();
else
return readb(SPL_ADDR + 0x28);
}
/* The sunxi internal brom will try to loader external bootloader
@@ -204,7 +229,7 @@ static int sunxi_get_boot_source(void) */ uint32_t sunxi_get_boot_device(void) {
- int boot_source = sunxi_get_boot_source();
uint32_t boot_source = sunxi_get_boot_source();
/*
- When booting from the SD card or NAND memory, the "eGON.BT0"
@@ -276,36 +301,10 @@ unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc, return sector; }
-#ifdef CONFIG_MACH_SUNIV -/*
- The suniv BROM does not pass the boot media type to SPL, so we try with the
- boot sequence in BROM: mmc0->spinor->fail.
- TODO: This has the slight chance of being wrong (invalid SPL signature,
- but valid U-Boot legacy image on the SD card), but this should be rare.
- It looks like we can deduce from some BROM state upon entering the SPL
- (registers, SP, or stack itself) where the BROM was coming from and use
- that here.
- */
-void board_boot_order(u32 *spl_boot_list) -{
- /*
* See the comments above in sunxi_get_boot_device() for information
* about FEL boot.
*/
- if (!is_boot0_magic(SPL_ADDR + 4)) {
spl_boot_list[0] = BOOT_DEVICE_BOARD;
return;
- }
- spl_boot_list[0] = BOOT_DEVICE_MMC1;
- spl_boot_list[1] = BOOT_DEVICE_SPI;
-} -#else u32 spl_boot_device(void) { return sunxi_get_boot_device(); } -#endif
__weak void sunxi_sram_init(void) {

The SUNIV SoCs come with a sun6i-style SPI controller at the base address of sun4i SPI controller. The module clock of the SPI controller is missing which leaves us running directly from the AHB clock, which is set to 200MHz.
Signed-off-by: Icenowy Zheng icenowy@aosc.io [Icenowy: Original implementation] Signed-off-by: Jesse Taube Mr.Bossman075@gmail.com [Jesse: adaptation to Upstream U-Boot] --- V1 -> V2: * Change commit description * Remove redundant conditional statment * Use else if for pin-function --- arch/arm/include/asm/arch-sunxi/gpio.h | 1 + arch/arm/mach-sunxi/spl_spi_sunxi.c | 24 +++++++++++++++++------- 2 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index 7f7eb0517c..edd0fbf49f 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -160,6 +160,7 @@ enum sunxi_gpio_number { #define SUNXI_GPC_SDC2 3 #define SUN6I_GPC_SDC3 4 #define SUN50I_GPC_SPI0 4 +#define SUNIV_GPC_SPI0 2
#define SUNXI_GPD_LCD0 2 #define SUNXI_GPD_LVDS0 3 diff --git a/arch/arm/mach-sunxi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c index 910e805016..734c165e5d 100644 --- a/arch/arm/mach-sunxi/spl_spi_sunxi.c +++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c @@ -90,6 +90,7 @@
#define SPI0_CLK_DIV_BY_2 0x1000 #define SPI0_CLK_DIV_BY_4 0x1001 +#define SPI0_CLK_DIV_BY_32 0x100f
/*****************************************************************************/
@@ -132,7 +133,8 @@ static uintptr_t spi0_base_address(void) if (IS_ENABLED(CONFIG_MACH_SUN50I_H6)) return 0x05010000;
- if (!is_sun6i_gen_spi()) + if (!is_sun6i_gen_spi() || + IS_ENABLED(CONFIG_MACH_SUNIV)) return 0x01C05000;
return 0x01C68000; @@ -156,11 +158,16 @@ static void spi0_enable_clock(void) if (!IS_ENABLED(CONFIG_MACH_SUN50I_H6)) setbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
- /* Divide by 4 */ - writel(SPI0_CLK_DIV_BY_4, base + (is_sun6i_gen_spi() ? - SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL)); - /* 24MHz from OSC24M */ - writel((1 << 31), CCM_SPI0_CLK); + if (IS_ENABLED(CONFIG_MACH_SUNIV)) { + /* Divide by 32, clock source is AHB clock 200MHz */ + writel(SPI0_CLK_DIV_BY_32, base + SUN6I_SPI0_CCTL); + } else { + /* Divide by 4 */ + writel(SPI0_CLK_DIV_BY_4, base + (is_sun6i_gen_spi() ? + SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL)); + /* 24MHz from OSC24M */ + writel((1 << 31), CCM_SPI0_CLK); + }
if (is_sun6i_gen_spi()) { /* Enable SPI in the master mode and do a soft reset */ @@ -191,7 +198,8 @@ static void spi0_disable_clock(void) SUN4I_CTL_ENABLE);
/* Disable the SPI0 clock */ - writel(0, CCM_SPI0_CLK); + if (!IS_ENABLED(CONFIG_MACH_SUNIV)) + writel(0, CCM_SPI0_CLK);
/* Close the SPI0 gate */ if (!IS_ENABLED(CONFIG_MACH_SUN50I_H6)) @@ -212,6 +220,8 @@ static void spi0_init(void) if (IS_ENABLED(CONFIG_MACH_SUN50I) || IS_ENABLED(CONFIG_MACH_SUN50I_H6)) pin_function = SUN50I_GPC_SPI0; + else if (IS_ENABLED(CONFIG_MACH_SUNIV)) + pin_function = SUNIV_GPC_SPI0;
spi0_pinmux_setup(pin_function); spi0_enable_clock();

Enable SPI boot in SPL on SUNIV architecture and use it in the licheepi nano that uses the F1C100s.
Signed-off-by: Jesse Taube Mr.Bossman075@gmail.com Reviewed-by: Andre Przywara andre.przywara@arm.com --- V1 -> V2: * Change commit description --- arch/arm/mach-sunxi/Kconfig | 2 +- configs/licheepi_nano_defconfig | 1 + 2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 205fe3c9d3..d1c60d2408 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -1038,7 +1038,7 @@ config SPL_STACK_R_ADDR
config SPL_SPI_SUNXI bool "Support for SPI Flash on Allwinner SoCs in SPL" - depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_R40 || MACH_SUN50I_H6 + depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_R40 || MACH_SUN50I_H6 || MACH_SUNIV help Enable support for SPI Flash. This option allows SPL to read from sunxi SPI Flash. It uses the same method as the boot ROM, so does diff --git a/configs/licheepi_nano_defconfig b/configs/licheepi_nano_defconfig index 2ac0ef4285..9fd1dcc995 100644 --- a/configs/licheepi_nano_defconfig +++ b/configs/licheepi_nano_defconfig @@ -9,3 +9,4 @@ CONFIG_MACH_SUNIV=y CONFIG_DRAM_CLK=156 CONFIG_DRAM_ZQ=0 # CONFIG_VIDEO_SUNXI is not set +CONFIG_SPL_SPI_SUNXI=y

Hey just checking if you know about this set.
This patch adds the ability to detect the BROM's boot source, as well as the ability to boot from SPI.
Jesse Taube (3): mach-sunxi: Add boot device detection for SUNIV/F1C100s mach-sunxi: Add SPL SPI boot for SUNIV mach-sunxi: Enable SPI boot for SUNIV and licheepi nano
arch/arm/include/asm/arch-sunxi/gpio.h | 1 + arch/arm/include/asm/arch-sunxi/spl.h | 10 +++++ arch/arm/mach-sunxi/Kconfig | 2 +- arch/arm/mach-sunxi/board.c | 57 +++++++++++++------------- arch/arm/mach-sunxi/spl_spi_sunxi.c | 24 +++++++---- configs/licheepi_nano_defconfig | 1 + 6 files changed, 58 insertions(+), 37 deletions(-)

On Mon, 28 Feb 2022 23:42:13 -0500 Jesse Taube mr.bossman075@gmail.com wrote:
Hi,
Hey just checking if you know about this set.
Yeah, I saw that, and am planning on taking it ASAP, so still this release. However I wanted to have this tested, which is now easier since I got my LicheePi Nano on Friday. So SPI boot seems to work, but I needed to fix FEL boot in mainline (see the other patch).
I am not convinced with the uint32_t part, though. I think "int" is fine, because it's either -1 or the uint8_t returned by readb(), which fits both nicely and correctly into an "int".
I will do some more testing and then see what other patches I can pick up (Jernej's PRCM ones, for instance).
Cheers, Andre
This patch adds the ability to detect the BROM's boot source, as well as the ability to boot from SPI.
Jesse Taube (3): mach-sunxi: Add boot device detection for SUNIV/F1C100s mach-sunxi: Add SPL SPI boot for SUNIV mach-sunxi: Enable SPI boot for SUNIV and licheepi nano
arch/arm/include/asm/arch-sunxi/gpio.h | 1 + arch/arm/include/asm/arch-sunxi/spl.h | 10 +++++ arch/arm/mach-sunxi/Kconfig | 2 +- arch/arm/mach-sunxi/board.c | 57 +++++++++++++------------- arch/arm/mach-sunxi/spl_spi_sunxi.c | 24 +++++++---- configs/licheepi_nano_defconfig | 1 + 6 files changed, 58 insertions(+), 37 deletions(-)

On Mon, 28 Feb 2022 23:42:13 -0500 Jesse Taube mr.bossman075@gmail.com wrote:
Hi,
Hey just checking if you know about this set.
This patch adds the ability to detect the BROM's boot source, as well as the ability to boot from SPI.
So I fixed two more things (FEL booting and reset), and massaged the first patch a bit (fixing arm64 compilation, and protecting U-Boot proper operation). I pushed the result to sunxi/master[1], and plan to send a PR as soon as I can do some more testing: the Nano boots fine, via FEL, MMC, and SPI, but I need to check other boards as well.
Please test this branch and scream if you are not happy!
Cheers, Andre
[1] https://source.denx.de/u-boot/custodians/u-boot-sunxi/-/commits/master/
Jesse Taube (3): mach-sunxi: Add boot device detection for SUNIV/F1C100s mach-sunxi: Add SPL SPI boot for SUNIV mach-sunxi: Enable SPI boot for SUNIV and licheepi nano
arch/arm/include/asm/arch-sunxi/gpio.h | 1 + arch/arm/include/asm/arch-sunxi/spl.h | 10 +++++ arch/arm/mach-sunxi/Kconfig | 2 +- arch/arm/mach-sunxi/board.c | 57 +++++++++++++------------- arch/arm/mach-sunxi/spl_spi_sunxi.c | 24 +++++++---- configs/licheepi_nano_defconfig | 1 + 6 files changed, 58 insertions(+), 37 deletions(-)
participants (2)
-
Andre Przywara
-
Jesse Taube