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