2008-01-30 09:30:45

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 00/12] Blackfin serial driver updates

- Blackfin on-chip serial driver bug fixing and updates
- Add Blackfin board IRQ requirement in 8250 serial driver


2008-01-30 09:31:16

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 01/12] [8250 Serial Driver]: Added support for 8250-class UARTs in HV Sistemas H8606 board

From: Javier Herrero <[email protected]>

Added support for 8250-class UARTs in HV Sistemas H8606 board,
modification in 8250.c driver for correct compilation with Blackfin

Signed-off-by: Javier Herrero <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/serial/8250.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index f94109c..96c221c 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -1548,6 +1548,10 @@ static int serial_link_irq_chain(struct uart_8250_port *up)
i->head = &up->list;
spin_unlock_irq(&i->lock);

+#ifdef SERIAL_EXTRA_IRQ_FLAGS
+ irq_flags |= SERIAL_EXTRA_IRQ_FLAGS;
+#endif
+
ret = request_irq(up->port.irq, serial8250_interrupt,
irq_flags, "serial", i);
if (ret < 0)
--
1.5.3.4

2008-01-30 09:31:37

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 02/12] [Blackfin] Serial driver: Fix bug - serial driver in PIO mode cant handle input very quickly

From: Sonic Zhang <[email protected]>

Output as many bytes as possible in PIO tx handler.
This reduce the number of tx interrupts and shorten the delay to handle
rx interrupt. So, rx overrun disappears.

Signed-off-by: Sonic Zhang <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/serial/bfin_5xx.c | 62 ++++++++++----------------------------------
1 files changed, 14 insertions(+), 48 deletions(-)

diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index ac2a3ef..e059475 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -74,7 +74,6 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);
#else
static void bfin_serial_do_work(struct work_struct *work);
static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
-static void local_put_char(struct bfin_serial_port *uart, char ch);
#endif

static void bfin_serial_mctrl_check(struct bfin_serial_port *uart);
@@ -85,6 +84,9 @@ static void bfin_serial_mctrl_check(struct bfin_serial_port *uart);
static void bfin_serial_stop_tx(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+#ifndef CONFIG_BF54x
+ unsigned short ier;
+#endif

while (!(UART_GET_LSR(uart) & TEMT))
continue;
@@ -100,8 +102,6 @@ static void bfin_serial_stop_tx(struct uart_port *port)
UART_PUT_LSR(uart, TFI);
UART_CLEAR_IER(uart, ETBEI);
#else
- unsigned short ier;
-
ier = UART_GET_IER(uart);
ier &= ~ETBEI;
UART_PUT_IER(uart, ier);
@@ -210,23 +210,6 @@ int kgdb_get_debug_char(void)
#endif

#ifdef CONFIG_SERIAL_BFIN_PIO
-static void local_put_char(struct bfin_serial_port *uart, char ch)
-{
- unsigned short status;
- int flags = 0;
-
- spin_lock_irqsave(&uart->port.lock, flags);
-
- do {
- status = UART_GET_LSR(uart);
- } while (!(status & THRE));
-
- UART_PUT_CHAR(uart, ch);
- SSYNC();
-
- spin_unlock_irqrestore(&uart->port.lock, flags);
-}
-
static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
{
struct tty_struct *tty = uart->port.info->tty;
@@ -236,8 +219,8 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
struct pt_regs *regs = get_irq_regs();
#endif

- status = UART_GET_LSR(uart);
ch = UART_GET_CHAR(uart);
+ status = UART_GET_LSR(uart);
uart->port.icount.rx++;

#ifdef CONFIG_KGDB_UART
@@ -337,9 +320,12 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
return;
}

- local_put_char(uart, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- uart->port.icount.tx++;
+ while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) {
+ UART_PUT_CHAR(uart, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ uart->port.icount.tx++;
+ SSYNC();
+ }

if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uart->port);
@@ -352,21 +338,11 @@ static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
{
struct bfin_serial_port *uart = dev_id;

-#ifdef CONFIG_BF54x
- unsigned short status;
spin_lock(&uart->port.lock);
- status = UART_GET_LSR(uart);
- while ((UART_GET_IER(uart) & ERBFI) && (status & DR)) {
+ while ((UART_GET_IER(uart) & ERBFI) && (UART_GET_LSR(uart) & DR))
bfin_serial_rx_chars(uart);
- status = UART_GET_LSR(uart);
- }
spin_unlock(&uart->port.lock);
-#else
- spin_lock(&uart->port.lock);
- while ((UART_GET_IIR(uart) & IIR_STATUS) == IIR_RX_READY)
- bfin_serial_rx_chars(uart);
- spin_unlock(&uart->port.lock);
-#endif
+
return IRQ_HANDLED;
}

@@ -374,21 +350,11 @@ static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)
{
struct bfin_serial_port *uart = dev_id;

-#ifdef CONFIG_BF54x
- unsigned short status;
spin_lock(&uart->port.lock);
- status = UART_GET_LSR(uart);
- while ((UART_GET_IER(uart) & ETBEI) && (status & THRE)) {
+ if ((UART_GET_IER(uart) & ETBEI) && (UART_GET_LSR(uart) & THRE))
bfin_serial_tx_chars(uart);
- status = UART_GET_LSR(uart);
- }
spin_unlock(&uart->port.lock);
-#else
- spin_lock(&uart->port.lock);
- while ((UART_GET_IIR(uart) & IIR_STATUS) == IIR_TX_READY)
- bfin_serial_tx_chars(uart);
- spin_unlock(&uart->port.lock);
-#endif
+
return IRQ_HANDLED;
}

