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

Commit be8e725a authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "serial: msm_geni_serial: Modify the clock on/off sequence for HS-UART"

parents d2ffc9b0 6d97cbc9
Loading
Loading
Loading
Loading
+11 −12
Original line number Diff line number Diff line
@@ -402,7 +402,7 @@ EXPORT_SYMBOL(geni_setup_s_cmd);
 */
void geni_cancel_m_cmd(void __iomem *base)
{
	geni_write_reg(M_GENI_CMD_CANCEL, base, SE_GENI_S_CMD_CTRL_REG);
	geni_write_reg(M_GENI_CMD_CANCEL, base, SE_GENI_M_CMD_CTRL_REG);
}
EXPORT_SYMBOL(geni_cancel_m_cmd);

@@ -684,16 +684,14 @@ int se_geni_resources_off(struct se_geni_rsc *rsc)
	if (unlikely(!geni_se_dev || !geni_se_dev->bus_bw))
		return -ENODEV;

	ret = pinctrl_select_state(rsc->geni_pinctrl, rsc->geni_gpio_sleep);
	if (ret) {
		GENI_SE_ERR(geni_se_dev->log_ctx, false, NULL,
			"%s: Error %d pinctrl_select_state\n", __func__, ret);
		return ret;
	}
	ret = se_geni_clks_off(rsc);
	if (ret)
		GENI_SE_ERR(geni_se_dev->log_ctx, false, NULL,
			"%s: Error %d turning off clocks\n", __func__, ret);
	ret = pinctrl_select_state(rsc->geni_pinctrl, rsc->geni_gpio_sleep);
	if (ret)
		GENI_SE_ERR(geni_se_dev->log_ctx, false, NULL,
			"%s: Error %d pinctrl_select_state\n", __func__, ret);
	return ret;
}
EXPORT_SYMBOL(se_geni_resources_off);
@@ -802,19 +800,20 @@ int se_geni_resources_on(struct se_geni_rsc *rsc)
	if (unlikely(!geni_se_dev))
		return -EPROBE_DEFER;

	ret = se_geni_clks_on(rsc);
	ret = pinctrl_select_state(rsc->geni_pinctrl, rsc->geni_gpio_active);
	if (ret) {
		GENI_SE_ERR(geni_se_dev->log_ctx, false, NULL,
			"%s: Error %d during clks_on\n", __func__, ret);
			"%s: Error %d pinctrl_select_state\n", __func__, ret);
		return ret;
	}

	ret = pinctrl_select_state(rsc->geni_pinctrl, rsc->geni_gpio_active);
	ret = se_geni_clks_on(rsc);
	if (ret) {
		GENI_SE_ERR(geni_se_dev->log_ctx, false, NULL,
			"%s: Error %d pinctrl_select_state\n", __func__, ret);
		se_geni_clks_off(rsc);
			"%s: Error %d during clks_on\n", __func__, ret);
		pinctrl_select_state(rsc->geni_pinctrl, rsc->geni_gpio_sleep);
	}

	return ret;
}
EXPORT_SYMBOL(se_geni_resources_on);
+137 −66
Original line number Diff line number Diff line
@@ -164,6 +164,7 @@ struct msm_geni_serial_port {
	int ioctl_count;
	int edge_count;
	unsigned int tx_yield_count;
	bool manual_flow;
};

static const struct uart_ops msm_geni_serial_pops;
@@ -266,16 +267,18 @@ static bool check_transfers_inflight(struct uart_port *uport)

	/* Possible stop tx is called multiple times. */
	m_cmd_active = geni_status & M_GENI_CMD_ACTIVE;
	if (port->xfer_mode == SE_DMA)
	if (port->xfer_mode == SE_DMA) {
		tx_fifo_status = port->tx_dma ? 1 : 0;
	else
		rx_fifo_status =
			geni_read_reg_nolog(uport->membase, SE_DMA_RX_LEN_IN);
	} else {
		tx_fifo_status = geni_read_reg_nolog(uport->membase,
						SE_GENI_TX_FIFO_STATUS);
	tx_active = m_cmd_active || tx_fifo_status;
		rx_fifo_status = geni_read_reg_nolog(uport->membase,
						SE_GENI_RX_FIFO_STATUS);
	if (rx_fifo_status)
		rx_active = true;
	}
	tx_active = m_cmd_active || tx_fifo_status;
	rx_active =  rx_fifo_status ? true : false;

	if (rx_active || tx_active || !uart_circ_empty(xmit))
		xfer_on = true;
