xref: /arm-trusted-firmware/plat/xilinx/common/plat_console.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
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