diff options
-rw-r--r-- | drivers/serial/tegra_hsuart.c | 120 |
1 files changed, 79 insertions, 41 deletions
diff --git a/drivers/serial/tegra_hsuart.c b/drivers/serial/tegra_hsuart.c index a8e3a5c93812..4d20df2ce64d 100644 --- a/drivers/serial/tegra_hsuart.c +++ b/drivers/serial/tegra_hsuart.c @@ -41,13 +41,14 @@ #include <linux/debugfs.h> #include <linux/slab.h> #include <mach/dma.h> +#include <mach/clk.h> #define TX_EMPTY_STATUS (UART_LSR_TEMT | UART_LSR_THRE) #define BYTES_TO_ALIGN(x) ((unsigned long)(ALIGN((x), sizeof(u32))) - \ (unsigned long)(x)) -#define UART_RX_DMA_BUFFER_SIZE 2048 +#define UART_RX_DMA_BUFFER_SIZE (2048*4) #define UART_LSR_FIFOE 0x80 #define UART_IER_EORD 0x20 @@ -114,6 +115,7 @@ struct tegra_uart_port { bool use_tx_dma; bool rx_timeout; + int rx_in_progress; }; static inline u8 uart_readb(struct tegra_uart_port *t, unsigned long reg) @@ -143,6 +145,7 @@ static inline void uart_writel(struct tegra_uart_port *t, u32 val, static void tegra_set_baudrate(struct tegra_uart_port *t, unsigned int baud); static void tegra_set_mctrl(struct uart_port *u, unsigned int mctrl); static void do_handle_rx_pio(struct tegra_uart_port *t); +static void do_handle_rx_dma(struct tegra_uart_port *t); static void set_rts(struct tegra_uart_port *t, bool active); static void set_dtr(struct tegra_uart_port *t, bool active); @@ -255,15 +258,7 @@ static void tegra_rx_dma_threshold_callback(struct tegra_dma_req *req) spin_lock_irqsave(&u->lock, flags); - 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); + do_handle_rx_dma(t); spin_unlock_irqrestore(&u->lock, flags); } @@ -296,10 +291,11 @@ static void tegra_rx_dma_complete_callback(struct tegra_dma_req *req) req->bytes_transferred); } - if (t->rx_timeout) { - t->rx_timeout = 0; - do_handle_rx_pio(t); - } + do_handle_rx_pio(t); + + /* Push the read data later in caller place. */ + if (req->status == -TEGRA_DMA_REQ_ERROR_ABORTED) + return; spin_unlock(&u->lock); tty_flip_buffer_push(u->state->port.tty); @@ -309,9 +305,11 @@ static void tegra_rx_dma_complete_callback(struct tegra_dma_req *req) /* Lock already taken */ static void do_handle_rx_dma(struct tegra_uart_port *t) { + struct uart_port *u = &t->uport; if (t->rts_active) set_rts(t, false); tegra_dma_dequeue(t->rx_dma); + tty_flip_buffer_push(u->state->port.tty); /* enqueue the request again */ tegra_start_dma_rx(t); if (t->rts_active) @@ -450,6 +448,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) struct uart_port *u = &t->uport; unsigned char iir; unsigned char ier; + bool is_rx_int = false; unsigned long flags; spin_lock_irqsave(&u->lock, flags); @@ -457,6 +456,16 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) while (1) { iir = uart_readb(t, UART_IIR); if (iir & UART_IIR_NO_INT) { + if (likely(t->use_rx_dma) && is_rx_int) { + do_handle_rx_dma(t); + + if (t->rx_in_progress) { + ier = t->ier_shadow; + ier |= (UART_IER_RLSI | UART_IER_RTOIE | UART_IER_EORD); + t->ier_shadow = ier; + uart_writeb(t, ier, UART_IER); + } + } spin_unlock_irqrestore(&u->lock, flags); return IRQ_HANDLED; } @@ -473,27 +482,26 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) do_handle_tx_pio(t); break; case 4: /* End of data */ - /* As per hw spec, to clear EORD interrupt, we need - * to disable and then re-enable the interrupt. - */ - ier = t->ier_shadow; - ier &= ~UART_IER_EORD; - uart_writeb(t, ier, UART_IER); - ier |= UART_IER_EORD; - uart_writeb(t, ier, UART_IER); - /* fallthrough */ case 6: /* Rx timeout */ - t->rx_timeout = 1; - /* fallthrough */ case 2: /* Receive */ - if (likely(t->use_rx_dma)) - do_handle_rx_dma(t); - else + if (likely(t->use_rx_dma)) { + if (!is_rx_int) { + is_rx_int = true; + /* Disable interrups */ + ier = t->ier_shadow; + ier |= UART_IER_RDI; + uart_writeb(t, ier, UART_IER); + ier &= ~(UART_IER_RDI | UART_IER_RLSI | UART_IER_RTOIE | UART_IER_EORD); + t->ier_shadow = ier; + uart_writeb(t, ier, UART_IER); + } + } else { do_handle_rx_pio(t); - spin_unlock_irqrestore(&u->lock, flags); - tty_flip_buffer_push(u->state->port.tty); - spin_lock_irqsave(&u->lock, flags); + spin_unlock_irqrestore(&u->lock, flags); + tty_flip_buffer_push(u->state->port.tty); + spin_lock_irqsave(&u->lock, flags); + } break; case 3: /* Receive error */ /* FIXME how to handle this? Why do we get here */ @@ -509,13 +517,24 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) static void tegra_stop_rx(struct uart_port *u) { struct tegra_uart_port *t; + unsigned char ier; t = container_of(u, struct tegra_uart_port, uport); if (t->rts_active) set_rts(t, false); - if (t->rx_dma) + + if (t->rx_in_progress) { + ier = t->ier_shadow; + ier &= ~(UART_IER_RDI | UART_IER_RLSI | UART_IER_RTOIE | UART_IER_EORD); + t->ier_shadow = ier; + uart_writeb(t, ier, UART_IER); + t->rx_in_progress = 0; + } + if (t->use_rx_dma && t->rx_dma) { tegra_dma_dequeue(t->rx_dma); + tty_flip_buffer_push(u->state->port.tty); + } return; } @@ -528,14 +547,14 @@ static void tegra_uart_hw_deinit(struct tegra_uart_port *t) uart_writeb(t, 0, UART_IER); while ((uart_readb(t, UART_LSR) & UART_LSR_TEMT) != UART_LSR_TEMT); - udelay(2000); + udelay(200); /* Reset the Rx and Tx FIFOs */ fcr = t->fcr_shadow; fcr |= UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR; uart_writeb(t, fcr, UART_FCR); - udelay(2000); + udelay(200); clk_disable(t->clk); t->baud = 0; @@ -547,10 +566,13 @@ static void tegra_uart_free_rx_dma(struct tegra_uart_port *t) return; tegra_dma_free_channel(t->rx_dma); + t->rx_dma = NULL; 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->rx_dma_req.dest_addr = 0; + t->rx_dma_req.virt_addr = NULL; t->use_rx_dma = false; } @@ -569,7 +591,14 @@ static int tegra_uart_hw_init(struct tegra_uart_port *t) t->baud = 0; clk_enable(t->clk); - msleep(10); + + /* Reset the UART controller to clear all previous status.*/ + tegra_periph_reset_assert(t->clk); + udelay(100); + tegra_periph_reset_deassert(t->clk); + udelay(100); + + t->rx_in_progress = 0; /* Reset the FIFO twice with some delay to make sure that the FIFOs are * really flushed. Wait is needed as the clearing needs to cross @@ -627,6 +656,8 @@ static int tegra_uart_hw_init(struct tegra_uart_port *t) else uart_writeb(t, t->fcr_shadow, UART_FCR); + t->rx_in_progress = 1; + /* * Enable IE_RXS for the receive status interrupts like line errros. * Enable IE_RX_TIMEOUT to get the bytes which cannot be DMA'd. @@ -667,12 +698,10 @@ static int tegra_uart_init_rx_dma(struct tegra_uart_port *t) t->rx_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_CONTINUOUS); if (!t->rx_dma) { - pr_err("%s: failed to allocate RX DMA.\n", __func__); + dev_err(t->uport.dev, "%s: failed to allocate RX DMA.\n", __func__); return -ENODEV; } - memset(&t->rx_dma_req, 0, sizeof(t->rx_dma_req)); - t->rx_dma_req.size = UART_RX_DMA_BUFFER_SIZE; rx_dma_virt = dma_alloc_coherent(t->uport.dev, t->rx_dma_req.size, &rx_dma_phys, GFP_KERNEL); @@ -774,12 +803,20 @@ static void tegra_shutdown(struct uart_port *u) tegra_uart_hw_deinit(t); spin_unlock_irqrestore(&u->lock, flags); + + t->rx_in_progress = 0; + t->tx_in_progress = 0; + tegra_uart_free_rx_dma(t); - if (t->use_tx_dma) + if (t->use_tx_dma) { tegra_dma_free_channel(t->tx_dma); + t->tx_dma = NULL; + t->use_tx_dma = false; + dma_unmap_single(t->uport.dev, t->xmit_dma_addr, UART_XMIT_SIZE, + DMA_TO_DEVICE); + t->xmit_dma_addr = 0; + } - dma_unmap_single(t->uport.dev, t->xmit_dma_addr, UART_XMIT_SIZE, - DMA_TO_DEVICE); free_irq(u->irq, t); dev_vdbg(u->dev, "-tegra_shutdown\n"); } @@ -902,6 +939,7 @@ static void tegra_stop_tx(struct uart_port *u) if (t->use_tx_dma) tegra_dma_dequeue_req(t->tx_dma, &t->tx_dma_req); + t->tx_in_progress = 0; return; } |