1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2017, Linaro Limited 4 */ 5 6 #include <compiler.h> 7 #include <console.h> 8 #include <drivers/cbmem_console.h> 9 #include <drivers/semihosting_console.h> 10 #include <drivers/serial.h> 11 #include <kernel/dt.h> 12 #include <kernel/dt_driver.h> 13 #include <kernel/panic.h> 14 #include <libfdt.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include <string_ext.h> 18 19 static struct serial_chip *serial_console __nex_bss; 20 21 /* May be overridden by platform */ 22 __weak void plat_console_init(void) 23 { 24 } 25 26 void console_init(void) 27 { 28 if (IS_ENABLED(CFG_SEMIHOSTING_CONSOLE)) 29 semihosting_console_init(CFG_SEMIHOSTING_CONSOLE_FILE); 30 else 31 plat_console_init(); 32 } 33 34 void __weak console_putc(int ch) 35 { 36 if (!serial_console) 37 return; 38 39 if (ch == '\n') 40 serial_console->ops->putc(serial_console, '\r'); 41 serial_console->ops->putc(serial_console, ch); 42 } 43 44 void __weak console_flush(void) 45 { 46 if (!serial_console || !serial_console->ops->flush) 47 return; 48 49 serial_console->ops->flush(serial_console); 50 } 51 52 void register_serial_console(struct serial_chip *chip) 53 { 54 serial_console = chip; 55 } 56 57 #ifdef CFG_DT 58 static int find_chosen_node(void *fdt) 59 { 60 int offset = 0; 61 62 if (!fdt) 63 return -1; 64 65 offset = fdt_path_offset(fdt, "/secure-chosen"); 66 67 if (offset < 0) 68 offset = fdt_path_offset(fdt, "/chosen"); 69 70 return offset; 71 } 72 73 TEE_Result get_console_node_from_dt(void *fdt, int *offs_out, 74 char **path_out, char **params_out) 75 { 76 const struct fdt_property *prop; 77 const char *uart; 78 const char *parms = NULL; 79 int offs; 80 char *stdout_data; 81 char *p; 82 TEE_Result rc = TEE_ERROR_GENERIC; 83 84 /* Probe console from secure DT and fallback to non-secure DT */ 85 offs = find_chosen_node(fdt); 86 if (offs < 0) { 87 DMSG("No console directive from DTB"); 88 return TEE_ERROR_ITEM_NOT_FOUND; 89 } 90 91 prop = fdt_get_property(fdt, offs, "stdout-path", NULL); 92 if (!prop) { 93 /* 94 * A secure-chosen or chosen node is present but defined 95 * no stdout-path property: no console expected 96 */ 97 IMSG("Switching off console"); 98 register_serial_console(NULL); 99 return TEE_ERROR_ITEM_NOT_FOUND; 100 } 101 102 stdout_data = nex_strdup(prop->data); 103 if (!stdout_data) 104 panic(); 105 p = strchr(stdout_data, ':'); 106 if (p) { 107 *p = '\0'; 108 parms = p + 1; 109 } 110 111 /* stdout-path may refer to an alias */ 112 uart = fdt_get_alias(fdt, stdout_data); 113 if (!uart) { 114 /* Not an alias, assume we have a node path */ 115 uart = stdout_data; 116 } 117 offs = fdt_path_offset(fdt, uart); 118 if (offs >= 0) { 119 if (offs_out) 120 *offs_out = offs; 121 if (params_out) 122 *params_out = parms ? nex_strdup(parms) : NULL; 123 if (path_out) 124 *path_out = uart ? nex_strdup(uart) : NULL; 125 126 rc = TEE_SUCCESS; 127 } 128 129 nex_free(stdout_data); 130 131 return rc; 132 } 133 134 void configure_console_from_dt(void) 135 { 136 const struct dt_driver *dt_drv; 137 const struct serial_driver *sdrv; 138 struct serial_chip *dev; 139 char *uart = NULL; 140 char *parms = NULL; 141 void *fdt; 142 int offs; 143 144 fdt = get_dt(); 145 146 if (IS_ENABLED(CFG_CBMEM_CONSOLE) && cbmem_console_init_from_dt(fdt)) 147 return; 148 149 if (get_console_node_from_dt(fdt, &offs, &uart, &parms)) 150 return; 151 152 dt_drv = dt_find_compatible_driver(fdt, offs); 153 if (!dt_drv || dt_drv->type != DT_DRIVER_UART) 154 goto out; 155 156 sdrv = (const struct serial_driver *)dt_drv->driver; 157 if (!sdrv) 158 goto out; 159 160 dev = sdrv->dev_alloc(); 161 if (!dev) 162 goto out; 163 164 /* 165 * If the console is the same as the early console, dev_init() might 166 * clear pending data. Flush to avoid that. 167 */ 168 console_flush(); 169 if (sdrv->dev_init(dev, fdt, offs, parms) < 0) { 170 sdrv->dev_free(dev); 171 goto out; 172 } 173 174 IMSG("Switching console to device: %s", uart); 175 register_serial_console(dev); 176 out: 177 nex_free(uart); 178 nex_free(parms); 179 } 180 181 #endif /* CFG_DT */ 182