18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Base port operations for 8250/16550-type serial ports 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. 68c2ecf20Sopenharmony_ci * Split from 8250_core.c, Copyright (C) 2001 Russell King. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * A note about mapbase / membase 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * mapbase is the physical address of the IO port. 118c2ecf20Sopenharmony_ci * membase is an 'ioremapped' cookie. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 168c2ecf20Sopenharmony_ci#include <linux/ioport.h> 178c2ecf20Sopenharmony_ci#include <linux/init.h> 188c2ecf20Sopenharmony_ci#include <linux/irq.h> 198c2ecf20Sopenharmony_ci#include <linux/console.h> 208c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 218c2ecf20Sopenharmony_ci#include <linux/sysrq.h> 228c2ecf20Sopenharmony_ci#include <linux/delay.h> 238c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 248c2ecf20Sopenharmony_ci#include <linux/tty.h> 258c2ecf20Sopenharmony_ci#include <linux/ratelimit.h> 268c2ecf20Sopenharmony_ci#include <linux/tty_flip.h> 278c2ecf20Sopenharmony_ci#include <linux/serial.h> 288c2ecf20Sopenharmony_ci#include <linux/serial_8250.h> 298c2ecf20Sopenharmony_ci#include <linux/nmi.h> 308c2ecf20Sopenharmony_ci#include <linux/mutex.h> 318c2ecf20Sopenharmony_ci#include <linux/slab.h> 328c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 338c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 348c2ecf20Sopenharmony_ci#include <linux/ktime.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <asm/io.h> 378c2ecf20Sopenharmony_ci#include <asm/irq.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include "8250.h" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* Nuvoton NPCM timeout register */ 428c2ecf20Sopenharmony_ci#define UART_NPCM_TOR 7 438c2ecf20Sopenharmony_ci#define UART_NPCM_TOIE BIT(7) /* Timeout Interrupt Enable */ 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* 468c2ecf20Sopenharmony_ci * Debugging. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ci#if 0 498c2ecf20Sopenharmony_ci#define DEBUG_AUTOCONF(fmt...) printk(fmt) 508c2ecf20Sopenharmony_ci#else 518c2ecf20Sopenharmony_ci#define DEBUG_AUTOCONF(fmt...) do { } while (0) 528c2ecf20Sopenharmony_ci#endif 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* 578c2ecf20Sopenharmony_ci * Here we define the default xmit fifo size used for each type of UART. 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_cistatic const struct serial8250_config uart_config[] = { 608c2ecf20Sopenharmony_ci [PORT_UNKNOWN] = { 618c2ecf20Sopenharmony_ci .name = "unknown", 628c2ecf20Sopenharmony_ci .fifo_size = 1, 638c2ecf20Sopenharmony_ci .tx_loadsz = 1, 648c2ecf20Sopenharmony_ci }, 658c2ecf20Sopenharmony_ci [PORT_8250] = { 668c2ecf20Sopenharmony_ci .name = "8250", 678c2ecf20Sopenharmony_ci .fifo_size = 1, 688c2ecf20Sopenharmony_ci .tx_loadsz = 1, 698c2ecf20Sopenharmony_ci }, 708c2ecf20Sopenharmony_ci [PORT_16450] = { 718c2ecf20Sopenharmony_ci .name = "16450", 728c2ecf20Sopenharmony_ci .fifo_size = 1, 738c2ecf20Sopenharmony_ci .tx_loadsz = 1, 748c2ecf20Sopenharmony_ci }, 758c2ecf20Sopenharmony_ci [PORT_16550] = { 768c2ecf20Sopenharmony_ci .name = "16550", 778c2ecf20Sopenharmony_ci .fifo_size = 1, 788c2ecf20Sopenharmony_ci .tx_loadsz = 1, 798c2ecf20Sopenharmony_ci }, 808c2ecf20Sopenharmony_ci [PORT_16550A] = { 818c2ecf20Sopenharmony_ci .name = "16550A", 828c2ecf20Sopenharmony_ci .fifo_size = 16, 838c2ecf20Sopenharmony_ci .tx_loadsz = 16, 848c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, 858c2ecf20Sopenharmony_ci .rxtrig_bytes = {1, 4, 8, 14}, 868c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO, 878c2ecf20Sopenharmony_ci }, 888c2ecf20Sopenharmony_ci [PORT_CIRRUS] = { 898c2ecf20Sopenharmony_ci .name = "Cirrus", 908c2ecf20Sopenharmony_ci .fifo_size = 1, 918c2ecf20Sopenharmony_ci .tx_loadsz = 1, 928c2ecf20Sopenharmony_ci }, 938c2ecf20Sopenharmony_ci [PORT_16650] = { 948c2ecf20Sopenharmony_ci .name = "ST16650", 958c2ecf20Sopenharmony_ci .fifo_size = 1, 968c2ecf20Sopenharmony_ci .tx_loadsz = 1, 978c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, 988c2ecf20Sopenharmony_ci }, 998c2ecf20Sopenharmony_ci [PORT_16650V2] = { 1008c2ecf20Sopenharmony_ci .name = "ST16650V2", 1018c2ecf20Sopenharmony_ci .fifo_size = 32, 1028c2ecf20Sopenharmony_ci .tx_loadsz = 16, 1038c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | 1048c2ecf20Sopenharmony_ci UART_FCR_T_TRIG_00, 1058c2ecf20Sopenharmony_ci .rxtrig_bytes = {8, 16, 24, 28}, 1068c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, 1078c2ecf20Sopenharmony_ci }, 1088c2ecf20Sopenharmony_ci [PORT_16750] = { 1098c2ecf20Sopenharmony_ci .name = "TI16750", 1108c2ecf20Sopenharmony_ci .fifo_size = 64, 1118c2ecf20Sopenharmony_ci .tx_loadsz = 64, 1128c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | 1138c2ecf20Sopenharmony_ci UART_FCR7_64BYTE, 1148c2ecf20Sopenharmony_ci .rxtrig_bytes = {1, 16, 32, 56}, 1158c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE, 1168c2ecf20Sopenharmony_ci }, 1178c2ecf20Sopenharmony_ci [PORT_STARTECH] = { 1188c2ecf20Sopenharmony_ci .name = "Startech", 1198c2ecf20Sopenharmony_ci .fifo_size = 1, 1208c2ecf20Sopenharmony_ci .tx_loadsz = 1, 1218c2ecf20Sopenharmony_ci }, 1228c2ecf20Sopenharmony_ci [PORT_16C950] = { 1238c2ecf20Sopenharmony_ci .name = "16C950/954", 1248c2ecf20Sopenharmony_ci .fifo_size = 128, 1258c2ecf20Sopenharmony_ci .tx_loadsz = 128, 1268c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01, 1278c2ecf20Sopenharmony_ci .rxtrig_bytes = {16, 32, 112, 120}, 1288c2ecf20Sopenharmony_ci /* UART_CAP_EFR breaks billionon CF bluetooth card. */ 1298c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO | UART_CAP_SLEEP, 1308c2ecf20Sopenharmony_ci }, 1318c2ecf20Sopenharmony_ci [PORT_16654] = { 1328c2ecf20Sopenharmony_ci .name = "ST16654", 1338c2ecf20Sopenharmony_ci .fifo_size = 64, 1348c2ecf20Sopenharmony_ci .tx_loadsz = 32, 1358c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | 1368c2ecf20Sopenharmony_ci UART_FCR_T_TRIG_10, 1378c2ecf20Sopenharmony_ci .rxtrig_bytes = {8, 16, 56, 60}, 1388c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, 1398c2ecf20Sopenharmony_ci }, 1408c2ecf20Sopenharmony_ci [PORT_16850] = { 1418c2ecf20Sopenharmony_ci .name = "XR16850", 1428c2ecf20Sopenharmony_ci .fifo_size = 128, 1438c2ecf20Sopenharmony_ci .tx_loadsz = 128, 1448c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, 1458c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, 1468c2ecf20Sopenharmony_ci }, 1478c2ecf20Sopenharmony_ci [PORT_RSA] = { 1488c2ecf20Sopenharmony_ci .name = "RSA", 1498c2ecf20Sopenharmony_ci .fifo_size = 2048, 1508c2ecf20Sopenharmony_ci .tx_loadsz = 2048, 1518c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11, 1528c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO, 1538c2ecf20Sopenharmony_ci }, 1548c2ecf20Sopenharmony_ci [PORT_NS16550A] = { 1558c2ecf20Sopenharmony_ci .name = "NS16550A", 1568c2ecf20Sopenharmony_ci .fifo_size = 16, 1578c2ecf20Sopenharmony_ci .tx_loadsz = 16, 1588c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, 1598c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO | UART_NATSEMI, 1608c2ecf20Sopenharmony_ci }, 1618c2ecf20Sopenharmony_ci [PORT_XSCALE] = { 1628c2ecf20Sopenharmony_ci .name = "XScale", 1638c2ecf20Sopenharmony_ci .fifo_size = 32, 1648c2ecf20Sopenharmony_ci .tx_loadsz = 32, 1658c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, 1668c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO | UART_CAP_UUE | UART_CAP_RTOIE, 1678c2ecf20Sopenharmony_ci }, 1688c2ecf20Sopenharmony_ci [PORT_OCTEON] = { 1698c2ecf20Sopenharmony_ci .name = "OCTEON", 1708c2ecf20Sopenharmony_ci .fifo_size = 64, 1718c2ecf20Sopenharmony_ci .tx_loadsz = 64, 1728c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, 1738c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO, 1748c2ecf20Sopenharmony_ci }, 1758c2ecf20Sopenharmony_ci [PORT_AR7] = { 1768c2ecf20Sopenharmony_ci .name = "AR7", 1778c2ecf20Sopenharmony_ci .fifo_size = 16, 1788c2ecf20Sopenharmony_ci .tx_loadsz = 16, 1798c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, 1808c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO /* | UART_CAP_AFE */, 1818c2ecf20Sopenharmony_ci }, 1828c2ecf20Sopenharmony_ci [PORT_U6_16550A] = { 1838c2ecf20Sopenharmony_ci .name = "U6_16550A", 1848c2ecf20Sopenharmony_ci .fifo_size = 64, 1858c2ecf20Sopenharmony_ci .tx_loadsz = 64, 1868c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, 1878c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO | UART_CAP_AFE, 1888c2ecf20Sopenharmony_ci }, 1898c2ecf20Sopenharmony_ci [PORT_TEGRA] = { 1908c2ecf20Sopenharmony_ci .name = "Tegra", 1918c2ecf20Sopenharmony_ci .fifo_size = 32, 1928c2ecf20Sopenharmony_ci .tx_loadsz = 8, 1938c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | 1948c2ecf20Sopenharmony_ci UART_FCR_T_TRIG_01, 1958c2ecf20Sopenharmony_ci .rxtrig_bytes = {1, 4, 8, 14}, 1968c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO | UART_CAP_RTOIE, 1978c2ecf20Sopenharmony_ci }, 1988c2ecf20Sopenharmony_ci [PORT_XR17D15X] = { 1998c2ecf20Sopenharmony_ci .name = "XR17D15X", 2008c2ecf20Sopenharmony_ci .fifo_size = 64, 2018c2ecf20Sopenharmony_ci .tx_loadsz = 64, 2028c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, 2038c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR | 2048c2ecf20Sopenharmony_ci UART_CAP_SLEEP, 2058c2ecf20Sopenharmony_ci }, 2068c2ecf20Sopenharmony_ci [PORT_XR17V35X] = { 2078c2ecf20Sopenharmony_ci .name = "XR17V35X", 2088c2ecf20Sopenharmony_ci .fifo_size = 256, 2098c2ecf20Sopenharmony_ci .tx_loadsz = 256, 2108c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11 | 2118c2ecf20Sopenharmony_ci UART_FCR_T_TRIG_11, 2128c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR | 2138c2ecf20Sopenharmony_ci UART_CAP_SLEEP, 2148c2ecf20Sopenharmony_ci }, 2158c2ecf20Sopenharmony_ci [PORT_LPC3220] = { 2168c2ecf20Sopenharmony_ci .name = "LPC3220", 2178c2ecf20Sopenharmony_ci .fifo_size = 64, 2188c2ecf20Sopenharmony_ci .tx_loadsz = 32, 2198c2ecf20Sopenharmony_ci .fcr = UART_FCR_DMA_SELECT | UART_FCR_ENABLE_FIFO | 2208c2ecf20Sopenharmony_ci UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00, 2218c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO, 2228c2ecf20Sopenharmony_ci }, 2238c2ecf20Sopenharmony_ci [PORT_BRCM_TRUMANAGE] = { 2248c2ecf20Sopenharmony_ci .name = "TruManage", 2258c2ecf20Sopenharmony_ci .fifo_size = 1, 2268c2ecf20Sopenharmony_ci .tx_loadsz = 1024, 2278c2ecf20Sopenharmony_ci .flags = UART_CAP_HFIFO, 2288c2ecf20Sopenharmony_ci }, 2298c2ecf20Sopenharmony_ci [PORT_8250_CIR] = { 2308c2ecf20Sopenharmony_ci .name = "CIR port" 2318c2ecf20Sopenharmony_ci }, 2328c2ecf20Sopenharmony_ci [PORT_ALTR_16550_F32] = { 2338c2ecf20Sopenharmony_ci .name = "Altera 16550 FIFO32", 2348c2ecf20Sopenharmony_ci .fifo_size = 32, 2358c2ecf20Sopenharmony_ci .tx_loadsz = 32, 2368c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, 2378c2ecf20Sopenharmony_ci .rxtrig_bytes = {1, 8, 16, 30}, 2388c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO | UART_CAP_AFE, 2398c2ecf20Sopenharmony_ci }, 2408c2ecf20Sopenharmony_ci [PORT_ALTR_16550_F64] = { 2418c2ecf20Sopenharmony_ci .name = "Altera 16550 FIFO64", 2428c2ecf20Sopenharmony_ci .fifo_size = 64, 2438c2ecf20Sopenharmony_ci .tx_loadsz = 64, 2448c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, 2458c2ecf20Sopenharmony_ci .rxtrig_bytes = {1, 16, 32, 62}, 2468c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO | UART_CAP_AFE, 2478c2ecf20Sopenharmony_ci }, 2488c2ecf20Sopenharmony_ci [PORT_ALTR_16550_F128] = { 2498c2ecf20Sopenharmony_ci .name = "Altera 16550 FIFO128", 2508c2ecf20Sopenharmony_ci .fifo_size = 128, 2518c2ecf20Sopenharmony_ci .tx_loadsz = 128, 2528c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, 2538c2ecf20Sopenharmony_ci .rxtrig_bytes = {1, 32, 64, 126}, 2548c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO | UART_CAP_AFE, 2558c2ecf20Sopenharmony_ci }, 2568c2ecf20Sopenharmony_ci /* 2578c2ecf20Sopenharmony_ci * tx_loadsz is set to 63-bytes instead of 64-bytes to implement 2588c2ecf20Sopenharmony_ci * workaround of errata A-008006 which states that tx_loadsz should 2598c2ecf20Sopenharmony_ci * be configured less than Maximum supported fifo bytes. 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_ci [PORT_16550A_FSL64] = { 2628c2ecf20Sopenharmony_ci .name = "16550A_FSL64", 2638c2ecf20Sopenharmony_ci .fifo_size = 64, 2648c2ecf20Sopenharmony_ci .tx_loadsz = 63, 2658c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | 2668c2ecf20Sopenharmony_ci UART_FCR7_64BYTE, 2678c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO, 2688c2ecf20Sopenharmony_ci }, 2698c2ecf20Sopenharmony_ci [PORT_RT2880] = { 2708c2ecf20Sopenharmony_ci .name = "Palmchip BK-3103", 2718c2ecf20Sopenharmony_ci .fifo_size = 16, 2728c2ecf20Sopenharmony_ci .tx_loadsz = 16, 2738c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, 2748c2ecf20Sopenharmony_ci .rxtrig_bytes = {1, 4, 8, 14}, 2758c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO, 2768c2ecf20Sopenharmony_ci }, 2778c2ecf20Sopenharmony_ci [PORT_DA830] = { 2788c2ecf20Sopenharmony_ci .name = "TI DA8xx/66AK2x", 2798c2ecf20Sopenharmony_ci .fifo_size = 16, 2808c2ecf20Sopenharmony_ci .tx_loadsz = 16, 2818c2ecf20Sopenharmony_ci .fcr = UART_FCR_DMA_SELECT | UART_FCR_ENABLE_FIFO | 2828c2ecf20Sopenharmony_ci UART_FCR_R_TRIG_10, 2838c2ecf20Sopenharmony_ci .rxtrig_bytes = {1, 4, 8, 14}, 2848c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO | UART_CAP_AFE, 2858c2ecf20Sopenharmony_ci }, 2868c2ecf20Sopenharmony_ci [PORT_MTK_BTIF] = { 2878c2ecf20Sopenharmony_ci .name = "MediaTek BTIF", 2888c2ecf20Sopenharmony_ci .fifo_size = 16, 2898c2ecf20Sopenharmony_ci .tx_loadsz = 16, 2908c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | 2918c2ecf20Sopenharmony_ci UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, 2928c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO, 2938c2ecf20Sopenharmony_ci }, 2948c2ecf20Sopenharmony_ci [PORT_NPCM] = { 2958c2ecf20Sopenharmony_ci .name = "Nuvoton 16550", 2968c2ecf20Sopenharmony_ci .fifo_size = 16, 2978c2ecf20Sopenharmony_ci .tx_loadsz = 16, 2988c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | 2998c2ecf20Sopenharmony_ci UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, 3008c2ecf20Sopenharmony_ci .rxtrig_bytes = {1, 4, 8, 14}, 3018c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO, 3028c2ecf20Sopenharmony_ci }, 3038c2ecf20Sopenharmony_ci [PORT_SUNIX] = { 3048c2ecf20Sopenharmony_ci .name = "Sunix", 3058c2ecf20Sopenharmony_ci .fifo_size = 128, 3068c2ecf20Sopenharmony_ci .tx_loadsz = 128, 3078c2ecf20Sopenharmony_ci .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, 3088c2ecf20Sopenharmony_ci .rxtrig_bytes = {1, 32, 64, 112}, 3098c2ecf20Sopenharmony_ci .flags = UART_CAP_FIFO | UART_CAP_SLEEP, 3108c2ecf20Sopenharmony_ci }, 3118c2ecf20Sopenharmony_ci}; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci/* Uart divisor latch read */ 3148c2ecf20Sopenharmony_cistatic int default_serial_dl_read(struct uart_8250_port *up) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci /* Assign these in pieces to truncate any bits above 7. */ 3178c2ecf20Sopenharmony_ci unsigned char dll = serial_in(up, UART_DLL); 3188c2ecf20Sopenharmony_ci unsigned char dlm = serial_in(up, UART_DLM); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci return dll | dlm << 8; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci/* Uart divisor latch write */ 3248c2ecf20Sopenharmony_cistatic void default_serial_dl_write(struct uart_8250_port *up, int value) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci serial_out(up, UART_DLL, value & 0xff); 3278c2ecf20Sopenharmony_ci serial_out(up, UART_DLM, value >> 8 & 0xff); 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_RT288X 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci/* Au1x00/RT288x UART hardware has a weird register layout */ 3338c2ecf20Sopenharmony_cistatic const s8 au_io_in_map[8] = { 3348c2ecf20Sopenharmony_ci 0, /* UART_RX */ 3358c2ecf20Sopenharmony_ci 2, /* UART_IER */ 3368c2ecf20Sopenharmony_ci 3, /* UART_IIR */ 3378c2ecf20Sopenharmony_ci 5, /* UART_LCR */ 3388c2ecf20Sopenharmony_ci 6, /* UART_MCR */ 3398c2ecf20Sopenharmony_ci 7, /* UART_LSR */ 3408c2ecf20Sopenharmony_ci 8, /* UART_MSR */ 3418c2ecf20Sopenharmony_ci -1, /* UART_SCR (unmapped) */ 3428c2ecf20Sopenharmony_ci}; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic const s8 au_io_out_map[8] = { 3458c2ecf20Sopenharmony_ci 1, /* UART_TX */ 3468c2ecf20Sopenharmony_ci 2, /* UART_IER */ 3478c2ecf20Sopenharmony_ci 4, /* UART_FCR */ 3488c2ecf20Sopenharmony_ci 5, /* UART_LCR */ 3498c2ecf20Sopenharmony_ci 6, /* UART_MCR */ 3508c2ecf20Sopenharmony_ci -1, /* UART_LSR (unmapped) */ 3518c2ecf20Sopenharmony_ci -1, /* UART_MSR (unmapped) */ 3528c2ecf20Sopenharmony_ci -1, /* UART_SCR (unmapped) */ 3538c2ecf20Sopenharmony_ci}; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ciunsigned int au_serial_in(struct uart_port *p, int offset) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci if (offset >= ARRAY_SIZE(au_io_in_map)) 3588c2ecf20Sopenharmony_ci return UINT_MAX; 3598c2ecf20Sopenharmony_ci offset = au_io_in_map[offset]; 3608c2ecf20Sopenharmony_ci if (offset < 0) 3618c2ecf20Sopenharmony_ci return UINT_MAX; 3628c2ecf20Sopenharmony_ci return __raw_readl(p->membase + (offset << p->regshift)); 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_civoid au_serial_out(struct uart_port *p, int offset, int value) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci if (offset >= ARRAY_SIZE(au_io_out_map)) 3688c2ecf20Sopenharmony_ci return; 3698c2ecf20Sopenharmony_ci offset = au_io_out_map[offset]; 3708c2ecf20Sopenharmony_ci if (offset < 0) 3718c2ecf20Sopenharmony_ci return; 3728c2ecf20Sopenharmony_ci __raw_writel(value, p->membase + (offset << p->regshift)); 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci/* Au1x00 haven't got a standard divisor latch */ 3768c2ecf20Sopenharmony_cistatic int au_serial_dl_read(struct uart_8250_port *up) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci return __raw_readl(up->port.membase + 0x28); 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic void au_serial_dl_write(struct uart_8250_port *up, int value) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci __raw_writel(value, up->port.membase + 0x28); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci#endif 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic unsigned int hub6_serial_in(struct uart_port *p, int offset) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci offset = offset << p->regshift; 3918c2ecf20Sopenharmony_ci outb(p->hub6 - 1 + offset, p->iobase); 3928c2ecf20Sopenharmony_ci return inb(p->iobase + 1); 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic void hub6_serial_out(struct uart_port *p, int offset, int value) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci offset = offset << p->regshift; 3988c2ecf20Sopenharmony_ci outb(p->hub6 - 1 + offset, p->iobase); 3998c2ecf20Sopenharmony_ci outb(value, p->iobase + 1); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic unsigned int mem_serial_in(struct uart_port *p, int offset) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci offset = offset << p->regshift; 4058c2ecf20Sopenharmony_ci return readb(p->membase + offset); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic void mem_serial_out(struct uart_port *p, int offset, int value) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci offset = offset << p->regshift; 4118c2ecf20Sopenharmony_ci writeb(value, p->membase + offset); 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic void mem16_serial_out(struct uart_port *p, int offset, int value) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci offset = offset << p->regshift; 4178c2ecf20Sopenharmony_ci writew(value, p->membase + offset); 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic unsigned int mem16_serial_in(struct uart_port *p, int offset) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci offset = offset << p->regshift; 4238c2ecf20Sopenharmony_ci return readw(p->membase + offset); 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic void mem32_serial_out(struct uart_port *p, int offset, int value) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci offset = offset << p->regshift; 4298c2ecf20Sopenharmony_ci writel(value, p->membase + offset); 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic unsigned int mem32_serial_in(struct uart_port *p, int offset) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci offset = offset << p->regshift; 4358c2ecf20Sopenharmony_ci return readl(p->membase + offset); 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic void mem32be_serial_out(struct uart_port *p, int offset, int value) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci offset = offset << p->regshift; 4418c2ecf20Sopenharmony_ci iowrite32be(value, p->membase + offset); 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic unsigned int mem32be_serial_in(struct uart_port *p, int offset) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci offset = offset << p->regshift; 4478c2ecf20Sopenharmony_ci return ioread32be(p->membase + offset); 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic unsigned int io_serial_in(struct uart_port *p, int offset) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci offset = offset << p->regshift; 4538c2ecf20Sopenharmony_ci return inb(p->iobase + offset); 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic void io_serial_out(struct uart_port *p, int offset, int value) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci offset = offset << p->regshift; 4598c2ecf20Sopenharmony_ci outb(value, p->iobase + offset); 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic int serial8250_default_handle_irq(struct uart_port *port); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic void set_io_from_upio(struct uart_port *p) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(p); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci up->dl_read = default_serial_dl_read; 4698c2ecf20Sopenharmony_ci up->dl_write = default_serial_dl_write; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci switch (p->iotype) { 4728c2ecf20Sopenharmony_ci case UPIO_HUB6: 4738c2ecf20Sopenharmony_ci p->serial_in = hub6_serial_in; 4748c2ecf20Sopenharmony_ci p->serial_out = hub6_serial_out; 4758c2ecf20Sopenharmony_ci break; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci case UPIO_MEM: 4788c2ecf20Sopenharmony_ci p->serial_in = mem_serial_in; 4798c2ecf20Sopenharmony_ci p->serial_out = mem_serial_out; 4808c2ecf20Sopenharmony_ci break; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci case UPIO_MEM16: 4838c2ecf20Sopenharmony_ci p->serial_in = mem16_serial_in; 4848c2ecf20Sopenharmony_ci p->serial_out = mem16_serial_out; 4858c2ecf20Sopenharmony_ci break; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci case UPIO_MEM32: 4888c2ecf20Sopenharmony_ci p->serial_in = mem32_serial_in; 4898c2ecf20Sopenharmony_ci p->serial_out = mem32_serial_out; 4908c2ecf20Sopenharmony_ci break; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci case UPIO_MEM32BE: 4938c2ecf20Sopenharmony_ci p->serial_in = mem32be_serial_in; 4948c2ecf20Sopenharmony_ci p->serial_out = mem32be_serial_out; 4958c2ecf20Sopenharmony_ci break; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_RT288X 4988c2ecf20Sopenharmony_ci case UPIO_AU: 4998c2ecf20Sopenharmony_ci p->serial_in = au_serial_in; 5008c2ecf20Sopenharmony_ci p->serial_out = au_serial_out; 5018c2ecf20Sopenharmony_ci up->dl_read = au_serial_dl_read; 5028c2ecf20Sopenharmony_ci up->dl_write = au_serial_dl_write; 5038c2ecf20Sopenharmony_ci break; 5048c2ecf20Sopenharmony_ci#endif 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci default: 5078c2ecf20Sopenharmony_ci p->serial_in = io_serial_in; 5088c2ecf20Sopenharmony_ci p->serial_out = io_serial_out; 5098c2ecf20Sopenharmony_ci break; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci /* Remember loaded iotype */ 5128c2ecf20Sopenharmony_ci up->cur_iotype = p->iotype; 5138c2ecf20Sopenharmony_ci p->handle_irq = serial8250_default_handle_irq; 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic void 5178c2ecf20Sopenharmony_ciserial_port_out_sync(struct uart_port *p, int offset, int value) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci switch (p->iotype) { 5208c2ecf20Sopenharmony_ci case UPIO_MEM: 5218c2ecf20Sopenharmony_ci case UPIO_MEM16: 5228c2ecf20Sopenharmony_ci case UPIO_MEM32: 5238c2ecf20Sopenharmony_ci case UPIO_MEM32BE: 5248c2ecf20Sopenharmony_ci case UPIO_AU: 5258c2ecf20Sopenharmony_ci p->serial_out(p, offset, value); 5268c2ecf20Sopenharmony_ci p->serial_in(p, UART_LCR); /* safe, no side-effects */ 5278c2ecf20Sopenharmony_ci break; 5288c2ecf20Sopenharmony_ci default: 5298c2ecf20Sopenharmony_ci p->serial_out(p, offset, value); 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci/* 5348c2ecf20Sopenharmony_ci * FIFO support. 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_cistatic void serial8250_clear_fifos(struct uart_8250_port *p) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci if (p->capabilities & UART_CAP_FIFO) { 5398c2ecf20Sopenharmony_ci serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO); 5408c2ecf20Sopenharmony_ci serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO | 5418c2ecf20Sopenharmony_ci UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); 5428c2ecf20Sopenharmony_ci serial_out(p, UART_FCR, 0); 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t); 5478c2ecf20Sopenharmony_cistatic enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_civoid serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci serial8250_clear_fifos(p); 5528c2ecf20Sopenharmony_ci serial_out(p, UART_FCR, p->fcr); 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_civoid serial8250_rpm_get(struct uart_8250_port *p) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci if (!(p->capabilities & UART_CAP_RPM)) 5598c2ecf20Sopenharmony_ci return; 5608c2ecf20Sopenharmony_ci pm_runtime_get_sync(p->port.dev); 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_rpm_get); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_civoid serial8250_rpm_put(struct uart_8250_port *p) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci if (!(p->capabilities & UART_CAP_RPM)) 5678c2ecf20Sopenharmony_ci return; 5688c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(p->port.dev); 5698c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(p->port.dev); 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_rpm_put); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci/** 5748c2ecf20Sopenharmony_ci * serial8250_em485_init() - put uart_8250_port into rs485 emulating 5758c2ecf20Sopenharmony_ci * @p: uart_8250_port port instance 5768c2ecf20Sopenharmony_ci * 5778c2ecf20Sopenharmony_ci * The function is used to start rs485 software emulating on the 5788c2ecf20Sopenharmony_ci * &struct uart_8250_port* @p. Namely, RTS is switched before/after 5798c2ecf20Sopenharmony_ci * transmission. The function is idempotent, so it is safe to call it 5808c2ecf20Sopenharmony_ci * multiple times. 5818c2ecf20Sopenharmony_ci * 5828c2ecf20Sopenharmony_ci * The caller MUST enable interrupt on empty shift register before 5838c2ecf20Sopenharmony_ci * calling serial8250_em485_init(). This interrupt is not a part of 5848c2ecf20Sopenharmony_ci * 8250 standard, but implementation defined. 5858c2ecf20Sopenharmony_ci * 5868c2ecf20Sopenharmony_ci * The function is supposed to be called from .rs485_config callback 5878c2ecf20Sopenharmony_ci * or from any other callback protected with p->port.lock spinlock. 5888c2ecf20Sopenharmony_ci * 5898c2ecf20Sopenharmony_ci * See also serial8250_em485_destroy() 5908c2ecf20Sopenharmony_ci * 5918c2ecf20Sopenharmony_ci * Return 0 - success, -errno - otherwise 5928c2ecf20Sopenharmony_ci */ 5938c2ecf20Sopenharmony_cistatic int serial8250_em485_init(struct uart_8250_port *p) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci if (p->em485) 5968c2ecf20Sopenharmony_ci goto deassert_rts; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci p->em485 = kmalloc(sizeof(struct uart_8250_em485), GFP_ATOMIC); 5998c2ecf20Sopenharmony_ci if (!p->em485) 6008c2ecf20Sopenharmony_ci return -ENOMEM; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci hrtimer_init(&p->em485->stop_tx_timer, CLOCK_MONOTONIC, 6038c2ecf20Sopenharmony_ci HRTIMER_MODE_REL); 6048c2ecf20Sopenharmony_ci hrtimer_init(&p->em485->start_tx_timer, CLOCK_MONOTONIC, 6058c2ecf20Sopenharmony_ci HRTIMER_MODE_REL); 6068c2ecf20Sopenharmony_ci p->em485->stop_tx_timer.function = &serial8250_em485_handle_stop_tx; 6078c2ecf20Sopenharmony_ci p->em485->start_tx_timer.function = &serial8250_em485_handle_start_tx; 6088c2ecf20Sopenharmony_ci p->em485->port = p; 6098c2ecf20Sopenharmony_ci p->em485->active_timer = NULL; 6108c2ecf20Sopenharmony_ci p->em485->tx_stopped = true; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cideassert_rts: 6138c2ecf20Sopenharmony_ci if (p->em485->tx_stopped) 6148c2ecf20Sopenharmony_ci p->rs485_stop_tx(p); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci return 0; 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci/** 6208c2ecf20Sopenharmony_ci * serial8250_em485_destroy() - put uart_8250_port into normal state 6218c2ecf20Sopenharmony_ci * @p: uart_8250_port port instance 6228c2ecf20Sopenharmony_ci * 6238c2ecf20Sopenharmony_ci * The function is used to stop rs485 software emulating on the 6248c2ecf20Sopenharmony_ci * &struct uart_8250_port* @p. The function is idempotent, so it is safe to 6258c2ecf20Sopenharmony_ci * call it multiple times. 6268c2ecf20Sopenharmony_ci * 6278c2ecf20Sopenharmony_ci * The function is supposed to be called from .rs485_config callback 6288c2ecf20Sopenharmony_ci * or from any other callback protected with p->port.lock spinlock. 6298c2ecf20Sopenharmony_ci * 6308c2ecf20Sopenharmony_ci * See also serial8250_em485_init() 6318c2ecf20Sopenharmony_ci */ 6328c2ecf20Sopenharmony_civoid serial8250_em485_destroy(struct uart_8250_port *p) 6338c2ecf20Sopenharmony_ci{ 6348c2ecf20Sopenharmony_ci if (!p->em485) 6358c2ecf20Sopenharmony_ci return; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci hrtimer_cancel(&p->em485->start_tx_timer); 6388c2ecf20Sopenharmony_ci hrtimer_cancel(&p->em485->stop_tx_timer); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci kfree(p->em485); 6418c2ecf20Sopenharmony_ci p->em485 = NULL; 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_em485_destroy); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci/** 6468c2ecf20Sopenharmony_ci * serial8250_em485_config() - generic ->rs485_config() callback 6478c2ecf20Sopenharmony_ci * @port: uart port 6488c2ecf20Sopenharmony_ci * @rs485: rs485 settings 6498c2ecf20Sopenharmony_ci * 6508c2ecf20Sopenharmony_ci * Generic callback usable by 8250 uart drivers to activate rs485 settings 6518c2ecf20Sopenharmony_ci * if the uart is incapable of driving RTS as a Transmit Enable signal in 6528c2ecf20Sopenharmony_ci * hardware, relying on software emulation instead. 6538c2ecf20Sopenharmony_ci */ 6548c2ecf20Sopenharmony_ciint serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci /* pick sane settings if the user hasn't */ 6598c2ecf20Sopenharmony_ci if (!!(rs485->flags & SER_RS485_RTS_ON_SEND) == 6608c2ecf20Sopenharmony_ci !!(rs485->flags & SER_RS485_RTS_AFTER_SEND)) { 6618c2ecf20Sopenharmony_ci rs485->flags |= SER_RS485_RTS_ON_SEND; 6628c2ecf20Sopenharmony_ci rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci gpiod_set_value(port->rs485_term_gpio, 6668c2ecf20Sopenharmony_ci rs485->flags & SER_RS485_TERMINATE_BUS); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci /* 6698c2ecf20Sopenharmony_ci * Both serial8250_em485_init() and serial8250_em485_destroy() 6708c2ecf20Sopenharmony_ci * are idempotent. 6718c2ecf20Sopenharmony_ci */ 6728c2ecf20Sopenharmony_ci if (rs485->flags & SER_RS485_ENABLED) 6738c2ecf20Sopenharmony_ci return serial8250_em485_init(up); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci serial8250_em485_destroy(up); 6768c2ecf20Sopenharmony_ci return 0; 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_em485_config); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci/* 6818c2ecf20Sopenharmony_ci * These two wrappers ensure that enable_runtime_pm_tx() can be called more than 6828c2ecf20Sopenharmony_ci * once and disable_runtime_pm_tx() will still disable RPM because the fifo is 6838c2ecf20Sopenharmony_ci * empty and the HW can idle again. 6848c2ecf20Sopenharmony_ci */ 6858c2ecf20Sopenharmony_civoid serial8250_rpm_get_tx(struct uart_8250_port *p) 6868c2ecf20Sopenharmony_ci{ 6878c2ecf20Sopenharmony_ci unsigned char rpm_active; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci if (!(p->capabilities & UART_CAP_RPM)) 6908c2ecf20Sopenharmony_ci return; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci rpm_active = xchg(&p->rpm_tx_active, 1); 6938c2ecf20Sopenharmony_ci if (rpm_active) 6948c2ecf20Sopenharmony_ci return; 6958c2ecf20Sopenharmony_ci pm_runtime_get_sync(p->port.dev); 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_rpm_get_tx); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_civoid serial8250_rpm_put_tx(struct uart_8250_port *p) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci unsigned char rpm_active; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci if (!(p->capabilities & UART_CAP_RPM)) 7048c2ecf20Sopenharmony_ci return; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci rpm_active = xchg(&p->rpm_tx_active, 0); 7078c2ecf20Sopenharmony_ci if (!rpm_active) 7088c2ecf20Sopenharmony_ci return; 7098c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(p->port.dev); 7108c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(p->port.dev); 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_rpm_put_tx); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci/* 7158c2ecf20Sopenharmony_ci * IER sleep support. UARTs which have EFRs need the "extended 7168c2ecf20Sopenharmony_ci * capability" bit enabled. Note that on XR16C850s, we need to 7178c2ecf20Sopenharmony_ci * reset LCR to write to IER. 7188c2ecf20Sopenharmony_ci */ 7198c2ecf20Sopenharmony_cistatic void serial8250_set_sleep(struct uart_8250_port *p, int sleep) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci unsigned char lcr = 0, efr = 0; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci serial8250_rpm_get(p); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci if (p->capabilities & UART_CAP_SLEEP) { 7268c2ecf20Sopenharmony_ci if (p->capabilities & UART_CAP_EFR) { 7278c2ecf20Sopenharmony_ci lcr = serial_in(p, UART_LCR); 7288c2ecf20Sopenharmony_ci efr = serial_in(p, UART_EFR); 7298c2ecf20Sopenharmony_ci serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); 7308c2ecf20Sopenharmony_ci serial_out(p, UART_EFR, UART_EFR_ECB); 7318c2ecf20Sopenharmony_ci serial_out(p, UART_LCR, 0); 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); 7348c2ecf20Sopenharmony_ci if (p->capabilities & UART_CAP_EFR) { 7358c2ecf20Sopenharmony_ci serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); 7368c2ecf20Sopenharmony_ci serial_out(p, UART_EFR, efr); 7378c2ecf20Sopenharmony_ci serial_out(p, UART_LCR, lcr); 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci serial8250_rpm_put(p); 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_RSA 7458c2ecf20Sopenharmony_ci/* 7468c2ecf20Sopenharmony_ci * Attempts to turn on the RSA FIFO. Returns zero on failure. 7478c2ecf20Sopenharmony_ci * We set the port uart clock rate if we succeed. 7488c2ecf20Sopenharmony_ci */ 7498c2ecf20Sopenharmony_cistatic int __enable_rsa(struct uart_8250_port *up) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci unsigned char mode; 7528c2ecf20Sopenharmony_ci int result; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci mode = serial_in(up, UART_RSA_MSR); 7558c2ecf20Sopenharmony_ci result = mode & UART_RSA_MSR_FIFO; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if (!result) { 7588c2ecf20Sopenharmony_ci serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); 7598c2ecf20Sopenharmony_ci mode = serial_in(up, UART_RSA_MSR); 7608c2ecf20Sopenharmony_ci result = mode & UART_RSA_MSR_FIFO; 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (result) 7648c2ecf20Sopenharmony_ci up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci return result; 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_cistatic void enable_rsa(struct uart_8250_port *up) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci if (up->port.type == PORT_RSA) { 7728c2ecf20Sopenharmony_ci if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { 7738c2ecf20Sopenharmony_ci spin_lock_irq(&up->port.lock); 7748c2ecf20Sopenharmony_ci __enable_rsa(up); 7758c2ecf20Sopenharmony_ci spin_unlock_irq(&up->port.lock); 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) 7788c2ecf20Sopenharmony_ci serial_out(up, UART_RSA_FRR, 0); 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci/* 7838c2ecf20Sopenharmony_ci * Attempts to turn off the RSA FIFO. Returns zero on failure. 7848c2ecf20Sopenharmony_ci * It is unknown why interrupts were disabled in here. However, 7858c2ecf20Sopenharmony_ci * the caller is expected to preserve this behaviour by grabbing 7868c2ecf20Sopenharmony_ci * the spinlock before calling this function. 7878c2ecf20Sopenharmony_ci */ 7888c2ecf20Sopenharmony_cistatic void disable_rsa(struct uart_8250_port *up) 7898c2ecf20Sopenharmony_ci{ 7908c2ecf20Sopenharmony_ci unsigned char mode; 7918c2ecf20Sopenharmony_ci int result; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci if (up->port.type == PORT_RSA && 7948c2ecf20Sopenharmony_ci up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { 7958c2ecf20Sopenharmony_ci spin_lock_irq(&up->port.lock); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci mode = serial_in(up, UART_RSA_MSR); 7988c2ecf20Sopenharmony_ci result = !(mode & UART_RSA_MSR_FIFO); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci if (!result) { 8018c2ecf20Sopenharmony_ci serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); 8028c2ecf20Sopenharmony_ci mode = serial_in(up, UART_RSA_MSR); 8038c2ecf20Sopenharmony_ci result = !(mode & UART_RSA_MSR_FIFO); 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (result) 8078c2ecf20Sopenharmony_ci up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; 8088c2ecf20Sopenharmony_ci spin_unlock_irq(&up->port.lock); 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ci#endif /* CONFIG_SERIAL_8250_RSA */ 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci/* 8148c2ecf20Sopenharmony_ci * This is a quickie test to see how big the FIFO is. 8158c2ecf20Sopenharmony_ci * It doesn't work at all the time, more's the pity. 8168c2ecf20Sopenharmony_ci */ 8178c2ecf20Sopenharmony_cistatic int size_fifo(struct uart_8250_port *up) 8188c2ecf20Sopenharmony_ci{ 8198c2ecf20Sopenharmony_ci unsigned char old_fcr, old_mcr, old_lcr; 8208c2ecf20Sopenharmony_ci unsigned short old_dl; 8218c2ecf20Sopenharmony_ci int count; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci old_lcr = serial_in(up, UART_LCR); 8248c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, 0); 8258c2ecf20Sopenharmony_ci old_fcr = serial_in(up, UART_FCR); 8268c2ecf20Sopenharmony_ci old_mcr = serial8250_in_MCR(up); 8278c2ecf20Sopenharmony_ci serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | 8288c2ecf20Sopenharmony_ci UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); 8298c2ecf20Sopenharmony_ci serial8250_out_MCR(up, UART_MCR_LOOP); 8308c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); 8318c2ecf20Sopenharmony_ci old_dl = serial_dl_read(up); 8328c2ecf20Sopenharmony_ci serial_dl_write(up, 0x0001); 8338c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, 0x03); 8348c2ecf20Sopenharmony_ci for (count = 0; count < 256; count++) 8358c2ecf20Sopenharmony_ci serial_out(up, UART_TX, count); 8368c2ecf20Sopenharmony_ci mdelay(20);/* FIXME - schedule_timeout */ 8378c2ecf20Sopenharmony_ci for (count = 0; (serial_in(up, UART_LSR) & UART_LSR_DR) && 8388c2ecf20Sopenharmony_ci (count < 256); count++) 8398c2ecf20Sopenharmony_ci serial_in(up, UART_RX); 8408c2ecf20Sopenharmony_ci serial_out(up, UART_FCR, old_fcr); 8418c2ecf20Sopenharmony_ci serial8250_out_MCR(up, old_mcr); 8428c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); 8438c2ecf20Sopenharmony_ci serial_dl_write(up, old_dl); 8448c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, old_lcr); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci return count; 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci/* 8508c2ecf20Sopenharmony_ci * Read UART ID using the divisor method - set DLL and DLM to zero 8518c2ecf20Sopenharmony_ci * and the revision will be in DLL and device type in DLM. We 8528c2ecf20Sopenharmony_ci * preserve the device state across this. 8538c2ecf20Sopenharmony_ci */ 8548c2ecf20Sopenharmony_cistatic unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci unsigned char old_lcr; 8578c2ecf20Sopenharmony_ci unsigned int id, old_dl; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci old_lcr = serial_in(p, UART_LCR); 8608c2ecf20Sopenharmony_ci serial_out(p, UART_LCR, UART_LCR_CONF_MODE_A); 8618c2ecf20Sopenharmony_ci old_dl = serial_dl_read(p); 8628c2ecf20Sopenharmony_ci serial_dl_write(p, 0); 8638c2ecf20Sopenharmony_ci id = serial_dl_read(p); 8648c2ecf20Sopenharmony_ci serial_dl_write(p, old_dl); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci serial_out(p, UART_LCR, old_lcr); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci return id; 8698c2ecf20Sopenharmony_ci} 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci/* 8728c2ecf20Sopenharmony_ci * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's. 8738c2ecf20Sopenharmony_ci * When this function is called we know it is at least a StarTech 8748c2ecf20Sopenharmony_ci * 16650 V2, but it might be one of several StarTech UARTs, or one of 8758c2ecf20Sopenharmony_ci * its clones. (We treat the broken original StarTech 16650 V1 as a 8768c2ecf20Sopenharmony_ci * 16550, and why not? Startech doesn't seem to even acknowledge its 8778c2ecf20Sopenharmony_ci * existence.) 8788c2ecf20Sopenharmony_ci * 8798c2ecf20Sopenharmony_ci * What evil have men's minds wrought... 8808c2ecf20Sopenharmony_ci */ 8818c2ecf20Sopenharmony_cistatic void autoconfig_has_efr(struct uart_8250_port *up) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci unsigned int id1, id2, id3, rev; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci /* 8868c2ecf20Sopenharmony_ci * Everything with an EFR has SLEEP 8878c2ecf20Sopenharmony_ci */ 8888c2ecf20Sopenharmony_ci up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci /* 8918c2ecf20Sopenharmony_ci * First we check to see if it's an Oxford Semiconductor UART. 8928c2ecf20Sopenharmony_ci * 8938c2ecf20Sopenharmony_ci * If we have to do this here because some non-National 8948c2ecf20Sopenharmony_ci * Semiconductor clone chips lock up if you try writing to the 8958c2ecf20Sopenharmony_ci * LSR register (which serial_icr_read does) 8968c2ecf20Sopenharmony_ci */ 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci /* 8998c2ecf20Sopenharmony_ci * Check for Oxford Semiconductor 16C950. 9008c2ecf20Sopenharmony_ci * 9018c2ecf20Sopenharmony_ci * EFR [4] must be set else this test fails. 9028c2ecf20Sopenharmony_ci * 9038c2ecf20Sopenharmony_ci * This shouldn't be necessary, but Mike Hudson (Exoray@isys.ca) 9048c2ecf20Sopenharmony_ci * claims that it's needed for 952 dual UART's (which are not 9058c2ecf20Sopenharmony_ci * recommended for new designs). 9068c2ecf20Sopenharmony_ci */ 9078c2ecf20Sopenharmony_ci up->acr = 0; 9088c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 9098c2ecf20Sopenharmony_ci serial_out(up, UART_EFR, UART_EFR_ECB); 9108c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, 0x00); 9118c2ecf20Sopenharmony_ci id1 = serial_icr_read(up, UART_ID1); 9128c2ecf20Sopenharmony_ci id2 = serial_icr_read(up, UART_ID2); 9138c2ecf20Sopenharmony_ci id3 = serial_icr_read(up, UART_ID3); 9148c2ecf20Sopenharmony_ci rev = serial_icr_read(up, UART_REV); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci if (id1 == 0x16 && id2 == 0xC9 && 9198c2ecf20Sopenharmony_ci (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) { 9208c2ecf20Sopenharmony_ci up->port.type = PORT_16C950; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci /* 9238c2ecf20Sopenharmony_ci * Enable work around for the Oxford Semiconductor 952 rev B 9248c2ecf20Sopenharmony_ci * chip which causes it to seriously miscalculate baud rates 9258c2ecf20Sopenharmony_ci * when DLL is 0. 9268c2ecf20Sopenharmony_ci */ 9278c2ecf20Sopenharmony_ci if (id3 == 0x52 && rev == 0x01) 9288c2ecf20Sopenharmony_ci up->bugs |= UART_BUG_QUOT; 9298c2ecf20Sopenharmony_ci return; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci /* 9338c2ecf20Sopenharmony_ci * We check for a XR16C850 by setting DLL and DLM to 0, and then 9348c2ecf20Sopenharmony_ci * reading back DLL and DLM. The chip type depends on the DLM 9358c2ecf20Sopenharmony_ci * value read back: 9368c2ecf20Sopenharmony_ci * 0x10 - XR16C850 and the DLL contains the chip revision. 9378c2ecf20Sopenharmony_ci * 0x12 - XR16C2850. 9388c2ecf20Sopenharmony_ci * 0x14 - XR16C854. 9398c2ecf20Sopenharmony_ci */ 9408c2ecf20Sopenharmony_ci id1 = autoconfig_read_divisor_id(up); 9418c2ecf20Sopenharmony_ci DEBUG_AUTOCONF("850id=%04x ", id1); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci id2 = id1 >> 8; 9448c2ecf20Sopenharmony_ci if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) { 9458c2ecf20Sopenharmony_ci up->port.type = PORT_16850; 9468c2ecf20Sopenharmony_ci return; 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci /* 9508c2ecf20Sopenharmony_ci * It wasn't an XR16C850. 9518c2ecf20Sopenharmony_ci * 9528c2ecf20Sopenharmony_ci * We distinguish between the '654 and the '650 by counting 9538c2ecf20Sopenharmony_ci * how many bytes are in the FIFO. I'm using this for now, 9548c2ecf20Sopenharmony_ci * since that's the technique that was sent to me in the 9558c2ecf20Sopenharmony_ci * serial driver update, but I'm not convinced this works. 9568c2ecf20Sopenharmony_ci * I've had problems doing this in the past. -TYT 9578c2ecf20Sopenharmony_ci */ 9588c2ecf20Sopenharmony_ci if (size_fifo(up) == 64) 9598c2ecf20Sopenharmony_ci up->port.type = PORT_16654; 9608c2ecf20Sopenharmony_ci else 9618c2ecf20Sopenharmony_ci up->port.type = PORT_16650V2; 9628c2ecf20Sopenharmony_ci} 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci/* 9658c2ecf20Sopenharmony_ci * We detected a chip without a FIFO. Only two fall into 9668c2ecf20Sopenharmony_ci * this category - the original 8250 and the 16450. The 9678c2ecf20Sopenharmony_ci * 16450 has a scratch register (accessible with LCR=0) 9688c2ecf20Sopenharmony_ci */ 9698c2ecf20Sopenharmony_cistatic void autoconfig_8250(struct uart_8250_port *up) 9708c2ecf20Sopenharmony_ci{ 9718c2ecf20Sopenharmony_ci unsigned char scratch, status1, status2; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci up->port.type = PORT_8250; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci scratch = serial_in(up, UART_SCR); 9768c2ecf20Sopenharmony_ci serial_out(up, UART_SCR, 0xa5); 9778c2ecf20Sopenharmony_ci status1 = serial_in(up, UART_SCR); 9788c2ecf20Sopenharmony_ci serial_out(up, UART_SCR, 0x5a); 9798c2ecf20Sopenharmony_ci status2 = serial_in(up, UART_SCR); 9808c2ecf20Sopenharmony_ci serial_out(up, UART_SCR, scratch); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci if (status1 == 0xa5 && status2 == 0x5a) 9838c2ecf20Sopenharmony_ci up->port.type = PORT_16450; 9848c2ecf20Sopenharmony_ci} 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_cistatic int broken_efr(struct uart_8250_port *up) 9878c2ecf20Sopenharmony_ci{ 9888c2ecf20Sopenharmony_ci /* 9898c2ecf20Sopenharmony_ci * Exar ST16C2550 "A2" devices incorrectly detect as 9908c2ecf20Sopenharmony_ci * having an EFR, and report an ID of 0x0201. See 9918c2ecf20Sopenharmony_ci * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html 9928c2ecf20Sopenharmony_ci */ 9938c2ecf20Sopenharmony_ci if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16) 9948c2ecf20Sopenharmony_ci return 1; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci return 0; 9978c2ecf20Sopenharmony_ci} 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci/* 10008c2ecf20Sopenharmony_ci * We know that the chip has FIFOs. Does it have an EFR? The 10018c2ecf20Sopenharmony_ci * EFR is located in the same register position as the IIR and 10028c2ecf20Sopenharmony_ci * we know the top two bits of the IIR are currently set. The 10038c2ecf20Sopenharmony_ci * EFR should contain zero. Try to read the EFR. 10048c2ecf20Sopenharmony_ci */ 10058c2ecf20Sopenharmony_cistatic void autoconfig_16550a(struct uart_8250_port *up) 10068c2ecf20Sopenharmony_ci{ 10078c2ecf20Sopenharmony_ci unsigned char status1, status2; 10088c2ecf20Sopenharmony_ci unsigned int iersave; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci up->port.type = PORT_16550A; 10118c2ecf20Sopenharmony_ci up->capabilities |= UART_CAP_FIFO; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_SERIAL_8250_16550A_VARIANTS) && 10148c2ecf20Sopenharmony_ci !(up->port.flags & UPF_FULL_PROBE)) 10158c2ecf20Sopenharmony_ci return; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci /* 10188c2ecf20Sopenharmony_ci * Check for presence of the EFR when DLAB is set. 10198c2ecf20Sopenharmony_ci * Only ST16C650V1 UARTs pass this test. 10208c2ecf20Sopenharmony_ci */ 10218c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); 10228c2ecf20Sopenharmony_ci if (serial_in(up, UART_EFR) == 0) { 10238c2ecf20Sopenharmony_ci serial_out(up, UART_EFR, 0xA8); 10248c2ecf20Sopenharmony_ci if (serial_in(up, UART_EFR) != 0) { 10258c2ecf20Sopenharmony_ci DEBUG_AUTOCONF("EFRv1 "); 10268c2ecf20Sopenharmony_ci up->port.type = PORT_16650; 10278c2ecf20Sopenharmony_ci up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; 10288c2ecf20Sopenharmony_ci } else { 10298c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, 0); 10308c2ecf20Sopenharmony_ci serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | 10318c2ecf20Sopenharmony_ci UART_FCR7_64BYTE); 10328c2ecf20Sopenharmony_ci status1 = serial_in(up, UART_IIR) >> 5; 10338c2ecf20Sopenharmony_ci serial_out(up, UART_FCR, 0); 10348c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, 0); 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci if (status1 == 7) 10378c2ecf20Sopenharmony_ci up->port.type = PORT_16550A_FSL64; 10388c2ecf20Sopenharmony_ci else 10398c2ecf20Sopenharmony_ci DEBUG_AUTOCONF("Motorola 8xxx DUART "); 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci serial_out(up, UART_EFR, 0); 10428c2ecf20Sopenharmony_ci return; 10438c2ecf20Sopenharmony_ci } 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci /* 10468c2ecf20Sopenharmony_ci * Maybe it requires 0xbf to be written to the LCR. 10478c2ecf20Sopenharmony_ci * (other ST16C650V2 UARTs, TI16C752A, etc) 10488c2ecf20Sopenharmony_ci */ 10498c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 10508c2ecf20Sopenharmony_ci if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) { 10518c2ecf20Sopenharmony_ci DEBUG_AUTOCONF("EFRv2 "); 10528c2ecf20Sopenharmony_ci autoconfig_has_efr(up); 10538c2ecf20Sopenharmony_ci return; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci /* 10578c2ecf20Sopenharmony_ci * Check for a National Semiconductor SuperIO chip. 10588c2ecf20Sopenharmony_ci * Attempt to switch to bank 2, read the value of the LOOP bit 10598c2ecf20Sopenharmony_ci * from EXCR1. Switch back to bank 0, change it in MCR. Then 10608c2ecf20Sopenharmony_ci * switch back to bank 2, read it from EXCR1 again and check 10618c2ecf20Sopenharmony_ci * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2 10628c2ecf20Sopenharmony_ci */ 10638c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, 0); 10648c2ecf20Sopenharmony_ci status1 = serial8250_in_MCR(up); 10658c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, 0xE0); 10668c2ecf20Sopenharmony_ci status2 = serial_in(up, 0x02); /* EXCR1 */ 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci if (!((status2 ^ status1) & UART_MCR_LOOP)) { 10698c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, 0); 10708c2ecf20Sopenharmony_ci serial8250_out_MCR(up, status1 ^ UART_MCR_LOOP); 10718c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, 0xE0); 10728c2ecf20Sopenharmony_ci status2 = serial_in(up, 0x02); /* EXCR1 */ 10738c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, 0); 10748c2ecf20Sopenharmony_ci serial8250_out_MCR(up, status1); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci if ((status2 ^ status1) & UART_MCR_LOOP) { 10778c2ecf20Sopenharmony_ci unsigned short quot; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, 0xE0); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci quot = serial_dl_read(up); 10828c2ecf20Sopenharmony_ci quot <<= 3; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci if (ns16550a_goto_highspeed(up)) 10858c2ecf20Sopenharmony_ci serial_dl_write(up, quot); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, 0); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci up->port.uartclk = 921600*16; 10908c2ecf20Sopenharmony_ci up->port.type = PORT_NS16550A; 10918c2ecf20Sopenharmony_ci up->capabilities |= UART_NATSEMI; 10928c2ecf20Sopenharmony_ci return; 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci /* 10978c2ecf20Sopenharmony_ci * No EFR. Try to detect a TI16750, which only sets bit 5 of 10988c2ecf20Sopenharmony_ci * the IIR when 64 byte FIFO mode is enabled when DLAB is set. 10998c2ecf20Sopenharmony_ci * Try setting it with and without DLAB set. Cheap clones 11008c2ecf20Sopenharmony_ci * set bit 5 without DLAB set. 11018c2ecf20Sopenharmony_ci */ 11028c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, 0); 11038c2ecf20Sopenharmony_ci serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); 11048c2ecf20Sopenharmony_ci status1 = serial_in(up, UART_IIR) >> 5; 11058c2ecf20Sopenharmony_ci serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); 11068c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); 11078c2ecf20Sopenharmony_ci serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); 11088c2ecf20Sopenharmony_ci status2 = serial_in(up, UART_IIR) >> 5; 11098c2ecf20Sopenharmony_ci serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); 11108c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, 0); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci if (status1 == 6 && status2 == 7) { 11158c2ecf20Sopenharmony_ci up->port.type = PORT_16750; 11168c2ecf20Sopenharmony_ci up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP; 11178c2ecf20Sopenharmony_ci return; 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci /* 11218c2ecf20Sopenharmony_ci * Try writing and reading the UART_IER_UUE bit (b6). 11228c2ecf20Sopenharmony_ci * If it works, this is probably one of the Xscale platform's 11238c2ecf20Sopenharmony_ci * internal UARTs. 11248c2ecf20Sopenharmony_ci * We're going to explicitly set the UUE bit to 0 before 11258c2ecf20Sopenharmony_ci * trying to write and read a 1 just to make sure it's not 11268c2ecf20Sopenharmony_ci * already a 1 and maybe locked there before we even start start. 11278c2ecf20Sopenharmony_ci */ 11288c2ecf20Sopenharmony_ci iersave = serial_in(up, UART_IER); 11298c2ecf20Sopenharmony_ci serial_out(up, UART_IER, iersave & ~UART_IER_UUE); 11308c2ecf20Sopenharmony_ci if (!(serial_in(up, UART_IER) & UART_IER_UUE)) { 11318c2ecf20Sopenharmony_ci /* 11328c2ecf20Sopenharmony_ci * OK it's in a known zero state, try writing and reading 11338c2ecf20Sopenharmony_ci * without disturbing the current state of the other bits. 11348c2ecf20Sopenharmony_ci */ 11358c2ecf20Sopenharmony_ci serial_out(up, UART_IER, iersave | UART_IER_UUE); 11368c2ecf20Sopenharmony_ci if (serial_in(up, UART_IER) & UART_IER_UUE) { 11378c2ecf20Sopenharmony_ci /* 11388c2ecf20Sopenharmony_ci * It's an Xscale. 11398c2ecf20Sopenharmony_ci * We'll leave the UART_IER_UUE bit set to 1 (enabled). 11408c2ecf20Sopenharmony_ci */ 11418c2ecf20Sopenharmony_ci DEBUG_AUTOCONF("Xscale "); 11428c2ecf20Sopenharmony_ci up->port.type = PORT_XSCALE; 11438c2ecf20Sopenharmony_ci up->capabilities |= UART_CAP_UUE | UART_CAP_RTOIE; 11448c2ecf20Sopenharmony_ci return; 11458c2ecf20Sopenharmony_ci } 11468c2ecf20Sopenharmony_ci } else { 11478c2ecf20Sopenharmony_ci /* 11488c2ecf20Sopenharmony_ci * If we got here we couldn't force the IER_UUE bit to 0. 11498c2ecf20Sopenharmony_ci * Log it and continue. 11508c2ecf20Sopenharmony_ci */ 11518c2ecf20Sopenharmony_ci DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 "); 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci serial_out(up, UART_IER, iersave); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci /* 11568c2ecf20Sopenharmony_ci * We distinguish between 16550A and U6 16550A by counting 11578c2ecf20Sopenharmony_ci * how many bytes are in the FIFO. 11588c2ecf20Sopenharmony_ci */ 11598c2ecf20Sopenharmony_ci if (up->port.type == PORT_16550A && size_fifo(up) == 64) { 11608c2ecf20Sopenharmony_ci up->port.type = PORT_U6_16550A; 11618c2ecf20Sopenharmony_ci up->capabilities |= UART_CAP_AFE; 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci} 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci/* 11668c2ecf20Sopenharmony_ci * This routine is called by rs_init() to initialize a specific serial 11678c2ecf20Sopenharmony_ci * port. It determines what type of UART chip this serial port is 11688c2ecf20Sopenharmony_ci * using: 8250, 16450, 16550, 16550A. The important question is 11698c2ecf20Sopenharmony_ci * whether or not this UART is a 16550A or not, since this will 11708c2ecf20Sopenharmony_ci * determine whether or not we can use its FIFO features or not. 11718c2ecf20Sopenharmony_ci */ 11728c2ecf20Sopenharmony_cistatic void autoconfig(struct uart_8250_port *up) 11738c2ecf20Sopenharmony_ci{ 11748c2ecf20Sopenharmony_ci unsigned char status1, scratch, scratch2, scratch3; 11758c2ecf20Sopenharmony_ci unsigned char save_lcr, save_mcr; 11768c2ecf20Sopenharmony_ci struct uart_port *port = &up->port; 11778c2ecf20Sopenharmony_ci unsigned long flags; 11788c2ecf20Sopenharmony_ci unsigned int old_capabilities; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci if (!port->iobase && !port->mapbase && !port->membase) 11818c2ecf20Sopenharmony_ci return; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci DEBUG_AUTOCONF("%s: autoconf (0x%04lx, 0x%p): ", 11848c2ecf20Sopenharmony_ci port->name, port->iobase, port->membase); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci /* 11878c2ecf20Sopenharmony_ci * We really do need global IRQs disabled here - we're going to 11888c2ecf20Sopenharmony_ci * be frobbing the chips IRQ enable register to see if it exists. 11898c2ecf20Sopenharmony_ci */ 11908c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci up->capabilities = 0; 11938c2ecf20Sopenharmony_ci up->bugs = 0; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci if (!(port->flags & UPF_BUGGY_UART)) { 11968c2ecf20Sopenharmony_ci /* 11978c2ecf20Sopenharmony_ci * Do a simple existence test first; if we fail this, 11988c2ecf20Sopenharmony_ci * there's no point trying anything else. 11998c2ecf20Sopenharmony_ci * 12008c2ecf20Sopenharmony_ci * 0x80 is used as a nonsense port to prevent against 12018c2ecf20Sopenharmony_ci * false positives due to ISA bus float. The 12028c2ecf20Sopenharmony_ci * assumption is that 0x80 is a non-existent port; 12038c2ecf20Sopenharmony_ci * which should be safe since include/asm/io.h also 12048c2ecf20Sopenharmony_ci * makes this assumption. 12058c2ecf20Sopenharmony_ci * 12068c2ecf20Sopenharmony_ci * Note: this is safe as long as MCR bit 4 is clear 12078c2ecf20Sopenharmony_ci * and the device is in "PC" mode. 12088c2ecf20Sopenharmony_ci */ 12098c2ecf20Sopenharmony_ci scratch = serial_in(up, UART_IER); 12108c2ecf20Sopenharmony_ci serial_out(up, UART_IER, 0); 12118c2ecf20Sopenharmony_ci#ifdef __i386__ 12128c2ecf20Sopenharmony_ci outb(0xff, 0x080); 12138c2ecf20Sopenharmony_ci#endif 12148c2ecf20Sopenharmony_ci /* 12158c2ecf20Sopenharmony_ci * Mask out IER[7:4] bits for test as some UARTs (e.g. TL 12168c2ecf20Sopenharmony_ci * 16C754B) allow only to modify them if an EFR bit is set. 12178c2ecf20Sopenharmony_ci */ 12188c2ecf20Sopenharmony_ci scratch2 = serial_in(up, UART_IER) & 0x0f; 12198c2ecf20Sopenharmony_ci serial_out(up, UART_IER, 0x0F); 12208c2ecf20Sopenharmony_ci#ifdef __i386__ 12218c2ecf20Sopenharmony_ci outb(0, 0x080); 12228c2ecf20Sopenharmony_ci#endif 12238c2ecf20Sopenharmony_ci scratch3 = serial_in(up, UART_IER) & 0x0f; 12248c2ecf20Sopenharmony_ci serial_out(up, UART_IER, scratch); 12258c2ecf20Sopenharmony_ci if (scratch2 != 0 || scratch3 != 0x0F) { 12268c2ecf20Sopenharmony_ci /* 12278c2ecf20Sopenharmony_ci * We failed; there's nothing here 12288c2ecf20Sopenharmony_ci */ 12298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 12308c2ecf20Sopenharmony_ci DEBUG_AUTOCONF("IER test failed (%02x, %02x) ", 12318c2ecf20Sopenharmony_ci scratch2, scratch3); 12328c2ecf20Sopenharmony_ci goto out; 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci } 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci save_mcr = serial8250_in_MCR(up); 12378c2ecf20Sopenharmony_ci save_lcr = serial_in(up, UART_LCR); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci /* 12408c2ecf20Sopenharmony_ci * Check to see if a UART is really there. Certain broken 12418c2ecf20Sopenharmony_ci * internal modems based on the Rockwell chipset fail this 12428c2ecf20Sopenharmony_ci * test, because they apparently don't implement the loopback 12438c2ecf20Sopenharmony_ci * test mode. So this test is skipped on the COM 1 through 12448c2ecf20Sopenharmony_ci * COM 4 ports. This *should* be safe, since no board 12458c2ecf20Sopenharmony_ci * manufacturer would be stupid enough to design a board 12468c2ecf20Sopenharmony_ci * that conflicts with COM 1-4 --- we hope! 12478c2ecf20Sopenharmony_ci */ 12488c2ecf20Sopenharmony_ci if (!(port->flags & UPF_SKIP_TEST)) { 12498c2ecf20Sopenharmony_ci serial8250_out_MCR(up, UART_MCR_LOOP | 0x0A); 12508c2ecf20Sopenharmony_ci status1 = serial_in(up, UART_MSR) & 0xF0; 12518c2ecf20Sopenharmony_ci serial8250_out_MCR(up, save_mcr); 12528c2ecf20Sopenharmony_ci if (status1 != 0x90) { 12538c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 12548c2ecf20Sopenharmony_ci DEBUG_AUTOCONF("LOOP test failed (%02x) ", 12558c2ecf20Sopenharmony_ci status1); 12568c2ecf20Sopenharmony_ci goto out; 12578c2ecf20Sopenharmony_ci } 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci /* 12618c2ecf20Sopenharmony_ci * We're pretty sure there's a port here. Lets find out what 12628c2ecf20Sopenharmony_ci * type of port it is. The IIR top two bits allows us to find 12638c2ecf20Sopenharmony_ci * out if it's 8250 or 16450, 16550, 16550A or later. This 12648c2ecf20Sopenharmony_ci * determines what we test for next. 12658c2ecf20Sopenharmony_ci * 12668c2ecf20Sopenharmony_ci * We also initialise the EFR (if any) to zero for later. The 12678c2ecf20Sopenharmony_ci * EFR occupies the same register location as the FCR and IIR. 12688c2ecf20Sopenharmony_ci */ 12698c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 12708c2ecf20Sopenharmony_ci serial_out(up, UART_EFR, 0); 12718c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, 0); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci /* Assign this as it is to truncate any bits above 7. */ 12768c2ecf20Sopenharmony_ci scratch = serial_in(up, UART_IIR); 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci switch (scratch >> 6) { 12798c2ecf20Sopenharmony_ci case 0: 12808c2ecf20Sopenharmony_ci autoconfig_8250(up); 12818c2ecf20Sopenharmony_ci break; 12828c2ecf20Sopenharmony_ci case 1: 12838c2ecf20Sopenharmony_ci port->type = PORT_UNKNOWN; 12848c2ecf20Sopenharmony_ci break; 12858c2ecf20Sopenharmony_ci case 2: 12868c2ecf20Sopenharmony_ci port->type = PORT_16550; 12878c2ecf20Sopenharmony_ci break; 12888c2ecf20Sopenharmony_ci case 3: 12898c2ecf20Sopenharmony_ci autoconfig_16550a(up); 12908c2ecf20Sopenharmony_ci break; 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_RSA 12948c2ecf20Sopenharmony_ci /* 12958c2ecf20Sopenharmony_ci * Only probe for RSA ports if we got the region. 12968c2ecf20Sopenharmony_ci */ 12978c2ecf20Sopenharmony_ci if (port->type == PORT_16550A && up->probe & UART_PROBE_RSA && 12988c2ecf20Sopenharmony_ci __enable_rsa(up)) 12998c2ecf20Sopenharmony_ci port->type = PORT_RSA; 13008c2ecf20Sopenharmony_ci#endif 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, save_lcr); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci port->fifosize = uart_config[up->port.type].fifo_size; 13058c2ecf20Sopenharmony_ci old_capabilities = up->capabilities; 13068c2ecf20Sopenharmony_ci up->capabilities = uart_config[port->type].flags; 13078c2ecf20Sopenharmony_ci up->tx_loadsz = uart_config[port->type].tx_loadsz; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci if (port->type == PORT_UNKNOWN) 13108c2ecf20Sopenharmony_ci goto out_lock; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci /* 13138c2ecf20Sopenharmony_ci * Reset the UART. 13148c2ecf20Sopenharmony_ci */ 13158c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_RSA 13168c2ecf20Sopenharmony_ci if (port->type == PORT_RSA) 13178c2ecf20Sopenharmony_ci serial_out(up, UART_RSA_FRR, 0); 13188c2ecf20Sopenharmony_ci#endif 13198c2ecf20Sopenharmony_ci serial8250_out_MCR(up, save_mcr); 13208c2ecf20Sopenharmony_ci serial8250_clear_fifos(up); 13218c2ecf20Sopenharmony_ci serial_in(up, UART_RX); 13228c2ecf20Sopenharmony_ci if (up->capabilities & UART_CAP_UUE) 13238c2ecf20Sopenharmony_ci serial_out(up, UART_IER, UART_IER_UUE); 13248c2ecf20Sopenharmony_ci else 13258c2ecf20Sopenharmony_ci serial_out(up, UART_IER, 0); 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ciout_lock: 13288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci /* 13318c2ecf20Sopenharmony_ci * Check if the device is a Fintek F81216A 13328c2ecf20Sopenharmony_ci */ 13338c2ecf20Sopenharmony_ci if (port->type == PORT_16550A && port->iotype == UPIO_PORT) 13348c2ecf20Sopenharmony_ci fintek_8250_probe(up); 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci if (up->capabilities != old_capabilities) { 13378c2ecf20Sopenharmony_ci dev_warn(port->dev, "detected caps %08x should be %08x\n", 13388c2ecf20Sopenharmony_ci old_capabilities, up->capabilities); 13398c2ecf20Sopenharmony_ci } 13408c2ecf20Sopenharmony_ciout: 13418c2ecf20Sopenharmony_ci DEBUG_AUTOCONF("iir=%d ", scratch); 13428c2ecf20Sopenharmony_ci DEBUG_AUTOCONF("type=%s\n", uart_config[port->type].name); 13438c2ecf20Sopenharmony_ci} 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_cistatic void autoconfig_irq(struct uart_8250_port *up) 13468c2ecf20Sopenharmony_ci{ 13478c2ecf20Sopenharmony_ci struct uart_port *port = &up->port; 13488c2ecf20Sopenharmony_ci unsigned char save_mcr, save_ier; 13498c2ecf20Sopenharmony_ci unsigned char save_ICP = 0; 13508c2ecf20Sopenharmony_ci unsigned int ICP = 0; 13518c2ecf20Sopenharmony_ci unsigned long irqs; 13528c2ecf20Sopenharmony_ci int irq; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci if (port->flags & UPF_FOURPORT) { 13558c2ecf20Sopenharmony_ci ICP = (port->iobase & 0xfe0) | 0x1f; 13568c2ecf20Sopenharmony_ci save_ICP = inb_p(ICP); 13578c2ecf20Sopenharmony_ci outb_p(0x80, ICP); 13588c2ecf20Sopenharmony_ci inb_p(ICP); 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci if (uart_console(port)) 13628c2ecf20Sopenharmony_ci console_lock(); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci /* forget possible initially masked and pending IRQ */ 13658c2ecf20Sopenharmony_ci probe_irq_off(probe_irq_on()); 13668c2ecf20Sopenharmony_ci save_mcr = serial8250_in_MCR(up); 13678c2ecf20Sopenharmony_ci save_ier = serial_in(up, UART_IER); 13688c2ecf20Sopenharmony_ci serial8250_out_MCR(up, UART_MCR_OUT1 | UART_MCR_OUT2); 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci irqs = probe_irq_on(); 13718c2ecf20Sopenharmony_ci serial8250_out_MCR(up, 0); 13728c2ecf20Sopenharmony_ci udelay(10); 13738c2ecf20Sopenharmony_ci if (port->flags & UPF_FOURPORT) { 13748c2ecf20Sopenharmony_ci serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS); 13758c2ecf20Sopenharmony_ci } else { 13768c2ecf20Sopenharmony_ci serial8250_out_MCR(up, 13778c2ecf20Sopenharmony_ci UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); 13788c2ecf20Sopenharmony_ci } 13798c2ecf20Sopenharmony_ci serial_out(up, UART_IER, 0x0f); /* enable all intrs */ 13808c2ecf20Sopenharmony_ci serial_in(up, UART_LSR); 13818c2ecf20Sopenharmony_ci serial_in(up, UART_RX); 13828c2ecf20Sopenharmony_ci serial_in(up, UART_IIR); 13838c2ecf20Sopenharmony_ci serial_in(up, UART_MSR); 13848c2ecf20Sopenharmony_ci serial_out(up, UART_TX, 0xFF); 13858c2ecf20Sopenharmony_ci udelay(20); 13868c2ecf20Sopenharmony_ci irq = probe_irq_off(irqs); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci serial8250_out_MCR(up, save_mcr); 13898c2ecf20Sopenharmony_ci serial_out(up, UART_IER, save_ier); 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci if (port->flags & UPF_FOURPORT) 13928c2ecf20Sopenharmony_ci outb_p(save_ICP, ICP); 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci if (uart_console(port)) 13958c2ecf20Sopenharmony_ci console_unlock(); 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci port->irq = (irq > 0) ? irq : 0; 13988c2ecf20Sopenharmony_ci} 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_cistatic void serial8250_stop_rx(struct uart_port *port) 14018c2ecf20Sopenharmony_ci{ 14028c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci serial8250_rpm_get(up); 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); 14078c2ecf20Sopenharmony_ci up->port.read_status_mask &= ~UART_LSR_DR; 14088c2ecf20Sopenharmony_ci serial_port_out(port, UART_IER, up->ier); 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci serial8250_rpm_put(up); 14118c2ecf20Sopenharmony_ci} 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci/** 14148c2ecf20Sopenharmony_ci * serial8250_em485_stop_tx() - generic ->rs485_stop_tx() callback 14158c2ecf20Sopenharmony_ci * @p: uart 8250 port 14168c2ecf20Sopenharmony_ci * 14178c2ecf20Sopenharmony_ci * Generic callback usable by 8250 uart drivers to stop rs485 transmission. 14188c2ecf20Sopenharmony_ci */ 14198c2ecf20Sopenharmony_civoid serial8250_em485_stop_tx(struct uart_8250_port *p) 14208c2ecf20Sopenharmony_ci{ 14218c2ecf20Sopenharmony_ci unsigned char mcr = serial8250_in_MCR(p); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND) 14248c2ecf20Sopenharmony_ci mcr |= UART_MCR_RTS; 14258c2ecf20Sopenharmony_ci else 14268c2ecf20Sopenharmony_ci mcr &= ~UART_MCR_RTS; 14278c2ecf20Sopenharmony_ci serial8250_out_MCR(p, mcr); 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci /* 14308c2ecf20Sopenharmony_ci * Empty the RX FIFO, we are not interested in anything 14318c2ecf20Sopenharmony_ci * received during the half-duplex transmission. 14328c2ecf20Sopenharmony_ci * Enable previously disabled RX interrupts. 14338c2ecf20Sopenharmony_ci */ 14348c2ecf20Sopenharmony_ci if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) { 14358c2ecf20Sopenharmony_ci serial8250_clear_and_reinit_fifos(p); 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci p->ier |= UART_IER_RLSI | UART_IER_RDI; 14388c2ecf20Sopenharmony_ci serial_port_out(&p->port, UART_IER, p->ier); 14398c2ecf20Sopenharmony_ci } 14408c2ecf20Sopenharmony_ci} 14418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_em485_stop_tx); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_cistatic enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t) 14448c2ecf20Sopenharmony_ci{ 14458c2ecf20Sopenharmony_ci struct uart_8250_em485 *em485; 14468c2ecf20Sopenharmony_ci struct uart_8250_port *p; 14478c2ecf20Sopenharmony_ci unsigned long flags; 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci em485 = container_of(t, struct uart_8250_em485, stop_tx_timer); 14508c2ecf20Sopenharmony_ci p = em485->port; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci serial8250_rpm_get(p); 14538c2ecf20Sopenharmony_ci spin_lock_irqsave(&p->port.lock, flags); 14548c2ecf20Sopenharmony_ci if (em485->active_timer == &em485->stop_tx_timer) { 14558c2ecf20Sopenharmony_ci p->rs485_stop_tx(p); 14568c2ecf20Sopenharmony_ci em485->active_timer = NULL; 14578c2ecf20Sopenharmony_ci em485->tx_stopped = true; 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p->port.lock, flags); 14608c2ecf20Sopenharmony_ci serial8250_rpm_put(p); 14618c2ecf20Sopenharmony_ci return HRTIMER_NORESTART; 14628c2ecf20Sopenharmony_ci} 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_cistatic void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec) 14658c2ecf20Sopenharmony_ci{ 14668c2ecf20Sopenharmony_ci long sec = msec / 1000; 14678c2ecf20Sopenharmony_ci long nsec = (msec % 1000) * 1000000; 14688c2ecf20Sopenharmony_ci ktime_t t = ktime_set(sec, nsec); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci hrtimer_start(hrt, t, HRTIMER_MODE_REL); 14718c2ecf20Sopenharmony_ci} 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_cistatic void __stop_tx_rs485(struct uart_8250_port *p) 14748c2ecf20Sopenharmony_ci{ 14758c2ecf20Sopenharmony_ci struct uart_8250_em485 *em485 = p->em485; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci /* 14788c2ecf20Sopenharmony_ci * rs485_stop_tx() is going to set RTS according to config 14798c2ecf20Sopenharmony_ci * AND flush RX FIFO if required. 14808c2ecf20Sopenharmony_ci */ 14818c2ecf20Sopenharmony_ci if (p->port.rs485.delay_rts_after_send > 0) { 14828c2ecf20Sopenharmony_ci em485->active_timer = &em485->stop_tx_timer; 14838c2ecf20Sopenharmony_ci start_hrtimer_ms(&em485->stop_tx_timer, 14848c2ecf20Sopenharmony_ci p->port.rs485.delay_rts_after_send); 14858c2ecf20Sopenharmony_ci } else { 14868c2ecf20Sopenharmony_ci p->rs485_stop_tx(p); 14878c2ecf20Sopenharmony_ci em485->active_timer = NULL; 14888c2ecf20Sopenharmony_ci em485->tx_stopped = true; 14898c2ecf20Sopenharmony_ci } 14908c2ecf20Sopenharmony_ci} 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_cistatic inline void __do_stop_tx(struct uart_8250_port *p) 14938c2ecf20Sopenharmony_ci{ 14948c2ecf20Sopenharmony_ci if (serial8250_clear_THRI(p)) 14958c2ecf20Sopenharmony_ci serial8250_rpm_put_tx(p); 14968c2ecf20Sopenharmony_ci} 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_cistatic inline void __stop_tx(struct uart_8250_port *p) 14998c2ecf20Sopenharmony_ci{ 15008c2ecf20Sopenharmony_ci struct uart_8250_em485 *em485 = p->em485; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci if (em485) { 15038c2ecf20Sopenharmony_ci unsigned char lsr = serial_in(p, UART_LSR); 15048c2ecf20Sopenharmony_ci p->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci /* 15078c2ecf20Sopenharmony_ci * To provide required timeing and allow FIFO transfer, 15088c2ecf20Sopenharmony_ci * __stop_tx_rs485() must be called only when both FIFO and 15098c2ecf20Sopenharmony_ci * shift register are empty. It is for device driver to enable 15108c2ecf20Sopenharmony_ci * interrupt on TEMT. 15118c2ecf20Sopenharmony_ci */ 15128c2ecf20Sopenharmony_ci if ((lsr & BOTH_EMPTY) != BOTH_EMPTY) 15138c2ecf20Sopenharmony_ci return; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci __stop_tx_rs485(p); 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci __do_stop_tx(p); 15188c2ecf20Sopenharmony_ci} 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_cistatic void serial8250_stop_tx(struct uart_port *port) 15218c2ecf20Sopenharmony_ci{ 15228c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci serial8250_rpm_get(up); 15258c2ecf20Sopenharmony_ci __stop_tx(up); 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci /* 15288c2ecf20Sopenharmony_ci * We really want to stop the transmitter from sending. 15298c2ecf20Sopenharmony_ci */ 15308c2ecf20Sopenharmony_ci if (port->type == PORT_16C950) { 15318c2ecf20Sopenharmony_ci up->acr |= UART_ACR_TXDIS; 15328c2ecf20Sopenharmony_ci serial_icr_write(up, UART_ACR, up->acr); 15338c2ecf20Sopenharmony_ci } 15348c2ecf20Sopenharmony_ci serial8250_rpm_put(up); 15358c2ecf20Sopenharmony_ci} 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_cistatic inline void __start_tx(struct uart_port *port) 15388c2ecf20Sopenharmony_ci{ 15398c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci if (up->dma && !up->dma->tx_dma(up)) 15428c2ecf20Sopenharmony_ci return; 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci if (serial8250_set_THRI(up)) { 15458c2ecf20Sopenharmony_ci if (up->bugs & UART_BUG_TXEN) { 15468c2ecf20Sopenharmony_ci unsigned char lsr; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci lsr = serial_in(up, UART_LSR); 15498c2ecf20Sopenharmony_ci up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; 15508c2ecf20Sopenharmony_ci if (lsr & UART_LSR_THRE) 15518c2ecf20Sopenharmony_ci serial8250_tx_chars(up); 15528c2ecf20Sopenharmony_ci } 15538c2ecf20Sopenharmony_ci } 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci /* 15568c2ecf20Sopenharmony_ci * Re-enable the transmitter if we disabled it. 15578c2ecf20Sopenharmony_ci */ 15588c2ecf20Sopenharmony_ci if (port->type == PORT_16C950 && up->acr & UART_ACR_TXDIS) { 15598c2ecf20Sopenharmony_ci up->acr &= ~UART_ACR_TXDIS; 15608c2ecf20Sopenharmony_ci serial_icr_write(up, UART_ACR, up->acr); 15618c2ecf20Sopenharmony_ci } 15628c2ecf20Sopenharmony_ci} 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci/** 15658c2ecf20Sopenharmony_ci * serial8250_em485_start_tx() - generic ->rs485_start_tx() callback 15668c2ecf20Sopenharmony_ci * @up: uart 8250 port 15678c2ecf20Sopenharmony_ci * 15688c2ecf20Sopenharmony_ci * Generic callback usable by 8250 uart drivers to start rs485 transmission. 15698c2ecf20Sopenharmony_ci * Assumes that setting the RTS bit in the MCR register means RTS is high. 15708c2ecf20Sopenharmony_ci * (Some chips use inverse semantics.) Further assumes that reception is 15718c2ecf20Sopenharmony_ci * stoppable by disabling the UART_IER_RDI interrupt. (Some chips set the 15728c2ecf20Sopenharmony_ci * UART_LSR_DR bit even when UART_IER_RDI is disabled, foiling this approach.) 15738c2ecf20Sopenharmony_ci */ 15748c2ecf20Sopenharmony_civoid serial8250_em485_start_tx(struct uart_8250_port *up) 15758c2ecf20Sopenharmony_ci{ 15768c2ecf20Sopenharmony_ci unsigned char mcr = serial8250_in_MCR(up); 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) 15798c2ecf20Sopenharmony_ci serial8250_stop_rx(&up->port); 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND) 15828c2ecf20Sopenharmony_ci mcr |= UART_MCR_RTS; 15838c2ecf20Sopenharmony_ci else 15848c2ecf20Sopenharmony_ci mcr &= ~UART_MCR_RTS; 15858c2ecf20Sopenharmony_ci serial8250_out_MCR(up, mcr); 15868c2ecf20Sopenharmony_ci} 15878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_em485_start_tx); 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_cistatic inline void start_tx_rs485(struct uart_port *port) 15908c2ecf20Sopenharmony_ci{ 15918c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 15928c2ecf20Sopenharmony_ci struct uart_8250_em485 *em485 = up->em485; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci /* 15958c2ecf20Sopenharmony_ci * While serial8250_em485_handle_stop_tx() is a noop if 15968c2ecf20Sopenharmony_ci * em485->active_timer != &em485->stop_tx_timer, it might happen that 15978c2ecf20Sopenharmony_ci * the timer is still armed and triggers only after the current bunch of 15988c2ecf20Sopenharmony_ci * chars is send and em485->active_timer == &em485->stop_tx_timer again. 15998c2ecf20Sopenharmony_ci * So cancel the timer. There is still a theoretical race condition if 16008c2ecf20Sopenharmony_ci * the timer is already running and only comes around to check for 16018c2ecf20Sopenharmony_ci * em485->active_timer when &em485->stop_tx_timer is armed again. 16028c2ecf20Sopenharmony_ci */ 16038c2ecf20Sopenharmony_ci if (em485->active_timer == &em485->stop_tx_timer) 16048c2ecf20Sopenharmony_ci hrtimer_try_to_cancel(&em485->stop_tx_timer); 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci em485->active_timer = NULL; 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci if (em485->tx_stopped) { 16098c2ecf20Sopenharmony_ci em485->tx_stopped = false; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci up->rs485_start_tx(up); 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci if (up->port.rs485.delay_rts_before_send > 0) { 16148c2ecf20Sopenharmony_ci em485->active_timer = &em485->start_tx_timer; 16158c2ecf20Sopenharmony_ci start_hrtimer_ms(&em485->start_tx_timer, 16168c2ecf20Sopenharmony_ci up->port.rs485.delay_rts_before_send); 16178c2ecf20Sopenharmony_ci return; 16188c2ecf20Sopenharmony_ci } 16198c2ecf20Sopenharmony_ci } 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci __start_tx(port); 16228c2ecf20Sopenharmony_ci} 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_cistatic enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t) 16258c2ecf20Sopenharmony_ci{ 16268c2ecf20Sopenharmony_ci struct uart_8250_em485 *em485; 16278c2ecf20Sopenharmony_ci struct uart_8250_port *p; 16288c2ecf20Sopenharmony_ci unsigned long flags; 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci em485 = container_of(t, struct uart_8250_em485, start_tx_timer); 16318c2ecf20Sopenharmony_ci p = em485->port; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci spin_lock_irqsave(&p->port.lock, flags); 16348c2ecf20Sopenharmony_ci if (em485->active_timer == &em485->start_tx_timer) { 16358c2ecf20Sopenharmony_ci __start_tx(&p->port); 16368c2ecf20Sopenharmony_ci em485->active_timer = NULL; 16378c2ecf20Sopenharmony_ci } 16388c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p->port.lock, flags); 16398c2ecf20Sopenharmony_ci return HRTIMER_NORESTART; 16408c2ecf20Sopenharmony_ci} 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_cistatic void serial8250_start_tx(struct uart_port *port) 16438c2ecf20Sopenharmony_ci{ 16448c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 16458c2ecf20Sopenharmony_ci struct uart_8250_em485 *em485 = up->em485; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci serial8250_rpm_get_tx(up); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci if (em485 && 16508c2ecf20Sopenharmony_ci em485->active_timer == &em485->start_tx_timer) 16518c2ecf20Sopenharmony_ci return; 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci if (em485) 16548c2ecf20Sopenharmony_ci start_tx_rs485(port); 16558c2ecf20Sopenharmony_ci else 16568c2ecf20Sopenharmony_ci __start_tx(port); 16578c2ecf20Sopenharmony_ci} 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_cistatic void serial8250_throttle(struct uart_port *port) 16608c2ecf20Sopenharmony_ci{ 16618c2ecf20Sopenharmony_ci port->throttle(port); 16628c2ecf20Sopenharmony_ci} 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_cistatic void serial8250_unthrottle(struct uart_port *port) 16658c2ecf20Sopenharmony_ci{ 16668c2ecf20Sopenharmony_ci port->unthrottle(port); 16678c2ecf20Sopenharmony_ci} 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_cistatic void serial8250_disable_ms(struct uart_port *port) 16708c2ecf20Sopenharmony_ci{ 16718c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci /* no MSR capabilities */ 16748c2ecf20Sopenharmony_ci if (up->bugs & UART_BUG_NOMSR) 16758c2ecf20Sopenharmony_ci return; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci mctrl_gpio_disable_ms(up->gpios); 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci up->ier &= ~UART_IER_MSI; 16808c2ecf20Sopenharmony_ci serial_port_out(port, UART_IER, up->ier); 16818c2ecf20Sopenharmony_ci} 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_cistatic void serial8250_enable_ms(struct uart_port *port) 16848c2ecf20Sopenharmony_ci{ 16858c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci /* no MSR capabilities */ 16888c2ecf20Sopenharmony_ci if (up->bugs & UART_BUG_NOMSR) 16898c2ecf20Sopenharmony_ci return; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci mctrl_gpio_enable_ms(up->gpios); 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci up->ier |= UART_IER_MSI; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci serial8250_rpm_get(up); 16968c2ecf20Sopenharmony_ci serial_port_out(port, UART_IER, up->ier); 16978c2ecf20Sopenharmony_ci serial8250_rpm_put(up); 16988c2ecf20Sopenharmony_ci} 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_civoid serial8250_read_char(struct uart_8250_port *up, unsigned char lsr) 17018c2ecf20Sopenharmony_ci{ 17028c2ecf20Sopenharmony_ci struct uart_port *port = &up->port; 17038c2ecf20Sopenharmony_ci unsigned char ch; 17048c2ecf20Sopenharmony_ci char flag = TTY_NORMAL; 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci if (likely(lsr & UART_LSR_DR)) 17078c2ecf20Sopenharmony_ci ch = serial_in(up, UART_RX); 17088c2ecf20Sopenharmony_ci else 17098c2ecf20Sopenharmony_ci /* 17108c2ecf20Sopenharmony_ci * Intel 82571 has a Serial Over Lan device that will 17118c2ecf20Sopenharmony_ci * set UART_LSR_BI without setting UART_LSR_DR when 17128c2ecf20Sopenharmony_ci * it receives a break. To avoid reading from the 17138c2ecf20Sopenharmony_ci * receive buffer without UART_LSR_DR bit set, we 17148c2ecf20Sopenharmony_ci * just force the read character to be 0 17158c2ecf20Sopenharmony_ci */ 17168c2ecf20Sopenharmony_ci ch = 0; 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci port->icount.rx++; 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci lsr |= up->lsr_saved_flags; 17218c2ecf20Sopenharmony_ci up->lsr_saved_flags = 0; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { 17248c2ecf20Sopenharmony_ci if (lsr & UART_LSR_BI) { 17258c2ecf20Sopenharmony_ci lsr &= ~(UART_LSR_FE | UART_LSR_PE); 17268c2ecf20Sopenharmony_ci port->icount.brk++; 17278c2ecf20Sopenharmony_ci /* 17288c2ecf20Sopenharmony_ci * We do the SysRQ and SAK checking 17298c2ecf20Sopenharmony_ci * here because otherwise the break 17308c2ecf20Sopenharmony_ci * may get masked by ignore_status_mask 17318c2ecf20Sopenharmony_ci * or read_status_mask. 17328c2ecf20Sopenharmony_ci */ 17338c2ecf20Sopenharmony_ci if (uart_handle_break(port)) 17348c2ecf20Sopenharmony_ci return; 17358c2ecf20Sopenharmony_ci } else if (lsr & UART_LSR_PE) 17368c2ecf20Sopenharmony_ci port->icount.parity++; 17378c2ecf20Sopenharmony_ci else if (lsr & UART_LSR_FE) 17388c2ecf20Sopenharmony_ci port->icount.frame++; 17398c2ecf20Sopenharmony_ci if (lsr & UART_LSR_OE) 17408c2ecf20Sopenharmony_ci port->icount.overrun++; 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci /* 17438c2ecf20Sopenharmony_ci * Mask off conditions which should be ignored. 17448c2ecf20Sopenharmony_ci */ 17458c2ecf20Sopenharmony_ci lsr &= port->read_status_mask; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci if (lsr & UART_LSR_BI) { 17488c2ecf20Sopenharmony_ci dev_dbg(port->dev, "handling break\n"); 17498c2ecf20Sopenharmony_ci flag = TTY_BREAK; 17508c2ecf20Sopenharmony_ci } else if (lsr & UART_LSR_PE) 17518c2ecf20Sopenharmony_ci flag = TTY_PARITY; 17528c2ecf20Sopenharmony_ci else if (lsr & UART_LSR_FE) 17538c2ecf20Sopenharmony_ci flag = TTY_FRAME; 17548c2ecf20Sopenharmony_ci } 17558c2ecf20Sopenharmony_ci if (uart_prepare_sysrq_char(port, ch)) 17568c2ecf20Sopenharmony_ci return; 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); 17598c2ecf20Sopenharmony_ci} 17608c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_read_char); 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci/* 17638c2ecf20Sopenharmony_ci * serial8250_rx_chars: processes according to the passed in LSR 17648c2ecf20Sopenharmony_ci * value, and returns the remaining LSR bits not handled 17658c2ecf20Sopenharmony_ci * by this Rx routine. 17668c2ecf20Sopenharmony_ci */ 17678c2ecf20Sopenharmony_ciunsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) 17688c2ecf20Sopenharmony_ci{ 17698c2ecf20Sopenharmony_ci struct uart_port *port = &up->port; 17708c2ecf20Sopenharmony_ci int max_count = 256; 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci do { 17738c2ecf20Sopenharmony_ci serial8250_read_char(up, lsr); 17748c2ecf20Sopenharmony_ci if (--max_count == 0) 17758c2ecf20Sopenharmony_ci break; 17768c2ecf20Sopenharmony_ci lsr = serial_in(up, UART_LSR); 17778c2ecf20Sopenharmony_ci } while (lsr & (UART_LSR_DR | UART_LSR_BI)); 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci tty_flip_buffer_push(&port->state->port); 17808c2ecf20Sopenharmony_ci return lsr; 17818c2ecf20Sopenharmony_ci} 17828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_rx_chars); 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_civoid serial8250_tx_chars(struct uart_8250_port *up) 17858c2ecf20Sopenharmony_ci{ 17868c2ecf20Sopenharmony_ci struct uart_port *port = &up->port; 17878c2ecf20Sopenharmony_ci struct circ_buf *xmit = &port->state->xmit; 17888c2ecf20Sopenharmony_ci int count; 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci if (port->x_char) { 17918c2ecf20Sopenharmony_ci uart_xchar_out(port, UART_TX); 17928c2ecf20Sopenharmony_ci return; 17938c2ecf20Sopenharmony_ci } 17948c2ecf20Sopenharmony_ci if (uart_tx_stopped(port)) { 17958c2ecf20Sopenharmony_ci serial8250_stop_tx(port); 17968c2ecf20Sopenharmony_ci return; 17978c2ecf20Sopenharmony_ci } 17988c2ecf20Sopenharmony_ci if (uart_circ_empty(xmit)) { 17998c2ecf20Sopenharmony_ci __stop_tx(up); 18008c2ecf20Sopenharmony_ci return; 18018c2ecf20Sopenharmony_ci } 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci count = up->tx_loadsz; 18048c2ecf20Sopenharmony_ci do { 18058c2ecf20Sopenharmony_ci serial_out(up, UART_TX, xmit->buf[xmit->tail]); 18068c2ecf20Sopenharmony_ci if (up->bugs & UART_BUG_TXRACE) { 18078c2ecf20Sopenharmony_ci /* 18088c2ecf20Sopenharmony_ci * The Aspeed BMC virtual UARTs have a bug where data 18098c2ecf20Sopenharmony_ci * may get stuck in the BMC's Tx FIFO from bursts of 18108c2ecf20Sopenharmony_ci * writes on the APB interface. 18118c2ecf20Sopenharmony_ci * 18128c2ecf20Sopenharmony_ci * Delay back-to-back writes by a read cycle to avoid 18138c2ecf20Sopenharmony_ci * stalling the VUART. Read a register that won't have 18148c2ecf20Sopenharmony_ci * side-effects and discard the result. 18158c2ecf20Sopenharmony_ci */ 18168c2ecf20Sopenharmony_ci serial_in(up, UART_SCR); 18178c2ecf20Sopenharmony_ci } 18188c2ecf20Sopenharmony_ci xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 18198c2ecf20Sopenharmony_ci port->icount.tx++; 18208c2ecf20Sopenharmony_ci if (uart_circ_empty(xmit)) 18218c2ecf20Sopenharmony_ci break; 18228c2ecf20Sopenharmony_ci if ((up->capabilities & UART_CAP_HFIFO) && 18238c2ecf20Sopenharmony_ci (serial_in(up, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY) 18248c2ecf20Sopenharmony_ci break; 18258c2ecf20Sopenharmony_ci /* The BCM2835 MINI UART THRE bit is really a not-full bit. */ 18268c2ecf20Sopenharmony_ci if ((up->capabilities & UART_CAP_MINI) && 18278c2ecf20Sopenharmony_ci !(serial_in(up, UART_LSR) & UART_LSR_THRE)) 18288c2ecf20Sopenharmony_ci break; 18298c2ecf20Sopenharmony_ci } while (--count > 0); 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 18328c2ecf20Sopenharmony_ci uart_write_wakeup(port); 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci /* 18358c2ecf20Sopenharmony_ci * With RPM enabled, we have to wait until the FIFO is empty before the 18368c2ecf20Sopenharmony_ci * HW can go idle. So we get here once again with empty FIFO and disable 18378c2ecf20Sopenharmony_ci * the interrupt and RPM in __stop_tx() 18388c2ecf20Sopenharmony_ci */ 18398c2ecf20Sopenharmony_ci if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM)) 18408c2ecf20Sopenharmony_ci __stop_tx(up); 18418c2ecf20Sopenharmony_ci} 18428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_tx_chars); 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci/* Caller holds uart port lock */ 18458c2ecf20Sopenharmony_ciunsigned int serial8250_modem_status(struct uart_8250_port *up) 18468c2ecf20Sopenharmony_ci{ 18478c2ecf20Sopenharmony_ci struct uart_port *port = &up->port; 18488c2ecf20Sopenharmony_ci unsigned int status = serial_in(up, UART_MSR); 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci status |= up->msr_saved_flags; 18518c2ecf20Sopenharmony_ci up->msr_saved_flags = 0; 18528c2ecf20Sopenharmony_ci if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI && 18538c2ecf20Sopenharmony_ci port->state != NULL) { 18548c2ecf20Sopenharmony_ci if (status & UART_MSR_TERI) 18558c2ecf20Sopenharmony_ci port->icount.rng++; 18568c2ecf20Sopenharmony_ci if (status & UART_MSR_DDSR) 18578c2ecf20Sopenharmony_ci port->icount.dsr++; 18588c2ecf20Sopenharmony_ci if (status & UART_MSR_DDCD) 18598c2ecf20Sopenharmony_ci uart_handle_dcd_change(port, status & UART_MSR_DCD); 18608c2ecf20Sopenharmony_ci if (status & UART_MSR_DCTS) 18618c2ecf20Sopenharmony_ci uart_handle_cts_change(port, status & UART_MSR_CTS); 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci wake_up_interruptible(&port->state->port.delta_msr_wait); 18648c2ecf20Sopenharmony_ci } 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci return status; 18678c2ecf20Sopenharmony_ci} 18688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_modem_status); 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_cistatic bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir) 18718c2ecf20Sopenharmony_ci{ 18728c2ecf20Sopenharmony_ci switch (iir & 0x3f) { 18738c2ecf20Sopenharmony_ci case UART_IIR_RDI: 18748c2ecf20Sopenharmony_ci if (!up->dma->rx_running) 18758c2ecf20Sopenharmony_ci break; 18768c2ecf20Sopenharmony_ci fallthrough; 18778c2ecf20Sopenharmony_ci case UART_IIR_RLSI: 18788c2ecf20Sopenharmony_ci case UART_IIR_RX_TIMEOUT: 18798c2ecf20Sopenharmony_ci serial8250_rx_dma_flush(up); 18808c2ecf20Sopenharmony_ci return true; 18818c2ecf20Sopenharmony_ci } 18828c2ecf20Sopenharmony_ci return up->dma->rx_dma(up); 18838c2ecf20Sopenharmony_ci} 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci/* 18868c2ecf20Sopenharmony_ci * This handles the interrupt from one port. 18878c2ecf20Sopenharmony_ci */ 18888c2ecf20Sopenharmony_ciint serial8250_handle_irq(struct uart_port *port, unsigned int iir) 18898c2ecf20Sopenharmony_ci{ 18908c2ecf20Sopenharmony_ci unsigned char status; 18918c2ecf20Sopenharmony_ci unsigned long flags; 18928c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 18938c2ecf20Sopenharmony_ci struct tty_port *tport = &port->state->port; 18948c2ecf20Sopenharmony_ci bool skip_rx = false; 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci if (iir & UART_IIR_NO_INT) 18978c2ecf20Sopenharmony_ci return 0; 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci status = serial_port_in(port, UART_LSR); 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci /* 19048c2ecf20Sopenharmony_ci * If port is stopped and there are no error conditions in the 19058c2ecf20Sopenharmony_ci * FIFO, then don't drain the FIFO, as this may lead to TTY buffer 19068c2ecf20Sopenharmony_ci * overflow. Not servicing, RX FIFO would trigger auto HW flow 19078c2ecf20Sopenharmony_ci * control when FIFO occupancy reaches preset threshold, thus 19088c2ecf20Sopenharmony_ci * halting RX. This only works when auto HW flow control is 19098c2ecf20Sopenharmony_ci * available. 19108c2ecf20Sopenharmony_ci */ 19118c2ecf20Sopenharmony_ci if (!(status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) && 19128c2ecf20Sopenharmony_ci (port->status & (UPSTAT_AUTOCTS | UPSTAT_AUTORTS)) && 19138c2ecf20Sopenharmony_ci !(port->read_status_mask & UART_LSR_DR)) 19148c2ecf20Sopenharmony_ci skip_rx = true; 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci if (status & (UART_LSR_DR | UART_LSR_BI) && !skip_rx) { 19178c2ecf20Sopenharmony_ci struct irq_data *d; 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci d = irq_get_irq_data(port->irq); 19208c2ecf20Sopenharmony_ci if (d && irqd_is_wakeup_set(d)) 19218c2ecf20Sopenharmony_ci pm_wakeup_event(tport->tty->dev, 0); 19228c2ecf20Sopenharmony_ci if (!up->dma || handle_rx_dma(up, iir)) 19238c2ecf20Sopenharmony_ci status = serial8250_rx_chars(up, status); 19248c2ecf20Sopenharmony_ci } 19258c2ecf20Sopenharmony_ci serial8250_modem_status(up); 19268c2ecf20Sopenharmony_ci if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE) && 19278c2ecf20Sopenharmony_ci (up->ier & UART_IER_THRI)) 19288c2ecf20Sopenharmony_ci serial8250_tx_chars(up); 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci uart_unlock_and_check_sysrq(port, flags); 19318c2ecf20Sopenharmony_ci return 1; 19328c2ecf20Sopenharmony_ci} 19338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_handle_irq); 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_cistatic int serial8250_default_handle_irq(struct uart_port *port) 19368c2ecf20Sopenharmony_ci{ 19378c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 19388c2ecf20Sopenharmony_ci unsigned int iir; 19398c2ecf20Sopenharmony_ci int ret; 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci serial8250_rpm_get(up); 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci iir = serial_port_in(port, UART_IIR); 19448c2ecf20Sopenharmony_ci ret = serial8250_handle_irq(port, iir); 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci serial8250_rpm_put(up); 19478c2ecf20Sopenharmony_ci return ret; 19488c2ecf20Sopenharmony_ci} 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci/* 19518c2ecf20Sopenharmony_ci * Newer 16550 compatible parts such as the SC16C650 & Altera 16550 Soft IP 19528c2ecf20Sopenharmony_ci * have a programmable TX threshold that triggers the THRE interrupt in 19538c2ecf20Sopenharmony_ci * the IIR register. In this case, the THRE interrupt indicates the FIFO 19548c2ecf20Sopenharmony_ci * has space available. Load it up with tx_loadsz bytes. 19558c2ecf20Sopenharmony_ci */ 19568c2ecf20Sopenharmony_cistatic int serial8250_tx_threshold_handle_irq(struct uart_port *port) 19578c2ecf20Sopenharmony_ci{ 19588c2ecf20Sopenharmony_ci unsigned long flags; 19598c2ecf20Sopenharmony_ci unsigned int iir = serial_port_in(port, UART_IIR); 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci /* TX Threshold IRQ triggered so load up FIFO */ 19628c2ecf20Sopenharmony_ci if ((iir & UART_IIR_ID) == UART_IIR_THRI) { 19638c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 19668c2ecf20Sopenharmony_ci serial8250_tx_chars(up); 19678c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 19688c2ecf20Sopenharmony_ci } 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci iir = serial_port_in(port, UART_IIR); 19718c2ecf20Sopenharmony_ci return serial8250_handle_irq(port, iir); 19728c2ecf20Sopenharmony_ci} 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_cistatic unsigned int serial8250_tx_empty(struct uart_port *port) 19758c2ecf20Sopenharmony_ci{ 19768c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 19778c2ecf20Sopenharmony_ci unsigned int result = 0; 19788c2ecf20Sopenharmony_ci unsigned long flags; 19798c2ecf20Sopenharmony_ci unsigned int lsr; 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci serial8250_rpm_get(up); 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 19848c2ecf20Sopenharmony_ci if (!serial8250_tx_dma_running(up)) { 19858c2ecf20Sopenharmony_ci lsr = serial_port_in(port, UART_LSR); 19868c2ecf20Sopenharmony_ci up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci if ((lsr & BOTH_EMPTY) == BOTH_EMPTY) 19898c2ecf20Sopenharmony_ci result = TIOCSER_TEMT; 19908c2ecf20Sopenharmony_ci } 19918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci serial8250_rpm_put(up); 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci return result; 19968c2ecf20Sopenharmony_ci} 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ciunsigned int serial8250_do_get_mctrl(struct uart_port *port) 19998c2ecf20Sopenharmony_ci{ 20008c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 20018c2ecf20Sopenharmony_ci unsigned int status; 20028c2ecf20Sopenharmony_ci unsigned int val; 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci serial8250_rpm_get(up); 20058c2ecf20Sopenharmony_ci status = serial8250_modem_status(up); 20068c2ecf20Sopenharmony_ci serial8250_rpm_put(up); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci val = serial8250_MSR_to_TIOCM(status); 20098c2ecf20Sopenharmony_ci if (up->gpios) 20108c2ecf20Sopenharmony_ci return mctrl_gpio_get(up->gpios, &val); 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci return val; 20138c2ecf20Sopenharmony_ci} 20148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_do_get_mctrl); 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_cistatic unsigned int serial8250_get_mctrl(struct uart_port *port) 20178c2ecf20Sopenharmony_ci{ 20188c2ecf20Sopenharmony_ci if (port->get_mctrl) 20198c2ecf20Sopenharmony_ci return port->get_mctrl(port); 20208c2ecf20Sopenharmony_ci return serial8250_do_get_mctrl(port); 20218c2ecf20Sopenharmony_ci} 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_civoid serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl) 20248c2ecf20Sopenharmony_ci{ 20258c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 20268c2ecf20Sopenharmony_ci unsigned char mcr; 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci mcr = serial8250_TIOCM_to_MCR(mctrl); 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci serial8250_out_MCR(up, mcr); 20338c2ecf20Sopenharmony_ci} 20348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_do_set_mctrl); 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_cistatic void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) 20378c2ecf20Sopenharmony_ci{ 20388c2ecf20Sopenharmony_ci if (port->rs485.flags & SER_RS485_ENABLED) 20398c2ecf20Sopenharmony_ci return; 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci if (port->set_mctrl) 20428c2ecf20Sopenharmony_ci port->set_mctrl(port, mctrl); 20438c2ecf20Sopenharmony_ci else 20448c2ecf20Sopenharmony_ci serial8250_do_set_mctrl(port, mctrl); 20458c2ecf20Sopenharmony_ci} 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_cistatic void serial8250_break_ctl(struct uart_port *port, int break_state) 20488c2ecf20Sopenharmony_ci{ 20498c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 20508c2ecf20Sopenharmony_ci unsigned long flags; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci serial8250_rpm_get(up); 20538c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 20548c2ecf20Sopenharmony_ci if (break_state == -1) 20558c2ecf20Sopenharmony_ci up->lcr |= UART_LCR_SBC; 20568c2ecf20Sopenharmony_ci else 20578c2ecf20Sopenharmony_ci up->lcr &= ~UART_LCR_SBC; 20588c2ecf20Sopenharmony_ci serial_port_out(port, UART_LCR, up->lcr); 20598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 20608c2ecf20Sopenharmony_ci serial8250_rpm_put(up); 20618c2ecf20Sopenharmony_ci} 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci/* 20648c2ecf20Sopenharmony_ci * Wait for transmitter & holding register to empty 20658c2ecf20Sopenharmony_ci */ 20668c2ecf20Sopenharmony_cistatic void wait_for_xmitr(struct uart_8250_port *up, int bits) 20678c2ecf20Sopenharmony_ci{ 20688c2ecf20Sopenharmony_ci unsigned int status, tmout = 10000; 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci /* Wait up to 10ms for the character(s) to be sent. */ 20718c2ecf20Sopenharmony_ci for (;;) { 20728c2ecf20Sopenharmony_ci status = serial_in(up, UART_LSR); 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci up->lsr_saved_flags |= status & LSR_SAVE_FLAGS; 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci if ((status & bits) == bits) 20778c2ecf20Sopenharmony_ci break; 20788c2ecf20Sopenharmony_ci if (--tmout == 0) 20798c2ecf20Sopenharmony_ci break; 20808c2ecf20Sopenharmony_ci udelay(1); 20818c2ecf20Sopenharmony_ci touch_nmi_watchdog(); 20828c2ecf20Sopenharmony_ci } 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci /* Wait up to 1s for flow control if necessary */ 20858c2ecf20Sopenharmony_ci if (up->port.flags & UPF_CONS_FLOW) { 20868c2ecf20Sopenharmony_ci for (tmout = 1000000; tmout; tmout--) { 20878c2ecf20Sopenharmony_ci unsigned int msr = serial_in(up, UART_MSR); 20888c2ecf20Sopenharmony_ci up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; 20898c2ecf20Sopenharmony_ci if (msr & UART_MSR_CTS) 20908c2ecf20Sopenharmony_ci break; 20918c2ecf20Sopenharmony_ci udelay(1); 20928c2ecf20Sopenharmony_ci touch_nmi_watchdog(); 20938c2ecf20Sopenharmony_ci } 20948c2ecf20Sopenharmony_ci } 20958c2ecf20Sopenharmony_ci} 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci#ifdef CONFIG_CONSOLE_POLL 20988c2ecf20Sopenharmony_ci/* 20998c2ecf20Sopenharmony_ci * Console polling routines for writing and reading from the uart while 21008c2ecf20Sopenharmony_ci * in an interrupt or debug context. 21018c2ecf20Sopenharmony_ci */ 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_cistatic int serial8250_get_poll_char(struct uart_port *port) 21048c2ecf20Sopenharmony_ci{ 21058c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 21068c2ecf20Sopenharmony_ci unsigned char lsr; 21078c2ecf20Sopenharmony_ci int status; 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci serial8250_rpm_get(up); 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci lsr = serial_port_in(port, UART_LSR); 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci if (!(lsr & UART_LSR_DR)) { 21148c2ecf20Sopenharmony_ci status = NO_POLL_CHAR; 21158c2ecf20Sopenharmony_ci goto out; 21168c2ecf20Sopenharmony_ci } 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci status = serial_port_in(port, UART_RX); 21198c2ecf20Sopenharmony_ciout: 21208c2ecf20Sopenharmony_ci serial8250_rpm_put(up); 21218c2ecf20Sopenharmony_ci return status; 21228c2ecf20Sopenharmony_ci} 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_cistatic void serial8250_put_poll_char(struct uart_port *port, 21268c2ecf20Sopenharmony_ci unsigned char c) 21278c2ecf20Sopenharmony_ci{ 21288c2ecf20Sopenharmony_ci unsigned int ier; 21298c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci serial8250_rpm_get(up); 21328c2ecf20Sopenharmony_ci /* 21338c2ecf20Sopenharmony_ci * First save the IER then disable the interrupts 21348c2ecf20Sopenharmony_ci */ 21358c2ecf20Sopenharmony_ci ier = serial_port_in(port, UART_IER); 21368c2ecf20Sopenharmony_ci if (up->capabilities & UART_CAP_UUE) 21378c2ecf20Sopenharmony_ci serial_port_out(port, UART_IER, UART_IER_UUE); 21388c2ecf20Sopenharmony_ci else 21398c2ecf20Sopenharmony_ci serial_port_out(port, UART_IER, 0); 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci wait_for_xmitr(up, BOTH_EMPTY); 21428c2ecf20Sopenharmony_ci /* 21438c2ecf20Sopenharmony_ci * Send the character out. 21448c2ecf20Sopenharmony_ci */ 21458c2ecf20Sopenharmony_ci serial_port_out(port, UART_TX, c); 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci /* 21488c2ecf20Sopenharmony_ci * Finally, wait for transmitter to become empty 21498c2ecf20Sopenharmony_ci * and restore the IER 21508c2ecf20Sopenharmony_ci */ 21518c2ecf20Sopenharmony_ci wait_for_xmitr(up, BOTH_EMPTY); 21528c2ecf20Sopenharmony_ci serial_port_out(port, UART_IER, ier); 21538c2ecf20Sopenharmony_ci serial8250_rpm_put(up); 21548c2ecf20Sopenharmony_ci} 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci#endif /* CONFIG_CONSOLE_POLL */ 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ciint serial8250_do_startup(struct uart_port *port) 21598c2ecf20Sopenharmony_ci{ 21608c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 21618c2ecf20Sopenharmony_ci unsigned long flags; 21628c2ecf20Sopenharmony_ci unsigned char lsr, iir; 21638c2ecf20Sopenharmony_ci int retval; 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci if (!port->fifosize) 21668c2ecf20Sopenharmony_ci port->fifosize = uart_config[port->type].fifo_size; 21678c2ecf20Sopenharmony_ci if (!up->tx_loadsz) 21688c2ecf20Sopenharmony_ci up->tx_loadsz = uart_config[port->type].tx_loadsz; 21698c2ecf20Sopenharmony_ci if (!up->capabilities) 21708c2ecf20Sopenharmony_ci up->capabilities = uart_config[port->type].flags; 21718c2ecf20Sopenharmony_ci up->mcr = 0; 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci if (port->iotype != up->cur_iotype) 21748c2ecf20Sopenharmony_ci set_io_from_upio(port); 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci serial8250_rpm_get(up); 21778c2ecf20Sopenharmony_ci if (port->type == PORT_16C950) { 21788c2ecf20Sopenharmony_ci /* Wake up and initialize UART */ 21798c2ecf20Sopenharmony_ci up->acr = 0; 21808c2ecf20Sopenharmony_ci serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); 21818c2ecf20Sopenharmony_ci serial_port_out(port, UART_EFR, UART_EFR_ECB); 21828c2ecf20Sopenharmony_ci serial_port_out(port, UART_IER, 0); 21838c2ecf20Sopenharmony_ci serial_port_out(port, UART_LCR, 0); 21848c2ecf20Sopenharmony_ci serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ 21858c2ecf20Sopenharmony_ci serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); 21868c2ecf20Sopenharmony_ci serial_port_out(port, UART_EFR, UART_EFR_ECB); 21878c2ecf20Sopenharmony_ci serial_port_out(port, UART_LCR, 0); 21888c2ecf20Sopenharmony_ci } 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci if (port->type == PORT_DA830) { 21918c2ecf20Sopenharmony_ci /* Reset the port */ 21928c2ecf20Sopenharmony_ci serial_port_out(port, UART_IER, 0); 21938c2ecf20Sopenharmony_ci serial_port_out(port, UART_DA830_PWREMU_MGMT, 0); 21948c2ecf20Sopenharmony_ci mdelay(10); 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci /* Enable Tx, Rx and free run mode */ 21978c2ecf20Sopenharmony_ci serial_port_out(port, UART_DA830_PWREMU_MGMT, 21988c2ecf20Sopenharmony_ci UART_DA830_PWREMU_MGMT_UTRST | 21998c2ecf20Sopenharmony_ci UART_DA830_PWREMU_MGMT_URRST | 22008c2ecf20Sopenharmony_ci UART_DA830_PWREMU_MGMT_FREE); 22018c2ecf20Sopenharmony_ci } 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci if (port->type == PORT_NPCM) { 22048c2ecf20Sopenharmony_ci /* 22058c2ecf20Sopenharmony_ci * Nuvoton calls the scratch register 'UART_TOR' (timeout 22068c2ecf20Sopenharmony_ci * register). Enable it, and set TIOC (timeout interrupt 22078c2ecf20Sopenharmony_ci * comparator) to be 0x20 for correct operation. 22088c2ecf20Sopenharmony_ci */ 22098c2ecf20Sopenharmony_ci serial_port_out(port, UART_NPCM_TOR, UART_NPCM_TOIE | 0x20); 22108c2ecf20Sopenharmony_ci } 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_RSA 22138c2ecf20Sopenharmony_ci /* 22148c2ecf20Sopenharmony_ci * If this is an RSA port, see if we can kick it up to the 22158c2ecf20Sopenharmony_ci * higher speed clock. 22168c2ecf20Sopenharmony_ci */ 22178c2ecf20Sopenharmony_ci enable_rsa(up); 22188c2ecf20Sopenharmony_ci#endif 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci /* 22218c2ecf20Sopenharmony_ci * Clear the FIFO buffers and disable them. 22228c2ecf20Sopenharmony_ci * (they will be reenabled in set_termios()) 22238c2ecf20Sopenharmony_ci */ 22248c2ecf20Sopenharmony_ci serial8250_clear_fifos(up); 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci /* 22278c2ecf20Sopenharmony_ci * Clear the interrupt registers. 22288c2ecf20Sopenharmony_ci */ 22298c2ecf20Sopenharmony_ci serial_port_in(port, UART_LSR); 22308c2ecf20Sopenharmony_ci serial_port_in(port, UART_RX); 22318c2ecf20Sopenharmony_ci serial_port_in(port, UART_IIR); 22328c2ecf20Sopenharmony_ci serial_port_in(port, UART_MSR); 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci /* 22358c2ecf20Sopenharmony_ci * At this point, there's no way the LSR could still be 0xff; 22368c2ecf20Sopenharmony_ci * if it is, then bail out, because there's likely no UART 22378c2ecf20Sopenharmony_ci * here. 22388c2ecf20Sopenharmony_ci */ 22398c2ecf20Sopenharmony_ci if (!(port->flags & UPF_BUGGY_UART) && 22408c2ecf20Sopenharmony_ci (serial_port_in(port, UART_LSR) == 0xff)) { 22418c2ecf20Sopenharmony_ci dev_info_ratelimited(port->dev, "LSR safety check engaged!\n"); 22428c2ecf20Sopenharmony_ci retval = -ENODEV; 22438c2ecf20Sopenharmony_ci goto out; 22448c2ecf20Sopenharmony_ci } 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci /* 22478c2ecf20Sopenharmony_ci * For a XR16C850, we need to set the trigger levels 22488c2ecf20Sopenharmony_ci */ 22498c2ecf20Sopenharmony_ci if (port->type == PORT_16850) { 22508c2ecf20Sopenharmony_ci unsigned char fctr; 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci fctr = serial_in(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); 22558c2ecf20Sopenharmony_ci serial_port_out(port, UART_FCTR, 22568c2ecf20Sopenharmony_ci fctr | UART_FCTR_TRGD | UART_FCTR_RX); 22578c2ecf20Sopenharmony_ci serial_port_out(port, UART_TRG, UART_TRG_96); 22588c2ecf20Sopenharmony_ci serial_port_out(port, UART_FCTR, 22598c2ecf20Sopenharmony_ci fctr | UART_FCTR_TRGD | UART_FCTR_TX); 22608c2ecf20Sopenharmony_ci serial_port_out(port, UART_TRG, UART_TRG_96); 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci serial_port_out(port, UART_LCR, 0); 22638c2ecf20Sopenharmony_ci } 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci /* 22668c2ecf20Sopenharmony_ci * For the Altera 16550 variants, set TX threshold trigger level. 22678c2ecf20Sopenharmony_ci */ 22688c2ecf20Sopenharmony_ci if (((port->type == PORT_ALTR_16550_F32) || 22698c2ecf20Sopenharmony_ci (port->type == PORT_ALTR_16550_F64) || 22708c2ecf20Sopenharmony_ci (port->type == PORT_ALTR_16550_F128)) && (port->fifosize > 1)) { 22718c2ecf20Sopenharmony_ci /* Bounds checking of TX threshold (valid 0 to fifosize-2) */ 22728c2ecf20Sopenharmony_ci if ((up->tx_loadsz < 2) || (up->tx_loadsz > port->fifosize)) { 22738c2ecf20Sopenharmony_ci dev_err(port->dev, "TX FIFO Threshold errors, skipping\n"); 22748c2ecf20Sopenharmony_ci } else { 22758c2ecf20Sopenharmony_ci serial_port_out(port, UART_ALTR_AFR, 22768c2ecf20Sopenharmony_ci UART_ALTR_EN_TXFIFO_LW); 22778c2ecf20Sopenharmony_ci serial_port_out(port, UART_ALTR_TX_LOW, 22788c2ecf20Sopenharmony_ci port->fifosize - up->tx_loadsz); 22798c2ecf20Sopenharmony_ci port->handle_irq = serial8250_tx_threshold_handle_irq; 22808c2ecf20Sopenharmony_ci } 22818c2ecf20Sopenharmony_ci } 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci /* Check if we need to have shared IRQs */ 22848c2ecf20Sopenharmony_ci if (port->irq && (up->port.flags & UPF_SHARE_IRQ)) 22858c2ecf20Sopenharmony_ci up->port.irqflags |= IRQF_SHARED; 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci retval = up->ops->setup_irq(up); 22888c2ecf20Sopenharmony_ci if (retval) 22898c2ecf20Sopenharmony_ci goto out; 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_ci if (port->irq && !(up->port.flags & UPF_NO_THRE_TEST)) { 22928c2ecf20Sopenharmony_ci unsigned char iir1; 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci if (port->irqflags & IRQF_SHARED) 22958c2ecf20Sopenharmony_ci disable_irq_nosync(port->irq); 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci /* 22988c2ecf20Sopenharmony_ci * Test for UARTs that do not reassert THRE when the 22998c2ecf20Sopenharmony_ci * transmitter is idle and the interrupt has already 23008c2ecf20Sopenharmony_ci * been cleared. Real 16550s should always reassert 23018c2ecf20Sopenharmony_ci * this interrupt whenever the transmitter is idle and 23028c2ecf20Sopenharmony_ci * the interrupt is enabled. Delays are necessary to 23038c2ecf20Sopenharmony_ci * allow register changes to become visible. 23048c2ecf20Sopenharmony_ci */ 23058c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci wait_for_xmitr(up, UART_LSR_THRE); 23088c2ecf20Sopenharmony_ci serial_port_out_sync(port, UART_IER, UART_IER_THRI); 23098c2ecf20Sopenharmony_ci udelay(1); /* allow THRE to set */ 23108c2ecf20Sopenharmony_ci iir1 = serial_port_in(port, UART_IIR); 23118c2ecf20Sopenharmony_ci serial_port_out(port, UART_IER, 0); 23128c2ecf20Sopenharmony_ci serial_port_out_sync(port, UART_IER, UART_IER_THRI); 23138c2ecf20Sopenharmony_ci udelay(1); /* allow a working UART time to re-assert THRE */ 23148c2ecf20Sopenharmony_ci iir = serial_port_in(port, UART_IIR); 23158c2ecf20Sopenharmony_ci serial_port_out(port, UART_IER, 0); 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci if (port->irqflags & IRQF_SHARED) 23208c2ecf20Sopenharmony_ci enable_irq(port->irq); 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci /* 23238c2ecf20Sopenharmony_ci * If the interrupt is not reasserted, or we otherwise 23248c2ecf20Sopenharmony_ci * don't trust the iir, setup a timer to kick the UART 23258c2ecf20Sopenharmony_ci * on a regular basis. 23268c2ecf20Sopenharmony_ci */ 23278c2ecf20Sopenharmony_ci if ((!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) || 23288c2ecf20Sopenharmony_ci up->port.flags & UPF_BUG_THRE) { 23298c2ecf20Sopenharmony_ci up->bugs |= UART_BUG_THRE; 23308c2ecf20Sopenharmony_ci } 23318c2ecf20Sopenharmony_ci } 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci up->ops->setup_timer(up); 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci /* 23368c2ecf20Sopenharmony_ci * Now, initialize the UART 23378c2ecf20Sopenharmony_ci */ 23388c2ecf20Sopenharmony_ci serial_port_out(port, UART_LCR, UART_LCR_WLEN8); 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 23418c2ecf20Sopenharmony_ci if (up->port.flags & UPF_FOURPORT) { 23428c2ecf20Sopenharmony_ci if (!up->port.irq) 23438c2ecf20Sopenharmony_ci up->port.mctrl |= TIOCM_OUT1; 23448c2ecf20Sopenharmony_ci } else 23458c2ecf20Sopenharmony_ci /* 23468c2ecf20Sopenharmony_ci * Most PC uarts need OUT2 raised to enable interrupts. 23478c2ecf20Sopenharmony_ci */ 23488c2ecf20Sopenharmony_ci if (port->irq) 23498c2ecf20Sopenharmony_ci up->port.mctrl |= TIOCM_OUT2; 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci serial8250_set_mctrl(port, port->mctrl); 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci /* 23548c2ecf20Sopenharmony_ci * Serial over Lan (SoL) hack: 23558c2ecf20Sopenharmony_ci * Intel 8257x Gigabit ethernet chips have a 16550 emulation, to be 23568c2ecf20Sopenharmony_ci * used for Serial Over Lan. Those chips take a longer time than a 23578c2ecf20Sopenharmony_ci * normal serial device to signalize that a transmission data was 23588c2ecf20Sopenharmony_ci * queued. Due to that, the above test generally fails. One solution 23598c2ecf20Sopenharmony_ci * would be to delay the reading of iir. However, this is not 23608c2ecf20Sopenharmony_ci * reliable, since the timeout is variable. So, let's just don't 23618c2ecf20Sopenharmony_ci * test if we receive TX irq. This way, we'll never enable 23628c2ecf20Sopenharmony_ci * UART_BUG_TXEN. 23638c2ecf20Sopenharmony_ci */ 23648c2ecf20Sopenharmony_ci if (up->port.quirks & UPQ_NO_TXEN_TEST) 23658c2ecf20Sopenharmony_ci goto dont_test_tx_en; 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci /* 23688c2ecf20Sopenharmony_ci * Do a quick test to see if we receive an interrupt when we enable 23698c2ecf20Sopenharmony_ci * the TX irq. 23708c2ecf20Sopenharmony_ci */ 23718c2ecf20Sopenharmony_ci serial_port_out(port, UART_IER, UART_IER_THRI); 23728c2ecf20Sopenharmony_ci lsr = serial_port_in(port, UART_LSR); 23738c2ecf20Sopenharmony_ci iir = serial_port_in(port, UART_IIR); 23748c2ecf20Sopenharmony_ci serial_port_out(port, UART_IER, 0); 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { 23778c2ecf20Sopenharmony_ci if (!(up->bugs & UART_BUG_TXEN)) { 23788c2ecf20Sopenharmony_ci up->bugs |= UART_BUG_TXEN; 23798c2ecf20Sopenharmony_ci dev_dbg(port->dev, "enabling bad tx status workarounds\n"); 23808c2ecf20Sopenharmony_ci } 23818c2ecf20Sopenharmony_ci } else { 23828c2ecf20Sopenharmony_ci up->bugs &= ~UART_BUG_TXEN; 23838c2ecf20Sopenharmony_ci } 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_cidont_test_tx_en: 23868c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci /* 23898c2ecf20Sopenharmony_ci * Clear the interrupt registers again for luck, and clear the 23908c2ecf20Sopenharmony_ci * saved flags to avoid getting false values from polling 23918c2ecf20Sopenharmony_ci * routines or the previous session. 23928c2ecf20Sopenharmony_ci */ 23938c2ecf20Sopenharmony_ci serial_port_in(port, UART_LSR); 23948c2ecf20Sopenharmony_ci serial_port_in(port, UART_RX); 23958c2ecf20Sopenharmony_ci serial_port_in(port, UART_IIR); 23968c2ecf20Sopenharmony_ci serial_port_in(port, UART_MSR); 23978c2ecf20Sopenharmony_ci up->lsr_saved_flags = 0; 23988c2ecf20Sopenharmony_ci up->msr_saved_flags = 0; 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci /* 24018c2ecf20Sopenharmony_ci * Request DMA channels for both RX and TX. 24028c2ecf20Sopenharmony_ci */ 24038c2ecf20Sopenharmony_ci if (up->dma) { 24048c2ecf20Sopenharmony_ci const char *msg = NULL; 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci if (uart_console(port)) 24078c2ecf20Sopenharmony_ci msg = "forbid DMA for kernel console"; 24088c2ecf20Sopenharmony_ci else if (serial8250_request_dma(up)) 24098c2ecf20Sopenharmony_ci msg = "failed to request DMA"; 24108c2ecf20Sopenharmony_ci if (msg) { 24118c2ecf20Sopenharmony_ci dev_warn_ratelimited(port->dev, "%s\n", msg); 24128c2ecf20Sopenharmony_ci up->dma = NULL; 24138c2ecf20Sopenharmony_ci } 24148c2ecf20Sopenharmony_ci } 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci /* 24178c2ecf20Sopenharmony_ci * Set the IER shadow for rx interrupts but defer actual interrupt 24188c2ecf20Sopenharmony_ci * enable until after the FIFOs are enabled; otherwise, an already- 24198c2ecf20Sopenharmony_ci * active sender can swamp the interrupt handler with "too much work". 24208c2ecf20Sopenharmony_ci */ 24218c2ecf20Sopenharmony_ci up->ier = UART_IER_RLSI | UART_IER_RDI; 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_ci if (port->flags & UPF_FOURPORT) { 24248c2ecf20Sopenharmony_ci unsigned int icp; 24258c2ecf20Sopenharmony_ci /* 24268c2ecf20Sopenharmony_ci * Enable interrupts on the AST Fourport board 24278c2ecf20Sopenharmony_ci */ 24288c2ecf20Sopenharmony_ci icp = (port->iobase & 0xfe0) | 0x01f; 24298c2ecf20Sopenharmony_ci outb_p(0x80, icp); 24308c2ecf20Sopenharmony_ci inb_p(icp); 24318c2ecf20Sopenharmony_ci } 24328c2ecf20Sopenharmony_ci retval = 0; 24338c2ecf20Sopenharmony_ciout: 24348c2ecf20Sopenharmony_ci serial8250_rpm_put(up); 24358c2ecf20Sopenharmony_ci return retval; 24368c2ecf20Sopenharmony_ci} 24378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_do_startup); 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_cistatic int serial8250_startup(struct uart_port *port) 24408c2ecf20Sopenharmony_ci{ 24418c2ecf20Sopenharmony_ci if (port->startup) 24428c2ecf20Sopenharmony_ci return port->startup(port); 24438c2ecf20Sopenharmony_ci return serial8250_do_startup(port); 24448c2ecf20Sopenharmony_ci} 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_civoid serial8250_do_shutdown(struct uart_port *port) 24478c2ecf20Sopenharmony_ci{ 24488c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 24498c2ecf20Sopenharmony_ci unsigned long flags; 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci serial8250_rpm_get(up); 24528c2ecf20Sopenharmony_ci /* 24538c2ecf20Sopenharmony_ci * Disable interrupts from this port 24548c2ecf20Sopenharmony_ci */ 24558c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 24568c2ecf20Sopenharmony_ci up->ier = 0; 24578c2ecf20Sopenharmony_ci serial_port_out(port, UART_IER, 0); 24588c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci synchronize_irq(port->irq); 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci if (up->dma) 24638c2ecf20Sopenharmony_ci serial8250_release_dma(up); 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 24668c2ecf20Sopenharmony_ci if (port->flags & UPF_FOURPORT) { 24678c2ecf20Sopenharmony_ci /* reset interrupts on the AST Fourport board */ 24688c2ecf20Sopenharmony_ci inb((port->iobase & 0xfe0) | 0x1f); 24698c2ecf20Sopenharmony_ci port->mctrl |= TIOCM_OUT1; 24708c2ecf20Sopenharmony_ci } else 24718c2ecf20Sopenharmony_ci port->mctrl &= ~TIOCM_OUT2; 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci serial8250_set_mctrl(port, port->mctrl); 24748c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ci /* 24778c2ecf20Sopenharmony_ci * Disable break condition and FIFOs 24788c2ecf20Sopenharmony_ci */ 24798c2ecf20Sopenharmony_ci serial_port_out(port, UART_LCR, 24808c2ecf20Sopenharmony_ci serial_port_in(port, UART_LCR) & ~UART_LCR_SBC); 24818c2ecf20Sopenharmony_ci serial8250_clear_fifos(up); 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_RSA 24848c2ecf20Sopenharmony_ci /* 24858c2ecf20Sopenharmony_ci * Reset the RSA board back to 115kbps compat mode. 24868c2ecf20Sopenharmony_ci */ 24878c2ecf20Sopenharmony_ci disable_rsa(up); 24888c2ecf20Sopenharmony_ci#endif 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci /* 24918c2ecf20Sopenharmony_ci * Read data port to reset things, and then unlink from 24928c2ecf20Sopenharmony_ci * the IRQ chain. 24938c2ecf20Sopenharmony_ci */ 24948c2ecf20Sopenharmony_ci serial_port_in(port, UART_RX); 24958c2ecf20Sopenharmony_ci serial8250_rpm_put(up); 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci up->ops->release_irq(up); 24988c2ecf20Sopenharmony_ci} 24998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_do_shutdown); 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_cistatic void serial8250_shutdown(struct uart_port *port) 25028c2ecf20Sopenharmony_ci{ 25038c2ecf20Sopenharmony_ci if (port->shutdown) 25048c2ecf20Sopenharmony_ci port->shutdown(port); 25058c2ecf20Sopenharmony_ci else 25068c2ecf20Sopenharmony_ci serial8250_do_shutdown(port); 25078c2ecf20Sopenharmony_ci} 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci/* Nuvoton NPCM UARTs have a custom divisor calculation */ 25108c2ecf20Sopenharmony_cistatic unsigned int npcm_get_divisor(struct uart_8250_port *up, 25118c2ecf20Sopenharmony_ci unsigned int baud) 25128c2ecf20Sopenharmony_ci{ 25138c2ecf20Sopenharmony_ci struct uart_port *port = &up->port; 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2; 25168c2ecf20Sopenharmony_ci} 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_cistatic unsigned int serial8250_do_get_divisor(struct uart_port *port, 25198c2ecf20Sopenharmony_ci unsigned int baud, 25208c2ecf20Sopenharmony_ci unsigned int *frac) 25218c2ecf20Sopenharmony_ci{ 25228c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 25238c2ecf20Sopenharmony_ci unsigned int quot; 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci /* 25268c2ecf20Sopenharmony_ci * Handle magic divisors for baud rates above baud_base on 25278c2ecf20Sopenharmony_ci * SMSC SuperIO chips. 25288c2ecf20Sopenharmony_ci * 25298c2ecf20Sopenharmony_ci */ 25308c2ecf20Sopenharmony_ci if ((port->flags & UPF_MAGIC_MULTIPLIER) && 25318c2ecf20Sopenharmony_ci baud == (port->uartclk/4)) 25328c2ecf20Sopenharmony_ci quot = 0x8001; 25338c2ecf20Sopenharmony_ci else if ((port->flags & UPF_MAGIC_MULTIPLIER) && 25348c2ecf20Sopenharmony_ci baud == (port->uartclk/8)) 25358c2ecf20Sopenharmony_ci quot = 0x8002; 25368c2ecf20Sopenharmony_ci else if (up->port.type == PORT_NPCM) 25378c2ecf20Sopenharmony_ci quot = npcm_get_divisor(up, baud); 25388c2ecf20Sopenharmony_ci else 25398c2ecf20Sopenharmony_ci quot = uart_get_divisor(port, baud); 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci /* 25428c2ecf20Sopenharmony_ci * Oxford Semi 952 rev B workaround 25438c2ecf20Sopenharmony_ci */ 25448c2ecf20Sopenharmony_ci if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0) 25458c2ecf20Sopenharmony_ci quot++; 25468c2ecf20Sopenharmony_ci 25478c2ecf20Sopenharmony_ci return quot; 25488c2ecf20Sopenharmony_ci} 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_cistatic unsigned int serial8250_get_divisor(struct uart_port *port, 25518c2ecf20Sopenharmony_ci unsigned int baud, 25528c2ecf20Sopenharmony_ci unsigned int *frac) 25538c2ecf20Sopenharmony_ci{ 25548c2ecf20Sopenharmony_ci if (port->get_divisor) 25558c2ecf20Sopenharmony_ci return port->get_divisor(port, baud, frac); 25568c2ecf20Sopenharmony_ci 25578c2ecf20Sopenharmony_ci return serial8250_do_get_divisor(port, baud, frac); 25588c2ecf20Sopenharmony_ci} 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_cistatic unsigned char serial8250_compute_lcr(struct uart_8250_port *up, 25618c2ecf20Sopenharmony_ci tcflag_t c_cflag) 25628c2ecf20Sopenharmony_ci{ 25638c2ecf20Sopenharmony_ci unsigned char cval; 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci switch (c_cflag & CSIZE) { 25668c2ecf20Sopenharmony_ci case CS5: 25678c2ecf20Sopenharmony_ci cval = UART_LCR_WLEN5; 25688c2ecf20Sopenharmony_ci break; 25698c2ecf20Sopenharmony_ci case CS6: 25708c2ecf20Sopenharmony_ci cval = UART_LCR_WLEN6; 25718c2ecf20Sopenharmony_ci break; 25728c2ecf20Sopenharmony_ci case CS7: 25738c2ecf20Sopenharmony_ci cval = UART_LCR_WLEN7; 25748c2ecf20Sopenharmony_ci break; 25758c2ecf20Sopenharmony_ci default: 25768c2ecf20Sopenharmony_ci case CS8: 25778c2ecf20Sopenharmony_ci cval = UART_LCR_WLEN8; 25788c2ecf20Sopenharmony_ci break; 25798c2ecf20Sopenharmony_ci } 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci if (c_cflag & CSTOPB) 25828c2ecf20Sopenharmony_ci cval |= UART_LCR_STOP; 25838c2ecf20Sopenharmony_ci if (c_cflag & PARENB) 25848c2ecf20Sopenharmony_ci cval |= UART_LCR_PARITY; 25858c2ecf20Sopenharmony_ci if (!(c_cflag & PARODD)) 25868c2ecf20Sopenharmony_ci cval |= UART_LCR_EPAR; 25878c2ecf20Sopenharmony_ci#ifdef CMSPAR 25888c2ecf20Sopenharmony_ci if (c_cflag & CMSPAR) 25898c2ecf20Sopenharmony_ci cval |= UART_LCR_SPAR; 25908c2ecf20Sopenharmony_ci#endif 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci return cval; 25938c2ecf20Sopenharmony_ci} 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_civoid serial8250_do_set_divisor(struct uart_port *port, unsigned int baud, 25968c2ecf20Sopenharmony_ci unsigned int quot, unsigned int quot_frac) 25978c2ecf20Sopenharmony_ci{ 25988c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 25998c2ecf20Sopenharmony_ci 26008c2ecf20Sopenharmony_ci /* Workaround to enable 115200 baud on OMAP1510 internal ports */ 26018c2ecf20Sopenharmony_ci if (is_omap1510_8250(up)) { 26028c2ecf20Sopenharmony_ci if (baud == 115200) { 26038c2ecf20Sopenharmony_ci quot = 1; 26048c2ecf20Sopenharmony_ci serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1); 26058c2ecf20Sopenharmony_ci } else 26068c2ecf20Sopenharmony_ci serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0); 26078c2ecf20Sopenharmony_ci } 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci /* 26108c2ecf20Sopenharmony_ci * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2, 26118c2ecf20Sopenharmony_ci * otherwise just set DLAB 26128c2ecf20Sopenharmony_ci */ 26138c2ecf20Sopenharmony_ci if (up->capabilities & UART_NATSEMI) 26148c2ecf20Sopenharmony_ci serial_port_out(port, UART_LCR, 0xe0); 26158c2ecf20Sopenharmony_ci else 26168c2ecf20Sopenharmony_ci serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB); 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_ci serial_dl_write(up, quot); 26198c2ecf20Sopenharmony_ci} 26208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_do_set_divisor); 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_cistatic void serial8250_set_divisor(struct uart_port *port, unsigned int baud, 26238c2ecf20Sopenharmony_ci unsigned int quot, unsigned int quot_frac) 26248c2ecf20Sopenharmony_ci{ 26258c2ecf20Sopenharmony_ci if (port->set_divisor) 26268c2ecf20Sopenharmony_ci port->set_divisor(port, baud, quot, quot_frac); 26278c2ecf20Sopenharmony_ci else 26288c2ecf20Sopenharmony_ci serial8250_do_set_divisor(port, baud, quot, quot_frac); 26298c2ecf20Sopenharmony_ci} 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_cistatic unsigned int serial8250_get_baud_rate(struct uart_port *port, 26328c2ecf20Sopenharmony_ci struct ktermios *termios, 26338c2ecf20Sopenharmony_ci struct ktermios *old) 26348c2ecf20Sopenharmony_ci{ 26358c2ecf20Sopenharmony_ci unsigned int tolerance = port->uartclk / 100; 26368c2ecf20Sopenharmony_ci unsigned int min; 26378c2ecf20Sopenharmony_ci unsigned int max; 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_ci /* 26408c2ecf20Sopenharmony_ci * Handle magic divisors for baud rates above baud_base on SMSC 26418c2ecf20Sopenharmony_ci * Super I/O chips. Enable custom rates of clk/4 and clk/8, but 26428c2ecf20Sopenharmony_ci * disable divisor values beyond 32767, which are unavailable. 26438c2ecf20Sopenharmony_ci */ 26448c2ecf20Sopenharmony_ci if (port->flags & UPF_MAGIC_MULTIPLIER) { 26458c2ecf20Sopenharmony_ci min = port->uartclk / 16 / UART_DIV_MAX >> 1; 26468c2ecf20Sopenharmony_ci max = (port->uartclk + tolerance) / 4; 26478c2ecf20Sopenharmony_ci } else { 26488c2ecf20Sopenharmony_ci min = port->uartclk / 16 / UART_DIV_MAX; 26498c2ecf20Sopenharmony_ci max = (port->uartclk + tolerance) / 16; 26508c2ecf20Sopenharmony_ci } 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci /* 26538c2ecf20Sopenharmony_ci * Ask the core to calculate the divisor for us. 26548c2ecf20Sopenharmony_ci * Allow 1% tolerance at the upper limit so uart clks marginally 26558c2ecf20Sopenharmony_ci * slower than nominal still match standard baud rates without 26568c2ecf20Sopenharmony_ci * causing transmission errors. 26578c2ecf20Sopenharmony_ci */ 26588c2ecf20Sopenharmony_ci return uart_get_baud_rate(port, termios, old, min, max); 26598c2ecf20Sopenharmony_ci} 26608c2ecf20Sopenharmony_ci 26618c2ecf20Sopenharmony_ci/* 26628c2ecf20Sopenharmony_ci * Note in order to avoid the tty port mutex deadlock don't use the next method 26638c2ecf20Sopenharmony_ci * within the uart port callbacks. Primarily it's supposed to be utilized to 26648c2ecf20Sopenharmony_ci * handle a sudden reference clock rate change. 26658c2ecf20Sopenharmony_ci */ 26668c2ecf20Sopenharmony_civoid serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk) 26678c2ecf20Sopenharmony_ci{ 26688c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 26698c2ecf20Sopenharmony_ci struct tty_port *tport = &port->state->port; 26708c2ecf20Sopenharmony_ci unsigned int baud, quot, frac = 0; 26718c2ecf20Sopenharmony_ci struct ktermios *termios; 26728c2ecf20Sopenharmony_ci struct tty_struct *tty; 26738c2ecf20Sopenharmony_ci unsigned long flags; 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_ci tty = tty_port_tty_get(tport); 26768c2ecf20Sopenharmony_ci if (!tty) { 26778c2ecf20Sopenharmony_ci mutex_lock(&tport->mutex); 26788c2ecf20Sopenharmony_ci port->uartclk = uartclk; 26798c2ecf20Sopenharmony_ci mutex_unlock(&tport->mutex); 26808c2ecf20Sopenharmony_ci return; 26818c2ecf20Sopenharmony_ci } 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci down_write(&tty->termios_rwsem); 26848c2ecf20Sopenharmony_ci mutex_lock(&tport->mutex); 26858c2ecf20Sopenharmony_ci 26868c2ecf20Sopenharmony_ci if (port->uartclk == uartclk) 26878c2ecf20Sopenharmony_ci goto out_lock; 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_ci port->uartclk = uartclk; 26908c2ecf20Sopenharmony_ci 26918c2ecf20Sopenharmony_ci if (!tty_port_initialized(tport)) 26928c2ecf20Sopenharmony_ci goto out_lock; 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci termios = &tty->termios; 26958c2ecf20Sopenharmony_ci 26968c2ecf20Sopenharmony_ci baud = serial8250_get_baud_rate(port, termios, NULL); 26978c2ecf20Sopenharmony_ci quot = serial8250_get_divisor(port, baud, &frac); 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci serial8250_rpm_get(up); 27008c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci uart_update_timeout(port, termios->c_cflag, baud); 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_ci serial8250_set_divisor(port, baud, quot, frac); 27058c2ecf20Sopenharmony_ci serial_port_out(port, UART_LCR, up->lcr); 27068c2ecf20Sopenharmony_ci 27078c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 27088c2ecf20Sopenharmony_ci serial8250_rpm_put(up); 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ciout_lock: 27118c2ecf20Sopenharmony_ci mutex_unlock(&tport->mutex); 27128c2ecf20Sopenharmony_ci up_write(&tty->termios_rwsem); 27138c2ecf20Sopenharmony_ci tty_kref_put(tty); 27148c2ecf20Sopenharmony_ci} 27158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_update_uartclk); 27168c2ecf20Sopenharmony_ci 27178c2ecf20Sopenharmony_civoid 27188c2ecf20Sopenharmony_ciserial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, 27198c2ecf20Sopenharmony_ci struct ktermios *old) 27208c2ecf20Sopenharmony_ci{ 27218c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 27228c2ecf20Sopenharmony_ci unsigned char cval; 27238c2ecf20Sopenharmony_ci unsigned long flags; 27248c2ecf20Sopenharmony_ci unsigned int baud, quot, frac = 0; 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_ci if (up->capabilities & UART_CAP_MINI) { 27278c2ecf20Sopenharmony_ci termios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CMSPAR); 27288c2ecf20Sopenharmony_ci if ((termios->c_cflag & CSIZE) == CS5 || 27298c2ecf20Sopenharmony_ci (termios->c_cflag & CSIZE) == CS6) 27308c2ecf20Sopenharmony_ci termios->c_cflag = (termios->c_cflag & ~CSIZE) | CS7; 27318c2ecf20Sopenharmony_ci } 27328c2ecf20Sopenharmony_ci cval = serial8250_compute_lcr(up, termios->c_cflag); 27338c2ecf20Sopenharmony_ci 27348c2ecf20Sopenharmony_ci baud = serial8250_get_baud_rate(port, termios, old); 27358c2ecf20Sopenharmony_ci quot = serial8250_get_divisor(port, baud, &frac); 27368c2ecf20Sopenharmony_ci 27378c2ecf20Sopenharmony_ci /* 27388c2ecf20Sopenharmony_ci * Ok, we're now changing the port state. Do it with 27398c2ecf20Sopenharmony_ci * interrupts disabled. 27408c2ecf20Sopenharmony_ci */ 27418c2ecf20Sopenharmony_ci serial8250_rpm_get(up); 27428c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci up->lcr = cval; /* Save computed LCR */ 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_ci if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { 27478c2ecf20Sopenharmony_ci if (baud < 2400 && !up->dma) { 27488c2ecf20Sopenharmony_ci up->fcr &= ~UART_FCR_TRIGGER_MASK; 27498c2ecf20Sopenharmony_ci up->fcr |= UART_FCR_TRIGGER_1; 27508c2ecf20Sopenharmony_ci } 27518c2ecf20Sopenharmony_ci } 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci /* 27548c2ecf20Sopenharmony_ci * MCR-based auto flow control. When AFE is enabled, RTS will be 27558c2ecf20Sopenharmony_ci * deasserted when the receive FIFO contains more characters than 27568c2ecf20Sopenharmony_ci * the trigger, or the MCR RTS bit is cleared. 27578c2ecf20Sopenharmony_ci */ 27588c2ecf20Sopenharmony_ci if (up->capabilities & UART_CAP_AFE) { 27598c2ecf20Sopenharmony_ci up->mcr &= ~UART_MCR_AFE; 27608c2ecf20Sopenharmony_ci if (termios->c_cflag & CRTSCTS) 27618c2ecf20Sopenharmony_ci up->mcr |= UART_MCR_AFE; 27628c2ecf20Sopenharmony_ci } 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_ci /* 27658c2ecf20Sopenharmony_ci * Update the per-port timeout. 27668c2ecf20Sopenharmony_ci */ 27678c2ecf20Sopenharmony_ci uart_update_timeout(port, termios->c_cflag, baud); 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; 27708c2ecf20Sopenharmony_ci if (termios->c_iflag & INPCK) 27718c2ecf20Sopenharmony_ci port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; 27728c2ecf20Sopenharmony_ci if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 27738c2ecf20Sopenharmony_ci port->read_status_mask |= UART_LSR_BI; 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci /* 27768c2ecf20Sopenharmony_ci * Characteres to ignore 27778c2ecf20Sopenharmony_ci */ 27788c2ecf20Sopenharmony_ci port->ignore_status_mask = 0; 27798c2ecf20Sopenharmony_ci if (termios->c_iflag & IGNPAR) 27808c2ecf20Sopenharmony_ci port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; 27818c2ecf20Sopenharmony_ci if (termios->c_iflag & IGNBRK) { 27828c2ecf20Sopenharmony_ci port->ignore_status_mask |= UART_LSR_BI; 27838c2ecf20Sopenharmony_ci /* 27848c2ecf20Sopenharmony_ci * If we're ignoring parity and break indicators, 27858c2ecf20Sopenharmony_ci * ignore overruns too (for real raw support). 27868c2ecf20Sopenharmony_ci */ 27878c2ecf20Sopenharmony_ci if (termios->c_iflag & IGNPAR) 27888c2ecf20Sopenharmony_ci port->ignore_status_mask |= UART_LSR_OE; 27898c2ecf20Sopenharmony_ci } 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci /* 27928c2ecf20Sopenharmony_ci * ignore all characters if CREAD is not set 27938c2ecf20Sopenharmony_ci */ 27948c2ecf20Sopenharmony_ci if ((termios->c_cflag & CREAD) == 0) 27958c2ecf20Sopenharmony_ci port->ignore_status_mask |= UART_LSR_DR; 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci /* 27988c2ecf20Sopenharmony_ci * CTS flow control flag and modem status interrupts 27998c2ecf20Sopenharmony_ci */ 28008c2ecf20Sopenharmony_ci up->ier &= ~UART_IER_MSI; 28018c2ecf20Sopenharmony_ci if (!(up->bugs & UART_BUG_NOMSR) && 28028c2ecf20Sopenharmony_ci UART_ENABLE_MS(&up->port, termios->c_cflag)) 28038c2ecf20Sopenharmony_ci up->ier |= UART_IER_MSI; 28048c2ecf20Sopenharmony_ci if (up->capabilities & UART_CAP_UUE) 28058c2ecf20Sopenharmony_ci up->ier |= UART_IER_UUE; 28068c2ecf20Sopenharmony_ci if (up->capabilities & UART_CAP_RTOIE) 28078c2ecf20Sopenharmony_ci up->ier |= UART_IER_RTOIE; 28088c2ecf20Sopenharmony_ci 28098c2ecf20Sopenharmony_ci serial_port_out(port, UART_IER, up->ier); 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci if (up->capabilities & UART_CAP_EFR) { 28128c2ecf20Sopenharmony_ci unsigned char efr = 0; 28138c2ecf20Sopenharmony_ci /* 28148c2ecf20Sopenharmony_ci * TI16C752/Startech hardware flow control. FIXME: 28158c2ecf20Sopenharmony_ci * - TI16C752 requires control thresholds to be set. 28168c2ecf20Sopenharmony_ci * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled. 28178c2ecf20Sopenharmony_ci */ 28188c2ecf20Sopenharmony_ci if (termios->c_cflag & CRTSCTS) 28198c2ecf20Sopenharmony_ci efr |= UART_EFR_CTS; 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_ci serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); 28228c2ecf20Sopenharmony_ci if (port->flags & UPF_EXAR_EFR) 28238c2ecf20Sopenharmony_ci serial_port_out(port, UART_XR_EFR, efr); 28248c2ecf20Sopenharmony_ci else 28258c2ecf20Sopenharmony_ci serial_port_out(port, UART_EFR, efr); 28268c2ecf20Sopenharmony_ci } 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_ci serial8250_set_divisor(port, baud, quot, frac); 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_ci /* 28318c2ecf20Sopenharmony_ci * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR 28328c2ecf20Sopenharmony_ci * is written without DLAB set, this mode will be disabled. 28338c2ecf20Sopenharmony_ci */ 28348c2ecf20Sopenharmony_ci if (port->type == PORT_16750) 28358c2ecf20Sopenharmony_ci serial_port_out(port, UART_FCR, up->fcr); 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_ci serial_port_out(port, UART_LCR, up->lcr); /* reset DLAB */ 28388c2ecf20Sopenharmony_ci if (port->type != PORT_16750) { 28398c2ecf20Sopenharmony_ci /* emulated UARTs (Lucent Venus 167x) need two steps */ 28408c2ecf20Sopenharmony_ci if (up->fcr & UART_FCR_ENABLE_FIFO) 28418c2ecf20Sopenharmony_ci serial_port_out(port, UART_FCR, UART_FCR_ENABLE_FIFO); 28428c2ecf20Sopenharmony_ci serial_port_out(port, UART_FCR, up->fcr); /* set fcr */ 28438c2ecf20Sopenharmony_ci } 28448c2ecf20Sopenharmony_ci serial8250_set_mctrl(port, port->mctrl); 28458c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 28468c2ecf20Sopenharmony_ci serial8250_rpm_put(up); 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_ci /* Don't rewrite B0 */ 28498c2ecf20Sopenharmony_ci if (tty_termios_baud_rate(termios)) 28508c2ecf20Sopenharmony_ci tty_termios_encode_baud_rate(termios, baud, baud); 28518c2ecf20Sopenharmony_ci} 28528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(serial8250_do_set_termios); 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_cistatic void 28558c2ecf20Sopenharmony_ciserial8250_set_termios(struct uart_port *port, struct ktermios *termios, 28568c2ecf20Sopenharmony_ci struct ktermios *old) 28578c2ecf20Sopenharmony_ci{ 28588c2ecf20Sopenharmony_ci if (port->set_termios) 28598c2ecf20Sopenharmony_ci port->set_termios(port, termios, old); 28608c2ecf20Sopenharmony_ci else 28618c2ecf20Sopenharmony_ci serial8250_do_set_termios(port, termios, old); 28628c2ecf20Sopenharmony_ci} 28638c2ecf20Sopenharmony_ci 28648c2ecf20Sopenharmony_civoid serial8250_do_set_ldisc(struct uart_port *port, struct ktermios *termios) 28658c2ecf20Sopenharmony_ci{ 28668c2ecf20Sopenharmony_ci if (termios->c_line == N_PPS) { 28678c2ecf20Sopenharmony_ci port->flags |= UPF_HARDPPS_CD; 28688c2ecf20Sopenharmony_ci spin_lock_irq(&port->lock); 28698c2ecf20Sopenharmony_ci serial8250_enable_ms(port); 28708c2ecf20Sopenharmony_ci spin_unlock_irq(&port->lock); 28718c2ecf20Sopenharmony_ci } else { 28728c2ecf20Sopenharmony_ci port->flags &= ~UPF_HARDPPS_CD; 28738c2ecf20Sopenharmony_ci if (!UART_ENABLE_MS(port, termios->c_cflag)) { 28748c2ecf20Sopenharmony_ci spin_lock_irq(&port->lock); 28758c2ecf20Sopenharmony_ci serial8250_disable_ms(port); 28768c2ecf20Sopenharmony_ci spin_unlock_irq(&port->lock); 28778c2ecf20Sopenharmony_ci } 28788c2ecf20Sopenharmony_ci } 28798c2ecf20Sopenharmony_ci} 28808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_do_set_ldisc); 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_cistatic void 28838c2ecf20Sopenharmony_ciserial8250_set_ldisc(struct uart_port *port, struct ktermios *termios) 28848c2ecf20Sopenharmony_ci{ 28858c2ecf20Sopenharmony_ci if (port->set_ldisc) 28868c2ecf20Sopenharmony_ci port->set_ldisc(port, termios); 28878c2ecf20Sopenharmony_ci else 28888c2ecf20Sopenharmony_ci serial8250_do_set_ldisc(port, termios); 28898c2ecf20Sopenharmony_ci} 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_civoid serial8250_do_pm(struct uart_port *port, unsigned int state, 28928c2ecf20Sopenharmony_ci unsigned int oldstate) 28938c2ecf20Sopenharmony_ci{ 28948c2ecf20Sopenharmony_ci struct uart_8250_port *p = up_to_u8250p(port); 28958c2ecf20Sopenharmony_ci 28968c2ecf20Sopenharmony_ci serial8250_set_sleep(p, state != 0); 28978c2ecf20Sopenharmony_ci} 28988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(serial8250_do_pm); 28998c2ecf20Sopenharmony_ci 29008c2ecf20Sopenharmony_cistatic void 29018c2ecf20Sopenharmony_ciserial8250_pm(struct uart_port *port, unsigned int state, 29028c2ecf20Sopenharmony_ci unsigned int oldstate) 29038c2ecf20Sopenharmony_ci{ 29048c2ecf20Sopenharmony_ci if (port->pm) 29058c2ecf20Sopenharmony_ci port->pm(port, state, oldstate); 29068c2ecf20Sopenharmony_ci else 29078c2ecf20Sopenharmony_ci serial8250_do_pm(port, state, oldstate); 29088c2ecf20Sopenharmony_ci} 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_cistatic unsigned int serial8250_port_size(struct uart_8250_port *pt) 29118c2ecf20Sopenharmony_ci{ 29128c2ecf20Sopenharmony_ci if (pt->port.mapsize) 29138c2ecf20Sopenharmony_ci return pt->port.mapsize; 29148c2ecf20Sopenharmony_ci if (pt->port.iotype == UPIO_AU) { 29158c2ecf20Sopenharmony_ci if (pt->port.type == PORT_RT2880) 29168c2ecf20Sopenharmony_ci return 0x100; 29178c2ecf20Sopenharmony_ci return 0x1000; 29188c2ecf20Sopenharmony_ci } 29198c2ecf20Sopenharmony_ci if (is_omap1_8250(pt)) 29208c2ecf20Sopenharmony_ci return 0x16 << pt->port.regshift; 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci return 8 << pt->port.regshift; 29238c2ecf20Sopenharmony_ci} 29248c2ecf20Sopenharmony_ci 29258c2ecf20Sopenharmony_ci/* 29268c2ecf20Sopenharmony_ci * Resource handling. 29278c2ecf20Sopenharmony_ci */ 29288c2ecf20Sopenharmony_cistatic int serial8250_request_std_resource(struct uart_8250_port *up) 29298c2ecf20Sopenharmony_ci{ 29308c2ecf20Sopenharmony_ci unsigned int size = serial8250_port_size(up); 29318c2ecf20Sopenharmony_ci struct uart_port *port = &up->port; 29328c2ecf20Sopenharmony_ci int ret = 0; 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_ci switch (port->iotype) { 29358c2ecf20Sopenharmony_ci case UPIO_AU: 29368c2ecf20Sopenharmony_ci case UPIO_TSI: 29378c2ecf20Sopenharmony_ci case UPIO_MEM32: 29388c2ecf20Sopenharmony_ci case UPIO_MEM32BE: 29398c2ecf20Sopenharmony_ci case UPIO_MEM16: 29408c2ecf20Sopenharmony_ci case UPIO_MEM: 29418c2ecf20Sopenharmony_ci if (!port->mapbase) { 29428c2ecf20Sopenharmony_ci ret = -EINVAL; 29438c2ecf20Sopenharmony_ci break; 29448c2ecf20Sopenharmony_ci } 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_ci if (!request_mem_region(port->mapbase, size, "serial")) { 29478c2ecf20Sopenharmony_ci ret = -EBUSY; 29488c2ecf20Sopenharmony_ci break; 29498c2ecf20Sopenharmony_ci } 29508c2ecf20Sopenharmony_ci 29518c2ecf20Sopenharmony_ci if (port->flags & UPF_IOREMAP) { 29528c2ecf20Sopenharmony_ci port->membase = ioremap(port->mapbase, size); 29538c2ecf20Sopenharmony_ci if (!port->membase) { 29548c2ecf20Sopenharmony_ci release_mem_region(port->mapbase, size); 29558c2ecf20Sopenharmony_ci ret = -ENOMEM; 29568c2ecf20Sopenharmony_ci } 29578c2ecf20Sopenharmony_ci } 29588c2ecf20Sopenharmony_ci break; 29598c2ecf20Sopenharmony_ci 29608c2ecf20Sopenharmony_ci case UPIO_HUB6: 29618c2ecf20Sopenharmony_ci case UPIO_PORT: 29628c2ecf20Sopenharmony_ci if (!request_region(port->iobase, size, "serial")) 29638c2ecf20Sopenharmony_ci ret = -EBUSY; 29648c2ecf20Sopenharmony_ci break; 29658c2ecf20Sopenharmony_ci } 29668c2ecf20Sopenharmony_ci return ret; 29678c2ecf20Sopenharmony_ci} 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_cistatic void serial8250_release_std_resource(struct uart_8250_port *up) 29708c2ecf20Sopenharmony_ci{ 29718c2ecf20Sopenharmony_ci unsigned int size = serial8250_port_size(up); 29728c2ecf20Sopenharmony_ci struct uart_port *port = &up->port; 29738c2ecf20Sopenharmony_ci 29748c2ecf20Sopenharmony_ci switch (port->iotype) { 29758c2ecf20Sopenharmony_ci case UPIO_AU: 29768c2ecf20Sopenharmony_ci case UPIO_TSI: 29778c2ecf20Sopenharmony_ci case UPIO_MEM32: 29788c2ecf20Sopenharmony_ci case UPIO_MEM32BE: 29798c2ecf20Sopenharmony_ci case UPIO_MEM16: 29808c2ecf20Sopenharmony_ci case UPIO_MEM: 29818c2ecf20Sopenharmony_ci if (!port->mapbase) 29828c2ecf20Sopenharmony_ci break; 29838c2ecf20Sopenharmony_ci 29848c2ecf20Sopenharmony_ci if (port->flags & UPF_IOREMAP) { 29858c2ecf20Sopenharmony_ci iounmap(port->membase); 29868c2ecf20Sopenharmony_ci port->membase = NULL; 29878c2ecf20Sopenharmony_ci } 29888c2ecf20Sopenharmony_ci 29898c2ecf20Sopenharmony_ci release_mem_region(port->mapbase, size); 29908c2ecf20Sopenharmony_ci break; 29918c2ecf20Sopenharmony_ci 29928c2ecf20Sopenharmony_ci case UPIO_HUB6: 29938c2ecf20Sopenharmony_ci case UPIO_PORT: 29948c2ecf20Sopenharmony_ci release_region(port->iobase, size); 29958c2ecf20Sopenharmony_ci break; 29968c2ecf20Sopenharmony_ci } 29978c2ecf20Sopenharmony_ci} 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_cistatic void serial8250_release_port(struct uart_port *port) 30008c2ecf20Sopenharmony_ci{ 30018c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 30028c2ecf20Sopenharmony_ci 30038c2ecf20Sopenharmony_ci serial8250_release_std_resource(up); 30048c2ecf20Sopenharmony_ci} 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_cistatic int serial8250_request_port(struct uart_port *port) 30078c2ecf20Sopenharmony_ci{ 30088c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_ci return serial8250_request_std_resource(up); 30118c2ecf20Sopenharmony_ci} 30128c2ecf20Sopenharmony_ci 30138c2ecf20Sopenharmony_cistatic int fcr_get_rxtrig_bytes(struct uart_8250_port *up) 30148c2ecf20Sopenharmony_ci{ 30158c2ecf20Sopenharmony_ci const struct serial8250_config *conf_type = &uart_config[up->port.type]; 30168c2ecf20Sopenharmony_ci unsigned char bytes; 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_ci bytes = conf_type->rxtrig_bytes[UART_FCR_R_TRIG_BITS(up->fcr)]; 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci return bytes ? bytes : -EOPNOTSUPP; 30218c2ecf20Sopenharmony_ci} 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_cistatic int bytes_to_fcr_rxtrig(struct uart_8250_port *up, unsigned char bytes) 30248c2ecf20Sopenharmony_ci{ 30258c2ecf20Sopenharmony_ci const struct serial8250_config *conf_type = &uart_config[up->port.type]; 30268c2ecf20Sopenharmony_ci int i; 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci if (!conf_type->rxtrig_bytes[UART_FCR_R_TRIG_BITS(UART_FCR_R_TRIG_00)]) 30298c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_ci for (i = 1; i < UART_FCR_R_TRIG_MAX_STATE; i++) { 30328c2ecf20Sopenharmony_ci if (bytes < conf_type->rxtrig_bytes[i]) 30338c2ecf20Sopenharmony_ci /* Use the nearest lower value */ 30348c2ecf20Sopenharmony_ci return (--i) << UART_FCR_R_TRIG_SHIFT; 30358c2ecf20Sopenharmony_ci } 30368c2ecf20Sopenharmony_ci 30378c2ecf20Sopenharmony_ci return UART_FCR_R_TRIG_11; 30388c2ecf20Sopenharmony_ci} 30398c2ecf20Sopenharmony_ci 30408c2ecf20Sopenharmony_cistatic int do_get_rxtrig(struct tty_port *port) 30418c2ecf20Sopenharmony_ci{ 30428c2ecf20Sopenharmony_ci struct uart_state *state = container_of(port, struct uart_state, port); 30438c2ecf20Sopenharmony_ci struct uart_port *uport = state->uart_port; 30448c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(uport); 30458c2ecf20Sopenharmony_ci 30468c2ecf20Sopenharmony_ci if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1) 30478c2ecf20Sopenharmony_ci return -EINVAL; 30488c2ecf20Sopenharmony_ci 30498c2ecf20Sopenharmony_ci return fcr_get_rxtrig_bytes(up); 30508c2ecf20Sopenharmony_ci} 30518c2ecf20Sopenharmony_ci 30528c2ecf20Sopenharmony_cistatic int do_serial8250_get_rxtrig(struct tty_port *port) 30538c2ecf20Sopenharmony_ci{ 30548c2ecf20Sopenharmony_ci int rxtrig_bytes; 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_ci mutex_lock(&port->mutex); 30578c2ecf20Sopenharmony_ci rxtrig_bytes = do_get_rxtrig(port); 30588c2ecf20Sopenharmony_ci mutex_unlock(&port->mutex); 30598c2ecf20Sopenharmony_ci 30608c2ecf20Sopenharmony_ci return rxtrig_bytes; 30618c2ecf20Sopenharmony_ci} 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_cistatic ssize_t rx_trig_bytes_show(struct device *dev, 30648c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 30658c2ecf20Sopenharmony_ci{ 30668c2ecf20Sopenharmony_ci struct tty_port *port = dev_get_drvdata(dev); 30678c2ecf20Sopenharmony_ci int rxtrig_bytes; 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci rxtrig_bytes = do_serial8250_get_rxtrig(port); 30708c2ecf20Sopenharmony_ci if (rxtrig_bytes < 0) 30718c2ecf20Sopenharmony_ci return rxtrig_bytes; 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", rxtrig_bytes); 30748c2ecf20Sopenharmony_ci} 30758c2ecf20Sopenharmony_ci 30768c2ecf20Sopenharmony_cistatic int do_set_rxtrig(struct tty_port *port, unsigned char bytes) 30778c2ecf20Sopenharmony_ci{ 30788c2ecf20Sopenharmony_ci struct uart_state *state = container_of(port, struct uart_state, port); 30798c2ecf20Sopenharmony_ci struct uart_port *uport = state->uart_port; 30808c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(uport); 30818c2ecf20Sopenharmony_ci int rxtrig; 30828c2ecf20Sopenharmony_ci 30838c2ecf20Sopenharmony_ci if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1) 30848c2ecf20Sopenharmony_ci return -EINVAL; 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_ci rxtrig = bytes_to_fcr_rxtrig(up, bytes); 30878c2ecf20Sopenharmony_ci if (rxtrig < 0) 30888c2ecf20Sopenharmony_ci return rxtrig; 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_ci serial8250_clear_fifos(up); 30918c2ecf20Sopenharmony_ci up->fcr &= ~UART_FCR_TRIGGER_MASK; 30928c2ecf20Sopenharmony_ci up->fcr |= (unsigned char)rxtrig; 30938c2ecf20Sopenharmony_ci serial_out(up, UART_FCR, up->fcr); 30948c2ecf20Sopenharmony_ci return 0; 30958c2ecf20Sopenharmony_ci} 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_cistatic int do_serial8250_set_rxtrig(struct tty_port *port, unsigned char bytes) 30988c2ecf20Sopenharmony_ci{ 30998c2ecf20Sopenharmony_ci int ret; 31008c2ecf20Sopenharmony_ci 31018c2ecf20Sopenharmony_ci mutex_lock(&port->mutex); 31028c2ecf20Sopenharmony_ci ret = do_set_rxtrig(port, bytes); 31038c2ecf20Sopenharmony_ci mutex_unlock(&port->mutex); 31048c2ecf20Sopenharmony_ci 31058c2ecf20Sopenharmony_ci return ret; 31068c2ecf20Sopenharmony_ci} 31078c2ecf20Sopenharmony_ci 31088c2ecf20Sopenharmony_cistatic ssize_t rx_trig_bytes_store(struct device *dev, 31098c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 31108c2ecf20Sopenharmony_ci{ 31118c2ecf20Sopenharmony_ci struct tty_port *port = dev_get_drvdata(dev); 31128c2ecf20Sopenharmony_ci unsigned char bytes; 31138c2ecf20Sopenharmony_ci int ret; 31148c2ecf20Sopenharmony_ci 31158c2ecf20Sopenharmony_ci if (!count) 31168c2ecf20Sopenharmony_ci return -EINVAL; 31178c2ecf20Sopenharmony_ci 31188c2ecf20Sopenharmony_ci ret = kstrtou8(buf, 10, &bytes); 31198c2ecf20Sopenharmony_ci if (ret < 0) 31208c2ecf20Sopenharmony_ci return ret; 31218c2ecf20Sopenharmony_ci 31228c2ecf20Sopenharmony_ci ret = do_serial8250_set_rxtrig(port, bytes); 31238c2ecf20Sopenharmony_ci if (ret < 0) 31248c2ecf20Sopenharmony_ci return ret; 31258c2ecf20Sopenharmony_ci 31268c2ecf20Sopenharmony_ci return count; 31278c2ecf20Sopenharmony_ci} 31288c2ecf20Sopenharmony_ci 31298c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(rx_trig_bytes); 31308c2ecf20Sopenharmony_ci 31318c2ecf20Sopenharmony_cistatic struct attribute *serial8250_dev_attrs[] = { 31328c2ecf20Sopenharmony_ci &dev_attr_rx_trig_bytes.attr, 31338c2ecf20Sopenharmony_ci NULL 31348c2ecf20Sopenharmony_ci}; 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_cistatic struct attribute_group serial8250_dev_attr_group = { 31378c2ecf20Sopenharmony_ci .attrs = serial8250_dev_attrs, 31388c2ecf20Sopenharmony_ci}; 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_cistatic void register_dev_spec_attr_grp(struct uart_8250_port *up) 31418c2ecf20Sopenharmony_ci{ 31428c2ecf20Sopenharmony_ci const struct serial8250_config *conf_type = &uart_config[up->port.type]; 31438c2ecf20Sopenharmony_ci 31448c2ecf20Sopenharmony_ci if (conf_type->rxtrig_bytes[0]) 31458c2ecf20Sopenharmony_ci up->port.attr_group = &serial8250_dev_attr_group; 31468c2ecf20Sopenharmony_ci} 31478c2ecf20Sopenharmony_ci 31488c2ecf20Sopenharmony_cistatic void serial8250_config_port(struct uart_port *port, int flags) 31498c2ecf20Sopenharmony_ci{ 31508c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 31518c2ecf20Sopenharmony_ci int ret; 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_ci /* 31548c2ecf20Sopenharmony_ci * Find the region that we can probe for. This in turn 31558c2ecf20Sopenharmony_ci * tells us whether we can probe for the type of port. 31568c2ecf20Sopenharmony_ci */ 31578c2ecf20Sopenharmony_ci ret = serial8250_request_std_resource(up); 31588c2ecf20Sopenharmony_ci if (ret < 0) 31598c2ecf20Sopenharmony_ci return; 31608c2ecf20Sopenharmony_ci 31618c2ecf20Sopenharmony_ci if (port->iotype != up->cur_iotype) 31628c2ecf20Sopenharmony_ci set_io_from_upio(port); 31638c2ecf20Sopenharmony_ci 31648c2ecf20Sopenharmony_ci if (flags & UART_CONFIG_TYPE) 31658c2ecf20Sopenharmony_ci autoconfig(up); 31668c2ecf20Sopenharmony_ci 31678c2ecf20Sopenharmony_ci /* if access method is AU, it is a 16550 with a quirk */ 31688c2ecf20Sopenharmony_ci if (port->type == PORT_16550A && port->iotype == UPIO_AU) 31698c2ecf20Sopenharmony_ci up->bugs |= UART_BUG_NOMSR; 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_ci /* HW bugs may trigger IRQ while IIR == NO_INT */ 31728c2ecf20Sopenharmony_ci if (port->type == PORT_TEGRA) 31738c2ecf20Sopenharmony_ci up->bugs |= UART_BUG_NOMSR; 31748c2ecf20Sopenharmony_ci 31758c2ecf20Sopenharmony_ci if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) 31768c2ecf20Sopenharmony_ci autoconfig_irq(up); 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_ci if (port->type == PORT_UNKNOWN) 31798c2ecf20Sopenharmony_ci serial8250_release_std_resource(up); 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_ci register_dev_spec_attr_grp(up); 31828c2ecf20Sopenharmony_ci up->fcr = uart_config[up->port.type].fcr; 31838c2ecf20Sopenharmony_ci} 31848c2ecf20Sopenharmony_ci 31858c2ecf20Sopenharmony_cistatic int 31868c2ecf20Sopenharmony_ciserial8250_verify_port(struct uart_port *port, struct serial_struct *ser) 31878c2ecf20Sopenharmony_ci{ 31888c2ecf20Sopenharmony_ci if (ser->irq >= nr_irqs || ser->irq < 0 || 31898c2ecf20Sopenharmony_ci ser->baud_base < 9600 || ser->type < PORT_UNKNOWN || 31908c2ecf20Sopenharmony_ci ser->type >= ARRAY_SIZE(uart_config) || ser->type == PORT_CIRRUS || 31918c2ecf20Sopenharmony_ci ser->type == PORT_STARTECH) 31928c2ecf20Sopenharmony_ci return -EINVAL; 31938c2ecf20Sopenharmony_ci return 0; 31948c2ecf20Sopenharmony_ci} 31958c2ecf20Sopenharmony_ci 31968c2ecf20Sopenharmony_cistatic const char *serial8250_type(struct uart_port *port) 31978c2ecf20Sopenharmony_ci{ 31988c2ecf20Sopenharmony_ci int type = port->type; 31998c2ecf20Sopenharmony_ci 32008c2ecf20Sopenharmony_ci if (type >= ARRAY_SIZE(uart_config)) 32018c2ecf20Sopenharmony_ci type = 0; 32028c2ecf20Sopenharmony_ci return uart_config[type].name; 32038c2ecf20Sopenharmony_ci} 32048c2ecf20Sopenharmony_ci 32058c2ecf20Sopenharmony_cistatic const struct uart_ops serial8250_pops = { 32068c2ecf20Sopenharmony_ci .tx_empty = serial8250_tx_empty, 32078c2ecf20Sopenharmony_ci .set_mctrl = serial8250_set_mctrl, 32088c2ecf20Sopenharmony_ci .get_mctrl = serial8250_get_mctrl, 32098c2ecf20Sopenharmony_ci .stop_tx = serial8250_stop_tx, 32108c2ecf20Sopenharmony_ci .start_tx = serial8250_start_tx, 32118c2ecf20Sopenharmony_ci .throttle = serial8250_throttle, 32128c2ecf20Sopenharmony_ci .unthrottle = serial8250_unthrottle, 32138c2ecf20Sopenharmony_ci .stop_rx = serial8250_stop_rx, 32148c2ecf20Sopenharmony_ci .enable_ms = serial8250_enable_ms, 32158c2ecf20Sopenharmony_ci .break_ctl = serial8250_break_ctl, 32168c2ecf20Sopenharmony_ci .startup = serial8250_startup, 32178c2ecf20Sopenharmony_ci .shutdown = serial8250_shutdown, 32188c2ecf20Sopenharmony_ci .set_termios = serial8250_set_termios, 32198c2ecf20Sopenharmony_ci .set_ldisc = serial8250_set_ldisc, 32208c2ecf20Sopenharmony_ci .pm = serial8250_pm, 32218c2ecf20Sopenharmony_ci .type = serial8250_type, 32228c2ecf20Sopenharmony_ci .release_port = serial8250_release_port, 32238c2ecf20Sopenharmony_ci .request_port = serial8250_request_port, 32248c2ecf20Sopenharmony_ci .config_port = serial8250_config_port, 32258c2ecf20Sopenharmony_ci .verify_port = serial8250_verify_port, 32268c2ecf20Sopenharmony_ci#ifdef CONFIG_CONSOLE_POLL 32278c2ecf20Sopenharmony_ci .poll_get_char = serial8250_get_poll_char, 32288c2ecf20Sopenharmony_ci .poll_put_char = serial8250_put_poll_char, 32298c2ecf20Sopenharmony_ci#endif 32308c2ecf20Sopenharmony_ci}; 32318c2ecf20Sopenharmony_ci 32328c2ecf20Sopenharmony_civoid serial8250_init_port(struct uart_8250_port *up) 32338c2ecf20Sopenharmony_ci{ 32348c2ecf20Sopenharmony_ci struct uart_port *port = &up->port; 32358c2ecf20Sopenharmony_ci 32368c2ecf20Sopenharmony_ci spin_lock_init(&port->lock); 32378c2ecf20Sopenharmony_ci port->pm = NULL; 32388c2ecf20Sopenharmony_ci port->ops = &serial8250_pops; 32398c2ecf20Sopenharmony_ci port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE); 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci up->cur_iotype = 0xFF; 32428c2ecf20Sopenharmony_ci} 32438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_init_port); 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_civoid serial8250_set_defaults(struct uart_8250_port *up) 32468c2ecf20Sopenharmony_ci{ 32478c2ecf20Sopenharmony_ci struct uart_port *port = &up->port; 32488c2ecf20Sopenharmony_ci 32498c2ecf20Sopenharmony_ci if (up->port.flags & UPF_FIXED_TYPE) { 32508c2ecf20Sopenharmony_ci unsigned int type = up->port.type; 32518c2ecf20Sopenharmony_ci 32528c2ecf20Sopenharmony_ci if (!up->port.fifosize) 32538c2ecf20Sopenharmony_ci up->port.fifosize = uart_config[type].fifo_size; 32548c2ecf20Sopenharmony_ci if (!up->tx_loadsz) 32558c2ecf20Sopenharmony_ci up->tx_loadsz = uart_config[type].tx_loadsz; 32568c2ecf20Sopenharmony_ci if (!up->capabilities) 32578c2ecf20Sopenharmony_ci up->capabilities = uart_config[type].flags; 32588c2ecf20Sopenharmony_ci } 32598c2ecf20Sopenharmony_ci 32608c2ecf20Sopenharmony_ci set_io_from_upio(port); 32618c2ecf20Sopenharmony_ci 32628c2ecf20Sopenharmony_ci /* default dma handlers */ 32638c2ecf20Sopenharmony_ci if (up->dma) { 32648c2ecf20Sopenharmony_ci if (!up->dma->tx_dma) 32658c2ecf20Sopenharmony_ci up->dma->tx_dma = serial8250_tx_dma; 32668c2ecf20Sopenharmony_ci if (!up->dma->rx_dma) 32678c2ecf20Sopenharmony_ci up->dma->rx_dma = serial8250_rx_dma; 32688c2ecf20Sopenharmony_ci } 32698c2ecf20Sopenharmony_ci} 32708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(serial8250_set_defaults); 32718c2ecf20Sopenharmony_ci 32728c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_CONSOLE 32738c2ecf20Sopenharmony_ci 32748c2ecf20Sopenharmony_cistatic void serial8250_console_putchar(struct uart_port *port, int ch) 32758c2ecf20Sopenharmony_ci{ 32768c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 32778c2ecf20Sopenharmony_ci 32788c2ecf20Sopenharmony_ci wait_for_xmitr(up, UART_LSR_THRE); 32798c2ecf20Sopenharmony_ci serial_port_out(port, UART_TX, ch); 32808c2ecf20Sopenharmony_ci} 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_ci/* 32838c2ecf20Sopenharmony_ci * Restore serial console when h/w power-off detected 32848c2ecf20Sopenharmony_ci */ 32858c2ecf20Sopenharmony_cistatic void serial8250_console_restore(struct uart_8250_port *up) 32868c2ecf20Sopenharmony_ci{ 32878c2ecf20Sopenharmony_ci struct uart_port *port = &up->port; 32888c2ecf20Sopenharmony_ci struct ktermios termios; 32898c2ecf20Sopenharmony_ci unsigned int baud, quot, frac = 0; 32908c2ecf20Sopenharmony_ci 32918c2ecf20Sopenharmony_ci termios.c_cflag = port->cons->cflag; 32928c2ecf20Sopenharmony_ci termios.c_ispeed = port->cons->ispeed; 32938c2ecf20Sopenharmony_ci termios.c_ospeed = port->cons->ospeed; 32948c2ecf20Sopenharmony_ci if (port->state->port.tty && termios.c_cflag == 0) { 32958c2ecf20Sopenharmony_ci termios.c_cflag = port->state->port.tty->termios.c_cflag; 32968c2ecf20Sopenharmony_ci termios.c_ispeed = port->state->port.tty->termios.c_ispeed; 32978c2ecf20Sopenharmony_ci termios.c_ospeed = port->state->port.tty->termios.c_ospeed; 32988c2ecf20Sopenharmony_ci } 32998c2ecf20Sopenharmony_ci 33008c2ecf20Sopenharmony_ci baud = serial8250_get_baud_rate(port, &termios, NULL); 33018c2ecf20Sopenharmony_ci quot = serial8250_get_divisor(port, baud, &frac); 33028c2ecf20Sopenharmony_ci 33038c2ecf20Sopenharmony_ci serial8250_set_divisor(port, baud, quot, frac); 33048c2ecf20Sopenharmony_ci serial_port_out(port, UART_LCR, up->lcr); 33058c2ecf20Sopenharmony_ci serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS); 33068c2ecf20Sopenharmony_ci} 33078c2ecf20Sopenharmony_ci 33088c2ecf20Sopenharmony_ci/* 33098c2ecf20Sopenharmony_ci * Print a string to the serial port trying not to disturb 33108c2ecf20Sopenharmony_ci * any possible real use of the port... 33118c2ecf20Sopenharmony_ci * 33128c2ecf20Sopenharmony_ci * The console_lock must be held when we get here. 33138c2ecf20Sopenharmony_ci * 33148c2ecf20Sopenharmony_ci * Doing runtime PM is really a bad idea for the kernel console. 33158c2ecf20Sopenharmony_ci * Thus, we assume the function is called when device is powered up. 33168c2ecf20Sopenharmony_ci */ 33178c2ecf20Sopenharmony_civoid serial8250_console_write(struct uart_8250_port *up, const char *s, 33188c2ecf20Sopenharmony_ci unsigned int count) 33198c2ecf20Sopenharmony_ci{ 33208c2ecf20Sopenharmony_ci struct uart_8250_em485 *em485 = up->em485; 33218c2ecf20Sopenharmony_ci struct uart_port *port = &up->port; 33228c2ecf20Sopenharmony_ci unsigned long flags; 33238c2ecf20Sopenharmony_ci unsigned int ier; 33248c2ecf20Sopenharmony_ci int locked = 1; 33258c2ecf20Sopenharmony_ci 33268c2ecf20Sopenharmony_ci touch_nmi_watchdog(); 33278c2ecf20Sopenharmony_ci 33288c2ecf20Sopenharmony_ci if (oops_in_progress) 33298c2ecf20Sopenharmony_ci locked = spin_trylock_irqsave(&port->lock, flags); 33308c2ecf20Sopenharmony_ci else 33318c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 33328c2ecf20Sopenharmony_ci 33338c2ecf20Sopenharmony_ci /* 33348c2ecf20Sopenharmony_ci * First save the IER then disable the interrupts 33358c2ecf20Sopenharmony_ci */ 33368c2ecf20Sopenharmony_ci ier = serial_port_in(port, UART_IER); 33378c2ecf20Sopenharmony_ci 33388c2ecf20Sopenharmony_ci if (up->capabilities & UART_CAP_UUE) 33398c2ecf20Sopenharmony_ci serial_port_out(port, UART_IER, UART_IER_UUE); 33408c2ecf20Sopenharmony_ci else 33418c2ecf20Sopenharmony_ci serial_port_out(port, UART_IER, 0); 33428c2ecf20Sopenharmony_ci 33438c2ecf20Sopenharmony_ci /* check scratch reg to see if port powered off during system sleep */ 33448c2ecf20Sopenharmony_ci if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) { 33458c2ecf20Sopenharmony_ci serial8250_console_restore(up); 33468c2ecf20Sopenharmony_ci up->canary = 0; 33478c2ecf20Sopenharmony_ci } 33488c2ecf20Sopenharmony_ci 33498c2ecf20Sopenharmony_ci if (em485) { 33508c2ecf20Sopenharmony_ci if (em485->tx_stopped) 33518c2ecf20Sopenharmony_ci up->rs485_start_tx(up); 33528c2ecf20Sopenharmony_ci mdelay(port->rs485.delay_rts_before_send); 33538c2ecf20Sopenharmony_ci } 33548c2ecf20Sopenharmony_ci 33558c2ecf20Sopenharmony_ci uart_console_write(port, s, count, serial8250_console_putchar); 33568c2ecf20Sopenharmony_ci 33578c2ecf20Sopenharmony_ci /* 33588c2ecf20Sopenharmony_ci * Finally, wait for transmitter to become empty 33598c2ecf20Sopenharmony_ci * and restore the IER 33608c2ecf20Sopenharmony_ci */ 33618c2ecf20Sopenharmony_ci wait_for_xmitr(up, BOTH_EMPTY); 33628c2ecf20Sopenharmony_ci 33638c2ecf20Sopenharmony_ci if (em485) { 33648c2ecf20Sopenharmony_ci mdelay(port->rs485.delay_rts_after_send); 33658c2ecf20Sopenharmony_ci if (em485->tx_stopped) 33668c2ecf20Sopenharmony_ci up->rs485_stop_tx(up); 33678c2ecf20Sopenharmony_ci } 33688c2ecf20Sopenharmony_ci 33698c2ecf20Sopenharmony_ci serial_port_out(port, UART_IER, ier); 33708c2ecf20Sopenharmony_ci 33718c2ecf20Sopenharmony_ci /* 33728c2ecf20Sopenharmony_ci * The receive handling will happen properly because the 33738c2ecf20Sopenharmony_ci * receive ready bit will still be set; it is not cleared 33748c2ecf20Sopenharmony_ci * on read. However, modem control will not, we must 33758c2ecf20Sopenharmony_ci * call it if we have saved something in the saved flags 33768c2ecf20Sopenharmony_ci * while processing with interrupts off. 33778c2ecf20Sopenharmony_ci */ 33788c2ecf20Sopenharmony_ci if (up->msr_saved_flags) 33798c2ecf20Sopenharmony_ci serial8250_modem_status(up); 33808c2ecf20Sopenharmony_ci 33818c2ecf20Sopenharmony_ci if (locked) 33828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 33838c2ecf20Sopenharmony_ci} 33848c2ecf20Sopenharmony_ci 33858c2ecf20Sopenharmony_cistatic unsigned int probe_baud(struct uart_port *port) 33868c2ecf20Sopenharmony_ci{ 33878c2ecf20Sopenharmony_ci unsigned char lcr, dll, dlm; 33888c2ecf20Sopenharmony_ci unsigned int quot; 33898c2ecf20Sopenharmony_ci 33908c2ecf20Sopenharmony_ci lcr = serial_port_in(port, UART_LCR); 33918c2ecf20Sopenharmony_ci serial_port_out(port, UART_LCR, lcr | UART_LCR_DLAB); 33928c2ecf20Sopenharmony_ci dll = serial_port_in(port, UART_DLL); 33938c2ecf20Sopenharmony_ci dlm = serial_port_in(port, UART_DLM); 33948c2ecf20Sopenharmony_ci serial_port_out(port, UART_LCR, lcr); 33958c2ecf20Sopenharmony_ci 33968c2ecf20Sopenharmony_ci quot = (dlm << 8) | dll; 33978c2ecf20Sopenharmony_ci return (port->uartclk / 16) / quot; 33988c2ecf20Sopenharmony_ci} 33998c2ecf20Sopenharmony_ci 34008c2ecf20Sopenharmony_ciint serial8250_console_setup(struct uart_port *port, char *options, bool probe) 34018c2ecf20Sopenharmony_ci{ 34028c2ecf20Sopenharmony_ci int baud = 9600; 34038c2ecf20Sopenharmony_ci int bits = 8; 34048c2ecf20Sopenharmony_ci int parity = 'n'; 34058c2ecf20Sopenharmony_ci int flow = 'n'; 34068c2ecf20Sopenharmony_ci int ret; 34078c2ecf20Sopenharmony_ci 34088c2ecf20Sopenharmony_ci if (!port->iobase && !port->membase) 34098c2ecf20Sopenharmony_ci return -ENODEV; 34108c2ecf20Sopenharmony_ci 34118c2ecf20Sopenharmony_ci if (options) 34128c2ecf20Sopenharmony_ci uart_parse_options(options, &baud, &parity, &bits, &flow); 34138c2ecf20Sopenharmony_ci else if (probe) 34148c2ecf20Sopenharmony_ci baud = probe_baud(port); 34158c2ecf20Sopenharmony_ci 34168c2ecf20Sopenharmony_ci ret = uart_set_options(port, port->cons, baud, parity, bits, flow); 34178c2ecf20Sopenharmony_ci if (ret) 34188c2ecf20Sopenharmony_ci return ret; 34198c2ecf20Sopenharmony_ci 34208c2ecf20Sopenharmony_ci if (port->dev) 34218c2ecf20Sopenharmony_ci pm_runtime_get_sync(port->dev); 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_ci return 0; 34248c2ecf20Sopenharmony_ci} 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_ciint serial8250_console_exit(struct uart_port *port) 34278c2ecf20Sopenharmony_ci{ 34288c2ecf20Sopenharmony_ci if (port->dev) 34298c2ecf20Sopenharmony_ci pm_runtime_put_sync(port->dev); 34308c2ecf20Sopenharmony_ci 34318c2ecf20Sopenharmony_ci return 0; 34328c2ecf20Sopenharmony_ci} 34338c2ecf20Sopenharmony_ci 34348c2ecf20Sopenharmony_ci#endif /* CONFIG_SERIAL_8250_CONSOLE */ 34358c2ecf20Sopenharmony_ci 34368c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3437