Commit b1691bd0 authored by Maciej W. Rozycki's avatar Maciej W. Rozycki Committed by Greg Kroah-Hartman
Browse files

serial: 8250: Document SMSC Super I/O UART peculiarities



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: default avatarMaciej 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: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1882441c
Loading
Loading
Loading
Loading
+29 −2
Original line number Diff line number Diff line
@@ -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))