serial: 8250: Add support for higher baud rates to Pericom chips
authorJay Dolan <jay.dolan@accesio.com>
Tue, 11 Jun 2019 11:47:15 +0000 (04:47 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 18 Jun 2019 07:32:04 +0000 (09:32 +0200)
The Pericom chips can achieve additional baud rates by programming the
sample clock register. The baud rates can be described as
921600 * 16 / (16 - scr) for scr values 5 to 15. The divisor is set to 1
for these baud rates.

Adds new quirk for Pericom chips other than the four port chips to use
the

Signed-off-by: Jay Dolan <jay.dolan@accesio.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/8250/8250_pci.c

index df41397..7ba1c3b 100644 (file)
@@ -1326,7 +1326,36 @@ static int pci_default_setup(struct serial_private *priv,
 
        return setup_port(priv, port, bar, offset, board->reg_shift);
 }
-
+void
+pericom_do_set_divisor(struct uart_port *port, unsigned int baud,
+                              unsigned int quot, unsigned int quot_frac)
+{
+       int scr;
+       int lcr;
+       int actual_baud;
+       int tolerance;
+
+       for (scr = 5 ; scr <= 15 ; scr++) {
+               actual_baud = 921600 * 16 / scr;
+               tolerance = actual_baud / 50;
+
+               if ((baud < actual_baud + tolerance) &&
+                       (baud > actual_baud - tolerance)) {
+
+                       lcr = serial_port_in(port, UART_LCR);
+                       serial_port_out(port, UART_LCR, lcr | 0x80);
+
+                       serial_port_out(port, UART_DLL, 1);
+                       serial_port_out(port, UART_DLM, 0);
+                       serial_port_out(port, 2, 16 - scr);
+                       serial_port_out(port, UART_LCR, lcr);
+                       return;
+               } else if (baud > actual_baud) {
+                       break;
+               }
+       }
+       serial8250_do_set_divisor(port, baud, quot, quot_frac);
+}
 static int pci_pericom_setup(struct serial_private *priv,
                  const struct pciserial_board *board,
                  struct uart_8250_port *port, int idx)
@@ -1339,6 +1368,30 @@ static int pci_pericom_setup(struct serial_private *priv,
        else
                offset += idx * board->uart_offset;
 
+
+       maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
+               (board->reg_shift + 3);
+
+       if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
+               return 1;
+
+       port->port.set_divisor = pericom_do_set_divisor;
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+static int pci_pericom_setup_four_at_eight(struct serial_private *priv,
+                 const struct pciserial_board *board,
+                 struct uart_8250_port *port, int idx)
+{
+       unsigned int bar, offset = board->first_offset, maxnr;
+
+       bar = FL_GET_BASE(board->flags);
+       if (board->flags & FL_BASE_BARS)
+               bar += idx;
+       else
+               offset += idx * board->uart_offset;
+
        if (idx==3)
                offset = 0x38;
 
@@ -1348,6 +1401,8 @@ static int pci_pericom_setup(struct serial_private *priv,
        if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
                return 1;
 
+       port->port.set_divisor = pericom_do_set_divisor;
+
        return setup_port(priv, port, bar, offset, board->reg_shift);
 }
 
@@ -1995,7 +2050,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .device         = PCI_DEVICE_ID_PERICOM_PI7C9X7954,
                .subvendor      = PCI_ANY_ID,
                .subdevice      = PCI_ANY_ID,
-               .setup          = pci_pericom_setup,
+               .setup          = pci_pericom_setup_four_at_eight,
        },
        /*
         * PLX
@@ -2032,107 +2087,113 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S,
                .device     = PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
        {
                .vendor     = PCI_VENDOR_ID_ACCESIO,
                .device     = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM,
                .subvendor  = PCI_ANY_ID,
                .subdevice  = PCI_ANY_ID,
-               .setup      = pci_pericom_setup,
+               .setup      = pci_pericom_setup_four_at_eight,
        },
-       /*
+       {
+               .vendor     = PCI_VENDOR_ID_ACCESIO,
+               .device     = PCI_ANY_ID,
+               .subvendor  = PCI_ANY_ID,
+               .subdevice  = PCI_ANY_ID,
+               .setup      = pci_pericom_setup,
+       },      /*
         * SBS Technologies, Inc., PMC-OCTALPRO 232
         */
        {