1 /* 2 * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <errno.h> 9 10 #include <common/fdt_fixup.h> 11 #include <common/fdt_wrappers.h> 12 #include <drivers/arm/gicv3.h> 13 #include <drivers/delay_timer.h> 14 #include <drivers/generic_delay_timer.h> 15 #include <libfdt.h> 16 17 #include "fpga_private.h" 18 #include <plat/common/platform.h> 19 #include <platform_def.h> 20 21 static entry_point_info_t bl33_image_ep_info; 22 volatile uint32_t secondary_core_spinlock; 23 24 uintptr_t plat_get_ns_image_entrypoint(void) 25 { 26 #ifdef PRELOADED_BL33_BASE 27 return PRELOADED_BL33_BASE; 28 #else 29 return 0ULL; 30 #endif 31 } 32 33 uint32_t fpga_get_spsr_for_bl33_entry(void) 34 { 35 return SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); 36 } 37 38 void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, 39 u_register_t arg2, u_register_t arg3) 40 { 41 /* Add this core to the VALID mpids list */ 42 fpga_valid_mpids[plat_my_core_pos()] = VALID_MPID; 43 44 /* 45 * Notify the secondary CPUs that the C runtime is ready 46 * so they can announce themselves. 47 */ 48 secondary_core_spinlock = C_RUNTIME_READY_KEY; 49 dsbish(); 50 sev(); 51 52 fpga_console_init(); 53 54 bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); 55 bl33_image_ep_info.spsr = fpga_get_spsr_for_bl33_entry(); 56 SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); 57 58 /* Set x0-x3 for the primary CPU as expected by the kernel */ 59 bl33_image_ep_info.args.arg0 = (u_register_t)FPGA_PRELOADED_DTB_BASE; 60 bl33_image_ep_info.args.arg1 = 0U; 61 bl33_image_ep_info.args.arg2 = 0U; 62 bl33_image_ep_info.args.arg3 = 0U; 63 } 64 65 void bl31_plat_arch_setup(void) 66 { 67 } 68 69 void bl31_platform_setup(void) 70 { 71 /* Write frequency to CNTCRL and initialize timer */ 72 generic_delay_timer_init(); 73 74 /* 75 * Before doing anything else, wait for some time to ensure that 76 * the secondary CPUs have populated the fpga_valid_mpids array. 77 * As the number of secondary cores is unknown and can even be 0, 78 * it is not possible to rely on any signal from them, so use a 79 * delay instead. 80 */ 81 mdelay(5); 82 83 /* 84 * On the event of a cold reset issued by, for instance, a reset pin 85 * assertion, we cannot guarantee memory to be initialized to zero. 86 * In such scenario, if the secondary cores reached 87 * plat_secondary_cold_boot_setup before the primary one initialized 88 * .BSS, we could end up having a race condition if the spinlock 89 * was not cleared before. 90 * 91 * Similarly, if there were a reset before the spinlock had been 92 * cleared, the secondary cores would find the lock opened before 93 * .BSS is cleared, causing another race condition. 94 * 95 * So clean the spinlock as soon as we think it is safe to reduce the 96 * chances of any race condition on a reset. 97 */ 98 secondary_core_spinlock = 0UL; 99 100 /* Initialize the GIC driver, cpu and distributor interfaces */ 101 plat_fpga_gic_init(); 102 } 103 104 entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) 105 { 106 entry_point_info_t *next_image_info; 107 next_image_info = &bl33_image_ep_info; 108 109 /* Only expecting BL33: the kernel will run in EL2NS */ 110 assert(type == NON_SECURE); 111 112 /* None of the images can have 0x0 as the entrypoint */ 113 if (next_image_info->pc) { 114 return next_image_info; 115 } else { 116 return NULL; 117 } 118 } 119 120 unsigned int plat_get_syscnt_freq2(void) 121 { 122 const void *fdt = (void *)(uintptr_t)FPGA_PRELOADED_DTB_BASE; 123 int node; 124 125 node = fdt_node_offset_by_compatible(fdt, 0, "arm,armv8-timer"); 126 if (node < 0) { 127 return FPGA_DEFAULT_TIMER_FREQUENCY; 128 } 129 130 return fdt_read_uint32_default(fdt, node, "clock-frequency", 131 FPGA_DEFAULT_TIMER_FREQUENCY); 132 } 133 134 static void fpga_prepare_dtb(void) 135 { 136 void *fdt = (void *)(uintptr_t)FPGA_PRELOADED_DTB_BASE; 137 const char *cmdline = (void *)(uintptr_t)FPGA_PRELOADED_CMD_LINE; 138 int err; 139 140 err = fdt_open_into(fdt, fdt, FPGA_MAX_DTB_SIZE); 141 if (err < 0) { 142 ERROR("cannot open devicetree at %p: %d\n", fdt, err); 143 panic(); 144 } 145 146 /* Check for the command line signature. */ 147 if (!strncmp(cmdline, "CMD:", 4)) { 148 int chosen; 149 150 INFO("using command line at 0x%x\n", FPGA_PRELOADED_CMD_LINE); 151 152 chosen = fdt_add_subnode(fdt, 0, "chosen"); 153 if (chosen == -FDT_ERR_EXISTS) { 154 chosen = fdt_path_offset(fdt, "/chosen"); 155 } 156 if (chosen < 0) { 157 ERROR("cannot find /chosen node: %d\n", chosen); 158 } else { 159 const char *eol; 160 char nul = 0; 161 int slen; 162 163 /* 164 * There is most likely an EOL at the end of the 165 * command line, make sure we terminate the line there. 166 * We can't replace the EOL with a NUL byte in the 167 * source, as this is in read-only memory. So we first 168 * create the property without any termination, then 169 * append a single NUL byte. 170 */ 171 eol = strchr(cmdline, '\n'); 172 if (!eol) { 173 eol = strchr(cmdline, 0); 174 } 175 /* Skip the signature and omit the EOL/NUL byte. */ 176 slen = eol - (cmdline + 4); 177 178 /* 179 * Let's limit the size of the property, just in case 180 * we find the signature by accident. The Linux kernel 181 * limits to 4096 characters at most (in fact 2048 for 182 * arm64), so that sounds like a reasonable number. 183 */ 184 if (slen > 4095) { 185 slen = 4095; 186 } 187 err = fdt_setprop(fdt, chosen, "bootargs", 188 cmdline + 4, slen); 189 if (!err) { 190 err = fdt_appendprop(fdt, chosen, "bootargs", 191 &nul, 1); 192 } 193 if (err) { 194 ERROR("Could not set command line: %d\n", err); 195 } 196 } 197 } 198 199 if (err < 0) { 200 ERROR("Error %d extending Device Tree\n", err); 201 panic(); 202 } 203 204 err = fdt_add_cpus_node(fdt, FPGA_MAX_PE_PER_CPU, 205 FPGA_MAX_CPUS_PER_CLUSTER, 206 FPGA_MAX_CLUSTER_COUNT); 207 208 if (err == -EEXIST) { 209 WARN("Not overwriting already existing /cpus node in DTB\n"); 210 } else { 211 if (err < 0) { 212 ERROR("Error %d creating the /cpus DT node\n", err); 213 panic(); 214 } else { 215 unsigned int nr_cores = fpga_get_nr_gic_cores(); 216 217 INFO("Adjusting GICR DT region to cover %u cores\n", 218 nr_cores); 219 err = fdt_adjust_gic_redist(fdt, nr_cores, 220 1U << GICR_PCPUBASE_SHIFT); 221 if (err < 0) { 222 ERROR("Error %d fixing up GIC DT node\n", err); 223 } 224 } 225 } 226 227 err = fdt_pack(fdt); 228 if (err < 0) { 229 ERROR("Failed to pack Device Tree at %p: error %d\n", fdt, err); 230 } 231 232 clean_dcache_range((uintptr_t)fdt, fdt_blob_size(fdt)); 233 } 234 235 void bl31_plat_runtime_setup(void) 236 { 237 fpga_prepare_dtb(); 238 } 239 240 void bl31_plat_enable_mmu(uint32_t flags) 241 { 242 /* TODO: determine if MMU needs to be enabled */ 243 } 244