Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1389066 > unrolled thread

[PATCH v3 00/11] serial: 8250: split LPSS to 8250_lpss, enable DMA on Quark

Started byAndy Shevchenko <andriy.shevchenko@linux.intel.com>
First post2016-04-27 15:50 +0200
Last post2016-04-27 16:00 +0200
Articles 7 — 1 participant

Back to article view | Back to linux.kernel


Contents

  [PATCH v3 00/11] serial: 8250: split LPSS to 8250_lpss, enable DMA on Quark Andy Shevchenko <andriy.shevchenko@linux.intel.com> - 2016-04-27 15:50 +0200
    [PATCH v3 07/11] serial: 8250: enable AFE on ports where FIFO is 16 bytes Andy Shevchenko <andriy.shevchenko@linux.intel.com> - 2016-04-27 15:50 +0200
    [PATCH v3 04/11] dmaengine: dw: override LLP support if asked in platform data Andy Shevchenko <andriy.shevchenko@linux.intel.com> - 2016-04-27 15:50 +0200
    [PATCH v3 01/11] dmaengine: dw: keep copy of custom slave config in dwc Andy Shevchenko <andriy.shevchenko@linux.intel.com> - 2016-04-27 16:00 +0200
    [PATCH v3 06/11] serial: 8250_dma: adjust DMA address of the UART Andy Shevchenko <andriy.shevchenko@linux.intel.com> - 2016-04-27 16:00 +0200
    [PATCH v3 10/11] serial: 8250_lpss: enable MSI for Intel Quark Andy Shevchenko <andriy.shevchenko@linux.intel.com> - 2016-04-27 16:00 +0200
    [PATCH v3 11/11] serial: 8250_lpss: enable DMA on Intel Quark UART Andy Shevchenko <andriy.shevchenko@linux.intel.com> - 2016-04-27 16:00 +0200

#1389066 — [PATCH v3 00/11] serial: 8250: split LPSS to 8250_lpss, enable DMA on Quark

FromAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Date2016-04-27 15:50 +0200
Subject[PATCH v3 00/11] serial: 8250: split LPSS to 8250_lpss, enable DMA on Quark
Message-ID<rsy0O-22y-3@gated-at.bofh.it>
This is combined series of two things:
- split out the Intel LPSS specific driver from 8250_pci into 8250_lpss
- enable DMA support on Intel Quark UART

The patch has been tested on few Intel SoCs / platforms. In any case I would
like to ask Bryan to do independent test.

This is targeting serial subsystem, thus it would be nice to get and Ack from
Vinod first. Moreover, the series depends on [1] that is now under review. On
the other hand Vinod proposed to take it through dma-slave tree. Greg?

That's why I asked Vinod to create immutable tag / branch for the [1] and the
dependants (at least one more, which is sata_dwc_460ex) can use it.

The series can be reached in the branch located at [2].

[1] http://www.spinics.net/lists/kernel/msg2244475.html
[2] https://bitbucket.org/andy-shev/linux/branch/topic%2Fdw%2Fqrk

Since v2:
- add tags
- rebase on top of new version of [1]

Since v1:
- address most of Peter's comments (mostly changelog to patch 8)
- add tag to patch 5
- drop patch 6 from the series to be separately dealt with

Andy Shevchenko (11):
  dmaengine: dw: keep copy of custom slave config in dwc
  dmaengine: dw: provide probe(), remove() stubs for users
  dmaengine: dw: set polarity of handshake interface
  dmaengine: dw: override LLP support if asked in platform data
  serial: 8250_dma: switch to new dmaengine_terminate_* API
  serial: 8250_dma: adjust DMA address of the UART
  serial: 8250: enable AFE on ports where FIFO is 16 bytes
  serial: 8250_lpss: split LPSS driver to separate module
  serial: 8250_lpss: move Quark code from PCI driver
  serial: 8250_lpss: enable MSI for Intel Quark
  serial: 8250_lpss: enable DMA on Intel Quark UART

 drivers/dma/dw/core.c                |  41 ++---
 drivers/dma/dw/regs.h                |   5 +-
 drivers/tty/serial/8250/8250.h       |   5 +
 drivers/tty/serial/8250/8250_dma.c   |  14 +-
 drivers/tty/serial/8250/8250_lpss.c  | 344 +++++++++++++++++++++++++++++++++++
 drivers/tty/serial/8250/8250_pci.c   | 242 +-----------------------
 drivers/tty/serial/8250/8250_port.c  |   9 +-
 drivers/tty/serial/8250/Kconfig      |  14 +-
 drivers/tty/serial/8250/Makefile     |   1 +
 include/linux/dma/dw.h               |   5 +
 include/linux/platform_data/dma-dw.h |   4 +
 11 files changed, 413 insertions(+), 271 deletions(-)
 create mode 100644 drivers/tty/serial/8250/8250_lpss.c