@@ -303,10 +306,12 @@ static void wait_for_transfers_inflight(struct uart_port *uport)
		u32 geni_ios = geni_read_reg_nolog(uport->membase, SE_GENI_IOS);
		u32 rx_fifo_status = geni_read_reg_nolog(uport->membase,
							SE_GENI_RX_FIFO_STATUS);
		u32 rx_dma =
			geni_read_reg_nolog(uport->membase, SE_DMA_RX_LEN_IN);

		IPC_LOG_MSG(port->ipc_log_misc,
			"%s IOS 0x%x geni status 0x%x rx fifo 0x%x\n",
			__func__, geni_ios, geni_status, rx_fifo_status);
			"%s IOS 0x%x geni status 0x%x rx: fifo 0x%x dma 0x%x\n",
		__func__, geni_ios, geni_status, rx_fifo_status, rx_dma);
	}
}

@@ -405,13 +410,9 @@ static unsigned int msm_geni_serial_get_mctrl(struct uart_port *uport)
{
	u32 geni_ios = 0;
	unsigned int mctrl = TIOCM_DSR | TIOCM_CAR;
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);

	if (device_pending_suspend(uport)) {
		IPC_LOG_MSG(port->ipc_log_misc,
				"%s.Device is suspended.\n", __func__);
	if (device_pending_suspend(uport))
		return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS;
	}

	geni_ios = geni_read_reg_nolog(uport->membase, SE_GENI_IOS);
	if (!(geni_ios & IO2_DATA_IN))
@@ -436,8 +437,12 @@ static void msm_geni_serial_set_mctrl(struct uart_port *uport,
				"%s.Device is suspended.\n", __func__);
		return;
	}
	if (!(mctrl & TIOCM_RTS))
	if (!(mctrl & TIOCM_RTS)) {
		uart_manual_rfr |= (UART_MANUAL_RFR_EN | UART_RFR_NOT_READY);
		port->manual_flow = true;
	} else {
		port->manual_flow = false;
	}
	geni_write_reg_nolog(uart_manual_rfr, uport->membase,
							SE_UART_MANUAL_RFR);
	/* Write to flow control must complete before return to client*/
@@ -542,7 +547,7 @@ static int msm_geni_serial_poll_bit(struct uart_port *uport,
		 * Total polling iterations based on FIFO worth of bytes to be
		 * sent at current baud .Add a little fluff to the wait.
		 */
		total_iter = ((fifo_bits * USEC_PER_SEC) / baud);
		total_iter = ((fifo_bits * USEC_PER_SEC) / baud) / 10;
		total_iter += 50;
	}

@@ -920,19 +925,12 @@ static void msm_geni_serial_tx_fsm_rst(struct uart_port *uport)
	geni_write_reg_nolog(tx_irq_en, uport->membase, SE_DMA_TX_IRQ_EN_SET);
}

static void msm_geni_serial_stop_tx(struct uart_port *uport)
static void stop_tx_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);

	if (!uart_console(uport) && device_pending_suspend(uport)) {
		dev_err(uport->dev, "%s.Device is suspended.\n", __func__);
		IPC_LOG_MSG(port->ipc_log_misc,
				"%s.Device is suspended.\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) {
@@ -948,9 +946,7 @@ static void msm_geni_serial_stop_tx(struct uart_port *uport)
		}
	}
	port->xmit_size = 0;

	geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN);

	geni_status = geni_read_reg_nolog(uport->membase,
						SE_GENI_STATUS);
	/* Possible stop tx is called multiple times. */
@@ -970,13 +966,9 @@ static void msm_geni_serial_stop_tx(struct uart_port *uport)
	IPC_LOG_MSG(port->ipc_log_misc, "%s\n", __func__);
}

static void msm_geni_serial_start_rx(struct uart_port *uport)
static void msm_geni_serial_stop_tx(struct uart_port *uport)
{
	unsigned int geni_s_irq_en;
	unsigned int geni_m_irq_en;
	unsigned int geni_status;
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
	int ret;

	if (!uart_console(uport) && device_pending_suspend(uport)) {
		dev_err(uport->dev, "%s.Device is suspended.\n", __func__);
@@ -984,6 +976,16 @@ static void msm_geni_serial_start_rx(struct uart_port *uport)
				"%s.Device is suspended.\n", __func__);
		return;
	}
	stop_tx_sequencer(uport);
}

