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