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