diff options
Diffstat (limited to 'drivers/tty/serial/8250/8250_pci.c')
-rw-r--r-- | drivers/tty/serial/8250/8250_pci.c | 439 |
1 files changed, 319 insertions, 120 deletions
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 892eb32cdef4..46bcebba54b2 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -21,12 +21,14 @@ #include <linux/serial_core.h> #include <linux/8250_pci.h> #include <linux/bitops.h> +#include <linux/rational.h> #include <asm/byteorder.h> #include <asm/io.h> #include <linux/dmaengine.h> #include <linux/platform_data/dma-dw.h> +#include <linux/platform_data/dma-hsu.h> #include "8250.h" @@ -1392,45 +1394,22 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old) { unsigned int baud = tty_termios_baud_rate(termios); - unsigned int m, n; + unsigned long fref = 100000000, fuart = baud * 16; + unsigned long w = BIT(15) - 1; + unsigned long m, n; u32 reg; + /* Get Fuart closer to Fref */ + fuart *= rounddown_pow_of_two(fref / fuart); + /* * For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the * dividers must be adjusted. * * uartclk = (m / n) * 100 MHz, where m <= n */ - switch (baud) { - case 500000: - case 1000000: - case 2000000: - case 4000000: - m = 64; - n = 100; - p->uartclk = 64000000; - break; - case 3500000: - m = 56; - n = 100; - p->uartclk = 56000000; - break; - case 1500000: - case 3000000: - m = 48; - n = 100; - p->uartclk = 48000000; - break; - case 2500000: - m = 40; - n = 100; - p->uartclk = 40000000; - break; - default: - m = 2304; - n = 3125; - p->uartclk = 73728000; - } + rational_best_approximation(fuart, fref, w, w, &m, &n); + p->uartclk = fuart; /* Reset the clock */ reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT); @@ -1525,6 +1504,167 @@ byt_serial_setup(struct serial_private *priv, return ret; } +#define INTEL_MID_UART_PS 0x30 +#define INTEL_MID_UART_MUL 0x34 +#define INTEL_MID_UART_DIV 0x38 + +static void intel_mid_set_termios(struct uart_port *p, + struct ktermios *termios, + struct ktermios *old, + unsigned long fref) +{ + unsigned int baud = tty_termios_baud_rate(termios); + unsigned short ps = 16; + unsigned long fuart = baud * ps; + unsigned long w = BIT(24) - 1; + unsigned long mul, div; + + if (fref < fuart) { + /* Find prescaler value that satisfies Fuart < Fref */ + if (fref > baud) + ps = fref / baud; /* baud rate too high */ + else + ps = 1; /* PLL case */ + fuart = baud * ps; + } else { + /* Get Fuart closer to Fref */ + fuart *= rounddown_pow_of_two(fref / fuart); + } + + rational_best_approximation(fuart, fref, w, w, &mul, &div); + p->uartclk = fuart * 16 / ps; /* core uses ps = 16 always */ + + writel(ps, p->membase + INTEL_MID_UART_PS); /* set PS */ + writel(mul, p->membase + INTEL_MID_UART_MUL); /* set MUL */ + writel(div, p->membase + INTEL_MID_UART_DIV); + + serial8250_do_set_termios(p, termios, old); +} + +static void intel_mid_set_termios_38_4M(struct uart_port *p, + struct ktermios *termios, + struct ktermios *old) +{ + intel_mid_set_termios(p, termios, old, 38400000); +} + +static void intel_mid_set_termios_50M(struct uart_port *p, + struct ktermios *termios, + struct ktermios *old) +{ + /* + * The uart clk is 50Mhz, and the baud rate come from: + * baud = 50M * MUL / (DIV * PS * DLAB) + */ + intel_mid_set_termios(p, termios, old, 50000000); +} + +static bool intel_mid_dma_filter(struct dma_chan *chan, void *param) +{ + struct hsu_dma_slave *s = param; + + if (s->dma_dev != chan->device->dev || s->chan_id != chan->chan_id) + return false; + + chan->private = s; + return true; +} + +static int intel_mid_serial_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx, + int index, struct pci_dev *dma_dev) +{ + struct device *dev = port->port.dev; + struct uart_8250_dma *dma; + struct hsu_dma_slave *tx_param, *rx_param; + + 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) + return -ENOMEM; + + rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL); + if (!rx_param) + return -ENOMEM; + + rx_param->chan_id = index * 2 + 1; + tx_param->chan_id = index * 2; + + dma->rxconf.src_maxburst = 64; + dma->txconf.dst_maxburst = 64; + + rx_param->dma_dev = &dma_dev->dev; + tx_param->dma_dev = &dma_dev->dev; + + dma->fn = intel_mid_dma_filter; + dma->rx_param = rx_param; + dma->tx_param = tx_param; + + port->port.type = PORT_16750; + port->port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE; + port->dma = dma; + + return pci_default_setup(priv, board, port, idx); +} + +#define PCI_DEVICE_ID_INTEL_PNW_UART1 0x081b +#define PCI_DEVICE_ID_INTEL_PNW_UART2 0x081c +#define PCI_DEVICE_ID_INTEL_PNW_UART3 0x081d + +static int pnw_serial_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + struct pci_dev *pdev = priv->dev; + struct pci_dev *dma_dev; + int index; + + switch (pdev->device) { + case PCI_DEVICE_ID_INTEL_PNW_UART1: + index = 0; + break; + case PCI_DEVICE_ID_INTEL_PNW_UART2: + index = 1; + break; + case PCI_DEVICE_ID_INTEL_PNW_UART3: + index = 2; + break; + default: + return -EINVAL; + } + + dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 3)); + + port->port.set_termios = intel_mid_set_termios_50M; + + return intel_mid_serial_setup(priv, board, port, idx, index, dma_dev); +} + +#define PCI_DEVICE_ID_INTEL_TNG_UART 0x1191 + +static int tng_serial_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + struct pci_dev *pdev = priv->dev; + struct pci_dev *dma_dev; + int index = PCI_FUNC(pdev->devfn); + + /* Currently no support for HSU port0 */ + if (index-- == 0) + return -ENODEV; + + dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(5, 0)); + + port->port.set_termios = intel_mid_set_termios_38_4M; + + return intel_mid_serial_setup(priv, board, port, idx, index, dma_dev); +} + static int pci_omegapci_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1550,95 +1690,71 @@ static int pci_fintek_setup(struct serial_private *priv, struct uart_8250_port *port, int idx) { struct pci_dev *pdev = priv->dev; - unsigned long base; - unsigned long iobase; - unsigned long ciobase = 0; u8 config_base; + u16 iobase; + + config_base = 0x40 + 0x08 * idx; + + /* Get the io address from configuration space */ + pci_read_config_word(pdev, config_base + 4, &iobase); + + dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase); + + port->port.iotype = UPIO_PORT; + port->port.iobase = iobase; + + return 0; +} + +static int pci_fintek_init(struct pci_dev *dev) +{ + unsigned long iobase; + u32 max_port, i; u32 bar_data[3]; + u8 config_base; - /* - * Find each UARTs offset in PCI configuraion space - */ - switch (idx) { - case 0: - config_base = 0x40; - break; - case 1: - config_base = 0x48; - break; - case 2: - config_base = 0x50; - break; - case 3: - config_base = 0x58; - break; - case 4: - config_base = 0x60; - break; - case 5: - config_base = 0x68; - break; - case 6: - config_base = 0x70; - break; - case 7: - config_base = 0x78; - break; - case 8: - config_base = 0x80; + switch (dev->device) { + case 0x1104: /* 4 ports */ + case 0x1108: /* 8 ports */ + max_port = dev->device & 0xff; break; - case 9: - config_base = 0x88; - break; - case 10: - config_base = 0x90; - break; - case 11: - config_base = 0x98; + case 0x1112: /* 12 ports */ + max_port = 12; break; default: - /* Unknown number of ports, get out of here */ return -EINVAL; } - if (idx < 4) { - base = pci_resource_start(priv->dev, 3); - ciobase = (int)(base + (0x8 * idx)); - } - /* Get the io address dispatch from the BIOS */ - pci_read_config_dword(pdev, 0x24, &bar_data[0]); - pci_read_config_dword(pdev, 0x20, &bar_data[1]); - pci_read_config_dword(pdev, 0x1c, &bar_data[2]); - - /* Calculate Real IO Port */ - iobase = (bar_data[idx/4] & 0xffffffe0) + (idx % 4) * 8; + pci_read_config_dword(dev, 0x24, &bar_data[0]); + pci_read_config_dword(dev, 0x20, &bar_data[1]); + pci_read_config_dword(dev, 0x1c, &bar_data[2]); - dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%lx ciobase=0x%lx config_base=0x%2x\n", - __func__, idx, iobase, ciobase, config_base); + for (i = 0; i < max_port; ++i) { + /* UART0 configuration offset start from 0x40 */ + config_base = 0x40 + 0x08 * i; - /* Enable UART I/O port */ - pci_write_config_byte(pdev, config_base + 0x00, 0x01); + /* Calculate Real IO Port */ + iobase = (bar_data[i / 4] & 0xffffffe0) + (i % 4) * 8; - /* Select 128-byte FIFO and 8x FIFO threshold */ - pci_write_config_byte(pdev, config_base + 0x01, 0x33); + /* Enable UART I/O port */ + pci_write_config_byte(dev, config_base + 0x00, 0x01); - /* LSB UART */ - pci_write_config_byte(pdev, config_base + 0x04, (u8)(iobase & 0xff)); + /* Select 128-byte FIFO and 8x FIFO threshold */ + pci_write_config_byte(dev, config_base + 0x01, 0x33); - /* MSB UART */ - pci_write_config_byte(pdev, config_base + 0x05, (u8)((iobase & 0xff00) >> 8)); + /* LSB UART */ + pci_write_config_byte(dev, config_base + 0x04, + (u8)(iobase & 0xff)); - /* irq number, this usually fails, but the spec says to do it anyway. */ - pci_write_config_byte(pdev, config_base + 0x06, pdev->irq); + /* MSB UART */ + pci_write_config_byte(dev, config_base + 0x05, + (u8)((iobase & 0xff00) >> 8)); - port->port.iotype = UPIO_PORT; - port->port.iobase = iobase; - port->port.mapbase = 0; - port->port.membase = NULL; - port->port.regshift = 0; + pci_write_config_byte(dev, config_base + 0x06, dev->irq); + } - return 0; + return max_port; } static int skip_tx_en_setup(struct serial_private *priv, @@ -1882,6 +1998,8 @@ pci_wch_ch38x_setup(struct serial_private *priv, #define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250 #define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470 +#define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358 + /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 #define PCI_SUBDEVICE_ID_UNKNOWN_0x1588 0x1588 @@ -1989,6 +2107,34 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { }, { .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_PNW_UART1, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pnw_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_PNW_UART2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pnw_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_PNW_UART3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pnw_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_TNG_UART, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = tng_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, .device = PCI_DEVICE_ID_INTEL_BSW_UART1, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, @@ -2376,6 +2522,13 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = pci_xr17v35x_setup, }, + { + .vendor = PCI_VENDOR_ID_EXAR, + .device = PCI_DEVICE_ID_EXAR_XR17V8358, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_xr17v35x_setup, + }, /* * Xircom cards */ @@ -2653,6 +2806,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_fintek_setup, + .init = pci_fintek_init, }, { .vendor = 0x1c29, @@ -2660,6 +2814,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_fintek_setup, + .init = pci_fintek_init, }, { .vendor = 0x1c29, @@ -2667,6 +2822,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_fintek_setup, + .init = pci_fintek_init, }, /* @@ -2852,6 +3008,7 @@ enum pci_board_num_t { pbn_exar_XR17V352, pbn_exar_XR17V354, pbn_exar_XR17V358, + pbn_exar_XR17V8358, pbn_exar_ibm_saturn, pbn_pasemi_1682M, pbn_ni8430_2, @@ -2864,6 +3021,8 @@ enum pci_board_num_t { pbn_ADDIDATA_PCIe_8_3906250, pbn_ce4100_1_115200, pbn_byt, + pbn_pnw, + pbn_tng, pbn_qrk, pbn_omegapci, pbn_NETMOS9900_2s_115200, @@ -3536,6 +3695,14 @@ static struct pciserial_board pci_boards[] = { .reg_shift = 0, .first_offset = 0, }, + [pbn_exar_XR17V8358] = { + .flags = FL_BASE0, + .num_ports = 16, + .base_baud = 7812500, + .uart_offset = 0x400, + .reg_shift = 0, + .first_offset = 0, + }, [pbn_exar_ibm_saturn] = { .flags = FL_BASE0, .num_ports = 1, @@ -3630,6 +3797,16 @@ static struct pciserial_board pci_boards[] = { .uart_offset = 0x80, .reg_shift = 2, }, + [pbn_pnw] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 115200, + }, + [pbn_tng] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 1843200, + }, [pbn_qrk] = { .flags = FL_BASE0, .num_ports = 1, @@ -4006,41 +4183,41 @@ static void pciserial_remove_one(struct pci_dev *dev) pci_disable_device(dev); } -#ifdef CONFIG_PM -static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int pciserial_suspend_one(struct device *dev) { - struct serial_private *priv = pci_get_drvdata(dev); + struct pci_dev *pdev = to_pci_dev(dev); + struct serial_private *priv = pci_get_drvdata(pdev); if (priv) pciserial_suspend_ports(priv); - pci_save_state(dev); - pci_set_power_state(dev, pci_choose_state(dev, state)); return 0; } -static int pciserial_resume_one(struct pci_dev *dev) +static int pciserial_resume_one(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); + struct serial_private *priv = pci_get_drvdata(pdev); int err; - struct serial_private *priv = pci_get_drvdata(dev); - - pci_set_power_state(dev, PCI_D0); - pci_restore_state(dev); if (priv) { /* * The device may have been disabled. Re-enable it. */ - err = pci_enable_device(dev); + err = pci_enable_device(pdev); /* FIXME: We cannot simply error out here */ if (err) - dev_err(&dev->dev, "Unable to re-enable ports, trying to continue.\n"); + dev_err(dev, "Unable to re-enable ports, trying to continue.\n"); pciserial_resume_ports(priv); } return 0; } #endif +static SIMPLE_DEV_PM_OPS(pciserial_pm_ops, pciserial_suspend_one, + pciserial_resume_one); + static struct pci_device_id serial_pci_tbl[] = { /* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */ { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620, @@ -4921,7 +5098,7 @@ static struct pci_device_id serial_pci_tbl[] = { 0, 0, pbn_exar_XR17C158 }, /* - * Exar Corp. XR17V35[248] Dual/Quad/Octal PCIe UARTs + * Exar Corp. XR17V[48]35[248] Dual/Quad/Octal/Hexa PCIe UARTs */ { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V352, PCI_ANY_ID, PCI_ANY_ID, @@ -4935,7 +5112,10 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_exar_XR17V358 }, - + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V8358, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17V8358 }, /* * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke) */ @@ -5363,6 +5543,26 @@ static struct pci_device_id serial_pci_tbl[] = { pbn_byt }, /* + * Intel Penwell + */ + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART1, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_pnw}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_pnw}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_pnw}, + + /* + * Intel Tangier + */ + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TNG_UART, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_tng}, + + /* * Intel Quark x1000 */ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_UART, @@ -5510,10 +5710,9 @@ static struct pci_driver serial_pci_driver = { .name = "serial", .probe = pciserial_init_one, .remove = pciserial_remove_one, -#ifdef CONFIG_PM - .suspend = pciserial_suspend_one, - .resume = pciserial_resume_one, -#endif + .driver = { + .pm = &pciserial_pm_ops, + }, .id_table = serial_pci_tbl, .err_handler = &serial8250_err_handler, }; |