--
1.5.3.4

2008-01-30 09:31:58

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 05/12] [Blackfin] serial driver: Fix bug serial driver in DMA mode spams history to console on shell restart

From: Sonic Zhang <[email protected]>

http://blackfin.uclinux.org/gf/project/uclinux-dist/tracker/?action=TrackerItemEdit&tracker_item_id=2920
Fix by increasing buffer tail immediately before starting tx dma.

Signed-off-by: Sonic Zhang <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/serial/bfin_5xx.c | 7 ++++---
1 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 838f491..0074146 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -411,6 +411,10 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
set_dma_x_modify(uart->tx_dma_channel, 1);
enable_dma(uart->tx_dma_channel);
+
+ xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
+ uart->port.icount.tx += uart->tx_count;
+
#ifdef CONFIG_BF54x
UART_SET_IER(uart, ETBEI);
#else
@@ -502,9 +506,6 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
ier &= ~ETBEI;
UART_PUT_IER(uart, ier);
#endif
- xmit->tail = (xmit->tail+uart->tx_count) &(UART_XMIT_SIZE -1);
- uart->port.icount.tx+=uart->tx_count;
-
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uart->port);

--
1.5.3.4

2008-01-30 09:32:30

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 04/12] [Blackfin] serial driver: Fix bug Free rx dma buffer in shutdown.

From: Sonic Zhang <[email protected]>

Kernel crash for the serial driver in DMA mode:
http://blackfin.uclinux.org/gf/project/uclinux-dist/tracker/?action=TrackerItemEdit&tracker_item_id=3679

Signed-off-by: Sonic Zhang <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/serial/bfin_5xx.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 3a2aa7e..838f491 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -704,6 +704,7 @@ static void bfin_serial_shutdown(struct uart_port *port)
disable_dma(uart->rx_dma_channel);
free_dma(uart->rx_dma_channel);
del_timer(&(uart->rx_dma_timer));
+ dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0);
#else
#ifdef CONFIG_KGDB_UART
if (uart->port.line != CONFIG_KGDB_UART_PORT)
--
1.5.3.4

2008-01-30 09:32:56

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 03/12] [Blackfin] serial driver: Clean up UART DMA code.

From: Sonic Zhang <[email protected]>

Start next TX DMA in tx dma handler instead of rx timer handler.

