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