diff options
Diffstat (limited to 'kernel/drivers/tty/serial/serial-tegra.c')
-rw-r--r-- | kernel/drivers/tty/serial/serial-tegra.c | 240 |
1 files changed, 119 insertions, 121 deletions
diff --git a/kernel/drivers/tty/serial/serial-tegra.c b/kernel/drivers/tty/serial/serial-tegra.c index 1d5ea3964..1d6fc60ed 100644 --- a/kernel/drivers/tty/serial/serial-tegra.c +++ b/kernel/drivers/tty/serial/serial-tegra.c @@ -131,8 +131,8 @@ struct tegra_uart_port { struct dma_async_tx_descriptor *rx_dma_desc; dma_cookie_t tx_cookie; dma_cookie_t rx_cookie; - int tx_bytes_requested; - int rx_bytes_requested; + unsigned int tx_bytes_requested; + unsigned int rx_bytes_requested; }; static void tegra_uart_start_next_tx(struct tegra_uart_port *tup); @@ -186,7 +186,6 @@ static void set_rts(struct tegra_uart_port *tup, bool active) tegra_uart_write(tup, mcr, UART_MCR); tup->mcr_shadow = mcr; } - return; } static void set_dtr(struct tegra_uart_port *tup, bool active) @@ -202,7 +201,6 @@ static void set_dtr(struct tegra_uart_port *tup, bool active) tegra_uart_write(tup, mcr, UART_MCR); tup->mcr_shadow = mcr; } - return; } static void tegra_uart_set_mctrl(struct uart_port *u, unsigned int mctrl) @@ -217,7 +215,6 @@ static void tegra_uart_set_mctrl(struct uart_port *u, unsigned int mctrl) dtr_enable = !!(mctrl & TIOCM_DTR); set_dtr(tup, dtr_enable); - return; } static void tegra_uart_break_ctl(struct uart_port *u, int break_ctl) @@ -234,6 +231,22 @@ static void tegra_uart_break_ctl(struct uart_port *u, int break_ctl) tup->lcr_shadow = lcr; } +/** + * tegra_uart_wait_cycle_time: Wait for N UART clock periods + * + * @tup: Tegra serial port data structure. + * @cycles: Number of clock periods to wait. + * + * Tegra UARTs are clocked at 16X the baud/bit rate and hence the UART + * clock speed is 16X the current baud rate. + */ +static void tegra_uart_wait_cycle_time(struct tegra_uart_port *tup, + unsigned int cycles) +{ + if (tup->current_baud) + udelay(DIV_ROUND_UP(cycles * 1000000, tup->current_baud * 16)); +} + /* Wait for a symbol-time. */ static void tegra_uart_wait_sym_time(struct tegra_uart_port *tup, unsigned int syms) @@ -263,8 +276,12 @@ static void tegra_uart_fifo_reset(struct tegra_uart_port *tup, u8 fcr_bits) /* Dummy read to ensure the write is posted */ tegra_uart_read(tup, UART_SCR); - /* Wait for the flush to propagate. */ - tegra_uart_wait_sym_time(tup, 1); + /* + * For all tegra devices (up to t210), there is a hardware issue that + * requires software to wait for 32 UART clock periods for the flush + * to propagate, otherwise data could be lost. + */ + tegra_uart_wait_cycle_time(tup, 32); } static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud) @@ -388,9 +405,9 @@ static void tegra_uart_tx_dma_complete(void *args) struct circ_buf *xmit = &tup->uport.state->xmit; struct dma_tx_state state; unsigned long flags; - int count; + unsigned int count; - dmaengine_tx_status(tup->tx_dma_chan, tup->rx_cookie, &state); + dmaengine_tx_status(tup->tx_dma_chan, tup->tx_cookie, &state); count = tup->tx_bytes_requested - state.residue; async_tx_ack(tup->tx_dma_desc); spin_lock_irqsave(&tup->uport.lock, flags); @@ -480,7 +497,7 @@ static void tegra_uart_stop_tx(struct uart_port *u) struct tegra_uart_port *tup = to_tegra_uport(u); struct circ_buf *xmit = &tup->uport.state->xmit; struct dma_tx_state state; - int count; + unsigned int count; if (tup->tx_in_progress != TEGRA_UART_TX_DMA) return; @@ -491,7 +508,6 @@ static void tegra_uart_stop_tx(struct uart_port *u) async_tx_ack(tup->tx_dma_desc); xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); tup->tx_in_progress = 0; - return; } static void tegra_uart_handle_tx_pio(struct tegra_uart_port *tup) @@ -503,7 +519,6 @@ static void tegra_uart_handle_tx_pio(struct tegra_uart_port *tup) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&tup->uport); tegra_uart_start_next_tx(tup); - return; } static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup, @@ -525,15 +540,18 @@ static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup, if (!uart_handle_sysrq_char(&tup->uport, ch) && tty) tty_insert_flip_char(tty, ch, flag); } while (1); - - return; } static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup, - struct tty_port *tty, int count) + struct tty_port *tty, + unsigned int count) { int copied; + /* If count is zero, then there is no data to be copied */ + if (!count) + return; + tup->uport.icount.rx += count; if (!tty) { dev_err(tup->uport.dev, "No tty port\n"); @@ -551,71 +569,69 @@ static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup, TEGRA_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE); } +static void tegra_uart_rx_buffer_push(struct tegra_uart_port *tup, + unsigned int residue) +{ + struct tty_port *port = &tup->uport.state->port; + struct tty_struct *tty = tty_port_tty_get(port); + unsigned int count; + + async_tx_ack(tup->rx_dma_desc); + count = tup->rx_bytes_requested - residue; + + /* If we are here, DMA is stopped */ + tegra_uart_copy_rx_to_tty(tup, port, count); + + tegra_uart_handle_rx_pio(tup, port); + if (tty) { + tty_flip_buffer_push(port); + tty_kref_put(tty); + } +} + static void tegra_uart_rx_dma_complete(void *args) { struct tegra_uart_port *tup = args; struct uart_port *u = &tup->uport; - int count = tup->rx_bytes_requested; - struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port); - struct tty_port *port = &u->state->port; unsigned long flags; + struct dma_tx_state state; + enum dma_status status; - async_tx_ack(tup->rx_dma_desc); spin_lock_irqsave(&u->lock, flags); + status = dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); + + if (status == DMA_IN_PROGRESS) { + dev_dbg(tup->uport.dev, "RX DMA is in progress\n"); + goto done; + } + /* Deactivate flow control to stop sender */ if (tup->rts_active) set_rts(tup, false); - /* If we are here, DMA is stopped */ - if (count) - tegra_uart_copy_rx_to_tty(tup, port, count); - - tegra_uart_handle_rx_pio(tup, port); - if (tty) { - spin_unlock_irqrestore(&u->lock, flags); - tty_flip_buffer_push(port); - spin_lock_irqsave(&u->lock, flags); - tty_kref_put(tty); - } + tegra_uart_rx_buffer_push(tup, 0); tegra_uart_start_rx_dma(tup); /* Activate flow control to start transfer */ if (tup->rts_active) set_rts(tup, true); +done: spin_unlock_irqrestore(&u->lock, flags); } -static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup, - unsigned long *flags) +static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup) { struct dma_tx_state state; - struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port); - struct tty_port *port = &tup->uport.state->port; - struct uart_port *u = &tup->uport; - int count; /* Deactivate flow control to stop sender */ if (tup->rts_active) set_rts(tup, false); dmaengine_terminate_all(tup->rx_dma_chan); - dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); - async_tx_ack(tup->rx_dma_desc); - count = tup->rx_bytes_requested - state.residue; - - /* If we are here, DMA is stopped */ - if (count) - tegra_uart_copy_rx_to_tty(tup, port, count); - - tegra_uart_handle_rx_pio(tup, port); - if (tty) { - spin_unlock_irqrestore(&u->lock, *flags); - tty_flip_buffer_push(port); - spin_lock_irqsave(&u->lock, *flags); - tty_kref_put(tty); - } + dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); + tegra_uart_rx_buffer_push(tup, state.residue); tegra_uart_start_rx_dma(tup); if (tup->rts_active) @@ -663,7 +679,6 @@ static void tegra_uart_handle_modem_signal_change(struct uart_port *u) /* Will start/stop_tx accordingly */ if (msr & UART_MSR_DCTS) uart_handle_cts_change(&tup->uport, msr & UART_MSR_CTS); - return; } static irqreturn_t tegra_uart_isr(int irq, void *data) @@ -680,7 +695,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) iir = tegra_uart_read(tup, UART_IIR); if (iir & UART_IIR_NO_INT) { if (is_rx_int) { - tegra_uart_handle_rx_dma(tup, &flags); + tegra_uart_handle_rx_dma(tup); if (tup->rx_in_progress) { ier = tup->ier_shadow; ier |= (UART_IER_RLSI | UART_IER_RTOIE | @@ -735,11 +750,8 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) static void tegra_uart_stop_rx(struct uart_port *u) { struct tegra_uart_port *tup = to_tegra_uport(u); - struct tty_struct *tty; - struct tty_port *port = &u->state->port; struct dma_tx_state state; unsigned long ier; - int count; if (tup->rts_active) set_rts(tup, false); @@ -747,8 +759,6 @@ static void tegra_uart_stop_rx(struct uart_port *u) if (!tup->rx_in_progress) return; - tty = tty_port_tty_get(&tup->uport.state->port); - tegra_uart_wait_sym_time(tup, 1); /* wait a character interval */ ier = tup->ier_shadow; @@ -757,21 +767,9 @@ static void tegra_uart_stop_rx(struct uart_port *u) tup->ier_shadow = ier; tegra_uart_write(tup, ier, UART_IER); tup->rx_in_progress = 0; - if (tup->rx_dma_chan) { - dmaengine_terminate_all(tup->rx_dma_chan); - dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); - async_tx_ack(tup->rx_dma_desc); - count = tup->rx_bytes_requested - state.residue; - tegra_uart_copy_rx_to_tty(tup, port, count); - tegra_uart_handle_rx_pio(tup, port); - } else { - tegra_uart_handle_rx_pio(tup, port); - } - if (tty) { - tty_flip_buffer_push(port); - tty_kref_put(tty); - } - return; + dmaengine_terminate_all(tup->rx_dma_chan); + dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); + tegra_uart_rx_buffer_push(tup, state.residue); } static void tegra_uart_hw_deinit(struct tegra_uart_port *tup) @@ -865,6 +863,16 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) tup->fcr_shadow |= TEGRA_UART_TX_TRIG_16B; tegra_uart_write(tup, tup->fcr_shadow, UART_FCR); + /* Dummy read to ensure the write is posted */ + tegra_uart_read(tup, UART_SCR); + + /* + * For all tegra devices (up to t210), there is a hardware issue that + * requires software to wait for 3 UART clock periods after enabling + * the TX fifo, otherwise data could be lost. + */ + tegra_uart_wait_cycle_time(tup, 3); + /* * Initialize the UART with default configuration * (115200, N, 8, 1) so that the receive DMA buffer may be @@ -905,6 +913,28 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) return 0; } +static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup, + bool dma_to_memory) +{ + if (dma_to_memory) { + dmaengine_terminate_all(tup->rx_dma_chan); + dma_release_channel(tup->rx_dma_chan); + dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE, + tup->rx_dma_buf_virt, tup->rx_dma_buf_phys); + tup->rx_dma_chan = NULL; + tup->rx_dma_buf_phys = 0; + tup->rx_dma_buf_virt = NULL; + } else { + dmaengine_terminate_all(tup->tx_dma_chan); + dma_release_channel(tup->tx_dma_chan); + dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys, + UART_XMIT_SIZE, DMA_TO_DEVICE); + tup->tx_dma_chan = NULL; + tup->tx_dma_buf_phys = 0; + tup->tx_dma_buf_virt = NULL; + } +} + static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup, bool dma_to_memory) { @@ -933,67 +963,39 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup, dma_release_channel(dma_chan); return -ENOMEM; } + dma_sconfig.src_addr = tup->uport.mapbase; + dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_sconfig.src_maxburst = 4; + tup->rx_dma_chan = dma_chan; + tup->rx_dma_buf_virt = dma_buf; + tup->rx_dma_buf_phys = dma_phys; } else { dma_phys = dma_map_single(tup->uport.dev, tup->uport.state->xmit.buf, UART_XMIT_SIZE, DMA_TO_DEVICE); + if (dma_mapping_error(tup->uport.dev, dma_phys)) { + dev_err(tup->uport.dev, "dma_map_single tx failed\n"); + dma_release_channel(dma_chan); + return -ENOMEM; + } dma_buf = tup->uport.state->xmit.buf; - } - - if (dma_to_memory) { - dma_sconfig.src_addr = tup->uport.mapbase; - dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - dma_sconfig.src_maxburst = 4; - } else { dma_sconfig.dst_addr = tup->uport.mapbase; dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma_sconfig.dst_maxburst = 16; + tup->tx_dma_chan = dma_chan; + tup->tx_dma_buf_virt = dma_buf; + tup->tx_dma_buf_phys = dma_phys; } ret = dmaengine_slave_config(dma_chan, &dma_sconfig); if (ret < 0) { dev_err(tup->uport.dev, "Dma slave config failed, err = %d\n", ret); - goto scrub; + tegra_uart_dma_channel_free(tup, dma_to_memory); + return ret; } - if (dma_to_memory) { - tup->rx_dma_chan = dma_chan; - tup->rx_dma_buf_virt = dma_buf; - tup->rx_dma_buf_phys = dma_phys; - } else { - tup->tx_dma_chan = dma_chan; - tup->tx_dma_buf_virt = dma_buf; - tup->tx_dma_buf_phys = dma_phys; - } return 0; - -scrub: - dma_release_channel(dma_chan); - return ret; -} - -static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup, - bool dma_to_memory) -{ - struct dma_chan *dma_chan; - - if (dma_to_memory) { - dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE, - tup->rx_dma_buf_virt, tup->rx_dma_buf_phys); - dma_chan = tup->rx_dma_chan; - tup->rx_dma_chan = NULL; - tup->rx_dma_buf_phys = 0; - tup->rx_dma_buf_virt = NULL; - } else { - dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys, - UART_XMIT_SIZE, DMA_TO_DEVICE); - dma_chan = tup->tx_dma_chan; - tup->tx_dma_chan = NULL; - tup->tx_dma_buf_phys = 0; - tup->tx_dma_buf_virt = NULL; - } - dma_release_channel(dma_chan); } static int tegra_uart_startup(struct uart_port *u) @@ -1045,7 +1047,6 @@ static void tegra_uart_flush_buffer(struct uart_port *u) tup->tx_bytes = 0; if (tup->tx_dma_chan) dmaengine_terminate_all(tup->tx_dma_chan); - return; } static void tegra_uart_shutdown(struct uart_port *u) @@ -1060,8 +1061,6 @@ static void tegra_uart_shutdown(struct uart_port *u) tegra_uart_dma_channel_free(tup, true); tegra_uart_dma_channel_free(tup, false); free_irq(u->irq, tup); - - tegra_uart_flush_buffer(u); } static void tegra_uart_enable_ms(struct uart_port *u) @@ -1187,7 +1186,6 @@ static void tegra_uart_set_termios(struct uart_port *u, tegra_uart_read(tup, UART_IER); spin_unlock_irqrestore(&u->lock, flags); - return; } static const char *tegra_uart_type(struct uart_port *u) |