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] = { ...@@ -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 }, { "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO },
{ "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
{ "XR16850", 128, 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) 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) ...@@ -481,6 +482,40 @@ static void autoconfig_16550a(struct uart_8250_port *up)
return; 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 * 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. * 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) ...@@ -1318,6 +1353,26 @@ static void serial8250_shutdown(struct uart_port *port)
serial_unlink_irq_chain(up); 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 static void
serial8250_set_termios(struct uart_port *port, struct termios *termios, serial8250_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old) struct termios *old)
...@@ -1358,7 +1413,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios, ...@@ -1358,7 +1413,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
* Ask the core to calculate the divisor for us. * Ask the core to calculate the divisor for us.
*/ */
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 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 * 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, ...@@ -1435,7 +1490,13 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
serial_outp(up, UART_EFR, serial_outp(up, UART_EFR,
termios->c_cflag & CRTSCTS ? UART_EFR_CTS :0); 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_LCR, cval | UART_LCR_DLAB);/* set DLAB */
}
serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */ serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */
serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */ serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */
if (up->port.type == PORT_16750) if (up->port.type == PORT_16750)
......
...@@ -91,6 +91,7 @@ struct serial_uart_config { ...@@ -91,6 +91,7 @@ struct serial_uart_config {
#define UART_CLEAR_FIFO 0x01 #define UART_CLEAR_FIFO 0x01
#define UART_USE_FIFO 0x02 #define UART_USE_FIFO 0x02
#define UART_STARTECH 0x04 #define UART_STARTECH 0x04
#define UART_NATSEMI 0x08
/* /*
* Definitions for async_struct (and serial_struct) flags field * Definitions for async_struct (and serial_struct) flags field
......
...@@ -37,7 +37,8 @@ ...@@ -37,7 +37,8 @@
#define PORT_16654 11 #define PORT_16654 11
#define PORT_16850 12 #define PORT_16850 12
#define PORT_RSA 13 #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 * ARM specific type numbers. These are not currently guaranteed
...@@ -172,6 +173,7 @@ struct uart_port { ...@@ -172,6 +173,7 @@ struct uart_port {
#define UPF_LOW_LATENCY (1 << 13) #define UPF_LOW_LATENCY (1 << 13)
#define UPF_BUGGY_UART (1 << 14) #define UPF_BUGGY_UART (1 << 14)
#define UPF_AUTOPROBE (1 << 15) #define UPF_AUTOPROBE (1 << 15)
#define UPF_MAGIC_MULTIPLIER (1 << 16)
#define UPF_BOOT_ONLYMCA (1 << 22) #define UPF_BOOT_ONLYMCA (1 << 22)
#define UPF_CONS_FLOW (1 << 23) #define UPF_CONS_FLOW (1 << 23)
#define UPF_SHARE_IRQ (1 << 24) #define UPF_SHARE_IRQ (1 << 24)
...@@ -179,7 +181,7 @@ struct uart_port { ...@@ -179,7 +181,7 @@ struct uart_port {
#define UPF_RESOURCES (1 << 30) #define UPF_RESOURCES (1 << 30)
#define UPF_IOREMAP (1 << 31) #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) #define UPF_USR_MASK (UPF_SPD_MASK|UPF_LOW_LATENCY)
unsigned int mctrl; /* current modem ctrl settings */ 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