serial: 8250_mid: add support for DMA engine handling from UART MMIO
authorHeikki Krogerus <heikki.krogerus@linux.intel.com>
Tue, 13 Oct 2015 10:29:06 +0000 (13:29 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 18 Oct 2015 04:22:08 +0000 (21:22 -0700)
The platforms that have this UART, but that don't have
separate PCI device for the DMA Engine, need to create the
HSU DMA Engine device separately.

Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/8250/8250_mid.c
drivers/tty/serial/8250/8250_pci.c

index 61f604c7aeee41ab1ab509fc75584dd974d9fca5..88531a36b69ccd3752c5197bd1c8b9f7f5f87705 100644 (file)
@@ -21,6 +21,7 @@
 #define PCI_DEVICE_ID_INTEL_PNW_UART2  0x081c
 #define PCI_DEVICE_ID_INTEL_PNW_UART3  0x081d
 #define PCI_DEVICE_ID_INTEL_TNG_UART   0x1191
+#define PCI_DEVICE_ID_INTEL_DNV_UART   0x19d8
 
 /* Intel MID Specific registers */
 #define INTEL_MID_UART_PS              0x30
@@ -33,6 +34,7 @@ struct mid8250_board {
        unsigned long freq;
        unsigned int base_baud;
        int (*setup)(struct mid8250 *, struct uart_port *p);
+       void (*exit)(struct mid8250 *);
 };
 
 struct mid8250 {
@@ -41,6 +43,7 @@ struct mid8250 {
        struct pci_dev *dma_dev;
        struct uart_8250_dma dma;
        struct mid8250_board *board;
+       struct hsu_dma_chip dma_chip;
 };
 
 /*****************************************************************************/
@@ -82,6 +85,53 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p)
        return 0;
 }
 
+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));
+}
+
+#define DNV_DMA_CHAN_OFFSET 0x80
+
+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);
+       int ret;
+
+       chip->dev = &pdev->dev;
+       chip->irq = pdev->irq;
+       chip->regs = p->membase;
+       chip->length = pci_resource_len(pdev, 0);
+       chip->offset = DNV_DMA_CHAN_OFFSET;
+
+       /* Falling back to PIO mode if DMA probing fails */
+       ret = hsu_dma_probe(chip);
+       if (ret)
+               return 0;
+
+       mid->dma_dev = pdev;
+
+       p->handle_irq = dnv_handle_irq;
+       return 0;
+}
+
+static void dnv_exit(struct mid8250 *mid)
+{
+       if (!mid->dma_dev)
+               return;
+       hsu_dma_remove(&mid->dma_chip);
+}
+
 /*****************************************************************************/
 
 static void mid8250_set_termios(struct uart_port *p,
@@ -135,6 +185,9 @@ static int mid8250_dma_setup(struct mid8250 *mid, struct uart_8250_port *port)
        struct hsu_dma_slave *rx_param;
        struct hsu_dma_slave *tx_param;
 
+       if (!mid->dma_dev)
+               return 0;
+
        rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL);
        if (!rx_param)
                return -ENOMEM;
@@ -202,22 +255,29 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        ret = mid8250_dma_setup(mid, &uart);
        if (ret)
-               return ret;
+               goto err;
 
        ret = serial8250_register_8250_port(&uart);
        if (ret < 0)
-               return ret;
+               goto err;
 
        mid->line = ret;
 
        pci_set_drvdata(pdev, mid);
        return 0;
+err:
+       if (mid->board->exit)
+               mid->board->exit(mid);
+       return ret;
 }
 
 static void mid8250_remove(struct pci_dev *pdev)
 {
        struct mid8250 *mid = pci_get_drvdata(pdev);
 
+       if (mid->board->exit)
+               mid->board->exit(mid);
+
        serial8250_unregister_port(mid->line);
 }
 
@@ -233,6 +293,13 @@ static const struct mid8250_board tng_board = {
        .setup = tng_setup,
 };
 
+static const struct mid8250_board dnv_board = {
+       .freq = 133333333,
+       .base_baud = 115200,
+       .setup = dnv_setup,
+       .exit = dnv_exit,
+};
+
 #define MID_DEVICE(id, board) { PCI_VDEVICE(INTEL, id), (kernel_ulong_t)&board }
 
 static const struct pci_device_id pci_ids[] = {
@@ -240,6 +307,7 @@ static const struct pci_device_id pci_ids[] = {
        MID_DEVICE(PCI_DEVICE_ID_INTEL_PNW_UART2, pnw_board),
        MID_DEVICE(PCI_DEVICE_ID_INTEL_PNW_UART3, pnw_board),
        MID_DEVICE(PCI_DEVICE_ID_INTEL_TNG_UART, tng_board),
+       MID_DEVICE(PCI_DEVICE_ID_INTEL_DNV_UART, dnv_board),
        { },
 };
 MODULE_DEVICE_TABLE(pci, pci_ids);
index 177eaeafeb3eaa8907705f4be3dfe2f597f61fd6..4097f3f65b3bb1bfc3e3d4d6a40f05fb46c70618 100644 (file)
@@ -3809,6 +3809,7 @@ static const struct pci_device_id blacklist[] = {
        { PCI_VDEVICE(INTEL, 0x081c), },
        { PCI_VDEVICE(INTEL, 0x081d), },
        { PCI_VDEVICE(INTEL, 0x1191), },
+       { PCI_VDEVICE(INTEL, 0x19d8), },
 };
 
 /*