139234622SPrasad Kummari /*
2ea453871SMaheedhar Bollapalli * Copyright (c) 2023-2025, Advanced Micro Devices, Inc. All rights reserved.
339234622SPrasad Kummari *
439234622SPrasad Kummari * SPDX-License-Identifier: BSD-3-Clause
539234622SPrasad Kummari */
639234622SPrasad Kummari
739234622SPrasad Kummari #include <assert.h>
839234622SPrasad Kummari #include <errno.h>
939234622SPrasad Kummari #include <stdlib.h>
1039234622SPrasad Kummari #include <string.h>
1139234622SPrasad Kummari
1239234622SPrasad Kummari #include <common/debug.h>
1339234622SPrasad Kummari #include <common/fdt_fixup.h>
1439234622SPrasad Kummari #include <common/fdt_wrappers.h>
1539234622SPrasad Kummari #include <drivers/arm/dcc.h>
1639234622SPrasad Kummari #include <drivers/arm/pl011.h>
1739234622SPrasad Kummari #include <drivers/cadence/cdns_uart.h>
1839234622SPrasad Kummari #include <drivers/console.h>
1939234622SPrasad Kummari #include <libfdt.h>
2039234622SPrasad Kummari #include <plat_console.h>
21e2d9dfe2SPrasad Kummari #include <plat_fdt.h>
2239234622SPrasad Kummari
2339234622SPrasad Kummari #include <platform_def.h>
2439234622SPrasad Kummari #include <plat_private.h>
2539234622SPrasad Kummari
266d413983SMichal Simek #if !(CONSOLE_IS(none))
27a542b9c1SPrasad Kummari static console_t boot_console;
28d2e00eeaSMaheedhar Bollapalli static console_holder boot_hd_console;
29d2e00eeaSMaheedhar Bollapalli #if defined(CONSOLE_RUNTIME)
30d2e00eeaSMaheedhar Bollapalli static console_t runtime_console;
31d2e00eeaSMaheedhar Bollapalli static console_holder rt_hd_console;
32d2e00eeaSMaheedhar Bollapalli #endif
3339234622SPrasad Kummari
344c5cf47fSMaheedhar Bollapalli #if ((CONSOLE_IS(dtb) || RT_CONSOLE_IS(dtb)) && (XLNX_DT_CFG == 1))
35d2e00eeaSMaheedhar Bollapalli static dt_uart_info_t dt_uart_info;
36d2e00eeaSMaheedhar Bollapalli #endif
37d2e00eeaSMaheedhar Bollapalli
384557ab69SPrasad Kummari /**
39d2e00eeaSMaheedhar Bollapalli * register_console() - Registers the uart with console list.
40d2e00eeaSMaheedhar Bollapalli * @consoleh: Console holder structure with UART base address,
41d2e00eeaSMaheedhar Bollapalli * UART clock, UART buad rate, flags & console type
424557ab69SPrasad Kummari * @console: Pointer to the console information structure.
434557ab69SPrasad Kummari */
register_console(const console_holder * consoleh,console_t * console)44d2e00eeaSMaheedhar Bollapalli static void register_console(const console_holder *consoleh, console_t *console)
454557ab69SPrasad Kummari {
464557ab69SPrasad Kummari int32_t rc = 0;
474557ab69SPrasad Kummari
48d2e00eeaSMaheedhar Bollapalli switch (consoleh->console_type) {
494557ab69SPrasad Kummari #if defined(PLAT_zynqmp)
50d2e00eeaSMaheedhar Bollapalli case CONSOLE_CDNS:
51d2e00eeaSMaheedhar Bollapalli rc = console_cdns_register(consoleh->base,
52d2e00eeaSMaheedhar Bollapalli consoleh->clk,
53d2e00eeaSMaheedhar Bollapalli consoleh->baud_rate,
544557ab69SPrasad Kummari console);
55d2e00eeaSMaheedhar Bollapalli break;
56d2e00eeaSMaheedhar Bollapalli #else
57d2e00eeaSMaheedhar Bollapalli case CONSOLE_PL011:
58d2e00eeaSMaheedhar Bollapalli rc = console_pl011_register(consoleh->base,
59d2e00eeaSMaheedhar Bollapalli consoleh->clk,
60d2e00eeaSMaheedhar Bollapalli consoleh->baud_rate,
614557ab69SPrasad Kummari console);
62d2e00eeaSMaheedhar Bollapalli break;
634557ab69SPrasad Kummari #endif
64d2e00eeaSMaheedhar Bollapalli case CONSOLE_DCC:
654557ab69SPrasad Kummari rc = console_dcc_register(console);
66d2e00eeaSMaheedhar Bollapalli break;
67d2e00eeaSMaheedhar Bollapalli default:
684557ab69SPrasad Kummari INFO("Invalid console type\n");
69d2e00eeaSMaheedhar Bollapalli break;
704557ab69SPrasad Kummari }
714557ab69SPrasad Kummari
724557ab69SPrasad Kummari if (rc == 0) {
734557ab69SPrasad Kummari panic();
744557ab69SPrasad Kummari }
754557ab69SPrasad Kummari
76d2e00eeaSMaheedhar Bollapalli console_set_scope(console, consoleh->console_scope);
774557ab69SPrasad Kummari }
784557ab69SPrasad Kummari
794c5cf47fSMaheedhar Bollapalli #if ((CONSOLE_IS(dtb) || RT_CONSOLE_IS(dtb)) && (XLNX_DT_CFG == 1))
8039234622SPrasad Kummari /**
8139234622SPrasad Kummari * get_baudrate() - Get the baudrate form DTB.
8239234622SPrasad Kummari * @dtb: Address of the Device Tree Blob (DTB).
8339234622SPrasad Kummari *
8439234622SPrasad Kummari * Return: On success returns the baudrate; on failure returns an error.
8539234622SPrasad Kummari */
get_baudrate(void * dtb)8639234622SPrasad Kummari static int32_t get_baudrate(void *dtb)
8739234622SPrasad Kummari {
8839234622SPrasad Kummari int node;
8939234622SPrasad Kummari int32_t ret = 0;
9039234622SPrasad Kummari const char *prop, *path;
9139234622SPrasad Kummari char *end;
9239234622SPrasad Kummari int32_t baud_rate = 0;
9339234622SPrasad Kummari
9439234622SPrasad Kummari node = fdt_path_offset(dtb, "/secure-chosen");
9539234622SPrasad Kummari if (node < 0) {
9639234622SPrasad Kummari node = fdt_path_offset(dtb, "/chosen");
9739234622SPrasad Kummari if (node < 0) {
9839234622SPrasad Kummari ret = -FDT_ERR_NOTFOUND;
9939234622SPrasad Kummari goto error;
10039234622SPrasad Kummari }
10139234622SPrasad Kummari }
10239234622SPrasad Kummari
10339234622SPrasad Kummari prop = fdt_getprop(dtb, node, "stdout-path", NULL);
10439234622SPrasad Kummari if (prop == NULL) {
10539234622SPrasad Kummari ret = -FDT_ERR_NOTFOUND;
10639234622SPrasad Kummari goto error;
10739234622SPrasad Kummari }
10839234622SPrasad Kummari
10939234622SPrasad Kummari /* Parse string serial0:115200n8 */
11039234622SPrasad Kummari path = strchr(prop, ':');
11139234622SPrasad Kummari if (!path) {
11239234622SPrasad Kummari ret = -FDT_ERR_NOTFOUND;
11339234622SPrasad Kummari goto error;
11439234622SPrasad Kummari } else {
11539234622SPrasad Kummari
11639234622SPrasad Kummari baud_rate = strtoul(path + 1, &end, 10);
11739234622SPrasad Kummari if (baud_rate == 0 && end == path) {
11839234622SPrasad Kummari ERROR("Conversion error occurred: %d\n", baud_rate);
11939234622SPrasad Kummari ret = -FDT_ERR_NOTFOUND;
12039234622SPrasad Kummari goto error;
12139234622SPrasad Kummari }
12239234622SPrasad Kummari ret = baud_rate;
12339234622SPrasad Kummari }
12439234622SPrasad Kummari
12539234622SPrasad Kummari error:
12639234622SPrasad Kummari return ret;
12739234622SPrasad Kummari }
12839234622SPrasad Kummari
12939234622SPrasad Kummari /**
13039234622SPrasad Kummari * get_node_status() - Get the DTB node status.
13139234622SPrasad Kummari * @dtb: Address of the Device Tree Blob (DTB).
13239234622SPrasad Kummari * @node: Node address in the device tree.
13339234622SPrasad Kummari *
13439234622SPrasad Kummari * Return: On success, it returns 1; on failure, it returns an 0.
13539234622SPrasad Kummari */
get_node_status(void * dtb,int node)13639234622SPrasad Kummari static uint32_t get_node_status(void *dtb, int node)
13739234622SPrasad Kummari {
13839234622SPrasad Kummari const char *status_cell;
13939234622SPrasad Kummari uint32_t status = 0;
14039234622SPrasad Kummari
14139234622SPrasad Kummari status_cell = fdt_getprop(dtb, node, "status", NULL);
14239234622SPrasad Kummari if (!status_cell || strcmp(status_cell, "okay") == 0) {
14339234622SPrasad Kummari status = 1;
14439234622SPrasad Kummari } else {
14539234622SPrasad Kummari status = 0;
14639234622SPrasad Kummari }
14739234622SPrasad Kummari
14839234622SPrasad Kummari return status;
14939234622SPrasad Kummari }
15039234622SPrasad Kummari
15139234622SPrasad Kummari /**
15239234622SPrasad Kummari * fdt_add_uart_info() - Add DTB information to a UART structure.
15339234622SPrasad Kummari * @info: Pointer to the UART information structure.
15439234622SPrasad Kummari * @node: Node address in the device tree.
15539234622SPrasad Kummari * @dtb: Address of the Device Tree Blob(DTB).
15639234622SPrasad Kummari *
157d2e00eeaSMaheedhar Bollapalli * Return: On success, it returns 0; on failure, it returns -1 or -FDT_ERR_NOTFOUND.
15839234622SPrasad Kummari */
fdt_add_uart_info(dt_uart_info_t * info,int node,void * dtb)159d2e00eeaSMaheedhar Bollapalli static int32_t fdt_add_uart_info(dt_uart_info_t *info, int node, void *dtb)
16039234622SPrasad Kummari {
16139234622SPrasad Kummari uintptr_t base_addr;
16239234622SPrasad Kummari const char *com;
1638eb6a1daSPrasad Kummari int32_t ret = 0;
164d2e00eeaSMaheedhar Bollapalli uint32_t status;
16539234622SPrasad Kummari
16639234622SPrasad Kummari com = fdt_getprop(dtb, node, "compatible", NULL);
16739234622SPrasad Kummari if (com != NULL) {
16839234622SPrasad Kummari strlcpy(info->compatible, com, sizeof(info->compatible));
16939234622SPrasad Kummari } else {
17039234622SPrasad Kummari ERROR("Compatible property not found in DTB node\n");
17139234622SPrasad Kummari ret = -FDT_ERR_NOTFOUND;
17239234622SPrasad Kummari goto error;
17339234622SPrasad Kummari }
17439234622SPrasad Kummari
175d2e00eeaSMaheedhar Bollapalli status = get_node_status(dtb, node);
176d2e00eeaSMaheedhar Bollapalli if (status == 0) {
177d989229bSPrasad Kummari ERROR("Uart node is disabled in DTB\n");
178d989229bSPrasad Kummari ret = -FDT_ERR_NOTFOUND;
179d989229bSPrasad Kummari goto error;
180d989229bSPrasad Kummari }
181d989229bSPrasad Kummari
182d989229bSPrasad Kummari if (strncmp(info->compatible, DT_UART_DCC_COMPAT, strlen(DT_UART_DCC_COMPAT)) != 0) {
18339234622SPrasad Kummari ret = fdt_get_reg_props_by_index(dtb, node, 0, &base_addr, NULL);
18439234622SPrasad Kummari if (ret >= 0) {
18539234622SPrasad Kummari info->base = base_addr;
18639234622SPrasad Kummari } else {
18739234622SPrasad Kummari ERROR("Failed to retrieve base address. Error code: %d\n", ret);
18839234622SPrasad Kummari ret = -FDT_ERR_NOTFOUND;
18939234622SPrasad Kummari goto error;
19039234622SPrasad Kummari }
19139234622SPrasad Kummari
19239234622SPrasad Kummari info->baud_rate = get_baudrate(dtb);
193d2e00eeaSMaheedhar Bollapalli
194d2e00eeaSMaheedhar Bollapalli if (strncmp(info->compatible, DT_UART_CAD_COMPAT,
195d2e00eeaSMaheedhar Bollapalli strlen(DT_UART_CAD_COMPAT)) == 0) {
196d2e00eeaSMaheedhar Bollapalli info->console_type = CONSOLE_CDNS;
197d2e00eeaSMaheedhar Bollapalli } else if (strncmp(info->compatible, DT_UART_PL011_COMPAT,
198d2e00eeaSMaheedhar Bollapalli strlen(DT_UART_PL011_COMPAT)) == 0) {
199d2e00eeaSMaheedhar Bollapalli info->console_type = CONSOLE_PL011;
200d2e00eeaSMaheedhar Bollapalli } else {
201d2e00eeaSMaheedhar Bollapalli ERROR("Incompatible uart node in DTB\n");
202d2e00eeaSMaheedhar Bollapalli ret = -FDT_ERR_NOTFOUND;
203d2e00eeaSMaheedhar Bollapalli }
204d2e00eeaSMaheedhar Bollapalli } else {
205d2e00eeaSMaheedhar Bollapalli info->console_type = CONSOLE_DCC;
206d989229bSPrasad Kummari }
20739234622SPrasad Kummari
20839234622SPrasad Kummari error:
20939234622SPrasad Kummari return ret;
21039234622SPrasad Kummari }
21139234622SPrasad Kummari
21239234622SPrasad Kummari /**
21339234622SPrasad Kummari * fdt_get_uart_info() - Get the uart information form DTB.
21439234622SPrasad Kummari * @info: Pointer to the UART information structure.
21539234622SPrasad Kummari *
21639234622SPrasad Kummari * Return: On success, it returns 0; on failure, it returns an error+reason.
21739234622SPrasad Kummari */
fdt_get_uart_info(dt_uart_info_t * info)21839234622SPrasad Kummari static int fdt_get_uart_info(dt_uart_info_t *info)
21939234622SPrasad Kummari {
2208eb6a1daSPrasad Kummari int node = 0, ret = 0;
221ea453871SMaheedhar Bollapalli void *dtb = (void *)plat_retrieve_dt_addr();
22239234622SPrasad Kummari
223e2d9dfe2SPrasad Kummari ret = is_valid_dtb(dtb);
22439234622SPrasad Kummari if (ret < 0) {
22539234622SPrasad Kummari ERROR("Invalid Device Tree at %p: error %d\n", dtb, ret);
22639234622SPrasad Kummari goto error;
22739234622SPrasad Kummari }
22839234622SPrasad Kummari
22939234622SPrasad Kummari node = fdt_get_stdout_node_offset(dtb);
23039234622SPrasad Kummari if (node < 0) {
23139234622SPrasad Kummari ERROR("DT get stdout node failed : %d\n", node);
23239234622SPrasad Kummari goto error;
23339234622SPrasad Kummari }
23439234622SPrasad Kummari
23539234622SPrasad Kummari ret = fdt_add_uart_info(info, node, dtb);
23639234622SPrasad Kummari if (ret < 0) {
23739234622SPrasad Kummari ERROR("Failed to add DT UART info: %d\n", ret);
23839234622SPrasad Kummari goto error;
23939234622SPrasad Kummari }
24039234622SPrasad Kummari
24139234622SPrasad Kummari error:
24239234622SPrasad Kummari return ret;
24339234622SPrasad Kummari }
24439234622SPrasad Kummari #endif
24539234622SPrasad Kummari
setup_console(void)24639234622SPrasad Kummari void setup_console(void)
24739234622SPrasad Kummari {
248d2e00eeaSMaheedhar Bollapalli /* This is hardcoded console setup just in case that DTB console fails */
249d2e00eeaSMaheedhar Bollapalli boot_hd_console.base = (uintptr_t)UART_BASE;
250d2e00eeaSMaheedhar Bollapalli boot_hd_console.baud_rate = (uint32_t)UART_BAUDRATE;
251d2e00eeaSMaheedhar Bollapalli boot_hd_console.clk = get_uart_clk();
252d2e00eeaSMaheedhar Bollapalli boot_hd_console.console_scope = CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH;
253d2e00eeaSMaheedhar Bollapalli boot_hd_console.console_type = UART_TYPE;
25439234622SPrasad Kummari
255d2e00eeaSMaheedhar Bollapalli /* For DT code decoding uncomment console registration below */
256d2e00eeaSMaheedhar Bollapalli /* register_console(&boot_hd_console, &boot_console); */
257d2e00eeaSMaheedhar Bollapalli
2584c5cf47fSMaheedhar Bollapalli #if ((CONSOLE_IS(dtb) || RT_CONSOLE_IS(dtb)) && (XLNX_DT_CFG == 1))
259d2e00eeaSMaheedhar Bollapalli /* Parse DTB console for UART information */
260d2e00eeaSMaheedhar Bollapalli if (fdt_get_uart_info(&dt_uart_info) == 0) {
261d2e00eeaSMaheedhar Bollapalli if (CONSOLE_IS(dtb)) {
262d2e00eeaSMaheedhar Bollapalli boot_hd_console.base = dt_uart_info.base;
263d2e00eeaSMaheedhar Bollapalli boot_hd_console.baud_rate = dt_uart_info.baud_rate;
264d2e00eeaSMaheedhar Bollapalli boot_hd_console.console_type = dt_uart_info.console_type;
265d2e00eeaSMaheedhar Bollapalli }
26609a02ce0SPrasad Kummari } else {
267d2e00eeaSMaheedhar Bollapalli ERROR("Failed to initialize DT console or console node is disabled\n");
26809a02ce0SPrasad Kummari }
26909a02ce0SPrasad Kummari #endif
27009a02ce0SPrasad Kummari
271d2e00eeaSMaheedhar Bollapalli /* Initialize the boot console */
272d2e00eeaSMaheedhar Bollapalli register_console(&boot_hd_console, &boot_console);
27339234622SPrasad Kummari
274cca2b865SMichal Simek INFO("BL31: Early console setup\n");
27539234622SPrasad Kummari
276cca2b865SMichal Simek #ifdef CONSOLE_RUNTIME
277cca2b865SMichal Simek rt_hd_console.base = (uintptr_t)RT_UART_BASE;
278cca2b865SMichal Simek rt_hd_console.baud_rate = (uint32_t)UART_BAUDRATE;
279cca2b865SMichal Simek rt_hd_console.console_type = RT_UART_TYPE;
280*0791be88SMaheedhar Bollapalli
281*0791be88SMaheedhar Bollapalli #if (RT_CONSOLE_IS(dtb) && (XLNX_DT_CFG == 1))
282*0791be88SMaheedhar Bollapalli if (dt_uart_info.base != 0U) {
283*0791be88SMaheedhar Bollapalli rt_hd_console.base = dt_uart_info.base;
284*0791be88SMaheedhar Bollapalli rt_hd_console.baud_rate = dt_uart_info.baud_rate;
285*0791be88SMaheedhar Bollapalli rt_hd_console.console_type = dt_uart_info.console_type;
286*0791be88SMaheedhar Bollapalli }
287cca2b865SMichal Simek #endif
288cca2b865SMichal Simek
289cca2b865SMichal Simek if ((rt_hd_console.console_type == boot_hd_console.console_type) &&
290cca2b865SMichal Simek (rt_hd_console.base == boot_hd_console.base)) {
291cca2b865SMichal Simek console_set_scope(&boot_console,
292cca2b865SMichal Simek CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH | CONSOLE_FLAG_RUNTIME);
293cca2b865SMichal Simek INFO("Successfully initialized runtime console\n");
294cca2b865SMichal Simek } else {
295cca2b865SMichal Simek rt_hd_console.clk = get_uart_clk();
296cca2b865SMichal Simek rt_hd_console.console_scope = CONSOLE_FLAG_RUNTIME;
297cca2b865SMichal Simek
298cca2b865SMichal Simek register_console(&rt_hd_console, &runtime_console);
299cca2b865SMichal Simek INFO("Successfully initialized new runtime console\n");
30039234622SPrasad Kummari }
30139234622SPrasad Kummari #endif
30239234622SPrasad Kummari }
3036d413983SMichal Simek #else
setup_console(void)3046d413983SMichal Simek void setup_console(void)
3056d413983SMichal Simek {
3066d413983SMichal Simek }
3076d413983SMichal Simek #endif
308