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