brintos

brintos / linux-shallow public Read only

0
0
Text · 8.8 KiB · b055d89 Raw
301 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/* Synopsys DesignWare 8250 library. */3 4#include <linux/bitops.h>5#include <linux/bitfield.h>6#include <linux/delay.h>7#include <linux/device.h>8#include <linux/kernel.h>9#include <linux/math.h>10#include <linux/property.h>11#include <linux/serial_8250.h>12#include <linux/serial_core.h>13 14#include "8250_dwlib.h"15 16/* Offsets for the DesignWare specific registers */17#define DW_UART_TCR	0xac /* Transceiver Control Register (RS485) */18#define DW_UART_DE_EN	0xb0 /* Driver Output Enable Register */19#define DW_UART_RE_EN	0xb4 /* Receiver Output Enable Register */20#define DW_UART_DLF	0xc0 /* Divisor Latch Fraction Register */21#define DW_UART_RAR	0xc4 /* Receive Address Register */22#define DW_UART_TAR	0xc8 /* Transmit Address Register */23#define DW_UART_LCR_EXT	0xcc /* Line Extended Control Register */24#define DW_UART_CPR	0xf4 /* Component Parameter Register */25#define DW_UART_UCV	0xf8 /* UART Component Version */26 27/* Receive / Transmit Address Register bits */28#define DW_UART_ADDR_MASK		GENMASK(7, 0)29 30/* Line Status Register bits */31#define DW_UART_LSR_ADDR_RCVD		BIT(8)32 33/* Transceiver Control Register bits */34#define DW_UART_TCR_RS485_EN		BIT(0)35#define DW_UART_TCR_RE_POL		BIT(1)36#define DW_UART_TCR_DE_POL		BIT(2)37#define DW_UART_TCR_XFER_MODE		GENMASK(4, 3)38#define DW_UART_TCR_XFER_MODE_DE_DURING_RE	FIELD_PREP(DW_UART_TCR_XFER_MODE, 0)39#define DW_UART_TCR_XFER_MODE_SW_DE_OR_RE	FIELD_PREP(DW_UART_TCR_XFER_MODE, 1)40#define DW_UART_TCR_XFER_MODE_DE_OR_RE		FIELD_PREP(DW_UART_TCR_XFER_MODE, 2)41 42/* Line Extended Control Register bits */43#define DW_UART_LCR_EXT_DLS_E		BIT(0)44#define DW_UART_LCR_EXT_ADDR_MATCH	BIT(1)45#define DW_UART_LCR_EXT_SEND_ADDR	BIT(2)46#define DW_UART_LCR_EXT_TRANSMIT_MODE	BIT(3)47 48/* Component Parameter Register bits */49#define DW_UART_CPR_ABP_DATA_WIDTH	GENMASK(1, 0)50#define DW_UART_CPR_AFCE_MODE		BIT(4)51#define DW_UART_CPR_THRE_MODE		BIT(5)52#define DW_UART_CPR_SIR_MODE		BIT(6)53#define DW_UART_CPR_SIR_LP_MODE		BIT(7)54#define DW_UART_CPR_ADDITIONAL_FEATURES	BIT(8)55#define DW_UART_CPR_FIFO_ACCESS		BIT(9)56#define DW_UART_CPR_FIFO_STAT		BIT(10)57#define DW_UART_CPR_SHADOW		BIT(11)58#define DW_UART_CPR_ENCODED_PARMS	BIT(12)59#define DW_UART_CPR_DMA_EXTRA		BIT(13)60#define DW_UART_CPR_FIFO_MODE		GENMASK(23, 16)61 62/* Helper for FIFO size calculation */63#define DW_UART_CPR_FIFO_SIZE(a)	(FIELD_GET(DW_UART_CPR_FIFO_MODE, (a)) * 16)64 65/*66 * divisor = div(I) + div(F)67 * "I" means integer, "F" means fractional68 * quot = div(I) = clk / (16 * baud)69 * frac = div(F) * 2^dlf_size70 *71 * let rem = clk % (16 * baud)72 * we have: div(F) * (16 * baud) = rem73 * so frac = 2^dlf_size * rem / (16 * baud) = (rem << dlf_size) / (16 * baud)74 */75static unsigned int dw8250_get_divisor(struct uart_port *p, unsigned int baud,76				       unsigned int *frac)77{78	unsigned int quot, rem, base_baud = baud * 16;79	struct dw8250_port_data *d = p->private_data;80 81	quot = p->uartclk / base_baud;82	rem = p->uartclk % base_baud;83	*frac = DIV_ROUND_CLOSEST(rem << d->dlf_size, base_baud);84 85	return quot;86}87 88static void dw8250_set_divisor(struct uart_port *p, unsigned int baud,89			       unsigned int quot, unsigned int quot_frac)90{91	dw8250_writel_ext(p, DW_UART_DLF, quot_frac);92	serial8250_do_set_divisor(p, baud, quot);93}94 95void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios,96			   const struct ktermios *old)97{98	p->status &= ~UPSTAT_AUTOCTS;99	if (termios->c_cflag & CRTSCTS)100		p->status |= UPSTAT_AUTOCTS;101 102	serial8250_do_set_termios(p, termios, old);103 104	/* Filter addresses which have 9th bit set */105	p->ignore_status_mask |= DW_UART_LSR_ADDR_RCVD;106	p->read_status_mask |= DW_UART_LSR_ADDR_RCVD;107}108EXPORT_SYMBOL_GPL(dw8250_do_set_termios);109 110/*111 * Wait until re is de-asserted for sure. An ongoing receive will keep112 * re asserted until end of frame. Without BUSY indication available,113 * only available course of action is to wait for the time it takes to114 * receive one frame (there might nothing to receive but w/o BUSY the115 * driver cannot know).116 */117static void dw8250_wait_re_deassert(struct uart_port *p)118{119	ndelay(p->frame_time);120}121 122static void dw8250_update_rar(struct uart_port *p, u32 addr)123{124	u32 re_en = dw8250_readl_ext(p, DW_UART_RE_EN);125 126	/*127	 * RAR shouldn't be changed while receiving. Thus, de-assert RE_EN128	 * if asserted and wait.129	 */130	if (re_en)131		dw8250_writel_ext(p, DW_UART_RE_EN, 0);132	dw8250_wait_re_deassert(p);133	dw8250_writel_ext(p, DW_UART_RAR, addr);134	if (re_en)135		dw8250_writel_ext(p, DW_UART_RE_EN, re_en);136}137 138static void dw8250_rs485_set_addr(struct uart_port *p, struct serial_rs485 *rs485,139				  struct ktermios *termios)140{141	u32 lcr = dw8250_readl_ext(p, DW_UART_LCR_EXT);142 143	if (rs485->flags & SER_RS485_ADDRB) {144		lcr |= DW_UART_LCR_EXT_DLS_E;145		if (termios)146			termios->c_cflag |= ADDRB;147 148		if (rs485->flags & SER_RS485_ADDR_RECV) {149			u32 delta = p->rs485.flags ^ rs485->flags;150 151			/*152			 * rs485 (param) is equal to uart_port's rs485 only during init153			 * (during init, delta is not yet applicable).154			 */155			if (unlikely(&p->rs485 == rs485))156				delta = rs485->flags;157 158			if ((delta & SER_RS485_ADDR_RECV) ||159			    (p->rs485.addr_recv != rs485->addr_recv))160				dw8250_update_rar(p, rs485->addr_recv);161			lcr |= DW_UART_LCR_EXT_ADDR_MATCH;162		} else {163			lcr &= ~DW_UART_LCR_EXT_ADDR_MATCH;164		}165		if (rs485->flags & SER_RS485_ADDR_DEST) {166			/*167			 * Don't skip writes here as another endpoint could168			 * have changed communication line's destination169			 * address in between.170			 */171			dw8250_writel_ext(p, DW_UART_TAR, rs485->addr_dest);172			lcr |= DW_UART_LCR_EXT_SEND_ADDR;173		}174	} else {175		lcr = 0;176	}177	dw8250_writel_ext(p, DW_UART_LCR_EXT, lcr);178}179 180static int dw8250_rs485_config(struct uart_port *p, struct ktermios *termios,181			       struct serial_rs485 *rs485)182{183	u32 tcr;184 185	tcr = dw8250_readl_ext(p, DW_UART_TCR);186	tcr &= ~DW_UART_TCR_XFER_MODE;187 188	if (rs485->flags & SER_RS485_ENABLED) {189		tcr |= DW_UART_TCR_RS485_EN;190 191		if (rs485->flags & SER_RS485_RX_DURING_TX)192			tcr |= DW_UART_TCR_XFER_MODE_DE_DURING_RE;193		else194			tcr |= DW_UART_TCR_XFER_MODE_DE_OR_RE;195		dw8250_writel_ext(p, DW_UART_DE_EN, 1);196		dw8250_writel_ext(p, DW_UART_RE_EN, 1);197	} else {198		if (termios)199			termios->c_cflag &= ~ADDRB;200 201		tcr &= ~DW_UART_TCR_RS485_EN;202	}203 204	/* Reset to default polarity */205	tcr |= DW_UART_TCR_DE_POL;206	tcr &= ~DW_UART_TCR_RE_POL;207 208	if (!(rs485->flags & SER_RS485_RTS_ON_SEND))209		tcr &= ~DW_UART_TCR_DE_POL;210	if (device_property_read_bool(p->dev, "rs485-rx-active-high"))211		tcr |= DW_UART_TCR_RE_POL;212 213	dw8250_writel_ext(p, DW_UART_TCR, tcr);214 215	/* Addressing mode can only be set up after TCR */216	if (rs485->flags & SER_RS485_ENABLED)217		dw8250_rs485_set_addr(p, rs485, termios);218 219	return 0;220}221 222/*223 * Tests if RE_EN register can have non-zero value to see if RS-485 HW support224 * is present.225 */226static bool dw8250_detect_rs485_hw(struct uart_port *p)227{228	u32 reg;229 230	dw8250_writel_ext(p, DW_UART_RE_EN, 1);231	reg = dw8250_readl_ext(p, DW_UART_RE_EN);232	dw8250_writel_ext(p, DW_UART_RE_EN, 0);233	return reg;234}235 236static const struct serial_rs485 dw8250_rs485_supported = {237	.flags = SER_RS485_ENABLED | SER_RS485_RX_DURING_TX | SER_RS485_RTS_ON_SEND |238		 SER_RS485_RTS_AFTER_SEND | SER_RS485_ADDRB | SER_RS485_ADDR_RECV |239		 SER_RS485_ADDR_DEST,240};241 242void dw8250_setup_port(struct uart_port *p)243{244	struct dw8250_port_data *pd = p->private_data;245	struct uart_8250_port *up = up_to_u8250p(p);246	u32 reg, old_dlf;247 248	pd->hw_rs485_support = dw8250_detect_rs485_hw(p);249	if (pd->hw_rs485_support) {250		p->rs485_config = dw8250_rs485_config;251		up->lsr_save_mask = LSR_SAVE_FLAGS | DW_UART_LSR_ADDR_RCVD;252		p->rs485_supported = dw8250_rs485_supported;253	} else {254		p->rs485_config = serial8250_em485_config;255		p->rs485_supported = serial8250_em485_supported;256		up->rs485_start_tx = serial8250_em485_start_tx;257		up->rs485_stop_tx = serial8250_em485_stop_tx;258	}259	up->capabilities |= UART_CAP_NOTEMT;260 261	/* Preserve value written by firmware or bootloader  */262	old_dlf = dw8250_readl_ext(p, DW_UART_DLF);263	dw8250_writel_ext(p, DW_UART_DLF, ~0U);264	reg = dw8250_readl_ext(p, DW_UART_DLF);265	dw8250_writel_ext(p, DW_UART_DLF, old_dlf);266 267	if (reg) {268		pd->dlf_size = fls(reg);269		p->get_divisor = dw8250_get_divisor;270		p->set_divisor = dw8250_set_divisor;271	}272 273	reg = dw8250_readl_ext(p, DW_UART_UCV);274	if (reg)275		dev_dbg(p->dev, "Designware UART version %c.%c%c\n",276			(reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);277 278	reg = dw8250_readl_ext(p, DW_UART_CPR);279	if (!reg) {280		reg = pd->cpr_value;281		dev_dbg(p->dev, "CPR is not available, using 0x%08x instead\n", reg);282	}283	if (!reg)284		return;285 286	/* Select the type based on FIFO */287	if (reg & DW_UART_CPR_FIFO_MODE) {288		p->type = PORT_16550A;289		p->flags |= UPF_FIXED_TYPE;290		p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);291		up->capabilities = UART_CAP_FIFO | UART_CAP_NOTEMT;292	}293 294	if (reg & DW_UART_CPR_AFCE_MODE)295		up->capabilities |= UART_CAP_AFE;296 297	if (reg & DW_UART_CPR_SIR_MODE)298		up->capabilities |= UART_CAP_IRDA;299}300EXPORT_SYMBOL_GPL(dw8250_setup_port);301