Serial ports of F81504/F81508/F81512 will failed when wakeup from S3(STR). It's due to when the system wakeup from S3(STR), this PCI device's configuration space from 0x40 to 0x40 + max_port * 0x08 should be re-configured. We move all initialization from pci_fintek_setup() to pci_fintek_init() and set it to pci_serial_quirks .init section. It's will re-init this device when system wakeup from pciserial_resume_ports(). Signed-off-by: Peter Hung <hpeter+linux_kernel@xxxxxxxxx> --- drivers/tty/serial/8250/8250_pci.c | 114 ++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 64 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 701b7b1..cfa477f 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1545,91 +1545,74 @@ pci_brcm_trumanage_setup(struct serial_private *priv, return ret; } -static int pci_fintek_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) +static int pci_fintek_init(struct pci_dev *dev) { - struct pci_dev *pdev = priv->dev; unsigned long iobase; - u8 config_base; + 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; + switch (dev->device) { + case 0x1104: /* 4 ports */ + case 0x1108: /* 8 ports */ + max_port = dev->device & 0xff; break; - case 6: - config_base = 0x70; - break; - case 7: - config_base = 0x78; - break; - case 8: - config_base = 0x80; - 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; } /* 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]); + 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]); + + for (i = 0; i < max_port; ++i) { + /* UART0 configuration offset start from 0x40 */ + config_base = 0x40 + 0x08 * i; + + /* Calculate Real IO Port */ + iobase = (bar_data[i / 4] & 0xffffffe0) + (i % 4) * 8; + + /* Enable UART I/O port */ + pci_write_config_byte(dev, config_base + 0x00, 0x01); + + /* Select 128-byte FIFO and 8x FIFO threshold */ + pci_write_config_byte(dev, config_base + 0x01, 0x33); - /* Calculate Real IO Port */ - iobase = (bar_data[idx/4] & 0xffffffe0) + (idx % 4) * 8; + /* LSB UART */ + pci_write_config_byte(dev, config_base + 0x04, + (u8)(iobase & 0xff)); - dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%lx config_base=0x%2x\n", - __func__, idx, iobase, config_base); + /* MSB UART */ + pci_write_config_byte(dev, config_base + 0x05, + (u8)((iobase & 0xff00) >> 8)); - /* Enable UART I/O port */ - pci_write_config_byte(pdev, config_base + 0x00, 0x01); + pci_write_config_byte(dev, config_base + 0x06, dev->irq); + } + + return max_port; +} - /* Select 128-byte FIFO and 8x FIFO threshold */ - pci_write_config_byte(pdev, config_base + 0x01, 0x33); +static int pci_fintek_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + struct pci_dev *pdev = priv->dev; + u8 config_base; + u16 iobase; - /* LSB UART */ - pci_write_config_byte(pdev, config_base + 0x04, (u8)(iobase & 0xff)); + config_base = 0x40 + 0x08 * idx; - /* MSB UART */ - pci_write_config_byte(pdev, config_base + 0x05, (u8)((iobase & 0xff00) >> 8)); + /* Get the io address from configuration space */ + pci_read_config_word(pdev, config_base + 4, &iobase); - /* irq number, this usually fails, but the spec says to do it anyway. */ - pci_write_config_byte(pdev, config_base + 0x06, pdev->irq); + dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase); port->port.iotype = UPIO_PORT; port->port.iobase = iobase; - port->port.mapbase = 0; - port->port.membase = NULL; - port->port.regshift = 0; return 0; } @@ -2646,6 +2629,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, @@ -2653,6 +2637,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 +2645,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, }, /* -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html