Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d0a86e9c authored by Mukesh Kumar Savaliya's avatar Mukesh Kumar Savaliya
Browse files

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: default avatarMukesh Kumar Savaliya <msavaliy@codeaurora.org>
parent c7448bfb
Loading
Loading
Loading
Loading
+38 −2
Original line number Diff line number Diff line
@@ -1171,6 +1171,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;
@@ -1972,6 +2004,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);
@@ -2063,8 +2097,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);
@@ -2075,6 +2109,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);