1
0
Fork 0

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>
alistair/sunxi64-5.4-dsi
Krishna Yarlagadda 2019-09-04 10:13:07 +05:30 committed by Greg Kroah-Hartman
parent d781ec21ba
commit 1dce2df3ee
1 changed files with 86 additions and 31 deletions

View File

@ -139,6 +139,8 @@ struct tegra_uart_port {
int n_adjustable_baud_rates; int n_adjustable_baud_rates;
int required_rate; int required_rate;
int configured_rate; int configured_rate;
bool use_rx_pio;
bool use_tx_pio;
}; };
static void tegra_uart_start_next_tx(struct tegra_uart_port *tup); 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) if (!count)
return; return;
if (count < TEGRA_UART_MIN_DMA) if (tup->use_tx_pio || count < TEGRA_UART_MIN_DMA)
tegra_uart_start_pio_tx(tup, count); tegra_uart_start_pio_tx(tup, count);
else if (BYTES_TO_ALIGN(tail) > 0) else if (BYTES_TO_ALIGN(tail) > 0)
tegra_uart_start_pio_tx(tup, BYTES_TO_ALIGN(tail)); 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); 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) static irqreturn_t tegra_uart_isr(int irq, void *data)
{ {
struct tegra_uart_port *tup = data; struct tegra_uart_port *tup = data;
@ -813,7 +827,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)
while (1) { while (1) {
iir = tegra_uart_read(tup, UART_IIR); iir = tegra_uart_read(tup, UART_IIR);
if (iir & UART_IIR_NO_INT) { if (iir & UART_IIR_NO_INT) {
if (is_rx_int) { if (!tup->use_rx_pio && is_rx_int) {
tegra_uart_handle_rx_dma(tup); tegra_uart_handle_rx_dma(tup);
if (tup->rx_in_progress) { if (tup->rx_in_progress) {
ier = tup->ier_shadow; ier = tup->ier_shadow;
@ -841,7 +855,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)
case 4: /* End of data */ case 4: /* End of data */
case 6: /* Rx timeout */ case 6: /* Rx timeout */
case 2: /* Receive */ case 2: /* Receive */
if (!is_rx_int) { if (!tup->use_rx_pio && !is_rx_int) {
is_rx_int = true; is_rx_int = true;
/* Disable Rx interrupts */ /* Disable Rx interrupts */
ier = tup->ier_shadow; 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); UART_IER_RTOIE | TEGRA_UART_IER_EORD);
tup->ier_shadow = ier; tup->ier_shadow = ier;
tegra_uart_write(tup, ier, UART_IER); tegra_uart_write(tup, ier, UART_IER);
} else {
do_handle_rx_pio(tup);
} }
break; 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) static void tegra_uart_stop_rx(struct uart_port *u)
{ {
struct tegra_uart_port *tup = to_tegra_uport(u); struct tegra_uart_port *tup = to_tegra_uport(u);
struct tty_port *port = &tup->uport.state->port;
struct dma_tx_state state; struct dma_tx_state state;
unsigned long ier; unsigned long ier;
@ -886,9 +903,13 @@ static void tegra_uart_stop_rx(struct uart_port *u)
tup->ier_shadow = ier; tup->ier_shadow = ier;
tegra_uart_write(tup, ier, UART_IER); tegra_uart_write(tup, ier, UART_IER);
tup->rx_in_progress = 0; tup->rx_in_progress = 0;
dmaengine_terminate_all(tup->rx_dma_chan); if (tup->rx_dma_chan && !tup->use_rx_pio) {
dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); dmaengine_terminate_all(tup->rx_dma_chan);
tegra_uart_rx_buffer_push(tup, state.residue); 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) 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->rx_in_progress = 0;
tup->tx_in_progress = 0; tup->tx_in_progress = 0;
tegra_uart_dma_channel_free(tup, true); if (!tup->use_rx_pio)
tegra_uart_dma_channel_free(tup, false); 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); 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; tup->fcr_shadow = UART_FCR_ENABLE_FIFO;
if (tup->cdata->max_dma_burst_bytes == 8) if (tup->use_rx_pio) {
tup->fcr_shadow |= UART_FCR_R_TRIG_10; tup->fcr_shadow |= UART_FCR_R_TRIG_11;
else } else {
tup->fcr_shadow |= UART_FCR_R_TRIG_01; 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; tup->fcr_shadow |= TEGRA_UART_TX_TRIG_16B;
tegra_uart_write(tup, tup->fcr_shadow, UART_FCR); 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 * (115200, N, 8, 1) so that the receive DMA buffer may be
* enqueued * enqueued
*/ */
tup->lcr_shadow = TEGRA_UART_DEFAULT_LSR;
ret = tegra_set_baudrate(tup, TEGRA_UART_DEFAULT_BAUD); ret = tegra_set_baudrate(tup, TEGRA_UART_DEFAULT_BAUD);
if (ret < 0) { if (ret < 0) {
dev_err(tup->uport.dev, "Failed to set baud rate\n"); dev_err(tup->uport.dev, "Failed to set baud rate\n");
return ret; return ret;
} }
tup->fcr_shadow |= UART_FCR_DMA_SELECT; if (!tup->use_rx_pio) {
tegra_uart_write(tup, tup->fcr_shadow, UART_FCR); 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); ret = tegra_uart_start_rx_dma(tup);
if (ret < 0) { if (ret < 0) {
dev_err(tup->uport.dev, "Not able to start Rx DMA\n"); dev_err(tup->uport.dev, "Not able to start Rx DMA\n");
return ret; return ret;
}
} else {
tegra_uart_write(tup, tup->fcr_shadow, UART_FCR);
} }
tup->rx_in_progress = 1; 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 * both the EORD as well as RX_TIMEOUT - SW sees RX_TIMEOUT first
* then the EORD. * 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); tegra_uart_write(tup, tup->ier_shadow, UART_IER);
return 0; return 0;
} }
@ -1145,16 +1181,22 @@ static int tegra_uart_startup(struct uart_port *u)
struct tegra_uart_port *tup = to_tegra_uport(u); struct tegra_uart_port *tup = to_tegra_uport(u);
int ret; int ret;
ret = tegra_uart_dma_channel_allocate(tup, false); if (!tup->use_tx_pio) {
if (ret < 0) { ret = tegra_uart_dma_channel_allocate(tup, false);
dev_err(u->dev, "Tx Dma allocation failed, err = %d\n", ret); if (ret < 0) {
return ret; dev_err(u->dev, "Tx Dma allocation failed, err = %d\n",
ret);
return ret;
}
} }
ret = tegra_uart_dma_channel_allocate(tup, true); if (!tup->use_rx_pio) {
if (ret < 0) { ret = tegra_uart_dma_channel_allocate(tup, true);
dev_err(u->dev, "Rx Dma allocation failed, err = %d\n", ret); if (ret < 0) {
goto fail_rx_dma; dev_err(u->dev, "Rx Dma allocation failed, err = %d\n",
ret);
goto fail_rx_dma;
}
} }
ret = tegra_uart_hw_init(tup); ret = tegra_uart_hw_init(tup);
@ -1172,9 +1214,11 @@ static int tegra_uart_startup(struct uart_port *u)
return 0; return 0;
fail_hw_init: 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: fail_rx_dma:
tegra_uart_dma_channel_free(tup, false); if (!tup->use_tx_pio)
tegra_uart_dma_channel_free(tup, false);
return ret; return ret;
} }
@ -1378,7 +1422,6 @@ static int tegra_uart_parse_dt(struct platform_device *pdev,
int count; int count;
int n_entries; int n_entries;
port = of_alias_get_id(np, "serial"); port = of_alias_get_id(np, "serial");
if (port < 0) { if (port < 0) {
dev_err(&pdev->dev, "failed to get alias id, errno %d\n", port); 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, tup->enable_modem_interrupt = of_property_read_bool(np,
"nvidia,enable-modem-interrupt"); "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"); n_entries = of_property_count_u32_elems(np, "nvidia,adjust-baud-rates");
if (n_entries > 0) { if (n_entries > 0) {
tup->n_adjustable_baud_rates = n_entries / 3; tup->n_adjustable_baud_rates = n_entries / 3;