1*97ef5305SMario Bălănică /*
2*97ef5305SMario Bălănică * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
3*97ef5305SMario Bălănică *
4*97ef5305SMario Bălănică * SPDX-License-Identifier: BSD-3-Clause
5*97ef5305SMario Bălănică */
6*97ef5305SMario Bălănică
7*97ef5305SMario Bălănică #include <assert.h>
8*97ef5305SMario Bălănică #include <inttypes.h>
9*97ef5305SMario Bălănică #include <stdint.h>
10*97ef5305SMario Bălănică
11*97ef5305SMario Bălănică #include <arch_helpers.h>
12*97ef5305SMario Bălănică #include <common/fdt_fixup.h>
13*97ef5305SMario Bălănică #include <common/fdt_wrappers.h>
14*97ef5305SMario Bălănică
15*97ef5305SMario Bălănică #include <rpi_shared.h>
16*97ef5305SMario Bălănică
17*97ef5305SMario Bălănică /*
18*97ef5305SMario Bălănică * Remove the FDT /memreserve/ entry that covers the region at the very
19*97ef5305SMario Bălănică * beginning of memory (if that exists). This is where the secondaries
20*97ef5305SMario Bălănică * originally spin, but we pull them out there.
21*97ef5305SMario Bălănică * Having overlapping /reserved-memory and /memreserve/ regions confuses
22*97ef5305SMario Bălănică * the Linux kernel, so we need to get rid of this one.
23*97ef5305SMario Bălănică */
remove_spintable_memreserve(void * dtb)24*97ef5305SMario Bălănică static void remove_spintable_memreserve(void *dtb)
25*97ef5305SMario Bălănică {
26*97ef5305SMario Bălănică uint64_t addr, size;
27*97ef5305SMario Bălănică int regions = fdt_num_mem_rsv(dtb);
28*97ef5305SMario Bălănică int i;
29*97ef5305SMario Bălănică
30*97ef5305SMario Bălănică for (i = 0; i < regions; i++) {
31*97ef5305SMario Bălănică if (fdt_get_mem_rsv(dtb, i, &addr, &size) != 0) {
32*97ef5305SMario Bălănică return;
33*97ef5305SMario Bălănică }
34*97ef5305SMario Bălănică if (size == 0U) {
35*97ef5305SMario Bălănică return;
36*97ef5305SMario Bălănică }
37*97ef5305SMario Bălănică /* We only look for the region at the beginning of DRAM. */
38*97ef5305SMario Bălănică if (addr != 0U) {
39*97ef5305SMario Bălănică continue;
40*97ef5305SMario Bălănică }
41*97ef5305SMario Bălănică /*
42*97ef5305SMario Bălănică * Currently the region in the existing DTs is exactly 4K
43*97ef5305SMario Bălănică * in size. Should this value ever change, there is probably
44*97ef5305SMario Bălănică * a reason for that, so inform the user about this.
45*97ef5305SMario Bălănică */
46*97ef5305SMario Bălănică if (size == 4096U) {
47*97ef5305SMario Bălănică fdt_del_mem_rsv(dtb, i);
48*97ef5305SMario Bălănică return;
49*97ef5305SMario Bălănică }
50*97ef5305SMario Bălănică WARN("Keeping unknown /memreserve/ region at 0, size: %" PRId64 "\n",
51*97ef5305SMario Bălănică size);
52*97ef5305SMario Bălănică }
53*97ef5305SMario Bălănică }
54*97ef5305SMario Bălănică
rpi4_prepare_dtb(void)55*97ef5305SMario Bălănică static void rpi4_prepare_dtb(void)
56*97ef5305SMario Bălănică {
57*97ef5305SMario Bălănică void *dtb = (void *)rpi4_get_dtb_address();
58*97ef5305SMario Bălănică uint32_t gic_int_prop[3];
59*97ef5305SMario Bălănică int ret, offs;
60*97ef5305SMario Bălănică
61*97ef5305SMario Bălănică /* Return if no device tree is detected */
62*97ef5305SMario Bălănică if (fdt_check_header(dtb) != 0)
63*97ef5305SMario Bălănică return;
64*97ef5305SMario Bălănică
65*97ef5305SMario Bălănică ret = fdt_open_into(dtb, dtb, 0x100000);
66*97ef5305SMario Bălănică if (ret < 0) {
67*97ef5305SMario Bălănică ERROR("Invalid Device Tree at %p: error %d\n", dtb, ret);
68*97ef5305SMario Bălănică return;
69*97ef5305SMario Bălănică }
70*97ef5305SMario Bălănică
71*97ef5305SMario Bălănică if (dt_add_psci_node(dtb)) {
72*97ef5305SMario Bălănică ERROR("Failed to add PSCI Device Tree node\n");
73*97ef5305SMario Bălănică return;
74*97ef5305SMario Bălănică }
75*97ef5305SMario Bălănică
76*97ef5305SMario Bălănică if (dt_add_psci_cpu_enable_methods(dtb)) {
77*97ef5305SMario Bălănică ERROR("Failed to add PSCI cpu enable methods in Device Tree\n");
78*97ef5305SMario Bălănică return;
79*97ef5305SMario Bălănică }
80*97ef5305SMario Bălănică
81*97ef5305SMario Bălănică /*
82*97ef5305SMario Bălănică * Remove the original reserved region (used for the spintable), and
83*97ef5305SMario Bălănică * replace it with a region describing the whole of Trusted Firmware.
84*97ef5305SMario Bălănică */
85*97ef5305SMario Bălănică remove_spintable_memreserve(dtb);
86*97ef5305SMario Bălănică if (fdt_add_reserved_memory(dtb, "atf@0", 0, 0x80000))
87*97ef5305SMario Bălănică WARN("Failed to add reserved memory nodes to DT.\n");
88*97ef5305SMario Bălănică
89*97ef5305SMario Bălănică offs = fdt_node_offset_by_compatible(dtb, 0, "arm,gic-400");
90*97ef5305SMario Bălănică gic_int_prop[0] = cpu_to_fdt32(1); // PPI
91*97ef5305SMario Bălănică gic_int_prop[1] = cpu_to_fdt32(9); // PPI #9
92*97ef5305SMario Bălănică gic_int_prop[2] = cpu_to_fdt32(0x0f04); // all cores, level high
93*97ef5305SMario Bălănică fdt_setprop(dtb, offs, "interrupts", gic_int_prop, 12);
94*97ef5305SMario Bălănică
95*97ef5305SMario Bălănică offs = fdt_path_offset(dtb, "/chosen");
96*97ef5305SMario Bălănică fdt_setprop_string(dtb, offs, "stdout-path", "serial0");
97*97ef5305SMario Bălănică
98*97ef5305SMario Bălănică ret = fdt_pack(dtb);
99*97ef5305SMario Bălănică if (ret < 0)
100*97ef5305SMario Bălănică ERROR("Failed to pack Device Tree at %p: error %d\n", dtb, ret);
101*97ef5305SMario Bălănică
102*97ef5305SMario Bălănică clean_dcache_range((uintptr_t)dtb, fdt_blob_size(dtb));
103*97ef5305SMario Bălănică INFO("Changed device tree to advertise PSCI.\n");
104*97ef5305SMario Bălănică }
105*97ef5305SMario Bălănică
plat_rpi_bl31_custom_setup(void)106*97ef5305SMario Bălănică void plat_rpi_bl31_custom_setup(void)
107*97ef5305SMario Bălănică {
108*97ef5305SMario Bălănică rpi4_prepare_dtb();
109*97ef5305SMario Bălănică }
110