Message ID | 1444052484-138915-6-git-send-email-heikki.krogerus@linux.intel.com (mailing list archive) |
---|---|
State | Not Applicable |
Headers | show |
On Mon, 2015-10-05 at 16:41 +0300, Heikki Krogerus wrote: > 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. One comment below. > > Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> > --- > drivers/tty/serial/8250/8250_mid.c | 67 > ++++++++++++++++++++++++++++++++++++-- > drivers/tty/serial/8250/8250_pci.c | 1 + > 2 files changed, 66 insertions(+), 2 deletions(-) > > diff --git a/drivers/tty/serial/8250/8250_mid.c > b/drivers/tty/serial/8250/8250_mid.c > index 61f604c..06eb10c 100644 > --- a/drivers/tty/serial/8250/8250_mid.c > +++ b/drivers/tty/serial/8250/8250_mid.c > @@ -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,51 @@ 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_REGS 0x80 > +#define DNV_DMA_OFFSET 0x40 > + > +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 + DNV_DMA_REGS; > + chip->length = pci_resource_len(pdev, 0) - DNV_DMA_REGS; > + chip->offset = DNV_DMA_OFFSET; This a bit buggy, since that offset stuff is coming for HSU PCI case where we have 1) 0x100 bytes for global DMA registers (like interrupt) 2) 0x40 * nr_channels So, in your case chip->offset should be 0, but _DMA_REGS should be renamed to something like DMA_REGS_START since it's an offset to UART register space. > + > + ret = hsu_dma_probe(chip); > + if (ret) > + return ret; > + > + mid->dma_dev = pdev; > + > + p->handle_irq = dnv_handle_irq; > + return 0; > +} > + > +static void dnv_exit(struct mid8250 *mid) > +{ > + hsu_dma_remove(&mid->dma_chip); > +} > + > /******************************************************************* > **********/ > > static void mid8250_set_termios(struct uart_port *p, > @@ -202,22 +250,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 +288,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 +302,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); > diff --git a/drivers/tty/serial/8250/8250_pci.c > b/drivers/tty/serial/8250/8250_pci.c > index 177eaea..4097f3f 100644 > --- a/drivers/tty/serial/8250/8250_pci.c > +++ b/drivers/tty/serial/8250/8250_pci.c > @@ -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), }, > }; > > /*
> > +#define DNV_DMA_REGS 0x80 > > +#define DNV_DMA_OFFSET 0x40 > > + > > +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 + DNV_DMA_REGS; > > + chip->length = pci_resource_len(pdev, 0) - DNV_DMA_REGS; > > + chip->offset = DNV_DMA_OFFSET; > > This a bit buggy, since that offset stuff is coming for HSU PCI case > where we have > 1) 0x100 bytes for global DMA registers (like interrupt) > 2) 0x40 * nr_channels > > So, in your case chip->offset should be 0, but _DMA_REGS should be > renamed to something like DMA_REGS_START since it's an offset to UART > register space. Good catch! I'll prepare v2 of this series today and fix that. Thanks Andy,
diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index 61f604c..06eb10c 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -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,51 @@ 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_REGS 0x80 +#define DNV_DMA_OFFSET 0x40 + +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 + DNV_DMA_REGS; + chip->length = pci_resource_len(pdev, 0) - DNV_DMA_REGS; + chip->offset = DNV_DMA_OFFSET; + + ret = hsu_dma_probe(chip); + if (ret) + return ret; + + mid->dma_dev = pdev; + + p->handle_irq = dnv_handle_irq; + return 0; +} + +static void dnv_exit(struct mid8250 *mid) +{ + hsu_dma_remove(&mid->dma_chip); +} + /*****************************************************************************/ static void mid8250_set_termios(struct uart_port *p, @@ -202,22 +250,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 +288,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 +302,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); diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 177eaea..4097f3f 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -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), }, }; /*
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> --- drivers/tty/serial/8250/8250_mid.c | 67 ++++++++++++++++++++++++++++++++++++-- drivers/tty/serial/8250/8250_pci.c | 1 + 2 files changed, 66 insertions(+), 2 deletions(-)