summaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/8250
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/8250')
-rw-r--r--drivers/tty/serial/8250/8250.h15
-rw-r--r--drivers/tty/serial/8250/8250_core.c3
-rw-r--r--drivers/tty/serial/8250/8250_dma.c68
-rw-r--r--drivers/tty/serial/8250/8250_dw.c8
-rw-r--r--drivers/tty/serial/8250/8250_fintek.c118
-rw-r--r--drivers/tty/serial/8250/8250_mid.c44
-rw-r--r--drivers/tty/serial/8250/8250_of.c2
-rw-r--r--drivers/tty/serial/8250/8250_omap.c93
-rw-r--r--drivers/tty/serial/8250/8250_pci.c15
-rw-r--r--drivers/tty/serial/8250/8250_port.c38
-rw-r--r--drivers/tty/serial/8250/8250_uniphier.c2
-rw-r--r--drivers/tty/serial/8250/Kconfig24
-rw-r--r--drivers/tty/serial/8250/Makefile2
13 files changed, 203 insertions, 229 deletions
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 047a7ba6796a..215a99237e95 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -17,7 +17,7 @@
struct uart_8250_dma {
int (*tx_dma)(struct uart_8250_port *p);
- int (*rx_dma)(struct uart_8250_port *p, unsigned int iir);
+ int (*rx_dma)(struct uart_8250_port *p);
/* Filter function */
dma_filter_fn fn;
@@ -84,7 +84,6 @@ struct serial8250_config {
#define UART_BUG_THRE (1 << 3) /* UART has buggy THRE reassertion */
#define UART_BUG_PARITY (1 << 4) /* UART mishandles parity if FIFO enabled */
-#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
#ifdef CONFIG_SERIAL_8250_SHARE_IRQ
#define SERIAL8250_SHARE_IRQS 1
@@ -151,6 +150,12 @@ static inline int serial8250_pnp_init(void) { return 0; }
static inline void serial8250_pnp_exit(void) { }
#endif
+#ifdef CONFIG_SERIAL_8250_FINTEK
+int fintek_8250_probe(struct uart_8250_port *uart);
+#else
+static inline int fintek_8250_probe(struct uart_8250_port *uart) { return 0; }
+#endif
+
#ifdef CONFIG_ARCH_OMAP1
static inline int is_omap1_8250(struct uart_8250_port *pt)
{
@@ -190,7 +195,8 @@ static inline int is_omap1510_8250(struct uart_8250_port *pt)
#ifdef CONFIG_SERIAL_8250_DMA
extern int serial8250_tx_dma(struct uart_8250_port *);
-extern int serial8250_rx_dma(struct uart_8250_port *, unsigned int iir);
+extern int serial8250_rx_dma(struct uart_8250_port *);
+extern void serial8250_rx_dma_flush(struct uart_8250_port *);
extern int serial8250_request_dma(struct uart_8250_port *);
extern void serial8250_release_dma(struct uart_8250_port *);
#else
@@ -198,10 +204,11 @@ static inline int serial8250_tx_dma(struct uart_8250_port *p)
{
return -1;
}
-static inline int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
+static inline int serial8250_rx_dma(struct uart_8250_port *p)
{
return -1;
}
+static inline void serial8250_rx_dma_flush(struct uart_8250_port *p) { }
static inline int serial8250_request_dma(struct uart_8250_port *p)
{
return -1;
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 2f4f5ee651db..0fbd7c033a25 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -830,6 +830,7 @@ static int serial8250_probe(struct platform_device *dev)
uart.port.handle_irq = p->handle_irq;
uart.port.handle_break = p->handle_break;
uart.port.set_termios = p->set_termios;
+ uart.port.get_mctrl = p->get_mctrl;
uart.port.pm = p->pm;
uart.port.dev = &dev->dev;
uart.port.irqflags |= irqflag;
@@ -1022,6 +1023,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
/* Possibly override set_termios call */
if (up->port.set_termios)
uart->port.set_termios = up->port.set_termios;
+ if (up->port.get_mctrl)
+ uart->port.get_mctrl = up->port.get_mctrl;
if (up->port.set_mctrl)
uart->port.set_mctrl = up->port.set_mctrl;
if (up->port.startup)
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index 78259d3c6a55..7f33d1c8d1a9 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -110,30 +110,11 @@ err:
return ret;
}
-int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
+int serial8250_rx_dma(struct uart_8250_port *p)
{
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 */
- 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_complete(p);
- dmaengine_terminate_all(dma->rxchan);
- }
- return -ETIMEDOUT;
- default:
- break;
- }
-
if (dma->rx_running)
return 0;
@@ -154,10 +135,23 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
return 0;
}
+void serial8250_rx_dma_flush(struct uart_8250_port *p)
+{
+ struct uart_8250_dma *dma = p->dma;
+
+ if (dma->rx_running) {
+ dmaengine_pause(dma->rxchan);
+ __dma_rx_complete(p);
+ dmaengine_terminate_all(dma->rxchan);
+ }
+}
+
int serial8250_request_dma(struct uart_8250_port *p)
{
struct uart_8250_dma *dma = p->dma;
dma_cap_mask_t mask;
+ struct dma_slave_caps caps;
+ int ret;
/* Default slave configuration parameters */
dma->rxconf.direction = DMA_DEV_TO_MEM;
@@ -178,6 +172,16 @@ int serial8250_request_dma(struct uart_8250_port *p)
if (!dma->rxchan)
return -ENODEV;
+ /* 8250 rx dma requires dmaengine driver to support pause/terminate */
+ ret = dma_get_slave_caps(dma->rxchan, &caps);
+ if (ret)
+ goto release_rx;
+ if (!caps.cmd_pause || !caps.cmd_terminate ||
+ caps.residue_granularity == DMA_RESIDUE_GRANULARITY_DESCRIPTOR) {
+ ret = -EINVAL;
+ goto release_rx;
+ }
+
dmaengine_slave_config(dma->rxchan, &dma->rxconf);
/* Get a channel for TX */
@@ -185,8 +189,17 @@ int serial8250_request_dma(struct uart_8250_port *p)
dma->fn, dma->tx_param,
p->port.dev, "tx");
if (!dma->txchan) {
- dma_release_channel(dma->rxchan);
- return -ENODEV;
+ ret = -ENODEV;
+ goto release_rx;
+ }
+
+ /* 8250 tx dma requires dmaengine driver to support terminate */
+ ret = dma_get_slave_caps(dma->txchan, &caps);
+ if (ret)
+ goto err;
+ if (!caps.cmd_terminate) {
+ ret = -EINVAL;
+ goto err;
}
dmaengine_slave_config(dma->txchan, &dma->txconf);
@@ -197,8 +210,10 @@ int serial8250_request_dma(struct uart_8250_port *p)
dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
&dma->rx_addr, GFP_KERNEL);
- if (!dma->rx_buf)
+ if (!dma->rx_buf) {
+ ret = -ENOMEM;
goto err;
+ }
/* TX buffer */
dma->tx_addr = dma_map_single(dma->txchan->device->dev,
@@ -208,6 +223,7 @@ int serial8250_request_dma(struct uart_8250_port *p)
if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) {
dma_free_coherent(dma->rxchan->device->dev, dma->rx_size,
dma->rx_buf, dma->rx_addr);
+ ret = -ENOMEM;
goto err;
}
@@ -215,10 +231,10 @@ int serial8250_request_dma(struct uart_8250_port *p)
return 0;
err:
- dma_release_channel(dma->rxchan);
dma_release_channel(dma->txchan);
-
- return -ENOMEM;
+release_rx:
+ dma_release_channel(dma->rxchan);
+ return ret;
}
EXPORT_SYMBOL_GPL(serial8250_request_dma);
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index a3fb95d85d7c..e19969614203 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -104,15 +104,16 @@ static void dw8250_check_lcr(struct uart_port *p, int value)
dw8250_force_idle(p);
#ifdef CONFIG_64BIT
- __raw_writeq(value & 0xff, offset);
-#else
+ if (p->type == PORT_OCTEON)
+ __raw_writeq(value & 0xff, offset);
+ else
+#endif
if (p->iotype == UPIO_MEM32)
writel(value, offset);
else if (p->iotype == UPIO_MEM32BE)
iowrite32be(value, offset);
else
writeb(value, offset);
-#endif
}
/*
* FIXME: this deadlocks if port->lock is already held
@@ -617,6 +618,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
{ "8086228A", 0 },
{ "APMC0D08", 0},
{ "AMD0020", 0 },
+ { "AMDI0020", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c
index 89474399ab89..870981dd9e39 100644
--- a/drivers/tty/serial/8250/8250_fintek.c
+++ b/drivers/tty/serial/8250/8250_fintek.c
@@ -1,9 +1,7 @@
/*
* Probe for F81216A LPC to 4 UART
*
- * Based on drivers/tty/serial/8250_pnp.c, by Russell King, et al
- *
- * Copyright (C) 2014 Ricardo Ribalda, Qtechnology A/S
+ * Copyright (C) 2014-2016 Ricardo Ribalda, Qtechnology A/S
*
*
* This program is free software; you can redistribute it and/or modify
@@ -38,19 +36,15 @@
#define RXW4C_IRA BIT(3)
#define TXW4C_IRA BIT(2)
-#define DRIVER_NAME "8250_fintek"
-
struct fintek_8250 {
u16 base_port;
u8 index;
u8 key;
- long line;
};
static int fintek_8250_enter_key(u16 base_port, u8 key)
{
-
- if (!request_muxed_region(base_port, 2, DRIVER_NAME))
+ if (!request_muxed_region(base_port, 2, "8250_fintek"))
return -EBUSY;
outb(key, base_port + ADDR_PORT);
@@ -138,7 +132,7 @@ static int fintek_8250_rs485_config(struct uart_port *port,
return 0;
}
-static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index)
+static int find_base_port(struct fintek_8250 *pdata, u16 io_address)
{
static const u16 addr[] = {0x4e, 0x2e};
static const u8 keys[] = {0x77, 0xa0, 0x87, 0x67};
@@ -168,10 +162,13 @@ static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index)
continue;
fintek_8250_exit_key(addr[i]);
- *key = keys[j];
- *index = k;
- return addr[i];
+ pdata->key = keys[j];
+ pdata->base_port = addr[i];
+ pdata->index = k;
+
+ return 0;
}
+
fintek_8250_exit_key(addr[i]);
}
}
@@ -179,104 +176,21 @@ static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index)
return -ENODEV;
}
-static int
-fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
+int fintek_8250_probe(struct uart_8250_port *uart)
{
- struct uart_8250_port uart;
struct fintek_8250 *pdata;
- int base_port;
- u8 key;
- u8 index;
-
- if (!pnp_port_valid(dev, 0))
- return -ENODEV;
+ struct fintek_8250 probe_data;
- base_port = fintek_8250_base_port(pnp_port_start(dev, 0), &key, &index);
- if (base_port < 0)
+ if (find_base_port(&probe_data, uart->port.iobase))
return -ENODEV;
- memset(&uart, 0, sizeof(uart));
-
- pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL);
+ pdata = devm_kzalloc(uart->port.dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
- uart.port.private_data = pdata;
- if (!pnp_irq_valid(dev, 0))
- return -ENODEV;
- uart.port.irq = pnp_irq(dev, 0);
- uart.port.iobase = pnp_port_start(dev, 0);
- uart.port.iotype = UPIO_PORT;
- 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)
- uart.port.flags |= UPF_SHARE_IRQ;
- uart.port.uartclk = 1843200;
- uart.port.dev = &dev->dev;
-
- pdata->key = key;
- pdata->base_port = base_port;
- pdata->index = index;
- pdata->line = serial8250_register_8250_port(&uart);
- if (pdata->line < 0)
- return -ENODEV;
+ memcpy(pdata, &probe_data, sizeof(probe_data));
+ uart->port.rs485_config = fintek_8250_rs485_config;
+ uart->port.private_data = pdata;
- pnp_set_drvdata(dev, pdata);
return 0;
}
-
-static void fintek_8250_remove(struct pnp_dev *dev)
-{
- struct fintek_8250 *pdata = pnp_get_drvdata(dev);
-
- if (pdata)
- serial8250_unregister_port(pdata->line);
-}
-
-#ifdef CONFIG_PM
-static int fintek_8250_suspend(struct pnp_dev *dev, pm_message_t state)
-{
- struct fintek_8250 *pdata = pnp_get_drvdata(dev);
-
- if (!pdata)
- return -ENODEV;
- serial8250_suspend_port(pdata->line);
- return 0;
-}
-
-static int fintek_8250_resume(struct pnp_dev *dev)
-{
- struct fintek_8250 *pdata = pnp_get_drvdata(dev);
-
- if (!pdata)
- return -ENODEV;
- serial8250_resume_port(pdata->line);
- return 0;
-}
-#else
-#define fintek_8250_suspend NULL
-#define fintek_8250_resume NULL
-#endif /* CONFIG_PM */
-
-static const struct pnp_device_id fintek_dev_table[] = {
- /* Qtechnology Panel PC / IO1000 */
- { "PNP0501"},
- {}
-};
-
-MODULE_DEVICE_TABLE(pnp, fintek_dev_table);
-
-static struct pnp_driver fintek_8250_driver = {
- .name = DRIVER_NAME,
- .probe = fintek_8250_probe,
- .remove = fintek_8250_remove,
- .suspend = fintek_8250_suspend,
- .resume = fintek_8250_resume,
- .id_table = fintek_dev_table,
-};
-
-module_pnp_driver(fintek_8250_driver);
-MODULE_DESCRIPTION("Fintek F812164 module");
-MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c
index 88531a36b69c..86379a79a6a3 100644
--- a/drivers/tty/serial/8250/8250_mid.c
+++ b/drivers/tty/serial/8250/8250_mid.c
@@ -9,11 +9,13 @@
* published by the Free Software Foundation.
*/
-#include <linux/rational.h>
+#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/rational.h>
#include <linux/dma/hsu.h>
+#include <linux/8250_pci.h>
#include "8250.h"
@@ -24,6 +26,7 @@
#define PCI_DEVICE_ID_INTEL_DNV_UART 0x19d8
/* Intel MID Specific registers */
+#define INTEL_MID_UART_DNV_FISR 0x08
#define INTEL_MID_UART_PS 0x30
#define INTEL_MID_UART_MUL 0x34
#define INTEL_MID_UART_DIV 0x38
@@ -31,6 +34,7 @@
struct mid8250;
struct mid8250_board {
+ unsigned int flags;
unsigned long freq;
unsigned int base_baud;
int (*setup)(struct mid8250 *, struct uart_port *p);
@@ -76,7 +80,11 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p)
struct pci_dev *pdev = to_pci_dev(p->dev);
int index = PCI_FUNC(pdev->devfn);
- /* Currently no support for HSU port0 */
+ /*
+ * Device 0000:00:04.0 is not a real HSU port. It provides a global
+ * register set for all HSU ports, although it has the same PCI ID.
+ * Skip it here.
+ */
if (index-- == 0)
return -ENODEV;
@@ -88,16 +96,16 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p)
static int dnv_handle_irq(struct uart_port *p)
{
struct mid8250 *mid = p->private_data;
- int ret;
-
- ret = hsu_dma_irq(&mid->dma_chip, 0);
- ret |= hsu_dma_irq(&mid->dma_chip, 1);
-
- /* For now, letting the HW generate separate interrupt for the UART */
- if (ret)
- return ret;
-
- return serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
+ unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR);
+ int ret = IRQ_NONE;
+
+ if (fisr & BIT(2))
+ ret |= hsu_dma_irq(&mid->dma_chip, 1);
+ if (fisr & BIT(1))
+ ret |= hsu_dma_irq(&mid->dma_chip, 0);
+ if (fisr & BIT(0))
+ ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
+ return ret;
}
#define DNV_DMA_CHAN_OFFSET 0x80
@@ -106,12 +114,13 @@ static int dnv_setup(struct mid8250 *mid, struct uart_port *p)
{
struct hsu_dma_chip *chip = &mid->dma_chip;
struct pci_dev *pdev = to_pci_dev(p->dev);
+ unsigned int bar = FL_GET_BASE(mid->board->flags);
int ret;
chip->dev = &pdev->dev;
chip->irq = pdev->irq;
chip->regs = p->membase;
- chip->length = pci_resource_len(pdev, 0);
+ chip->length = pci_resource_len(pdev, bar);
chip->offset = DNV_DMA_CHAN_OFFSET;
/* Falling back to PIO mode if DMA probing fails */
@@ -217,6 +226,7 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct uart_8250_port uart;
struct mid8250 *mid;
+ unsigned int bar;
int ret;
ret = pcim_enable_device(pdev);
@@ -230,6 +240,7 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return -ENOMEM;
mid->board = (struct mid8250_board *)id->driver_data;
+ bar = FL_GET_BASE(mid->board->flags);
memset(&uart, 0, sizeof(struct uart_8250_port));
@@ -242,8 +253,8 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE;
uart.port.set_termios = mid8250_set_termios;
- uart.port.mapbase = pci_resource_start(pdev, 0);
- uart.port.membase = pcim_iomap(pdev, 0, 0);
+ uart.port.mapbase = pci_resource_start(pdev, bar);
+ uart.port.membase = pcim_iomap(pdev, bar, 0);
if (!uart.port.membase)
return -ENOMEM;
@@ -282,18 +293,21 @@ static void mid8250_remove(struct pci_dev *pdev)
}
static const struct mid8250_board pnw_board = {
+ .flags = FL_BASE0,
.freq = 50000000,
.base_baud = 115200,
.setup = pnw_setup,
};
static const struct mid8250_board tng_board = {
+ .flags = FL_BASE0,
.freq = 38400000,
.base_baud = 1843200,
.setup = tng_setup,
};
static const struct mid8250_board dnv_board = {
+ .flags = FL_BASE1,
.freq = 133333333,
.base_baud = 115200,
.setup = dnv_setup,
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index c7ed3d2bc8b2..38963d7bcf84 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -29,7 +29,7 @@ struct of_serial_info {
};
#ifdef CONFIG_ARCH_TEGRA
-void tegra_serial_handle_break(struct uart_port *p)
+static void tegra_serial_handle_break(struct uart_port *p)
{
unsigned int status, tmout = 10000;
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 6f760510e46d..2c44c792d586 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -115,6 +115,12 @@ struct omap8250_priv {
bool rx_dma_broken;
};
+#ifdef CONFIG_SERIAL_8250_DMA
+static void omap_8250_rx_dma_flush(struct uart_8250_port *p);
+#else
+static inline void omap_8250_rx_dma_flush(struct uart_8250_port *p) { }
+#endif
+
static u32 uart_read(struct uart_8250_port *up, u32 reg)
{
return readl(up->port.membase + (reg << up->port.regshift));
@@ -635,7 +641,7 @@ static int omap_8250_startup(struct uart_port *port)
serial_out(up, UART_OMAP_WER, priv->wer);
if (up->dma)
- up->dma->rx_dma(up, 0);
+ up->dma->rx_dma(up);
pm_runtime_mark_last_busy(port->dev);
pm_runtime_put_autosuspend(port->dev);
@@ -654,7 +660,7 @@ static void omap_8250_shutdown(struct uart_port *port)
flush_work(&priv->qos_work);
if (up->dma)
- up->dma->rx_dma(up, UART_IIR_RX_TIMEOUT);
+ omap_8250_rx_dma_flush(up);
pm_runtime_get_sync(port->dev);
@@ -742,9 +748,9 @@ static void omap_8250_unthrottle(struct uart_port *port)
}
#ifdef CONFIG_SERIAL_8250_DMA
-static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir);
+static int omap_8250_rx_dma(struct uart_8250_port *p);
-static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
+static void __dma_rx_do_complete(struct uart_8250_port *p)
{
struct omap8250_priv *priv = p->port.private_data;
struct uart_8250_dma *dma = p->dma;
@@ -754,9 +760,6 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
unsigned long flags;
int ret;
- dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
- dma->rx_size, DMA_FROM_DEVICE);
-
spin_lock_irqsave(&priv->rx_dma_lock, flags);
if (!dma->rx_running)
@@ -764,7 +767,6 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
dma->rx_running = 0;
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
- dmaengine_terminate_all(dma->rxchan);
count = dma->rx_size - state.residue;
@@ -775,15 +777,13 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
unlock:
spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
- 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);
+ __dma_rx_do_complete(param);
+ omap_8250_rx_dma(param);
}
static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
@@ -806,10 +806,11 @@ static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
- __dma_rx_do_complete(p, true);
+ __dma_rx_do_complete(p);
+ dmaengine_terminate_all(dma->rxchan);
}
-static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
+static int omap_8250_rx_dma(struct uart_8250_port *p)
{
struct omap8250_priv *priv = p->port.private_data;
struct uart_8250_dma *dma = p->dma;
@@ -817,35 +818,6 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
struct dma_async_tx_descriptor *desc;
unsigned long flags;
- switch (iir & 0x3f) {
- case UART_IIR_RLSI:
- /* 8250_core handles errors and break interrupts */
- omap_8250_rx_dma_flush(p);
- 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.
- */
- omap_8250_rx_dma_flush(p);
- 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.
- */
- omap_8250_rx_dma_flush(p);
- return -ETIMEDOUT;
-
- default:
- break;
- }
-
if (priv->rx_dma_broken)
return -EINVAL;
@@ -868,9 +840,6 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
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);
out:
spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
@@ -1022,6 +991,18 @@ err:
return ret;
}
+static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
+{
+ switch (iir & 0x3f) {
+ case UART_IIR_RLSI:
+ case UART_IIR_RX_TIMEOUT:
+ case UART_IIR_RDI:
+ omap_8250_rx_dma_flush(up);
+ return true;
+ }
+ return omap_8250_rx_dma(up);
+}
+
/*
* 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
@@ -1033,7 +1014,6 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
unsigned char status;
unsigned long flags;
u8 iir;
- int dma_err = 0;
serial8250_rpm_get(up);
@@ -1048,11 +1028,9 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
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) {
+ if (handle_rx_dma(up, iir)) {
status = serial8250_rx_chars(up, status);
- omap_8250_rx_dma(up, 0);
+ omap_8250_rx_dma(up);
}
}
serial8250_modem_status(up);
@@ -1066,8 +1044,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
* try again due to an earlier failer which
* might have been resolved by now.
*/
- dma_err = omap_8250_tx_dma(up);
- if (dma_err)
+ if (omap_8250_tx_dma(up))
serial8250_tx_chars(up);
}
}
@@ -1084,7 +1061,7 @@ static bool the_no_dma_filter_fn(struct dma_chan *chan, void *param)
#else
-static inline int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
+static inline int omap_8250_rx_dma(struct uart_8250_port *p)
{
return -EINVAL;
}
@@ -1395,7 +1372,7 @@ static int omap8250_runtime_suspend(struct device *dev)
}
if (up->dma && up->dma->rxchan)
- omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT);
+ omap_8250_rx_dma_flush(up);
priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
schedule_work(&priv->qos_work);
@@ -1407,20 +1384,18 @@ 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);
- loss_cntx = omap8250_lost_context(up);
- if (loss_cntx)
+ if (omap8250_lost_context(up))
omap8250_restore_regs(up);
if (up->dma && up->dma->rxchan)
- omap_8250_rx_dma(up, 0);
+ omap_8250_rx_dma(up);
priv->latency = priv->calc_latency;
schedule_work(&priv->qos_work);
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 98862aa5bb58..0cf512377189 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1377,6 +1377,9 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios,
unsigned long m, n;
u32 reg;
+ /* Gracefully handle the B0 case: fall back to B9600 */
+ fuart = fuart ? fuart : 9600 * 16;
+
/* Get Fuart closer to Fref */
fuart *= rounddown_pow_of_two(fref / fuart);
@@ -1413,6 +1416,17 @@ static bool byt_dma_filter(struct dma_chan *chan, void *param)
return true;
}
+static unsigned int
+byt_get_mctrl(struct uart_port *port)
+{
+ unsigned int ret = serial8250_do_get_mctrl(port);
+
+ /* Force DCD and DSR signals to permanently be reported as active. */
+ ret |= TIOCM_CAR | TIOCM_DSR;
+
+ return ret;
+}
+
static int
byt_serial_setup(struct serial_private *priv,
const struct pciserial_board *board,
@@ -1477,6 +1491,7 @@ byt_serial_setup(struct serial_private *priv,
port->port.type = PORT_16550A;
port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
port->port.set_termios = byt_set_termios;
+ port->port.get_mctrl = byt_get_mctrl;
port->port.fifosize = 64;
port->tx_loadsz = 64;
port->dma = dma;
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 00ad2637b08c..d4036038a4dd 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -1315,6 +1315,13 @@ static void autoconfig(struct uart_8250_port *up)
out_lock:
spin_unlock_irqrestore(&port->lock, flags);
+
+ /*
+ * Check if the device is a Fintek F81216A
+ */
+ if (port->type == PORT_16550A)
+ fintek_8250_probe(up);
+
if (up->capabilities != old_capabilities) {
pr_warn("ttyS%d: detected caps %08x should be %08x\n",
serial_index(port), old_capabilities,
@@ -1788,6 +1795,18 @@ unsigned int serial8250_modem_status(struct uart_8250_port *up)
}
EXPORT_SYMBOL_GPL(serial8250_modem_status);
+static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
+{
+ switch (iir & 0x3f) {
+ case UART_IIR_RX_TIMEOUT:
+ serial8250_rx_dma_flush(up);
+ /* fall-through */
+ case UART_IIR_RLSI:
+ return true;
+ }
+ return up->dma->rx_dma(up);
+}
+
/*
* This handles the interrupt from one port.
*/
@@ -1796,7 +1815,6 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
unsigned char status;
unsigned long flags;
struct uart_8250_port *up = up_to_u8250p(port);
- int dma_err = 0;
if (iir & UART_IIR_NO_INT)
return 0;
@@ -1808,15 +1826,11 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
DEBUG_INTR("status = %x...", status);
if (status & (UART_LSR_DR | UART_LSR_BI)) {
- if (up->dma)
- dma_err = up->dma->rx_dma(up, iir);
-
- if (!up->dma || dma_err)
+ if (!up->dma || handle_rx_dma(up, iir))
status = serial8250_rx_chars(up, status);
}
serial8250_modem_status(up);
- if ((!up->dma || (up->dma && up->dma->tx_err)) &&
- (status & UART_LSR_THRE))
+ if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE))
serial8250_tx_chars(up);
spin_unlock_irqrestore(&port->lock, flags);
@@ -1882,7 +1896,7 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0;
}
-static unsigned int serial8250_get_mctrl(struct uart_port *port)
+unsigned int serial8250_do_get_mctrl(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned int status;
@@ -1903,6 +1917,14 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port)
ret |= TIOCM_CTS;
return ret;
}
+EXPORT_SYMBOL_GPL(serial8250_do_get_mctrl);
+
+static unsigned int serial8250_get_mctrl(struct uart_port *port)
+{
+ if (port->get_mctrl)
+ return port->get_mctrl(port);
+ return serial8250_do_get_mctrl(port);
+}
void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c
index 1b7bd26555b7..efd1f9c047b1 100644
--- a/drivers/tty/serial/8250/8250_uniphier.c
+++ b/drivers/tty/serial/8250/8250_uniphier.c
@@ -209,7 +209,7 @@ static int uniphier_uart_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
- dev_err(dev, "failed to get IRQ number");
+ dev_err(dev, "failed to get IRQ number\n");
return irq;
}
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 4d7cb9c04fce..e46761d20f7b 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -57,6 +57,18 @@ config SERIAL_8250_PNP
This builds standard PNP serial support. You may be able to
disable this feature if you only need legacy serial support.
+config SERIAL_8250_FINTEK
+ bool "Support for Fintek F81216A LPC to 4 UART RS485 API"
+ depends on SERIAL_8250
+ ---help---
+ Selecting this option will add support for the RS485 capabilities
+ of the Fintek F81216A LPC to 4 UART.
+
+ If this option is not selected the device will be configured as a
+ standard 16550A serial port.
+
+ If unsure, say N.
+
config SERIAL_8250_CONSOLE
bool "Console on 8250/16550 and compatible serial port"
depends on SERIAL_8250=y
@@ -358,14 +370,6 @@ config SERIAL_8250_OMAP_TTYO_FIXUP
not booting kernel because the serial console remains silent in case
they forgot to update the command line.
-config SERIAL_8250_FINTEK
- tristate "Support for Fintek F81216A LPC to 4 UART"
- depends on SERIAL_8250 && PNP
- help
- Selecting this option will add support for the Fintek F81216A
- LPC to 4 UART. This device has some RS485 functionality not available
- through the PNP driver. If unsure, say N.
-
config SERIAL_8250_LPC18XX
tristate "NXP LPC18xx/43xx serial port support"
depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST)
@@ -398,8 +402,10 @@ config SERIAL_8250_INGENIC
its UARTs, say Y to this option. If unsure, say N.
config SERIAL_8250_MID
- tristate "Support for serial ports on Intel MID platforms"
+ tristate "Support for serial ports on Intel MID platforms" if EXPERT
+ default SERIAL_8250
depends on SERIAL_8250 && PCI
+ depends on X86 || COMPILE_TEST
select HSU_DMA if SERIAL_8250_DMA
select HSU_DMA_PCI if (HSU_DMA && X86_INTEL_MID)
select RATIONAL
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index c9a2d6ed87e9..367d403d28d5 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o
8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
8250_base-y := 8250_port.o
8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o
+8250_base-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o
obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
@@ -23,7 +24,6 @@ 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_LPC18XX) += 8250_lpc18xx.o
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o
OpenPOWER on IntegriCloud