diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2005-11-19 06:10:35 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2005-11-19 06:10:35 -0500 |
commit | b63d4f0fb80918ab37b6c0ee1adcd49e05c9994c (patch) | |
tree | 33af84cc60a0ad29c01632f24cba42eeb498be1a /drivers | |
parent | 811803c5572b296e0031e0099203de90d77c7bcf (diff) |
[SERIAL] Fix status reporting with PL011 serial driver
The receiver status register reports latched error conditions, which
must be cleared by writing to it. However, the data register reports
unlatched conditions which are associated with the current character.
Use the data register to interpret error status rather than the RSR.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/serial/amba-pl011.c | 45 |
1 files changed, 22 insertions, 23 deletions
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 938d185841c9..89d7bd3eaee3 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c | |||
@@ -49,7 +49,6 @@ | |||
49 | #include <linux/serial.h> | 49 | #include <linux/serial.h> |
50 | 50 | ||
51 | #include <asm/io.h> | 51 | #include <asm/io.h> |
52 | #include <asm/irq.h> | ||
53 | #include <asm/sizes.h> | 52 | #include <asm/sizes.h> |
54 | #include <asm/hardware/amba.h> | 53 | #include <asm/hardware/amba.h> |
55 | #include <asm/hardware/clock.h> | 54 | #include <asm/hardware/clock.h> |
@@ -63,7 +62,8 @@ | |||
63 | 62 | ||
64 | #define AMBA_ISR_PASS_LIMIT 256 | 63 | #define AMBA_ISR_PASS_LIMIT 256 |
65 | 64 | ||
66 | #define UART_DUMMY_RSR_RX 256 | 65 | #define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) |
66 | #define UART_DUMMY_DR_RX (1 << 16) | ||
67 | 67 | ||
68 | /* | 68 | /* |
69 | * We wrap our port structure around the generic uart_port. | 69 | * We wrap our port structure around the generic uart_port. |
@@ -116,7 +116,7 @@ pl011_rx_chars(struct uart_amba_port *uap) | |||
116 | #endif | 116 | #endif |
117 | { | 117 | { |
118 | struct tty_struct *tty = uap->port.info->tty; | 118 | struct tty_struct *tty = uap->port.info->tty; |
119 | unsigned int status, ch, flag, rsr, max_count = 256; | 119 | unsigned int status, ch, flag, max_count = 256; |
120 | 120 | ||
121 | status = readw(uap->port.membase + UART01x_FR); | 121 | status = readw(uap->port.membase + UART01x_FR); |
122 | while ((status & UART01x_FR_RXFE) == 0 && max_count--) { | 122 | while ((status & UART01x_FR_RXFE) == 0 && max_count--) { |
@@ -129,7 +129,7 @@ pl011_rx_chars(struct uart_amba_port *uap) | |||
129 | */ | 129 | */ |
130 | } | 130 | } |
131 | 131 | ||
132 | ch = readw(uap->port.membase + UART01x_DR); | 132 | ch = readw(uap->port.membase + UART01x_DR) | UART_DUMMY_DR_RX; |
133 | flag = TTY_NORMAL; | 133 | flag = TTY_NORMAL; |
134 | uap->port.icount.rx++; | 134 | uap->port.icount.rx++; |
135 | 135 | ||
@@ -137,34 +137,33 @@ pl011_rx_chars(struct uart_amba_port *uap) | |||
137 | * Note that the error handling code is | 137 | * Note that the error handling code is |
138 | * out of the main execution path | 138 | * out of the main execution path |
139 | */ | 139 | */ |
140 | rsr = readw(uap->port.membase + UART01x_RSR) | UART_DUMMY_RSR_RX; | 140 | if (unlikely(ch & UART_DR_ERROR)) { |
141 | if (unlikely(rsr & UART01x_RSR_ANY)) { | 141 | if (ch & UART011_DR_BE) { |
142 | if (rsr & UART01x_RSR_BE) { | 142 | ch &= ~(UART011_DR_FE | UART011_DR_PE); |
143 | rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE); | ||
144 | uap->port.icount.brk++; | 143 | uap->port.icount.brk++; |
145 | if (uart_handle_break(&uap->port)) | 144 | if (uart_handle_break(&uap->port)) |
146 | goto ignore_char; | 145 | goto ignore_char; |
147 | } else if (rsr & UART01x_RSR_PE) | 146 | } else if (ch & UART011_DR_PE) |
148 | uap->port.icount.parity++; | 147 | uap->port.icount.parity++; |
149 | else if (rsr & UART01x_RSR_FE) | 148 | else if (ch & UART011_DR_FE) |
150 | uap->port.icount.frame++; | 149 | uap->port.icount.frame++; |
151 | if (rsr & UART01x_RSR_OE) | 150 | if (ch & UART011_DR_OE) |
152 | uap->port.icount.overrun++; | 151 | uap->port.icount.overrun++; |
153 | 152 | ||
154 | rsr &= uap->port.read_status_mask; | 153 | ch &= uap->port.read_status_mask; |
155 | 154 | ||
156 | if (rsr & UART01x_RSR_BE) | 155 | if (ch & UART011_DR_BE) |
157 | flag = TTY_BREAK; | 156 | flag = TTY_BREAK; |
158 | else if (rsr & UART01x_RSR_PE) | 157 | else if (ch & UART011_DR_PE) |
159 | flag = TTY_PARITY; | 158 | flag = TTY_PARITY; |
160 | else if (rsr & UART01x_RSR_FE) | 159 | else if (ch & UART011_DR_FE) |
161 | flag = TTY_FRAME; | 160 | flag = TTY_FRAME; |
162 | } | 161 | } |
163 | 162 | ||
164 | if (uart_handle_sysrq_char(&uap->port, ch, regs)) | 163 | if (uart_handle_sysrq_char(&uap->port, ch, regs)) |
165 | goto ignore_char; | 164 | goto ignore_char; |
166 | 165 | ||
167 | uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag); | 166 | uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); |
168 | 167 | ||
169 | ignore_char: | 168 | ignore_char: |
170 | status = readw(uap->port.membase + UART01x_FR); | 169 | status = readw(uap->port.membase + UART01x_FR); |
@@ -476,33 +475,33 @@ pl011_set_termios(struct uart_port *port, struct termios *termios, | |||
476 | */ | 475 | */ |
477 | uart_update_timeout(port, termios->c_cflag, baud); | 476 | uart_update_timeout(port, termios->c_cflag, baud); |
478 | 477 | ||
479 | port->read_status_mask = UART01x_RSR_OE; | 478 | port->read_status_mask = UART011_DR_OE | 255; |
480 | if (termios->c_iflag & INPCK) | 479 | if (termios->c_iflag & INPCK) |
481 | port->read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; | 480 | port->read_status_mask |= UART011_DR_FE | UART011_DR_PE; |
482 | if (termios->c_iflag & (BRKINT | PARMRK)) | 481 | if (termios->c_iflag & (BRKINT | PARMRK)) |
483 | port->read_status_mask |= UART01x_RSR_BE; | 482 | port->read_status_mask |= UART011_DR_BE; |
484 | 483 | ||
485 | /* | 484 | /* |
486 | * Characters to ignore | 485 | * Characters to ignore |
487 | */ | 486 | */ |
488 | port->ignore_status_mask = 0; | 487 | port->ignore_status_mask = 0; |
489 | if (termios->c_iflag & IGNPAR) | 488 | if (termios->c_iflag & IGNPAR) |
490 | port->ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; | 489 | port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE; |
491 | if (termios->c_iflag & IGNBRK) { | 490 | if (termios->c_iflag & IGNBRK) { |
492 | port->ignore_status_mask |= UART01x_RSR_BE; | 491 | port->ignore_status_mask |= UART011_DR_BE; |
493 | /* | 492 | /* |
494 | * If we're ignoring parity and break indicators, | 493 | * If we're ignoring parity and break indicators, |
495 | * ignore overruns too (for real raw support). | 494 | * ignore overruns too (for real raw support). |
496 | */ | 495 | */ |
497 | if (termios->c_iflag & IGNPAR) | 496 | if (termios->c_iflag & IGNPAR) |
498 | port->ignore_status_mask |= UART01x_RSR_OE; | 497 | port->ignore_status_mask |= UART011_DR_OE; |
499 | } | 498 | } |
500 | 499 | ||
501 | /* | 500 | /* |
502 | * Ignore all characters if CREAD is not set. | 501 | * Ignore all characters if CREAD is not set. |
503 | */ | 502 | */ |
504 | if ((termios->c_cflag & CREAD) == 0) | 503 | if ((termios->c_cflag & CREAD) == 0) |
505 | port->ignore_status_mask |= UART_DUMMY_RSR_RX; | 504 | port->ignore_status_mask |= UART_DUMMY_DR_RX; |
506 | 505 | ||
507 | if (UART_ENABLE_MS(port, termios->c_cflag)) | 506 | if (UART_ENABLE_MS(port, termios->c_cflag)) |
508 | pl011_enable_ms(port); | 507 | pl011_enable_ms(port); |