xref: /rk3399_ARM-atf/plat/xilinx/common/plat_console.c (revision ea453871ef70c116d40c950926c3c1a2c4036896)
139234622SPrasad Kummari /*
2*ea453871SMaheedhar 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 
34d2e00eeaSMaheedhar Bollapalli #if ((CONSOLE_IS(dtb) || RT_CONSOLE_IS(dtb)) && defined(XILINX_OF_BOARD_DTB_ADDR)) && \
3509a02ce0SPrasad Kummari 	(!defined(PLAT_zynqmp) || (defined(PLAT_zynqmp) && \
36d2e00eeaSMaheedhar Bollapalli 				   !IS_TFA_IN_OCM(BL31_BASE)))
37d2e00eeaSMaheedhar Bollapalli static dt_uart_info_t dt_uart_info;
38d2e00eeaSMaheedhar Bollapalli #endif
39d2e00eeaSMaheedhar Bollapalli 
404557ab69SPrasad Kummari /**
41d2e00eeaSMaheedhar Bollapalli  * register_console() - Registers the uart with console list.
42d2e00eeaSMaheedhar Bollapalli  * @consoleh: Console holder structure with UART base address,
43d2e00eeaSMaheedhar Bollapalli  *  UART clock, UART buad rate, flags & console type
444557ab69SPrasad Kummari  * @console: Pointer to the console information structure.
454557ab69SPrasad Kummari  */
46d2e00eeaSMaheedhar Bollapalli static void register_console(const console_holder *consoleh, console_t *console)
474557ab69SPrasad Kummari {
484557ab69SPrasad Kummari 	int32_t rc = 0;
494557ab69SPrasad Kummari 
50d2e00eeaSMaheedhar Bollapalli 	switch (consoleh->console_type) {
514557ab69SPrasad Kummari #if defined(PLAT_zynqmp)
52d2e00eeaSMaheedhar Bollapalli 	case CONSOLE_CDNS:
53d2e00eeaSMaheedhar Bollapalli 		rc = console_cdns_register(consoleh->base,
54d2e00eeaSMaheedhar Bollapalli 				consoleh->clk,
55d2e00eeaSMaheedhar Bollapalli 				consoleh->baud_rate,
564557ab69SPrasad Kummari 				console);
57d2e00eeaSMaheedhar Bollapalli 		break;
58d2e00eeaSMaheedhar Bollapalli #else
59d2e00eeaSMaheedhar Bollapalli 	case CONSOLE_PL011:
60d2e00eeaSMaheedhar Bollapalli 		rc = console_pl011_register(consoleh->base,
61d2e00eeaSMaheedhar Bollapalli 				consoleh->clk,
62d2e00eeaSMaheedhar Bollapalli 				consoleh->baud_rate,
634557ab69SPrasad Kummari 				console);
64d2e00eeaSMaheedhar Bollapalli 		break;
654557ab69SPrasad Kummari #endif
66d2e00eeaSMaheedhar Bollapalli 	case CONSOLE_DCC:
674557ab69SPrasad Kummari 		rc = console_dcc_register(console);
68d2e00eeaSMaheedhar Bollapalli 		break;
69d2e00eeaSMaheedhar Bollapalli 	default:
704557ab69SPrasad Kummari 		INFO("Invalid console type\n");
71d2e00eeaSMaheedhar Bollapalli 		break;
724557ab69SPrasad Kummari 	}
734557ab69SPrasad Kummari 
744557ab69SPrasad Kummari 	if (rc == 0) {
754557ab69SPrasad Kummari 		panic();
764557ab69SPrasad Kummari 	}
774557ab69SPrasad Kummari 
78d2e00eeaSMaheedhar Bollapalli 	console_set_scope(console, consoleh->console_scope);
794557ab69SPrasad Kummari }
804557ab69SPrasad Kummari 
81d2e00eeaSMaheedhar Bollapalli #if ((CONSOLE_IS(dtb) || RT_CONSOLE_IS(dtb)) && defined(XILINX_OF_BOARD_DTB_ADDR)) && \
8209a02ce0SPrasad Kummari 	(!defined(PLAT_zynqmp) || (defined(PLAT_zynqmp) && \
8309a02ce0SPrasad Kummari 				   !IS_TFA_IN_OCM(BL31_BASE)))
8439234622SPrasad Kummari /**
8539234622SPrasad Kummari  * get_baudrate() - Get the baudrate form DTB.
8639234622SPrasad Kummari  * @dtb: Address of the Device Tree Blob (DTB).
8739234622SPrasad Kummari  *
8839234622SPrasad Kummari  * Return: On success returns the baudrate; on failure returns an error.
8939234622SPrasad Kummari  */
9039234622SPrasad Kummari static int32_t get_baudrate(void *dtb)
9139234622SPrasad Kummari {
9239234622SPrasad Kummari 	int node;
9339234622SPrasad Kummari 	int32_t ret = 0;
9439234622SPrasad Kummari 	const char *prop, *path;
9539234622SPrasad Kummari 	char *end;
9639234622SPrasad Kummari 	int32_t baud_rate = 0;
9739234622SPrasad Kummari 
9839234622SPrasad Kummari 	node = fdt_path_offset(dtb, "/secure-chosen");
9939234622SPrasad Kummari 	if (node < 0) {
10039234622SPrasad Kummari 		node = fdt_path_offset(dtb, "/chosen");
10139234622SPrasad Kummari 		if (node < 0) {
10239234622SPrasad Kummari 			ret = -FDT_ERR_NOTFOUND;
10339234622SPrasad Kummari 			goto error;
10439234622SPrasad Kummari 		}
10539234622SPrasad Kummari 	}
10639234622SPrasad Kummari 
10739234622SPrasad Kummari 	prop = fdt_getprop(dtb, node, "stdout-path", NULL);
10839234622SPrasad Kummari 	if (prop == NULL) {
10939234622SPrasad Kummari 		ret = -FDT_ERR_NOTFOUND;
11039234622SPrasad Kummari 		goto error;
11139234622SPrasad Kummari 	}
11239234622SPrasad Kummari 
11339234622SPrasad Kummari 	/* Parse string serial0:115200n8 */
11439234622SPrasad Kummari 	path = strchr(prop, ':');
11539234622SPrasad Kummari 	if (!path) {
11639234622SPrasad Kummari 		ret = -FDT_ERR_NOTFOUND;
11739234622SPrasad Kummari 		goto error;
11839234622SPrasad Kummari 	} else {
11939234622SPrasad Kummari 
12039234622SPrasad Kummari 		baud_rate = strtoul(path + 1, &end, 10);
12139234622SPrasad Kummari 		if (baud_rate == 0 && end == path) {
12239234622SPrasad Kummari 			ERROR("Conversion error occurred: %d\n", baud_rate);
12339234622SPrasad Kummari 			ret = -FDT_ERR_NOTFOUND;
12439234622SPrasad Kummari 			goto error;
12539234622SPrasad Kummari 		}
12639234622SPrasad Kummari 		ret = baud_rate;
12739234622SPrasad Kummari 	}
12839234622SPrasad Kummari 
12939234622SPrasad Kummari error:
13039234622SPrasad Kummari 	return ret;
13139234622SPrasad Kummari }
13239234622SPrasad Kummari 
13339234622SPrasad Kummari /**
13439234622SPrasad Kummari  * get_node_status() - Get the DTB node status.
13539234622SPrasad Kummari  * @dtb: Address of the Device Tree Blob (DTB).
13639234622SPrasad Kummari  * @node: Node address in the device tree.
13739234622SPrasad Kummari  *
13839234622SPrasad Kummari  * Return: On success, it returns 1; on failure, it returns an 0.
13939234622SPrasad Kummari  */
14039234622SPrasad Kummari static uint32_t get_node_status(void *dtb, int node)
14139234622SPrasad Kummari {
14239234622SPrasad Kummari 	const char *status_cell;
14339234622SPrasad Kummari 	uint32_t status = 0;
14439234622SPrasad Kummari 
14539234622SPrasad Kummari 	status_cell = fdt_getprop(dtb, node, "status", NULL);
14639234622SPrasad Kummari 	if (!status_cell || strcmp(status_cell, "okay") == 0) {
14739234622SPrasad Kummari 		status = 1;
14839234622SPrasad Kummari 	} else {
14939234622SPrasad Kummari 		status = 0;
15039234622SPrasad Kummari 	}
15139234622SPrasad Kummari 
15239234622SPrasad Kummari 	return status;
15339234622SPrasad Kummari }
15439234622SPrasad Kummari 
15539234622SPrasad Kummari /**
15639234622SPrasad Kummari  * fdt_add_uart_info() - Add DTB information to a UART structure.
15739234622SPrasad Kummari  * @info: Pointer to the UART information structure.
15839234622SPrasad Kummari  * @node: Node address in the device tree.
15939234622SPrasad Kummari  * @dtb: Address of the Device Tree Blob(DTB).
16039234622SPrasad Kummari  *
161d2e00eeaSMaheedhar Bollapalli  * Return: On success, it returns 0; on failure, it returns -1 or -FDT_ERR_NOTFOUND.
16239234622SPrasad Kummari  */
163d2e00eeaSMaheedhar Bollapalli static int32_t fdt_add_uart_info(dt_uart_info_t *info, int node, void *dtb)
16439234622SPrasad Kummari {
16539234622SPrasad Kummari 	uintptr_t base_addr;
16639234622SPrasad Kummari 	const char *com;
1678eb6a1daSPrasad Kummari 	int32_t ret = 0;
168d2e00eeaSMaheedhar Bollapalli 	uint32_t status;
16939234622SPrasad Kummari 
17039234622SPrasad Kummari 	com = fdt_getprop(dtb, node, "compatible", NULL);
17139234622SPrasad Kummari 	if (com != NULL) {
17239234622SPrasad Kummari 		strlcpy(info->compatible, com, sizeof(info->compatible));
17339234622SPrasad Kummari 	} else {
17439234622SPrasad Kummari 		ERROR("Compatible property not found in DTB node\n");
17539234622SPrasad Kummari 		ret = -FDT_ERR_NOTFOUND;
17639234622SPrasad Kummari 		goto error;
17739234622SPrasad Kummari 	}
17839234622SPrasad Kummari 
179d2e00eeaSMaheedhar Bollapalli 	status = get_node_status(dtb, node);
180d2e00eeaSMaheedhar Bollapalli 	if (status == 0) {
181d989229bSPrasad Kummari 		ERROR("Uart node is disabled in DTB\n");
182d989229bSPrasad Kummari 		ret = -FDT_ERR_NOTFOUND;
183d989229bSPrasad Kummari 		goto error;
184d989229bSPrasad Kummari 	}
185d989229bSPrasad Kummari 
186d989229bSPrasad Kummari 	if (strncmp(info->compatible, DT_UART_DCC_COMPAT, strlen(DT_UART_DCC_COMPAT)) != 0) {
18739234622SPrasad Kummari 		ret = fdt_get_reg_props_by_index(dtb, node, 0, &base_addr, NULL);
18839234622SPrasad Kummari 		if (ret >= 0) {
18939234622SPrasad Kummari 			info->base = base_addr;
19039234622SPrasad Kummari 		} else {
19139234622SPrasad Kummari 			ERROR("Failed to retrieve base address. Error code: %d\n", ret);
19239234622SPrasad Kummari 			ret = -FDT_ERR_NOTFOUND;
19339234622SPrasad Kummari 			goto error;
19439234622SPrasad Kummari 		}
19539234622SPrasad Kummari 
19639234622SPrasad Kummari 		info->baud_rate = get_baudrate(dtb);
197d2e00eeaSMaheedhar Bollapalli 
198d2e00eeaSMaheedhar Bollapalli 		if (strncmp(info->compatible, DT_UART_CAD_COMPAT,
199d2e00eeaSMaheedhar Bollapalli 					strlen(DT_UART_CAD_COMPAT)) == 0) {
200d2e00eeaSMaheedhar Bollapalli 			info->console_type = CONSOLE_CDNS;
201d2e00eeaSMaheedhar Bollapalli 		} else if (strncmp(info->compatible, DT_UART_PL011_COMPAT,
202d2e00eeaSMaheedhar Bollapalli 					strlen(DT_UART_PL011_COMPAT)) == 0) {
203d2e00eeaSMaheedhar Bollapalli 			info->console_type = CONSOLE_PL011;
204d2e00eeaSMaheedhar Bollapalli 		} else {
205d2e00eeaSMaheedhar Bollapalli 			ERROR("Incompatible uart node in DTB\n");
206d2e00eeaSMaheedhar Bollapalli 			ret = -FDT_ERR_NOTFOUND;
207d2e00eeaSMaheedhar Bollapalli 		}
208d2e00eeaSMaheedhar Bollapalli 	} else {
209d2e00eeaSMaheedhar Bollapalli 		info->console_type = CONSOLE_DCC;
210d989229bSPrasad Kummari 	}
21139234622SPrasad Kummari 
21239234622SPrasad Kummari error:
21339234622SPrasad Kummari 	return ret;
21439234622SPrasad Kummari }
21539234622SPrasad Kummari 
21639234622SPrasad Kummari /**
21739234622SPrasad Kummari  * fdt_get_uart_info() - Get the uart information form DTB.
21839234622SPrasad Kummari  * @info: Pointer to the UART information structure.
21939234622SPrasad Kummari  *
22039234622SPrasad Kummari  * Return: On success, it returns 0; on failure, it returns an error+reason.
22139234622SPrasad Kummari  */
22239234622SPrasad Kummari static int fdt_get_uart_info(dt_uart_info_t *info)
22339234622SPrasad Kummari {
2248eb6a1daSPrasad Kummari 	int node = 0, ret = 0;
225*ea453871SMaheedhar Bollapalli 	void *dtb = (void *)plat_retrieve_dt_addr();
22639234622SPrasad Kummari 
227e2d9dfe2SPrasad Kummari 	ret = is_valid_dtb(dtb);
22839234622SPrasad Kummari 	if (ret < 0) {
22939234622SPrasad Kummari 		ERROR("Invalid Device Tree at %p: error %d\n", dtb, ret);
23039234622SPrasad Kummari 		goto error;
23139234622SPrasad Kummari 	}
23239234622SPrasad Kummari 
23339234622SPrasad Kummari 	node = fdt_get_stdout_node_offset(dtb);
23439234622SPrasad Kummari 	if (node < 0) {
23539234622SPrasad Kummari 		ERROR("DT get stdout node failed : %d\n", node);
23639234622SPrasad Kummari 		goto error;
23739234622SPrasad Kummari 	}
23839234622SPrasad Kummari 
23939234622SPrasad Kummari 	ret = fdt_add_uart_info(info, node, dtb);
24039234622SPrasad Kummari 	if (ret < 0) {
24139234622SPrasad Kummari 		ERROR("Failed to add DT UART info: %d\n", ret);
24239234622SPrasad Kummari 		goto error;
24339234622SPrasad Kummari 	}
24439234622SPrasad Kummari 
24539234622SPrasad Kummari error:
24639234622SPrasad Kummari 	return ret;
24739234622SPrasad Kummari }
24839234622SPrasad Kummari #endif
24939234622SPrasad Kummari 
25039234622SPrasad Kummari void setup_console(void)
25139234622SPrasad Kummari {
252d2e00eeaSMaheedhar Bollapalli 	/* This is hardcoded console setup just in case that DTB console fails */
253d2e00eeaSMaheedhar Bollapalli 	boot_hd_console.base = (uintptr_t)UART_BASE;
254d2e00eeaSMaheedhar Bollapalli 	boot_hd_console.baud_rate = (uint32_t)UART_BAUDRATE;
255d2e00eeaSMaheedhar Bollapalli 	boot_hd_console.clk = get_uart_clk();
256d2e00eeaSMaheedhar Bollapalli 	boot_hd_console.console_scope = CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH;
257d2e00eeaSMaheedhar Bollapalli 	boot_hd_console.console_type = UART_TYPE;
25839234622SPrasad Kummari 
259d2e00eeaSMaheedhar Bollapalli 	/* For DT code decoding uncomment console registration below */
260d2e00eeaSMaheedhar Bollapalli 	/* register_console(&boot_hd_console, &boot_console); */
261d2e00eeaSMaheedhar Bollapalli 
262d2e00eeaSMaheedhar Bollapalli #if ((CONSOLE_IS(dtb) || RT_CONSOLE_IS(dtb)) && defined(XILINX_OF_BOARD_DTB_ADDR)) && \
26309a02ce0SPrasad Kummari 	(!defined(PLAT_zynqmp) || (defined(PLAT_zynqmp) && \
26409a02ce0SPrasad Kummari 				   !IS_TFA_IN_OCM(BL31_BASE)))
265d2e00eeaSMaheedhar Bollapalli 	/* Parse DTB console for UART information  */
266d2e00eeaSMaheedhar Bollapalli 	if (fdt_get_uart_info(&dt_uart_info) == 0) {
267d2e00eeaSMaheedhar Bollapalli 		if (CONSOLE_IS(dtb)) {
268d2e00eeaSMaheedhar Bollapalli 			boot_hd_console.base = dt_uart_info.base;
269d2e00eeaSMaheedhar Bollapalli 			boot_hd_console.baud_rate = dt_uart_info.baud_rate;
270d2e00eeaSMaheedhar Bollapalli 			boot_hd_console.console_type = dt_uart_info.console_type;
271d2e00eeaSMaheedhar Bollapalli 		}
27209a02ce0SPrasad Kummari 	} else {
273d2e00eeaSMaheedhar Bollapalli 		ERROR("Failed to initialize DT console or console node is disabled\n");
27409a02ce0SPrasad Kummari 	}
27509a02ce0SPrasad Kummari #endif
27609a02ce0SPrasad Kummari 
277d2e00eeaSMaheedhar Bollapalli 	/* Initialize the boot console */
278d2e00eeaSMaheedhar Bollapalli 	register_console(&boot_hd_console, &boot_console);
27939234622SPrasad Kummari 
280cca2b865SMichal Simek 	INFO("BL31: Early console setup\n");
28139234622SPrasad Kummari 
282cca2b865SMichal Simek #ifdef CONSOLE_RUNTIME
283cca2b865SMichal Simek #if (RT_CONSOLE_IS(dtb) && defined(XILINX_OF_BOARD_DTB_ADDR)) && \
284cca2b865SMichal Simek 	       (!defined(PLAT_zynqmp) || (defined(PLAT_zynqmp) && \
285cca2b865SMichal Simek 					!IS_TFA_IN_OCM(BL31_BASE)))
286cca2b865SMichal Simek 	rt_hd_console.base = dt_uart_info.base;
287cca2b865SMichal Simek 	rt_hd_console.baud_rate = dt_uart_info.baud_rate;
288cca2b865SMichal Simek 	rt_hd_console.console_type = dt_uart_info.console_type;
289cca2b865SMichal Simek #else
290cca2b865SMichal Simek 	rt_hd_console.base = (uintptr_t)RT_UART_BASE;
291cca2b865SMichal Simek 	rt_hd_console.baud_rate = (uint32_t)UART_BAUDRATE;
292cca2b865SMichal Simek 	rt_hd_console.console_type = RT_UART_TYPE;
293cca2b865SMichal Simek #endif
294cca2b865SMichal Simek 
295cca2b865SMichal Simek 	if ((rt_hd_console.console_type == boot_hd_console.console_type) &&
296cca2b865SMichal Simek 			(rt_hd_console.base == boot_hd_console.base)) {
297cca2b865SMichal Simek 		console_set_scope(&boot_console,
298cca2b865SMichal Simek 				CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH | CONSOLE_FLAG_RUNTIME);
299cca2b865SMichal Simek 		INFO("Successfully initialized runtime console\n");
300cca2b865SMichal Simek 	} else {
301cca2b865SMichal Simek 		rt_hd_console.clk = get_uart_clk();
302cca2b865SMichal Simek 		rt_hd_console.console_scope = CONSOLE_FLAG_RUNTIME;
303cca2b865SMichal Simek 
304cca2b865SMichal Simek 		register_console(&rt_hd_console, &runtime_console);
305cca2b865SMichal Simek 		INFO("Successfully initialized new runtime console\n");
30639234622SPrasad Kummari 	}
30739234622SPrasad Kummari #endif
30839234622SPrasad Kummari }
3096d413983SMichal Simek #else
3106d413983SMichal Simek void setup_console(void)
3116d413983SMichal Simek {
3126d413983SMichal Simek }
3136d413983SMichal Simek #endif
314