Commit 0bcfd70e authored by Mike Frysinger's avatar Mike Frysinger Committed by Bryan Wu

[Blackfin] serial driver: fix bug - cache the bits of the LSR on systems where...

[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: default avatarMike Frysinger <michael.frysinger@analog.com>
Signed-off-by: default avatarBryan Wu <bryan.wu@analog.com>
parent 4c195ad8
...@@ -216,8 +216,10 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) ...@@ -216,8 +216,10 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
struct pt_regs *regs = get_irq_regs(); struct pt_regs *regs = get_irq_regs();
#endif #endif
ch = UART_GET_CHAR(uart);
status = UART_GET_LSR(uart); status = UART_GET_LSR(uart);
UART_CLEAR_LSR(uart);
ch = UART_GET_CHAR(uart);
uart->port.icount.rx++; uart->port.icount.rx++;
#ifdef CONFIG_KGDB_UART #ifdef CONFIG_KGDB_UART
...@@ -335,7 +337,7 @@ static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id) ...@@ -335,7 +337,7 @@ static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
struct bfin_serial_port *uart = dev_id; struct bfin_serial_port *uart = dev_id;
spin_lock(&uart->port.lock); spin_lock(&uart->port.lock);
while ((UART_GET_IER(uart) & ERBFI) && (UART_GET_LSR(uart) & DR)) while (UART_GET_LSR(uart) & DR)
bfin_serial_rx_chars(uart); bfin_serial_rx_chars(uart);
spin_unlock(&uart->port.lock); spin_unlock(&uart->port.lock);
...@@ -347,7 +349,7 @@ static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id) ...@@ -347,7 +349,7 @@ static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)
struct bfin_serial_port *uart = dev_id; struct bfin_serial_port *uart = dev_id;
spin_lock(&uart->port.lock); spin_lock(&uart->port.lock);
if ((UART_GET_IER(uart) & ETBEI) && (UART_GET_LSR(uart) & THRE)) if (UART_GET_LSR(uart) & THRE)
bfin_serial_tx_chars(uart); bfin_serial_tx_chars(uart);
spin_unlock(&uart->port.lock); spin_unlock(&uart->port.lock);
...@@ -428,6 +430,8 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) ...@@ -428,6 +430,8 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
int i, flg, status; int i, flg, status;
status = UART_GET_LSR(uart); status = UART_GET_LSR(uart);
UART_CLEAR_LSR(uart);
uart->port.icount.rx += CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, UART_XMIT_SIZE);; uart->port.icount.rx += CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, UART_XMIT_SIZE);;
if (status & BI) { if (status & BI) {
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH)) #define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH))
#define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR)) #define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR))
#define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR)) #define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR))
#define UART_GET_LSR(uart) bfin_read16(((uart)->port.membase + OFFSET_LSR))
#define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL)) #define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL))
#define UART_PUT_CHAR(uart, v) bfin_write16(((uart)->port.membase + OFFSET_THR), v) #define UART_PUT_CHAR(uart, v) bfin_write16(((uart)->port.membase + OFFSET_THR), v)
...@@ -58,6 +57,7 @@ ...@@ -58,6 +57,7 @@
struct bfin_serial_port { struct bfin_serial_port {
struct uart_port port; struct uart_port port;
unsigned int old_status; unsigned int old_status;
unsigned int lsr;
#ifdef CONFIG_SERIAL_BFIN_DMA #ifdef CONFIG_SERIAL_BFIN_DMA
int tx_done; int tx_done;
int tx_count; int tx_count;
...@@ -76,6 +76,23 @@ struct bfin_serial_port { ...@@ -76,6 +76,23 @@ struct bfin_serial_port {
#endif #endif
}; };
/* The hardware clears the LSR bits upon read, so we need to cache
* some of the more fun bits in software so they don't get lost
* when checking the LSR in other code paths (TX).
*/
static inline unsigned int UART_GET_LSR(struct bfin_serial_port *uart)
{
unsigned int lsr = bfin_read16(uart->port.membase + OFFSET_LSR);
uart->lsr |= (lsr & (BI|FE|PE|OE));
return lsr | uart->lsr;
}
static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
{
uart->lsr = 0;
bfin_write16(uart->port.membase + OFFSET_LSR, -1);
}
struct bfin_serial_port bfin_serial_ports[NR_PORTS]; struct bfin_serial_port bfin_serial_ports[NR_PORTS];
struct bfin_serial_res { struct bfin_serial_res {
unsigned long uart_base_addr; unsigned long uart_base_addr;
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH)) #define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH))
#define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR)) #define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR))
#define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR)) #define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR))
#define UART_GET_LSR(uart) bfin_read16(((uart)->port.membase + OFFSET_LSR))
#define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL)) #define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL))
#define UART_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v) #define UART_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v)
...@@ -46,6 +45,7 @@ ...@@ -46,6 +45,7 @@
struct bfin_serial_port { struct bfin_serial_port {
struct uart_port port; struct uart_port port;
unsigned int old_status; unsigned int old_status;
unsigned int lsr;
#ifdef CONFIG_SERIAL_BFIN_DMA #ifdef CONFIG_SERIAL_BFIN_DMA
int tx_done; int tx_done;
int tx_count; int tx_count;
...@@ -64,6 +64,23 @@ struct bfin_serial_port { ...@@ -64,6 +64,23 @@ struct bfin_serial_port {
#endif #endif
}; };
/* The hardware clears the LSR bits upon read, so we need to cache
* some of the more fun bits in software so they don't get lost
* when checking the LSR in other code paths (TX).
*/
static inline unsigned int UART_GET_LSR(struct bfin_serial_port *uart)
{
unsigned int lsr = bfin_read16(uart->port.membase + OFFSET_LSR);
uart->lsr |= (lsr & (BI|FE|PE|OE));
return lsr | uart->lsr;
}
static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
{
uart->lsr = 0;
bfin_write16(uart->port.membase + OFFSET_LSR, -1);
}
struct bfin_serial_port bfin_serial_ports[NR_PORTS]; struct bfin_serial_port bfin_serial_ports[NR_PORTS];
struct bfin_serial_res { struct bfin_serial_res {
unsigned long uart_base_addr; unsigned long uart_base_addr;
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH)) #define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH))
#define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR)) #define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR))
#define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR)) #define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR))
#define UART_GET_LSR(uart) bfin_read16(((uart)->port.membase + OFFSET_LSR))
#define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL)) #define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL))
#define UART_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v) #define UART_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v)
...@@ -58,6 +57,7 @@ ...@@ -58,6 +57,7 @@
struct bfin_serial_port { struct bfin_serial_port {
struct uart_port port; struct uart_port port;
unsigned int old_status; unsigned int old_status;
unsigned int lsr;
#ifdef CONFIG_SERIAL_BFIN_DMA #ifdef CONFIG_SERIAL_BFIN_DMA
int tx_done; int tx_done;
int tx_count; int tx_count;
...@@ -76,6 +76,23 @@ struct bfin_serial_port { ...@@ -76,6 +76,23 @@ struct bfin_serial_port {
#endif #endif
}; };
/* The hardware clears the LSR bits upon read, so we need to cache
* some of the more fun bits in software so they don't get lost
* when checking the LSR in other code paths (TX).
*/
static inline unsigned int UART_GET_LSR(struct bfin_serial_port *uart)
{
unsigned int lsr = bfin_read16(uart->port.membase + OFFSET_LSR);
uart->lsr |= (lsr & (BI|FE|PE|OE));
return lsr | uart->lsr;
}
static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
{
uart->lsr = 0;
bfin_write16(uart->port.membase + OFFSET_LSR, -1);
}
struct bfin_serial_port bfin_serial_ports[NR_PORTS]; struct bfin_serial_port bfin_serial_ports[NR_PORTS];
struct bfin_serial_res { struct bfin_serial_res {
unsigned long uart_base_addr; unsigned long uart_base_addr;
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#define UART_PUT_DLH(uart,v) bfin_write16(((uart)->port.membase + OFFSET_DLH),v) #define UART_PUT_DLH(uart,v) bfin_write16(((uart)->port.membase + OFFSET_DLH),v)
#define UART_PUT_LSR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_LSR),v) #define UART_PUT_LSR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_LSR),v)
#define UART_PUT_LCR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_LCR),v) #define UART_PUT_LCR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_LCR),v)
#define UART_CLEAR_LSR(uart) bfin_write16(((uart)->port.membase + OFFSET_LSR), -1)
#define UART_PUT_GCTL(uart,v) bfin_write16(((uart)->port.membase + OFFSET_GCTL),v) #define UART_PUT_GCTL(uart,v) bfin_write16(((uart)->port.membase + OFFSET_GCTL),v)
#if defined(CONFIG_BFIN_UART0_CTSRTS) || defined(CONFIG_BFIN_UART1_CTSRTS) #if defined(CONFIG_BFIN_UART0_CTSRTS) || defined(CONFIG_BFIN_UART1_CTSRTS)
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH)) #define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH))
#define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR)) #define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR))
#define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR)) #define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR))
#define UART_GET_LSR(uart) bfin_read16(((uart)->port.membase + OFFSET_LSR))
#define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL)) #define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL))
#define UART_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v) #define UART_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v)
...@@ -46,6 +45,7 @@ ...@@ -46,6 +45,7 @@
struct bfin_serial_port { struct bfin_serial_port {
struct uart_port port; struct uart_port port;
unsigned int old_status; unsigned int old_status;
unsigned int lsr;
#ifdef CONFIG_SERIAL_BFIN_DMA #ifdef CONFIG_SERIAL_BFIN_DMA
int tx_done; int tx_done;
int tx_count; int tx_count;
...@@ -64,6 +64,23 @@ struct bfin_serial_port { ...@@ -64,6 +64,23 @@ struct bfin_serial_port {
#endif #endif
}; };
/* The hardware clears the LSR bits upon read, so we need to cache
* some of the more fun bits in software so they don't get lost
* when checking the LSR in other code paths (TX).
*/
static inline unsigned int UART_GET_LSR(struct bfin_serial_port *uart)
{
unsigned int lsr = bfin_read16(uart->port.membase + OFFSET_LSR);
uart->lsr |= (lsr & (BI|FE|PE|OE));
return lsr | uart->lsr;
}
static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
{
uart->lsr = 0;
bfin_write16(uart->port.membase + OFFSET_LSR, -1);
}
struct bfin_serial_port bfin_serial_ports[NR_PORTS]; struct bfin_serial_port bfin_serial_ports[NR_PORTS];
struct bfin_serial_res { struct bfin_serial_res {
unsigned long uart_base_addr; unsigned long uart_base_addr;
......
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