serial: 8250: Document SMSC Super I/O UART peculiarities
authorMaciej W. Rozycki <macro@orcam.me.uk>
Thu, 10 Jun 2021 18:38:28 +0000 (20:38 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 16 Jun 2021 07:20:29 +0000 (09:20 +0200)
Contrary to what SMSC documentation says and unlike NS16C550A UARTs the
SMSC Super I/O IC claims compatibility with the SMSC UART implementation
does not support dividing the internal PLL clock by any divisor from 1
to 65535[1], with the exception of two magic divisors of 32769 and 32770
used respectively to select the high-speed data rates of 460800bps and
230400bps[2] if enabled on a port-by-port basis in with the Serial Port
Mode Register in the Device Configuration Space[3][4].

Instead empirical evidence indicates that the divisor, as stored in the
DLL and DLM register pair, has the range of 1 to 32767 only, and bit 7
of the DLM register (bit 15 of the divisor) effectively serves as a
selection bit for the prescaler from the base frequency of 7.3728MHz,
either 4 if the bit is 0, or 1 if the bit is 1 and high-speed operation
has been enabled with the Serial Port Mode Register.

So if high-speed operation has not been enabled, then say the values of
1 and 32769 (0x8001) written into the combined DLL and DLM register pair
both select the divisor of 1 and the baud rate of 115200bps.

[1] "FDC37M81x, PC98/99 Compliant Enhanced Super I/O Controller with
    Keyboard/Mouse Wake-Up", Standard Microsystems Corporation, Rev.
    03/27/2000, Section "Programmable Baud Rate Generator (and Divisor
    Latches DLH, DLL)", p. 75

[2] same, Table 31 - "Baud Rates", p. 77

[3] same, Table 60 - "Serial Port 1, Logical Device 4 [Logical Device
    Number = 0x04]", p. 153

[4] same, Table 61 - "Serial Port 2, Logical Device 5 [Logical Device
    Number = 0x05]", p. 153

Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Link: https://lore.kernel.org/r/alpine.DEB.2.21.2106092330530.5469@angie.orcam.me.uk
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/8250/8250_port.c

index fc5ab203228213c4b0524d59f9478db813d3f687..b96562102b43254a33f4fbd7e3a43a61d4001cb8 100644 (file)
@@ -2516,9 +2516,36 @@ static unsigned int serial8250_do_get_divisor(struct uart_port *port,
        unsigned int quot;
 
        /*
-        * Handle magic divisors for baud rates above baud_base on
-        * SMSC SuperIO chips.
+        * Handle magic divisors for baud rates above baud_base on SMSC
+        * Super I/O chips.  We clamp custom rates from clk/6 and clk/12
+        * up to clk/4 (0x8001) and clk/8 (0x8002) respectively.  These
+        * magic divisors actually reprogram the baud rate generator's
+        * reference clock derived from chips's 14.318MHz clock input.
         *
+        * Documentation claims that with these magic divisors the base
+        * frequencies of 7.3728MHz and 3.6864MHz are used respectively
+        * for the extra baud rates of 460800bps and 230400bps rather
+        * than the usual base frequency of 1.8462MHz.  However empirical
+        * evidence contradicts that.
+        *
+        * Instead bit 7 of the DLM register (bit 15 of the divisor) is
+        * effectively used as a clock prescaler selection bit for the
+        * base frequency of 7.3728MHz, always used.  If set to 0, then
+        * the base frequency is divided by 4 for use by the Baud Rate
+        * Generator, for the usual arrangement where the value of 1 of
+        * the divisor produces the baud rate of 115200bps.  Conversely,
+        * if set to 1 and high-speed operation has been enabled with the
+        * Serial Port Mode Register in the Device Configuration Space,
+        * then the base frequency is supplied directly to the Baud Rate
+        * Generator, so for the divisor values of 0x8001, 0x8002, 0x8003,
+        * 0x8004, etc. the respective baud rates produced are 460800bps,
+        * 230400bps, 153600bps, 115200bps, etc.
+        *
+        * In all cases only low 15 bits of the divisor are used to divide
+        * the baud base and therefore 32767 is the maximum divisor value
+        * possible, even though documentation says that the programmable
+        * Baud Rate Generator is capable of dividing the internal PLL
+        * clock by any divisor from 1 to 65535.
         */
        if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
            baud == (port->uartclk/4))