aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorYin Kangkai <kangkai.yin@linux.intel.com>2011-02-08 22:35:18 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-02-17 14:23:50 -0500
commit0d0389e5414c8950b1613e8bdc74289cde3d6d98 (patch)
tree3c67d32443f0439e9e8cae1c0fb299abcd3067c0 /drivers/tty
parent95926d2db6256e08d06b753752a0d903a0580acc (diff)
serial: change the divisor latch only when prescalar actually changed
In 8250.c original ns16550 autoconfig code, we change the divisor latch when we goto to high speed mode, we're assuming the previous speed is legacy. This some times is not true. For example in a system with both CONFIG_SERIAL_8250 and CONFIG_SERIAL_8250_PNP set, in this case, the code (autoconfig) will be called twice, one in serial8250_init/probe() and the other is from serial_pnp_probe. When serial_pnp_probe calls the autoconfig for NS16550A, it's already in high speed mode, change the divisor latch (quot << 3) in this case will make the UART console garbled. CC: Greg Kroah-Hartman <greg@kroah.com> CC: David Woodhouse <dwmw2@infradead.org> CC: linux-kernel@vger.kernel.org CC: stable@kernel.org Signed-off-by: Yin Kangkai <kangkai.yin@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/serial/8250.c32
1 files changed, 20 insertions, 12 deletions
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
index c10a6a909c76..b3b881bc4712 100644
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -954,6 +954,23 @@ static int broken_efr(struct uart_8250_port *up)
954 return 0; 954 return 0;
955} 955}
956 956
957static inline int ns16550a_goto_highspeed(struct uart_8250_port *up)
958{
959 unsigned char status;
960
961 status = serial_in(up, 0x04); /* EXCR2 */
962#define PRESL(x) ((x) & 0x30)
963 if (PRESL(status) == 0x10) {
964 /* already in high speed mode */
965 return 0;
966 } else {
967 status &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
968 status |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
969 serial_outp(up, 0x04, status);
970 }
971 return 1;
972}
973
957/* 974/*
958 * We know that the chip has FIFOs. Does it have an EFR? The 975 * We know that the chip has FIFOs. Does it have an EFR? The
959 * EFR is located in the same register position as the IIR and 976 * EFR is located in the same register position as the IIR and
@@ -1025,12 +1042,8 @@ static void autoconfig_16550a(struct uart_8250_port *up)
1025 quot = serial_dl_read(up); 1042 quot = serial_dl_read(up);
1026 quot <<= 3; 1043 quot <<= 3;
1027 1044
1028 status1 = serial_in(up, 0x04); /* EXCR2 */ 1045 if (ns16550a_goto_highspeed(up))
1029 status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ 1046 serial_dl_write(up, quot);
1030 status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
1031 serial_outp(up, 0x04, status1);
1032
1033 serial_dl_write(up, quot);
1034 1047
1035 serial_outp(up, UART_LCR, 0); 1048 serial_outp(up, UART_LCR, 0);
1036 1049
@@ -3025,15 +3038,10 @@ void serial8250_resume_port(int line)
3025 struct uart_8250_port *up = &serial8250_ports[line]; 3038 struct uart_8250_port *up = &serial8250_ports[line];
3026 3039
3027 if (up->capabilities & UART_NATSEMI) { 3040 if (up->capabilities & UART_NATSEMI) {
3028 unsigned char tmp;
3029
3030 /* Ensure it's still in high speed mode */ 3041 /* Ensure it's still in high speed mode */
3031 serial_outp(up, UART_LCR, 0xE0); 3042 serial_outp(up, UART_LCR, 0xE0);
3032 3043
3033 tmp = serial_in(up, 0x04); /* EXCR2 */ 3044 ns16550a_goto_highspeed(up);
3034 tmp &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
3035 tmp |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
3036 serial_outp(up, 0x04, tmp);
3037 3045
3038 serial_outp(up, UART_LCR, 0); 3046 serial_outp(up, UART_LCR, 0);
3039 up->port.uartclk = 921600*16; 3047 up->port.uartclk = 921600*16;