[linux-yocto] [PATCH 1/2] valleyisland-io: add baytrail io patch for HSUART controller support
rebecca.swee.fun.chang at intel.com
rebecca.swee.fun.chang at intel.com
Wed Dec 11 01:41:51 PST 2013
From: "Chang, Rebecca Swee Fun" <rebecca.swee.fun.chang at intel.com>
Baytrail has two HSUART controllers which can be PCI or ACPI enumerated.
Signed-off-by: Chang, Rebecca Swee Fun <rebecca.swee.fun.chang at intel.com>
---
...-Add-support-for-HSUART-controllers-on-In.patch | 1295 ++++++++++++++++++++
1 file changed, 1295 insertions(+)
create mode 100644 meta/cfg/kernel-cache/features/valleyisland-io/0003-serial-8250-Add-support-for-HSUART-controllers-on-In.patch
diff --git a/meta/cfg/kernel-cache/features/valleyisland-io/0003-serial-8250-Add-support-for-HSUART-controllers-on-In.patch b/meta/cfg/kernel-cache/features/valleyisland-io/0003-serial-8250-Add-support-for-HSUART-controllers-on-In.patch
new file mode 100644
index 0000000..6f9b8e8
--- /dev/null
+++ b/meta/cfg/kernel-cache/features/valleyisland-io/0003-serial-8250-Add-support-for-HSUART-controllers-on-In.patch
@@ -0,0 +1,1295 @@
+serial/8250: Add support for HSUART controllers on Baytrail
+
+Baytrail has two HSUART controllers which can be PCI or ACPI enumerated.
+
+Signed-off-by: Chang, Rebecca Swee Fun <rebecca.swee.fun.chang at intel.com>
+---
+ drivers/tty/serial/8250/8250.c | 72 +++++--
+ drivers/tty/serial/8250/8250.h | 55 +++++
+ drivers/tty/serial/8250/8250_dma.c | 222 ++++++++++++++++++++
+ drivers/tty/serial/8250/8250_dw.c | 378 +++++++++++++++++++++++++++++-----
+ drivers/tty/serial/8250/8250_early.c | 2 +-
+ drivers/tty/serial/8250/8250_pci.c | 190 +++++++++++++++++
+ drivers/tty/serial/8250/Kconfig | 10 +-
+ drivers/tty/serial/8250/Makefile | 1 +
+ include/linux/serial_8250.h | 4 +
+ 9 files changed, 873 insertions(+), 61 deletions(-)
+ create mode 100644 drivers/tty/serial/8250/8250_dma.c
+
+diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
+index f932043..469a83c 100644
+--- a/drivers/tty/serial/8250/8250.c
++++ b/drivers/tty/serial/8250/8250.c
+@@ -1341,7 +1341,9 @@ static void serial8250_start_tx(struct uart_port *port)
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
+
+- if (!(up->ier & UART_IER_THRI)) {
++ if (up->dma && !serial8250_tx_dma(up)) {
++ return;
++ } else if (!(up->ier & UART_IER_THRI)) {
+ up->ier |= UART_IER_THRI;
+ serial_port_out(port, UART_IER, up->ier);
+
+@@ -1397,7 +1399,6 @@ unsigned char
+ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
+ {
+ struct uart_port *port = &up->port;
+- struct tty_struct *tty = port->state->port.tty;
+ unsigned char ch;
+ int max_count = 256;
+ char flag;
+@@ -1462,7 +1463,7 @@ ignore_char:
+ lsr = serial_in(up, UART_LSR);
+ } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
+ spin_unlock(&port->lock);
+- tty_flip_buffer_push(tty);
++ tty_flip_buffer_push(&port->state->port);
+ spin_lock(&port->lock);
+ return lsr;
+ }
+@@ -1518,6 +1519,10 @@ unsigned int serial8250_modem_status(struct uart_8250_port *up)
+ struct uart_port *port = &up->port;
+ unsigned int status = serial_in(up, UART_MSR);
+
++ if (up->ier & UART_IER_MSI && up->mcr & UART_MCR_AFE) {
++ status &= ~(UART_MSR_DCTS);
++ status |= UART_MSR_CTS;
++ }
+ status |= up->msr_saved_flags;
+ up->msr_saved_flags = 0;
+ if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
+@@ -1547,20 +1552,34 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
+ unsigned long flags;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
++ int dma_err = 0;
+
+ if (iir & UART_IIR_NO_INT)
+ return 0;
+
+ spin_lock_irqsave(&port->lock, flags);
+
++ if( (up->port.dev->id == PCI_DEVICE_ID_INTEL_BYT_UART1 ||
++ up->port.dev->id == PCI_DEVICE_ID_INTEL_BYT_UART2) &&
++ (iir & UART_IIR_RLSI) ) {
++
++ readl(port->membase + LPSS_UART_BYTE_CNT);
++ readl(port->membase + LPSS_UART_OVRFLW_INTR_STAT);
++ }
++
+ status = serial_port_in(port, UART_LSR);
+
+ DEBUG_INTR("status = %x...", status);
+
+- if (status & (UART_LSR_DR | UART_LSR_BI))
+- status = serial8250_rx_chars(up, status);
++ if (status & (UART_LSR_DR | UART_LSR_BI)) {
++ if (up->dma)
++ dma_err = serial8250_rx_dma(up, iir);
++
++ if (!up->dma || dma_err)
++ status = serial8250_rx_chars(up, status);
++ }
+ serial8250_modem_status(up);
+- if (status & UART_LSR_THRE)
++ if (status & UART_LSR_THRE && (iir & 0x3f) == UART_IIR_THRI)
+ serial8250_tx_chars(up);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+@@ -1991,9 +2010,12 @@ static int serial8250_startup(struct uart_port *port)
+ if (port->type == PORT_8250_CIR)
+ return -ENODEV;
+
+- port->fifosize = uart_config[up->port.type].fifo_size;
+- up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
+- up->capabilities = uart_config[up->port.type].flags;
++ if (!port->fifosize)
++ port->fifosize = uart_config[port->type].fifo_size;
++ if (!up->tx_loadsz)
++ up->tx_loadsz = uart_config[port->type].tx_loadsz;
++ if (!up->capabilities)
++ up->capabilities = uart_config[port->type].flags;
+ up->mcr = 0;
+
+ if (port->iotype != up->cur_iotype)
+@@ -2198,6 +2220,18 @@ dont_test_tx_en:
+ up->msr_saved_flags = 0;
+
+ /*
++ * Request DMA channels for both RX and TX.
++ */
++ if (up->dma) {
++ retval = serial8250_request_dma(up);
++ if (retval) {
++ pr_warn_ratelimited("ttyS%d - failed to request DMA\n",
++ serial_index(port));
++ up->dma = NULL;
++ }
++ }
++
++ /*
+ * Finally, enable interrupts. Note: Modem status interrupts
+ * are set via set_termios(), which will be occurring imminently
+ * anyway, so we don't enable them here.
+@@ -2230,6 +2264,9 @@ static void serial8250_shutdown(struct uart_port *port)
+ up->ier = 0;
+ serial_port_out(port, UART_IER, 0);
+
++ if (up->dma)
++ serial8250_release_dma(up);
++
+ spin_lock_irqsave(&port->lock, flags);
+ if (port->flags & UPF_FOURPORT) {
+ /* reset interrupts on the AST Fourport board */
+@@ -2344,7 +2381,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
+
+ if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
+ fcr = uart_config[port->type].fcr;
+- if (baud < 2400 || fifo_bug) {
++ if (baud < 2400 && !up->dma || fifo_bug) {
+ fcr &= ~UART_FCR_TRIGGER_MASK;
+ fcr |= UART_FCR_TRIGGER_1;
+ }
+@@ -2826,9 +2863,12 @@ static void
+ serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type)
+ {
+ up->port.type = type;
+- up->port.fifosize = uart_config[type].fifo_size;
+- up->capabilities = uart_config[type].flags;
+- up->tx_loadsz = uart_config[type].tx_loadsz;
++ if (!up->port.fifosize)
++ up->port.fifosize = uart_config[type].fifo_size;
++ if (!up->tx_loadsz)
++ up->tx_loadsz = uart_config[type].tx_loadsz;
++ if (!up->capabilities)
++ up->capabilities = uart_config[type].flags;
+ }
+
+ static void __init
+@@ -3262,6 +3302,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
+ uart->bugs = up->bugs;
+ uart->port.mapbase = up->port.mapbase;
+ uart->port.private_data = up->port.private_data;
++ uart->port.fifosize = up->port.fifosize;
++ uart->tx_loadsz = up->tx_loadsz;
++ uart->capabilities = up->capabilities;
++
+ if (up->port.dev)
+ uart->port.dev = up->port.dev;
+
+@@ -3287,6 +3331,8 @@ 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)
++ uart->dma = up->dma;
+
+ if (serial8250_isa_config != NULL)
+ serial8250_isa_config(0, &uart->port,
+diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
+index 12caa12..aa97212 100644
+--- a/drivers/tty/serial/8250/8250.h
++++ b/drivers/tty/serial/8250/8250.h
+@@ -12,6 +12,35 @@
+ */
+
+ #include <linux/serial_8250.h>
++#include <linux/dmaengine.h>
++
++struct uart_8250_dma {
++ dma_filter_fn fn;
++ void *rx_param;
++ void *tx_param;
++
++ int rx_chan_id;
++ int tx_chan_id;
++
++ struct dma_slave_config rxconf;
++ struct dma_slave_config txconf;
++
++ struct dma_chan *rxchan;
++ struct dma_chan *txchan;
++
++ dma_addr_t rx_addr;
++ dma_addr_t tx_addr;
++
++ dma_cookie_t rx_cookie;
++ dma_cookie_t tx_cookie;
++
++ void *rx_buf;
++
++ size_t rx_size;
++ size_t tx_size;
++
++ unsigned char tx_running:1;
++};
+
+ struct old_serial_port {
+ unsigned int uart;
+@@ -59,6 +88,11 @@ struct serial8250_config {
+ #define SERIAL8250_SHARE_IRQS 0
+ #endif
+
++#define PCI_DEVICE_ID_INTEL_BYT_UART1 0x0f0a
++#define PCI_DEVICE_ID_INTEL_BYT_UART2 0x0f0c
++#define LPSS_UART_BYTE_CNT 0x818
++#define LPSS_UART_OVRFLW_INTR_STAT 0x820
++
+ static inline int serial_in(struct uart_8250_port *up, int offset)
+ {
+ return up->port.serial_in(&up->port, offset);
+@@ -143,3 +177,24 @@ static inline int is_omap1510_8250(struct uart_8250_port *pt)
+ return 0;
+ }
+ #endif
++
++#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_request_dma(struct uart_8250_port *);
++extern void serial8250_release_dma(struct uart_8250_port *);
++#else
++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)
++{
++ return -1;
++}
++static inline int serial8250_request_dma(struct uart_8250_port *p)
++{
++ return -1;
++}
++static inline void serial8250_release_dma(struct uart_8250_port *p) { }
++#endif
+diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
+new file mode 100644
+index 0000000..29d45e7
+--- /dev/null
++++ b/drivers/tty/serial/8250/8250_dma.c
+@@ -0,0 +1,222 @@
++/*
++ * 8250_dma.c - DMA Engine API support for 8250.c
++ *
++ * Copyright (C) 2013 Intel Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/serial_reg.h>
++#include <linux/dma-mapping.h>
++
++#include "8250.h"
++
++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;
++
++ dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
++ UART_XMIT_SIZE, DMA_TO_DEVICE);
++
++ xmit->tail += dma->tx_size;
++ xmit->tail &= UART_XMIT_SIZE - 1;
++ p->port.icount.tx += dma->tx_size;
++
++ 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);
++}
++
++static void __dma_rx_complete(void *param)
++{
++ struct uart_8250_port *p = param;
++ 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);
++
++ 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;
++
++ tty_flip_buffer_push(tty_port);
++}
++
++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;
++
++ if (uart_tx_stopped(&p->port) || dma->tx_running
++ || uart_circ_empty(xmit))
++ return 0;
++
++ dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
++
++ desc = dmaengine_prep_slave_single(dma->txchan,
++ dma->tx_addr + xmit->tail,
++ dma->tx_size, DMA_MEM_TO_DEV,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ if (!desc)
++ return -EBUSY;
++
++ dma->tx_running = 1;
++
++ desc->callback = __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);
++
++ return 0;
++}
++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:
++ /* 8250.c 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.c copy the remaining data.
++ */
++ if (dma_status == DMA_IN_PROGRESS) {
++ dmaengine_pause(dma->rxchan);
++ __dma_rx_complete(p);
++ }
++ return -ETIMEDOUT;
++ default:
++ break;
++ }
++
++ if (dma_status)
++ 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;
++
++ 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;
++}
++EXPORT_SYMBOL_GPL(serial8250_rx_dma);
++
++int serial8250_request_dma(struct uart_8250_port *p)
++{
++ struct uart_8250_dma *dma = p->dma;
++ dma_cap_mask_t mask;
++
++ dma->rxconf.src_addr = p->port.mapbase + UART_RX;
++ dma->txconf.dst_addr = p->port.mapbase + UART_TX;
++
++ dma_cap_zero(mask);
++ dma_cap_set(DMA_SLAVE, mask);
++
++ /* Get a channel for RX */
++ dma->rxchan = dma_request_channel(mask, dma->fn, dma->rx_param);
++ if (!dma->rxchan)
++ return -ENODEV;
++
++ dmaengine_slave_config(dma->rxchan, &dma->rxconf);
++
++ /* Get a channel for TX */
++ dma->txchan = dma_request_channel(mask, dma->fn, dma->tx_param);
++ if (!dma->txchan) {
++ dma_release_channel(dma->rxchan);
++ return -ENODEV;
++ }
++
++ dmaengine_slave_config(dma->txchan, &dma->txconf);
++
++ /* RX buffer */
++ if (!dma->rx_size)
++ dma->rx_size = PAGE_SIZE;
++
++ dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
++ &dma->rx_addr, GFP_KERNEL);
++ if (!dma->rx_buf) {
++ dma_release_channel(dma->rxchan);
++ dma_release_channel(dma->txchan);
++ return -ENOMEM;
++ }
++
++ /* TX buffer */
++ dma->tx_addr = dma_map_single(dma->txchan->device->dev,
++ p->port.state->xmit.buf,
++ UART_XMIT_SIZE,
++ DMA_TO_DEVICE);
++
++ dev_dbg_ratelimited(p->port.dev, "got both dma channels\n");
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(serial8250_request_dma);
++
++void serial8250_release_dma(struct uart_8250_port *p)
++{
++ struct uart_8250_dma *dma = p->dma;
++
++ if (!dma)
++ return;
++
++ /* Release RX resources */
++ dmaengine_terminate_all(dma->rxchan);
++ dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf,
++ dma->rx_addr);
++ dma_release_channel(dma->rxchan);
++ dma->rxchan = NULL;
++
++ /* Release TX resources */
++ dmaengine_terminate_all(dma->txchan);
++ dma_unmap_single(dma->txchan->device->dev, dma->tx_addr,
++ UART_XMIT_SIZE, DMA_TO_DEVICE);
++ dma_release_channel(dma->txchan);
++ dma->txchan = NULL;
++ dma->tx_running = 0;
++
++ dev_dbg_ratelimited(p->port.dev, "dma channels released\n");
++}
++EXPORT_SYMBOL_GPL(serial8250_release_dma);
+diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
+index 096d2ef..1d8ed86 100644
+--- a/drivers/tty/serial/8250/8250_dw.c
++++ b/drivers/tty/serial/8250/8250_dw.c
+@@ -2,6 +2,7 @@
+ * Synopsys DesignWare 8250 driver.
+ *
+ * Copyright 2011 Picochip, Jamie Iles.
++ * Copyright 2013 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+@@ -24,10 +25,42 @@
+ #include <linux/of_platform.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
++#include <linux/acpi.h>
++#include <linux/pm_runtime.h>
++#include <linux/clk.h>
++
++#include "8250.h"
++
++static bool use_dma = 1;
++module_param(use_dma, bool, 0);
++MODULE_PARM_DESC(use_dma, "use_dma=1 (enable DMA)/use_dma=0(disable DMA)");
++
++/* Offsets for the DesignWare specific registers */
++#define DW_UART_USR 0x1f /* UART Status Register */
++#define DW_UART_CPR 0xf4 /* Component Parameter Register */
++#define DW_UART_UCV 0xf8 /* UART Component Version */
++
++/* Component Parameter Register bits */
++#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0)
++#define DW_UART_CPR_AFCE_MODE (1 << 4)
++#define DW_UART_CPR_THRE_MODE (1 << 5)
++#define DW_UART_CPR_SIR_MODE (1 << 6)
++#define DW_UART_CPR_SIR_LP_MODE (1 << 7)
++#define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8)
++#define DW_UART_CPR_FIFO_ACCESS (1 << 9)
++#define DW_UART_CPR_FIFO_STAT (1 << 10)
++#define DW_UART_CPR_SHADOW (1 << 11)
++#define DW_UART_CPR_ENCODED_PARMS (1 << 12)
++#define DW_UART_CPR_DMA_EXTRA (1 << 13)
++#define DW_UART_CPR_FIFO_MODE (0xff << 16)
++/* Helper for fifo size calculation */
++#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16)
++
+
+ struct dw8250_data {
+ int last_lcr;
+ int line;
++ struct clk *clk;
+ };
+
+ static void dw8250_serial_out(struct uart_port *p, int offset, int value)
+@@ -66,19 +99,79 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
+ return readl(p->membase + offset);
+ }
+
+-/* Offset for the DesignWare's UART Status Register. */
+-#define UART_USR 0x1f
++#define LPSS_PRV_CLK 0x800
++#define LPSS_PRV_CLK_EN (1 << 0)
++#define LPSS_PRV_CLK_M_VAL_SHIFT 1
++#define LPSS_PRV_CLK_N_VAL_SHIFT 16
++#define LPSS_PRV_CLK_UPDATE (1 << 31)
++
++#define LPSS_HSUART_GENERAL_REG 0x808
++#define LPSS_GENERAL_DIS_RTS_N_OVERRIDE (1 << 3)
++
++static void
++dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
++ struct ktermios *old)
++{
++ struct uart_8250_port *up =
++ container_of(p, struct uart_8250_port, port);
++ unsigned int baud = tty_termios_baud_rate(termios);
++ unsigned int m = 6912;
++ unsigned int n = 15625;
++ u32 reg;
++
++ /*
++ * For baud rates 1000000, 2000000 and 4000000 the dividers must be
++ * adjusted.
++ */
++ if (baud == 1000000 || baud == 2000000 || baud == 4000000) {
++ m = 64;
++ n = 100;
++
++ p->uartclk = 64000000;
++ } else if (baud == 3000000){
++ m = 48;
++ n = 100;
++
++ p->uartclk = 48000000;
++ }else {
++ p->uartclk = 44236800;
++ }
++
++ /* Reset the clock */
++ reg = (m << LPSS_PRV_CLK_M_VAL_SHIFT) | (n << LPSS_PRV_CLK_N_VAL_SHIFT);
++ writel(reg, p->membase + LPSS_PRV_CLK);
++ reg |= LPSS_PRV_CLK_EN | LPSS_PRV_CLK_UPDATE;
++ writel(reg, p->membase + LPSS_PRV_CLK);
++
++ /* For BYT, hs-uart is capable of auto flow control */
++ up->capabilities |= UART_CAP_AFE;
++
++ /* If auto-handshake mechanism is not enabled,
++ * disable rts_n override */
++ reg = readl(p->membase + LPSS_HSUART_GENERAL_REG);
++ reg &= ~LPSS_GENERAL_DIS_RTS_N_OVERRIDE;
++ if (termios->c_cflag & CRTSCTS)
++ reg |= LPSS_GENERAL_DIS_RTS_N_OVERRIDE;
++ writel(reg, p->membase + LPSS_HSUART_GENERAL_REG);
++
++ serial8250_do_set_termios(p, termios, old);
++}
+
+ 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(iir & UART_IIR_RLSI) {
++ readl(p->membase + LPSS_UART_BYTE_CNT);
++ readl(p->membase + LPSS_UART_OVRFLW_INTR_STAT);
++ }
++
+ 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. */
+- (void)p->serial_in(p, UART_USR);
++ (void)p->serial_in(p, DW_UART_USR);
+ p->serial_out(p, UART_LCR, d->last_lcr);
+
+ return 1;
+@@ -87,61 +180,216 @@ static int dw8250_handle_irq(struct uart_port *p)
+ return 0;
+ }
+
++static void
++dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
++{
++ if (!state)
++ pm_runtime_get_sync(port->dev);
++
++ serial8250_do_pm(port, state, old);
++
++ if (state)
++ pm_runtime_put_sync_suspend(port->dev);
++}
++
++static int dw8250_probe_of(struct uart_port *p)
++{
++ struct device_node *np = p->dev->of_node;
++ u32 val;
++
++ if (!of_property_read_u32(np, "reg-io-width", &val)) {
++ switch (val) {
++ case 1:
++ break;
++ case 4:
++ p->iotype = UPIO_MEM32;
++ p->serial_in = dw8250_serial_in32;
++ p->serial_out = dw8250_serial_out32;
++ break;
++ default:
++ dev_err(p->dev, "unsupported reg-io-width (%u)\n", val);
++ return -EINVAL;
++ }
++ }
++
++ if (!of_property_read_u32(np, "reg-shift", &val))
++ p->regshift = val;
++
++ if (of_property_read_u32(np, "clock-frequency", &val)) {
++ dev_err(p->dev, "no clock-frequency property set\n");
++ return -EINVAL;
++ }
++ p->uartclk = val;
++
++ return 0;
++}
++
++#ifdef CONFIG_ACPI
++static bool dw8250_acpi_dma_filter(struct dma_chan *chan, void *parm)
++{
++ return chan->chan_id == *(int *)parm;
++}
++
++static acpi_status
++dw8250_acpi_walk_resource(struct acpi_resource *res, void *data)
++{
++ struct uart_port *p = data;
++ struct uart_8250_port *port;
++ struct uart_8250_dma *dma;
++ struct acpi_resource_fixed_dma *fixed_dma;
++ struct dma_slave_config *slave;
++
++ port = container_of(p, struct uart_8250_port, port);
++
++ switch (res->type) {
++ case ACPI_RESOURCE_TYPE_FIXED_DMA:
++ fixed_dma = &res->data.fixed_dma;
++
++ /* TX comes first */
++ if (!port->dma) {
++ dma = devm_kzalloc(p->dev, sizeof(*dma), GFP_KERNEL);
++ if (!dma)
++ return AE_NO_MEMORY;
++
++ port->dma = dma;
++ slave = &dma->txconf;
++
++ slave->direction = DMA_MEM_TO_DEV;
++ slave->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
++ slave->slave_id = fixed_dma->request_lines;
++ slave->dst_maxburst = port->tx_loadsz / 4;
++
++ dma->tx_chan_id = fixed_dma->channels;
++ dma->tx_param = &dma->tx_chan_id;
++ dma->fn = dw8250_acpi_dma_filter;
++ } else {
++ dma = port->dma;
++ slave = &dma->rxconf;
++
++ slave->direction = DMA_DEV_TO_MEM;
++ slave->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
++ slave->slave_id = fixed_dma->request_lines;
++ slave->src_maxburst = p->fifosize / 4;
++
++ dma->rx_chan_id = fixed_dma->channels;
++ dma->rx_param = &dma->rx_chan_id;
++ }
++
++ break;
++ }
++
++ return AE_OK;
++}
++
++static int dw8250_probe_acpi(struct uart_port *p)
++{
++ struct dw8250_data *data = p->private_data;
++ acpi_status status;
++
++ p->iotype = UPIO_MEM32;
++ p->serial_in = dw8250_serial_in32;
++ p->serial_out = dw8250_serial_out32;
++ p->set_termios = dw8250_set_termios;
++ p->regshift = 2;
++ p->uartclk = clk_get_rate(data->clk);
++
++ if (use_dma){
++ status = acpi_walk_resources(ACPI_HANDLE(p->dev), METHOD_NAME__CRS,
++ dw8250_acpi_walk_resource, p);
++ if (ACPI_FAILURE(status)) {
++ dev_err_ratelimited(p->dev, "%s failed \"%s\"\n", __func__,
++ acpi_format_exception(status));
++ return -ENODEV;
++ }
++ }
++ return 0;
++}
++#else
++static inline int dw8250_probe_acpi(struct uart_port *p)
++{
++ return -ENODEV;
++}
++#endif /* CONFIG_ACPI */
++
++static void dw8250_setup_port(struct uart_8250_port *up)
++{
++ struct uart_port *p = &up->port;
++ u32 reg = readl(p->membase + DW_UART_UCV);
++
++ /*
++ * If the Component Version Register returns zero, we know that
++ * ADDITIONAL_FEATURES are not enabled. No need to go any further.
++ */
++ if (!reg)
++ return;
++
++ dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n",
++ (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
++
++ reg = readl(p->membase + DW_UART_CPR);
++ if (!reg)
++ return;
++
++ /* Select the type based on fifo */
++ if (reg & DW_UART_CPR_FIFO_MODE) {
++ p->type = PORT_16550A;
++ p->flags |= UPF_FIXED_TYPE;
++ p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
++ up->tx_loadsz = p->fifosize;
++ }
++}
++
+ static int dw8250_probe(struct platform_device *pdev)
+ {
+ struct uart_8250_port uart = {};
+ struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+- struct device_node *np = pdev->dev.of_node;
+- u32 val;
+ struct dw8250_data *data;
++ int err;
+
+ if (!regs || !irq) {
+ dev_err(&pdev->dev, "no registers/irq defined\n");
+ return -EINVAL;
+ }
+
+- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+- if (!data)
+- return -ENOMEM;
+- uart.port.private_data = data;
+-
+ spin_lock_init(&uart.port.lock);
+ uart.port.mapbase = regs->start;
+ uart.port.irq = irq->start;
+ uart.port.handle_irq = dw8250_handle_irq;
++ uart.port.pm = dw8250_do_pm;
+ uart.port.type = PORT_8250;
+- uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP |
+- UPF_FIXED_PORT | UPF_FIXED_TYPE;
++ uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
+ uart.port.dev = &pdev->dev;
+
++ uart.port.membase = ioremap(regs->start, resource_size(regs));
++ if (!uart.port.membase)
++ return -ENOMEM;
++
++ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++
+ uart.port.iotype = UPIO_MEM;
+ uart.port.serial_in = dw8250_serial_in;
+ uart.port.serial_out = dw8250_serial_out;
+- if (!of_property_read_u32(np, "reg-io-width", &val)) {
+- switch (val) {
+- case 1:
+- break;
+- case 4:
+- uart.port.iotype = UPIO_MEM32;
+- uart.port.serial_in = dw8250_serial_in32;
+- uart.port.serial_out = dw8250_serial_out32;
+- break;
+- default:
+- dev_err(&pdev->dev, "unsupported reg-io-width (%u)\n",
+- val);
+- return -EINVAL;
+- }
+- }
+-
+- if (!of_property_read_u32(np, "reg-shift", &val))
+- uart.port.regshift = val;
++ uart.port.private_data = data;
+
+- if (of_property_read_u32(np, "clock-frequency", &val)) {
+- dev_err(&pdev->dev, "no clock-frequency property set\n");
+- return -EINVAL;
++ data->clk = devm_clk_get(&pdev->dev, NULL);
++ clk_prepare_enable(data->clk);
++
++ dw8250_setup_port(&uart);
++
++ if (pdev->dev.of_node) {
++ err = dw8250_probe_of(&uart.port);
++ if (err)
++ return err;
++ } else if (ACPI_HANDLE(&pdev->dev)) {
++ err = dw8250_probe_acpi(&uart.port);
++ if (err)
++ return err;
++ } else {
++ return -ENODEV;
+ }
+- uart.port.uartclk = val;
+
+ data->line = serial8250_register_8250_port(&uart);
+ if (data->line < 0)
+@@ -149,6 +397,8 @@ static int dw8250_probe(struct platform_device *pdev)
+
+ platform_set_drvdata(pdev, data);
+
++ pm_runtime_forbid(&pdev->dev);
++
+ return 0;
+ }
+
+@@ -156,50 +406,86 @@ static int dw8250_remove(struct platform_device *pdev)
+ {
+ struct dw8250_data *data = platform_get_drvdata(pdev);
+
++ pm_runtime_get_sync(&pdev->dev);
++
+ serial8250_unregister_port(data->line);
++ clk_disable_unprepare(data->clk);
++
++ pm_runtime_disable(&pdev->dev);
++ pm_runtime_put_noidle(&pdev->dev);
+
+ return 0;
+ }
+
+ #ifdef CONFIG_PM
+-static int dw8250_suspend(struct platform_device *pdev, pm_message_t state)
++static int dw8250_suspend(struct device *dev)
+ {
+- struct dw8250_data *data = platform_get_drvdata(pdev);
++ struct dw8250_data *data = dev_get_drvdata(dev);
+
+ serial8250_suspend_port(data->line);
+
+ return 0;
+ }
+
+-static int dw8250_resume(struct platform_device *pdev)
++static int dw8250_resume(struct device *dev)
+ {
+- struct dw8250_data *data = platform_get_drvdata(pdev);
++ struct dw8250_data *data = dev_get_drvdata(dev);
+
+ serial8250_resume_port(data->line);
+
+ return 0;
+ }
+-#else
+-#define dw8250_suspend NULL
+-#define dw8250_resume NULL
+ #endif /* CONFIG_PM */
+
+-static const struct of_device_id dw8250_match[] = {
++#ifdef CONFIG_PM_RUNTIME
++static int dw8250_runtime_suspend(struct device *dev)
++{
++ struct dw8250_data *data = dev_get_drvdata(dev);
++
++ clk_disable_unprepare(data->clk);
++
++ return 0;
++}
++
++static int dw8250_runtime_resume(struct device *dev)
++{
++ struct dw8250_data *data = dev_get_drvdata(dev);
++
++ clk_prepare_enable(data->clk);
++
++ return 0;
++}
++#endif
++
++static const struct dev_pm_ops dw8250_pm_ops = {
++ SET_SYSTEM_SLEEP_PM_OPS(dw8250_suspend, dw8250_resume)
++ SET_RUNTIME_PM_OPS(dw8250_runtime_suspend, dw8250_runtime_resume, NULL)
++};
++
++static const struct of_device_id dw8250_of_match[] = {
+ { .compatible = "snps,dw-apb-uart" },
+ { /* Sentinel */ }
+ };
+-MODULE_DEVICE_TABLE(of, dw8250_match);
++MODULE_DEVICE_TABLE(of, dw8250_of_match);
++
++static const struct acpi_device_id dw8250_acpi_match[] = {
++ { "80860F0A", 0 },
++ { "INT33C4", 0 },
++ { "INT33C5", 0 },
++ { },
++};
++MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
+
+ static struct platform_driver dw8250_platform_driver = {
+ .driver = {
+ .name = "dw-apb-uart",
+ .owner = THIS_MODULE,
+- .of_match_table = dw8250_match,
++ .pm = &dw8250_pm_ops,
++ .of_match_table = dw8250_of_match,
++ .acpi_match_table = ACPI_PTR(dw8250_acpi_match),
+ },
+ .probe = dw8250_probe,
+ .remove = dw8250_remove,
+- .suspend = dw8250_suspend,
+- .resume = dw8250_resume,
+ };
+
+ module_platform_driver(dw8250_platform_driver);
+diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
+index f53a7db..721904f 100644
+--- a/drivers/tty/serial/8250/8250_early.c
++++ b/drivers/tty/serial/8250/8250_early.c
+@@ -194,7 +194,7 @@ static int __init parse_options(struct early_serial8250_device *device,
+ options++;
+ device->baud = simple_strtoul(options, NULL, 0);
+ length = min(strcspn(options, " "), sizeof(device->options));
+- strncpy(device->options, options, length);
++ strlcpy(device->options, options, length);
+ } else {
+ device->baud = probe_baud(port);
+ snprintf(device->options, sizeof(device->options), "%u",
+diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
+index a27a98e..27b82d4 100644
+--- a/drivers/tty/serial/8250/8250_pci.c
++++ b/drivers/tty/serial/8250/8250_pci.c
+@@ -1077,6 +1077,134 @@ ce4100_serial_setup(struct serial_private *priv,
+ return ret;
+ }
+
++static bool lpss_dma_filter(struct dma_chan *chan, void *param)
++{
++ return chan->chan_id == *(int*)param;
++}
++
++#define PCI_DEVICE_ID_INTEL_HSW_UART1 0x9c63
++#define PCI_DEVICE_ID_INTEL_HSW_UART2 0x9c64
++
++#define LPSS_PRV_CLK 0x800
++#define LPSS_PRV_CLK_EN (1 << 0)
++#define LPSS_PRV_CLK_M_VAL_SHIFT 1
++#define LPSS_PRV_CLK_N_VAL_SHIFT 16
++#define LPSS_PRV_CLK_UPDATE (1 << 31)
++
++#define LPSS_HSUART_GENERAL_REG 0x808
++#define LPSS_GENERAL_DIS_RTS_N_OVERRIDE (1 << 3)
++
++static void
++lpss_set_termios(struct uart_port *p, struct ktermios *termios,
++ struct ktermios *old)
++{
++ struct uart_8250_port *up =
++ container_of(p, struct uart_8250_port, port);
++ unsigned int baud = tty_termios_baud_rate(termios);
++ unsigned int m = 6912;
++ unsigned int n = 15625;
++ u32 reg;
++
++ /*
++ * For baud rates 1000000, 2000000 and 4000000 the dividers must be
++ * adjusted.
++ */
++ if (baud == 1000000 || baud == 2000000 || baud == 4000000) {
++ m = 64;
++ n = 100;
++
++ p->uartclk = 64000000;
++ } else if (baud == 3000000){
++ m = 48;
++ n = 100;
++
++ p->uartclk = 48000000;
++ } else {
++ p->uartclk = 44236800;
++ }
++
++ /* Reset the clock */
++ reg = (m << LPSS_PRV_CLK_M_VAL_SHIFT) | (n << LPSS_PRV_CLK_N_VAL_SHIFT);
++ writel(reg, p->membase + LPSS_PRV_CLK);
++ reg |= LPSS_PRV_CLK_EN | LPSS_PRV_CLK_UPDATE;
++ writel(reg, p->membase + LPSS_PRV_CLK);
++
++ /* For BYT, hs-uart is capable of auto flow control */
++ up->capabilities |= UART_CAP_AFE;
++
++ /*
++ * If auto-handshake mechanism is not enabled,
++ * disable rts_n override
++ */
++ reg = readl(p->membase + LPSS_HSUART_GENERAL_REG);
++ reg &= ~LPSS_GENERAL_DIS_RTS_N_OVERRIDE;
++ if (termios->c_cflag & CRTSCTS)
++ reg |= LPSS_GENERAL_DIS_RTS_N_OVERRIDE;
++ writel(reg, p->membase + LPSS_HSUART_GENERAL_REG);
++
++ serial8250_do_set_termios(p, termios, old);
++}
++
++static int
++lpss_serial_setup(struct serial_private *priv,
++ const struct pciserial_board *board,
++ struct uart_8250_port *port, int idx)
++{
++ struct uart_8250_dma *dma;
++ int ret;
++
++ dma = devm_kzalloc(port->port.dev, sizeof(*dma), GFP_KERNEL);
++ if (!dma)
++ return -ENOMEM;
++
++ switch (priv->dev->device) {
++ case PCI_DEVICE_ID_INTEL_BYT_UART1:
++ dma->rx_chan_id = 3;
++ dma->rxconf.slave_id = dma->rx_chan_id;
++ dma->tx_chan_id = 2;
++ dma->txconf.slave_id = dma->tx_chan_id;
++ break;
++ case PCI_DEVICE_ID_INTEL_BYT_UART2:
++ dma->rx_chan_id = 5;
++ dma->rxconf.slave_id = dma->rx_chan_id;
++ dma->tx_chan_id = 4;
++ dma->txconf.slave_id = dma->tx_chan_id;
++ break;
++ case PCI_DEVICE_ID_INTEL_HSW_UART1:
++ dma->rx_chan_id = 5;
++ dma->rxconf.slave_id = 21;
++ dma->tx_chan_id = 4;
++ dma->txconf.slave_id = 20;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ dma->rxconf.direction = DMA_DEV_TO_MEM;
++ dma->rxconf.src_addr_width = 1;
++ dma->rxconf.src_maxburst = 16;
++
++ dma->txconf.direction = DMA_MEM_TO_DEV;
++ dma->txconf.dst_addr_width = 1;
++ dma->rxconf.dst_maxburst = 16;
++
++ dma->fn = lpss_dma_filter;
++ dma->rx_param = &dma->rx_chan_id;
++ dma->tx_param = &dma->tx_chan_id;
++
++ ret = pci_default_setup(priv, board, port, idx);
++ port->port.iotype = UPIO_MEM;
++ port->port.type = PORT_16550A;
++ port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
++ port->port.set_termios = lpss_set_termios;
++ port->port.fifosize = 64;
++ port->tx_loadsz = 64;
++ port->dma = dma;
++ port->port.dev->id = priv->dev->device;
++
++ return ret;
++}
++
+ static int
+ pci_omegapci_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+@@ -1409,6 +1537,34 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
+ .subdevice = PCI_ANY_ID,
+ .setup = kt_serial_setup,
+ },
++ {
++ .vendor = PCI_VENDOR_ID_INTEL,
++ .device = PCI_DEVICE_ID_INTEL_BYT_UART1,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ .setup = lpss_serial_setup,
++ },
++ {
++ .vendor = PCI_VENDOR_ID_INTEL,
++ .device = PCI_DEVICE_ID_INTEL_BYT_UART2,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ .setup = lpss_serial_setup,
++ },
++ {
++ .vendor = PCI_VENDOR_ID_INTEL,
++ .device = PCI_DEVICE_ID_INTEL_HSW_UART1,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ .setup = lpss_serial_setup,
++ },
++ {
++ .vendor = PCI_VENDOR_ID_INTEL,
++ .device = PCI_DEVICE_ID_INTEL_HSW_UART2,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ .setup = pci_default_setup,
++ },
+ /*
+ * ITE
+ */
+@@ -2170,6 +2326,8 @@ enum pci_board_num_t {
+ pbn_ADDIDATA_PCIe_4_3906250,
+ pbn_ADDIDATA_PCIe_8_3906250,
+ pbn_ce4100_1_115200,
++ pbn_byt,
++ pbn_hsw,
+ pbn_omegapci,
+ pbn_NETMOS9900_2s_115200,
+ pbn_brcm_trumanage,
+@@ -2906,6 +3064,20 @@ static struct pciserial_board pci_boards[] = {
+ .base_baud = 921600,
+ .reg_shift = 2,
+ },
++ [pbn_byt] = {
++ .flags = FL_BASE0,
++ .num_ports = 1,
++ .base_baud = 2764800,
++ .uart_offset = 0x80,
++ .reg_shift = 2,
++ },
++ [pbn_hsw] = {
++ .flags = FL_BASE0,
++ .num_ports = 1,
++ .base_baud = 6250000,
++ .uart_offset = 0x80,
++ .reg_shift = 2,
++ },
+ [pbn_omegapci] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+@@ -4493,6 +4665,24 @@ static struct pci_device_id serial_pci_tbl[] = {
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ce4100_1_115200 },
++ /* Intel BYT */
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_UART1,
++ PCI_ANY_ID, PCI_ANY_ID,
++ PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
++ pbn_byt },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_UART2,
++ PCI_ANY_ID, PCI_ANY_ID,
++ PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
++ pbn_byt },
++ /* Intel Haswell-ULT */
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_UART1,
++ PCI_ANY_ID, PCI_ANY_ID,
++ PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
++ pbn_hsw },
++ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_UART2,
++ PCI_ANY_ID, PCI_ANY_ID,
++ PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
++ pbn_hsw },
+
+ /*
+ * Cronyx Omega PCI
+diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
+index c31133a..2748125 100644
+--- a/drivers/tty/serial/8250/Kconfig
++++ b/drivers/tty/serial/8250/Kconfig
+@@ -84,6 +84,14 @@ config SERIAL_8250_GSC
+ depends on SERIAL_8250 && GSC
+ default SERIAL_8250
+
++config SERIAL_8250_DMA
++ bool "DMA support for 16550 compatible UART controllers" if EXPERT
++ depends on SERIAL_8250 && DMADEVICES=y
++ default SERIAL_8250
++ help
++ This builds DMA support that can be used with 8250/16650
++ compatible UART controllers that support DMA signaling.
++
+ config SERIAL_8250_PCI
+ tristate "8250/16550 PCI device support" if EXPERT
+ depends on SERIAL_8250 && PCI
+@@ -265,7 +273,7 @@ config SERIAL_8250_FSL
+
+ config SERIAL_8250_DW
+ tristate "Support for Synopsys DesignWare 8250 quirks"
+- depends on SERIAL_8250 && OF
++ depends on SERIAL_8250
+ help
+ Selecting this option will enable handling of the extra features
+ present in the Synopsys DesignWare APB UART.
+diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
+index 108fe7f..a23838a 100644
+--- a/drivers/tty/serial/8250/Makefile
++++ b/drivers/tty/serial/8250/Makefile
+@@ -5,6 +5,7 @@
+ obj-$(CONFIG_SERIAL_8250) += 8250_core.o
+ 8250_core-y := 8250.o
+ 8250_core-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
++8250_core-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.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
+diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
+index c490d20..af47a8a 100644
+--- a/include/linux/serial_8250.h
++++ b/include/linux/serial_8250.h
+@@ -59,6 +59,8 @@ enum {
+ PLAT8250_DEV_SM501,
+ };
+
++struct uart_8250_dma;
++
+ /*
+ * This should be used by drivers which want to register
+ * their own 8250 ports without registering their own
+@@ -91,6 +93,8 @@ struct uart_8250_port {
+ #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
+ unsigned char msr_saved_flags;
+
++ struct uart_8250_dma *dma;
++
+ /* 8250 specific callbacks */
+ int (*dl_read)(struct uart_8250_port *);
+ void (*dl_write)(struct uart_8250_port *, int);
+--
+1.7.10.4
+
--
1.7.10.4
More information about the linux-yocto
mailing list