diff options
Diffstat (limited to 'drivers/tty/serial/8250')
-rw-r--r-- | drivers/tty/serial/8250/8250_core.c | 8 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_dma.c | 9 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_dw.c | 76 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_early.c | 137 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_gsc.c | 3 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_pci.c | 12 | ||||
-rw-r--r-- | drivers/tty/serial/8250/Kconfig | 1 |
7 files changed, 96 insertions, 150 deletions
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 86c00b1c5583..d8c06a3d391e 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -555,7 +555,7 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) */ if ((p->port.type == PORT_XR17V35X) || (p->port.type == PORT_XR17D15X)) { - serial_out(p, UART_EXAR_SLEEP, 0xff); + serial_out(p, UART_EXAR_SLEEP, sleep ? 0xff : 0); return; } @@ -1520,7 +1520,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) status = serial8250_rx_chars(up, status); } serial8250_modem_status(up); - if (status & UART_LSR_THRE) + if (!up->dma && (status & UART_LSR_THRE)) serial8250_tx_chars(up); spin_unlock_irqrestore(&port->lock, flags); @@ -2670,6 +2670,10 @@ static void serial8250_config_port(struct uart_port *port, int flags) if (port->type == PORT_16550A && port->iotype == UPIO_AU) up->bugs |= UART_BUG_NOMSR; + /* HW bugs may trigger IRQ while IIR == NO_INT */ + if (port->type == PORT_TEGRA) + up->bugs |= UART_BUG_NOMSR; + if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) autoconfig_irq(up); diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index 7046769608d4..ab9096dc3849 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -20,12 +20,15 @@ static void __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; - - dma->tx_running = 0; + unsigned long flags; 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; @@ -35,6 +38,8 @@ static void __dma_tx_complete(void *param) if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) serial8250_tx_dma(p); + + spin_unlock_irqrestore(&p->port.lock, flags); } static void __dma_rx_complete(void *param) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index d07b6af3a937..345b5ddcb1a0 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -54,58 +54,100 @@ struct dw8250_data { - int last_lcr; + int last_mcr; int line; struct clk *clk; }; +static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) +{ + struct dw8250_data *d = p->private_data; + + /* If reading MSR, report CTS asserted when auto-CTS/RTS enabled */ + if (offset == UART_MSR && d->last_mcr & UART_MCR_AFE) { + value |= UART_MSR_CTS; + value &= ~UART_MSR_DCTS; + } + + return value; +} + +static void dw8250_force_idle(struct uart_port *p) +{ + serial8250_clear_and_reinit_fifos(container_of + (p, struct uart_8250_port, port)); + (void)p->serial_in(p, UART_RX); +} + static void dw8250_serial_out(struct uart_port *p, int offset, int value) { struct dw8250_data *d = p->private_data; - if (offset == UART_LCR) - d->last_lcr = value; + if (offset == UART_MCR) + d->last_mcr = value; + + writeb(value, p->membase + (offset << p->regshift)); - offset <<= p->regshift; - writeb(value, p->membase + offset); + /* 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); + writeb(value, p->membase + (UART_LCR << p->regshift)); + } + dev_err(p->dev, "Couldn't set LCR to %d\n", value); + } } static unsigned int dw8250_serial_in(struct uart_port *p, int offset) { - offset <<= p->regshift; + unsigned int value = readb(p->membase + (offset << p->regshift)); - return readb(p->membase + offset); + return dw8250_modify_msr(p, offset, value); } static void dw8250_serial_out32(struct uart_port *p, int offset, int value) { struct dw8250_data *d = p->private_data; - if (offset == UART_LCR) - d->last_lcr = value; + if (offset == UART_MCR) + d->last_mcr = value; - offset <<= p->regshift; - writel(value, p->membase + offset); + writel(value, p->membase + (offset << 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); + writel(value, p->membase + (UART_LCR << p->regshift)); + } + dev_err(p->dev, "Couldn't set LCR to %d\n", value); + } } static unsigned int dw8250_serial_in32(struct uart_port *p, int offset) { - offset <<= p->regshift; + unsigned int value = readl(p->membase + (offset << p->regshift)); - return readl(p->membase + offset); + return dw8250_modify_msr(p, offset, value); } static int dw8250_handle_irq(struct uart_port *p) { - struct dw8250_data *d = p->private_data; unsigned int iir = p->serial_in(p, UART_IIR); if (serial8250_handle_irq(p, iir)) { return 1; } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { - /* Clear the USR and write the LCR again. */ + /* Clear the USR */ (void)p->serial_in(p, DW_UART_USR); - p->serial_out(p, UART_LCR, d->last_lcr); return 1; } @@ -369,6 +411,8 @@ MODULE_DEVICE_TABLE(of, dw8250_of_match); static const struct acpi_device_id dw8250_acpi_match[] = { { "INT33C4", 0 }, { "INT33C5", 0 }, + { "INT3434", 0 }, + { "INT3435", 0 }, { "80860F0A", 0 }, { }, }; diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index 721904f8efa9..e83c9db3300c 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -35,18 +35,8 @@ #include <linux/serial_8250.h> #include <asm/io.h> #include <asm/serial.h> -#ifdef CONFIG_FIX_EARLYCON_MEM -#include <asm/pgtable.h> -#include <asm/fixmap.h> -#endif -struct early_serial8250_device { - struct uart_port port; - char options[16]; /* e.g., 115200n8 */ - unsigned int baud; -}; - -static struct early_serial8250_device early_device; +static struct earlycon_device *early_device; unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offset) { @@ -100,7 +90,7 @@ static void __init serial_putc(struct uart_port *port, int c) static void __init early_serial8250_write(struct console *console, const char *s, unsigned int count) { - struct uart_port *port = &early_device.port; + struct uart_port *port = &early_device->port; unsigned int ier; /* Save the IER and disable interrupts */ @@ -129,7 +119,7 @@ static unsigned int __init probe_baud(struct uart_port *port) return (port->uartclk / 16) / quot; } -static void __init init_port(struct early_serial8250_device *device) +static void __init init_port(struct earlycon_device *device) { struct uart_port *port = &device->port; unsigned int divisor; @@ -148,127 +138,32 @@ static void __init init_port(struct early_serial8250_device *device) serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB); } -static int __init parse_options(struct early_serial8250_device *device, - char *options) -{ - struct uart_port *port = &device->port; - int mmio, mmio32, length; - - if (!options) - return -ENODEV; - - port->uartclk = BASE_BAUD * 16; - - mmio = !strncmp(options, "mmio,", 5); - mmio32 = !strncmp(options, "mmio32,", 7); - if (mmio || mmio32) { - port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32); - port->mapbase = simple_strtoul(options + (mmio ? 5 : 7), - &options, 0); - if (mmio32) - port->regshift = 2; -#ifdef CONFIG_FIX_EARLYCON_MEM - set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, - port->mapbase & PAGE_MASK); - port->membase = - (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); - port->membase += port->mapbase & ~PAGE_MASK; -#else - port->membase = ioremap_nocache(port->mapbase, 64); - if (!port->membase) { - printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n", - __func__, - (unsigned long long) port->mapbase); - return -ENOMEM; - } -#endif - } else if (!strncmp(options, "io,", 3)) { - port->iotype = UPIO_PORT; - port->iobase = simple_strtoul(options + 3, &options, 0); - mmio = 0; - } else - return -EINVAL; - - options = strchr(options, ','); - if (options) { - options++; - device->baud = simple_strtoul(options, NULL, 0); - length = min(strcspn(options, " "), sizeof(device->options)); - strlcpy(device->options, options, length); - } else { - device->baud = probe_baud(port); - snprintf(device->options, sizeof(device->options), "%u", - device->baud); - } - - if (mmio || mmio32) - printk(KERN_INFO - "Early serial console at MMIO%s 0x%llx (options '%s')\n", - mmio32 ? "32" : "", - (unsigned long long)port->mapbase, - device->options); - else - printk(KERN_INFO - "Early serial console at I/O port 0x%lx (options '%s')\n", - port->iobase, - device->options); - - return 0; -} - -static struct console early_serial8250_console __initdata = { - .name = "uart", - .write = early_serial8250_write, - .flags = CON_PRINTBUFFER | CON_BOOT, - .index = -1, -}; - -static int __init early_serial8250_setup(char *options) +static int __init early_serial8250_setup(struct earlycon_device *device, + const char *options) { - struct early_serial8250_device *device = &early_device; - int err; - - if (device->port.membase || device->port.iobase) + if (!(device->port.membase || device->port.iobase)) return 0; - err = parse_options(device, options); - if (err < 0) - return err; + if (!device->baud) + device->baud = probe_baud(&device->port); init_port(device); - return 0; -} - -int __init setup_early_serial8250_console(char *cmdline) -{ - char *options; - int err; - - options = strstr(cmdline, "uart8250,"); - if (!options) { - options = strstr(cmdline, "uart,"); - if (!options) - return 0; - } - - options = strchr(cmdline, ',') + 1; - err = early_serial8250_setup(options); - if (err < 0) - return err; - - register_console(&early_serial8250_console); + early_device = device; + device->con->write = early_serial8250_write; return 0; } +EARLYCON_DECLARE(uart8250, early_serial8250_setup); +EARLYCON_DECLARE(uart, early_serial8250_setup); int serial8250_find_port_for_earlycon(void) { - struct early_serial8250_device *device = &early_device; - struct uart_port *port = &device->port; + struct earlycon_device *device = early_device; + struct uart_port *port = device ? &device->port : NULL; int line; int ret; - if (!device->port.membase && !device->port.iobase) + if (!port || (!port->membase && !port->iobase)) return -ENODEV; line = serial8250_find_port(port); @@ -283,5 +178,3 @@ int serial8250_find_port_for_earlycon(void) return ret; } - -early_param("earlycon", setup_early_serial8250_console); diff --git a/drivers/tty/serial/8250/8250_gsc.c b/drivers/tty/serial/8250/8250_gsc.c index bb91b4713ebd..2e3ea1a70d7b 100644 --- a/drivers/tty/serial/8250/8250_gsc.c +++ b/drivers/tty/serial/8250/8250_gsc.c @@ -31,9 +31,8 @@ static int __init serial_init_chip(struct parisc_device *dev) int err; #ifdef CONFIG_64BIT - extern int iosapic_serial_irq(int cellnum); if (!dev->irq && (dev->id.sversion == 0xad)) - dev->irq = iosapic_serial_irq(dev->mod_index-1); + dev->irq = iosapic_serial_irq(dev); #endif if (!dev->irq) { diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 26e3a97ab157..8d3c0b5e2878 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1260,10 +1260,10 @@ static int pci_quatech_init(struct pci_dev *dev) unsigned long base = pci_resource_start(dev, 0); if (base) { u32 tmp; - outl(inl(base + 0x38), base + 0x38); + outl(inl(base + 0x38) | 0x00002000, base + 0x38); tmp = inl(base + 0x3c); outl(tmp | 0x01000000, base + 0x3c); - outl(tmp, base + 0x3c); + outl(tmp &= ~0x01000000, base + 0x3c); } } return 0; @@ -1545,6 +1545,7 @@ pci_wch_ch353_setup(struct serial_private *priv, #define PCI_DEVICE_ID_TITAN_800E 0xA014 #define PCI_DEVICE_ID_TITAN_200EI 0xA016 #define PCI_DEVICE_ID_TITAN_200EISI 0xA017 +#define PCI_DEVICE_ID_TITAN_200V3 0xA306 #define PCI_DEVICE_ID_TITAN_400V3 0xA310 #define PCI_DEVICE_ID_TITAN_410V3 0xA312 #define PCI_DEVICE_ID_TITAN_800V3 0xA314 @@ -4139,6 +4140,9 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_oxsemi_2_4000000 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200V3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_921600 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400V3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_4_921600 }, @@ -4797,10 +4801,6 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_VENDOR_ID_IBM, 0x0299, 0, 0, pbn_b0_bt_2_115200 }, - { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835, - 0x1000, 0x0012, - 0, 0, pbn_b0_bt_2_115200 }, - { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901, 0xA000, 0x1000, 0, 0, pbn_b0_1_115200 }, diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 80fe91e64a52..902c4bf15f0b 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -62,6 +62,7 @@ config SERIAL_8250_CONSOLE bool "Console on 8250/16550 and compatible serial port" depends on SERIAL_8250=y select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON ---help--- If you say Y here, it will be possible to use a serial port as the system console (the system console is the device which receives all |