1 /* 2 * Copyright (c) 2023, Advanced Micro Devices, Inc. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <errno.h> 9 #include <stdlib.h> 10 #include <string.h> 11 12 #include <common/debug.h> 13 #include <common/fdt_fixup.h> 14 #include <common/fdt_wrappers.h> 15 #include <drivers/arm/dcc.h> 16 #include <drivers/arm/pl011.h> 17 #include <drivers/cadence/cdns_uart.h> 18 #include <drivers/console.h> 19 #include <libfdt.h> 20 #include <plat_console.h> 21 #include <plat_fdt.h> 22 23 #include <platform_def.h> 24 #include <plat_private.h> 25 26 #if !(CONSOLE_IS(none)) 27 static console_t boot_console; 28 static console_holder boot_hd_console; 29 #if defined(CONSOLE_RUNTIME) 30 static console_t runtime_console; 31 static console_holder rt_hd_console; 32 #endif 33 34 #if ((CONSOLE_IS(dtb) || RT_CONSOLE_IS(dtb)) && defined(XILINX_OF_BOARD_DTB_ADDR)) && \ 35 (!defined(PLAT_zynqmp) || (defined(PLAT_zynqmp) && \ 36 !IS_TFA_IN_OCM(BL31_BASE))) 37 static dt_uart_info_t dt_uart_info; 38 #endif 39 40 /** 41 * register_console() - Registers the uart with console list. 42 * @consoleh: Console holder structure with UART base address, 43 * UART clock, UART buad rate, flags & console type 44 * @console: Pointer to the console information structure. 45 */ 46 static void register_console(const console_holder *consoleh, console_t *console) 47 { 48 int32_t rc = 0; 49 50 switch (consoleh->console_type) { 51 #if defined(PLAT_zynqmp) 52 case CONSOLE_CDNS: 53 rc = console_cdns_register(consoleh->base, 54 consoleh->clk, 55 consoleh->baud_rate, 56 console); 57 break; 58 #else 59 case CONSOLE_PL011: 60 rc = console_pl011_register(consoleh->base, 61 consoleh->clk, 62 consoleh->baud_rate, 63 console); 64 break; 65 #endif 66 case CONSOLE_DCC: 67 rc = console_dcc_register(console); 68 break; 69 default: 70 INFO("Invalid console type\n"); 71 break; 72 } 73 74 if (rc == 0) { 75 panic(); 76 } 77 78 console_set_scope(console, consoleh->console_scope); 79 } 80 81 #if ((CONSOLE_IS(dtb) || RT_CONSOLE_IS(dtb)) && defined(XILINX_OF_BOARD_DTB_ADDR)) && \ 82 (!defined(PLAT_zynqmp) || (defined(PLAT_zynqmp) && \ 83 !IS_TFA_IN_OCM(BL31_BASE))) 84 /** 85 * get_baudrate() - Get the baudrate form DTB. 86 * @dtb: Address of the Device Tree Blob (DTB). 87 * 88 * Return: On success returns the baudrate; on failure returns an error. 89 */ 90 static int32_t get_baudrate(void *dtb) 91 { 92 int node; 93 int32_t ret = 0; 94 const char *prop, *path; 95 char *end; 96 int32_t baud_rate = 0; 97 98 node = fdt_path_offset(dtb, "/secure-chosen"); 99 if (node < 0) { 100 node = fdt_path_offset(dtb, "/chosen"); 101 if (node < 0) { 102 ret = -FDT_ERR_NOTFOUND; 103 goto error; 104 } 105 } 106 107 prop = fdt_getprop(dtb, node, "stdout-path", NULL); 108 if (prop == NULL) { 109 ret = -FDT_ERR_NOTFOUND; 110 goto error; 111 } 112 113 /* Parse string serial0:115200n8 */ 114 path = strchr(prop, ':'); 115 if (!path) { 116 ret = -FDT_ERR_NOTFOUND; 117 goto error; 118 } else { 119 120 baud_rate = strtoul(path + 1, &end, 10); 121 if (baud_rate == 0 && end == path) { 122 ERROR("Conversion error occurred: %d\n", baud_rate); 123 ret = -FDT_ERR_NOTFOUND; 124 goto error; 125 } 126 ret = baud_rate; 127 } 128 129 error: 130 return ret; 131 } 132 133 /** 134 * get_node_status() - Get the DTB node status. 135 * @dtb: Address of the Device Tree Blob (DTB). 136 * @node: Node address in the device tree. 137 * 138 * Return: On success, it returns 1; on failure, it returns an 0. 139 */ 140 static uint32_t get_node_status(void *dtb, int node) 141 { 142 const char *status_cell; 143 uint32_t status = 0; 144 145 status_cell = fdt_getprop(dtb, node, "status", NULL); 146 if (!status_cell || strcmp(status_cell, "okay") == 0) { 147 status = 1; 148 } else { 149 status = 0; 150 } 151 152 return status; 153 } 154 155 /** 156 * fdt_add_uart_info() - Add DTB information to a UART structure. 157 * @info: Pointer to the UART information structure. 158 * @node: Node address in the device tree. 159 * @dtb: Address of the Device Tree Blob(DTB). 160 * 161 * Return: On success, it returns 0; on failure, it returns -1 or -FDT_ERR_NOTFOUND. 162 */ 163 static int32_t fdt_add_uart_info(dt_uart_info_t *info, int node, void *dtb) 164 { 165 uintptr_t base_addr; 166 const char *com; 167 int32_t ret = 0; 168 uint32_t status; 169 170 com = fdt_getprop(dtb, node, "compatible", NULL); 171 if (com != NULL) { 172 strlcpy(info->compatible, com, sizeof(info->compatible)); 173 } else { 174 ERROR("Compatible property not found in DTB node\n"); 175 ret = -FDT_ERR_NOTFOUND; 176 goto error; 177 } 178 179 status = get_node_status(dtb, node); 180 if (status == 0) { 181 ERROR("Uart node is disabled in DTB\n"); 182 ret = -FDT_ERR_NOTFOUND; 183 goto error; 184 } 185 186 if (strncmp(info->compatible, DT_UART_DCC_COMPAT, strlen(DT_UART_DCC_COMPAT)) != 0) { 187 ret = fdt_get_reg_props_by_index(dtb, node, 0, &base_addr, NULL); 188 if (ret >= 0) { 189 info->base = base_addr; 190 } else { 191 ERROR("Failed to retrieve base address. Error code: %d\n", ret); 192 ret = -FDT_ERR_NOTFOUND; 193 goto error; 194 } 195 196 info->baud_rate = get_baudrate(dtb); 197 198 if (strncmp(info->compatible, DT_UART_CAD_COMPAT, 199 strlen(DT_UART_CAD_COMPAT)) == 0) { 200 info->console_type = CONSOLE_CDNS; 201 } else if (strncmp(info->compatible, DT_UART_PL011_COMPAT, 202 strlen(DT_UART_PL011_COMPAT)) == 0) { 203 info->console_type = CONSOLE_PL011; 204 } else { 205 ERROR("Incompatible uart node in DTB\n"); 206 ret = -FDT_ERR_NOTFOUND; 207 } 208 } else { 209 info->console_type = CONSOLE_DCC; 210 } 211 212 error: 213 return ret; 214 } 215 216 /** 217 * fdt_get_uart_info() - Get the uart information form DTB. 218 * @info: Pointer to the UART information structure. 219 * 220 * Return: On success, it returns 0; on failure, it returns an error+reason. 221 */ 222 static int fdt_get_uart_info(dt_uart_info_t *info) 223 { 224 int node = 0, ret = 0; 225 void *dtb = (void *)XILINX_OF_BOARD_DTB_ADDR; 226 227 ret = is_valid_dtb(dtb); 228 if (ret < 0) { 229 ERROR("Invalid Device Tree at %p: error %d\n", dtb, ret); 230 goto error; 231 } 232 233 node = fdt_get_stdout_node_offset(dtb); 234 if (node < 0) { 235 ERROR("DT get stdout node failed : %d\n", node); 236 goto error; 237 } 238 239 ret = fdt_add_uart_info(info, node, dtb); 240 if (ret < 0) { 241 ERROR("Failed to add DT UART info: %d\n", ret); 242 goto error; 243 } 244 245 error: 246 return ret; 247 } 248 #endif 249 250 void setup_console(void) 251 { 252 /* This is hardcoded console setup just in case that DTB console fails */ 253 boot_hd_console.base = (uintptr_t)UART_BASE; 254 boot_hd_console.baud_rate = (uint32_t)UART_BAUDRATE; 255 boot_hd_console.clk = get_uart_clk(); 256 boot_hd_console.console_scope = CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH; 257 boot_hd_console.console_type = UART_TYPE; 258 259 /* For DT code decoding uncomment console registration below */ 260 /* register_console(&boot_hd_console, &boot_console); */ 261 262 #if ((CONSOLE_IS(dtb) || RT_CONSOLE_IS(dtb)) && defined(XILINX_OF_BOARD_DTB_ADDR)) && \ 263 (!defined(PLAT_zynqmp) || (defined(PLAT_zynqmp) && \ 264 !IS_TFA_IN_OCM(BL31_BASE))) 265 /* Parse DTB console for UART information */ 266 if (fdt_get_uart_info(&dt_uart_info) == 0) { 267 if (CONSOLE_IS(dtb)) { 268 boot_hd_console.base = dt_uart_info.base; 269 boot_hd_console.baud_rate = dt_uart_info.baud_rate; 270 boot_hd_console.console_type = dt_uart_info.console_type; 271 } 272 } else { 273 ERROR("Failed to initialize DT console or console node is disabled\n"); 274 } 275 #endif 276 277 /* Initialize the boot console */ 278 register_console(&boot_hd_console, &boot_console); 279 280 INFO("BL31: Early console setup\n"); 281 282 #ifdef CONSOLE_RUNTIME 283 #if (RT_CONSOLE_IS(dtb) && defined(XILINX_OF_BOARD_DTB_ADDR)) && \ 284 (!defined(PLAT_zynqmp) || (defined(PLAT_zynqmp) && \ 285 !IS_TFA_IN_OCM(BL31_BASE))) 286 rt_hd_console.base = dt_uart_info.base; 287 rt_hd_console.baud_rate = dt_uart_info.baud_rate; 288 rt_hd_console.console_type = dt_uart_info.console_type; 289 #else 290 rt_hd_console.base = (uintptr_t)RT_UART_BASE; 291 rt_hd_console.baud_rate = (uint32_t)UART_BAUDRATE; 292 rt_hd_console.console_type = RT_UART_TYPE; 293 #endif 294 295 if ((rt_hd_console.console_type == boot_hd_console.console_type) && 296 (rt_hd_console.base == boot_hd_console.base)) { 297 console_set_scope(&boot_console, 298 CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH | CONSOLE_FLAG_RUNTIME); 299 INFO("Successfully initialized runtime console\n"); 300 } else { 301 rt_hd_console.clk = get_uart_clk(); 302 rt_hd_console.console_scope = CONSOLE_FLAG_RUNTIME; 303 304 register_console(&rt_hd_console, &runtime_console); 305 INFO("Successfully initialized new runtime console\n"); 306 } 307 #endif 308 } 309 #else 310 void setup_console(void) 311 { 312 } 313 #endif 314