-- 
2.8.0.rc3

[toc] | [next] | [standalone]


#1389070 — [PATCH v3 07/11] serial: 8250: enable AFE on ports where FIFO is 16 bytes

FromAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Date2016-04-27 15:50 +0200
Subject[PATCH v3 07/11] serial: 8250: enable AFE on ports where FIFO is 16 bytes
Message-ID<rsy0P-22y-37@gated-at.bofh.it>
In reply to#1389066
Intel Quark has 16550A compatible UART with autoflow feature enabled. It has
only 16 bytes of FIFO. Currently serial8250_do_set_termios() prevents to enable
autoflow since the minimum requirement of 32 bytes of FIFO size.

Drop a FIFO size limitation to allow autoflow control be enabled on such UARTs.

While here, comment out UART_CAP_AFE for PORT_AR7 since it wasn't working and
it will be not a good idea to use it in conjunction with trigger level of 1
byte.

Suggested-by: Peter Hurley <peter@hurleysoftware.com>
Reviewed-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/tty/serial/8250/8250_port.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 00ad263..719a561 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -178,7 +178,7 @@ static const struct serial8250_config uart_config[] = {
 		.fifo_size	= 16,
 		.tx_loadsz	= 16,
 		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
-		.flags		= UART_CAP_FIFO | UART_CAP_AFE,
+		.flags		= UART_CAP_FIFO /* | UART_CAP_AFE */,
 	},
 	[PORT_U6_16550A] = {
 		.name		= "U6_16550A",
@@ -2528,12 +2528,9 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
 	/*
 	 * MCR-based auto flow control.  When AFE is enabled, RTS will be
 	 * deasserted when the receive FIFO contains more characters than
-	 * the trigger, or the MCR RTS bit is cleared.  In the case where
-	 * the remote UART is not using CTS auto flow control, we must
-	 * have sufficient FIFO entries for the latency of the remote
-	 * UART to respond.  IOW, at least 32 bytes of FIFO.
+	 * the trigger, or the MCR RTS bit is cleared.
 	 */
-	if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) {
+	if (up->capabilities & UART_CAP_AFE) {
 		up->mcr &= ~UART_MCR_AFE;
 		if (termios->c_cflag & CRTSCTS)
 			up->mcr |= UART_MCR_AFE;
-- 
2.8.0.rc3

[toc] | [prev] | [next] | [standalone]


#1389071 — [PATCH v3 04/11] dmaengine: dw: override LLP support if asked in platform data

FromAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Date2016-04-27 15:50 +0200
Subject[PATCH v3 04/11] dmaengine: dw: override LLP support if asked in platform data
Message-ID<rsy0P-22y-41@gated-at.bofh.it>
In reply to#1389066
There is at least one known device, i.e. UART on Intel Galileo, that works
unreliably in case of use of multi block transfer support in DMA mode.

Override autodetection by user provided data.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/dma/dw/core.c                | 10 +++++++---
 include/linux/platform_data/dma-dw.h |  2 ++
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index 9c7bc7a..f66d104 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -1571,9 +1571,13 @@ int dw_dma_probe(struct dw_dma_chip *chip)
 			dwc->block_size = pdata->block_size;
 
 			/* Check if channel supports multi block transfer */
-			channel_writel(dwc, LLP, DWC_LLP_LOC(0xffffffff));
-			dwc->nollp = DWC_LLP_LOC(channel_readl(dwc, LLP)) == 0;
-			channel_writel(dwc, LLP, 0);
+			if (pdata->is_nollp) {
+				dwc->nollp = pdata->is_nollp;
+			} else {
+				channel_writel(dwc, LLP, DWC_LLP_LOC(0xffffffff));
+				dwc->nollp = DWC_LLP_LOC(channel_readl(dwc, LLP)) == 0;
+				channel_writel(dwc, LLP, 0);
+			}
 		}
 	}
 
