#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];
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;
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);
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);
spin_unlock(&u->lock);
tty_flip_buffer_push(u->state->port.tty);
spin_lock(&u->lock);
-
- tegra_start_dma_rx(t);
}
/* Lock already taken */
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);
}
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;
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
* 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.
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;
}
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);
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);
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;
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);
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;
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;
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;