linux/drivers/tty/serial/8250/8250_early.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Early serial console for 8250/16550 devices
   4 *
   5 * (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
   6 *      Bjorn Helgaas <bjorn.helgaas@hp.com>
   7 *
   8 * Based on the 8250.c serial driver, Copyright (C) 2001 Russell King,
   9 * and on early_printk.c by Andi Kleen.
  10 *
  11 * This is for use before the serial driver has initialized, in
  12 * particular, before the UARTs have been discovered and named.
  13 * Instead of specifying the console device as, e.g., "ttyS0",
  14 * we locate the device directly by its MMIO or I/O port address.
  15 *
  16 * The user can specify the device directly, e.g.,
  17 *      earlycon=uart8250,io,0x3f8,9600n8
  18 *      earlycon=uart8250,mmio,0xff5e0000,115200n8
  19 *      earlycon=uart8250,mmio32,0xff5e0000,115200n8
  20 * or
  21 *      console=uart8250,io,0x3f8,9600n8
  22 *      console=uart8250,mmio,0xff5e0000,115200n8
  23 *      console=uart8250,mmio32,0xff5e0000,115200n8
  24 */
  25
  26#include <linux/tty.h>
  27#include <linux/init.h>
  28#include <linux/console.h>
  29#include <linux/of.h>
  30#include <linux/of_device.h>
  31#include <linux/serial_reg.h>
  32#include <linux/serial.h>
  33#include <linux/serial_8250.h>
  34#include <asm/io.h>
  35#include <asm/serial.h>
  36
  37static unsigned int serial8250_early_in(struct uart_port *port, int offset)
  38{
  39        int reg_offset = offset;
  40        offset <<= port->regshift;
  41
  42        switch (port->iotype) {
  43        case UPIO_MEM:
  44                return readb(port->membase + offset);
  45        case UPIO_MEM16:
  46                return readw(port->membase + offset);
  47        case UPIO_MEM32:
  48                return readl(port->membase + offset);
  49        case UPIO_MEM32BE:
  50                return ioread32be(port->membase + offset);
  51        case UPIO_PORT:
  52                return inb(port->iobase + offset);
  53        case UPIO_AU:
  54                return port->serial_in(port, reg_offset);
  55        default:
  56                return 0;
  57        }
  58}
  59
  60static void serial8250_early_out(struct uart_port *port, int offset, int value)
  61{
  62        int reg_offset = offset;
  63        offset <<= port->regshift;
  64
  65        switch (port->iotype) {
  66        case UPIO_MEM:
  67                writeb(value, port->membase + offset);
  68                break;
  69        case UPIO_MEM16:
  70                writew(value, port->membase + offset);
  71                break;
  72        case UPIO_MEM32:
  73                writel(value, port->membase + offset);
  74                break;
  75        case UPIO_MEM32BE:
  76                iowrite32be(value, port->membase + offset);
  77                break;
  78        case UPIO_PORT:
  79                outb(value, port->iobase + offset);
  80                break;
  81        case UPIO_AU:
  82                port->serial_out(port, reg_offset, value);
  83                break;
  84        }
  85}
  86
  87#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
  88
  89static void serial_putc(struct uart_port *port, int c)
  90{
  91        unsigned int status;
  92
  93        serial8250_early_out(port, UART_TX, c);
  94
  95        for (;;) {
  96                status = serial8250_early_in(port, UART_LSR);
  97                if ((status & BOTH_EMPTY) == BOTH_EMPTY)
  98                        break;
  99                cpu_relax();
 100        }
 101}
 102
 103static void early_serial8250_write(struct console *console,
 104                                        const char *s, unsigned int count)
 105{
 106        struct earlycon_device *device = console->data;
 107        struct uart_port *port = &device->port;
 108
 109        uart_console_write(port, s, count, serial_putc);
 110}
 111
 112#ifdef CONFIG_CONSOLE_POLL
 113static int early_serial8250_read(struct console *console,
 114                                 char *s, unsigned int count)
 115{
 116        struct earlycon_device *device = console->data;
 117        struct uart_port *port = &device->port;
 118        unsigned int status;
 119        int num_read = 0;
 120
 121        while (num_read < count) {
 122                status = serial8250_early_in(port, UART_LSR);
 123                if (!(status & UART_LSR_DR))
 124                        break;
 125                s[num_read++] = serial8250_early_in(port, UART_RX);
 126        }
 127
 128        return num_read;
 129}
 130#else
 131#define early_serial8250_read NULL
 132#endif
 133
 134static void __init init_port(struct earlycon_device *device)
 135{
 136        struct uart_port *port = &device->port;
 137        unsigned int divisor;
 138        unsigned char c;
 139        unsigned int ier;
 140
 141        serial8250_early_out(port, UART_LCR, 0x3);      /* 8n1 */
 142        ier = serial8250_early_in(port, UART_IER);
 143        serial8250_early_out(port, UART_IER, ier & UART_IER_UUE); /* no interrupt */
 144        serial8250_early_out(port, UART_FCR, 0);        /* no fifo */
 145        serial8250_early_out(port, UART_MCR, 0x3);      /* DTR + RTS */
 146
 147        if (port->uartclk) {
 148                divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud);
 149                c = serial8250_early_in(port, UART_LCR);
 150                serial8250_early_out(port, UART_LCR, c | UART_LCR_DLAB);
 151                serial8250_early_out(port, UART_DLL, divisor & 0xff);
 152                serial8250_early_out(port, UART_DLM, (divisor >> 8) & 0xff);
 153                serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB);
 154        }
 155}
 156
 157int __init early_serial8250_setup(struct earlycon_device *device,
 158                                         const char *options)
 159{
 160        if (!(device->port.membase || device->port.iobase))
 161                return -ENODEV;
 162
 163        if (!device->baud) {
 164                struct uart_port *port = &device->port;
 165                unsigned int ier;
 166
 167                /* assume the device was initialized, only mask interrupts */
 168                ier = serial8250_early_in(port, UART_IER);
 169                serial8250_early_out(port, UART_IER, ier & UART_IER_UUE);
 170        } else
 171                init_port(device);
 172
 173        device->con->write = early_serial8250_write;
 174        device->con->read = early_serial8250_read;
 175        return 0;
 176}
 177EARLYCON_DECLARE(uart8250, early_serial8250_setup);
 178EARLYCON_DECLARE(uart, early_serial8250_setup);
 179OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup);
 180OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup);
 181OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup);
 182OF_EARLYCON_DECLARE(uart, "snps,dw-apb-uart", early_serial8250_setup);
 183
 184#ifdef CONFIG_SERIAL_8250_OMAP
 185
 186static int __init early_omap8250_setup(struct earlycon_device *device,
 187                                       const char *options)
 188{
 189        struct uart_port *port = &device->port;
 190
 191        if (!(device->port.membase || device->port.iobase))
 192                return -ENODEV;
 193
 194        port->regshift = 2;
 195        device->con->write = early_serial8250_write;
 196        return 0;
 197}
 198
 199OF_EARLYCON_DECLARE(omap8250, "ti,omap2-uart", early_omap8250_setup);
 200OF_EARLYCON_DECLARE(omap8250, "ti,omap3-uart", early_omap8250_setup);
 201OF_EARLYCON_DECLARE(omap8250, "ti,omap4-uart", early_omap8250_setup);
 202
 203#endif
 204
 205#ifdef CONFIG_SERIAL_8250_RT288X
 206
 207static int __init early_au_setup(struct earlycon_device *dev, const char *opt)
 208{
 209        dev->port.serial_in = au_serial_in;
 210        dev->port.serial_out = au_serial_out;
 211        dev->port.iotype = UPIO_AU;
 212        dev->con->write = early_serial8250_write;
 213        return 0;
 214}
 215OF_EARLYCON_DECLARE(palmchip, "ralink,rt2880-uart", early_au_setup);
 216
 217#endif
 218