diff --git a/include/linux/platform_data/dma-dw.h b/include/linux/platform_data/dma-dw.h
index 192f3a2..ec7f7d3 100644
--- a/include/linux/platform_data/dma-dw.h
+++ b/include/linux/platform_data/dma-dw.h
@@ -40,6 +40,7 @@ struct dw_dma_slave {
  * @is_private: The device channels should be marked as private and not for
  *	by the general purpose DMA channel allocator.
  * @is_memcpy: The device channels do support memory-to-memory transfers.
+ * @is_nollp: The device channels does not support multi block transfers.
  * @chan_allocation_order: Allocate channels starting from 0 or 7
  * @chan_priority: Set channel priority increasing from 0 to 7 or 7 to 0.
  * @block_size: Maximum block size supported by the controller
@@ -51,6 +52,7 @@ struct dw_dma_platform_data {
 	unsigned int	nr_channels;
 	bool		is_private;
 	bool		is_memcpy;
+	bool		is_nollp;
 #define CHAN_ALLOCATION_ASCENDING	0	/* zero to seven */
 #define CHAN_ALLOCATION_DESCENDING	1	/* seven to zero */
 	unsigned char	chan_allocation_order;
-- 
2.8.0.rc3

[toc] | [prev] | [next] | [standalone]


#1389080 — [PATCH v3 01/11] dmaengine: dw: keep copy of custom slave config in dwc

FromAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Date2016-04-27 16:00 +0200
Subject[PATCH v3 01/11] dmaengine: dw: keep copy of custom slave config in dwc
Message-ID<rsyav-26F-41@gated-at.bofh.it>
In reply to#1389066
It seems we need to extend custom slave configuration by one more member to
support Intel Quart UART. It becomes a burden to manage all members of struct
dw_dma_slave one-by-one.

Replace set of fields by embedding struct dw_dma_slave into struct dw_dma_chan.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/dma/dw/core.c | 29 ++++++++++-------------------
 drivers/dma/dw/regs.h |  5 +----
 2 files changed, 11 insertions(+), 23 deletions(-)

diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index edf053f..81b06df 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -46,9 +46,9 @@
 		u8 _dmsize = _is_slave ? _sconfig->dst_maxburst :	\
 			DW_DMA_MSIZE_16;			\
 		u8 _dms = (_dwc->direction == DMA_MEM_TO_DEV) ?		\
-			_dwc->p_master : _dwc->m_master;		\
+			_dwc->dws.p_master : _dwc->dws.m_master;	\
 		u8 _sms = (_dwc->direction == DMA_DEV_TO_MEM) ?		\
-			_dwc->p_master : _dwc->m_master;		\
+			_dwc->dws.p_master : _dwc->dws.m_master;	\
 								\
 		(DWC_CTLL_DST_MSIZE(_dmsize)			\
 		 | DWC_CTLL_SRC_MSIZE(_smsize)			\
@@ -147,8 +147,8 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
 	if (test_bit(DW_DMA_IS_INITIALIZED, &dwc->flags))
 		return;
 
-	cfghi |= DWC_CFGH_DST_PER(dwc->dst_id);
-	cfghi |= DWC_CFGH_SRC_PER(dwc->src_id);
+	cfghi |= DWC_CFGH_DST_PER(dwc->dws.dst_id);
+	cfghi |= DWC_CFGH_SRC_PER(dwc->dws.src_id);
 
 	channel_writel(dwc, CFG_LO, cfglo);
 	channel_writel(dwc, CFG_HI, cfghi);
@@ -209,7 +209,7 @@ static inline void dwc_do_single_block(struct dw_dma_chan *dwc,
 static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
 {
 	struct dw_dma	*dw = to_dw_dma(dwc->chan.device);
-	u8		lms = DWC_LLP_LMS(dwc->m_master);
+	u8		lms = DWC_LLP_LMS(dwc->dws.m_master);
 	unsigned long	was_soft_llp;
 
 	/* ASSERT:  channel is idle */
@@ -662,7 +662,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 	struct dw_desc		*prev;
 	size_t			xfer_count;
 	size_t			offset;
-	u8			m_master = dwc->m_master;
+	u8			m_master = dwc->dws.m_master;
 	unsigned int		src_width;
 	unsigned int		dst_width;
 	unsigned int		data_width = dw->pdata->data_width[m_master];
@@ -740,7 +740,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 	struct dw_desc		*prev;
 	struct dw_desc		*first;
 	u32			ctllo;
-	u8			m_master = dwc->m_master;
+	u8			m_master = dwc->dws.m_master;
 	u8			lms = DWC_LLP_LMS(m_master);
 	dma_addr_t		reg;
 	unsigned int		reg_width;
@@ -895,12 +895,7 @@ bool dw_dma_filter(struct dma_chan *chan, void *param)
 		return false;
 
 	/* We have to copy data since dws can be temporary storage */
-
-	dwc->src_id = dws->src_id;
-	dwc->dst_id = dws->dst_id;
-
-	dwc->m_master = dws->m_master;
-	dwc->p_master = dws->p_master;
+	memcpy(&dwc->dws, dws, sizeof(struct dw_dma_slave));
 
 	return true;
 }
@@ -1167,11 +1162,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
 	spin_lock_irqsave(&dwc->lock, flags);
 
 	/* Clear custom channel configuration */
-	dwc->src_id = 0;
-	dwc->dst_id = 0;
-
-	dwc->m_master = 0;
-	dwc->p_master = 0;
+	memset(&dwc->dws, 0, sizeof(struct dw_dma_slave));
 
 	clear_bit(DW_DMA_IS_INITIALIZED, &dwc->flags);
 
@@ -1264,7 +1255,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
 	struct dw_cyclic_desc		*retval = NULL;
 	struct dw_desc			*desc;
 	struct dw_desc			*last = NULL;
-	u8				lms = DWC_LLP_LMS(dwc->m_master);
+	u8				lms = DWC_LLP_LMS(dwc->dws.m_master);
 	unsigned long			was_cyclic;
 	unsigned int			reg_width;
 	unsigned int			periods;
diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h
index 4b7bd78..f65dd10 100644
--- a/drivers/dma/dw/regs.h
+++ b/drivers/dma/dw/regs.h
@@ -245,10 +245,7 @@ struct dw_dma_chan {
 	bool			nollp;
 
 	/* custom slave configuration */
-	u8			src_id;
-	u8			dst_id;
-	u8			m_master;
-	u8			p_master;
+	struct dw_dma_slave	dws;
 
 	/* configuration passed via .device_config */
 	struct dma_slave_config dma_sconfig;
-- 
2.8.0.rc3

[toc] | [prev] | [next] | [standalone]


#1389084 — [PATCH v3 06/11] serial: 8250_dma: adjust DMA address of the UART

FromAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Date2016-04-27 16:00 +0200
Subject[PATCH v3 06/11] serial: 8250_dma: adjust DMA address of the UART
Message-ID<rsyaw-26F-45@gated-at.bofh.it>
In reply to#1389066
Some UARTs, e.g. one is used in Intel Quark, have a different address base for
DMA operations. Introduce an additional field (per RX and TX DMA channels) in
struct uart_8250_dma to cover those cases.

Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/tty/serial/8250/8250.h     | 5 +++++
 drivers/tty/serial/8250/8250_dma.c | 8 ++++++--
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 047a7ba..526ed3e 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -31,6 +31,11 @@ struct uart_8250_dma {
 	struct dma_chan		*rxchan;
 	struct dma_chan		*txchan;
 
+	/* Device address base for DMA operations */
+	phys_addr_t		rx_dma_addr;
+	phys_addr_t		tx_dma_addr;
+
+	/* DMA address of the buffer in memory */
 	dma_addr_t		rx_addr;
 	dma_addr_t		tx_addr;
 
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index 9d80bb1..1553181 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -157,16 +157,20 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
 int serial8250_request_dma(struct uart_8250_port *p)
 {
 	struct uart_8250_dma	*dma = p->dma;
+	phys_addr_t rx_dma_addr = dma->rx_dma_addr ?
+				  dma->rx_dma_addr : p->port.mapbase;
+	phys_addr_t tx_dma_addr = dma->tx_dma_addr ?
+				  dma->tx_dma_addr : p->port.mapbase;
 	dma_cap_mask_t		mask;
 
 	/* Default slave configuration parameters */
 	dma->rxconf.direction		= DMA_DEV_TO_MEM;
 	dma->rxconf.src_addr_width	= DMA_SLAVE_BUSWIDTH_1_BYTE;
-	dma->rxconf.src_addr		= p->port.mapbase + UART_RX;
+	dma->rxconf.src_addr		= rx_dma_addr + UART_RX;
 
 	dma->txconf.direction		= DMA_MEM_TO_DEV;
 	dma->txconf.dst_addr_width	= DMA_SLAVE_BUSWIDTH_1_BYTE;
-	dma->txconf.dst_addr		= p->port.mapbase + UART_TX;
+	dma->txconf.dst_addr		= tx_dma_addr + UART_TX;
 
 	dma_cap_zero(mask);
 	dma_cap_set(DMA_SLAVE, mask);
-- 
2.8.0.rc3

[toc] | [prev] | [next] | [standalone]


#1389086 — [PATCH v3 10/11] serial: 8250_lpss: enable MSI for Intel Quark

FromAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Date2016-04-27 16:00 +0200
Subject[PATCH v3 10/11] serial: 8250_lpss: enable MSI for Intel Quark
Message-ID<rsyaw-26F-51@gated-at.bofh.it>
In reply to#1389066
Intel Quark SoC supports MSI for LPSS, in particular for UART. Enable MSI for
Intel Quark.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/tty/serial/8250/8250_lpss.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c
index af34189..4e4abfc 100644
--- a/drivers/tty/serial/8250/8250_lpss.c
+++ b/drivers/tty/serial/8250/8250_lpss.c
@@ -137,6 +137,17 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
 	return 0;
 }
 
+static int qrk_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
+{
+	struct pci_dev *pdev = to_pci_dev(port->dev);
+
+	pci_enable_msi(pdev);
+
+	port->irq = pdev->irq;
+
+	return 0;
+}
+
 static bool lpss8250_dma_filter(struct dma_chan *chan, void *param)
 {
 	struct dw_dma_slave *dws = param;
@@ -247,6 +258,7 @@ static const struct lpss8250_board byt_board = {
 static const struct lpss8250_board qrk_board = {
 	.freq = 44236800,
 	.base_baud = 2764800,
+	.setup = qrk_serial_setup,
 };
 
 #define LPSS_DEVICE(id, board) { PCI_VDEVICE(INTEL, id), (kernel_ulong_t)&board }
-- 
2.8.0.rc3

[toc] | [prev] | [next] | [standalone]


#1389088 — [PATCH v3 11/11] serial: 8250_lpss: enable DMA on Intel Quark UART

FromAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Date2016-04-27 16:00 +0200
Subject[PATCH v3 11/11] serial: 8250_lpss: enable DMA on Intel Quark UART
Message-ID<rsyaw-26F-55@gated-at.bofh.it>
In reply to#1389066
DMA on Intel Quark SoC is a part of UART IP block. Enable it.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/tty/serial/8250/8250_lpss.c | 61 +++++++++++++++++++++++++++++++++++--
 1 file changed, 58 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c
index 4e4abfc..c9a9004 100644
--- a/drivers/tty/serial/8250/8250_lpss.c
+++ b/drivers/tty/serial/8250/8250_lpss.c
@@ -15,7 +15,7 @@
 #include <linux/rational.h>
 
 #include <linux/dmaengine.h>
-#include <linux/platform_data/dma-dw.h>
+#include <linux/dma/dw.h>
 
 #include "8250.h"
 
@@ -47,6 +47,7 @@ struct lpss8250_board {
 	unsigned long freq;
 	unsigned int base_baud;
 	int (*setup)(struct lpss8250 *, struct uart_port *p);
+	void (*exit)(struct lpss8250 *);
 };
 
 struct lpss8250 {
@@ -55,6 +56,7 @@ struct lpss8250 {
 
 	/* DMA parameters */
 	struct uart_8250_dma dma;
+	struct dw_dma_chip dma_chip;
 	struct dw_dma_slave dma_param;
 	u8 dma_maxburst;
 };
@@ -137,17 +139,61 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
 	return 0;
 }
 
+static const struct dw_dma_platform_data qrk_serial_dma_pdata = {
+	.nr_channels = 2,
+	.is_private = true,
+	.is_nollp = true,
+	.chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
+	.chan_priority = CHAN_PRIORITY_ASCENDING,
+	.block_size = 4095,
+	.nr_masters = 1,
+	.data_width = {4},
+};
+
 static int qrk_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
 {
+	struct uart_8250_dma *dma = &lpss->dma;
+	struct dw_dma_chip *chip = &lpss->dma_chip;
+	struct dw_dma_slave *param = &lpss->dma_param;
 	struct pci_dev *pdev = to_pci_dev(port->dev);
+	int ret;
 
 	pci_enable_msi(pdev);
 
 	port->irq = pdev->irq;
 
+	chip->dev = &pdev->dev;
+	chip->irq = pdev->irq;
+	chip->regs = pci_ioremap_bar(pdev, 1);
+	chip->pdata = &qrk_serial_dma_pdata;
+
+	/* Falling back to PIO mode if DMA probing fails */
+	ret = dw_dma_probe(chip);
+	if (ret)
+		return 0;
+
+	/* Special DMA address for UART */
+	dma->rx_dma_addr = 0xfffff000;
+	dma->tx_dma_addr = 0xfffff000;
+
+	param->dma_dev = &pdev->dev;
+	param->src_id = 0;
+	param->dst_id = 1;
+	param->polarity = true;
+
+	lpss->dma_maxburst = 8;
 	return 0;
 }
 
+static void qrk_serial_exit(struct lpss8250 *lpss)
+{
+	struct dw_dma_slave *param = &lpss->dma_param;
+
+	if (!param->dma_dev)
+		return;
+	dw_dma_remove(&lpss->dma_chip);
+}
+
 static bool lpss8250_dma_filter(struct dma_chan *chan, void *param)
 {
 	struct dw_dma_slave *dws = param;
@@ -230,22 +276,30 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	ret = lpss8250_dma_setup(lpss, &uart);
 	if (ret)
-		return ret;
+		goto err_exit;
 
 	ret = serial8250_register_8250_port(&uart);
 	if (ret < 0)
-		return ret;
+		goto err_exit;
 
 	lpss->line = ret;
 
 	pci_set_drvdata(pdev, lpss);
 	return 0;
+
+err_exit:
+	if (lpss->board->exit)
+		lpss->board->exit(lpss);
+	return ret;
 }
 
 static void lpss8250_remove(struct pci_dev *pdev)
 {
 	struct lpss8250 *lpss = pci_get_drvdata(pdev);
 
+	if (lpss->board->exit)
+		lpss->board->exit(lpss);
+
 	serial8250_unregister_port(lpss->line);
 }
 
@@ -259,6 +313,7 @@ static const struct lpss8250_board qrk_board = {
 	.freq = 44236800,
 	.base_baud = 2764800,
 	.setup = qrk_serial_setup,
+	.exit = qrk_serial_exit,
 };
 
 #define LPSS_DEVICE(id, board) { PCI_VDEVICE(INTEL, id), (kernel_ulong_t)&board }
-- 
2.8.0.rc3

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web