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);