xref: /rk3399_rockchip-uboot/common/spl/spl_atf.c (revision 189f3a8c31f44d1cfa98bbccddf34e6b9de15d23)
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