static void start_rx_sequencer(struct uart_port *uport)
{
	unsigned int geni_s_irq_en;
	unsigned int geni_m_irq_en;
	unsigned int geni_status;
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
	int ret;

	geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
	if (geni_status & S_GENI_CMD_ACTIVE)
@@ -1011,7 +1013,7 @@ static void msm_geni_serial_start_rx(struct uart_port *uport)
			dev_err(uport->dev, "%s: RX Prep dma failed %d\n",
				__func__, ret);
			msm_geni_serial_stop_rx(uport);
			goto exit_geni_serial_start_rx;
			goto exit_start_rx_sequencer;
		}
	}
	/*
@@ -1020,10 +1022,24 @@ static void msm_geni_serial_start_rx(struct uart_port *uport)
	 */
	mb();
	geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
exit_geni_serial_start_rx:
exit_start_rx_sequencer:
	IPC_LOG_MSG(port->ipc_log_misc, "%s 0x%x\n", __func__, geni_status);
}

static void msm_geni_serial_start_rx(struct uart_port *uport)
{
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);

	if (!uart_console(uport) && device_pending_suspend(uport)) {
		dev_err(uport->dev, "%s.Device is suspended.\n", __func__);
		IPC_LOG_MSG(port->ipc_log_misc,
				"%s.Device is suspended.\n", __func__);
		return;
	}
	start_rx_sequencer(&port->uport);
}


static void msm_geni_serial_rx_fsm_rst(struct uart_port *uport)
{
	unsigned int rx_irq_en;
@@ -1043,19 +1059,15 @@ 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_stop_rx(struct uart_port *uport)
static void stop_rx_sequencer(struct uart_port *uport)
{
	unsigned int geni_s_irq_en;
	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;
	bool done;

	if (!uart_console(uport) && device_pending_suspend(uport)) {
		IPC_LOG_MSG(port->ipc_log_misc,
				"%s.Device is suspended.\n", __func__);
		return;
	}
	IPC_LOG_MSG(port->ipc_log_misc, "%s\n", __func__);
	if (port->xfer_mode == FIFO_MODE) {
		geni_s_irq_en = geni_read_reg_nolog(uport->membase,
@@ -1069,28 +1081,47 @@ static void msm_geni_serial_stop_rx(struct uart_port *uport)
							SE_GENI_S_IRQ_EN);
		geni_write_reg_nolog(geni_m_irq_en, uport->membase,
							SE_GENI_M_IRQ_EN);
	} else if (port->xfer_mode == SE_DMA && port->rx_dma) {
		msm_geni_serial_rx_fsm_rst(uport);
		geni_se_rx_dma_unprep(port->wrapper_dev, port->rx_dma,
						      DMA_RX_BUF_SIZE);
		port->rx_dma = (dma_addr_t)NULL;
	}

	geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
	/* Possible stop rx is called multiple times. */
	if (!(geni_status & S_GENI_CMD_ACTIVE))
		return;
		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_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG,
	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)
		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))
		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);
		geni_se_rx_dma_unprep(port->wrapper_dev, port->rx_dma,
						      DMA_RX_BUF_SIZE);
		port->rx_dma = (dma_addr_t)NULL;
	}
}

static void msm_geni_serial_stop_rx(struct uart_port *uport)
{
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);

	if (!uart_console(uport) && device_pending_suspend(uport)) {
		IPC_LOG_MSG(port->ipc_log_misc,
				"%s.Device is suspended.\n", __func__);
		return;
	}
	stop_rx_sequencer(uport);
}

static int handle_rx_hs(struct uart_port *uport,
@@ -1890,7 +1921,7 @@ static unsigned int msm_geni_serial_tx_empty(struct uart_port *uport)
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);

	if (!uart_console(uport) && device_pending_suspend(uport))
		return 0;
		return 1;

	if (port->xfer_mode == SE_DMA)
		tx_fifo_status = port->tx_dma ? 1 : 0;
