xref: /optee_os/core/kernel/console.c (revision 2f82082fada310cd58bcb8145d677144e9bfccaa)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2756aea59SJerome Forissier /*
3756aea59SJerome Forissier  * Copyright (c) 2017, Linaro Limited
4756aea59SJerome Forissier  */
5756aea59SJerome Forissier 
6756aea59SJerome Forissier #include <console.h>
7756aea59SJerome Forissier #include <compiler.h>
8756aea59SJerome Forissier #include <drivers/serial.h>
9*2f82082fSEdison Ai #include <kernel/generic_boot.h>
104dc31c52SJerome Forissier #include <kernel/panic.h>
11756aea59SJerome Forissier #include <stdlib.h>
124dc31c52SJerome Forissier #include <string.h>
134dc31c52SJerome Forissier 
144dc31c52SJerome Forissier #ifdef CFG_DT
154dc31c52SJerome Forissier #include <kernel/dt.h>
164dc31c52SJerome Forissier #include <libfdt.h>
174dc31c52SJerome Forissier #endif
18756aea59SJerome Forissier 
1923660121SJerome Forissier static struct serial_chip *serial_console;
20756aea59SJerome Forissier 
21756aea59SJerome Forissier void __weak console_putc(int ch)
22756aea59SJerome Forissier {
23756aea59SJerome Forissier 	if (!serial_console)
24756aea59SJerome Forissier 		return;
25756aea59SJerome Forissier 
26756aea59SJerome Forissier 	if (ch == '\n')
27756aea59SJerome Forissier 		serial_console->ops->putc(serial_console, '\r');
28756aea59SJerome Forissier 	serial_console->ops->putc(serial_console, ch);
29756aea59SJerome Forissier }
30756aea59SJerome Forissier 
31756aea59SJerome Forissier void __weak console_flush(void)
32756aea59SJerome Forissier {
33756aea59SJerome Forissier 	if (!serial_console)
34756aea59SJerome Forissier 		return;
35756aea59SJerome Forissier 
36756aea59SJerome Forissier 	serial_console->ops->flush(serial_console);
37756aea59SJerome Forissier }
38756aea59SJerome Forissier 
39756aea59SJerome Forissier void register_serial_console(struct serial_chip *chip)
40756aea59SJerome Forissier {
41756aea59SJerome Forissier 	serial_console = chip;
42756aea59SJerome Forissier }
434dc31c52SJerome Forissier 
444dc31c52SJerome Forissier #ifdef CFG_DT
454dc31c52SJerome Forissier 
464dc31c52SJerome Forissier /*
474dc31c52SJerome Forissier  * Check if the /secure-chosen node in the DT contains an stdout-path value
484dc31c52SJerome Forissier  * for which we have a compatible driver. If so, switch the console to
494dc31c52SJerome Forissier  * this device.
504dc31c52SJerome Forissier  */
51*2f82082fSEdison Ai void configure_console_from_dt(void)
524dc31c52SJerome Forissier {
534dc31c52SJerome Forissier 	const struct dt_driver *dt_drv;
544dc31c52SJerome Forissier 	const struct serial_driver *sdrv;
554dc31c52SJerome Forissier 	const struct fdt_property *prop;
564dc31c52SJerome Forissier 	struct serial_chip *dev;
574dc31c52SJerome Forissier 	char *stdout_data;
584dc31c52SJerome Forissier 	const char *uart;
594dc31c52SJerome Forissier 	const char *parms = NULL;
60*2f82082fSEdison Ai 	void *fdt = get_dt_blob();
614dc31c52SJerome Forissier 	int offs;
624dc31c52SJerome Forissier 	char *p;
634dc31c52SJerome Forissier 
644dc31c52SJerome Forissier 	if (!fdt)
65*2f82082fSEdison Ai 		return;
664dc31c52SJerome Forissier 
674dc31c52SJerome Forissier 	offs = fdt_path_offset(fdt, "/secure-chosen");
684dc31c52SJerome Forissier 	if (offs < 0)
694dc31c52SJerome Forissier 		return;
704dc31c52SJerome Forissier 	prop = fdt_get_property(fdt, offs, "stdout-path", NULL);
714dc31c52SJerome Forissier 	if (!prop) {
724dc31c52SJerome Forissier 		/*
734dc31c52SJerome Forissier 		 * /secure-chosen node present but no stdout-path property
744dc31c52SJerome Forissier 		 * means we don't want any console output
754dc31c52SJerome Forissier 		 */
764dc31c52SJerome Forissier 		IMSG("Switching off console");
774dc31c52SJerome Forissier 		register_serial_console(NULL);
784dc31c52SJerome Forissier 		return;
794dc31c52SJerome Forissier 	}
804dc31c52SJerome Forissier 
814dc31c52SJerome Forissier 	stdout_data = strdup(prop->data);
824dc31c52SJerome Forissier 	if (!stdout_data)
834dc31c52SJerome Forissier 		return;
844dc31c52SJerome Forissier 	p = strchr(stdout_data, ':');
854dc31c52SJerome Forissier 	if (p) {
864dc31c52SJerome Forissier 		*p = '\0';
874dc31c52SJerome Forissier 		parms = p + 1;
884dc31c52SJerome Forissier 	}
894dc31c52SJerome Forissier 
904dc31c52SJerome Forissier 	/* stdout-path may refer to an alias */
914dc31c52SJerome Forissier 	uart = fdt_get_alias(fdt, stdout_data);
924dc31c52SJerome Forissier 	if (!uart) {
934dc31c52SJerome Forissier 		/* Not an alias, assume we have a node path */
944dc31c52SJerome Forissier 		uart = stdout_data;
954dc31c52SJerome Forissier 	}
964dc31c52SJerome Forissier 	offs = fdt_path_offset(fdt, uart);
974dc31c52SJerome Forissier 	if (offs < 0)
984dc31c52SJerome Forissier 		goto out;
994dc31c52SJerome Forissier 
1004dc31c52SJerome Forissier 	dt_drv = dt_find_compatible_driver(fdt, offs);
1014dc31c52SJerome Forissier 	if (!dt_drv)
1024dc31c52SJerome Forissier 		goto out;
1034dc31c52SJerome Forissier 
1044dc31c52SJerome Forissier 	sdrv = (const struct serial_driver *)dt_drv->driver;
1054dc31c52SJerome Forissier 	if (!sdrv)
1064dc31c52SJerome Forissier 		goto out;
1074dc31c52SJerome Forissier 	dev = sdrv->dev_alloc();
1084dc31c52SJerome Forissier 	if (!dev)
1094dc31c52SJerome Forissier 		goto out;
1104dc31c52SJerome Forissier 	/*
1114dc31c52SJerome Forissier 	 * If the console is the same as the early console, dev_init() might
1124dc31c52SJerome Forissier 	 * clear pending data. Flush to avoid that.
1134dc31c52SJerome Forissier 	 */
1144dc31c52SJerome Forissier 	console_flush();
1154dc31c52SJerome Forissier 	if (sdrv->dev_init(dev, fdt, offs, parms) < 0) {
1164dc31c52SJerome Forissier 		sdrv->dev_free(dev);
1174dc31c52SJerome Forissier 		goto out;
1184dc31c52SJerome Forissier 	}
1194dc31c52SJerome Forissier 
1204dc31c52SJerome Forissier 	IMSG("Switching console to device: %s", uart);
1214dc31c52SJerome Forissier 	register_serial_console(dev);
1224dc31c52SJerome Forissier out:
1234dc31c52SJerome Forissier 	free(stdout_data);
1244dc31c52SJerome Forissier }
1254dc31c52SJerome Forissier 
1264dc31c52SJerome Forissier #endif /* CFG_DT */
127