xref: /optee_os/core/kernel/console.c (revision 4dc31c52544a7241e97d0452d512330ee30ed664)
1756aea59SJerome Forissier /*
2756aea59SJerome Forissier  * Copyright (c) 2017, Linaro Limited
3756aea59SJerome Forissier  * All rights reserved.
4756aea59SJerome Forissier  *
5756aea59SJerome Forissier  * Redistribution and use in source and binary forms, with or without
6756aea59SJerome Forissier  * modification, are permitted provided that the following conditions are met:
7756aea59SJerome Forissier  *
8756aea59SJerome Forissier  * 1. Redistributions of source code must retain the above copyright notice,
9756aea59SJerome Forissier  * this list of conditions and the following disclaimer.
10756aea59SJerome Forissier  *
11756aea59SJerome Forissier  * 2. Redistributions in binary form must reproduce the above copyright notice,
12756aea59SJerome Forissier  * this list of conditions and the following disclaimer in the documentation
13756aea59SJerome Forissier  * and/or other materials provided with the distribution.
14756aea59SJerome Forissier  *
15756aea59SJerome Forissier  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16756aea59SJerome Forissier  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17756aea59SJerome Forissier  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18756aea59SJerome Forissier  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19756aea59SJerome Forissier  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20756aea59SJerome Forissier  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21756aea59SJerome Forissier  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22756aea59SJerome Forissier  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23756aea59SJerome Forissier  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24756aea59SJerome Forissier  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25756aea59SJerome Forissier  * POSSIBILITY OF SUCH DAMAGE.
26756aea59SJerome Forissier  */
27756aea59SJerome Forissier 
28756aea59SJerome Forissier #include <console.h>
29756aea59SJerome Forissier #include <compiler.h>
30756aea59SJerome Forissier #include <drivers/serial.h>
31*4dc31c52SJerome Forissier #include <kernel/panic.h>
32756aea59SJerome Forissier #include <stdlib.h>
33*4dc31c52SJerome Forissier #include <string.h>
34*4dc31c52SJerome Forissier 
35*4dc31c52SJerome Forissier #ifdef CFG_DT
36*4dc31c52SJerome Forissier #include <kernel/dt.h>
37*4dc31c52SJerome Forissier #include <libfdt.h>
38*4dc31c52SJerome Forissier #endif
39756aea59SJerome Forissier 
40756aea59SJerome Forissier static struct serial_chip *serial_console __early_bss;
41756aea59SJerome Forissier 
42756aea59SJerome Forissier void __weak console_putc(int ch)
43756aea59SJerome Forissier {
44756aea59SJerome Forissier 	if (!serial_console)
45756aea59SJerome Forissier 		return;
46756aea59SJerome Forissier 
47756aea59SJerome Forissier 	if (ch == '\n')
48756aea59SJerome Forissier 		serial_console->ops->putc(serial_console, '\r');
49756aea59SJerome Forissier 	serial_console->ops->putc(serial_console, ch);
50756aea59SJerome Forissier }
51756aea59SJerome Forissier 
52756aea59SJerome Forissier void __weak console_flush(void)
53756aea59SJerome Forissier {
54756aea59SJerome Forissier 	if (!serial_console)
55756aea59SJerome Forissier 		return;
56756aea59SJerome Forissier 
57756aea59SJerome Forissier 	serial_console->ops->flush(serial_console);
58756aea59SJerome Forissier }
59756aea59SJerome Forissier 
60756aea59SJerome Forissier void register_serial_console(struct serial_chip *chip)
61756aea59SJerome Forissier {
62756aea59SJerome Forissier 	serial_console = chip;
63756aea59SJerome Forissier }
64*4dc31c52SJerome Forissier 
65*4dc31c52SJerome Forissier #ifdef CFG_DT
66*4dc31c52SJerome Forissier 
67*4dc31c52SJerome Forissier /*
68*4dc31c52SJerome Forissier  * Check if the /secure-chosen node in the DT contains an stdout-path value
69*4dc31c52SJerome Forissier  * for which we have a compatible driver. If so, switch the console to
70*4dc31c52SJerome Forissier  * this device.
71*4dc31c52SJerome Forissier  */
72*4dc31c52SJerome Forissier void configure_console_from_dt(unsigned long phys_fdt)
73*4dc31c52SJerome Forissier {
74*4dc31c52SJerome Forissier 	const struct dt_driver *dt_drv;
75*4dc31c52SJerome Forissier 	const struct serial_driver *sdrv;
76*4dc31c52SJerome Forissier 	const struct fdt_property *prop;
77*4dc31c52SJerome Forissier 	struct serial_chip *dev;
78*4dc31c52SJerome Forissier 	char *stdout_data;
79*4dc31c52SJerome Forissier 	const char *uart;
80*4dc31c52SJerome Forissier 	const char *parms = NULL;
81*4dc31c52SJerome Forissier 	void *fdt;
82*4dc31c52SJerome Forissier 	int offs;
83*4dc31c52SJerome Forissier 	char *p;
84*4dc31c52SJerome Forissier 
85*4dc31c52SJerome Forissier 	if (!phys_fdt)
86*4dc31c52SJerome Forissier 		return;
87*4dc31c52SJerome Forissier 	fdt = phys_to_virt(phys_fdt, MEM_AREA_IO_NSEC);
88*4dc31c52SJerome Forissier 	if (!fdt)
89*4dc31c52SJerome Forissier 		panic();
90*4dc31c52SJerome Forissier 
91*4dc31c52SJerome Forissier 	offs = fdt_path_offset(fdt, "/secure-chosen");
92*4dc31c52SJerome Forissier 	if (offs < 0)
93*4dc31c52SJerome Forissier 		return;
94*4dc31c52SJerome Forissier 	prop = fdt_get_property(fdt, offs, "stdout-path", NULL);
95*4dc31c52SJerome Forissier 	if (!prop) {
96*4dc31c52SJerome Forissier 		/*
97*4dc31c52SJerome Forissier 		 * /secure-chosen node present but no stdout-path property
98*4dc31c52SJerome Forissier 		 * means we don't want any console output
99*4dc31c52SJerome Forissier 		 */
100*4dc31c52SJerome Forissier 		IMSG("Switching off console");
101*4dc31c52SJerome Forissier 		register_serial_console(NULL);
102*4dc31c52SJerome Forissier 		return;
103*4dc31c52SJerome Forissier 	}
104*4dc31c52SJerome Forissier 
105*4dc31c52SJerome Forissier 	stdout_data = strdup(prop->data);
106*4dc31c52SJerome Forissier 	if (!stdout_data)
107*4dc31c52SJerome Forissier 		return;
108*4dc31c52SJerome Forissier 	p = strchr(stdout_data, ':');
109*4dc31c52SJerome Forissier 	if (p) {
110*4dc31c52SJerome Forissier 		*p = '\0';
111*4dc31c52SJerome Forissier 		parms = p + 1;
112*4dc31c52SJerome Forissier 	}
113*4dc31c52SJerome Forissier 
114*4dc31c52SJerome Forissier 	/* stdout-path may refer to an alias */
115*4dc31c52SJerome Forissier 	uart = fdt_get_alias(fdt, stdout_data);
116*4dc31c52SJerome Forissier 	if (!uart) {
117*4dc31c52SJerome Forissier 		/* Not an alias, assume we have a node path */
118*4dc31c52SJerome Forissier 		uart = stdout_data;
119*4dc31c52SJerome Forissier 	}
120*4dc31c52SJerome Forissier 	offs = fdt_path_offset(fdt, uart);
121*4dc31c52SJerome Forissier 	if (offs < 0)
122*4dc31c52SJerome Forissier 		goto out;
123*4dc31c52SJerome Forissier 
124*4dc31c52SJerome Forissier 	dt_drv = dt_find_compatible_driver(fdt, offs);
125*4dc31c52SJerome Forissier 	if (!dt_drv)
126*4dc31c52SJerome Forissier 		goto out;
127*4dc31c52SJerome Forissier 
128*4dc31c52SJerome Forissier 	sdrv = (const struct serial_driver *)dt_drv->driver;
129*4dc31c52SJerome Forissier 	if (!sdrv)
130*4dc31c52SJerome Forissier 		goto out;
131*4dc31c52SJerome Forissier 	dev = sdrv->dev_alloc();
132*4dc31c52SJerome Forissier 	if (!dev)
133*4dc31c52SJerome Forissier 		goto out;
134*4dc31c52SJerome Forissier 	/*
135*4dc31c52SJerome Forissier 	 * If the console is the same as the early console, dev_init() might
136*4dc31c52SJerome Forissier 	 * clear pending data. Flush to avoid that.
137*4dc31c52SJerome Forissier 	 */
138*4dc31c52SJerome Forissier 	console_flush();
139*4dc31c52SJerome Forissier 	if (sdrv->dev_init(dev, fdt, offs, parms) < 0) {
140*4dc31c52SJerome Forissier 		sdrv->dev_free(dev);
141*4dc31c52SJerome Forissier 		goto out;
142*4dc31c52SJerome Forissier 	}
143*4dc31c52SJerome Forissier 
144*4dc31c52SJerome Forissier 	IMSG("Switching console to device: %s", uart);
145*4dc31c52SJerome Forissier 	register_serial_console(dev);
146*4dc31c52SJerome Forissier out:
147*4dc31c52SJerome Forissier 	free(stdout_data);
148*4dc31c52SJerome Forissier }
149*4dc31c52SJerome Forissier 
150*4dc31c52SJerome Forissier #endif /* CFG_DT */
151