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); 83bcc1726aSKever Yang 84bcc1726aSKever Yang bl2_to_bl31_params->bl33_image_info = &bl31_params_mem.bl33_image_info; 85bcc1726aSKever Yang SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info, 86bcc1726aSKever Yang ATF_PARAM_IMAGE_BINARY, ATF_VERSION_1, 0); 87bcc1726aSKever Yang 88bcc1726aSKever Yang return bl2_to_bl31_params; 89bcc1726aSKever Yang } 90bcc1726aSKever Yang 912e15a11cSPhilipp Tomsich static inline void raw_write_daif(unsigned int daif) 92bcc1726aSKever Yang { 93bcc1726aSKever Yang __asm__ __volatile__("msr DAIF, %0\n\t" : : "r" (daif) : "memory"); 94bcc1726aSKever Yang } 95bcc1726aSKever Yang 962e15a11cSPhilipp Tomsich typedef void (*atf_entry_t)(struct bl31_params *params, void *plat_params); 972e15a11cSPhilipp Tomsich 98*64d1b263SJoseph Chen void bl31_entry(uintptr_t bl31_entry, uintptr_t bl32_entry, 99b04f87d7SJoseph Chen uintptr_t bl33_entry, uintptr_t fdt_addr) 100bcc1726aSKever Yang { 101bcc1726aSKever Yang struct bl31_params *bl31_params; 1022e15a11cSPhilipp Tomsich atf_entry_t atf_entry = (atf_entry_t)bl31_entry; 103bcc1726aSKever Yang 104b04f87d7SJoseph Chen bl31_params = bl2_plat_get_bl31_params(bl32_entry, bl33_entry); 105bcc1726aSKever Yang 106bcc1726aSKever Yang raw_write_daif(SPSR_EXCEPTION_MASK); 107bcc1726aSKever Yang dcache_disable(); 108bcc1726aSKever Yang 1092e15a11cSPhilipp Tomsich atf_entry((void *)bl31_params, (void *)fdt_addr); 1102e15a11cSPhilipp Tomsich } 1112e15a11cSPhilipp Tomsich 112b04f87d7SJoseph Chen static int spl_fit_images_find(void *blob, int os) 1132e15a11cSPhilipp Tomsich { 1142e15a11cSPhilipp Tomsich int parent, node, ndepth; 1152e15a11cSPhilipp Tomsich const void *data; 1162e15a11cSPhilipp Tomsich 1172e15a11cSPhilipp Tomsich if (!blob) 1182e15a11cSPhilipp Tomsich return -FDT_ERR_BADMAGIC; 1192e15a11cSPhilipp Tomsich 1202e15a11cSPhilipp Tomsich parent = fdt_path_offset(blob, "/fit-images"); 1212e15a11cSPhilipp Tomsich if (parent < 0) 1222e15a11cSPhilipp Tomsich return -FDT_ERR_NOTFOUND; 1232e15a11cSPhilipp Tomsich 1242e15a11cSPhilipp Tomsich for (node = fdt_next_node(blob, parent, &ndepth); 1252e15a11cSPhilipp Tomsich (node >= 0) && (ndepth > 0); 1262e15a11cSPhilipp Tomsich node = fdt_next_node(blob, node, &ndepth)) { 1272e15a11cSPhilipp Tomsich if (ndepth != 1) 1282e15a11cSPhilipp Tomsich continue; 1292e15a11cSPhilipp Tomsich 1302e15a11cSPhilipp Tomsich data = fdt_getprop(blob, node, FIT_OS_PROP, NULL); 1312e15a11cSPhilipp Tomsich if (!data) 1322e15a11cSPhilipp Tomsich continue; 1332e15a11cSPhilipp Tomsich 134b04f87d7SJoseph Chen if (genimg_get_os_id(data) == os) 1352e15a11cSPhilipp Tomsich return node; 1362e15a11cSPhilipp Tomsich }; 1372e15a11cSPhilipp Tomsich 1382e15a11cSPhilipp Tomsich return -FDT_ERR_NOTFOUND; 1392e15a11cSPhilipp Tomsich } 1402e15a11cSPhilipp Tomsich 1412e15a11cSPhilipp Tomsich uintptr_t spl_fit_images_get_entry(void *blob, int node) 1422e15a11cSPhilipp Tomsich { 1432e15a11cSPhilipp Tomsich ulong val; 1442e15a11cSPhilipp Tomsich 1452e15a11cSPhilipp Tomsich val = fdt_getprop_u32(blob, node, "entry-point"); 1462e15a11cSPhilipp Tomsich if (val == FDT_ERROR) 1472e15a11cSPhilipp Tomsich val = fdt_getprop_u32(blob, node, "load-addr"); 1482e15a11cSPhilipp Tomsich 1492e15a11cSPhilipp Tomsich debug("%s: entry point 0x%lx\n", __func__, val); 1502e15a11cSPhilipp Tomsich return val; 1512e15a11cSPhilipp Tomsich } 1522e15a11cSPhilipp Tomsich 1532e15a11cSPhilipp Tomsich void spl_invoke_atf(struct spl_image_info *spl_image) 1542e15a11cSPhilipp Tomsich { 155b04f87d7SJoseph Chen uintptr_t bl32_entry = -1; 1562e15a11cSPhilipp Tomsich uintptr_t bl33_entry = CONFIG_SYS_TEXT_BASE; 1572e15a11cSPhilipp Tomsich void *blob = spl_image->fdt_addr; 1584bba5ee7SPhilipp Tomsich uintptr_t platform_param = (uintptr_t)blob; 1592e15a11cSPhilipp Tomsich int node; 1602e15a11cSPhilipp Tomsich 161b04f87d7SJoseph Chen node = spl_fit_images_find(blob, IH_OS_OP_TEE); 162b04f87d7SJoseph Chen if (node >= 0) 163b04f87d7SJoseph Chen bl32_entry = spl_fit_images_get_entry(blob, node); 164b04f87d7SJoseph Chen 1652e15a11cSPhilipp Tomsich /* 1662e15a11cSPhilipp Tomsich * Find the U-Boot binary (in /fit-images) load addreess or 1672e15a11cSPhilipp Tomsich * entry point (if different) and pass it as the BL3-3 entry 1682e15a11cSPhilipp Tomsich * point. 1692e15a11cSPhilipp Tomsich * This will need to be extended to support Falcon mode. 1702e15a11cSPhilipp Tomsich */ 1712e15a11cSPhilipp Tomsich 172b04f87d7SJoseph Chen node = spl_fit_images_find(blob, IH_OS_U_BOOT); 1732e15a11cSPhilipp Tomsich if (node >= 0) 1742e15a11cSPhilipp Tomsich bl33_entry = spl_fit_images_get_entry(blob, node); 1752e15a11cSPhilipp Tomsich 1762e15a11cSPhilipp Tomsich /* 1774bba5ee7SPhilipp Tomsich * If ATF_NO_PLATFORM_PARAM is set, we override the platform 1784bba5ee7SPhilipp Tomsich * parameter and always pass 0. This is a workaround for 1794bba5ee7SPhilipp Tomsich * older ATF versions that have insufficiently robust (or 1804bba5ee7SPhilipp Tomsich * overzealous) argument validation. 1814bba5ee7SPhilipp Tomsich */ 1824bba5ee7SPhilipp Tomsich if (CONFIG_IS_ENABLED(ATF_NO_PLATFORM_PARAM)) 1834bba5ee7SPhilipp Tomsich platform_param = 0; 1844bba5ee7SPhilipp Tomsich 1854bba5ee7SPhilipp Tomsich /* 1862e15a11cSPhilipp Tomsich * We don't provide a BL3-2 entry yet, but this will be possible 1872e15a11cSPhilipp Tomsich * using similar logic. 1882e15a11cSPhilipp Tomsich */ 189b04f87d7SJoseph Chen bl31_entry(spl_image->entry_point, bl32_entry, 190b04f87d7SJoseph Chen bl33_entry, platform_param); 191bcc1726aSKever Yang } 192