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 */ 34b04f87d7SJoseph Chen static struct bl31_params *bl2_plat_get_bl31_params(uintptr_t bl32_entry, 35b04f87d7SJoseph Chen uintptr_t bl33_entry) 36bcc1726aSKever Yang { 37b04f87d7SJoseph Chen struct entry_point_info *bl32_ep_info; 38bcc1726aSKever Yang struct entry_point_info *bl33_ep_info; 39bcc1726aSKever Yang 40bcc1726aSKever Yang /* 41bcc1726aSKever Yang * Initialise the memory for all the arguments that needs to 42bcc1726aSKever Yang * be passed to BL31 43bcc1726aSKever Yang */ 44bcc1726aSKever Yang memset(&bl31_params_mem, 0, sizeof(struct bl2_to_bl31_params_mem)); 45bcc1726aSKever Yang 46bcc1726aSKever Yang /* Assign memory for TF related information */ 47bcc1726aSKever Yang bl2_to_bl31_params = &bl31_params_mem.bl31_params; 48bcc1726aSKever Yang SET_PARAM_HEAD(bl2_to_bl31_params, ATF_PARAM_BL31, ATF_VERSION_1, 0); 49bcc1726aSKever Yang 50bcc1726aSKever Yang /* Fill BL31 related information */ 51bcc1726aSKever Yang SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info, 52bcc1726aSKever Yang ATF_PARAM_IMAGE_BINARY, ATF_VERSION_1, 0); 53bcc1726aSKever Yang 54b04f87d7SJoseph Chen if (bl32_entry == -1) 55b04f87d7SJoseph Chen goto bl33_setup; 56b04f87d7SJoseph Chen 57b04f87d7SJoseph Chen /* Fill BL32 related information */ 58bcc1726aSKever Yang bl2_to_bl31_params->bl32_ep_info = &bl31_params_mem.bl32_ep_info; 59b04f87d7SJoseph Chen bl32_ep_info = &bl31_params_mem.bl32_ep_info; 60b04f87d7SJoseph Chen SET_PARAM_HEAD(bl32_ep_info, ATF_PARAM_EP, ATF_VERSION_1, 61b04f87d7SJoseph Chen ATF_EP_SECURE); 62b04f87d7SJoseph Chen 63b04f87d7SJoseph Chen bl32_ep_info->pc = bl32_entry; 64b04f87d7SJoseph Chen bl32_ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, 65b04f87d7SJoseph Chen DISABLE_ALL_EXECPTIONS); 66b04f87d7SJoseph Chen 67bcc1726aSKever Yang bl2_to_bl31_params->bl32_image_info = &bl31_params_mem.bl32_image_info; 68bcc1726aSKever Yang SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info, 69bcc1726aSKever Yang ATF_PARAM_IMAGE_BINARY, ATF_VERSION_1, 0); 70bcc1726aSKever Yang 71b04f87d7SJoseph Chen bl33_setup: 72bcc1726aSKever Yang /* Fill BL33 related information */ 73bcc1726aSKever Yang bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem.bl33_ep_info; 74bcc1726aSKever Yang bl33_ep_info = &bl31_params_mem.bl33_ep_info; 75bcc1726aSKever Yang SET_PARAM_HEAD(bl33_ep_info, ATF_PARAM_EP, ATF_VERSION_1, 76bcc1726aSKever Yang ATF_EP_NON_SECURE); 77bcc1726aSKever Yang 78bcc1726aSKever Yang /* BL33 expects to receive the primary CPU MPID (through x0) */ 79bcc1726aSKever Yang bl33_ep_info->args.arg0 = 0xffff & read_mpidr(); 802e15a11cSPhilipp Tomsich bl33_ep_info->pc = bl33_entry; 81bcc1726aSKever Yang bl33_ep_info->spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, 82bcc1726aSKever Yang DISABLE_ALL_EXECPTIONS); 83*189f3a8cSJason Zhu #if defined(CONFIG_SPL_KERNEL_BOOT) && defined(CONFIG_ARM64) 84*189f3a8cSJason Zhu /* 85*189f3a8cSJason Zhu * Reference: arch/arm/lib/bootm.c 86*189f3a8cSJason Zhu * boot_jump_linux(bootm_headers_t *images, int flag) 87*189f3a8cSJason Zhu * { 88*189f3a8cSJason Zhu * ...... 89*189f3a8cSJason Zhu * armv8_switch_to_el2((u64)images->ft_addr, 0, 0, 0, 90*189f3a8cSJason Zhu * images->ep, ES_TO_AARCH64); 91*189f3a8cSJason Zhu * } 92*189f3a8cSJason Zhu */ 93*189f3a8cSJason Zhu bl33_ep_info->args.arg0 = CONFIG_SPL_FDT_ADDR; 94*189f3a8cSJason Zhu #endif 95bcc1726aSKever Yang bl2_to_bl31_params->bl33_image_info = &bl31_params_mem.bl33_image_info; 96bcc1726aSKever Yang SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info, 97bcc1726aSKever Yang ATF_PARAM_IMAGE_BINARY, ATF_VERSION_1, 0); 98bcc1726aSKever Yang 99bcc1726aSKever Yang return bl2_to_bl31_params; 100bcc1726aSKever Yang } 101bcc1726aSKever Yang 1022e15a11cSPhilipp Tomsich static inline void raw_write_daif(unsigned int daif) 103bcc1726aSKever Yang { 104bcc1726aSKever Yang __asm__ __volatile__("msr DAIF, %0\n\t" : : "r" (daif) : "memory"); 105bcc1726aSKever Yang } 106bcc1726aSKever Yang 1072e15a11cSPhilipp Tomsich typedef void (*atf_entry_t)(struct bl31_params *params, void *plat_params); 1082e15a11cSPhilipp Tomsich 10964d1b263SJoseph Chen void bl31_entry(uintptr_t bl31_entry, uintptr_t bl32_entry, 110b04f87d7SJoseph Chen uintptr_t bl33_entry, uintptr_t fdt_addr) 111bcc1726aSKever Yang { 112bcc1726aSKever Yang struct bl31_params *bl31_params; 1132e15a11cSPhilipp Tomsich atf_entry_t atf_entry = (atf_entry_t)bl31_entry; 114bcc1726aSKever Yang 115b04f87d7SJoseph Chen bl31_params = bl2_plat_get_bl31_params(bl32_entry, bl33_entry); 116bcc1726aSKever Yang 117bcc1726aSKever Yang raw_write_daif(SPSR_EXCEPTION_MASK); 118df5ff5a3SJoseph Chen 119df5ff5a3SJoseph Chen /* 120df5ff5a3SJoseph Chen * Turn off I-cache and invalidate it 121df5ff5a3SJoseph Chen */ 122df5ff5a3SJoseph Chen icache_disable(); 123df5ff5a3SJoseph Chen invalidate_icache_all(); 124df5ff5a3SJoseph Chen 125df5ff5a3SJoseph Chen /* 126df5ff5a3SJoseph Chen * turn off D-cache 127df5ff5a3SJoseph Chen * dcache_disable() in turn flushes the d-cache and disables MMU 128df5ff5a3SJoseph Chen */ 129bcc1726aSKever Yang dcache_disable(); 130df5ff5a3SJoseph Chen invalidate_dcache_all(); 131bcc1726aSKever Yang 1322e15a11cSPhilipp Tomsich atf_entry((void *)bl31_params, (void *)fdt_addr); 1332e15a11cSPhilipp Tomsich } 1342e15a11cSPhilipp Tomsich 135b04f87d7SJoseph Chen static int spl_fit_images_find(void *blob, int os) 1362e15a11cSPhilipp Tomsich { 1372e15a11cSPhilipp Tomsich int parent, node, ndepth; 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 1472e15a11cSPhilipp Tomsich for (node = fdt_next_node(blob, parent, &ndepth); 1482e15a11cSPhilipp Tomsich (node >= 0) && (ndepth > 0); 1492e15a11cSPhilipp Tomsich node = fdt_next_node(blob, node, &ndepth)) { 1502e15a11cSPhilipp Tomsich if (ndepth != 1) 1512e15a11cSPhilipp Tomsich continue; 1522e15a11cSPhilipp Tomsich 1532e15a11cSPhilipp Tomsich data = fdt_getprop(blob, node, FIT_OS_PROP, NULL); 1542e15a11cSPhilipp Tomsich if (!data) 1552e15a11cSPhilipp Tomsich continue; 1562e15a11cSPhilipp Tomsich 157b04f87d7SJoseph Chen if (genimg_get_os_id(data) == os) 1582e15a11cSPhilipp Tomsich return node; 1592e15a11cSPhilipp Tomsich }; 1602e15a11cSPhilipp Tomsich 1612e15a11cSPhilipp Tomsich return -FDT_ERR_NOTFOUND; 1622e15a11cSPhilipp Tomsich } 1632e15a11cSPhilipp Tomsich 1642e15a11cSPhilipp Tomsich uintptr_t spl_fit_images_get_entry(void *blob, int node) 1652e15a11cSPhilipp Tomsich { 1662e15a11cSPhilipp Tomsich ulong val; 1672e15a11cSPhilipp Tomsich 1682e15a11cSPhilipp Tomsich val = fdt_getprop_u32(blob, node, "entry-point"); 1692e15a11cSPhilipp Tomsich if (val == FDT_ERROR) 1702e15a11cSPhilipp Tomsich val = fdt_getprop_u32(blob, node, "load-addr"); 1712e15a11cSPhilipp Tomsich 1722e15a11cSPhilipp Tomsich debug("%s: entry point 0x%lx\n", __func__, val); 1732e15a11cSPhilipp Tomsich return val; 1742e15a11cSPhilipp Tomsich } 1752e15a11cSPhilipp Tomsich 1762e15a11cSPhilipp Tomsich void spl_invoke_atf(struct spl_image_info *spl_image) 1772e15a11cSPhilipp Tomsich { 1781620aad4SJoseph Chen uintptr_t bl32_entry, bl33_entry; 1792e15a11cSPhilipp Tomsich void *blob = spl_image->fdt_addr; 1804bba5ee7SPhilipp Tomsich uintptr_t platform_param = (uintptr_t)blob; 1812e15a11cSPhilipp Tomsich int node; 1822e15a11cSPhilipp Tomsich 1831620aad4SJoseph Chen /* 1841620aad4SJoseph Chen * Find the OP-TEE binary (in /fit-images) load address or 1851620aad4SJoseph Chen * entry point (if different) and pass it as the BL3-2 entry 1861620aad4SJoseph Chen * point, this is optional. 1871620aad4SJoseph Chen * This will need to be extended to support Falcon mode. 1881620aad4SJoseph Chen */ 189b04f87d7SJoseph Chen node = spl_fit_images_find(blob, IH_OS_OP_TEE); 190b04f87d7SJoseph Chen if (node >= 0) 191b04f87d7SJoseph Chen bl32_entry = spl_fit_images_get_entry(blob, node); 1921620aad4SJoseph Chen else 1931620aad4SJoseph Chen bl32_entry = spl_image->entry_point_bl32; /* optional */ 194b04f87d7SJoseph Chen 1952e15a11cSPhilipp Tomsich /* 1962e15a11cSPhilipp Tomsich * Find the U-Boot binary (in /fit-images) load addreess or 1972e15a11cSPhilipp Tomsich * entry point (if different) and pass it as the BL3-3 entry 1982e15a11cSPhilipp Tomsich * point. 1992e15a11cSPhilipp Tomsich * This will need to be extended to support Falcon mode. 2002e15a11cSPhilipp Tomsich */ 201b04f87d7SJoseph Chen node = spl_fit_images_find(blob, IH_OS_U_BOOT); 2022e15a11cSPhilipp Tomsich if (node >= 0) 2032e15a11cSPhilipp Tomsich bl33_entry = spl_fit_images_get_entry(blob, node); 2041620aad4SJoseph Chen else 2051620aad4SJoseph Chen bl33_entry = spl_image->entry_point_bl33; 2062e15a11cSPhilipp Tomsich 2072e15a11cSPhilipp Tomsich /* 2084bba5ee7SPhilipp Tomsich * If ATF_NO_PLATFORM_PARAM is set, we override the platform 2094bba5ee7SPhilipp Tomsich * parameter and always pass 0. This is a workaround for 2104bba5ee7SPhilipp Tomsich * older ATF versions that have insufficiently robust (or 2114bba5ee7SPhilipp Tomsich * overzealous) argument validation. 2124bba5ee7SPhilipp Tomsich */ 2134bba5ee7SPhilipp Tomsich if (CONFIG_IS_ENABLED(ATF_NO_PLATFORM_PARAM)) 2144bba5ee7SPhilipp Tomsich platform_param = 0; 2154bba5ee7SPhilipp Tomsich 2164bba5ee7SPhilipp Tomsich /* 2172e15a11cSPhilipp Tomsich * We don't provide a BL3-2 entry yet, but this will be possible 2182e15a11cSPhilipp Tomsich * using similar logic. 2192e15a11cSPhilipp Tomsich */ 220b04f87d7SJoseph Chen bl31_entry(spl_image->entry_point, bl32_entry, 221b04f87d7SJoseph Chen bl33_entry, platform_param); 222bcc1726aSKever Yang } 223