serial: tegra: Add PIO mode support
authorKrishna Yarlagadda <kyarlagadda@nvidia.com>
Wed, 4 Sep 2019 04:43:07 +0000 (10:13 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 Sep 2019 08:00:05 +0000 (10:00 +0200)
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>
drivers/tty/serial/serial-tegra.c

index d0fd417..2f59951 100644 (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;