From cb35d91ead269bc7e5525fe38c1cea7deafda2f2 Mon Sep 17 00:00:00 2001 From: Mukesh Kumar Savaliya <msavaliy@codeaurora.org> Date: Tue, 25 Jun 2019 17:28:03 +0530 Subject: [PATCH] serial: msm_geni_serial: Disable Flow before stopping Rx Add manual flow control to disable and enable flow as per the driver need. Basically at the time of stop rx, we do not expect peer device to send any data on RX line. In some cases, peer device is not in sync with client driver and UART driver reads unexpected data. This change just prevents the same. Change-Id: I2bdc70bc68198f441c8e7051c799353abcb4c41c Signed-off-by: Mukesh Kumar Savaliya <msavaliy@codeaurora.org> --- drivers/tty/serial/msm_geni_serial.c | 40 ++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index b542804ff1400..56ecb45f05c6e 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -1094,6 +1094,38 @@ static void msm_geni_serial_rx_fsm_rst(struct uart_port *uport) geni_write_reg_nolog(rx_irq_en, uport->membase, SE_DMA_RX_IRQ_EN_SET); } +static void msm_geni_serial_set_manual_flow(bool enable, + struct msm_geni_serial_port *port) +{ + u32 uart_manual_rfr = 0; + + if (!enable) { + uart_manual_rfr |= (UART_MANUAL_RFR_EN); + geni_write_reg_nolog(uart_manual_rfr, port->uport.membase, + SE_UART_MANUAL_RFR); + /* UART FW needs delay per HW experts recommendation */ + udelay(10); + + uart_manual_rfr |= (UART_RFR_NOT_READY); + geni_write_reg_nolog(uart_manual_rfr, port->uport.membase, + SE_UART_MANUAL_RFR); + /* + * Ensure that the manual flow on writes go through before + * doing a stop_rx. + */ + mb(); + IPC_LOG_MSG(port->ipc_log_pwr, + "%s: Manual Flow Enabled, HW Flow OFF\n", __func__); + } else { + geni_write_reg_nolog(0, port->uport.membase, + SE_UART_MANUAL_RFR); + /* Ensure that the manual flow off writes go through */ + mb(); + IPC_LOG_MSG(port->ipc_log_pwr, + "%s: Manual Flow Disabled, HW Flow ON\n", __func__); + } +} + static void stop_rx_sequencer(struct uart_port *uport) { unsigned int geni_s_irq_en; @@ -1847,6 +1879,8 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, * and FSM_RESET. This also has a potential race with the dma_map/unmap * operations of ISR. */ + disable_irq(uport->irq); + msm_geni_serial_set_manual_flow(false, port); spin_lock_irqsave(&uport->lock, flags); msm_geni_serial_stop_rx(uport); spin_unlock_irqrestore(&uport->lock, flags); @@ -1935,8 +1969,8 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, if (termios->c_cflag & CRTSCTS) { geni_write_reg_nolog(0x0, uport->membase, SE_UART_MANUAL_RFR); - IPC_LOG_MSG(port->ipc_log_misc, "%s: Manual flow off\n", - __func__); + IPC_LOG_MSG(port->ipc_log_misc, + "%s: Manual flow Disabled, HW Flow ON\n", __func__); } IPC_LOG_MSG(port->ipc_log_misc, "%s: baud %d\n", __func__, baud); @@ -1947,6 +1981,8 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, IPC_LOG_MSG(port->ipc_log_misc, "BitsChar%d stop bit%d\n", bits_per_char, stop_bit_len); exit_set_termios: + msm_geni_serial_set_manual_flow(true, port); + enable_irq(uport->irq); msm_geni_serial_start_rx(uport); if (!uart_console(uport)) msm_geni_serial_power_off(uport); -- GitLab