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ă */ 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ă 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ă 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