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 9864d1b263SJoseph 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); 107*df5ff5a3SJoseph Chen 108*df5ff5a3SJoseph Chen /* 109*df5ff5a3SJoseph Chen * Turn off I-cache and invalidate it 110*df5ff5a3SJoseph Chen */ 111*df5ff5a3SJoseph Chen icache_disable(); 112*df5ff5a3SJoseph Chen invalidate_icache_all(); 113*df5ff5a3SJoseph Chen 114*df5ff5a3SJoseph Chen /* 115*df5ff5a3SJoseph Chen * turn off D-cache 116*df5ff5a3SJoseph Chen * dcache_disable() in turn flushes the d-cache and disables MMU 117*df5ff5a3SJoseph Chen */ 118bcc1726aSKever Yang dcache_disable(); 119*df5ff5a3SJoseph Chen invalidate_dcache_all(); 120bcc1726aSKever Yang 1212e15a11cSPhilipp Tomsich atf_entry((void *)bl31_params, (void *)fdt_addr); 1222e15a11cSPhilipp Tomsich } 1232e15a11cSPhilipp Tomsich 124b04f87d7SJoseph Chen static int spl_fit_images_find(void *blob, int os) 1252e15a11cSPhilipp Tomsich { 1262e15a11cSPhilipp Tomsich int parent, node, ndepth; 1272e15a11cSPhilipp Tomsich const void *data; 1282e15a11cSPhilipp Tomsich 1292e15a11cSPhilipp Tomsich if (!blob) 1302e15a11cSPhilipp Tomsich return -FDT_ERR_BADMAGIC; 1312e15a11cSPhilipp Tomsich 1322e15a11cSPhilipp Tomsich parent = fdt_path_offset(blob, "/fit-images"); 1332e15a11cSPhilipp Tomsich if (parent < 0) 1342e15a11cSPhilipp Tomsich return -FDT_ERR_NOTFOUND; 1352e15a11cSPhilipp Tomsich 1362e15a11cSPhilipp Tomsich for (node = fdt_next_node(blob, parent, &ndepth); 1372e15a11cSPhilipp Tomsich (node >= 0) && (ndepth > 0); 1382e15a11cSPhilipp Tomsich node = fdt_next_node(blob, node, &ndepth)) { 1392e15a11cSPhilipp Tomsich if (ndepth != 1) 1402e15a11cSPhilipp Tomsich continue; 1412e15a11cSPhilipp Tomsich 1422e15a11cSPhilipp Tomsich data = fdt_getprop(blob, node, FIT_OS_PROP, NULL); 1432e15a11cSPhilipp Tomsich if (!data) 1442e15a11cSPhilipp Tomsich continue; 1452e15a11cSPhilipp Tomsich 146b04f87d7SJoseph Chen if (genimg_get_os_id(data) == os) 1472e15a11cSPhilipp Tomsich return node; 1482e15a11cSPhilipp Tomsich }; 1492e15a11cSPhilipp Tomsich 1502e15a11cSPhilipp Tomsich return -FDT_ERR_NOTFOUND; 1512e15a11cSPhilipp Tomsich } 1522e15a11cSPhilipp Tomsich 1532e15a11cSPhilipp Tomsich uintptr_t spl_fit_images_get_entry(void *blob, int node) 1542e15a11cSPhilipp Tomsich { 1552e15a11cSPhilipp Tomsich ulong val; 1562e15a11cSPhilipp Tomsich 1572e15a11cSPhilipp Tomsich val = fdt_getprop_u32(blob, node, "entry-point"); 1582e15a11cSPhilipp Tomsich if (val == FDT_ERROR) 1592e15a11cSPhilipp Tomsich val = fdt_getprop_u32(blob, node, "load-addr"); 1602e15a11cSPhilipp Tomsich 1612e15a11cSPhilipp Tomsich debug("%s: entry point 0x%lx\n", __func__, val); 1622e15a11cSPhilipp Tomsich return val; 1632e15a11cSPhilipp Tomsich } 1642e15a11cSPhilipp Tomsich 1652e15a11cSPhilipp Tomsich void spl_invoke_atf(struct spl_image_info *spl_image) 1662e15a11cSPhilipp Tomsich { 1671620aad4SJoseph Chen uintptr_t bl32_entry, bl33_entry; 1682e15a11cSPhilipp Tomsich void *blob = spl_image->fdt_addr; 1694bba5ee7SPhilipp Tomsich uintptr_t platform_param = (uintptr_t)blob; 1702e15a11cSPhilipp Tomsich int node; 1712e15a11cSPhilipp Tomsich 1721620aad4SJoseph Chen /* 1731620aad4SJoseph Chen * Find the OP-TEE binary (in /fit-images) load address or 1741620aad4SJoseph Chen * entry point (if different) and pass it as the BL3-2 entry 1751620aad4SJoseph Chen * point, this is optional. 1761620aad4SJoseph Chen * This will need to be extended to support Falcon mode. 1771620aad4SJoseph Chen */ 178b04f87d7SJoseph Chen node = spl_fit_images_find(blob, IH_OS_OP_TEE); 179b04f87d7SJoseph Chen if (node >= 0) 180b04f87d7SJoseph Chen bl32_entry = spl_fit_images_get_entry(blob, node); 1811620aad4SJoseph Chen else 1821620aad4SJoseph Chen bl32_entry = spl_image->entry_point_bl32; /* optional */ 183b04f87d7SJoseph Chen 1842e15a11cSPhilipp Tomsich /* 1852e15a11cSPhilipp Tomsich * Find the U-Boot binary (in /fit-images) load addreess or 1862e15a11cSPhilipp Tomsich * entry point (if different) and pass it as the BL3-3 entry 1872e15a11cSPhilipp Tomsich * point. 1882e15a11cSPhilipp Tomsich * This will need to be extended to support Falcon mode. 1892e15a11cSPhilipp Tomsich */ 190b04f87d7SJoseph Chen node = spl_fit_images_find(blob, IH_OS_U_BOOT); 1912e15a11cSPhilipp Tomsich if (node >= 0) 1922e15a11cSPhilipp Tomsich bl33_entry = spl_fit_images_get_entry(blob, node); 1931620aad4SJoseph Chen else 1941620aad4SJoseph Chen bl33_entry = spl_image->entry_point_bl33; 1952e15a11cSPhilipp Tomsich 1962e15a11cSPhilipp Tomsich /* 1974bba5ee7SPhilipp Tomsich * If ATF_NO_PLATFORM_PARAM is set, we override the platform 1984bba5ee7SPhilipp Tomsich * parameter and always pass 0. This is a workaround for 1994bba5ee7SPhilipp Tomsich * older ATF versions that have insufficiently robust (or 2004bba5ee7SPhilipp Tomsich * overzealous) argument validation. 2014bba5ee7SPhilipp Tomsich */ 2024bba5ee7SPhilipp Tomsich if (CONFIG_IS_ENABLED(ATF_NO_PLATFORM_PARAM)) 2034bba5ee7SPhilipp Tomsich platform_param = 0; 2044bba5ee7SPhilipp Tomsich 2054bba5ee7SPhilipp Tomsich /* 2062e15a11cSPhilipp Tomsich * We don't provide a BL3-2 entry yet, but this will be possible 2072e15a11cSPhilipp Tomsich * using similar logic. 2082e15a11cSPhilipp Tomsich */ 209b04f87d7SJoseph Chen bl31_entry(spl_image->entry_point, bl32_entry, 210b04f87d7SJoseph Chen bl33_entry, platform_param); 211bcc1726aSKever Yang } 212