xref: /rk3399_ARM-atf/plat/xilinx/common/plat_console.c (revision 7a6230c18c700e676fd3bcfa0d6423f42f47e67a)
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