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

Commit 066e1cac authored by venkata manasa kakarla's avatar venkata manasa kakarla
Browse files

tty: serial: msm_geni_serial: Add SSR support for SSC QUPs



This change is related to SSC QUP SSR.
Common driver will get initial notification about SSR and
respective bus client driver will get called accordingly for
SSR down and up sequence. For UART this feature gets controlled
with dtsi flag entry per uart node.

Change-Id: I31407dbce4030af8ca71e6f8cc1f113fac821680
Signed-off-by: default avatarvenkata manasa kakarla <venkka@codeaurora.org>
parent d4afd5e4
Loading
Loading
Loading
Loading
+207 −0
Original line number Diff line number Diff line
@@ -132,6 +132,11 @@
#define DMA_RX_BUF_SIZE		(2048)
#define UART_CONSOLE_RX_WM	(2)

struct msm_geni_serial_ssr {
	struct mutex ssr_lock;
	bool is_ssr_down;
};

struct msm_geni_serial_ver_info {
	int hw_major_ver;
	int hw_minor_ver;
@@ -181,6 +186,7 @@ struct msm_geni_serial_port {
	u32 cur_tx_remaining;
	bool startup_in_progress;
	bool pm_auto_suspend_disable;
	struct msm_geni_serial_ssr uart_ssr;
};

static const struct uart_ops msm_geni_serial_pops;
@@ -208,6 +214,8 @@ static int uart_line_id;
static int msm_geni_serial_get_ver_info(struct uart_port *uport);
static void msm_geni_serial_set_manual_flow(bool enable,
				struct msm_geni_serial_port *port);
static int msm_geni_serial_ssr_down(struct device *dev);
static int msm_geni_serial_ssr_up(struct device *dev);

#define GET_DEV_PORT(uport) \
	container_of(uport, struct msm_geni_serial_port, uport)
@@ -310,6 +318,12 @@ static void wait_for_transfers_inflight(struct uart_port *uport)
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
	unsigned int geni_status;

	if (port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(port->ipc_log_misc, "%s: SSR Down event set\n",
			__func__);
		return;
	}

	geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
	/* Possible stop rx is called before this. */
	if (!(geni_status & S_GENI_CMD_ACTIVE))
@@ -445,6 +459,12 @@ static unsigned int msm_geni_serial_get_mctrl(struct uart_port *uport)
	unsigned int mctrl = TIOCM_DSR | TIOCM_CAR;
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);

	if (port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(port->ipc_log_misc, "%s: SSR Down event set\n",
			__func__);
		return 0;
	}

	if (!uart_console(uport) && device_pending_suspend(uport)) {
		IPC_LOG_MSG(port->ipc_log_misc,
				"%s.Device is suspended, %s\n",
@@ -470,6 +490,12 @@ static void msm_geni_serial_set_mctrl(struct uart_port *uport,
	u32 uart_manual_rfr = 0;
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);

	if (port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(port->ipc_log_misc, "%s: SSR Down event set\n",
			__func__);
		return;
	}

	if (device_pending_suspend(uport)) {
		IPC_LOG_MSG(port->ipc_log_misc,
			"%s.Device is suspended, %s: mctrl=0x%x\n",
@@ -520,6 +546,14 @@ static int msm_geni_serial_power_on(struct uart_port *uport)
	int ret = 0;
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);

	mutex_lock(&port->uart_ssr.ssr_lock);
	if (port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(port->ipc_log_misc, "%s: SSR Down event set\n",
			__func__);
		mutex_unlock(&port->uart_ssr.ssr_lock);
		return -EINVAL;
	}

	if (!pm_runtime_enabled(uport->dev)) {
		if (pm_runtime_status_suspended(uport->dev)) {
			struct uart_state *state = uport->state;
@@ -550,9 +584,11 @@ static int msm_geni_serial_power_on(struct uart_port *uport)
			WARN_ON_ONCE(1);
			pm_runtime_put_noidle(uport->dev);
			pm_runtime_set_suspended(uport->dev);
			mutex_unlock(&port->uart_ssr.ssr_lock);
			return ret;
		}
	}
	mutex_unlock(&port->uart_ssr.ssr_lock);
	return 0;
}

@@ -665,6 +701,12 @@ static void msm_geni_serial_complete_rx_eot(struct uart_port *uport)
	int poll_done = 0, tries = 0;
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);

	if (port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(port->ipc_log_misc, "%s: SSR Down event set\n",
			__func__);
		return;
	}

	do {
		poll_done = msm_geni_serial_poll_bit(uport, SE_DMA_RX_IRQ_STAT,
								RX_EOT, true);
@@ -918,6 +960,12 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport)
	bool done = 0;
	int ret = 0;

	if (msm_port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: SSR Down event set\n",
			__func__);
		return -EINVAL;
	}

	xmit_size = uart_circ_chars_pending(xmit);
	if (xmit_size < WAKEUP_CHARS)
		uart_write_wakeup(uport);
