805 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Driver for AMBA serial ports4 *5 * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.6 *7 * Copyright 1999 ARM Limited8 * Copyright (C) 2000 Deep Blue Solutions Ltd.9 *10 * This is a generic driver for ARM AMBA-type serial ports. They11 * have a lot of 16550-like features, but are not register compatible.12 * Note that although they do have CTS, DCD and DSR inputs, they do13 * not have an RI input, nor do they have DTR or RTS outputs. If14 * required, these have to be supplied via some other means (eg, GPIO)15 * and hooked into this driver.16 */17 18#include <linux/module.h>19#include <linux/ioport.h>20#include <linux/init.h>21#include <linux/console.h>22#include <linux/sysrq.h>23#include <linux/device.h>24#include <linux/tty.h>25#include <linux/tty_flip.h>26#include <linux/serial_core.h>27#include <linux/serial.h>28#include <linux/amba/bus.h>29#include <linux/amba/serial.h>30#include <linux/clk.h>31#include <linux/slab.h>32#include <linux/io.h>33 34#define UART_NR 835 36#define SERIAL_AMBA_MAJOR 20437#define SERIAL_AMBA_MINOR 1638#define SERIAL_AMBA_NR UART_NR39 40#define AMBA_ISR_PASS_LIMIT 25641 42#define UART_RX_DATA(s) (((s) & UART01x_FR_RXFE) == 0)43#define UART_TX_READY(s) (((s) & UART01x_FR_TXFF) == 0)44 45#define UART_DUMMY_RSR_RX 25646#define UART_PORT_SIZE 6447 48/*49 * We wrap our port structure around the generic uart_port.50 */51struct uart_amba_port {52 struct uart_port port;53 struct clk *clk;54 struct amba_device *dev;55 struct amba_pl010_data *data;56 unsigned int old_status;57};58 59static void pl010_stop_tx(struct uart_port *port)60{61 struct uart_amba_port *uap =62 container_of(port, struct uart_amba_port, port);63 unsigned int cr;64 65 cr = readb(uap->port.membase + UART010_CR);66 cr &= ~UART010_CR_TIE;67 writel(cr, uap->port.membase + UART010_CR);68}69 70static void pl010_start_tx(struct uart_port *port)71{72 struct uart_amba_port *uap =73 container_of(port, struct uart_amba_port, port);74 unsigned int cr;75 76 cr = readb(uap->port.membase + UART010_CR);77 cr |= UART010_CR_TIE;78 writel(cr, uap->port.membase + UART010_CR);79}80 81static void pl010_stop_rx(struct uart_port *port)82{83 struct uart_amba_port *uap =84 container_of(port, struct uart_amba_port, port);85 unsigned int cr;86 87 cr = readb(uap->port.membase + UART010_CR);88 cr &= ~(UART010_CR_RIE | UART010_CR_RTIE);89 writel(cr, uap->port.membase + UART010_CR);90}91 92static void pl010_disable_ms(struct uart_port *port)93{94 struct uart_amba_port *uap = (struct uart_amba_port *)port;95 unsigned int cr;96 97 cr = readb(uap->port.membase + UART010_CR);98 cr &= ~UART010_CR_MSIE;99 writel(cr, uap->port.membase + UART010_CR);100}101 102static void pl010_enable_ms(struct uart_port *port)103{104 struct uart_amba_port *uap =105 container_of(port, struct uart_amba_port, port);106 unsigned int cr;107 108 cr = readb(uap->port.membase + UART010_CR);109 cr |= UART010_CR_MSIE;110 writel(cr, uap->port.membase + UART010_CR);111}112 113static void pl010_rx_chars(struct uart_port *port)114{115 unsigned int status, rsr, max_count = 256;116 u8 ch, flag;117 118 status = readb(port->membase + UART01x_FR);119 while (UART_RX_DATA(status) && max_count--) {120 ch = readb(port->membase + UART01x_DR);121 flag = TTY_NORMAL;122 123 port->icount.rx++;124 125 /*126 * Note that the error handling code is127 * out of the main execution path128 */129 rsr = readb(port->membase + UART01x_RSR) | UART_DUMMY_RSR_RX;130 if (unlikely(rsr & UART01x_RSR_ANY)) {131 writel(0, port->membase + UART01x_ECR);132 133 if (rsr & UART01x_RSR_BE) {134 rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE);135 port->icount.brk++;136 if (uart_handle_break(port))137 goto ignore_char;138 } else if (rsr & UART01x_RSR_PE)139 port->icount.parity++;140 else if (rsr & UART01x_RSR_FE)141 port->icount.frame++;142 if (rsr & UART01x_RSR_OE)143 port->icount.overrun++;144 145 rsr &= port->read_status_mask;146 147 if (rsr & UART01x_RSR_BE)148 flag = TTY_BREAK;149 else if (rsr & UART01x_RSR_PE)150 flag = TTY_PARITY;151 else if (rsr & UART01x_RSR_FE)152 flag = TTY_FRAME;153 }154 155 if (uart_handle_sysrq_char(port, ch))156 goto ignore_char;157 158 uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag);159 160 ignore_char:161 status = readb(port->membase + UART01x_FR);162 }163 tty_flip_buffer_push(&port->state->port);164}165 166static void pl010_tx_chars(struct uart_port *port)167{168 u8 ch;169 170 uart_port_tx_limited(port, ch, port->fifosize >> 1,171 true,172 writel(ch, port->membase + UART01x_DR),173 ({}));174}175 176static void pl010_modem_status(struct uart_amba_port *uap)177{178 struct uart_port *port = &uap->port;179 unsigned int status, delta;180 181 writel(0, port->membase + UART010_ICR);182 183 status = readb(port->membase + UART01x_FR) & UART01x_FR_MODEM_ANY;184 185 delta = status ^ uap->old_status;186 uap->old_status = status;187 188 if (!delta)189 return;190 191 if (delta & UART01x_FR_DCD)192 uart_handle_dcd_change(port, status & UART01x_FR_DCD);193 194 if (delta & UART01x_FR_DSR)195 port->icount.dsr++;196 197 if (delta & UART01x_FR_CTS)198 uart_handle_cts_change(port, status & UART01x_FR_CTS);199 200 wake_up_interruptible(&port->state->port.delta_msr_wait);201}202 203static irqreturn_t pl010_int(int irq, void *dev_id)204{205 struct uart_amba_port *uap = dev_id;206 struct uart_port *port = &uap->port;207 unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;208 int handled = 0;209 210 uart_port_lock(port);211 212 status = readb(port->membase + UART010_IIR);213 if (status) {214 do {215 if (status & (UART010_IIR_RTIS | UART010_IIR_RIS))216 pl010_rx_chars(port);217 if (status & UART010_IIR_MIS)218 pl010_modem_status(uap);219 if (status & UART010_IIR_TIS)220 pl010_tx_chars(port);221 222 if (pass_counter-- == 0)223 break;224 225 status = readb(port->membase + UART010_IIR);226 } while (status & (UART010_IIR_RTIS | UART010_IIR_RIS |227 UART010_IIR_TIS));228 handled = 1;229 }230 231 uart_port_unlock(port);232 233 return IRQ_RETVAL(handled);234}235 236static unsigned int pl010_tx_empty(struct uart_port *port)237{238 unsigned int status = readb(port->membase + UART01x_FR);239 240 return status & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT;241}242 243static unsigned int pl010_get_mctrl(struct uart_port *port)244{245 unsigned int result = 0;246 unsigned int status;247 248 status = readb(port->membase + UART01x_FR);249 if (status & UART01x_FR_DCD)250 result |= TIOCM_CAR;251 if (status & UART01x_FR_DSR)252 result |= TIOCM_DSR;253 if (status & UART01x_FR_CTS)254 result |= TIOCM_CTS;255 256 return result;257}258 259static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl)260{261 struct uart_amba_port *uap =262 container_of(port, struct uart_amba_port, port);263 264 if (uap->data)265 uap->data->set_mctrl(uap->dev, port->membase, mctrl);266}267 268static void pl010_break_ctl(struct uart_port *port, int break_state)269{270 unsigned long flags;271 unsigned int lcr_h;272 273 uart_port_lock_irqsave(port, &flags);274 lcr_h = readb(port->membase + UART010_LCRH);275 if (break_state == -1)276 lcr_h |= UART01x_LCRH_BRK;277 else278 lcr_h &= ~UART01x_LCRH_BRK;279 writel(lcr_h, port->membase + UART010_LCRH);280 uart_port_unlock_irqrestore(port, flags);281}282 283static int pl010_startup(struct uart_port *port)284{285 struct uart_amba_port *uap =286 container_of(port, struct uart_amba_port, port);287 int retval;288 289 /*290 * Try to enable the clock producer.291 */292 retval = clk_prepare_enable(uap->clk);293 if (retval)294 goto out;295 296 port->uartclk = clk_get_rate(uap->clk);297 298 /*299 * Allocate the IRQ300 */301 retval = request_irq(port->irq, pl010_int, 0, "uart-pl010", uap);302 if (retval)303 goto clk_dis;304 305 /*306 * initialise the old status of the modem signals307 */308 uap->old_status = readb(port->membase + UART01x_FR) & UART01x_FR_MODEM_ANY;309 310 /*311 * Finally, enable interrupts312 */313 writel(UART01x_CR_UARTEN | UART010_CR_RIE | UART010_CR_RTIE,314 port->membase + UART010_CR);315 316 return 0;317 318 clk_dis:319 clk_disable_unprepare(uap->clk);320 out:321 return retval;322}323 324static void pl010_shutdown(struct uart_port *port)325{326 struct uart_amba_port *uap =327 container_of(port, struct uart_amba_port, port);328 329 /*330 * Free the interrupt331 */332 free_irq(port->irq, uap);333 334 /*335 * disable all interrupts, disable the port336 */337 writel(0, port->membase + UART010_CR);338 339 /* disable break condition and fifos */340 writel(readb(port->membase + UART010_LCRH) &341 ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN),342 port->membase + UART010_LCRH);343 344 /*345 * Shut down the clock producer346 */347 clk_disable_unprepare(uap->clk);348}349 350static void351pl010_set_termios(struct uart_port *port, struct ktermios *termios,352 const struct ktermios *old)353{354 unsigned int lcr_h, old_cr;355 unsigned long flags;356 unsigned int baud, quot;357 358 /*359 * Ask the core to calculate the divisor for us.360 */361 baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);362 quot = uart_get_divisor(port, baud);363 364 switch (termios->c_cflag & CSIZE) {365 case CS5:366 lcr_h = UART01x_LCRH_WLEN_5;367 break;368 case CS6:369 lcr_h = UART01x_LCRH_WLEN_6;370 break;371 case CS7:372 lcr_h = UART01x_LCRH_WLEN_7;373 break;374 default: // CS8375 lcr_h = UART01x_LCRH_WLEN_8;376 break;377 }378 if (termios->c_cflag & CSTOPB)379 lcr_h |= UART01x_LCRH_STP2;380 if (termios->c_cflag & PARENB) {381 lcr_h |= UART01x_LCRH_PEN;382 if (!(termios->c_cflag & PARODD))383 lcr_h |= UART01x_LCRH_EPS;384 }385 if (port->fifosize > 1)386 lcr_h |= UART01x_LCRH_FEN;387 388 uart_port_lock_irqsave(port, &flags);389 390 /*391 * Update the per-port timeout.392 */393 uart_update_timeout(port, termios->c_cflag, baud);394 395 port->read_status_mask = UART01x_RSR_OE;396 if (termios->c_iflag & INPCK)397 port->read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;398 if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))399 port->read_status_mask |= UART01x_RSR_BE;400 401 /*402 * Characters to ignore403 */404 port->ignore_status_mask = 0;405 if (termios->c_iflag & IGNPAR)406 port->ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;407 if (termios->c_iflag & IGNBRK) {408 port->ignore_status_mask |= UART01x_RSR_BE;409 /*410 * If we're ignoring parity and break indicators,411 * ignore overruns too (for real raw support).412 */413 if (termios->c_iflag & IGNPAR)414 port->ignore_status_mask |= UART01x_RSR_OE;415 }416 417 /*418 * Ignore all characters if CREAD is not set.419 */420 if ((termios->c_cflag & CREAD) == 0)421 port->ignore_status_mask |= UART_DUMMY_RSR_RX;422 423 old_cr = readb(port->membase + UART010_CR) & ~UART010_CR_MSIE;424 425 if (UART_ENABLE_MS(port, termios->c_cflag))426 old_cr |= UART010_CR_MSIE;427 428 /* Set baud rate */429 quot -= 1;430 writel((quot & 0xf00) >> 8, port->membase + UART010_LCRM);431 writel(quot & 0xff, port->membase + UART010_LCRL);432 433 /*434 * ----------v----------v----------v----------v-----435 * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L436 * ----------^----------^----------^----------^-----437 */438 writel(lcr_h, port->membase + UART010_LCRH);439 writel(old_cr, port->membase + UART010_CR);440 441 uart_port_unlock_irqrestore(port, flags);442}443 444static void pl010_set_ldisc(struct uart_port *port, struct ktermios *termios)445{446 if (termios->c_line == N_PPS) {447 port->flags |= UPF_HARDPPS_CD;448 uart_port_lock_irq(port);449 pl010_enable_ms(port);450 uart_port_unlock_irq(port);451 } else {452 port->flags &= ~UPF_HARDPPS_CD;453 if (!UART_ENABLE_MS(port, termios->c_cflag)) {454 uart_port_lock_irq(port);455 pl010_disable_ms(port);456 uart_port_unlock_irq(port);457 }458 }459}460 461static const char *pl010_type(struct uart_port *port)462{463 return port->type == PORT_AMBA ? "AMBA" : NULL;464}465 466/*467 * Release the memory region(s) being used by 'port'468 */469static void pl010_release_port(struct uart_port *port)470{471 release_mem_region(port->mapbase, UART_PORT_SIZE);472}473 474/*475 * Request the memory region(s) being used by 'port'476 */477static int pl010_request_port(struct uart_port *port)478{479 return request_mem_region(port->mapbase, UART_PORT_SIZE, "uart-pl010")480 != NULL ? 0 : -EBUSY;481}482 483/*484 * Configure/autoconfigure the port.485 */486static void pl010_config_port(struct uart_port *port, int flags)487{488 if (flags & UART_CONFIG_TYPE) {489 port->type = PORT_AMBA;490 pl010_request_port(port);491 }492}493 494/*495 * verify the new serial_struct (for TIOCSSERIAL).496 */497static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)498{499 int ret = 0;500 if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)501 ret = -EINVAL;502 if (ser->irq < 0 || ser->irq >= nr_irqs)503 ret = -EINVAL;504 if (ser->baud_base < 9600)505 ret = -EINVAL;506 return ret;507}508 509static const struct uart_ops amba_pl010_pops = {510 .tx_empty = pl010_tx_empty,511 .set_mctrl = pl010_set_mctrl,512 .get_mctrl = pl010_get_mctrl,513 .stop_tx = pl010_stop_tx,514 .start_tx = pl010_start_tx,515 .stop_rx = pl010_stop_rx,516 .enable_ms = pl010_enable_ms,517 .break_ctl = pl010_break_ctl,518 .startup = pl010_startup,519 .shutdown = pl010_shutdown,520 .set_termios = pl010_set_termios,521 .set_ldisc = pl010_set_ldisc,522 .type = pl010_type,523 .release_port = pl010_release_port,524 .request_port = pl010_request_port,525 .config_port = pl010_config_port,526 .verify_port = pl010_verify_port,527};528 529static struct uart_amba_port *amba_ports[UART_NR];530 531#ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE532 533static void pl010_console_putchar(struct uart_port *port, unsigned char ch)534{535 unsigned int status;536 537 do {538 status = readb(port->membase + UART01x_FR);539 barrier();540 } while (!UART_TX_READY(status));541 writel(ch, port->membase + UART01x_DR);542}543 544static void545pl010_console_write(struct console *co, const char *s, unsigned int count)546{547 struct uart_amba_port *uap = amba_ports[co->index];548 struct uart_port *port = &uap->port;549 unsigned int status, old_cr;550 551 clk_enable(uap->clk);552 553 /*554 * First save the CR then disable the interrupts555 */556 old_cr = readb(port->membase + UART010_CR);557 writel(UART01x_CR_UARTEN, port->membase + UART010_CR);558 559 uart_console_write(port, s, count, pl010_console_putchar);560 561 /*562 * Finally, wait for transmitter to become empty563 * and restore the TCR564 */565 do {566 status = readb(port->membase + UART01x_FR);567 barrier();568 } while (status & UART01x_FR_BUSY);569 writel(old_cr, port->membase + UART010_CR);570 571 clk_disable(uap->clk);572}573 574static void __init575pl010_console_get_options(struct uart_amba_port *uap, int *baud,576 int *parity, int *bits)577{578 if (readb(uap->port.membase + UART010_CR) & UART01x_CR_UARTEN) {579 unsigned int lcr_h, quot;580 lcr_h = readb(uap->port.membase + UART010_LCRH);581 582 *parity = 'n';583 if (lcr_h & UART01x_LCRH_PEN) {584 if (lcr_h & UART01x_LCRH_EPS)585 *parity = 'e';586 else587 *parity = 'o';588 }589 590 if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)591 *bits = 7;592 else593 *bits = 8;594 595 quot = readb(uap->port.membase + UART010_LCRL) |596 readb(uap->port.membase + UART010_LCRM) << 8;597 *baud = uap->port.uartclk / (16 * (quot + 1));598 }599}600 601static int __init pl010_console_setup(struct console *co, char *options)602{603 struct uart_amba_port *uap;604 int baud = 38400;605 int bits = 8;606 int parity = 'n';607 int flow = 'n';608 int ret;609 610 /*611 * Check whether an invalid uart number has been specified, and612 * if so, search for the first available port that does have613 * console support.614 */615 if (co->index >= UART_NR)616 co->index = 0;617 uap = amba_ports[co->index];618 if (!uap)619 return -ENODEV;620 621 ret = clk_prepare(uap->clk);622 if (ret)623 return ret;624 625 uap->port.uartclk = clk_get_rate(uap->clk);626 627 if (options)628 uart_parse_options(options, &baud, &parity, &bits, &flow);629 else630 pl010_console_get_options(uap, &baud, &parity, &bits);631 632 return uart_set_options(&uap->port, co, baud, parity, bits, flow);633}634 635static struct uart_driver amba_reg;636static struct console amba_console = {637 .name = "ttyAM",638 .write = pl010_console_write,639 .device = uart_console_device,640 .setup = pl010_console_setup,641 .flags = CON_PRINTBUFFER,642 .index = -1,643 .data = &amba_reg,644};645 646#define AMBA_CONSOLE &amba_console647#else648#define AMBA_CONSOLE NULL649#endif650 651static DEFINE_MUTEX(amba_reg_lock);652static struct uart_driver amba_reg = {653 .owner = THIS_MODULE,654 .driver_name = "ttyAM",655 .dev_name = "ttyAM",656 .major = SERIAL_AMBA_MAJOR,657 .minor = SERIAL_AMBA_MINOR,658 .nr = UART_NR,659 .cons = AMBA_CONSOLE,660};661 662static int pl010_probe(struct amba_device *dev, const struct amba_id *id)663{664 struct uart_amba_port *uap;665 void __iomem *base;666 int i, ret;667 668 for (i = 0; i < ARRAY_SIZE(amba_ports); i++)669 if (amba_ports[i] == NULL)670 break;671 672 if (i == ARRAY_SIZE(amba_ports))673 return -EBUSY;674 675 uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port),676 GFP_KERNEL);677 if (!uap)678 return -ENOMEM;679 680 base = devm_ioremap(&dev->dev, dev->res.start,681 resource_size(&dev->res));682 if (!base)683 return -ENOMEM;684 685 uap->clk = devm_clk_get(&dev->dev, NULL);686 if (IS_ERR(uap->clk))687 return PTR_ERR(uap->clk);688 689 uap->port.dev = &dev->dev;690 uap->port.mapbase = dev->res.start;691 uap->port.membase = base;692 uap->port.iotype = UPIO_MEM;693 uap->port.irq = dev->irq[0];694 uap->port.fifosize = 16;695 uap->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_AMBA_PL010_CONSOLE);696 uap->port.ops = &amba_pl010_pops;697 uap->port.flags = UPF_BOOT_AUTOCONF;698 uap->port.line = i;699 uap->dev = dev;700 uap->data = dev_get_platdata(&dev->dev);701 702 amba_ports[i] = uap;703 704 amba_set_drvdata(dev, uap);705 706 mutex_lock(&amba_reg_lock);707 if (!amba_reg.state) {708 ret = uart_register_driver(&amba_reg);709 if (ret < 0) {710 mutex_unlock(&amba_reg_lock);711 dev_err(uap->port.dev,712 "Failed to register AMBA-PL010 driver\n");713 return ret;714 }715 }716 mutex_unlock(&amba_reg_lock);717 718 ret = uart_add_one_port(&amba_reg, &uap->port);719 if (ret)720 amba_ports[i] = NULL;721 722 return ret;723}724 725static void pl010_remove(struct amba_device *dev)726{727 struct uart_amba_port *uap = amba_get_drvdata(dev);728 int i;729 bool busy = false;730 731 uart_remove_one_port(&amba_reg, &uap->port);732 733 for (i = 0; i < ARRAY_SIZE(amba_ports); i++)734 if (amba_ports[i] == uap)735 amba_ports[i] = NULL;736 else if (amba_ports[i])737 busy = true;738 739 if (!busy)740 uart_unregister_driver(&amba_reg);741}742 743#ifdef CONFIG_PM_SLEEP744static int pl010_suspend(struct device *dev)745{746 struct uart_amba_port *uap = dev_get_drvdata(dev);747 748 if (uap)749 uart_suspend_port(&amba_reg, &uap->port);750 751 return 0;752}753 754static int pl010_resume(struct device *dev)755{756 struct uart_amba_port *uap = dev_get_drvdata(dev);757 758 if (uap)759 uart_resume_port(&amba_reg, &uap->port);760 761 return 0;762}763#endif764 765static SIMPLE_DEV_PM_OPS(pl010_dev_pm_ops, pl010_suspend, pl010_resume);766 767static const struct amba_id pl010_ids[] = {768 {769 .id = 0x00041010,770 .mask = 0x000fffff,771 },772 { 0, 0 },773};774 775MODULE_DEVICE_TABLE(amba, pl010_ids);776 777static struct amba_driver pl010_driver = {778 .drv = {779 .name = "uart-pl010",780 .pm = &pl010_dev_pm_ops,781 },782 .id_table = pl010_ids,783 .probe = pl010_probe,784 .remove = pl010_remove,785};786 787static int __init pl010_init(void)788{789 printk(KERN_INFO "Serial: AMBA driver\n");790 791 return amba_driver_register(&pl010_driver);792}793 794static void __exit pl010_exit(void)795{796 amba_driver_unregister(&pl010_driver);797}798 799module_init(pl010_init);800module_exit(pl010_exit);801 802MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");803MODULE_DESCRIPTION("ARM AMBA serial port driver");804MODULE_LICENSE("GPL");805