cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

8250_early.c (5991B)


      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, unsigned char 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