@@ -978,6 +1026,12 @@ static void msm_geni_serial_start_tx(struct uart_port *uport)
	unsigned int geni_ios;
	static unsigned int ios_log_limit;

	if (msm_port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: SSR Down event set\n",
			__func__);
		return;
	}

	if (!uart_console(uport) && !pm_runtime_active(uport->dev)) {
		IPC_LOG_MSG(msm_port->ipc_log_misc,
				"%s.Putting in async RPM vote\n", __func__);
@@ -1034,6 +1088,13 @@ static void msm_geni_serial_tx_fsm_rst(struct uart_port *uport)
	unsigned int tx_irq_en;
	int done = 0;
	int tries = 0;
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);

	if (port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(port->ipc_log_misc, "%s: SSR Down event set\n",
			__func__);
		return;
	}

	tx_irq_en = geni_read_reg_nolog(uport->membase, SE_DMA_TX_IRQ_EN);
	geni_write_reg_nolog(0, uport->membase, SE_DMA_TX_IRQ_EN_SET);
@@ -1055,6 +1116,12 @@ static void stop_tx_sequencer(struct uart_port *uport)
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
	bool done = 0;

	if (port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(port->ipc_log_misc, "%s: SSR Down event set\n",
			__func__);
		return;
	}

	geni_m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN);
	geni_m_irq_en &= ~M_CMD_DONE_EN;
	if (port->xfer_mode == FIFO_MODE) {
@@ -1143,6 +1210,12 @@ static void start_rx_sequencer(struct uart_port *uport)
	if (port->startup_in_progress)
		return;

	if (port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(port->ipc_log_misc, "%s: SSR Down event set\n",
			__func__);
		return;
	}

	geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
	IPC_LOG_MSG(port->ipc_log_misc, "%s: 0x%x\n",
		    __func__, geni_status);
@@ -1220,6 +1293,13 @@ static void msm_geni_serial_rx_fsm_rst(struct uart_port *uport)
	unsigned int rx_irq_en;
	int done = 0;
	int tries = 0;
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);

	if (port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(port->ipc_log_misc, "%s: SSR Down event set\n",
			__func__);
		return;
	}

	rx_irq_en = geni_read_reg_nolog(uport->membase, SE_DMA_RX_IRQ_EN);
	geni_write_reg_nolog(0, uport->membase, SE_DMA_RX_IRQ_EN_SET);
