serial: tegra: Add PIO mode support

Add PIO mode support in receive and transmit path with RX interrupt
trigger of 16 bytes for Tegra194 and older chips.

Signed-off-by: Shardar Shariff Md <smohammed@nvidia.com>
Signed-off-by: Krishna Yarlagadda <kyarlagadda@nvidia.com>
Link: https://lore.kernel.org/r/1567572187-29820-13-git-send-email-kyarlagadda@nvidia.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Krishna Yarlagadda 2019-09-04 10:13:07 +05:30 committed by Greg Kroah-Hartman
parent d781ec21ba
commit 1dce2df3ee

View File

@ -139,6 +139,8 @@ struct tegra_uart_port {
int n_adjustable_baud_rates;
int required_rate;
int configured_rate;
bool use_rx_pio;
bool use_tx_pio;
};
static void tegra_uart_start_next_tx(struct tegra_uart_port *tup);
@ -567,7 +569,7 @@ static void tegra_uart_start_next_tx(struct tegra_uart_port *tup)
if (!count)
return;
if (count < TEGRA_UART_MIN_DMA)
if (tup->use_tx_pio || count < TEGRA_UART_MIN_DMA)
tegra_uart_start_pio_tx(tup, count);
else if (BYTES_TO_ALIGN(tail) > 0)
tegra_uart_start_pio_tx(tup, BYTES_TO_ALIGN(tail));
@ -800,6 +802,18 @@ static void tegra_uart_handle_modem_signal_change(struct uart_port *u)
uart_handle_cts_change(&tup->uport, msr & UART_MSR_CTS);
}
static void do_handle_rx_pio(struct tegra_uart_port *tup)
{
struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
struct tty_port *port = &tup->uport.state->port;
tegra_uart_handle_rx_pio(tup, port);
if (tty) {
tty_flip_buffer_push(port);
tty_kref_put(tty);
}
}
static irqreturn_t tegra_uart_isr(int irq, void *data)
{
struct tegra_uart_port *tup = data;
@ -813,7 +827,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)
while (1) {
iir = tegra_uart_read(tup, UART_IIR);
if (iir & UART_IIR_NO_INT) {
if (is_rx_int) {
if (!tup->use_rx_pio && is_rx_int) {
tegra_uart_handle_rx_dma(tup);
if (tup->rx_in_progress) {
ier = tup->ier_shadow;
@ -841,7 +855,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)
case 4: /* End of data */
case 6: /* Rx timeout */
case 2: /* Receive */
if (!is_rx_int) {
if (!tup->use_rx_pio && !is_rx_int) {
is_rx_int = true;
/* Disable Rx interrupts */
ier = tup->ier_shadow;
@ -851,6 +865,8 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)
UART_IER_RTOIE | TEGRA_UART_IER_EORD);
tup->ier_shadow = ier;
tegra_uart_write(tup, ier, UART_IER);
} else {
do_handle_rx_pio(tup);
}
break;
@ -869,6 +885,7 @@ 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_port *port = &tup->uport.state->port;
struct dma_tx_state state;
unsigned long ier;
@ -886,9 +903,13 @@ 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;
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);
if (tup->rx_dma_chan && !tup->use_rx_pio) {
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);
} else {
tegra_uart_handle_rx_pio(tup, port);
}
}
static void tegra_uart_hw_deinit(struct tegra_uart_port *tup)
@ -939,8 +960,10 @@ static void tegra_uart_hw_deinit(struct tegra_uart_port *tup)
tup->rx_in_progress = 0;
tup->tx_in_progress = 0;
tegra_uart_dma_channel_free(tup, true);
tegra_uart_dma_channel_free(tup, false);
if (!tup->use_rx_pio)
tegra_uart_dma_channel_free(tup, true);
if (!tup->use_tx_pio)
tegra_uart_dma_channel_free(tup, false);
clk_disable_unprepare(tup->uart_clk);
}
@ -985,10 +1008,14 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
*/
tup->fcr_shadow = UART_FCR_ENABLE_FIFO;
if (tup->cdata->max_dma_burst_bytes == 8)
tup->fcr_shadow |= UART_FCR_R_TRIG_10;
else
tup->fcr_shadow |= UART_FCR_R_TRIG_01;
if (tup->use_rx_pio) {
tup->fcr_shadow |= UART_FCR_R_TRIG_11;
} else {
if (tup->cdata->max_dma_burst_bytes == 8)
tup->fcr_shadow |= UART_FCR_R_TRIG_10;
else
tup->fcr_shadow |= UART_FCR_R_TRIG_01;
}
tup->fcr_shadow |= TEGRA_UART_TX_TRIG_16B;
tegra_uart_write(tup, tup->fcr_shadow, UART_FCR);
@ -1016,19 +1043,23 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
* (115200, N, 8, 1) so that the receive DMA buffer may be
* enqueued
*/
tup->lcr_shadow = TEGRA_UART_DEFAULT_LSR;
ret = tegra_set_baudrate(tup, TEGRA_UART_DEFAULT_BAUD);
if (ret < 0) {
dev_err(tup->uport.dev, "Failed to set baud rate\n");
return ret;
}
tup->fcr_shadow |= UART_FCR_DMA_SELECT;
tegra_uart_write(tup, tup->fcr_shadow, UART_FCR);
if (!tup->use_rx_pio) {
tup->lcr_shadow = TEGRA_UART_DEFAULT_LSR;
tup->fcr_shadow |= UART_FCR_DMA_SELECT;
tegra_uart_write(tup, tup->fcr_shadow, UART_FCR);
ret = tegra_uart_start_rx_dma(tup);
if (ret < 0) {
dev_err(tup->uport.dev, "Not able to start Rx DMA\n");
return ret;
ret = tegra_uart_start_rx_dma(tup);
if (ret < 0) {
dev_err(tup->uport.dev, "Not able to start Rx DMA\n");
return ret;
}
} else {
tegra_uart_write(tup, tup->fcr_shadow, UART_FCR);
}
tup->rx_in_progress = 1;
@ -1050,7 +1081,12 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
* both the EORD as well as RX_TIMEOUT - SW sees RX_TIMEOUT first
* then the EORD.
*/
tup->ier_shadow = UART_IER_RLSI | UART_IER_RTOIE | TEGRA_UART_IER_EORD;
if (!tup->use_rx_pio)
tup->ier_shadow = UART_IER_RLSI | UART_IER_RTOIE |
TEGRA_UART_IER_EORD;
else
tup->ier_shadow = UART_IER_RLSI | UART_IER_RTOIE | UART_IER_RDI;
tegra_uart_write(tup, tup->ier_shadow, UART_IER);
return 0;
}
@ -1145,16 +1181,22 @@ static int tegra_uart_startup(struct uart_port *u)
struct tegra_uart_port *tup = to_tegra_uport(u);
int ret;
ret = tegra_uart_dma_channel_allocate(tup, false);
if (ret < 0) {
dev_err(u->dev, "Tx Dma allocation failed, err = %d\n", ret);
return ret;
if (!tup->use_tx_pio) {
ret = tegra_uart_dma_channel_allocate(tup, false);
if (ret < 0) {
dev_err(u->dev, "Tx Dma allocation failed, err = %d\n",
ret);
return ret;
}
}
ret = tegra_uart_dma_channel_allocate(tup, true);
if (ret < 0) {
dev_err(u->dev, "Rx Dma allocation failed, err = %d\n", ret);
goto fail_rx_dma;
if (!tup->use_rx_pio) {
ret = tegra_uart_dma_channel_allocate(tup, true);
if (ret < 0) {
dev_err(u->dev, "Rx Dma allocation failed, err = %d\n",
ret);
goto fail_rx_dma;
}
}
ret = tegra_uart_hw_init(tup);
@ -1172,9 +1214,11 @@ static int tegra_uart_startup(struct uart_port *u)
return 0;
fail_hw_init:
tegra_uart_dma_channel_free(tup, true);
if (!tup->use_rx_pio)
tegra_uart_dma_channel_free(tup, true);
fail_rx_dma:
tegra_uart_dma_channel_free(tup, false);
if (!tup->use_tx_pio)
tegra_uart_dma_channel_free(tup, false);
return ret;
}
@ -1378,7 +1422,6 @@ static int tegra_uart_parse_dt(struct platform_device *pdev,
int count;
int n_entries;
port = of_alias_get_id(np, "serial");
if (port < 0) {
dev_err(&pdev->dev, "failed to get alias id, errno %d\n", port);
@ -1388,6 +1431,18 @@ static int tegra_uart_parse_dt(struct platform_device *pdev,
tup->enable_modem_interrupt = of_property_read_bool(np,
"nvidia,enable-modem-interrupt");
index = of_property_match_string(np, "dma-names", "rx");
if (index < 0) {
tup->use_rx_pio = true;
dev_info(&pdev->dev, "RX in PIO mode\n");
}
index = of_property_match_string(np, "dma-names", "tx");
if (index < 0) {
tup->use_tx_pio = true;
dev_info(&pdev->dev, "TX in PIO mode\n");
}
n_entries = of_property_count_u32_elems(np, "nvidia,adjust-baud-rates");
if (n_entries > 0) {
tup->n_adjustable_baud_rates = n_entries / 3;