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

Commit 020642e2 authored by Mukesh Kumar Savaliya's avatar Mukesh Kumar Savaliya
Browse files

serial: msm_geni_serial: Remove manual flow control and set as RFR OPEN



This patch removes the manual flow control and instead gives the RFR
control to the HW depending on the FIFO level. In case of Manual flow
control FW introduced a race and caused RFR to remain High at RX shutdown
which blocked peer device from sending any data.

The latest FW along with this patch makes sure RFR gets configured as an
RFR OPEN post RX cancel and removes the need to have any manual flow. Also
wait for the RX EOT bit post cancel command as per the suggested sequence.

Also Log the GENI FW version for primary and secondary sequencer.

Change-Id: Ifc06a3f1c971eb7490ff8e678779e7163008f999
Signed-off-by: default avatarMukesh Kumar Savaliya <msavaliy@codeaurora.org>
parent ad957023
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -157,6 +157,38 @@ int get_se_proto(void __iomem *base)
}
EXPORT_SYMBOL(get_se_proto);

/**
 * get_se_m_fw() - Read the Firmware ver for the Main seqeuncer engine
 * @base:	Base address of the serial engine's register block.
 *
 * Return:	Firmware version for the Main seqeuncer engine
 */
int get_se_m_fw(void __iomem *base)
{
	int fw_ver_m;

	fw_ver_m = ((geni_read_reg(base, GENI_FW_REVISION_RO)
			& FW_REV_VERSION_MSK));
	return fw_ver_m;
}
EXPORT_SYMBOL(get_se_m_fw);

/**
 * get_se_s_fw() - Read the Firmware ver for the Secondry seqeuncer engine
 * @base:	Base address of the serial engine's register block.
 *
 * Return:	Firmware version for the Secondry seqeuncer engine
 */
int get_se_s_fw(void __iomem *base)
{
	int fw_ver_s;

	fw_ver_s = ((geni_read_reg(base, GENI_FW_S_REVISION_RO)
			& FW_REV_VERSION_MSK));
	return fw_ver_s;
}
EXPORT_SYMBOL(get_se_s_fw);

static int se_geni_irq_en(void __iomem *base)
{
	unsigned int common_geni_m_irq_en;
+44 −27
Original line number Diff line number Diff line
@@ -96,6 +96,7 @@
/* UART S_CMD OP codes */
#define UART_START_READ		(0x1)
#define UART_PARAM		(0x1)
#define UART_PARAM_RFR_OPEN		(BIT(7))

/* UART DMA Rx GP_IRQ_BITS */
#define UART_DMA_RX_PARITY_ERR	BIT(5)
@@ -610,6 +611,27 @@ static void msm_geni_serial_abort_rx(struct uart_port *uport)
	geni_write_reg(FORCE_DEFAULT, uport->membase, GENI_FORCE_DEFAULT_REG);
}

static void msm_geni_serial_complete_rx_eot(struct uart_port *uport)
{
	int poll_done = 0, tries = 0;
	u32 geni_status = 0;
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);

	do {
		poll_done = msm_geni_serial_poll_bit(uport, SE_DMA_RX_IRQ_STAT,
								RX_EOT, true);
		tries++;
	} while (!poll_done && tries < 5);

	geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);

	if (!poll_done)
		IPC_LOG_MSG(port->ipc_log_misc, "%s: RX_EOT, GENI:0x%x\n",
							__func__, geni_status);
	else
		geni_write_reg_nolog(RX_EOT, uport->membase, SE_DMA_RX_IRQ_CLR);
}

