From a08b04b5c75a7e9122dfc733c66b978aa0afe4ba Mon Sep 17 00:00:00 2001 From: Jesse Taube Date: Fri, 11 Feb 2022 19:32:33 -0500 Subject: mach-sunxi: Add boot device detection for SUNIV/F1C100s 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. The only caveat is that this only works in the SPL, as the SPL header gets overwritten with the exception vectors, once U-Boot proper takes over. Always return MMC0 as the boot source, when called from U-Boot proper, as a placeholder for now, until we find another way. Signed-off-by: Jesse Taube Suggested-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- arch/arm/include/asm/arch-sunxi/spl.h | 9 +++++ arch/arm/mach-sunxi/board.c | 64 ++++++++++++++++++++--------------- 2 files changed, 46 insertions(+), 27 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h index 58cdf806d9a..b543d24e5a0 100644 --- a/arch/arm/include/asm/arch-sunxi/spl.h +++ b/arch/arm/include/asm/arch-sunxi/spl.h @@ -19,6 +19,15 @@ #define SUNXI_BOOTED_FROM_MMC0_HIGH 0x10 #define SUNXI_BOOTED_FROM_MMC2_HIGH 0x12 +/* + * Values taken from the F1C200s BootROM stack + * 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 57078f7a7b2..0071de19ffd 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -191,12 +191,48 @@ SPL_LOAD_IMAGE_METHOD("FEL", 0, BOOT_DEVICE_BOARD, spl_board_load_image); #define SUNXI_INVALID_BOOT_SOURCE -1 +static int suniv_get_boot_source(void) +{ + /* Get the last function call from BootROM's stack. */ + u32 brom_call = *(u32 *)(uintptr_t)(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 not supported yet. */ + 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 int sunxi_get_boot_source(void) { + /* + * On the ARMv5 SoCs, the SPL header in SRAM is overwritten by the + * exception vectors in U-Boot proper, so we won't find any + * information there. Also the FEL stash is only valid in the SPL, + * so we can't use that either. So if this is called from U-Boot + * proper, just return MMC0 as a placeholder, for now. + */ + if (IS_ENABLED(CONFIG_MACH_SUNIV) && + !IS_ENABLED(CONFIG_SPL_BUILD)) + return SUNXI_BOOTED_FROM_MMC0; + 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 @@ -276,36 +312,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) { -- cgit v1.2.3 From 0dcdaff8b88e996de5d9c91141084cbfcfb01be6 Mon Sep 17 00:00:00 2001 From: Jesse Taube Date: Fri, 11 Feb 2022 19:32:34 -0500 Subject: mach-sunxi: Add SPL SPI boot for SUNIV 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: Original implementation] Signed-off-by: Jesse Taube [Jesse: adaptation to Upstream U-Boot] Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- 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 7f7eb0517cf..edd0fbf49fe 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 910e8050161..734c165e5d2 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(); -- cgit v1.2.3 From 640f2f3bf1d6320274b17192a1ab9d8030211302 Mon Sep 17 00:00:00 2001 From: Jesse Taube Date: Fri, 11 Feb 2022 19:32:35 -0500 Subject: mach-sunxi: Enable SPI boot for SUNIV and licheepi nano Enable SPI boot in SPL on SUNIV architecture and use it in the licheepi nano that uses the F1C100s. Signed-off-by: Jesse Taube Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- 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 205fe3c9d3c..d1c60d24082 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 2ac0ef42856..9fd1dcc9958 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 -- cgit v1.2.3 From c21f3d45711135179b4abbdc9462109a41060df6 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Tue, 1 Mar 2022 12:21:58 +0000 Subject: sunxi: f1c100s: Fix FEL registers restore Commit 88998f777531 ("arm: arm926ej-s: Add sunxi code") introduced the ARM926 version of the code to save and restore some FEL state, to be able to return to the BROM FEL code after the SPL has run. However during review a change was made, that happened to mess up the register restore part, so SCTLR and CPSR ended up with the wrong values, breaking return to FEL. Use the same offset that we actually save those registers to, to make FEL booting actually work on the Lichee Pi Nano. Signed-off-by: Andre Przywara --- arch/arm/cpu/arm926ejs/sunxi/fel_utils.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S b/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S index 08be7ed11aa..25924033c63 100644 --- a/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S +++ b/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S @@ -25,9 +25,9 @@ ENTRY(return_to_fel) mov sp, r0 mov lr, r1 ldr r0, =fel_stash - ldr r1, [r0, #16] - mcr p15, 0, r1, c1, c0, 0 @ Write CP15 Control Register ldr r1, [r0, #12] + mcr p15, 0, r1, c1, c0, 0 @ Write CP15 SCTLR register + ldr r1, [r0, #8] msr cpsr, r1 @ Write CPSR bx lr ENDPROC(return_to_fel) -- cgit v1.2.3 From cfcf1952c11e6ffcbbf88eb63c49edca2acf1d5e Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Wed, 2 Mar 2022 01:30:55 +0000 Subject: sunxi: f1c100s: Drop SYSRESET to enable reset functionality The F1C100s DT contains the wrong compatible string for the watchdog, which breaks reset functionality. Updating the DT goes via the Linux tree, but to allow reset functionality meanwhile (useful for development!), disable SYSRESET for now, to let the old-fashioned watchdog driver kick in and provide the reset_cpu() implementation. Signed-off-by: Andre Przywara --- configs/licheepi_nano_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/licheepi_nano_defconfig b/configs/licheepi_nano_defconfig index 9fd1dcc9958..67b7b85c491 100644 --- a/configs/licheepi_nano_defconfig +++ b/configs/licheepi_nano_defconfig @@ -10,3 +10,4 @@ CONFIG_DRAM_CLK=156 CONFIG_DRAM_ZQ=0 # CONFIG_VIDEO_SUNXI is not set CONFIG_SPL_SPI_SUNXI=y +# CONFIG_SYSRESET is not set -- cgit v1.2.3