Signed-off-by: Sonic Zhang <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/serial/bfin_5xx.c | 25 ++++++++++---------------
1 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index e059475..3a2aa7e 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -84,7 +84,7 @@ static void bfin_serial_mctrl_check(struct bfin_serial_port *uart);
static void bfin_serial_stop_tx(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-#ifndef CONFIG_BF54x
+#if !defined(CONFIG_BF54x) && !defined(CONFIG_SERIAL_BFIN_DMA)
unsigned short ier;
#endif

@@ -307,7 +307,6 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
UART_PUT_CHAR(uart, uart->port.x_char);
uart->port.icount.tx++;
uart->port.x_char = 0;
- return;
}
/*
* Check the modem control lines before
@@ -376,28 +375,26 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)

if (!uart->tx_done)
return;
-
uart->tx_done = 0;

+ if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
+ bfin_serial_stop_tx(&uart->port);
+ uart->tx_done = 1;
+ return;
+ }
+
if (uart->port.x_char) {
UART_PUT_CHAR(uart, uart->port.x_char);
uart->port.icount.tx++;
uart->port.x_char = 0;
- uart->tx_done = 1;
- return;
}
+
/*
* Check the modem control lines before
* transmitting anything.
*/
bfin_serial_mctrl_check(uart);

- if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
- bfin_serial_stop_tx(&uart->port);
- uart->tx_done = 1;
- return;
- }
-
spin_lock_irqsave(&uart->port.lock, flags);
uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail))
@@ -471,8 +468,6 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
int x_pos, pos;
int flags = 0;

- bfin_serial_dma_tx_chars(uart);
-
spin_lock_irqsave(&uart->port.lock, flags);
x_pos = DMA_RX_XCOUNT - get_dma_curr_xcount(uart->rx_dma_channel);
if (x_pos == DMA_RX_XCOUNT)
@@ -513,9 +508,9 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uart->port);

- if (uart_circ_empty(xmit))
- bfin_serial_stop_tx(&uart->port);
uart->tx_done = 1;
+
+ bfin_serial_dma_tx_chars(uart);
}

spin_unlock(&uart->port.lock);
--
1.5.3.4

2008-01-30 09:33:27

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 06/12] [Blackfin] serial driver: fix bug - should not wait for the TFI bit, just clear it when tx stop.

From: Sonic Zhang <[email protected]>

Signed-off-by: Sonic Zhang <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/serial/bfin_5xx.c | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)

diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 0074146..ca9ceaa 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -95,9 +95,6 @@ static void bfin_serial_stop_tx(struct uart_port *port)
disable_dma(uart->tx_dma_channel);
#else
#ifdef CONFIG_BF54x
- /* Waiting for Transmission Finished */
- while (!(UART_GET_LSR(uart) & TFI))
- continue;
/* Clear TFI bit */
UART_PUT_LSR(uart, TFI);
UART_CLEAR_IER(uart, ETBEI);
--
1.5.3.4

2008-01-30 09:33:57

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 10/12] [Blackfin] serial driver: use simpler comment headers and strip out information that is maintained in the scm's log

From: Mike Frysinger <[email protected]>

Signed-off-by: Mike Frysinger <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/serial/bfin_5xx.c | 27 ++++-----------------------
1 files changed, 4 insertions(+), 23 deletions(-)

diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 50aa3b2..a07df53 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -1,30 +1,11 @@
/*
- * File: drivers/serial/bfin_5xx.c
- * Based on: Based on drivers/serial/sa1100.c
- * Author: Aubrey Li <[email protected]>
+ * Blackfin On-Chip Serial Driver
*
- * Created:
- * Description: Driver for blackfin 5xx serial ports
+ * Copyright 2006-2007 Analog Devices Inc.
*
- * Modified:
- * Copyright 2006 Analog Devices Inc.
+ * Enter bugs at http://blackfin.uclinux.org/
*
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/

#if defined(CONFIG_SERIAL_BFIN_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
--
1.5.3.4

2008-01-30 09:34:32

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 07/12] [Blackfin] serial driver: add extra IRQ flag for 8250 serial driver

From: Javier Herrero <[email protected]>

Signed-off-by: Javier Herrero <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
include/asm-blackfin/serial.h | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
create mode 100644 include/asm-blackfin/serial.h

diff --git a/include/asm-blackfin/serial.h b/include/asm-blackfin/serial.h
new file mode 100644
index 0000000..994dd86
--- /dev/null
+++ b/include/asm-blackfin/serial.h
@@ -0,0 +1,5 @@
+/*
+ * include/asm-blackfin/serial.h
+ */
+
+#define SERIAL_EXTRA_IRQ_FLAGS IRQF_TRIGGER_HIGH
--
1.5.3.4