#ifdef CONFIG_CONSOLE_POLL
static int msm_geni_serial_get_char(struct uart_port *uport)
{
@@ -996,12 +1018,14 @@ static void start_rx_sequencer(struct uart_port *uport)
	unsigned int geni_status;
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
	int ret;
	u32 geni_se_param = UART_PARAM_RFR_OPEN;

	geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
	if (geni_status & S_GENI_CMD_ACTIVE)
		msm_geni_serial_stop_rx(uport);

	geni_setup_s_cmd(uport->membase, UART_START_READ, 0);
	/* Start RX with the RFR_OPEN to keep RFR in always ready state */
	geni_setup_s_cmd(uport->membase, UART_START_READ, geni_se_param);

	if (port->xfer_mode == FIFO_MODE) {
		geni_s_irq_en = geni_read_reg_nolog(uport->membase,
@@ -1075,7 +1099,7 @@ static void stop_rx_sequencer(struct uart_port *uport)
	unsigned int geni_m_irq_en;
	unsigned int geni_status;
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
	u32 irq_clear = S_CMD_DONE_EN;
	u32 irq_clear = S_CMD_CANCEL_EN;
	bool done;

	IPC_LOG_MSG(port->ipc_log_misc, "%s\n", __func__);
@@ -1097,22 +1121,31 @@ static void stop_rx_sequencer(struct uart_port *uport)
	/* Possible stop rx is called multiple times. */
	if (!(geni_status & S_GENI_CMD_ACTIVE))
		goto exit_rx_seq;

	geni_cancel_s_cmd(uport->membase);
	/*
	 * Ensure that the cancel goes through before polling for the
	 * cancel control bit.
	 */
	mb();
	msm_geni_serial_complete_rx_eot(uport);
	done = msm_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG,
					S_GENI_CMD_CANCEL, false);
	geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
	if (!done)
	if (done) {
		geni_write_reg_nolog(irq_clear, uport->membase,
						SE_GENI_S_IRQ_CLEAR);
		goto exit_rx_seq;
	} else {
		IPC_LOG_MSG(port->ipc_log_misc, "%s Cancel fail 0x%x\n",
						__func__, geni_status);
	}

	geni_write_reg_nolog(irq_clear, uport->membase, SE_GENI_S_IRQ_CLEAR);
	if ((geni_status & S_GENI_CMD_ACTIVE))
	geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
	if ((geni_status & S_GENI_CMD_ACTIVE)) {
		IPC_LOG_MSG(port->ipc_log_misc, "%s:Abort Rx, GENI:0x%x\n",
						__func__, geni_status);
		msm_geni_serial_abort_rx(uport);
	}
exit_rx_seq:
	if (port->xfer_mode == SE_DMA && port->rx_dma) {
		msm_geni_serial_rx_fsm_rst(uport);
@@ -1690,6 +1723,9 @@ static int msm_geni_serial_startup(struct uart_port *uport)
		ret = -ENXIO;
		goto exit_startup;
	}
	IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: FW Ver:0x%x%x\n",
		__func__,
		get_se_m_fw(uport->membase), get_se_s_fw(uport->membase));

	get_tx_fifo_size(msm_port);
	if (!msm_port->port_setup) {
@@ -2514,7 +2550,6 @@ static int msm_geni_serial_runtime_suspend(struct device *dev)
	struct platform_device *pdev = to_platform_device(dev);
	struct msm_geni_serial_port *port = platform_get_drvdata(pdev);
	int ret = 0;
	u32 uart_manual_rfr = 0;
	u32 geni_status = geni_read_reg_nolog(port->uport.membase,
							SE_GENI_STATUS);

@@ -2526,23 +2561,8 @@ static int msm_geni_serial_runtime_suspend(struct device *dev)
	 * Resources off
	 */
	disable_irq(port->uport.irq);
	/*
	 * If the clients haven't done a manual flow on/off then go ahead and
	 * set this to manual flow on.
	 */
	if (!port->manual_flow) {
		uart_manual_rfr |= (UART_MANUAL_RFR_EN | UART_RFR_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 else we could end up flowing off the peer.
		 */
		mb();
		IPC_LOG_MSG(port->ipc_log_pwr, "%s: Manual Flow ON 0x%x\n",
						 __func__, uart_manual_rfr);
	}
	stop_rx_sequencer(&port->uport);
	geni_status = geni_read_reg_nolog(port->uport.membase, SE_GENI_STATUS);
	if ((geni_status & M_GENI_CMD_ACTIVE))
		stop_tx_sequencer(&port->uport);
	ret = se_geni_resources_off(&port->serial_rsc);
@@ -2587,9 +2607,6 @@ static int msm_geni_serial_runtime_resume(struct device *dev)
		goto exit_runtime_resume;
	}
	start_rx_sequencer(&port->uport);
	if (!port->manual_flow)
		geni_write_reg_nolog(0, port->uport.membase,
						SE_UART_MANUAL_RFR);
	/* Ensure that the Rx is running before enabling interrupts */
	mb();
	if (pm_runtime_enabled(dev))
+17 −0
Original line number Diff line number Diff line
@@ -154,6 +154,7 @@ struct se_geni_rsc {
/* FW_REVISION_RO fields */
#define FW_REV_PROTOCOL_MSK	(GENMASK(15, 8))
#define FW_REV_PROTOCOL_SHFT	(8)
#define FW_REV_VERSION_MSK	(GENMASK(7, 0))

/* GENI_CLK_SEL fields */
#define CLK_SEL_MSK		(GENMASK(2, 0))
@@ -404,6 +405,22 @@ void geni_write_reg(unsigned int value, void __iomem *base, int offset);
 */
int get_se_proto(void __iomem *base);

/**
 * get_se_m_fw() - Read the Firmware ver for the Main seqeuncer engine
 * @base:	Base address of the serial engine's register block.
 *
 * Return:	Firmware version for the Main seqeuncer engine
 */
int get_se_m_fw(void __iomem *base);

/**
 * get_se_s_fw() - Read the Firmware ver for the Secondry seqeuncer engine
 * @base:	Base address of the serial engine's register block.
 *
 * Return:	Firmware version for the Secondry seqeuncer engine
 */
int get_se_s_fw(void __iomem *base);

/**
 * geni_se_init() - Initialize the GENI Serial Engine
 * @base:	Base address of the serial engine's register block.