xref: /rk3399_ARM-atf/plat/arm/board/arm_fpga/fpga_bl31_setup.c (revision 5906d97a832b6f6c4ee58557a4ff197ddb358135)
1536d906aSOliver Swede /*
2536d906aSOliver Swede  * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
3536d906aSOliver Swede  *
4536d906aSOliver Swede  * SPDX-License-Identifier: BSD-3-Clause
5536d906aSOliver Swede  */
6536d906aSOliver Swede 
75cfe699fSOliver Swede #include <assert.h>
820ff991eSJavier Almansa Sobrino #include <errno.h>
9670c66afSAndre Przywara 
10*b7253a14SAndre Przywara #include <arch_features.h>
1120ff991eSJavier Almansa Sobrino #include <common/fdt_fixup.h>
12670c66afSAndre Przywara #include <common/fdt_wrappers.h>
13283e5595SAndre Przywara #include <drivers/arm/gicv3.h>
14727bbf68SJavier Almansa Sobrino #include <drivers/delay_timer.h>
152d696d18SOliver Swede #include <drivers/generic_delay_timer.h>
1640a0de19SAndre Przywara #include <lib/extensions/spe.h>
17d850169cSAndre Przywara #include <lib/mmio.h>
18670c66afSAndre Przywara #include <libfdt.h>
195cfe699fSOliver Swede 
20727bbf68SJavier Almansa Sobrino #include "fpga_private.h"
21536d906aSOliver Swede #include <plat/common/platform.h>
22536d906aSOliver Swede #include <platform_def.h>
23536d906aSOliver Swede 
245cfe699fSOliver Swede static entry_point_info_t bl33_image_ep_info;
25422b44fbSAndre Przywara static unsigned int system_freq;
26727bbf68SJavier Almansa Sobrino volatile uint32_t secondary_core_spinlock;
275cfe699fSOliver Swede 
plat_get_ns_image_entrypoint(void)285cfe699fSOliver Swede uintptr_t plat_get_ns_image_entrypoint(void)
295cfe699fSOliver Swede {
305cfe699fSOliver Swede #ifdef PRELOADED_BL33_BASE
315cfe699fSOliver Swede 	return PRELOADED_BL33_BASE;
325cfe699fSOliver Swede #else
33727bbf68SJavier Almansa Sobrino 	return 0ULL;
345cfe699fSOliver Swede #endif
355cfe699fSOliver Swede }
365cfe699fSOliver Swede 
fpga_get_spsr_for_bl33_entry(void)375cfe699fSOliver Swede uint32_t fpga_get_spsr_for_bl33_entry(void)
385cfe699fSOliver Swede {
395cfe699fSOliver Swede 	return SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
405cfe699fSOliver Swede }
415cfe699fSOliver Swede 
bl31_early_platform_setup2(u_register_t arg0,u_register_t arg1,u_register_t arg2,u_register_t arg3)42536d906aSOliver Swede void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
43536d906aSOliver Swede 				u_register_t arg2, u_register_t arg3)
44536d906aSOliver Swede {
45727bbf68SJavier Almansa Sobrino 	/* Add this core to the VALID mpids list */
46727bbf68SJavier Almansa Sobrino 	fpga_valid_mpids[plat_my_core_pos()] = VALID_MPID;
47727bbf68SJavier Almansa Sobrino 
48727bbf68SJavier Almansa Sobrino 	/*
49727bbf68SJavier Almansa Sobrino 	 * Notify the secondary CPUs that the C runtime is ready
50727bbf68SJavier Almansa Sobrino 	 * so they can announce themselves.
51727bbf68SJavier Almansa Sobrino 	 */
52727bbf68SJavier Almansa Sobrino 	secondary_core_spinlock = C_RUNTIME_READY_KEY;
53727bbf68SJavier Almansa Sobrino 	dsbish();
54727bbf68SJavier Almansa Sobrino 	sev();
55727bbf68SJavier Almansa Sobrino 
56536d906aSOliver Swede 	fpga_console_init();
575cfe699fSOliver Swede 
585cfe699fSOliver Swede 	bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
595cfe699fSOliver Swede 	bl33_image_ep_info.spsr = fpga_get_spsr_for_bl33_entry();
605cfe699fSOliver Swede 	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
615cfe699fSOliver Swede 
625cfe699fSOliver Swede 	/* Set x0-x3 for the primary CPU as expected by the kernel */
635cfe699fSOliver Swede 	bl33_image_ep_info.args.arg0 = (u_register_t)FPGA_PRELOADED_DTB_BASE;
645cfe699fSOliver Swede 	bl33_image_ep_info.args.arg1 = 0U;
655cfe699fSOliver Swede 	bl33_image_ep_info.args.arg2 = 0U;
665cfe699fSOliver Swede 	bl33_image_ep_info.args.arg3 = 0U;
67536d906aSOliver Swede }
68536d906aSOliver Swede 
bl31_plat_arch_setup(void)69536d906aSOliver Swede void bl31_plat_arch_setup(void)
70536d906aSOliver Swede {
71536d906aSOliver Swede }
72536d906aSOliver Swede 
bl31_platform_setup(void)73536d906aSOliver Swede void bl31_platform_setup(void)
74536d906aSOliver Swede {
752d696d18SOliver Swede 	/* Write frequency to CNTCRL and initialize timer */
762d696d18SOliver Swede 	generic_delay_timer_init();
77727bbf68SJavier Almansa Sobrino 
78727bbf68SJavier Almansa Sobrino 	/*
79727bbf68SJavier Almansa Sobrino 	 * Before doing anything else, wait for some time to ensure that
80727bbf68SJavier Almansa Sobrino 	 * the secondary CPUs have populated the fpga_valid_mpids array.
81727bbf68SJavier Almansa Sobrino 	 * As the number of secondary cores is unknown and can even be 0,
82727bbf68SJavier Almansa Sobrino 	 * it is not possible to rely on any signal from them, so use a
83727bbf68SJavier Almansa Sobrino 	 * delay instead.
84727bbf68SJavier Almansa Sobrino 	 */
85727bbf68SJavier Almansa Sobrino 	mdelay(5);
86727bbf68SJavier Almansa Sobrino 
87727bbf68SJavier Almansa Sobrino 	/*
88727bbf68SJavier Almansa Sobrino 	 * On the event of a cold reset issued by, for instance, a reset pin
89727bbf68SJavier Almansa Sobrino 	 * assertion, we cannot guarantee memory to be initialized to zero.
90727bbf68SJavier Almansa Sobrino 	 * In such scenario, if the secondary cores reached
91727bbf68SJavier Almansa Sobrino 	 * plat_secondary_cold_boot_setup before the primary one initialized
92727bbf68SJavier Almansa Sobrino 	 * .BSS, we could end up having a race condition if the spinlock
93727bbf68SJavier Almansa Sobrino 	 * was not cleared before.
94727bbf68SJavier Almansa Sobrino 	 *
95727bbf68SJavier Almansa Sobrino 	 * Similarly, if there were a reset before the spinlock had been
96727bbf68SJavier Almansa Sobrino 	 * cleared, the secondary cores would find the lock opened before
97727bbf68SJavier Almansa Sobrino 	 * .BSS is cleared, causing another race condition.
98727bbf68SJavier Almansa Sobrino 	 *
99727bbf68SJavier Almansa Sobrino 	 * So clean the spinlock as soon as we think it is safe to reduce the
100727bbf68SJavier Almansa Sobrino 	 * chances of any race condition on a reset.
101727bbf68SJavier Almansa Sobrino 	 */
102727bbf68SJavier Almansa Sobrino 	secondary_core_spinlock = 0UL;
103727bbf68SJavier Almansa Sobrino 
104727bbf68SJavier Almansa Sobrino 	/* Initialize the GIC driver, cpu and distributor interfaces */
105727bbf68SJavier Almansa Sobrino 	plat_fpga_gic_init();
106536d906aSOliver Swede }
107536d906aSOliver Swede 
bl31_plat_get_next_image_ep_info(uint32_t type)108536d906aSOliver Swede entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
109536d906aSOliver Swede {
1105cfe699fSOliver Swede 	entry_point_info_t *next_image_info;
1115cfe699fSOliver Swede 	next_image_info = &bl33_image_ep_info;
1125cfe699fSOliver Swede 
1135cfe699fSOliver Swede 	/* Only expecting BL33: the kernel will run in EL2NS */
1145cfe699fSOliver Swede 	assert(type == NON_SECURE);
1155cfe699fSOliver Swede 
1165cfe699fSOliver Swede 	/* None of the images can have 0x0 as the entrypoint */
1175cfe699fSOliver Swede 	if (next_image_info->pc) {
1185cfe699fSOliver Swede 		return next_image_info;
1195cfe699fSOliver Swede 	} else {
120536d906aSOliver Swede 		return NULL;
121536d906aSOliver Swede 	}
1225cfe699fSOliver Swede }
123536d906aSOliver Swede 
124d850169cSAndre Przywara /*
125d850169cSAndre Przywara  * Even though we sell the FPGA UART as an SBSA variant, it is actually
126d850169cSAndre Przywara  * a full fledged PL011. So the baudrate divider registers exist.
127d850169cSAndre Przywara  */
128d850169cSAndre Przywara #ifndef UARTIBRD
129d850169cSAndre Przywara #define UARTIBRD	0x024
130d850169cSAndre Przywara #define UARTFBRD	0x028
131d850169cSAndre Przywara #endif
132d850169cSAndre Przywara 
133d850169cSAndre Przywara /* Round an integer to the closest multiple of a value. */
round_multiple(unsigned int x,unsigned int multiple)134d850169cSAndre Przywara static unsigned int round_multiple(unsigned int x, unsigned int multiple)
135d850169cSAndre Przywara {
136d850169cSAndre Przywara 	if (multiple < 2) {
137d850169cSAndre Przywara 		return x;
138d850169cSAndre Przywara 	}
139d850169cSAndre Przywara 
140d850169cSAndre Przywara 	return ((x + (multiple / 2 - 1)) / multiple) * multiple;
141d850169cSAndre Przywara }
142d850169cSAndre Przywara 
143d850169cSAndre Przywara #define PL011_FRAC_SHIFT	6
144d850169cSAndre Przywara #define FPGA_DEFAULT_BAUDRATE	38400
145d850169cSAndre Przywara #define PL011_OVERSAMPLING	16
pl011_freq_from_divider(unsigned int divider)146d850169cSAndre Przywara static unsigned int pl011_freq_from_divider(unsigned int divider)
147d850169cSAndre Przywara {
148d850169cSAndre Przywara 	unsigned int freq;
149d850169cSAndre Przywara 
150d850169cSAndre Przywara 	freq = divider * FPGA_DEFAULT_BAUDRATE * PL011_OVERSAMPLING;
151d850169cSAndre Przywara 
152d850169cSAndre Przywara 	return freq >> PL011_FRAC_SHIFT;
153d850169cSAndre Przywara }
154d850169cSAndre Przywara 
155d850169cSAndre Przywara /*
156d850169cSAndre Przywara  * The FPGAs run most peripherals from one main clock, among them the CPUs,
157d850169cSAndre Przywara  * the arch timer, and the UART baud base clock.
158d850169cSAndre Przywara  * The SCP knows this frequency and programs the UART clock divider for a
159d850169cSAndre Przywara  * 38400 bps baudrate. Recalculate the base input clock from there.
160d850169cSAndre Przywara  */
fpga_get_system_frequency(void)161d850169cSAndre Przywara static unsigned int fpga_get_system_frequency(void)
162536d906aSOliver Swede {
163670c66afSAndre Przywara 	const void *fdt = (void *)(uintptr_t)FPGA_PRELOADED_DTB_BASE;
164d850169cSAndre Przywara 	int node, err;
165670c66afSAndre Przywara 
166d850169cSAndre Przywara 	/*
167d850169cSAndre Przywara 	 * If the arch timer DT node has an explicit clock-frequency property
168d850169cSAndre Przywara 	 * set, use that, to allow people overriding auto-detection.
169d850169cSAndre Przywara 	 */
170670c66afSAndre Przywara 	node = fdt_node_offset_by_compatible(fdt, 0, "arm,armv8-timer");
171d850169cSAndre Przywara 	if (node >= 0) {
172d850169cSAndre Przywara 		uint32_t freq;
173d850169cSAndre Przywara 
174d850169cSAndre Przywara 		err = fdt_read_uint32(fdt, node, "clock-frequency", &freq);
175d850169cSAndre Przywara 		if (err >= 0) {
176d850169cSAndre Przywara 			return freq;
177d850169cSAndre Przywara 		}
178d850169cSAndre Przywara 	}
179d850169cSAndre Przywara 
180d850169cSAndre Przywara 	node = fdt_node_offset_by_compatible(fdt, 0, "arm,pl011");
181d850169cSAndre Przywara 	if (node >= 0) {
182d850169cSAndre Przywara 		uintptr_t pl011_base;
183d850169cSAndre Przywara 		unsigned int divider;
184d850169cSAndre Przywara 
185d850169cSAndre Przywara 		err = fdt_get_reg_props_by_index(fdt, node, 0,
186d850169cSAndre Przywara 						 &pl011_base, NULL);
187d850169cSAndre Przywara 		if (err >= 0) {
188d850169cSAndre Przywara 			divider = mmio_read_32(pl011_base + UARTIBRD);
189d850169cSAndre Przywara 			divider <<= PL011_FRAC_SHIFT;
190d850169cSAndre Przywara 			divider += mmio_read_32(pl011_base + UARTFBRD);
191d850169cSAndre Przywara 
192d850169cSAndre Przywara 			/*
193d850169cSAndre Przywara 			 * The result won't be exact, due to rounding errors,
194d850169cSAndre Przywara 			 * but the input frequency was a multiple of 250 KHz.
195d850169cSAndre Przywara 			 */
196d850169cSAndre Przywara 			return round_multiple(pl011_freq_from_divider(divider),
197d850169cSAndre Przywara 					      250000);
198d850169cSAndre Przywara 		} else {
199d850169cSAndre Przywara 			WARN("Cannot read PL011 MMIO base\n");
200d850169cSAndre Przywara 		}
201d850169cSAndre Przywara 	} else {
202d850169cSAndre Przywara 		WARN("No PL011 DT node\n");
203d850169cSAndre Przywara 	}
204d850169cSAndre Przywara 
205d850169cSAndre Przywara 	/* No PL011 DT node or calculation failed. */
206670c66afSAndre Przywara 	return FPGA_DEFAULT_TIMER_FREQUENCY;
207670c66afSAndre Przywara }
208670c66afSAndre Przywara 
plat_get_syscnt_freq2(void)209d850169cSAndre Przywara unsigned int plat_get_syscnt_freq2(void)
210d850169cSAndre Przywara {
211422b44fbSAndre Przywara 	if (system_freq == 0U) {
212422b44fbSAndre Przywara 		system_freq = fpga_get_system_frequency();
213422b44fbSAndre Przywara 	}
214422b44fbSAndre Przywara 
215422b44fbSAndre Przywara 	return system_freq;
216422b44fbSAndre Przywara }
217422b44fbSAndre Przywara 
fpga_dtb_update_clock(void * fdt,unsigned int freq)218422b44fbSAndre Przywara static void fpga_dtb_update_clock(void *fdt, unsigned int freq)
219422b44fbSAndre Przywara {
220422b44fbSAndre Przywara 	uint32_t freq_dtb = fdt32_to_cpu(freq);
221422b44fbSAndre Przywara 	uint32_t phandle;
222422b44fbSAndre Przywara 	int node, err;
223422b44fbSAndre Przywara 
224422b44fbSAndre Przywara 	node = fdt_node_offset_by_compatible(fdt, 0, "arm,pl011");
225422b44fbSAndre Przywara 	if (node < 0) {
226422b44fbSAndre Przywara 		WARN("%s(): No PL011 DT node found\n", __func__);
227422b44fbSAndre Przywara 
228422b44fbSAndre Przywara 		return;
229422b44fbSAndre Przywara 	}
230422b44fbSAndre Przywara 
231422b44fbSAndre Przywara 	err = fdt_read_uint32(fdt, node, "clocks", &phandle);
232422b44fbSAndre Przywara 	if (err != 0) {
233422b44fbSAndre Przywara 		WARN("Cannot find clocks property\n");
234422b44fbSAndre Przywara 
235422b44fbSAndre Przywara 		return;
236422b44fbSAndre Przywara 	}
237422b44fbSAndre Przywara 
238422b44fbSAndre Przywara 	node = fdt_node_offset_by_phandle(fdt, phandle);
239422b44fbSAndre Przywara 	if (node < 0) {
240422b44fbSAndre Przywara 		WARN("Cannot get phandle\n");
241422b44fbSAndre Przywara 
242422b44fbSAndre Przywara 		return;
243422b44fbSAndre Przywara 	}
244422b44fbSAndre Przywara 
245422b44fbSAndre Przywara 	err = fdt_setprop_inplace(fdt, node,
246422b44fbSAndre Przywara 				  "clock-frequency",
247422b44fbSAndre Przywara 				  &freq_dtb,
248422b44fbSAndre Przywara 				  sizeof(freq_dtb));
249422b44fbSAndre Przywara 	if (err < 0) {
250422b44fbSAndre Przywara 		WARN("Could not update DT baud clock frequency\n");
251422b44fbSAndre Przywara 
252422b44fbSAndre Przywara 		return;
253422b44fbSAndre Przywara 	}
254536d906aSOliver Swede }
255536d906aSOliver Swede 
25652b8f446SAndre Przywara #define CMDLINE_SIGNATURE	"CMD:"
25752b8f446SAndre Przywara 
fpga_dtb_set_commandline(void * fdt,const char * cmdline)25852b8f446SAndre Przywara static int fpga_dtb_set_commandline(void *fdt, const char *cmdline)
25952b8f446SAndre Przywara {
26052b8f446SAndre Przywara 	int chosen;
26152b8f446SAndre Przywara 	const char *eol;
26252b8f446SAndre Przywara 	char nul = 0;
26352b8f446SAndre Przywara 	int slen, err;
26452b8f446SAndre Przywara 
26552b8f446SAndre Przywara 	chosen = fdt_add_subnode(fdt, 0, "chosen");
26652b8f446SAndre Przywara 	if (chosen == -FDT_ERR_EXISTS) {
26752b8f446SAndre Przywara 		chosen = fdt_path_offset(fdt, "/chosen");
26852b8f446SAndre Przywara 	}
26952b8f446SAndre Przywara 
27052b8f446SAndre Przywara 	if (chosen < 0) {
27152b8f446SAndre Przywara 		return chosen;
27252b8f446SAndre Przywara 	}
27352b8f446SAndre Przywara 
27452b8f446SAndre Przywara 	/*
27552b8f446SAndre Przywara 	 * There is most likely an EOL at the end of the
27652b8f446SAndre Przywara 	 * command line, make sure we terminate the line there.
27752b8f446SAndre Przywara 	 * We can't replace the EOL with a NUL byte in the
27852b8f446SAndre Przywara 	 * source, as this is in read-only memory. So we first
27952b8f446SAndre Przywara 	 * create the property without any termination, then
28052b8f446SAndre Przywara 	 * append a single NUL byte.
28152b8f446SAndre Przywara 	 */
28252b8f446SAndre Przywara 	eol = strchr(cmdline, '\n');
28352b8f446SAndre Przywara 	if (eol == NULL) {
28452b8f446SAndre Przywara 		eol = strchr(cmdline, 0);
28552b8f446SAndre Przywara 	}
28652b8f446SAndre Przywara 	/* Skip the signature and omit the EOL/NUL byte. */
28752b8f446SAndre Przywara 	slen = eol - (cmdline + strlen(CMDLINE_SIGNATURE));
28852b8f446SAndre Przywara 	/*
28952b8f446SAndre Przywara 	 * Let's limit the size of the property, just in case
29052b8f446SAndre Przywara 	 * we find the signature by accident. The Linux kernel
29152b8f446SAndre Przywara 	 * limits to 4096 characters at most (in fact 2048 for
29252b8f446SAndre Przywara 	 * arm64), so that sounds like a reasonable number.
29352b8f446SAndre Przywara 	 */
29452b8f446SAndre Przywara 	if (slen > 4095) {
29552b8f446SAndre Przywara 		slen = 4095;
29652b8f446SAndre Przywara 	}
29752b8f446SAndre Przywara 
29852b8f446SAndre Przywara 	err = fdt_setprop(fdt, chosen, "bootargs",
29952b8f446SAndre Przywara 			  cmdline + strlen(CMDLINE_SIGNATURE), slen);
30052b8f446SAndre Przywara 	if (err != 0) {
30152b8f446SAndre Przywara 		return err;
30252b8f446SAndre Przywara 	}
30352b8f446SAndre Przywara 
30452b8f446SAndre Przywara 	return fdt_appendprop(fdt, chosen, "bootargs", &nul, 1);
30552b8f446SAndre Przywara }
30652b8f446SAndre Przywara 
fpga_prepare_dtb(void)307fa30f73bSAndre Przywara static void fpga_prepare_dtb(void)
308fa30f73bSAndre Przywara {
309fa30f73bSAndre Przywara 	void *fdt = (void *)(uintptr_t)FPGA_PRELOADED_DTB_BASE;
310fa30f73bSAndre Przywara 	const char *cmdline = (void *)(uintptr_t)FPGA_PRELOADED_CMD_LINE;
311fa30f73bSAndre Przywara 	int err;
312fa30f73bSAndre Przywara 
313fa30f73bSAndre Przywara 	err = fdt_open_into(fdt, fdt, FPGA_MAX_DTB_SIZE);
314fa30f73bSAndre Przywara 	if (err < 0) {
315fa30f73bSAndre Przywara 		ERROR("cannot open devicetree at %p: %d\n", fdt, err);
316fa30f73bSAndre Przywara 		panic();
317fa30f73bSAndre Przywara 	}
318fa30f73bSAndre Przywara 
31913e16feeSAndre Przywara 	/* Reserve memory used by Trusted Firmware. */
32013e16feeSAndre Przywara 	if (fdt_add_reserved_memory(fdt, "tf-a@80000000", BL31_BASE,
32113e16feeSAndre Przywara 				    BL31_LIMIT - BL31_BASE)) {
32213e16feeSAndre Przywara 		WARN("Failed to add reserved memory node to DT\n");
32313e16feeSAndre Przywara 	}
32413e16feeSAndre Przywara 
325fa30f73bSAndre Przywara 	/* Check for the command line signature. */
32652b8f446SAndre Przywara 	if (!strncmp(cmdline, CMDLINE_SIGNATURE, strlen(CMDLINE_SIGNATURE))) {
32752b8f446SAndre Przywara 		err = fpga_dtb_set_commandline(fdt, cmdline);
32852b8f446SAndre Przywara 		if (err == 0) {
32952b8f446SAndre Przywara 			INFO("using command line at 0x%x\n",
33052b8f446SAndre Przywara 			     FPGA_PRELOADED_CMD_LINE);
331fa30f73bSAndre Przywara 		} else {
33252b8f446SAndre Przywara 			ERROR("failed to put command line into DTB: %d\n", err);
333fa30f73bSAndre Przywara 		}
334fa30f73bSAndre Przywara 	}
335fa30f73bSAndre Przywara 
33620ff991eSJavier Almansa Sobrino 	if (err < 0) {
33720ff991eSJavier Almansa Sobrino 		ERROR("Error %d extending Device Tree\n", err);
33820ff991eSJavier Almansa Sobrino 		panic();
33920ff991eSJavier Almansa Sobrino 	}
34020ff991eSJavier Almansa Sobrino 
34120ff991eSJavier Almansa Sobrino 	err = fdt_add_cpus_node(fdt, FPGA_MAX_PE_PER_CPU,
34220ff991eSJavier Almansa Sobrino 				FPGA_MAX_CPUS_PER_CLUSTER,
34320ff991eSJavier Almansa Sobrino 				FPGA_MAX_CLUSTER_COUNT);
34420ff991eSJavier Almansa Sobrino 
34520ff991eSJavier Almansa Sobrino 	if (err == -EEXIST) {
34620ff991eSJavier Almansa Sobrino 		WARN("Not overwriting already existing /cpus node in DTB\n");
34720ff991eSJavier Almansa Sobrino 	} else {
34820ff991eSJavier Almansa Sobrino 		if (err < 0) {
34920ff991eSJavier Almansa Sobrino 			ERROR("Error %d creating the /cpus DT node\n", err);
35020ff991eSJavier Almansa Sobrino 			panic();
351283e5595SAndre Przywara 		} else {
352283e5595SAndre Przywara 			unsigned int nr_cores = fpga_get_nr_gic_cores();
353283e5595SAndre Przywara 
354283e5595SAndre Przywara 			INFO("Adjusting GICR DT region to cover %u cores\n",
355283e5595SAndre Przywara 			      nr_cores);
356283e5595SAndre Przywara 			err = fdt_adjust_gic_redist(fdt, nr_cores,
35793b785f5SAndre Przywara 						    fpga_get_redist_base(),
358c69f815bSAndre Przywara 						    fpga_get_redist_size());
359283e5595SAndre Przywara 			if (err < 0) {
360283e5595SAndre Przywara 				ERROR("Error %d fixing up GIC DT node\n", err);
361283e5595SAndre Przywara 			}
36220ff991eSJavier Almansa Sobrino 		}
36320ff991eSJavier Almansa Sobrino 	}
36420ff991eSJavier Almansa Sobrino 
365422b44fbSAndre Przywara 	fpga_dtb_update_clock(fdt, system_freq);
366422b44fbSAndre Przywara 
36740a0de19SAndre Przywara 	/* Check whether we support the SPE PMU. Remove the DT node if not. */
3686437a09aSAndre Przywara 	if (!is_feat_spe_supported()) {
36940a0de19SAndre Przywara 		int node = fdt_node_offset_by_compatible(fdt, 0,
37040a0de19SAndre Przywara 				     "arm,statistical-profiling-extension-v1");
37140a0de19SAndre Przywara 
37240a0de19SAndre Przywara 		if (node >= 0) {
37340a0de19SAndre Przywara 			fdt_del_node(fdt, node);
37440a0de19SAndre Przywara 		}
37540a0de19SAndre Przywara 	}
37640a0de19SAndre Przywara 
377d7e39c43SAndre Przywara 	/* Check whether we have an ITS. Remove the DT node if not. */
378d7e39c43SAndre Przywara 	if (!fpga_has_its()) {
379d7e39c43SAndre Przywara 		int node = fdt_node_offset_by_compatible(fdt, 0,
380d7e39c43SAndre Przywara 							 "arm,gic-v3-its");
381d7e39c43SAndre Przywara 
382d7e39c43SAndre Przywara 		if (node >= 0) {
383d7e39c43SAndre Przywara 			fdt_del_node(fdt, node);
384d7e39c43SAndre Przywara 		}
385d7e39c43SAndre Przywara 	}
386d7e39c43SAndre Przywara 
387fa30f73bSAndre Przywara 	err = fdt_pack(fdt);
388fa30f73bSAndre Przywara 	if (err < 0) {
389fa30f73bSAndre Przywara 		ERROR("Failed to pack Device Tree at %p: error %d\n", fdt, err);
390fa30f73bSAndre Przywara 	}
391fa30f73bSAndre Przywara 
392fa30f73bSAndre Przywara 	clean_dcache_range((uintptr_t)fdt, fdt_blob_size(fdt));
393fa30f73bSAndre Przywara }
394fa30f73bSAndre Przywara 
bl31_plat_runtime_setup(void)395fa30f73bSAndre Przywara void bl31_plat_runtime_setup(void)
396fa30f73bSAndre Przywara {
397fa30f73bSAndre Przywara 	fpga_prepare_dtb();
398fa30f73bSAndre Przywara }
399fa30f73bSAndre Przywara 
bl31_plat_enable_mmu(uint32_t flags)400536d906aSOliver Swede void bl31_plat_enable_mmu(uint32_t flags)
401536d906aSOliver Swede {
402536d906aSOliver Swede 	/* TODO: determine if MMU needs to be enabled */
403536d906aSOliver Swede }
404