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 <Mr.Bossman075@gmail.com>
Suggested-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
This commit is contained in:
Jesse Taube 2022-02-11 19:32:33 -05:00 committed by Andre Przywara
parent f64aac4a69
commit a08b04b5c7
2 changed files with 46 additions and 27 deletions

View file

@ -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);

View file

@ -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)
{