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

timbuart.c (12378B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * timbuart.c timberdale FPGA UART driver
      4 * Copyright (c) 2009 Intel Corporation
      5 */
      6
      7/* Supports:
      8 * Timberdale FPGA UART
      9 */
     10
     11#include <linux/pci.h>
     12#include <linux/interrupt.h>
     13#include <linux/serial_core.h>
     14#include <linux/tty.h>
     15#include <linux/tty_flip.h>
     16#include <linux/kernel.h>
     17#include <linux/platform_device.h>
     18#include <linux/ioport.h>
     19#include <linux/slab.h>
     20#include <linux/module.h>
     21
     22#include "timbuart.h"
     23
     24struct timbuart_port {
     25	struct uart_port	port;
     26	struct tasklet_struct	tasklet;
     27	int			usedma;
     28	u32			last_ier;
     29	struct platform_device  *dev;
     30};
     31
     32static int baudrates[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800,
     33	921600, 1843200, 3250000};
     34
     35static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier);
     36
     37static irqreturn_t timbuart_handleinterrupt(int irq, void *devid);
     38
     39static void timbuart_stop_rx(struct uart_port *port)
     40{
     41	/* spin lock held by upper layer, disable all RX interrupts */
     42	u32 ier = ioread32(port->membase + TIMBUART_IER) & ~RXFLAGS;
     43	iowrite32(ier, port->membase + TIMBUART_IER);
     44}
     45
     46static void timbuart_stop_tx(struct uart_port *port)
     47{
     48	/* spinlock held by upper layer, disable TX interrupt */
     49	u32 ier = ioread32(port->membase + TIMBUART_IER) & ~TXBAE;
     50	iowrite32(ier, port->membase + TIMBUART_IER);
     51}
     52
     53static void timbuart_start_tx(struct uart_port *port)
     54{
     55	struct timbuart_port *uart =
     56		container_of(port, struct timbuart_port, port);
     57
     58	/* do not transfer anything here -> fire off the tasklet */
     59	tasklet_schedule(&uart->tasklet);
     60}
     61
     62static unsigned int timbuart_tx_empty(struct uart_port *port)
     63{
     64	u32 isr = ioread32(port->membase + TIMBUART_ISR);
     65
     66	return (isr & TXBE) ? TIOCSER_TEMT : 0;
     67}
     68
     69static void timbuart_flush_buffer(struct uart_port *port)
     70{
     71	if (!timbuart_tx_empty(port)) {
     72		u8 ctl = ioread8(port->membase + TIMBUART_CTRL) |
     73			TIMBUART_CTRL_FLSHTX;
     74
     75		iowrite8(ctl, port->membase + TIMBUART_CTRL);
     76		iowrite32(TXBF, port->membase + TIMBUART_ISR);
     77	}
     78}
     79
     80static void timbuart_rx_chars(struct uart_port *port)
     81{
     82	struct tty_port *tport = &port->state->port;
     83
     84	while (ioread32(port->membase + TIMBUART_ISR) & RXDP) {
     85		u8 ch = ioread8(port->membase + TIMBUART_RXFIFO);
     86		port->icount.rx++;
     87		tty_insert_flip_char(tport, ch, TTY_NORMAL);
     88	}
     89
     90	tty_flip_buffer_push(tport);
     91
     92	dev_dbg(port->dev, "%s - total read %d bytes\n",
     93		__func__, port->icount.rx);
     94}
     95
     96static void timbuart_tx_chars(struct uart_port *port)
     97{
     98	struct circ_buf *xmit = &port->state->xmit;
     99
    100	while (!(ioread32(port->membase + TIMBUART_ISR) & TXBF) &&
    101		!uart_circ_empty(xmit)) {
    102		iowrite8(xmit->buf[xmit->tail],
    103			port->membase + TIMBUART_TXFIFO);
    104		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
    105		port->icount.tx++;
    106	}
    107
    108	dev_dbg(port->dev,
    109		"%s - total written %d bytes, CTL: %x, RTS: %x, baud: %x\n",
    110		 __func__,
    111		port->icount.tx,
    112		ioread8(port->membase + TIMBUART_CTRL),
    113		port->mctrl & TIOCM_RTS,
    114		ioread8(port->membase + TIMBUART_BAUDRATE));
    115}
    116
    117static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier)
    118{
    119	struct timbuart_port *uart =
    120		container_of(port, struct timbuart_port, port);
    121	struct circ_buf *xmit = &port->state->xmit;
    122
    123	if (uart_circ_empty(xmit) || uart_tx_stopped(port))
    124		return;
    125
    126	if (port->x_char)
    127		return;
    128
    129	if (isr & TXFLAGS) {
    130		timbuart_tx_chars(port);
    131		/* clear all TX interrupts */
    132		iowrite32(TXFLAGS, port->membase + TIMBUART_ISR);
    133
    134		if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
    135			uart_write_wakeup(port);
    136	} else
    137		/* Re-enable any tx interrupt */
    138		*ier |= uart->last_ier & TXFLAGS;
    139
    140	/* enable interrupts if there are chars in the transmit buffer,
    141	 * Or if we delivered some bytes and want the almost empty interrupt
    142	 * we wake up the upper layer later when we got the interrupt
    143	 * to give it some time to go out...
    144	 */
    145	if (!uart_circ_empty(xmit))
    146		*ier |= TXBAE;
    147
    148	dev_dbg(port->dev, "%s - leaving\n", __func__);
    149}
    150
    151static void timbuart_handle_rx_port(struct uart_port *port, u32 isr, u32 *ier)
    152{
    153	if (isr & RXFLAGS) {
    154		/* Some RX status is set */
    155		if (isr & RXBF) {
    156			u8 ctl = ioread8(port->membase + TIMBUART_CTRL) |
    157				TIMBUART_CTRL_FLSHRX;
    158			iowrite8(ctl, port->membase + TIMBUART_CTRL);
    159			port->icount.overrun++;
    160		} else if (isr & (RXDP))
    161			timbuart_rx_chars(port);
    162
    163		/* ack all RX interrupts */
    164		iowrite32(RXFLAGS, port->membase + TIMBUART_ISR);
    165	}
    166
    167	/* always have the RX interrupts enabled */
    168	*ier |= RXBAF | RXBF | RXTT;
    169
    170	dev_dbg(port->dev, "%s - leaving\n", __func__);
    171}
    172
    173static void timbuart_tasklet(struct tasklet_struct *t)
    174{
    175	struct timbuart_port *uart = from_tasklet(uart, t, tasklet);
    176	u32 isr, ier = 0;
    177
    178	spin_lock(&uart->port.lock);
    179
    180	isr = ioread32(uart->port.membase + TIMBUART_ISR);
    181	dev_dbg(uart->port.dev, "%s ISR: %x\n", __func__, isr);
    182
    183	if (!uart->usedma)
    184		timbuart_handle_tx_port(&uart->port, isr, &ier);
    185
    186	timbuart_mctrl_check(&uart->port, isr, &ier);
    187
    188	if (!uart->usedma)
    189		timbuart_handle_rx_port(&uart->port, isr, &ier);
    190
    191	iowrite32(ier, uart->port.membase + TIMBUART_IER);
    192
    193	spin_unlock(&uart->port.lock);
    194	dev_dbg(uart->port.dev, "%s leaving\n", __func__);
    195}
    196
    197static unsigned int timbuart_get_mctrl(struct uart_port *port)
    198{
    199	u8 cts = ioread8(port->membase + TIMBUART_CTRL);
    200	dev_dbg(port->dev, "%s - cts %x\n", __func__, cts);
    201
    202	if (cts & TIMBUART_CTRL_CTS)
    203		return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
    204	else
    205		return TIOCM_DSR | TIOCM_CAR;
    206}
    207
    208static void timbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
    209{
    210	dev_dbg(port->dev, "%s - %x\n", __func__, mctrl);
    211
    212	if (mctrl & TIOCM_RTS)
    213		iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL);
    214	else
    215		iowrite8(0, port->membase + TIMBUART_CTRL);
    216}
    217
    218static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier)
    219{
    220	unsigned int cts;
    221
    222	if (isr & CTS_DELTA) {
    223		/* ack */
    224		iowrite32(CTS_DELTA, port->membase + TIMBUART_ISR);
    225		cts = timbuart_get_mctrl(port);
    226		uart_handle_cts_change(port, cts & TIOCM_CTS);
    227		wake_up_interruptible(&port->state->port.delta_msr_wait);
    228	}
    229
    230	*ier |= CTS_DELTA;
    231}
    232
    233static void timbuart_break_ctl(struct uart_port *port, int ctl)
    234{
    235	/* N/A */
    236}
    237
    238static int timbuart_startup(struct uart_port *port)
    239{
    240	struct timbuart_port *uart =
    241		container_of(port, struct timbuart_port, port);
    242
    243	dev_dbg(port->dev, "%s\n", __func__);
    244
    245	iowrite8(TIMBUART_CTRL_FLSHRX, port->membase + TIMBUART_CTRL);
    246	iowrite32(0x1ff, port->membase + TIMBUART_ISR);
    247	/* Enable all but TX interrupts */
    248	iowrite32(RXBAF | RXBF | RXTT | CTS_DELTA,
    249		port->membase + TIMBUART_IER);
    250
    251	return request_irq(port->irq, timbuart_handleinterrupt, IRQF_SHARED,
    252		"timb-uart", uart);
    253}
    254
    255static void timbuart_shutdown(struct uart_port *port)
    256{
    257	struct timbuart_port *uart =
    258		container_of(port, struct timbuart_port, port);
    259	dev_dbg(port->dev, "%s\n", __func__);
    260	free_irq(port->irq, uart);
    261	iowrite32(0, port->membase + TIMBUART_IER);
    262
    263	timbuart_flush_buffer(port);
    264}
    265
    266static int get_bindex(int baud)
    267{
    268	int i;
    269
    270	for (i = 0; i < ARRAY_SIZE(baudrates); i++)
    271		if (baud <= baudrates[i])
    272			return i;
    273
    274	return -1;
    275}
    276
    277static void timbuart_set_termios(struct uart_port *port,
    278	struct ktermios *termios,
    279	struct ktermios *old)
    280{
    281	unsigned int baud;
    282	short bindex;
    283	unsigned long flags;
    284
    285	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
    286	bindex = get_bindex(baud);
    287	dev_dbg(port->dev, "%s - bindex %d\n", __func__, bindex);
    288
    289	if (bindex < 0)
    290		bindex = 0;
    291	baud = baudrates[bindex];
    292
    293	/* The serial layer calls into this once with old = NULL when setting
    294	   up initially */
    295	if (old)
    296		tty_termios_copy_hw(termios, old);
    297	tty_termios_encode_baud_rate(termios, baud, baud);
    298
    299	spin_lock_irqsave(&port->lock, flags);
    300	iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE);
    301	uart_update_timeout(port, termios->c_cflag, baud);
    302	spin_unlock_irqrestore(&port->lock, flags);
    303}
    304
    305static const char *timbuart_type(struct uart_port *port)
    306{
    307	return port->type == PORT_UNKNOWN ? "timbuart" : NULL;
    308}
    309
    310/* We do not request/release mappings of the registers here,
    311 * currently it's done in the proble function.
    312 */
    313static void timbuart_release_port(struct uart_port *port)
    314{
    315	struct platform_device *pdev = to_platform_device(port->dev);
    316	int size =
    317		resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0));
    318
    319	if (port->flags & UPF_IOREMAP) {
    320		iounmap(port->membase);
    321		port->membase = NULL;
    322	}
    323
    324	release_mem_region(port->mapbase, size);
    325}
    326
    327static int timbuart_request_port(struct uart_port *port)
    328{
    329	struct platform_device *pdev = to_platform_device(port->dev);
    330	int size =
    331		resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0));
    332
    333	if (!request_mem_region(port->mapbase, size, "timb-uart"))
    334		return -EBUSY;
    335
    336	if (port->flags & UPF_IOREMAP) {
    337		port->membase = ioremap(port->mapbase, size);
    338		if (port->membase == NULL) {
    339			release_mem_region(port->mapbase, size);
    340			return -ENOMEM;
    341		}
    342	}
    343
    344	return 0;
    345}
    346
    347static irqreturn_t timbuart_handleinterrupt(int irq, void *devid)
    348{
    349	struct timbuart_port *uart = (struct timbuart_port *)devid;
    350
    351	if (ioread8(uart->port.membase + TIMBUART_IPR)) {
    352		uart->last_ier = ioread32(uart->port.membase + TIMBUART_IER);
    353
    354		/* disable interrupts, the tasklet enables them again */
    355		iowrite32(0, uart->port.membase + TIMBUART_IER);
    356
    357		/* fire off bottom half */
    358		tasklet_schedule(&uart->tasklet);
    359
    360		return IRQ_HANDLED;
    361	} else
    362		return IRQ_NONE;
    363}
    364
    365/*
    366 * Configure/autoconfigure the port.
    367 */
    368static void timbuart_config_port(struct uart_port *port, int flags)
    369{
    370	if (flags & UART_CONFIG_TYPE) {
    371		port->type = PORT_TIMBUART;
    372		timbuart_request_port(port);
    373	}
    374}
    375
    376static int timbuart_verify_port(struct uart_port *port,
    377	struct serial_struct *ser)
    378{
    379	/* we don't want the core code to modify any port params */
    380	return -EINVAL;
    381}
    382
    383static const struct uart_ops timbuart_ops = {
    384	.tx_empty = timbuart_tx_empty,
    385	.set_mctrl = timbuart_set_mctrl,
    386	.get_mctrl = timbuart_get_mctrl,
    387	.stop_tx = timbuart_stop_tx,
    388	.start_tx = timbuart_start_tx,
    389	.flush_buffer = timbuart_flush_buffer,
    390	.stop_rx = timbuart_stop_rx,
    391	.break_ctl = timbuart_break_ctl,
    392	.startup = timbuart_startup,
    393	.shutdown = timbuart_shutdown,
    394	.set_termios = timbuart_set_termios,
    395	.type = timbuart_type,
    396	.release_port = timbuart_release_port,
    397	.request_port = timbuart_request_port,
    398	.config_port = timbuart_config_port,
    399	.verify_port = timbuart_verify_port
    400};
    401
    402static struct uart_driver timbuart_driver = {
    403	.owner = THIS_MODULE,
    404	.driver_name = "timberdale_uart",
    405	.dev_name = "ttyTU",
    406	.major = TIMBUART_MAJOR,
    407	.minor = TIMBUART_MINOR,
    408	.nr = 1
    409};
    410
    411static int timbuart_probe(struct platform_device *dev)
    412{
    413	int err, irq;
    414	struct timbuart_port *uart;
    415	struct resource *iomem;
    416
    417	dev_dbg(&dev->dev, "%s\n", __func__);
    418
    419	uart = kzalloc(sizeof(*uart), GFP_KERNEL);
    420	if (!uart) {
    421		err = -EINVAL;
    422		goto err_mem;
    423	}
    424
    425	uart->usedma = 0;
    426
    427	uart->port.uartclk = 3250000 * 16;
    428	uart->port.fifosize  = TIMBUART_FIFO_SIZE;
    429	uart->port.regshift  = 2;
    430	uart->port.iotype  = UPIO_MEM;
    431	uart->port.ops = &timbuart_ops;
    432	uart->port.irq = 0;
    433	uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
    434	uart->port.line  = 0;
    435	uart->port.dev	= &dev->dev;
    436
    437	iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
    438	if (!iomem) {
    439		err = -ENOMEM;
    440		goto err_register;
    441	}
    442	uart->port.mapbase = iomem->start;
    443	uart->port.membase = NULL;
    444
    445	irq = platform_get_irq(dev, 0);
    446	if (irq < 0) {
    447		err = -EINVAL;
    448		goto err_register;
    449	}
    450	uart->port.irq = irq;
    451
    452	tasklet_setup(&uart->tasklet, timbuart_tasklet);
    453
    454	err = uart_register_driver(&timbuart_driver);
    455	if (err)
    456		goto err_register;
    457
    458	err = uart_add_one_port(&timbuart_driver, &uart->port);
    459	if (err)
    460		goto err_add_port;
    461
    462	platform_set_drvdata(dev, uart);
    463
    464	return 0;
    465
    466err_add_port:
    467	uart_unregister_driver(&timbuart_driver);
    468err_register:
    469	kfree(uart);
    470err_mem:
    471	printk(KERN_ERR "timberdale: Failed to register Timberdale UART: %d\n",
    472		err);
    473
    474	return err;
    475}
    476
    477static int timbuart_remove(struct platform_device *dev)
    478{
    479	struct timbuart_port *uart = platform_get_drvdata(dev);
    480
    481	tasklet_kill(&uart->tasklet);
    482	uart_remove_one_port(&timbuart_driver, &uart->port);
    483	uart_unregister_driver(&timbuart_driver);
    484	kfree(uart);
    485
    486	return 0;
    487}
    488
    489static struct platform_driver timbuart_platform_driver = {
    490	.driver = {
    491		.name	= "timb-uart",
    492	},
    493	.probe		= timbuart_probe,
    494	.remove		= timbuart_remove,
    495};
    496
    497module_platform_driver(timbuart_platform_driver);
    498
    499MODULE_DESCRIPTION("Timberdale UART driver");
    500MODULE_LICENSE("GPL v2");
    501MODULE_ALIAS("platform:timb-uart");
    502