diff options
author | Mike Frysinger <michael.frysinger@analog.com> | 2007-12-24 06:40:05 -0500 |
---|---|---|
committer | Bryan Wu <cooloney@kernel.org> | 2007-12-24 06:40:05 -0500 |
commit | 0bcfd70ea11a5d6f2362be463513a60245a62baf (patch) | |
tree | fdf47e68cc5fc916da5d985f797b262c36997c4e | |
parent | 4c195ad88b7df54b2e7340dec3446aee6ca84cd1 (diff) |
[Blackfin] serial driver: fix bug - cache the bits of the LSR on systems where the LSR is read-to-clear
Cache the bits of the LSR on systems where the LSR is read-to-clear
so that we can safely read the LSR in random places. this fixes
older parts where break/framing/parity/overflow was not being detected
at all in PIO mode, and this fixes newer parts where
break/framing/parity/overflow was being reported all the time
without being cleared.
Signed-off-by: Mike Frysinger <michael.frysinger@analog.com>
Signed-off-by: Bryan Wu <bryan.wu@analog.com>
-rw-r--r-- | drivers/serial/bfin_5xx.c | 10 | ||||
-rw-r--r-- | include/asm-blackfin/mach-bf527/bfin_serial_5xx.h | 19 | ||||
-rw-r--r-- | include/asm-blackfin/mach-bf533/bfin_serial_5xx.h | 19 | ||||
-rw-r--r-- | include/asm-blackfin/mach-bf537/bfin_serial_5xx.h | 19 | ||||
-rw-r--r-- | include/asm-blackfin/mach-bf548/bfin_serial_5xx.h | 1 | ||||
-rw-r--r-- | include/asm-blackfin/mach-bf561/bfin_serial_5xx.h | 19 |
6 files changed, 80 insertions, 7 deletions
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index ca9ceaa113a2..af84984df775 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c | |||
@@ -216,8 +216,10 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) | |||
216 | struct pt_regs *regs = get_irq_regs(); | 216 | struct pt_regs *regs = get_irq_regs(); |
217 | #endif | 217 | #endif |
218 | 218 | ||
219 | ch = UART_GET_CHAR(uart); | ||
220 | status = UART_GET_LSR(uart); | 219 | status = UART_GET_LSR(uart); |
220 | UART_CLEAR_LSR(uart); | ||
221 | |||
222 | ch = UART_GET_CHAR(uart); | ||
221 | uart->port.icount.rx++; | 223 | uart->port.icount.rx++; |
222 | 224 | ||
223 | #ifdef CONFIG_KGDB_UART | 225 | #ifdef CONFIG_KGDB_UART |
@@ -335,7 +337,7 @@ static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id) | |||
335 | struct bfin_serial_port *uart = dev_id; | 337 | struct bfin_serial_port *uart = dev_id; |
336 | 338 | ||
337 | spin_lock(&uart->port.lock); | 339 | spin_lock(&uart->port.lock); |
338 | while ((UART_GET_IER(uart) & ERBFI) && (UART_GET_LSR(uart) & DR)) | 340 | while (UART_GET_LSR(uart) & DR) |
339 | bfin_serial_rx_chars(uart); | 341 | bfin_serial_rx_chars(uart); |
340 | spin_unlock(&uart->port.lock); | 342 | spin_unlock(&uart->port.lock); |
341 | 343 | ||
@@ -347,7 +349,7 @@ static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id) | |||
347 | struct bfin_serial_port *uart = dev_id; | 349 | struct bfin_serial_port *uart = dev_id; |
348 | 350 | ||
349 | spin_lock(&uart->port.lock); | 351 | spin_lock(&uart->port.lock); |
350 | if ((UART_GET_IER(uart) & ETBEI) && (UART_GET_LSR(uart) & THRE)) | 352 | if (UART_GET_LSR(uart) & THRE) |
351 | bfin_serial_tx_chars(uart); | 353 | bfin_serial_tx_chars(uart); |
352 | spin_unlock(&uart->port.lock); | 354 | spin_unlock(&uart->port.lock); |
353 | 355 | ||
@@ -428,6 +430,8 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) | |||
428 | int i, flg, status; | 430 | int i, flg, status; |
429 | 431 | ||
430 | status = UART_GET_LSR(uart); | 432 | status = UART_GET_LSR(uart); |
433 | UART_CLEAR_LSR(uart); | ||
434 | |||
431 | uart->port.icount.rx += CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, UART_XMIT_SIZE);; | 435 | uart->port.icount.rx += CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, UART_XMIT_SIZE);; |
432 | 436 | ||
433 | if (status & BI) { | 437 | if (status & BI) { |
diff --git a/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h index 15dbc21eed8b..233c585efc1e 100644 --- a/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h +++ b/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h | |||
@@ -23,7 +23,6 @@ | |||
23 | #define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH)) | 23 | #define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH)) |
24 | #define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR)) | 24 | #define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR)) |
25 | #define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR)) | 25 | #define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR)) |
26 | #define UART_GET_LSR(uart) bfin_read16(((uart)->port.membase + OFFSET_LSR)) | ||
27 | #define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL)) | 26 | #define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL)) |
28 | 27 | ||
29 | #define UART_PUT_CHAR(uart, v) bfin_write16(((uart)->port.membase + OFFSET_THR), v) | 28 | #define UART_PUT_CHAR(uart, v) bfin_write16(((uart)->port.membase + OFFSET_THR), v) |
@@ -58,6 +57,7 @@ | |||
58 | struct bfin_serial_port { | 57 | struct bfin_serial_port { |
59 | struct uart_port port; | 58 | struct uart_port port; |
60 | unsigned int old_status; | 59 | unsigned int old_status; |
60 | unsigned int lsr; | ||
61 | #ifdef CONFIG_SERIAL_BFIN_DMA | 61 | #ifdef CONFIG_SERIAL_BFIN_DMA |
62 | int tx_done; | 62 | int tx_done; |
63 | int tx_count; | 63 | int tx_count; |
@@ -76,6 +76,23 @@ struct bfin_serial_port { | |||
76 | #endif | 76 | #endif |
77 | }; | 77 | }; |
78 | 78 | ||
79 | /* The hardware clears the LSR bits upon read, so we need to cache | ||
80 | * some of the more fun bits in software so they don't get lost | ||
81 | * when checking the LSR in other code paths (TX). | ||
82 | */ | ||
83 | static inline unsigned int UART_GET_LSR(struct bfin_serial_port *uart) | ||
84 | { | ||
85 | unsigned int lsr = bfin_read16(uart->port.membase + OFFSET_LSR); | ||
86 | uart->lsr |= (lsr & (BI|FE|PE|OE)); | ||
87 | return lsr | uart->lsr; | ||
88 | } | ||
89 | |||
90 | static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart) | ||
91 | { | ||
92 | uart->lsr = 0; | ||
93 | bfin_write16(uart->port.membase + OFFSET_LSR, -1); | ||
94 | } | ||
95 | |||
79 | struct bfin_serial_port bfin_serial_ports[NR_PORTS]; | 96 | struct bfin_serial_port bfin_serial_ports[NR_PORTS]; |
80 | struct bfin_serial_res { | 97 | struct bfin_serial_res { |
81 | unsigned long uart_base_addr; | 98 | unsigned long uart_base_addr; |
diff --git a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h index 7871d4313f49..b619065ceeb0 100644 --- a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h +++ b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h | |||
@@ -23,7 +23,6 @@ | |||
23 | #define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH)) | 23 | #define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH)) |
24 | #define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR)) | 24 | #define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR)) |
25 | #define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR)) | 25 | #define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR)) |
26 | #define UART_GET_LSR(uart) bfin_read16(((uart)->port.membase + OFFSET_LSR)) | ||
27 | #define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL)) | 26 | #define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL)) |
28 | 27 | ||
29 | #define UART_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v) | 28 | #define UART_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v) |
@@ -46,6 +45,7 @@ | |||
46 | struct bfin_serial_port { | 45 | struct bfin_serial_port { |
47 | struct uart_port port; | 46 | struct uart_port port; |
48 | unsigned int old_status; | 47 | unsigned int old_status; |
48 | unsigned int lsr; | ||
49 | #ifdef CONFIG_SERIAL_BFIN_DMA | 49 | #ifdef CONFIG_SERIAL_BFIN_DMA |
50 | int tx_done; | 50 | int tx_done; |
51 | int tx_count; | 51 | int tx_count; |
@@ -64,6 +64,23 @@ struct bfin_serial_port { | |||
64 | #endif | 64 | #endif |
65 | }; | 65 | }; |
66 | 66 | ||
67 | /* The hardware clears the LSR bits upon read, so we need to cache | ||
68 | * some of the more fun bits in software so they don't get lost | ||
69 | * when checking the LSR in other code paths (TX). | ||
70 | */ | ||
71 | static inline unsigned int UART_GET_LSR(struct bfin_serial_port *uart) | ||
72 | { | ||
73 | unsigned int lsr = bfin_read16(uart->port.membase + OFFSET_LSR); | ||
74 | uart->lsr |= (lsr & (BI|FE|PE|OE)); | ||
75 | return lsr | uart->lsr; | ||
76 | } | ||
77 | |||
78 | static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart) | ||
79 | { | ||
80 | uart->lsr = 0; | ||
81 | bfin_write16(uart->port.membase + OFFSET_LSR, -1); | ||
82 | } | ||
83 | |||
67 | struct bfin_serial_port bfin_serial_ports[NR_PORTS]; | 84 | struct bfin_serial_port bfin_serial_ports[NR_PORTS]; |
68 | struct bfin_serial_res { | 85 | struct bfin_serial_res { |
69 | unsigned long uart_base_addr; | 86 | unsigned long uart_base_addr; |
diff --git a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h index 86e45c379838..f18c517cc935 100644 --- a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h +++ b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h | |||
@@ -23,7 +23,6 @@ | |||
23 | #define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH)) | 23 | #define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH)) |
24 | #define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR)) | 24 | #define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR)) |
25 | #define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR)) | 25 | #define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR)) |
26 | #define UART_GET_LSR(uart) bfin_read16(((uart)->port.membase + OFFSET_LSR)) | ||
27 | #define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL)) | 26 | #define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL)) |
28 | 27 | ||
29 | #define UART_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v) | 28 | #define UART_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v) |
@@ -58,6 +57,7 @@ | |||
58 | struct bfin_serial_port { | 57 | struct bfin_serial_port { |
59 | struct uart_port port; | 58 | struct uart_port port; |
60 | unsigned int old_status; | 59 | unsigned int old_status; |
60 | unsigned int lsr; | ||
61 | #ifdef CONFIG_SERIAL_BFIN_DMA | 61 | #ifdef CONFIG_SERIAL_BFIN_DMA |
62 | int tx_done; | 62 | int tx_done; |
63 | int tx_count; | 63 | int tx_count; |
@@ -76,6 +76,23 @@ struct bfin_serial_port { | |||
76 | #endif | 76 | #endif |
77 | }; | 77 | }; |
78 | 78 | ||
79 | /* The hardware clears the LSR bits upon read, so we need to cache | ||
80 | * some of the more fun bits in software so they don't get lost | ||
81 | * when checking the LSR in other code paths (TX). | ||
82 | */ | ||
83 | static inline unsigned int UART_GET_LSR(struct bfin_serial_port *uart) | ||
84 | { | ||
85 | unsigned int lsr = bfin_read16(uart->port.membase + OFFSET_LSR); | ||
86 | uart->lsr |= (lsr & (BI|FE|PE|OE)); | ||
87 | return lsr | uart->lsr; | ||
88 | } | ||
89 | |||
90 | static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart) | ||
91 | { | ||
92 | uart->lsr = 0; | ||
93 | bfin_write16(uart->port.membase + OFFSET_LSR, -1); | ||
94 | } | ||
95 | |||
79 | struct bfin_serial_port bfin_serial_ports[NR_PORTS]; | 96 | struct bfin_serial_port bfin_serial_ports[NR_PORTS]; |
80 | struct bfin_serial_res { | 97 | struct bfin_serial_res { |
81 | unsigned long uart_base_addr; | 98 | unsigned long uart_base_addr; |
diff --git a/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h index 3770aa38ee9f..8733d47747e5 100644 --- a/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h +++ b/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h | |||
@@ -32,6 +32,7 @@ | |||
32 | #define UART_PUT_DLH(uart,v) bfin_write16(((uart)->port.membase + OFFSET_DLH),v) | 32 | #define UART_PUT_DLH(uart,v) bfin_write16(((uart)->port.membase + OFFSET_DLH),v) |
33 | #define UART_PUT_LSR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_LSR),v) | 33 | #define UART_PUT_LSR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_LSR),v) |
34 | #define UART_PUT_LCR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_LCR),v) | 34 | #define UART_PUT_LCR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_LCR),v) |
35 | #define UART_CLEAR_LSR(uart) bfin_write16(((uart)->port.membase + OFFSET_LSR), -1) | ||
35 | #define UART_PUT_GCTL(uart,v) bfin_write16(((uart)->port.membase + OFFSET_GCTL),v) | 36 | #define UART_PUT_GCTL(uart,v) bfin_write16(((uart)->port.membase + OFFSET_GCTL),v) |
36 | 37 | ||
37 | #if defined(CONFIG_BFIN_UART0_CTSRTS) || defined(CONFIG_BFIN_UART1_CTSRTS) | 38 | #if defined(CONFIG_BFIN_UART0_CTSRTS) || defined(CONFIG_BFIN_UART1_CTSRTS) |
diff --git a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h index 7871d4313f49..b619065ceeb0 100644 --- a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h +++ b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h | |||
@@ -23,7 +23,6 @@ | |||
23 | #define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH)) | 23 | #define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH)) |
24 | #define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR)) | 24 | #define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR)) |
25 | #define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR)) | 25 | #define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR)) |
26 | #define UART_GET_LSR(uart) bfin_read16(((uart)->port.membase + OFFSET_LSR)) | ||
27 | #define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL)) | 26 | #define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL)) |
28 | 27 | ||
29 | #define UART_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v) | 28 | #define UART_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v) |
@@ -46,6 +45,7 @@ | |||
46 | struct bfin_serial_port { | 45 | struct bfin_serial_port { |
47 | struct uart_port port; | 46 | struct uart_port port; |
48 | unsigned int old_status; | 47 | unsigned int old_status; |
48 | unsigned int lsr; | ||
49 | #ifdef CONFIG_SERIAL_BFIN_DMA | 49 | #ifdef CONFIG_SERIAL_BFIN_DMA |
50 | int tx_done; | 50 | int tx_done; |
51 | int tx_count; | 51 | int tx_count; |
@@ -64,6 +64,23 @@ struct bfin_serial_port { | |||
64 | #endif | 64 | #endif |
65 | }; | 65 | }; |
66 | 66 | ||
67 | /* The hardware clears the LSR bits upon read, so we need to cache | ||
68 | * some of the more fun bits in software so they don't get lost | ||
69 | * when checking the LSR in other code paths (TX). | ||
70 | */ | ||
71 | static inline unsigned int UART_GET_LSR(struct bfin_serial_port *uart) | ||
72 | { | ||
73 | unsigned int lsr = bfin_read16(uart->port.membase + OFFSET_LSR); | ||
74 | uart->lsr |= (lsr & (BI|FE|PE|OE)); | ||
75 | return lsr | uart->lsr; | ||
76 | } | ||
77 | |||
78 | static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart) | ||
79 | { | ||
80 | uart->lsr = 0; | ||
81 | bfin_write16(uart->port.membase + OFFSET_LSR, -1); | ||
82 | } | ||
83 | |||
67 | struct bfin_serial_port bfin_serial_ports[NR_PORTS]; | 84 | struct bfin_serial_port bfin_serial_ports[NR_PORTS]; |
68 | struct bfin_serial_res { | 85 | struct bfin_serial_res { |
69 | unsigned long uart_base_addr; | 86 | unsigned long uart_base_addr; |