xref: /optee_os/core/kernel/console.c (revision 1bb929836182ecb96d2d9d268daa807c67596396)
1*1bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2756aea59SJerome Forissier /*
3756aea59SJerome Forissier  * Copyright (c) 2017, Linaro Limited
4756aea59SJerome Forissier  * All rights reserved.
5756aea59SJerome Forissier  *
6756aea59SJerome Forissier  * Redistribution and use in source and binary forms, with or without
7756aea59SJerome Forissier  * modification, are permitted provided that the following conditions are met:
8756aea59SJerome Forissier  *
9756aea59SJerome Forissier  * 1. Redistributions of source code must retain the above copyright notice,
10756aea59SJerome Forissier  * this list of conditions and the following disclaimer.
11756aea59SJerome Forissier  *
12756aea59SJerome Forissier  * 2. Redistributions in binary form must reproduce the above copyright notice,
13756aea59SJerome Forissier  * this list of conditions and the following disclaimer in the documentation
14756aea59SJerome Forissier  * and/or other materials provided with the distribution.
15756aea59SJerome Forissier  *
16756aea59SJerome Forissier  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17756aea59SJerome Forissier  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18756aea59SJerome Forissier  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19756aea59SJerome Forissier  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20756aea59SJerome Forissier  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21756aea59SJerome Forissier  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22756aea59SJerome Forissier  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23756aea59SJerome Forissier  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24756aea59SJerome Forissier  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25756aea59SJerome Forissier  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26756aea59SJerome Forissier  * POSSIBILITY OF SUCH DAMAGE.
27756aea59SJerome Forissier  */
28756aea59SJerome Forissier 
29756aea59SJerome Forissier #include <console.h>
30756aea59SJerome Forissier #include <compiler.h>
31756aea59SJerome Forissier #include <drivers/serial.h>
324dc31c52SJerome Forissier #include <kernel/panic.h>
33756aea59SJerome Forissier #include <stdlib.h>
344dc31c52SJerome Forissier #include <string.h>
354dc31c52SJerome Forissier 
364dc31c52SJerome Forissier #ifdef CFG_DT
374dc31c52SJerome Forissier #include <kernel/dt.h>
384dc31c52SJerome Forissier #include <libfdt.h>
394dc31c52SJerome Forissier #endif
40756aea59SJerome Forissier 
4123660121SJerome Forissier static struct serial_chip *serial_console;
42756aea59SJerome Forissier 
43756aea59SJerome Forissier void __weak console_putc(int ch)
44756aea59SJerome Forissier {
45756aea59SJerome Forissier 	if (!serial_console)
46756aea59SJerome Forissier 		return;
47756aea59SJerome Forissier 
48756aea59SJerome Forissier 	if (ch == '\n')
49756aea59SJerome Forissier 		serial_console->ops->putc(serial_console, '\r');
50756aea59SJerome Forissier 	serial_console->ops->putc(serial_console, ch);
51756aea59SJerome Forissier }
52756aea59SJerome Forissier 
53756aea59SJerome Forissier void __weak console_flush(void)
54756aea59SJerome Forissier {
55756aea59SJerome Forissier 	if (!serial_console)
56756aea59SJerome Forissier 		return;
57756aea59SJerome Forissier 
58756aea59SJerome Forissier 	serial_console->ops->flush(serial_console);
59756aea59SJerome Forissier }
60756aea59SJerome Forissier 
61756aea59SJerome Forissier void register_serial_console(struct serial_chip *chip)
62756aea59SJerome Forissier {
63756aea59SJerome Forissier 	serial_console = chip;
64756aea59SJerome Forissier }
654dc31c52SJerome Forissier 
664dc31c52SJerome Forissier #ifdef CFG_DT
674dc31c52SJerome Forissier 
684dc31c52SJerome Forissier /*
694dc31c52SJerome Forissier  * Check if the /secure-chosen node in the DT contains an stdout-path value
704dc31c52SJerome Forissier  * for which we have a compatible driver. If so, switch the console to
714dc31c52SJerome Forissier  * this device.
724dc31c52SJerome Forissier  */
734dc31c52SJerome Forissier void configure_console_from_dt(unsigned long phys_fdt)
744dc31c52SJerome Forissier {
754dc31c52SJerome Forissier 	const struct dt_driver *dt_drv;
764dc31c52SJerome Forissier 	const struct serial_driver *sdrv;
774dc31c52SJerome Forissier 	const struct fdt_property *prop;
784dc31c52SJerome Forissier 	struct serial_chip *dev;
794dc31c52SJerome Forissier 	char *stdout_data;
804dc31c52SJerome Forissier 	const char *uart;
814dc31c52SJerome Forissier 	const char *parms = NULL;
824dc31c52SJerome Forissier 	void *fdt;
834dc31c52SJerome Forissier 	int offs;
844dc31c52SJerome Forissier 	char *p;
854dc31c52SJerome Forissier 
864dc31c52SJerome Forissier 	if (!phys_fdt)
874dc31c52SJerome Forissier 		return;
884dc31c52SJerome Forissier 	fdt = phys_to_virt(phys_fdt, MEM_AREA_IO_NSEC);
894dc31c52SJerome Forissier 	if (!fdt)
904dc31c52SJerome Forissier 		panic();
914dc31c52SJerome Forissier 
924dc31c52SJerome Forissier 	offs = fdt_path_offset(fdt, "/secure-chosen");
934dc31c52SJerome Forissier 	if (offs < 0)
944dc31c52SJerome Forissier 		return;
954dc31c52SJerome Forissier 	prop = fdt_get_property(fdt, offs, "stdout-path", NULL);
964dc31c52SJerome Forissier 	if (!prop) {
974dc31c52SJerome Forissier 		/*
984dc31c52SJerome Forissier 		 * /secure-chosen node present but no stdout-path property
994dc31c52SJerome Forissier 		 * means we don't want any console output
1004dc31c52SJerome Forissier 		 */
1014dc31c52SJerome Forissier 		IMSG("Switching off console");
1024dc31c52SJerome Forissier 		register_serial_console(NULL);
1034dc31c52SJerome Forissier 		return;
1044dc31c52SJerome Forissier 	}
1054dc31c52SJerome Forissier 
1064dc31c52SJerome Forissier 	stdout_data = strdup(prop->data);
1074dc31c52SJerome Forissier 	if (!stdout_data)
1084dc31c52SJerome Forissier 		return;
1094dc31c52SJerome Forissier 	p = strchr(stdout_data, ':');
1104dc31c52SJerome Forissier 	if (p) {
1114dc31c52SJerome Forissier 		*p = '\0';
1124dc31c52SJerome Forissier 		parms = p + 1;
1134dc31c52SJerome Forissier 	}
1144dc31c52SJerome Forissier 
1154dc31c52SJerome Forissier 	/* stdout-path may refer to an alias */
1164dc31c52SJerome Forissier 	uart = fdt_get_alias(fdt, stdout_data);
1174dc31c52SJerome Forissier 	if (!uart) {
1184dc31c52SJerome Forissier 		/* Not an alias, assume we have a node path */
1194dc31c52SJerome Forissier 		uart = stdout_data;
1204dc31c52SJerome Forissier 	}
1214dc31c52SJerome Forissier 	offs = fdt_path_offset(fdt, uart);
1224dc31c52SJerome Forissier 	if (offs < 0)
1234dc31c52SJerome Forissier 		goto out;
1244dc31c52SJerome Forissier 
1254dc31c52SJerome Forissier 	dt_drv = dt_find_compatible_driver(fdt, offs);
1264dc31c52SJerome Forissier 	if (!dt_drv)
1274dc31c52SJerome Forissier 		goto out;
1284dc31c52SJerome Forissier 
1294dc31c52SJerome Forissier 	sdrv = (const struct serial_driver *)dt_drv->driver;
1304dc31c52SJerome Forissier 	if (!sdrv)
1314dc31c52SJerome Forissier 		goto out;
1324dc31c52SJerome Forissier 	dev = sdrv->dev_alloc();
1334dc31c52SJerome Forissier 	if (!dev)
1344dc31c52SJerome Forissier 		goto out;
1354dc31c52SJerome Forissier 	/*
1364dc31c52SJerome Forissier 	 * If the console is the same as the early console, dev_init() might
1374dc31c52SJerome Forissier 	 * clear pending data. Flush to avoid that.
1384dc31c52SJerome Forissier 	 */
1394dc31c52SJerome Forissier 	console_flush();
1404dc31c52SJerome Forissier 	if (sdrv->dev_init(dev, fdt, offs, parms) < 0) {
1414dc31c52SJerome Forissier 		sdrv->dev_free(dev);
1424dc31c52SJerome Forissier 		goto out;
1434dc31c52SJerome Forissier 	}
1444dc31c52SJerome Forissier 
1454dc31c52SJerome Forissier 	IMSG("Switching console to device: %s", uart);
1464dc31c52SJerome Forissier 	register_serial_console(dev);
1474dc31c52SJerome Forissier out:
1484dc31c52SJerome Forissier 	free(stdout_data);
1494dc31c52SJerome Forissier }
1504dc31c52SJerome Forissier 
1514dc31c52SJerome Forissier #endif /* CFG_DT */
152