@@ -1239,6 +1319,12 @@ static void msm_geni_serial_set_manual_flow(bool enable,
{
	u32 uart_manual_rfr = 0;

	if (port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(port->ipc_log_misc, "%s: SSR Down event set\n",
			__func__);
		return;
	}

	if (!enable) {
		uart_manual_rfr |= (UART_MANUAL_RFR_EN);
		geni_write_reg_nolog(uart_manual_rfr, port->uport.membase,
@@ -1275,6 +1361,13 @@ static void stop_rx_sequencer(struct uart_port *uport)
	u32 irq_clear = S_CMD_CANCEL_EN;
	bool done;

	IPC_LOG_MSG(port->ipc_log_misc, "%s\n", __func__);
	if (port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(port->ipc_log_misc, "%s: SSR Down event set\n",
			__func__);
		return;
	}

	if (port->xfer_mode == FIFO_MODE) {
		geni_s_irq_en = geni_read_reg_nolog(uport->membase,
							SE_GENI_S_IRQ_EN);
@@ -1422,6 +1515,12 @@ static int msm_geni_serial_handle_tx(struct uart_port *uport, bool done,
	int temp_tail = 0;
	int irq_en;

	if (msm_port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: SSR Down event set\n",
				__func__);
		return -EINVAL;
	}

	tx_fifo_status = geni_read_reg_nolog(uport->membase,
					SE_GENI_TX_FIFO_STATUS);

@@ -1466,6 +1565,13 @@ static int msm_geni_serial_handle_tx(struct uart_port *uport, bool done,
		unsigned int buf = 0;
		int c;

		if (msm_port->uart_ssr.is_ssr_down) {
			ret = -EINVAL;
			IPC_LOG_MSG(msm_port->ipc_log_misc,
				"%s.SSR Down event set\n", __func__);
			goto exit_ssr;
		}

		tx_bytes = ((bytes_remaining < fifo_width_bytes) ?
					bytes_remaining : fifo_width_bytes);

@@ -1504,6 +1610,8 @@ static int msm_geni_serial_handle_tx(struct uart_port *uport, bool done,

	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
		uart_write_wakeup(uport);

exit_ssr:
	return ret;
}

@@ -1515,6 +1623,12 @@ static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx)
	int ret;
	unsigned int geni_status;

	if (msm_port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: SSR Down event set\n",
				__func__);
		return -EINVAL;
	}

	geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
	/* Possible stop rx is called */
	if (!(geni_status & S_GENI_CMD_ACTIVE)) {
@@ -1558,6 +1672,12 @@ static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx)
			msm_port->rx_buf, DMA_RX_BUF_SIZE, &msm_port->rx_dma);
	if (ret)
		IPC_LOG_MSG(msm_port->ipc_log_rx, "%s: %d\n", __func__, ret);

	if (msm_port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: SSR Down event set\n",
				__func__);
		return -EINVAL;
	}
	return ret;
}

@@ -1566,6 +1686,12 @@ static int msm_geni_serial_handle_dma_tx(struct uart_port *uport)
	struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
	struct circ_buf *xmit = &uport->state->xmit;

	if (msm_port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: SSR Down event set\n",
				__func__);
		return -EINVAL;
	}

	xmit->tail = (xmit->tail + msm_port->xmit_size) & (UART_XMIT_SIZE - 1);
	geni_se_tx_dma_unprep(msm_port->wrapper_dev, msm_port->tx_dma,
				msm_port->xmit_size);
