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

apbuart.c (16281B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *  Driver for GRLIB serial ports (APBUART)
      4 *
      5 *  Based on linux/drivers/serial/amba.c
      6 *
      7 *  Copyright (C) 2000 Deep Blue Solutions Ltd.
      8 *  Copyright (C) 2003 Konrad Eisele <eiselekd@web.de>
      9 *  Copyright (C) 2006 Daniel Hellstrom <daniel@gaisler.com>, Aeroflex Gaisler AB
     10 *  Copyright (C) 2008 Gilead Kutnick <kutnickg@zin-tech.com>
     11 *  Copyright (C) 2009 Kristoffer Glembo <kristoffer@gaisler.com>, Aeroflex Gaisler AB
     12 */
     13
     14#include <linux/module.h>
     15#include <linux/tty.h>
     16#include <linux/tty_flip.h>
     17#include <linux/ioport.h>
     18#include <linux/init.h>
     19#include <linux/serial.h>
     20#include <linux/console.h>
     21#include <linux/sysrq.h>
     22#include <linux/kthread.h>
     23#include <linux/device.h>
     24#include <linux/of.h>
     25#include <linux/of_device.h>
     26#include <linux/of_platform.h>
     27#include <linux/of_irq.h>
     28#include <linux/platform_device.h>
     29#include <linux/io.h>
     30#include <linux/serial_core.h>
     31#include <asm/irq.h>
     32
     33#include "apbuart.h"
     34
     35#define SERIAL_APBUART_MAJOR	TTY_MAJOR
     36#define SERIAL_APBUART_MINOR	64
     37#define UART_DUMMY_RSR_RX	0x8000	/* for ignore all read */
     38
     39static void apbuart_tx_chars(struct uart_port *port);
     40
     41static void apbuart_stop_tx(struct uart_port *port)
     42{
     43	unsigned int cr;
     44
     45	cr = UART_GET_CTRL(port);
     46	cr &= ~UART_CTRL_TI;
     47	UART_PUT_CTRL(port, cr);
     48}
     49
     50static void apbuart_start_tx(struct uart_port *port)
     51{
     52	unsigned int cr;
     53
     54	cr = UART_GET_CTRL(port);
     55	cr |= UART_CTRL_TI;
     56	UART_PUT_CTRL(port, cr);
     57
     58	if (UART_GET_STATUS(port) & UART_STATUS_THE)
     59		apbuart_tx_chars(port);
     60}
     61
     62static void apbuart_stop_rx(struct uart_port *port)
     63{
     64	unsigned int cr;
     65
     66	cr = UART_GET_CTRL(port);
     67	cr &= ~(UART_CTRL_RI);
     68	UART_PUT_CTRL(port, cr);
     69}
     70
     71static void apbuart_rx_chars(struct uart_port *port)
     72{
     73	unsigned int status, ch, rsr, flag;
     74	unsigned int max_chars = port->fifosize;
     75
     76	status = UART_GET_STATUS(port);
     77
     78	while (UART_RX_DATA(status) && (max_chars--)) {
     79
     80		ch = UART_GET_CHAR(port);
     81		flag = TTY_NORMAL;
     82
     83		port->icount.rx++;
     84
     85		rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX;
     86		UART_PUT_STATUS(port, 0);
     87		if (rsr & UART_STATUS_ERR) {
     88
     89			if (rsr & UART_STATUS_BR) {
     90				rsr &= ~(UART_STATUS_FE | UART_STATUS_PE);
     91				port->icount.brk++;
     92				if (uart_handle_break(port))
     93					goto ignore_char;
     94			} else if (rsr & UART_STATUS_PE) {
     95				port->icount.parity++;
     96			} else if (rsr & UART_STATUS_FE) {
     97				port->icount.frame++;
     98			}
     99			if (rsr & UART_STATUS_OE)
    100				port->icount.overrun++;
    101
    102			rsr &= port->read_status_mask;
    103
    104			if (rsr & UART_STATUS_PE)
    105				flag = TTY_PARITY;
    106			else if (rsr & UART_STATUS_FE)
    107				flag = TTY_FRAME;
    108		}
    109
    110		if (uart_handle_sysrq_char(port, ch))
    111			goto ignore_char;
    112
    113		uart_insert_char(port, rsr, UART_STATUS_OE, ch, flag);
    114
    115
    116	      ignore_char:
    117		status = UART_GET_STATUS(port);
    118	}
    119
    120	tty_flip_buffer_push(&port->state->port);
    121}
    122
    123static void apbuart_tx_chars(struct uart_port *port)
    124{
    125	struct circ_buf *xmit = &port->state->xmit;
    126	int count;
    127
    128	if (port->x_char) {
    129		UART_PUT_CHAR(port, port->x_char);
    130		port->icount.tx++;
    131		port->x_char = 0;
    132		return;
    133	}
    134
    135	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
    136		apbuart_stop_tx(port);
    137		return;
    138	}
    139
    140	/* amba: fill FIFO */
    141	count = port->fifosize >> 1;
    142	do {
    143		UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
    144		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
    145		port->icount.tx++;
    146		if (uart_circ_empty(xmit))
    147			break;
    148	} while (--count > 0);
    149
    150	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
    151		uart_write_wakeup(port);
    152
    153	if (uart_circ_empty(xmit))
    154		apbuart_stop_tx(port);
    155}
    156
    157static irqreturn_t apbuart_int(int irq, void *dev_id)
    158{
    159	struct uart_port *port = dev_id;
    160	unsigned int status;
    161
    162	spin_lock(&port->lock);
    163
    164	status = UART_GET_STATUS(port);
    165	if (status & UART_STATUS_DR)
    166		apbuart_rx_chars(port);
    167	if (status & UART_STATUS_THE)
    168		apbuart_tx_chars(port);
    169
    170	spin_unlock(&port->lock);
    171
    172	return IRQ_HANDLED;
    173}
    174
    175static unsigned int apbuart_tx_empty(struct uart_port *port)
    176{
    177	unsigned int status = UART_GET_STATUS(port);
    178	return status & UART_STATUS_THE ? TIOCSER_TEMT : 0;
    179}
    180
    181static unsigned int apbuart_get_mctrl(struct uart_port *port)
    182{
    183	/* The GRLIB APBUART handles flow control in hardware */
    184	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
    185}
    186
    187static void apbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
    188{
    189	/* The GRLIB APBUART handles flow control in hardware */
    190}
    191
    192static void apbuart_break_ctl(struct uart_port *port, int break_state)
    193{
    194	/* We don't support sending break */
    195}
    196
    197static int apbuart_startup(struct uart_port *port)
    198{
    199	int retval;
    200	unsigned int cr;
    201
    202	/* Allocate the IRQ */
    203	retval = request_irq(port->irq, apbuart_int, 0, "apbuart", port);
    204	if (retval)
    205		return retval;
    206
    207	/* Finally, enable interrupts */
    208	cr = UART_GET_CTRL(port);
    209	UART_PUT_CTRL(port,
    210		      cr | UART_CTRL_RE | UART_CTRL_TE |
    211		      UART_CTRL_RI | UART_CTRL_TI);
    212
    213	return 0;
    214}
    215
    216static void apbuart_shutdown(struct uart_port *port)
    217{
    218	unsigned int cr;
    219
    220	/* disable all interrupts, disable the port */
    221	cr = UART_GET_CTRL(port);
    222	UART_PUT_CTRL(port,
    223		      cr & ~(UART_CTRL_RE | UART_CTRL_TE |
    224			     UART_CTRL_RI | UART_CTRL_TI));
    225
    226	/* Free the interrupt */
    227	free_irq(port->irq, port);
    228}
    229
    230static void apbuart_set_termios(struct uart_port *port,
    231				struct ktermios *termios, struct ktermios *old)
    232{
    233	unsigned int cr;
    234	unsigned long flags;
    235	unsigned int baud, quot;
    236
    237	/* Ask the core to calculate the divisor for us. */
    238	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
    239	if (baud == 0)
    240		panic("invalid baudrate %i\n", port->uartclk / 16);
    241
    242	/* uart_get_divisor calc a *16 uart freq, apbuart is *8 */
    243	quot = (uart_get_divisor(port, baud)) * 2;
    244	cr = UART_GET_CTRL(port);
    245	cr &= ~(UART_CTRL_PE | UART_CTRL_PS);
    246
    247	if (termios->c_cflag & PARENB) {
    248		cr |= UART_CTRL_PE;
    249		if ((termios->c_cflag & PARODD))
    250			cr |= UART_CTRL_PS;
    251	}
    252
    253	/* Enable flow control. */
    254	if (termios->c_cflag & CRTSCTS)
    255		cr |= UART_CTRL_FL;
    256
    257	spin_lock_irqsave(&port->lock, flags);
    258
    259	/* Update the per-port timeout. */
    260	uart_update_timeout(port, termios->c_cflag, baud);
    261
    262	port->read_status_mask = UART_STATUS_OE;
    263	if (termios->c_iflag & INPCK)
    264		port->read_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
    265
    266	/* Characters to ignore */
    267	port->ignore_status_mask = 0;
    268	if (termios->c_iflag & IGNPAR)
    269		port->ignore_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
    270
    271	/* Ignore all characters if CREAD is not set. */
    272	if ((termios->c_cflag & CREAD) == 0)
    273		port->ignore_status_mask |= UART_DUMMY_RSR_RX;
    274
    275	/* Set baud rate */
    276	quot -= 1;
    277	UART_PUT_SCAL(port, quot);
    278	UART_PUT_CTRL(port, cr);
    279
    280	spin_unlock_irqrestore(&port->lock, flags);
    281}
    282
    283static const char *apbuart_type(struct uart_port *port)
    284{
    285	return port->type == PORT_APBUART ? "GRLIB/APBUART" : NULL;
    286}
    287
    288static void apbuart_release_port(struct uart_port *port)
    289{
    290	release_mem_region(port->mapbase, 0x100);
    291}
    292
    293static int apbuart_request_port(struct uart_port *port)
    294{
    295	return request_mem_region(port->mapbase, 0x100, "grlib-apbuart")
    296	    != NULL ? 0 : -EBUSY;
    297	return 0;
    298}
    299
    300/* Configure/autoconfigure the port */
    301static void apbuart_config_port(struct uart_port *port, int flags)
    302{
    303	if (flags & UART_CONFIG_TYPE) {
    304		port->type = PORT_APBUART;
    305		apbuart_request_port(port);
    306	}
    307}
    308
    309/* Verify the new serial_struct (for TIOCSSERIAL) */
    310static int apbuart_verify_port(struct uart_port *port,
    311			       struct serial_struct *ser)
    312{
    313	int ret = 0;
    314	if (ser->type != PORT_UNKNOWN && ser->type != PORT_APBUART)
    315		ret = -EINVAL;
    316	if (ser->irq < 0 || ser->irq >= NR_IRQS)
    317		ret = -EINVAL;
    318	if (ser->baud_base < 9600)
    319		ret = -EINVAL;
    320	return ret;
    321}
    322
    323static const struct uart_ops grlib_apbuart_ops = {
    324	.tx_empty = apbuart_tx_empty,
    325	.set_mctrl = apbuart_set_mctrl,
    326	.get_mctrl = apbuart_get_mctrl,
    327	.stop_tx = apbuart_stop_tx,
    328	.start_tx = apbuart_start_tx,
    329	.stop_rx = apbuart_stop_rx,
    330	.break_ctl = apbuart_break_ctl,
    331	.startup = apbuart_startup,
    332	.shutdown = apbuart_shutdown,
    333	.set_termios = apbuart_set_termios,
    334	.type = apbuart_type,
    335	.release_port = apbuart_release_port,
    336	.request_port = apbuart_request_port,
    337	.config_port = apbuart_config_port,
    338	.verify_port = apbuart_verify_port,
    339};
    340
    341static struct uart_port grlib_apbuart_ports[UART_NR];
    342static struct device_node *grlib_apbuart_nodes[UART_NR];
    343
    344static int apbuart_scan_fifo_size(struct uart_port *port, int portnumber)
    345{
    346	int ctrl, loop = 0;
    347	int status;
    348	int fifosize;
    349	unsigned long flags;
    350
    351	ctrl = UART_GET_CTRL(port);
    352
    353	/*
    354	 * Enable the transceiver and wait for it to be ready to send data.
    355	 * Clear interrupts so that this process will not be externally
    356	 * interrupted in the middle (which can cause the transceiver to
    357	 * drain prematurely).
    358	 */
    359
    360	local_irq_save(flags);
    361
    362	UART_PUT_CTRL(port, ctrl | UART_CTRL_TE);
    363
    364	while (!UART_TX_READY(UART_GET_STATUS(port)))
    365		loop++;
    366
    367	/*
    368	 * Disable the transceiver so data isn't actually sent during the
    369	 * actual test.
    370	 */
    371
    372	UART_PUT_CTRL(port, ctrl & ~(UART_CTRL_TE));
    373
    374	fifosize = 1;
    375	UART_PUT_CHAR(port, 0);
    376
    377	/*
    378	 * So long as transmitting a character increments the tranceivier FIFO
    379	 * length the FIFO must be at least that big. These bytes will
    380	 * automatically drain off of the FIFO.
    381	 */
    382
    383	status = UART_GET_STATUS(port);
    384	while (((status >> 20) & 0x3F) == fifosize) {
    385		fifosize++;
    386		UART_PUT_CHAR(port, 0);
    387		status = UART_GET_STATUS(port);
    388	}
    389
    390	fifosize--;
    391
    392	UART_PUT_CTRL(port, ctrl);
    393	local_irq_restore(flags);
    394
    395	if (fifosize == 0)
    396		fifosize = 1;
    397
    398	return fifosize;
    399}
    400
    401static void apbuart_flush_fifo(struct uart_port *port)
    402{
    403	int i;
    404
    405	for (i = 0; i < port->fifosize; i++)
    406		UART_GET_CHAR(port);
    407}
    408
    409
    410/* ======================================================================== */
    411/* Console driver, if enabled                                               */
    412/* ======================================================================== */
    413
    414#ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
    415
    416static void apbuart_console_putchar(struct uart_port *port, unsigned char ch)
    417{
    418	unsigned int status;
    419	do {
    420		status = UART_GET_STATUS(port);
    421	} while (!UART_TX_READY(status));
    422	UART_PUT_CHAR(port, ch);
    423}
    424
    425static void
    426apbuart_console_write(struct console *co, const char *s, unsigned int count)
    427{
    428	struct uart_port *port = &grlib_apbuart_ports[co->index];
    429	unsigned int status, old_cr, new_cr;
    430
    431	/* First save the CR then disable the interrupts */
    432	old_cr = UART_GET_CTRL(port);
    433	new_cr = old_cr & ~(UART_CTRL_RI | UART_CTRL_TI);
    434	UART_PUT_CTRL(port, new_cr);
    435
    436	uart_console_write(port, s, count, apbuart_console_putchar);
    437
    438	/*
    439	 *      Finally, wait for transmitter to become empty
    440	 *      and restore the TCR
    441	 */
    442	do {
    443		status = UART_GET_STATUS(port);
    444	} while (!UART_TX_READY(status));
    445	UART_PUT_CTRL(port, old_cr);
    446}
    447
    448static void __init
    449apbuart_console_get_options(struct uart_port *port, int *baud,
    450			    int *parity, int *bits)
    451{
    452	if (UART_GET_CTRL(port) & (UART_CTRL_RE | UART_CTRL_TE)) {
    453
    454		unsigned int quot, status;
    455		status = UART_GET_STATUS(port);
    456
    457		*parity = 'n';
    458		if (status & UART_CTRL_PE) {
    459			if ((status & UART_CTRL_PS) == 0)
    460				*parity = 'e';
    461			else
    462				*parity = 'o';
    463		}
    464
    465		*bits = 8;
    466		quot = UART_GET_SCAL(port) / 8;
    467		*baud = port->uartclk / (16 * (quot + 1));
    468	}
    469}
    470
    471static int __init apbuart_console_setup(struct console *co, char *options)
    472{
    473	struct uart_port *port;
    474	int baud = 38400;
    475	int bits = 8;
    476	int parity = 'n';
    477	int flow = 'n';
    478
    479	pr_debug("apbuart_console_setup co=%p, co->index=%i, options=%s\n",
    480		 co, co->index, options);
    481
    482	/*
    483	 * Check whether an invalid uart number has been specified, and
    484	 * if so, search for the first available port that does have
    485	 * console support.
    486	 */
    487	if (co->index >= grlib_apbuart_port_nr)
    488		co->index = 0;
    489
    490	port = &grlib_apbuart_ports[co->index];
    491
    492	spin_lock_init(&port->lock);
    493
    494	if (options)
    495		uart_parse_options(options, &baud, &parity, &bits, &flow);
    496	else
    497		apbuart_console_get_options(port, &baud, &parity, &bits);
    498
    499	return uart_set_options(port, co, baud, parity, bits, flow);
    500}
    501
    502static struct uart_driver grlib_apbuart_driver;
    503
    504static struct console grlib_apbuart_console = {
    505	.name = "ttyS",
    506	.write = apbuart_console_write,
    507	.device = uart_console_device,
    508	.setup = apbuart_console_setup,
    509	.flags = CON_PRINTBUFFER,
    510	.index = -1,
    511	.data = &grlib_apbuart_driver,
    512};
    513
    514
    515static int grlib_apbuart_configure(void);
    516
    517static int __init apbuart_console_init(void)
    518{
    519	if (grlib_apbuart_configure())
    520		return -ENODEV;
    521	register_console(&grlib_apbuart_console);
    522	return 0;
    523}
    524
    525console_initcall(apbuart_console_init);
    526
    527#define APBUART_CONSOLE	(&grlib_apbuart_console)
    528#else
    529#define APBUART_CONSOLE	NULL
    530#endif
    531
    532static struct uart_driver grlib_apbuart_driver = {
    533	.owner = THIS_MODULE,
    534	.driver_name = "serial",
    535	.dev_name = "ttyS",
    536	.major = SERIAL_APBUART_MAJOR,
    537	.minor = SERIAL_APBUART_MINOR,
    538	.nr = UART_NR,
    539	.cons = APBUART_CONSOLE,
    540};
    541
    542
    543/* ======================================================================== */
    544/* OF Platform Driver                                                       */
    545/* ======================================================================== */
    546
    547static int apbuart_probe(struct platform_device *op)
    548{
    549	int i;
    550	struct uart_port *port = NULL;
    551
    552	for (i = 0; i < grlib_apbuart_port_nr; i++) {
    553		if (op->dev.of_node == grlib_apbuart_nodes[i])
    554			break;
    555	}
    556
    557	port = &grlib_apbuart_ports[i];
    558	port->dev = &op->dev;
    559	port->irq = op->archdata.irqs[0];
    560
    561	uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *) port);
    562
    563	apbuart_flush_fifo((struct uart_port *) port);
    564
    565	printk(KERN_INFO "grlib-apbuart at 0x%llx, irq %d\n",
    566	       (unsigned long long) port->mapbase, port->irq);
    567	return 0;
    568}
    569
    570static const struct of_device_id apbuart_match[] = {
    571	{
    572	 .name = "GAISLER_APBUART",
    573	 },
    574	{
    575	 .name = "01_00c",
    576	 },
    577	{},
    578};
    579MODULE_DEVICE_TABLE(of, apbuart_match);
    580
    581static struct platform_driver grlib_apbuart_of_driver = {
    582	.probe = apbuart_probe,
    583	.driver = {
    584		.name = "grlib-apbuart",
    585		.of_match_table = apbuart_match,
    586	},
    587};
    588
    589
    590static int __init grlib_apbuart_configure(void)
    591{
    592	struct device_node *np;
    593	int line = 0;
    594
    595	for_each_matching_node(np, apbuart_match) {
    596		const int *ampopts;
    597		const u32 *freq_hz;
    598		const struct amba_prom_registers *regs;
    599		struct uart_port *port;
    600		unsigned long addr;
    601
    602		ampopts = of_get_property(np, "ampopts", NULL);
    603		if (ampopts && (*ampopts == 0))
    604			continue; /* Ignore if used by another OS instance */
    605		regs = of_get_property(np, "reg", NULL);
    606		/* Frequency of APB Bus is frequency of UART */
    607		freq_hz = of_get_property(np, "freq", NULL);
    608
    609		if (!regs || !freq_hz || (*freq_hz == 0))
    610			continue;
    611
    612		grlib_apbuart_nodes[line] = np;
    613
    614		addr = regs->phys_addr;
    615
    616		port = &grlib_apbuart_ports[line];
    617
    618		port->mapbase = addr;
    619		port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map));
    620		port->irq = 0;
    621		port->iotype = UPIO_MEM;
    622		port->ops = &grlib_apbuart_ops;
    623		port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE);
    624		port->flags = UPF_BOOT_AUTOCONF;
    625		port->line = line;
    626		port->uartclk = *freq_hz;
    627		port->fifosize = apbuart_scan_fifo_size((struct uart_port *) port, line);
    628		line++;
    629
    630		/* We support maximum UART_NR uarts ... */
    631		if (line == UART_NR)
    632			break;
    633	}
    634
    635	grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line;
    636	return line ? 0 : -ENODEV;
    637}
    638
    639static int __init grlib_apbuart_init(void)
    640{
    641	int ret;
    642
    643	/* Find all APBUARTS in device the tree and initialize their ports */
    644	ret = grlib_apbuart_configure();
    645	if (ret)
    646		return ret;
    647
    648	printk(KERN_INFO "Serial: GRLIB APBUART driver\n");
    649
    650	ret = uart_register_driver(&grlib_apbuart_driver);
    651
    652	if (ret) {
    653		printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
    654		       __FILE__, ret);
    655		return ret;
    656	}
    657
    658	ret = platform_driver_register(&grlib_apbuart_of_driver);
    659	if (ret) {
    660		printk(KERN_ERR
    661		       "%s: platform_driver_register failed (%i)\n",
    662		       __FILE__, ret);
    663		uart_unregister_driver(&grlib_apbuart_driver);
    664		return ret;
    665	}
    666
    667	return ret;
    668}
    669
    670static void __exit grlib_apbuart_exit(void)
    671{
    672	int i;
    673
    674	for (i = 0; i < grlib_apbuart_port_nr; i++)
    675		uart_remove_one_port(&grlib_apbuart_driver,
    676				     &grlib_apbuart_ports[i]);
    677
    678	uart_unregister_driver(&grlib_apbuart_driver);
    679	platform_driver_unregister(&grlib_apbuart_of_driver);
    680}
    681
    682module_init(grlib_apbuart_init);
    683module_exit(grlib_apbuart_exit);
    684
    685MODULE_AUTHOR("Aeroflex Gaisler AB");
    686MODULE_DESCRIPTION("GRLIB APBUART serial driver");
    687MODULE_VERSION("2.1");
    688MODULE_LICENSE("GPL");