162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* Synopsys DesignWare 8250 library. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/bitops.h> 562306a36Sopenharmony_ci#include <linux/bitfield.h> 662306a36Sopenharmony_ci#include <linux/delay.h> 762306a36Sopenharmony_ci#include <linux/device.h> 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/math.h> 1062306a36Sopenharmony_ci#include <linux/property.h> 1162306a36Sopenharmony_ci#include <linux/serial_8250.h> 1262306a36Sopenharmony_ci#include <linux/serial_core.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "8250_dwlib.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* Offsets for the DesignWare specific registers */ 1762306a36Sopenharmony_ci#define DW_UART_TCR 0xac /* Transceiver Control Register (RS485) */ 1862306a36Sopenharmony_ci#define DW_UART_DE_EN 0xb0 /* Driver Output Enable Register */ 1962306a36Sopenharmony_ci#define DW_UART_RE_EN 0xb4 /* Receiver Output Enable Register */ 2062306a36Sopenharmony_ci#define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */ 2162306a36Sopenharmony_ci#define DW_UART_RAR 0xc4 /* Receive Address Register */ 2262306a36Sopenharmony_ci#define DW_UART_TAR 0xc8 /* Transmit Address Register */ 2362306a36Sopenharmony_ci#define DW_UART_LCR_EXT 0xcc /* Line Extended Control Register */ 2462306a36Sopenharmony_ci#define DW_UART_CPR 0xf4 /* Component Parameter Register */ 2562306a36Sopenharmony_ci#define DW_UART_UCV 0xf8 /* UART Component Version */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* Receive / Transmit Address Register bits */ 2862306a36Sopenharmony_ci#define DW_UART_ADDR_MASK GENMASK(7, 0) 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* Line Status Register bits */ 3162306a36Sopenharmony_ci#define DW_UART_LSR_ADDR_RCVD BIT(8) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* Transceiver Control Register bits */ 3462306a36Sopenharmony_ci#define DW_UART_TCR_RS485_EN BIT(0) 3562306a36Sopenharmony_ci#define DW_UART_TCR_RE_POL BIT(1) 3662306a36Sopenharmony_ci#define DW_UART_TCR_DE_POL BIT(2) 3762306a36Sopenharmony_ci#define DW_UART_TCR_XFER_MODE GENMASK(4, 3) 3862306a36Sopenharmony_ci#define DW_UART_TCR_XFER_MODE_DE_DURING_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 0) 3962306a36Sopenharmony_ci#define DW_UART_TCR_XFER_MODE_SW_DE_OR_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 1) 4062306a36Sopenharmony_ci#define DW_UART_TCR_XFER_MODE_DE_OR_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 2) 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* Line Extended Control Register bits */ 4362306a36Sopenharmony_ci#define DW_UART_LCR_EXT_DLS_E BIT(0) 4462306a36Sopenharmony_ci#define DW_UART_LCR_EXT_ADDR_MATCH BIT(1) 4562306a36Sopenharmony_ci#define DW_UART_LCR_EXT_SEND_ADDR BIT(2) 4662306a36Sopenharmony_ci#define DW_UART_LCR_EXT_TRANSMIT_MODE BIT(3) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* Component Parameter Register bits */ 4962306a36Sopenharmony_ci#define DW_UART_CPR_ABP_DATA_WIDTH GENMASK(1, 0) 5062306a36Sopenharmony_ci#define DW_UART_CPR_AFCE_MODE BIT(4) 5162306a36Sopenharmony_ci#define DW_UART_CPR_THRE_MODE BIT(5) 5262306a36Sopenharmony_ci#define DW_UART_CPR_SIR_MODE BIT(6) 5362306a36Sopenharmony_ci#define DW_UART_CPR_SIR_LP_MODE BIT(7) 5462306a36Sopenharmony_ci#define DW_UART_CPR_ADDITIONAL_FEATURES BIT(8) 5562306a36Sopenharmony_ci#define DW_UART_CPR_FIFO_ACCESS BIT(9) 5662306a36Sopenharmony_ci#define DW_UART_CPR_FIFO_STAT BIT(10) 5762306a36Sopenharmony_ci#define DW_UART_CPR_SHADOW BIT(11) 5862306a36Sopenharmony_ci#define DW_UART_CPR_ENCODED_PARMS BIT(12) 5962306a36Sopenharmony_ci#define DW_UART_CPR_DMA_EXTRA BIT(13) 6062306a36Sopenharmony_ci#define DW_UART_CPR_FIFO_MODE GENMASK(23, 16) 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* Helper for FIFO size calculation */ 6362306a36Sopenharmony_ci#define DW_UART_CPR_FIFO_SIZE(a) (FIELD_GET(DW_UART_CPR_FIFO_MODE, (a)) * 16) 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* 6662306a36Sopenharmony_ci * divisor = div(I) + div(F) 6762306a36Sopenharmony_ci * "I" means integer, "F" means fractional 6862306a36Sopenharmony_ci * quot = div(I) = clk / (16 * baud) 6962306a36Sopenharmony_ci * frac = div(F) * 2^dlf_size 7062306a36Sopenharmony_ci * 7162306a36Sopenharmony_ci * let rem = clk % (16 * baud) 7262306a36Sopenharmony_ci * we have: div(F) * (16 * baud) = rem 7362306a36Sopenharmony_ci * so frac = 2^dlf_size * rem / (16 * baud) = (rem << dlf_size) / (16 * baud) 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_cistatic unsigned int dw8250_get_divisor(struct uart_port *p, unsigned int baud, 7662306a36Sopenharmony_ci unsigned int *frac) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci unsigned int quot, rem, base_baud = baud * 16; 7962306a36Sopenharmony_ci struct dw8250_port_data *d = p->private_data; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci quot = p->uartclk / base_baud; 8262306a36Sopenharmony_ci rem = p->uartclk % base_baud; 8362306a36Sopenharmony_ci *frac = DIV_ROUND_CLOSEST(rem << d->dlf_size, base_baud); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return quot; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic void dw8250_set_divisor(struct uart_port *p, unsigned int baud, 8962306a36Sopenharmony_ci unsigned int quot, unsigned int quot_frac) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci dw8250_writel_ext(p, DW_UART_DLF, quot_frac); 9262306a36Sopenharmony_ci serial8250_do_set_divisor(p, baud, quot, quot_frac); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_civoid dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, 9662306a36Sopenharmony_ci const struct ktermios *old) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci p->status &= ~UPSTAT_AUTOCTS; 9962306a36Sopenharmony_ci if (termios->c_cflag & CRTSCTS) 10062306a36Sopenharmony_ci p->status |= UPSTAT_AUTOCTS; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci serial8250_do_set_termios(p, termios, old); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci /* Filter addresses which have 9th bit set */ 10562306a36Sopenharmony_ci p->ignore_status_mask |= DW_UART_LSR_ADDR_RCVD; 10662306a36Sopenharmony_ci p->read_status_mask |= DW_UART_LSR_ADDR_RCVD; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw8250_do_set_termios); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci/* 11162306a36Sopenharmony_ci * Wait until re is de-asserted for sure. An ongoing receive will keep 11262306a36Sopenharmony_ci * re asserted until end of frame. Without BUSY indication available, 11362306a36Sopenharmony_ci * only available course of action is to wait for the time it takes to 11462306a36Sopenharmony_ci * receive one frame (there might nothing to receive but w/o BUSY the 11562306a36Sopenharmony_ci * driver cannot know). 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_cistatic void dw8250_wait_re_deassert(struct uart_port *p) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci ndelay(p->frame_time); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic void dw8250_update_rar(struct uart_port *p, u32 addr) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci u32 re_en = dw8250_readl_ext(p, DW_UART_RE_EN); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* 12762306a36Sopenharmony_ci * RAR shouldn't be changed while receiving. Thus, de-assert RE_EN 12862306a36Sopenharmony_ci * if asserted and wait. 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci if (re_en) 13162306a36Sopenharmony_ci dw8250_writel_ext(p, DW_UART_RE_EN, 0); 13262306a36Sopenharmony_ci dw8250_wait_re_deassert(p); 13362306a36Sopenharmony_ci dw8250_writel_ext(p, DW_UART_RAR, addr); 13462306a36Sopenharmony_ci if (re_en) 13562306a36Sopenharmony_ci dw8250_writel_ext(p, DW_UART_RE_EN, re_en); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic void dw8250_rs485_set_addr(struct uart_port *p, struct serial_rs485 *rs485, 13962306a36Sopenharmony_ci struct ktermios *termios) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci u32 lcr = dw8250_readl_ext(p, DW_UART_LCR_EXT); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (rs485->flags & SER_RS485_ADDRB) { 14462306a36Sopenharmony_ci lcr |= DW_UART_LCR_EXT_DLS_E; 14562306a36Sopenharmony_ci if (termios) 14662306a36Sopenharmony_ci termios->c_cflag |= ADDRB; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (rs485->flags & SER_RS485_ADDR_RECV) { 14962306a36Sopenharmony_ci u32 delta = p->rs485.flags ^ rs485->flags; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* 15262306a36Sopenharmony_ci * rs485 (param) is equal to uart_port's rs485 only during init 15362306a36Sopenharmony_ci * (during init, delta is not yet applicable). 15462306a36Sopenharmony_ci */ 15562306a36Sopenharmony_ci if (unlikely(&p->rs485 == rs485)) 15662306a36Sopenharmony_ci delta = rs485->flags; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if ((delta & SER_RS485_ADDR_RECV) || 15962306a36Sopenharmony_ci (p->rs485.addr_recv != rs485->addr_recv)) 16062306a36Sopenharmony_ci dw8250_update_rar(p, rs485->addr_recv); 16162306a36Sopenharmony_ci lcr |= DW_UART_LCR_EXT_ADDR_MATCH; 16262306a36Sopenharmony_ci } else { 16362306a36Sopenharmony_ci lcr &= ~DW_UART_LCR_EXT_ADDR_MATCH; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci if (rs485->flags & SER_RS485_ADDR_DEST) { 16662306a36Sopenharmony_ci /* 16762306a36Sopenharmony_ci * Don't skip writes here as another endpoint could 16862306a36Sopenharmony_ci * have changed communication line's destination 16962306a36Sopenharmony_ci * address in between. 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ci dw8250_writel_ext(p, DW_UART_TAR, rs485->addr_dest); 17262306a36Sopenharmony_ci lcr |= DW_UART_LCR_EXT_SEND_ADDR; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci } else { 17562306a36Sopenharmony_ci lcr = 0; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci dw8250_writel_ext(p, DW_UART_LCR_EXT, lcr); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic int dw8250_rs485_config(struct uart_port *p, struct ktermios *termios, 18162306a36Sopenharmony_ci struct serial_rs485 *rs485) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci u32 tcr; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci tcr = dw8250_readl_ext(p, DW_UART_TCR); 18662306a36Sopenharmony_ci tcr &= ~DW_UART_TCR_XFER_MODE; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (rs485->flags & SER_RS485_ENABLED) { 18962306a36Sopenharmony_ci tcr |= DW_UART_TCR_RS485_EN; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (rs485->flags & SER_RS485_RX_DURING_TX) 19262306a36Sopenharmony_ci tcr |= DW_UART_TCR_XFER_MODE_DE_DURING_RE; 19362306a36Sopenharmony_ci else 19462306a36Sopenharmony_ci tcr |= DW_UART_TCR_XFER_MODE_DE_OR_RE; 19562306a36Sopenharmony_ci dw8250_writel_ext(p, DW_UART_DE_EN, 1); 19662306a36Sopenharmony_ci dw8250_writel_ext(p, DW_UART_RE_EN, 1); 19762306a36Sopenharmony_ci } else { 19862306a36Sopenharmony_ci if (termios) 19962306a36Sopenharmony_ci termios->c_cflag &= ~ADDRB; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci tcr &= ~DW_UART_TCR_RS485_EN; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* Reset to default polarity */ 20562306a36Sopenharmony_ci tcr |= DW_UART_TCR_DE_POL; 20662306a36Sopenharmony_ci tcr &= ~DW_UART_TCR_RE_POL; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (!(rs485->flags & SER_RS485_RTS_ON_SEND)) 20962306a36Sopenharmony_ci tcr &= ~DW_UART_TCR_DE_POL; 21062306a36Sopenharmony_ci if (device_property_read_bool(p->dev, "rs485-rx-active-high")) 21162306a36Sopenharmony_ci tcr |= DW_UART_TCR_RE_POL; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci dw8250_writel_ext(p, DW_UART_TCR, tcr); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* Addressing mode can only be set up after TCR */ 21662306a36Sopenharmony_ci if (rs485->flags & SER_RS485_ENABLED) 21762306a36Sopenharmony_ci dw8250_rs485_set_addr(p, rs485, termios); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci return 0; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci/* 22362306a36Sopenharmony_ci * Tests if RE_EN register can have non-zero value to see if RS-485 HW support 22462306a36Sopenharmony_ci * is present. 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_cistatic bool dw8250_detect_rs485_hw(struct uart_port *p) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci u32 reg; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci dw8250_writel_ext(p, DW_UART_RE_EN, 1); 23162306a36Sopenharmony_ci reg = dw8250_readl_ext(p, DW_UART_RE_EN); 23262306a36Sopenharmony_ci dw8250_writel_ext(p, DW_UART_RE_EN, 0); 23362306a36Sopenharmony_ci return reg; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic const struct serial_rs485 dw8250_rs485_supported = { 23762306a36Sopenharmony_ci .flags = SER_RS485_ENABLED | SER_RS485_RX_DURING_TX | SER_RS485_RTS_ON_SEND | 23862306a36Sopenharmony_ci SER_RS485_RTS_AFTER_SEND | SER_RS485_ADDRB | SER_RS485_ADDR_RECV | 23962306a36Sopenharmony_ci SER_RS485_ADDR_DEST, 24062306a36Sopenharmony_ci}; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_civoid dw8250_setup_port(struct uart_port *p) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci struct dw8250_port_data *pd = p->private_data; 24562306a36Sopenharmony_ci struct dw8250_data *data = to_dw8250_data(pd); 24662306a36Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(p); 24762306a36Sopenharmony_ci u32 reg, old_dlf; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci pd->hw_rs485_support = dw8250_detect_rs485_hw(p); 25062306a36Sopenharmony_ci if (pd->hw_rs485_support) { 25162306a36Sopenharmony_ci p->rs485_config = dw8250_rs485_config; 25262306a36Sopenharmony_ci up->lsr_save_mask = LSR_SAVE_FLAGS | DW_UART_LSR_ADDR_RCVD; 25362306a36Sopenharmony_ci p->rs485_supported = dw8250_rs485_supported; 25462306a36Sopenharmony_ci } else { 25562306a36Sopenharmony_ci p->rs485_config = serial8250_em485_config; 25662306a36Sopenharmony_ci p->rs485_supported = serial8250_em485_supported; 25762306a36Sopenharmony_ci up->rs485_start_tx = serial8250_em485_start_tx; 25862306a36Sopenharmony_ci up->rs485_stop_tx = serial8250_em485_stop_tx; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci up->capabilities |= UART_CAP_NOTEMT; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci /* 26362306a36Sopenharmony_ci * If the Component Version Register returns zero, we know that 26462306a36Sopenharmony_ci * ADDITIONAL_FEATURES are not enabled. No need to go any further. 26562306a36Sopenharmony_ci */ 26662306a36Sopenharmony_ci reg = dw8250_readl_ext(p, DW_UART_UCV); 26762306a36Sopenharmony_ci if (!reg) 26862306a36Sopenharmony_ci return; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci dev_dbg(p->dev, "Designware UART version %c.%c%c\n", 27162306a36Sopenharmony_ci (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* Preserve value written by firmware or bootloader */ 27462306a36Sopenharmony_ci old_dlf = dw8250_readl_ext(p, DW_UART_DLF); 27562306a36Sopenharmony_ci dw8250_writel_ext(p, DW_UART_DLF, ~0U); 27662306a36Sopenharmony_ci reg = dw8250_readl_ext(p, DW_UART_DLF); 27762306a36Sopenharmony_ci dw8250_writel_ext(p, DW_UART_DLF, old_dlf); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (reg) { 28062306a36Sopenharmony_ci pd->dlf_size = fls(reg); 28162306a36Sopenharmony_ci p->get_divisor = dw8250_get_divisor; 28262306a36Sopenharmony_ci p->set_divisor = dw8250_set_divisor; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci reg = dw8250_readl_ext(p, DW_UART_CPR); 28662306a36Sopenharmony_ci if (!reg) { 28762306a36Sopenharmony_ci reg = data->pdata->cpr_val; 28862306a36Sopenharmony_ci dev_dbg(p->dev, "CPR is not available, using 0x%08x instead\n", reg); 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci if (!reg) 29162306a36Sopenharmony_ci return; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* Select the type based on FIFO */ 29462306a36Sopenharmony_ci if (reg & DW_UART_CPR_FIFO_MODE) { 29562306a36Sopenharmony_ci p->type = PORT_16550A; 29662306a36Sopenharmony_ci p->flags |= UPF_FIXED_TYPE; 29762306a36Sopenharmony_ci p->fifosize = DW_UART_CPR_FIFO_SIZE(reg); 29862306a36Sopenharmony_ci up->capabilities = UART_CAP_FIFO | UART_CAP_NOTEMT; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (reg & DW_UART_CPR_AFCE_MODE) 30262306a36Sopenharmony_ci up->capabilities |= UART_CAP_AFE; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (reg & DW_UART_CPR_SIR_MODE) 30562306a36Sopenharmony_ci up->capabilities |= UART_CAP_IRDA; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw8250_setup_port); 308