2008-01-30 09:35:01

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 08/12] [Blackfin] serial driver: fix bug - cache the bits of the LSR on systems where the LSR is read-to-clear

From: Mike Frysinger <[email protected]>

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 <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/serial/bfin_5xx.c | 10 +++++++---
include/asm-blackfin/mach-bf527/bfin_serial_5xx.h | 19 ++++++++++++++++++-
include/asm-blackfin/mach-bf533/bfin_serial_5xx.h | 19 ++++++++++++++++++-
include/asm-blackfin/mach-bf537/bfin_serial_5xx.h | 19 ++++++++++++++++++-
include/asm-blackfin/mach-bf548/bfin_serial_5xx.h | 1 +
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 ca9ceaa..af84984 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)
struct pt_regs *regs = get_irq_regs();
#endif

- ch = UART_GET_CHAR(uart);
status = UART_GET_LSR(uart);
+ UART_CLEAR_LSR(uart);
+
+ ch = UART_GET_CHAR(uart);
uart->port.icount.rx++;

#ifdef CONFIG_KGDB_UART
@@ -335,7 +337,7 @@ static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
struct bfin_serial_port *uart = dev_id;

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);
spin_unlock(&uart->port.lock);

@@ -347,7 +349,7 @@ static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)
struct bfin_serial_port *uart = dev_id;

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);
spin_unlock(&uart->port.lock);

