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 */ 342e15a11cSPhilipp Tomsich static struct bl31_params *bl2_plat_get_bl31_params(uintptr_t bl33_entry) 35bcc1726aSKever Yang { 36bcc1726aSKever Yang struct entry_point_info *bl33_ep_info; 37bcc1726aSKever Yang 38bcc1726aSKever Yang /* 39bcc1726aSKever Yang * Initialise the memory for all the arguments that needs to 40bcc1726aSKever Yang * be passed to BL31 41bcc1726aSKever Yang */ 42bcc1726aSKever Yang memset(&bl31_params_mem, 0, sizeof(struct bl2_to_bl31_params_mem)); 43bcc1726aSKever Yang 44bcc1726aSKever Yang /* Assign memory for TF related information */ 45bcc1726aSKever Yang bl2_to_bl31_params = &bl31_params_mem.bl31_params; 46bcc1726aSKever Yang SET_PARAM_HEAD(bl2_to_bl31_params, ATF_PARAM_BL31, ATF_VERSION_1, 0); 47bcc1726aSKever Yang 48bcc1726aSKever Yang /* Fill BL31 related information */ 49bcc1726aSKever Yang SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info, 50bcc1726aSKever Yang ATF_PARAM_IMAGE_BINARY, ATF_VERSION_1, 0); 51bcc1726aSKever Yang 52bcc1726aSKever Yang /* Fill BL32 related information if it exists */ 53bcc1726aSKever Yang bl2_to_bl31_params->bl32_ep_info = &bl31_params_mem.bl32_ep_info; 54bcc1726aSKever Yang SET_PARAM_HEAD(bl2_to_bl31_params->bl32_ep_info, ATF_PARAM_EP, 55bcc1726aSKever Yang ATF_VERSION_1, 0); 56bcc1726aSKever Yang bl2_to_bl31_params->bl32_image_info = &bl31_params_mem.bl32_image_info; 57bcc1726aSKever Yang SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info, 58bcc1726aSKever Yang ATF_PARAM_IMAGE_BINARY, ATF_VERSION_1, 0); 5993a905c1SKever Yang #ifndef BL32_BASE 6093a905c1SKever Yang bl2_to_bl31_params->bl32_ep_info->pc = 0; 61bcc1726aSKever Yang #endif /* BL32_BASE */ 62bcc1726aSKever Yang 63bcc1726aSKever Yang /* Fill BL33 related information */ 64bcc1726aSKever Yang bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem.bl33_ep_info; 65bcc1726aSKever Yang bl33_ep_info = &bl31_params_mem.bl33_ep_info; 66bcc1726aSKever Yang SET_PARAM_HEAD(bl33_ep_info, ATF_PARAM_EP, ATF_VERSION_1, 67bcc1726aSKever Yang ATF_EP_NON_SECURE); 68bcc1726aSKever Yang 69bcc1726aSKever Yang /* BL33 expects to receive the primary CPU MPID (through x0) */ 70bcc1726aSKever Yang bl33_ep_info->args.arg0 = 0xffff & read_mpidr(); 712e15a11cSPhilipp Tomsich bl33_ep_info->pc = bl33_entry; 72bcc1726aSKever Yang bl33_ep_info->spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, 73bcc1726aSKever Yang DISABLE_ALL_EXECPTIONS); 74bcc1726aSKever Yang 75bcc1726aSKever Yang bl2_to_bl31_params->bl33_image_info = &bl31_params_mem.bl33_image_info; 76bcc1726aSKever Yang SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info, 77bcc1726aSKever Yang ATF_PARAM_IMAGE_BINARY, ATF_VERSION_1, 0); 78bcc1726aSKever Yang 79bcc1726aSKever Yang return bl2_to_bl31_params; 80bcc1726aSKever Yang } 81bcc1726aSKever Yang 822e15a11cSPhilipp Tomsich static inline void raw_write_daif(unsigned int daif) 83bcc1726aSKever Yang { 84bcc1726aSKever Yang __asm__ __volatile__("msr DAIF, %0\n\t" : : "r" (daif) : "memory"); 85bcc1726aSKever Yang } 86bcc1726aSKever Yang 872e15a11cSPhilipp Tomsich typedef void (*atf_entry_t)(struct bl31_params *params, void *plat_params); 882e15a11cSPhilipp Tomsich 892e15a11cSPhilipp Tomsich static void bl31_entry(uintptr_t bl31_entry, uintptr_t bl33_entry, 902e15a11cSPhilipp Tomsich uintptr_t fdt_addr) 91bcc1726aSKever Yang { 92bcc1726aSKever Yang struct bl31_params *bl31_params; 932e15a11cSPhilipp Tomsich atf_entry_t atf_entry = (atf_entry_t)bl31_entry; 94bcc1726aSKever Yang 952e15a11cSPhilipp Tomsich bl31_params = bl2_plat_get_bl31_params(bl33_entry); 96bcc1726aSKever Yang 97bcc1726aSKever Yang raw_write_daif(SPSR_EXCEPTION_MASK); 98bcc1726aSKever Yang dcache_disable(); 99bcc1726aSKever Yang 1002e15a11cSPhilipp Tomsich atf_entry((void *)bl31_params, (void *)fdt_addr); 1012e15a11cSPhilipp Tomsich } 1022e15a11cSPhilipp Tomsich 1032e15a11cSPhilipp Tomsich static int spl_fit_images_find_uboot(void *blob) 1042e15a11cSPhilipp Tomsich { 1052e15a11cSPhilipp Tomsich int parent, node, ndepth; 1062e15a11cSPhilipp Tomsich const void *data; 1072e15a11cSPhilipp Tomsich 1082e15a11cSPhilipp Tomsich if (!blob) 1092e15a11cSPhilipp Tomsich return -FDT_ERR_BADMAGIC; 1102e15a11cSPhilipp Tomsich 1112e15a11cSPhilipp Tomsich parent = fdt_path_offset(blob, "/fit-images"); 1122e15a11cSPhilipp Tomsich if (parent < 0) 1132e15a11cSPhilipp Tomsich return -FDT_ERR_NOTFOUND; 1142e15a11cSPhilipp Tomsich 1152e15a11cSPhilipp Tomsich for (node = fdt_next_node(blob, parent, &ndepth); 1162e15a11cSPhilipp Tomsich (node >= 0) && (ndepth > 0); 1172e15a11cSPhilipp Tomsich node = fdt_next_node(blob, node, &ndepth)) { 1182e15a11cSPhilipp Tomsich if (ndepth != 1) 1192e15a11cSPhilipp Tomsich continue; 1202e15a11cSPhilipp Tomsich 1212e15a11cSPhilipp Tomsich data = fdt_getprop(blob, node, FIT_OS_PROP, NULL); 1222e15a11cSPhilipp Tomsich if (!data) 1232e15a11cSPhilipp Tomsich continue; 1242e15a11cSPhilipp Tomsich 1252e15a11cSPhilipp Tomsich if (genimg_get_os_id(data) == IH_OS_U_BOOT) 1262e15a11cSPhilipp Tomsich return node; 1272e15a11cSPhilipp Tomsich }; 1282e15a11cSPhilipp Tomsich 1292e15a11cSPhilipp Tomsich return -FDT_ERR_NOTFOUND; 1302e15a11cSPhilipp Tomsich } 1312e15a11cSPhilipp Tomsich 1322e15a11cSPhilipp Tomsich uintptr_t spl_fit_images_get_entry(void *blob, int node) 1332e15a11cSPhilipp Tomsich { 1342e15a11cSPhilipp Tomsich ulong val; 1352e15a11cSPhilipp Tomsich 1362e15a11cSPhilipp Tomsich val = fdt_getprop_u32(blob, node, "entry-point"); 1372e15a11cSPhilipp Tomsich if (val == FDT_ERROR) 1382e15a11cSPhilipp Tomsich val = fdt_getprop_u32(blob, node, "load-addr"); 1392e15a11cSPhilipp Tomsich 1402e15a11cSPhilipp Tomsich debug("%s: entry point 0x%lx\n", __func__, val); 1412e15a11cSPhilipp Tomsich return val; 1422e15a11cSPhilipp Tomsich } 1432e15a11cSPhilipp Tomsich 1442e15a11cSPhilipp Tomsich void spl_invoke_atf(struct spl_image_info *spl_image) 1452e15a11cSPhilipp Tomsich { 1462e15a11cSPhilipp Tomsich uintptr_t bl33_entry = CONFIG_SYS_TEXT_BASE; 1472e15a11cSPhilipp Tomsich void *blob = spl_image->fdt_addr; 148*4bba5ee7SPhilipp Tomsich uintptr_t platform_param = (uintptr_t)blob; 1492e15a11cSPhilipp Tomsich int node; 1502e15a11cSPhilipp Tomsich 1512e15a11cSPhilipp Tomsich /* 1522e15a11cSPhilipp Tomsich * Find the U-Boot binary (in /fit-images) load addreess or 1532e15a11cSPhilipp Tomsich * entry point (if different) and pass it as the BL3-3 entry 1542e15a11cSPhilipp Tomsich * point. 1552e15a11cSPhilipp Tomsich * This will need to be extended to support Falcon mode. 1562e15a11cSPhilipp Tomsich */ 1572e15a11cSPhilipp Tomsich 1582e15a11cSPhilipp Tomsich node = spl_fit_images_find_uboot(blob); 1592e15a11cSPhilipp Tomsich if (node >= 0) 1602e15a11cSPhilipp Tomsich bl33_entry = spl_fit_images_get_entry(blob, node); 1612e15a11cSPhilipp Tomsich 1622e15a11cSPhilipp Tomsich /* 163*4bba5ee7SPhilipp Tomsich * If ATF_NO_PLATFORM_PARAM is set, we override the platform 164*4bba5ee7SPhilipp Tomsich * parameter and always pass 0. This is a workaround for 165*4bba5ee7SPhilipp Tomsich * older ATF versions that have insufficiently robust (or 166*4bba5ee7SPhilipp Tomsich * overzealous) argument validation. 167*4bba5ee7SPhilipp Tomsich */ 168*4bba5ee7SPhilipp Tomsich if (CONFIG_IS_ENABLED(ATF_NO_PLATFORM_PARAM)) 169*4bba5ee7SPhilipp Tomsich platform_param = 0; 170*4bba5ee7SPhilipp Tomsich 171*4bba5ee7SPhilipp Tomsich /* 1722e15a11cSPhilipp Tomsich * We don't provide a BL3-2 entry yet, but this will be possible 1732e15a11cSPhilipp Tomsich * using similar logic. 1742e15a11cSPhilipp Tomsich */ 175*4bba5ee7SPhilipp Tomsich bl31_entry(spl_image->entry_point, bl33_entry, platform_param); 176bcc1726aSKever Yang } 177