@@ -1605,6 +1731,26 @@ static irqreturn_t msm_geni_serial_isr(int isr, void *dev)
	struct tty_port *tport = &uport->state->port;
	bool drop_rx = false;

	if (msm_port->uart_ssr.is_ssr_down) {
		m_irq_status = geni_read_reg_nolog(uport->membase,
							SE_GENI_M_IRQ_STATUS);
		s_irq_status = geni_read_reg_nolog(uport->membase,
							SE_GENI_S_IRQ_STATUS);
		geni_write_reg_nolog(m_irq_status, uport->membase,
							SE_GENI_M_IRQ_CLEAR);
		geni_write_reg_nolog(s_irq_status, uport->membase,
							SE_GENI_S_IRQ_CLEAR);
		if (dma_tx_status)
			geni_write_reg_nolog(dma_tx_status, uport->membase,
						SE_DMA_TX_IRQ_CLR);
		if (dma_rx_status)
			geni_write_reg_nolog(dma_rx_status, uport->membase,
						SE_DMA_RX_IRQ_CLR);
		IPC_LOG_MSG(msm_port->ipc_log_misc,
					"%s.SSR Down event set\n", __func__);
		return IRQ_HANDLED;
	}

	spin_lock_irqsave(&uport->lock, flags);
	if (uart_console(uport) && uport->suspended) {
		IPC_LOG_MSG(msm_port->console_log,
@@ -2089,6 +2235,15 @@ static void msm_geni_serial_set_termios(struct uart_port *uport,
	spin_lock_irqsave(&uport->lock, flags);
	msm_geni_serial_stop_rx(uport);
	spin_unlock_irqrestore(&uport->lock, flags);

	mutex_lock(&port->uart_ssr.ssr_lock);
	if (port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(port->ipc_log_misc, "%s. SSR Down event set\n",
			__func__);
		mutex_unlock(&port->uart_ssr.ssr_lock);
		return;
	}

	/* baud rate */
	baud = uart_get_baud_rate(uport, termios, old, 300, 4000000);
	port->cur_baud = baud;
@@ -2196,6 +2351,7 @@ static void msm_geni_serial_set_termios(struct uart_port *uport,
	msm_geni_serial_start_rx(uport);
	if (!uart_console(uport))
		msm_geni_serial_power_off(uport);
	mutex_unlock(&port->uart_ssr.ssr_lock);
	return;

}
@@ -2890,6 +3046,19 @@ static int msm_geni_serial_probe(struct platform_device *pdev)

	dev_info(&pdev->dev, "Serial port%d added.FifoSize %d is_console%d\n",
				line, uport->fifosize, is_console);

	/*
	 * SSR functionalities are required for SSC QUP in
	 * Automotive platform only
	 */
	dev_port->serial_rsc.rsc_ssr.ssr_enable = of_property_read_bool(
			pdev->dev.of_node, "ssr-enable");
	dev_port->serial_rsc.rsc_ssr.force_suspend =
			msm_geni_serial_ssr_down;
	dev_port->serial_rsc.rsc_ssr.force_resume =
			msm_geni_serial_ssr_up;
	mutex_init(&dev_port->uart_ssr.ssr_lock);

	device_create_file(uport->dev, &dev_attr_loopback);
	device_create_file(uport->dev, &dev_attr_xfer_mode);
	device_create_file(uport->dev, &dev_attr_ver_info);
@@ -3115,6 +3284,44 @@ static const struct dev_pm_ops msm_geni_serial_pm_ops = {
	.restore = msm_geni_serial_sys_hib_resume_noirq,
};

static int msm_geni_serial_ssr_down(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct msm_geni_serial_port *port = platform_get_drvdata(pdev);
	struct uart_port *uport = &port->uport;
	int ret = 0;

	mutex_lock(&port->uart_ssr.ssr_lock);
	port->uart_ssr.is_ssr_down = true;
	ret = pm_runtime_force_suspend(uport->dev);
	if (ret) {
		dev_err(uport->dev, "%s:force suspend failed %d\n",
						ret, __func__);
		goto exit;
	}

	pm_runtime_put_noidle(uport->dev);
	pm_runtime_enable(uport->dev);

	IPC_LOG_MSG(port->ipc_log_misc, "%s: Force suspend done\n", __func__);
exit:
	mutex_unlock(&port->uart_ssr.ssr_lock);
	return ret;
}

static int msm_geni_serial_ssr_up(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct msm_geni_serial_port *port = platform_get_drvdata(pdev);

	mutex_lock(&port->uart_ssr.ssr_lock);
	port->uart_ssr.is_ssr_down = false;
	port->port_setup = false;
	IPC_LOG_MSG(port->ipc_log_misc, "%s: Force resume done\n", __func__);
	mutex_unlock(&port->uart_ssr.ssr_lock);
	return 0;
}

static struct platform_driver msm_geni_serial_platform_driver = {
	.remove = msm_geni_serial_remove,
	.probe = msm_geni_serial_probe,