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

altera_jtaguart.c (13692B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * altera_jtaguart.c -- Altera JTAG UART driver
      4 *
      5 * Based on mcf.c -- Freescale ColdFire UART driver
      6 *
      7 * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
      8 * (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
      9 * (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
     10 */
     11
     12#include <linux/kernel.h>
     13#include <linux/init.h>
     14#include <linux/interrupt.h>
     15#include <linux/module.h>
     16#include <linux/console.h>
     17#include <linux/of.h>
     18#include <linux/tty.h>
     19#include <linux/tty_flip.h>
     20#include <linux/serial.h>
     21#include <linux/serial_core.h>
     22#include <linux/platform_device.h>
     23#include <linux/io.h>
     24#include <linux/altera_jtaguart.h>
     25
     26#define DRV_NAME "altera_jtaguart"
     27
     28/*
     29 * Altera JTAG UART register definitions according to the Altera JTAG UART
     30 * datasheet: https://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf
     31 */
     32
     33#define ALTERA_JTAGUART_SIZE			8
     34
     35#define ALTERA_JTAGUART_DATA_REG		0
     36
     37#define ALTERA_JTAGUART_DATA_DATA_MSK		0x000000FF
     38#define ALTERA_JTAGUART_DATA_RVALID_MSK		0x00008000
     39#define ALTERA_JTAGUART_DATA_RAVAIL_MSK		0xFFFF0000
     40#define ALTERA_JTAGUART_DATA_RAVAIL_OFF		16
     41
     42#define ALTERA_JTAGUART_CONTROL_REG		4
     43
     44#define ALTERA_JTAGUART_CONTROL_RE_MSK		0x00000001
     45#define ALTERA_JTAGUART_CONTROL_WE_MSK		0x00000002
     46#define ALTERA_JTAGUART_CONTROL_RI_MSK		0x00000100
     47#define ALTERA_JTAGUART_CONTROL_RI_OFF		8
     48#define ALTERA_JTAGUART_CONTROL_WI_MSK		0x00000200
     49#define ALTERA_JTAGUART_CONTROL_AC_MSK		0x00000400
     50#define ALTERA_JTAGUART_CONTROL_WSPACE_MSK	0xFFFF0000
     51#define ALTERA_JTAGUART_CONTROL_WSPACE_OFF	16
     52
     53/*
     54 * Local per-uart structure.
     55 */
     56struct altera_jtaguart {
     57	struct uart_port port;
     58	unsigned int sigs;	/* Local copy of line sigs */
     59	unsigned long imr;	/* Local IMR mirror */
     60};
     61
     62static unsigned int altera_jtaguart_tx_empty(struct uart_port *port)
     63{
     64	return (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
     65		ALTERA_JTAGUART_CONTROL_WSPACE_MSK) ? TIOCSER_TEMT : 0;
     66}
     67
     68static unsigned int altera_jtaguart_get_mctrl(struct uart_port *port)
     69{
     70	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
     71}
     72
     73static void altera_jtaguart_set_mctrl(struct uart_port *port, unsigned int sigs)
     74{
     75}
     76
     77static void altera_jtaguart_start_tx(struct uart_port *port)
     78{
     79	struct altera_jtaguart *pp =
     80	    container_of(port, struct altera_jtaguart, port);
     81
     82	pp->imr |= ALTERA_JTAGUART_CONTROL_WE_MSK;
     83	writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
     84}
     85
     86static void altera_jtaguart_stop_tx(struct uart_port *port)
     87{
     88	struct altera_jtaguart *pp =
     89	    container_of(port, struct altera_jtaguart, port);
     90
     91	pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
     92	writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
     93}
     94
     95static void altera_jtaguart_stop_rx(struct uart_port *port)
     96{
     97	struct altera_jtaguart *pp =
     98	    container_of(port, struct altera_jtaguart, port);
     99
    100	pp->imr &= ~ALTERA_JTAGUART_CONTROL_RE_MSK;
    101	writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
    102}
    103
    104static void altera_jtaguart_break_ctl(struct uart_port *port, int break_state)
    105{
    106}
    107
    108static void altera_jtaguart_set_termios(struct uart_port *port,
    109					struct ktermios *termios,
    110					struct ktermios *old)
    111{
    112	/* Just copy the old termios settings back */
    113	if (old)
    114		tty_termios_copy_hw(termios, old);
    115}
    116
    117static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp)
    118{
    119	struct uart_port *port = &pp->port;
    120	unsigned char ch, flag;
    121	unsigned long status;
    122
    123	while ((status = readl(port->membase + ALTERA_JTAGUART_DATA_REG)) &
    124	       ALTERA_JTAGUART_DATA_RVALID_MSK) {
    125		ch = status & ALTERA_JTAGUART_DATA_DATA_MSK;
    126		flag = TTY_NORMAL;
    127		port->icount.rx++;
    128
    129		if (uart_handle_sysrq_char(port, ch))
    130			continue;
    131		uart_insert_char(port, 0, 0, ch, flag);
    132	}
    133
    134	tty_flip_buffer_push(&port->state->port);
    135}
    136
    137static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp)
    138{
    139	struct uart_port *port = &pp->port;
    140	struct circ_buf *xmit = &port->state->xmit;
    141	unsigned int pending, count;
    142
    143	if (port->x_char) {
    144		/* Send special char - probably flow control */
    145		writel(port->x_char, port->membase + ALTERA_JTAGUART_DATA_REG);
    146		port->x_char = 0;
    147		port->icount.tx++;
    148		return;
    149	}
    150
    151	pending = uart_circ_chars_pending(xmit);
    152	if (pending > 0) {
    153		count = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
    154				ALTERA_JTAGUART_CONTROL_WSPACE_MSK) >>
    155			ALTERA_JTAGUART_CONTROL_WSPACE_OFF;
    156		if (count > pending)
    157			count = pending;
    158		if (count > 0) {
    159			pending -= count;
    160			while (count--) {
    161				writel(xmit->buf[xmit->tail],
    162				       port->membase + ALTERA_JTAGUART_DATA_REG);
    163				xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
    164				port->icount.tx++;
    165			}
    166			if (pending < WAKEUP_CHARS)
    167				uart_write_wakeup(port);
    168		}
    169	}
    170
    171	if (pending == 0)
    172		altera_jtaguart_stop_tx(port);
    173}
    174
    175static irqreturn_t altera_jtaguart_interrupt(int irq, void *data)
    176{
    177	struct uart_port *port = data;
    178	struct altera_jtaguart *pp =
    179	    container_of(port, struct altera_jtaguart, port);
    180	unsigned int isr;
    181
    182	isr = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) >>
    183	       ALTERA_JTAGUART_CONTROL_RI_OFF) & pp->imr;
    184
    185	spin_lock(&port->lock);
    186
    187	if (isr & ALTERA_JTAGUART_CONTROL_RE_MSK)
    188		altera_jtaguart_rx_chars(pp);
    189	if (isr & ALTERA_JTAGUART_CONTROL_WE_MSK)
    190		altera_jtaguart_tx_chars(pp);
    191
    192	spin_unlock(&port->lock);
    193
    194	return IRQ_RETVAL(isr);
    195}
    196
    197static void altera_jtaguart_config_port(struct uart_port *port, int flags)
    198{
    199	port->type = PORT_ALTERA_JTAGUART;
    200
    201	/* Clear mask, so no surprise interrupts. */
    202	writel(0, port->membase + ALTERA_JTAGUART_CONTROL_REG);
    203}
    204
    205static int altera_jtaguart_startup(struct uart_port *port)
    206{
    207	struct altera_jtaguart *pp =
    208	    container_of(port, struct altera_jtaguart, port);
    209	unsigned long flags;
    210	int ret;
    211
    212	ret = request_irq(port->irq, altera_jtaguart_interrupt, 0,
    213			DRV_NAME, port);
    214	if (ret) {
    215		pr_err(DRV_NAME ": unable to attach Altera JTAG UART %d "
    216		       "interrupt vector=%d\n", port->line, port->irq);
    217		return ret;
    218	}
    219
    220	spin_lock_irqsave(&port->lock, flags);
    221
    222	/* Enable RX interrupts now */
    223	pp->imr = ALTERA_JTAGUART_CONTROL_RE_MSK;
    224	writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
    225
    226	spin_unlock_irqrestore(&port->lock, flags);
    227
    228	return 0;
    229}
    230
    231static void altera_jtaguart_shutdown(struct uart_port *port)
    232{
    233	struct altera_jtaguart *pp =
    234	    container_of(port, struct altera_jtaguart, port);
    235	unsigned long flags;
    236
    237	spin_lock_irqsave(&port->lock, flags);
    238
    239	/* Disable all interrupts now */
    240	pp->imr = 0;
    241	writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
    242
    243	spin_unlock_irqrestore(&port->lock, flags);
    244
    245	free_irq(port->irq, port);
    246}
    247
    248static const char *altera_jtaguart_type(struct uart_port *port)
    249{
    250	return (port->type == PORT_ALTERA_JTAGUART) ? "Altera JTAG UART" : NULL;
    251}
    252
    253static int altera_jtaguart_request_port(struct uart_port *port)
    254{
    255	/* UARTs always present */
    256	return 0;
    257}
    258
    259static void altera_jtaguart_release_port(struct uart_port *port)
    260{
    261	/* Nothing to release... */
    262}
    263
    264static int altera_jtaguart_verify_port(struct uart_port *port,
    265				       struct serial_struct *ser)
    266{
    267	if (ser->type != PORT_UNKNOWN && ser->type != PORT_ALTERA_JTAGUART)
    268		return -EINVAL;
    269	return 0;
    270}
    271
    272/*
    273 *	Define the basic serial functions we support.
    274 */
    275static const struct uart_ops altera_jtaguart_ops = {
    276	.tx_empty	= altera_jtaguart_tx_empty,
    277	.get_mctrl	= altera_jtaguart_get_mctrl,
    278	.set_mctrl	= altera_jtaguart_set_mctrl,
    279	.start_tx	= altera_jtaguart_start_tx,
    280	.stop_tx	= altera_jtaguart_stop_tx,
    281	.stop_rx	= altera_jtaguart_stop_rx,
    282	.break_ctl	= altera_jtaguart_break_ctl,
    283	.startup	= altera_jtaguart_startup,
    284	.shutdown	= altera_jtaguart_shutdown,
    285	.set_termios	= altera_jtaguart_set_termios,
    286	.type		= altera_jtaguart_type,
    287	.request_port	= altera_jtaguart_request_port,
    288	.release_port	= altera_jtaguart_release_port,
    289	.config_port	= altera_jtaguart_config_port,
    290	.verify_port	= altera_jtaguart_verify_port,
    291};
    292
    293#define ALTERA_JTAGUART_MAXPORTS 1
    294static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS];
    295
    296#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE)
    297
    298#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS)
    299static void altera_jtaguart_console_putc(struct uart_port *port, unsigned char c)
    300{
    301	unsigned long status;
    302	unsigned long flags;
    303
    304	spin_lock_irqsave(&port->lock, flags);
    305	while (((status = readl(port->membase + ALTERA_JTAGUART_CONTROL_REG)) &
    306		ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
    307		if ((status & ALTERA_JTAGUART_CONTROL_AC_MSK) == 0) {
    308			spin_unlock_irqrestore(&port->lock, flags);
    309			return;	/* no connection activity */
    310		}
    311		spin_unlock_irqrestore(&port->lock, flags);
    312		cpu_relax();
    313		spin_lock_irqsave(&port->lock, flags);
    314	}
    315	writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
    316	spin_unlock_irqrestore(&port->lock, flags);
    317}
    318#else
    319static void altera_jtaguart_console_putc(struct uart_port *port, unsigned char c)
    320{
    321	unsigned long flags;
    322
    323	spin_lock_irqsave(&port->lock, flags);
    324	while ((readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
    325		ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
    326		spin_unlock_irqrestore(&port->lock, flags);
    327		cpu_relax();
    328		spin_lock_irqsave(&port->lock, flags);
    329	}
    330	writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
    331	spin_unlock_irqrestore(&port->lock, flags);
    332}
    333#endif
    334
    335static void altera_jtaguart_console_write(struct console *co, const char *s,
    336					  unsigned int count)
    337{
    338	struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
    339
    340	uart_console_write(port, s, count, altera_jtaguart_console_putc);
    341}
    342
    343static int __init altera_jtaguart_console_setup(struct console *co,
    344						char *options)
    345{
    346	struct uart_port *port;
    347
    348	if (co->index < 0 || co->index >= ALTERA_JTAGUART_MAXPORTS)
    349		return -EINVAL;
    350	port = &altera_jtaguart_ports[co->index].port;
    351	if (port->membase == NULL)
    352		return -ENODEV;
    353	return 0;
    354}
    355
    356static struct uart_driver altera_jtaguart_driver;
    357
    358static struct console altera_jtaguart_console = {
    359	.name	= "ttyJ",
    360	.write	= altera_jtaguart_console_write,
    361	.device	= uart_console_device,
    362	.setup	= altera_jtaguart_console_setup,
    363	.flags	= CON_PRINTBUFFER,
    364	.index	= -1,
    365	.data	= &altera_jtaguart_driver,
    366};
    367
    368static int __init altera_jtaguart_console_init(void)
    369{
    370	register_console(&altera_jtaguart_console);
    371	return 0;
    372}
    373
    374console_initcall(altera_jtaguart_console_init);
    375
    376#define	ALTERA_JTAGUART_CONSOLE	(&altera_jtaguart_console)
    377
    378static void altera_jtaguart_earlycon_write(struct console *co, const char *s,
    379					   unsigned int count)
    380{
    381	struct earlycon_device *dev = co->data;
    382
    383	uart_console_write(&dev->port, s, count, altera_jtaguart_console_putc);
    384}
    385
    386static int __init altera_jtaguart_earlycon_setup(struct earlycon_device *dev,
    387						 const char *options)
    388{
    389	if (!dev->port.membase)
    390		return -ENODEV;
    391
    392	dev->con->write = altera_jtaguart_earlycon_write;
    393	return 0;
    394}
    395
    396OF_EARLYCON_DECLARE(juart, "altr,juart-1.0", altera_jtaguart_earlycon_setup);
    397
    398#else
    399
    400#define	ALTERA_JTAGUART_CONSOLE	NULL
    401
    402#endif /* CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE */
    403
    404static struct uart_driver altera_jtaguart_driver = {
    405	.owner		= THIS_MODULE,
    406	.driver_name	= "altera_jtaguart",
    407	.dev_name	= "ttyJ",
    408	.major		= ALTERA_JTAGUART_MAJOR,
    409	.minor		= ALTERA_JTAGUART_MINOR,
    410	.nr		= ALTERA_JTAGUART_MAXPORTS,
    411	.cons		= ALTERA_JTAGUART_CONSOLE,
    412};
    413
    414static int altera_jtaguart_probe(struct platform_device *pdev)
    415{
    416	struct altera_jtaguart_platform_uart *platp =
    417			dev_get_platdata(&pdev->dev);
    418	struct uart_port *port;
    419	struct resource *res_mem;
    420	int i = pdev->id;
    421	int irq;
    422
    423	/* -1 emphasizes that the platform must have one port, no .N suffix */
    424	if (i == -1)
    425		i = 0;
    426
    427	if (i >= ALTERA_JTAGUART_MAXPORTS)
    428		return -EINVAL;
    429
    430	port = &altera_jtaguart_ports[i].port;
    431
    432	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    433	if (res_mem)
    434		port->mapbase = res_mem->start;
    435	else if (platp)
    436		port->mapbase = platp->mapbase;
    437	else
    438		return -ENODEV;
    439
    440	irq = platform_get_irq_optional(pdev, 0);
    441	if (irq < 0 && irq != -ENXIO)
    442		return irq;
    443	if (irq > 0)
    444		port->irq = irq;
    445	else if (platp)
    446		port->irq = platp->irq;
    447	else
    448		return -ENODEV;
    449
    450	port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
    451	if (!port->membase)
    452		return -ENOMEM;
    453
    454	port->line = i;
    455	port->type = PORT_ALTERA_JTAGUART;
    456	port->iotype = SERIAL_IO_MEM;
    457	port->ops = &altera_jtaguart_ops;
    458	port->flags = UPF_BOOT_AUTOCONF;
    459	port->dev = &pdev->dev;
    460
    461	uart_add_one_port(&altera_jtaguart_driver, port);
    462
    463	return 0;
    464}
    465
    466static int altera_jtaguart_remove(struct platform_device *pdev)
    467{
    468	struct uart_port *port;
    469	int i = pdev->id;
    470
    471	if (i == -1)
    472		i = 0;
    473
    474	port = &altera_jtaguart_ports[i].port;
    475	uart_remove_one_port(&altera_jtaguart_driver, port);
    476	iounmap(port->membase);
    477
    478	return 0;
    479}
    480
    481#ifdef CONFIG_OF
    482static const struct of_device_id altera_jtaguart_match[] = {
    483	{ .compatible = "ALTR,juart-1.0", },
    484	{ .compatible = "altr,juart-1.0", },
    485	{},
    486};
    487MODULE_DEVICE_TABLE(of, altera_jtaguart_match);
    488#endif /* CONFIG_OF */
    489
    490static struct platform_driver altera_jtaguart_platform_driver = {
    491	.probe	= altera_jtaguart_probe,
    492	.remove	= altera_jtaguart_remove,
    493	.driver	= {
    494		.name		= DRV_NAME,
    495		.of_match_table	= of_match_ptr(altera_jtaguart_match),
    496	},
    497};
    498
    499static int __init altera_jtaguart_init(void)
    500{
    501	int rc;
    502
    503	rc = uart_register_driver(&altera_jtaguart_driver);
    504	if (rc)
    505		return rc;
    506	rc = platform_driver_register(&altera_jtaguart_platform_driver);
    507	if (rc)
    508		uart_unregister_driver(&altera_jtaguart_driver);
    509	return rc;
    510}
    511
    512static void __exit altera_jtaguart_exit(void)
    513{
    514	platform_driver_unregister(&altera_jtaguart_platform_driver);
    515	uart_unregister_driver(&altera_jtaguart_driver);
    516}
    517
    518module_init(altera_jtaguart_init);
    519module_exit(altera_jtaguart_exit);
    520
    521MODULE_DESCRIPTION("Altera JTAG UART driver");
    522MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
    523MODULE_LICENSE("GPL");
    524MODULE_ALIAS("platform:" DRV_NAME);