Commit c84c2b62 authored by David Woodhouse's avatar David Woodhouse

Support high-speed serial modes of National Semiconductor and SMSC Super-IO chips.

parent d0e462fc
......@@ -159,7 +159,8 @@ static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = {
{ "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO },
{ "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
{ "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
{ "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO }
{ "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO },
{ "NS16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO | UART_NATSEMI }
};
static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset)
......@@ -481,6 +482,40 @@ static void autoconfig_16550a(struct uart_8250_port *up)
return;
}
/*
* Check for a National Semiconductor SuperIO chip.
* Attempt to switch to bank 2, read the value of the LOOP bit
* from EXCR1. Switch back to bank 0, change it in MCR. Then
* switch back to bank 2, read it from EXCR1 again and check
* it's changed. If so, set baud_base in EXCR2 to 921600.
*/
serial_outp(up, UART_LCR, 0);
status1 = serial_in(up, UART_MCR);
serial_outp(up, UART_LCR, 0xE0);
status2 = serial_in(up, 0x02); /* EXCR1 */
if (!((status2 ^ status1) & UART_MCR_LOOP)) {
serial_outp(up, UART_LCR, 0);
serial_outp(up, UART_MCR, status1 ^ UART_MCR_LOOP);
serial_outp(up, UART_LCR, 0xE0);
status2 = serial_in(up, 0x02); /* EXCR1 */
serial_outp(up, UART_LCR, 0);
serial_outp(up, UART_MCR, status1);
if ((status2 ^ status1) & UART_MCR_LOOP) {
serial_outp(up, UART_LCR, 0xE0);
status1 = serial_in(up, 0x04); /* EXCR1 */
status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
serial_outp(up, 0x04, status1);
serial_outp(up, UART_LCR, 0);
up->port.type = PORT_NS16550A;
up->port.uartclk = 921600*16;
return;
}
}
/*
* No EFR. Try to detect a TI16750, which only sets bit 5 of
* the IIR when 64 byte FIFO mode is enabled when DLAB is set.
......@@ -1318,6 +1353,26 @@ static void serial8250_shutdown(struct uart_port *port)
serial_unlink_irq_chain(up);
}
static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
{
unsigned int quot;
/*
* Handle magic divisors for baud rates above baud_base on
* SMSC SuperIO chips.
*/
if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
baud == (port->uartclk/4))
quot = 0x8001;
else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
baud == (port->uartclk/8))
quot = 0x8002;
else
quot = uart_get_divisor(port, baud);
return quot;
}
static void
serial8250_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
......@@ -1358,7 +1413,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
* Ask the core to calculate the divisor for us.
*/
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
quot = serial8250_get_divisor(port, baud);
/*
* Work around a bug in the Oxford Semiconductor 952 rev B
......@@ -1435,7 +1490,13 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
serial_outp(up, UART_EFR,
termios->c_cflag & CRTSCTS ? UART_EFR_CTS :0);
}
if (uart_config[up->port.type].flags & UART_NATSEMI) {
/* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */
serial_outp(up, UART_LCR, 0xe0);
} else {
serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
}
serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */
serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */
if (up->port.type == PORT_16750)
......
......@@ -91,6 +91,7 @@ struct serial_uart_config {
#define UART_CLEAR_FIFO 0x01
#define UART_USE_FIFO 0x02
#define UART_STARTECH 0x04
#define UART_NATSEMI 0x08
/*
* Definitions for async_struct (and serial_struct) flags field
......
......@@ -37,7 +37,8 @@
#define PORT_16654 11
#define PORT_16850 12
#define PORT_RSA 13
#define PORT_MAX_8250 13 /* max port ID */
#define PORT_NS16550A 14
#define PORT_MAX_8250 14 /* max port ID */
/*
* ARM specific type numbers. These are not currently guaranteed
......@@ -172,6 +173,7 @@ struct uart_port {
#define UPF_LOW_LATENCY (1 << 13)
#define UPF_BUGGY_UART (1 << 14)
#define UPF_AUTOPROBE (1 << 15)
#define UPF_MAGIC_MULTIPLIER (1 << 16)
#define UPF_BOOT_ONLYMCA (1 << 22)
#define UPF_CONS_FLOW (1 << 23)
#define UPF_SHARE_IRQ (1 << 24)
......@@ -179,7 +181,7 @@ struct uart_port {
#define UPF_RESOURCES (1 << 30)
#define UPF_IOREMAP (1 << 31)
#define UPF_CHANGE_MASK (0x7fff)
#define UPF_CHANGE_MASK (0x17fff)
#define UPF_USR_MASK (UPF_SPD_MASK|UPF_LOW_LATENCY)
unsigned int mctrl; /* current modem ctrl settings */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment