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

Commit 00fad1d1 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

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

parents 1eb0d559 066e1cac
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,