[PATCH 2/2] serial: 8250_pci: add DMA support for Broxton HSUART

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Huiquan Zhong <huiquan.zhong@xxxxxxxxx>

Intel Broxton HSUART controller have attached the Integrated DMA IP
which just have two channels[TX, RX]. Add special DMA filter function
for idma.

Signed-off-by: Huiquan Zhong <huiquan.zhong@xxxxxxxxx>
Signed-off-by: qipeng.zha <qipeng.zha@xxxxxxxxx>
---
 drivers/tty/serial/8250/8250_pci.c | 108 +++++++++++++++++++++++++++++++++++++
 1 file changed, 108 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 824ca72..ee8a56e 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -27,6 +27,7 @@
 
 #include <linux/dmaengine.h>
 #include <linux/platform_data/dma-dw.h>
+#include <linux/dma/dw.h>
 
 #include "8250.h"
 
@@ -56,6 +57,7 @@ struct serial_private {
 	unsigned int		nr;
 	void __iomem		*remapped_bar[PCI_NUM_BAR_RESOURCES];
 	struct pci_serial_quirk	*quirk;
+	struct dw_dma_chip	*chip;
 	int			line[0];
 };
 
@@ -1547,6 +1549,11 @@ byt_serial_setup(struct serial_private *priv,
 #define BXT_UART_IC_CLOCK_IDMA		0xc
 #define BXT_UART_IC_CLOCK_UART		0x3
 
+#define BXT_UART_CAP			0x2FC
+#define IDMA_PRESENT			BIT(8)
+
+#define BXT_IDMA_OFFSET			0x800
+
 static void
 bxt_set_termios(struct uart_port *p, struct ktermios *termios,
 		struct ktermios *old)
@@ -1566,11 +1573,60 @@ bxt_set_termios(struct uart_port *p, struct ktermios *termios,
 	serial8250_do_set_termios(p, termios, old);
 }
 
+static bool bxt_dma_filter(struct dma_chan *chan, void *param)
+{
+	struct dw_dma_slave *dws = param;
+
+	if (dws->dma_dev != chan->device->dev)
+		return false;
+
+	chan->private = dws;
+	return true;
+}
+
+static struct dw_dma_platform_data bxt_idma_pdata = {
+	.nr_channels = 2,
+	.is_private = true,
+	.chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
+	.chan_priority = CHAN_PRIORITY_ASCENDING,
+	.block_size = 0x1ffff, /* 128KB -1 */
+};
+
+static struct dw_dma_chip *bxt_idma_probe(struct device *dev,
+		void __iomem *base, int irq)
+{
+	struct dw_dma_chip *chip;
+	int err;
+
+	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return ERR_PTR(-ENOMEM);
+
+	chip->irq = irq;
+	chip->regs = base + BXT_IDMA_OFFSET;
+	chip->type = DW_DMAC_TYPE_IDMA;
+
+	err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
+	if (err)
+		return ERR_PTR(err);
+
+	chip->dev = dev;
+	err = dw_dma_probe(chip, &bxt_idma_pdata);
+	if (err)
+		return ERR_PTR(err);
+
+	return chip;
+}
+
 static int
 bxt_serial_setup(struct serial_private *priv,
 		 const struct pciserial_board *board,
 		 struct uart_8250_port *port, int idx)
 {
+	struct device *dev = port->port.dev;
+	struct uart_8250_dma *dma;
+	struct dw_dma_slave *tx_param, *rx_param;
+	unsigned int uart_cap;
 	int ret;
 
 	ret = pci_default_setup(priv, board, port, idx);
@@ -1582,6 +1638,50 @@ bxt_serial_setup(struct serial_private *priv,
 	port->tx_loadsz = 64;
 	port->capabilities = UART_CAP_FIFO | UART_CAP_AFE;
 
+	uart_cap = readl(port->port.membase + BXT_UART_CAP);
+	if (!(uart_cap & IDMA_PRESENT)) {
+		dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
+		if (!dma)
+			return -ENOMEM;
+
+		tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL);
+		if (!tx_param) {
+			ret = -ENOMEM;
+			goto err_dma_alloc;
+		}
+
+		rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL);
+		if (!rx_param) {
+			ret = -ENOMEM;
+			goto err_tx_param_alloc;
+		}
+
+		tx_param->dst_id = 0;
+		rx_param->src_id = 1;
+
+		dma->rxconf.src_maxburst = 8;
+		dma->rxconf.dst_maxburst = 8;
+		dma->txconf.src_maxburst = 8;
+		dma->txconf.dst_maxburst = 8;
+
+		rx_param->dma_dev = dev;
+		tx_param->dma_dev = dev;
+
+		dma->fn = bxt_dma_filter;
+		dma->rx_param = rx_param;
+		dma->tx_param = tx_param;
+
+		priv->chip = bxt_idma_probe(dev, port->port.membase,
+				port->port.irq);
+		if (!priv->chip) {
+			dev_err(dev, "error: DMA device register failed\n");
+			ret = PTR_ERR(priv->chip);
+			goto err_rx_param_alloc;
+		}
+
+		port->dma = dma;
+	}
+
 	/* Hw reset */
 	writel(0, port->port.membase + BXT_UART_RESET);
 	writel(BXT_UART_IDMA_RESET | BXT_UART_HOST_RESET,
@@ -1591,6 +1691,14 @@ bxt_serial_setup(struct serial_private *priv,
 			port->port.membase + BXT_UART_IC_CLOCK);
 
 	return ret;
+
+err_rx_param_alloc:
+	devm_kfree(dev, rx_param);
+err_tx_param_alloc:
+	devm_kfree(dev, tx_param);
+err_dma_alloc:
+	devm_kfree(dev, dma);
+	return ret;
 }
 
 static int
-- 
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux PPP]     [Linux FS]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Linmodem]     [Device Mapper]     [Linux Kernel for ARM]

  Powered by Linux