diff options
Diffstat (limited to 'roms/u-boot/common/spl/spl.c')
-rw-r--r-- | roms/u-boot/common/spl/spl.c | 895 |
1 files changed, 895 insertions, 0 deletions
diff --git a/roms/u-boot/common/spl/spl.c b/roms/u-boot/common/spl/spl.c new file mode 100644 index 000000000..a0a608fd7 --- /dev/null +++ b/roms/u-boot/common/spl/spl.c @@ -0,0 +1,895 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2010 + * Texas Instruments, <www.ti.com> + * + * Aneesh V <aneesh@ti.com> + */ + +#include <common.h> +#include <bloblist.h> +#include <binman_sym.h> +#include <bootstage.h> +#include <dm.h> +#include <handoff.h> +#include <hang.h> +#include <init.h> +#include <irq_func.h> +#include <log.h> +#include <mapmem.h> +#include <serial.h> +#include <spl.h> +#include <asm/global_data.h> +#include <asm/u-boot.h> +#include <nand.h> +#include <fat.h> +#include <u-boot/crc.h> +#include <version.h> +#include <image.h> +#include <malloc.h> +#include <mapmem.h> +#include <dm/root.h> +#include <linux/compiler.h> +#include <fdt_support.h> +#include <bootcount.h> +#include <wdt.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifndef CONFIG_SYS_UBOOT_START +#define CONFIG_SYS_UBOOT_START CONFIG_SYS_TEXT_BASE +#endif +#ifndef CONFIG_SYS_MONITOR_LEN +/* Unknown U-Boot size, let's assume it will not be more than 200 KB */ +#define CONFIG_SYS_MONITOR_LEN (200 * 1024) +#endif + +u32 *boot_params_ptr = NULL; + +/* See spl.h for information about this */ +binman_sym_declare(ulong, u_boot_any, image_pos); +binman_sym_declare(ulong, u_boot_any, size); + +#ifdef CONFIG_TPL +binman_sym_declare(ulong, spl, image_pos); +binman_sym_declare(ulong, spl, size); +#endif + +/* Define board data structure */ +static struct bd_info bdata __attribute__ ((section(".data"))); + +/* + * Board-specific Platform code can reimplement show_boot_progress () if needed + */ +__weak void show_boot_progress(int val) {} + +#if defined(CONFIG_SPL_OS_BOOT) || CONFIG_IS_ENABLED(HANDOFF) || \ + defined(CONFIG_SPL_ATF) +/* weak, default platform-specific function to initialize dram banks */ +__weak int dram_init_banksize(void) +{ + return 0; +} +#endif + +/* + * Default function to determine if u-boot or the OS should + * be started. This implementation always returns 1. + * + * Please implement your own board specific funcion to do this. + * + * RETURN + * 0 to not start u-boot + * positive if u-boot should start + */ +#ifdef CONFIG_SPL_OS_BOOT +__weak int spl_start_uboot(void) +{ + puts(SPL_TPL_PROMPT + "Please implement spl_start_uboot() for your board\n"); + puts(SPL_TPL_PROMPT "Direct Linux boot not active!\n"); + return 1; +} + +/* + * Weak default function for arch specific zImage check. Return zero + * and fill start and end address if image is recognized. + */ +int __weak bootz_setup(ulong image, ulong *start, ulong *end) +{ + return 1; +} +#endif + +/* Weak default function for arch/board-specific fixups to the spl_image_info */ +void __weak spl_perform_fixups(struct spl_image_info *spl_image) +{ +} + +void spl_fixup_fdt(void *fdt_blob) +{ +#if defined(CONFIG_SPL_OF_LIBFDT) + int err; + + if (!fdt_blob) + return; + + err = fdt_check_header(fdt_blob); + if (err < 0) { + printf("fdt_root: %s\n", fdt_strerror(err)); + return; + } + + /* fixup the memory dt node */ + err = fdt_shrink_to_minimum(fdt_blob, 0); + if (err == 0) { + printf(SPL_TPL_PROMPT "fdt_shrink_to_minimum err - %d\n", err); + return; + } + + err = arch_fixup_fdt(fdt_blob); + if (err) { + printf(SPL_TPL_PROMPT "arch_fixup_fdt err - %d\n", err); + return; + } +#endif +} + +ulong spl_get_image_pos(void) +{ + return spl_phase() == PHASE_TPL ? + binman_sym(ulong, spl, image_pos) : + binman_sym(ulong, u_boot_any, image_pos); +} + +ulong spl_get_image_size(void) +{ + return spl_phase() == PHASE_TPL ? + binman_sym(ulong, spl, size) : + binman_sym(ulong, u_boot_any, size); +} + +ulong spl_get_image_text_base(void) +{ + return spl_phase() == PHASE_TPL ? CONFIG_SPL_TEXT_BASE : + CONFIG_SYS_TEXT_BASE; +} + +/* + * Weak default function for board specific cleanup/preparation before + * Linux boot. Some boards/platforms might not need it, so just provide + * an empty stub here. + */ +__weak void spl_board_prepare_for_linux(void) +{ + /* Nothing to do! */ +} + +__weak void spl_board_prepare_for_boot(void) +{ + /* Nothing to do! */ +} + +__weak struct image_header *spl_get_load_buffer(ssize_t offset, size_t size) +{ + return map_sysmem(CONFIG_SYS_TEXT_BASE + offset, 0); +} + +void spl_set_header_raw_uboot(struct spl_image_info *spl_image) +{ + ulong u_boot_pos = binman_sym(ulong, u_boot_any, image_pos); + + spl_image->size = CONFIG_SYS_MONITOR_LEN; + + /* + * Binman error cases: address of the end of the previous region or the + * start of the image's entry area (usually 0) if there is no previous + * region. + */ + if (u_boot_pos && u_boot_pos != BINMAN_SYM_MISSING) { + /* Binman does not support separated entry addresses */ + spl_image->entry_point = u_boot_pos; + spl_image->load_addr = u_boot_pos; + } else { + spl_image->entry_point = CONFIG_SYS_UBOOT_START; + spl_image->load_addr = CONFIG_SYS_TEXT_BASE; + } + spl_image->os = IH_OS_U_BOOT; + spl_image->name = "U-Boot"; +} + +#ifdef CONFIG_SPL_LOAD_FIT_FULL +/* Parse and load full fitImage in SPL */ +static int spl_load_fit_image(struct spl_image_info *spl_image, + const struct image_header *header) +{ + bootm_headers_t images; + const char *fit_uname_config = NULL; + uintptr_t fdt_hack; + const char *uname; + ulong fw_data = 0, dt_data = 0, img_data = 0; + ulong fw_len = 0, dt_len = 0, img_len = 0; + int idx, conf_noffset; + int ret; + +#ifdef CONFIG_SPL_FIT_SIGNATURE + images.verify = 1; +#endif + ret = fit_image_load(&images, (ulong)header, + NULL, &fit_uname_config, + IH_ARCH_DEFAULT, IH_TYPE_STANDALONE, -1, + FIT_LOAD_OPTIONAL, &fw_data, &fw_len); + if (ret >= 0) { + printf("DEPRECATED: 'standalone = ' property."); + printf("Please use either 'firmware =' or 'kernel ='\n"); + } else { + ret = fit_image_load(&images, (ulong)header, NULL, + &fit_uname_config, IH_ARCH_DEFAULT, + IH_TYPE_FIRMWARE, -1, FIT_LOAD_OPTIONAL, + &fw_data, &fw_len); + } + + if (ret < 0) { + ret = fit_image_load(&images, (ulong)header, NULL, + &fit_uname_config, IH_ARCH_DEFAULT, + IH_TYPE_KERNEL, -1, FIT_LOAD_OPTIONAL, + &fw_data, &fw_len); + } + + if (ret < 0) + return ret; + + spl_image->size = fw_len; + spl_image->entry_point = fw_data; + spl_image->load_addr = fw_data; + if (fit_image_get_os(header, ret, &spl_image->os)) + spl_image->os = IH_OS_INVALID; + spl_image->name = genimg_get_os_name(spl_image->os); + + debug(SPL_TPL_PROMPT "payload image: %32s load addr: 0x%lx size: %d\n", + spl_image->name, spl_image->load_addr, spl_image->size); + +#ifdef CONFIG_SPL_FIT_SIGNATURE + images.verify = 1; +#endif + ret = fit_image_load(&images, (ulong)header, NULL, &fit_uname_config, + IH_ARCH_DEFAULT, IH_TYPE_FLATDT, -1, + FIT_LOAD_OPTIONAL, &dt_data, &dt_len); + if (ret >= 0) { + spl_image->fdt_addr = (void *)dt_data; + + if (spl_image->os == IH_OS_U_BOOT) { + /* HACK: U-boot expects FDT at a specific address */ + fdt_hack = spl_image->load_addr + spl_image->size; + fdt_hack = (fdt_hack + 3) & ~3; + debug("Relocating FDT to %p\n", spl_image->fdt_addr); + memcpy((void *)fdt_hack, spl_image->fdt_addr, dt_len); + } + } + + conf_noffset = fit_conf_get_node((const void *)header, + fit_uname_config); + if (conf_noffset <= 0) + return 0; + + for (idx = 0; + uname = fdt_stringlist_get((const void *)header, conf_noffset, + FIT_LOADABLE_PROP, idx, + NULL), uname; + idx++) + { +#ifdef CONFIG_SPL_FIT_SIGNATURE + images.verify = 1; +#endif + ret = fit_image_load(&images, (ulong)header, + &uname, &fit_uname_config, + IH_ARCH_DEFAULT, IH_TYPE_LOADABLE, -1, + FIT_LOAD_OPTIONAL_NON_ZERO, + &img_data, &img_len); + if (ret < 0) + return ret; + } + + return 0; +} +#endif + +__weak int spl_parse_legacy_header(struct spl_image_info *spl_image, + const struct image_header *header) +{ + /* LEGACY image not supported */ + debug("Legacy boot image support not enabled, proceeding to other boot methods\n"); + return -EINVAL; +} + +int spl_parse_image_header(struct spl_image_info *spl_image, + const struct image_header *header) +{ +#ifdef CONFIG_SPL_LOAD_FIT_FULL + int ret = spl_load_fit_image(spl_image, header); + + if (!ret) + return ret; +#endif + if (image_get_magic(header) == IH_MAGIC) { + int ret; + + ret = spl_parse_legacy_header(spl_image, header); + if (ret) + return ret; + } else { +#ifdef CONFIG_SPL_PANIC_ON_RAW_IMAGE + /* + * CONFIG_SPL_PANIC_ON_RAW_IMAGE is defined when the + * code which loads images in SPL cannot guarantee that + * absolutely all read errors will be reported. + * An example is the LPC32XX MLC NAND driver, which + * will consider that a completely unreadable NAND block + * is bad, and thus should be skipped silently. + */ + panic("** no mkimage signature but raw image not supported"); +#endif + +#ifdef CONFIG_SPL_OS_BOOT + ulong start, end; + + if (!bootz_setup((ulong)header, &start, &end)) { + spl_image->name = "Linux"; + spl_image->os = IH_OS_LINUX; + spl_image->load_addr = CONFIG_SYS_LOAD_ADDR; + spl_image->entry_point = CONFIG_SYS_LOAD_ADDR; + spl_image->size = end - start; + debug(SPL_TPL_PROMPT + "payload zImage, load addr: 0x%lx size: %d\n", + spl_image->load_addr, spl_image->size); + return 0; + } +#endif + +#ifdef CONFIG_SPL_RAW_IMAGE_SUPPORT + /* Signature not found - assume u-boot.bin */ + debug("mkimage signature not found - ih_magic = %x\n", + header->ih_magic); + spl_set_header_raw_uboot(spl_image); +#else + /* RAW image not supported, proceed to other boot methods. */ + debug("Raw boot image support not enabled, proceeding to other boot methods\n"); + return -EINVAL; +#endif + } + + return 0; +} + +__weak void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) +{ + typedef void __noreturn (*image_entry_noargs_t)(void); + + image_entry_noargs_t image_entry = + (image_entry_noargs_t)spl_image->entry_point; + + debug("image entry point: 0x%lx\n", spl_image->entry_point); + image_entry(); +} + +#if CONFIG_IS_ENABLED(HANDOFF) +/** + * Set up the SPL hand-off information + * + * This is initially empty (zero) but can be written by + */ +static int setup_spl_handoff(void) +{ + struct spl_handoff *ho; + + ho = bloblist_ensure(BLOBLISTT_SPL_HANDOFF, sizeof(struct spl_handoff)); + if (!ho) + return -ENOENT; + + return 0; +} + +__weak int handoff_arch_save(struct spl_handoff *ho) +{ + return 0; +} + +static int write_spl_handoff(void) +{ + struct spl_handoff *ho; + int ret; + + ho = bloblist_find(BLOBLISTT_SPL_HANDOFF, sizeof(struct spl_handoff)); + if (!ho) + return -ENOENT; + handoff_save_dram(ho); + ret = handoff_arch_save(ho); + if (ret) + return ret; + debug(SPL_TPL_PROMPT "Wrote SPL handoff\n"); + + return 0; +} +#else +static inline int setup_spl_handoff(void) { return 0; } +static inline int write_spl_handoff(void) { return 0; } + +#endif /* HANDOFF */ + +/** + * get_bootstage_id() - Get the bootstage ID to emit + * + * @start: true if this is for starting SPL, false for ending it + * @return bootstage ID to use + */ +static enum bootstage_id get_bootstage_id(bool start) +{ + enum u_boot_phase phase = spl_phase(); + + if (IS_ENABLED(CONFIG_TPL_BUILD) && phase == PHASE_TPL) + return start ? BOOTSTAGE_ID_START_TPL : BOOTSTAGE_ID_END_TPL; + else + return start ? BOOTSTAGE_ID_START_SPL : BOOTSTAGE_ID_END_SPL; +} + +static int spl_common_init(bool setup_malloc) +{ + int ret; + +#if CONFIG_VAL(SYS_MALLOC_F_LEN) + if (setup_malloc) { +#ifdef CONFIG_MALLOC_F_ADDR + gd->malloc_base = CONFIG_MALLOC_F_ADDR; +#endif + gd->malloc_limit = CONFIG_VAL(SYS_MALLOC_F_LEN); + gd->malloc_ptr = 0; + } +#endif + ret = bootstage_init(u_boot_first_phase()); + if (ret) { + debug("%s: Failed to set up bootstage: ret=%d\n", __func__, + ret); + return ret; + } +#ifdef CONFIG_BOOTSTAGE_STASH + if (!u_boot_first_phase()) { + const void *stash = map_sysmem(CONFIG_BOOTSTAGE_STASH_ADDR, + CONFIG_BOOTSTAGE_STASH_SIZE); + + ret = bootstage_unstash(stash, CONFIG_BOOTSTAGE_STASH_SIZE); + if (ret) + debug("%s: Failed to unstash bootstage: ret=%d\n", + __func__, ret); + } +#endif /* CONFIG_BOOTSTAGE_STASH */ + bootstage_mark_name(get_bootstage_id(true), + spl_phase_name(spl_phase())); +#if CONFIG_IS_ENABLED(LOG) + ret = log_init(); + if (ret) { + debug("%s: Failed to set up logging\n", __func__); + return ret; + } +#endif + if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { + ret = fdtdec_setup(); + if (ret) { + debug("fdtdec_setup() returned error %d\n", ret); + return ret; + } + } + if (CONFIG_IS_ENABLED(DM)) { + bootstage_start(BOOTSTAGE_ID_ACCUM_DM_SPL, + spl_phase() == PHASE_TPL ? "dm tpl" : "dm_spl"); + /* With CONFIG_SPL_OF_PLATDATA, bring in all devices */ + ret = dm_init_and_scan(!CONFIG_IS_ENABLED(OF_PLATDATA)); + bootstage_accum(BOOTSTAGE_ID_ACCUM_DM_SPL); + if (ret) { + debug("dm_init_and_scan() returned error %d\n", ret); + return ret; + } + } + + return 0; +} + +void spl_set_bd(void) +{ + /* + * NOTE: On some platforms (e.g. x86) bdata may be in flash and not + * writeable. + */ + if (!gd->bd) + gd->bd = &bdata; +} + +int spl_early_init(void) +{ + int ret; + + debug("%s\n", __func__); + + ret = spl_common_init(true); + if (ret) + return ret; + gd->flags |= GD_FLG_SPL_EARLY_INIT; + + return 0; +} + +int spl_init(void) +{ + int ret; + bool setup_malloc = !(IS_ENABLED(CONFIG_SPL_STACK_R) && + IS_ENABLED(CONFIG_SPL_SYS_MALLOC_SIMPLE)); + + debug("%s\n", __func__); + + if (!(gd->flags & GD_FLG_SPL_EARLY_INIT)) { + ret = spl_common_init(setup_malloc); + if (ret) + return ret; + } + gd->flags |= GD_FLG_SPL_INIT; + + return 0; +} + +#ifndef BOOT_DEVICE_NONE +#define BOOT_DEVICE_NONE 0xdeadbeef +#endif + +__weak void board_boot_order(u32 *spl_boot_list) +{ + spl_boot_list[0] = spl_boot_device(); +} + +static struct spl_image_loader *spl_ll_find_loader(uint boot_device) +{ + struct spl_image_loader *drv = + ll_entry_start(struct spl_image_loader, spl_image_loader); + const int n_ents = + ll_entry_count(struct spl_image_loader, spl_image_loader); + struct spl_image_loader *entry; + + for (entry = drv; entry != drv + n_ents; entry++) { + if (boot_device == entry->boot_device) + return entry; + } + + /* Not found */ + return NULL; +} + +static int spl_load_image(struct spl_image_info *spl_image, + struct spl_image_loader *loader) +{ + int ret; + struct spl_boot_device bootdev; + + bootdev.boot_device = loader->boot_device; + bootdev.boot_device_name = NULL; + + ret = loader->load_image(spl_image, &bootdev); +#ifdef CONFIG_SPL_LEGACY_IMAGE_CRC_CHECK + if (!ret && spl_image->dcrc_length) { + /* check data crc */ + ulong dcrc = crc32_wd(0, (unsigned char *)spl_image->dcrc_data, + spl_image->dcrc_length, CHUNKSZ_CRC32); + if (dcrc != spl_image->dcrc) { + puts("SPL: Image data CRC check failed!\n"); + ret = -EINVAL; + } + } +#endif + return ret; +} + +/** + * boot_from_devices() - Try loading a booting U-Boot from a list of devices + * + * @spl_image: Place to put the image details if successful + * @spl_boot_list: List of boot devices to try + * @count: Number of elements in spl_boot_list + * @return 0 if OK, -ve on error + */ +static int boot_from_devices(struct spl_image_info *spl_image, + u32 spl_boot_list[], int count) +{ + int i; + + for (i = 0; i < count && spl_boot_list[i] != BOOT_DEVICE_NONE; i++) { + struct spl_image_loader *loader; + + loader = spl_ll_find_loader(spl_boot_list[i]); +#if defined(CONFIG_SPL_SERIAL_SUPPORT) \ + && defined(CONFIG_SPL_LIBCOMMON_SUPPORT) \ + && !defined(CONFIG_SILENT_CONSOLE) + if (loader) + printf("Trying to boot from %s\n", loader->name); + else + puts(SPL_TPL_PROMPT "Unsupported Boot Device!\n"); +#endif + if (loader && !spl_load_image(spl_image, loader)) { + spl_image->boot_device = spl_boot_list[i]; + return 0; + } + } + + return -ENODEV; +} + +#if defined(CONFIG_SPL_FRAMEWORK_BOARD_INIT_F) +void board_init_f(ulong dummy) +{ + if (CONFIG_IS_ENABLED(OF_CONTROL)) { + int ret; + + ret = spl_early_init(); + if (ret) { + debug("spl_early_init() failed: %d\n", ret); + hang(); + } + } + + preloader_console_init(); +} +#endif + +void board_init_r(gd_t *dummy1, ulong dummy2) +{ + u32 spl_boot_list[] = { + BOOT_DEVICE_NONE, + BOOT_DEVICE_NONE, + BOOT_DEVICE_NONE, + BOOT_DEVICE_NONE, + BOOT_DEVICE_NONE, + }; + struct spl_image_info spl_image; + int ret; + + debug(">>" SPL_TPL_PROMPT "board_init_r()\n"); + + spl_set_bd(); + +#if defined(CONFIG_SYS_SPL_MALLOC_START) + mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START, + CONFIG_SYS_SPL_MALLOC_SIZE); + gd->flags |= GD_FLG_FULL_MALLOC_INIT; +#endif + if (!(gd->flags & GD_FLG_SPL_INIT)) { + if (spl_init()) + hang(); + } +#if !defined(CONFIG_PPC) && !defined(CONFIG_ARCH_MX6) + /* + * timer_init() does not exist on PPC systems. The timer is initialized + * and enabled (decrementer) in interrupt_init() here. + */ + timer_init(); +#endif + if (CONFIG_IS_ENABLED(BLOBLIST)) { + ret = bloblist_init(); + if (ret) { + debug("%s: Failed to set up bloblist: ret=%d\n", + __func__, ret); + puts(SPL_TPL_PROMPT "Cannot set up bloblist\n"); + hang(); + } + } + if (CONFIG_IS_ENABLED(HANDOFF)) { + int ret; + + ret = setup_spl_handoff(); + if (ret) { + puts(SPL_TPL_PROMPT "Cannot set up SPL handoff\n"); + hang(); + } + } + +#if CONFIG_IS_ENABLED(BOARD_INIT) + spl_board_init(); +#endif + +#if defined(CONFIG_SPL_WATCHDOG_SUPPORT) && CONFIG_IS_ENABLED(WDT) + initr_watchdog(); +#endif + + if (IS_ENABLED(CONFIG_SPL_OS_BOOT) || CONFIG_IS_ENABLED(HANDOFF) || + IS_ENABLED(CONFIG_SPL_ATF)) + dram_init_banksize(); + + bootcount_inc(); + + memset(&spl_image, '\0', sizeof(spl_image)); +#ifdef CONFIG_SYS_SPL_ARGS_ADDR + spl_image.arg = (void *)CONFIG_SYS_SPL_ARGS_ADDR; +#endif + spl_image.boot_device = BOOT_DEVICE_NONE; + board_boot_order(spl_boot_list); + + if (boot_from_devices(&spl_image, spl_boot_list, + ARRAY_SIZE(spl_boot_list))) { + puts(SPL_TPL_PROMPT "failed to boot from all boot devices\n"); + hang(); + } + + spl_perform_fixups(&spl_image); + if (CONFIG_IS_ENABLED(HANDOFF)) { + ret = write_spl_handoff(); + if (ret) + printf(SPL_TPL_PROMPT + "SPL hand-off write failed (err=%d)\n", ret); + } + if (CONFIG_IS_ENABLED(BLOBLIST)) { + ret = bloblist_finish(); + if (ret) + printf("Warning: Failed to finish bloblist (ret=%d)\n", + ret); + } + +#ifdef CONFIG_CPU_V7M + spl_image.entry_point |= 0x1; +#endif + switch (spl_image.os) { + case IH_OS_U_BOOT: + debug("Jumping to %s...\n", spl_phase_name(spl_next_phase())); + break; +#if CONFIG_IS_ENABLED(ATF) + case IH_OS_ARM_TRUSTED_FIRMWARE: + debug("Jumping to U-Boot via ARM Trusted Firmware\n"); + spl_fixup_fdt(spl_image.fdt_addr); + spl_invoke_atf(&spl_image); + break; +#endif +#if CONFIG_IS_ENABLED(OPTEE) + case IH_OS_TEE: + debug("Jumping to U-Boot via OP-TEE\n"); + spl_optee_entry(NULL, NULL, spl_image.fdt_addr, + (void *)spl_image.entry_point); + break; +#endif +#if CONFIG_IS_ENABLED(OPENSBI) + case IH_OS_OPENSBI: + debug("Jumping to U-Boot via RISC-V OpenSBI\n"); + spl_invoke_opensbi(&spl_image); + break; +#endif +#ifdef CONFIG_SPL_OS_BOOT + case IH_OS_LINUX: + debug("Jumping to Linux\n"); +#if defined(CONFIG_SYS_SPL_ARGS_ADDR) + spl_fixup_fdt((void *)CONFIG_SYS_SPL_ARGS_ADDR); +#endif + spl_board_prepare_for_linux(); + jump_to_image_linux(&spl_image); +#endif + default: + debug("Unsupported OS image.. Jumping nevertheless..\n"); + } +#if CONFIG_VAL(SYS_MALLOC_F_LEN) && !defined(CONFIG_SYS_SPL_MALLOC_SIZE) + debug("SPL malloc() used 0x%lx bytes (%ld KB)\n", gd->malloc_ptr, + gd->malloc_ptr / 1024); +#endif + bootstage_mark_name(get_bootstage_id(false), "end phase"); +#ifdef CONFIG_BOOTSTAGE_STASH + ret = bootstage_stash((void *)CONFIG_BOOTSTAGE_STASH_ADDR, + CONFIG_BOOTSTAGE_STASH_SIZE); + if (ret) + debug("Failed to stash bootstage: err=%d\n", ret); +#endif + + spl_board_prepare_for_boot(); + jump_to_image_no_args(&spl_image); +} + +/* + * This requires UART clocks to be enabled. In order for this to work the + * caller must ensure that the gd pointer is valid. + */ +void preloader_console_init(void) +{ +#ifdef CONFIG_SPL_SERIAL_SUPPORT + gd->baudrate = CONFIG_BAUDRATE; + + serial_init(); /* serial communications setup */ + + gd->have_console = 1; + +#if CONFIG_IS_ENABLED(BANNER_PRINT) + puts("\nU-Boot " SPL_TPL_NAME " " PLAIN_VERSION " (" U_BOOT_DATE " - " + U_BOOT_TIME " " U_BOOT_TZ ")\n"); +#endif +#ifdef CONFIG_SPL_DISPLAY_PRINT + spl_display_print(); +#endif +#endif +} + +/** + * This function is called before the stack is changed from initial stack to + * relocated stack. It tries to dump the stack size used + */ +__weak void spl_relocate_stack_check(void) +{ +#if CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE) + ulong init_sp = gd->start_addr_sp; + ulong stack_bottom = init_sp - CONFIG_VAL(SIZE_LIMIT_PROVIDE_STACK); + u8 *ptr = (u8 *)stack_bottom; + ulong i; + + for (i = 0; i < CONFIG_VAL(SIZE_LIMIT_PROVIDE_STACK); i++) { + if (*ptr != CONFIG_VAL(SYS_STACK_F_CHECK_BYTE)) + break; + ptr++; + } + printf("SPL initial stack usage: %lu bytes\n", + CONFIG_VAL(SIZE_LIMIT_PROVIDE_STACK) - i); +#endif +} + +/** + * spl_relocate_stack_gd() - Relocate stack ready for board_init_r() execution + * + * Sometimes board_init_f() runs with a stack in SRAM but we want to use SDRAM + * for the main board_init_r() execution. This is typically because we need + * more stack space for things like the MMC sub-system. + * + * This function calculates the stack position, copies the global_data into + * place, sets the new gd (except for ARM, for which setting GD within a C + * function may not always work) and returns the new stack position. The + * caller is responsible for setting up the sp register and, in the case + * of ARM, setting up gd. + * + * All of this is done using the same layout and alignments as done in + * board_init_f_init_reserve() / board_init_f_alloc_reserve(). + * + * @return new stack location, or 0 to use the same stack + */ +ulong spl_relocate_stack_gd(void) +{ +#ifdef CONFIG_SPL_STACK_R + gd_t *new_gd; + ulong ptr = CONFIG_SPL_STACK_R_ADDR; + + if (CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE)) + spl_relocate_stack_check(); + +#if defined(CONFIG_SPL_SYS_MALLOC_SIMPLE) && CONFIG_VAL(SYS_MALLOC_F_LEN) + if (CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN) { + debug("SPL malloc() before relocation used 0x%lx bytes (%ld KB)\n", + gd->malloc_ptr, gd->malloc_ptr / 1024); + ptr -= CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN; + gd->malloc_base = ptr; + gd->malloc_limit = CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN; + gd->malloc_ptr = 0; + } +#endif + /* Get stack position: use 8-byte alignment for ABI compliance */ + ptr = CONFIG_SPL_STACK_R_ADDR - roundup(sizeof(gd_t),16); + new_gd = (gd_t *)ptr; + memcpy(new_gd, (void *)gd, sizeof(gd_t)); +#if CONFIG_IS_ENABLED(DM) + dm_fixup_for_gd_move(new_gd); +#endif +#if !defined(CONFIG_ARM) && !defined(CONFIG_RISCV) + gd = new_gd; +#endif + return ptr; +#else + return 0; +#endif +} + +#if defined(CONFIG_BOOTCOUNT_LIMIT) && \ + ((!defined(CONFIG_TPL_BUILD) && !defined(CONFIG_SPL_BOOTCOUNT_LIMIT)) || \ + (defined(CONFIG_TPL_BUILD) && !defined(CONFIG_TPL_BOOTCOUNT_LIMIT))) +void bootcount_store(ulong a) +{ +} + +ulong bootcount_load(void) +{ + return 0; +} +#endif |