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