@@ -428,6 +430,8 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
int i, flg, status;

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);;

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 15dbc21..233c585 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 @@
#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_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_PUT_CHAR(uart, v) bfin_write16(((uart)->port.membase + OFFSET_THR), v)
@@ -58,6 +57,7 @@
struct bfin_serial_port {
struct uart_port port;
unsigned int old_status;
+ unsigned int lsr;
#ifdef CONFIG_SERIAL_BFIN_DMA
int tx_done;
int tx_count;
@@ -76,6 +76,23 @@ struct bfin_serial_port {
#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_res {
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 7871d43..b619065 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 @@
#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_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_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v)
@@ -46,6 +45,7 @@
struct bfin_serial_port {
struct uart_port port;
unsigned int old_status;
+ unsigned int lsr;
#ifdef CONFIG_SERIAL_BFIN_DMA
int tx_done;
int tx_count;
@@ -64,6 +64,23 @@ struct bfin_serial_port {
#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_res {
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 86e45c3..f18c517 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 @@
#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_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_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v)
@@ -58,6 +57,7 @@
struct bfin_serial_port {
struct uart_port port;
unsigned int old_status;
+ unsigned int lsr;
#ifdef CONFIG_SERIAL_BFIN_DMA
int tx_done;
int tx_count;
@@ -76,6 +76,23 @@ struct bfin_serial_port {
#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_res {
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 3770aa3..8733d47 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 @@
#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_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)

#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 7871d43..b619065 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 @@
#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_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_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v)
@@ -46,6 +45,7 @@
struct bfin_serial_port {
struct uart_port port;
unsigned int old_status;
+ unsigned int lsr;
#ifdef CONFIG_SERIAL_BFIN_DMA
int tx_done;
int tx_count;
@@ -64,6 +64,23 @@ struct bfin_serial_port {
#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_res {
unsigned long uart_base_addr;
--
1.5.3.4

2008-01-30 09:35:29

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 09/12] [Blackfin] serial driver: rework break flood anomaly handling to be more robust/realistic about what we can actually work around

From: Mike Frysinger <[email protected]>

Signed-off-by: Mike Frysinger <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/serial/bfin_5xx.c | 66 ++++++++++++++++-----
include/asm-blackfin/mach-bf533/bfin_serial_5xx.h | 3 +
include/asm-blackfin/mach-bf561/bfin_serial_5xx.h | 3 +
3 files changed, 58 insertions(+), 14 deletions(-)

diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index af84984..50aa3b2 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -206,12 +206,20 @@ int kgdb_get_debug_char(void)
}
#endif

+#if ANOMALY_05000230 && defined(CONFIG_SERIAL_BFIN_PIO)
+# define UART_GET_ANOMALY_THRESHOLD(uart) ((uart)->anomaly_threshold)
+# define UART_SET_ANOMALY_THRESHOLD(uart, v) ((uart)->anomaly_threshold = (v))
+#else
+# define UART_GET_ANOMALY_THRESHOLD(uart) 0
+# define UART_SET_ANOMALY_THRESHOLD(uart, v)
+#endif
+
#ifdef CONFIG_SERIAL_BFIN_PIO
static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
{
struct tty_struct *tty = uart->port.info->tty;
unsigned int status, ch, flg;
- static int in_break = 0;
+ static struct timeval anomaly_start = { .tv_sec = 0 };
#ifdef CONFIG_KGDB_UART
struct pt_regs *regs = get_irq_regs();
#endif
@@ -244,28 +252,56 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
#endif

if (ANOMALY_05000230) {
- /* The BF533 family of processors have a nice misbehavior where
- * they continuously generate characters for a "single" break.
+ /* The BF533 (and BF561) family of processors have a nice anomaly
+ * where they continuously generate characters for a "single" break.
* We have to basically ignore this flood until the "next" valid
- * character comes across. All other Blackfin families operate
- * properly though.
+ * character comes across. Due to the nature of the flood, it is
+ * not possible to reliably catch bytes that are sent too quickly
+ * after this break. So application code talking to the Blackfin
+ * which sends a break signal must allow at least 1.5 character
+ * times after the end of the break for things to stabilize. This
+ * timeout was picked as it must absolutely be larger than 1
+ * character time +/- some percent. So 1.5 sounds good. All other
+ * Blackfin families operate properly. Woo.
* Note: While Anomaly 05000230 does not directly address this,
* the changes that went in for it also fixed this issue.
+ * That anomaly was fixed in 0.5+ silicon. I like bunnies.
*/
- if (in_break) {
- if (ch != 0) {
- in_break = 0;
- ch = UART_GET_CHAR(uart);
- if (bfin_revid() < 5)
- return;
- } else
- return;
+ if (anomaly_start.tv_sec) {
+ struct timeval curr;
+ suseconds_t usecs;
+
+ if ((~ch & (~ch + 1)) & 0xff)
+ goto known_good_char;
+
+ do_gettimeofday(&curr);
+ if (curr.tv_sec - anomaly_start.tv_sec > 1)
+ goto known_good_char;
+
+ usecs = 0;
+ if (curr.tv_sec != anomaly_start.tv_sec)
+ usecs += USEC_PER_SEC;
+ usecs += curr.tv_usec - anomaly_start.tv_usec;
+
+ if (usecs > UART_GET_ANOMALY_THRESHOLD(uart))
+ goto known_good_char;
+
+ if (ch)
+ anomaly_start.tv_sec = 0;
+ else
+ anomaly_start = curr;
+
+ return;
+
+ known_good_char:
+ anomaly_start.tv_sec = 0;
}
}

if (status & BI) {
if (ANOMALY_05000230)
- in_break = 1;
+ if (bfin_revid() < 5)
+ do_gettimeofday(&anomaly_start);
uart->port.icount.brk++;
if (uart_handle_break(&uart->port))
goto ignore_char;
@@ -778,6 +814,8 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
quot = uart_get_divisor(port, baud);
spin_lock_irqsave(&uart->port.lock, flags);

+ UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15);
+
do {
lsr = UART_GET_LSR(uart);
} while (!(lsr & TEMT));
diff --git a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
index b619065..a1b4f4e 100644
--- a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
@@ -57,6 +57,9 @@ struct bfin_serial_port {
struct work_struct tx_dma_workqueue;
#else
struct work_struct cts_workqueue;
+# if ANOMALY_05000230
+ unsigned int anomaly_threshold;
+# endif
#endif
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
int cts_pin;
diff --git a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
index b619065..a1b4f4e 100644
--- a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
@@ -57,6 +57,9 @@ struct bfin_serial_port {
struct work_struct tx_dma_workqueue;
#else
struct work_struct cts_workqueue;
+# if ANOMALY_05000230
+ unsigned int anomaly_threshold;
+# endif
#endif
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
int cts_pin;
--
1.5.3.4

2008-01-30 09:35:58

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 12/12] [Blackfin] serial driver: Fix bug Poll RTS/CTS status in DMA mode as well

From: Sonic Zhang <[email protected]>

https://blackfin.uclinux.org/gf/project/uclinux-dist/tracker/?action=TrackerItemEdit&tracker_item_id=3858

Signed-off-by: Sonic Zhang <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/serial/bfin_5xx.c | 16 +++++-----------
include/asm-blackfin/mach-bf527/bfin_serial_5xx.h | 3 +--
include/asm-blackfin/mach-bf533/bfin_serial_5xx.h | 2 +-
include/asm-blackfin/mach-bf537/bfin_serial_5xx.h | 3 +--
include/asm-blackfin/mach-bf548/bfin_serial_5xx.h | 3 +--
include/asm-blackfin/mach-bf561/bfin_serial_5xx.h | 2 +-
6 files changed, 10 insertions(+), 19 deletions(-)

diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index a07df53..af866ab 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -53,7 +53,6 @@
#ifdef CONFIG_SERIAL_BFIN_DMA
static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);
#else
-static void bfin_serial_do_work(struct work_struct *work);
static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
#endif

@@ -372,8 +371,9 @@ static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)

return IRQ_HANDLED;
}
+#endif

-
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
static void bfin_serial_do_work(struct work_struct *work)
{
struct bfin_serial_port *uart = container_of(work, struct bfin_serial_port, cts_workqueue);
@@ -607,22 +607,17 @@ static void bfin_serial_mctrl_check(struct bfin_serial_port *uart)
{
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
unsigned int status;
-# ifdef CONFIG_SERIAL_BFIN_DMA
struct uart_info *info = uart->port.info;
struct tty_struct *tty = info->tty;

status = bfin_serial_get_mctrl(&uart->port);
+ uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
if (!(status & TIOCM_CTS)) {
tty->hw_stopped = 1;
+ schedule_work(&uart->cts_workqueue);
} else {
tty->hw_stopped = 0;
}
-# else
- status = bfin_serial_get_mctrl(&uart->port);
- uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
- if (!(status & TIOCM_CTS))
- schedule_work(&uart->cts_workqueue);
-# endif
#endif
}

@@ -939,10 +934,9 @@ static void __init bfin_serial_init_ports(void)
bfin_serial_ports[i].rx_dma_channel =
bfin_serial_resource[i].uart_rx_dma_channel;
init_timer(&(bfin_serial_ports[i].rx_dma_timer));
-#else
- INIT_WORK(&bfin_serial_ports[i].cts_workqueue, bfin_serial_do_work);
#endif
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ INIT_WORK(&bfin_serial_ports[i].cts_workqueue, bfin_serial_do_work);
bfin_serial_ports[i].cts_pin =
bfin_serial_resource[i].uart_cts_pin;
bfin_serial_ports[i].rts_pin =
diff --git a/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
index 233c585..c0694ec 100644
--- a/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
@@ -67,10 +67,9 @@ struct bfin_serial_port {
unsigned int tx_dma_channel;
unsigned int rx_dma_channel;
struct work_struct tx_dma_workqueue;
-#else
- struct work_struct cts_workqueue;
#endif
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ struct work_struct cts_workqueue;
int cts_pin;
int rts_pin;
#endif
diff --git a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
index a1b4f4e..b6f513b 100644
--- a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
@@ -56,12 +56,12 @@ struct bfin_serial_port {
unsigned int rx_dma_channel;
struct work_struct tx_dma_workqueue;
#else
- struct work_struct cts_workqueue;
# if ANOMALY_05000230
unsigned int anomaly_threshold;
# endif
#endif
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ struct work_struct cts_workqueue;
int cts_pin;
int rts_pin;
#endif
diff --git a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
index f18c517..8fc672d 100644
--- a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
@@ -67,10 +67,9 @@ struct bfin_serial_port {
unsigned int tx_dma_channel;
unsigned int rx_dma_channel;
struct work_struct tx_dma_workqueue;
-#else
- struct work_struct cts_workqueue;
#endif
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ struct work_struct cts_workqueue;
int cts_pin;
int rts_pin;
#endif
diff --git a/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
index 8733d47..c459c48 100644
--- a/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
@@ -69,10 +69,9 @@ struct bfin_serial_port {
unsigned int tx_dma_channel;
unsigned int rx_dma_channel;
struct work_struct tx_dma_workqueue;
-#else
- struct work_struct cts_workqueue;
#endif
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ struct work_struct cts_workqueue;
int cts_pin;
int rts_pin;
#endif
diff --git a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
index a1b4f4e..b6f513b 100644
--- a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
@@ -56,12 +56,12 @@ struct bfin_serial_port {
unsigned int rx_dma_channel;
struct work_struct tx_dma_workqueue;
#else
- struct work_struct cts_workqueue;
# if ANOMALY_05000230
unsigned int anomaly_threshold;
# endif
#endif
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ struct work_struct cts_workqueue;
int cts_pin;
int rts_pin;
#endif
--
1.5.3.4

2008-01-30 09:36:22

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 11/12] [Blackfin] serial driver: ADSP-BF52x arch/mach support

From: Michael Hennerich <[email protected]>

Signed-off-by: Michael Hennerich <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/serial/Kconfig | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index d7e1996..27fffa4 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -667,7 +667,7 @@ config UART0_RTS_PIN

config SERIAL_BFIN_UART1
bool "Enable UART1"
- depends on SERIAL_BFIN && (BF534 || BF536 || BF537 || BF54x)
+ depends on SERIAL_BFIN && (BF52x || BF53x || BF54x)
help
Enable UART1

--
1.5.3.4

2008-01-30 21:01:32

by Mike Frysinger

[permalink] [raw]
Subject: Re: [PATCH 11/12] [Blackfin] serial driver: ADSP-BF52x arch/mach support

On Jan 30, 2008 4:30 AM, Bryan Wu <[email protected]> wrote:
> config SERIAL_BFIN_UART1
> bool "Enable UART1"
> - depends on SERIAL_BFIN && (BF534 || BF536 || BF537 || BF54x)
> + depends on SERIAL_BFIN && (BF52x || BF53x || BF54x)
> help
> Enable UART1

erp, i just noticed this is slightly wrong ... BF53x is not OK as the
BF533 family does not have a UART1 ... i committed the fix to our repo
so you can re-post a fixed version of this for inclusion ;)
-mike

2008-01-31 06:47:39

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 11/12 try #2] [Blackfin] serial driver: ADSP-BF52x arch/mach support

>From c7070625a67da75c62bc4ee76417bb89a96b95f6 Mon Sep 17 00:00:00 2001
From: Michael Hennerich <[email protected]>
Date: Thu, 31 Jan 2008 14:44:40 +0800
Subject: [PATCH] [Blackfin] serial driver: ADSP-BF52x arch/mach support

Signed-off-by: Michael Hennerich <[email protected]>
Cc: Mike Frysinger <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/serial/Kconfig | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index d7e1996..5b70d14 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -667,7 +667,7 @@ config UART0_RTS_PIN

config SERIAL_BFIN_UART1
bool "Enable UART1"
- depends on SERIAL_BFIN && (BF534 || BF536 || BF537 || BF54x)
+ depends on SERIAL_BFIN && (!BF531 && !BF532 && !BF533 && !BF561)
help
Enable UART1

--
1.5.3.4