diff options
Diffstat (limited to 'common/spl')
-rw-r--r-- | common/spl/Kconfig | 17 | ||||
-rw-r--r-- | common/spl/Makefile | 1 | ||||
-rw-r--r-- | common/spl/spl.c | 8 | ||||
-rw-r--r-- | common/spl/spl_fit.c | 37 | ||||
-rw-r--r-- | common/spl/spl_opensbi.c | 85 |
5 files changed, 134 insertions, 14 deletions
diff --git a/common/spl/Kconfig b/common/spl/Kconfig index e48419825e..f467eca2be 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -1157,6 +1157,23 @@ config SPL_OPTEE OP-TEE is an open source Trusted OS which is loaded by SPL. More detail at: https://github.com/OP-TEE/optee_os +config SPL_OPENSBI + bool "Support RISC-V OpenSBI" + depends on RISCV && SPL_RISCV_MMODE && RISCV_SMODE + help + OpenSBI is an open-source implementation of the RISC-V Supervisor Binary + Interface (SBI) specification. U-Boot supports the OpenSBI FW_DYNAMIC + firmware. It is loaded and started by U-Boot SPL. + + More details are available at https://github.com/riscv/opensbi and + https://github.com/riscv/riscv-sbi-doc + +config SPL_OPENSBI_LOAD_ADDR + hex "OpenSBI load address" + depends on SPL_OPENSBI + help + Load address of the OpenSBI binary. + config TPL bool depends on SUPPORT_TPL diff --git a/common/spl/Makefile b/common/spl/Makefile index d28de692dd..5ce6f4ae48 100644 --- a/common/spl/Makefile +++ b/common/spl/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_$(SPL_TPL_)NET_SUPPORT) += spl_net.o obj-$(CONFIG_$(SPL_TPL_)MMC_SUPPORT) += spl_mmc.o obj-$(CONFIG_$(SPL_TPL_)ATF) += spl_atf.o obj-$(CONFIG_$(SPL_TPL_)OPTEE) += spl_optee.o +obj-$(CONFIG_$(SPL_TPL_)OPENSBI) += spl_opensbi.o obj-$(CONFIG_$(SPL_TPL_)USB_STORAGE) += spl_usb.o obj-$(CONFIG_$(SPL_TPL_)FS_FAT) += spl_fat.o obj-$(CONFIG_$(SPL_TPL_)FS_EXT4) += spl_ext.o diff --git a/common/spl/spl.c b/common/spl/spl.c index 2c696f2a79..082fa2bd94 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -659,6 +659,12 @@ void board_init_r(gd_t *dummy1, ulong dummy2) (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"); @@ -775,7 +781,7 @@ ulong spl_relocate_stack_gd(void) #if CONFIG_IS_ENABLED(DM) dm_fixup_for_gd_move(new_gd); #endif -#if !defined(CONFIG_ARM) +#if !defined(CONFIG_ARM) && !defined(CONFIG_RISCV) gd = new_gd; #endif return ptr; diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index 2e2e09eafb..b3e3ccd5a2 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -12,6 +12,8 @@ #include <linux/libfdt.h> #include <spl.h> +DECLARE_GLOBAL_DATA_PTR; + #ifndef CONFIG_SYS_BOOTM_LEN #define CONFIG_SYS_BOOTM_LEN (64 << 20) #endif @@ -279,25 +281,34 @@ static int spl_fit_append_fdt(struct spl_image_info *spl_image, void *fit, int images, ulong base_offset) { struct spl_image_info image_info; - int node, ret; + int node, ret = 0; + + /* + * Use the address following the image as target address for the + * device tree. + */ + image_info.load_addr = spl_image->load_addr + spl_image->size; /* Figure out which device tree the board wants to use */ node = spl_fit_get_image_node(fit, images, FIT_FDT_PROP, 0); if (node < 0) { debug("%s: cannot find FDT node\n", __func__); - return node; - } - - /* - * Read the device tree and place it after the image. - * Align the destination address to ARCH_DMA_MINALIGN. - */ - image_info.load_addr = spl_image->load_addr + spl_image->size; - ret = spl_load_fit_image(info, sector, fit, base_offset, node, - &image_info); - if (ret < 0) - return ret; + /* + * U-Boot did not find a device tree inside the FIT image. Use + * the U-Boot device tree instead. + */ + if (gd->fdt_blob) + memcpy((void *)image_info.load_addr, gd->fdt_blob, + fdt_totalsize(gd->fdt_blob)); + else + return node; + } else { + ret = spl_load_fit_image(info, sector, fit, base_offset, node, + &image_info); + if (ret < 0) + return ret; + } /* Make the load-address of the FDT available for the SPL framework */ spl_image->fdt_addr = (void *)image_info.load_addr; diff --git a/common/spl/spl_opensbi.c b/common/spl/spl_opensbi.c new file mode 100644 index 0000000000..a6b4480ed2 --- /dev/null +++ b/common/spl/spl_opensbi.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Fraunhofer AISEC, + * Lukas Auer <lukas.auer@aisec.fraunhofer.de> + * + * Based on common/spl/spl_atf.c + */ +#include <common.h> +#include <errno.h> +#include <spl.h> +#include <asm/smp.h> +#include <opensbi.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct fw_dynamic_info opensbi_info; + +static int spl_opensbi_find_uboot_node(void *blob, int *uboot_node) +{ + int fit_images_node, node; + const char *fit_os; + + fit_images_node = fdt_path_offset(blob, "/fit-images"); + if (fit_images_node < 0) + return -ENODEV; + + fdt_for_each_subnode(node, blob, fit_images_node) { + fit_os = fdt_getprop(blob, node, FIT_OS_PROP, NULL); + if (!fit_os) + continue; + + if (genimg_get_os_id(fit_os) == IH_OS_U_BOOT) { + *uboot_node = node; + return 0; + } + } + + return -ENODEV; +} + +void spl_invoke_opensbi(struct spl_image_info *spl_image) +{ + int ret, uboot_node; + ulong uboot_entry; + void (*opensbi_entry)(ulong hartid, ulong dtb, ulong info); + + if (!spl_image->fdt_addr) { + pr_err("No device tree specified in SPL image\n"); + hang(); + } + + /* Find U-Boot image in /fit-images */ + ret = spl_opensbi_find_uboot_node(spl_image->fdt_addr, &uboot_node); + if (ret) { + pr_err("Can't find U-Boot node, %d", ret); + hang(); + } + + /* Get U-Boot entry point */ + uboot_entry = fdt_getprop_u32(spl_image->fdt_addr, uboot_node, + "entry-point"); + if (uboot_entry == FDT_ERROR) + uboot_entry = fdt_getprop_u32(spl_image->fdt_addr, uboot_node, + "load-addr"); + + /* Prepare obensbi_info object */ + opensbi_info.magic = FW_DYNAMIC_INFO_MAGIC_VALUE; + opensbi_info.version = FW_DYNAMIC_INFO_VERSION; + opensbi_info.next_addr = uboot_entry; + opensbi_info.next_mode = FW_DYNAMIC_INFO_NEXT_MODE_S; + opensbi_info.options = SBI_SCRATCH_NO_BOOT_PRINTS; + + opensbi_entry = (void (*)(ulong, ulong, ulong))spl_image->entry_point; + invalidate_icache_all(); + +#ifdef CONFIG_SMP + ret = smp_call_function((ulong)spl_image->entry_point, + (ulong)spl_image->fdt_addr, + (ulong)&opensbi_info); + if (ret) + hang(); +#endif + opensbi_entry(gd->arch.boot_hart, (ulong)spl_image->fdt_addr, + (ulong)&opensbi_info); +} |