18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * 8250-core based driver for the OMAP internal UART
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * based on omap-serial.c, Copyright (C) 2010 Texas Instruments.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 2014 Sebastian Andrzej Siewior
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/clk.h>
128c2ecf20Sopenharmony_ci#include <linux/device.h>
138c2ecf20Sopenharmony_ci#include <linux/io.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/serial_8250.h>
168c2ecf20Sopenharmony_ci#include <linux/serial_reg.h>
178c2ecf20Sopenharmony_ci#include <linux/tty_flip.h>
188c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
198c2ecf20Sopenharmony_ci#include <linux/slab.h>
208c2ecf20Sopenharmony_ci#include <linux/of.h>
218c2ecf20Sopenharmony_ci#include <linux/of_device.h>
228c2ecf20Sopenharmony_ci#include <linux/of_gpio.h>
238c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
248c2ecf20Sopenharmony_ci#include <linux/delay.h>
258c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
268c2ecf20Sopenharmony_ci#include <linux/console.h>
278c2ecf20Sopenharmony_ci#include <linux/pm_qos.h>
288c2ecf20Sopenharmony_ci#include <linux/pm_wakeirq.h>
298c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
308c2ecf20Sopenharmony_ci#include <linux/sys_soc.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include "8250.h"
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define DEFAULT_CLK_SPEED	48000000
358c2ecf20Sopenharmony_ci#define OMAP_UART_REGSHIFT	2
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#define UART_ERRATA_i202_MDR1_ACCESS	(1 << 0)
388c2ecf20Sopenharmony_ci#define OMAP_UART_WER_HAS_TX_WAKEUP	(1 << 1)
398c2ecf20Sopenharmony_ci#define OMAP_DMA_TX_KICK		(1 << 2)
408c2ecf20Sopenharmony_ci/*
418c2ecf20Sopenharmony_ci * See Advisory 21 in AM437x errata SPRZ408B, updated April 2015.
428c2ecf20Sopenharmony_ci * The same errata is applicable to AM335x and DRA7x processors too.
438c2ecf20Sopenharmony_ci */
448c2ecf20Sopenharmony_ci#define UART_ERRATA_CLOCK_DISABLE	(1 << 3)
458c2ecf20Sopenharmony_ci#define	UART_HAS_EFR2			BIT(4)
468c2ecf20Sopenharmony_ci#define UART_HAS_RHR_IT_DIS		BIT(5)
478c2ecf20Sopenharmony_ci#define UART_RX_TIMEOUT_QUIRK		BIT(6)
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#define OMAP_UART_FCR_RX_TRIG		6
508c2ecf20Sopenharmony_ci#define OMAP_UART_FCR_TX_TRIG		4
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/* SCR register bitmasks */
538c2ecf20Sopenharmony_ci#define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK	(1 << 7)
548c2ecf20Sopenharmony_ci#define OMAP_UART_SCR_TX_TRIG_GRANU1_MASK	(1 << 6)
558c2ecf20Sopenharmony_ci#define OMAP_UART_SCR_TX_EMPTY			(1 << 3)
568c2ecf20Sopenharmony_ci#define OMAP_UART_SCR_DMAMODE_MASK		(3 << 1)
578c2ecf20Sopenharmony_ci#define OMAP_UART_SCR_DMAMODE_1			(1 << 1)
588c2ecf20Sopenharmony_ci#define OMAP_UART_SCR_DMAMODE_CTL		(1 << 0)
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci/* MVR register bitmasks */
618c2ecf20Sopenharmony_ci#define OMAP_UART_MVR_SCHEME_SHIFT	30
628c2ecf20Sopenharmony_ci#define OMAP_UART_LEGACY_MVR_MAJ_MASK	0xf0
638c2ecf20Sopenharmony_ci#define OMAP_UART_LEGACY_MVR_MAJ_SHIFT	4
648c2ecf20Sopenharmony_ci#define OMAP_UART_LEGACY_MVR_MIN_MASK	0x0f
658c2ecf20Sopenharmony_ci#define OMAP_UART_MVR_MAJ_MASK		0x700
668c2ecf20Sopenharmony_ci#define OMAP_UART_MVR_MAJ_SHIFT		8
678c2ecf20Sopenharmony_ci#define OMAP_UART_MVR_MIN_MASK		0x3f
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci/* SYSC register bitmasks */
708c2ecf20Sopenharmony_ci#define OMAP_UART_SYSC_SOFTRESET	(1 << 1)
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci/* SYSS register bitmasks */
738c2ecf20Sopenharmony_ci#define OMAP_UART_SYSS_RESETDONE	(1 << 0)
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#define UART_TI752_TLR_TX	0
768c2ecf20Sopenharmony_ci#define UART_TI752_TLR_RX	4
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci#define TRIGGER_TLR_MASK(x)	((x & 0x3c) >> 2)
798c2ecf20Sopenharmony_ci#define TRIGGER_FCR_MASK(x)	(x & 3)
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/* Enable XON/XOFF flow control on output */
828c2ecf20Sopenharmony_ci#define OMAP_UART_SW_TX		0x08
838c2ecf20Sopenharmony_ci/* Enable XON/XOFF flow control on input */
848c2ecf20Sopenharmony_ci#define OMAP_UART_SW_RX		0x02
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#define OMAP_UART_WER_MOD_WKUP	0x7f
878c2ecf20Sopenharmony_ci#define OMAP_UART_TX_WAKEUP_EN	(1 << 7)
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci#define TX_TRIGGER	1
908c2ecf20Sopenharmony_ci#define RX_TRIGGER	48
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci#define OMAP_UART_TCR_RESTORE(x)	((x / 4) << 4)
938c2ecf20Sopenharmony_ci#define OMAP_UART_TCR_HALT(x)		((x / 4) << 0)
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci#define UART_BUILD_REVISION(x, y)	(((x) << 8) | (y))
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci#define OMAP_UART_REV_46 0x0406
988c2ecf20Sopenharmony_ci#define OMAP_UART_REV_52 0x0502
998c2ecf20Sopenharmony_ci#define OMAP_UART_REV_63 0x0603
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci/* Interrupt Enable Register 2 */
1028c2ecf20Sopenharmony_ci#define UART_OMAP_IER2			0x1B
1038c2ecf20Sopenharmony_ci#define UART_OMAP_IER2_RHR_IT_DIS	BIT(2)
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci/* Enhanced features register 2 */
1068c2ecf20Sopenharmony_ci#define UART_OMAP_EFR2			0x23
1078c2ecf20Sopenharmony_ci#define UART_OMAP_EFR2_TIMEOUT_BEHAVE	BIT(6)
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci/* RX FIFO occupancy indicator */
1108c2ecf20Sopenharmony_ci#define UART_OMAP_RX_LVL		0x19
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistruct omap8250_priv {
1138c2ecf20Sopenharmony_ci	void __iomem *membase;
1148c2ecf20Sopenharmony_ci	int line;
1158c2ecf20Sopenharmony_ci	u8 habit;
1168c2ecf20Sopenharmony_ci	u8 mdr1;
1178c2ecf20Sopenharmony_ci	u8 efr;
1188c2ecf20Sopenharmony_ci	u8 scr;
1198c2ecf20Sopenharmony_ci	u8 wer;
1208c2ecf20Sopenharmony_ci	u8 xon;
1218c2ecf20Sopenharmony_ci	u8 xoff;
1228c2ecf20Sopenharmony_ci	u8 delayed_restore;
1238c2ecf20Sopenharmony_ci	u16 quot;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	u8 tx_trigger;
1268c2ecf20Sopenharmony_ci	u8 rx_trigger;
1278c2ecf20Sopenharmony_ci	bool is_suspending;
1288c2ecf20Sopenharmony_ci	int wakeirq;
1298c2ecf20Sopenharmony_ci	int wakeups_enabled;
1308c2ecf20Sopenharmony_ci	u32 latency;
1318c2ecf20Sopenharmony_ci	u32 calc_latency;
1328c2ecf20Sopenharmony_ci	struct pm_qos_request pm_qos_request;
1338c2ecf20Sopenharmony_ci	struct work_struct qos_work;
1348c2ecf20Sopenharmony_ci	struct uart_8250_dma omap8250_dma;
1358c2ecf20Sopenharmony_ci	spinlock_t rx_dma_lock;
1368c2ecf20Sopenharmony_ci	bool rx_dma_broken;
1378c2ecf20Sopenharmony_ci	bool throttled;
1388c2ecf20Sopenharmony_ci};
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistruct omap8250_dma_params {
1418c2ecf20Sopenharmony_ci	u32 rx_size;
1428c2ecf20Sopenharmony_ci	u8 rx_trigger;
1438c2ecf20Sopenharmony_ci	u8 tx_trigger;
1448c2ecf20Sopenharmony_ci};
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistruct omap8250_platdata {
1478c2ecf20Sopenharmony_ci	struct omap8250_dma_params *dma_params;
1488c2ecf20Sopenharmony_ci	u8 habit;
1498c2ecf20Sopenharmony_ci};
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_DMA
1528c2ecf20Sopenharmony_cistatic void omap_8250_rx_dma_flush(struct uart_8250_port *p);
1538c2ecf20Sopenharmony_ci#else
1548c2ecf20Sopenharmony_cistatic inline void omap_8250_rx_dma_flush(struct uart_8250_port *p) { }
1558c2ecf20Sopenharmony_ci#endif
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic u32 uart_read(struct omap8250_priv *priv, u32 reg)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	return readl(priv->membase + (reg << OMAP_UART_REGSHIFT));
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic void uart_write(struct omap8250_priv *priv, u32 reg, u32 val)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	writel(val, priv->membase + (reg << OMAP_UART_REGSHIFT));
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci/*
1688c2ecf20Sopenharmony_ci * Called on runtime PM resume path from omap8250_restore_regs(), and
1698c2ecf20Sopenharmony_ci * omap8250_set_mctrl().
1708c2ecf20Sopenharmony_ci */
1718c2ecf20Sopenharmony_cistatic void __omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	struct uart_8250_port *up = up_to_u8250p(port);
1748c2ecf20Sopenharmony_ci	struct omap8250_priv *priv = up->port.private_data;
1758c2ecf20Sopenharmony_ci	u8 lcr;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	serial8250_do_set_mctrl(port, mctrl);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (!mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS)) {
1808c2ecf20Sopenharmony_ci		/*
1818c2ecf20Sopenharmony_ci		 * Turn off autoRTS if RTS is lowered and restore autoRTS
1828c2ecf20Sopenharmony_ci		 * setting if RTS is raised
1838c2ecf20Sopenharmony_ci		 */
1848c2ecf20Sopenharmony_ci		lcr = serial_in(up, UART_LCR);
1858c2ecf20Sopenharmony_ci		serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
1868c2ecf20Sopenharmony_ci		if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
1878c2ecf20Sopenharmony_ci			priv->efr |= UART_EFR_RTS;
1888c2ecf20Sopenharmony_ci		else
1898c2ecf20Sopenharmony_ci			priv->efr &= ~UART_EFR_RTS;
1908c2ecf20Sopenharmony_ci		serial_out(up, UART_EFR, priv->efr);
1918c2ecf20Sopenharmony_ci		serial_out(up, UART_LCR, lcr);
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	int err;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	err = pm_runtime_resume_and_get(port->dev);
2008c2ecf20Sopenharmony_ci	if (err)
2018c2ecf20Sopenharmony_ci		return;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	__omap8250_set_mctrl(port, mctrl);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(port->dev);
2068c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(port->dev);
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci/*
2108c2ecf20Sopenharmony_ci * Work Around for Errata i202 (2430, 3430, 3630, 4430 and 4460)
2118c2ecf20Sopenharmony_ci * The access to uart register after MDR1 Access
2128c2ecf20Sopenharmony_ci * causes UART to corrupt data.
2138c2ecf20Sopenharmony_ci *
2148c2ecf20Sopenharmony_ci * Need a delay =
2158c2ecf20Sopenharmony_ci * 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS)
2168c2ecf20Sopenharmony_ci * give 10 times as much
2178c2ecf20Sopenharmony_ci */
2188c2ecf20Sopenharmony_cistatic void omap_8250_mdr1_errataset(struct uart_8250_port *up,
2198c2ecf20Sopenharmony_ci				     struct omap8250_priv *priv)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	serial_out(up, UART_OMAP_MDR1, priv->mdr1);
2228c2ecf20Sopenharmony_ci	udelay(2);
2238c2ecf20Sopenharmony_ci	serial_out(up, UART_FCR, up->fcr | UART_FCR_CLEAR_XMIT |
2248c2ecf20Sopenharmony_ci			UART_FCR_CLEAR_RCVR);
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic void omap_8250_get_divisor(struct uart_port *port, unsigned int baud,
2288c2ecf20Sopenharmony_ci				  struct omap8250_priv *priv)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	unsigned int uartclk = port->uartclk;
2318c2ecf20Sopenharmony_ci	unsigned int div_13, div_16;
2328c2ecf20Sopenharmony_ci	unsigned int abs_d13, abs_d16;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	/*
2358c2ecf20Sopenharmony_ci	 * Old custom speed handling.
2368c2ecf20Sopenharmony_ci	 */
2378c2ecf20Sopenharmony_ci	if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) {
2388c2ecf20Sopenharmony_ci		priv->quot = port->custom_divisor & UART_DIV_MAX;
2398c2ecf20Sopenharmony_ci		/*
2408c2ecf20Sopenharmony_ci		 * I assume that nobody is using this. But hey, if somebody
2418c2ecf20Sopenharmony_ci		 * would like to specify the divisor _and_ the mode then the
2428c2ecf20Sopenharmony_ci		 * driver is ready and waiting for it.
2438c2ecf20Sopenharmony_ci		 */
2448c2ecf20Sopenharmony_ci		if (port->custom_divisor & (1 << 16))
2458c2ecf20Sopenharmony_ci			priv->mdr1 = UART_OMAP_MDR1_13X_MODE;
2468c2ecf20Sopenharmony_ci		else
2478c2ecf20Sopenharmony_ci			priv->mdr1 = UART_OMAP_MDR1_16X_MODE;
2488c2ecf20Sopenharmony_ci		return;
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci	div_13 = DIV_ROUND_CLOSEST(uartclk, 13 * baud);
2518c2ecf20Sopenharmony_ci	div_16 = DIV_ROUND_CLOSEST(uartclk, 16 * baud);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	if (!div_13)
2548c2ecf20Sopenharmony_ci		div_13 = 1;
2558c2ecf20Sopenharmony_ci	if (!div_16)
2568c2ecf20Sopenharmony_ci		div_16 = 1;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	abs_d13 = abs(baud - uartclk / 13 / div_13);
2598c2ecf20Sopenharmony_ci	abs_d16 = abs(baud - uartclk / 16 / div_16);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (abs_d13 >= abs_d16) {
2628c2ecf20Sopenharmony_ci		priv->mdr1 = UART_OMAP_MDR1_16X_MODE;
2638c2ecf20Sopenharmony_ci		priv->quot = div_16;
2648c2ecf20Sopenharmony_ci	} else {
2658c2ecf20Sopenharmony_ci		priv->mdr1 = UART_OMAP_MDR1_13X_MODE;
2668c2ecf20Sopenharmony_ci		priv->quot = div_13;
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic void omap8250_update_scr(struct uart_8250_port *up,
2718c2ecf20Sopenharmony_ci				struct omap8250_priv *priv)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	u8 old_scr;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	old_scr = serial_in(up, UART_OMAP_SCR);
2768c2ecf20Sopenharmony_ci	if (old_scr == priv->scr)
2778c2ecf20Sopenharmony_ci		return;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	/*
2808c2ecf20Sopenharmony_ci	 * The manual recommends not to enable the DMA mode selector in the SCR
2818c2ecf20Sopenharmony_ci	 * (instead of the FCR) register _and_ selecting the DMA mode as one
2828c2ecf20Sopenharmony_ci	 * register write because this may lead to malfunction.
2838c2ecf20Sopenharmony_ci	 */
2848c2ecf20Sopenharmony_ci	if (priv->scr & OMAP_UART_SCR_DMAMODE_MASK)
2858c2ecf20Sopenharmony_ci		serial_out(up, UART_OMAP_SCR,
2868c2ecf20Sopenharmony_ci			   priv->scr & ~OMAP_UART_SCR_DMAMODE_MASK);
2878c2ecf20Sopenharmony_ci	serial_out(up, UART_OMAP_SCR, priv->scr);
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic void omap8250_update_mdr1(struct uart_8250_port *up,
2918c2ecf20Sopenharmony_ci				 struct omap8250_priv *priv)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	if (priv->habit & UART_ERRATA_i202_MDR1_ACCESS)
2948c2ecf20Sopenharmony_ci		omap_8250_mdr1_errataset(up, priv);
2958c2ecf20Sopenharmony_ci	else
2968c2ecf20Sopenharmony_ci		serial_out(up, UART_OMAP_MDR1, priv->mdr1);
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cistatic void omap8250_restore_regs(struct uart_8250_port *up)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	struct omap8250_priv *priv = up->port.private_data;
3028c2ecf20Sopenharmony_ci	struct uart_8250_dma	*dma = up->dma;
3038c2ecf20Sopenharmony_ci	u8 mcr = serial8250_in_MCR(up);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	if (dma && dma->tx_running) {
3068c2ecf20Sopenharmony_ci		/*
3078c2ecf20Sopenharmony_ci		 * TCSANOW requests the change to occur immediately however if
3088c2ecf20Sopenharmony_ci		 * we have a TX-DMA operation in progress then it has been
3098c2ecf20Sopenharmony_ci		 * observed that it might stall and never complete. Therefore we
3108c2ecf20Sopenharmony_ci		 * delay DMA completes to prevent this hang from happen.
3118c2ecf20Sopenharmony_ci		 */
3128c2ecf20Sopenharmony_ci		priv->delayed_restore = 1;
3138c2ecf20Sopenharmony_ci		return;
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
3178c2ecf20Sopenharmony_ci	serial_out(up, UART_EFR, UART_EFR_ECB);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
3208c2ecf20Sopenharmony_ci	serial8250_out_MCR(up, mcr | UART_MCR_TCRTLR);
3218c2ecf20Sopenharmony_ci	serial_out(up, UART_FCR, up->fcr);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	omap8250_update_scr(up, priv);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_RESTORE(16) |
3288c2ecf20Sopenharmony_ci			OMAP_UART_TCR_HALT(52));
3298c2ecf20Sopenharmony_ci	serial_out(up, UART_TI752_TLR,
3308c2ecf20Sopenharmony_ci		   TRIGGER_TLR_MASK(priv->tx_trigger) << UART_TI752_TLR_TX |
3318c2ecf20Sopenharmony_ci		   TRIGGER_TLR_MASK(priv->rx_trigger) << UART_TI752_TLR_RX);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	serial_out(up, UART_LCR, 0);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	/* drop TCR + TLR access, we setup XON/XOFF later */
3368c2ecf20Sopenharmony_ci	serial8250_out_MCR(up, mcr);
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	serial_out(up, UART_IER, up->ier);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
3418c2ecf20Sopenharmony_ci	serial_dl_write(up, priv->quot);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	serial_out(up, UART_EFR, priv->efr);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	/* Configure flow control */
3468c2ecf20Sopenharmony_ci	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
3478c2ecf20Sopenharmony_ci	serial_out(up, UART_XON1, priv->xon);
3488c2ecf20Sopenharmony_ci	serial_out(up, UART_XOFF1, priv->xoff);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	serial_out(up, UART_LCR, up->lcr);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	omap8250_update_mdr1(up, priv);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	__omap8250_set_mctrl(&up->port, up->port.mctrl);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (up->port.rs485.flags & SER_RS485_ENABLED)
3578c2ecf20Sopenharmony_ci		serial8250_em485_stop_tx(up);
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci/*
3618c2ecf20Sopenharmony_ci * OMAP can use "CLK / (16 or 13) / div" for baud rate. And then we have have
3628c2ecf20Sopenharmony_ci * some differences in how we want to handle flow control.
3638c2ecf20Sopenharmony_ci */
3648c2ecf20Sopenharmony_cistatic void omap_8250_set_termios(struct uart_port *port,
3658c2ecf20Sopenharmony_ci				  struct ktermios *termios,
3668c2ecf20Sopenharmony_ci				  struct ktermios *old)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	struct uart_8250_port *up = up_to_u8250p(port);
3698c2ecf20Sopenharmony_ci	struct omap8250_priv *priv = up->port.private_data;
3708c2ecf20Sopenharmony_ci	unsigned char cval = 0;
3718c2ecf20Sopenharmony_ci	unsigned int baud;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	switch (termios->c_cflag & CSIZE) {
3748c2ecf20Sopenharmony_ci	case CS5:
3758c2ecf20Sopenharmony_ci		cval = UART_LCR_WLEN5;
3768c2ecf20Sopenharmony_ci		break;
3778c2ecf20Sopenharmony_ci	case CS6:
3788c2ecf20Sopenharmony_ci		cval = UART_LCR_WLEN6;
3798c2ecf20Sopenharmony_ci		break;
3808c2ecf20Sopenharmony_ci	case CS7:
3818c2ecf20Sopenharmony_ci		cval = UART_LCR_WLEN7;
3828c2ecf20Sopenharmony_ci		break;
3838c2ecf20Sopenharmony_ci	default:
3848c2ecf20Sopenharmony_ci	case CS8:
3858c2ecf20Sopenharmony_ci		cval = UART_LCR_WLEN8;
3868c2ecf20Sopenharmony_ci		break;
3878c2ecf20Sopenharmony_ci	}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	if (termios->c_cflag & CSTOPB)
3908c2ecf20Sopenharmony_ci		cval |= UART_LCR_STOP;
3918c2ecf20Sopenharmony_ci	if (termios->c_cflag & PARENB)
3928c2ecf20Sopenharmony_ci		cval |= UART_LCR_PARITY;
3938c2ecf20Sopenharmony_ci	if (!(termios->c_cflag & PARODD))
3948c2ecf20Sopenharmony_ci		cval |= UART_LCR_EPAR;
3958c2ecf20Sopenharmony_ci	if (termios->c_cflag & CMSPAR)
3968c2ecf20Sopenharmony_ci		cval |= UART_LCR_SPAR;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	/*
3998c2ecf20Sopenharmony_ci	 * Ask the core to calculate the divisor for us.
4008c2ecf20Sopenharmony_ci	 */
4018c2ecf20Sopenharmony_ci	baud = uart_get_baud_rate(port, termios, old,
4028c2ecf20Sopenharmony_ci				  port->uartclk / 16 / UART_DIV_MAX,
4038c2ecf20Sopenharmony_ci				  port->uartclk / 13);
4048c2ecf20Sopenharmony_ci	omap_8250_get_divisor(port, baud, priv);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	/*
4078c2ecf20Sopenharmony_ci	 * Ok, we're now changing the port state. Do it with
4088c2ecf20Sopenharmony_ci	 * interrupts disabled.
4098c2ecf20Sopenharmony_ci	 */
4108c2ecf20Sopenharmony_ci	pm_runtime_get_sync(port->dev);
4118c2ecf20Sopenharmony_ci	spin_lock_irq(&port->lock);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	/*
4148c2ecf20Sopenharmony_ci	 * Update the per-port timeout.
4158c2ecf20Sopenharmony_ci	 */
4168c2ecf20Sopenharmony_ci	uart_update_timeout(port, termios->c_cflag, baud);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
4198c2ecf20Sopenharmony_ci	if (termios->c_iflag & INPCK)
4208c2ecf20Sopenharmony_ci		up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
4218c2ecf20Sopenharmony_ci	if (termios->c_iflag & (IGNBRK | PARMRK))
4228c2ecf20Sopenharmony_ci		up->port.read_status_mask |= UART_LSR_BI;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	/*
4258c2ecf20Sopenharmony_ci	 * Characters to ignore
4268c2ecf20Sopenharmony_ci	 */
4278c2ecf20Sopenharmony_ci	up->port.ignore_status_mask = 0;
4288c2ecf20Sopenharmony_ci	if (termios->c_iflag & IGNPAR)
4298c2ecf20Sopenharmony_ci		up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
4308c2ecf20Sopenharmony_ci	if (termios->c_iflag & IGNBRK) {
4318c2ecf20Sopenharmony_ci		up->port.ignore_status_mask |= UART_LSR_BI;
4328c2ecf20Sopenharmony_ci		/*
4338c2ecf20Sopenharmony_ci		 * If we're ignoring parity and break indicators,
4348c2ecf20Sopenharmony_ci		 * ignore overruns too (for real raw support).
4358c2ecf20Sopenharmony_ci		 */
4368c2ecf20Sopenharmony_ci		if (termios->c_iflag & IGNPAR)
4378c2ecf20Sopenharmony_ci			up->port.ignore_status_mask |= UART_LSR_OE;
4388c2ecf20Sopenharmony_ci	}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	/*
4418c2ecf20Sopenharmony_ci	 * ignore all characters if CREAD is not set
4428c2ecf20Sopenharmony_ci	 */
4438c2ecf20Sopenharmony_ci	if ((termios->c_cflag & CREAD) == 0)
4448c2ecf20Sopenharmony_ci		up->port.ignore_status_mask |= UART_LSR_DR;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	/*
4478c2ecf20Sopenharmony_ci	 * Modem status interrupts
4488c2ecf20Sopenharmony_ci	 */
4498c2ecf20Sopenharmony_ci	up->ier &= ~UART_IER_MSI;
4508c2ecf20Sopenharmony_ci	if (UART_ENABLE_MS(&up->port, termios->c_cflag))
4518c2ecf20Sopenharmony_ci		up->ier |= UART_IER_MSI;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	up->lcr = cval;
4548c2ecf20Sopenharmony_ci	/* Up to here it was mostly serial8250_do_set_termios() */
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	/*
4578c2ecf20Sopenharmony_ci	 * We enable TRIG_GRANU for RX and TX and additionally we set
4588c2ecf20Sopenharmony_ci	 * SCR_TX_EMPTY bit. The result is the following:
4598c2ecf20Sopenharmony_ci	 * - RX_TRIGGER amount of bytes in the FIFO will cause an interrupt.
4608c2ecf20Sopenharmony_ci	 * - less than RX_TRIGGER number of bytes will also cause an interrupt
4618c2ecf20Sopenharmony_ci	 *   once the UART decides that there no new bytes arriving.
4628c2ecf20Sopenharmony_ci	 * - Once THRE is enabled, the interrupt will be fired once the FIFO is
4638c2ecf20Sopenharmony_ci	 *   empty - the trigger level is ignored here.
4648c2ecf20Sopenharmony_ci	 *
4658c2ecf20Sopenharmony_ci	 * Once DMA is enabled:
4668c2ecf20Sopenharmony_ci	 * - UART will assert the TX DMA line once there is room for TX_TRIGGER
4678c2ecf20Sopenharmony_ci	 *   bytes in the TX FIFO. On each assert the DMA engine will move
4688c2ecf20Sopenharmony_ci	 *   TX_TRIGGER bytes into the FIFO.
4698c2ecf20Sopenharmony_ci	 * - UART will assert the RX DMA line once there are RX_TRIGGER bytes in
4708c2ecf20Sopenharmony_ci	 *   the FIFO and move RX_TRIGGER bytes.
4718c2ecf20Sopenharmony_ci	 * This is because threshold and trigger values are the same.
4728c2ecf20Sopenharmony_ci	 */
4738c2ecf20Sopenharmony_ci	up->fcr = UART_FCR_ENABLE_FIFO;
4748c2ecf20Sopenharmony_ci	up->fcr |= TRIGGER_FCR_MASK(priv->tx_trigger) << OMAP_UART_FCR_TX_TRIG;
4758c2ecf20Sopenharmony_ci	up->fcr |= TRIGGER_FCR_MASK(priv->rx_trigger) << OMAP_UART_FCR_RX_TRIG;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	priv->scr = OMAP_UART_SCR_RX_TRIG_GRANU1_MASK | OMAP_UART_SCR_TX_EMPTY |
4788c2ecf20Sopenharmony_ci		OMAP_UART_SCR_TX_TRIG_GRANU1_MASK;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	if (up->dma)
4818c2ecf20Sopenharmony_ci		priv->scr |= OMAP_UART_SCR_DMAMODE_1 |
4828c2ecf20Sopenharmony_ci			OMAP_UART_SCR_DMAMODE_CTL;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	priv->xon = termios->c_cc[VSTART];
4858c2ecf20Sopenharmony_ci	priv->xoff = termios->c_cc[VSTOP];
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	priv->efr = 0;
4888c2ecf20Sopenharmony_ci	up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW &&
4918c2ecf20Sopenharmony_ci	    !mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS) &&
4928c2ecf20Sopenharmony_ci	    !mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_CTS)) {
4938c2ecf20Sopenharmony_ci		/* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */
4948c2ecf20Sopenharmony_ci		up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
4958c2ecf20Sopenharmony_ci		priv->efr |= UART_EFR_CTS;
4968c2ecf20Sopenharmony_ci	} else	if (up->port.flags & UPF_SOFT_FLOW) {
4978c2ecf20Sopenharmony_ci		/*
4988c2ecf20Sopenharmony_ci		 * OMAP rx s/w flow control is borked; the transmitter remains
4998c2ecf20Sopenharmony_ci		 * stuck off even if rx flow control is subsequently disabled
5008c2ecf20Sopenharmony_ci		 */
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci		/*
5038c2ecf20Sopenharmony_ci		 * IXOFF Flag:
5048c2ecf20Sopenharmony_ci		 * Enable XON/XOFF flow control on output.
5058c2ecf20Sopenharmony_ci		 * Transmit XON1, XOFF1
5068c2ecf20Sopenharmony_ci		 */
5078c2ecf20Sopenharmony_ci		if (termios->c_iflag & IXOFF) {
5088c2ecf20Sopenharmony_ci			up->port.status |= UPSTAT_AUTOXOFF;
5098c2ecf20Sopenharmony_ci			priv->efr |= OMAP_UART_SW_TX;
5108c2ecf20Sopenharmony_ci		}
5118c2ecf20Sopenharmony_ci	}
5128c2ecf20Sopenharmony_ci	omap8250_restore_regs(up);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	spin_unlock_irq(&up->port.lock);
5158c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(port->dev);
5168c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(port->dev);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	/* calculate wakeup latency constraint */
5198c2ecf20Sopenharmony_ci	priv->calc_latency = USEC_PER_SEC * 64 * 8 / baud;
5208c2ecf20Sopenharmony_ci	priv->latency = priv->calc_latency;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	schedule_work(&priv->qos_work);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	/* Don't rewrite B0 */
5258c2ecf20Sopenharmony_ci	if (tty_termios_baud_rate(termios))
5268c2ecf20Sopenharmony_ci		tty_termios_encode_baud_rate(termios, baud, baud);
5278c2ecf20Sopenharmony_ci}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci/* same as 8250 except that we may have extra flow bits set in EFR */
5308c2ecf20Sopenharmony_cistatic void omap_8250_pm(struct uart_port *port, unsigned int state,
5318c2ecf20Sopenharmony_ci			 unsigned int oldstate)
5328c2ecf20Sopenharmony_ci{
5338c2ecf20Sopenharmony_ci	struct uart_8250_port *up = up_to_u8250p(port);
5348c2ecf20Sopenharmony_ci	u8 efr;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	pm_runtime_get_sync(port->dev);
5378c2ecf20Sopenharmony_ci	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
5388c2ecf20Sopenharmony_ci	efr = serial_in(up, UART_EFR);
5398c2ecf20Sopenharmony_ci	serial_out(up, UART_EFR, efr | UART_EFR_ECB);
5408c2ecf20Sopenharmony_ci	serial_out(up, UART_LCR, 0);
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0);
5438c2ecf20Sopenharmony_ci	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
5448c2ecf20Sopenharmony_ci	serial_out(up, UART_EFR, efr);
5458c2ecf20Sopenharmony_ci	serial_out(up, UART_LCR, 0);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(port->dev);
5488c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(port->dev);
5498c2ecf20Sopenharmony_ci}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_cistatic void omap_serial_fill_features_erratas(struct uart_8250_port *up,
5528c2ecf20Sopenharmony_ci					      struct omap8250_priv *priv)
5538c2ecf20Sopenharmony_ci{
5548c2ecf20Sopenharmony_ci	const struct soc_device_attribute k3_soc_devices[] = {
5558c2ecf20Sopenharmony_ci		{ .family = "AM65X",  },
5568c2ecf20Sopenharmony_ci		{ .family = "J721E", .revision = "SR1.0" },
5578c2ecf20Sopenharmony_ci		{ /* sentinel */ }
5588c2ecf20Sopenharmony_ci	};
5598c2ecf20Sopenharmony_ci	u32 mvr, scheme;
5608c2ecf20Sopenharmony_ci	u16 revision, major, minor;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	mvr = uart_read(priv, UART_OMAP_MVER);
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	/* Check revision register scheme */
5658c2ecf20Sopenharmony_ci	scheme = mvr >> OMAP_UART_MVR_SCHEME_SHIFT;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	switch (scheme) {
5688c2ecf20Sopenharmony_ci	case 0: /* Legacy Scheme: OMAP2/3 */
5698c2ecf20Sopenharmony_ci		/* MINOR_REV[0:4], MAJOR_REV[4:7] */
5708c2ecf20Sopenharmony_ci		major = (mvr & OMAP_UART_LEGACY_MVR_MAJ_MASK) >>
5718c2ecf20Sopenharmony_ci			OMAP_UART_LEGACY_MVR_MAJ_SHIFT;
5728c2ecf20Sopenharmony_ci		minor = (mvr & OMAP_UART_LEGACY_MVR_MIN_MASK);
5738c2ecf20Sopenharmony_ci		break;
5748c2ecf20Sopenharmony_ci	case 1:
5758c2ecf20Sopenharmony_ci		/* New Scheme: OMAP4+ */
5768c2ecf20Sopenharmony_ci		/* MINOR_REV[0:5], MAJOR_REV[8:10] */
5778c2ecf20Sopenharmony_ci		major = (mvr & OMAP_UART_MVR_MAJ_MASK) >>
5788c2ecf20Sopenharmony_ci			OMAP_UART_MVR_MAJ_SHIFT;
5798c2ecf20Sopenharmony_ci		minor = (mvr & OMAP_UART_MVR_MIN_MASK);
5808c2ecf20Sopenharmony_ci		break;
5818c2ecf20Sopenharmony_ci	default:
5828c2ecf20Sopenharmony_ci		dev_warn(up->port.dev,
5838c2ecf20Sopenharmony_ci			 "Unknown revision, defaulting to highest\n");
5848c2ecf20Sopenharmony_ci		/* highest possible revision */
5858c2ecf20Sopenharmony_ci		major = 0xff;
5868c2ecf20Sopenharmony_ci		minor = 0xff;
5878c2ecf20Sopenharmony_ci	}
5888c2ecf20Sopenharmony_ci	/* normalize revision for the driver */
5898c2ecf20Sopenharmony_ci	revision = UART_BUILD_REVISION(major, minor);
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	switch (revision) {
5928c2ecf20Sopenharmony_ci	case OMAP_UART_REV_46:
5938c2ecf20Sopenharmony_ci		priv->habit |= UART_ERRATA_i202_MDR1_ACCESS;
5948c2ecf20Sopenharmony_ci		break;
5958c2ecf20Sopenharmony_ci	case OMAP_UART_REV_52:
5968c2ecf20Sopenharmony_ci		priv->habit |= UART_ERRATA_i202_MDR1_ACCESS |
5978c2ecf20Sopenharmony_ci				OMAP_UART_WER_HAS_TX_WAKEUP;
5988c2ecf20Sopenharmony_ci		break;
5998c2ecf20Sopenharmony_ci	case OMAP_UART_REV_63:
6008c2ecf20Sopenharmony_ci		priv->habit |= UART_ERRATA_i202_MDR1_ACCESS |
6018c2ecf20Sopenharmony_ci			OMAP_UART_WER_HAS_TX_WAKEUP;
6028c2ecf20Sopenharmony_ci		break;
6038c2ecf20Sopenharmony_ci	default:
6048c2ecf20Sopenharmony_ci		break;
6058c2ecf20Sopenharmony_ci	}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	/*
6088c2ecf20Sopenharmony_ci	 * AM65x SR1.0, AM65x SR2.0 and J721e SR1.0 don't
6098c2ecf20Sopenharmony_ci	 * don't have RHR_IT_DIS bit in IER2 register. So drop to flag
6108c2ecf20Sopenharmony_ci	 * to enable errata workaround.
6118c2ecf20Sopenharmony_ci	 */
6128c2ecf20Sopenharmony_ci	if (soc_device_match(k3_soc_devices))
6138c2ecf20Sopenharmony_ci		priv->habit &= ~UART_HAS_RHR_IT_DIS;
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_cistatic void omap8250_uart_qos_work(struct work_struct *work)
6178c2ecf20Sopenharmony_ci{
6188c2ecf20Sopenharmony_ci	struct omap8250_priv *priv;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	priv = container_of(work, struct omap8250_priv, qos_work);
6218c2ecf20Sopenharmony_ci	cpu_latency_qos_update_request(&priv->pm_qos_request, priv->latency);
6228c2ecf20Sopenharmony_ci}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_DMA
6258c2ecf20Sopenharmony_cistatic int omap_8250_dma_handle_irq(struct uart_port *port);
6268c2ecf20Sopenharmony_ci#endif
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_cistatic irqreturn_t omap8250_irq(int irq, void *dev_id)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	struct uart_port *port = dev_id;
6318c2ecf20Sopenharmony_ci	struct omap8250_priv *priv = port->private_data;
6328c2ecf20Sopenharmony_ci	struct uart_8250_port *up = up_to_u8250p(port);
6338c2ecf20Sopenharmony_ci	unsigned int iir, lsr;
6348c2ecf20Sopenharmony_ci	int ret;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_DMA
6378c2ecf20Sopenharmony_ci	if (up->dma) {
6388c2ecf20Sopenharmony_ci		ret = omap_8250_dma_handle_irq(port);
6398c2ecf20Sopenharmony_ci		return IRQ_RETVAL(ret);
6408c2ecf20Sopenharmony_ci	}
6418c2ecf20Sopenharmony_ci#endif
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	serial8250_rpm_get(up);
6448c2ecf20Sopenharmony_ci	lsr = serial_port_in(port, UART_LSR);
6458c2ecf20Sopenharmony_ci	iir = serial_port_in(port, UART_IIR);
6468c2ecf20Sopenharmony_ci	ret = serial8250_handle_irq(port, iir);
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	/*
6498c2ecf20Sopenharmony_ci	 * On K3 SoCs, it is observed that RX TIMEOUT is signalled after
6508c2ecf20Sopenharmony_ci	 * FIFO has been drained, in which case a dummy read of RX FIFO
6518c2ecf20Sopenharmony_ci	 * is required to clear RX TIMEOUT condition.
6528c2ecf20Sopenharmony_ci	 */
6538c2ecf20Sopenharmony_ci	if (priv->habit & UART_RX_TIMEOUT_QUIRK &&
6548c2ecf20Sopenharmony_ci	    (iir & UART_IIR_RX_TIMEOUT) == UART_IIR_RX_TIMEOUT &&
6558c2ecf20Sopenharmony_ci	    serial_port_in(port, UART_OMAP_RX_LVL) == 0) {
6568c2ecf20Sopenharmony_ci		serial_port_in(port, UART_RX);
6578c2ecf20Sopenharmony_ci	}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	/* Stop processing interrupts on input overrun */
6608c2ecf20Sopenharmony_ci	if ((lsr & UART_LSR_OE) && up->overrun_backoff_time_ms > 0) {
6618c2ecf20Sopenharmony_ci		unsigned long delay;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci		/* Synchronize UART_IER access against the console. */
6648c2ecf20Sopenharmony_ci		spin_lock(&port->lock);
6658c2ecf20Sopenharmony_ci		up->ier = port->serial_in(port, UART_IER);
6668c2ecf20Sopenharmony_ci		if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
6678c2ecf20Sopenharmony_ci			port->ops->stop_rx(port);
6688c2ecf20Sopenharmony_ci		} else {
6698c2ecf20Sopenharmony_ci			/* Keep restarting the timer until
6708c2ecf20Sopenharmony_ci			 * the input overrun subsides.
6718c2ecf20Sopenharmony_ci			 */
6728c2ecf20Sopenharmony_ci			cancel_delayed_work(&up->overrun_backoff);
6738c2ecf20Sopenharmony_ci		}
6748c2ecf20Sopenharmony_ci		spin_unlock(&port->lock);
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci		delay = msecs_to_jiffies(up->overrun_backoff_time_ms);
6778c2ecf20Sopenharmony_ci		schedule_delayed_work(&up->overrun_backoff, delay);
6788c2ecf20Sopenharmony_ci	}
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	serial8250_rpm_put(up);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	return IRQ_RETVAL(ret);
6838c2ecf20Sopenharmony_ci}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_cistatic int omap_8250_startup(struct uart_port *port)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	struct uart_8250_port *up = up_to_u8250p(port);
6888c2ecf20Sopenharmony_ci	struct omap8250_priv *priv = port->private_data;
6898c2ecf20Sopenharmony_ci	int ret;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	if (priv->wakeirq) {
6928c2ecf20Sopenharmony_ci		ret = dev_pm_set_dedicated_wake_irq(port->dev, priv->wakeirq);
6938c2ecf20Sopenharmony_ci		if (ret)
6948c2ecf20Sopenharmony_ci			return ret;
6958c2ecf20Sopenharmony_ci	}
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	pm_runtime_get_sync(port->dev);
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	serial_out(up, UART_LCR, UART_LCR_WLEN8);
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	up->lsr_saved_flags = 0;
7048c2ecf20Sopenharmony_ci	up->msr_saved_flags = 0;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	/* Disable DMA for console UART */
7078c2ecf20Sopenharmony_ci	if (uart_console(port))
7088c2ecf20Sopenharmony_ci		up->dma = NULL;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	if (up->dma) {
7118c2ecf20Sopenharmony_ci		ret = serial8250_request_dma(up);
7128c2ecf20Sopenharmony_ci		if (ret) {
7138c2ecf20Sopenharmony_ci			dev_warn_ratelimited(port->dev,
7148c2ecf20Sopenharmony_ci					     "failed to request DMA\n");
7158c2ecf20Sopenharmony_ci			up->dma = NULL;
7168c2ecf20Sopenharmony_ci		}
7178c2ecf20Sopenharmony_ci	}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	ret = request_irq(port->irq, omap8250_irq, IRQF_SHARED,
7208c2ecf20Sopenharmony_ci			  dev_name(port->dev), port);
7218c2ecf20Sopenharmony_ci	if (ret < 0)
7228c2ecf20Sopenharmony_ci		goto err;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	up->ier = UART_IER_RLSI | UART_IER_RDI;
7258c2ecf20Sopenharmony_ci	serial_out(up, UART_IER, up->ier);
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
7288c2ecf20Sopenharmony_ci	up->capabilities |= UART_CAP_RPM;
7298c2ecf20Sopenharmony_ci#endif
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	/* Enable module level wake up */
7328c2ecf20Sopenharmony_ci	priv->wer = OMAP_UART_WER_MOD_WKUP;
7338c2ecf20Sopenharmony_ci	if (priv->habit & OMAP_UART_WER_HAS_TX_WAKEUP)
7348c2ecf20Sopenharmony_ci		priv->wer |= OMAP_UART_TX_WAKEUP_EN;
7358c2ecf20Sopenharmony_ci	serial_out(up, UART_OMAP_WER, priv->wer);
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	if (up->dma && !(priv->habit & UART_HAS_EFR2))
7388c2ecf20Sopenharmony_ci		up->dma->rx_dma(up);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(port->dev);
7418c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(port->dev);
7428c2ecf20Sopenharmony_ci	return 0;
7438c2ecf20Sopenharmony_cierr:
7448c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(port->dev);
7458c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(port->dev);
7468c2ecf20Sopenharmony_ci	dev_pm_clear_wake_irq(port->dev);
7478c2ecf20Sopenharmony_ci	return ret;
7488c2ecf20Sopenharmony_ci}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_cistatic void omap_8250_shutdown(struct uart_port *port)
7518c2ecf20Sopenharmony_ci{
7528c2ecf20Sopenharmony_ci	struct uart_8250_port *up = up_to_u8250p(port);
7538c2ecf20Sopenharmony_ci	struct omap8250_priv *priv = port->private_data;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	flush_work(&priv->qos_work);
7568c2ecf20Sopenharmony_ci	if (up->dma)
7578c2ecf20Sopenharmony_ci		omap_8250_rx_dma_flush(up);
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	pm_runtime_get_sync(port->dev);
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	serial_out(up, UART_OMAP_WER, 0);
7628c2ecf20Sopenharmony_ci	if (priv->habit & UART_HAS_EFR2)
7638c2ecf20Sopenharmony_ci		serial_out(up, UART_OMAP_EFR2, 0x0);
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	up->ier = 0;
7668c2ecf20Sopenharmony_ci	serial_out(up, UART_IER, 0);
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	if (up->dma)
7698c2ecf20Sopenharmony_ci		serial8250_release_dma(up);
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	/*
7728c2ecf20Sopenharmony_ci	 * Disable break condition and FIFOs
7738c2ecf20Sopenharmony_ci	 */
7748c2ecf20Sopenharmony_ci	if (up->lcr & UART_LCR_SBC)
7758c2ecf20Sopenharmony_ci		serial_out(up, UART_LCR, up->lcr & ~UART_LCR_SBC);
7768c2ecf20Sopenharmony_ci	serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(port->dev);
7798c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(port->dev);
7808c2ecf20Sopenharmony_ci	free_irq(port->irq, port);
7818c2ecf20Sopenharmony_ci	dev_pm_clear_wake_irq(port->dev);
7828c2ecf20Sopenharmony_ci}
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_cistatic void omap_8250_throttle(struct uart_port *port)
7858c2ecf20Sopenharmony_ci{
7868c2ecf20Sopenharmony_ci	struct omap8250_priv *priv = port->private_data;
7878c2ecf20Sopenharmony_ci	unsigned long flags;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	pm_runtime_get_sync(port->dev);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	spin_lock_irqsave(&port->lock, flags);
7928c2ecf20Sopenharmony_ci	port->ops->stop_rx(port);
7938c2ecf20Sopenharmony_ci	priv->throttled = true;
7948c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&port->lock, flags);
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(port->dev);
7978c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(port->dev);
7988c2ecf20Sopenharmony_ci}
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_cistatic void omap_8250_unthrottle(struct uart_port *port)
8018c2ecf20Sopenharmony_ci{
8028c2ecf20Sopenharmony_ci	struct omap8250_priv *priv = port->private_data;
8038c2ecf20Sopenharmony_ci	struct uart_8250_port *up = up_to_u8250p(port);
8048c2ecf20Sopenharmony_ci	unsigned long flags;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	pm_runtime_get_sync(port->dev);
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	spin_lock_irqsave(&port->lock, flags);
8098c2ecf20Sopenharmony_ci	priv->throttled = false;
8108c2ecf20Sopenharmony_ci	if (up->dma)
8118c2ecf20Sopenharmony_ci		up->dma->rx_dma(up);
8128c2ecf20Sopenharmony_ci	up->ier |= UART_IER_RLSI | UART_IER_RDI;
8138c2ecf20Sopenharmony_ci	port->read_status_mask |= UART_LSR_DR;
8148c2ecf20Sopenharmony_ci	serial_out(up, UART_IER, up->ier);
8158c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&port->lock, flags);
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(port->dev);
8188c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(port->dev);
8198c2ecf20Sopenharmony_ci}
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_DMA
8228c2ecf20Sopenharmony_cistatic int omap_8250_rx_dma(struct uart_8250_port *p);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci/* Must be called while priv->rx_dma_lock is held */
8258c2ecf20Sopenharmony_cistatic void __dma_rx_do_complete(struct uart_8250_port *p)
8268c2ecf20Sopenharmony_ci{
8278c2ecf20Sopenharmony_ci	struct uart_8250_dma    *dma = p->dma;
8288c2ecf20Sopenharmony_ci	struct tty_port         *tty_port = &p->port.state->port;
8298c2ecf20Sopenharmony_ci	struct omap8250_priv	*priv = p->port.private_data;
8308c2ecf20Sopenharmony_ci	struct dma_chan		*rxchan = dma->rxchan;
8318c2ecf20Sopenharmony_ci	dma_cookie_t		cookie;
8328c2ecf20Sopenharmony_ci	struct dma_tx_state     state;
8338c2ecf20Sopenharmony_ci	int                     count;
8348c2ecf20Sopenharmony_ci	int			ret;
8358c2ecf20Sopenharmony_ci	u32			reg;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	if (!dma->rx_running)
8388c2ecf20Sopenharmony_ci		goto out;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	cookie = dma->rx_cookie;
8418c2ecf20Sopenharmony_ci	dma->rx_running = 0;
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	/* Re-enable RX FIFO interrupt now that transfer is complete */
8448c2ecf20Sopenharmony_ci	if (priv->habit & UART_HAS_RHR_IT_DIS) {
8458c2ecf20Sopenharmony_ci		reg = serial_in(p, UART_OMAP_IER2);
8468c2ecf20Sopenharmony_ci		reg &= ~UART_OMAP_IER2_RHR_IT_DIS;
8478c2ecf20Sopenharmony_ci		serial_out(p, UART_OMAP_IER2, reg);
8488c2ecf20Sopenharmony_ci	}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	dmaengine_tx_status(rxchan, cookie, &state);
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	count = dma->rx_size - state.residue + state.in_flight_bytes;
8538c2ecf20Sopenharmony_ci	if (count < dma->rx_size) {
8548c2ecf20Sopenharmony_ci		dmaengine_terminate_async(rxchan);
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci		/*
8578c2ecf20Sopenharmony_ci		 * Poll for teardown to complete which guarantees in
8588c2ecf20Sopenharmony_ci		 * flight data is drained.
8598c2ecf20Sopenharmony_ci		 */
8608c2ecf20Sopenharmony_ci		if (state.in_flight_bytes) {
8618c2ecf20Sopenharmony_ci			int poll_count = 25;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci			while (dmaengine_tx_status(rxchan, cookie, NULL) &&
8648c2ecf20Sopenharmony_ci			       poll_count--)
8658c2ecf20Sopenharmony_ci				cpu_relax();
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci			if (poll_count == -1)
8688c2ecf20Sopenharmony_ci				dev_err(p->port.dev, "teardown incomplete\n");
8698c2ecf20Sopenharmony_ci		}
8708c2ecf20Sopenharmony_ci	}
8718c2ecf20Sopenharmony_ci	if (!count)
8728c2ecf20Sopenharmony_ci		goto out;
8738c2ecf20Sopenharmony_ci	ret = tty_insert_flip_string(tty_port, dma->rx_buf, count);
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	p->port.icount.rx += ret;
8768c2ecf20Sopenharmony_ci	p->port.icount.buf_overrun += count - ret;
8778c2ecf20Sopenharmony_ciout:
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	tty_flip_buffer_push(tty_port);
8808c2ecf20Sopenharmony_ci}
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_cistatic void __dma_rx_complete(void *param)
8838c2ecf20Sopenharmony_ci{
8848c2ecf20Sopenharmony_ci	struct uart_8250_port *p = param;
8858c2ecf20Sopenharmony_ci	struct omap8250_priv *priv = p->port.private_data;
8868c2ecf20Sopenharmony_ci	struct uart_8250_dma *dma = p->dma;
8878c2ecf20Sopenharmony_ci	struct dma_tx_state     state;
8888c2ecf20Sopenharmony_ci	unsigned long flags;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	spin_lock_irqsave(&p->port.lock, flags);
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	/*
8938c2ecf20Sopenharmony_ci	 * If the tx status is not DMA_COMPLETE, then this is a delayed
8948c2ecf20Sopenharmony_ci	 * completion callback. A previous RX timeout flush would have
8958c2ecf20Sopenharmony_ci	 * already pushed the data, so exit.
8968c2ecf20Sopenharmony_ci	 */
8978c2ecf20Sopenharmony_ci	if (dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state) !=
8988c2ecf20Sopenharmony_ci			DMA_COMPLETE) {
8998c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&p->port.lock, flags);
9008c2ecf20Sopenharmony_ci		return;
9018c2ecf20Sopenharmony_ci	}
9028c2ecf20Sopenharmony_ci	__dma_rx_do_complete(p);
9038c2ecf20Sopenharmony_ci	if (!priv->throttled) {
9048c2ecf20Sopenharmony_ci		p->ier |= UART_IER_RLSI | UART_IER_RDI;
9058c2ecf20Sopenharmony_ci		serial_out(p, UART_IER, p->ier);
9068c2ecf20Sopenharmony_ci		if (!(priv->habit & UART_HAS_EFR2))
9078c2ecf20Sopenharmony_ci			omap_8250_rx_dma(p);
9088c2ecf20Sopenharmony_ci	}
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&p->port.lock, flags);
9118c2ecf20Sopenharmony_ci}
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_cistatic void omap_8250_rx_dma_flush(struct uart_8250_port *p)
9148c2ecf20Sopenharmony_ci{
9158c2ecf20Sopenharmony_ci	struct omap8250_priv	*priv = p->port.private_data;
9168c2ecf20Sopenharmony_ci	struct uart_8250_dma	*dma = p->dma;
9178c2ecf20Sopenharmony_ci	struct dma_tx_state     state;
9188c2ecf20Sopenharmony_ci	unsigned long		flags;
9198c2ecf20Sopenharmony_ci	int ret;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	spin_lock_irqsave(&priv->rx_dma_lock, flags);
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	if (!dma->rx_running) {
9248c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
9258c2ecf20Sopenharmony_ci		return;
9268c2ecf20Sopenharmony_ci	}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	ret = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
9298c2ecf20Sopenharmony_ci	if (ret == DMA_IN_PROGRESS) {
9308c2ecf20Sopenharmony_ci		ret = dmaengine_pause(dma->rxchan);
9318c2ecf20Sopenharmony_ci		if (WARN_ON_ONCE(ret))
9328c2ecf20Sopenharmony_ci			priv->rx_dma_broken = true;
9338c2ecf20Sopenharmony_ci	}
9348c2ecf20Sopenharmony_ci	__dma_rx_do_complete(p);
9358c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
9368c2ecf20Sopenharmony_ci}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_cistatic int omap_8250_rx_dma(struct uart_8250_port *p)
9398c2ecf20Sopenharmony_ci{
9408c2ecf20Sopenharmony_ci	struct omap8250_priv		*priv = p->port.private_data;
9418c2ecf20Sopenharmony_ci	struct uart_8250_dma            *dma = p->dma;
9428c2ecf20Sopenharmony_ci	int				err = 0;
9438c2ecf20Sopenharmony_ci	struct dma_async_tx_descriptor  *desc;
9448c2ecf20Sopenharmony_ci	unsigned long			flags;
9458c2ecf20Sopenharmony_ci	u32				reg;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	if (priv->rx_dma_broken)
9488c2ecf20Sopenharmony_ci		return -EINVAL;
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	spin_lock_irqsave(&priv->rx_dma_lock, flags);
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	if (dma->rx_running) {
9538c2ecf20Sopenharmony_ci		enum dma_status state;
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci		state = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, NULL);
9568c2ecf20Sopenharmony_ci		if (state == DMA_COMPLETE) {
9578c2ecf20Sopenharmony_ci			/*
9588c2ecf20Sopenharmony_ci			 * Disable RX interrupts to allow RX DMA completion
9598c2ecf20Sopenharmony_ci			 * callback to run.
9608c2ecf20Sopenharmony_ci			 */
9618c2ecf20Sopenharmony_ci			p->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
9628c2ecf20Sopenharmony_ci			serial_out(p, UART_IER, p->ier);
9638c2ecf20Sopenharmony_ci		}
9648c2ecf20Sopenharmony_ci		goto out;
9658c2ecf20Sopenharmony_ci	}
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
9688c2ecf20Sopenharmony_ci					   dma->rx_size, DMA_DEV_TO_MEM,
9698c2ecf20Sopenharmony_ci					   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
9708c2ecf20Sopenharmony_ci	if (!desc) {
9718c2ecf20Sopenharmony_ci		err = -EBUSY;
9728c2ecf20Sopenharmony_ci		goto out;
9738c2ecf20Sopenharmony_ci	}
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	dma->rx_running = 1;
9768c2ecf20Sopenharmony_ci	desc->callback = __dma_rx_complete;
9778c2ecf20Sopenharmony_ci	desc->callback_param = p;
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	dma->rx_cookie = dmaengine_submit(desc);
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	/*
9828c2ecf20Sopenharmony_ci	 * Disable RX FIFO interrupt while RX DMA is enabled, else
9838c2ecf20Sopenharmony_ci	 * spurious interrupt may be raised when data is in the RX FIFO
9848c2ecf20Sopenharmony_ci	 * but is yet to be drained by DMA.
9858c2ecf20Sopenharmony_ci	 */
9868c2ecf20Sopenharmony_ci	if (priv->habit & UART_HAS_RHR_IT_DIS) {
9878c2ecf20Sopenharmony_ci		reg = serial_in(p, UART_OMAP_IER2);
9888c2ecf20Sopenharmony_ci		reg |= UART_OMAP_IER2_RHR_IT_DIS;
9898c2ecf20Sopenharmony_ci		serial_out(p, UART_OMAP_IER2, reg);
9908c2ecf20Sopenharmony_ci	}
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	dma_async_issue_pending(dma->rxchan);
9938c2ecf20Sopenharmony_ciout:
9948c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
9958c2ecf20Sopenharmony_ci	return err;
9968c2ecf20Sopenharmony_ci}
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_cistatic int omap_8250_tx_dma(struct uart_8250_port *p);
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_cistatic void omap_8250_dma_tx_complete(void *param)
10018c2ecf20Sopenharmony_ci{
10028c2ecf20Sopenharmony_ci	struct uart_8250_port	*p = param;
10038c2ecf20Sopenharmony_ci	struct uart_8250_dma	*dma = p->dma;
10048c2ecf20Sopenharmony_ci	struct circ_buf		*xmit = &p->port.state->xmit;
10058c2ecf20Sopenharmony_ci	unsigned long		flags;
10068c2ecf20Sopenharmony_ci	bool			en_thri = false;
10078c2ecf20Sopenharmony_ci	struct omap8250_priv	*priv = p->port.private_data;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
10108c2ecf20Sopenharmony_ci				UART_XMIT_SIZE, DMA_TO_DEVICE);
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	spin_lock_irqsave(&p->port.lock, flags);
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	dma->tx_running = 0;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	xmit->tail += dma->tx_size;
10178c2ecf20Sopenharmony_ci	xmit->tail &= UART_XMIT_SIZE - 1;
10188c2ecf20Sopenharmony_ci	p->port.icount.tx += dma->tx_size;
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	if (priv->delayed_restore) {
10218c2ecf20Sopenharmony_ci		priv->delayed_restore = 0;
10228c2ecf20Sopenharmony_ci		omap8250_restore_regs(p);
10238c2ecf20Sopenharmony_ci	}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
10268c2ecf20Sopenharmony_ci		uart_write_wakeup(&p->port);
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) {
10298c2ecf20Sopenharmony_ci		int ret;
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci		ret = omap_8250_tx_dma(p);
10328c2ecf20Sopenharmony_ci		if (ret)
10338c2ecf20Sopenharmony_ci			en_thri = true;
10348c2ecf20Sopenharmony_ci	} else if (p->capabilities & UART_CAP_RPM) {
10358c2ecf20Sopenharmony_ci		en_thri = true;
10368c2ecf20Sopenharmony_ci	}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	if (en_thri) {
10398c2ecf20Sopenharmony_ci		dma->tx_err = 1;
10408c2ecf20Sopenharmony_ci		serial8250_set_THRI(p);
10418c2ecf20Sopenharmony_ci	}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&p->port.lock, flags);
10448c2ecf20Sopenharmony_ci}
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_cistatic int omap_8250_tx_dma(struct uart_8250_port *p)
10478c2ecf20Sopenharmony_ci{
10488c2ecf20Sopenharmony_ci	struct uart_8250_dma		*dma = p->dma;
10498c2ecf20Sopenharmony_ci	struct omap8250_priv		*priv = p->port.private_data;
10508c2ecf20Sopenharmony_ci	struct circ_buf			*xmit = &p->port.state->xmit;
10518c2ecf20Sopenharmony_ci	struct dma_async_tx_descriptor	*desc;
10528c2ecf20Sopenharmony_ci	unsigned int	skip_byte = 0;
10538c2ecf20Sopenharmony_ci	int ret;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	if (dma->tx_running)
10568c2ecf20Sopenharmony_ci		return 0;
10578c2ecf20Sopenharmony_ci	if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) {
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci		/*
10608c2ecf20Sopenharmony_ci		 * Even if no data, we need to return an error for the two cases
10618c2ecf20Sopenharmony_ci		 * below so serial8250_tx_chars() is invoked and properly clears
10628c2ecf20Sopenharmony_ci		 * THRI and/or runtime suspend.
10638c2ecf20Sopenharmony_ci		 */
10648c2ecf20Sopenharmony_ci		if (dma->tx_err || p->capabilities & UART_CAP_RPM) {
10658c2ecf20Sopenharmony_ci			ret = -EBUSY;
10668c2ecf20Sopenharmony_ci			goto err;
10678c2ecf20Sopenharmony_ci		}
10688c2ecf20Sopenharmony_ci		serial8250_clear_THRI(p);
10698c2ecf20Sopenharmony_ci		return 0;
10708c2ecf20Sopenharmony_ci	}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
10738c2ecf20Sopenharmony_ci	if (priv->habit & OMAP_DMA_TX_KICK) {
10748c2ecf20Sopenharmony_ci		u8 tx_lvl;
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci		/*
10778c2ecf20Sopenharmony_ci		 * We need to put the first byte into the FIFO in order to start
10788c2ecf20Sopenharmony_ci		 * the DMA transfer. For transfers smaller than four bytes we
10798c2ecf20Sopenharmony_ci		 * don't bother doing DMA at all. It seem not matter if there
10808c2ecf20Sopenharmony_ci		 * are still bytes in the FIFO from the last transfer (in case
10818c2ecf20Sopenharmony_ci		 * we got here directly from omap_8250_dma_tx_complete()). Bytes
10828c2ecf20Sopenharmony_ci		 * leaving the FIFO seem not to trigger the DMA transfer. It is
10838c2ecf20Sopenharmony_ci		 * really the byte that we put into the FIFO.
10848c2ecf20Sopenharmony_ci		 * If the FIFO is already full then we most likely got here from
10858c2ecf20Sopenharmony_ci		 * omap_8250_dma_tx_complete(). And this means the DMA engine
10868c2ecf20Sopenharmony_ci		 * just completed its work. We don't have to wait the complete
10878c2ecf20Sopenharmony_ci		 * 86us at 115200,8n1 but around 60us (not to mention lower
10888c2ecf20Sopenharmony_ci		 * baudrates). So in that case we take the interrupt and try
10898c2ecf20Sopenharmony_ci		 * again with an empty FIFO.
10908c2ecf20Sopenharmony_ci		 */
10918c2ecf20Sopenharmony_ci		tx_lvl = serial_in(p, UART_OMAP_TX_LVL);
10928c2ecf20Sopenharmony_ci		if (tx_lvl == p->tx_loadsz) {
10938c2ecf20Sopenharmony_ci			ret = -EBUSY;
10948c2ecf20Sopenharmony_ci			goto err;
10958c2ecf20Sopenharmony_ci		}
10968c2ecf20Sopenharmony_ci		if (dma->tx_size < 4) {
10978c2ecf20Sopenharmony_ci			ret = -EINVAL;
10988c2ecf20Sopenharmony_ci			goto err;
10998c2ecf20Sopenharmony_ci		}
11008c2ecf20Sopenharmony_ci		skip_byte = 1;
11018c2ecf20Sopenharmony_ci	}
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	desc = dmaengine_prep_slave_single(dma->txchan,
11048c2ecf20Sopenharmony_ci			dma->tx_addr + xmit->tail + skip_byte,
11058c2ecf20Sopenharmony_ci			dma->tx_size - skip_byte, DMA_MEM_TO_DEV,
11068c2ecf20Sopenharmony_ci			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
11078c2ecf20Sopenharmony_ci	if (!desc) {
11088c2ecf20Sopenharmony_ci		ret = -EBUSY;
11098c2ecf20Sopenharmony_ci		goto err;
11108c2ecf20Sopenharmony_ci	}
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	dma->tx_running = 1;
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	desc->callback = omap_8250_dma_tx_complete;
11158c2ecf20Sopenharmony_ci	desc->callback_param = p;
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	dma->tx_cookie = dmaengine_submit(desc);
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	dma_sync_single_for_device(dma->txchan->device->dev, dma->tx_addr,
11208c2ecf20Sopenharmony_ci				   UART_XMIT_SIZE, DMA_TO_DEVICE);
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	dma_async_issue_pending(dma->txchan);
11238c2ecf20Sopenharmony_ci	if (dma->tx_err)
11248c2ecf20Sopenharmony_ci		dma->tx_err = 0;
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	serial8250_clear_THRI(p);
11278c2ecf20Sopenharmony_ci	if (skip_byte)
11288c2ecf20Sopenharmony_ci		serial_out(p, UART_TX, xmit->buf[xmit->tail]);
11298c2ecf20Sopenharmony_ci	return 0;
11308c2ecf20Sopenharmony_cierr:
11318c2ecf20Sopenharmony_ci	dma->tx_err = 1;
11328c2ecf20Sopenharmony_ci	return ret;
11338c2ecf20Sopenharmony_ci}
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_cistatic bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
11368c2ecf20Sopenharmony_ci{
11378c2ecf20Sopenharmony_ci	switch (iir & 0x3f) {
11388c2ecf20Sopenharmony_ci	case UART_IIR_RLSI:
11398c2ecf20Sopenharmony_ci	case UART_IIR_RX_TIMEOUT:
11408c2ecf20Sopenharmony_ci	case UART_IIR_RDI:
11418c2ecf20Sopenharmony_ci		omap_8250_rx_dma_flush(up);
11428c2ecf20Sopenharmony_ci		return true;
11438c2ecf20Sopenharmony_ci	}
11448c2ecf20Sopenharmony_ci	return omap_8250_rx_dma(up);
11458c2ecf20Sopenharmony_ci}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_cistatic unsigned char omap_8250_handle_rx_dma(struct uart_8250_port *up,
11488c2ecf20Sopenharmony_ci					     u8 iir, unsigned char status)
11498c2ecf20Sopenharmony_ci{
11508c2ecf20Sopenharmony_ci	if ((status & (UART_LSR_DR | UART_LSR_BI)) &&
11518c2ecf20Sopenharmony_ci	    (iir & UART_IIR_RDI)) {
11528c2ecf20Sopenharmony_ci		if (handle_rx_dma(up, iir)) {
11538c2ecf20Sopenharmony_ci			status = serial8250_rx_chars(up, status);
11548c2ecf20Sopenharmony_ci			omap_8250_rx_dma(up);
11558c2ecf20Sopenharmony_ci		}
11568c2ecf20Sopenharmony_ci	}
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	return status;
11598c2ecf20Sopenharmony_ci}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_cistatic void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir,
11628c2ecf20Sopenharmony_ci				     unsigned char status)
11638c2ecf20Sopenharmony_ci{
11648c2ecf20Sopenharmony_ci	/*
11658c2ecf20Sopenharmony_ci	 * Queue a new transfer if FIFO has data.
11668c2ecf20Sopenharmony_ci	 */
11678c2ecf20Sopenharmony_ci	if ((status & (UART_LSR_DR | UART_LSR_BI)) &&
11688c2ecf20Sopenharmony_ci	    (up->ier & UART_IER_RDI)) {
11698c2ecf20Sopenharmony_ci		omap_8250_rx_dma(up);
11708c2ecf20Sopenharmony_ci		serial_out(up, UART_OMAP_EFR2, UART_OMAP_EFR2_TIMEOUT_BEHAVE);
11718c2ecf20Sopenharmony_ci	} else if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) {
11728c2ecf20Sopenharmony_ci		/*
11738c2ecf20Sopenharmony_ci		 * Disable RX timeout, read IIR to clear
11748c2ecf20Sopenharmony_ci		 * current timeout condition, clear EFR2 to
11758c2ecf20Sopenharmony_ci		 * periodic timeouts, re-enable interrupts.
11768c2ecf20Sopenharmony_ci		 */
11778c2ecf20Sopenharmony_ci		up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
11788c2ecf20Sopenharmony_ci		serial_out(up, UART_IER, up->ier);
11798c2ecf20Sopenharmony_ci		omap_8250_rx_dma_flush(up);
11808c2ecf20Sopenharmony_ci		serial_in(up, UART_IIR);
11818c2ecf20Sopenharmony_ci		serial_out(up, UART_OMAP_EFR2, 0x0);
11828c2ecf20Sopenharmony_ci		up->ier |= UART_IER_RLSI | UART_IER_RDI;
11838c2ecf20Sopenharmony_ci		serial_out(up, UART_IER, up->ier);
11848c2ecf20Sopenharmony_ci	}
11858c2ecf20Sopenharmony_ci}
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci/*
11888c2ecf20Sopenharmony_ci * This is mostly serial8250_handle_irq(). We have a slightly different DMA
11898c2ecf20Sopenharmony_ci * hoook for RX/TX and need different logic for them in the ISR. Therefore we
11908c2ecf20Sopenharmony_ci * use the default routine in the non-DMA case and this one for with DMA.
11918c2ecf20Sopenharmony_ci */
11928c2ecf20Sopenharmony_cistatic int omap_8250_dma_handle_irq(struct uart_port *port)
11938c2ecf20Sopenharmony_ci{
11948c2ecf20Sopenharmony_ci	struct uart_8250_port *up = up_to_u8250p(port);
11958c2ecf20Sopenharmony_ci	struct omap8250_priv *priv = up->port.private_data;
11968c2ecf20Sopenharmony_ci	unsigned char status;
11978c2ecf20Sopenharmony_ci	unsigned long flags;
11988c2ecf20Sopenharmony_ci	u8 iir;
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	serial8250_rpm_get(up);
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	iir = serial_port_in(port, UART_IIR);
12038c2ecf20Sopenharmony_ci	if (iir & UART_IIR_NO_INT) {
12048c2ecf20Sopenharmony_ci		serial8250_rpm_put(up);
12058c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
12068c2ecf20Sopenharmony_ci	}
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	spin_lock_irqsave(&port->lock, flags);
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	status = serial_port_in(port, UART_LSR);
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	if ((iir & 0x3f) != UART_IIR_THRI) {
12138c2ecf20Sopenharmony_ci		if (priv->habit & UART_HAS_EFR2)
12148c2ecf20Sopenharmony_ci			am654_8250_handle_rx_dma(up, iir, status);
12158c2ecf20Sopenharmony_ci		else
12168c2ecf20Sopenharmony_ci			status = omap_8250_handle_rx_dma(up, iir, status);
12178c2ecf20Sopenharmony_ci	}
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	serial8250_modem_status(up);
12208c2ecf20Sopenharmony_ci	if (status & UART_LSR_THRE && up->dma->tx_err) {
12218c2ecf20Sopenharmony_ci		if (uart_tx_stopped(&up->port) ||
12228c2ecf20Sopenharmony_ci		    uart_circ_empty(&up->port.state->xmit)) {
12238c2ecf20Sopenharmony_ci			up->dma->tx_err = 0;
12248c2ecf20Sopenharmony_ci			serial8250_tx_chars(up);
12258c2ecf20Sopenharmony_ci		} else  {
12268c2ecf20Sopenharmony_ci			/*
12278c2ecf20Sopenharmony_ci			 * try again due to an earlier failer which
12288c2ecf20Sopenharmony_ci			 * might have been resolved by now.
12298c2ecf20Sopenharmony_ci			 */
12308c2ecf20Sopenharmony_ci			if (omap_8250_tx_dma(up))
12318c2ecf20Sopenharmony_ci				serial8250_tx_chars(up);
12328c2ecf20Sopenharmony_ci		}
12338c2ecf20Sopenharmony_ci	}
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	uart_unlock_and_check_sysrq(port, flags);
12368c2ecf20Sopenharmony_ci	serial8250_rpm_put(up);
12378c2ecf20Sopenharmony_ci	return 1;
12388c2ecf20Sopenharmony_ci}
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_cistatic bool the_no_dma_filter_fn(struct dma_chan *chan, void *param)
12418c2ecf20Sopenharmony_ci{
12428c2ecf20Sopenharmony_ci	return false;
12438c2ecf20Sopenharmony_ci}
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci#else
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_cistatic inline int omap_8250_rx_dma(struct uart_8250_port *p)
12488c2ecf20Sopenharmony_ci{
12498c2ecf20Sopenharmony_ci	return -EINVAL;
12508c2ecf20Sopenharmony_ci}
12518c2ecf20Sopenharmony_ci#endif
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_cistatic int omap8250_no_handle_irq(struct uart_port *port)
12548c2ecf20Sopenharmony_ci{
12558c2ecf20Sopenharmony_ci	/* IRQ has not been requested but handling irq? */
12568c2ecf20Sopenharmony_ci	WARN_ONCE(1, "Unexpected irq handling before port startup\n");
12578c2ecf20Sopenharmony_ci	return 0;
12588c2ecf20Sopenharmony_ci}
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_cistatic struct omap8250_dma_params am654_dma = {
12618c2ecf20Sopenharmony_ci	.rx_size = SZ_2K,
12628c2ecf20Sopenharmony_ci	.rx_trigger = 1,
12638c2ecf20Sopenharmony_ci	.tx_trigger = TX_TRIGGER,
12648c2ecf20Sopenharmony_ci};
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_cistatic struct omap8250_dma_params am33xx_dma = {
12678c2ecf20Sopenharmony_ci	.rx_size = RX_TRIGGER,
12688c2ecf20Sopenharmony_ci	.rx_trigger = RX_TRIGGER,
12698c2ecf20Sopenharmony_ci	.tx_trigger = TX_TRIGGER,
12708c2ecf20Sopenharmony_ci};
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_cistatic struct omap8250_platdata am654_platdata = {
12738c2ecf20Sopenharmony_ci	.dma_params	= &am654_dma,
12748c2ecf20Sopenharmony_ci	.habit		= UART_HAS_EFR2 | UART_HAS_RHR_IT_DIS |
12758c2ecf20Sopenharmony_ci			  UART_RX_TIMEOUT_QUIRK,
12768c2ecf20Sopenharmony_ci};
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_cistatic struct omap8250_platdata am33xx_platdata = {
12798c2ecf20Sopenharmony_ci	.dma_params	= &am33xx_dma,
12808c2ecf20Sopenharmony_ci	.habit		= OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE,
12818c2ecf20Sopenharmony_ci};
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_cistatic struct omap8250_platdata omap4_platdata = {
12848c2ecf20Sopenharmony_ci	.dma_params	= &am33xx_dma,
12858c2ecf20Sopenharmony_ci	.habit		= UART_ERRATA_CLOCK_DISABLE,
12868c2ecf20Sopenharmony_ci};
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_cistatic const struct of_device_id omap8250_dt_ids[] = {
12898c2ecf20Sopenharmony_ci	{ .compatible = "ti,am654-uart", .data = &am654_platdata, },
12908c2ecf20Sopenharmony_ci	{ .compatible = "ti,omap2-uart" },
12918c2ecf20Sopenharmony_ci	{ .compatible = "ti,omap3-uart" },
12928c2ecf20Sopenharmony_ci	{ .compatible = "ti,omap4-uart", .data = &omap4_platdata, },
12938c2ecf20Sopenharmony_ci	{ .compatible = "ti,am3352-uart", .data = &am33xx_platdata, },
12948c2ecf20Sopenharmony_ci	{ .compatible = "ti,am4372-uart", .data = &am33xx_platdata, },
12958c2ecf20Sopenharmony_ci	{ .compatible = "ti,dra742-uart", .data = &omap4_platdata, },
12968c2ecf20Sopenharmony_ci	{},
12978c2ecf20Sopenharmony_ci};
12988c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, omap8250_dt_ids);
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_cistatic int omap8250_probe(struct platform_device *pdev)
13018c2ecf20Sopenharmony_ci{
13028c2ecf20Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
13038c2ecf20Sopenharmony_ci	struct omap8250_priv *priv;
13048c2ecf20Sopenharmony_ci	const struct omap8250_platdata *pdata;
13058c2ecf20Sopenharmony_ci	struct uart_8250_port up;
13068c2ecf20Sopenharmony_ci	struct resource *regs;
13078c2ecf20Sopenharmony_ci	void __iomem *membase;
13088c2ecf20Sopenharmony_ci	int irq, ret;
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
13118c2ecf20Sopenharmony_ci	if (irq < 0)
13128c2ecf20Sopenharmony_ci		return irq;
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
13158c2ecf20Sopenharmony_ci	if (!regs) {
13168c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "missing registers\n");
13178c2ecf20Sopenharmony_ci		return -EINVAL;
13188c2ecf20Sopenharmony_ci	}
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
13218c2ecf20Sopenharmony_ci	if (!priv)
13228c2ecf20Sopenharmony_ci		return -ENOMEM;
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci	membase = devm_ioremap(&pdev->dev, regs->start,
13258c2ecf20Sopenharmony_ci				       resource_size(regs));
13268c2ecf20Sopenharmony_ci	if (!membase)
13278c2ecf20Sopenharmony_ci		return -ENODEV;
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	memset(&up, 0, sizeof(up));
13308c2ecf20Sopenharmony_ci	up.port.dev = &pdev->dev;
13318c2ecf20Sopenharmony_ci	up.port.mapbase = regs->start;
13328c2ecf20Sopenharmony_ci	up.port.membase = membase;
13338c2ecf20Sopenharmony_ci	up.port.irq = irq;
13348c2ecf20Sopenharmony_ci	/*
13358c2ecf20Sopenharmony_ci	 * It claims to be 16C750 compatible however it is a little different.
13368c2ecf20Sopenharmony_ci	 * It has EFR and has no FCR7_64byte bit. The AFE (which it claims to
13378c2ecf20Sopenharmony_ci	 * have) is enabled via EFR instead of MCR. The type is set here 8250
13388c2ecf20Sopenharmony_ci	 * just to get things going. UNKNOWN does not work for a few reasons and
13398c2ecf20Sopenharmony_ci	 * we don't need our own type since we don't use 8250's set_termios()
13408c2ecf20Sopenharmony_ci	 * or pm callback.
13418c2ecf20Sopenharmony_ci	 */
13428c2ecf20Sopenharmony_ci	up.port.type = PORT_8250;
13438c2ecf20Sopenharmony_ci	up.port.iotype = UPIO_MEM;
13448c2ecf20Sopenharmony_ci	up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SOFT_FLOW |
13458c2ecf20Sopenharmony_ci		UPF_HARD_FLOW;
13468c2ecf20Sopenharmony_ci	up.port.private_data = priv;
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	up.port.regshift = OMAP_UART_REGSHIFT;
13498c2ecf20Sopenharmony_ci	up.port.fifosize = 64;
13508c2ecf20Sopenharmony_ci	up.tx_loadsz = 64;
13518c2ecf20Sopenharmony_ci	up.capabilities = UART_CAP_FIFO;
13528c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
13538c2ecf20Sopenharmony_ci	/*
13548c2ecf20Sopenharmony_ci	 * Runtime PM is mostly transparent. However to do it right we need to a
13558c2ecf20Sopenharmony_ci	 * TX empty interrupt before we can put the device to auto idle. So if
13568c2ecf20Sopenharmony_ci	 * PM is not enabled we don't add that flag and can spare that one extra
13578c2ecf20Sopenharmony_ci	 * interrupt in the TX path.
13588c2ecf20Sopenharmony_ci	 */
13598c2ecf20Sopenharmony_ci	up.capabilities |= UART_CAP_RPM;
13608c2ecf20Sopenharmony_ci#endif
13618c2ecf20Sopenharmony_ci	up.port.set_termios = omap_8250_set_termios;
13628c2ecf20Sopenharmony_ci	up.port.set_mctrl = omap8250_set_mctrl;
13638c2ecf20Sopenharmony_ci	up.port.pm = omap_8250_pm;
13648c2ecf20Sopenharmony_ci	up.port.startup = omap_8250_startup;
13658c2ecf20Sopenharmony_ci	up.port.shutdown = omap_8250_shutdown;
13668c2ecf20Sopenharmony_ci	up.port.throttle = omap_8250_throttle;
13678c2ecf20Sopenharmony_ci	up.port.unthrottle = omap_8250_unthrottle;
13688c2ecf20Sopenharmony_ci	up.port.rs485_config = serial8250_em485_config;
13698c2ecf20Sopenharmony_ci	up.rs485_start_tx = serial8250_em485_start_tx;
13708c2ecf20Sopenharmony_ci	up.rs485_stop_tx = serial8250_em485_stop_tx;
13718c2ecf20Sopenharmony_ci	up.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	ret = of_alias_get_id(np, "serial");
13748c2ecf20Sopenharmony_ci	if (ret < 0) {
13758c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to get alias\n");
13768c2ecf20Sopenharmony_ci		return ret;
13778c2ecf20Sopenharmony_ci	}
13788c2ecf20Sopenharmony_ci	up.port.line = ret;
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci	if (of_property_read_u32(np, "clock-frequency", &up.port.uartclk)) {
13818c2ecf20Sopenharmony_ci		struct clk *clk;
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci		clk = devm_clk_get(&pdev->dev, NULL);
13848c2ecf20Sopenharmony_ci		if (IS_ERR(clk)) {
13858c2ecf20Sopenharmony_ci			if (PTR_ERR(clk) == -EPROBE_DEFER)
13868c2ecf20Sopenharmony_ci				return -EPROBE_DEFER;
13878c2ecf20Sopenharmony_ci		} else {
13888c2ecf20Sopenharmony_ci			up.port.uartclk = clk_get_rate(clk);
13898c2ecf20Sopenharmony_ci		}
13908c2ecf20Sopenharmony_ci	}
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	if (of_property_read_u32(np, "overrun-throttle-ms",
13938c2ecf20Sopenharmony_ci				 &up.overrun_backoff_time_ms) != 0)
13948c2ecf20Sopenharmony_ci		up.overrun_backoff_time_ms = 0;
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci	priv->wakeirq = irq_of_parse_and_map(np, 1);
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	pdata = of_device_get_match_data(&pdev->dev);
13998c2ecf20Sopenharmony_ci	if (pdata)
14008c2ecf20Sopenharmony_ci		priv->habit |= pdata->habit;
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	if (!up.port.uartclk) {
14038c2ecf20Sopenharmony_ci		up.port.uartclk = DEFAULT_CLK_SPEED;
14048c2ecf20Sopenharmony_ci		dev_warn(&pdev->dev,
14058c2ecf20Sopenharmony_ci			 "No clock speed specified: using default: %d\n",
14068c2ecf20Sopenharmony_ci			 DEFAULT_CLK_SPEED);
14078c2ecf20Sopenharmony_ci	}
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	priv->membase = membase;
14108c2ecf20Sopenharmony_ci	priv->line = -ENODEV;
14118c2ecf20Sopenharmony_ci	priv->latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE;
14128c2ecf20Sopenharmony_ci	priv->calc_latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE;
14138c2ecf20Sopenharmony_ci	cpu_latency_qos_add_request(&priv->pm_qos_request, priv->latency);
14148c2ecf20Sopenharmony_ci	INIT_WORK(&priv->qos_work, omap8250_uart_qos_work);
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci	spin_lock_init(&priv->rx_dma_lock);
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, priv);
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	device_init_wakeup(&pdev->dev, true);
14218c2ecf20Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
14228c2ecf20Sopenharmony_ci	pm_runtime_use_autosuspend(&pdev->dev);
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci	/*
14258c2ecf20Sopenharmony_ci	 * Disable runtime PM until autosuspend delay unless specifically
14268c2ecf20Sopenharmony_ci	 * enabled by the user via sysfs. This is the historic way to
14278c2ecf20Sopenharmony_ci	 * prevent an unsafe default policy with lossy characters on wake-up.
14288c2ecf20Sopenharmony_ci	 * For serdev devices this is not needed, the policy can be managed by
14298c2ecf20Sopenharmony_ci	 * the serdev driver.
14308c2ecf20Sopenharmony_ci	 */
14318c2ecf20Sopenharmony_ci	if (!of_get_available_child_count(pdev->dev.of_node))
14328c2ecf20Sopenharmony_ci		pm_runtime_set_autosuspend_delay(&pdev->dev, -1);
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	pm_runtime_irq_safe(&pdev->dev);
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	pm_runtime_get_sync(&pdev->dev);
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	omap_serial_fill_features_erratas(&up, priv);
14398c2ecf20Sopenharmony_ci	up.port.handle_irq = omap8250_no_handle_irq;
14408c2ecf20Sopenharmony_ci	priv->rx_trigger = RX_TRIGGER;
14418c2ecf20Sopenharmony_ci	priv->tx_trigger = TX_TRIGGER;
14428c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_DMA
14438c2ecf20Sopenharmony_ci	/*
14448c2ecf20Sopenharmony_ci	 * Oh DMA support. If there are no DMA properties in the DT then
14458c2ecf20Sopenharmony_ci	 * we will fall back to a generic DMA channel which does not
14468c2ecf20Sopenharmony_ci	 * really work here. To ensure that we do not get a generic DMA
14478c2ecf20Sopenharmony_ci	 * channel assigned, we have the the_no_dma_filter_fn() here.
14488c2ecf20Sopenharmony_ci	 * To avoid "failed to request DMA" messages we check for DMA
14498c2ecf20Sopenharmony_ci	 * properties in DT.
14508c2ecf20Sopenharmony_ci	 */
14518c2ecf20Sopenharmony_ci	ret = of_property_count_strings(np, "dma-names");
14528c2ecf20Sopenharmony_ci	if (ret == 2) {
14538c2ecf20Sopenharmony_ci		struct omap8250_dma_params *dma_params = NULL;
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci		up.dma = &priv->omap8250_dma;
14568c2ecf20Sopenharmony_ci		up.dma->fn = the_no_dma_filter_fn;
14578c2ecf20Sopenharmony_ci		up.dma->tx_dma = omap_8250_tx_dma;
14588c2ecf20Sopenharmony_ci		up.dma->rx_dma = omap_8250_rx_dma;
14598c2ecf20Sopenharmony_ci		if (pdata)
14608c2ecf20Sopenharmony_ci			dma_params = pdata->dma_params;
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci		if (dma_params) {
14638c2ecf20Sopenharmony_ci			up.dma->rx_size = dma_params->rx_size;
14648c2ecf20Sopenharmony_ci			up.dma->rxconf.src_maxburst = dma_params->rx_trigger;
14658c2ecf20Sopenharmony_ci			up.dma->txconf.dst_maxburst = dma_params->tx_trigger;
14668c2ecf20Sopenharmony_ci			priv->rx_trigger = dma_params->rx_trigger;
14678c2ecf20Sopenharmony_ci			priv->tx_trigger = dma_params->tx_trigger;
14688c2ecf20Sopenharmony_ci		} else {
14698c2ecf20Sopenharmony_ci			up.dma->rx_size = RX_TRIGGER;
14708c2ecf20Sopenharmony_ci			up.dma->rxconf.src_maxburst = RX_TRIGGER;
14718c2ecf20Sopenharmony_ci			up.dma->txconf.dst_maxburst = TX_TRIGGER;
14728c2ecf20Sopenharmony_ci		}
14738c2ecf20Sopenharmony_ci	}
14748c2ecf20Sopenharmony_ci#endif
14758c2ecf20Sopenharmony_ci	ret = serial8250_register_8250_port(&up);
14768c2ecf20Sopenharmony_ci	if (ret < 0) {
14778c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "unable to register 8250 port\n");
14788c2ecf20Sopenharmony_ci		goto err;
14798c2ecf20Sopenharmony_ci	}
14808c2ecf20Sopenharmony_ci	priv->line = ret;
14818c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(&pdev->dev);
14828c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(&pdev->dev);
14838c2ecf20Sopenharmony_ci	return 0;
14848c2ecf20Sopenharmony_cierr:
14858c2ecf20Sopenharmony_ci	pm_runtime_dont_use_autosuspend(&pdev->dev);
14868c2ecf20Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
14878c2ecf20Sopenharmony_ci	flush_work(&priv->qos_work);
14888c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
14898c2ecf20Sopenharmony_ci	cpu_latency_qos_remove_request(&priv->pm_qos_request);
14908c2ecf20Sopenharmony_ci	return ret;
14918c2ecf20Sopenharmony_ci}
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_cistatic int omap8250_remove(struct platform_device *pdev)
14948c2ecf20Sopenharmony_ci{
14958c2ecf20Sopenharmony_ci	struct omap8250_priv *priv = platform_get_drvdata(pdev);
14968c2ecf20Sopenharmony_ci	int err;
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	err = pm_runtime_resume_and_get(&pdev->dev);
14998c2ecf20Sopenharmony_ci	if (err)
15008c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Failed to resume hardware\n");
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	serial8250_unregister_port(priv->line);
15038c2ecf20Sopenharmony_ci	priv->line = -ENODEV;
15048c2ecf20Sopenharmony_ci	pm_runtime_dont_use_autosuspend(&pdev->dev);
15058c2ecf20Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
15068c2ecf20Sopenharmony_ci	flush_work(&priv->qos_work);
15078c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
15088c2ecf20Sopenharmony_ci	cpu_latency_qos_remove_request(&priv->pm_qos_request);
15098c2ecf20Sopenharmony_ci	device_init_wakeup(&pdev->dev, false);
15108c2ecf20Sopenharmony_ci	return 0;
15118c2ecf20Sopenharmony_ci}
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
15148c2ecf20Sopenharmony_cistatic int omap8250_prepare(struct device *dev)
15158c2ecf20Sopenharmony_ci{
15168c2ecf20Sopenharmony_ci	struct omap8250_priv *priv = dev_get_drvdata(dev);
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	if (!priv)
15198c2ecf20Sopenharmony_ci		return 0;
15208c2ecf20Sopenharmony_ci	priv->is_suspending = true;
15218c2ecf20Sopenharmony_ci	return 0;
15228c2ecf20Sopenharmony_ci}
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_cistatic void omap8250_complete(struct device *dev)
15258c2ecf20Sopenharmony_ci{
15268c2ecf20Sopenharmony_ci	struct omap8250_priv *priv = dev_get_drvdata(dev);
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	if (!priv)
15298c2ecf20Sopenharmony_ci		return;
15308c2ecf20Sopenharmony_ci	priv->is_suspending = false;
15318c2ecf20Sopenharmony_ci}
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_cistatic int omap8250_suspend(struct device *dev)
15348c2ecf20Sopenharmony_ci{
15358c2ecf20Sopenharmony_ci	struct omap8250_priv *priv = dev_get_drvdata(dev);
15368c2ecf20Sopenharmony_ci	struct uart_8250_port *up = serial8250_get_port(priv->line);
15378c2ecf20Sopenharmony_ci	int err = 0;
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	serial8250_suspend_port(priv->line);
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	err = pm_runtime_resume_and_get(dev);
15428c2ecf20Sopenharmony_ci	if (err)
15438c2ecf20Sopenharmony_ci		return err;
15448c2ecf20Sopenharmony_ci	if (!device_may_wakeup(dev))
15458c2ecf20Sopenharmony_ci		priv->wer = 0;
15468c2ecf20Sopenharmony_ci	serial_out(up, UART_OMAP_WER, priv->wer);
15478c2ecf20Sopenharmony_ci	if (uart_console(&up->port) && console_suspend_enabled)
15488c2ecf20Sopenharmony_ci		err = pm_runtime_force_suspend(dev);
15498c2ecf20Sopenharmony_ci	flush_work(&priv->qos_work);
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci	return err;
15528c2ecf20Sopenharmony_ci}
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_cistatic int omap8250_resume(struct device *dev)
15558c2ecf20Sopenharmony_ci{
15568c2ecf20Sopenharmony_ci	struct omap8250_priv *priv = dev_get_drvdata(dev);
15578c2ecf20Sopenharmony_ci	struct uart_8250_port *up = serial8250_get_port(priv->line);
15588c2ecf20Sopenharmony_ci	int err;
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	if (uart_console(&up->port) && console_suspend_enabled) {
15618c2ecf20Sopenharmony_ci		err = pm_runtime_force_resume(dev);
15628c2ecf20Sopenharmony_ci		if (err)
15638c2ecf20Sopenharmony_ci			return err;
15648c2ecf20Sopenharmony_ci	}
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	serial8250_resume_port(priv->line);
15678c2ecf20Sopenharmony_ci	/* Paired with pm_runtime_resume_and_get() in omap8250_suspend() */
15688c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(dev);
15698c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(dev);
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	return 0;
15728c2ecf20Sopenharmony_ci}
15738c2ecf20Sopenharmony_ci#else
15748c2ecf20Sopenharmony_ci#define omap8250_prepare NULL
15758c2ecf20Sopenharmony_ci#define omap8250_complete NULL
15768c2ecf20Sopenharmony_ci#endif
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
15798c2ecf20Sopenharmony_cistatic int omap8250_lost_context(struct uart_8250_port *up)
15808c2ecf20Sopenharmony_ci{
15818c2ecf20Sopenharmony_ci	u32 val;
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	val = serial_in(up, UART_OMAP_SCR);
15848c2ecf20Sopenharmony_ci	/*
15858c2ecf20Sopenharmony_ci	 * If we lose context, then SCR is set to its reset value of zero.
15868c2ecf20Sopenharmony_ci	 * After set_termios() we set bit 3 of SCR (TX_EMPTY_CTL_IT) to 1,
15878c2ecf20Sopenharmony_ci	 * among other bits, to never set the register back to zero again.
15888c2ecf20Sopenharmony_ci	 */
15898c2ecf20Sopenharmony_ci	if (!val)
15908c2ecf20Sopenharmony_ci		return 1;
15918c2ecf20Sopenharmony_ci	return 0;
15928c2ecf20Sopenharmony_ci}
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_ci/* TODO: in future, this should happen via API in drivers/reset/ */
15958c2ecf20Sopenharmony_cistatic int omap8250_soft_reset(struct device *dev)
15968c2ecf20Sopenharmony_ci{
15978c2ecf20Sopenharmony_ci	struct omap8250_priv *priv = dev_get_drvdata(dev);
15988c2ecf20Sopenharmony_ci	int timeout = 100;
15998c2ecf20Sopenharmony_ci	int sysc;
16008c2ecf20Sopenharmony_ci	int syss;
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci	/*
16038c2ecf20Sopenharmony_ci	 * At least on omap4, unused uarts may not idle after reset without
16048c2ecf20Sopenharmony_ci	 * a basic scr dma configuration even with no dma in use. The
16058c2ecf20Sopenharmony_ci	 * module clkctrl status bits will be 1 instead of 3 blocking idle
16068c2ecf20Sopenharmony_ci	 * for the whole clockdomain. The softreset below will clear scr,
16078c2ecf20Sopenharmony_ci	 * and we restore it on resume so this is safe to do on all SoCs
16088c2ecf20Sopenharmony_ci	 * needing omap8250_soft_reset() quirk. Do it in two writes as
16098c2ecf20Sopenharmony_ci	 * recommended in the comment for omap8250_update_scr().
16108c2ecf20Sopenharmony_ci	 */
16118c2ecf20Sopenharmony_ci	uart_write(priv, UART_OMAP_SCR, OMAP_UART_SCR_DMAMODE_1);
16128c2ecf20Sopenharmony_ci	uart_write(priv, UART_OMAP_SCR,
16138c2ecf20Sopenharmony_ci		   OMAP_UART_SCR_DMAMODE_1 | OMAP_UART_SCR_DMAMODE_CTL);
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	sysc = uart_read(priv, UART_OMAP_SYSC);
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	/* softreset the UART */
16188c2ecf20Sopenharmony_ci	sysc |= OMAP_UART_SYSC_SOFTRESET;
16198c2ecf20Sopenharmony_ci	uart_write(priv, UART_OMAP_SYSC, sysc);
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	/* By experiments, 1us enough for reset complete on AM335x */
16228c2ecf20Sopenharmony_ci	do {
16238c2ecf20Sopenharmony_ci		udelay(1);
16248c2ecf20Sopenharmony_ci		syss = uart_read(priv, UART_OMAP_SYSS);
16258c2ecf20Sopenharmony_ci	} while (--timeout && !(syss & OMAP_UART_SYSS_RESETDONE));
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci	if (!timeout) {
16288c2ecf20Sopenharmony_ci		dev_err(dev, "timed out waiting for reset done\n");
16298c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
16308c2ecf20Sopenharmony_ci	}
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	return 0;
16338c2ecf20Sopenharmony_ci}
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_cistatic int omap8250_runtime_suspend(struct device *dev)
16368c2ecf20Sopenharmony_ci{
16378c2ecf20Sopenharmony_ci	struct omap8250_priv *priv = dev_get_drvdata(dev);
16388c2ecf20Sopenharmony_ci	struct uart_8250_port *up = NULL;
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_ci	if (priv->line >= 0)
16418c2ecf20Sopenharmony_ci		up = serial8250_get_port(priv->line);
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ci	if (priv->habit & UART_ERRATA_CLOCK_DISABLE) {
16448c2ecf20Sopenharmony_ci		int ret;
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci		ret = omap8250_soft_reset(dev);
16478c2ecf20Sopenharmony_ci		if (ret)
16488c2ecf20Sopenharmony_ci			return ret;
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_ci		if (up) {
16518c2ecf20Sopenharmony_ci			/* Restore to UART mode after reset (for wakeup) */
16528c2ecf20Sopenharmony_ci			omap8250_update_mdr1(up, priv);
16538c2ecf20Sopenharmony_ci			/* Restore wakeup enable register */
16548c2ecf20Sopenharmony_ci			serial_out(up, UART_OMAP_WER, priv->wer);
16558c2ecf20Sopenharmony_ci		}
16568c2ecf20Sopenharmony_ci	}
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci	if (up && up->dma && up->dma->rxchan)
16598c2ecf20Sopenharmony_ci		omap_8250_rx_dma_flush(up);
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci	priv->latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE;
16628c2ecf20Sopenharmony_ci	schedule_work(&priv->qos_work);
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci	return 0;
16658c2ecf20Sopenharmony_ci}
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_cistatic int omap8250_runtime_resume(struct device *dev)
16688c2ecf20Sopenharmony_ci{
16698c2ecf20Sopenharmony_ci	struct omap8250_priv *priv = dev_get_drvdata(dev);
16708c2ecf20Sopenharmony_ci	struct uart_8250_port *up = NULL;
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci	if (priv->line >= 0)
16738c2ecf20Sopenharmony_ci		up = serial8250_get_port(priv->line);
16748c2ecf20Sopenharmony_ci
16758c2ecf20Sopenharmony_ci	if (up && omap8250_lost_context(up))
16768c2ecf20Sopenharmony_ci		omap8250_restore_regs(up);
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	if (up && up->dma && up->dma->rxchan && !(priv->habit & UART_HAS_EFR2))
16798c2ecf20Sopenharmony_ci		omap_8250_rx_dma(up);
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	priv->latency = priv->calc_latency;
16828c2ecf20Sopenharmony_ci	schedule_work(&priv->qos_work);
16838c2ecf20Sopenharmony_ci	return 0;
16848c2ecf20Sopenharmony_ci}
16858c2ecf20Sopenharmony_ci#endif
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_OMAP_TTYO_FIXUP
16888c2ecf20Sopenharmony_cistatic int __init omap8250_console_fixup(void)
16898c2ecf20Sopenharmony_ci{
16908c2ecf20Sopenharmony_ci	char *omap_str;
16918c2ecf20Sopenharmony_ci	char *options;
16928c2ecf20Sopenharmony_ci	u8 idx;
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci	if (strstr(boot_command_line, "console=ttyS"))
16958c2ecf20Sopenharmony_ci		/* user set a ttyS based name for the console */
16968c2ecf20Sopenharmony_ci		return 0;
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci	omap_str = strstr(boot_command_line, "console=ttyO");
16998c2ecf20Sopenharmony_ci	if (!omap_str)
17008c2ecf20Sopenharmony_ci		/* user did not set ttyO based console, so we don't care */
17018c2ecf20Sopenharmony_ci		return 0;
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci	omap_str += 12;
17048c2ecf20Sopenharmony_ci	if ('0' <= *omap_str && *omap_str <= '9')
17058c2ecf20Sopenharmony_ci		idx = *omap_str - '0';
17068c2ecf20Sopenharmony_ci	else
17078c2ecf20Sopenharmony_ci		return 0;
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci	omap_str++;
17108c2ecf20Sopenharmony_ci	if (omap_str[0] == ',') {
17118c2ecf20Sopenharmony_ci		omap_str++;
17128c2ecf20Sopenharmony_ci		options = omap_str;
17138c2ecf20Sopenharmony_ci	} else {
17148c2ecf20Sopenharmony_ci		options = NULL;
17158c2ecf20Sopenharmony_ci	}
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci	add_preferred_console("ttyS", idx, options);
17188c2ecf20Sopenharmony_ci	pr_err("WARNING: Your 'console=ttyO%d' has been replaced by 'ttyS%d'\n",
17198c2ecf20Sopenharmony_ci	       idx, idx);
17208c2ecf20Sopenharmony_ci	pr_err("This ensures that you still see kernel messages. Please\n");
17218c2ecf20Sopenharmony_ci	pr_err("update your kernel commandline.\n");
17228c2ecf20Sopenharmony_ci	return 0;
17238c2ecf20Sopenharmony_ci}
17248c2ecf20Sopenharmony_ciconsole_initcall(omap8250_console_fixup);
17258c2ecf20Sopenharmony_ci#endif
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_cistatic const struct dev_pm_ops omap8250_dev_pm_ops = {
17288c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(omap8250_suspend, omap8250_resume)
17298c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(omap8250_runtime_suspend,
17308c2ecf20Sopenharmony_ci			   omap8250_runtime_resume, NULL)
17318c2ecf20Sopenharmony_ci	.prepare        = omap8250_prepare,
17328c2ecf20Sopenharmony_ci	.complete       = omap8250_complete,
17338c2ecf20Sopenharmony_ci};
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_cistatic struct platform_driver omap8250_platform_driver = {
17368c2ecf20Sopenharmony_ci	.driver = {
17378c2ecf20Sopenharmony_ci		.name		= "omap8250",
17388c2ecf20Sopenharmony_ci		.pm		= &omap8250_dev_pm_ops,
17398c2ecf20Sopenharmony_ci		.of_match_table = omap8250_dt_ids,
17408c2ecf20Sopenharmony_ci	},
17418c2ecf20Sopenharmony_ci	.probe			= omap8250_probe,
17428c2ecf20Sopenharmony_ci	.remove			= omap8250_remove,
17438c2ecf20Sopenharmony_ci};
17448c2ecf20Sopenharmony_cimodule_platform_driver(omap8250_platform_driver);
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sebastian Andrzej Siewior");
17478c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("OMAP 8250 Driver");
17488c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
1749