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