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