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