summaryrefslogtreecommitdiff
path: root/drivers/serial
diff options
context:
space:
mode:
authorJay Cheng <jacheng@nvidia.com>2010-08-19 07:09:49 -0400
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:35:24 -0800
commit2aa6fd5dbbac14836e052ac50d23b6697c2bf3df (patch)
tree0e246c0a957bdcd34b17e984bb42d2263c26269e /drivers/serial
parente6ff60a24e1fcc165c1b4ae1bace3e32db111928 (diff)
serial: tegra_hsuart: fix receive DMA, RTS, timeout, and tx trigger
initialize baud rate and configuration settings to safe default values when receive DMA is in use, so that the DMA request may be enqueued at initialization time re-enqueue the receive DMA buffer immediately it is dequeued by the DMA threshold callback and the receive ISR, rather than waiting for the DMA complete callback originally fixed by Gary King <gking@nvidia.com> Fixing tx trigger level setting: On tegra uart, the FCR setting for different tx trigger level is not same as the 16550 tx trigger level setting. The tegra uart have the setting in reverse direction on tx fifo attention level: b00 for 16 bytes attention level. b01 for 8 byte attention level. b10 for 4 byte attention level b11 for 1 byte attention level. The rx trigger attention level match with the standard uart FCR register setttings. Also fixing the typo in code when setting DTR. originally fixed by Laxman Dewangan (ldewangan@nvidia.com) Change-Id: Iea00478f143e61c604828035c6c92d614fa7cccb Signed-off-by: Jay Cheng <jacheng@nvidia.com>
Diffstat (limited to 'drivers/serial')
-rw-r--r--drivers/serial/tegra_hsuart.c84
1 files changed, 61 insertions, 23 deletions
diff --git a/drivers/serial/tegra_hsuart.c b/drivers/serial/tegra_hsuart.c
index 2433a8555270..33f4592cf6ac 100644
--- a/drivers/serial/tegra_hsuart.c
+++ b/drivers/serial/tegra_hsuart.c
@@ -73,6 +73,13 @@ const int dma_req_sel[] = {
#define TEGRA_UART_MIN_DMA 16
#define TEGRA_UART_FIFO_SIZE 8
+/* Tx fifo trigger level setting in tegra uart is in
+ * reverse way then conventional uart */
+#define TEGRA_UART_TX_TRIG_16B 0x00
+#define TEGRA_UART_TX_TRIG_8B 0x10
+#define TEGRA_UART_TX_TRIG_4B 0x20
+#define TEGRA_UART_TX_TRIG_1B 0x30
+
struct tegra_uart_port {
struct uart_port uport;
char port_name[32];
@@ -158,7 +165,7 @@ static void tegra_start_pio_tx(struct tegra_uart_port *t, unsigned int bytes)
bytes = TEGRA_UART_FIFO_SIZE;
t->fcr_shadow &= ~UART_FCR_T_TRIG_11;
- t->fcr_shadow |= UART_FCR_T_TRIG_10;
+ t->fcr_shadow |= TEGRA_UART_TX_TRIG_8B;
uart_writeb(t, t->fcr_shadow, UART_FCR);
t->tx_in_progress = TEGRA_TX_PIO;
t->tx_bytes = bytes;
@@ -175,7 +182,7 @@ static void tegra_start_dma_tx(struct tegra_uart_port *t, unsigned long bytes)
UART_XMIT_SIZE, DMA_TO_DEVICE);
t->fcr_shadow &= ~UART_FCR_T_TRIG_11;
- t->fcr_shadow |= UART_FCR_T_TRIG_01;
+ t->fcr_shadow |= TEGRA_UART_TX_TRIG_4B;
uart_writeb(t, t->fcr_shadow, UART_FCR);
t->tx_bytes = bytes & ~(sizeof(u32)-1);
@@ -251,6 +258,10 @@ static void tegra_rx_dma_threshold_callback(struct tegra_dma_req *req)
if (t->rts_active)
set_rts(t, false);
tegra_dma_dequeue(t->rx_dma);
+
+ /* enqueue the request again */
+ tegra_start_dma_rx(t);
+
if (t->rts_active)
set_rts(t, true);
@@ -293,8 +304,6 @@ static void tegra_rx_dma_complete_callback(struct tegra_dma_req *req)
spin_unlock(&u->lock);
tty_flip_buffer_push(u->state->port.tty);
spin_lock(&u->lock);
-
- tegra_start_dma_rx(t);
}
/* Lock already taken */
@@ -303,6 +312,8 @@ static void do_handle_rx_dma(struct tegra_uart_port *t)
if (t->rts_active)
set_rts(t, false);
tegra_dma_dequeue(t->rx_dma);
+ /* enqueue the request again */
+ tegra_start_dma_rx(t);
if (t->rts_active)
set_rts(t, true);
}
@@ -530,6 +541,20 @@ static void tegra_uart_hw_deinit(struct tegra_uart_port *t)
t->baud = 0;
}
+static void tegra_uart_free_rx_dma(struct tegra_uart_port *t)
+{
+ if (!t->use_rx_dma)
+ return;
+
+ tegra_dma_free_channel(t->rx_dma);
+
+ if (likely(t->rx_dma_req.dest_addr))
+ dma_free_coherent(t->uport.dev, t->rx_dma_req.size,
+ t->rx_dma_req.virt_addr, t->rx_dma_req.dest_addr);
+
+ t->use_rx_dma = false;
+}
+
static int tegra_uart_hw_init(struct tegra_uart_port *t)
{
unsigned char fcr;
@@ -557,7 +582,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *t)
uart_writeb(t, fcr, UART_FCR);
udelay(100);
- uart_writeb(t, fcr, UART_FCR);
+ uart_writeb(t, t->fcr_shadow, UART_FCR);
udelay(100);
/* Set the trigger level
@@ -582,12 +607,25 @@ static int tegra_uart_hw_init(struct tegra_uart_port *t)
* programmed in the DMA registers.
* */
t->fcr_shadow |= UART_FCR_R_TRIG_01;
- t->fcr_shadow |= UART_FCR_T_TRIG_10;
+ t->fcr_shadow |= TEGRA_UART_TX_TRIG_8B;
uart_writeb(t, t->fcr_shadow, UART_FCR);
- if (t->use_rx_dma)
- t->fcr_shadow |= UART_FCR_DMA_SELECT;
- uart_writeb(t, t->fcr_shadow, UART_FCR);
+ if (t->use_rx_dma) {
+ /* initialize the UART for a simple default configuration
+ * so that the receive DMA buffer may be enqueued */
+ t->lcr_shadow = 3; /* no parity, stop, 8 data bits */
+ tegra_set_baudrate(t, 9600);
+ t->fcr_shadow |= UART_FCR_DMA_SELECT;
+ uart_writeb(t, t->fcr_shadow, UART_FCR);
+ if (tegra_start_dma_rx(t)) {
+ dev_err(t->uport.dev, "Rx DMA enqueue failed\n");
+ tegra_uart_free_rx_dma(t);
+ t->fcr_shadow &= ~UART_FCR_DMA_SELECT;
+ uart_writeb(t, t->fcr_shadow, UART_FCR);
+ }
+ }
+ else
+ uart_writeb(t, t->fcr_shadow, UART_FCR);
/*
* Enable IE_RXS for the receive status interrupts like line errros.
@@ -656,10 +694,7 @@ static int tegra_uart_init_rx_dma(struct tegra_uart_port *t)
return 0;
fail:
- tegra_dma_free_channel(t->rx_dma);
- if (t->rx_dma_req.dest_addr)
- dma_free_coherent(t->uport.dev, t->rx_dma_req.size,
- t->rx_dma_req.virt_addr, t->rx_dma_req.dest_addr);
+ tegra_uart_free_rx_dma(t);
return -ENODEV;
}
@@ -707,9 +742,6 @@ static int tegra_startup(struct uart_port *u)
if (ret)
goto fail;
- if (t->use_rx_dma)
- tegra_start_dma_rx(t);
-
dev_dbg(u->dev, "Requesting IRQ %d\n", u->irq);
msleep(1);
@@ -738,12 +770,7 @@ static void tegra_shutdown(struct uart_port *u)
tegra_uart_hw_deinit(t);
spin_unlock_irqrestore(&u->lock, flags);
- if (t->use_rx_dma) {
- tegra_dma_free_channel(t->rx_dma);
- dma_free_coherent(u->dev, t->rx_dma_req.size,
- t->rx_dma_req.virt_addr, t->rx_dma_req.dest_addr);
- }
-
+ tegra_uart_free_rx_dma(t);
if (t->use_tx_dma)
tegra_dma_free_channel(t->tx_dma);
@@ -788,7 +815,7 @@ static void set_dtr(struct tegra_uart_port *t, bool active)
if (active)
mcr |= UART_MCR_DTR;
else
- mcr &= UART_MCR_DTR;
+ mcr &= ~UART_MCR_DTR;
if (mcr != t->mcr_shadow) {
uart_writeb(t, mcr, UART_MCR);
t->mcr_shadow = mcr;
@@ -926,6 +953,10 @@ static void tegra_set_termios(struct uart_port *u, struct ktermios *termios,
spin_lock_irqsave(&u->lock, flags);
+ /* Changing configuration, it is safe to stop any rx now */
+ if (t->rts_active)
+ set_rts(t, false);
+
/* Baud rate */
baud = uart_get_baud_rate(u, termios, oldtermios, 200, 4000000);
tegra_set_baudrate(t, baud);
@@ -981,6 +1012,9 @@ static void tegra_set_termios(struct uart_port *u, struct ktermios *termios,
t->mcr_shadow = mcr;
uart_writeb(t, mcr, UART_MCR);
t->use_cts_control = true;
+ /* if top layer has asked to set rts active then do so here */
+ if (t->rts_active)
+ set_rts(t, true);
} else {
mcr = t->mcr_shadow;
mcr &= ~UART_MCR_CTS_EN;
@@ -990,6 +1024,9 @@ static void tegra_set_termios(struct uart_port *u, struct ktermios *termios,
t->use_cts_control = false;
}
+ /* update the port timeout based on new settings */
+ uart_update_timeout(u, termios->c_cflag, baud);
+
spin_unlock_irqrestore(&u->lock, flags);
dev_vdbg(t->uport.dev, "-tegra_set_termios\n");
return;
@@ -1141,6 +1178,7 @@ static int tegra_uart_probe(struct platform_device *pdev)
u->line = pdev->id;
u->ops = &tegra_uart_ops;
u->type = ~PORT_UNKNOWN;
+ u->fifosize = 32;
u->mapbase = pdata->mapbase;
u->membase = pdata->membase;
u->irq = pdata->irq;