@@ -2377,6 +2408,11 @@ static int msm_geni_serial_probe(struct platform_device *pdev)
		goto exit_geni_serial_probe;
	}

	/* Optional to use the Rx pin as wakeup irq */
	dev_port->wakeup_irq = platform_get_irq(pdev, 1);
	if ((dev_port->wakeup_irq < 0 && !is_console))
		dev_info(&pdev->dev, "No wakeup IRQ configured\n");

	dev_port->serial_rsc.geni_pinctrl = devm_pinctrl_get(&pdev->dev);
	if (IS_ERR_OR_NULL(dev_port->serial_rsc.geni_pinctrl)) {
		dev_err(&pdev->dev, "No pinctrl config specified!\n");
@@ -2391,6 +2427,16 @@ static int msm_geni_serial_probe(struct platform_device *pdev)
		ret = PTR_ERR(dev_port->serial_rsc.geni_gpio_active);
		goto exit_geni_serial_probe;
	}

	/*
	 * For clients who setup an Inband wakeup, leave the GPIO pins
	 * always connected to the core, else move the pins to their
	 * defined "sleep" state.
	 */
	if (dev_port->wakeup_irq > 0) {
		dev_port->serial_rsc.geni_gpio_sleep =
			dev_port->serial_rsc.geni_gpio_active;
	} else {
		dev_port->serial_rsc.geni_gpio_sleep =
			pinctrl_lookup_state(dev_port->serial_rsc.geni_pinctrl,
							PINCTRL_SLEEP);
@@ -2399,6 +2445,7 @@ static int msm_geni_serial_probe(struct platform_device *pdev)
			ret = PTR_ERR(dev_port->serial_rsc.geni_gpio_sleep);
			goto exit_geni_serial_probe;
		}
	}

	wakeup_source_init(&dev_port->geni_wake, dev_name(&pdev->dev));
	dev_port->tx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
@@ -2414,11 +2461,6 @@ static int msm_geni_serial_probe(struct platform_device *pdev)
		goto exit_geni_serial_probe;
	}

	/* Optional to use the Rx pin as wakeup irq */
	dev_port->wakeup_irq = platform_get_irq(pdev, 1);
	if ((dev_port->wakeup_irq < 0 && !is_console))
		dev_info(&pdev->dev, "No wakeup IRQ configured\n");

	uport->private_data = (void *)drv;
	platform_set_drvdata(pdev, dev_port);
	if (is_console) {
@@ -2462,25 +2504,42 @@ 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);

	wait_for_transfers_inflight(&port->uport);
	/*
	 * Disable Interrupt
	 * Manual RFR On.
	 * Stop Rx.
	 * 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();
	}
	stop_rx_sequencer(&port->uport);
	if ((geni_status & M_GENI_CMD_ACTIVE))
		stop_tx_sequencer(&port->uport);
	ret = se_geni_resources_off(&port->serial_rsc);
	if (ret) {
		dev_err(dev, "%s: Error ret %d\n", __func__, ret);
		goto exit_runtime_suspend;
	}
	if (port->wakeup_irq > 0) {
		struct se_geni_rsc *rsc = &port->serial_rsc;

		port->edge_count = 0;
		ret = pinctrl_select_state(rsc->geni_pinctrl,
						rsc->geni_gpio_active);
		if (ret) {
			dev_err(dev, "%s: Error %d pinctrl_select_state\n",
							__func__, ret);
			goto exit_runtime_suspend;
		}
		enable_irq(port->wakeup_irq);
	}
	IPC_LOG_MSG(port->ipc_log_pwr, "%s:\n", __func__);
@@ -2503,12 +2562,24 @@ static int msm_geni_serial_runtime_resume(struct device *dev)
	__pm_stay_awake(&port->geni_wake);
	if (port->wakeup_irq > 0)
		disable_irq(port->wakeup_irq);
	/*
	 * Resources On.
	 * Start Rx.
	 * Auto RFR.
	 * Enable IRQ.
	 */
	ret = se_geni_resources_on(&port->serial_rsc);
	if (ret) {
		dev_err(dev, "%s: Error ret %d\n", __func__, ret);
		__pm_relax(&port->geni_wake);
		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();
	enable_irq(port->uport.irq);
	IPC_LOG_MSG(port->ipc_log_pwr, "%s:\n", __func__);
exit_runtime_resume: