diff options
Diffstat (limited to 'drivers/tty/serial/8250')
-rw-r--r-- | drivers/tty/serial/8250/8250.h | 9 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_core.c | 112 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_dma.c | 39 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_dw.c | 69 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_em.c | 4 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_fintek.c | 8 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_hp300.c | 4 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_mtk.c | 4 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_omap.c | 1281 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_pci.c | 198 | ||||
-rw-r--r-- | drivers/tty/serial/8250/Kconfig | 11 | ||||
-rw-r--r-- | drivers/tty/serial/8250/Makefile | 1 |
12 files changed, 1597 insertions, 143 deletions
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index cb51be55989e..b00836851061 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -16,6 +16,9 @@ #include <linux/dmaengine.h> struct uart_8250_dma { + int (*tx_dma)(struct uart_8250_port *p); + int (*rx_dma)(struct uart_8250_port *p, unsigned int iir); + /* Filter function */ dma_filter_fn fn; @@ -41,6 +44,8 @@ struct uart_8250_dma { size_t tx_size; unsigned char tx_running:1; + unsigned char tx_err: 1; + unsigned char rx_running:1; }; struct old_serial_port { @@ -51,7 +56,7 @@ struct old_serial_port { unsigned int flags; unsigned char hub6; unsigned char io_type; - unsigned char *iomem_base; + unsigned char __iomem *iomem_base; unsigned short iomem_reg_shift; unsigned long irqflags; }; @@ -114,6 +119,8 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value) } struct uart_8250_port *serial8250_get_port(int line); +void serial8250_rpm_get(struct uart_8250_port *p); +void serial8250_rpm_put(struct uart_8250_port *p); #if defined(__alpha__) && !defined(CONFIG_PCI) /* diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index ca5cfdc1459a..9515924b7f38 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -541,23 +541,25 @@ void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) } EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); -static void serial8250_rpm_get(struct uart_8250_port *p) +void serial8250_rpm_get(struct uart_8250_port *p) { if (!(p->capabilities & UART_CAP_RPM)) return; pm_runtime_get_sync(p->port.dev); } +EXPORT_SYMBOL_GPL(serial8250_rpm_get); -static void serial8250_rpm_put(struct uart_8250_port *p) +void serial8250_rpm_put(struct uart_8250_port *p) { if (!(p->capabilities & UART_CAP_RPM)) return; pm_runtime_mark_last_busy(p->port.dev); pm_runtime_put_autosuspend(p->port.dev); } +EXPORT_SYMBOL_GPL(serial8250_rpm_put); /* - * This two wrapper ensure, that enable_runtime_pm_tx() can be called more than + * These two wrappers ensure that enable_runtime_pm_tx() can be called more than * once and disable_runtime_pm_tx() will still disable RPM because the fifo is * empty and the HW can idle again. */ @@ -595,6 +597,7 @@ static void serial8250_rpm_put_tx(struct uart_8250_port *p) */ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) { + unsigned char lcr = 0, efr = 0; /* * Exar UARTs have a SLEEP register that enables or disables * each UART to enter sleep mode separately. On the XR17V35x the @@ -611,6 +614,8 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) if (p->capabilities & UART_CAP_SLEEP) { if (p->capabilities & UART_CAP_EFR) { + lcr = serial_in(p, UART_LCR); + efr = serial_in(p, UART_EFR); serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); serial_out(p, UART_EFR, UART_EFR_ECB); serial_out(p, UART_LCR, 0); @@ -618,8 +623,8 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); if (p->capabilities & UART_CAP_EFR) { serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(p, UART_EFR, 0); - serial_out(p, UART_LCR, 0); + serial_out(p, UART_EFR, efr); + serial_out(p, UART_LCR, lcr); } } out: @@ -1350,7 +1355,7 @@ static void serial8250_start_tx(struct uart_port *port) struct uart_8250_port *up = up_to_u8250p(port); serial8250_rpm_get_tx(up); - if (up->dma && !serial8250_tx_dma(up)) { + if (up->dma && !up->dma->tx_dma(up)) { return; } else if (!(up->ier & UART_IER_THRI)) { up->ier |= UART_IER_THRI; @@ -1397,6 +1402,19 @@ static void serial8250_stop_rx(struct uart_port *port) serial8250_rpm_put(up); } +static void serial8250_disable_ms(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + /* no MSR capabilities */ + if (up->bugs & UART_BUG_NOMSR) + return; + + up->ier &= ~UART_IER_MSI; + serial_port_out(port, UART_IER, up->ier); +} + static void serial8250_enable_ms(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); @@ -1483,7 +1501,7 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) ignore_char: lsr = serial_in(up, UART_LSR); - } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0)); + } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (--max_count > 0)); spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); spin_lock(&port->lock); @@ -1532,7 +1550,7 @@ void serial8250_tx_chars(struct uart_8250_port *up) DEBUG_INTR("THRE..."); /* - * With RPM enabled, we have to wait once the FIFO is empty before the + * With RPM enabled, we have to wait until the FIFO is empty before the * HW can go idle. So we get here once again with empty FIFO and disable * the interrupt and RPM in __stop_tx() */ @@ -1588,13 +1606,14 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) if (status & (UART_LSR_DR | UART_LSR_BI)) { if (up->dma) - dma_err = serial8250_rx_dma(up, iir); + dma_err = up->dma->rx_dma(up, iir); if (!up->dma || dma_err) status = serial8250_rx_chars(up, status); } serial8250_modem_status(up); - if (!up->dma && (status & UART_LSR_THRE)) + if ((!up->dma || (up->dma && up->dma->tx_err)) && + (status & UART_LSR_THRE)) serial8250_tx_chars(up); spin_unlock_irqrestore(&port->lock, flags); @@ -2603,13 +2622,21 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios, } static void -serial8250_set_ldisc(struct uart_port *port, int new) +serial8250_set_ldisc(struct uart_port *port, struct ktermios *termios) { - if (new == N_PPS) { + if (termios->c_line == N_PPS) { port->flags |= UPF_HARDPPS_CD; + spin_lock_irq(&port->lock); serial8250_enable_ms(port); - } else + spin_unlock_irq(&port->lock); + } else { port->flags &= ~UPF_HARDPPS_CD; + if (!UART_ENABLE_MS(port, termios->c_cflag)) { + spin_lock_irq(&port->lock); + serial8250_disable_ms(port); + spin_unlock_irq(&port->lock); + } + } } @@ -2634,8 +2661,11 @@ serial8250_pm(struct uart_port *port, unsigned int state, static unsigned int serial8250_port_size(struct uart_8250_port *pt) { - if (pt->port.iotype == UPIO_AU) + if (pt->port.iotype == UPIO_AU) { + if (pt->port.type == PORT_RT2880) + return 0x100; return 0x1000; + } if (is_omap1_8250(pt)) return 0x16 << pt->port.regshift; @@ -2975,42 +3005,6 @@ serial8250_verify_port(struct uart_port *port, struct serial_struct *ser) return 0; } -static int serial8250_ioctl(struct uart_port *port, unsigned int cmd, - unsigned long arg) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - int ret; - struct serial_rs485 rs485_config; - - if (!up->rs485_config) - return -ENOIOCTLCMD; - - switch (cmd) { - case TIOCSRS485: - if (copy_from_user(&rs485_config, (void __user *)arg, - sizeof(rs485_config))) - return -EFAULT; - - ret = up->rs485_config(up, &rs485_config); - if (ret) - return ret; - - memcpy(&up->rs485, &rs485_config, sizeof(rs485_config)); - - return 0; - case TIOCGRS485: - if (copy_to_user((void __user *)arg, &up->rs485, - sizeof(up->rs485))) - return -EFAULT; - return 0; - default: - break; - } - - return -ENOIOCTLCMD; -} - static const char * serial8250_type(struct uart_port *port) { @@ -3042,7 +3036,6 @@ static struct uart_ops serial8250_pops = { .request_port = serial8250_request_port, .config_port = serial8250_config_port, .verify_port = serial8250_verify_port, - .ioctl = serial8250_ioctl, #ifdef CONFIG_CONSOLE_POLL .poll_get_char = serial8250_get_poll_char, .poll_put_char = serial8250_put_poll_char, @@ -3198,7 +3191,9 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) serial8250_rpm_get(up); - if (port->sysrq || oops_in_progress) + if (port->sysrq) + locked = 0; + else if (oops_in_progress) locked = spin_trylock_irqsave(&port->lock, flags); else spin_lock_irqsave(&port->lock, flags); @@ -3237,7 +3232,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) serial8250_rpm_put(up); } -static int __init serial8250_console_setup(struct console *co, char *options) +static int serial8250_console_setup(struct console *co, char *options) { struct uart_port *port; int baud = 9600; @@ -3585,10 +3580,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->port.fifosize = up->port.fifosize; uart->tx_loadsz = up->tx_loadsz; uart->capabilities = up->capabilities; - uart->rs485_config = up->rs485_config; - uart->rs485 = up->rs485; uart->port.throttle = up->port.throttle; uart->port.unthrottle = up->port.unthrottle; + uart->port.rs485_config = up->port.rs485_config; + uart->port.rs485 = up->port.rs485; /* Take tx_loadsz from fifosize if it wasn't set separately */ if (uart->port.fifosize && !uart->tx_loadsz) @@ -3623,8 +3618,13 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->dl_read = up->dl_read; if (up->dl_write) uart->dl_write = up->dl_write; - if (up->dma) + if (up->dma) { uart->dma = up->dma; + if (!uart->dma->tx_dma) + uart->dma->tx_dma = serial8250_tx_dma; + if (!uart->dma->rx_dma) + uart->dma->rx_dma = serial8250_rx_dma; + } if (serial8250_isa_config != NULL) serial8250_isa_config(0, &uart->port, diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index 148ffe4c232f..fcd7ac6af2fc 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -21,6 +21,7 @@ static void __dma_tx_complete(void *param) struct uart_8250_dma *dma = p->dma; struct circ_buf *xmit = &p->port.state->xmit; unsigned long flags; + int ret; dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr, UART_XMIT_SIZE, DMA_TO_DEVICE); @@ -36,8 +37,11 @@ static void __dma_tx_complete(void *param) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&p->port); - if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) - serial8250_tx_dma(p); + ret = serial8250_tx_dma(p); + if (ret) { + p->ier |= UART_IER_THRI; + serial_port_out(&p->port, UART_IER, p->ier); + } spin_unlock_irqrestore(&p->port.lock, flags); } @@ -53,6 +57,7 @@ static void __dma_rx_complete(void *param) dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr, dma->rx_size, DMA_FROM_DEVICE); + dma->rx_running = 0; dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); dmaengine_terminate_all(dma->rxchan); @@ -69,6 +74,7 @@ int serial8250_tx_dma(struct uart_8250_port *p) struct uart_8250_dma *dma = p->dma; struct circ_buf *xmit = &p->port.state->xmit; struct dma_async_tx_descriptor *desc; + int ret; if (uart_tx_stopped(&p->port) || dma->tx_running || uart_circ_empty(xmit)) @@ -80,11 +86,12 @@ int serial8250_tx_dma(struct uart_8250_port *p) dma->tx_addr + xmit->tail, dma->tx_size, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) - return -EBUSY; + if (!desc) { + ret = -EBUSY; + goto err; + } dma->tx_running = 1; - desc->callback = __dma_tx_complete; desc->callback_param = p; @@ -94,19 +101,23 @@ int serial8250_tx_dma(struct uart_8250_port *p) UART_XMIT_SIZE, DMA_TO_DEVICE); dma_async_issue_pending(dma->txchan); - + if (dma->tx_err) { + dma->tx_err = 0; + if (p->ier & UART_IER_THRI) { + p->ier &= ~UART_IER_THRI; + serial_out(p, UART_IER, p->ier); + } + } return 0; +err: + dma->tx_err = 1; + return ret; } -EXPORT_SYMBOL_GPL(serial8250_tx_dma); int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) { struct uart_8250_dma *dma = p->dma; struct dma_async_tx_descriptor *desc; - struct dma_tx_state state; - int dma_status; - - dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); switch (iir & 0x3f) { case UART_IIR_RLSI: @@ -117,7 +128,7 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) * If RCVR FIFO trigger level was not reached, complete the * transfer and let 8250_core copy the remaining data. */ - if (dma_status == DMA_IN_PROGRESS) { + if (dma->rx_running) { dmaengine_pause(dma->rxchan); __dma_rx_complete(p); } @@ -126,7 +137,7 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) break; } - if (dma_status) + if (dma->rx_running) return 0; desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr, @@ -135,6 +146,7 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) if (!desc) return -EBUSY; + dma->rx_running = 1; desc->callback = __dma_rx_complete; desc->callback_param = p; @@ -147,7 +159,6 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) return 0; } -EXPORT_SYMBOL_GPL(serial8250_rx_dma); int serial8250_request_dma(struct uart_8250_port *p) { diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index beea6ca73ee5..f4fd362f6da2 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -122,13 +122,44 @@ static unsigned int dw8250_serial_in(struct uart_port *p, int offset) return dw8250_modify_msr(p, offset, value); } -/* Read Back (rb) version to ensure register access ording. */ -static void dw8250_serial_out_rb(struct uart_port *p, int offset, int value) +#ifdef CONFIG_64BIT +static unsigned int dw8250_serial_inq(struct uart_port *p, int offset) { - dw8250_serial_out(p, offset, value); - dw8250_serial_in(p, UART_LCR); + unsigned int value; + + value = (u8)__raw_readq(p->membase + (offset << p->regshift)); + + return dw8250_modify_msr(p, offset, value); } +static void dw8250_serial_outq(struct uart_port *p, int offset, int value) +{ + struct dw8250_data *d = p->private_data; + + if (offset == UART_MCR) + d->last_mcr = value; + + value &= 0xff; + __raw_writeq(value, p->membase + (offset << p->regshift)); + /* Read back to ensure register write ordering. */ + __raw_readq(p->membase + (UART_LCR << p->regshift)); + + /* Make sure LCR write wasn't ignored */ + if (offset == UART_LCR) { + int tries = 1000; + while (tries--) { + unsigned int lcr = p->serial_in(p, UART_LCR); + if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR)) + return; + dw8250_force_idle(p); + __raw_writeq(value & 0xff, + p->membase + (UART_LCR << p->regshift)); + } + dev_err(p->dev, "Couldn't set LCR to %d\n", value); + } +} +#endif /* CONFIG_64BIT */ + static void dw8250_serial_out32(struct uart_port *p, int offset, int value) { struct dw8250_data *d = p->private_data; @@ -258,22 +289,19 @@ static int dw8250_probe_of(struct uart_port *p, struct uart_8250_port *up = up_to_u8250p(p); u32 val; bool has_ucv = true; + int id; +#ifdef CONFIG_64BIT if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) { -#ifdef __BIG_ENDIAN - /* - * Low order bits of these 64-bit registers, when - * accessed as a byte, are 7 bytes further down in the - * address space in big endian mode. - */ - p->membase += 7; -#endif - p->serial_out = dw8250_serial_out_rb; + p->serial_in = dw8250_serial_inq; + p->serial_out = dw8250_serial_outq; p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; p->type = PORT_OCTEON; data->usr_reg = 0x27; has_ucv = false; - } else if (!of_property_read_u32(np, "reg-io-width", &val)) { + } else +#endif + if (!of_property_read_u32(np, "reg-io-width", &val)) { switch (val) { case 1: break; @@ -290,9 +318,22 @@ static int dw8250_probe_of(struct uart_port *p, if (has_ucv) dw8250_setup_port(up); + /* if we have a valid fifosize, try hooking up DMA here */ + if (p->fifosize) { + up->dma = &data->dma; + + up->dma->rxconf.src_maxburst = p->fifosize / 4; + up->dma->txconf.dst_maxburst = p->fifosize / 4; + } + if (!of_property_read_u32(np, "reg-shift", &val)) p->regshift = val; + /* get index of serial line, if found in DT aliases */ + id = of_alias_get_id(np, "serial"); + if (id >= 0) + p->line = id; + /* clock got configured through clk api, all done */ if (p->uartclk) return 0; diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c index 56c87232b6a0..478599d82506 100644 --- a/drivers/tty/serial/8250/8250_em.c +++ b/drivers/tty/serial/8250/8250_em.c @@ -102,10 +102,8 @@ static int serial8250_em_probe(struct platform_device *pdev) } priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "unable to allocate private data\n"); + if (!priv) return -ENOMEM; - } priv->sclk = devm_clk_get(&pdev->dev, "sclk"); if (IS_ERR(priv->sclk)) { diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index 1bb28cb69493..1e6899bc9429 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -89,11 +89,11 @@ static int fintek_8250_check_id(void) return 0; } -static int fintek_8250_rs4850_config(struct uart_8250_port *uart, +static int fintek_8250_rs485_config(struct uart_port *port, struct serial_rs485 *rs485) { uint8_t config = 0; - int index = fintek_8250_get_index(uart->port.iobase); + int index = fintek_8250_get_index(port->iobase); if (index < 0) return -EINVAL; @@ -134,6 +134,8 @@ static int fintek_8250_rs4850_config(struct uart_8250_port *uart, outb(config, DATA_PORT); fintek_8250_exit_key(); + port->rs485 = *rs485; + return 0; } @@ -166,7 +168,7 @@ fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) uart.port.irq = pnp_irq(dev, 0); uart.port.iobase = pnp_port_start(dev, 0); uart.port.iotype = UPIO_PORT; - uart.rs485_config = fintek_8250_rs4850_config; + uart.port.rs485_config = fintek_8250_rs485_config; uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE) diff --git a/drivers/tty/serial/8250/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c index afffe4d1f034..b4882082b247 100644 --- a/drivers/tty/serial/8250/8250_hp300.c +++ b/drivers/tty/serial/8250/8250_hp300.c @@ -88,10 +88,6 @@ extern int hp300_uart_scode; /* * Parse the bootinfo to find descriptions for headless console and * debug serial ports and register them with the 8250 driver. - * This function should be called before serial_console_init() is called - * to make sure the serial console will be available for use. IA-64 kernel - * calls this function from setup_arch() after the EFI and ACPI tables have - * been parsed. */ int __init hp300_setup_serial_console(void) { diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index de7aae523b37..6f93123a428a 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -74,14 +74,14 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, /* Set to next lower baudrate supported */ if ((baud == 500000) || (baud == 576000)) baud = 460800; - quot = DIV_ROUND_CLOSEST(port->uartclk, 4 * baud); + quot = DIV_ROUND_UP(port->uartclk, 4 * baud); } else { serial_port_out(port, UART_MTK_HIGHS, 0x3); /* Set to highest baudrate supported */ if (baud >= 1152000) baud = 921600; - quot = (port->uartclk / (256 * baud)) + 1; + quot = DIV_ROUND_UP(port->uartclk, 256 * baud); } /* diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c new file mode 100644 index 000000000000..336602eb453e --- /dev/null +++ b/drivers/tty/serial/8250/8250_omap.c @@ -0,0 +1,1281 @@ +/* + * 8250-core based driver for the OMAP internal UART + * + * based on omap-serial.c, Copyright (C) 2010 Texas Instruments. + * + * Copyright (C) 2014 Sebastian Andrzej Siewior + * + */ + +#include <linux/device.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/serial_8250.h> +#include <linux/serial_core.h> +#include <linux/serial_reg.h> +#include <linux/tty_flip.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/of_irq.h> +#include <linux/delay.h> +#include <linux/pm_runtime.h> +#include <linux/console.h> +#include <linux/pm_qos.h> +#include <linux/dma-mapping.h> + +#include "8250.h" + +#define DEFAULT_CLK_SPEED 48000000 + +#define UART_ERRATA_i202_MDR1_ACCESS (1 << 0) +#define OMAP_UART_WER_HAS_TX_WAKEUP (1 << 1) +#define OMAP_DMA_TX_KICK (1 << 2) + +#define OMAP_UART_FCR_RX_TRIG 6 +#define OMAP_UART_FCR_TX_TRIG 4 + +/* SCR register bitmasks */ +#define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK (1 << 7) +#define OMAP_UART_SCR_TX_TRIG_GRANU1_MASK (1 << 6) +#define OMAP_UART_SCR_TX_EMPTY (1 << 3) +#define OMAP_UART_SCR_DMAMODE_MASK (3 << 1) +#define OMAP_UART_SCR_DMAMODE_1 (1 << 1) +#define OMAP_UART_SCR_DMAMODE_CTL (1 << 0) + +/* MVR register bitmasks */ +#define OMAP_UART_MVR_SCHEME_SHIFT 30 +#define OMAP_UART_LEGACY_MVR_MAJ_MASK 0xf0 +#define OMAP_UART_LEGACY_MVR_MAJ_SHIFT 4 +#define OMAP_UART_LEGACY_MVR_MIN_MASK 0x0f +#define OMAP_UART_MVR_MAJ_MASK 0x700 +#define OMAP_UART_MVR_MAJ_SHIFT 8 +#define OMAP_UART_MVR_MIN_MASK 0x3f + +#define UART_TI752_TLR_TX 0 +#define UART_TI752_TLR_RX 4 + +#define TRIGGER_TLR_MASK(x) ((x & 0x3c) >> 2) +#define TRIGGER_FCR_MASK(x) (x & 3) + +/* Enable XON/XOFF flow control on output */ +#define OMAP_UART_SW_TX 0x08 +/* Enable XON/XOFF flow control on input */ +#define OMAP_UART_SW_RX 0x02 + +#define OMAP_UART_WER_MOD_WKUP 0x7f +#define OMAP_UART_TX_WAKEUP_EN (1 << 7) + +#define TX_TRIGGER 1 +#define RX_TRIGGER 48 + +#define OMAP_UART_TCR_RESTORE(x) ((x / 4) << 4) +#define OMAP_UART_TCR_HALT(x) ((x / 4) << 0) + +#define UART_BUILD_REVISION(x, y) (((x) << 8) | (y)) + +#define OMAP_UART_REV_46 0x0406 +#define OMAP_UART_REV_52 0x0502 +#define OMAP_UART_REV_63 0x0603 + +struct omap8250_priv { + int line; + u8 habit; + u8 mdr1; + u8 efr; + u8 scr; + u8 wer; + u8 xon; + u8 xoff; + u8 delayed_restore; + u16 quot; + + bool is_suspending; + int wakeirq; + int wakeups_enabled; + u32 latency; + u32 calc_latency; + struct pm_qos_request pm_qos_request; + struct work_struct qos_work; + struct uart_8250_dma omap8250_dma; +}; + +static u32 uart_read(struct uart_8250_port *up, u32 reg) +{ + return readl(up->port.membase + (reg << up->port.regshift)); +} + +/* + * Work Around for Errata i202 (2430, 3430, 3630, 4430 and 4460) + * The access to uart register after MDR1 Access + * causes UART to corrupt data. + * + * Need a delay = + * 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS) + * give 10 times as much + */ +static void omap_8250_mdr1_errataset(struct uart_8250_port *up, + struct omap8250_priv *priv) +{ + u8 timeout = 255; + u8 old_mdr1; + + old_mdr1 = serial_in(up, UART_OMAP_MDR1); + if (old_mdr1 == priv->mdr1) + return; + + serial_out(up, UART_OMAP_MDR1, priv->mdr1); + udelay(2); + serial_out(up, UART_FCR, up->fcr | UART_FCR_CLEAR_XMIT | + UART_FCR_CLEAR_RCVR); + /* + * Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and + * TX_FIFO_E bit is 1. + */ + while (UART_LSR_THRE != (serial_in(up, UART_LSR) & + (UART_LSR_THRE | UART_LSR_DR))) { + timeout--; + if (!timeout) { + /* Should *never* happen. we warn and carry on */ + dev_crit(up->port.dev, "Errata i202: timedout %x\n", + serial_in(up, UART_LSR)); + break; + } + udelay(1); + } +} + +static void omap_8250_get_divisor(struct uart_port *port, unsigned int baud, + struct omap8250_priv *priv) +{ + unsigned int uartclk = port->uartclk; + unsigned int div_13, div_16; + unsigned int abs_d13, abs_d16; + + /* + * Old custom speed handling. + */ + if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) { + priv->quot = port->custom_divisor & 0xffff; + /* + * I assume that nobody is using this. But hey, if somebody + * would like to specify the divisor _and_ the mode then the + * driver is ready and waiting for it. + */ + if (port->custom_divisor & (1 << 16)) + priv->mdr1 = UART_OMAP_MDR1_13X_MODE; + else + priv->mdr1 = UART_OMAP_MDR1_16X_MODE; + return; + } + div_13 = DIV_ROUND_CLOSEST(uartclk, 13 * baud); + div_16 = DIV_ROUND_CLOSEST(uartclk, 16 * baud); + + if (!div_13) + div_13 = 1; + if (!div_16) + div_16 = 1; + + abs_d13 = abs(baud - uartclk / 13 / div_13); + abs_d16 = abs(baud - uartclk / 16 / div_16); + + if (abs_d13 >= abs_d16) { + priv->mdr1 = UART_OMAP_MDR1_16X_MODE; + priv->quot = div_16; + } else { + priv->mdr1 = UART_OMAP_MDR1_13X_MODE; + priv->quot = div_13; + } +} + +static void omap8250_update_scr(struct uart_8250_port *up, + struct omap8250_priv *priv) +{ + u8 old_scr; + + old_scr = serial_in(up, UART_OMAP_SCR); + if (old_scr == priv->scr) + return; + + /* + * The manual recommends not to enable the DMA mode selector in the SCR + * (instead of the FCR) register _and_ selecting the DMA mode as one + * register write because this may lead to malfunction. + */ + if (priv->scr & OMAP_UART_SCR_DMAMODE_MASK) + serial_out(up, UART_OMAP_SCR, + priv->scr & ~OMAP_UART_SCR_DMAMODE_MASK); + serial_out(up, UART_OMAP_SCR, priv->scr); +} + +static void omap8250_restore_regs(struct uart_8250_port *up) +{ + struct omap8250_priv *priv = up->port.private_data; + struct uart_8250_dma *dma = up->dma; + + if (dma && dma->tx_running) { + /* + * TCSANOW requests the change to occur immediately however if + * we have a TX-DMA operation in progress then it has been + * observed that it might stall and never complete. Therefore we + * delay DMA completes to prevent this hang from happen. + */ + priv->delayed_restore = 1; + return; + } + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, UART_EFR_ECB); + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_out(up, UART_MCR, UART_MCR_TCRTLR); + serial_out(up, UART_FCR, up->fcr); + + omap8250_update_scr(up, priv); + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + + serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_RESTORE(16) | + OMAP_UART_TCR_HALT(52)); + serial_out(up, UART_TI752_TLR, + TRIGGER_TLR_MASK(TX_TRIGGER) << UART_TI752_TLR_TX | + TRIGGER_TLR_MASK(RX_TRIGGER) << UART_TI752_TLR_RX); + + serial_out(up, UART_LCR, 0); + + /* drop TCR + TLR access, we setup XON/XOFF later */ + serial_out(up, UART_MCR, up->mcr); + serial_out(up, UART_IER, up->ier); + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_dl_write(up, priv->quot); + + serial_out(up, UART_EFR, priv->efr); + + /* Configure flow control */ + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_XON1, priv->xon); + serial_out(up, UART_XOFF1, priv->xoff); + + serial_out(up, UART_LCR, up->lcr); + /* need mode A for FCR */ + if (priv->habit & UART_ERRATA_i202_MDR1_ACCESS) + omap_8250_mdr1_errataset(up, priv); + else + serial_out(up, UART_OMAP_MDR1, priv->mdr1); + up->port.ops->set_mctrl(&up->port, up->port.mctrl); +} + +/* + * OMAP can use "CLK / (16 or 13) / div" for baud rate. And then we have have + * some differences in how we want to handle flow control. + */ +static void omap_8250_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + struct omap8250_priv *priv = up->port.private_data; + unsigned char cval = 0; + unsigned int baud; + + switch (termios->c_cflag & CSIZE) { + case CS5: + cval = UART_LCR_WLEN5; + break; + case CS6: + cval = UART_LCR_WLEN6; + break; + case CS7: + cval = UART_LCR_WLEN7; + break; + default: + case CS8: + cval = UART_LCR_WLEN8; + break; + } + + if (termios->c_cflag & CSTOPB) + cval |= UART_LCR_STOP; + if (termios->c_cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(termios->c_cflag & PARODD)) + cval |= UART_LCR_EPAR; + if (termios->c_cflag & CMSPAR) + cval |= UART_LCR_SPAR; + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, + port->uartclk / 16 / 0xffff, + port->uartclk / 13); + omap_8250_get_divisor(port, baud, priv); + + /* + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ + pm_runtime_get_sync(port->dev); + spin_lock_irq(&port->lock); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if (termios->c_iflag & INPCK) + up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (termios->c_iflag & (IGNBRK | PARMRK)) + up->port.read_status_mask |= UART_LSR_BI; + + /* + * Characters to ignore + */ + up->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (termios->c_iflag & IGNBRK) { + up->port.ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_OE; + } + + /* + * ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) + up->port.ignore_status_mask |= UART_LSR_DR; + + /* + * Modem status interrupts + */ + up->ier &= ~UART_IER_MSI; + if (UART_ENABLE_MS(&up->port, termios->c_cflag)) + up->ier |= UART_IER_MSI; + + up->lcr = cval; + /* Up to here it was mostly serial8250_do_set_termios() */ + + /* + * We enable TRIG_GRANU for RX and TX and additionaly we set + * SCR_TX_EMPTY bit. The result is the following: + * - RX_TRIGGER amount of bytes in the FIFO will cause an interrupt. + * - less than RX_TRIGGER number of bytes will also cause an interrupt + * once the UART decides that there no new bytes arriving. + * - Once THRE is enabled, the interrupt will be fired once the FIFO is + * empty - the trigger level is ignored here. + * + * Once DMA is enabled: + * - UART will assert the TX DMA line once there is room for TX_TRIGGER + * bytes in the TX FIFO. On each assert the DMA engine will move + * TX_TRIGGER bytes into the FIFO. + * - UART will assert the RX DMA line once there are RX_TRIGGER bytes in + * the FIFO and move RX_TRIGGER bytes. + * This is because threshold and trigger values are the same. + */ + up->fcr = UART_FCR_ENABLE_FIFO; + up->fcr |= TRIGGER_FCR_MASK(TX_TRIGGER) << OMAP_UART_FCR_TX_TRIG; + up->fcr |= TRIGGER_FCR_MASK(RX_TRIGGER) << OMAP_UART_FCR_RX_TRIG; + + priv->scr = OMAP_UART_SCR_RX_TRIG_GRANU1_MASK | OMAP_UART_SCR_TX_EMPTY | + OMAP_UART_SCR_TX_TRIG_GRANU1_MASK; + + if (up->dma) + priv->scr |= OMAP_UART_SCR_DMAMODE_1 | + OMAP_UART_SCR_DMAMODE_CTL; + + priv->xon = termios->c_cc[VSTART]; + priv->xoff = termios->c_cc[VSTOP]; + + priv->efr = 0; + up->mcr &= ~(UART_MCR_RTS | UART_MCR_XONANY); + if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) { + /* Enable AUTORTS and AUTOCTS */ + priv->efr |= UART_EFR_CTS | UART_EFR_RTS; + + /* Ensure MCR RTS is asserted */ + up->mcr |= UART_MCR_RTS; + } else if (up->port.flags & UPF_SOFT_FLOW) { + /* + * IXON Flag: + * Enable XON/XOFF flow control on input. + * Receiver compares XON1, XOFF1. + */ + if (termios->c_iflag & IXON) + priv->efr |= OMAP_UART_SW_RX; + + /* + * IXOFF Flag: + * Enable XON/XOFF flow control on output. + * Transmit XON1, XOFF1 + */ + if (termios->c_iflag & IXOFF) + priv->efr |= OMAP_UART_SW_TX; + + /* + * IXANY Flag: + * Enable any character to restart output. + * Operation resumes after receiving any + * character after recognition of the XOFF character + */ + if (termios->c_iflag & IXANY) + up->mcr |= UART_MCR_XONANY; + } + omap8250_restore_regs(up); + + spin_unlock_irq(&up->port.lock); + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); + + /* calculate wakeup latency constraint */ + priv->calc_latency = USEC_PER_SEC * 64 * 8 / baud; + priv->latency = priv->calc_latency; + + schedule_work(&priv->qos_work); + + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); +} + +/* same as 8250 except that we may have extra flow bits set in EFR */ +static void omap_8250_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + struct omap8250_priv *priv = up->port.private_data; + + pm_runtime_get_sync(port->dev); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, priv->efr | UART_EFR_ECB); + serial_out(up, UART_LCR, 0); + + serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, priv->efr); + serial_out(up, UART_LCR, 0); + + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); +} + +static void omap_serial_fill_features_erratas(struct uart_8250_port *up, + struct omap8250_priv *priv) +{ + u32 mvr, scheme; + u16 revision, major, minor; + + mvr = uart_read(up, UART_OMAP_MVER); + + /* Check revision register scheme */ + scheme = mvr >> OMAP_UART_MVR_SCHEME_SHIFT; + + switch (scheme) { + case 0: /* Legacy Scheme: OMAP2/3 */ + /* MINOR_REV[0:4], MAJOR_REV[4:7] */ + major = (mvr & OMAP_UART_LEGACY_MVR_MAJ_MASK) >> + OMAP_UART_LEGACY_MVR_MAJ_SHIFT; + minor = (mvr & OMAP_UART_LEGACY_MVR_MIN_MASK); + break; + case 1: + /* New Scheme: OMAP4+ */ + /* MINOR_REV[0:5], MAJOR_REV[8:10] */ + major = (mvr & OMAP_UART_MVR_MAJ_MASK) >> + OMAP_UART_MVR_MAJ_SHIFT; + minor = (mvr & OMAP_UART_MVR_MIN_MASK); + break; + default: + dev_warn(up->port.dev, + "Unknown revision, defaulting to highest\n"); + /* highest possible revision */ + major = 0xff; + minor = 0xff; + } + /* normalize revision for the driver */ + revision = UART_BUILD_REVISION(major, minor); + + switch (revision) { + case OMAP_UART_REV_46: + priv->habit = UART_ERRATA_i202_MDR1_ACCESS; + break; + case OMAP_UART_REV_52: + priv->habit = UART_ERRATA_i202_MDR1_ACCESS | + OMAP_UART_WER_HAS_TX_WAKEUP; + break; + case OMAP_UART_REV_63: + priv->habit = UART_ERRATA_i202_MDR1_ACCESS | + OMAP_UART_WER_HAS_TX_WAKEUP; + break; + default: + break; + } +} + +static void omap8250_uart_qos_work(struct work_struct *work) +{ + struct omap8250_priv *priv; + + priv = container_of(work, struct omap8250_priv, qos_work); + pm_qos_update_request(&priv->pm_qos_request, priv->latency); +} + +static irqreturn_t omap_wake_irq(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + int ret; + + ret = port->handle_irq(port); + if (ret) + return IRQ_HANDLED; + return IRQ_NONE; +} + +static int omap_8250_startup(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + struct omap8250_priv *priv = port->private_data; + + int ret; + + if (priv->wakeirq) { + ret = request_irq(priv->wakeirq, omap_wake_irq, + port->irqflags, "uart wakeup irq", port); + if (ret) + return ret; + disable_irq(priv->wakeirq); + } + + pm_runtime_get_sync(port->dev); + + ret = serial8250_do_startup(port); + if (ret) + goto err; + +#ifdef CONFIG_PM_RUNTIME + up->capabilities |= UART_CAP_RPM; +#endif + + /* Enable module level wake up */ + priv->wer = OMAP_UART_WER_MOD_WKUP; + if (priv->habit & OMAP_UART_WER_HAS_TX_WAKEUP) + priv->wer |= OMAP_UART_TX_WAKEUP_EN; + serial_out(up, UART_OMAP_WER, priv->wer); + + if (up->dma) + up->dma->rx_dma(up, 0); + + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); + return 0; +err: + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); + if (priv->wakeirq) + free_irq(priv->wakeirq, port); + return ret; +} + +static void omap_8250_shutdown(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + struct omap8250_priv *priv = port->private_data; + + flush_work(&priv->qos_work); + if (up->dma) + up->dma->rx_dma(up, UART_IIR_RX_TIMEOUT); + + pm_runtime_get_sync(port->dev); + + serial_out(up, UART_OMAP_WER, 0); + serial8250_do_shutdown(port); + + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); + + if (priv->wakeirq) + free_irq(priv->wakeirq, port); +} + +static void omap_8250_throttle(struct uart_port *port) +{ + unsigned long flags; + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + pm_runtime_get_sync(port->dev); + + spin_lock_irqsave(&port->lock, flags); + up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); + serial_out(up, UART_IER, up->ier); + spin_unlock_irqrestore(&port->lock, flags); + + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); +} + +static void omap_8250_unthrottle(struct uart_port *port) +{ + unsigned long flags; + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + pm_runtime_get_sync(port->dev); + + spin_lock_irqsave(&port->lock, flags); + up->ier |= UART_IER_RLSI | UART_IER_RDI; + serial_out(up, UART_IER, up->ier); + spin_unlock_irqrestore(&port->lock, flags); + + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); +} + +#ifdef CONFIG_SERIAL_8250_DMA +static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir); + +static void __dma_rx_do_complete(struct uart_8250_port *p, bool error) +{ + struct uart_8250_dma *dma = p->dma; + struct tty_port *tty_port = &p->port.state->port; + struct dma_tx_state state; + int count; + + dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr, + dma->rx_size, DMA_FROM_DEVICE); + + dma->rx_running = 0; + dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); + dmaengine_terminate_all(dma->rxchan); + + count = dma->rx_size - state.residue; + + tty_insert_flip_string(tty_port, dma->rx_buf, count); + p->port.icount.rx += count; + if (!error) + omap_8250_rx_dma(p, 0); + + tty_flip_buffer_push(tty_port); +} + +static void __dma_rx_complete(void *param) +{ + __dma_rx_do_complete(param, false); +} + +static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) +{ + struct uart_8250_dma *dma = p->dma; + struct dma_async_tx_descriptor *desc; + + switch (iir & 0x3f) { + case UART_IIR_RLSI: + /* 8250_core handles errors and break interrupts */ + if (dma->rx_running) { + dmaengine_pause(dma->rxchan); + __dma_rx_do_complete(p, true); + } + return -EIO; + case UART_IIR_RX_TIMEOUT: + /* + * If RCVR FIFO trigger level was not reached, complete the + * transfer and let 8250_core copy the remaining data. + */ + if (dma->rx_running) { + dmaengine_pause(dma->rxchan); + __dma_rx_do_complete(p, true); + } + return -ETIMEDOUT; + case UART_IIR_RDI: + /* + * The OMAP UART is a special BEAST. If we receive RDI we _have_ + * a DMA transfer programmed but it didn't work. One reason is + * that we were too slow and there were too many bytes in the + * FIFO, the UART counted wrong and never kicked the DMA engine + * to do anything. That means once we receive RDI on OMAP then + * the DMA won't do anything soon so we have to cancel the DMA + * transfer and purge the FIFO manually. + */ + if (dma->rx_running) { + dmaengine_pause(dma->rxchan); + __dma_rx_do_complete(p, true); + } + return -ETIMEDOUT; + + default: + break; + } + + if (dma->rx_running) + return 0; + + desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr, + dma->rx_size, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) + return -EBUSY; + + dma->rx_running = 1; + desc->callback = __dma_rx_complete; + desc->callback_param = p; + + dma->rx_cookie = dmaengine_submit(desc); + + dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr, + dma->rx_size, DMA_FROM_DEVICE); + + dma_async_issue_pending(dma->rxchan); + return 0; +} + +static int omap_8250_tx_dma(struct uart_8250_port *p); + +static void omap_8250_dma_tx_complete(void *param) +{ + struct uart_8250_port *p = param; + struct uart_8250_dma *dma = p->dma; + struct circ_buf *xmit = &p->port.state->xmit; + unsigned long flags; + bool en_thri = false; + struct omap8250_priv *priv = p->port.private_data; + + dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr, + UART_XMIT_SIZE, DMA_TO_DEVICE); + + spin_lock_irqsave(&p->port.lock, flags); + + dma->tx_running = 0; + + xmit->tail += dma->tx_size; + xmit->tail &= UART_XMIT_SIZE - 1; + p->port.icount.tx += dma->tx_size; + + if (priv->delayed_restore) { + priv->delayed_restore = 0; + omap8250_restore_regs(p); + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&p->port); + + if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) { + int ret; + + ret = omap_8250_tx_dma(p); + if (ret) + en_thri = true; + + } else if (p->capabilities & UART_CAP_RPM) { + en_thri = true; + } + + if (en_thri) { + dma->tx_err = 1; + p->ier |= UART_IER_THRI; + serial_port_out(&p->port, UART_IER, p->ier); + } + + spin_unlock_irqrestore(&p->port.lock, flags); +} + +static int omap_8250_tx_dma(struct uart_8250_port *p) +{ + struct uart_8250_dma *dma = p->dma; + struct omap8250_priv *priv = p->port.private_data; + struct circ_buf *xmit = &p->port.state->xmit; + struct dma_async_tx_descriptor *desc; + unsigned int skip_byte = 0; + int ret; + + if (dma->tx_running) + return 0; + if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) { + + /* + * Even if no data, we need to return an error for the two cases + * below so serial8250_tx_chars() is invoked and properly clears + * THRI and/or runtime suspend. + */ + if (dma->tx_err || p->capabilities & UART_CAP_RPM) { + ret = -EBUSY; + goto err; + } + if (p->ier & UART_IER_THRI) { + p->ier &= ~UART_IER_THRI; + serial_out(p, UART_IER, p->ier); + } + return 0; + } + + dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + if (priv->habit & OMAP_DMA_TX_KICK) { + u8 tx_lvl; + + /* + * We need to put the first byte into the FIFO in order to start + * the DMA transfer. For transfers smaller than four bytes we + * don't bother doing DMA at all. It seem not matter if there + * are still bytes in the FIFO from the last transfer (in case + * we got here directly from omap_8250_dma_tx_complete()). Bytes + * leaving the FIFO seem not to trigger the DMA transfer. It is + * really the byte that we put into the FIFO. + * If the FIFO is already full then we most likely got here from + * omap_8250_dma_tx_complete(). And this means the DMA engine + * just completed its work. We don't have to wait the complete + * 86us at 115200,8n1 but around 60us (not to mention lower + * baudrates). So in that case we take the interrupt and try + * again with an empty FIFO. + */ + tx_lvl = serial_in(p, UART_OMAP_TX_LVL); + if (tx_lvl == p->tx_loadsz) { + ret = -EBUSY; + goto err; + } + if (dma->tx_size < 4) { + ret = -EINVAL; + goto err; + } + skip_byte = 1; + } + + desc = dmaengine_prep_slave_single(dma->txchan, + dma->tx_addr + xmit->tail + skip_byte, + dma->tx_size - skip_byte, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + ret = -EBUSY; + goto err; + } + + dma->tx_running = 1; + + desc->callback = omap_8250_dma_tx_complete; + desc->callback_param = p; + + dma->tx_cookie = dmaengine_submit(desc); + + dma_sync_single_for_device(dma->txchan->device->dev, dma->tx_addr, + UART_XMIT_SIZE, DMA_TO_DEVICE); + + dma_async_issue_pending(dma->txchan); + if (dma->tx_err) + dma->tx_err = 0; + + if (p->ier & UART_IER_THRI) { + p->ier &= ~UART_IER_THRI; + serial_out(p, UART_IER, p->ier); + } + if (skip_byte) + serial_out(p, UART_TX, xmit->buf[xmit->tail]); + return 0; +err: + dma->tx_err = 1; + return ret; +} + +/* + * This is mostly serial8250_handle_irq(). We have a slightly different DMA + * hoook for RX/TX and need different logic for them in the ISR. Therefore we + * use the default routine in the non-DMA case and this one for with DMA. + */ +static int omap_8250_dma_handle_irq(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned char status; + unsigned long flags; + u8 iir; + int dma_err = 0; + + serial8250_rpm_get(up); + + iir = serial_port_in(port, UART_IIR); + if (iir & UART_IIR_NO_INT) { + serial8250_rpm_put(up); + return 0; + } + + spin_lock_irqsave(&port->lock, flags); + + status = serial_port_in(port, UART_LSR); + + if (status & (UART_LSR_DR | UART_LSR_BI)) { + + dma_err = omap_8250_rx_dma(up, iir); + if (dma_err) { + status = serial8250_rx_chars(up, status); + omap_8250_rx_dma(up, 0); + } + } + serial8250_modem_status(up); + if (status & UART_LSR_THRE && up->dma->tx_err) { + if (uart_tx_stopped(&up->port) || + uart_circ_empty(&up->port.state->xmit)) { + up->dma->tx_err = 0; + serial8250_tx_chars(up); + } else { + /* + * try again due to an earlier failer which + * might have been resolved by now. + */ + dma_err = omap_8250_tx_dma(up); + if (dma_err) + serial8250_tx_chars(up); + } + } + + spin_unlock_irqrestore(&port->lock, flags); + serial8250_rpm_put(up); + return 1; +} + +static bool the_no_dma_filter_fn(struct dma_chan *chan, void *param) +{ + return false; +} + +#else + +static inline int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) +{ + return -EINVAL; +} +#endif + +static int omap8250_probe(struct platform_device *pdev) +{ + struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + struct omap8250_priv *priv; + struct uart_8250_port up; + int ret; + void __iomem *membase; + + if (!regs || !irq) { + dev_err(&pdev->dev, "missing registers or irq\n"); + return -EINVAL; + } + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + membase = devm_ioremap_nocache(&pdev->dev, regs->start, + resource_size(regs)); + if (!membase) + return -ENODEV; + + memset(&up, 0, sizeof(up)); + up.port.dev = &pdev->dev; + up.port.mapbase = regs->start; + up.port.membase = membase; + up.port.irq = irq->start; + /* + * It claims to be 16C750 compatible however it is a little different. + * It has EFR and has no FCR7_64byte bit. The AFE (which it claims to + * have) is enabled via EFR instead of MCR. The type is set here 8250 + * just to get things going. UNKNOWN does not work for a few reasons and + * we don't need our own type since we don't use 8250's set_termios() + * or pm callback. + */ + up.port.type = PORT_8250; + up.port.iotype = UPIO_MEM; + up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SOFT_FLOW | + UPF_HARD_FLOW; + up.port.private_data = priv; + + up.port.regshift = 2; + up.port.fifosize = 64; + up.tx_loadsz = 64; + up.capabilities = UART_CAP_FIFO; +#ifdef CONFIG_PM_RUNTIME + /* + * PM_RUNTIME is mostly transparent. However to do it right we need to a + * TX empty interrupt before we can put the device to auto idle. So if + * PM_RUNTIME is not enabled we don't add that flag and can spare that + * one extra interrupt in the TX path. + */ + up.capabilities |= UART_CAP_RPM; +#endif + up.port.set_termios = omap_8250_set_termios; + up.port.pm = omap_8250_pm; + up.port.startup = omap_8250_startup; + up.port.shutdown = omap_8250_shutdown; + up.port.throttle = omap_8250_throttle; + up.port.unthrottle = omap_8250_unthrottle; + + if (pdev->dev.of_node) { + ret = of_alias_get_id(pdev->dev.of_node, "serial"); + + of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &up.port.uartclk); + priv->wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1); + } else { + ret = pdev->id; + } + if (ret < 0) { + dev_err(&pdev->dev, "failed to get alias/pdev id\n"); + return ret; + } + up.port.line = ret; + + if (!up.port.uartclk) { + up.port.uartclk = DEFAULT_CLK_SPEED; + dev_warn(&pdev->dev, + "No clock speed specified: using default: %d\n", + DEFAULT_CLK_SPEED); + } + + priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; + priv->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; + pm_qos_add_request(&priv->pm_qos_request, PM_QOS_CPU_DMA_LATENCY, + priv->latency); + INIT_WORK(&priv->qos_work, omap8250_uart_qos_work); + + device_init_wakeup(&pdev->dev, true); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, -1); + + pm_runtime_irq_safe(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + pm_runtime_get_sync(&pdev->dev); + + omap_serial_fill_features_erratas(&up, priv); +#ifdef CONFIG_SERIAL_8250_DMA + if (pdev->dev.of_node) { + /* + * Oh DMA support. If there are no DMA properties in the DT then + * we will fall back to a generic DMA channel which does not + * really work here. To ensure that we do not get a generic DMA + * channel assigned, we have the the_no_dma_filter_fn() here. + * To avoid "failed to request DMA" messages we check for DMA + * properties in DT. + */ + ret = of_property_count_strings(pdev->dev.of_node, "dma-names"); + if (ret == 2) { + up.dma = &priv->omap8250_dma; + up.port.handle_irq = omap_8250_dma_handle_irq; + priv->omap8250_dma.fn = the_no_dma_filter_fn; + priv->omap8250_dma.tx_dma = omap_8250_tx_dma; + priv->omap8250_dma.rx_dma = omap_8250_rx_dma; + priv->omap8250_dma.rx_size = RX_TRIGGER; + priv->omap8250_dma.rxconf.src_maxburst = RX_TRIGGER; + priv->omap8250_dma.txconf.dst_maxburst = TX_TRIGGER; + + if (of_machine_is_compatible("ti,am33xx")) + priv->habit |= OMAP_DMA_TX_KICK; + } + } +#endif + ret = serial8250_register_8250_port(&up); + if (ret < 0) { + dev_err(&pdev->dev, "unable to register 8250 port\n"); + goto err; + } + priv->line = ret; + platform_set_drvdata(pdev, priv); + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + return 0; +err: + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); + return ret; +} + +static int omap8250_remove(struct platform_device *pdev) +{ + struct omap8250_priv *priv = platform_get_drvdata(pdev); + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + serial8250_unregister_port(priv->line); + pm_qos_remove_request(&priv->pm_qos_request); + device_init_wakeup(&pdev->dev, false); + return 0; +} + +#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME) + +static inline void omap8250_enable_wakeirq(struct omap8250_priv *priv, + bool enable) +{ + if (!priv->wakeirq) + return; + + if (enable) + enable_irq(priv->wakeirq); + else + disable_irq_nosync(priv->wakeirq); +} + +static void omap8250_enable_wakeup(struct omap8250_priv *priv, + bool enable) +{ + if (enable == priv->wakeups_enabled) + return; + + omap8250_enable_wakeirq(priv, enable); + priv->wakeups_enabled = enable; +} +#endif + +#ifdef CONFIG_PM_SLEEP +static int omap8250_prepare(struct device *dev) +{ + struct omap8250_priv *priv = dev_get_drvdata(dev); + + if (!priv) + return 0; + priv->is_suspending = true; + return 0; +} + +static void omap8250_complete(struct device *dev) +{ + struct omap8250_priv *priv = dev_get_drvdata(dev); + + if (!priv) + return; + priv->is_suspending = false; +} + +static int omap8250_suspend(struct device *dev) +{ + struct omap8250_priv *priv = dev_get_drvdata(dev); + + serial8250_suspend_port(priv->line); + flush_work(&priv->qos_work); + + if (device_may_wakeup(dev)) + omap8250_enable_wakeup(priv, true); + else + omap8250_enable_wakeup(priv, false); + return 0; +} + +static int omap8250_resume(struct device *dev) +{ + struct omap8250_priv *priv = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + omap8250_enable_wakeup(priv, false); + + serial8250_resume_port(priv->line); + return 0; +} +#else +#define omap8250_prepare NULL +#define omap8250_complete NULL +#endif + +#ifdef CONFIG_PM_RUNTIME +static int omap8250_lost_context(struct uart_8250_port *up) +{ + u32 val; + + val = serial_in(up, UART_OMAP_MDR1); + /* + * If we lose context, then MDR1 is set to its reset value which is + * UART_OMAP_MDR1_DISABLE. After set_termios() we set it either to 13x + * or 16x but never to disable again. + */ + if (val == UART_OMAP_MDR1_DISABLE) + return 1; + return 0; +} + +static int omap8250_runtime_suspend(struct device *dev) +{ + struct omap8250_priv *priv = dev_get_drvdata(dev); + struct uart_8250_port *up; + + up = serial8250_get_port(priv->line); + /* + * When using 'no_console_suspend', the console UART must not be + * suspended. Since driver suspend is managed by runtime suspend, + * preventing runtime suspend (by returning error) will keep device + * active during suspend. + */ + if (priv->is_suspending && !console_suspend_enabled) { + if (uart_console(&up->port)) + return -EBUSY; + } + + omap8250_enable_wakeup(priv, true); + if (up->dma) + omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT); + + priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; + schedule_work(&priv->qos_work); + + return 0; +} + +static int omap8250_runtime_resume(struct device *dev) +{ + struct omap8250_priv *priv = dev_get_drvdata(dev); + struct uart_8250_port *up; + int loss_cntx; + + /* In case runtime-pm tries this before we are setup */ + if (!priv) + return 0; + + up = serial8250_get_port(priv->line); + omap8250_enable_wakeup(priv, false); + loss_cntx = omap8250_lost_context(up); + + if (loss_cntx) + omap8250_restore_regs(up); + + if (up->dma) + omap_8250_rx_dma(up, 0); + + priv->latency = priv->calc_latency; + schedule_work(&priv->qos_work); + return 0; +} +#endif + +static const struct dev_pm_ops omap8250_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(omap8250_suspend, omap8250_resume) + SET_RUNTIME_PM_OPS(omap8250_runtime_suspend, + omap8250_runtime_resume, NULL) + .prepare = omap8250_prepare, + .complete = omap8250_complete, +}; + +static const struct of_device_id omap8250_dt_ids[] = { + { .compatible = "ti,omap2-uart" }, + { .compatible = "ti,omap3-uart" }, + { .compatible = "ti,omap4-uart" }, + {}, +}; +MODULE_DEVICE_TABLE(of, omap8250_dt_ids); + +static struct platform_driver omap8250_platform_driver = { + .driver = { + .name = "omap8250", + .pm = &omap8250_dev_pm_ops, + .of_match_table = omap8250_dt_ids, + .owner = THIS_MODULE, + }, + .probe = omap8250_probe, + .remove = omap8250_remove, +}; +module_platform_driver(omap8250_platform_driver); + +MODULE_AUTHOR("Sebastian Andrzej Siewior"); +MODULE_DESCRIPTION("OMAP 8250 Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index beb9d71cd47a..31feeb2d0a66 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -79,29 +79,24 @@ setup_port(struct serial_private *priv, struct uart_8250_port *port, int bar, int offset, int regshift) { struct pci_dev *dev = priv->dev; - unsigned long base, len; if (bar >= PCI_NUM_BAR_RESOURCES) return -EINVAL; - base = pci_resource_start(dev, bar); - if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) { - len = pci_resource_len(dev, bar); - if (!priv->remapped_bar[bar]) - priv->remapped_bar[bar] = ioremap_nocache(base, len); + priv->remapped_bar[bar] = pci_ioremap_bar(dev, bar); if (!priv->remapped_bar[bar]) return -ENOMEM; port->port.iotype = UPIO_MEM; port->port.iobase = 0; - port->port.mapbase = base + offset; + port->port.mapbase = pci_resource_start(dev, bar) + offset; port->port.membase = priv->remapped_bar[bar] + offset; port->port.regshift = regshift; } else { port->port.iotype = UPIO_PORT; - port->port.iobase = base + offset; + port->port.iobase = pci_resource_start(dev, bar) + offset; port->port.mapbase = 0; port->port.membase = NULL; port->port.regshift = 0; @@ -317,7 +312,6 @@ static void pci_plx9050_exit(struct pci_dev *dev) static void pci_ni8420_exit(struct pci_dev *dev) { void __iomem *p; - unsigned long base, len; unsigned int bar = 0; if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) { @@ -325,9 +319,7 @@ static void pci_ni8420_exit(struct pci_dev *dev) return; } - base = pci_resource_start(dev, bar); - len = pci_resource_len(dev, bar); - p = ioremap_nocache(base, len); + p = pci_ioremap_bar(dev, bar); if (p == NULL) return; @@ -349,7 +341,6 @@ static void pci_ni8420_exit(struct pci_dev *dev) static void pci_ni8430_exit(struct pci_dev *dev) { void __iomem *p; - unsigned long base, len; unsigned int bar = 0; if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) { @@ -357,9 +348,7 @@ static void pci_ni8430_exit(struct pci_dev *dev) return; } - base = pci_resource_start(dev, bar); - len = pci_resource_len(dev, bar); - p = ioremap_nocache(base, len); + p = pci_ioremap_bar(dev, bar); if (p == NULL) return; @@ -682,7 +671,6 @@ static int pci_xircom_init(struct pci_dev *dev) static int pci_ni8420_init(struct pci_dev *dev) { void __iomem *p; - unsigned long base, len; unsigned int bar = 0; if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) { @@ -690,9 +678,7 @@ static int pci_ni8420_init(struct pci_dev *dev) return 0; } - base = pci_resource_start(dev, bar); - len = pci_resource_len(dev, bar); - p = ioremap_nocache(base, len); + p = pci_ioremap_bar(dev, bar); if (p == NULL) return -ENOMEM; @@ -714,7 +700,7 @@ static int pci_ni8420_init(struct pci_dev *dev) static int pci_ni8430_init(struct pci_dev *dev) { void __iomem *p; - unsigned long base, len; + struct pci_bus_region region; u32 device_window; unsigned int bar = 0; @@ -723,14 +709,17 @@ static int pci_ni8430_init(struct pci_dev *dev) return 0; } - base = pci_resource_start(dev, bar); - len = pci_resource_len(dev, bar); - p = ioremap_nocache(base, len); + p = pci_ioremap_bar(dev, bar); if (p == NULL) return -ENOMEM; - /* Set device window address and size in BAR0 */ - device_window = ((base + MITE_IOWBSR1_WIN_OFFSET) & 0xffffff00) + /* + * Set device window address and size in BAR0, while acknowledging that + * the resource structure may contain a translated address that differs + * from the address the device responds to. + */ + pcibios_resource_to_bus(dev->bus, ®ion, &dev->resource[bar]); + device_window = ((region.start + MITE_IOWBSR1_WIN_OFFSET) & 0xffffff00) | MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE; writel(device_window, p + MITE_IOWBSR1); @@ -757,8 +746,8 @@ pci_ni8430_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + struct pci_dev *dev = priv->dev; void __iomem *p; - unsigned long base, len; unsigned int bar, offset = board->first_offset; if (idx >= board->num_ports) @@ -767,9 +756,9 @@ pci_ni8430_setup(struct serial_private *priv, bar = FL_GET_BASE(board->flags); offset += idx * board->uart_offset; - base = pci_resource_start(priv->dev, bar); - len = pci_resource_len(priv->dev, bar); - p = ioremap_nocache(base, len); + p = pci_ioremap_bar(dev, bar); + if (!p) + return -ENOMEM; /* enable the transceiver */ writeb(readb(p + offset + NI8430_PORTCON) | NI8430_PORTCON_TXVR_ENABLE, @@ -1003,6 +992,40 @@ static void pci_ite887x_exit(struct pci_dev *dev) } /* + * EndRun Technologies. + * Determine the number of ports available on the device. + */ +#define PCI_VENDOR_ID_ENDRUN 0x7401 +#define PCI_DEVICE_ID_ENDRUN_1588 0xe100 + +static int pci_endrun_init(struct pci_dev *dev) +{ + u8 __iomem *p; + unsigned long deviceID; + unsigned int number_uarts = 0; + + /* EndRun device is all 0xexxx */ + if (dev->vendor == PCI_VENDOR_ID_ENDRUN && + (dev->device & 0xf000) != 0xe000) + return 0; + + p = pci_iomap(dev, 0, 5); + if (p == NULL) + return -ENOMEM; + + deviceID = ioread32(p); + /* EndRun device */ + if (deviceID == 0x07000200) { + number_uarts = ioread8(p + 4); + dev_dbg(&dev->dev, + "%d ports detected on EndRun PCI Express device\n", + number_uarts); + } + pci_iounmap(dev, p); + return number_uarts; +} + +/* * Oxford Semiconductor Inc. * Check that device is part of the Tornado range of devices, then determine * the number of ports available on the device. @@ -1531,25 +1554,48 @@ static int pci_fintek_setup(struct serial_private *priv, unsigned long iobase; unsigned long ciobase = 0; u8 config_base; + u32 bar_data[3]; /* - * We are supposed to be able to read these from the PCI config space, - * but the values there don't seem to match what we need to use, so - * just use these hard-coded values for now, as they are correct. + * Find each UARTs offset in PCI configuraion space */ switch (idx) { - case 0: iobase = 0xe000; config_base = 0x40; break; - case 1: iobase = 0xe008; config_base = 0x48; break; - case 2: iobase = 0xe010; config_base = 0x50; break; - case 3: iobase = 0xe018; config_base = 0x58; break; - case 4: iobase = 0xe020; config_base = 0x60; break; - case 5: iobase = 0xe028; config_base = 0x68; break; - case 6: iobase = 0xe030; config_base = 0x70; break; - case 7: iobase = 0xe038; config_base = 0x78; break; - case 8: iobase = 0xe040; config_base = 0x80; break; - case 9: iobase = 0xe048; config_base = 0x88; break; - case 10: iobase = 0xe050; config_base = 0x90; break; - case 11: iobase = 0xe058; config_base = 0x98; break; + case 0: + config_base = 0x40; + break; + case 1: + config_base = 0x48; + break; + case 2: + config_base = 0x50; + break; + case 3: + config_base = 0x58; + break; + case 4: + config_base = 0x60; + break; + case 5: + config_base = 0x68; + break; + case 6: + config_base = 0x70; + break; + case 7: + config_base = 0x78; + break; + case 8: + config_base = 0x80; + break; + case 9: + config_base = 0x88; + break; + case 10: + config_base = 0x90; + break; + case 11: + config_base = 0x98; + break; default: /* Unknown number of ports, get out of here */ return -EINVAL; @@ -1560,6 +1606,14 @@ static int pci_fintek_setup(struct serial_private *priv, ciobase = (int)(base + (0x8 * idx)); } + /* Get the io address dispatch from the BIOS */ + pci_read_config_dword(pdev, 0x24, &bar_data[0]); + pci_read_config_dword(pdev, 0x20, &bar_data[1]); + pci_read_config_dword(pdev, 0x1c, &bar_data[2]); + + /* Calculate Real IO Port */ + iobase = (bar_data[idx/4] & 0xffffffe0) + (idx % 4) * 8; + dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%lx ciobase=0x%lx config_base=0x%2x\n", __func__, idx, iobase, ciobase, config_base); @@ -1760,6 +1814,16 @@ pci_wch_ch353_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } +static int +pci_wch_ch382_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + port->port.flags |= UPF_FIXED_TYPE; + port->port.type = PORT_16850; + return pci_default_setup(priv, board, port, idx); +} + #define PCI_VENDOR_ID_SBSMODULARIO 0x124B #define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B #define PCI_DEVICE_ID_OCTPRO 0x0001 @@ -1814,6 +1878,8 @@ pci_wch_ch353_setup(struct serial_private *priv, #define PCI_VENDOR_ID_SUNIX 0x1fd4 #define PCI_DEVICE_ID_SUNIX_1999 0x1999 +#define PCIE_VENDOR_ID_WCH 0x1c00 +#define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 @@ -2346,6 +2412,17 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .setup = pci_netmos_9900_setup, }, /* + * EndRun Technologies + */ + { + .vendor = PCI_VENDOR_ID_ENDRUN, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_endrun_init, + .setup = pci_default_setup, + }, + /* * For Oxford Semiconductor Tornado based devices */ { @@ -2494,6 +2571,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = pci_wch_ch353_setup, }, + /* WCH CH382 2S1P card (16750 clone) */ + { + .vendor = PCIE_VENDOR_ID_WCH, + .device = PCIE_DEVICE_ID_WCH_CH382_2S1P, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_wch_ch382_setup, + }, /* * ASIX devices with FIFO bug */ @@ -2754,6 +2839,7 @@ enum pci_board_num_t { pbn_panacom2, pbn_panacom4, pbn_plx_romulus, + pbn_endrun_2_4000000, pbn_oxsemi, pbn_oxsemi_1_4000000, pbn_oxsemi_2_4000000, @@ -3299,6 +3385,20 @@ static struct pciserial_board pci_boards[] = { }, /* + * EndRun Technologies + * Uses the size of PCI Base region 0 to + * signal now many ports are available + * 2 port 952 Uart support + */ + [pbn_endrun_2_4000000] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 4000000, + .uart_offset = 0x200, + .first_offset = 0x1000, + }, + + /* * This board uses the size of PCI Base region 0 to * signal now many ports are available */ @@ -3586,6 +3686,7 @@ static const struct pci_device_id blacklist[] = { /* multi-io cards handled by parport_serial */ { PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */ { PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */ + { PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */ }; /* @@ -4171,6 +4272,13 @@ static struct pci_device_id serial_pci_tbl[] = { 0x10b5, 0x106a, 0, 0, pbn_plx_romulus }, /* + * EndRun Technologies. PCI express device range. + * EndRun PTP/1588 has 2 Native UARTs. + */ + { PCI_VENDOR_ID_ENDRUN, PCI_DEVICE_ID_ENDRUN_1588, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_endrun_2_4000000 }, + /* * Quatech cards. These actually have configurable clocks but for * now we just use the default. * diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 21eca79224e4..0fcbcd29502f 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -293,12 +293,21 @@ config SERIAL_8250_EM config SERIAL_8250_RT288X bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support" - depends on SERIAL_8250 && (SOC_RT288X || SOC_RT305X || SOC_RT3883) + depends on SERIAL_8250 && (SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620) help If you have a Ralink RT288x/RT305x SoC based board and want to use the serial port, say Y to this option. The driver can handle up to 2 serial ports. If unsure, say N. +config SERIAL_8250_OMAP + tristate "Support for OMAP internal UART (8250 based driver)" + depends on SERIAL_8250 && ARCH_OMAP2PLUS + help + If you have a machine based on an Texas Instruments OMAP CPU you + can enable its onboard serial ports by enabling this option. + + This driver uses ttyS instead of ttyO. + config SERIAL_8250_FINTEK tristate "Support for Fintek F81216A LPC to 4 UART" depends on SERIAL_8250 && PNP diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index 5256b894e46a..31e7cdc6865c 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -20,5 +20,6 @@ obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o +obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o obj-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o |