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
parent
d781ec21ba
commit
1dce2df3ee
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue