--- zzzz-none-000/linux-3.10.107/drivers/tty/serial/arc_uart.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/tty/serial/arc_uart.c 2021-02-04 17:41:59.000000000 +0000 @@ -37,8 +37,8 @@ #include #include #include -#include -#include +#include +#include /************************************* * ARC UART Hardware Specs @@ -72,7 +72,7 @@ #define RXOERR 0x02 /* OverFlow Err: Char recv but RXFULL still set */ /* Uart bit fiddling helpers: lowest level */ -#define RBASE(uart, reg) (uart->port.membase + reg) +#define RBASE(port, reg) (port->membase + reg) #define UART_REG_SET(u, r, v) writeb((v), RBASE(u, r)) #define UART_REG_GET(u, r) readb(RBASE(u, r)) @@ -102,7 +102,6 @@ struct arc_uart_port { struct uart_port port; unsigned long baud; - int is_emulated; /* H/w vs. Instruction Set Simulator */ }; #define to_arc_port(uport) container_of(uport, struct arc_uart_port, port) @@ -129,19 +128,15 @@ static void arc_serial_stop_rx(struct uart_port *port) { - struct arc_uart_port *uart = to_arc_port(port); - - UART_RX_IRQ_DISABLE(uart); + UART_RX_IRQ_DISABLE(port); } static void arc_serial_stop_tx(struct uart_port *port) { - struct arc_uart_port *uart = to_arc_port(port); - - while (!(UART_GET_STATUS(uart) & TXEMPTY)) + while (!(UART_GET_STATUS(port) & TXEMPTY)) cpu_relax(); - UART_TX_IRQ_DISABLE(uart); + UART_TX_IRQ_DISABLE(port); } /* @@ -149,10 +144,9 @@ */ static unsigned int arc_serial_tx_empty(struct uart_port *port) { - struct arc_uart_port *uart = to_arc_port(port); unsigned int stat; - stat = UART_GET_STATUS(uart); + stat = UART_GET_STATUS(port); if (stat & TXEMPTY) return TIOCSER_TEMT; @@ -166,24 +160,24 @@ * = by uart_start( ) before calling us * = tx_ist checks that too before calling */ -static void arc_serial_tx_chars(struct arc_uart_port *uart) +static void arc_serial_tx_chars(struct uart_port *port) { - struct circ_buf *xmit = &uart->port.state->xmit; + struct circ_buf *xmit = &port->state->xmit; int sent = 0; unsigned char ch; - if (unlikely(uart->port.x_char)) { - UART_SET_DATA(uart, uart->port.x_char); - uart->port.icount.tx++; - uart->port.x_char = 0; + if (unlikely(port->x_char)) { + UART_SET_DATA(port, port->x_char); + port->icount.tx++; + port->x_char = 0; sent = 1; - } else if (xmit->tail != xmit->head) { /* TODO: uart_circ_empty */ + } else if (!uart_circ_empty(xmit)) { ch = xmit->buf[xmit->tail]; xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - uart->port.icount.tx++; - while (!(UART_GET_STATUS(uart) & TXEMPTY)) + port->icount.tx++; + while (!(UART_GET_STATUS(port) & TXEMPTY)) cpu_relax(); - UART_SET_DATA(uart, ch); + UART_SET_DATA(port, ch); sent = 1; } @@ -192,10 +186,10 @@ * By Hard ISR to schedule processing in software interrupt part */ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&uart->port); + uart_write_wakeup(port); if (sent) - UART_TX_IRQ_ENABLE(uart); + UART_TX_IRQ_ENABLE(port); } /* @@ -204,14 +198,12 @@ */ static void arc_serial_start_tx(struct uart_port *port) { - struct arc_uart_port *uart = to_arc_port(port); - - arc_serial_tx_chars(uart); + arc_serial_tx_chars(port); } -static void arc_serial_rx_chars(struct arc_uart_port *uart) +static void arc_serial_rx_chars(struct uart_port *port, unsigned int status) { - unsigned int status, ch, flg = 0; + unsigned int ch, flg = 0; /* * UART has 4 deep RX-FIFO. Driver's recongnition of this fact @@ -222,34 +214,39 @@ * before RX-EMPTY=0, implies some sort of buffering going on in the * controller, which is indeed the Rx-FIFO. */ - while (!((status = UART_GET_STATUS(uart)) & RXEMPTY)) { - - ch = UART_GET_DATA(uart); - uart->port.icount.rx++; - + do { + /* + * This could be an Rx Intr for err (no data), + * so check err and clear that Intr first + */ if (unlikely(status & (RXOERR | RXFERR))) { if (status & RXOERR) { - uart->port.icount.overrun++; + port->icount.overrun++; flg = TTY_OVERRUN; - UART_CLR_STATUS(uart, RXOERR); + UART_CLR_STATUS(port, RXOERR); } if (status & RXFERR) { - uart->port.icount.frame++; + port->icount.frame++; flg = TTY_FRAME; - UART_CLR_STATUS(uart, RXFERR); + UART_CLR_STATUS(port, RXFERR); } } else flg = TTY_NORMAL; - if (unlikely(uart_handle_sysrq_char(&uart->port, ch))) - goto done; + if (status & RXEMPTY) + continue; - uart_insert_char(&uart->port, status, RXOERR, ch, flg); + ch = UART_GET_DATA(port); + port->icount.rx++; -done: - tty_flip_buffer_push(&uart->port.state->port); - } + if (!(uart_handle_sysrq_char(port, ch))) + uart_insert_char(port, status, RXOERR, ch, flg); + + spin_unlock(&port->lock); + tty_flip_buffer_push(&port->state->port); + spin_lock(&port->lock); + } while (!((status = UART_GET_STATUS(port)) & RXEMPTY)); } /* @@ -282,22 +279,22 @@ static irqreturn_t arc_serial_isr(int irq, void *dev_id) { - struct arc_uart_port *uart = dev_id; + struct uart_port *port = dev_id; unsigned int status; - status = UART_GET_STATUS(uart); + status = UART_GET_STATUS(port); /* * Single IRQ for both Rx (data available) Tx (room available) Interrupt * notifications from the UART Controller. * To demultiplex between the two, we check the relevant bits */ - if ((status & RXIENB) && !(status & RXEMPTY)) { + if (status & RXIENB) { /* already in ISR, no need of xx_irqsave */ - spin_lock(&uart->port.lock); - arc_serial_rx_chars(uart); - spin_unlock(&uart->port.lock); + spin_lock(&port->lock); + arc_serial_rx_chars(port, status); + spin_unlock(&port->lock); } if ((status & TXIENB) && (status & TXEMPTY)) { @@ -305,14 +302,14 @@ /* Unconditionally disable further Tx-Interrupts. * will be enabled by tx_chars() if needed. */ - UART_TX_IRQ_DISABLE(uart); + UART_TX_IRQ_DISABLE(port); - spin_lock(&uart->port.lock); + spin_lock(&port->lock); - if (!uart_tx_stopped(&uart->port)) - arc_serial_tx_chars(uart); + if (!uart_tx_stopped(port)) + arc_serial_tx_chars(port); - spin_unlock(&uart->port.lock); + spin_unlock(&port->lock); } return IRQ_HANDLED; @@ -335,13 +332,6 @@ /* MCR not present */ } -/* Enable Modem Status Interrupts */ - -static void arc_serial_enable_ms(struct uart_port *port) -{ - /* MSR not present */ -} - static void arc_serial_break_ctl(struct uart_port *port, int break_state) { /* ARC UART doesn't support sending Break signal */ @@ -349,18 +339,15 @@ static int arc_serial_startup(struct uart_port *port) { - struct arc_uart_port *uart = to_arc_port(port); - /* Before we hook up the ISR, Disable all UART Interrupts */ - UART_ALL_IRQ_DISABLE(uart); + UART_ALL_IRQ_DISABLE(port); - if (request_irq(uart->port.irq, arc_serial_isr, 0, "arc uart rx-tx", - uart)) { - dev_warn(uart->port.dev, "Unable to attach ARC UART intr\n"); + if (request_irq(port->irq, arc_serial_isr, 0, "arc uart rx-tx", port)) { + dev_warn(port->dev, "Unable to attach ARC UART intr\n"); return -EBUSY; } - UART_RX_IRQ_ENABLE(uart); /* Only Rx IRQ enabled to begin with */ + UART_RX_IRQ_ENABLE(port); /* Only Rx IRQ enabled to begin with */ return 0; } @@ -368,8 +355,7 @@ /* This is not really needed */ static void arc_serial_shutdown(struct uart_port *port) { - struct arc_uart_port *uart = to_arc_port(port); - free_irq(uart->port.irq, uart); + free_irq(port->irq, port); } static void @@ -393,25 +379,14 @@ uartl = hw_val & 0xFF; uarth = (hw_val >> 8) & 0xFF; - /* - * UART ISS(Instruction Set simulator) emulation has a subtle bug: - * A existing value of Baudh = 0 is used as a indication to startup - * it's internal state machine. - * Thus if baudh is set to 0, 2 times, it chokes. - * This happens with BAUD=115200 and the formaula above - * Until that is fixed, when running on ISS, we will set baudh to !0 - */ - if (uart->is_emulated) - uarth = 1; - spin_lock_irqsave(&port->lock, flags); - UART_ALL_IRQ_DISABLE(uart); + UART_ALL_IRQ_DISABLE(port); - UART_SET_BAUDL(uart, uartl); - UART_SET_BAUDH(uart, uarth); + UART_SET_BAUDL(port, uartl); + UART_SET_BAUDH(port, uarth); - UART_RX_IRQ_ENABLE(uart); + UART_RX_IRQ_ENABLE(port); /* * UART doesn't support Parity/Hardware Flow Control; @@ -434,9 +409,7 @@ static const char *arc_serial_type(struct uart_port *port) { - struct arc_uart_port *uart = to_arc_port(port); - - return uart->port.type == PORT_ARC ? DRIVER_NAME : NULL; + return port->type == PORT_ARC ? DRIVER_NAME : NULL; } static void arc_serial_release_port(struct uart_port *port) @@ -465,35 +438,28 @@ */ static void arc_serial_config_port(struct uart_port *port, int flags) { - struct arc_uart_port *uart = to_arc_port(port); - if (flags & UART_CONFIG_TYPE) - uart->port.type = PORT_ARC; + port->type = PORT_ARC; } -#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_ARC_CONSOLE) +#ifdef CONFIG_CONSOLE_POLL static void arc_serial_poll_putchar(struct uart_port *port, unsigned char chr) { - struct arc_uart_port *uart = to_arc_port(port); - - while (!(UART_GET_STATUS(uart) & TXEMPTY)) + while (!(UART_GET_STATUS(port) & TXEMPTY)) cpu_relax(); - UART_SET_DATA(uart, chr); + UART_SET_DATA(port, chr); } -#endif -#ifdef CONFIG_CONSOLE_POLL static int arc_serial_poll_getchar(struct uart_port *port) { - struct arc_uart_port *uart = to_arc_port(port); unsigned char chr; - while (!(UART_GET_STATUS(uart) & RXEMPTY)) + while (!(UART_GET_STATUS(port) & RXEMPTY)) cpu_relax(); - chr = UART_GET_DATA(uart); + chr = UART_GET_DATA(port); return chr; } #endif @@ -505,7 +471,6 @@ .stop_tx = arc_serial_stop_tx, .start_tx = arc_serial_start_tx, .stop_rx = arc_serial_stop_rx, - .enable_ms = arc_serial_enable_ms, .break_ctl = arc_serial_break_ctl, .startup = arc_serial_startup, .shutdown = arc_serial_shutdown, @@ -521,71 +486,6 @@ #endif }; -static int -arc_uart_init_one(struct platform_device *pdev, int dev_id) -{ - struct resource *res, *res2; - unsigned long *plat_data; - struct arc_uart_port *uart = &arc_uart_ports[dev_id]; - - plat_data = ((unsigned long *)(pdev->dev.platform_data)); - if (!plat_data) - return -ENODEV; - - uart->is_emulated = !!plat_data[0]; /* workaround ISS bug */ - - if (is_early_platform_device(pdev)) { - uart->port.uartclk = plat_data[1]; - uart->baud = plat_data[2]; - } else { - struct device_node *np = pdev->dev.of_node; - u32 val; - - if (of_property_read_u32(np, "clock-frequency", &val)) { - dev_err(&pdev->dev, "clock-frequency property NOTset\n"); - return -EINVAL; - } - uart->port.uartclk = val; - - if (of_property_read_u32(np, "current-speed", &val)) { - dev_err(&pdev->dev, "current-speed property NOT set\n"); - return -EINVAL; - } - uart->baud = val; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res2) - return -ENODEV; - - uart->port.mapbase = res->start; - uart->port.membase = ioremap_nocache(res->start, resource_size(res)); - if (!uart->port.membase) - /* No point of dev_err since UART itself is hosed here */ - return -ENXIO; - - uart->port.irq = res2->start; - uart->port.dev = &pdev->dev; - uart->port.iotype = UPIO_MEM; - uart->port.flags = UPF_BOOT_AUTOCONF; - uart->port.line = dev_id; - uart->port.ops = &arc_serial_pops; - - uart->port.fifosize = ARC_UART_TX_FIFO_SIZE; - - /* - * uart_insert_char( ) uses it in decideding whether to ignore a - * char or not. Explicitly setting it here, removes the subtelty - */ - uart->port.ignore_status_mask = 0; - - return 0; -} - #ifdef CONFIG_SERIAL_ARC_CONSOLE static int arc_serial_console_setup(struct console *co, char *options) @@ -619,7 +519,10 @@ static void arc_serial_console_putchar(struct uart_port *port, int ch) { - arc_serial_poll_putchar(port, (unsigned char)ch); + while (!(UART_GET_STATUS(port) & TXEMPTY)) + cpu_relax(); + + UART_SET_DATA(port, (unsigned char)ch); } /* @@ -646,48 +549,44 @@ .data = &arc_uart_driver }; -static __init void early_serial_write(struct console *con, const char *s, - unsigned int n) +static __init void arc_early_serial_write(struct console *con, const char *s, + unsigned int n) { - struct uart_port *port = &arc_uart_ports[con->index].port; - unsigned int i; + struct earlycon_device *dev = con->data; - for (i = 0; i < n; i++, s++) { - if (*s == '\n') - arc_serial_poll_putchar(port, '\r'); - arc_serial_poll_putchar(port, *s); - } + uart_console_write(&dev->port, s, n, arc_serial_console_putchar); } -static struct console arc_early_serial_console __initdata = { - .name = "early_ARCuart", - .write = early_serial_write, - .flags = CON_PRINTBUFFER | CON_BOOT, - .index = -1 -}; - -static int __init arc_serial_probe_earlyprintk(struct platform_device *pdev) +static int __init arc_early_console_setup(struct earlycon_device *dev, + const char *opt) { - int dev_id = pdev->id < 0 ? 0 : pdev->id; - int rc; + struct uart_port *port = &dev->port; + unsigned int l, h, hw_val; - arc_early_serial_console.index = dev_id; + if (!dev->port.membase) + return -ENODEV; - rc = arc_uart_init_one(pdev, dev_id); - if (rc) - panic("early console init failed\n"); + hw_val = port->uartclk / (dev->baud * 4) - 1; + l = hw_val & 0xFF; + h = (hw_val >> 8) & 0xFF; - arc_serial_console_setup(&arc_early_serial_console, NULL); + UART_SET_BAUDL(port, l); + UART_SET_BAUDH(port, h); - register_console(&arc_early_serial_console); + dev->con->write = arc_early_serial_write; return 0; } +OF_EARLYCON_DECLARE(arc_uart, "snps,arc-uart", arc_early_console_setup); + #endif /* CONFIG_SERIAL_ARC_CONSOLE */ static int arc_serial_probe(struct platform_device *pdev) { - int rc, dev_id; struct device_node *np = pdev->dev.of_node; + struct arc_uart_port *uart; + struct uart_port *port; + int dev_id; + u32 val; /* no device tree device */ if (!np) @@ -697,12 +596,43 @@ if (dev_id < 0) dev_id = 0; - rc = arc_uart_init_one(pdev, dev_id); - if (rc) - return rc; + uart = &arc_uart_ports[dev_id]; + port = &uart->port; + + if (of_property_read_u32(np, "clock-frequency", &val)) { + dev_err(&pdev->dev, "clock-frequency property NOTset\n"); + return -EINVAL; + } + port->uartclk = val; + + if (of_property_read_u32(np, "current-speed", &val)) { + dev_err(&pdev->dev, "current-speed property NOT set\n"); + return -EINVAL; + } + uart->baud = val; - rc = uart_add_one_port(&arc_uart_driver, &arc_uart_ports[dev_id].port); - return rc; + port->membase = of_iomap(np, 0); + if (!port->membase) + /* No point of dev_err since UART itself is hosed here */ + return -ENXIO; + + port->irq = irq_of_parse_and_map(np, 0); + + port->dev = &pdev->dev; + port->iotype = UPIO_MEM; + port->flags = UPF_BOOT_AUTOCONF; + port->line = dev_id; + port->ops = &arc_serial_pops; + + port->fifosize = ARC_UART_TX_FIFO_SIZE; + + /* + * uart_insert_char( ) uses it in decideding whether to ignore a + * char or not. Explicitly setting it here, removes the subtelty + */ + port->ignore_status_mask = 0; + + return uart_add_one_port(&arc_uart_driver, &arc_uart_ports[dev_id].port); } static int arc_serial_remove(struct platform_device *pdev) @@ -722,32 +652,10 @@ .remove = arc_serial_remove, .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .of_match_table = arc_uart_dt_ids, }, }; -#ifdef CONFIG_SERIAL_ARC_CONSOLE - -static struct platform_driver early_arc_platform_driver __initdata = { - .probe = arc_serial_probe_earlyprintk, - .remove = arc_serial_remove, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, -}; -/* - * Register an early platform driver of "earlyprintk" class. - * ARCH platform code installs the driver and probes the early devices - * The installation could rely on user specifying earlyprintk=xyx in cmd line - * or it could be done independently, for all "earlyprintk" class drivers. - * [see arch/arc/plat-arcfpga/platform.c] - */ -early_platform_init("earlyprintk", &early_arc_platform_driver); - -#endif /* CONFIG_SERIAL_ARC_CONSOLE */ - static int __init arc_serial_init(void) { int ret;