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