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