663 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Driver for GRLIB serial ports (APBUART)4 *5 * Based on linux/drivers/serial/amba.c6 *7 * Copyright (C) 2000 Deep Blue Solutions Ltd.8 * Copyright (C) 2003 Konrad Eisele <eiselekd@web.de>9 * Copyright (C) 2006 Daniel Hellstrom <daniel@gaisler.com>, Aeroflex Gaisler AB10 * Copyright (C) 2008 Gilead Kutnick <kutnickg@zin-tech.com>11 * Copyright (C) 2009 Kristoffer Glembo <kristoffer@gaisler.com>, Aeroflex Gaisler AB12 */13 14#include <linux/module.h>15#include <linux/tty.h>16#include <linux/tty_flip.h>17#include <linux/ioport.h>18#include <linux/init.h>19#include <linux/serial.h>20#include <linux/console.h>21#include <linux/sysrq.h>22#include <linux/kthread.h>23#include <linux/device.h>24#include <linux/of.h>25#include <linux/platform_device.h>26#include <linux/io.h>27#include <linux/serial_core.h>28#include <asm/irq.h>29 30#include "apbuart.h"31 32#define SERIAL_APBUART_MAJOR TTY_MAJOR33#define SERIAL_APBUART_MINOR 6434#define UART_DUMMY_RSR_RX 0x8000 /* for ignore all read */35 36static void apbuart_tx_chars(struct uart_port *port);37 38static void apbuart_stop_tx(struct uart_port *port)39{40 unsigned int cr;41 42 cr = UART_GET_CTRL(port);43 cr &= ~UART_CTRL_TI;44 UART_PUT_CTRL(port, cr);45}46 47static void apbuart_start_tx(struct uart_port *port)48{49 unsigned int cr;50 51 cr = UART_GET_CTRL(port);52 cr |= UART_CTRL_TI;53 UART_PUT_CTRL(port, cr);54 55 if (UART_GET_STATUS(port) & UART_STATUS_THE)56 apbuart_tx_chars(port);57}58 59static void apbuart_stop_rx(struct uart_port *port)60{61 unsigned int cr;62 63 cr = UART_GET_CTRL(port);64 cr &= ~(UART_CTRL_RI);65 UART_PUT_CTRL(port, cr);66}67 68static void apbuart_rx_chars(struct uart_port *port)69{70 unsigned int status, rsr;71 unsigned int max_chars = port->fifosize;72 u8 ch, flag;73 74 status = UART_GET_STATUS(port);75 76 while (UART_RX_DATA(status) && (max_chars--)) {77 78 ch = UART_GET_CHAR(port);79 flag = TTY_NORMAL;80 81 port->icount.rx++;82 83 rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX;84 UART_PUT_STATUS(port, 0);85 if (rsr & UART_STATUS_ERR) {86 87 if (rsr & UART_STATUS_BR) {88 rsr &= ~(UART_STATUS_FE | UART_STATUS_PE);89 port->icount.brk++;90 if (uart_handle_break(port))91 goto ignore_char;92 } else if (rsr & UART_STATUS_PE) {93 port->icount.parity++;94 } else if (rsr & UART_STATUS_FE) {95 port->icount.frame++;96 }97 if (rsr & UART_STATUS_OE)98 port->icount.overrun++;99 100 rsr &= port->read_status_mask;101 102 if (rsr & UART_STATUS_PE)103 flag = TTY_PARITY;104 else if (rsr & UART_STATUS_FE)105 flag = TTY_FRAME;106 }107 108 if (uart_handle_sysrq_char(port, ch))109 goto ignore_char;110 111 uart_insert_char(port, rsr, UART_STATUS_OE, ch, flag);112 113 114 ignore_char:115 status = UART_GET_STATUS(port);116 }117 118 tty_flip_buffer_push(&port->state->port);119}120 121static void apbuart_tx_chars(struct uart_port *port)122{123 u8 ch;124 125 uart_port_tx_limited(port, ch, port->fifosize,126 true,127 UART_PUT_CHAR(port, ch),128 ({}));129}130 131static irqreturn_t apbuart_int(int irq, void *dev_id)132{133 struct uart_port *port = dev_id;134 unsigned int status;135 136 uart_port_lock(port);137 138 status = UART_GET_STATUS(port);139 if (status & UART_STATUS_DR)140 apbuart_rx_chars(port);141 if (status & UART_STATUS_THE)142 apbuart_tx_chars(port);143 144 uart_port_unlock(port);145 146 return IRQ_HANDLED;147}148 149static unsigned int apbuart_tx_empty(struct uart_port *port)150{151 unsigned int status = UART_GET_STATUS(port);152 return status & UART_STATUS_THE ? TIOCSER_TEMT : 0;153}154 155static unsigned int apbuart_get_mctrl(struct uart_port *port)156{157 /* The GRLIB APBUART handles flow control in hardware */158 return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;159}160 161static void apbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)162{163 /* The GRLIB APBUART handles flow control in hardware */164}165 166static void apbuart_break_ctl(struct uart_port *port, int break_state)167{168 /* We don't support sending break */169}170 171static int apbuart_startup(struct uart_port *port)172{173 int retval;174 unsigned int cr;175 176 /* Allocate the IRQ */177 retval = request_irq(port->irq, apbuart_int, 0, "apbuart", port);178 if (retval)179 return retval;180 181 /* Finally, enable interrupts */182 cr = UART_GET_CTRL(port);183 UART_PUT_CTRL(port,184 cr | UART_CTRL_RE | UART_CTRL_TE |185 UART_CTRL_RI | UART_CTRL_TI);186 187 return 0;188}189 190static void apbuart_shutdown(struct uart_port *port)191{192 unsigned int cr;193 194 /* disable all interrupts, disable the port */195 cr = UART_GET_CTRL(port);196 UART_PUT_CTRL(port,197 cr & ~(UART_CTRL_RE | UART_CTRL_TE |198 UART_CTRL_RI | UART_CTRL_TI));199 200 /* Free the interrupt */201 free_irq(port->irq, port);202}203 204static void apbuart_set_termios(struct uart_port *port,205 struct ktermios *termios, const struct ktermios *old)206{207 unsigned int cr;208 unsigned long flags;209 unsigned int baud, quot;210 211 /* Ask the core to calculate the divisor for us. */212 baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);213 if (baud == 0)214 panic("invalid baudrate %i\n", port->uartclk / 16);215 216 /* uart_get_divisor calc a *16 uart freq, apbuart is *8 */217 quot = (uart_get_divisor(port, baud)) * 2;218 cr = UART_GET_CTRL(port);219 cr &= ~(UART_CTRL_PE | UART_CTRL_PS);220 221 if (termios->c_cflag & PARENB) {222 cr |= UART_CTRL_PE;223 if ((termios->c_cflag & PARODD))224 cr |= UART_CTRL_PS;225 }226 227 /* Enable flow control. */228 if (termios->c_cflag & CRTSCTS)229 cr |= UART_CTRL_FL;230 231 uart_port_lock_irqsave(port, &flags);232 233 /* Update the per-port timeout. */234 uart_update_timeout(port, termios->c_cflag, baud);235 236 port->read_status_mask = UART_STATUS_OE;237 if (termios->c_iflag & INPCK)238 port->read_status_mask |= UART_STATUS_FE | UART_STATUS_PE;239 240 /* Characters to ignore */241 port->ignore_status_mask = 0;242 if (termios->c_iflag & IGNPAR)243 port->ignore_status_mask |= UART_STATUS_FE | UART_STATUS_PE;244 245 /* Ignore all characters if CREAD is not set. */246 if ((termios->c_cflag & CREAD) == 0)247 port->ignore_status_mask |= UART_DUMMY_RSR_RX;248 249 /* Set baud rate */250 quot -= 1;251 UART_PUT_SCAL(port, quot);252 UART_PUT_CTRL(port, cr);253 254 uart_port_unlock_irqrestore(port, flags);255}256 257static const char *apbuart_type(struct uart_port *port)258{259 return port->type == PORT_APBUART ? "GRLIB/APBUART" : NULL;260}261 262static void apbuart_release_port(struct uart_port *port)263{264 release_mem_region(port->mapbase, 0x100);265}266 267static int apbuart_request_port(struct uart_port *port)268{269 return request_mem_region(port->mapbase, 0x100, "grlib-apbuart")270 != NULL ? 0 : -EBUSY;271 return 0;272}273 274/* Configure/autoconfigure the port */275static void apbuart_config_port(struct uart_port *port, int flags)276{277 if (flags & UART_CONFIG_TYPE) {278 port->type = PORT_APBUART;279 apbuart_request_port(port);280 }281}282 283/* Verify the new serial_struct (for TIOCSSERIAL) */284static int apbuart_verify_port(struct uart_port *port,285 struct serial_struct *ser)286{287 int ret = 0;288 if (ser->type != PORT_UNKNOWN && ser->type != PORT_APBUART)289 ret = -EINVAL;290 if (ser->irq < 0 || ser->irq >= NR_IRQS)291 ret = -EINVAL;292 if (ser->baud_base < 9600)293 ret = -EINVAL;294 return ret;295}296 297static const struct uart_ops grlib_apbuart_ops = {298 .tx_empty = apbuart_tx_empty,299 .set_mctrl = apbuart_set_mctrl,300 .get_mctrl = apbuart_get_mctrl,301 .stop_tx = apbuart_stop_tx,302 .start_tx = apbuart_start_tx,303 .stop_rx = apbuart_stop_rx,304 .break_ctl = apbuart_break_ctl,305 .startup = apbuart_startup,306 .shutdown = apbuart_shutdown,307 .set_termios = apbuart_set_termios,308 .type = apbuart_type,309 .release_port = apbuart_release_port,310 .request_port = apbuart_request_port,311 .config_port = apbuart_config_port,312 .verify_port = apbuart_verify_port,313};314 315static struct uart_port grlib_apbuart_ports[UART_NR];316static struct device_node *grlib_apbuart_nodes[UART_NR];317 318static int apbuart_scan_fifo_size(struct uart_port *port, int portnumber)319{320 int ctrl, loop = 0;321 int status;322 int fifosize;323 unsigned long flags;324 325 ctrl = UART_GET_CTRL(port);326 327 /*328 * Enable the transceiver and wait for it to be ready to send data.329 * Clear interrupts so that this process will not be externally330 * interrupted in the middle (which can cause the transceiver to331 * drain prematurely).332 */333 334 local_irq_save(flags);335 336 UART_PUT_CTRL(port, ctrl | UART_CTRL_TE);337 338 while (!UART_TX_READY(UART_GET_STATUS(port)))339 loop++;340 341 /*342 * Disable the transceiver so data isn't actually sent during the343 * actual test.344 */345 346 UART_PUT_CTRL(port, ctrl & ~(UART_CTRL_TE));347 348 fifosize = 1;349 UART_PUT_CHAR(port, 0);350 351 /*352 * So long as transmitting a character increments the tranceivier FIFO353 * length the FIFO must be at least that big. These bytes will354 * automatically drain off of the FIFO.355 */356 357 status = UART_GET_STATUS(port);358 while (((status >> 20) & 0x3F) == fifosize) {359 fifosize++;360 UART_PUT_CHAR(port, 0);361 status = UART_GET_STATUS(port);362 }363 364 fifosize--;365 366 UART_PUT_CTRL(port, ctrl);367 local_irq_restore(flags);368 369 if (fifosize == 0)370 fifosize = 1;371 372 return fifosize;373}374 375static void apbuart_flush_fifo(struct uart_port *port)376{377 int i;378 379 for (i = 0; i < port->fifosize; i++)380 UART_GET_CHAR(port);381}382 383 384/* ======================================================================== */385/* Console driver, if enabled */386/* ======================================================================== */387 388#ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE389 390static void apbuart_console_putchar(struct uart_port *port, unsigned char ch)391{392 unsigned int status;393 do {394 status = UART_GET_STATUS(port);395 } while (!UART_TX_READY(status));396 UART_PUT_CHAR(port, ch);397}398 399static void400apbuart_console_write(struct console *co, const char *s, unsigned int count)401{402 struct uart_port *port = &grlib_apbuart_ports[co->index];403 unsigned int status, old_cr, new_cr;404 405 /* First save the CR then disable the interrupts */406 old_cr = UART_GET_CTRL(port);407 new_cr = old_cr & ~(UART_CTRL_RI | UART_CTRL_TI);408 UART_PUT_CTRL(port, new_cr);409 410 uart_console_write(port, s, count, apbuart_console_putchar);411 412 /*413 * Finally, wait for transmitter to become empty414 * and restore the TCR415 */416 do {417 status = UART_GET_STATUS(port);418 } while (!UART_TX_READY(status));419 UART_PUT_CTRL(port, old_cr);420}421 422static void __init423apbuart_console_get_options(struct uart_port *port, int *baud,424 int *parity, int *bits)425{426 if (UART_GET_CTRL(port) & (UART_CTRL_RE | UART_CTRL_TE)) {427 428 unsigned int quot, status;429 status = UART_GET_STATUS(port);430 431 *parity = 'n';432 if (status & UART_CTRL_PE) {433 if ((status & UART_CTRL_PS) == 0)434 *parity = 'e';435 else436 *parity = 'o';437 }438 439 *bits = 8;440 quot = UART_GET_SCAL(port) / 8;441 *baud = port->uartclk / (16 * (quot + 1));442 }443}444 445static int __init apbuart_console_setup(struct console *co, char *options)446{447 struct uart_port *port;448 int baud = 38400;449 int bits = 8;450 int parity = 'n';451 int flow = 'n';452 453 pr_debug("apbuart_console_setup co=%p, co->index=%i, options=%s\n",454 co, co->index, options);455 456 /*457 * Check whether an invalid uart number has been specified, and458 * if so, search for the first available port that does have459 * console support.460 */461 if (co->index >= grlib_apbuart_port_nr)462 co->index = 0;463 464 port = &grlib_apbuart_ports[co->index];465 466 spin_lock_init(&port->lock);467 468 if (options)469 uart_parse_options(options, &baud, &parity, &bits, &flow);470 else471 apbuart_console_get_options(port, &baud, &parity, &bits);472 473 return uart_set_options(port, co, baud, parity, bits, flow);474}475 476static struct uart_driver grlib_apbuart_driver;477 478static struct console grlib_apbuart_console = {479 .name = "ttyS",480 .write = apbuart_console_write,481 .device = uart_console_device,482 .setup = apbuart_console_setup,483 .flags = CON_PRINTBUFFER,484 .index = -1,485 .data = &grlib_apbuart_driver,486};487 488 489static int grlib_apbuart_configure(void);490 491static int __init apbuart_console_init(void)492{493 if (grlib_apbuart_configure())494 return -ENODEV;495 register_console(&grlib_apbuart_console);496 return 0;497}498 499console_initcall(apbuart_console_init);500 501#define APBUART_CONSOLE (&grlib_apbuart_console)502#else503#define APBUART_CONSOLE NULL504#endif505 506static struct uart_driver grlib_apbuart_driver = {507 .owner = THIS_MODULE,508 .driver_name = "serial",509 .dev_name = "ttyS",510 .major = SERIAL_APBUART_MAJOR,511 .minor = SERIAL_APBUART_MINOR,512 .nr = UART_NR,513 .cons = APBUART_CONSOLE,514};515 516 517/* ======================================================================== */518/* OF Platform Driver */519/* ======================================================================== */520 521static int apbuart_probe(struct platform_device *op)522{523 int i;524 struct uart_port *port = NULL;525 526 for (i = 0; i < grlib_apbuart_port_nr; i++) {527 if (op->dev.of_node == grlib_apbuart_nodes[i])528 break;529 }530 531 port = &grlib_apbuart_ports[i];532 port->dev = &op->dev;533 port->irq = op->archdata.irqs[0];534 535 uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *) port);536 537 apbuart_flush_fifo((struct uart_port *) port);538 539 printk(KERN_INFO "grlib-apbuart at 0x%llx, irq %d\n",540 (unsigned long long) port->mapbase, port->irq);541 return 0;542}543 544static const struct of_device_id apbuart_match[] = {545 {546 .name = "GAISLER_APBUART",547 },548 {549 .name = "01_00c",550 },551 {},552};553MODULE_DEVICE_TABLE(of, apbuart_match);554 555static struct platform_driver grlib_apbuart_of_driver = {556 .probe = apbuart_probe,557 .driver = {558 .name = "grlib-apbuart",559 .of_match_table = apbuart_match,560 },561};562 563 564static int __init grlib_apbuart_configure(void)565{566 struct device_node *np;567 int line = 0;568 569 for_each_matching_node(np, apbuart_match) {570 const int *ampopts;571 const u32 *freq_hz;572 const struct amba_prom_registers *regs;573 struct uart_port *port;574 unsigned long addr;575 576 ampopts = of_get_property(np, "ampopts", NULL);577 if (ampopts && (*ampopts == 0))578 continue; /* Ignore if used by another OS instance */579 regs = of_get_property(np, "reg", NULL);580 /* Frequency of APB Bus is frequency of UART */581 freq_hz = of_get_property(np, "freq", NULL);582 583 if (!regs || !freq_hz || (*freq_hz == 0))584 continue;585 586 grlib_apbuart_nodes[line] = np;587 588 addr = regs->phys_addr;589 590 port = &grlib_apbuart_ports[line];591 592 port->mapbase = addr;593 port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map));594 port->irq = 0;595 port->iotype = UPIO_MEM;596 port->ops = &grlib_apbuart_ops;597 port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE);598 port->flags = UPF_BOOT_AUTOCONF;599 port->line = line;600 port->uartclk = *freq_hz;601 port->fifosize = apbuart_scan_fifo_size((struct uart_port *) port, line);602 line++;603 604 /* We support maximum UART_NR uarts ... */605 if (line == UART_NR)606 break;607 }608 609 grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line;610 return line ? 0 : -ENODEV;611}612 613static int __init grlib_apbuart_init(void)614{615 int ret;616 617 /* Find all APBUARTS in device the tree and initialize their ports */618 ret = grlib_apbuart_configure();619 if (ret)620 return ret;621 622 printk(KERN_INFO "Serial: GRLIB APBUART driver\n");623 624 ret = uart_register_driver(&grlib_apbuart_driver);625 626 if (ret) {627 printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",628 __FILE__, ret);629 return ret;630 }631 632 ret = platform_driver_register(&grlib_apbuart_of_driver);633 if (ret) {634 printk(KERN_ERR635 "%s: platform_driver_register failed (%i)\n",636 __FILE__, ret);637 uart_unregister_driver(&grlib_apbuart_driver);638 return ret;639 }640 641 return ret;642}643 644static void __exit grlib_apbuart_exit(void)645{646 int i;647 648 for (i = 0; i < grlib_apbuart_port_nr; i++)649 uart_remove_one_port(&grlib_apbuart_driver,650 &grlib_apbuart_ports[i]);651 652 uart_unregister_driver(&grlib_apbuart_driver);653 platform_driver_unregister(&grlib_apbuart_of_driver);654}655 656module_init(grlib_apbuart_init);657module_exit(grlib_apbuart_exit);658 659MODULE_AUTHOR("Aeroflex Gaisler AB");660MODULE_DESCRIPTION("GRLIB APBUART serial driver");661MODULE_VERSION("2.1");662MODULE_LICENSE("GPL");663