1bcc1726aSKever Yang /*
2bcc1726aSKever Yang * Reference to the ARM TF Project,
3bcc1726aSKever Yang * plat/arm/common/arm_bl2_setup.c
4bcc1726aSKever Yang * Portions copyright (c) 2013-2016, ARM Limited and Contributors. All rights
5bcc1726aSKever Yang * reserved.
6bcc1726aSKever Yang * Copyright (C) 2016 Rockchip Electronic Co.,Ltd
7bcc1726aSKever Yang * Written by Kever Yang <kever.yang@rock-chips.com>
82e15a11cSPhilipp Tomsich * Copyright (C) 2017 Theobroma Systems Design und Consulting GmbH
9bcc1726aSKever Yang *
10bcc1726aSKever Yang * SPDX-License-Identifier: BSD-3-Clause
11bcc1726aSKever Yang */
12bcc1726aSKever Yang
13bcc1726aSKever Yang #include <common.h>
14bcc1726aSKever Yang #include <atf_common.h>
15bcc1726aSKever Yang #include <errno.h>
16bcc1726aSKever Yang #include <spl.h>
17bcc1726aSKever Yang
18bcc1726aSKever Yang static struct bl2_to_bl31_params_mem bl31_params_mem;
19bcc1726aSKever Yang static struct bl31_params *bl2_to_bl31_params;
20bcc1726aSKever Yang
21bcc1726aSKever Yang /**
22bcc1726aSKever Yang * bl2_plat_get_bl31_params() - prepare params for bl31.
23bcc1726aSKever Yang *
24bcc1726aSKever Yang * This function assigns a pointer to the memory that the platform has kept
25bcc1726aSKever Yang * aside to pass platform specific and trusted firmware related information
26bcc1726aSKever Yang * to BL31. This memory is allocated by allocating memory to
27bcc1726aSKever Yang * bl2_to_bl31_params_mem structure which is a superset of all the
28bcc1726aSKever Yang * structure whose information is passed to BL31
29bcc1726aSKever Yang * NOTE: This function should be called only once and should be done
30bcc1726aSKever Yang * before generating params to BL31
31bcc1726aSKever Yang *
32bcc1726aSKever Yang * @return bl31 params structure pointer
33bcc1726aSKever Yang */
bl2_plat_get_bl31_params(struct spl_image_info * spl_image,uintptr_t bl32_entry,uintptr_t bl33_entry)343bf65388SJason Zhu static struct bl31_params *bl2_plat_get_bl31_params(struct spl_image_info *spl_image,
353bf65388SJason Zhu uintptr_t bl32_entry,
36b04f87d7SJoseph Chen uintptr_t bl33_entry)
37bcc1726aSKever Yang {
38b04f87d7SJoseph Chen struct entry_point_info *bl32_ep_info;
39bcc1726aSKever Yang struct entry_point_info *bl33_ep_info;
40bcc1726aSKever Yang
41bcc1726aSKever Yang /*
42bcc1726aSKever Yang * Initialise the memory for all the arguments that needs to
43bcc1726aSKever Yang * be passed to BL31
44bcc1726aSKever Yang */
45bcc1726aSKever Yang memset(&bl31_params_mem, 0, sizeof(struct bl2_to_bl31_params_mem));
46bcc1726aSKever Yang
47bcc1726aSKever Yang /* Assign memory for TF related information */
48bcc1726aSKever Yang bl2_to_bl31_params = &bl31_params_mem.bl31_params;
49bcc1726aSKever Yang SET_PARAM_HEAD(bl2_to_bl31_params, ATF_PARAM_BL31, ATF_VERSION_1, 0);
50bcc1726aSKever Yang
51bcc1726aSKever Yang /* Fill BL31 related information */
52bcc1726aSKever Yang SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info,
53bcc1726aSKever Yang ATF_PARAM_IMAGE_BINARY, ATF_VERSION_1, 0);
54bcc1726aSKever Yang
55b04f87d7SJoseph Chen /* Fill BL32 related information */
56bcc1726aSKever Yang bl2_to_bl31_params->bl32_ep_info = &bl31_params_mem.bl32_ep_info;
57b04f87d7SJoseph Chen bl32_ep_info = &bl31_params_mem.bl32_ep_info;
58b04f87d7SJoseph Chen SET_PARAM_HEAD(bl32_ep_info, ATF_PARAM_EP, ATF_VERSION_1,
59b04f87d7SJoseph Chen ATF_EP_SECURE);
60b04f87d7SJoseph Chen
612687dce2SJoseph Chen bl32_ep_info->pc = bl32_entry == -1 ? 0 : bl32_entry;
62b04f87d7SJoseph Chen bl32_ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
63b04f87d7SJoseph Chen DISABLE_ALL_EXECPTIONS);
64b04f87d7SJoseph Chen
65bcc1726aSKever Yang bl2_to_bl31_params->bl32_image_info = &bl31_params_mem.bl32_image_info;
66bcc1726aSKever Yang SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info,
67bcc1726aSKever Yang ATF_PARAM_IMAGE_BINARY, ATF_VERSION_1, 0);
68bcc1726aSKever Yang
69bcc1726aSKever Yang /* Fill BL33 related information */
70bcc1726aSKever Yang bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem.bl33_ep_info;
71bcc1726aSKever Yang bl33_ep_info = &bl31_params_mem.bl33_ep_info;
72bcc1726aSKever Yang SET_PARAM_HEAD(bl33_ep_info, ATF_PARAM_EP, ATF_VERSION_1,
73bcc1726aSKever Yang ATF_EP_NON_SECURE);
74bcc1726aSKever Yang
75bcc1726aSKever Yang /* BL33 expects to receive the primary CPU MPID (through x0) */
76bcc1726aSKever Yang bl33_ep_info->args.arg0 = 0xffff & read_mpidr();
772e15a11cSPhilipp Tomsich bl33_ep_info->pc = bl33_entry;
785d74586aSJoseph Chen
79*17629ef7SZiyuan Xu if (spl_image->flags & SPL_ATF_AARCH32_BL33) {
805d74586aSJoseph Chen bl33_ep_info->spsr = SPSR_32(MODE32_svc, SPSR_T_ARM, EP_EE_LITTLE,
815d74586aSJoseph Chen DISABLE_ALL_EXECPTIONS_32);
82*17629ef7SZiyuan Xu
83*17629ef7SZiyuan Xu /*
84*17629ef7SZiyuan Xu * r1 - machine type
85*17629ef7SZiyuan Xu * r2 - boot data (atags/dt) pointer
86*17629ef7SZiyuan Xu */
87*17629ef7SZiyuan Xu if (spl_image->next_stage == SPL_NEXT_STAGE_KERNEL) {
88*17629ef7SZiyuan Xu bl33_ep_info->args.arg0 = 0;
89*17629ef7SZiyuan Xu bl33_ep_info->args.arg1 = 0xffffffff;
90*17629ef7SZiyuan Xu bl33_ep_info->args.arg2 = (unsigned long)spl_image->fdt_addr;
91*17629ef7SZiyuan Xu }
92*17629ef7SZiyuan Xu } else {
93bcc1726aSKever Yang bl33_ep_info->spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
94bcc1726aSKever Yang DISABLE_ALL_EXECPTIONS);
95*17629ef7SZiyuan Xu
96189f3a8cSJason Zhu /*
97189f3a8cSJason Zhu * Reference: arch/arm/lib/bootm.c
98189f3a8cSJason Zhu * boot_jump_linux(bootm_headers_t *images, int flag)
99189f3a8cSJason Zhu * {
100189f3a8cSJason Zhu * ......
101189f3a8cSJason Zhu * armv8_switch_to_el2((u64)images->ft_addr, 0, 0, 0,
102189f3a8cSJason Zhu * images->ep, ES_TO_AARCH64);
103189f3a8cSJason Zhu * }
104189f3a8cSJason Zhu */
1053bf65388SJason Zhu if (spl_image->next_stage == SPL_NEXT_STAGE_KERNEL)
1063bf65388SJason Zhu bl33_ep_info->args.arg0 = (unsigned long)spl_image->fdt_addr;
107*17629ef7SZiyuan Xu }
1083bf65388SJason Zhu
109bcc1726aSKever Yang bl2_to_bl31_params->bl33_image_info = &bl31_params_mem.bl33_image_info;
110bcc1726aSKever Yang SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info,
111bcc1726aSKever Yang ATF_PARAM_IMAGE_BINARY, ATF_VERSION_1, 0);
112bcc1726aSKever Yang
113bcc1726aSKever Yang return bl2_to_bl31_params;
114bcc1726aSKever Yang }
115bcc1726aSKever Yang
raw_write_daif(unsigned int daif)1162e15a11cSPhilipp Tomsich static inline void raw_write_daif(unsigned int daif)
117bcc1726aSKever Yang {
118bcc1726aSKever Yang __asm__ __volatile__("msr DAIF, %0\n\t" : : "r" (daif) : "memory");
119bcc1726aSKever Yang }
120bcc1726aSKever Yang
1212e15a11cSPhilipp Tomsich typedef void (*atf_entry_t)(struct bl31_params *params, void *plat_params);
1222e15a11cSPhilipp Tomsich
bl31_entry(struct spl_image_info * spl_image,uintptr_t bl31_entry,uintptr_t bl32_entry,uintptr_t bl33_entry,uintptr_t fdt_addr)1233bf65388SJason Zhu void bl31_entry(struct spl_image_info *spl_image,
1243bf65388SJason Zhu uintptr_t bl31_entry, uintptr_t bl32_entry,
125b04f87d7SJoseph Chen uintptr_t bl33_entry, uintptr_t fdt_addr)
126bcc1726aSKever Yang {
127bcc1726aSKever Yang struct bl31_params *bl31_params;
1282e15a11cSPhilipp Tomsich atf_entry_t atf_entry = (atf_entry_t)bl31_entry;
129bcc1726aSKever Yang
1303bf65388SJason Zhu bl31_params = bl2_plat_get_bl31_params(spl_image, bl32_entry, bl33_entry);
131bcc1726aSKever Yang
1322e15a11cSPhilipp Tomsich atf_entry((void *)bl31_params, (void *)fdt_addr);
1332e15a11cSPhilipp Tomsich }
1342e15a11cSPhilipp Tomsich
spl_fit_images_find(void * blob,int os)135b04f87d7SJoseph Chen static int spl_fit_images_find(void *blob, int os)
1362e15a11cSPhilipp Tomsich {
13769a04b4fSJoseph Chen int parent, node;
1382e15a11cSPhilipp Tomsich const void *data;
1392e15a11cSPhilipp Tomsich
1402e15a11cSPhilipp Tomsich if (!blob)
1412e15a11cSPhilipp Tomsich return -FDT_ERR_BADMAGIC;
1422e15a11cSPhilipp Tomsich
1432e15a11cSPhilipp Tomsich parent = fdt_path_offset(blob, "/fit-images");
1442e15a11cSPhilipp Tomsich if (parent < 0)
1452e15a11cSPhilipp Tomsich return -FDT_ERR_NOTFOUND;
1462e15a11cSPhilipp Tomsich
14769a04b4fSJoseph Chen fdt_for_each_subnode(node, blob, parent) {
1482e15a11cSPhilipp Tomsich data = fdt_getprop(blob, node, FIT_OS_PROP, NULL);
1492e15a11cSPhilipp Tomsich if (!data)
1502e15a11cSPhilipp Tomsich continue;
1512e15a11cSPhilipp Tomsich
152b04f87d7SJoseph Chen if (genimg_get_os_id(data) == os)
1532e15a11cSPhilipp Tomsich return node;
15469a04b4fSJoseph Chen }
1552e15a11cSPhilipp Tomsich
1562e15a11cSPhilipp Tomsich return -FDT_ERR_NOTFOUND;
1572e15a11cSPhilipp Tomsich }
1582e15a11cSPhilipp Tomsich
spl_fit_images_get_entry(void * blob,int node)1592e15a11cSPhilipp Tomsich uintptr_t spl_fit_images_get_entry(void *blob, int node)
1602e15a11cSPhilipp Tomsich {
1612e15a11cSPhilipp Tomsich ulong val;
1622e15a11cSPhilipp Tomsich
1632e15a11cSPhilipp Tomsich val = fdt_getprop_u32(blob, node, "entry-point");
1642e15a11cSPhilipp Tomsich if (val == FDT_ERROR)
1652e15a11cSPhilipp Tomsich val = fdt_getprop_u32(blob, node, "load-addr");
1662e15a11cSPhilipp Tomsich
1672e15a11cSPhilipp Tomsich debug("%s: entry point 0x%lx\n", __func__, val);
1682e15a11cSPhilipp Tomsich return val;
1692e15a11cSPhilipp Tomsich }
1702e15a11cSPhilipp Tomsich
spl_invoke_atf(struct spl_image_info * spl_image)1712e15a11cSPhilipp Tomsich void spl_invoke_atf(struct spl_image_info *spl_image)
1722e15a11cSPhilipp Tomsich {
1731620aad4SJoseph Chen uintptr_t bl32_entry, bl33_entry;
1742e15a11cSPhilipp Tomsich void *blob = spl_image->fdt_addr;
1754bba5ee7SPhilipp Tomsich uintptr_t platform_param = (uintptr_t)blob;
1762e15a11cSPhilipp Tomsich int node;
1772e15a11cSPhilipp Tomsich
1781620aad4SJoseph Chen /*
1791620aad4SJoseph Chen * Find the OP-TEE binary (in /fit-images) load address or
1801620aad4SJoseph Chen * entry point (if different) and pass it as the BL3-2 entry
1811620aad4SJoseph Chen * point, this is optional.
1821620aad4SJoseph Chen * This will need to be extended to support Falcon mode.
1831620aad4SJoseph Chen */
184b04f87d7SJoseph Chen node = spl_fit_images_find(blob, IH_OS_OP_TEE);
185b04f87d7SJoseph Chen if (node >= 0)
186b04f87d7SJoseph Chen bl32_entry = spl_fit_images_get_entry(blob, node);
1871620aad4SJoseph Chen else
1881620aad4SJoseph Chen bl32_entry = spl_image->entry_point_bl32; /* optional */
189b04f87d7SJoseph Chen
1902e15a11cSPhilipp Tomsich /*
1912e15a11cSPhilipp Tomsich * Find the U-Boot binary (in /fit-images) load addreess or
1922e15a11cSPhilipp Tomsich * entry point (if different) and pass it as the BL3-3 entry
1932e15a11cSPhilipp Tomsich * point.
1942e15a11cSPhilipp Tomsich * This will need to be extended to support Falcon mode.
1952e15a11cSPhilipp Tomsich */
196b04f87d7SJoseph Chen node = spl_fit_images_find(blob, IH_OS_U_BOOT);
1972e15a11cSPhilipp Tomsich if (node >= 0)
1982e15a11cSPhilipp Tomsich bl33_entry = spl_fit_images_get_entry(blob, node);
1991620aad4SJoseph Chen else
2001620aad4SJoseph Chen bl33_entry = spl_image->entry_point_bl33;
2012e15a11cSPhilipp Tomsich
2022e15a11cSPhilipp Tomsich /*
2034bba5ee7SPhilipp Tomsich * If ATF_NO_PLATFORM_PARAM is set, we override the platform
2044bba5ee7SPhilipp Tomsich * parameter and always pass 0. This is a workaround for
2054bba5ee7SPhilipp Tomsich * older ATF versions that have insufficiently robust (or
2064bba5ee7SPhilipp Tomsich * overzealous) argument validation.
2074bba5ee7SPhilipp Tomsich */
2084bba5ee7SPhilipp Tomsich if (CONFIG_IS_ENABLED(ATF_NO_PLATFORM_PARAM))
2094bba5ee7SPhilipp Tomsich platform_param = 0;
2104bba5ee7SPhilipp Tomsich
211f8ca9d16SJoseph Chen /* do cleanup */
212f8ca9d16SJoseph Chen spl_cleanup_before_jump(spl_image);
213f8ca9d16SJoseph Chen
2144bba5ee7SPhilipp Tomsich /*
2152e15a11cSPhilipp Tomsich * We don't provide a BL3-2 entry yet, but this will be possible
2162e15a11cSPhilipp Tomsich * using similar logic.
2172e15a11cSPhilipp Tomsich */
2183bf65388SJason Zhu bl31_entry(spl_image, spl_image->entry_point, bl32_entry,
219b04f87d7SJoseph Chen bl33_entry, platform_param);
220bcc1726aSKever Yang }
221