xref: /linux/drivers/tty/serial/amba-pl011.c (revision 255abd49)
1e3b3d0f5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
2ab4382d2SGreg Kroah-Hartman /*
3ab4382d2SGreg Kroah-Hartman  *  Driver for AMBA serial ports
4ab4382d2SGreg Kroah-Hartman  *
5ab4382d2SGreg Kroah-Hartman  *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
6ab4382d2SGreg Kroah-Hartman  *
7ab4382d2SGreg Kroah-Hartman  *  Copyright 1999 ARM Limited
8ab4382d2SGreg Kroah-Hartman  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
9ab4382d2SGreg Kroah-Hartman  *  Copyright (C) 2010 ST-Ericsson SA
10ab4382d2SGreg Kroah-Hartman  *
11ab4382d2SGreg Kroah-Hartman  * This is a generic driver for ARM AMBA-type serial ports.  They
12ab4382d2SGreg Kroah-Hartman  * have a lot of 16550-like features, but are not register compatible.
13ab4382d2SGreg Kroah-Hartman  * Note that although they do have CTS, DCD and DSR inputs, they do
14ab4382d2SGreg Kroah-Hartman  * not have an RI input, nor do they have DTR or RTS outputs.  If
15ab4382d2SGreg Kroah-Hartman  * required, these have to be supplied via some other means (eg, GPIO)
16ab4382d2SGreg Kroah-Hartman  * and hooked into this driver.
17ab4382d2SGreg Kroah-Hartman  */
18ab4382d2SGreg Kroah-Hartman 
19ab4382d2SGreg Kroah-Hartman #include <linux/module.h>
20ab4382d2SGreg Kroah-Hartman #include <linux/ioport.h>
21ab4382d2SGreg Kroah-Hartman #include <linux/init.h>
22ab4382d2SGreg Kroah-Hartman #include <linux/console.h>
2329e5c442SRob Herring #include <linux/platform_device.h>
24ab4382d2SGreg Kroah-Hartman #include <linux/sysrq.h>
25ab4382d2SGreg Kroah-Hartman #include <linux/device.h>
26ab4382d2SGreg Kroah-Hartman #include <linux/tty.h>
27ab4382d2SGreg Kroah-Hartman #include <linux/tty_flip.h>
28ab4382d2SGreg Kroah-Hartman #include <linux/serial_core.h>
29ab4382d2SGreg Kroah-Hartman #include <linux/serial.h>
30ab4382d2SGreg Kroah-Hartman #include <linux/amba/bus.h>
31ab4382d2SGreg Kroah-Hartman #include <linux/amba/serial.h>
32ab4382d2SGreg Kroah-Hartman #include <linux/clk.h>
33ab4382d2SGreg Kroah-Hartman #include <linux/slab.h>
34ab4382d2SGreg Kroah-Hartman #include <linux/dmaengine.h>
35ab4382d2SGreg Kroah-Hartman #include <linux/dma-mapping.h>
36ab4382d2SGreg Kroah-Hartman #include <linux/scatterlist.h>
37c16d51a3SShreshtha Kumar Sahu #include <linux/delay.h>
38258aea76SViresh Kumar #include <linux/types.h>
3932614aadSMatthew Leach #include <linux/of.h>
40258e0551SShawn Guo #include <linux/pinctrl/consumer.h>
41cb70706cSAlessandro Rubini #include <linux/sizes.h>
42de609582SLinus Walleij #include <linux/io.h>
433db9ab0bSGraeme Gregory #include <linux/acpi.h>
44ab4382d2SGreg Kroah-Hartman 
45ab4382d2SGreg Kroah-Hartman #define UART_NR			14
46ab4382d2SGreg Kroah-Hartman 
47ab4382d2SGreg Kroah-Hartman #define SERIAL_AMBA_MAJOR	204
48ab4382d2SGreg Kroah-Hartman #define SERIAL_AMBA_MINOR	64
49ab4382d2SGreg Kroah-Hartman #define SERIAL_AMBA_NR		UART_NR
50ab4382d2SGreg Kroah-Hartman 
51ab4382d2SGreg Kroah-Hartman #define AMBA_ISR_PASS_LIMIT	256
52ab4382d2SGreg Kroah-Hartman 
53ab4382d2SGreg Kroah-Hartman #define UART_DR_ERROR		(UART011_DR_OE | UART011_DR_BE | UART011_DR_PE | UART011_DR_FE)
54826bd77aSThéo Lebrun #define UART_DUMMY_DR_RX	BIT(16)
55ab4382d2SGreg Kroah-Hartman 
569bb13b2fSJiri Slaby enum {
579bb13b2fSJiri Slaby 	REG_DR,
589bb13b2fSJiri Slaby 	REG_ST_DMAWM,
599bb13b2fSJiri Slaby 	REG_ST_TIMEOUT,
609bb13b2fSJiri Slaby 	REG_FR,
619bb13b2fSJiri Slaby 	REG_LCRH_RX,
629bb13b2fSJiri Slaby 	REG_LCRH_TX,
639bb13b2fSJiri Slaby 	REG_IBRD,
649bb13b2fSJiri Slaby 	REG_FBRD,
659bb13b2fSJiri Slaby 	REG_CR,
669bb13b2fSJiri Slaby 	REG_IFLS,
679bb13b2fSJiri Slaby 	REG_IMSC,
689bb13b2fSJiri Slaby 	REG_RIS,
699bb13b2fSJiri Slaby 	REG_MIS,
709bb13b2fSJiri Slaby 	REG_ICR,
719bb13b2fSJiri Slaby 	REG_DMACR,
729bb13b2fSJiri Slaby 	REG_ST_XFCR,
739bb13b2fSJiri Slaby 	REG_ST_XON1,
749bb13b2fSJiri Slaby 	REG_ST_XON2,
759bb13b2fSJiri Slaby 	REG_ST_XOFF1,
769bb13b2fSJiri Slaby 	REG_ST_XOFF2,
779bb13b2fSJiri Slaby 	REG_ST_ITCR,
789bb13b2fSJiri Slaby 	REG_ST_ITIP,
799bb13b2fSJiri Slaby 	REG_ST_ABCR,
809bb13b2fSJiri Slaby 	REG_ST_ABIMSC,
819bb13b2fSJiri Slaby 
829bb13b2fSJiri Slaby 	/* The size of the array - must be last */
839bb13b2fSJiri Slaby 	REG_ARRAY_SIZE,
849bb13b2fSJiri Slaby };
859bb13b2fSJiri Slaby 
86debb7f64SRussell King static u16 pl011_std_offsets[REG_ARRAY_SIZE] = {
87debb7f64SRussell King 	[REG_DR] = UART01x_DR,
88debb7f64SRussell King 	[REG_FR] = UART01x_FR,
89e4df9a80SRussell King 	[REG_LCRH_RX] = UART011_LCRH,
90e4df9a80SRussell King 	[REG_LCRH_TX] = UART011_LCRH,
91debb7f64SRussell King 	[REG_IBRD] = UART011_IBRD,
92debb7f64SRussell King 	[REG_FBRD] = UART011_FBRD,
93debb7f64SRussell King 	[REG_CR] = UART011_CR,
94debb7f64SRussell King 	[REG_IFLS] = UART011_IFLS,
95debb7f64SRussell King 	[REG_IMSC] = UART011_IMSC,
96debb7f64SRussell King 	[REG_RIS] = UART011_RIS,
97debb7f64SRussell King 	[REG_MIS] = UART011_MIS,
98debb7f64SRussell King 	[REG_ICR] = UART011_ICR,
99debb7f64SRussell King 	[REG_DMACR] = UART011_DMACR,
100debb7f64SRussell King };
101debb7f64SRussell King 
102ab4382d2SGreg Kroah-Hartman /* There is by now at least one vendor with differing details, so handle it */
103ab4382d2SGreg Kroah-Hartman struct vendor_data {
104439403bdSRussell King 	const u16		*reg_offset;
105ab4382d2SGreg Kroah-Hartman 	unsigned int		ifls;
1060e125a5fSShawn Guo 	unsigned int		fr_busy;
1070e125a5fSShawn Guo 	unsigned int		fr_dsr;
1080e125a5fSShawn Guo 	unsigned int		fr_cts;
1090e125a5fSShawn Guo 	unsigned int		fr_ri;
110d8a4995bSChristopher Covington 	unsigned int		inv_fr;
11184c3e03bSRussell King 	bool			access_32b;
112ab4382d2SGreg Kroah-Hartman 	bool			oversampling;
113ab4382d2SGreg Kroah-Hartman 	bool			dma_threshold;
1144fd0690bSRajanikanth H.V 	bool			cts_event_workaround;
11571eec483SAndre Przywara 	bool			always_enabled;
116cefc2d1dSAndre Przywara 	bool			fixed_options;
11778506f22SJongsung Kim 
118ea33640aSJongsung Kim 	unsigned int (*get_fifosize)(struct amba_device *dev);
119ab4382d2SGreg Kroah-Hartman };
120ab4382d2SGreg Kroah-Hartman 
get_fifosize_arm(struct amba_device * dev)121ea33640aSJongsung Kim static unsigned int get_fifosize_arm(struct amba_device *dev)
12278506f22SJongsung Kim {
123ea33640aSJongsung Kim 	return amba_rev(dev) < 3 ? 16 : 32;
12478506f22SJongsung Kim }
12578506f22SJongsung Kim 
126ab4382d2SGreg Kroah-Hartman static struct vendor_data vendor_arm = {
127439403bdSRussell King 	.reg_offset		= pl011_std_offsets,
128ab4382d2SGreg Kroah-Hartman 	.ifls			= UART011_IFLS_RX4_8 | UART011_IFLS_TX4_8,
1290e125a5fSShawn Guo 	.fr_busy		= UART01x_FR_BUSY,
1300e125a5fSShawn Guo 	.fr_dsr			= UART01x_FR_DSR,
1310e125a5fSShawn Guo 	.fr_cts			= UART01x_FR_CTS,
1320e125a5fSShawn Guo 	.fr_ri			= UART011_FR_RI,
133ab4382d2SGreg Kroah-Hartman 	.oversampling		= false,
134ab4382d2SGreg Kroah-Hartman 	.dma_threshold		= false,
1354fd0690bSRajanikanth H.V 	.cts_event_workaround	= false,
13671eec483SAndre Przywara 	.always_enabled		= false,
137cefc2d1dSAndre Przywara 	.fixed_options		= false,
13878506f22SJongsung Kim 	.get_fifosize		= get_fifosize_arm,
139ab4382d2SGreg Kroah-Hartman };
140ab4382d2SGreg Kroah-Hartman 
141d054b3acSJulia Lawall static const struct vendor_data vendor_sbsa = {
142439403bdSRussell King 	.reg_offset		= pl011_std_offsets,
1430e125a5fSShawn Guo 	.fr_busy		= UART01x_FR_BUSY,
1440e125a5fSShawn Guo 	.fr_dsr			= UART01x_FR_DSR,
1450e125a5fSShawn Guo 	.fr_cts			= UART01x_FR_CTS,
1460e125a5fSShawn Guo 	.fr_ri			= UART011_FR_RI,
1471aabf523SChristopher Covington 	.access_32b		= true,
1480dd1e247SAndre Przywara 	.oversampling		= false,
1490dd1e247SAndre Przywara 	.dma_threshold		= false,
1500dd1e247SAndre Przywara 	.cts_event_workaround	= false,
1510dd1e247SAndre Przywara 	.always_enabled		= true,
1520dd1e247SAndre Przywara 	.fixed_options		= true,
1530dd1e247SAndre Przywara };
1540dd1e247SAndre Przywara 
15537ef38f3STimur Tabi #ifdef CONFIG_ACPI_SPCR_TABLE
156d054b3acSJulia Lawall static const struct vendor_data vendor_qdt_qdf2400_e44 = {
157d8a4995bSChristopher Covington 	.reg_offset		= pl011_std_offsets,
158d8a4995bSChristopher Covington 	.fr_busy		= UART011_FR_TXFE,
159d8a4995bSChristopher Covington 	.fr_dsr			= UART01x_FR_DSR,
160d8a4995bSChristopher Covington 	.fr_cts			= UART01x_FR_CTS,
161d8a4995bSChristopher Covington 	.fr_ri			= UART011_FR_RI,
162d8a4995bSChristopher Covington 	.inv_fr			= UART011_FR_TXFE,
163d8a4995bSChristopher Covington 	.access_32b		= true,
164d8a4995bSChristopher Covington 	.oversampling		= false,
165d8a4995bSChristopher Covington 	.dma_threshold		= false,
166d8a4995bSChristopher Covington 	.cts_event_workaround	= false,
167d8a4995bSChristopher Covington 	.always_enabled		= true,
168d8a4995bSChristopher Covington 	.fixed_options		= true,
169d8a4995bSChristopher Covington };
17037ef38f3STimur Tabi #endif
171d8a4995bSChristopher Covington 
172bf69ff8aSRussell King static u16 pl011_st_offsets[REG_ARRAY_SIZE] = {
173bf69ff8aSRussell King 	[REG_DR] = UART01x_DR,
174bf69ff8aSRussell King 	[REG_ST_DMAWM] = ST_UART011_DMAWM,
175bf69ff8aSRussell King 	[REG_ST_TIMEOUT] = ST_UART011_TIMEOUT,
176bf69ff8aSRussell King 	[REG_FR] = UART01x_FR,
177e4df9a80SRussell King 	[REG_LCRH_RX] = ST_UART011_LCRH_RX,
178e4df9a80SRussell King 	[REG_LCRH_TX] = ST_UART011_LCRH_TX,
179bf69ff8aSRussell King 	[REG_IBRD] = UART011_IBRD,
180bf69ff8aSRussell King 	[REG_FBRD] = UART011_FBRD,
181bf69ff8aSRussell King 	[REG_CR] = UART011_CR,
182bf69ff8aSRussell King 	[REG_IFLS] = UART011_IFLS,
183bf69ff8aSRussell King 	[REG_IMSC] = UART011_IMSC,
184bf69ff8aSRussell King 	[REG_RIS] = UART011_RIS,
185bf69ff8aSRussell King 	[REG_MIS] = UART011_MIS,
186bf69ff8aSRussell King 	[REG_ICR] = UART011_ICR,
187bf69ff8aSRussell King 	[REG_DMACR] = UART011_DMACR,
188bf69ff8aSRussell King 	[REG_ST_XFCR] = ST_UART011_XFCR,
189bf69ff8aSRussell King 	[REG_ST_XON1] = ST_UART011_XON1,
190bf69ff8aSRussell King 	[REG_ST_XON2] = ST_UART011_XON2,
191bf69ff8aSRussell King 	[REG_ST_XOFF1] = ST_UART011_XOFF1,
192bf69ff8aSRussell King 	[REG_ST_XOFF2] = ST_UART011_XOFF2,
193bf69ff8aSRussell King 	[REG_ST_ITCR] = ST_UART011_ITCR,
194bf69ff8aSRussell King 	[REG_ST_ITIP] = ST_UART011_ITIP,
195bf69ff8aSRussell King 	[REG_ST_ABCR] = ST_UART011_ABCR,
196bf69ff8aSRussell King 	[REG_ST_ABIMSC] = ST_UART011_ABIMSC,
197bf69ff8aSRussell King };
198bf69ff8aSRussell King 
get_fifosize_st(struct amba_device * dev)199ea33640aSJongsung Kim static unsigned int get_fifosize_st(struct amba_device *dev)
20078506f22SJongsung Kim {
20178506f22SJongsung Kim 	return 64;
20278506f22SJongsung Kim }
20378506f22SJongsung Kim 
204ab4382d2SGreg Kroah-Hartman static struct vendor_data vendor_st = {
205bf69ff8aSRussell King 	.reg_offset		= pl011_st_offsets,
206ab4382d2SGreg Kroah-Hartman 	.ifls			= UART011_IFLS_RX_HALF | UART011_IFLS_TX_HALF,
2070e125a5fSShawn Guo 	.fr_busy		= UART01x_FR_BUSY,
2080e125a5fSShawn Guo 	.fr_dsr			= UART01x_FR_DSR,
2090e125a5fSShawn Guo 	.fr_cts			= UART01x_FR_CTS,
2100e125a5fSShawn Guo 	.fr_ri			= UART011_FR_RI,
211ab4382d2SGreg Kroah-Hartman 	.oversampling		= true,
212ab4382d2SGreg Kroah-Hartman 	.dma_threshold		= true,
2134fd0690bSRajanikanth H.V 	.cts_event_workaround	= true,
21471eec483SAndre Przywara 	.always_enabled		= false,
215cefc2d1dSAndre Przywara 	.fixed_options		= false,
21678506f22SJongsung Kim 	.get_fifosize		= get_fifosize_st,
217ab4382d2SGreg Kroah-Hartman };
218ab4382d2SGreg Kroah-Hartman 
219ab4382d2SGreg Kroah-Hartman /* Deals with DMA transactions */
220ead76f32SLinus Walleij 
22158ac1b37SArnd Bergmann struct pl011_dmabuf {
22258ac1b37SArnd Bergmann 	dma_addr_t		dma;
22358ac1b37SArnd Bergmann 	size_t			len;
224ead76f32SLinus Walleij 	char			*buf;
225ead76f32SLinus Walleij };
226ead76f32SLinus Walleij 
227ead76f32SLinus Walleij struct pl011_dmarx_data {
228ead76f32SLinus Walleij 	struct dma_chan		*chan;
229ead76f32SLinus Walleij 	struct completion	complete;
230ead76f32SLinus Walleij 	bool			use_buf_b;
23158ac1b37SArnd Bergmann 	struct pl011_dmabuf	dbuf_a;
23258ac1b37SArnd Bergmann 	struct pl011_dmabuf	dbuf_b;
233ead76f32SLinus Walleij 	dma_cookie_t		cookie;
234ead76f32SLinus Walleij 	bool			running;
235cb06ff10SChanho Min 	struct timer_list	timer;
236cb06ff10SChanho Min 	unsigned int last_residue;
237cb06ff10SChanho Min 	unsigned long last_jiffies;
238cb06ff10SChanho Min 	bool auto_poll_rate;
239cb06ff10SChanho Min 	unsigned int poll_rate;
240cb06ff10SChanho Min 	unsigned int poll_timeout;
241ead76f32SLinus Walleij };
242ead76f32SLinus Walleij 
243ab4382d2SGreg Kroah-Hartman struct pl011_dmatx_data {
244ab4382d2SGreg Kroah-Hartman 	struct dma_chan		*chan;
24558ac1b37SArnd Bergmann 	dma_addr_t		dma;
24658ac1b37SArnd Bergmann 	size_t			len;
247ab4382d2SGreg Kroah-Hartman 	char			*buf;
248ab4382d2SGreg Kroah-Hartman 	bool			queued;
249ab4382d2SGreg Kroah-Hartman };
250ab4382d2SGreg Kroah-Hartman 
251ab4382d2SGreg Kroah-Hartman /*
252ab4382d2SGreg Kroah-Hartman  * We wrap our port structure around the generic uart_port.
253ab4382d2SGreg Kroah-Hartman  */
254ab4382d2SGreg Kroah-Hartman struct uart_amba_port {
255ab4382d2SGreg Kroah-Hartman 	struct uart_port	port;
256debb7f64SRussell King 	const u16		*reg_offset;
257ab4382d2SGreg Kroah-Hartman 	struct clk		*clk;
258ab4382d2SGreg Kroah-Hartman 	const struct vendor_data *vendor;
259ab4382d2SGreg Kroah-Hartman 	unsigned int		im;		/* interrupt mask */
260ab4382d2SGreg Kroah-Hartman 	unsigned int		old_status;
261ab4382d2SGreg Kroah-Hartman 	unsigned int		fifosize;	/* vendor-specific */
262cefc2d1dSAndre Przywara 	unsigned int		fixed_baud;	/* vendor-set fixed baud rate */
263ab4382d2SGreg Kroah-Hartman 	char			type[12];
2648d479237SLino Sanfilippo 	bool			rs485_tx_started;
2658d479237SLino Sanfilippo 	unsigned int		rs485_tx_drain_interval; /* usecs */
266ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_DMA_ENGINE
267ab4382d2SGreg Kroah-Hartman 	/* DMA stuff */
268*255abd49SLino Sanfilippo 	unsigned int		dmacr;		/* dma control reg */
269ead76f32SLinus Walleij 	bool			using_tx_dma;
270ead76f32SLinus Walleij 	bool			using_rx_dma;
271ead76f32SLinus Walleij 	struct pl011_dmarx_data dmarx;
272ab4382d2SGreg Kroah-Hartman 	struct pl011_dmatx_data	dmatx;
2731c9be310SJorge Ramirez-Ortiz 	bool			dma_probed;
274ab4382d2SGreg Kroah-Hartman #endif
275ab4382d2SGreg Kroah-Hartman };
276ab4382d2SGreg Kroah-Hartman 
2778d479237SLino Sanfilippo static unsigned int pl011_tx_empty(struct uart_port *port);
2788d479237SLino Sanfilippo 
pl011_reg_to_offset(const struct uart_amba_port * uap,unsigned int reg)2799f25bc51SRussell King static unsigned int pl011_reg_to_offset(const struct uart_amba_port *uap,
2809f25bc51SRussell King 					unsigned int reg)
2819f25bc51SRussell King {
282debb7f64SRussell King 	return uap->reg_offset[reg];
2839f25bc51SRussell King }
2849f25bc51SRussell King 
pl011_read(const struct uart_amba_port * uap,unsigned int reg)285b2a4e24cSRussell King static unsigned int pl011_read(const struct uart_amba_port *uap,
286b2a4e24cSRussell King 			       unsigned int reg)
28775836339SRussell King {
28884c3e03bSRussell King 	void __iomem *addr = uap->port.membase + pl011_reg_to_offset(uap, reg);
28984c3e03bSRussell King 
2903b78fae7STimur Tabi 	return (uap->port.iotype == UPIO_MEM32) ?
2913b78fae7STimur Tabi 		readl_relaxed(addr) : readw_relaxed(addr);
29275836339SRussell King }
29375836339SRussell King 
pl011_write(unsigned int val,const struct uart_amba_port * uap,unsigned int reg)294b2a4e24cSRussell King static void pl011_write(unsigned int val, const struct uart_amba_port *uap,
295b2a4e24cSRussell King 			unsigned int reg)
29675836339SRussell King {
29784c3e03bSRussell King 	void __iomem *addr = uap->port.membase + pl011_reg_to_offset(uap, reg);
29884c3e03bSRussell King 
2993b78fae7STimur Tabi 	if (uap->port.iotype == UPIO_MEM32)
300f5ce6eddSRussell King 		writel_relaxed(val, addr);
30184c3e03bSRussell King 	else
302f5ce6eddSRussell King 		writew_relaxed(val, addr);
30375836339SRussell King }
30475836339SRussell King 
305ab4382d2SGreg Kroah-Hartman /*
30629772c4eSLinus Walleij  * Reads up to 256 characters from the FIFO or until it's empty and
30729772c4eSLinus Walleij  * inserts them into the TTY layer. Returns the number of characters
30829772c4eSLinus Walleij  * read from the FIFO.
30929772c4eSLinus Walleij  */
pl011_fifo_to_tty(struct uart_amba_port * uap)31029772c4eSLinus Walleij static int pl011_fifo_to_tty(struct uart_amba_port *uap)
31129772c4eSLinus Walleij {
312fd2b55f8SJiri Slaby 	unsigned int ch, fifotaken;
313534cf755SPeter Zijlstra 	int sysrq;
314534cf755SPeter Zijlstra 	u16 status;
315fd2b55f8SJiri Slaby 	u8 flag;
31629772c4eSLinus Walleij 
317e73be92dSLukas Wunner 	for (fifotaken = 0; fifotaken != 256; fifotaken++) {
3189f25bc51SRussell King 		status = pl011_read(uap, REG_FR);
31929772c4eSLinus Walleij 		if (status & UART01x_FR_RXFE)
32029772c4eSLinus Walleij 			break;
32129772c4eSLinus Walleij 
32229772c4eSLinus Walleij 		/* Take chars from the FIFO and update status */
3239f25bc51SRussell King 		ch = pl011_read(uap, REG_DR) | UART_DUMMY_DR_RX;
32429772c4eSLinus Walleij 		flag = TTY_NORMAL;
32529772c4eSLinus Walleij 		uap->port.icount.rx++;
32629772c4eSLinus Walleij 
32729772c4eSLinus Walleij 		if (unlikely(ch & UART_DR_ERROR)) {
32829772c4eSLinus Walleij 			if (ch & UART011_DR_BE) {
32929772c4eSLinus Walleij 				ch &= ~(UART011_DR_FE | UART011_DR_PE);
33029772c4eSLinus Walleij 				uap->port.icount.brk++;
33129772c4eSLinus Walleij 				if (uart_handle_break(&uap->port))
33229772c4eSLinus Walleij 					continue;
33328a7ec8cSThéo Lebrun 			} else if (ch & UART011_DR_PE) {
33429772c4eSLinus Walleij 				uap->port.icount.parity++;
33528a7ec8cSThéo Lebrun 			} else if (ch & UART011_DR_FE) {
33629772c4eSLinus Walleij 				uap->port.icount.frame++;
33728a7ec8cSThéo Lebrun 			}
33829772c4eSLinus Walleij 			if (ch & UART011_DR_OE)
33929772c4eSLinus Walleij 				uap->port.icount.overrun++;
34029772c4eSLinus Walleij 
34129772c4eSLinus Walleij 			ch &= uap->port.read_status_mask;
34229772c4eSLinus Walleij 
34329772c4eSLinus Walleij 			if (ch & UART011_DR_BE)
34429772c4eSLinus Walleij 				flag = TTY_BREAK;
34529772c4eSLinus Walleij 			else if (ch & UART011_DR_PE)
34629772c4eSLinus Walleij 				flag = TTY_PARITY;
34729772c4eSLinus Walleij 			else if (ch & UART011_DR_FE)
34829772c4eSLinus Walleij 				flag = TTY_FRAME;
34929772c4eSLinus Walleij 		}
35029772c4eSLinus Walleij 
3512432f71cSSebastian Andrzej Siewior 		sysrq = uart_prepare_sysrq_char(&uap->port, ch & 255);
352534cf755SPeter Zijlstra 		if (!sysrq)
35329772c4eSLinus Walleij 			uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
35429772c4eSLinus Walleij 	}
35529772c4eSLinus Walleij 
35629772c4eSLinus Walleij 	return fifotaken;
35729772c4eSLinus Walleij }
35829772c4eSLinus Walleij 
35929772c4eSLinus Walleij /*
360ab4382d2SGreg Kroah-Hartman  * All the DMA operation mode stuff goes inside this ifdef.
361ab4382d2SGreg Kroah-Hartman  * This assumes that you have a generic DMA device interface,
362ab4382d2SGreg Kroah-Hartman  * no custom DMA interfaces are supported.
363ab4382d2SGreg Kroah-Hartman  */
364ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_DMA_ENGINE
365ab4382d2SGreg Kroah-Hartman 
366ab4382d2SGreg Kroah-Hartman #define PL011_DMA_BUFFER_SIZE PAGE_SIZE
367ab4382d2SGreg Kroah-Hartman 
pl011_dmabuf_init(struct dma_chan * chan,struct pl011_dmabuf * db,enum dma_data_direction dir)36858ac1b37SArnd Bergmann static int pl011_dmabuf_init(struct dma_chan *chan, struct pl011_dmabuf *db,
369ead76f32SLinus Walleij 			     enum dma_data_direction dir)
370ead76f32SLinus Walleij {
37158ac1b37SArnd Bergmann 	db->buf = dma_alloc_coherent(chan->device->dev, PL011_DMA_BUFFER_SIZE,
37258ac1b37SArnd Bergmann 				     &db->dma, GFP_KERNEL);
37358ac1b37SArnd Bergmann 	if (!db->buf)
374ead76f32SLinus Walleij 		return -ENOMEM;
37558ac1b37SArnd Bergmann 	db->len = PL011_DMA_BUFFER_SIZE;
376ead76f32SLinus Walleij 
377ead76f32SLinus Walleij 	return 0;
378ead76f32SLinus Walleij }
379ead76f32SLinus Walleij 
pl011_dmabuf_free(struct dma_chan * chan,struct pl011_dmabuf * db,enum dma_data_direction dir)38058ac1b37SArnd Bergmann static void pl011_dmabuf_free(struct dma_chan *chan, struct pl011_dmabuf *db,
381ead76f32SLinus Walleij 			      enum dma_data_direction dir)
382ead76f32SLinus Walleij {
38358ac1b37SArnd Bergmann 	if (db->buf) {
384cb06ff10SChanho Min 		dma_free_coherent(chan->device->dev,
38558ac1b37SArnd Bergmann 				  PL011_DMA_BUFFER_SIZE, db->buf, db->dma);
386ead76f32SLinus Walleij 	}
387ead76f32SLinus Walleij }
388ead76f32SLinus Walleij 
pl011_dma_probe(struct uart_amba_port * uap)3891c9be310SJorge Ramirez-Ortiz static void pl011_dma_probe(struct uart_amba_port *uap)
390ab4382d2SGreg Kroah-Hartman {
391ab4382d2SGreg Kroah-Hartman 	/* DMA is the sole user of the platform data right now */
392574de559SJingoo Han 	struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev);
3931c9be310SJorge Ramirez-Ortiz 	struct device *dev = uap->port.dev;
394ab4382d2SGreg Kroah-Hartman 	struct dma_slave_config tx_conf = {
3959f25bc51SRussell King 		.dst_addr = uap->port.mapbase +
3969f25bc51SRussell King 				 pl011_reg_to_offset(uap, REG_DR),
397ab4382d2SGreg Kroah-Hartman 		.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
398a485df4bSVinod Koul 		.direction = DMA_MEM_TO_DEV,
399ab4382d2SGreg Kroah-Hartman 		.dst_maxburst = uap->fifosize >> 1,
400258aea76SViresh Kumar 		.device_fc = false,
401ab4382d2SGreg Kroah-Hartman 	};
402ab4382d2SGreg Kroah-Hartman 	struct dma_chan *chan;
403ab4382d2SGreg Kroah-Hartman 	dma_cap_mask_t mask;
404ab4382d2SGreg Kroah-Hartman 
4051c9be310SJorge Ramirez-Ortiz 	uap->dma_probed = true;
40661b37b04SPeter Ujfalusi 	chan = dma_request_chan(dev, "tx");
4071c9be310SJorge Ramirez-Ortiz 	if (IS_ERR(chan)) {
4081c9be310SJorge Ramirez-Ortiz 		if (PTR_ERR(chan) == -EPROBE_DEFER) {
4091c9be310SJorge Ramirez-Ortiz 			uap->dma_probed = false;
4101c9be310SJorge Ramirez-Ortiz 			return;
4111c9be310SJorge Ramirez-Ortiz 		}
412787b0c1fSArnd Bergmann 
413ab4382d2SGreg Kroah-Hartman 		/* We need platform data */
414ab4382d2SGreg Kroah-Hartman 		if (!plat || !plat->dma_filter) {
4156905ab83SFabio Estevam 			dev_dbg(uap->port.dev, "no DMA platform data\n");
416ab4382d2SGreg Kroah-Hartman 			return;
417ab4382d2SGreg Kroah-Hartman 		}
418ab4382d2SGreg Kroah-Hartman 
419ead76f32SLinus Walleij 		/* Try to acquire a generic DMA engine slave TX channel */
420ab4382d2SGreg Kroah-Hartman 		dma_cap_zero(mask);
421ab4382d2SGreg Kroah-Hartman 		dma_cap_set(DMA_SLAVE, mask);
422ab4382d2SGreg Kroah-Hartman 
423787b0c1fSArnd Bergmann 		chan = dma_request_channel(mask, plat->dma_filter,
424787b0c1fSArnd Bergmann 					   plat->dma_tx_param);
425ab4382d2SGreg Kroah-Hartman 		if (!chan) {
426ab4382d2SGreg Kroah-Hartman 			dev_err(uap->port.dev, "no TX DMA channel!\n");
427ab4382d2SGreg Kroah-Hartman 			return;
428ab4382d2SGreg Kroah-Hartman 		}
429787b0c1fSArnd Bergmann 	}
430ab4382d2SGreg Kroah-Hartman 
431ab4382d2SGreg Kroah-Hartman 	dmaengine_slave_config(chan, &tx_conf);
432ab4382d2SGreg Kroah-Hartman 	uap->dmatx.chan = chan;
433ab4382d2SGreg Kroah-Hartman 
434ab4382d2SGreg Kroah-Hartman 	dev_info(uap->port.dev, "DMA channel TX %s\n",
435ab4382d2SGreg Kroah-Hartman 		 dma_chan_name(uap->dmatx.chan));
436ead76f32SLinus Walleij 
437ead76f32SLinus Walleij 	/* Optionally make use of an RX channel as well */
438e6cc3948SChristophe JAILLET 	chan = dma_request_chan(dev, "rx");
439787b0c1fSArnd Bergmann 
440e6cc3948SChristophe JAILLET 	if (IS_ERR(chan) && plat && plat->dma_rx_param) {
441787b0c1fSArnd Bergmann 		chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
442787b0c1fSArnd Bergmann 
443787b0c1fSArnd Bergmann 		if (!chan) {
444787b0c1fSArnd Bergmann 			dev_err(uap->port.dev, "no RX DMA channel!\n");
445787b0c1fSArnd Bergmann 			return;
446787b0c1fSArnd Bergmann 		}
447787b0c1fSArnd Bergmann 	}
448787b0c1fSArnd Bergmann 
449e6cc3948SChristophe JAILLET 	if (!IS_ERR(chan)) {
450ead76f32SLinus Walleij 		struct dma_slave_config rx_conf = {
4519f25bc51SRussell King 			.src_addr = uap->port.mapbase +
4529f25bc51SRussell King 				pl011_reg_to_offset(uap, REG_DR),
453ead76f32SLinus Walleij 			.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
454a485df4bSVinod Koul 			.direction = DMA_DEV_TO_MEM,
455b2aeb775SGuennadi Liakhovetski 			.src_maxburst = uap->fifosize >> 2,
456258aea76SViresh Kumar 			.device_fc = false,
457ead76f32SLinus Walleij 		};
4582d3b7d6eSAndrew Jackson 		struct dma_slave_caps caps;
459ead76f32SLinus Walleij 
4602d3b7d6eSAndrew Jackson 		/*
4612d3b7d6eSAndrew Jackson 		 * Some DMA controllers provide information on their capabilities.
4622d3b7d6eSAndrew Jackson 		 * If the controller does, check for suitable residue processing
4632d3b7d6eSAndrew Jackson 		 * otherwise assime all is well.
4642d3b7d6eSAndrew Jackson 		 */
46528a7ec8cSThéo Lebrun 		if (dma_get_slave_caps(chan, &caps) == 0) {
4662d3b7d6eSAndrew Jackson 			if (caps.residue_granularity ==
4672d3b7d6eSAndrew Jackson 					DMA_RESIDUE_GRANULARITY_DESCRIPTOR) {
4682d3b7d6eSAndrew Jackson 				dma_release_channel(chan);
4692d3b7d6eSAndrew Jackson 				dev_info(uap->port.dev,
4702d3b7d6eSAndrew Jackson 					 "RX DMA disabled - no residue processing\n");
4712d3b7d6eSAndrew Jackson 				return;
4722d3b7d6eSAndrew Jackson 			}
4732d3b7d6eSAndrew Jackson 		}
474ead76f32SLinus Walleij 		dmaengine_slave_config(chan, &rx_conf);
475ead76f32SLinus Walleij 		uap->dmarx.chan = chan;
476ead76f32SLinus Walleij 
47798267d33SAndrew Jackson 		uap->dmarx.auto_poll_rate = false;
4788f898bfdSGreg Kroah-Hartman 		if (plat && plat->dma_rx_poll_enable) {
479cb06ff10SChanho Min 			/* Set poll rate if specified. */
480cb06ff10SChanho Min 			if (plat->dma_rx_poll_rate) {
481cb06ff10SChanho Min 				uap->dmarx.auto_poll_rate = false;
482cb06ff10SChanho Min 				uap->dmarx.poll_rate = plat->dma_rx_poll_rate;
483cb06ff10SChanho Min 			} else {
484cb06ff10SChanho Min 				/*
485cb06ff10SChanho Min 				 * 100 ms defaults to poll rate if not
486cb06ff10SChanho Min 				 * specified. This will be adjusted with
487cb06ff10SChanho Min 				 * the baud rate at set_termios.
488cb06ff10SChanho Min 				 */
489cb06ff10SChanho Min 				uap->dmarx.auto_poll_rate = true;
490cb06ff10SChanho Min 				uap->dmarx.poll_rate =  100;
491cb06ff10SChanho Min 			}
492cb06ff10SChanho Min 			/* 3 secs defaults poll_timeout if not specified. */
493cb06ff10SChanho Min 			if (plat->dma_rx_poll_timeout)
494cb06ff10SChanho Min 				uap->dmarx.poll_timeout =
495cb06ff10SChanho Min 					plat->dma_rx_poll_timeout;
496cb06ff10SChanho Min 			else
497cb06ff10SChanho Min 				uap->dmarx.poll_timeout = 3000;
49898267d33SAndrew Jackson 		} else if (!plat && dev->of_node) {
499d93ebe0fSThéo Lebrun 			uap->dmarx.auto_poll_rate =
500d93ebe0fSThéo Lebrun 					of_property_read_bool(dev->of_node, "auto-poll");
50198267d33SAndrew Jackson 			if (uap->dmarx.auto_poll_rate) {
50298267d33SAndrew Jackson 				u32 x;
503cb06ff10SChanho Min 
50428a7ec8cSThéo Lebrun 				if (of_property_read_u32(dev->of_node, "poll-rate-ms", &x) == 0)
50598267d33SAndrew Jackson 					uap->dmarx.poll_rate = x;
50698267d33SAndrew Jackson 				else
50798267d33SAndrew Jackson 					uap->dmarx.poll_rate = 100;
50828a7ec8cSThéo Lebrun 				if (of_property_read_u32(dev->of_node, "poll-timeout-ms", &x) == 0)
50998267d33SAndrew Jackson 					uap->dmarx.poll_timeout = x;
51098267d33SAndrew Jackson 				else
51198267d33SAndrew Jackson 					uap->dmarx.poll_timeout = 3000;
51298267d33SAndrew Jackson 			}
51398267d33SAndrew Jackson 		}
514ead76f32SLinus Walleij 		dev_info(uap->port.dev, "DMA channel RX %s\n",
515ead76f32SLinus Walleij 			 dma_chan_name(uap->dmarx.chan));
516ead76f32SLinus Walleij 	}
517ab4382d2SGreg Kroah-Hartman }
518ab4382d2SGreg Kroah-Hartman 
pl011_dma_remove(struct uart_amba_port * uap)519ab4382d2SGreg Kroah-Hartman static void pl011_dma_remove(struct uart_amba_port *uap)
520ab4382d2SGreg Kroah-Hartman {
521ab4382d2SGreg Kroah-Hartman 	if (uap->dmatx.chan)
522ab4382d2SGreg Kroah-Hartman 		dma_release_channel(uap->dmatx.chan);
523ead76f32SLinus Walleij 	if (uap->dmarx.chan)
524ead76f32SLinus Walleij 		dma_release_channel(uap->dmarx.chan);
525ab4382d2SGreg Kroah-Hartman }
526ab4382d2SGreg Kroah-Hartman 
527734745caSDave Martin /* Forward declare these for the refill routine */
528ab4382d2SGreg Kroah-Hartman static int pl011_dma_tx_refill(struct uart_amba_port *uap);
529734745caSDave Martin static void pl011_start_tx_pio(struct uart_amba_port *uap);
530ab4382d2SGreg Kroah-Hartman 
531ab4382d2SGreg Kroah-Hartman /*
532ab4382d2SGreg Kroah-Hartman  * The current DMA TX buffer has been sent.
533ab4382d2SGreg Kroah-Hartman  * Try to queue up another DMA buffer.
534ab4382d2SGreg Kroah-Hartman  */
pl011_dma_tx_callback(void * data)535ab4382d2SGreg Kroah-Hartman static void pl011_dma_tx_callback(void *data)
536ab4382d2SGreg Kroah-Hartman {
537ab4382d2SGreg Kroah-Hartman 	struct uart_amba_port *uap = data;
5381788cf6aSJiri Slaby (SUSE) 	struct tty_port *tport = &uap->port.state->port;
539ab4382d2SGreg Kroah-Hartman 	struct pl011_dmatx_data *dmatx = &uap->dmatx;
540ab4382d2SGreg Kroah-Hartman 	unsigned long flags;
541ab4382d2SGreg Kroah-Hartman 	u16 dmacr;
542ab4382d2SGreg Kroah-Hartman 
54368ca3e72SThomas Gleixner 	uart_port_lock_irqsave(&uap->port, &flags);
544ab4382d2SGreg Kroah-Hartman 	if (uap->dmatx.queued)
54558ac1b37SArnd Bergmann 		dma_unmap_single(dmatx->chan->device->dev, dmatx->dma,
54658ac1b37SArnd Bergmann 				 dmatx->len, DMA_TO_DEVICE);
547ab4382d2SGreg Kroah-Hartman 
548ab4382d2SGreg Kroah-Hartman 	dmacr = uap->dmacr;
549ab4382d2SGreg Kroah-Hartman 	uap->dmacr = dmacr & ~UART011_TXDMAE;
5509f25bc51SRussell King 	pl011_write(uap->dmacr, uap, REG_DMACR);
551ab4382d2SGreg Kroah-Hartman 
552ab4382d2SGreg Kroah-Hartman 	/*
553ab4382d2SGreg Kroah-Hartman 	 * If TX DMA was disabled, it means that we've stopped the DMA for
554ab4382d2SGreg Kroah-Hartman 	 * some reason (eg, XOFF received, or we want to send an X-char.)
555ab4382d2SGreg Kroah-Hartman 	 *
556ab4382d2SGreg Kroah-Hartman 	 * Note: we need to be careful here of a potential race between DMA
557ab4382d2SGreg Kroah-Hartman 	 * and the rest of the driver - if the driver disables TX DMA while
558ab4382d2SGreg Kroah-Hartman 	 * a TX buffer completing, we must update the tx queued status to
559ab4382d2SGreg Kroah-Hartman 	 * get further refills (hence we check dmacr).
560ab4382d2SGreg Kroah-Hartman 	 */
561ab4382d2SGreg Kroah-Hartman 	if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) ||
5621788cf6aSJiri Slaby (SUSE) 	    kfifo_is_empty(&tport->xmit_fifo)) {
563ab4382d2SGreg Kroah-Hartman 		uap->dmatx.queued = false;
56468ca3e72SThomas Gleixner 		uart_port_unlock_irqrestore(&uap->port, flags);
565ab4382d2SGreg Kroah-Hartman 		return;
566ab4382d2SGreg Kroah-Hartman 	}
567ab4382d2SGreg Kroah-Hartman 
568734745caSDave Martin 	if (pl011_dma_tx_refill(uap) <= 0)
569ab4382d2SGreg Kroah-Hartman 		/*
570ab4382d2SGreg Kroah-Hartman 		 * We didn't queue a DMA buffer for some reason, but we
571ab4382d2SGreg Kroah-Hartman 		 * have data pending to be sent.  Re-enable the TX IRQ.
572ab4382d2SGreg Kroah-Hartman 		 */
573734745caSDave Martin 		pl011_start_tx_pio(uap);
574734745caSDave Martin 
57568ca3e72SThomas Gleixner 	uart_port_unlock_irqrestore(&uap->port, flags);
576ab4382d2SGreg Kroah-Hartman }
577ab4382d2SGreg Kroah-Hartman 
578ab4382d2SGreg Kroah-Hartman /*
579ab4382d2SGreg Kroah-Hartman  * Try to refill the TX DMA buffer.
580ab4382d2SGreg Kroah-Hartman  * Locking: called with port lock held and IRQs disabled.
581ab4382d2SGreg Kroah-Hartman  * Returns:
582ab4382d2SGreg Kroah-Hartman  *   1 if we queued up a TX DMA buffer.
583ab4382d2SGreg Kroah-Hartman  *   0 if we didn't want to handle this by DMA
584ab4382d2SGreg Kroah-Hartman  *  <0 on error
585ab4382d2SGreg Kroah-Hartman  */
pl011_dma_tx_refill(struct uart_amba_port * uap)586ab4382d2SGreg Kroah-Hartman static int pl011_dma_tx_refill(struct uart_amba_port *uap)
587ab4382d2SGreg Kroah-Hartman {
588ab4382d2SGreg Kroah-Hartman 	struct pl011_dmatx_data *dmatx = &uap->dmatx;
589ab4382d2SGreg Kroah-Hartman 	struct dma_chan *chan = dmatx->chan;
590ab4382d2SGreg Kroah-Hartman 	struct dma_device *dma_dev = chan->device;
591ab4382d2SGreg Kroah-Hartman 	struct dma_async_tx_descriptor *desc;
5921788cf6aSJiri Slaby (SUSE) 	struct tty_port *tport = &uap->port.state->port;
593ab4382d2SGreg Kroah-Hartman 	unsigned int count;
594ab4382d2SGreg Kroah-Hartman 
595ab4382d2SGreg Kroah-Hartman 	/*
596ab4382d2SGreg Kroah-Hartman 	 * Try to avoid the overhead involved in using DMA if the
597ab4382d2SGreg Kroah-Hartman 	 * transaction fits in the first half of the FIFO, by using
598ab4382d2SGreg Kroah-Hartman 	 * the standard interrupt handling.  This ensures that we
599ab4382d2SGreg Kroah-Hartman 	 * issue a uart_write_wakeup() at the appropriate time.
600ab4382d2SGreg Kroah-Hartman 	 */
6011788cf6aSJiri Slaby (SUSE) 	count = kfifo_len(&tport->xmit_fifo);
602ab4382d2SGreg Kroah-Hartman 	if (count < (uap->fifosize >> 1)) {
603ab4382d2SGreg Kroah-Hartman 		uap->dmatx.queued = false;
604ab4382d2SGreg Kroah-Hartman 		return 0;
605ab4382d2SGreg Kroah-Hartman 	}
606ab4382d2SGreg Kroah-Hartman 
607ab4382d2SGreg Kroah-Hartman 	/*
608ab4382d2SGreg Kroah-Hartman 	 * Bodge: don't send the last character by DMA, as this
609ab4382d2SGreg Kroah-Hartman 	 * will prevent XON from notifying us to restart DMA.
610ab4382d2SGreg Kroah-Hartman 	 */
611ab4382d2SGreg Kroah-Hartman 	count -= 1;
612ab4382d2SGreg Kroah-Hartman 
613ab4382d2SGreg Kroah-Hartman 	/* Else proceed to copy the TX chars to the DMA buffer and fire DMA */
614ab4382d2SGreg Kroah-Hartman 	if (count > PL011_DMA_BUFFER_SIZE)
615ab4382d2SGreg Kroah-Hartman 		count = PL011_DMA_BUFFER_SIZE;
616ab4382d2SGreg Kroah-Hartman 
6171788cf6aSJiri Slaby (SUSE) 	count = kfifo_out_peek(&tport->xmit_fifo, dmatx->buf, count);
61858ac1b37SArnd Bergmann 	dmatx->len = count;
61958ac1b37SArnd Bergmann 	dmatx->dma = dma_map_single(dma_dev->dev, dmatx->buf, count,
62058ac1b37SArnd Bergmann 				    DMA_TO_DEVICE);
62158ac1b37SArnd Bergmann 	if (dmatx->dma == DMA_MAPPING_ERROR) {
622ab4382d2SGreg Kroah-Hartman 		uap->dmatx.queued = false;
623ab4382d2SGreg Kroah-Hartman 		dev_dbg(uap->port.dev, "unable to map TX DMA\n");
624ab4382d2SGreg Kroah-Hartman 		return -EBUSY;
625ab4382d2SGreg Kroah-Hartman 	}
626ab4382d2SGreg Kroah-Hartman 
62758ac1b37SArnd Bergmann 	desc = dmaengine_prep_slave_single(chan, dmatx->dma, dmatx->len, DMA_MEM_TO_DEV,
628ab4382d2SGreg Kroah-Hartman 					   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
629ab4382d2SGreg Kroah-Hartman 	if (!desc) {
63058ac1b37SArnd Bergmann 		dma_unmap_single(dma_dev->dev, dmatx->dma, dmatx->len, DMA_TO_DEVICE);
631ab4382d2SGreg Kroah-Hartman 		uap->dmatx.queued = false;
632ab4382d2SGreg Kroah-Hartman 		/*
633ab4382d2SGreg Kroah-Hartman 		 * If DMA cannot be used right now, we complete this
634ab4382d2SGreg Kroah-Hartman 		 * transaction via IRQ and let the TTY layer retry.
635ab4382d2SGreg Kroah-Hartman 		 */
636ab4382d2SGreg Kroah-Hartman 		dev_dbg(uap->port.dev, "TX DMA busy\n");
637ab4382d2SGreg Kroah-Hartman 		return -EBUSY;
638ab4382d2SGreg Kroah-Hartman 	}
639ab4382d2SGreg Kroah-Hartman 
640ab4382d2SGreg Kroah-Hartman 	/* Some data to go along to the callback */
641ab4382d2SGreg Kroah-Hartman 	desc->callback = pl011_dma_tx_callback;
642ab4382d2SGreg Kroah-Hartman 	desc->callback_param = uap;
643ab4382d2SGreg Kroah-Hartman 
644ab4382d2SGreg Kroah-Hartman 	/* All errors should happen at prepare time */
645ab4382d2SGreg Kroah-Hartman 	dmaengine_submit(desc);
646ab4382d2SGreg Kroah-Hartman 
647ab4382d2SGreg Kroah-Hartman 	/* Fire the DMA transaction */
648ab4382d2SGreg Kroah-Hartman 	dma_dev->device_issue_pending(chan);
649ab4382d2SGreg Kroah-Hartman 
650ab4382d2SGreg Kroah-Hartman 	uap->dmacr |= UART011_TXDMAE;
6519f25bc51SRussell King 	pl011_write(uap->dmacr, uap, REG_DMACR);
652ab4382d2SGreg Kroah-Hartman 	uap->dmatx.queued = true;
653ab4382d2SGreg Kroah-Hartman 
654ab4382d2SGreg Kroah-Hartman 	/*
655ab4382d2SGreg Kroah-Hartman 	 * Now we know that DMA will fire, so advance the ring buffer
656ab4382d2SGreg Kroah-Hartman 	 * with the stuff we just dispatched.
657ab4382d2SGreg Kroah-Hartman 	 */
65871a67573SIlpo Järvinen 	uart_xmit_advance(&uap->port, count);
659ab4382d2SGreg Kroah-Hartman 
6601788cf6aSJiri Slaby (SUSE) 	if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
661ab4382d2SGreg Kroah-Hartman 		uart_write_wakeup(&uap->port);
662ab4382d2SGreg Kroah-Hartman 
663ab4382d2SGreg Kroah-Hartman 	return 1;
664ab4382d2SGreg Kroah-Hartman }
665ab4382d2SGreg Kroah-Hartman 
666ab4382d2SGreg Kroah-Hartman /*
667ab4382d2SGreg Kroah-Hartman  * We received a transmit interrupt without a pending X-char but with
668ab4382d2SGreg Kroah-Hartman  * pending characters.
669ab4382d2SGreg Kroah-Hartman  * Locking: called with port lock held and IRQs disabled.
670ab4382d2SGreg Kroah-Hartman  * Returns:
671ab4382d2SGreg Kroah-Hartman  *   false if we want to use PIO to transmit
672ab4382d2SGreg Kroah-Hartman  *   true if we queued a DMA buffer
673ab4382d2SGreg Kroah-Hartman  */
pl011_dma_tx_irq(struct uart_amba_port * uap)674ab4382d2SGreg Kroah-Hartman static bool pl011_dma_tx_irq(struct uart_amba_port *uap)
675ab4382d2SGreg Kroah-Hartman {
676ead76f32SLinus Walleij 	if (!uap->using_tx_dma)
677ab4382d2SGreg Kroah-Hartman 		return false;
678ab4382d2SGreg Kroah-Hartman 
679ab4382d2SGreg Kroah-Hartman 	/*
680ab4382d2SGreg Kroah-Hartman 	 * If we already have a TX buffer queued, but received a
681ab4382d2SGreg Kroah-Hartman 	 * TX interrupt, it will be because we've just sent an X-char.
682ab4382d2SGreg Kroah-Hartman 	 * Ensure the TX DMA is enabled and the TX IRQ is disabled.
683ab4382d2SGreg Kroah-Hartman 	 */
684ab4382d2SGreg Kroah-Hartman 	if (uap->dmatx.queued) {
685ab4382d2SGreg Kroah-Hartman 		uap->dmacr |= UART011_TXDMAE;
6869f25bc51SRussell King 		pl011_write(uap->dmacr, uap, REG_DMACR);
687ab4382d2SGreg Kroah-Hartman 		uap->im &= ~UART011_TXIM;
6889f25bc51SRussell King 		pl011_write(uap->im, uap, REG_IMSC);
689ab4382d2SGreg Kroah-Hartman 		return true;
690ab4382d2SGreg Kroah-Hartman 	}
691ab4382d2SGreg Kroah-Hartman 
692ab4382d2SGreg Kroah-Hartman 	/*
693ab4382d2SGreg Kroah-Hartman 	 * We don't have a TX buffer queued, so try to queue one.
69425985edcSLucas De Marchi 	 * If we successfully queued a buffer, mask the TX IRQ.
695ab4382d2SGreg Kroah-Hartman 	 */
696ab4382d2SGreg Kroah-Hartman 	if (pl011_dma_tx_refill(uap) > 0) {
697ab4382d2SGreg Kroah-Hartman 		uap->im &= ~UART011_TXIM;
6989f25bc51SRussell King 		pl011_write(uap->im, uap, REG_IMSC);
699ab4382d2SGreg Kroah-Hartman 		return true;
700ab4382d2SGreg Kroah-Hartman 	}
701ab4382d2SGreg Kroah-Hartman 	return false;
702ab4382d2SGreg Kroah-Hartman }
703ab4382d2SGreg Kroah-Hartman 
704ab4382d2SGreg Kroah-Hartman /*
705ab4382d2SGreg Kroah-Hartman  * Stop the DMA transmit (eg, due to received XOFF).
706ab4382d2SGreg Kroah-Hartman  * Locking: called with port lock held and IRQs disabled.
707ab4382d2SGreg Kroah-Hartman  */
pl011_dma_tx_stop(struct uart_amba_port * uap)708ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
709ab4382d2SGreg Kroah-Hartman {
710ab4382d2SGreg Kroah-Hartman 	if (uap->dmatx.queued) {
711ab4382d2SGreg Kroah-Hartman 		uap->dmacr &= ~UART011_TXDMAE;
7129f25bc51SRussell King 		pl011_write(uap->dmacr, uap, REG_DMACR);
713ab4382d2SGreg Kroah-Hartman 	}
714ab4382d2SGreg Kroah-Hartman }
715ab4382d2SGreg Kroah-Hartman 
716ab4382d2SGreg Kroah-Hartman /*
717ab4382d2SGreg Kroah-Hartman  * Try to start a DMA transmit, or in the case of an XON/OFF
718ab4382d2SGreg Kroah-Hartman  * character queued for send, try to get that character out ASAP.
719ab4382d2SGreg Kroah-Hartman  * Locking: called with port lock held and IRQs disabled.
720ab4382d2SGreg Kroah-Hartman  * Returns:
721ab4382d2SGreg Kroah-Hartman  *   false if we want the TX IRQ to be enabled
722ab4382d2SGreg Kroah-Hartman  *   true if we have a buffer queued
723ab4382d2SGreg Kroah-Hartman  */
pl011_dma_tx_start(struct uart_amba_port * uap)724ab4382d2SGreg Kroah-Hartman static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
725ab4382d2SGreg Kroah-Hartman {
726ab4382d2SGreg Kroah-Hartman 	u16 dmacr;
727ab4382d2SGreg Kroah-Hartman 
728ead76f32SLinus Walleij 	if (!uap->using_tx_dma)
729ab4382d2SGreg Kroah-Hartman 		return false;
730ab4382d2SGreg Kroah-Hartman 
731ab4382d2SGreg Kroah-Hartman 	if (!uap->port.x_char) {
732ab4382d2SGreg Kroah-Hartman 		/* no X-char, try to push chars out in DMA mode */
733ab4382d2SGreg Kroah-Hartman 		bool ret = true;
734ab4382d2SGreg Kroah-Hartman 
735ab4382d2SGreg Kroah-Hartman 		if (!uap->dmatx.queued) {
736ab4382d2SGreg Kroah-Hartman 			if (pl011_dma_tx_refill(uap) > 0) {
737ab4382d2SGreg Kroah-Hartman 				uap->im &= ~UART011_TXIM;
7389f25bc51SRussell King 				pl011_write(uap->im, uap, REG_IMSC);
73928a7ec8cSThéo Lebrun 			} else {
740ab4382d2SGreg Kroah-Hartman 				ret = false;
74128a7ec8cSThéo Lebrun 			}
742ab4382d2SGreg Kroah-Hartman 		} else if (!(uap->dmacr & UART011_TXDMAE)) {
743ab4382d2SGreg Kroah-Hartman 			uap->dmacr |= UART011_TXDMAE;
7449f25bc51SRussell King 			pl011_write(uap->dmacr, uap, REG_DMACR);
745ab4382d2SGreg Kroah-Hartman 		}
746ab4382d2SGreg Kroah-Hartman 		return ret;
747ab4382d2SGreg Kroah-Hartman 	}
748ab4382d2SGreg Kroah-Hartman 
749ab4382d2SGreg Kroah-Hartman 	/*
750ab4382d2SGreg Kroah-Hartman 	 * We have an X-char to send.  Disable DMA to prevent it loading
751ab4382d2SGreg Kroah-Hartman 	 * the TX fifo, and then see if we can stuff it into the FIFO.
752ab4382d2SGreg Kroah-Hartman 	 */
753ab4382d2SGreg Kroah-Hartman 	dmacr = uap->dmacr;
754ab4382d2SGreg Kroah-Hartman 	uap->dmacr &= ~UART011_TXDMAE;
7559f25bc51SRussell King 	pl011_write(uap->dmacr, uap, REG_DMACR);
756ab4382d2SGreg Kroah-Hartman 
7579f25bc51SRussell King 	if (pl011_read(uap, REG_FR) & UART01x_FR_TXFF) {
758ab4382d2SGreg Kroah-Hartman 		/*
759ab4382d2SGreg Kroah-Hartman 		 * No space in the FIFO, so enable the transmit interrupt
760ab4382d2SGreg Kroah-Hartman 		 * so we know when there is space.  Note that once we've
761ab4382d2SGreg Kroah-Hartman 		 * loaded the character, we should just re-enable DMA.
762ab4382d2SGreg Kroah-Hartman 		 */
763ab4382d2SGreg Kroah-Hartman 		return false;
764ab4382d2SGreg Kroah-Hartman 	}
765ab4382d2SGreg Kroah-Hartman 
7669f25bc51SRussell King 	pl011_write(uap->port.x_char, uap, REG_DR);
767ab4382d2SGreg Kroah-Hartman 	uap->port.icount.tx++;
768ab4382d2SGreg Kroah-Hartman 	uap->port.x_char = 0;
769ab4382d2SGreg Kroah-Hartman 
770ab4382d2SGreg Kroah-Hartman 	/* Success - restore the DMA state */
771ab4382d2SGreg Kroah-Hartman 	uap->dmacr = dmacr;
7729f25bc51SRussell King 	pl011_write(dmacr, uap, REG_DMACR);
773ab4382d2SGreg Kroah-Hartman 
774ab4382d2SGreg Kroah-Hartman 	return true;
775ab4382d2SGreg Kroah-Hartman }
776ab4382d2SGreg Kroah-Hartman 
777ab4382d2SGreg Kroah-Hartman /*
778ab4382d2SGreg Kroah-Hartman  * Flush the transmit buffer.
779ab4382d2SGreg Kroah-Hartman  * Locking: called with port lock held and IRQs disabled.
780ab4382d2SGreg Kroah-Hartman  */
pl011_dma_flush_buffer(struct uart_port * port)781ab4382d2SGreg Kroah-Hartman static void pl011_dma_flush_buffer(struct uart_port *port)
782b83286bfSFabio Estevam __releases(&uap->port.lock)
783b83286bfSFabio Estevam __acquires(&uap->port.lock)
784ab4382d2SGreg Kroah-Hartman {
785a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
786a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
787ab4382d2SGreg Kroah-Hartman 
788ead76f32SLinus Walleij 	if (!uap->using_tx_dma)
789ab4382d2SGreg Kroah-Hartman 		return;
790ab4382d2SGreg Kroah-Hartman 
791f6a19647SVincent Whitchurch 	dmaengine_terminate_async(uap->dmatx.chan);
792f6a19647SVincent Whitchurch 
793ab4382d2SGreg Kroah-Hartman 	if (uap->dmatx.queued) {
79458ac1b37SArnd Bergmann 		dma_unmap_single(uap->dmatx.chan->device->dev, uap->dmatx.dma,
79558ac1b37SArnd Bergmann 				 uap->dmatx.len, DMA_TO_DEVICE);
796ab4382d2SGreg Kroah-Hartman 		uap->dmatx.queued = false;
797ab4382d2SGreg Kroah-Hartman 		uap->dmacr &= ~UART011_TXDMAE;
7989f25bc51SRussell King 		pl011_write(uap->dmacr, uap, REG_DMACR);
799ab4382d2SGreg Kroah-Hartman 	}
800ab4382d2SGreg Kroah-Hartman }
801ab4382d2SGreg Kroah-Hartman 
802ead76f32SLinus Walleij static void pl011_dma_rx_callback(void *data);
803ead76f32SLinus Walleij 
pl011_dma_rx_trigger_dma(struct uart_amba_port * uap)804ead76f32SLinus Walleij static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
805ead76f32SLinus Walleij {
806ead76f32SLinus Walleij 	struct dma_chan *rxchan = uap->dmarx.chan;
807ead76f32SLinus Walleij 	struct pl011_dmarx_data *dmarx = &uap->dmarx;
808ead76f32SLinus Walleij 	struct dma_async_tx_descriptor *desc;
80958ac1b37SArnd Bergmann 	struct pl011_dmabuf *dbuf;
810ead76f32SLinus Walleij 
811ead76f32SLinus Walleij 	if (!rxchan)
812ead76f32SLinus Walleij 		return -EIO;
813ead76f32SLinus Walleij 
814ead76f32SLinus Walleij 	/* Start the RX DMA job */
81558ac1b37SArnd Bergmann 	dbuf = uap->dmarx.use_buf_b ?
81658ac1b37SArnd Bergmann 		&uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
81758ac1b37SArnd Bergmann 	desc = dmaengine_prep_slave_single(rxchan, dbuf->dma, dbuf->len,
818a485df4bSVinod Koul 					   DMA_DEV_TO_MEM,
819ead76f32SLinus Walleij 					   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
820ead76f32SLinus Walleij 	/*
821ead76f32SLinus Walleij 	 * If the DMA engine is busy and cannot prepare a
822ead76f32SLinus Walleij 	 * channel, no big deal, the driver will fall back
823ead76f32SLinus Walleij 	 * to interrupt mode as a result of this error code.
824ead76f32SLinus Walleij 	 */
825ead76f32SLinus Walleij 	if (!desc) {
826ead76f32SLinus Walleij 		uap->dmarx.running = false;
827ead76f32SLinus Walleij 		dmaengine_terminate_all(rxchan);
828ead76f32SLinus Walleij 		return -EBUSY;
829ead76f32SLinus Walleij 	}
830ead76f32SLinus Walleij 
831ead76f32SLinus Walleij 	/* Some data to go along to the callback */
832ead76f32SLinus Walleij 	desc->callback = pl011_dma_rx_callback;
833ead76f32SLinus Walleij 	desc->callback_param = uap;
834ead76f32SLinus Walleij 	dmarx->cookie = dmaengine_submit(desc);
835ead76f32SLinus Walleij 	dma_async_issue_pending(rxchan);
836ead76f32SLinus Walleij 
837ead76f32SLinus Walleij 	uap->dmacr |= UART011_RXDMAE;
8389f25bc51SRussell King 	pl011_write(uap->dmacr, uap, REG_DMACR);
839ead76f32SLinus Walleij 	uap->dmarx.running = true;
840ead76f32SLinus Walleij 
841ead76f32SLinus Walleij 	uap->im &= ~UART011_RXIM;
8429f25bc51SRussell King 	pl011_write(uap->im, uap, REG_IMSC);
843ead76f32SLinus Walleij 
844ead76f32SLinus Walleij 	return 0;
845ead76f32SLinus Walleij }
846ead76f32SLinus Walleij 
847ead76f32SLinus Walleij /*
848ead76f32SLinus Walleij  * This is called when either the DMA job is complete, or
849ead76f32SLinus Walleij  * the FIFO timeout interrupt occurred. This must be called
850ead76f32SLinus Walleij  * with the port spinlock uap->port.lock held.
851ead76f32SLinus Walleij  */
pl011_dma_rx_chars(struct uart_amba_port * uap,u32 pending,bool use_buf_b,bool readfifo)852ead76f32SLinus Walleij static void pl011_dma_rx_chars(struct uart_amba_port *uap,
853ead76f32SLinus Walleij 			       u32 pending, bool use_buf_b,
854ead76f32SLinus Walleij 			       bool readfifo)
855ead76f32SLinus Walleij {
85605c7cd39SJiri Slaby 	struct tty_port *port = &uap->port.state->port;
85758ac1b37SArnd Bergmann 	struct pl011_dmabuf *dbuf = use_buf_b ?
85858ac1b37SArnd Bergmann 		&uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
859ead76f32SLinus Walleij 	int dma_count = 0;
860ead76f32SLinus Walleij 	u32 fifotaken = 0; /* only used for vdbg() */
861ead76f32SLinus Walleij 
862cb06ff10SChanho Min 	struct pl011_dmarx_data *dmarx = &uap->dmarx;
863cb06ff10SChanho Min 	int dmataken = 0;
864cb06ff10SChanho Min 
865cb06ff10SChanho Min 	if (uap->dmarx.poll_rate) {
866cb06ff10SChanho Min 		/* The data can be taken by polling */
86758ac1b37SArnd Bergmann 		dmataken = dbuf->len - dmarx->last_residue;
868cb06ff10SChanho Min 		/* Recalculate the pending size */
869cb06ff10SChanho Min 		if (pending >= dmataken)
870cb06ff10SChanho Min 			pending -= dmataken;
871cb06ff10SChanho Min 	}
872cb06ff10SChanho Min 
873cb06ff10SChanho Min 	/* Pick the remain data from the DMA */
874ead76f32SLinus Walleij 	if (pending) {
875ead76f32SLinus Walleij 		/*
876ead76f32SLinus Walleij 		 * First take all chars in the DMA pipe, then look in the FIFO.
877ead76f32SLinus Walleij 		 * Note that tty_insert_flip_buf() tries to take as many chars
878ead76f32SLinus Walleij 		 * as it can.
879ead76f32SLinus Walleij 		 */
880d93ebe0fSThéo Lebrun 		dma_count = tty_insert_flip_string(port, dbuf->buf + dmataken, pending);
881ead76f32SLinus Walleij 
882ead76f32SLinus Walleij 		uap->port.icount.rx += dma_count;
883ead76f32SLinus Walleij 		if (dma_count < pending)
884ead76f32SLinus Walleij 			dev_warn(uap->port.dev,
885ead76f32SLinus Walleij 				 "couldn't insert all characters (TTY is full?)\n");
886ead76f32SLinus Walleij 	}
887ead76f32SLinus Walleij 
888cb06ff10SChanho Min 	/* Reset the last_residue for Rx DMA poll */
889cb06ff10SChanho Min 	if (uap->dmarx.poll_rate)
89058ac1b37SArnd Bergmann 		dmarx->last_residue = dbuf->len;
891cb06ff10SChanho Min 
892ead76f32SLinus Walleij 	/*
893ead76f32SLinus Walleij 	 * Only continue with trying to read the FIFO if all DMA chars have
894ead76f32SLinus Walleij 	 * been taken first.
895ead76f32SLinus Walleij 	 */
896ead76f32SLinus Walleij 	if (dma_count == pending && readfifo) {
897ead76f32SLinus Walleij 		/* Clear any error flags */
89875836339SRussell King 		pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS |
8999f25bc51SRussell King 			    UART011_FEIS, uap, REG_ICR);
900ead76f32SLinus Walleij 
901ead76f32SLinus Walleij 		/*
902ead76f32SLinus Walleij 		 * If we read all the DMA'd characters, and we had an
90329772c4eSLinus Walleij 		 * incomplete buffer, that could be due to an rx error, or
90429772c4eSLinus Walleij 		 * maybe we just timed out. Read any pending chars and check
90529772c4eSLinus Walleij 		 * the error status.
90629772c4eSLinus Walleij 		 *
90729772c4eSLinus Walleij 		 * Error conditions will only occur in the FIFO, these will
90829772c4eSLinus Walleij 		 * trigger an immediate interrupt and stop the DMA job, so we
90929772c4eSLinus Walleij 		 * will always find the error in the FIFO, never in the DMA
91029772c4eSLinus Walleij 		 * buffer.
911ead76f32SLinus Walleij 		 */
91229772c4eSLinus Walleij 		fifotaken = pl011_fifo_to_tty(uap);
913ead76f32SLinus Walleij 	}
914ead76f32SLinus Walleij 
915ead76f32SLinus Walleij 	dev_vdbg(uap->port.dev,
916ead76f32SLinus Walleij 		 "Took %d chars from DMA buffer and %d chars from the FIFO\n",
917ead76f32SLinus Walleij 		 dma_count, fifotaken);
9182e124b4aSJiri Slaby 	tty_flip_buffer_push(port);
919ead76f32SLinus Walleij }
920ead76f32SLinus Walleij 
pl011_dma_rx_irq(struct uart_amba_port * uap)921ead76f32SLinus Walleij static void pl011_dma_rx_irq(struct uart_amba_port *uap)
922ead76f32SLinus Walleij {
923ead76f32SLinus Walleij 	struct pl011_dmarx_data *dmarx = &uap->dmarx;
924ead76f32SLinus Walleij 	struct dma_chan *rxchan = dmarx->chan;
92558ac1b37SArnd Bergmann 	struct pl011_dmabuf *dbuf = dmarx->use_buf_b ?
92658ac1b37SArnd Bergmann 		&dmarx->dbuf_b : &dmarx->dbuf_a;
927ead76f32SLinus Walleij 	size_t pending;
928ead76f32SLinus Walleij 	struct dma_tx_state state;
929ead76f32SLinus Walleij 	enum dma_status dmastat;
930ead76f32SLinus Walleij 
931ead76f32SLinus Walleij 	/*
932ead76f32SLinus Walleij 	 * Pause the transfer so we can trust the current counter,
933ead76f32SLinus Walleij 	 * do this before we pause the PL011 block, else we may
934ead76f32SLinus Walleij 	 * overflow the FIFO.
935ead76f32SLinus Walleij 	 */
936ead76f32SLinus Walleij 	if (dmaengine_pause(rxchan))
937ead76f32SLinus Walleij 		dev_err(uap->port.dev, "unable to pause DMA transfer\n");
938ead76f32SLinus Walleij 	dmastat = rxchan->device->device_tx_status(rxchan,
939ead76f32SLinus Walleij 						   dmarx->cookie, &state);
940ead76f32SLinus Walleij 	if (dmastat != DMA_PAUSED)
941ead76f32SLinus Walleij 		dev_err(uap->port.dev, "unable to pause DMA transfer\n");
942ead76f32SLinus Walleij 
943ead76f32SLinus Walleij 	/* Disable RX DMA - incoming data will wait in the FIFO */
944ead76f32SLinus Walleij 	uap->dmacr &= ~UART011_RXDMAE;
9459f25bc51SRussell King 	pl011_write(uap->dmacr, uap, REG_DMACR);
946ead76f32SLinus Walleij 	uap->dmarx.running = false;
947ead76f32SLinus Walleij 
94858ac1b37SArnd Bergmann 	pending = dbuf->len - state.residue;
949ead76f32SLinus Walleij 	BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
950ead76f32SLinus Walleij 	/* Then we terminate the transfer - we now know our residue */
951ead76f32SLinus Walleij 	dmaengine_terminate_all(rxchan);
952ead76f32SLinus Walleij 
953ead76f32SLinus Walleij 	/*
954ead76f32SLinus Walleij 	 * This will take the chars we have so far and insert
955ead76f32SLinus Walleij 	 * into the framework.
956ead76f32SLinus Walleij 	 */
957ead76f32SLinus Walleij 	pl011_dma_rx_chars(uap, pending, dmarx->use_buf_b, true);
958ead76f32SLinus Walleij 
959ead76f32SLinus Walleij 	/* Switch buffer & re-trigger DMA job */
960ead76f32SLinus Walleij 	dmarx->use_buf_b = !dmarx->use_buf_b;
961ead76f32SLinus Walleij 	if (pl011_dma_rx_trigger_dma(uap)) {
962fd64ff09SThéo Lebrun 		dev_dbg(uap->port.dev,
963fd64ff09SThéo Lebrun 			"could not retrigger RX DMA job fall back to interrupt mode\n");
964ead76f32SLinus Walleij 		uap->im |= UART011_RXIM;
9659f25bc51SRussell King 		pl011_write(uap->im, uap, REG_IMSC);
966ead76f32SLinus Walleij 	}
967ead76f32SLinus Walleij }
968ead76f32SLinus Walleij 
pl011_dma_rx_callback(void * data)969ead76f32SLinus Walleij static void pl011_dma_rx_callback(void *data)
970ead76f32SLinus Walleij {
971ead76f32SLinus Walleij 	struct uart_amba_port *uap = data;
972ead76f32SLinus Walleij 	struct pl011_dmarx_data *dmarx = &uap->dmarx;
9736dc01aa6SChanho Min 	struct dma_chan *rxchan = dmarx->chan;
974ead76f32SLinus Walleij 	bool lastbuf = dmarx->use_buf_b;
97558ac1b37SArnd Bergmann 	struct pl011_dmabuf *dbuf = dmarx->use_buf_b ?
97658ac1b37SArnd Bergmann 		&dmarx->dbuf_b : &dmarx->dbuf_a;
9776dc01aa6SChanho Min 	size_t pending;
9786dc01aa6SChanho Min 	struct dma_tx_state state;
979ead76f32SLinus Walleij 	int ret;
980ead76f32SLinus Walleij 
981ead76f32SLinus Walleij 	/*
982ead76f32SLinus Walleij 	 * This completion interrupt occurs typically when the
983ead76f32SLinus Walleij 	 * RX buffer is totally stuffed but no timeout has yet
984ead76f32SLinus Walleij 	 * occurred. When that happens, we just want the RX
985ead76f32SLinus Walleij 	 * routine to flush out the secondary DMA buffer while
986ead76f32SLinus Walleij 	 * we immediately trigger the next DMA job.
987ead76f32SLinus Walleij 	 */
98868ca3e72SThomas Gleixner 	uart_port_lock_irq(&uap->port);
9896dc01aa6SChanho Min 	/*
9906dc01aa6SChanho Min 	 * Rx data can be taken by the UART interrupts during
9916dc01aa6SChanho Min 	 * the DMA irq handler. So we check the residue here.
9926dc01aa6SChanho Min 	 */
9936dc01aa6SChanho Min 	rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
99458ac1b37SArnd Bergmann 	pending = dbuf->len - state.residue;
9956dc01aa6SChanho Min 	BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
9966dc01aa6SChanho Min 	/* Then we terminate the transfer - we now know our residue */
9976dc01aa6SChanho Min 	dmaengine_terminate_all(rxchan);
9986dc01aa6SChanho Min 
999ead76f32SLinus Walleij 	uap->dmarx.running = false;
1000ead76f32SLinus Walleij 	dmarx->use_buf_b = !lastbuf;
1001ead76f32SLinus Walleij 	ret = pl011_dma_rx_trigger_dma(uap);
1002ead76f32SLinus Walleij 
10036dc01aa6SChanho Min 	pl011_dma_rx_chars(uap, pending, lastbuf, false);
10042432f71cSSebastian Andrzej Siewior 	uart_unlock_and_check_sysrq(&uap->port);
1005ead76f32SLinus Walleij 	/*
1006ead76f32SLinus Walleij 	 * Do this check after we picked the DMA chars so we don't
1007ead76f32SLinus Walleij 	 * get some IRQ immediately from RX.
1008ead76f32SLinus Walleij 	 */
1009ead76f32SLinus Walleij 	if (ret) {
1010fd64ff09SThéo Lebrun 		dev_dbg(uap->port.dev,
1011fd64ff09SThéo Lebrun 			"could not retrigger RX DMA job fall back to interrupt mode\n");
1012ead76f32SLinus Walleij 		uap->im |= UART011_RXIM;
10139f25bc51SRussell King 		pl011_write(uap->im, uap, REG_IMSC);
1014ead76f32SLinus Walleij 	}
1015ead76f32SLinus Walleij }
1016ead76f32SLinus Walleij 
1017ead76f32SLinus Walleij /*
1018ead76f32SLinus Walleij  * Stop accepting received characters, when we're shutting down or
1019ead76f32SLinus Walleij  * suspending this port.
1020ead76f32SLinus Walleij  * Locking: called with port lock held and IRQs disabled.
1021ead76f32SLinus Walleij  */
pl011_dma_rx_stop(struct uart_amba_port * uap)1022ead76f32SLinus Walleij static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
1023ead76f32SLinus Walleij {
102494cdb9f3SJiamei Xie 	if (!uap->using_rx_dma)
102594cdb9f3SJiamei Xie 		return;
102694cdb9f3SJiamei Xie 
1027ead76f32SLinus Walleij 	/* FIXME.  Just disable the DMA enable */
1028ead76f32SLinus Walleij 	uap->dmacr &= ~UART011_RXDMAE;
10299f25bc51SRussell King 	pl011_write(uap->dmacr, uap, REG_DMACR);
1030ead76f32SLinus Walleij }
1031ab4382d2SGreg Kroah-Hartman 
1032cb06ff10SChanho Min /*
1033cb06ff10SChanho Min  * Timer handler for Rx DMA polling.
1034cb06ff10SChanho Min  * Every polling, It checks the residue in the dma buffer and transfer
1035cb06ff10SChanho Min  * data to the tty. Also, last_residue is updated for the next polling.
1036cb06ff10SChanho Min  */
pl011_dma_rx_poll(struct timer_list * t)1037f7f73096SKees Cook static void pl011_dma_rx_poll(struct timer_list *t)
1038cb06ff10SChanho Min {
1039f7f73096SKees Cook 	struct uart_amba_port *uap = from_timer(uap, t, dmarx.timer);
1040cb06ff10SChanho Min 	struct tty_port *port = &uap->port.state->port;
1041cb06ff10SChanho Min 	struct pl011_dmarx_data *dmarx = &uap->dmarx;
1042cb06ff10SChanho Min 	struct dma_chan *rxchan = uap->dmarx.chan;
104318ee37e1SJohan Hovold 	unsigned long flags;
1044cb06ff10SChanho Min 	unsigned int dmataken = 0;
1045cb06ff10SChanho Min 	unsigned int size = 0;
104658ac1b37SArnd Bergmann 	struct pl011_dmabuf *dbuf;
1047cb06ff10SChanho Min 	int dma_count;
1048cb06ff10SChanho Min 	struct dma_tx_state state;
1049cb06ff10SChanho Min 
105058ac1b37SArnd Bergmann 	dbuf = dmarx->use_buf_b ? &uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
1051cb06ff10SChanho Min 	rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
1052cb06ff10SChanho Min 	if (likely(state.residue < dmarx->last_residue)) {
105358ac1b37SArnd Bergmann 		dmataken = dbuf->len - dmarx->last_residue;
1054cb06ff10SChanho Min 		size = dmarx->last_residue - state.residue;
105558ac1b37SArnd Bergmann 		dma_count = tty_insert_flip_string(port, dbuf->buf + dmataken,
1056cb06ff10SChanho Min 						   size);
1057cb06ff10SChanho Min 		if (dma_count == size)
1058cb06ff10SChanho Min 			dmarx->last_residue =  state.residue;
1059cb06ff10SChanho Min 		dmarx->last_jiffies = jiffies;
1060cb06ff10SChanho Min 	}
1061cb06ff10SChanho Min 	tty_flip_buffer_push(port);
1062cb06ff10SChanho Min 
1063cb06ff10SChanho Min 	/*
1064cb06ff10SChanho Min 	 * If no data is received in poll_timeout, the driver will fall back
1065cb06ff10SChanho Min 	 * to interrupt mode. We will retrigger DMA at the first interrupt.
1066cb06ff10SChanho Min 	 */
1067cb06ff10SChanho Min 	if (jiffies_to_msecs(jiffies - dmarx->last_jiffies)
1068cb06ff10SChanho Min 			> uap->dmarx.poll_timeout) {
106968ca3e72SThomas Gleixner 		uart_port_lock_irqsave(&uap->port, &flags);
1070cb06ff10SChanho Min 		pl011_dma_rx_stop(uap);
1071c25a1ad7SGuennadi Liakhovetski 		uap->im |= UART011_RXIM;
10729f25bc51SRussell King 		pl011_write(uap->im, uap, REG_IMSC);
107368ca3e72SThomas Gleixner 		uart_port_unlock_irqrestore(&uap->port, flags);
1074cb06ff10SChanho Min 
1075cb06ff10SChanho Min 		uap->dmarx.running = false;
1076cb06ff10SChanho Min 		dmaengine_terminate_all(rxchan);
1077cb06ff10SChanho Min 		del_timer(&uap->dmarx.timer);
1078cb06ff10SChanho Min 	} else {
1079cb06ff10SChanho Min 		mod_timer(&uap->dmarx.timer,
1080cb06ff10SChanho Min 			  jiffies + msecs_to_jiffies(uap->dmarx.poll_rate));
1081cb06ff10SChanho Min 	}
1082cb06ff10SChanho Min }
1083cb06ff10SChanho Min 
pl011_dma_startup(struct uart_amba_port * uap)1084ab4382d2SGreg Kroah-Hartman static void pl011_dma_startup(struct uart_amba_port *uap)
1085ab4382d2SGreg Kroah-Hartman {
1086ead76f32SLinus Walleij 	int ret;
1087ead76f32SLinus Walleij 
10881c9be310SJorge Ramirez-Ortiz 	if (!uap->dma_probed)
10891c9be310SJorge Ramirez-Ortiz 		pl011_dma_probe(uap);
10901c9be310SJorge Ramirez-Ortiz 
1091ab4382d2SGreg Kroah-Hartman 	if (!uap->dmatx.chan)
1092ab4382d2SGreg Kroah-Hartman 		return;
1093ab4382d2SGreg Kroah-Hartman 
10944c0be45bSAndrew Jackson 	uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL | __GFP_DMA);
1095ab4382d2SGreg Kroah-Hartman 	if (!uap->dmatx.buf) {
1096ab4382d2SGreg Kroah-Hartman 		uap->port.fifosize = uap->fifosize;
1097ab4382d2SGreg Kroah-Hartman 		return;
1098ab4382d2SGreg Kroah-Hartman 	}
1099ab4382d2SGreg Kroah-Hartman 
110058ac1b37SArnd Bergmann 	uap->dmatx.len = PL011_DMA_BUFFER_SIZE;
1101ab4382d2SGreg Kroah-Hartman 
1102ab4382d2SGreg Kroah-Hartman 	/* The DMA buffer is now the FIFO the TTY subsystem can use */
1103ab4382d2SGreg Kroah-Hartman 	uap->port.fifosize = PL011_DMA_BUFFER_SIZE;
1104ead76f32SLinus Walleij 	uap->using_tx_dma = true;
1105ab4382d2SGreg Kroah-Hartman 
1106ead76f32SLinus Walleij 	if (!uap->dmarx.chan)
1107ead76f32SLinus Walleij 		goto skip_rx;
1108ead76f32SLinus Walleij 
1109ead76f32SLinus Walleij 	/* Allocate and map DMA RX buffers */
111058ac1b37SArnd Bergmann 	ret = pl011_dmabuf_init(uap->dmarx.chan, &uap->dmarx.dbuf_a,
1111ead76f32SLinus Walleij 				DMA_FROM_DEVICE);
1112ead76f32SLinus Walleij 	if (ret) {
1113ead76f32SLinus Walleij 		dev_err(uap->port.dev, "failed to init DMA %s: %d\n",
1114ead76f32SLinus Walleij 			"RX buffer A", ret);
1115ead76f32SLinus Walleij 		goto skip_rx;
1116ead76f32SLinus Walleij 	}
1117ead76f32SLinus Walleij 
111858ac1b37SArnd Bergmann 	ret = pl011_dmabuf_init(uap->dmarx.chan, &uap->dmarx.dbuf_b,
1119ead76f32SLinus Walleij 				DMA_FROM_DEVICE);
1120ead76f32SLinus Walleij 	if (ret) {
1121ead76f32SLinus Walleij 		dev_err(uap->port.dev, "failed to init DMA %s: %d\n",
1122ead76f32SLinus Walleij 			"RX buffer B", ret);
112358ac1b37SArnd Bergmann 		pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a,
1124ead76f32SLinus Walleij 				  DMA_FROM_DEVICE);
1125ead76f32SLinus Walleij 		goto skip_rx;
1126ead76f32SLinus Walleij 	}
1127ead76f32SLinus Walleij 
1128ead76f32SLinus Walleij 	uap->using_rx_dma = true;
1129ead76f32SLinus Walleij 
1130ead76f32SLinus Walleij skip_rx:
1131ab4382d2SGreg Kroah-Hartman 	/* Turn on DMA error (RX/TX will be enabled on demand) */
1132ab4382d2SGreg Kroah-Hartman 	uap->dmacr |= UART011_DMAONERR;
11339f25bc51SRussell King 	pl011_write(uap->dmacr, uap, REG_DMACR);
1134ab4382d2SGreg Kroah-Hartman 
1135ab4382d2SGreg Kroah-Hartman 	/*
1136ab4382d2SGreg Kroah-Hartman 	 * ST Micro variants has some specific dma burst threshold
1137ab4382d2SGreg Kroah-Hartman 	 * compensation. Set this to 16 bytes, so burst will only
1138ab4382d2SGreg Kroah-Hartman 	 * be issued above/below 16 bytes.
1139ab4382d2SGreg Kroah-Hartman 	 */
1140ab4382d2SGreg Kroah-Hartman 	if (uap->vendor->dma_threshold)
114175836339SRussell King 		pl011_write(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16,
11429f25bc51SRussell King 			    uap, REG_ST_DMAWM);
1143ead76f32SLinus Walleij 
1144ead76f32SLinus Walleij 	if (uap->using_rx_dma) {
1145ead76f32SLinus Walleij 		if (pl011_dma_rx_trigger_dma(uap))
1146fd64ff09SThéo Lebrun 			dev_dbg(uap->port.dev,
1147fd64ff09SThéo Lebrun 				"could not trigger initial RX DMA job, fall back to interrupt mode\n");
1148cb06ff10SChanho Min 		if (uap->dmarx.poll_rate) {
1149f7f73096SKees Cook 			timer_setup(&uap->dmarx.timer, pl011_dma_rx_poll, 0);
1150cb06ff10SChanho Min 			mod_timer(&uap->dmarx.timer,
1151d93ebe0fSThéo Lebrun 				  jiffies + msecs_to_jiffies(uap->dmarx.poll_rate));
1152cb06ff10SChanho Min 			uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE;
1153cb06ff10SChanho Min 			uap->dmarx.last_jiffies = jiffies;
1154cb06ff10SChanho Min 		}
1155ead76f32SLinus Walleij 	}
1156ab4382d2SGreg Kroah-Hartman }
1157ab4382d2SGreg Kroah-Hartman 
pl011_dma_shutdown(struct uart_amba_port * uap)1158ab4382d2SGreg Kroah-Hartman static void pl011_dma_shutdown(struct uart_amba_port *uap)
1159ab4382d2SGreg Kroah-Hartman {
1160ead76f32SLinus Walleij 	if (!(uap->using_tx_dma || uap->using_rx_dma))
1161ab4382d2SGreg Kroah-Hartman 		return;
1162ab4382d2SGreg Kroah-Hartman 
1163ab4382d2SGreg Kroah-Hartman 	/* Disable RX and TX DMA */
11640e125a5fSShawn Guo 	while (pl011_read(uap, REG_FR) & uap->vendor->fr_busy)
11652f2fd089STimur Tabi 		cpu_relax();
1166ab4382d2SGreg Kroah-Hartman 
116768ca3e72SThomas Gleixner 	uart_port_lock_irq(&uap->port);
1168ab4382d2SGreg Kroah-Hartman 	uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
11699f25bc51SRussell King 	pl011_write(uap->dmacr, uap, REG_DMACR);
117068ca3e72SThomas Gleixner 	uart_port_unlock_irq(&uap->port);
1171ab4382d2SGreg Kroah-Hartman 
1172ead76f32SLinus Walleij 	if (uap->using_tx_dma) {
1173ab4382d2SGreg Kroah-Hartman 		/* In theory, this should already be done by pl011_dma_flush_buffer */
1174ab4382d2SGreg Kroah-Hartman 		dmaengine_terminate_all(uap->dmatx.chan);
1175ab4382d2SGreg Kroah-Hartman 		if (uap->dmatx.queued) {
117658ac1b37SArnd Bergmann 			dma_unmap_single(uap->dmatx.chan->device->dev,
117758ac1b37SArnd Bergmann 					 uap->dmatx.dma, uap->dmatx.len,
1178ab4382d2SGreg Kroah-Hartman 					 DMA_TO_DEVICE);
1179ab4382d2SGreg Kroah-Hartman 			uap->dmatx.queued = false;
1180ab4382d2SGreg Kroah-Hartman 		}
1181ab4382d2SGreg Kroah-Hartman 
1182ab4382d2SGreg Kroah-Hartman 		kfree(uap->dmatx.buf);
1183ead76f32SLinus Walleij 		uap->using_tx_dma = false;
1184ab4382d2SGreg Kroah-Hartman 	}
1185ab4382d2SGreg Kroah-Hartman 
1186ead76f32SLinus Walleij 	if (uap->using_rx_dma) {
1187ead76f32SLinus Walleij 		dmaengine_terminate_all(uap->dmarx.chan);
1188ead76f32SLinus Walleij 		/* Clean up the RX DMA */
118958ac1b37SArnd Bergmann 		pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a, DMA_FROM_DEVICE);
119058ac1b37SArnd Bergmann 		pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_b, DMA_FROM_DEVICE);
1191cb06ff10SChanho Min 		if (uap->dmarx.poll_rate)
1192cb06ff10SChanho Min 			del_timer_sync(&uap->dmarx.timer);
1193ead76f32SLinus Walleij 		uap->using_rx_dma = false;
1194ead76f32SLinus Walleij 	}
1195ead76f32SLinus Walleij }
1196ead76f32SLinus Walleij 
pl011_dma_rx_available(struct uart_amba_port * uap)1197ead76f32SLinus Walleij static inline bool pl011_dma_rx_available(struct uart_amba_port *uap)
1198ead76f32SLinus Walleij {
1199ead76f32SLinus Walleij 	return uap->using_rx_dma;
1200ead76f32SLinus Walleij }
1201ead76f32SLinus Walleij 
pl011_dma_rx_running(struct uart_amba_port * uap)1202ead76f32SLinus Walleij static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
1203ead76f32SLinus Walleij {
1204ead76f32SLinus Walleij 	return uap->using_rx_dma && uap->dmarx.running;
1205ead76f32SLinus Walleij }
1206ead76f32SLinus Walleij 
1207ab4382d2SGreg Kroah-Hartman #else
1208ab4382d2SGreg Kroah-Hartman /* Blank functions if the DMA engine is not available */
pl011_dma_remove(struct uart_amba_port * uap)1209ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_remove(struct uart_amba_port *uap)
1210ab4382d2SGreg Kroah-Hartman {
1211ab4382d2SGreg Kroah-Hartman }
1212ab4382d2SGreg Kroah-Hartman 
pl011_dma_startup(struct uart_amba_port * uap)1213ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_startup(struct uart_amba_port *uap)
1214ab4382d2SGreg Kroah-Hartman {
1215ab4382d2SGreg Kroah-Hartman }
1216ab4382d2SGreg Kroah-Hartman 
pl011_dma_shutdown(struct uart_amba_port * uap)1217ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_shutdown(struct uart_amba_port *uap)
1218ab4382d2SGreg Kroah-Hartman {
1219ab4382d2SGreg Kroah-Hartman }
1220ab4382d2SGreg Kroah-Hartman 
pl011_dma_tx_irq(struct uart_amba_port * uap)1221ab4382d2SGreg Kroah-Hartman static inline bool pl011_dma_tx_irq(struct uart_amba_port *uap)
1222ab4382d2SGreg Kroah-Hartman {
1223ab4382d2SGreg Kroah-Hartman 	return false;
1224ab4382d2SGreg Kroah-Hartman }
1225ab4382d2SGreg Kroah-Hartman 
pl011_dma_tx_stop(struct uart_amba_port * uap)1226ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
1227ab4382d2SGreg Kroah-Hartman {
1228ab4382d2SGreg Kroah-Hartman }
1229ab4382d2SGreg Kroah-Hartman 
pl011_dma_tx_start(struct uart_amba_port * uap)1230ab4382d2SGreg Kroah-Hartman static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
1231ab4382d2SGreg Kroah-Hartman {
1232ab4382d2SGreg Kroah-Hartman 	return false;
1233ab4382d2SGreg Kroah-Hartman }
1234ab4382d2SGreg Kroah-Hartman 
pl011_dma_rx_irq(struct uart_amba_port * uap)1235ead76f32SLinus Walleij static inline void pl011_dma_rx_irq(struct uart_amba_port *uap)
1236ead76f32SLinus Walleij {
1237ead76f32SLinus Walleij }
1238ead76f32SLinus Walleij 
pl011_dma_rx_stop(struct uart_amba_port * uap)1239ead76f32SLinus Walleij static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
1240ead76f32SLinus Walleij {
1241ead76f32SLinus Walleij }
1242ead76f32SLinus Walleij 
pl011_dma_rx_trigger_dma(struct uart_amba_port * uap)1243ead76f32SLinus Walleij static inline int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
1244ead76f32SLinus Walleij {
1245ead76f32SLinus Walleij 	return -EIO;
1246ead76f32SLinus Walleij }
1247ead76f32SLinus Walleij 
pl011_dma_rx_available(struct uart_amba_port * uap)1248ead76f32SLinus Walleij static inline bool pl011_dma_rx_available(struct uart_amba_port *uap)
1249ead76f32SLinus Walleij {
1250ead76f32SLinus Walleij 	return false;
1251ead76f32SLinus Walleij }
1252ead76f32SLinus Walleij 
pl011_dma_rx_running(struct uart_amba_port * uap)1253ead76f32SLinus Walleij static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
1254ead76f32SLinus Walleij {
1255ead76f32SLinus Walleij 	return false;
1256ead76f32SLinus Walleij }
1257ead76f32SLinus Walleij 
1258ab4382d2SGreg Kroah-Hartman #define pl011_dma_flush_buffer	NULL
1259ab4382d2SGreg Kroah-Hartman #endif
1260ab4382d2SGreg Kroah-Hartman 
pl011_rs485_tx_stop(struct uart_amba_port * uap)12618d479237SLino Sanfilippo static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
12628d479237SLino Sanfilippo {
12630e4deb56SLino Sanfilippo 	/*
12640e4deb56SLino Sanfilippo 	 * To be on the safe side only time out after twice as many iterations
12650e4deb56SLino Sanfilippo 	 * as fifo size.
12660e4deb56SLino Sanfilippo 	 */
12670e4deb56SLino Sanfilippo 	const int MAX_TX_DRAIN_ITERS = uap->port.fifosize * 2;
12688d479237SLino Sanfilippo 	struct uart_port *port = &uap->port;
12698d479237SLino Sanfilippo 	int i = 0;
12708d479237SLino Sanfilippo 	u32 cr;
12718d479237SLino Sanfilippo 
12728d479237SLino Sanfilippo 	/* Wait until hardware tx queue is empty */
12738d479237SLino Sanfilippo 	while (!pl011_tx_empty(port)) {
12740e4deb56SLino Sanfilippo 		if (i > MAX_TX_DRAIN_ITERS) {
12758d479237SLino Sanfilippo 			dev_warn(port->dev,
12768d479237SLino Sanfilippo 				 "timeout while draining hardware tx queue\n");
12778d479237SLino Sanfilippo 			break;
12788d479237SLino Sanfilippo 		}
12798d479237SLino Sanfilippo 
12808d479237SLino Sanfilippo 		udelay(uap->rs485_tx_drain_interval);
12818d479237SLino Sanfilippo 		i++;
12828d479237SLino Sanfilippo 	}
12838d479237SLino Sanfilippo 
12848d479237SLino Sanfilippo 	if (port->rs485.delay_rts_after_send)
12858d479237SLino Sanfilippo 		mdelay(port->rs485.delay_rts_after_send);
12868d479237SLino Sanfilippo 
12878d479237SLino Sanfilippo 	cr = pl011_read(uap, REG_CR);
12888d479237SLino Sanfilippo 
12898d479237SLino Sanfilippo 	if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
12908d479237SLino Sanfilippo 		cr &= ~UART011_CR_RTS;
12918d479237SLino Sanfilippo 	else
12928d479237SLino Sanfilippo 		cr |= UART011_CR_RTS;
12938d479237SLino Sanfilippo 
12948d479237SLino Sanfilippo 	/* Disable the transmitter and reenable the transceiver */
12958d479237SLino Sanfilippo 	cr &= ~UART011_CR_TXE;
12968d479237SLino Sanfilippo 	cr |= UART011_CR_RXE;
12978d479237SLino Sanfilippo 	pl011_write(cr, uap, REG_CR);
12988d479237SLino Sanfilippo 
12998d479237SLino Sanfilippo 	uap->rs485_tx_started = false;
13008d479237SLino Sanfilippo }
13018d479237SLino Sanfilippo 
pl011_stop_tx(struct uart_port * port)1302ab4382d2SGreg Kroah-Hartman static void pl011_stop_tx(struct uart_port *port)
1303ab4382d2SGreg Kroah-Hartman {
1304a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1305a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1306ab4382d2SGreg Kroah-Hartman 
1307ab4382d2SGreg Kroah-Hartman 	uap->im &= ~UART011_TXIM;
13089f25bc51SRussell King 	pl011_write(uap->im, uap, REG_IMSC);
1309ab4382d2SGreg Kroah-Hartman 	pl011_dma_tx_stop(uap);
13108d479237SLino Sanfilippo 
13118d479237SLino Sanfilippo 	if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started)
13128d479237SLino Sanfilippo 		pl011_rs485_tx_stop(uap);
1313ab4382d2SGreg Kroah-Hartman }
1314ab4382d2SGreg Kroah-Hartman 
13157d05587cSJayachandran C static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq);
1316734745caSDave Martin 
1317734745caSDave Martin /* Start TX with programmed I/O only (no DMA) */
pl011_start_tx_pio(struct uart_amba_port * uap)1318734745caSDave Martin static void pl011_start_tx_pio(struct uart_amba_port *uap)
1319734745caSDave Martin {
13207d05587cSJayachandran C 	if (pl011_tx_chars(uap, false)) {
1321734745caSDave Martin 		uap->im |= UART011_TXIM;
13229f25bc51SRussell King 		pl011_write(uap->im, uap, REG_IMSC);
13237d05587cSJayachandran C 	}
1324734745caSDave Martin }
1325734745caSDave Martin 
pl011_rs485_tx_start(struct uart_amba_port * uap)13263b69e32eSLino Sanfilippo static void pl011_rs485_tx_start(struct uart_amba_port *uap)
13273b69e32eSLino Sanfilippo {
13283b69e32eSLino Sanfilippo 	struct uart_port *port = &uap->port;
13293b69e32eSLino Sanfilippo 	u32 cr;
13303b69e32eSLino Sanfilippo 
13313b69e32eSLino Sanfilippo 	/* Enable transmitter */
13323b69e32eSLino Sanfilippo 	cr = pl011_read(uap, REG_CR);
13333b69e32eSLino Sanfilippo 	cr |= UART011_CR_TXE;
13343b69e32eSLino Sanfilippo 
13353b69e32eSLino Sanfilippo 	/* Disable receiver if half-duplex */
13363b69e32eSLino Sanfilippo 	if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
13373b69e32eSLino Sanfilippo 		cr &= ~UART011_CR_RXE;
13383b69e32eSLino Sanfilippo 
13393b69e32eSLino Sanfilippo 	if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
13403b69e32eSLino Sanfilippo 		cr &= ~UART011_CR_RTS;
13413b69e32eSLino Sanfilippo 	else
13423b69e32eSLino Sanfilippo 		cr |= UART011_CR_RTS;
13433b69e32eSLino Sanfilippo 
13443b69e32eSLino Sanfilippo 	pl011_write(cr, uap, REG_CR);
13453b69e32eSLino Sanfilippo 
13463b69e32eSLino Sanfilippo 	if (port->rs485.delay_rts_before_send)
13473b69e32eSLino Sanfilippo 		mdelay(port->rs485.delay_rts_before_send);
13483b69e32eSLino Sanfilippo 
13493b69e32eSLino Sanfilippo 	uap->rs485_tx_started = true;
13503b69e32eSLino Sanfilippo }
13513b69e32eSLino Sanfilippo 
pl011_start_tx(struct uart_port * port)1352ab4382d2SGreg Kroah-Hartman static void pl011_start_tx(struct uart_port *port)
1353ab4382d2SGreg Kroah-Hartman {
1354a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1355a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1356ab4382d2SGreg Kroah-Hartman 
13573b69e32eSLino Sanfilippo 	if ((uap->port.rs485.flags & SER_RS485_ENABLED) &&
13583b69e32eSLino Sanfilippo 	    !uap->rs485_tx_started)
13593b69e32eSLino Sanfilippo 		pl011_rs485_tx_start(uap);
13603b69e32eSLino Sanfilippo 
1361734745caSDave Martin 	if (!pl011_dma_tx_start(uap))
1362734745caSDave Martin 		pl011_start_tx_pio(uap);
1363ab4382d2SGreg Kroah-Hartman }
1364ab4382d2SGreg Kroah-Hartman 
pl011_stop_rx(struct uart_port * port)1365ab4382d2SGreg Kroah-Hartman static void pl011_stop_rx(struct uart_port *port)
1366ab4382d2SGreg Kroah-Hartman {
1367a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1368a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1369ab4382d2SGreg Kroah-Hartman 
1370ab4382d2SGreg Kroah-Hartman 	uap->im &= ~(UART011_RXIM | UART011_RTIM | UART011_FEIM |
1371ab4382d2SGreg Kroah-Hartman 		     UART011_PEIM | UART011_BEIM | UART011_OEIM);
13729f25bc51SRussell King 	pl011_write(uap->im, uap, REG_IMSC);
1373ead76f32SLinus Walleij 
1374ead76f32SLinus Walleij 	pl011_dma_rx_stop(uap);
1375ab4382d2SGreg Kroah-Hartman }
1376ab4382d2SGreg Kroah-Hartman 
pl011_throttle_rx(struct uart_port * port)1377211565b1SIlpo Järvinen static void pl011_throttle_rx(struct uart_port *port)
1378211565b1SIlpo Järvinen {
1379211565b1SIlpo Järvinen 	unsigned long flags;
1380211565b1SIlpo Järvinen 
138168ca3e72SThomas Gleixner 	uart_port_lock_irqsave(port, &flags);
1382211565b1SIlpo Järvinen 	pl011_stop_rx(port);
138368ca3e72SThomas Gleixner 	uart_port_unlock_irqrestore(port, flags);
1384211565b1SIlpo Järvinen }
1385211565b1SIlpo Järvinen 
pl011_enable_ms(struct uart_port * port)1386ab4382d2SGreg Kroah-Hartman static void pl011_enable_ms(struct uart_port *port)
1387ab4382d2SGreg Kroah-Hartman {
1388a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1389a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1390ab4382d2SGreg Kroah-Hartman 
1391ab4382d2SGreg Kroah-Hartman 	uap->im |= UART011_RIMIM | UART011_CTSMIM | UART011_DCDMIM | UART011_DSRMIM;
13929f25bc51SRussell King 	pl011_write(uap->im, uap, REG_IMSC);
1393ab4382d2SGreg Kroah-Hartman }
1394ab4382d2SGreg Kroah-Hartman 
pl011_rx_chars(struct uart_amba_port * uap)1395ab4382d2SGreg Kroah-Hartman static void pl011_rx_chars(struct uart_amba_port *uap)
1396b83286bfSFabio Estevam __releases(&uap->port.lock)
1397b83286bfSFabio Estevam __acquires(&uap->port.lock)
1398ab4382d2SGreg Kroah-Hartman {
139929772c4eSLinus Walleij 	pl011_fifo_to_tty(uap);
1400ab4382d2SGreg Kroah-Hartman 
140168ca3e72SThomas Gleixner 	uart_port_unlock(&uap->port);
14022e124b4aSJiri Slaby 	tty_flip_buffer_push(&uap->port.state->port);
1403ead76f32SLinus Walleij 	/*
1404ead76f32SLinus Walleij 	 * If we were temporarily out of DMA mode for a while,
1405ead76f32SLinus Walleij 	 * attempt to switch back to DMA mode again.
1406ead76f32SLinus Walleij 	 */
1407ead76f32SLinus Walleij 	if (pl011_dma_rx_available(uap)) {
1408ead76f32SLinus Walleij 		if (pl011_dma_rx_trigger_dma(uap)) {
1409fd64ff09SThéo Lebrun 			dev_dbg(uap->port.dev,
1410fd64ff09SThéo Lebrun 				"could not trigger RX DMA job fall back to interrupt mode again\n");
1411ead76f32SLinus Walleij 			uap->im |= UART011_RXIM;
14129f25bc51SRussell King 			pl011_write(uap->im, uap, REG_IMSC);
1413cb06ff10SChanho Min 		} else {
141489fa28dbSChanho Min #ifdef CONFIG_DMA_ENGINE
1415cb06ff10SChanho Min 			/* Start Rx DMA poll */
1416cb06ff10SChanho Min 			if (uap->dmarx.poll_rate) {
1417cb06ff10SChanho Min 				uap->dmarx.last_jiffies = jiffies;
1418cb06ff10SChanho Min 				uap->dmarx.last_residue	= PL011_DMA_BUFFER_SIZE;
1419cb06ff10SChanho Min 				mod_timer(&uap->dmarx.timer,
1420d93ebe0fSThéo Lebrun 					  jiffies + msecs_to_jiffies(uap->dmarx.poll_rate));
1421cb06ff10SChanho Min 			}
142289fa28dbSChanho Min #endif
1423cb06ff10SChanho Min 		}
1424ead76f32SLinus Walleij 	}
142568ca3e72SThomas Gleixner 	uart_port_lock(&uap->port);
1426ab4382d2SGreg Kroah-Hartman }
1427ab4382d2SGreg Kroah-Hartman 
pl011_tx_char(struct uart_amba_port * uap,unsigned char c,bool from_irq)14281e84d223SDave Martin static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
14291e84d223SDave Martin 			  bool from_irq)
1430734745caSDave Martin {
14311e84d223SDave Martin 	if (unlikely(!from_irq) &&
14329f25bc51SRussell King 	    pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
14331e84d223SDave Martin 		return false; /* unable to transmit character */
14341e84d223SDave Martin 
14359f25bc51SRussell King 	pl011_write(c, uap, REG_DR);
1436734745caSDave Martin 	uap->port.icount.tx++;
1437734745caSDave Martin 
1438734745caSDave Martin 	return true;
1439734745caSDave Martin }
1440734745caSDave Martin 
14417d05587cSJayachandran C /* Returns true if tx interrupts have to be (kept) enabled  */
pl011_tx_chars(struct uart_amba_port * uap,bool from_irq)14427d05587cSJayachandran C static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
1443ab4382d2SGreg Kroah-Hartman {
14441788cf6aSJiri Slaby (SUSE) 	struct tty_port *tport = &uap->port.state->port;
14451e84d223SDave Martin 	int count = uap->fifosize >> 1;
1446734745caSDave Martin 
1447ab4382d2SGreg Kroah-Hartman 	if (uap->port.x_char) {
14481e84d223SDave Martin 		if (!pl011_tx_char(uap, uap->port.x_char, from_irq))
14497d05587cSJayachandran C 			return true;
1450ab4382d2SGreg Kroah-Hartman 		uap->port.x_char = 0;
1451734745caSDave Martin 		--count;
1452ab4382d2SGreg Kroah-Hartman 	}
14531788cf6aSJiri Slaby (SUSE) 	if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(&uap->port)) {
1454ab4382d2SGreg Kroah-Hartman 		pl011_stop_tx(&uap->port);
14557d05587cSJayachandran C 		return false;
1456ab4382d2SGreg Kroah-Hartman 	}
1457ab4382d2SGreg Kroah-Hartman 
1458ab4382d2SGreg Kroah-Hartman 	/* If we are using DMA mode, try to send some characters. */
1459ab4382d2SGreg Kroah-Hartman 	if (pl011_dma_tx_irq(uap))
14607d05587cSJayachandran C 		return true;
1461ab4382d2SGreg Kroah-Hartman 
14621788cf6aSJiri Slaby (SUSE) 	while (1) {
14631788cf6aSJiri Slaby (SUSE) 		unsigned char c;
14641788cf6aSJiri Slaby (SUSE) 
14651e84d223SDave Martin 		if (likely(from_irq) && count-- == 0)
1466ab4382d2SGreg Kroah-Hartman 			break;
14671e84d223SDave Martin 
14681788cf6aSJiri Slaby (SUSE) 		if (!kfifo_peek(&tport->xmit_fifo, &c))
14691e84d223SDave Martin 			break;
14701e84d223SDave Martin 
14711788cf6aSJiri Slaby (SUSE) 		if (!pl011_tx_char(uap, c, from_irq))
14721788cf6aSJiri Slaby (SUSE) 			break;
1473ab4382d2SGreg Kroah-Hartman 
14741788cf6aSJiri Slaby (SUSE) 		kfifo_skip(&tport->xmit_fifo);
14751788cf6aSJiri Slaby (SUSE) 	}
14761788cf6aSJiri Slaby (SUSE) 
14771788cf6aSJiri Slaby (SUSE) 	if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
1478ab4382d2SGreg Kroah-Hartman 		uart_write_wakeup(&uap->port);
1479ab4382d2SGreg Kroah-Hartman 
14801788cf6aSJiri Slaby (SUSE) 	if (kfifo_is_empty(&tport->xmit_fifo)) {
1481ab4382d2SGreg Kroah-Hartman 		pl011_stop_tx(&uap->port);
14827d05587cSJayachandran C 		return false;
14837d05587cSJayachandran C 	}
14847d05587cSJayachandran C 	return true;
1485ab4382d2SGreg Kroah-Hartman }
1486ab4382d2SGreg Kroah-Hartman 
pl011_modem_status(struct uart_amba_port * uap)1487ab4382d2SGreg Kroah-Hartman static void pl011_modem_status(struct uart_amba_port *uap)
1488ab4382d2SGreg Kroah-Hartman {
1489ab4382d2SGreg Kroah-Hartman 	unsigned int status, delta;
1490ab4382d2SGreg Kroah-Hartman 
14919f25bc51SRussell King 	status = pl011_read(uap, REG_FR) & UART01x_FR_MODEM_ANY;
1492ab4382d2SGreg Kroah-Hartman 
1493ab4382d2SGreg Kroah-Hartman 	delta = status ^ uap->old_status;
1494ab4382d2SGreg Kroah-Hartman 	uap->old_status = status;
1495ab4382d2SGreg Kroah-Hartman 
1496ab4382d2SGreg Kroah-Hartman 	if (!delta)
1497ab4382d2SGreg Kroah-Hartman 		return;
1498ab4382d2SGreg Kroah-Hartman 
1499ab4382d2SGreg Kroah-Hartman 	if (delta & UART01x_FR_DCD)
1500ab4382d2SGreg Kroah-Hartman 		uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
1501ab4382d2SGreg Kroah-Hartman 
15020e125a5fSShawn Guo 	if (delta & uap->vendor->fr_dsr)
1503ab4382d2SGreg Kroah-Hartman 		uap->port.icount.dsr++;
1504ab4382d2SGreg Kroah-Hartman 
15050e125a5fSShawn Guo 	if (delta & uap->vendor->fr_cts)
15060e125a5fSShawn Guo 		uart_handle_cts_change(&uap->port,
15070e125a5fSShawn Guo 				       status & uap->vendor->fr_cts);
1508ab4382d2SGreg Kroah-Hartman 
1509ab4382d2SGreg Kroah-Hartman 	wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
1510ab4382d2SGreg Kroah-Hartman }
1511ab4382d2SGreg Kroah-Hartman 
check_apply_cts_event_workaround(struct uart_amba_port * uap)15129c4ef4b0SAndre Przywara static void check_apply_cts_event_workaround(struct uart_amba_port *uap)
1513ab4382d2SGreg Kroah-Hartman {
15149c4ef4b0SAndre Przywara 	if (!uap->vendor->cts_event_workaround)
15159c4ef4b0SAndre Przywara 		return;
15169c4ef4b0SAndre Przywara 
15174fd0690bSRajanikanth H.V 	/* workaround to make sure that all bits are unlocked.. */
15189f25bc51SRussell King 	pl011_write(0x00, uap, REG_ICR);
15194fd0690bSRajanikanth H.V 
15204fd0690bSRajanikanth H.V 	/*
15214fd0690bSRajanikanth H.V 	 * WA: introduce 26ns(1 uart clk) delay before W1C;
15224fd0690bSRajanikanth H.V 	 * single apb access will incur 2 pclk(133.12Mhz) delay,
15234fd0690bSRajanikanth H.V 	 * so add 2 dummy reads
15244fd0690bSRajanikanth H.V 	 */
152594345aeeSXiongfeng Wang 	pl011_read(uap, REG_ICR);
152694345aeeSXiongfeng Wang 	pl011_read(uap, REG_ICR);
15274fd0690bSRajanikanth H.V }
15284fd0690bSRajanikanth H.V 
pl011_int(int irq,void * dev_id)15299c4ef4b0SAndre Przywara static irqreturn_t pl011_int(int irq, void *dev_id)
15309c4ef4b0SAndre Przywara {
15319c4ef4b0SAndre Przywara 	struct uart_amba_port *uap = dev_id;
15329c4ef4b0SAndre Przywara 	unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
15339c4ef4b0SAndre Przywara 	int handled = 0;
15349c4ef4b0SAndre Przywara 
15352432f71cSSebastian Andrzej Siewior 	uart_port_lock(&uap->port);
1536d3a96c94SLukas Wunner 	status = pl011_read(uap, REG_RIS) & uap->im;
15379c4ef4b0SAndre Przywara 	if (status) {
15389c4ef4b0SAndre Przywara 		do {
15399c4ef4b0SAndre Przywara 			check_apply_cts_event_workaround(uap);
1540f11c9841SGreg Kroah-Hartman 
1541d93ebe0fSThéo Lebrun 			pl011_write(status & ~(UART011_TXIS | UART011_RTIS | UART011_RXIS),
15429f25bc51SRussell King 				    uap, REG_ICR);
1543ab4382d2SGreg Kroah-Hartman 
1544ead76f32SLinus Walleij 			if (status & (UART011_RTIS | UART011_RXIS)) {
1545ead76f32SLinus Walleij 				if (pl011_dma_rx_running(uap))
1546ead76f32SLinus Walleij 					pl011_dma_rx_irq(uap);
1547ead76f32SLinus Walleij 				else
1548ab4382d2SGreg Kroah-Hartman 					pl011_rx_chars(uap);
1549ead76f32SLinus Walleij 			}
1550ab4382d2SGreg Kroah-Hartman 			if (status & (UART011_DSRMIS | UART011_DCDMIS |
1551ab4382d2SGreg Kroah-Hartman 				      UART011_CTSMIS | UART011_RIMIS))
1552ab4382d2SGreg Kroah-Hartman 				pl011_modem_status(uap);
15531e84d223SDave Martin 			if (status & UART011_TXIS)
15541e84d223SDave Martin 				pl011_tx_chars(uap, true);
1555ab4382d2SGreg Kroah-Hartman 
15564fd0690bSRajanikanth H.V 			if (pass_counter-- == 0)
1557ab4382d2SGreg Kroah-Hartman 				break;
1558ab4382d2SGreg Kroah-Hartman 
1559d3a96c94SLukas Wunner 			status = pl011_read(uap, REG_RIS) & uap->im;
1560ab4382d2SGreg Kroah-Hartman 		} while (status != 0);
1561ab4382d2SGreg Kroah-Hartman 		handled = 1;
1562ab4382d2SGreg Kroah-Hartman 	}
1563ab4382d2SGreg Kroah-Hartman 
15642432f71cSSebastian Andrzej Siewior 	uart_unlock_and_check_sysrq(&uap->port);
1565ab4382d2SGreg Kroah-Hartman 
1566ab4382d2SGreg Kroah-Hartman 	return IRQ_RETVAL(handled);
1567ab4382d2SGreg Kroah-Hartman }
1568ab4382d2SGreg Kroah-Hartman 
pl011_tx_empty(struct uart_port * port)1569e643f87fSLinus Walleij static unsigned int pl011_tx_empty(struct uart_port *port)
1570ab4382d2SGreg Kroah-Hartman {
1571a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1572a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1573d8a4995bSChristopher Covington 
1574d8a4995bSChristopher Covington 	/* Allow feature register bits to be inverted to work around errata */
1575d8a4995bSChristopher Covington 	unsigned int status = pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr;
1576d8a4995bSChristopher Covington 
15770e125a5fSShawn Guo 	return status & (uap->vendor->fr_busy | UART01x_FR_TXFF) ?
15780e125a5fSShawn Guo 							0 : TIOCSER_TEMT;
1579ab4382d2SGreg Kroah-Hartman }
1580ab4382d2SGreg Kroah-Hartman 
pl011_maybe_set_bit(bool cond,unsigned int * ptr,unsigned int mask)1581dc00f0ccSThéo Lebrun static void pl011_maybe_set_bit(bool cond, unsigned int *ptr, unsigned int mask)
1582dc00f0ccSThéo Lebrun {
1583dc00f0ccSThéo Lebrun 	if (cond)
1584dc00f0ccSThéo Lebrun 		*ptr |= mask;
1585dc00f0ccSThéo Lebrun }
1586dc00f0ccSThéo Lebrun 
pl011_get_mctrl(struct uart_port * port)1587e643f87fSLinus Walleij static unsigned int pl011_get_mctrl(struct uart_port *port)
1588ab4382d2SGreg Kroah-Hartman {
1589a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1590a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1591ab4382d2SGreg Kroah-Hartman 	unsigned int result = 0;
15929f25bc51SRussell King 	unsigned int status = pl011_read(uap, REG_FR);
1593ab4382d2SGreg Kroah-Hartman 
1594dc00f0ccSThéo Lebrun 	pl011_maybe_set_bit(status & UART01x_FR_DCD, &result, TIOCM_CAR);
1595dc00f0ccSThéo Lebrun 	pl011_maybe_set_bit(status & uap->vendor->fr_dsr, &result, TIOCM_DSR);
1596dc00f0ccSThéo Lebrun 	pl011_maybe_set_bit(status & uap->vendor->fr_cts, &result, TIOCM_CTS);
1597dc00f0ccSThéo Lebrun 	pl011_maybe_set_bit(status & uap->vendor->fr_ri, &result, TIOCM_RNG);
1598ab4382d2SGreg Kroah-Hartman 
1599ab4382d2SGreg Kroah-Hartman 	return result;
1600ab4382d2SGreg Kroah-Hartman }
1601ab4382d2SGreg Kroah-Hartman 
pl011_assign_bit(bool cond,unsigned int * ptr,unsigned int mask)1602dc00f0ccSThéo Lebrun static void pl011_assign_bit(bool cond, unsigned int *ptr, unsigned int mask)
1603dc00f0ccSThéo Lebrun {
1604dc00f0ccSThéo Lebrun 	if (cond)
1605dc00f0ccSThéo Lebrun 		*ptr |= mask;
1606dc00f0ccSThéo Lebrun 	else
1607dc00f0ccSThéo Lebrun 		*ptr &= ~mask;
1608dc00f0ccSThéo Lebrun }
1609dc00f0ccSThéo Lebrun 
pl011_set_mctrl(struct uart_port * port,unsigned int mctrl)1610ab4382d2SGreg Kroah-Hartman static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
1611ab4382d2SGreg Kroah-Hartman {
1612a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1613a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1614ab4382d2SGreg Kroah-Hartman 	unsigned int cr;
1615ab4382d2SGreg Kroah-Hartman 
16169f25bc51SRussell King 	cr = pl011_read(uap, REG_CR);
1617ab4382d2SGreg Kroah-Hartman 
1618dc00f0ccSThéo Lebrun 	pl011_assign_bit(mctrl & TIOCM_RTS, &cr, UART011_CR_RTS);
1619dc00f0ccSThéo Lebrun 	pl011_assign_bit(mctrl & TIOCM_DTR, &cr, UART011_CR_DTR);
1620dc00f0ccSThéo Lebrun 	pl011_assign_bit(mctrl & TIOCM_OUT1, &cr, UART011_CR_OUT1);
1621dc00f0ccSThéo Lebrun 	pl011_assign_bit(mctrl & TIOCM_OUT2, &cr, UART011_CR_OUT2);
1622dc00f0ccSThéo Lebrun 	pl011_assign_bit(mctrl & TIOCM_LOOP, &cr, UART011_CR_LBE);
1623ab4382d2SGreg Kroah-Hartman 
16242a76fa28SLukas Wunner 	if (port->status & UPSTAT_AUTORTS) {
1625ab4382d2SGreg Kroah-Hartman 		/* We need to disable auto-RTS if we want to turn RTS off */
1626dc00f0ccSThéo Lebrun 		pl011_assign_bit(mctrl & TIOCM_RTS, &cr, UART011_CR_RTSEN);
1627ab4382d2SGreg Kroah-Hartman 	}
1628ab4382d2SGreg Kroah-Hartman 
16299f25bc51SRussell King 	pl011_write(cr, uap, REG_CR);
1630ab4382d2SGreg Kroah-Hartman }
1631ab4382d2SGreg Kroah-Hartman 
pl011_break_ctl(struct uart_port * port,int break_state)1632ab4382d2SGreg Kroah-Hartman static void pl011_break_ctl(struct uart_port *port, int break_state)
1633ab4382d2SGreg Kroah-Hartman {
1634a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1635a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1636ab4382d2SGreg Kroah-Hartman 	unsigned long flags;
1637ab4382d2SGreg Kroah-Hartman 	unsigned int lcr_h;
1638ab4382d2SGreg Kroah-Hartman 
163968ca3e72SThomas Gleixner 	uart_port_lock_irqsave(&uap->port, &flags);
1640e4df9a80SRussell King 	lcr_h = pl011_read(uap, REG_LCRH_TX);
1641ab4382d2SGreg Kroah-Hartman 	if (break_state == -1)
1642ab4382d2SGreg Kroah-Hartman 		lcr_h |= UART01x_LCRH_BRK;
1643ab4382d2SGreg Kroah-Hartman 	else
1644ab4382d2SGreg Kroah-Hartman 		lcr_h &= ~UART01x_LCRH_BRK;
1645e4df9a80SRussell King 	pl011_write(lcr_h, uap, REG_LCRH_TX);
164668ca3e72SThomas Gleixner 	uart_port_unlock_irqrestore(&uap->port, flags);
1647ab4382d2SGreg Kroah-Hartman }
1648ab4382d2SGreg Kroah-Hartman 
1649ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_CONSOLE_POLL
16505c8124a0SAnton Vorontsov 
pl011_quiesce_irqs(struct uart_port * port)16515c8124a0SAnton Vorontsov static void pl011_quiesce_irqs(struct uart_port *port)
16525c8124a0SAnton Vorontsov {
1653a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1654a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
16555c8124a0SAnton Vorontsov 
16569f25bc51SRussell King 	pl011_write(pl011_read(uap, REG_MIS), uap, REG_ICR);
16575c8124a0SAnton Vorontsov 	/*
16585c8124a0SAnton Vorontsov 	 * There is no way to clear TXIM as this is "ready to transmit IRQ", so
16595c8124a0SAnton Vorontsov 	 * we simply mask it. start_tx() will unmask it.
16605c8124a0SAnton Vorontsov 	 *
16615c8124a0SAnton Vorontsov 	 * Note we can race with start_tx(), and if the race happens, the
16625c8124a0SAnton Vorontsov 	 * polling user might get another interrupt just after we clear it.
16635c8124a0SAnton Vorontsov 	 * But it should be OK and can happen even w/o the race, e.g.
16645c8124a0SAnton Vorontsov 	 * controller immediately got some new data and raised the IRQ.
16655c8124a0SAnton Vorontsov 	 *
16665c8124a0SAnton Vorontsov 	 * And whoever uses polling routines assumes that it manages the device
16675c8124a0SAnton Vorontsov 	 * (including tx queue), so we're also fine with start_tx()'s caller
16685c8124a0SAnton Vorontsov 	 * side.
16695c8124a0SAnton Vorontsov 	 */
16709f25bc51SRussell King 	pl011_write(pl011_read(uap, REG_IMSC) & ~UART011_TXIM, uap,
16719f25bc51SRussell King 		    REG_IMSC);
16725c8124a0SAnton Vorontsov }
16735c8124a0SAnton Vorontsov 
pl011_get_poll_char(struct uart_port * port)1674e643f87fSLinus Walleij static int pl011_get_poll_char(struct uart_port *port)
1675ab4382d2SGreg Kroah-Hartman {
1676a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1677a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1678ab4382d2SGreg Kroah-Hartman 	unsigned int status;
1679ab4382d2SGreg Kroah-Hartman 
16805c8124a0SAnton Vorontsov 	/*
16815c8124a0SAnton Vorontsov 	 * The caller might need IRQs lowered, e.g. if used with KDB NMI
16825c8124a0SAnton Vorontsov 	 * debugger.
16835c8124a0SAnton Vorontsov 	 */
16845c8124a0SAnton Vorontsov 	pl011_quiesce_irqs(port);
16855c8124a0SAnton Vorontsov 
16869f25bc51SRussell King 	status = pl011_read(uap, REG_FR);
1687ab4382d2SGreg Kroah-Hartman 	if (status & UART01x_FR_RXFE)
1688ab4382d2SGreg Kroah-Hartman 		return NO_POLL_CHAR;
1689ab4382d2SGreg Kroah-Hartman 
16909f25bc51SRussell King 	return pl011_read(uap, REG_DR);
1691ab4382d2SGreg Kroah-Hartman }
1692ab4382d2SGreg Kroah-Hartman 
pl011_put_poll_char(struct uart_port * port,unsigned char ch)1693d93ebe0fSThéo Lebrun static void pl011_put_poll_char(struct uart_port *port, unsigned char ch)
1694ab4382d2SGreg Kroah-Hartman {
1695a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1696a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1697ab4382d2SGreg Kroah-Hartman 
16989f25bc51SRussell King 	while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
16992f2fd089STimur Tabi 		cpu_relax();
1700ab4382d2SGreg Kroah-Hartman 
17019f25bc51SRussell King 	pl011_write(ch, uap, REG_DR);
1702ab4382d2SGreg Kroah-Hartman }
1703ab4382d2SGreg Kroah-Hartman 
1704ab4382d2SGreg Kroah-Hartman #endif /* CONFIG_CONSOLE_POLL */
1705ab4382d2SGreg Kroah-Hartman 
pl011_hwinit(struct uart_port * port)1706b3564c2cSAnton Vorontsov static int pl011_hwinit(struct uart_port *port)
1707ab4382d2SGreg Kroah-Hartman {
1708a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1709a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1710ab4382d2SGreg Kroah-Hartman 	int retval;
1711ab4382d2SGreg Kroah-Hartman 
171278d80c5aSLinus Walleij 	/* Optionaly enable pins to be muxed in and configured */
17132b996fc5SLinus Walleij 	pinctrl_pm_select_default_state(port->dev);
171478d80c5aSLinus Walleij 
1715ab4382d2SGreg Kroah-Hartman 	/*
1716ab4382d2SGreg Kroah-Hartman 	 * Try to enable the clock producer.
1717ab4382d2SGreg Kroah-Hartman 	 */
17181c4c4394SJulia Lawall 	retval = clk_prepare_enable(uap->clk);
1719ab4382d2SGreg Kroah-Hartman 	if (retval)
17207f6d942aSTushar Behera 		return retval;
1721ab4382d2SGreg Kroah-Hartman 
1722ab4382d2SGreg Kroah-Hartman 	uap->port.uartclk = clk_get_rate(uap->clk);
1723ab4382d2SGreg Kroah-Hartman 
17249b96fbacSLinus Walleij 	/* Clear pending error and receive interrupts */
172575836339SRussell King 	pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS |
172675836339SRussell King 		    UART011_FEIS | UART011_RTIS | UART011_RXIS,
17279f25bc51SRussell King 		    uap, REG_ICR);
17289b96fbacSLinus Walleij 
1729ab4382d2SGreg Kroah-Hartman 	/*
1730b3564c2cSAnton Vorontsov 	 * Save interrupts enable mask, and enable RX interrupts in case if
1731b3564c2cSAnton Vorontsov 	 * the interrupt is used for NMI entry.
1732b3564c2cSAnton Vorontsov 	 */
17339f25bc51SRussell King 	uap->im = pl011_read(uap, REG_IMSC);
17349f25bc51SRussell King 	pl011_write(UART011_RTIM | UART011_RXIM, uap, REG_IMSC);
1735b3564c2cSAnton Vorontsov 
1736574de559SJingoo Han 	if (dev_get_platdata(uap->port.dev)) {
1737b3564c2cSAnton Vorontsov 		struct amba_pl011_data *plat;
1738b3564c2cSAnton Vorontsov 
1739574de559SJingoo Han 		plat = dev_get_platdata(uap->port.dev);
1740b3564c2cSAnton Vorontsov 		if (plat->init)
1741b3564c2cSAnton Vorontsov 			plat->init();
1742b3564c2cSAnton Vorontsov 	}
1743b3564c2cSAnton Vorontsov 	return 0;
1744b3564c2cSAnton Vorontsov }
1745b3564c2cSAnton Vorontsov 
pl011_split_lcrh(const struct uart_amba_port * uap)17467fe9a5a9SRussell King static bool pl011_split_lcrh(const struct uart_amba_port *uap)
17477fe9a5a9SRussell King {
1748e4df9a80SRussell King 	return pl011_reg_to_offset(uap, REG_LCRH_RX) !=
1749e4df9a80SRussell King 	       pl011_reg_to_offset(uap, REG_LCRH_TX);
17507fe9a5a9SRussell King }
17517fe9a5a9SRussell King 
pl011_write_lcr_h(struct uart_amba_port * uap,unsigned int lcr_h)1752b60f2f66SJon Medhurst static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
1753b60f2f66SJon Medhurst {
1754e4df9a80SRussell King 	pl011_write(lcr_h, uap, REG_LCRH_RX);
17557fe9a5a9SRussell King 	if (pl011_split_lcrh(uap)) {
1756b60f2f66SJon Medhurst 		int i;
1757b60f2f66SJon Medhurst 		/*
1758b60f2f66SJon Medhurst 		 * Wait 10 PCLKs before writing LCRH_TX register,
1759b60f2f66SJon Medhurst 		 * to get this delay write read only register 10 times
1760b60f2f66SJon Medhurst 		 */
1761b60f2f66SJon Medhurst 		for (i = 0; i < 10; ++i)
17629f25bc51SRussell King 			pl011_write(0xff, uap, REG_MIS);
1763e4df9a80SRussell King 		pl011_write(lcr_h, uap, REG_LCRH_TX);
1764b60f2f66SJon Medhurst 	}
1765b60f2f66SJon Medhurst }
1766b60f2f66SJon Medhurst 
pl011_allocate_irq(struct uart_amba_port * uap)1767867b8e8eSAndre Przywara static int pl011_allocate_irq(struct uart_amba_port *uap)
1768867b8e8eSAndre Przywara {
17699f25bc51SRussell King 	pl011_write(uap->im, uap, REG_IMSC);
1770867b8e8eSAndre Przywara 
177194560f61SQian Cai 	return request_irq(uap->port.irq, pl011_int, IRQF_SHARED, "uart-pl011", uap);
1772867b8e8eSAndre Przywara }
1773867b8e8eSAndre Przywara 
1774867b8e8eSAndre Przywara /*
1775867b8e8eSAndre Przywara  * Enable interrupts, only timeouts when using DMA
1776867b8e8eSAndre Przywara  * if initial RX DMA job failed, start in interrupt mode
1777867b8e8eSAndre Przywara  * as well.
1778867b8e8eSAndre Przywara  */
pl011_enable_interrupts(struct uart_amba_port * uap)1779867b8e8eSAndre Przywara static void pl011_enable_interrupts(struct uart_amba_port *uap)
1780867b8e8eSAndre Przywara {
1781211565b1SIlpo Järvinen 	unsigned long flags;
17824a7e625cSDave Martin 	unsigned int i;
17834a7e625cSDave Martin 
178468ca3e72SThomas Gleixner 	uart_port_lock_irqsave(&uap->port, &flags);
1785867b8e8eSAndre Przywara 
1786867b8e8eSAndre Przywara 	/* Clear out any spuriously appearing RX interrupts */
17879f25bc51SRussell King 	pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR);
17884a7e625cSDave Martin 
17894a7e625cSDave Martin 	/*
17904a7e625cSDave Martin 	 * RXIS is asserted only when the RX FIFO transitions from below
17914a7e625cSDave Martin 	 * to above the trigger threshold.  If the RX FIFO is already
17924a7e625cSDave Martin 	 * full to the threshold this can't happen and RXIS will now be
17934a7e625cSDave Martin 	 * stuck off.  Drain the RX FIFO explicitly to fix this:
17944a7e625cSDave Martin 	 */
17954a7e625cSDave Martin 	for (i = 0; i < uap->fifosize * 2; ++i) {
17964a7e625cSDave Martin 		if (pl011_read(uap, REG_FR) & UART01x_FR_RXFE)
17974a7e625cSDave Martin 			break;
17984a7e625cSDave Martin 
17994a7e625cSDave Martin 		pl011_read(uap, REG_DR);
18004a7e625cSDave Martin 	}
18014a7e625cSDave Martin 
1802867b8e8eSAndre Przywara 	uap->im = UART011_RTIM;
1803867b8e8eSAndre Przywara 	if (!pl011_dma_rx_running(uap))
1804867b8e8eSAndre Przywara 		uap->im |= UART011_RXIM;
18059f25bc51SRussell King 	pl011_write(uap->im, uap, REG_IMSC);
180668ca3e72SThomas Gleixner 	uart_port_unlock_irqrestore(&uap->port, flags);
1807211565b1SIlpo Järvinen }
1808211565b1SIlpo Järvinen 
pl011_unthrottle_rx(struct uart_port * port)1809211565b1SIlpo Järvinen static void pl011_unthrottle_rx(struct uart_port *port)
1810211565b1SIlpo Järvinen {
1811211565b1SIlpo Järvinen 	struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port);
1812032d5a71Sdelisun 	unsigned long flags;
1813211565b1SIlpo Järvinen 
181468ca3e72SThomas Gleixner 	uart_port_lock_irqsave(&uap->port, &flags);
1815032d5a71Sdelisun 
1816032d5a71Sdelisun 	uap->im = UART011_RTIM;
1817032d5a71Sdelisun 	if (!pl011_dma_rx_running(uap))
1818032d5a71Sdelisun 		uap->im |= UART011_RXIM;
1819032d5a71Sdelisun 
1820032d5a71Sdelisun 	pl011_write(uap->im, uap, REG_IMSC);
1821032d5a71Sdelisun 
182268ca3e72SThomas Gleixner 	uart_port_unlock_irqrestore(&uap->port, flags);
1823867b8e8eSAndre Przywara }
1824867b8e8eSAndre Przywara 
pl011_startup(struct uart_port * port)1825b3564c2cSAnton Vorontsov static int pl011_startup(struct uart_port *port)
1826b3564c2cSAnton Vorontsov {
1827a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1828a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1829734745caSDave Martin 	unsigned int cr;
1830b3564c2cSAnton Vorontsov 	int retval;
1831b3564c2cSAnton Vorontsov 
1832b3564c2cSAnton Vorontsov 	retval = pl011_hwinit(port);
1833b3564c2cSAnton Vorontsov 	if (retval)
1834b3564c2cSAnton Vorontsov 		goto clk_dis;
1835b3564c2cSAnton Vorontsov 
1836867b8e8eSAndre Przywara 	retval = pl011_allocate_irq(uap);
1837ab4382d2SGreg Kroah-Hartman 	if (retval)
1838ab4382d2SGreg Kroah-Hartman 		goto clk_dis;
1839ab4382d2SGreg Kroah-Hartman 
18409f25bc51SRussell King 	pl011_write(uap->vendor->ifls, uap, REG_IFLS);
1841ab4382d2SGreg Kroah-Hartman 
184268ca3e72SThomas Gleixner 	uart_port_lock_irq(&uap->port);
1843fe433907SJon Medhurst 
184449a80424SLukas Wunner 	cr = pl011_read(uap, REG_CR);
184549a80424SLukas Wunner 	cr &= UART011_CR_RTS | UART011_CR_DTR;
18468d479237SLino Sanfilippo 	cr |= UART01x_CR_UARTEN | UART011_CR_RXE;
18478d479237SLino Sanfilippo 
18482dd8a74fSLukas Wunner 	if (!(port->rs485.flags & SER_RS485_ENABLED))
18498d479237SLino Sanfilippo 		cr |= UART011_CR_TXE;
18508d479237SLino Sanfilippo 
18519f25bc51SRussell King 	pl011_write(cr, uap, REG_CR);
1852ab4382d2SGreg Kroah-Hartman 
185368ca3e72SThomas Gleixner 	uart_port_unlock_irq(&uap->port);
1854fe433907SJon Medhurst 
1855ab4382d2SGreg Kroah-Hartman 	/*
1856ab4382d2SGreg Kroah-Hartman 	 * initialise the old status of the modem signals
1857ab4382d2SGreg Kroah-Hartman 	 */
18589f25bc51SRussell King 	uap->old_status = pl011_read(uap, REG_FR) & UART01x_FR_MODEM_ANY;
1859ab4382d2SGreg Kroah-Hartman 
1860ab4382d2SGreg Kroah-Hartman 	/* Startup DMA */
1861ab4382d2SGreg Kroah-Hartman 	pl011_dma_startup(uap);
1862ab4382d2SGreg Kroah-Hartman 
1863867b8e8eSAndre Przywara 	pl011_enable_interrupts(uap);
1864ab4382d2SGreg Kroah-Hartman 
1865ab4382d2SGreg Kroah-Hartman 	return 0;
1866ab4382d2SGreg Kroah-Hartman 
1867ab4382d2SGreg Kroah-Hartman  clk_dis:
18681c4c4394SJulia Lawall 	clk_disable_unprepare(uap->clk);
1869ab4382d2SGreg Kroah-Hartman 	return retval;
1870ab4382d2SGreg Kroah-Hartman }
1871ab4382d2SGreg Kroah-Hartman 
sbsa_uart_startup(struct uart_port * port)18720dd1e247SAndre Przywara static int sbsa_uart_startup(struct uart_port *port)
18730dd1e247SAndre Przywara {
18740dd1e247SAndre Przywara 	struct uart_amba_port *uap =
18750dd1e247SAndre Przywara 		container_of(port, struct uart_amba_port, port);
18760dd1e247SAndre Przywara 	int retval;
18770dd1e247SAndre Przywara 
18780dd1e247SAndre Przywara 	retval = pl011_hwinit(port);
18790dd1e247SAndre Przywara 	if (retval)
18800dd1e247SAndre Przywara 		return retval;
18810dd1e247SAndre Przywara 
18820dd1e247SAndre Przywara 	retval = pl011_allocate_irq(uap);
18830dd1e247SAndre Przywara 	if (retval)
18840dd1e247SAndre Przywara 		return retval;
18850dd1e247SAndre Przywara 
18860dd1e247SAndre Przywara 	/* The SBSA UART does not support any modem status lines. */
18870dd1e247SAndre Przywara 	uap->old_status = 0;
18880dd1e247SAndre Przywara 
18890dd1e247SAndre Przywara 	pl011_enable_interrupts(uap);
18900dd1e247SAndre Przywara 
18910dd1e247SAndre Przywara 	return 0;
18920dd1e247SAndre Przywara }
18930dd1e247SAndre Przywara 
pl011_shutdown_channel(struct uart_amba_port * uap,unsigned int lcrh)1894d93ebe0fSThéo Lebrun static void pl011_shutdown_channel(struct uart_amba_port *uap, unsigned int lcrh)
1895ab4382d2SGreg Kroah-Hartman {
1896ab4382d2SGreg Kroah-Hartman 	unsigned long val;
1897ab4382d2SGreg Kroah-Hartman 
1898b2a4e24cSRussell King 	val = pl011_read(uap, lcrh);
1899ab4382d2SGreg Kroah-Hartman 	val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
1900b2a4e24cSRussell King 	pl011_write(val, uap, lcrh);
1901ab4382d2SGreg Kroah-Hartman }
1902ab4382d2SGreg Kroah-Hartman 
1903ab4382d2SGreg Kroah-Hartman /*
1904d8d8ffa4SShreshtha Kumar Sahu  * disable the port. It should not disable RTS and DTR.
1905d8d8ffa4SShreshtha Kumar Sahu  * Also RTS and DTR state should be preserved to restore
1906d8d8ffa4SShreshtha Kumar Sahu  * it during startup().
1907ab4382d2SGreg Kroah-Hartman  */
pl011_disable_uart(struct uart_amba_port * uap)190895166a3fSAndre Przywara static void pl011_disable_uart(struct uart_amba_port *uap)
190995166a3fSAndre Przywara {
191095166a3fSAndre Przywara 	unsigned int cr;
191195166a3fSAndre Przywara 
19122a76fa28SLukas Wunner 	uap->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
191368ca3e72SThomas Gleixner 	uart_port_lock_irq(&uap->port);
19149f25bc51SRussell King 	cr = pl011_read(uap, REG_CR);
1915d8d8ffa4SShreshtha Kumar Sahu 	cr &= UART011_CR_RTS | UART011_CR_DTR;
1916d8d8ffa4SShreshtha Kumar Sahu 	cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
19179f25bc51SRussell King 	pl011_write(cr, uap, REG_CR);
191868ca3e72SThomas Gleixner 	uart_port_unlock_irq(&uap->port);
1919ab4382d2SGreg Kroah-Hartman 
1920ab4382d2SGreg Kroah-Hartman 	/*
1921ab4382d2SGreg Kroah-Hartman 	 * disable break condition and fifos
1922ab4382d2SGreg Kroah-Hartman 	 */
1923e4df9a80SRussell King 	pl011_shutdown_channel(uap, REG_LCRH_RX);
19247fe9a5a9SRussell King 	if (pl011_split_lcrh(uap))
1925e4df9a80SRussell King 		pl011_shutdown_channel(uap, REG_LCRH_TX);
192695166a3fSAndre Przywara }
192795166a3fSAndre Przywara 
pl011_disable_interrupts(struct uart_amba_port * uap)192895166a3fSAndre Przywara static void pl011_disable_interrupts(struct uart_amba_port *uap)
192995166a3fSAndre Przywara {
193068ca3e72SThomas Gleixner 	uart_port_lock_irq(&uap->port);
193195166a3fSAndre Przywara 
193295166a3fSAndre Przywara 	/* mask all interrupts and clear all pending ones */
193395166a3fSAndre Przywara 	uap->im = 0;
19349f25bc51SRussell King 	pl011_write(uap->im, uap, REG_IMSC);
19359f25bc51SRussell King 	pl011_write(0xffff, uap, REG_ICR);
193695166a3fSAndre Przywara 
193768ca3e72SThomas Gleixner 	uart_port_unlock_irq(&uap->port);
193895166a3fSAndre Przywara }
193995166a3fSAndre Przywara 
pl011_shutdown(struct uart_port * port)194095166a3fSAndre Przywara static void pl011_shutdown(struct uart_port *port)
194195166a3fSAndre Przywara {
194295166a3fSAndre Przywara 	struct uart_amba_port *uap =
194395166a3fSAndre Przywara 		container_of(port, struct uart_amba_port, port);
194495166a3fSAndre Przywara 
194595166a3fSAndre Przywara 	pl011_disable_interrupts(uap);
194695166a3fSAndre Przywara 
194795166a3fSAndre Przywara 	pl011_dma_shutdown(uap);
194895166a3fSAndre Przywara 
19498d479237SLino Sanfilippo 	if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started)
19508d479237SLino Sanfilippo 		pl011_rs485_tx_stop(uap);
19518d479237SLino Sanfilippo 
195294560f61SQian Cai 	free_irq(uap->port.irq, uap);
195395166a3fSAndre Przywara 
195495166a3fSAndre Przywara 	pl011_disable_uart(uap);
1955ab4382d2SGreg Kroah-Hartman 
1956ab4382d2SGreg Kroah-Hartman 	/*
1957ab4382d2SGreg Kroah-Hartman 	 * Shut down the clock producer
1958ab4382d2SGreg Kroah-Hartman 	 */
19591c4c4394SJulia Lawall 	clk_disable_unprepare(uap->clk);
196078d80c5aSLinus Walleij 	/* Optionally let pins go into sleep states */
19612b996fc5SLinus Walleij 	pinctrl_pm_select_sleep_state(port->dev);
1962c16d51a3SShreshtha Kumar Sahu 
1963574de559SJingoo Han 	if (dev_get_platdata(uap->port.dev)) {
1964c16d51a3SShreshtha Kumar Sahu 		struct amba_pl011_data *plat;
1965c16d51a3SShreshtha Kumar Sahu 
1966574de559SJingoo Han 		plat = dev_get_platdata(uap->port.dev);
1967c16d51a3SShreshtha Kumar Sahu 		if (plat->exit)
1968c16d51a3SShreshtha Kumar Sahu 			plat->exit();
1969c16d51a3SShreshtha Kumar Sahu 	}
1970c16d51a3SShreshtha Kumar Sahu 
197136f339d1SPeter Hurley 	if (uap->port.ops->flush_buffer)
197236f339d1SPeter Hurley 		uap->port.ops->flush_buffer(port);
1973ab4382d2SGreg Kroah-Hartman }
1974ab4382d2SGreg Kroah-Hartman 
sbsa_uart_shutdown(struct uart_port * port)19750dd1e247SAndre Przywara static void sbsa_uart_shutdown(struct uart_port *port)
19760dd1e247SAndre Przywara {
19770dd1e247SAndre Przywara 	struct uart_amba_port *uap =
19780dd1e247SAndre Przywara 		container_of(port, struct uart_amba_port, port);
19790dd1e247SAndre Przywara 
19800dd1e247SAndre Przywara 	pl011_disable_interrupts(uap);
19810dd1e247SAndre Przywara 
198294560f61SQian Cai 	free_irq(uap->port.irq, uap);
19830dd1e247SAndre Przywara 
19840dd1e247SAndre Przywara 	if (uap->port.ops->flush_buffer)
19850dd1e247SAndre Przywara 		uap->port.ops->flush_buffer(port);
19860dd1e247SAndre Przywara }
19870dd1e247SAndre Przywara 
1988ab4382d2SGreg Kroah-Hartman static void
pl011_setup_status_masks(struct uart_port * port,struct ktermios * termios)1989ef5a9358SAndre Przywara pl011_setup_status_masks(struct uart_port *port, struct ktermios *termios)
1990ef5a9358SAndre Przywara {
1991ef5a9358SAndre Przywara 	port->read_status_mask = UART011_DR_OE | 255;
1992ef5a9358SAndre Przywara 	if (termios->c_iflag & INPCK)
1993ef5a9358SAndre Przywara 		port->read_status_mask |= UART011_DR_FE | UART011_DR_PE;
1994ef5a9358SAndre Przywara 	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
1995ef5a9358SAndre Przywara 		port->read_status_mask |= UART011_DR_BE;
1996ef5a9358SAndre Przywara 
1997ef5a9358SAndre Przywara 	/*
1998ef5a9358SAndre Przywara 	 * Characters to ignore
1999ef5a9358SAndre Przywara 	 */
2000ef5a9358SAndre Przywara 	port->ignore_status_mask = 0;
2001ef5a9358SAndre Przywara 	if (termios->c_iflag & IGNPAR)
2002ef5a9358SAndre Przywara 		port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE;
2003ef5a9358SAndre Przywara 	if (termios->c_iflag & IGNBRK) {
2004ef5a9358SAndre Przywara 		port->ignore_status_mask |= UART011_DR_BE;
2005ef5a9358SAndre Przywara 		/*
2006ef5a9358SAndre Przywara 		 * If we're ignoring parity and break indicators,
2007ef5a9358SAndre Przywara 		 * ignore overruns too (for real raw support).
2008ef5a9358SAndre Przywara 		 */
2009ef5a9358SAndre Przywara 		if (termios->c_iflag & IGNPAR)
2010ef5a9358SAndre Przywara 			port->ignore_status_mask |= UART011_DR_OE;
2011ef5a9358SAndre Przywara 	}
2012ef5a9358SAndre Przywara 
2013ef5a9358SAndre Przywara 	/*
2014ef5a9358SAndre Przywara 	 * Ignore all characters if CREAD is not set.
2015ef5a9358SAndre Przywara 	 */
2016ef5a9358SAndre Przywara 	if ((termios->c_cflag & CREAD) == 0)
2017ef5a9358SAndre Przywara 		port->ignore_status_mask |= UART_DUMMY_DR_RX;
2018ef5a9358SAndre Przywara }
2019ef5a9358SAndre Przywara 
2020ef5a9358SAndre Przywara static void
pl011_set_termios(struct uart_port * port,struct ktermios * termios,const struct ktermios * old)2021ab4382d2SGreg Kroah-Hartman pl011_set_termios(struct uart_port *port, struct ktermios *termios,
2022bec5b814SIlpo Järvinen 		  const struct ktermios *old)
2023ab4382d2SGreg Kroah-Hartman {
2024a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
2025a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
2026ab4382d2SGreg Kroah-Hartman 	unsigned int lcr_h, old_cr;
2027ab4382d2SGreg Kroah-Hartman 	unsigned long flags;
2028ab4382d2SGreg Kroah-Hartman 	unsigned int baud, quot, clkdiv;
20298d479237SLino Sanfilippo 	unsigned int bits;
2030ab4382d2SGreg Kroah-Hartman 
2031ab4382d2SGreg Kroah-Hartman 	if (uap->vendor->oversampling)
2032ab4382d2SGreg Kroah-Hartman 		clkdiv = 8;
2033ab4382d2SGreg Kroah-Hartman 	else
2034ab4382d2SGreg Kroah-Hartman 		clkdiv = 16;
2035ab4382d2SGreg Kroah-Hartman 
2036ab4382d2SGreg Kroah-Hartman 	/*
2037ab4382d2SGreg Kroah-Hartman 	 * Ask the core to calculate the divisor for us.
2038ab4382d2SGreg Kroah-Hartman 	 */
2039ab4382d2SGreg Kroah-Hartman 	baud = uart_get_baud_rate(port, termios, old, 0,
2040ab4382d2SGreg Kroah-Hartman 				  port->uartclk / clkdiv);
204189fa28dbSChanho Min #ifdef CONFIG_DMA_ENGINE
2042cb06ff10SChanho Min 	/*
2043cb06ff10SChanho Min 	 * Adjust RX DMA polling rate with baud rate if not specified.
2044cb06ff10SChanho Min 	 */
2045cb06ff10SChanho Min 	if (uap->dmarx.auto_poll_rate)
2046cb06ff10SChanho Min 		uap->dmarx.poll_rate = DIV_ROUND_UP(10000000, baud);
204789fa28dbSChanho Min #endif
2048ab4382d2SGreg Kroah-Hartman 
2049ab4382d2SGreg Kroah-Hartman 	if (baud > port->uartclk / 16)
2050ab4382d2SGreg Kroah-Hartman 		quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
2051ab4382d2SGreg Kroah-Hartman 	else
2052ab4382d2SGreg Kroah-Hartman 		quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud);
2053ab4382d2SGreg Kroah-Hartman 
2054ab4382d2SGreg Kroah-Hartman 	switch (termios->c_cflag & CSIZE) {
2055ab4382d2SGreg Kroah-Hartman 	case CS5:
2056ab4382d2SGreg Kroah-Hartman 		lcr_h = UART01x_LCRH_WLEN_5;
2057ab4382d2SGreg Kroah-Hartman 		break;
2058ab4382d2SGreg Kroah-Hartman 	case CS6:
2059ab4382d2SGreg Kroah-Hartman 		lcr_h = UART01x_LCRH_WLEN_6;
2060ab4382d2SGreg Kroah-Hartman 		break;
2061ab4382d2SGreg Kroah-Hartman 	case CS7:
2062ab4382d2SGreg Kroah-Hartman 		lcr_h = UART01x_LCRH_WLEN_7;
2063ab4382d2SGreg Kroah-Hartman 		break;
2064ab4382d2SGreg Kroah-Hartman 	default: // CS8
2065ab4382d2SGreg Kroah-Hartman 		lcr_h = UART01x_LCRH_WLEN_8;
2066ab4382d2SGreg Kroah-Hartman 		break;
2067ab4382d2SGreg Kroah-Hartman 	}
2068ab4382d2SGreg Kroah-Hartman 	if (termios->c_cflag & CSTOPB)
2069ab4382d2SGreg Kroah-Hartman 		lcr_h |= UART01x_LCRH_STP2;
2070ab4382d2SGreg Kroah-Hartman 	if (termios->c_cflag & PARENB) {
2071ab4382d2SGreg Kroah-Hartman 		lcr_h |= UART01x_LCRH_PEN;
2072ab4382d2SGreg Kroah-Hartman 		if (!(termios->c_cflag & PARODD))
2073ab4382d2SGreg Kroah-Hartman 			lcr_h |= UART01x_LCRH_EPS;
2074bb70002cSEd Spiridonov 		if (termios->c_cflag & CMSPAR)
2075bb70002cSEd Spiridonov 			lcr_h |= UART011_LCRH_SPS;
2076ab4382d2SGreg Kroah-Hartman 	}
2077ab4382d2SGreg Kroah-Hartman 	if (uap->fifosize > 1)
2078ab4382d2SGreg Kroah-Hartman 		lcr_h |= UART01x_LCRH_FEN;
2079ab4382d2SGreg Kroah-Hartman 
20808d479237SLino Sanfilippo 	bits = tty_get_frame_size(termios->c_cflag);
20818d479237SLino Sanfilippo 
208268ca3e72SThomas Gleixner 	uart_port_lock_irqsave(port, &flags);
2083ab4382d2SGreg Kroah-Hartman 
2084ab4382d2SGreg Kroah-Hartman 	/*
2085ab4382d2SGreg Kroah-Hartman 	 * Update the per-port timeout.
2086ab4382d2SGreg Kroah-Hartman 	 */
2087ab4382d2SGreg Kroah-Hartman 	uart_update_timeout(port, termios->c_cflag, baud);
2088ab4382d2SGreg Kroah-Hartman 
20898d479237SLino Sanfilippo 	/*
20908d479237SLino Sanfilippo 	 * Calculate the approximated time it takes to transmit one character
20918d479237SLino Sanfilippo 	 * with the given baud rate. We use this as the poll interval when we
20928d479237SLino Sanfilippo 	 * wait for the tx queue to empty.
20938d479237SLino Sanfilippo 	 */
20940e4deb56SLino Sanfilippo 	uap->rs485_tx_drain_interval = DIV_ROUND_UP(bits * 1000 * 1000, baud);
20958d479237SLino Sanfilippo 
2096ef5a9358SAndre Przywara 	pl011_setup_status_masks(port, termios);
2097ab4382d2SGreg Kroah-Hartman 
2098ab4382d2SGreg Kroah-Hartman 	if (UART_ENABLE_MS(port, termios->c_cflag))
2099ab4382d2SGreg Kroah-Hartman 		pl011_enable_ms(port);
2100ab4382d2SGreg Kroah-Hartman 
21018d479237SLino Sanfilippo 	if (port->rs485.flags & SER_RS485_ENABLED)
21028d479237SLino Sanfilippo 		termios->c_cflag &= ~CRTSCTS;
21038d479237SLino Sanfilippo 
21049f25bc51SRussell King 	old_cr = pl011_read(uap, REG_CR);
2105ab4382d2SGreg Kroah-Hartman 
2106ab4382d2SGreg Kroah-Hartman 	if (termios->c_cflag & CRTSCTS) {
2107ab4382d2SGreg Kroah-Hartman 		if (old_cr & UART011_CR_RTS)
2108ab4382d2SGreg Kroah-Hartman 			old_cr |= UART011_CR_RTSEN;
2109ab4382d2SGreg Kroah-Hartman 
2110ab4382d2SGreg Kroah-Hartman 		old_cr |= UART011_CR_CTSEN;
21112a76fa28SLukas Wunner 		port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
2112ab4382d2SGreg Kroah-Hartman 	} else {
2113ab4382d2SGreg Kroah-Hartman 		old_cr &= ~(UART011_CR_CTSEN | UART011_CR_RTSEN);
21142a76fa28SLukas Wunner 		port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
2115ab4382d2SGreg Kroah-Hartman 	}
2116ab4382d2SGreg Kroah-Hartman 
2117ab4382d2SGreg Kroah-Hartman 	if (uap->vendor->oversampling) {
2118ab4382d2SGreg Kroah-Hartman 		if (baud > port->uartclk / 16)
2119ab4382d2SGreg Kroah-Hartman 			old_cr |= ST_UART011_CR_OVSFACT;
2120ab4382d2SGreg Kroah-Hartman 		else
2121ab4382d2SGreg Kroah-Hartman 			old_cr &= ~ST_UART011_CR_OVSFACT;
2122ab4382d2SGreg Kroah-Hartman 	}
2123ab4382d2SGreg Kroah-Hartman 
2124c5dd553bSLinus Walleij 	/*
2125c5dd553bSLinus Walleij 	 * Workaround for the ST Micro oversampling variants to
2126c5dd553bSLinus Walleij 	 * increase the bitrate slightly, by lowering the divisor,
2127c5dd553bSLinus Walleij 	 * to avoid delayed sampling of start bit at high speeds,
2128c5dd553bSLinus Walleij 	 * else we see data corruption.
2129c5dd553bSLinus Walleij 	 */
2130c5dd553bSLinus Walleij 	if (uap->vendor->oversampling) {
213128a7ec8cSThéo Lebrun 		if (baud >= 3000000 && baud < 3250000 && quot > 1)
2132c5dd553bSLinus Walleij 			quot -= 1;
213328a7ec8cSThéo Lebrun 		else if (baud > 3250000 && quot > 2)
2134c5dd553bSLinus Walleij 			quot -= 2;
2135c5dd553bSLinus Walleij 	}
2136ab4382d2SGreg Kroah-Hartman 	/* Set baud rate */
21379f25bc51SRussell King 	pl011_write(quot & 0x3f, uap, REG_FBRD);
21389f25bc51SRussell King 	pl011_write(quot >> 6, uap, REG_IBRD);
2139ab4382d2SGreg Kroah-Hartman 
2140ab4382d2SGreg Kroah-Hartman 	/*
2141ab4382d2SGreg Kroah-Hartman 	 * ----------v----------v----------v----------v-----
2142e4df9a80SRussell King 	 * NOTE: REG_LCRH_TX and REG_LCRH_RX MUST BE WRITTEN AFTER
21439f25bc51SRussell King 	 * REG_FBRD & REG_IBRD.
2144ab4382d2SGreg Kroah-Hartman 	 * ----------^----------^----------^----------^-----
2145ab4382d2SGreg Kroah-Hartman 	 */
2146b60f2f66SJon Medhurst 	pl011_write_lcr_h(uap, lcr_h);
21476d8c1fcaSHongyu Xie 
21486d8c1fcaSHongyu Xie 	/*
21496d8c1fcaSHongyu Xie 	 * Receive was disabled by pl011_disable_uart during shutdown.
21506d8c1fcaSHongyu Xie 	 * Need to reenable receive if you need to use a tty_driver
21516d8c1fcaSHongyu Xie 	 * returns from tty_find_polling_driver() after a port shutdown.
21526d8c1fcaSHongyu Xie 	 */
21536d8c1fcaSHongyu Xie 	old_cr |= UART011_CR_RXE;
21549f25bc51SRussell King 	pl011_write(old_cr, uap, REG_CR);
2155ab4382d2SGreg Kroah-Hartman 
215668ca3e72SThomas Gleixner 	uart_port_unlock_irqrestore(port, flags);
2157ab4382d2SGreg Kroah-Hartman }
2158ab4382d2SGreg Kroah-Hartman 
21590dd1e247SAndre Przywara static void
sbsa_uart_set_termios(struct uart_port * port,struct ktermios * termios,const struct ktermios * old)21600dd1e247SAndre Przywara sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios,
2161bec5b814SIlpo Järvinen 		      const struct ktermios *old)
21620dd1e247SAndre Przywara {
21630dd1e247SAndre Przywara 	struct uart_amba_port *uap =
21640dd1e247SAndre Przywara 	    container_of(port, struct uart_amba_port, port);
21650dd1e247SAndre Przywara 	unsigned long flags;
21660dd1e247SAndre Przywara 
21670dd1e247SAndre Przywara 	tty_termios_encode_baud_rate(termios, uap->fixed_baud, uap->fixed_baud);
21680dd1e247SAndre Przywara 
21690dd1e247SAndre Przywara 	/* The SBSA UART only supports 8n1 without hardware flow control. */
21700dd1e247SAndre Przywara 	termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
21710dd1e247SAndre Przywara 	termios->c_cflag &= ~(CMSPAR | CRTSCTS);
21720dd1e247SAndre Przywara 	termios->c_cflag |= CS8 | CLOCAL;
21730dd1e247SAndre Przywara 
217468ca3e72SThomas Gleixner 	uart_port_lock_irqsave(port, &flags);
21750dd1e247SAndre Przywara 	uart_update_timeout(port, CS8, uap->fixed_baud);
21760dd1e247SAndre Przywara 	pl011_setup_status_masks(port, termios);
217768ca3e72SThomas Gleixner 	uart_port_unlock_irqrestore(port, flags);
21780dd1e247SAndre Przywara }
21790dd1e247SAndre Przywara 
pl011_type(struct uart_port * port)2180ab4382d2SGreg Kroah-Hartman static const char *pl011_type(struct uart_port *port)
2181ab4382d2SGreg Kroah-Hartman {
2182a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
2183a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
2184ab4382d2SGreg Kroah-Hartman 	return uap->port.type == PORT_AMBA ? uap->type : NULL;
2185ab4382d2SGreg Kroah-Hartman }
2186ab4382d2SGreg Kroah-Hartman 
2187ab4382d2SGreg Kroah-Hartman /*
2188ab4382d2SGreg Kroah-Hartman  * Configure/autoconfigure the port.
2189ab4382d2SGreg Kroah-Hartman  */
pl011_config_port(struct uart_port * port,int flags)2190e643f87fSLinus Walleij static void pl011_config_port(struct uart_port *port, int flags)
2191ab4382d2SGreg Kroah-Hartman {
2192d1180405SLino Sanfilippo 	if (flags & UART_CONFIG_TYPE)
2193ab4382d2SGreg Kroah-Hartman 		port->type = PORT_AMBA;
2194ab4382d2SGreg Kroah-Hartman }
2195ab4382d2SGreg Kroah-Hartman 
2196ab4382d2SGreg Kroah-Hartman /*
2197ab4382d2SGreg Kroah-Hartman  * verify the new serial_struct (for TIOCSSERIAL).
2198ab4382d2SGreg Kroah-Hartman  */
pl011_verify_port(struct uart_port * port,struct serial_struct * ser)2199e643f87fSLinus Walleij static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser)
2200ab4382d2SGreg Kroah-Hartman {
2201ab4382d2SGreg Kroah-Hartman 	int ret = 0;
2202d93ebe0fSThéo Lebrun 
2203ab4382d2SGreg Kroah-Hartman 	if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
2204ab4382d2SGreg Kroah-Hartman 		ret = -EINVAL;
2205ab4382d2SGreg Kroah-Hartman 	if (ser->irq < 0 || ser->irq >= nr_irqs)
2206ab4382d2SGreg Kroah-Hartman 		ret = -EINVAL;
2207ab4382d2SGreg Kroah-Hartman 	if (ser->baud_base < 9600)
2208ab4382d2SGreg Kroah-Hartman 		ret = -EINVAL;
2209d1180405SLino Sanfilippo 	if (port->mapbase != (unsigned long)ser->iomem_base)
2210d1180405SLino Sanfilippo 		ret = -EINVAL;
2211ab4382d2SGreg Kroah-Hartman 	return ret;
2212ab4382d2SGreg Kroah-Hartman }
2213ab4382d2SGreg Kroah-Hartman 
pl011_rs485_config(struct uart_port * port,struct ktermios * termios,struct serial_rs485 * rs485)2214ae50bb27SIlpo Järvinen static int pl011_rs485_config(struct uart_port *port, struct ktermios *termios,
22158d479237SLino Sanfilippo 			      struct serial_rs485 *rs485)
22168d479237SLino Sanfilippo {
22178d479237SLino Sanfilippo 	struct uart_amba_port *uap =
22188d479237SLino Sanfilippo 		container_of(port, struct uart_amba_port, port);
22198d479237SLino Sanfilippo 
22208d479237SLino Sanfilippo 	if (port->rs485.flags & SER_RS485_ENABLED)
22218d479237SLino Sanfilippo 		pl011_rs485_tx_stop(uap);
22228d479237SLino Sanfilippo 
22238d479237SLino Sanfilippo 	/* Make sure auto RTS is disabled */
2224a9efa452SLino Sanfilippo 	if (rs485->flags & SER_RS485_ENABLED) {
22258d479237SLino Sanfilippo 		u32 cr = pl011_read(uap, REG_CR);
22268d479237SLino Sanfilippo 
22278d479237SLino Sanfilippo 		cr &= ~UART011_CR_RTSEN;
22288d479237SLino Sanfilippo 		pl011_write(cr, uap, REG_CR);
22298d479237SLino Sanfilippo 		port->status &= ~UPSTAT_AUTORTS;
22308d479237SLino Sanfilippo 	}
22318d479237SLino Sanfilippo 
22328d479237SLino Sanfilippo 	return 0;
22338d479237SLino Sanfilippo }
22348d479237SLino Sanfilippo 
22352331e068SBhumika Goyal static const struct uart_ops amba_pl011_pops = {
2236e643f87fSLinus Walleij 	.tx_empty	= pl011_tx_empty,
2237ab4382d2SGreg Kroah-Hartman 	.set_mctrl	= pl011_set_mctrl,
2238e643f87fSLinus Walleij 	.get_mctrl	= pl011_get_mctrl,
2239ab4382d2SGreg Kroah-Hartman 	.stop_tx	= pl011_stop_tx,
2240ab4382d2SGreg Kroah-Hartman 	.start_tx	= pl011_start_tx,
2241ab4382d2SGreg Kroah-Hartman 	.stop_rx	= pl011_stop_rx,
2242211565b1SIlpo Järvinen 	.throttle	= pl011_throttle_rx,
2243211565b1SIlpo Järvinen 	.unthrottle	= pl011_unthrottle_rx,
2244ab4382d2SGreg Kroah-Hartman 	.enable_ms	= pl011_enable_ms,
2245ab4382d2SGreg Kroah-Hartman 	.break_ctl	= pl011_break_ctl,
2246ab4382d2SGreg Kroah-Hartman 	.startup	= pl011_startup,
2247ab4382d2SGreg Kroah-Hartman 	.shutdown	= pl011_shutdown,
2248ab4382d2SGreg Kroah-Hartman 	.flush_buffer	= pl011_dma_flush_buffer,
2249ab4382d2SGreg Kroah-Hartman 	.set_termios	= pl011_set_termios,
2250ab4382d2SGreg Kroah-Hartman 	.type		= pl011_type,
2251e643f87fSLinus Walleij 	.config_port	= pl011_config_port,
2252e643f87fSLinus Walleij 	.verify_port	= pl011_verify_port,
2253ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_CONSOLE_POLL
2254b3564c2cSAnton Vorontsov 	.poll_init     = pl011_hwinit,
2255e643f87fSLinus Walleij 	.poll_get_char = pl011_get_poll_char,
2256e643f87fSLinus Walleij 	.poll_put_char = pl011_put_poll_char,
2257ab4382d2SGreg Kroah-Hartman #endif
2258ab4382d2SGreg Kroah-Hartman };
2259ab4382d2SGreg Kroah-Hartman 
sbsa_uart_set_mctrl(struct uart_port * port,unsigned int mctrl)22600dd1e247SAndre Przywara static void sbsa_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
22610dd1e247SAndre Przywara {
22620dd1e247SAndre Przywara }
22630dd1e247SAndre Przywara 
sbsa_uart_get_mctrl(struct uart_port * port)22640dd1e247SAndre Przywara static unsigned int sbsa_uart_get_mctrl(struct uart_port *port)
22650dd1e247SAndre Przywara {
22660dd1e247SAndre Przywara 	return 0;
22670dd1e247SAndre Przywara }
22680dd1e247SAndre Przywara 
22690dd1e247SAndre Przywara static const struct uart_ops sbsa_uart_pops = {
22700dd1e247SAndre Przywara 	.tx_empty	= pl011_tx_empty,
22710dd1e247SAndre Przywara 	.set_mctrl	= sbsa_uart_set_mctrl,
22720dd1e247SAndre Przywara 	.get_mctrl	= sbsa_uart_get_mctrl,
22730dd1e247SAndre Przywara 	.stop_tx	= pl011_stop_tx,
22740dd1e247SAndre Przywara 	.start_tx	= pl011_start_tx,
22750dd1e247SAndre Przywara 	.stop_rx	= pl011_stop_rx,
22760dd1e247SAndre Przywara 	.startup	= sbsa_uart_startup,
22770dd1e247SAndre Przywara 	.shutdown	= sbsa_uart_shutdown,
22780dd1e247SAndre Przywara 	.set_termios	= sbsa_uart_set_termios,
22790dd1e247SAndre Przywara 	.type		= pl011_type,
22800dd1e247SAndre Przywara 	.config_port	= pl011_config_port,
22810dd1e247SAndre Przywara 	.verify_port	= pl011_verify_port,
22820dd1e247SAndre Przywara #ifdef CONFIG_CONSOLE_POLL
22830dd1e247SAndre Przywara 	.poll_init     = pl011_hwinit,
22840dd1e247SAndre Przywara 	.poll_get_char = pl011_get_poll_char,
22850dd1e247SAndre Przywara 	.poll_put_char = pl011_put_poll_char,
22860dd1e247SAndre Przywara #endif
22870dd1e247SAndre Przywara };
22880dd1e247SAndre Przywara 
2289ab4382d2SGreg Kroah-Hartman static struct uart_amba_port *amba_ports[UART_NR];
2290ab4382d2SGreg Kroah-Hartman 
2291ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE
2292ab4382d2SGreg Kroah-Hartman 
pl011_console_putchar(struct uart_port * port,unsigned char ch)22933f8bab17SJiri Slaby static void pl011_console_putchar(struct uart_port *port, unsigned char ch)
2294ab4382d2SGreg Kroah-Hartman {
2295a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
2296a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
2297ab4382d2SGreg Kroah-Hartman 
22989f25bc51SRussell King 	while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
22992f2fd089STimur Tabi 		cpu_relax();
23009f25bc51SRussell King 	pl011_write(ch, uap, REG_DR);
2301ab4382d2SGreg Kroah-Hartman }
2302ab4382d2SGreg Kroah-Hartman 
2303ab4382d2SGreg Kroah-Hartman static void
pl011_console_write(struct console * co,const char * s,unsigned int count)2304ab4382d2SGreg Kroah-Hartman pl011_console_write(struct console *co, const char *s, unsigned int count)
2305ab4382d2SGreg Kroah-Hartman {
2306ab4382d2SGreg Kroah-Hartman 	struct uart_amba_port *uap = amba_ports[co->index];
23072f2fd089STimur Tabi 	unsigned int old_cr = 0, new_cr;
2308ef605fdbSRabin Vincent 	unsigned long flags;
2309ef605fdbSRabin Vincent 	int locked = 1;
2310ab4382d2SGreg Kroah-Hartman 
2311ab4382d2SGreg Kroah-Hartman 	clk_enable(uap->clk);
2312ab4382d2SGreg Kroah-Hartman 
23132432f71cSSebastian Andrzej Siewior 	if (oops_in_progress)
23142432f71cSSebastian Andrzej Siewior 		locked = uart_port_trylock_irqsave(&uap->port, &flags);
2315ef605fdbSRabin Vincent 	else
23162432f71cSSebastian Andrzej Siewior 		uart_port_lock_irqsave(&uap->port, &flags);
2317ef605fdbSRabin Vincent 
2318ab4382d2SGreg Kroah-Hartman 	/*
2319ab4382d2SGreg Kroah-Hartman 	 *	First save the CR then disable the interrupts
2320ab4382d2SGreg Kroah-Hartman 	 */
232171eec483SAndre Przywara 	if (!uap->vendor->always_enabled) {
23229f25bc51SRussell King 		old_cr = pl011_read(uap, REG_CR);
2323ab4382d2SGreg Kroah-Hartman 		new_cr = old_cr & ~UART011_CR_CTSEN;
2324ab4382d2SGreg Kroah-Hartman 		new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
23259f25bc51SRussell King 		pl011_write(new_cr, uap, REG_CR);
232671eec483SAndre Przywara 	}
2327ab4382d2SGreg Kroah-Hartman 
2328ab4382d2SGreg Kroah-Hartman 	uart_console_write(&uap->port, s, count, pl011_console_putchar);
2329ab4382d2SGreg Kroah-Hartman 
2330ab4382d2SGreg Kroah-Hartman 	/*
2331d8a4995bSChristopher Covington 	 *	Finally, wait for transmitter to become empty and restore the
2332d8a4995bSChristopher Covington 	 *	TCR. Allow feature register bits to be inverted to work around
2333d8a4995bSChristopher Covington 	 *	errata.
2334ab4382d2SGreg Kroah-Hartman 	 */
2335d8a4995bSChristopher Covington 	while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr)
2336d8a4995bSChristopher Covington 						& uap->vendor->fr_busy)
23372f2fd089STimur Tabi 		cpu_relax();
233871eec483SAndre Przywara 	if (!uap->vendor->always_enabled)
23399f25bc51SRussell King 		pl011_write(old_cr, uap, REG_CR);
2340ab4382d2SGreg Kroah-Hartman 
2341ef605fdbSRabin Vincent 	if (locked)
23422432f71cSSebastian Andrzej Siewior 		uart_port_unlock_irqrestore(&uap->port, flags);
2343ef605fdbSRabin Vincent 
2344ab4382d2SGreg Kroah-Hartman 	clk_disable(uap->clk);
2345ab4382d2SGreg Kroah-Hartman }
2346ab4382d2SGreg Kroah-Hartman 
pl011_console_get_options(struct uart_amba_port * uap,int * baud,int * parity,int * bits)234727afac93SLukas Wunner static void pl011_console_get_options(struct uart_amba_port *uap, int *baud,
2348ab4382d2SGreg Kroah-Hartman 				      int *parity, int *bits)
2349ab4382d2SGreg Kroah-Hartman {
2350ab4382d2SGreg Kroah-Hartman 	unsigned int lcr_h, ibrd, fbrd;
2351ab4382d2SGreg Kroah-Hartman 
23528ff87406SThéo Lebrun 	if (!(pl011_read(uap, REG_CR) & UART01x_CR_UARTEN))
23538ff87406SThéo Lebrun 		return;
23548ff87406SThéo Lebrun 
2355e4df9a80SRussell King 	lcr_h = pl011_read(uap, REG_LCRH_TX);
2356ab4382d2SGreg Kroah-Hartman 
2357ab4382d2SGreg Kroah-Hartman 	*parity = 'n';
2358ab4382d2SGreg Kroah-Hartman 	if (lcr_h & UART01x_LCRH_PEN) {
2359ab4382d2SGreg Kroah-Hartman 		if (lcr_h & UART01x_LCRH_EPS)
2360ab4382d2SGreg Kroah-Hartman 			*parity = 'e';
2361ab4382d2SGreg Kroah-Hartman 		else
2362ab4382d2SGreg Kroah-Hartman 			*parity = 'o';
2363ab4382d2SGreg Kroah-Hartman 	}
2364ab4382d2SGreg Kroah-Hartman 
2365ab4382d2SGreg Kroah-Hartman 	if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)
2366ab4382d2SGreg Kroah-Hartman 		*bits = 7;
2367ab4382d2SGreg Kroah-Hartman 	else
2368ab4382d2SGreg Kroah-Hartman 		*bits = 8;
2369ab4382d2SGreg Kroah-Hartman 
23709f25bc51SRussell King 	ibrd = pl011_read(uap, REG_IBRD);
23719f25bc51SRussell King 	fbrd = pl011_read(uap, REG_FBRD);
2372ab4382d2SGreg Kroah-Hartman 
2373ab4382d2SGreg Kroah-Hartman 	*baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
2374ab4382d2SGreg Kroah-Hartman 
23758ff87406SThéo Lebrun 	if (uap->vendor->oversampling &&
23768ff87406SThéo Lebrun 	    (pl011_read(uap, REG_CR) & ST_UART011_CR_OVSFACT))
2377ab4382d2SGreg Kroah-Hartman 		*baud *= 2;
2378ab4382d2SGreg Kroah-Hartman }
2379ab4382d2SGreg Kroah-Hartman 
pl011_console_setup(struct console * co,char * options)238027afac93SLukas Wunner static int pl011_console_setup(struct console *co, char *options)
2381ab4382d2SGreg Kroah-Hartman {
2382ab4382d2SGreg Kroah-Hartman 	struct uart_amba_port *uap;
2383ab4382d2SGreg Kroah-Hartman 	int baud = 38400;
2384ab4382d2SGreg Kroah-Hartman 	int bits = 8;
2385ab4382d2SGreg Kroah-Hartman 	int parity = 'n';
2386ab4382d2SGreg Kroah-Hartman 	int flow = 'n';
23874b4851c6SRussell King 	int ret;
2388ab4382d2SGreg Kroah-Hartman 
2389ab4382d2SGreg Kroah-Hartman 	/*
2390ab4382d2SGreg Kroah-Hartman 	 * Check whether an invalid uart number has been specified, and
2391ab4382d2SGreg Kroah-Hartman 	 * if so, search for the first available port that does have
2392ab4382d2SGreg Kroah-Hartman 	 * console support.
2393ab4382d2SGreg Kroah-Hartman 	 */
2394ab4382d2SGreg Kroah-Hartman 	if (co->index >= UART_NR)
2395ab4382d2SGreg Kroah-Hartman 		co->index = 0;
2396ab4382d2SGreg Kroah-Hartman 	uap = amba_ports[co->index];
2397ab4382d2SGreg Kroah-Hartman 	if (!uap)
2398ab4382d2SGreg Kroah-Hartman 		return -ENODEV;
2399ab4382d2SGreg Kroah-Hartman 
240078d80c5aSLinus Walleij 	/* Allow pins to be muxed in and configured */
24012b996fc5SLinus Walleij 	pinctrl_pm_select_default_state(uap->port.dev);
240278d80c5aSLinus Walleij 
24034b4851c6SRussell King 	ret = clk_prepare(uap->clk);
24044b4851c6SRussell King 	if (ret)
24054b4851c6SRussell King 		return ret;
24064b4851c6SRussell King 
2407574de559SJingoo Han 	if (dev_get_platdata(uap->port.dev)) {
2408c16d51a3SShreshtha Kumar Sahu 		struct amba_pl011_data *plat;
2409c16d51a3SShreshtha Kumar Sahu 
2410574de559SJingoo Han 		plat = dev_get_platdata(uap->port.dev);
2411c16d51a3SShreshtha Kumar Sahu 		if (plat->init)
2412c16d51a3SShreshtha Kumar Sahu 			plat->init();
2413c16d51a3SShreshtha Kumar Sahu 	}
2414c16d51a3SShreshtha Kumar Sahu 
2415ab4382d2SGreg Kroah-Hartman 	uap->port.uartclk = clk_get_rate(uap->clk);
2416ab4382d2SGreg Kroah-Hartman 
2417cefc2d1dSAndre Przywara 	if (uap->vendor->fixed_options) {
2418cefc2d1dSAndre Przywara 		baud = uap->fixed_baud;
2419cefc2d1dSAndre Przywara 	} else {
2420ab4382d2SGreg Kroah-Hartman 		if (options)
2421cefc2d1dSAndre Przywara 			uart_parse_options(options,
2422cefc2d1dSAndre Przywara 					   &baud, &parity, &bits, &flow);
2423ab4382d2SGreg Kroah-Hartman 		else
2424ab4382d2SGreg Kroah-Hartman 			pl011_console_get_options(uap, &baud, &parity, &bits);
2425cefc2d1dSAndre Przywara 	}
2426ab4382d2SGreg Kroah-Hartman 
2427ab4382d2SGreg Kroah-Hartman 	return uart_set_options(&uap->port, co, baud, parity, bits, flow);
2428ab4382d2SGreg Kroah-Hartman }
2429ab4382d2SGreg Kroah-Hartman 
243010879ae5SAleksey Makarov /**
243110879ae5SAleksey Makarov  *	pl011_console_match - non-standard console matching
243210879ae5SAleksey Makarov  *	@co:	  registering console
243310879ae5SAleksey Makarov  *	@name:	  name from console command line
243410879ae5SAleksey Makarov  *	@idx:	  index from console command line
243510879ae5SAleksey Makarov  *	@options: ptr to option string from console command line
243610879ae5SAleksey Makarov  *
243710879ae5SAleksey Makarov  *	Only attempts to match console command lines of the form:
243810879ae5SAleksey Makarov  *	    console=pl011,mmio|mmio32,<addr>[,<options>]
243910879ae5SAleksey Makarov  *	    console=pl011,0x<addr>[,<options>]
244010879ae5SAleksey Makarov  *	This form is used to register an initial earlycon boot console and
244110879ae5SAleksey Makarov  *	replace it with the amba_console at pl011 driver init.
244210879ae5SAleksey Makarov  *
244310879ae5SAleksey Makarov  *	Performs console setup for a match (as required by interface)
244410879ae5SAleksey Makarov  *	If no <options> are specified, then assume the h/w is already setup.
244510879ae5SAleksey Makarov  *
244610879ae5SAleksey Makarov  *	Returns 0 if console matches; otherwise non-zero to use default matching
244710879ae5SAleksey Makarov  */
pl011_console_match(struct console * co,char * name,int idx,char * options)244827afac93SLukas Wunner static int pl011_console_match(struct console *co, char *name, int idx,
244910879ae5SAleksey Makarov 			       char *options)
245010879ae5SAleksey Makarov {
245110879ae5SAleksey Makarov 	unsigned char iotype;
245210879ae5SAleksey Makarov 	resource_size_t addr;
245310879ae5SAleksey Makarov 	int i;
245410879ae5SAleksey Makarov 
245537ef38f3STimur Tabi 	/*
245637ef38f3STimur Tabi 	 * Systems affected by the Qualcomm Technologies QDF2400 E44 erratum
245737ef38f3STimur Tabi 	 * have a distinct console name, so make sure we check for that.
245837ef38f3STimur Tabi 	 * The actual implementation of the erratum occurs in the probe
245937ef38f3STimur Tabi 	 * function.
246037ef38f3STimur Tabi 	 */
246137ef38f3STimur Tabi 	if ((strcmp(name, "qdf2400_e44") != 0) && (strcmp(name, "pl011") != 0))
246210879ae5SAleksey Makarov 		return -ENODEV;
246310879ae5SAleksey Makarov 
246410879ae5SAleksey Makarov 	if (uart_parse_earlycon(options, &iotype, &addr, &options))
246510879ae5SAleksey Makarov 		return -ENODEV;
246610879ae5SAleksey Makarov 
246710879ae5SAleksey Makarov 	if (iotype != UPIO_MEM && iotype != UPIO_MEM32)
246810879ae5SAleksey Makarov 		return -ENODEV;
246910879ae5SAleksey Makarov 
247010879ae5SAleksey Makarov 	/* try to match the port specified on the command line */
247110879ae5SAleksey Makarov 	for (i = 0; i < ARRAY_SIZE(amba_ports); i++) {
247210879ae5SAleksey Makarov 		struct uart_port *port;
247310879ae5SAleksey Makarov 
247410879ae5SAleksey Makarov 		if (!amba_ports[i])
247510879ae5SAleksey Makarov 			continue;
247610879ae5SAleksey Makarov 
247710879ae5SAleksey Makarov 		port = &amba_ports[i]->port;
247810879ae5SAleksey Makarov 
247910879ae5SAleksey Makarov 		if (port->mapbase != addr)
248010879ae5SAleksey Makarov 			continue;
248110879ae5SAleksey Makarov 
248210879ae5SAleksey Makarov 		co->index = i;
248310879ae5SAleksey Makarov 		port->cons = co;
248410879ae5SAleksey Makarov 		return pl011_console_setup(co, options);
248510879ae5SAleksey Makarov 	}
248610879ae5SAleksey Makarov 
248710879ae5SAleksey Makarov 	return -ENODEV;
248810879ae5SAleksey Makarov }
248910879ae5SAleksey Makarov 
2490ab4382d2SGreg Kroah-Hartman static struct uart_driver amba_reg;
2491ab4382d2SGreg Kroah-Hartman static struct console amba_console = {
2492ab4382d2SGreg Kroah-Hartman 	.name		= "ttyAMA",
2493ab4382d2SGreg Kroah-Hartman 	.write		= pl011_console_write,
2494ab4382d2SGreg Kroah-Hartman 	.device		= uart_console_device,
2495ab4382d2SGreg Kroah-Hartman 	.setup		= pl011_console_setup,
249610879ae5SAleksey Makarov 	.match		= pl011_console_match,
24977951ffc9SAlexander Sverdlin 	.flags		= CON_PRINTBUFFER | CON_ANYTIME,
2498ab4382d2SGreg Kroah-Hartman 	.index		= -1,
2499ab4382d2SGreg Kroah-Hartman 	.data		= &amba_reg,
2500ab4382d2SGreg Kroah-Hartman };
2501ab4382d2SGreg Kroah-Hartman 
2502ab4382d2SGreg Kroah-Hartman #define AMBA_CONSOLE	(&amba_console)
25030d3c673eSRob Herring 
qdf2400_e44_putc(struct uart_port * port,unsigned char c)25043f8bab17SJiri Slaby static void qdf2400_e44_putc(struct uart_port *port, unsigned char c)
2505d8a4995bSChristopher Covington {
2506d8a4995bSChristopher Covington 	while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
2507d8a4995bSChristopher Covington 		cpu_relax();
2508d8a4995bSChristopher Covington 	writel(c, port->membase + UART01x_DR);
2509d8a4995bSChristopher Covington 	while (!(readl(port->membase + UART01x_FR) & UART011_FR_TXFE))
2510d8a4995bSChristopher Covington 		cpu_relax();
2511d8a4995bSChristopher Covington }
2512d8a4995bSChristopher Covington 
qdf2400_e44_early_write(struct console * con,const char * s,unsigned int n)2513826bd77aSThéo Lebrun static void qdf2400_e44_early_write(struct console *con, const char *s, unsigned int n)
2514d8a4995bSChristopher Covington {
2515d8a4995bSChristopher Covington 	struct earlycon_device *dev = con->data;
2516d8a4995bSChristopher Covington 
2517d8a4995bSChristopher Covington 	uart_console_write(&dev->port, s, n, qdf2400_e44_putc);
2518d8a4995bSChristopher Covington }
2519d8a4995bSChristopher Covington 
pl011_putc(struct uart_port * port,unsigned char c)25203f8bab17SJiri Slaby static void pl011_putc(struct uart_port *port, unsigned char c)
25210d3c673eSRob Herring {
2522cdf091caSRussell King 	while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
25232f2fd089STimur Tabi 		cpu_relax();
25243b78fae7STimur Tabi 	if (port->iotype == UPIO_MEM32)
25253b78fae7STimur Tabi 		writel(c, port->membase + UART01x_DR);
25263b78fae7STimur Tabi 	else
2527cdf091caSRussell King 		writeb(c, port->membase + UART01x_DR);
2528e06690bfSShawn Guo 	while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)
25292f2fd089STimur Tabi 		cpu_relax();
25300d3c673eSRob Herring }
25310d3c673eSRob Herring 
pl011_early_write(struct console * con,const char * s,unsigned int n)2532826bd77aSThéo Lebrun static void pl011_early_write(struct console *con, const char *s, unsigned int n)
25330d3c673eSRob Herring {
25340d3c673eSRob Herring 	struct earlycon_device *dev = con->data;
25350d3c673eSRob Herring 
25360d3c673eSRob Herring 	uart_console_write(&dev->port, s, n, pl011_putc);
25370d3c673eSRob Herring }
25380d3c673eSRob Herring 
2539195867ffSSumit Garg #ifdef CONFIG_CONSOLE_POLL
pl011_getc(struct uart_port * port)2540195867ffSSumit Garg static int pl011_getc(struct uart_port *port)
2541195867ffSSumit Garg {
2542195867ffSSumit Garg 	if (readl(port->membase + UART01x_FR) & UART01x_FR_RXFE)
2543195867ffSSumit Garg 		return NO_POLL_CHAR;
2544195867ffSSumit Garg 
2545195867ffSSumit Garg 	if (port->iotype == UPIO_MEM32)
2546195867ffSSumit Garg 		return readl(port->membase + UART01x_DR);
2547195867ffSSumit Garg 	else
2548195867ffSSumit Garg 		return readb(port->membase + UART01x_DR);
2549195867ffSSumit Garg }
2550195867ffSSumit Garg 
pl011_early_read(struct console * con,char * s,unsigned int n)2551195867ffSSumit Garg static int pl011_early_read(struct console *con, char *s, unsigned int n)
2552195867ffSSumit Garg {
2553195867ffSSumit Garg 	struct earlycon_device *dev = con->data;
2554195867ffSSumit Garg 	int ch, num_read = 0;
2555195867ffSSumit Garg 
2556195867ffSSumit Garg 	while (num_read < n) {
2557195867ffSSumit Garg 		ch = pl011_getc(&dev->port);
2558195867ffSSumit Garg 		if (ch == NO_POLL_CHAR)
2559195867ffSSumit Garg 			break;
2560195867ffSSumit Garg 
2561195867ffSSumit Garg 		s[num_read++] = ch;
2562195867ffSSumit Garg 	}
2563195867ffSSumit Garg 
2564195867ffSSumit Garg 	return num_read;
2565195867ffSSumit Garg }
2566195867ffSSumit Garg #else
2567195867ffSSumit Garg #define pl011_early_read NULL
2568195867ffSSumit Garg #endif
2569195867ffSSumit Garg 
2570e53e597fSTimur Tabi /*
2571e53e597fSTimur Tabi  * On non-ACPI systems, earlycon is enabled by specifying
2572e53e597fSTimur Tabi  * "earlycon=pl011,<address>" on the kernel command line.
2573e53e597fSTimur Tabi  *
2574e53e597fSTimur Tabi  * On ACPI ARM64 systems, an "early" console is enabled via the SPCR table,
2575e53e597fSTimur Tabi  * by specifying only "earlycon" on the command line.  Because it requires
2576e53e597fSTimur Tabi  * SPCR, the console starts after ACPI is parsed, which is later than a
2577e53e597fSTimur Tabi  * traditional early console.
2578e53e597fSTimur Tabi  *
2579e53e597fSTimur Tabi  * To get the traditional early console that starts before ACPI is parsed,
2580e53e597fSTimur Tabi  * specify the full "earlycon=pl011,<address>" option.
2581e53e597fSTimur Tabi  */
pl011_early_console_setup(struct earlycon_device * device,const char * opt)25820d3c673eSRob Herring static int __init pl011_early_console_setup(struct earlycon_device *device,
25830d3c673eSRob Herring 					    const char *opt)
25840d3c673eSRob Herring {
25850d3c673eSRob Herring 	if (!device->port.membase)
25860d3c673eSRob Herring 		return -ENODEV;
25870d3c673eSRob Herring 
2588e53e597fSTimur Tabi 	device->con->write = pl011_early_write;
2589195867ffSSumit Garg 	device->con->read = pl011_early_read;
2590e53e597fSTimur Tabi 
25910d3c673eSRob Herring 	return 0;
25920d3c673eSRob Herring }
2593d93ebe0fSThéo Lebrun 
259445e0f0f5SRob Herring OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);
2595d93ebe0fSThéo Lebrun 
2596fcb32159SKefeng Wang OF_EARLYCON_DECLARE(pl011, "arm,sbsa-uart", pl011_early_console_setup);
25975a0722b8STimur Tabi 
25985a0722b8STimur Tabi /*
25995a0722b8STimur Tabi  * On Qualcomm Datacenter Technologies QDF2400 SOCs affected by
26005a0722b8STimur Tabi  * Erratum 44, traditional earlycon can be enabled by specifying
26015a0722b8STimur Tabi  * "earlycon=qdf2400_e44,<address>".  Any options are ignored.
26025a0722b8STimur Tabi  *
26035a0722b8STimur Tabi  * Alternatively, you can just specify "earlycon", and the early console
26045a0722b8STimur Tabi  * will be enabled with the information from the SPCR table.  In this
26055a0722b8STimur Tabi  * case, the SPCR code will detect the need for the E44 work-around,
26065a0722b8STimur Tabi  * and set the console name to "qdf2400_e44".
26075a0722b8STimur Tabi  */
26085a0722b8STimur Tabi static int __init
qdf2400_e44_early_console_setup(struct earlycon_device * device,const char * opt)26095a0722b8STimur Tabi qdf2400_e44_early_console_setup(struct earlycon_device *device,
26105a0722b8STimur Tabi 				const char *opt)
26115a0722b8STimur Tabi {
26125a0722b8STimur Tabi 	if (!device->port.membase)
26135a0722b8STimur Tabi 		return -ENODEV;
26145a0722b8STimur Tabi 
26155a0722b8STimur Tabi 	device->con->write = qdf2400_e44_early_write;
26165a0722b8STimur Tabi 	return 0;
26175a0722b8STimur Tabi }
2618d93ebe0fSThéo Lebrun 
26195a0722b8STimur Tabi EARLYCON_DECLARE(qdf2400_e44, qdf2400_e44_early_console_setup);
26200d3c673eSRob Herring 
2621ab4382d2SGreg Kroah-Hartman #else
2622ab4382d2SGreg Kroah-Hartman #define AMBA_CONSOLE	NULL
2623ab4382d2SGreg Kroah-Hartman #endif
2624ab4382d2SGreg Kroah-Hartman 
2625ab4382d2SGreg Kroah-Hartman static struct uart_driver amba_reg = {
2626ab4382d2SGreg Kroah-Hartman 	.owner			= THIS_MODULE,
2627ab4382d2SGreg Kroah-Hartman 	.driver_name		= "ttyAMA",
2628ab4382d2SGreg Kroah-Hartman 	.dev_name		= "ttyAMA",
2629ab4382d2SGreg Kroah-Hartman 	.major			= SERIAL_AMBA_MAJOR,
2630ab4382d2SGreg Kroah-Hartman 	.minor			= SERIAL_AMBA_MINOR,
2631ab4382d2SGreg Kroah-Hartman 	.nr			= UART_NR,
2632ab4382d2SGreg Kroah-Hartman 	.cons			= AMBA_CONSOLE,
2633ab4382d2SGreg Kroah-Hartman };
2634ab4382d2SGreg Kroah-Hartman 
pl011_probe_dt_alias(int index,struct device * dev)263532614aadSMatthew Leach static int pl011_probe_dt_alias(int index, struct device *dev)
263632614aadSMatthew Leach {
263732614aadSMatthew Leach 	struct device_node *np;
2638826bd77aSThéo Lebrun 	static bool seen_dev_with_alias;
2639826bd77aSThéo Lebrun 	static bool seen_dev_without_alias;
264032614aadSMatthew Leach 	int ret = index;
264132614aadSMatthew Leach 
264232614aadSMatthew Leach 	if (!IS_ENABLED(CONFIG_OF))
264332614aadSMatthew Leach 		return ret;
264432614aadSMatthew Leach 
264532614aadSMatthew Leach 	np = dev->of_node;
264632614aadSMatthew Leach 	if (!np)
264732614aadSMatthew Leach 		return ret;
264832614aadSMatthew Leach 
264932614aadSMatthew Leach 	ret = of_alias_get_id(np, "serial");
2650287980e4SArnd Bergmann 	if (ret < 0) {
265132614aadSMatthew Leach 		seen_dev_without_alias = true;
265232614aadSMatthew Leach 		ret = index;
265332614aadSMatthew Leach 	} else {
265432614aadSMatthew Leach 		seen_dev_with_alias = true;
265528a7ec8cSThéo Lebrun 		if (ret >= ARRAY_SIZE(amba_ports) || amba_ports[ret]) {
265632614aadSMatthew Leach 			dev_warn(dev, "requested serial port %d  not available.\n", ret);
265732614aadSMatthew Leach 			ret = index;
265832614aadSMatthew Leach 		}
265932614aadSMatthew Leach 	}
266032614aadSMatthew Leach 
266132614aadSMatthew Leach 	if (seen_dev_with_alias && seen_dev_without_alias)
266232614aadSMatthew Leach 		dev_warn(dev, "aliased and non-aliased serial devices found in device tree. Serial port enumeration may be unpredictable.\n");
266332614aadSMatthew Leach 
266432614aadSMatthew Leach 	return ret;
266532614aadSMatthew Leach }
266632614aadSMatthew Leach 
266749bb3c86SAndre Przywara /* unregisters the driver also if no more ports are left */
pl011_unregister_port(struct uart_amba_port * uap)266849bb3c86SAndre Przywara static void pl011_unregister_port(struct uart_amba_port *uap)
266949bb3c86SAndre Przywara {
267049bb3c86SAndre Przywara 	int i;
267149bb3c86SAndre Przywara 	bool busy = false;
267249bb3c86SAndre Przywara 
267349bb3c86SAndre Przywara 	for (i = 0; i < ARRAY_SIZE(amba_ports); i++) {
267449bb3c86SAndre Przywara 		if (amba_ports[i] == uap)
267549bb3c86SAndre Przywara 			amba_ports[i] = NULL;
267649bb3c86SAndre Przywara 		else if (amba_ports[i])
267749bb3c86SAndre Przywara 			busy = true;
267849bb3c86SAndre Przywara 	}
267949bb3c86SAndre Przywara 	pl011_dma_remove(uap);
268049bb3c86SAndre Przywara 	if (!busy)
268149bb3c86SAndre Przywara 		uart_unregister_driver(&amba_reg);
268249bb3c86SAndre Przywara }
268349bb3c86SAndre Przywara 
pl011_find_free_port(void)26843873e2d7SAndre Przywara static int pl011_find_free_port(void)
2685ab4382d2SGreg Kroah-Hartman {
26863873e2d7SAndre Przywara 	int i;
2687ab4382d2SGreg Kroah-Hartman 
2688ab4382d2SGreg Kroah-Hartman 	for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
268928a7ec8cSThéo Lebrun 		if (!amba_ports[i])
26903873e2d7SAndre Przywara 			return i;
2691ab4382d2SGreg Kroah-Hartman 
26927f6d942aSTushar Behera 	return -EBUSY;
26933873e2d7SAndre Przywara }
2694ab4382d2SGreg Kroah-Hartman 
pl011_setup_port(struct device * dev,struct uart_amba_port * uap,struct resource * mmiobase,int index)26953873e2d7SAndre Przywara static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
26963873e2d7SAndre Przywara 			    struct resource *mmiobase, int index)
26973873e2d7SAndre Przywara {
26983873e2d7SAndre Przywara 	void __iomem *base;
26998d479237SLino Sanfilippo 	int ret;
2700ab4382d2SGreg Kroah-Hartman 
27013873e2d7SAndre Przywara 	base = devm_ioremap_resource(dev, mmiobase);
270297a60eacSKrzysztof Kozlowski 	if (IS_ERR(base))
270397a60eacSKrzysztof Kozlowski 		return PTR_ERR(base);
2704ab4382d2SGreg Kroah-Hartman 
27053873e2d7SAndre Przywara 	index = pl011_probe_dt_alias(index, dev);
2706ab4382d2SGreg Kroah-Hartman 
27073873e2d7SAndre Przywara 	uap->port.dev = dev;
27083873e2d7SAndre Przywara 	uap->port.mapbase = mmiobase->start;
2709ab4382d2SGreg Kroah-Hartman 	uap->port.membase = base;
2710ab4382d2SGreg Kroah-Hartman 	uap->port.fifosize = uap->fifosize;
27115f99fca9SDmitry Safonov 	uap->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_AMBA_PL011_CONSOLE);
2712ab4382d2SGreg Kroah-Hartman 	uap->port.flags = UPF_BOOT_AUTOCONF;
27133873e2d7SAndre Przywara 	uap->port.line = index;
27143873e2d7SAndre Przywara 
2715838022deSLino Sanfilippo 	ret = uart_get_rs485_mode(&uap->port);
27168d479237SLino Sanfilippo 	if (ret)
27178d479237SLino Sanfilippo 		return ret;
27188d479237SLino Sanfilippo 
27193873e2d7SAndre Przywara 	amba_ports[index] = uap;
27203873e2d7SAndre Przywara 
27213873e2d7SAndre Przywara 	return 0;
27223873e2d7SAndre Przywara }
27233873e2d7SAndre Przywara 
pl011_register_port(struct uart_amba_port * uap)27243873e2d7SAndre Przywara static int pl011_register_port(struct uart_amba_port *uap)
27253873e2d7SAndre Przywara {
272689efbe70SLukas Wunner 	int ret, i;
2727ab4382d2SGreg Kroah-Hartman 
2728c3d8b76fSLinus Walleij 	/* Ensure interrupts from this UART are masked and cleared */
27299f25bc51SRussell King 	pl011_write(0, uap, REG_IMSC);
27309f25bc51SRussell King 	pl011_write(0xffff, uap, REG_ICR);
2731c3d8b76fSLinus Walleij 
2732ef2889f7STushar Behera 	if (!amba_reg.state) {
2733ef2889f7STushar Behera 		ret = uart_register_driver(&amba_reg);
2734ef2889f7STushar Behera 		if (ret < 0) {
27353873e2d7SAndre Przywara 			dev_err(uap->port.dev,
27361c9be310SJorge Ramirez-Ortiz 				"Failed to register AMBA-PL011 driver\n");
273789efbe70SLukas Wunner 			for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
273889efbe70SLukas Wunner 				if (amba_ports[i] == uap)
273989efbe70SLukas Wunner 					amba_ports[i] = NULL;
2740ef2889f7STushar Behera 			return ret;
2741ef2889f7STushar Behera 		}
2742ef2889f7STushar Behera 	}
2743ef2889f7STushar Behera 
2744ab4382d2SGreg Kroah-Hartman 	ret = uart_add_one_port(&amba_reg, &uap->port);
274549bb3c86SAndre Przywara 	if (ret)
274649bb3c86SAndre Przywara 		pl011_unregister_port(uap);
27477f6d942aSTushar Behera 
2748ab4382d2SGreg Kroah-Hartman 	return ret;
2749ab4382d2SGreg Kroah-Hartman }
2750ab4382d2SGreg Kroah-Hartman 
2751ebe2cf73SIlpo Järvinen static const struct serial_rs485 pl011_rs485_supported = {
2752ebe2cf73SIlpo Järvinen 	.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND |
2753ebe2cf73SIlpo Järvinen 		 SER_RS485_RX_DURING_TX,
2754ebe2cf73SIlpo Järvinen 	.delay_rts_before_send = 1,
2755ebe2cf73SIlpo Järvinen 	.delay_rts_after_send = 1,
2756ebe2cf73SIlpo Järvinen };
2757ebe2cf73SIlpo Järvinen 
pl011_probe(struct amba_device * dev,const struct amba_id * id)27583873e2d7SAndre Przywara static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
27593873e2d7SAndre Przywara {
27603873e2d7SAndre Przywara 	struct uart_amba_port *uap;
27613873e2d7SAndre Przywara 	struct vendor_data *vendor = id->data;
27623873e2d7SAndre Przywara 	int portnr, ret;
276381db9e8eSShubhrajyoti Datta 	u32 val;
27643873e2d7SAndre Przywara 
27653873e2d7SAndre Przywara 	portnr = pl011_find_free_port();
27663873e2d7SAndre Przywara 	if (portnr < 0)
27673873e2d7SAndre Przywara 		return portnr;
27683873e2d7SAndre Przywara 
27693873e2d7SAndre Przywara 	uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port),
27703873e2d7SAndre Przywara 			   GFP_KERNEL);
27713873e2d7SAndre Przywara 	if (!uap)
27723873e2d7SAndre Przywara 		return -ENOMEM;
27733873e2d7SAndre Przywara 
27743873e2d7SAndre Przywara 	uap->clk = devm_clk_get(&dev->dev, NULL);
27753873e2d7SAndre Przywara 	if (IS_ERR(uap->clk))
27763873e2d7SAndre Przywara 		return PTR_ERR(uap->clk);
27773873e2d7SAndre Przywara 
2778439403bdSRussell King 	uap->reg_offset = vendor->reg_offset;
27793873e2d7SAndre Przywara 	uap->vendor = vendor;
27803873e2d7SAndre Przywara 	uap->fifosize = vendor->get_fifosize(dev);
27813b78fae7STimur Tabi 	uap->port.iotype = vendor->access_32b ? UPIO_MEM32 : UPIO_MEM;
27823873e2d7SAndre Przywara 	uap->port.irq = dev->irq[0];
27833873e2d7SAndre Przywara 	uap->port.ops = &amba_pl011_pops;
27848d479237SLino Sanfilippo 	uap->port.rs485_config = pl011_rs485_config;
27850139da50SIlpo Järvinen 	uap->port.rs485_supported = pl011_rs485_supported;
27863873e2d7SAndre Przywara 	snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
27873873e2d7SAndre Przywara 
278881db9e8eSShubhrajyoti Datta 	if (device_property_read_u32(&dev->dev, "reg-io-width", &val) == 0) {
278981db9e8eSShubhrajyoti Datta 		switch (val) {
279081db9e8eSShubhrajyoti Datta 		case 1:
279181db9e8eSShubhrajyoti Datta 			uap->port.iotype = UPIO_MEM;
279281db9e8eSShubhrajyoti Datta 			break;
279381db9e8eSShubhrajyoti Datta 		case 4:
279481db9e8eSShubhrajyoti Datta 			uap->port.iotype = UPIO_MEM32;
279581db9e8eSShubhrajyoti Datta 			break;
279681db9e8eSShubhrajyoti Datta 		default:
279781db9e8eSShubhrajyoti Datta 			dev_warn(&dev->dev, "unsupported reg-io-width (%d)\n",
279881db9e8eSShubhrajyoti Datta 				 val);
279981db9e8eSShubhrajyoti Datta 			return -EINVAL;
280081db9e8eSShubhrajyoti Datta 		}
280181db9e8eSShubhrajyoti Datta 	}
280281db9e8eSShubhrajyoti Datta 
28033873e2d7SAndre Przywara 	ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr);
28043873e2d7SAndre Przywara 	if (ret)
28053873e2d7SAndre Przywara 		return ret;
28063873e2d7SAndre Przywara 
28073873e2d7SAndre Przywara 	amba_set_drvdata(dev, uap);
28083873e2d7SAndre Przywara 
28093873e2d7SAndre Przywara 	return pl011_register_port(uap);
28103873e2d7SAndre Przywara }
28113873e2d7SAndre Przywara 
pl011_remove(struct amba_device * dev)28123fd269e7SUwe Kleine-König static void pl011_remove(struct amba_device *dev)
2813ab4382d2SGreg Kroah-Hartman {
2814ab4382d2SGreg Kroah-Hartman 	struct uart_amba_port *uap = amba_get_drvdata(dev);
2815ab4382d2SGreg Kroah-Hartman 
2816ab4382d2SGreg Kroah-Hartman 	uart_remove_one_port(&amba_reg, &uap->port);
281749bb3c86SAndre Przywara 	pl011_unregister_port(uap);
2818ab4382d2SGreg Kroah-Hartman }
2819ab4382d2SGreg Kroah-Hartman 
2820d0ce850dSUlf Hansson #ifdef CONFIG_PM_SLEEP
pl011_suspend(struct device * dev)2821d0ce850dSUlf Hansson static int pl011_suspend(struct device *dev)
2822ab4382d2SGreg Kroah-Hartman {
2823d0ce850dSUlf Hansson 	struct uart_amba_port *uap = dev_get_drvdata(dev);
2824ab4382d2SGreg Kroah-Hartman 
2825ab4382d2SGreg Kroah-Hartman 	if (!uap)
2826ab4382d2SGreg Kroah-Hartman 		return -EINVAL;
2827ab4382d2SGreg Kroah-Hartman 
2828ab4382d2SGreg Kroah-Hartman 	return uart_suspend_port(&amba_reg, &uap->port);
2829ab4382d2SGreg Kroah-Hartman }
2830ab4382d2SGreg Kroah-Hartman 
pl011_resume(struct device * dev)2831d0ce850dSUlf Hansson static int pl011_resume(struct device *dev)
2832ab4382d2SGreg Kroah-Hartman {
2833d0ce850dSUlf Hansson 	struct uart_amba_port *uap = dev_get_drvdata(dev);
2834ab4382d2SGreg Kroah-Hartman 
2835ab4382d2SGreg Kroah-Hartman 	if (!uap)
2836ab4382d2SGreg Kroah-Hartman 		return -EINVAL;
2837ab4382d2SGreg Kroah-Hartman 
2838ab4382d2SGreg Kroah-Hartman 	return uart_resume_port(&amba_reg, &uap->port);
2839ab4382d2SGreg Kroah-Hartman }
2840ab4382d2SGreg Kroah-Hartman #endif
2841ab4382d2SGreg Kroah-Hartman 
2842d0ce850dSUlf Hansson static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume);
2843d0ce850dSUlf Hansson 
2844a49a8b9dSThéo Lebrun #ifdef CONFIG_ACPI_SPCR_TABLE
qpdf2400_erratum44_workaround(struct device * dev,struct uart_amba_port * uap)2845a49a8b9dSThéo Lebrun static void qpdf2400_erratum44_workaround(struct device *dev,
2846a49a8b9dSThéo Lebrun 					  struct uart_amba_port *uap)
2847a49a8b9dSThéo Lebrun {
2848a49a8b9dSThéo Lebrun 	if (!qdf2400_e44_present)
2849a49a8b9dSThéo Lebrun 		return;
2850a49a8b9dSThéo Lebrun 
2851a49a8b9dSThéo Lebrun 	dev_info(dev, "working around QDF2400 SoC erratum 44\n");
2852a49a8b9dSThéo Lebrun 	uap->vendor = &vendor_qdt_qdf2400_e44;
2853a49a8b9dSThéo Lebrun }
2854a49a8b9dSThéo Lebrun #else
qpdf2400_erratum44_workaround(struct device * dev,struct uart_amba_port * uap)2855a49a8b9dSThéo Lebrun static void qpdf2400_erratum44_workaround(struct device *dev,
2856a49a8b9dSThéo Lebrun 					  struct uart_amba_port *uap)
2857a49a8b9dSThéo Lebrun { /* empty */ }
2858a49a8b9dSThéo Lebrun #endif
2859a49a8b9dSThéo Lebrun 
sbsa_uart_probe(struct platform_device * pdev)28600dd1e247SAndre Przywara static int sbsa_uart_probe(struct platform_device *pdev)
28610dd1e247SAndre Przywara {
28620dd1e247SAndre Przywara 	struct uart_amba_port *uap;
28630dd1e247SAndre Przywara 	struct resource *r;
28640dd1e247SAndre Przywara 	int portnr, ret;
28650dd1e247SAndre Przywara 	int baudrate;
28660dd1e247SAndre Przywara 
28670dd1e247SAndre Przywara 	/*
28680dd1e247SAndre Przywara 	 * Check the mandatory baud rate parameter in the DT node early
28690dd1e247SAndre Przywara 	 * so that we can easily exit with the error.
28700dd1e247SAndre Przywara 	 */
28710dd1e247SAndre Przywara 	if (pdev->dev.of_node) {
28720dd1e247SAndre Przywara 		struct device_node *np = pdev->dev.of_node;
28730dd1e247SAndre Przywara 
28740dd1e247SAndre Przywara 		ret = of_property_read_u32(np, "current-speed", &baudrate);
28750dd1e247SAndre Przywara 		if (ret)
28760dd1e247SAndre Przywara 			return ret;
28770dd1e247SAndre Przywara 	} else {
28780dd1e247SAndre Przywara 		baudrate = 115200;
28790dd1e247SAndre Przywara 	}
28800dd1e247SAndre Przywara 
28810dd1e247SAndre Przywara 	portnr = pl011_find_free_port();
28820dd1e247SAndre Przywara 	if (portnr < 0)
28830dd1e247SAndre Przywara 		return portnr;
28840dd1e247SAndre Przywara 
28850dd1e247SAndre Przywara 	uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port),
28860dd1e247SAndre Przywara 			   GFP_KERNEL);
28870dd1e247SAndre Przywara 	if (!uap)
28880dd1e247SAndre Przywara 		return -ENOMEM;
28890dd1e247SAndre Przywara 
2890394a9e2cSJiri Slaby 	ret = platform_get_irq(pdev, 0);
28911df21786SStephen Boyd 	if (ret < 0)
2892394a9e2cSJiri Slaby 		return ret;
2893394a9e2cSJiri Slaby 	uap->port.irq	= ret;
2894394a9e2cSJiri Slaby 
289537ef38f3STimur Tabi 	uap->vendor = &vendor_sbsa;
2896a49a8b9dSThéo Lebrun 	qpdf2400_erratum44_workaround(&pdev->dev, uap);
289737ef38f3STimur Tabi 
289837ef38f3STimur Tabi 	uap->reg_offset	= uap->vendor->reg_offset;
28990dd1e247SAndre Przywara 	uap->fifosize	= 32;
290037ef38f3STimur Tabi 	uap->port.iotype = uap->vendor->access_32b ? UPIO_MEM32 : UPIO_MEM;
29010dd1e247SAndre Przywara 	uap->port.ops	= &sbsa_uart_pops;
29020dd1e247SAndre Przywara 	uap->fixed_baud = baudrate;
29030dd1e247SAndre Przywara 
29040dd1e247SAndre Przywara 	snprintf(uap->type, sizeof(uap->type), "SBSA");
29050dd1e247SAndre Przywara 
29060dd1e247SAndre Przywara 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
29070dd1e247SAndre Przywara 
29080dd1e247SAndre Przywara 	ret = pl011_setup_port(&pdev->dev, uap, r, portnr);
29090dd1e247SAndre Przywara 	if (ret)
29100dd1e247SAndre Przywara 		return ret;
29110dd1e247SAndre Przywara 
29120dd1e247SAndre Przywara 	platform_set_drvdata(pdev, uap);
29130dd1e247SAndre Przywara 
29140dd1e247SAndre Przywara 	return pl011_register_port(uap);
29150dd1e247SAndre Przywara }
29160dd1e247SAndre Przywara 
sbsa_uart_remove(struct platform_device * pdev)2917788f501aSUwe Kleine-König static void sbsa_uart_remove(struct platform_device *pdev)
29180dd1e247SAndre Przywara {
29190dd1e247SAndre Przywara 	struct uart_amba_port *uap = platform_get_drvdata(pdev);
29200dd1e247SAndre Przywara 
29210dd1e247SAndre Przywara 	uart_remove_one_port(&amba_reg, &uap->port);
29220dd1e247SAndre Przywara 	pl011_unregister_port(uap);
29230dd1e247SAndre Przywara }
29240dd1e247SAndre Przywara 
29250dd1e247SAndre Przywara static const struct of_device_id sbsa_uart_of_match[] = {
29260dd1e247SAndre Przywara 	{ .compatible = "arm,sbsa-uart", },
29270dd1e247SAndre Przywara 	{},
29280dd1e247SAndre Przywara };
29290dd1e247SAndre Przywara MODULE_DEVICE_TABLE(of, sbsa_uart_of_match);
29300dd1e247SAndre Przywara 
29317789c1f1SLee Jones static const struct acpi_device_id __maybe_unused sbsa_uart_acpi_match[] = {
29323db9ab0bSGraeme Gregory 	{ "ARMH0011", 0 },
2933ac442a07SPierre Gondois 	{ "ARMHB000", 0 },
29343db9ab0bSGraeme Gregory 	{},
29353db9ab0bSGraeme Gregory };
29363db9ab0bSGraeme Gregory MODULE_DEVICE_TABLE(acpi, sbsa_uart_acpi_match);
29373db9ab0bSGraeme Gregory 
29380dd1e247SAndre Przywara static struct platform_driver arm_sbsa_uart_platform_driver = {
29390dd1e247SAndre Przywara 	.probe		= sbsa_uart_probe,
2940788f501aSUwe Kleine-König 	.remove_new	= sbsa_uart_remove,
29410dd1e247SAndre Przywara 	.driver	= {
29420dd1e247SAndre Przywara 		.name	= "sbsa-uart",
29432301ec36SShubhrajyoti Datta 		.pm	= &pl011_dev_pm_ops,
29440dd1e247SAndre Przywara 		.of_match_table = of_match_ptr(sbsa_uart_of_match),
29453db9ab0bSGraeme Gregory 		.acpi_match_table = ACPI_PTR(sbsa_uart_acpi_match),
294664609794SAnders Roxell 		.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
29470dd1e247SAndre Przywara 	},
29480dd1e247SAndre Przywara };
29490dd1e247SAndre Przywara 
2950a704ddc2SArvind Yadav static const struct amba_id pl011_ids[] = {
2951ab4382d2SGreg Kroah-Hartman 	{
2952ab4382d2SGreg Kroah-Hartman 		.id	= 0x00041011,
2953ab4382d2SGreg Kroah-Hartman 		.mask	= 0x000fffff,
2954ab4382d2SGreg Kroah-Hartman 		.data	= &vendor_arm,
2955ab4382d2SGreg Kroah-Hartman 	},
2956ab4382d2SGreg Kroah-Hartman 	{
2957ab4382d2SGreg Kroah-Hartman 		.id	= 0x00380802,
2958ab4382d2SGreg Kroah-Hartman 		.mask	= 0x00ffffff,
2959ab4382d2SGreg Kroah-Hartman 		.data	= &vendor_st,
2960ab4382d2SGreg Kroah-Hartman 	},
2961ab4382d2SGreg Kroah-Hartman 	{ 0, 0 },
2962ab4382d2SGreg Kroah-Hartman };
2963ab4382d2SGreg Kroah-Hartman 
296460f7a33bSDave Martin MODULE_DEVICE_TABLE(amba, pl011_ids);
296560f7a33bSDave Martin 
2966ab4382d2SGreg Kroah-Hartman static struct amba_driver pl011_driver = {
2967ab4382d2SGreg Kroah-Hartman 	.drv = {
2968ab4382d2SGreg Kroah-Hartman 		.name	= "uart-pl011",
2969d0ce850dSUlf Hansson 		.pm	= &pl011_dev_pm_ops,
297064609794SAnders Roxell 		.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
2971ab4382d2SGreg Kroah-Hartman 	},
2972ab4382d2SGreg Kroah-Hartman 	.id_table	= pl011_ids,
2973ab4382d2SGreg Kroah-Hartman 	.probe		= pl011_probe,
2974ab4382d2SGreg Kroah-Hartman 	.remove		= pl011_remove,
2975ab4382d2SGreg Kroah-Hartman };
2976ab4382d2SGreg Kroah-Hartman 
pl011_init(void)2977ab4382d2SGreg Kroah-Hartman static int __init pl011_init(void)
2978ab4382d2SGreg Kroah-Hartman {
2979826bd77aSThéo Lebrun 	pr_info("Serial: AMBA PL011 UART driver\n");
2980ab4382d2SGreg Kroah-Hartman 
29810dd1e247SAndre Przywara 	if (platform_driver_register(&arm_sbsa_uart_platform_driver))
29820dd1e247SAndre Przywara 		pr_warn("could not register SBSA UART platform driver\n");
2983062a68a5SGreg Kroah-Hartman 	return amba_driver_register(&pl011_driver);
2984ab4382d2SGreg Kroah-Hartman }
2985ab4382d2SGreg Kroah-Hartman 
pl011_exit(void)2986ab4382d2SGreg Kroah-Hartman static void __exit pl011_exit(void)
2987ab4382d2SGreg Kroah-Hartman {
29880dd1e247SAndre Przywara 	platform_driver_unregister(&arm_sbsa_uart_platform_driver);
2989ab4382d2SGreg Kroah-Hartman 	amba_driver_unregister(&pl011_driver);
2990ab4382d2SGreg Kroah-Hartman }
2991ab4382d2SGreg Kroah-Hartman 
2992ab4382d2SGreg Kroah-Hartman /*
2993ab4382d2SGreg Kroah-Hartman  * While this can be a module, if builtin it's most likely the console
2994ab4382d2SGreg Kroah-Hartman  * So let's leave module_exit but move module_init to an earlier place
2995ab4382d2SGreg Kroah-Hartman  */
2996ab4382d2SGreg Kroah-Hartman arch_initcall(pl011_init);
2997ab4382d2SGreg Kroah-Hartman module_exit(pl011_exit);
2998ab4382d2SGreg Kroah-Hartman 
2999ab4382d2SGreg Kroah-Hartman MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
3000ab4382d2SGreg Kroah-Hartman MODULE_DESCRIPTION("ARM AMBA serial port driver");
3001ab4382d2SGreg Kroah-Hartman MODULE_LICENSE("GPL");
3002