blob: 8127ebc946b3edd45154abbe5bb9102cbde247a7 [file] [log] [blame]
Lukas Auer5e30e452019-08-21 21:14:44 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2019 Fraunhofer AISEC,
4 * Lukas Auer <lukas.auer@aisec.fraunhofer.de>
5 *
6 * Based on common/spl/spl_atf.c
7 */
8#include <common.h>
Simon Glass1eb69ae2019-11-14 12:57:39 -07009#include <cpu_func.h>
Lukas Auer5e30e452019-08-21 21:14:44 +020010#include <errno.h>
Simon Glassdb41d652019-12-28 10:45:07 -070011#include <hang.h>
Simon Glass4d72caa2020-05-10 11:40:01 -060012#include <image.h>
Lukas Auer5e30e452019-08-21 21:14:44 +020013#include <spl.h>
Simon Glass401d1c42020-10-30 21:38:53 -060014#include <asm/global_data.h>
Lukas Auer5e30e452019-08-21 21:14:44 +020015#include <asm/smp.h>
16#include <opensbi.h>
Simon Glass4d72caa2020-05-10 11:40:01 -060017#include <linux/libfdt.h>
Simon Glass1e94b462023-09-14 18:21:46 -060018#include <linux/printk.h>
Randolph10c4ab82023-12-29 16:32:22 +080019#include <mapmem.h>
Lukas Auer5e30e452019-08-21 21:14:44 +020020
21DECLARE_GLOBAL_DATA_PTR;
22
23struct fw_dynamic_info opensbi_info;
24
Randolph5367b9e2023-10-12 14:35:03 +080025static int spl_opensbi_find_os_node(void *blob, int *uboot_node, int os_type)
Lukas Auer5e30e452019-08-21 21:14:44 +020026{
27 int fit_images_node, node;
28 const char *fit_os;
29
30 fit_images_node = fdt_path_offset(blob, "/fit-images");
31 if (fit_images_node < 0)
32 return -ENODEV;
33
34 fdt_for_each_subnode(node, blob, fit_images_node) {
35 fit_os = fdt_getprop(blob, node, FIT_OS_PROP, NULL);
36 if (!fit_os)
37 continue;
38
Randolph5367b9e2023-10-12 14:35:03 +080039 if (genimg_get_os_id(fit_os) == os_type) {
Lukas Auer5e30e452019-08-21 21:14:44 +020040 *uboot_node = node;
41 return 0;
42 }
43 }
44
45 return -ENODEV;
46}
47
Chanho Parkef086872023-08-29 10:20:14 +090048void __noreturn spl_invoke_opensbi(struct spl_image_info *spl_image)
Lukas Auer5e30e452019-08-21 21:14:44 +020049{
Randolph5367b9e2023-10-12 14:35:03 +080050 int ret, os_node;
51 ulong os_entry;
52 int os_type;
Chanho Parkef086872023-08-29 10:20:14 +090053 typedef void __noreturn (*opensbi_entry_t)(ulong hartid, ulong dtb, ulong info);
54 opensbi_entry_t opensbi_entry;
Lukas Auer5e30e452019-08-21 21:14:44 +020055
56 if (!spl_image->fdt_addr) {
57 pr_err("No device tree specified in SPL image\n");
58 hang();
59 }
60
Randolph5367b9e2023-10-12 14:35:03 +080061 /*
Randolph10c4ab82023-12-29 16:32:22 +080062 * Originally, u-boot-spl will place DTB directly after the kernel,
63 * but the size of the kernel did not include the BSS section, which
64 * means u-boot-spl will place the DTB in the kernel BSS section
65 * causing the DTB to be cleared by kernel BSS initializtion.
66 * Moving DTB in front of the kernel can avoid the error.
67 */
68#if CONFIG_IS_ENABLED(LOAD_FIT_OPENSBI_OS_BOOT) && \
69 CONFIG_IS_ENABLED(PAYLOAD_ARGS_ADDR)
70 memcpy((void *)CONFIG_SPL_PAYLOAD_ARGS_ADDR, spl_image->fdt_addr,
71 fdt_totalsize(spl_image->fdt_addr));
72 spl_image->fdt_addr = map_sysmem(CONFIG_SPL_PAYLOAD_ARGS_ADDR, 0);
73#endif
74
75 /*
Randolph5367b9e2023-10-12 14:35:03 +080076 * Find next os image in /fit-images
Randolph58fa2a52023-10-12 14:35:07 +080077 * The next os image default is u-boot proper, once enable
78 * OpenSBI OS boot mode, the OS image should be linux.
Randolph5367b9e2023-10-12 14:35:03 +080079 */
Randolph58fa2a52023-10-12 14:35:07 +080080 if (CONFIG_IS_ENABLED(LOAD_FIT_OPENSBI_OS_BOOT))
81 os_type = IH_OS_LINUX;
82 else
83 os_type = IH_OS_U_BOOT;
84
Randolph5367b9e2023-10-12 14:35:03 +080085 ret = spl_opensbi_find_os_node(spl_image->fdt_addr, &os_node, os_type);
Lukas Auer5e30e452019-08-21 21:14:44 +020086 if (ret) {
Randolph5367b9e2023-10-12 14:35:03 +080087 pr_err("Can't find %s node for opensbi, %d\n",
88 genimg_get_os_name(os_type), ret);
Lukas Auer5e30e452019-08-21 21:14:44 +020089 hang();
90 }
91
92 /* Get U-Boot entry point */
Randolph5367b9e2023-10-12 14:35:03 +080093 ret = fit_image_get_entry(spl_image->fdt_addr, os_node, &os_entry);
Michal Simekcaa7fc22020-09-03 11:24:28 +020094 if (ret)
Randolph5367b9e2023-10-12 14:35:03 +080095 ret = fit_image_get_load(spl_image->fdt_addr, os_node, &os_entry);
Lukas Auer5e30e452019-08-21 21:14:44 +020096
Nikita Shubin48da0ca2022-08-08 13:24:25 +030097 /* Prepare opensbi_info object */
Lukas Auer5e30e452019-08-21 21:14:44 +020098 opensbi_info.magic = FW_DYNAMIC_INFO_MAGIC_VALUE;
99 opensbi_info.version = FW_DYNAMIC_INFO_VERSION;
Randolph5367b9e2023-10-12 14:35:03 +0800100 opensbi_info.next_addr = os_entry;
Lukas Auer5e30e452019-08-21 21:14:44 +0200101 opensbi_info.next_mode = FW_DYNAMIC_INFO_NEXT_MODE_S;
Nikita Shubinaa0eda12022-08-08 13:28:52 +0300102 opensbi_info.options = CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS;
Lukas Auerb86f6d12019-12-08 23:28:49 +0100103 opensbi_info.boot_hart = gd->arch.boot_hart;
Lukas Auer5e30e452019-08-21 21:14:44 +0200104
Chanho Parkef086872023-08-29 10:20:14 +0900105 opensbi_entry = (opensbi_entry_t)spl_image->entry_point;
Lukas Auer5e30e452019-08-21 21:14:44 +0200106 invalidate_icache_all();
107
Bin Meng191636e2020-04-16 08:09:30 -0700108#ifdef CONFIG_SPL_SMP
Lukas Auer0e1233c2019-12-08 23:28:52 +0100109 /*
110 * Start OpenSBI on all secondary harts and wait for acknowledgment.
111 *
112 * OpenSBI first relocates itself to its link address. This is done by
113 * the main hart. To make sure no hart is still running U-Boot SPL
114 * during relocation, we wait for all secondary harts to acknowledge
115 * the call-function request before entering OpenSBI on the main hart.
116 * Otherwise, code corruption can occur if the link address ranges of
117 * U-Boot SPL and OpenSBI overlap.
118 */
Lukas Auer5e30e452019-08-21 21:14:44 +0200119 ret = smp_call_function((ulong)spl_image->entry_point,
120 (ulong)spl_image->fdt_addr,
Lukas Auer0e1233c2019-12-08 23:28:52 +0100121 (ulong)&opensbi_info, 1);
Lukas Auer5e30e452019-08-21 21:14:44 +0200122 if (ret)
123 hang();
124#endif
125 opensbi_entry(gd->arch.boot_hart, (ulong)spl_image->fdt_addr,
126 (ulong)&opensbi_info);
127}