xref: /openbmc/linux/drivers/tty/serial/amba-pl011.c (revision 278002edb19bce2c628fafb0af936e77000f3a5b)
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)
54ab4382d2SGreg Kroah-Hartman #define UART_DUMMY_DR_RX	(1 << 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 
221c865b77eSArnd Bergmann struct pl011_dmabuf {
222c865b77eSArnd Bergmann 	dma_addr_t		dma;
223c865b77eSArnd 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;
231c865b77eSArnd Bergmann 	struct pl011_dmabuf	dbuf_a;
232c865b77eSArnd 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;
245c865b77eSArnd Bergmann 	dma_addr_t		dma;
246c865b77eSArnd 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		dmacr;		/* dma control reg */
260ab4382d2SGreg Kroah-Hartman 	unsigned int		im;		/* interrupt mask */
261ab4382d2SGreg Kroah-Hartman 	unsigned int		old_status;
262ab4382d2SGreg Kroah-Hartman 	unsigned int		fifosize;	/* vendor-specific */
263cefc2d1dSAndre Przywara 	unsigned int		fixed_baud;	/* vendor-set fixed baud rate */
264ab4382d2SGreg Kroah-Hartman 	char			type[12];
2658d479237SLino Sanfilippo 	bool			rs485_tx_started;
2668d479237SLino Sanfilippo 	unsigned int		rs485_tx_drain_interval; /* usecs */
267ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_DMA_ENGINE
268ab4382d2SGreg Kroah-Hartman 	/* DMA stuff */
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;
33329772c4eSLinus Walleij 			} else if (ch & UART011_DR_PE)
33429772c4eSLinus Walleij 				uap->port.icount.parity++;
33529772c4eSLinus Walleij 			else if (ch & UART011_DR_FE)
33629772c4eSLinus Walleij 				uap->port.icount.frame++;
33729772c4eSLinus Walleij 			if (ch & UART011_DR_OE)
33829772c4eSLinus Walleij 				uap->port.icount.overrun++;
33929772c4eSLinus Walleij 
34029772c4eSLinus Walleij 			ch &= uap->port.read_status_mask;
34129772c4eSLinus Walleij 
34229772c4eSLinus Walleij 			if (ch & UART011_DR_BE)
34329772c4eSLinus Walleij 				flag = TTY_BREAK;
34429772c4eSLinus Walleij 			else if (ch & UART011_DR_PE)
34529772c4eSLinus Walleij 				flag = TTY_PARITY;
34629772c4eSLinus Walleij 			else if (ch & UART011_DR_FE)
34729772c4eSLinus Walleij 				flag = TTY_FRAME;
34829772c4eSLinus Walleij 		}
34929772c4eSLinus Walleij 
3505aea1229SThomas Gleixner 		uart_port_unlock(&uap->port);
351534cf755SPeter Zijlstra 		sysrq = uart_handle_sysrq_char(&uap->port, ch & 255);
3525aea1229SThomas Gleixner 		uart_port_lock(&uap->port);
35329772c4eSLinus Walleij 
354534cf755SPeter Zijlstra 		if (!sysrq)
35529772c4eSLinus Walleij 			uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
35629772c4eSLinus Walleij 	}
35729772c4eSLinus Walleij 
35829772c4eSLinus Walleij 	return fifotaken;
35929772c4eSLinus Walleij }
36029772c4eSLinus Walleij 
36129772c4eSLinus Walleij 
36229772c4eSLinus Walleij /*
363ab4382d2SGreg Kroah-Hartman  * All the DMA operation mode stuff goes inside this ifdef.
364ab4382d2SGreg Kroah-Hartman  * This assumes that you have a generic DMA device interface,
365ab4382d2SGreg Kroah-Hartman  * no custom DMA interfaces are supported.
366ab4382d2SGreg Kroah-Hartman  */
367ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_DMA_ENGINE
368ab4382d2SGreg Kroah-Hartman 
369ab4382d2SGreg Kroah-Hartman #define PL011_DMA_BUFFER_SIZE PAGE_SIZE
370ab4382d2SGreg Kroah-Hartman 
pl011_dmabuf_init(struct dma_chan * chan,struct pl011_dmabuf * db,enum dma_data_direction dir)371c865b77eSArnd Bergmann static int pl011_dmabuf_init(struct dma_chan *chan, struct pl011_dmabuf *db,
372ead76f32SLinus Walleij 	enum dma_data_direction dir)
373ead76f32SLinus Walleij {
374c865b77eSArnd Bergmann 	db->buf = dma_alloc_coherent(chan->device->dev, PL011_DMA_BUFFER_SIZE,
375c865b77eSArnd Bergmann 				     &db->dma, GFP_KERNEL);
376c865b77eSArnd Bergmann 	if (!db->buf)
377ead76f32SLinus Walleij 		return -ENOMEM;
378c865b77eSArnd Bergmann 	db->len = PL011_DMA_BUFFER_SIZE;
379ead76f32SLinus Walleij 
380ead76f32SLinus Walleij 	return 0;
381ead76f32SLinus Walleij }
382ead76f32SLinus Walleij 
pl011_dmabuf_free(struct dma_chan * chan,struct pl011_dmabuf * db,enum dma_data_direction dir)383c865b77eSArnd Bergmann static void pl011_dmabuf_free(struct dma_chan *chan, struct pl011_dmabuf *db,
384ead76f32SLinus Walleij 	enum dma_data_direction dir)
385ead76f32SLinus Walleij {
386c865b77eSArnd Bergmann 	if (db->buf) {
387cb06ff10SChanho Min 		dma_free_coherent(chan->device->dev,
388c865b77eSArnd Bergmann 				  PL011_DMA_BUFFER_SIZE, db->buf, db->dma);
389ead76f32SLinus Walleij 	}
390ead76f32SLinus Walleij }
391ead76f32SLinus Walleij 
pl011_dma_probe(struct uart_amba_port * uap)3921c9be310SJorge Ramirez-Ortiz static void pl011_dma_probe(struct uart_amba_port *uap)
393ab4382d2SGreg Kroah-Hartman {
394ab4382d2SGreg Kroah-Hartman 	/* DMA is the sole user of the platform data right now */
395574de559SJingoo Han 	struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev);
3961c9be310SJorge Ramirez-Ortiz 	struct device *dev = uap->port.dev;
397ab4382d2SGreg Kroah-Hartman 	struct dma_slave_config tx_conf = {
3989f25bc51SRussell King 		.dst_addr = uap->port.mapbase +
3999f25bc51SRussell King 				 pl011_reg_to_offset(uap, REG_DR),
400ab4382d2SGreg Kroah-Hartman 		.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
401a485df4bSVinod Koul 		.direction = DMA_MEM_TO_DEV,
402ab4382d2SGreg Kroah-Hartman 		.dst_maxburst = uap->fifosize >> 1,
403258aea76SViresh Kumar 		.device_fc = false,
404ab4382d2SGreg Kroah-Hartman 	};
405ab4382d2SGreg Kroah-Hartman 	struct dma_chan *chan;
406ab4382d2SGreg Kroah-Hartman 	dma_cap_mask_t mask;
407ab4382d2SGreg Kroah-Hartman 
4081c9be310SJorge Ramirez-Ortiz 	uap->dma_probed = true;
40961b37b04SPeter Ujfalusi 	chan = dma_request_chan(dev, "tx");
4101c9be310SJorge Ramirez-Ortiz 	if (IS_ERR(chan)) {
4111c9be310SJorge Ramirez-Ortiz 		if (PTR_ERR(chan) == -EPROBE_DEFER) {
4121c9be310SJorge Ramirez-Ortiz 			uap->dma_probed = false;
4131c9be310SJorge Ramirez-Ortiz 			return;
4141c9be310SJorge Ramirez-Ortiz 		}
415787b0c1fSArnd Bergmann 
416ab4382d2SGreg Kroah-Hartman 		/* We need platform data */
417ab4382d2SGreg Kroah-Hartman 		if (!plat || !plat->dma_filter) {
418ab4382d2SGreg Kroah-Hartman 			dev_info(uap->port.dev, "no DMA platform data\n");
419ab4382d2SGreg Kroah-Hartman 			return;
420ab4382d2SGreg Kroah-Hartman 		}
421ab4382d2SGreg Kroah-Hartman 
422ead76f32SLinus Walleij 		/* Try to acquire a generic DMA engine slave TX channel */
423ab4382d2SGreg Kroah-Hartman 		dma_cap_zero(mask);
424ab4382d2SGreg Kroah-Hartman 		dma_cap_set(DMA_SLAVE, mask);
425ab4382d2SGreg Kroah-Hartman 
426787b0c1fSArnd Bergmann 		chan = dma_request_channel(mask, plat->dma_filter,
427787b0c1fSArnd Bergmann 						plat->dma_tx_param);
428ab4382d2SGreg Kroah-Hartman 		if (!chan) {
429ab4382d2SGreg Kroah-Hartman 			dev_err(uap->port.dev, "no TX DMA channel!\n");
430ab4382d2SGreg Kroah-Hartman 			return;
431ab4382d2SGreg Kroah-Hartman 		}
432787b0c1fSArnd Bergmann 	}
433ab4382d2SGreg Kroah-Hartman 
434ab4382d2SGreg Kroah-Hartman 	dmaengine_slave_config(chan, &tx_conf);
435ab4382d2SGreg Kroah-Hartman 	uap->dmatx.chan = chan;
436ab4382d2SGreg Kroah-Hartman 
437ab4382d2SGreg Kroah-Hartman 	dev_info(uap->port.dev, "DMA channel TX %s\n",
438ab4382d2SGreg Kroah-Hartman 		 dma_chan_name(uap->dmatx.chan));
439ead76f32SLinus Walleij 
440ead76f32SLinus Walleij 	/* Optionally make use of an RX channel as well */
441787b0c1fSArnd Bergmann 	chan = dma_request_slave_channel(dev, "rx");
442787b0c1fSArnd Bergmann 
443d9e105caSRobin Murphy 	if (!chan && plat && plat->dma_rx_param) {
444787b0c1fSArnd Bergmann 		chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
445787b0c1fSArnd Bergmann 
446787b0c1fSArnd Bergmann 		if (!chan) {
447787b0c1fSArnd Bergmann 			dev_err(uap->port.dev, "no RX DMA channel!\n");
448787b0c1fSArnd Bergmann 			return;
449787b0c1fSArnd Bergmann 		}
450787b0c1fSArnd Bergmann 	}
451787b0c1fSArnd Bergmann 
452787b0c1fSArnd Bergmann 	if (chan) {
453ead76f32SLinus Walleij 		struct dma_slave_config rx_conf = {
4549f25bc51SRussell King 			.src_addr = uap->port.mapbase +
4559f25bc51SRussell King 				pl011_reg_to_offset(uap, REG_DR),
456ead76f32SLinus Walleij 			.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
457a485df4bSVinod Koul 			.direction = DMA_DEV_TO_MEM,
458b2aeb775SGuennadi Liakhovetski 			.src_maxburst = uap->fifosize >> 2,
459258aea76SViresh Kumar 			.device_fc = false,
460ead76f32SLinus Walleij 		};
4612d3b7d6eSAndrew Jackson 		struct dma_slave_caps caps;
462ead76f32SLinus Walleij 
4632d3b7d6eSAndrew Jackson 		/*
4642d3b7d6eSAndrew Jackson 		 * Some DMA controllers provide information on their capabilities.
4652d3b7d6eSAndrew Jackson 		 * If the controller does, check for suitable residue processing
4662d3b7d6eSAndrew Jackson 		 * otherwise assime all is well.
4672d3b7d6eSAndrew Jackson 		 */
4682d3b7d6eSAndrew Jackson 		if (0 == dma_get_slave_caps(chan, &caps)) {
4692d3b7d6eSAndrew Jackson 			if (caps.residue_granularity ==
4702d3b7d6eSAndrew Jackson 					DMA_RESIDUE_GRANULARITY_DESCRIPTOR) {
4712d3b7d6eSAndrew Jackson 				dma_release_channel(chan);
4722d3b7d6eSAndrew Jackson 				dev_info(uap->port.dev,
4732d3b7d6eSAndrew Jackson 					"RX DMA disabled - no residue processing\n");
4742d3b7d6eSAndrew Jackson 				return;
4752d3b7d6eSAndrew Jackson 			}
4762d3b7d6eSAndrew Jackson 		}
477ead76f32SLinus Walleij 		dmaengine_slave_config(chan, &rx_conf);
478ead76f32SLinus Walleij 		uap->dmarx.chan = chan;
479ead76f32SLinus Walleij 
48098267d33SAndrew Jackson 		uap->dmarx.auto_poll_rate = false;
4818f898bfdSGreg Kroah-Hartman 		if (plat && plat->dma_rx_poll_enable) {
482cb06ff10SChanho Min 			/* Set poll rate if specified. */
483cb06ff10SChanho Min 			if (plat->dma_rx_poll_rate) {
484cb06ff10SChanho Min 				uap->dmarx.auto_poll_rate = false;
485cb06ff10SChanho Min 				uap->dmarx.poll_rate = plat->dma_rx_poll_rate;
486cb06ff10SChanho Min 			} else {
487cb06ff10SChanho Min 				/*
488cb06ff10SChanho Min 				 * 100 ms defaults to poll rate if not
489cb06ff10SChanho Min 				 * specified. This will be adjusted with
490cb06ff10SChanho Min 				 * the baud rate at set_termios.
491cb06ff10SChanho Min 				 */
492cb06ff10SChanho Min 				uap->dmarx.auto_poll_rate = true;
493cb06ff10SChanho Min 				uap->dmarx.poll_rate =  100;
494cb06ff10SChanho Min 			}
495cb06ff10SChanho Min 			/* 3 secs defaults poll_timeout if not specified. */
496cb06ff10SChanho Min 			if (plat->dma_rx_poll_timeout)
497cb06ff10SChanho Min 				uap->dmarx.poll_timeout =
498cb06ff10SChanho Min 					plat->dma_rx_poll_timeout;
499cb06ff10SChanho Min 			else
500cb06ff10SChanho Min 				uap->dmarx.poll_timeout = 3000;
50198267d33SAndrew Jackson 		} else if (!plat && dev->of_node) {
50298267d33SAndrew Jackson 			uap->dmarx.auto_poll_rate = of_property_read_bool(
50398267d33SAndrew Jackson 						dev->of_node, "auto-poll");
50498267d33SAndrew Jackson 			if (uap->dmarx.auto_poll_rate) {
50598267d33SAndrew Jackson 				u32 x;
506cb06ff10SChanho Min 
50798267d33SAndrew Jackson 				if (0 == of_property_read_u32(dev->of_node,
50898267d33SAndrew Jackson 						"poll-rate-ms", &x))
50998267d33SAndrew Jackson 					uap->dmarx.poll_rate = x;
51098267d33SAndrew Jackson 				else
51198267d33SAndrew Jackson 					uap->dmarx.poll_rate = 100;
51298267d33SAndrew Jackson 				if (0 == of_property_read_u32(dev->of_node,
51398267d33SAndrew Jackson 						"poll-timeout-ms", &x))
51498267d33SAndrew Jackson 					uap->dmarx.poll_timeout = x;
51598267d33SAndrew Jackson 				else
51698267d33SAndrew Jackson 					uap->dmarx.poll_timeout = 3000;
51798267d33SAndrew Jackson 			}
51898267d33SAndrew Jackson 		}
519ead76f32SLinus Walleij 		dev_info(uap->port.dev, "DMA channel RX %s\n",
520ead76f32SLinus Walleij 			 dma_chan_name(uap->dmarx.chan));
521ead76f32SLinus Walleij 	}
522ab4382d2SGreg Kroah-Hartman }
523ab4382d2SGreg Kroah-Hartman 
pl011_dma_remove(struct uart_amba_port * uap)524ab4382d2SGreg Kroah-Hartman static void pl011_dma_remove(struct uart_amba_port *uap)
525ab4382d2SGreg Kroah-Hartman {
526ab4382d2SGreg Kroah-Hartman 	if (uap->dmatx.chan)
527ab4382d2SGreg Kroah-Hartman 		dma_release_channel(uap->dmatx.chan);
528ead76f32SLinus Walleij 	if (uap->dmarx.chan)
529ead76f32SLinus Walleij 		dma_release_channel(uap->dmarx.chan);
530ab4382d2SGreg Kroah-Hartman }
531ab4382d2SGreg Kroah-Hartman 
532734745caSDave Martin /* Forward declare these for the refill routine */
533ab4382d2SGreg Kroah-Hartman static int pl011_dma_tx_refill(struct uart_amba_port *uap);
534734745caSDave Martin static void pl011_start_tx_pio(struct uart_amba_port *uap);
535ab4382d2SGreg Kroah-Hartman 
536ab4382d2SGreg Kroah-Hartman /*
537ab4382d2SGreg Kroah-Hartman  * The current DMA TX buffer has been sent.
538ab4382d2SGreg Kroah-Hartman  * Try to queue up another DMA buffer.
539ab4382d2SGreg Kroah-Hartman  */
pl011_dma_tx_callback(void * data)540ab4382d2SGreg Kroah-Hartman static void pl011_dma_tx_callback(void *data)
541ab4382d2SGreg Kroah-Hartman {
542ab4382d2SGreg Kroah-Hartman 	struct uart_amba_port *uap = data;
543ab4382d2SGreg Kroah-Hartman 	struct pl011_dmatx_data *dmatx = &uap->dmatx;
544ab4382d2SGreg Kroah-Hartman 	unsigned long flags;
545ab4382d2SGreg Kroah-Hartman 	u16 dmacr;
546ab4382d2SGreg Kroah-Hartman 
5475aea1229SThomas Gleixner 	uart_port_lock_irqsave(&uap->port, &flags);
548ab4382d2SGreg Kroah-Hartman 	if (uap->dmatx.queued)
549c865b77eSArnd Bergmann 		dma_unmap_single(dmatx->chan->device->dev, dmatx->dma,
550c865b77eSArnd Bergmann 				dmatx->len, DMA_TO_DEVICE);
551ab4382d2SGreg Kroah-Hartman 
552ab4382d2SGreg Kroah-Hartman 	dmacr = uap->dmacr;
553ab4382d2SGreg Kroah-Hartman 	uap->dmacr = dmacr & ~UART011_TXDMAE;
5549f25bc51SRussell King 	pl011_write(uap->dmacr, uap, REG_DMACR);
555ab4382d2SGreg Kroah-Hartman 
556ab4382d2SGreg Kroah-Hartman 	/*
557ab4382d2SGreg Kroah-Hartman 	 * If TX DMA was disabled, it means that we've stopped the DMA for
558ab4382d2SGreg Kroah-Hartman 	 * some reason (eg, XOFF received, or we want to send an X-char.)
559ab4382d2SGreg Kroah-Hartman 	 *
560ab4382d2SGreg Kroah-Hartman 	 * Note: we need to be careful here of a potential race between DMA
561ab4382d2SGreg Kroah-Hartman 	 * and the rest of the driver - if the driver disables TX DMA while
562ab4382d2SGreg Kroah-Hartman 	 * a TX buffer completing, we must update the tx queued status to
563ab4382d2SGreg Kroah-Hartman 	 * get further refills (hence we check dmacr).
564ab4382d2SGreg Kroah-Hartman 	 */
565ab4382d2SGreg Kroah-Hartman 	if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) ||
566ab4382d2SGreg Kroah-Hartman 	    uart_circ_empty(&uap->port.state->xmit)) {
567ab4382d2SGreg Kroah-Hartman 		uap->dmatx.queued = false;
5685aea1229SThomas Gleixner 		uart_port_unlock_irqrestore(&uap->port, flags);
569ab4382d2SGreg Kroah-Hartman 		return;
570ab4382d2SGreg Kroah-Hartman 	}
571ab4382d2SGreg Kroah-Hartman 
572734745caSDave Martin 	if (pl011_dma_tx_refill(uap) <= 0)
573ab4382d2SGreg Kroah-Hartman 		/*
574ab4382d2SGreg Kroah-Hartman 		 * We didn't queue a DMA buffer for some reason, but we
575ab4382d2SGreg Kroah-Hartman 		 * have data pending to be sent.  Re-enable the TX IRQ.
576ab4382d2SGreg Kroah-Hartman 		 */
577734745caSDave Martin 		pl011_start_tx_pio(uap);
578734745caSDave Martin 
5795aea1229SThomas Gleixner 	uart_port_unlock_irqrestore(&uap->port, flags);
580ab4382d2SGreg Kroah-Hartman }
581ab4382d2SGreg Kroah-Hartman 
582ab4382d2SGreg Kroah-Hartman /*
583ab4382d2SGreg Kroah-Hartman  * Try to refill the TX DMA buffer.
584ab4382d2SGreg Kroah-Hartman  * Locking: called with port lock held and IRQs disabled.
585ab4382d2SGreg Kroah-Hartman  * Returns:
586ab4382d2SGreg Kroah-Hartman  *   1 if we queued up a TX DMA buffer.
587ab4382d2SGreg Kroah-Hartman  *   0 if we didn't want to handle this by DMA
588ab4382d2SGreg Kroah-Hartman  *  <0 on error
589ab4382d2SGreg Kroah-Hartman  */
pl011_dma_tx_refill(struct uart_amba_port * uap)590ab4382d2SGreg Kroah-Hartman static int pl011_dma_tx_refill(struct uart_amba_port *uap)
591ab4382d2SGreg Kroah-Hartman {
592ab4382d2SGreg Kroah-Hartman 	struct pl011_dmatx_data *dmatx = &uap->dmatx;
593ab4382d2SGreg Kroah-Hartman 	struct dma_chan *chan = dmatx->chan;
594ab4382d2SGreg Kroah-Hartman 	struct dma_device *dma_dev = chan->device;
595ab4382d2SGreg Kroah-Hartman 	struct dma_async_tx_descriptor *desc;
596ab4382d2SGreg Kroah-Hartman 	struct circ_buf *xmit = &uap->port.state->xmit;
597ab4382d2SGreg Kroah-Hartman 	unsigned int count;
598ab4382d2SGreg Kroah-Hartman 
599ab4382d2SGreg Kroah-Hartman 	/*
600ab4382d2SGreg Kroah-Hartman 	 * Try to avoid the overhead involved in using DMA if the
601ab4382d2SGreg Kroah-Hartman 	 * transaction fits in the first half of the FIFO, by using
602ab4382d2SGreg Kroah-Hartman 	 * the standard interrupt handling.  This ensures that we
603ab4382d2SGreg Kroah-Hartman 	 * issue a uart_write_wakeup() at the appropriate time.
604ab4382d2SGreg Kroah-Hartman 	 */
605ab4382d2SGreg Kroah-Hartman 	count = uart_circ_chars_pending(xmit);
606ab4382d2SGreg Kroah-Hartman 	if (count < (uap->fifosize >> 1)) {
607ab4382d2SGreg Kroah-Hartman 		uap->dmatx.queued = false;
608ab4382d2SGreg Kroah-Hartman 		return 0;
609ab4382d2SGreg Kroah-Hartman 	}
610ab4382d2SGreg Kroah-Hartman 
611ab4382d2SGreg Kroah-Hartman 	/*
612ab4382d2SGreg Kroah-Hartman 	 * Bodge: don't send the last character by DMA, as this
613ab4382d2SGreg Kroah-Hartman 	 * will prevent XON from notifying us to restart DMA.
614ab4382d2SGreg Kroah-Hartman 	 */
615ab4382d2SGreg Kroah-Hartman 	count -= 1;
616ab4382d2SGreg Kroah-Hartman 
617ab4382d2SGreg Kroah-Hartman 	/* Else proceed to copy the TX chars to the DMA buffer and fire DMA */
618ab4382d2SGreg Kroah-Hartman 	if (count > PL011_DMA_BUFFER_SIZE)
619ab4382d2SGreg Kroah-Hartman 		count = PL011_DMA_BUFFER_SIZE;
620ab4382d2SGreg Kroah-Hartman 
621ab4382d2SGreg Kroah-Hartman 	if (xmit->tail < xmit->head)
622ab4382d2SGreg Kroah-Hartman 		memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count);
623ab4382d2SGreg Kroah-Hartman 	else {
624ab4382d2SGreg Kroah-Hartman 		size_t first = UART_XMIT_SIZE - xmit->tail;
625e2a545a6SAndrew Jackson 		size_t second;
626e2a545a6SAndrew Jackson 
627e2a545a6SAndrew Jackson 		if (first > count)
628e2a545a6SAndrew Jackson 			first = count;
629e2a545a6SAndrew Jackson 		second = count - first;
630ab4382d2SGreg Kroah-Hartman 
631ab4382d2SGreg Kroah-Hartman 		memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first);
632ab4382d2SGreg Kroah-Hartman 		if (second)
633ab4382d2SGreg Kroah-Hartman 			memcpy(&dmatx->buf[first], &xmit->buf[0], second);
634ab4382d2SGreg Kroah-Hartman 	}
635ab4382d2SGreg Kroah-Hartman 
636c865b77eSArnd Bergmann 	dmatx->len = count;
637c865b77eSArnd Bergmann 	dmatx->dma = dma_map_single(dma_dev->dev, dmatx->buf, count,
638c865b77eSArnd Bergmann 				    DMA_TO_DEVICE);
639c865b77eSArnd Bergmann 	if (dmatx->dma == DMA_MAPPING_ERROR) {
640ab4382d2SGreg Kroah-Hartman 		uap->dmatx.queued = false;
641ab4382d2SGreg Kroah-Hartman 		dev_dbg(uap->port.dev, "unable to map TX DMA\n");
642ab4382d2SGreg Kroah-Hartman 		return -EBUSY;
643ab4382d2SGreg Kroah-Hartman 	}
644ab4382d2SGreg Kroah-Hartman 
645c865b77eSArnd Bergmann 	desc = dmaengine_prep_slave_single(chan, dmatx->dma, dmatx->len, DMA_MEM_TO_DEV,
646ab4382d2SGreg Kroah-Hartman 					     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
647ab4382d2SGreg Kroah-Hartman 	if (!desc) {
648c865b77eSArnd Bergmann 		dma_unmap_single(dma_dev->dev, dmatx->dma, dmatx->len, DMA_TO_DEVICE);
649ab4382d2SGreg Kroah-Hartman 		uap->dmatx.queued = false;
650ab4382d2SGreg Kroah-Hartman 		/*
651ab4382d2SGreg Kroah-Hartman 		 * If DMA cannot be used right now, we complete this
652ab4382d2SGreg Kroah-Hartman 		 * transaction via IRQ and let the TTY layer retry.
653ab4382d2SGreg Kroah-Hartman 		 */
654ab4382d2SGreg Kroah-Hartman 		dev_dbg(uap->port.dev, "TX DMA busy\n");
655ab4382d2SGreg Kroah-Hartman 		return -EBUSY;
656ab4382d2SGreg Kroah-Hartman 	}
657ab4382d2SGreg Kroah-Hartman 
658ab4382d2SGreg Kroah-Hartman 	/* Some data to go along to the callback */
659ab4382d2SGreg Kroah-Hartman 	desc->callback = pl011_dma_tx_callback;
660ab4382d2SGreg Kroah-Hartman 	desc->callback_param = uap;
661ab4382d2SGreg Kroah-Hartman 
662ab4382d2SGreg Kroah-Hartman 	/* All errors should happen at prepare time */
663ab4382d2SGreg Kroah-Hartman 	dmaengine_submit(desc);
664ab4382d2SGreg Kroah-Hartman 
665ab4382d2SGreg Kroah-Hartman 	/* Fire the DMA transaction */
666ab4382d2SGreg Kroah-Hartman 	dma_dev->device_issue_pending(chan);
667ab4382d2SGreg Kroah-Hartman 
668ab4382d2SGreg Kroah-Hartman 	uap->dmacr |= UART011_TXDMAE;
6699f25bc51SRussell King 	pl011_write(uap->dmacr, uap, REG_DMACR);
670ab4382d2SGreg Kroah-Hartman 	uap->dmatx.queued = true;
671ab4382d2SGreg Kroah-Hartman 
672ab4382d2SGreg Kroah-Hartman 	/*
673ab4382d2SGreg Kroah-Hartman 	 * Now we know that DMA will fire, so advance the ring buffer
674ab4382d2SGreg Kroah-Hartman 	 * with the stuff we just dispatched.
675ab4382d2SGreg Kroah-Hartman 	 */
67671a67573SIlpo Järvinen 	uart_xmit_advance(&uap->port, count);
677ab4382d2SGreg Kroah-Hartman 
678ab4382d2SGreg Kroah-Hartman 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
679ab4382d2SGreg Kroah-Hartman 		uart_write_wakeup(&uap->port);
680ab4382d2SGreg Kroah-Hartman 
681ab4382d2SGreg Kroah-Hartman 	return 1;
682ab4382d2SGreg Kroah-Hartman }
683ab4382d2SGreg Kroah-Hartman 
684ab4382d2SGreg Kroah-Hartman /*
685ab4382d2SGreg Kroah-Hartman  * We received a transmit interrupt without a pending X-char but with
686ab4382d2SGreg Kroah-Hartman  * pending characters.
687ab4382d2SGreg Kroah-Hartman  * Locking: called with port lock held and IRQs disabled.
688ab4382d2SGreg Kroah-Hartman  * Returns:
689ab4382d2SGreg Kroah-Hartman  *   false if we want to use PIO to transmit
690ab4382d2SGreg Kroah-Hartman  *   true if we queued a DMA buffer
691ab4382d2SGreg Kroah-Hartman  */
pl011_dma_tx_irq(struct uart_amba_port * uap)692ab4382d2SGreg Kroah-Hartman static bool pl011_dma_tx_irq(struct uart_amba_port *uap)
693ab4382d2SGreg Kroah-Hartman {
694ead76f32SLinus Walleij 	if (!uap->using_tx_dma)
695ab4382d2SGreg Kroah-Hartman 		return false;
696ab4382d2SGreg Kroah-Hartman 
697ab4382d2SGreg Kroah-Hartman 	/*
698ab4382d2SGreg Kroah-Hartman 	 * If we already have a TX buffer queued, but received a
699ab4382d2SGreg Kroah-Hartman 	 * TX interrupt, it will be because we've just sent an X-char.
700ab4382d2SGreg Kroah-Hartman 	 * Ensure the TX DMA is enabled and the TX IRQ is disabled.
701ab4382d2SGreg Kroah-Hartman 	 */
702ab4382d2SGreg Kroah-Hartman 	if (uap->dmatx.queued) {
703ab4382d2SGreg Kroah-Hartman 		uap->dmacr |= UART011_TXDMAE;
7049f25bc51SRussell King 		pl011_write(uap->dmacr, uap, REG_DMACR);
705ab4382d2SGreg Kroah-Hartman 		uap->im &= ~UART011_TXIM;
7069f25bc51SRussell King 		pl011_write(uap->im, uap, REG_IMSC);
707ab4382d2SGreg Kroah-Hartman 		return true;
708ab4382d2SGreg Kroah-Hartman 	}
709ab4382d2SGreg Kroah-Hartman 
710ab4382d2SGreg Kroah-Hartman 	/*
711ab4382d2SGreg Kroah-Hartman 	 * We don't have a TX buffer queued, so try to queue one.
71225985edcSLucas De Marchi 	 * If we successfully queued a buffer, mask the TX IRQ.
713ab4382d2SGreg Kroah-Hartman 	 */
714ab4382d2SGreg Kroah-Hartman 	if (pl011_dma_tx_refill(uap) > 0) {
715ab4382d2SGreg Kroah-Hartman 		uap->im &= ~UART011_TXIM;
7169f25bc51SRussell King 		pl011_write(uap->im, uap, REG_IMSC);
717ab4382d2SGreg Kroah-Hartman 		return true;
718ab4382d2SGreg Kroah-Hartman 	}
719ab4382d2SGreg Kroah-Hartman 	return false;
720ab4382d2SGreg Kroah-Hartman }
721ab4382d2SGreg Kroah-Hartman 
722ab4382d2SGreg Kroah-Hartman /*
723ab4382d2SGreg Kroah-Hartman  * Stop the DMA transmit (eg, due to received XOFF).
724ab4382d2SGreg Kroah-Hartman  * Locking: called with port lock held and IRQs disabled.
725ab4382d2SGreg Kroah-Hartman  */
pl011_dma_tx_stop(struct uart_amba_port * uap)726ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
727ab4382d2SGreg Kroah-Hartman {
728ab4382d2SGreg Kroah-Hartman 	if (uap->dmatx.queued) {
729ab4382d2SGreg Kroah-Hartman 		uap->dmacr &= ~UART011_TXDMAE;
7309f25bc51SRussell King 		pl011_write(uap->dmacr, uap, REG_DMACR);
731ab4382d2SGreg Kroah-Hartman 	}
732ab4382d2SGreg Kroah-Hartman }
733ab4382d2SGreg Kroah-Hartman 
734ab4382d2SGreg Kroah-Hartman /*
735ab4382d2SGreg Kroah-Hartman  * Try to start a DMA transmit, or in the case of an XON/OFF
736ab4382d2SGreg Kroah-Hartman  * character queued for send, try to get that character out ASAP.
737ab4382d2SGreg Kroah-Hartman  * Locking: called with port lock held and IRQs disabled.
738ab4382d2SGreg Kroah-Hartman  * Returns:
739ab4382d2SGreg Kroah-Hartman  *   false if we want the TX IRQ to be enabled
740ab4382d2SGreg Kroah-Hartman  *   true if we have a buffer queued
741ab4382d2SGreg Kroah-Hartman  */
pl011_dma_tx_start(struct uart_amba_port * uap)742ab4382d2SGreg Kroah-Hartman static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
743ab4382d2SGreg Kroah-Hartman {
744ab4382d2SGreg Kroah-Hartman 	u16 dmacr;
745ab4382d2SGreg Kroah-Hartman 
746ead76f32SLinus Walleij 	if (!uap->using_tx_dma)
747ab4382d2SGreg Kroah-Hartman 		return false;
748ab4382d2SGreg Kroah-Hartman 
749ab4382d2SGreg Kroah-Hartman 	if (!uap->port.x_char) {
750ab4382d2SGreg Kroah-Hartman 		/* no X-char, try to push chars out in DMA mode */
751ab4382d2SGreg Kroah-Hartman 		bool ret = true;
752ab4382d2SGreg Kroah-Hartman 
753ab4382d2SGreg Kroah-Hartman 		if (!uap->dmatx.queued) {
754ab4382d2SGreg Kroah-Hartman 			if (pl011_dma_tx_refill(uap) > 0) {
755ab4382d2SGreg Kroah-Hartman 				uap->im &= ~UART011_TXIM;
7569f25bc51SRussell King 				pl011_write(uap->im, uap, REG_IMSC);
757734745caSDave Martin 			} else
758ab4382d2SGreg Kroah-Hartman 				ret = false;
759ab4382d2SGreg Kroah-Hartman 		} else if (!(uap->dmacr & UART011_TXDMAE)) {
760ab4382d2SGreg Kroah-Hartman 			uap->dmacr |= UART011_TXDMAE;
7619f25bc51SRussell King 			pl011_write(uap->dmacr, uap, REG_DMACR);
762ab4382d2SGreg Kroah-Hartman 		}
763ab4382d2SGreg Kroah-Hartman 		return ret;
764ab4382d2SGreg Kroah-Hartman 	}
765ab4382d2SGreg Kroah-Hartman 
766ab4382d2SGreg Kroah-Hartman 	/*
767ab4382d2SGreg Kroah-Hartman 	 * We have an X-char to send.  Disable DMA to prevent it loading
768ab4382d2SGreg Kroah-Hartman 	 * the TX fifo, and then see if we can stuff it into the FIFO.
769ab4382d2SGreg Kroah-Hartman 	 */
770ab4382d2SGreg Kroah-Hartman 	dmacr = uap->dmacr;
771ab4382d2SGreg Kroah-Hartman 	uap->dmacr &= ~UART011_TXDMAE;
7729f25bc51SRussell King 	pl011_write(uap->dmacr, uap, REG_DMACR);
773ab4382d2SGreg Kroah-Hartman 
7749f25bc51SRussell King 	if (pl011_read(uap, REG_FR) & UART01x_FR_TXFF) {
775ab4382d2SGreg Kroah-Hartman 		/*
776ab4382d2SGreg Kroah-Hartman 		 * No space in the FIFO, so enable the transmit interrupt
777ab4382d2SGreg Kroah-Hartman 		 * so we know when there is space.  Note that once we've
778ab4382d2SGreg Kroah-Hartman 		 * loaded the character, we should just re-enable DMA.
779ab4382d2SGreg Kroah-Hartman 		 */
780ab4382d2SGreg Kroah-Hartman 		return false;
781ab4382d2SGreg Kroah-Hartman 	}
782ab4382d2SGreg Kroah-Hartman 
7839f25bc51SRussell King 	pl011_write(uap->port.x_char, uap, REG_DR);
784ab4382d2SGreg Kroah-Hartman 	uap->port.icount.tx++;
785ab4382d2SGreg Kroah-Hartman 	uap->port.x_char = 0;
786ab4382d2SGreg Kroah-Hartman 
787ab4382d2SGreg Kroah-Hartman 	/* Success - restore the DMA state */
788ab4382d2SGreg Kroah-Hartman 	uap->dmacr = dmacr;
7899f25bc51SRussell King 	pl011_write(dmacr, uap, REG_DMACR);
790ab4382d2SGreg Kroah-Hartman 
791ab4382d2SGreg Kroah-Hartman 	return true;
792ab4382d2SGreg Kroah-Hartman }
793ab4382d2SGreg Kroah-Hartman 
794ab4382d2SGreg Kroah-Hartman /*
795ab4382d2SGreg Kroah-Hartman  * Flush the transmit buffer.
796ab4382d2SGreg Kroah-Hartman  * Locking: called with port lock held and IRQs disabled.
797ab4382d2SGreg Kroah-Hartman  */
pl011_dma_flush_buffer(struct uart_port * port)798ab4382d2SGreg Kroah-Hartman static void pl011_dma_flush_buffer(struct uart_port *port)
799b83286bfSFabio Estevam __releases(&uap->port.lock)
800b83286bfSFabio Estevam __acquires(&uap->port.lock)
801ab4382d2SGreg Kroah-Hartman {
802a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
803a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
804ab4382d2SGreg Kroah-Hartman 
805ead76f32SLinus Walleij 	if (!uap->using_tx_dma)
806ab4382d2SGreg Kroah-Hartman 		return;
807ab4382d2SGreg Kroah-Hartman 
808f6a19647SVincent Whitchurch 	dmaengine_terminate_async(uap->dmatx.chan);
809f6a19647SVincent Whitchurch 
810ab4382d2SGreg Kroah-Hartman 	if (uap->dmatx.queued) {
811c865b77eSArnd Bergmann 		dma_unmap_single(uap->dmatx.chan->device->dev, uap->dmatx.dma,
812c865b77eSArnd Bergmann 				 uap->dmatx.len, DMA_TO_DEVICE);
813ab4382d2SGreg Kroah-Hartman 		uap->dmatx.queued = false;
814ab4382d2SGreg Kroah-Hartman 		uap->dmacr &= ~UART011_TXDMAE;
8159f25bc51SRussell King 		pl011_write(uap->dmacr, uap, REG_DMACR);
816ab4382d2SGreg Kroah-Hartman 	}
817ab4382d2SGreg Kroah-Hartman }
818ab4382d2SGreg Kroah-Hartman 
819ead76f32SLinus Walleij static void pl011_dma_rx_callback(void *data);
820ead76f32SLinus Walleij 
pl011_dma_rx_trigger_dma(struct uart_amba_port * uap)821ead76f32SLinus Walleij static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
822ead76f32SLinus Walleij {
823ead76f32SLinus Walleij 	struct dma_chan *rxchan = uap->dmarx.chan;
824ead76f32SLinus Walleij 	struct pl011_dmarx_data *dmarx = &uap->dmarx;
825ead76f32SLinus Walleij 	struct dma_async_tx_descriptor *desc;
826c865b77eSArnd Bergmann 	struct pl011_dmabuf *dbuf;
827ead76f32SLinus Walleij 
828ead76f32SLinus Walleij 	if (!rxchan)
829ead76f32SLinus Walleij 		return -EIO;
830ead76f32SLinus Walleij 
831ead76f32SLinus Walleij 	/* Start the RX DMA job */
832c865b77eSArnd Bergmann 	dbuf = uap->dmarx.use_buf_b ?
833c865b77eSArnd Bergmann 		&uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
834c865b77eSArnd Bergmann 	desc = dmaengine_prep_slave_single(rxchan, dbuf->dma, dbuf->len,
835a485df4bSVinod Koul 					DMA_DEV_TO_MEM,
836ead76f32SLinus Walleij 					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
837ead76f32SLinus Walleij 	/*
838ead76f32SLinus Walleij 	 * If the DMA engine is busy and cannot prepare a
839ead76f32SLinus Walleij 	 * channel, no big deal, the driver will fall back
840ead76f32SLinus Walleij 	 * to interrupt mode as a result of this error code.
841ead76f32SLinus Walleij 	 */
842ead76f32SLinus Walleij 	if (!desc) {
843ead76f32SLinus Walleij 		uap->dmarx.running = false;
844ead76f32SLinus Walleij 		dmaengine_terminate_all(rxchan);
845ead76f32SLinus Walleij 		return -EBUSY;
846ead76f32SLinus Walleij 	}
847ead76f32SLinus Walleij 
848ead76f32SLinus Walleij 	/* Some data to go along to the callback */
849ead76f32SLinus Walleij 	desc->callback = pl011_dma_rx_callback;
850ead76f32SLinus Walleij 	desc->callback_param = uap;
851ead76f32SLinus Walleij 	dmarx->cookie = dmaengine_submit(desc);
852ead76f32SLinus Walleij 	dma_async_issue_pending(rxchan);
853ead76f32SLinus Walleij 
854ead76f32SLinus Walleij 	uap->dmacr |= UART011_RXDMAE;
8559f25bc51SRussell King 	pl011_write(uap->dmacr, uap, REG_DMACR);
856ead76f32SLinus Walleij 	uap->dmarx.running = true;
857ead76f32SLinus Walleij 
858ead76f32SLinus Walleij 	uap->im &= ~UART011_RXIM;
8599f25bc51SRussell King 	pl011_write(uap->im, uap, REG_IMSC);
860ead76f32SLinus Walleij 
861ead76f32SLinus Walleij 	return 0;
862ead76f32SLinus Walleij }
863ead76f32SLinus Walleij 
864ead76f32SLinus Walleij /*
865ead76f32SLinus Walleij  * This is called when either the DMA job is complete, or
866ead76f32SLinus Walleij  * the FIFO timeout interrupt occurred. This must be called
867ead76f32SLinus Walleij  * with the port spinlock uap->port.lock held.
868ead76f32SLinus Walleij  */
pl011_dma_rx_chars(struct uart_amba_port * uap,u32 pending,bool use_buf_b,bool readfifo)869ead76f32SLinus Walleij static void pl011_dma_rx_chars(struct uart_amba_port *uap,
870ead76f32SLinus Walleij 			       u32 pending, bool use_buf_b,
871ead76f32SLinus Walleij 			       bool readfifo)
872ead76f32SLinus Walleij {
87305c7cd39SJiri Slaby 	struct tty_port *port = &uap->port.state->port;
874c865b77eSArnd Bergmann 	struct pl011_dmabuf *dbuf = use_buf_b ?
875c865b77eSArnd Bergmann 		&uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
876ead76f32SLinus Walleij 	int dma_count = 0;
877ead76f32SLinus Walleij 	u32 fifotaken = 0; /* only used for vdbg() */
878ead76f32SLinus Walleij 
879cb06ff10SChanho Min 	struct pl011_dmarx_data *dmarx = &uap->dmarx;
880cb06ff10SChanho Min 	int dmataken = 0;
881cb06ff10SChanho Min 
882cb06ff10SChanho Min 	if (uap->dmarx.poll_rate) {
883cb06ff10SChanho Min 		/* The data can be taken by polling */
884c865b77eSArnd Bergmann 		dmataken = dbuf->len - dmarx->last_residue;
885cb06ff10SChanho Min 		/* Recalculate the pending size */
886cb06ff10SChanho Min 		if (pending >= dmataken)
887cb06ff10SChanho Min 			pending -= dmataken;
888cb06ff10SChanho Min 	}
889cb06ff10SChanho Min 
890cb06ff10SChanho Min 	/* Pick the remain data from the DMA */
891ead76f32SLinus Walleij 	if (pending) {
892ead76f32SLinus Walleij 
893ead76f32SLinus Walleij 		/*
894ead76f32SLinus Walleij 		 * First take all chars in the DMA pipe, then look in the FIFO.
895ead76f32SLinus Walleij 		 * Note that tty_insert_flip_buf() tries to take as many chars
896ead76f32SLinus Walleij 		 * as it can.
897ead76f32SLinus Walleij 		 */
898c865b77eSArnd Bergmann 		dma_count = tty_insert_flip_string(port, dbuf->buf + dmataken,
899cb06ff10SChanho Min 				pending);
900ead76f32SLinus Walleij 
901ead76f32SLinus Walleij 		uap->port.icount.rx += dma_count;
902ead76f32SLinus Walleij 		if (dma_count < pending)
903ead76f32SLinus Walleij 			dev_warn(uap->port.dev,
904ead76f32SLinus Walleij 				 "couldn't insert all characters (TTY is full?)\n");
905ead76f32SLinus Walleij 	}
906ead76f32SLinus Walleij 
907cb06ff10SChanho Min 	/* Reset the last_residue for Rx DMA poll */
908cb06ff10SChanho Min 	if (uap->dmarx.poll_rate)
909c865b77eSArnd Bergmann 		dmarx->last_residue = dbuf->len;
910cb06ff10SChanho Min 
911ead76f32SLinus Walleij 	/*
912ead76f32SLinus Walleij 	 * Only continue with trying to read the FIFO if all DMA chars have
913ead76f32SLinus Walleij 	 * been taken first.
914ead76f32SLinus Walleij 	 */
915ead76f32SLinus Walleij 	if (dma_count == pending && readfifo) {
916ead76f32SLinus Walleij 		/* Clear any error flags */
91775836339SRussell King 		pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS |
9189f25bc51SRussell King 			    UART011_FEIS, uap, REG_ICR);
919ead76f32SLinus Walleij 
920ead76f32SLinus Walleij 		/*
921ead76f32SLinus Walleij 		 * If we read all the DMA'd characters, and we had an
92229772c4eSLinus Walleij 		 * incomplete buffer, that could be due to an rx error, or
92329772c4eSLinus Walleij 		 * maybe we just timed out. Read any pending chars and check
92429772c4eSLinus Walleij 		 * the error status.
92529772c4eSLinus Walleij 		 *
92629772c4eSLinus Walleij 		 * Error conditions will only occur in the FIFO, these will
92729772c4eSLinus Walleij 		 * trigger an immediate interrupt and stop the DMA job, so we
92829772c4eSLinus Walleij 		 * will always find the error in the FIFO, never in the DMA
92929772c4eSLinus Walleij 		 * buffer.
930ead76f32SLinus Walleij 		 */
93129772c4eSLinus Walleij 		fifotaken = pl011_fifo_to_tty(uap);
932ead76f32SLinus Walleij 	}
933ead76f32SLinus Walleij 
934ead76f32SLinus Walleij 	dev_vdbg(uap->port.dev,
935ead76f32SLinus Walleij 		 "Took %d chars from DMA buffer and %d chars from the FIFO\n",
936ead76f32SLinus Walleij 		 dma_count, fifotaken);
9372e124b4aSJiri Slaby 	tty_flip_buffer_push(port);
938ead76f32SLinus Walleij }
939ead76f32SLinus Walleij 
pl011_dma_rx_irq(struct uart_amba_port * uap)940ead76f32SLinus Walleij static void pl011_dma_rx_irq(struct uart_amba_port *uap)
941ead76f32SLinus Walleij {
942ead76f32SLinus Walleij 	struct pl011_dmarx_data *dmarx = &uap->dmarx;
943ead76f32SLinus Walleij 	struct dma_chan *rxchan = dmarx->chan;
944c865b77eSArnd Bergmann 	struct pl011_dmabuf *dbuf = dmarx->use_buf_b ?
945c865b77eSArnd Bergmann 		&dmarx->dbuf_b : &dmarx->dbuf_a;
946ead76f32SLinus Walleij 	size_t pending;
947ead76f32SLinus Walleij 	struct dma_tx_state state;
948ead76f32SLinus Walleij 	enum dma_status dmastat;
949ead76f32SLinus Walleij 
950ead76f32SLinus Walleij 	/*
951ead76f32SLinus Walleij 	 * Pause the transfer so we can trust the current counter,
952ead76f32SLinus Walleij 	 * do this before we pause the PL011 block, else we may
953ead76f32SLinus Walleij 	 * overflow the FIFO.
954ead76f32SLinus Walleij 	 */
955ead76f32SLinus Walleij 	if (dmaengine_pause(rxchan))
956ead76f32SLinus Walleij 		dev_err(uap->port.dev, "unable to pause DMA transfer\n");
957ead76f32SLinus Walleij 	dmastat = rxchan->device->device_tx_status(rxchan,
958ead76f32SLinus Walleij 						   dmarx->cookie, &state);
959ead76f32SLinus Walleij 	if (dmastat != DMA_PAUSED)
960ead76f32SLinus Walleij 		dev_err(uap->port.dev, "unable to pause DMA transfer\n");
961ead76f32SLinus Walleij 
962ead76f32SLinus Walleij 	/* Disable RX DMA - incoming data will wait in the FIFO */
963ead76f32SLinus Walleij 	uap->dmacr &= ~UART011_RXDMAE;
9649f25bc51SRussell King 	pl011_write(uap->dmacr, uap, REG_DMACR);
965ead76f32SLinus Walleij 	uap->dmarx.running = false;
966ead76f32SLinus Walleij 
967c865b77eSArnd Bergmann 	pending = dbuf->len - state.residue;
968ead76f32SLinus Walleij 	BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
969ead76f32SLinus Walleij 	/* Then we terminate the transfer - we now know our residue */
970ead76f32SLinus Walleij 	dmaengine_terminate_all(rxchan);
971ead76f32SLinus Walleij 
972ead76f32SLinus Walleij 	/*
973ead76f32SLinus Walleij 	 * This will take the chars we have so far and insert
974ead76f32SLinus Walleij 	 * into the framework.
975ead76f32SLinus Walleij 	 */
976ead76f32SLinus Walleij 	pl011_dma_rx_chars(uap, pending, dmarx->use_buf_b, true);
977ead76f32SLinus Walleij 
978ead76f32SLinus Walleij 	/* Switch buffer & re-trigger DMA job */
979ead76f32SLinus Walleij 	dmarx->use_buf_b = !dmarx->use_buf_b;
980ead76f32SLinus Walleij 	if (pl011_dma_rx_trigger_dma(uap)) {
981ead76f32SLinus Walleij 		dev_dbg(uap->port.dev, "could not retrigger RX DMA job "
982ead76f32SLinus Walleij 			"fall back to interrupt mode\n");
983ead76f32SLinus Walleij 		uap->im |= UART011_RXIM;
9849f25bc51SRussell King 		pl011_write(uap->im, uap, REG_IMSC);
985ead76f32SLinus Walleij 	}
986ead76f32SLinus Walleij }
987ead76f32SLinus Walleij 
pl011_dma_rx_callback(void * data)988ead76f32SLinus Walleij static void pl011_dma_rx_callback(void *data)
989ead76f32SLinus Walleij {
990ead76f32SLinus Walleij 	struct uart_amba_port *uap = data;
991ead76f32SLinus Walleij 	struct pl011_dmarx_data *dmarx = &uap->dmarx;
9926dc01aa6SChanho Min 	struct dma_chan *rxchan = dmarx->chan;
993ead76f32SLinus Walleij 	bool lastbuf = dmarx->use_buf_b;
994c865b77eSArnd Bergmann 	struct pl011_dmabuf *dbuf = dmarx->use_buf_b ?
995c865b77eSArnd Bergmann 		&dmarx->dbuf_b : &dmarx->dbuf_a;
9966dc01aa6SChanho Min 	size_t pending;
9976dc01aa6SChanho Min 	struct dma_tx_state state;
998ead76f32SLinus Walleij 	int ret;
999ead76f32SLinus Walleij 
1000ead76f32SLinus Walleij 	/*
1001ead76f32SLinus Walleij 	 * This completion interrupt occurs typically when the
1002ead76f32SLinus Walleij 	 * RX buffer is totally stuffed but no timeout has yet
1003ead76f32SLinus Walleij 	 * occurred. When that happens, we just want the RX
1004ead76f32SLinus Walleij 	 * routine to flush out the secondary DMA buffer while
1005ead76f32SLinus Walleij 	 * we immediately trigger the next DMA job.
1006ead76f32SLinus Walleij 	 */
10075aea1229SThomas Gleixner 	uart_port_lock_irq(&uap->port);
10086dc01aa6SChanho Min 	/*
10096dc01aa6SChanho Min 	 * Rx data can be taken by the UART interrupts during
10106dc01aa6SChanho Min 	 * the DMA irq handler. So we check the residue here.
10116dc01aa6SChanho Min 	 */
10126dc01aa6SChanho Min 	rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
1013c865b77eSArnd Bergmann 	pending = dbuf->len - state.residue;
10146dc01aa6SChanho Min 	BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
10156dc01aa6SChanho Min 	/* Then we terminate the transfer - we now know our residue */
10166dc01aa6SChanho Min 	dmaengine_terminate_all(rxchan);
10176dc01aa6SChanho Min 
1018ead76f32SLinus Walleij 	uap->dmarx.running = false;
1019ead76f32SLinus Walleij 	dmarx->use_buf_b = !lastbuf;
1020ead76f32SLinus Walleij 	ret = pl011_dma_rx_trigger_dma(uap);
1021ead76f32SLinus Walleij 
10226dc01aa6SChanho Min 	pl011_dma_rx_chars(uap, pending, lastbuf, false);
10235aea1229SThomas Gleixner 	uart_port_unlock_irq(&uap->port);
1024ead76f32SLinus Walleij 	/*
1025ead76f32SLinus Walleij 	 * Do this check after we picked the DMA chars so we don't
1026ead76f32SLinus Walleij 	 * get some IRQ immediately from RX.
1027ead76f32SLinus Walleij 	 */
1028ead76f32SLinus Walleij 	if (ret) {
1029ead76f32SLinus Walleij 		dev_dbg(uap->port.dev, "could not retrigger RX DMA job "
1030ead76f32SLinus Walleij 			"fall back to interrupt mode\n");
1031ead76f32SLinus Walleij 		uap->im |= UART011_RXIM;
10329f25bc51SRussell King 		pl011_write(uap->im, uap, REG_IMSC);
1033ead76f32SLinus Walleij 	}
1034ead76f32SLinus Walleij }
1035ead76f32SLinus Walleij 
1036ead76f32SLinus Walleij /*
1037ead76f32SLinus Walleij  * Stop accepting received characters, when we're shutting down or
1038ead76f32SLinus Walleij  * suspending this port.
1039ead76f32SLinus Walleij  * Locking: called with port lock held and IRQs disabled.
1040ead76f32SLinus Walleij  */
pl011_dma_rx_stop(struct uart_amba_port * uap)1041ead76f32SLinus Walleij static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
1042ead76f32SLinus Walleij {
104394cdb9f3SJiamei Xie 	if (!uap->using_rx_dma)
104494cdb9f3SJiamei Xie 		return;
104594cdb9f3SJiamei Xie 
1046ead76f32SLinus Walleij 	/* FIXME.  Just disable the DMA enable */
1047ead76f32SLinus Walleij 	uap->dmacr &= ~UART011_RXDMAE;
10489f25bc51SRussell King 	pl011_write(uap->dmacr, uap, REG_DMACR);
1049ead76f32SLinus Walleij }
1050ab4382d2SGreg Kroah-Hartman 
1051cb06ff10SChanho Min /*
1052cb06ff10SChanho Min  * Timer handler for Rx DMA polling.
1053cb06ff10SChanho Min  * Every polling, It checks the residue in the dma buffer and transfer
1054cb06ff10SChanho Min  * data to the tty. Also, last_residue is updated for the next polling.
1055cb06ff10SChanho Min  */
pl011_dma_rx_poll(struct timer_list * t)1056f7f73096SKees Cook static void pl011_dma_rx_poll(struct timer_list *t)
1057cb06ff10SChanho Min {
1058f7f73096SKees Cook 	struct uart_amba_port *uap = from_timer(uap, t, dmarx.timer);
1059cb06ff10SChanho Min 	struct tty_port *port = &uap->port.state->port;
1060cb06ff10SChanho Min 	struct pl011_dmarx_data *dmarx = &uap->dmarx;
1061cb06ff10SChanho Min 	struct dma_chan *rxchan = uap->dmarx.chan;
106218ee37e1SJohan Hovold 	unsigned long flags;
1063cb06ff10SChanho Min 	unsigned int dmataken = 0;
1064cb06ff10SChanho Min 	unsigned int size = 0;
1065c865b77eSArnd Bergmann 	struct pl011_dmabuf *dbuf;
1066cb06ff10SChanho Min 	int dma_count;
1067cb06ff10SChanho Min 	struct dma_tx_state state;
1068cb06ff10SChanho Min 
1069c865b77eSArnd Bergmann 	dbuf = dmarx->use_buf_b ? &uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
1070cb06ff10SChanho Min 	rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
1071cb06ff10SChanho Min 	if (likely(state.residue < dmarx->last_residue)) {
1072c865b77eSArnd Bergmann 		dmataken = dbuf->len - dmarx->last_residue;
1073cb06ff10SChanho Min 		size = dmarx->last_residue - state.residue;
1074c865b77eSArnd Bergmann 		dma_count = tty_insert_flip_string(port, dbuf->buf + dmataken,
1075cb06ff10SChanho Min 				size);
1076cb06ff10SChanho Min 		if (dma_count == size)
1077cb06ff10SChanho Min 			dmarx->last_residue =  state.residue;
1078cb06ff10SChanho Min 		dmarx->last_jiffies = jiffies;
1079cb06ff10SChanho Min 	}
1080cb06ff10SChanho Min 	tty_flip_buffer_push(port);
1081cb06ff10SChanho Min 
1082cb06ff10SChanho Min 	/*
1083cb06ff10SChanho Min 	 * If no data is received in poll_timeout, the driver will fall back
1084cb06ff10SChanho Min 	 * to interrupt mode. We will retrigger DMA at the first interrupt.
1085cb06ff10SChanho Min 	 */
1086cb06ff10SChanho Min 	if (jiffies_to_msecs(jiffies - dmarx->last_jiffies)
1087cb06ff10SChanho Min 			> uap->dmarx.poll_timeout) {
1088cb06ff10SChanho Min 
10895aea1229SThomas Gleixner 		uart_port_lock_irqsave(&uap->port, &flags);
1090cb06ff10SChanho Min 		pl011_dma_rx_stop(uap);
1091c25a1ad7SGuennadi Liakhovetski 		uap->im |= UART011_RXIM;
10929f25bc51SRussell King 		pl011_write(uap->im, uap, REG_IMSC);
10935aea1229SThomas Gleixner 		uart_port_unlock_irqrestore(&uap->port, flags);
1094cb06ff10SChanho Min 
1095cb06ff10SChanho Min 		uap->dmarx.running = false;
1096cb06ff10SChanho Min 		dmaengine_terminate_all(rxchan);
1097cb06ff10SChanho Min 		del_timer(&uap->dmarx.timer);
1098cb06ff10SChanho Min 	} else {
1099cb06ff10SChanho Min 		mod_timer(&uap->dmarx.timer,
1100cb06ff10SChanho Min 			jiffies + msecs_to_jiffies(uap->dmarx.poll_rate));
1101cb06ff10SChanho Min 	}
1102cb06ff10SChanho Min }
1103cb06ff10SChanho Min 
pl011_dma_startup(struct uart_amba_port * uap)1104ab4382d2SGreg Kroah-Hartman static void pl011_dma_startup(struct uart_amba_port *uap)
1105ab4382d2SGreg Kroah-Hartman {
1106ead76f32SLinus Walleij 	int ret;
1107ead76f32SLinus Walleij 
11081c9be310SJorge Ramirez-Ortiz 	if (!uap->dma_probed)
11091c9be310SJorge Ramirez-Ortiz 		pl011_dma_probe(uap);
11101c9be310SJorge Ramirez-Ortiz 
1111ab4382d2SGreg Kroah-Hartman 	if (!uap->dmatx.chan)
1112ab4382d2SGreg Kroah-Hartman 		return;
1113ab4382d2SGreg Kroah-Hartman 
11144c0be45bSAndrew Jackson 	uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL | __GFP_DMA);
1115ab4382d2SGreg Kroah-Hartman 	if (!uap->dmatx.buf) {
1116ab4382d2SGreg Kroah-Hartman 		dev_err(uap->port.dev, "no memory for DMA TX buffer\n");
1117ab4382d2SGreg Kroah-Hartman 		uap->port.fifosize = uap->fifosize;
1118ab4382d2SGreg Kroah-Hartman 		return;
1119ab4382d2SGreg Kroah-Hartman 	}
1120ab4382d2SGreg Kroah-Hartman 
1121c865b77eSArnd Bergmann 	uap->dmatx.len = PL011_DMA_BUFFER_SIZE;
1122ab4382d2SGreg Kroah-Hartman 
1123ab4382d2SGreg Kroah-Hartman 	/* The DMA buffer is now the FIFO the TTY subsystem can use */
1124ab4382d2SGreg Kroah-Hartman 	uap->port.fifosize = PL011_DMA_BUFFER_SIZE;
1125ead76f32SLinus Walleij 	uap->using_tx_dma = true;
1126ab4382d2SGreg Kroah-Hartman 
1127ead76f32SLinus Walleij 	if (!uap->dmarx.chan)
1128ead76f32SLinus Walleij 		goto skip_rx;
1129ead76f32SLinus Walleij 
1130ead76f32SLinus Walleij 	/* Allocate and map DMA RX buffers */
1131c865b77eSArnd Bergmann 	ret = pl011_dmabuf_init(uap->dmarx.chan, &uap->dmarx.dbuf_a,
1132ead76f32SLinus Walleij 			       DMA_FROM_DEVICE);
1133ead76f32SLinus Walleij 	if (ret) {
1134ead76f32SLinus Walleij 		dev_err(uap->port.dev, "failed to init DMA %s: %d\n",
1135ead76f32SLinus Walleij 			"RX buffer A", ret);
1136ead76f32SLinus Walleij 		goto skip_rx;
1137ead76f32SLinus Walleij 	}
1138ead76f32SLinus Walleij 
1139c865b77eSArnd Bergmann 	ret = pl011_dmabuf_init(uap->dmarx.chan, &uap->dmarx.dbuf_b,
1140ead76f32SLinus Walleij 			       DMA_FROM_DEVICE);
1141ead76f32SLinus Walleij 	if (ret) {
1142ead76f32SLinus Walleij 		dev_err(uap->port.dev, "failed to init DMA %s: %d\n",
1143ead76f32SLinus Walleij 			"RX buffer B", ret);
1144c865b77eSArnd Bergmann 		pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a,
1145ead76f32SLinus Walleij 				 DMA_FROM_DEVICE);
1146ead76f32SLinus Walleij 		goto skip_rx;
1147ead76f32SLinus Walleij 	}
1148ead76f32SLinus Walleij 
1149ead76f32SLinus Walleij 	uap->using_rx_dma = true;
1150ead76f32SLinus Walleij 
1151ead76f32SLinus Walleij skip_rx:
1152ab4382d2SGreg Kroah-Hartman 	/* Turn on DMA error (RX/TX will be enabled on demand) */
1153ab4382d2SGreg Kroah-Hartman 	uap->dmacr |= UART011_DMAONERR;
11549f25bc51SRussell King 	pl011_write(uap->dmacr, uap, REG_DMACR);
1155ab4382d2SGreg Kroah-Hartman 
1156ab4382d2SGreg Kroah-Hartman 	/*
1157ab4382d2SGreg Kroah-Hartman 	 * ST Micro variants has some specific dma burst threshold
1158ab4382d2SGreg Kroah-Hartman 	 * compensation. Set this to 16 bytes, so burst will only
1159ab4382d2SGreg Kroah-Hartman 	 * be issued above/below 16 bytes.
1160ab4382d2SGreg Kroah-Hartman 	 */
1161ab4382d2SGreg Kroah-Hartman 	if (uap->vendor->dma_threshold)
116275836339SRussell King 		pl011_write(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16,
11639f25bc51SRussell King 			    uap, REG_ST_DMAWM);
1164ead76f32SLinus Walleij 
1165ead76f32SLinus Walleij 	if (uap->using_rx_dma) {
1166ead76f32SLinus Walleij 		if (pl011_dma_rx_trigger_dma(uap))
1167ead76f32SLinus Walleij 			dev_dbg(uap->port.dev, "could not trigger initial "
1168ead76f32SLinus Walleij 				"RX DMA job, fall back to interrupt mode\n");
1169cb06ff10SChanho Min 		if (uap->dmarx.poll_rate) {
1170f7f73096SKees Cook 			timer_setup(&uap->dmarx.timer, pl011_dma_rx_poll, 0);
1171cb06ff10SChanho Min 			mod_timer(&uap->dmarx.timer,
1172cb06ff10SChanho Min 				jiffies +
1173cb06ff10SChanho Min 				msecs_to_jiffies(uap->dmarx.poll_rate));
1174cb06ff10SChanho Min 			uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE;
1175cb06ff10SChanho Min 			uap->dmarx.last_jiffies = jiffies;
1176cb06ff10SChanho Min 		}
1177ead76f32SLinus Walleij 	}
1178ab4382d2SGreg Kroah-Hartman }
1179ab4382d2SGreg Kroah-Hartman 
pl011_dma_shutdown(struct uart_amba_port * uap)1180ab4382d2SGreg Kroah-Hartman static void pl011_dma_shutdown(struct uart_amba_port *uap)
1181ab4382d2SGreg Kroah-Hartman {
1182ead76f32SLinus Walleij 	if (!(uap->using_tx_dma || uap->using_rx_dma))
1183ab4382d2SGreg Kroah-Hartman 		return;
1184ab4382d2SGreg Kroah-Hartman 
1185ab4382d2SGreg Kroah-Hartman 	/* Disable RX and TX DMA */
11860e125a5fSShawn Guo 	while (pl011_read(uap, REG_FR) & uap->vendor->fr_busy)
11872f2fd089STimur Tabi 		cpu_relax();
1188ab4382d2SGreg Kroah-Hartman 
11895aea1229SThomas Gleixner 	uart_port_lock_irq(&uap->port);
1190ab4382d2SGreg Kroah-Hartman 	uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
11919f25bc51SRussell King 	pl011_write(uap->dmacr, uap, REG_DMACR);
11925aea1229SThomas Gleixner 	uart_port_unlock_irq(&uap->port);
1193ab4382d2SGreg Kroah-Hartman 
1194ead76f32SLinus Walleij 	if (uap->using_tx_dma) {
1195ab4382d2SGreg Kroah-Hartman 		/* In theory, this should already be done by pl011_dma_flush_buffer */
1196ab4382d2SGreg Kroah-Hartman 		dmaengine_terminate_all(uap->dmatx.chan);
1197ab4382d2SGreg Kroah-Hartman 		if (uap->dmatx.queued) {
1198c865b77eSArnd Bergmann 			dma_unmap_single(uap->dmatx.chan->device->dev,
1199c865b77eSArnd Bergmann 					 uap->dmatx.dma, uap->dmatx.len,
1200ab4382d2SGreg Kroah-Hartman 					 DMA_TO_DEVICE);
1201ab4382d2SGreg Kroah-Hartman 			uap->dmatx.queued = false;
1202ab4382d2SGreg Kroah-Hartman 		}
1203ab4382d2SGreg Kroah-Hartman 
1204ab4382d2SGreg Kroah-Hartman 		kfree(uap->dmatx.buf);
1205ead76f32SLinus Walleij 		uap->using_tx_dma = false;
1206ab4382d2SGreg Kroah-Hartman 	}
1207ab4382d2SGreg Kroah-Hartman 
1208ead76f32SLinus Walleij 	if (uap->using_rx_dma) {
1209ead76f32SLinus Walleij 		dmaengine_terminate_all(uap->dmarx.chan);
1210ead76f32SLinus Walleij 		/* Clean up the RX DMA */
1211c865b77eSArnd Bergmann 		pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a, DMA_FROM_DEVICE);
1212c865b77eSArnd Bergmann 		pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_b, DMA_FROM_DEVICE);
1213cb06ff10SChanho Min 		if (uap->dmarx.poll_rate)
1214cb06ff10SChanho Min 			del_timer_sync(&uap->dmarx.timer);
1215ead76f32SLinus Walleij 		uap->using_rx_dma = false;
1216ead76f32SLinus Walleij 	}
1217ead76f32SLinus Walleij }
1218ead76f32SLinus Walleij 
pl011_dma_rx_available(struct uart_amba_port * uap)1219ead76f32SLinus Walleij static inline bool pl011_dma_rx_available(struct uart_amba_port *uap)
1220ead76f32SLinus Walleij {
1221ead76f32SLinus Walleij 	return uap->using_rx_dma;
1222ead76f32SLinus Walleij }
1223ead76f32SLinus Walleij 
pl011_dma_rx_running(struct uart_amba_port * uap)1224ead76f32SLinus Walleij static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
1225ead76f32SLinus Walleij {
1226ead76f32SLinus Walleij 	return uap->using_rx_dma && uap->dmarx.running;
1227ead76f32SLinus Walleij }
1228ead76f32SLinus Walleij 
1229ab4382d2SGreg Kroah-Hartman #else
1230ab4382d2SGreg Kroah-Hartman /* Blank functions if the DMA engine is not available */
pl011_dma_remove(struct uart_amba_port * uap)1231ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_remove(struct uart_amba_port *uap)
1232ab4382d2SGreg Kroah-Hartman {
1233ab4382d2SGreg Kroah-Hartman }
1234ab4382d2SGreg Kroah-Hartman 
pl011_dma_startup(struct uart_amba_port * uap)1235ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_startup(struct uart_amba_port *uap)
1236ab4382d2SGreg Kroah-Hartman {
1237ab4382d2SGreg Kroah-Hartman }
1238ab4382d2SGreg Kroah-Hartman 
pl011_dma_shutdown(struct uart_amba_port * uap)1239ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_shutdown(struct uart_amba_port *uap)
1240ab4382d2SGreg Kroah-Hartman {
1241ab4382d2SGreg Kroah-Hartman }
1242ab4382d2SGreg Kroah-Hartman 
pl011_dma_tx_irq(struct uart_amba_port * uap)1243ab4382d2SGreg Kroah-Hartman static inline bool pl011_dma_tx_irq(struct uart_amba_port *uap)
1244ab4382d2SGreg Kroah-Hartman {
1245ab4382d2SGreg Kroah-Hartman 	return false;
1246ab4382d2SGreg Kroah-Hartman }
1247ab4382d2SGreg Kroah-Hartman 
pl011_dma_tx_stop(struct uart_amba_port * uap)1248ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
1249ab4382d2SGreg Kroah-Hartman {
1250ab4382d2SGreg Kroah-Hartman }
1251ab4382d2SGreg Kroah-Hartman 
pl011_dma_tx_start(struct uart_amba_port * uap)1252ab4382d2SGreg Kroah-Hartman static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
1253ab4382d2SGreg Kroah-Hartman {
1254ab4382d2SGreg Kroah-Hartman 	return false;
1255ab4382d2SGreg Kroah-Hartman }
1256ab4382d2SGreg Kroah-Hartman 
pl011_dma_rx_irq(struct uart_amba_port * uap)1257ead76f32SLinus Walleij static inline void pl011_dma_rx_irq(struct uart_amba_port *uap)
1258ead76f32SLinus Walleij {
1259ead76f32SLinus Walleij }
1260ead76f32SLinus Walleij 
pl011_dma_rx_stop(struct uart_amba_port * uap)1261ead76f32SLinus Walleij static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
1262ead76f32SLinus Walleij {
1263ead76f32SLinus Walleij }
1264ead76f32SLinus Walleij 
pl011_dma_rx_trigger_dma(struct uart_amba_port * uap)1265ead76f32SLinus Walleij static inline int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
1266ead76f32SLinus Walleij {
1267ead76f32SLinus Walleij 	return -EIO;
1268ead76f32SLinus Walleij }
1269ead76f32SLinus Walleij 
pl011_dma_rx_available(struct uart_amba_port * uap)1270ead76f32SLinus Walleij static inline bool pl011_dma_rx_available(struct uart_amba_port *uap)
1271ead76f32SLinus Walleij {
1272ead76f32SLinus Walleij 	return false;
1273ead76f32SLinus Walleij }
1274ead76f32SLinus Walleij 
pl011_dma_rx_running(struct uart_amba_port * uap)1275ead76f32SLinus Walleij static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
1276ead76f32SLinus Walleij {
1277ead76f32SLinus Walleij 	return false;
1278ead76f32SLinus Walleij }
1279ead76f32SLinus Walleij 
1280ab4382d2SGreg Kroah-Hartman #define pl011_dma_flush_buffer	NULL
1281ab4382d2SGreg Kroah-Hartman #endif
1282ab4382d2SGreg Kroah-Hartman 
pl011_rs485_tx_stop(struct uart_amba_port * uap)12838d479237SLino Sanfilippo static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
12848d479237SLino Sanfilippo {
12850e4deb56SLino Sanfilippo 	/*
12860e4deb56SLino Sanfilippo 	 * To be on the safe side only time out after twice as many iterations
12870e4deb56SLino Sanfilippo 	 * as fifo size.
12880e4deb56SLino Sanfilippo 	 */
12890e4deb56SLino Sanfilippo 	const int MAX_TX_DRAIN_ITERS = uap->port.fifosize * 2;
12908d479237SLino Sanfilippo 	struct uart_port *port = &uap->port;
12918d479237SLino Sanfilippo 	int i = 0;
12928d479237SLino Sanfilippo 	u32 cr;
12938d479237SLino Sanfilippo 
12948d479237SLino Sanfilippo 	/* Wait until hardware tx queue is empty */
12958d479237SLino Sanfilippo 	while (!pl011_tx_empty(port)) {
12960e4deb56SLino Sanfilippo 		if (i > MAX_TX_DRAIN_ITERS) {
12978d479237SLino Sanfilippo 			dev_warn(port->dev,
12988d479237SLino Sanfilippo 				 "timeout while draining hardware tx queue\n");
12998d479237SLino Sanfilippo 			break;
13008d479237SLino Sanfilippo 		}
13018d479237SLino Sanfilippo 
13028d479237SLino Sanfilippo 		udelay(uap->rs485_tx_drain_interval);
13038d479237SLino Sanfilippo 		i++;
13048d479237SLino Sanfilippo 	}
13058d479237SLino Sanfilippo 
13068d479237SLino Sanfilippo 	if (port->rs485.delay_rts_after_send)
13078d479237SLino Sanfilippo 		mdelay(port->rs485.delay_rts_after_send);
13088d479237SLino Sanfilippo 
13098d479237SLino Sanfilippo 	cr = pl011_read(uap, REG_CR);
13108d479237SLino Sanfilippo 
13118d479237SLino Sanfilippo 	if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
13128d479237SLino Sanfilippo 		cr &= ~UART011_CR_RTS;
13138d479237SLino Sanfilippo 	else
13148d479237SLino Sanfilippo 		cr |= UART011_CR_RTS;
13158d479237SLino Sanfilippo 
13168d479237SLino Sanfilippo 	/* Disable the transmitter and reenable the transceiver */
13178d479237SLino Sanfilippo 	cr &= ~UART011_CR_TXE;
13188d479237SLino Sanfilippo 	cr |= UART011_CR_RXE;
13198d479237SLino Sanfilippo 	pl011_write(cr, uap, REG_CR);
13208d479237SLino Sanfilippo 
13218d479237SLino Sanfilippo 	uap->rs485_tx_started = false;
13228d479237SLino Sanfilippo }
13238d479237SLino Sanfilippo 
pl011_stop_tx(struct uart_port * port)1324ab4382d2SGreg Kroah-Hartman static void pl011_stop_tx(struct uart_port *port)
1325ab4382d2SGreg Kroah-Hartman {
1326a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1327a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1328ab4382d2SGreg Kroah-Hartman 
1329ab4382d2SGreg Kroah-Hartman 	uap->im &= ~UART011_TXIM;
13309f25bc51SRussell King 	pl011_write(uap->im, uap, REG_IMSC);
1331ab4382d2SGreg Kroah-Hartman 	pl011_dma_tx_stop(uap);
13328d479237SLino Sanfilippo 
13338d479237SLino Sanfilippo 	if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started)
13348d479237SLino Sanfilippo 		pl011_rs485_tx_stop(uap);
1335ab4382d2SGreg Kroah-Hartman }
1336ab4382d2SGreg Kroah-Hartman 
13377d05587cSJayachandran C static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq);
1338734745caSDave Martin 
1339734745caSDave Martin /* Start TX with programmed I/O only (no DMA) */
pl011_start_tx_pio(struct uart_amba_port * uap)1340734745caSDave Martin static void pl011_start_tx_pio(struct uart_amba_port *uap)
1341734745caSDave Martin {
13427d05587cSJayachandran C 	if (pl011_tx_chars(uap, false)) {
1343734745caSDave Martin 		uap->im |= UART011_TXIM;
13449f25bc51SRussell King 		pl011_write(uap->im, uap, REG_IMSC);
13457d05587cSJayachandran C 	}
1346734745caSDave Martin }
1347734745caSDave Martin 
pl011_rs485_tx_start(struct uart_amba_port * uap)13489319ecb8SLino Sanfilippo static void pl011_rs485_tx_start(struct uart_amba_port *uap)
13499319ecb8SLino Sanfilippo {
13509319ecb8SLino Sanfilippo 	struct uart_port *port = &uap->port;
13519319ecb8SLino Sanfilippo 	u32 cr;
13529319ecb8SLino Sanfilippo 
13539319ecb8SLino Sanfilippo 	/* Enable transmitter */
13549319ecb8SLino Sanfilippo 	cr = pl011_read(uap, REG_CR);
13559319ecb8SLino Sanfilippo 	cr |= UART011_CR_TXE;
13569319ecb8SLino Sanfilippo 
13579319ecb8SLino Sanfilippo 	/* Disable receiver if half-duplex */
13589319ecb8SLino Sanfilippo 	if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
13599319ecb8SLino Sanfilippo 		cr &= ~UART011_CR_RXE;
13609319ecb8SLino Sanfilippo 
13619319ecb8SLino Sanfilippo 	if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
13629319ecb8SLino Sanfilippo 		cr &= ~UART011_CR_RTS;
13639319ecb8SLino Sanfilippo 	else
13649319ecb8SLino Sanfilippo 		cr |= UART011_CR_RTS;
13659319ecb8SLino Sanfilippo 
13669319ecb8SLino Sanfilippo 	pl011_write(cr, uap, REG_CR);
13679319ecb8SLino Sanfilippo 
13689319ecb8SLino Sanfilippo 	if (port->rs485.delay_rts_before_send)
13699319ecb8SLino Sanfilippo 		mdelay(port->rs485.delay_rts_before_send);
13709319ecb8SLino Sanfilippo 
13719319ecb8SLino Sanfilippo 	uap->rs485_tx_started = true;
13729319ecb8SLino Sanfilippo }
13739319ecb8SLino Sanfilippo 
pl011_start_tx(struct uart_port * port)1374ab4382d2SGreg Kroah-Hartman static void pl011_start_tx(struct uart_port *port)
1375ab4382d2SGreg Kroah-Hartman {
1376a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1377a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1378ab4382d2SGreg Kroah-Hartman 
13799319ecb8SLino Sanfilippo 	if ((uap->port.rs485.flags & SER_RS485_ENABLED) &&
13809319ecb8SLino Sanfilippo 	    !uap->rs485_tx_started)
13819319ecb8SLino Sanfilippo 		pl011_rs485_tx_start(uap);
13829319ecb8SLino Sanfilippo 
1383734745caSDave Martin 	if (!pl011_dma_tx_start(uap))
1384734745caSDave Martin 		pl011_start_tx_pio(uap);
1385ab4382d2SGreg Kroah-Hartman }
1386ab4382d2SGreg Kroah-Hartman 
pl011_stop_rx(struct uart_port * port)1387ab4382d2SGreg Kroah-Hartman static void pl011_stop_rx(struct uart_port *port)
1388ab4382d2SGreg Kroah-Hartman {
1389a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1390a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1391ab4382d2SGreg Kroah-Hartman 
1392ab4382d2SGreg Kroah-Hartman 	uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
1393ab4382d2SGreg Kroah-Hartman 		     UART011_PEIM|UART011_BEIM|UART011_OEIM);
13949f25bc51SRussell King 	pl011_write(uap->im, uap, REG_IMSC);
1395ead76f32SLinus Walleij 
1396ead76f32SLinus Walleij 	pl011_dma_rx_stop(uap);
1397ab4382d2SGreg Kroah-Hartman }
1398ab4382d2SGreg Kroah-Hartman 
pl011_throttle_rx(struct uart_port * port)1399211565b1SIlpo Järvinen static void pl011_throttle_rx(struct uart_port *port)
1400211565b1SIlpo Järvinen {
1401211565b1SIlpo Järvinen 	unsigned long flags;
1402211565b1SIlpo Järvinen 
14035aea1229SThomas Gleixner 	uart_port_lock_irqsave(port, &flags);
1404211565b1SIlpo Järvinen 	pl011_stop_rx(port);
14055aea1229SThomas Gleixner 	uart_port_unlock_irqrestore(port, flags);
1406211565b1SIlpo Järvinen }
1407211565b1SIlpo Järvinen 
pl011_enable_ms(struct uart_port * port)1408ab4382d2SGreg Kroah-Hartman static void pl011_enable_ms(struct uart_port *port)
1409ab4382d2SGreg Kroah-Hartman {
1410a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1411a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1412ab4382d2SGreg Kroah-Hartman 
1413ab4382d2SGreg Kroah-Hartman 	uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM;
14149f25bc51SRussell King 	pl011_write(uap->im, uap, REG_IMSC);
1415ab4382d2SGreg Kroah-Hartman }
1416ab4382d2SGreg Kroah-Hartman 
pl011_rx_chars(struct uart_amba_port * uap)1417ab4382d2SGreg Kroah-Hartman static void pl011_rx_chars(struct uart_amba_port *uap)
1418b83286bfSFabio Estevam __releases(&uap->port.lock)
1419b83286bfSFabio Estevam __acquires(&uap->port.lock)
1420ab4382d2SGreg Kroah-Hartman {
142129772c4eSLinus Walleij 	pl011_fifo_to_tty(uap);
1422ab4382d2SGreg Kroah-Hartman 
14235aea1229SThomas Gleixner 	uart_port_unlock(&uap->port);
14242e124b4aSJiri Slaby 	tty_flip_buffer_push(&uap->port.state->port);
1425ead76f32SLinus Walleij 	/*
1426ead76f32SLinus Walleij 	 * If we were temporarily out of DMA mode for a while,
1427ead76f32SLinus Walleij 	 * attempt to switch back to DMA mode again.
1428ead76f32SLinus Walleij 	 */
1429ead76f32SLinus Walleij 	if (pl011_dma_rx_available(uap)) {
1430ead76f32SLinus Walleij 		if (pl011_dma_rx_trigger_dma(uap)) {
1431ead76f32SLinus Walleij 			dev_dbg(uap->port.dev, "could not trigger RX DMA job "
1432ead76f32SLinus Walleij 				"fall back to interrupt mode again\n");
1433ead76f32SLinus Walleij 			uap->im |= UART011_RXIM;
14349f25bc51SRussell King 			pl011_write(uap->im, uap, REG_IMSC);
1435cb06ff10SChanho Min 		} else {
143689fa28dbSChanho Min #ifdef CONFIG_DMA_ENGINE
1437cb06ff10SChanho Min 			/* Start Rx DMA poll */
1438cb06ff10SChanho Min 			if (uap->dmarx.poll_rate) {
1439cb06ff10SChanho Min 				uap->dmarx.last_jiffies = jiffies;
1440cb06ff10SChanho Min 				uap->dmarx.last_residue	= PL011_DMA_BUFFER_SIZE;
1441cb06ff10SChanho Min 				mod_timer(&uap->dmarx.timer,
1442cb06ff10SChanho Min 					jiffies +
1443cb06ff10SChanho Min 					msecs_to_jiffies(uap->dmarx.poll_rate));
1444cb06ff10SChanho Min 			}
144589fa28dbSChanho Min #endif
1446cb06ff10SChanho Min 		}
1447ead76f32SLinus Walleij 	}
14485aea1229SThomas Gleixner 	uart_port_lock(&uap->port);
1449ab4382d2SGreg Kroah-Hartman }
1450ab4382d2SGreg Kroah-Hartman 
pl011_tx_char(struct uart_amba_port * uap,unsigned char c,bool from_irq)14511e84d223SDave Martin static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
14521e84d223SDave Martin 			  bool from_irq)
1453734745caSDave Martin {
14541e84d223SDave Martin 	if (unlikely(!from_irq) &&
14559f25bc51SRussell King 	    pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
14561e84d223SDave Martin 		return false; /* unable to transmit character */
14571e84d223SDave Martin 
14589f25bc51SRussell King 	pl011_write(c, uap, REG_DR);
1459734745caSDave Martin 	uap->port.icount.tx++;
1460734745caSDave Martin 
1461734745caSDave Martin 	return true;
1462734745caSDave Martin }
1463734745caSDave Martin 
14647d05587cSJayachandran C /* Returns true if tx interrupts have to be (kept) enabled  */
pl011_tx_chars(struct uart_amba_port * uap,bool from_irq)14657d05587cSJayachandran C static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
1466ab4382d2SGreg Kroah-Hartman {
1467ab4382d2SGreg Kroah-Hartman 	struct circ_buf *xmit = &uap->port.state->xmit;
14681e84d223SDave Martin 	int count = uap->fifosize >> 1;
1469734745caSDave Martin 
1470ab4382d2SGreg Kroah-Hartman 	if (uap->port.x_char) {
14711e84d223SDave Martin 		if (!pl011_tx_char(uap, uap->port.x_char, from_irq))
14727d05587cSJayachandran C 			return true;
1473ab4382d2SGreg Kroah-Hartman 		uap->port.x_char = 0;
1474734745caSDave Martin 		--count;
1475ab4382d2SGreg Kroah-Hartman 	}
1476ab4382d2SGreg Kroah-Hartman 	if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
1477ab4382d2SGreg Kroah-Hartman 		pl011_stop_tx(&uap->port);
14787d05587cSJayachandran C 		return false;
1479ab4382d2SGreg Kroah-Hartman 	}
1480ab4382d2SGreg Kroah-Hartman 
1481ab4382d2SGreg Kroah-Hartman 	/* If we are using DMA mode, try to send some characters. */
1482ab4382d2SGreg Kroah-Hartman 	if (pl011_dma_tx_irq(uap))
14837d05587cSJayachandran C 		return true;
1484ab4382d2SGreg Kroah-Hartman 
14851e84d223SDave Martin 	do {
14861e84d223SDave Martin 		if (likely(from_irq) && count-- == 0)
1487ab4382d2SGreg Kroah-Hartman 			break;
14881e84d223SDave Martin 
14891e84d223SDave Martin 		if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq))
14901e84d223SDave Martin 			break;
14911e84d223SDave Martin 
14921e84d223SDave Martin 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
14931e84d223SDave Martin 	} while (!uart_circ_empty(xmit));
1494ab4382d2SGreg Kroah-Hartman 
1495ab4382d2SGreg Kroah-Hartman 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
1496ab4382d2SGreg Kroah-Hartman 		uart_write_wakeup(&uap->port);
1497ab4382d2SGreg Kroah-Hartman 
14987d05587cSJayachandran C 	if (uart_circ_empty(xmit)) {
1499ab4382d2SGreg Kroah-Hartman 		pl011_stop_tx(&uap->port);
15007d05587cSJayachandran C 		return false;
15017d05587cSJayachandran C 	}
15027d05587cSJayachandran C 	return true;
1503ab4382d2SGreg Kroah-Hartman }
1504ab4382d2SGreg Kroah-Hartman 
pl011_modem_status(struct uart_amba_port * uap)1505ab4382d2SGreg Kroah-Hartman static void pl011_modem_status(struct uart_amba_port *uap)
1506ab4382d2SGreg Kroah-Hartman {
1507ab4382d2SGreg Kroah-Hartman 	unsigned int status, delta;
1508ab4382d2SGreg Kroah-Hartman 
15099f25bc51SRussell King 	status = pl011_read(uap, REG_FR) & UART01x_FR_MODEM_ANY;
1510ab4382d2SGreg Kroah-Hartman 
1511ab4382d2SGreg Kroah-Hartman 	delta = status ^ uap->old_status;
1512ab4382d2SGreg Kroah-Hartman 	uap->old_status = status;
1513ab4382d2SGreg Kroah-Hartman 
1514ab4382d2SGreg Kroah-Hartman 	if (!delta)
1515ab4382d2SGreg Kroah-Hartman 		return;
1516ab4382d2SGreg Kroah-Hartman 
1517ab4382d2SGreg Kroah-Hartman 	if (delta & UART01x_FR_DCD)
1518ab4382d2SGreg Kroah-Hartman 		uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
1519ab4382d2SGreg Kroah-Hartman 
15200e125a5fSShawn Guo 	if (delta & uap->vendor->fr_dsr)
1521ab4382d2SGreg Kroah-Hartman 		uap->port.icount.dsr++;
1522ab4382d2SGreg Kroah-Hartman 
15230e125a5fSShawn Guo 	if (delta & uap->vendor->fr_cts)
15240e125a5fSShawn Guo 		uart_handle_cts_change(&uap->port,
15250e125a5fSShawn Guo 				       status & uap->vendor->fr_cts);
1526ab4382d2SGreg Kroah-Hartman 
1527ab4382d2SGreg Kroah-Hartman 	wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
1528ab4382d2SGreg Kroah-Hartman }
1529ab4382d2SGreg Kroah-Hartman 
check_apply_cts_event_workaround(struct uart_amba_port * uap)15309c4ef4b0SAndre Przywara static void check_apply_cts_event_workaround(struct uart_amba_port *uap)
1531ab4382d2SGreg Kroah-Hartman {
15329c4ef4b0SAndre Przywara 	if (!uap->vendor->cts_event_workaround)
15339c4ef4b0SAndre Przywara 		return;
15349c4ef4b0SAndre Przywara 
15354fd0690bSRajanikanth H.V 	/* workaround to make sure that all bits are unlocked.. */
15369f25bc51SRussell King 	pl011_write(0x00, uap, REG_ICR);
15374fd0690bSRajanikanth H.V 
15384fd0690bSRajanikanth H.V 	/*
15394fd0690bSRajanikanth H.V 	 * WA: introduce 26ns(1 uart clk) delay before W1C;
15404fd0690bSRajanikanth H.V 	 * single apb access will incur 2 pclk(133.12Mhz) delay,
15414fd0690bSRajanikanth H.V 	 * so add 2 dummy reads
15424fd0690bSRajanikanth H.V 	 */
154394345aeeSXiongfeng Wang 	pl011_read(uap, REG_ICR);
154494345aeeSXiongfeng Wang 	pl011_read(uap, REG_ICR);
15454fd0690bSRajanikanth H.V }
15464fd0690bSRajanikanth H.V 
pl011_int(int irq,void * dev_id)15479c4ef4b0SAndre Przywara static irqreturn_t pl011_int(int irq, void *dev_id)
15489c4ef4b0SAndre Przywara {
15499c4ef4b0SAndre Przywara 	struct uart_amba_port *uap = dev_id;
15509c4ef4b0SAndre Przywara 	unsigned long flags;
15519c4ef4b0SAndre Przywara 	unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
15529c4ef4b0SAndre Przywara 	int handled = 0;
15539c4ef4b0SAndre Przywara 
15545aea1229SThomas Gleixner 	uart_port_lock_irqsave(&uap->port, &flags);
1555d3a96c94SLukas Wunner 	status = pl011_read(uap, REG_RIS) & uap->im;
15569c4ef4b0SAndre Przywara 	if (status) {
15579c4ef4b0SAndre Przywara 		do {
15589c4ef4b0SAndre Przywara 			check_apply_cts_event_workaround(uap);
1559f11c9841SGreg Kroah-Hartman 
156075836339SRussell King 			pl011_write(status & ~(UART011_TXIS|UART011_RTIS|
1561f11c9841SGreg Kroah-Hartman 					       UART011_RXIS),
15629f25bc51SRussell King 				    uap, REG_ICR);
1563ab4382d2SGreg Kroah-Hartman 
1564ead76f32SLinus Walleij 			if (status & (UART011_RTIS|UART011_RXIS)) {
1565ead76f32SLinus Walleij 				if (pl011_dma_rx_running(uap))
1566ead76f32SLinus Walleij 					pl011_dma_rx_irq(uap);
1567ead76f32SLinus Walleij 				else
1568ab4382d2SGreg Kroah-Hartman 					pl011_rx_chars(uap);
1569ead76f32SLinus Walleij 			}
1570ab4382d2SGreg Kroah-Hartman 			if (status & (UART011_DSRMIS|UART011_DCDMIS|
1571ab4382d2SGreg Kroah-Hartman 				      UART011_CTSMIS|UART011_RIMIS))
1572ab4382d2SGreg Kroah-Hartman 				pl011_modem_status(uap);
15731e84d223SDave Martin 			if (status & UART011_TXIS)
15741e84d223SDave Martin 				pl011_tx_chars(uap, true);
1575ab4382d2SGreg Kroah-Hartman 
15764fd0690bSRajanikanth H.V 			if (pass_counter-- == 0)
1577ab4382d2SGreg Kroah-Hartman 				break;
1578ab4382d2SGreg Kroah-Hartman 
1579d3a96c94SLukas Wunner 			status = pl011_read(uap, REG_RIS) & uap->im;
1580ab4382d2SGreg Kroah-Hartman 		} while (status != 0);
1581ab4382d2SGreg Kroah-Hartman 		handled = 1;
1582ab4382d2SGreg Kroah-Hartman 	}
1583ab4382d2SGreg Kroah-Hartman 
15845aea1229SThomas Gleixner 	uart_port_unlock_irqrestore(&uap->port, flags);
1585ab4382d2SGreg Kroah-Hartman 
1586ab4382d2SGreg Kroah-Hartman 	return IRQ_RETVAL(handled);
1587ab4382d2SGreg Kroah-Hartman }
1588ab4382d2SGreg Kroah-Hartman 
pl011_tx_empty(struct uart_port * port)1589e643f87fSLinus Walleij static unsigned int pl011_tx_empty(struct uart_port *port)
1590ab4382d2SGreg Kroah-Hartman {
1591a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1592a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1593d8a4995bSChristopher Covington 
1594d8a4995bSChristopher Covington 	/* Allow feature register bits to be inverted to work around errata */
1595d8a4995bSChristopher Covington 	unsigned int status = pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr;
1596d8a4995bSChristopher Covington 
15970e125a5fSShawn Guo 	return status & (uap->vendor->fr_busy | UART01x_FR_TXFF) ?
15980e125a5fSShawn Guo 							0 : TIOCSER_TEMT;
1599ab4382d2SGreg Kroah-Hartman }
1600ab4382d2SGreg Kroah-Hartman 
pl011_get_mctrl(struct uart_port * port)1601e643f87fSLinus Walleij static unsigned int pl011_get_mctrl(struct uart_port *port)
1602ab4382d2SGreg Kroah-Hartman {
1603a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1604a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1605ab4382d2SGreg Kroah-Hartman 	unsigned int result = 0;
16069f25bc51SRussell King 	unsigned int status = pl011_read(uap, REG_FR);
1607ab4382d2SGreg Kroah-Hartman 
1608ab4382d2SGreg Kroah-Hartman #define TIOCMBIT(uartbit, tiocmbit)	\
1609ab4382d2SGreg Kroah-Hartman 	if (status & uartbit)		\
1610ab4382d2SGreg Kroah-Hartman 		result |= tiocmbit
1611ab4382d2SGreg Kroah-Hartman 
1612ab4382d2SGreg Kroah-Hartman 	TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR);
16130e125a5fSShawn Guo 	TIOCMBIT(uap->vendor->fr_dsr, TIOCM_DSR);
16140e125a5fSShawn Guo 	TIOCMBIT(uap->vendor->fr_cts, TIOCM_CTS);
16150e125a5fSShawn Guo 	TIOCMBIT(uap->vendor->fr_ri, TIOCM_RNG);
1616ab4382d2SGreg Kroah-Hartman #undef TIOCMBIT
1617ab4382d2SGreg Kroah-Hartman 	return result;
1618ab4382d2SGreg Kroah-Hartman }
1619ab4382d2SGreg Kroah-Hartman 
pl011_set_mctrl(struct uart_port * port,unsigned int mctrl)1620ab4382d2SGreg Kroah-Hartman static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
1621ab4382d2SGreg Kroah-Hartman {
1622a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1623a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1624ab4382d2SGreg Kroah-Hartman 	unsigned int cr;
1625ab4382d2SGreg Kroah-Hartman 
16269f25bc51SRussell King 	cr = pl011_read(uap, REG_CR);
1627ab4382d2SGreg Kroah-Hartman 
1628ab4382d2SGreg Kroah-Hartman #define	TIOCMBIT(tiocmbit, uartbit)		\
1629ab4382d2SGreg Kroah-Hartman 	if (mctrl & tiocmbit)		\
1630ab4382d2SGreg Kroah-Hartman 		cr |= uartbit;		\
1631ab4382d2SGreg Kroah-Hartman 	else				\
1632ab4382d2SGreg Kroah-Hartman 		cr &= ~uartbit
1633ab4382d2SGreg Kroah-Hartman 
1634ab4382d2SGreg Kroah-Hartman 	TIOCMBIT(TIOCM_RTS, UART011_CR_RTS);
1635ab4382d2SGreg Kroah-Hartman 	TIOCMBIT(TIOCM_DTR, UART011_CR_DTR);
1636ab4382d2SGreg Kroah-Hartman 	TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1);
1637ab4382d2SGreg Kroah-Hartman 	TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2);
1638ab4382d2SGreg Kroah-Hartman 	TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE);
1639ab4382d2SGreg Kroah-Hartman 
16402a76fa28SLukas Wunner 	if (port->status & UPSTAT_AUTORTS) {
1641ab4382d2SGreg Kroah-Hartman 		/* We need to disable auto-RTS if we want to turn RTS off */
1642ab4382d2SGreg Kroah-Hartman 		TIOCMBIT(TIOCM_RTS, UART011_CR_RTSEN);
1643ab4382d2SGreg Kroah-Hartman 	}
1644ab4382d2SGreg Kroah-Hartman #undef TIOCMBIT
1645ab4382d2SGreg Kroah-Hartman 
16469f25bc51SRussell King 	pl011_write(cr, uap, REG_CR);
1647ab4382d2SGreg Kroah-Hartman }
1648ab4382d2SGreg Kroah-Hartman 
pl011_break_ctl(struct uart_port * port,int break_state)1649ab4382d2SGreg Kroah-Hartman static void pl011_break_ctl(struct uart_port *port, int break_state)
1650ab4382d2SGreg Kroah-Hartman {
1651a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1652a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1653ab4382d2SGreg Kroah-Hartman 	unsigned long flags;
1654ab4382d2SGreg Kroah-Hartman 	unsigned int lcr_h;
1655ab4382d2SGreg Kroah-Hartman 
16565aea1229SThomas Gleixner 	uart_port_lock_irqsave(&uap->port, &flags);
1657e4df9a80SRussell King 	lcr_h = pl011_read(uap, REG_LCRH_TX);
1658ab4382d2SGreg Kroah-Hartman 	if (break_state == -1)
1659ab4382d2SGreg Kroah-Hartman 		lcr_h |= UART01x_LCRH_BRK;
1660ab4382d2SGreg Kroah-Hartman 	else
1661ab4382d2SGreg Kroah-Hartman 		lcr_h &= ~UART01x_LCRH_BRK;
1662e4df9a80SRussell King 	pl011_write(lcr_h, uap, REG_LCRH_TX);
16635aea1229SThomas Gleixner 	uart_port_unlock_irqrestore(&uap->port, flags);
1664ab4382d2SGreg Kroah-Hartman }
1665ab4382d2SGreg Kroah-Hartman 
1666ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_CONSOLE_POLL
16675c8124a0SAnton Vorontsov 
pl011_quiesce_irqs(struct uart_port * port)16685c8124a0SAnton Vorontsov static void pl011_quiesce_irqs(struct uart_port *port)
16695c8124a0SAnton Vorontsov {
1670a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1671a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
16725c8124a0SAnton Vorontsov 
16739f25bc51SRussell King 	pl011_write(pl011_read(uap, REG_MIS), uap, REG_ICR);
16745c8124a0SAnton Vorontsov 	/*
16755c8124a0SAnton Vorontsov 	 * There is no way to clear TXIM as this is "ready to transmit IRQ", so
16765c8124a0SAnton Vorontsov 	 * we simply mask it. start_tx() will unmask it.
16775c8124a0SAnton Vorontsov 	 *
16785c8124a0SAnton Vorontsov 	 * Note we can race with start_tx(), and if the race happens, the
16795c8124a0SAnton Vorontsov 	 * polling user might get another interrupt just after we clear it.
16805c8124a0SAnton Vorontsov 	 * But it should be OK and can happen even w/o the race, e.g.
16815c8124a0SAnton Vorontsov 	 * controller immediately got some new data and raised the IRQ.
16825c8124a0SAnton Vorontsov 	 *
16835c8124a0SAnton Vorontsov 	 * And whoever uses polling routines assumes that it manages the device
16845c8124a0SAnton Vorontsov 	 * (including tx queue), so we're also fine with start_tx()'s caller
16855c8124a0SAnton Vorontsov 	 * side.
16865c8124a0SAnton Vorontsov 	 */
16879f25bc51SRussell King 	pl011_write(pl011_read(uap, REG_IMSC) & ~UART011_TXIM, uap,
16889f25bc51SRussell King 		    REG_IMSC);
16895c8124a0SAnton Vorontsov }
16905c8124a0SAnton Vorontsov 
pl011_get_poll_char(struct uart_port * port)1691e643f87fSLinus Walleij static int pl011_get_poll_char(struct uart_port *port)
1692ab4382d2SGreg Kroah-Hartman {
1693a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1694a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1695ab4382d2SGreg Kroah-Hartman 	unsigned int status;
1696ab4382d2SGreg Kroah-Hartman 
16975c8124a0SAnton Vorontsov 	/*
16985c8124a0SAnton Vorontsov 	 * The caller might need IRQs lowered, e.g. if used with KDB NMI
16995c8124a0SAnton Vorontsov 	 * debugger.
17005c8124a0SAnton Vorontsov 	 */
17015c8124a0SAnton Vorontsov 	pl011_quiesce_irqs(port);
17025c8124a0SAnton Vorontsov 
17039f25bc51SRussell King 	status = pl011_read(uap, REG_FR);
1704ab4382d2SGreg Kroah-Hartman 	if (status & UART01x_FR_RXFE)
1705ab4382d2SGreg Kroah-Hartman 		return NO_POLL_CHAR;
1706ab4382d2SGreg Kroah-Hartman 
17079f25bc51SRussell King 	return pl011_read(uap, REG_DR);
1708ab4382d2SGreg Kroah-Hartman }
1709ab4382d2SGreg Kroah-Hartman 
pl011_put_poll_char(struct uart_port * port,unsigned char ch)1710e643f87fSLinus Walleij static void pl011_put_poll_char(struct uart_port *port,
1711ab4382d2SGreg Kroah-Hartman 			 unsigned char ch)
1712ab4382d2SGreg Kroah-Hartman {
1713a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1714a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1715ab4382d2SGreg Kroah-Hartman 
17169f25bc51SRussell King 	while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
17172f2fd089STimur Tabi 		cpu_relax();
1718ab4382d2SGreg Kroah-Hartman 
17199f25bc51SRussell King 	pl011_write(ch, uap, REG_DR);
1720ab4382d2SGreg Kroah-Hartman }
1721ab4382d2SGreg Kroah-Hartman 
1722ab4382d2SGreg Kroah-Hartman #endif /* CONFIG_CONSOLE_POLL */
1723ab4382d2SGreg Kroah-Hartman 
pl011_hwinit(struct uart_port * port)1724b3564c2cSAnton Vorontsov static int pl011_hwinit(struct uart_port *port)
1725ab4382d2SGreg Kroah-Hartman {
1726a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1727a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1728ab4382d2SGreg Kroah-Hartman 	int retval;
1729ab4382d2SGreg Kroah-Hartman 
173078d80c5aSLinus Walleij 	/* Optionaly enable pins to be muxed in and configured */
17312b996fc5SLinus Walleij 	pinctrl_pm_select_default_state(port->dev);
173278d80c5aSLinus Walleij 
1733ab4382d2SGreg Kroah-Hartman 	/*
1734ab4382d2SGreg Kroah-Hartman 	 * Try to enable the clock producer.
1735ab4382d2SGreg Kroah-Hartman 	 */
17361c4c4394SJulia Lawall 	retval = clk_prepare_enable(uap->clk);
1737ab4382d2SGreg Kroah-Hartman 	if (retval)
17387f6d942aSTushar Behera 		return retval;
1739ab4382d2SGreg Kroah-Hartman 
1740ab4382d2SGreg Kroah-Hartman 	uap->port.uartclk = clk_get_rate(uap->clk);
1741ab4382d2SGreg Kroah-Hartman 
17429b96fbacSLinus Walleij 	/* Clear pending error and receive interrupts */
174375836339SRussell King 	pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS |
174475836339SRussell King 		    UART011_FEIS | UART011_RTIS | UART011_RXIS,
17459f25bc51SRussell King 		    uap, REG_ICR);
17469b96fbacSLinus Walleij 
1747ab4382d2SGreg Kroah-Hartman 	/*
1748b3564c2cSAnton Vorontsov 	 * Save interrupts enable mask, and enable RX interrupts in case if
1749b3564c2cSAnton Vorontsov 	 * the interrupt is used for NMI entry.
1750b3564c2cSAnton Vorontsov 	 */
17519f25bc51SRussell King 	uap->im = pl011_read(uap, REG_IMSC);
17529f25bc51SRussell King 	pl011_write(UART011_RTIM | UART011_RXIM, uap, REG_IMSC);
1753b3564c2cSAnton Vorontsov 
1754574de559SJingoo Han 	if (dev_get_platdata(uap->port.dev)) {
1755b3564c2cSAnton Vorontsov 		struct amba_pl011_data *plat;
1756b3564c2cSAnton Vorontsov 
1757574de559SJingoo Han 		plat = dev_get_platdata(uap->port.dev);
1758b3564c2cSAnton Vorontsov 		if (plat->init)
1759b3564c2cSAnton Vorontsov 			plat->init();
1760b3564c2cSAnton Vorontsov 	}
1761b3564c2cSAnton Vorontsov 	return 0;
1762b3564c2cSAnton Vorontsov }
1763b3564c2cSAnton Vorontsov 
pl011_split_lcrh(const struct uart_amba_port * uap)17647fe9a5a9SRussell King static bool pl011_split_lcrh(const struct uart_amba_port *uap)
17657fe9a5a9SRussell King {
1766e4df9a80SRussell King 	return pl011_reg_to_offset(uap, REG_LCRH_RX) !=
1767e4df9a80SRussell King 	       pl011_reg_to_offset(uap, REG_LCRH_TX);
17687fe9a5a9SRussell King }
17697fe9a5a9SRussell King 
pl011_write_lcr_h(struct uart_amba_port * uap,unsigned int lcr_h)1770b60f2f66SJon Medhurst static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
1771b60f2f66SJon Medhurst {
1772e4df9a80SRussell King 	pl011_write(lcr_h, uap, REG_LCRH_RX);
17737fe9a5a9SRussell King 	if (pl011_split_lcrh(uap)) {
1774b60f2f66SJon Medhurst 		int i;
1775b60f2f66SJon Medhurst 		/*
1776b60f2f66SJon Medhurst 		 * Wait 10 PCLKs before writing LCRH_TX register,
1777b60f2f66SJon Medhurst 		 * to get this delay write read only register 10 times
1778b60f2f66SJon Medhurst 		 */
1779b60f2f66SJon Medhurst 		for (i = 0; i < 10; ++i)
17809f25bc51SRussell King 			pl011_write(0xff, uap, REG_MIS);
1781e4df9a80SRussell King 		pl011_write(lcr_h, uap, REG_LCRH_TX);
1782b60f2f66SJon Medhurst 	}
1783b60f2f66SJon Medhurst }
1784b60f2f66SJon Medhurst 
pl011_allocate_irq(struct uart_amba_port * uap)1785867b8e8eSAndre Przywara static int pl011_allocate_irq(struct uart_amba_port *uap)
1786867b8e8eSAndre Przywara {
17879f25bc51SRussell King 	pl011_write(uap->im, uap, REG_IMSC);
1788867b8e8eSAndre Przywara 
178994560f61SQian Cai 	return request_irq(uap->port.irq, pl011_int, IRQF_SHARED, "uart-pl011", uap);
1790867b8e8eSAndre Przywara }
1791867b8e8eSAndre Przywara 
1792867b8e8eSAndre Przywara /*
1793867b8e8eSAndre Przywara  * Enable interrupts, only timeouts when using DMA
1794867b8e8eSAndre Przywara  * if initial RX DMA job failed, start in interrupt mode
1795867b8e8eSAndre Przywara  * as well.
1796867b8e8eSAndre Przywara  */
pl011_enable_interrupts(struct uart_amba_port * uap)1797867b8e8eSAndre Przywara static void pl011_enable_interrupts(struct uart_amba_port *uap)
1798867b8e8eSAndre Przywara {
1799211565b1SIlpo Järvinen 	unsigned long flags;
18004a7e625cSDave Martin 	unsigned int i;
18014a7e625cSDave Martin 
18025aea1229SThomas Gleixner 	uart_port_lock_irqsave(&uap->port, &flags);
1803867b8e8eSAndre Przywara 
1804867b8e8eSAndre Przywara 	/* Clear out any spuriously appearing RX interrupts */
18059f25bc51SRussell King 	pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR);
18064a7e625cSDave Martin 
18074a7e625cSDave Martin 	/*
18084a7e625cSDave Martin 	 * RXIS is asserted only when the RX FIFO transitions from below
18094a7e625cSDave Martin 	 * to above the trigger threshold.  If the RX FIFO is already
18104a7e625cSDave Martin 	 * full to the threshold this can't happen and RXIS will now be
18114a7e625cSDave Martin 	 * stuck off.  Drain the RX FIFO explicitly to fix this:
18124a7e625cSDave Martin 	 */
18134a7e625cSDave Martin 	for (i = 0; i < uap->fifosize * 2; ++i) {
18144a7e625cSDave Martin 		if (pl011_read(uap, REG_FR) & UART01x_FR_RXFE)
18154a7e625cSDave Martin 			break;
18164a7e625cSDave Martin 
18174a7e625cSDave Martin 		pl011_read(uap, REG_DR);
18184a7e625cSDave Martin 	}
18194a7e625cSDave Martin 
1820867b8e8eSAndre Przywara 	uap->im = UART011_RTIM;
1821867b8e8eSAndre Przywara 	if (!pl011_dma_rx_running(uap))
1822867b8e8eSAndre Przywara 		uap->im |= UART011_RXIM;
18239f25bc51SRussell King 	pl011_write(uap->im, uap, REG_IMSC);
18245aea1229SThomas Gleixner 	uart_port_unlock_irqrestore(&uap->port, flags);
1825211565b1SIlpo Järvinen }
1826211565b1SIlpo Järvinen 
pl011_unthrottle_rx(struct uart_port * port)1827211565b1SIlpo Järvinen static void pl011_unthrottle_rx(struct uart_port *port)
1828211565b1SIlpo Järvinen {
1829211565b1SIlpo Järvinen 	struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port);
1830032d5a71Sdelisun 	unsigned long flags;
1831211565b1SIlpo Järvinen 
18325aea1229SThomas Gleixner 	uart_port_lock_irqsave(&uap->port, &flags);
1833032d5a71Sdelisun 
1834032d5a71Sdelisun 	uap->im = UART011_RTIM;
1835032d5a71Sdelisun 	if (!pl011_dma_rx_running(uap))
1836032d5a71Sdelisun 		uap->im |= UART011_RXIM;
1837032d5a71Sdelisun 
1838032d5a71Sdelisun 	pl011_write(uap->im, uap, REG_IMSC);
1839032d5a71Sdelisun 
1840*1baed369SArnd Bergmann #ifdef CONFIG_DMA_ENGINE
18412eb983f6SKartik Rajput 	if (uap->using_rx_dma) {
18422eb983f6SKartik Rajput 		uap->dmacr |= UART011_RXDMAE;
18432eb983f6SKartik Rajput 		pl011_write(uap->dmacr, uap, REG_DMACR);
18442eb983f6SKartik Rajput 	}
1845*1baed369SArnd Bergmann #endif
18462eb983f6SKartik Rajput 
18475aea1229SThomas Gleixner 	uart_port_unlock_irqrestore(&uap->port, flags);
1848867b8e8eSAndre Przywara }
1849867b8e8eSAndre Przywara 
pl011_startup(struct uart_port * port)1850b3564c2cSAnton Vorontsov static int pl011_startup(struct uart_port *port)
1851b3564c2cSAnton Vorontsov {
1852a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
1853a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
1854734745caSDave Martin 	unsigned int cr;
1855b3564c2cSAnton Vorontsov 	int retval;
1856b3564c2cSAnton Vorontsov 
1857b3564c2cSAnton Vorontsov 	retval = pl011_hwinit(port);
1858b3564c2cSAnton Vorontsov 	if (retval)
1859b3564c2cSAnton Vorontsov 		goto clk_dis;
1860b3564c2cSAnton Vorontsov 
1861867b8e8eSAndre Przywara 	retval = pl011_allocate_irq(uap);
1862ab4382d2SGreg Kroah-Hartman 	if (retval)
1863ab4382d2SGreg Kroah-Hartman 		goto clk_dis;
1864ab4382d2SGreg Kroah-Hartman 
18659f25bc51SRussell King 	pl011_write(uap->vendor->ifls, uap, REG_IFLS);
1866ab4382d2SGreg Kroah-Hartman 
18675aea1229SThomas Gleixner 	uart_port_lock_irq(&uap->port);
1868fe433907SJon Medhurst 
186949a80424SLukas Wunner 	cr = pl011_read(uap, REG_CR);
187049a80424SLukas Wunner 	cr &= UART011_CR_RTS | UART011_CR_DTR;
18718d479237SLino Sanfilippo 	cr |= UART01x_CR_UARTEN | UART011_CR_RXE;
18728d479237SLino Sanfilippo 
18732dd8a74fSLukas Wunner 	if (!(port->rs485.flags & SER_RS485_ENABLED))
18748d479237SLino Sanfilippo 		cr |= UART011_CR_TXE;
18758d479237SLino Sanfilippo 
18769f25bc51SRussell King 	pl011_write(cr, uap, REG_CR);
1877ab4382d2SGreg Kroah-Hartman 
18785aea1229SThomas Gleixner 	uart_port_unlock_irq(&uap->port);
1879fe433907SJon Medhurst 
1880ab4382d2SGreg Kroah-Hartman 	/*
1881ab4382d2SGreg Kroah-Hartman 	 * initialise the old status of the modem signals
1882ab4382d2SGreg Kroah-Hartman 	 */
18839f25bc51SRussell King 	uap->old_status = pl011_read(uap, REG_FR) & UART01x_FR_MODEM_ANY;
1884ab4382d2SGreg Kroah-Hartman 
1885ab4382d2SGreg Kroah-Hartman 	/* Startup DMA */
1886ab4382d2SGreg Kroah-Hartman 	pl011_dma_startup(uap);
1887ab4382d2SGreg Kroah-Hartman 
1888867b8e8eSAndre Przywara 	pl011_enable_interrupts(uap);
1889ab4382d2SGreg Kroah-Hartman 
1890ab4382d2SGreg Kroah-Hartman 	return 0;
1891ab4382d2SGreg Kroah-Hartman 
1892ab4382d2SGreg Kroah-Hartman  clk_dis:
18931c4c4394SJulia Lawall 	clk_disable_unprepare(uap->clk);
1894ab4382d2SGreg Kroah-Hartman 	return retval;
1895ab4382d2SGreg Kroah-Hartman }
1896ab4382d2SGreg Kroah-Hartman 
sbsa_uart_startup(struct uart_port * port)18970dd1e247SAndre Przywara static int sbsa_uart_startup(struct uart_port *port)
18980dd1e247SAndre Przywara {
18990dd1e247SAndre Przywara 	struct uart_amba_port *uap =
19000dd1e247SAndre Przywara 		container_of(port, struct uart_amba_port, port);
19010dd1e247SAndre Przywara 	int retval;
19020dd1e247SAndre Przywara 
19030dd1e247SAndre Przywara 	retval = pl011_hwinit(port);
19040dd1e247SAndre Przywara 	if (retval)
19050dd1e247SAndre Przywara 		return retval;
19060dd1e247SAndre Przywara 
19070dd1e247SAndre Przywara 	retval = pl011_allocate_irq(uap);
19080dd1e247SAndre Przywara 	if (retval)
19090dd1e247SAndre Przywara 		return retval;
19100dd1e247SAndre Przywara 
19110dd1e247SAndre Przywara 	/* The SBSA UART does not support any modem status lines. */
19120dd1e247SAndre Przywara 	uap->old_status = 0;
19130dd1e247SAndre Przywara 
19140dd1e247SAndre Przywara 	pl011_enable_interrupts(uap);
19150dd1e247SAndre Przywara 
19160dd1e247SAndre Przywara 	return 0;
19170dd1e247SAndre Przywara }
19180dd1e247SAndre Przywara 
pl011_shutdown_channel(struct uart_amba_port * uap,unsigned int lcrh)1919ab4382d2SGreg Kroah-Hartman static void pl011_shutdown_channel(struct uart_amba_port *uap,
1920ab4382d2SGreg Kroah-Hartman 					unsigned int lcrh)
1921ab4382d2SGreg Kroah-Hartman {
1922ab4382d2SGreg Kroah-Hartman       unsigned long val;
1923ab4382d2SGreg Kroah-Hartman 
1924b2a4e24cSRussell King       val = pl011_read(uap, lcrh);
1925ab4382d2SGreg Kroah-Hartman       val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
1926b2a4e24cSRussell King       pl011_write(val, uap, lcrh);
1927ab4382d2SGreg Kroah-Hartman }
1928ab4382d2SGreg Kroah-Hartman 
1929ab4382d2SGreg Kroah-Hartman /*
1930d8d8ffa4SShreshtha Kumar Sahu  * disable the port. It should not disable RTS and DTR.
1931d8d8ffa4SShreshtha Kumar Sahu  * Also RTS and DTR state should be preserved to restore
1932d8d8ffa4SShreshtha Kumar Sahu  * it during startup().
1933ab4382d2SGreg Kroah-Hartman  */
pl011_disable_uart(struct uart_amba_port * uap)193495166a3fSAndre Przywara static void pl011_disable_uart(struct uart_amba_port *uap)
193595166a3fSAndre Przywara {
193695166a3fSAndre Przywara 	unsigned int cr;
193795166a3fSAndre Przywara 
19382a76fa28SLukas Wunner 	uap->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
19395aea1229SThomas Gleixner 	uart_port_lock_irq(&uap->port);
19409f25bc51SRussell King 	cr = pl011_read(uap, REG_CR);
1941d8d8ffa4SShreshtha Kumar Sahu 	cr &= UART011_CR_RTS | UART011_CR_DTR;
1942d8d8ffa4SShreshtha Kumar Sahu 	cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
19439f25bc51SRussell King 	pl011_write(cr, uap, REG_CR);
19445aea1229SThomas Gleixner 	uart_port_unlock_irq(&uap->port);
1945ab4382d2SGreg Kroah-Hartman 
1946ab4382d2SGreg Kroah-Hartman 	/*
1947ab4382d2SGreg Kroah-Hartman 	 * disable break condition and fifos
1948ab4382d2SGreg Kroah-Hartman 	 */
1949e4df9a80SRussell King 	pl011_shutdown_channel(uap, REG_LCRH_RX);
19507fe9a5a9SRussell King 	if (pl011_split_lcrh(uap))
1951e4df9a80SRussell King 		pl011_shutdown_channel(uap, REG_LCRH_TX);
195295166a3fSAndre Przywara }
195395166a3fSAndre Przywara 
pl011_disable_interrupts(struct uart_amba_port * uap)195495166a3fSAndre Przywara static void pl011_disable_interrupts(struct uart_amba_port *uap)
195595166a3fSAndre Przywara {
19565aea1229SThomas Gleixner 	uart_port_lock_irq(&uap->port);
195795166a3fSAndre Przywara 
195895166a3fSAndre Przywara 	/* mask all interrupts and clear all pending ones */
195995166a3fSAndre Przywara 	uap->im = 0;
19609f25bc51SRussell King 	pl011_write(uap->im, uap, REG_IMSC);
19619f25bc51SRussell King 	pl011_write(0xffff, uap, REG_ICR);
196295166a3fSAndre Przywara 
19635aea1229SThomas Gleixner 	uart_port_unlock_irq(&uap->port);
196495166a3fSAndre Przywara }
196595166a3fSAndre Przywara 
pl011_shutdown(struct uart_port * port)196695166a3fSAndre Przywara static void pl011_shutdown(struct uart_port *port)
196795166a3fSAndre Przywara {
196895166a3fSAndre Przywara 	struct uart_amba_port *uap =
196995166a3fSAndre Przywara 		container_of(port, struct uart_amba_port, port);
197095166a3fSAndre Przywara 
197195166a3fSAndre Przywara 	pl011_disable_interrupts(uap);
197295166a3fSAndre Przywara 
197395166a3fSAndre Przywara 	pl011_dma_shutdown(uap);
197495166a3fSAndre Przywara 
19758d479237SLino Sanfilippo 	if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started)
19768d479237SLino Sanfilippo 		pl011_rs485_tx_stop(uap);
19778d479237SLino Sanfilippo 
197894560f61SQian Cai 	free_irq(uap->port.irq, uap);
197995166a3fSAndre Przywara 
198095166a3fSAndre Przywara 	pl011_disable_uart(uap);
1981ab4382d2SGreg Kroah-Hartman 
1982ab4382d2SGreg Kroah-Hartman 	/*
1983ab4382d2SGreg Kroah-Hartman 	 * Shut down the clock producer
1984ab4382d2SGreg Kroah-Hartman 	 */
19851c4c4394SJulia Lawall 	clk_disable_unprepare(uap->clk);
198678d80c5aSLinus Walleij 	/* Optionally let pins go into sleep states */
19872b996fc5SLinus Walleij 	pinctrl_pm_select_sleep_state(port->dev);
1988c16d51a3SShreshtha Kumar Sahu 
1989574de559SJingoo Han 	if (dev_get_platdata(uap->port.dev)) {
1990c16d51a3SShreshtha Kumar Sahu 		struct amba_pl011_data *plat;
1991c16d51a3SShreshtha Kumar Sahu 
1992574de559SJingoo Han 		plat = dev_get_platdata(uap->port.dev);
1993c16d51a3SShreshtha Kumar Sahu 		if (plat->exit)
1994c16d51a3SShreshtha Kumar Sahu 			plat->exit();
1995c16d51a3SShreshtha Kumar Sahu 	}
1996c16d51a3SShreshtha Kumar Sahu 
199736f339d1SPeter Hurley 	if (uap->port.ops->flush_buffer)
199836f339d1SPeter Hurley 		uap->port.ops->flush_buffer(port);
1999ab4382d2SGreg Kroah-Hartman }
2000ab4382d2SGreg Kroah-Hartman 
sbsa_uart_shutdown(struct uart_port * port)20010dd1e247SAndre Przywara static void sbsa_uart_shutdown(struct uart_port *port)
20020dd1e247SAndre Przywara {
20030dd1e247SAndre Przywara 	struct uart_amba_port *uap =
20040dd1e247SAndre Przywara 		container_of(port, struct uart_amba_port, port);
20050dd1e247SAndre Przywara 
20060dd1e247SAndre Przywara 	pl011_disable_interrupts(uap);
20070dd1e247SAndre Przywara 
200894560f61SQian Cai 	free_irq(uap->port.irq, uap);
20090dd1e247SAndre Przywara 
20100dd1e247SAndre Przywara 	if (uap->port.ops->flush_buffer)
20110dd1e247SAndre Przywara 		uap->port.ops->flush_buffer(port);
20120dd1e247SAndre Przywara }
20130dd1e247SAndre Przywara 
2014ab4382d2SGreg Kroah-Hartman static void
pl011_setup_status_masks(struct uart_port * port,struct ktermios * termios)2015ef5a9358SAndre Przywara pl011_setup_status_masks(struct uart_port *port, struct ktermios *termios)
2016ef5a9358SAndre Przywara {
2017ef5a9358SAndre Przywara 	port->read_status_mask = UART011_DR_OE | 255;
2018ef5a9358SAndre Przywara 	if (termios->c_iflag & INPCK)
2019ef5a9358SAndre Przywara 		port->read_status_mask |= UART011_DR_FE | UART011_DR_PE;
2020ef5a9358SAndre Przywara 	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
2021ef5a9358SAndre Przywara 		port->read_status_mask |= UART011_DR_BE;
2022ef5a9358SAndre Przywara 
2023ef5a9358SAndre Przywara 	/*
2024ef5a9358SAndre Przywara 	 * Characters to ignore
2025ef5a9358SAndre Przywara 	 */
2026ef5a9358SAndre Przywara 	port->ignore_status_mask = 0;
2027ef5a9358SAndre Przywara 	if (termios->c_iflag & IGNPAR)
2028ef5a9358SAndre Przywara 		port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE;
2029ef5a9358SAndre Przywara 	if (termios->c_iflag & IGNBRK) {
2030ef5a9358SAndre Przywara 		port->ignore_status_mask |= UART011_DR_BE;
2031ef5a9358SAndre Przywara 		/*
2032ef5a9358SAndre Przywara 		 * If we're ignoring parity and break indicators,
2033ef5a9358SAndre Przywara 		 * ignore overruns too (for real raw support).
2034ef5a9358SAndre Przywara 		 */
2035ef5a9358SAndre Przywara 		if (termios->c_iflag & IGNPAR)
2036ef5a9358SAndre Przywara 			port->ignore_status_mask |= UART011_DR_OE;
2037ef5a9358SAndre Przywara 	}
2038ef5a9358SAndre Przywara 
2039ef5a9358SAndre Przywara 	/*
2040ef5a9358SAndre Przywara 	 * Ignore all characters if CREAD is not set.
2041ef5a9358SAndre Przywara 	 */
2042ef5a9358SAndre Przywara 	if ((termios->c_cflag & CREAD) == 0)
2043ef5a9358SAndre Przywara 		port->ignore_status_mask |= UART_DUMMY_DR_RX;
2044ef5a9358SAndre Przywara }
2045ef5a9358SAndre Przywara 
2046ef5a9358SAndre Przywara static void
pl011_set_termios(struct uart_port * port,struct ktermios * termios,const struct ktermios * old)2047ab4382d2SGreg Kroah-Hartman pl011_set_termios(struct uart_port *port, struct ktermios *termios,
2048bec5b814SIlpo Järvinen 		  const struct ktermios *old)
2049ab4382d2SGreg Kroah-Hartman {
2050a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
2051a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
2052ab4382d2SGreg Kroah-Hartman 	unsigned int lcr_h, old_cr;
2053ab4382d2SGreg Kroah-Hartman 	unsigned long flags;
2054ab4382d2SGreg Kroah-Hartman 	unsigned int baud, quot, clkdiv;
20558d479237SLino Sanfilippo 	unsigned int bits;
2056ab4382d2SGreg Kroah-Hartman 
2057ab4382d2SGreg Kroah-Hartman 	if (uap->vendor->oversampling)
2058ab4382d2SGreg Kroah-Hartman 		clkdiv = 8;
2059ab4382d2SGreg Kroah-Hartman 	else
2060ab4382d2SGreg Kroah-Hartman 		clkdiv = 16;
2061ab4382d2SGreg Kroah-Hartman 
2062ab4382d2SGreg Kroah-Hartman 	/*
2063ab4382d2SGreg Kroah-Hartman 	 * Ask the core to calculate the divisor for us.
2064ab4382d2SGreg Kroah-Hartman 	 */
2065ab4382d2SGreg Kroah-Hartman 	baud = uart_get_baud_rate(port, termios, old, 0,
2066ab4382d2SGreg Kroah-Hartman 				  port->uartclk / clkdiv);
206789fa28dbSChanho Min #ifdef CONFIG_DMA_ENGINE
2068cb06ff10SChanho Min 	/*
2069cb06ff10SChanho Min 	 * Adjust RX DMA polling rate with baud rate if not specified.
2070cb06ff10SChanho Min 	 */
2071cb06ff10SChanho Min 	if (uap->dmarx.auto_poll_rate)
2072cb06ff10SChanho Min 		uap->dmarx.poll_rate = DIV_ROUND_UP(10000000, baud);
207389fa28dbSChanho Min #endif
2074ab4382d2SGreg Kroah-Hartman 
2075ab4382d2SGreg Kroah-Hartman 	if (baud > port->uartclk/16)
2076ab4382d2SGreg Kroah-Hartman 		quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
2077ab4382d2SGreg Kroah-Hartman 	else
2078ab4382d2SGreg Kroah-Hartman 		quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud);
2079ab4382d2SGreg Kroah-Hartman 
2080ab4382d2SGreg Kroah-Hartman 	switch (termios->c_cflag & CSIZE) {
2081ab4382d2SGreg Kroah-Hartman 	case CS5:
2082ab4382d2SGreg Kroah-Hartman 		lcr_h = UART01x_LCRH_WLEN_5;
2083ab4382d2SGreg Kroah-Hartman 		break;
2084ab4382d2SGreg Kroah-Hartman 	case CS6:
2085ab4382d2SGreg Kroah-Hartman 		lcr_h = UART01x_LCRH_WLEN_6;
2086ab4382d2SGreg Kroah-Hartman 		break;
2087ab4382d2SGreg Kroah-Hartman 	case CS7:
2088ab4382d2SGreg Kroah-Hartman 		lcr_h = UART01x_LCRH_WLEN_7;
2089ab4382d2SGreg Kroah-Hartman 		break;
2090ab4382d2SGreg Kroah-Hartman 	default: // CS8
2091ab4382d2SGreg Kroah-Hartman 		lcr_h = UART01x_LCRH_WLEN_8;
2092ab4382d2SGreg Kroah-Hartman 		break;
2093ab4382d2SGreg Kroah-Hartman 	}
2094ab4382d2SGreg Kroah-Hartman 	if (termios->c_cflag & CSTOPB)
2095ab4382d2SGreg Kroah-Hartman 		lcr_h |= UART01x_LCRH_STP2;
2096ab4382d2SGreg Kroah-Hartman 	if (termios->c_cflag & PARENB) {
2097ab4382d2SGreg Kroah-Hartman 		lcr_h |= UART01x_LCRH_PEN;
2098ab4382d2SGreg Kroah-Hartman 		if (!(termios->c_cflag & PARODD))
2099ab4382d2SGreg Kroah-Hartman 			lcr_h |= UART01x_LCRH_EPS;
2100bb70002cSEd Spiridonov 		if (termios->c_cflag & CMSPAR)
2101bb70002cSEd Spiridonov 			lcr_h |= UART011_LCRH_SPS;
2102ab4382d2SGreg Kroah-Hartman 	}
2103ab4382d2SGreg Kroah-Hartman 	if (uap->fifosize > 1)
2104ab4382d2SGreg Kroah-Hartman 		lcr_h |= UART01x_LCRH_FEN;
2105ab4382d2SGreg Kroah-Hartman 
21068d479237SLino Sanfilippo 	bits = tty_get_frame_size(termios->c_cflag);
21078d479237SLino Sanfilippo 
21085aea1229SThomas Gleixner 	uart_port_lock_irqsave(port, &flags);
2109ab4382d2SGreg Kroah-Hartman 
2110ab4382d2SGreg Kroah-Hartman 	/*
2111ab4382d2SGreg Kroah-Hartman 	 * Update the per-port timeout.
2112ab4382d2SGreg Kroah-Hartman 	 */
2113ab4382d2SGreg Kroah-Hartman 	uart_update_timeout(port, termios->c_cflag, baud);
2114ab4382d2SGreg Kroah-Hartman 
21158d479237SLino Sanfilippo 	/*
21168d479237SLino Sanfilippo 	 * Calculate the approximated time it takes to transmit one character
21178d479237SLino Sanfilippo 	 * with the given baud rate. We use this as the poll interval when we
21188d479237SLino Sanfilippo 	 * wait for the tx queue to empty.
21198d479237SLino Sanfilippo 	 */
21200e4deb56SLino Sanfilippo 	uap->rs485_tx_drain_interval = DIV_ROUND_UP(bits * 1000 * 1000, baud);
21218d479237SLino Sanfilippo 
2122ef5a9358SAndre Przywara 	pl011_setup_status_masks(port, termios);
2123ab4382d2SGreg Kroah-Hartman 
2124ab4382d2SGreg Kroah-Hartman 	if (UART_ENABLE_MS(port, termios->c_cflag))
2125ab4382d2SGreg Kroah-Hartman 		pl011_enable_ms(port);
2126ab4382d2SGreg Kroah-Hartman 
21278d479237SLino Sanfilippo 	if (port->rs485.flags & SER_RS485_ENABLED)
21288d479237SLino Sanfilippo 		termios->c_cflag &= ~CRTSCTS;
21298d479237SLino Sanfilippo 
21309f25bc51SRussell King 	old_cr = pl011_read(uap, REG_CR);
2131ab4382d2SGreg Kroah-Hartman 
2132ab4382d2SGreg Kroah-Hartman 	if (termios->c_cflag & CRTSCTS) {
2133ab4382d2SGreg Kroah-Hartman 		if (old_cr & UART011_CR_RTS)
2134ab4382d2SGreg Kroah-Hartman 			old_cr |= UART011_CR_RTSEN;
2135ab4382d2SGreg Kroah-Hartman 
2136ab4382d2SGreg Kroah-Hartman 		old_cr |= UART011_CR_CTSEN;
21372a76fa28SLukas Wunner 		port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
2138ab4382d2SGreg Kroah-Hartman 	} else {
2139ab4382d2SGreg Kroah-Hartman 		old_cr &= ~(UART011_CR_CTSEN | UART011_CR_RTSEN);
21402a76fa28SLukas Wunner 		port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
2141ab4382d2SGreg Kroah-Hartman 	}
2142ab4382d2SGreg Kroah-Hartman 
2143ab4382d2SGreg Kroah-Hartman 	if (uap->vendor->oversampling) {
2144ab4382d2SGreg Kroah-Hartman 		if (baud > port->uartclk / 16)
2145ab4382d2SGreg Kroah-Hartman 			old_cr |= ST_UART011_CR_OVSFACT;
2146ab4382d2SGreg Kroah-Hartman 		else
2147ab4382d2SGreg Kroah-Hartman 			old_cr &= ~ST_UART011_CR_OVSFACT;
2148ab4382d2SGreg Kroah-Hartman 	}
2149ab4382d2SGreg Kroah-Hartman 
2150c5dd553bSLinus Walleij 	/*
2151c5dd553bSLinus Walleij 	 * Workaround for the ST Micro oversampling variants to
2152c5dd553bSLinus Walleij 	 * increase the bitrate slightly, by lowering the divisor,
2153c5dd553bSLinus Walleij 	 * to avoid delayed sampling of start bit at high speeds,
2154c5dd553bSLinus Walleij 	 * else we see data corruption.
2155c5dd553bSLinus Walleij 	 */
2156c5dd553bSLinus Walleij 	if (uap->vendor->oversampling) {
2157c5dd553bSLinus Walleij 		if ((baud >= 3000000) && (baud < 3250000) && (quot > 1))
2158c5dd553bSLinus Walleij 			quot -= 1;
2159c5dd553bSLinus Walleij 		else if ((baud > 3250000) && (quot > 2))
2160c5dd553bSLinus Walleij 			quot -= 2;
2161c5dd553bSLinus Walleij 	}
2162ab4382d2SGreg Kroah-Hartman 	/* Set baud rate */
21639f25bc51SRussell King 	pl011_write(quot & 0x3f, uap, REG_FBRD);
21649f25bc51SRussell King 	pl011_write(quot >> 6, uap, REG_IBRD);
2165ab4382d2SGreg Kroah-Hartman 
2166ab4382d2SGreg Kroah-Hartman 	/*
2167ab4382d2SGreg Kroah-Hartman 	 * ----------v----------v----------v----------v-----
2168e4df9a80SRussell King 	 * NOTE: REG_LCRH_TX and REG_LCRH_RX MUST BE WRITTEN AFTER
21699f25bc51SRussell King 	 * REG_FBRD & REG_IBRD.
2170ab4382d2SGreg Kroah-Hartman 	 * ----------^----------^----------^----------^-----
2171ab4382d2SGreg Kroah-Hartman 	 */
2172b60f2f66SJon Medhurst 	pl011_write_lcr_h(uap, lcr_h);
21736d8c1fcaSHongyu Xie 
21746d8c1fcaSHongyu Xie 	/*
21756d8c1fcaSHongyu Xie 	 * Receive was disabled by pl011_disable_uart during shutdown.
21766d8c1fcaSHongyu Xie 	 * Need to reenable receive if you need to use a tty_driver
21776d8c1fcaSHongyu Xie 	 * returns from tty_find_polling_driver() after a port shutdown.
21786d8c1fcaSHongyu Xie 	 */
21796d8c1fcaSHongyu Xie 	old_cr |= UART011_CR_RXE;
21809f25bc51SRussell King 	pl011_write(old_cr, uap, REG_CR);
2181ab4382d2SGreg Kroah-Hartman 
21825aea1229SThomas Gleixner 	uart_port_unlock_irqrestore(port, flags);
2183ab4382d2SGreg Kroah-Hartman }
2184ab4382d2SGreg Kroah-Hartman 
21850dd1e247SAndre Przywara static void
sbsa_uart_set_termios(struct uart_port * port,struct ktermios * termios,const struct ktermios * old)21860dd1e247SAndre Przywara sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios,
2187bec5b814SIlpo Järvinen 		      const struct ktermios *old)
21880dd1e247SAndre Przywara {
21890dd1e247SAndre Przywara 	struct uart_amba_port *uap =
21900dd1e247SAndre Przywara 	    container_of(port, struct uart_amba_port, port);
21910dd1e247SAndre Przywara 	unsigned long flags;
21920dd1e247SAndre Przywara 
21930dd1e247SAndre Przywara 	tty_termios_encode_baud_rate(termios, uap->fixed_baud, uap->fixed_baud);
21940dd1e247SAndre Przywara 
21950dd1e247SAndre Przywara 	/* The SBSA UART only supports 8n1 without hardware flow control. */
21960dd1e247SAndre Przywara 	termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
21970dd1e247SAndre Przywara 	termios->c_cflag &= ~(CMSPAR | CRTSCTS);
21980dd1e247SAndre Przywara 	termios->c_cflag |= CS8 | CLOCAL;
21990dd1e247SAndre Przywara 
22005aea1229SThomas Gleixner 	uart_port_lock_irqsave(port, &flags);
22010dd1e247SAndre Przywara 	uart_update_timeout(port, CS8, uap->fixed_baud);
22020dd1e247SAndre Przywara 	pl011_setup_status_masks(port, termios);
22035aea1229SThomas Gleixner 	uart_port_unlock_irqrestore(port, flags);
22040dd1e247SAndre Przywara }
22050dd1e247SAndre Przywara 
pl011_type(struct uart_port * port)2206ab4382d2SGreg Kroah-Hartman static const char *pl011_type(struct uart_port *port)
2207ab4382d2SGreg Kroah-Hartman {
2208a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
2209a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
2210ab4382d2SGreg Kroah-Hartman 	return uap->port.type == PORT_AMBA ? uap->type : NULL;
2211ab4382d2SGreg Kroah-Hartman }
2212ab4382d2SGreg Kroah-Hartman 
2213ab4382d2SGreg Kroah-Hartman /*
2214ab4382d2SGreg Kroah-Hartman  * Configure/autoconfigure the port.
2215ab4382d2SGreg Kroah-Hartman  */
pl011_config_port(struct uart_port * port,int flags)2216e643f87fSLinus Walleij static void pl011_config_port(struct uart_port *port, int flags)
2217ab4382d2SGreg Kroah-Hartman {
2218d1180405SLino Sanfilippo 	if (flags & UART_CONFIG_TYPE)
2219ab4382d2SGreg Kroah-Hartman 		port->type = PORT_AMBA;
2220ab4382d2SGreg Kroah-Hartman }
2221ab4382d2SGreg Kroah-Hartman 
2222ab4382d2SGreg Kroah-Hartman /*
2223ab4382d2SGreg Kroah-Hartman  * verify the new serial_struct (for TIOCSSERIAL).
2224ab4382d2SGreg Kroah-Hartman  */
pl011_verify_port(struct uart_port * port,struct serial_struct * ser)2225e643f87fSLinus Walleij static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser)
2226ab4382d2SGreg Kroah-Hartman {
2227ab4382d2SGreg Kroah-Hartman 	int ret = 0;
2228ab4382d2SGreg Kroah-Hartman 	if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
2229ab4382d2SGreg Kroah-Hartman 		ret = -EINVAL;
2230ab4382d2SGreg Kroah-Hartman 	if (ser->irq < 0 || ser->irq >= nr_irqs)
2231ab4382d2SGreg Kroah-Hartman 		ret = -EINVAL;
2232ab4382d2SGreg Kroah-Hartman 	if (ser->baud_base < 9600)
2233ab4382d2SGreg Kroah-Hartman 		ret = -EINVAL;
2234d1180405SLino Sanfilippo 	if (port->mapbase != (unsigned long) ser->iomem_base)
2235d1180405SLino Sanfilippo 		ret = -EINVAL;
2236ab4382d2SGreg Kroah-Hartman 	return ret;
2237ab4382d2SGreg Kroah-Hartman }
2238ab4382d2SGreg Kroah-Hartman 
pl011_rs485_config(struct uart_port * port,struct ktermios * termios,struct serial_rs485 * rs485)2239ae50bb27SIlpo Järvinen static int pl011_rs485_config(struct uart_port *port, struct ktermios *termios,
22408d479237SLino Sanfilippo 			      struct serial_rs485 *rs485)
22418d479237SLino Sanfilippo {
22428d479237SLino Sanfilippo 	struct uart_amba_port *uap =
22438d479237SLino Sanfilippo 		container_of(port, struct uart_amba_port, port);
22448d479237SLino Sanfilippo 
22458d479237SLino Sanfilippo 	if (port->rs485.flags & SER_RS485_ENABLED)
22468d479237SLino Sanfilippo 		pl011_rs485_tx_stop(uap);
22478d479237SLino Sanfilippo 
22488d479237SLino Sanfilippo 	/* Make sure auto RTS is disabled */
2249a9efa452SLino Sanfilippo 	if (rs485->flags & SER_RS485_ENABLED) {
22508d479237SLino Sanfilippo 		u32 cr = pl011_read(uap, REG_CR);
22518d479237SLino Sanfilippo 
22528d479237SLino Sanfilippo 		cr &= ~UART011_CR_RTSEN;
22538d479237SLino Sanfilippo 		pl011_write(cr, uap, REG_CR);
22548d479237SLino Sanfilippo 		port->status &= ~UPSTAT_AUTORTS;
22558d479237SLino Sanfilippo 	}
22568d479237SLino Sanfilippo 
22578d479237SLino Sanfilippo 	return 0;
22588d479237SLino Sanfilippo }
22598d479237SLino Sanfilippo 
22602331e068SBhumika Goyal static const struct uart_ops amba_pl011_pops = {
2261e643f87fSLinus Walleij 	.tx_empty	= pl011_tx_empty,
2262ab4382d2SGreg Kroah-Hartman 	.set_mctrl	= pl011_set_mctrl,
2263e643f87fSLinus Walleij 	.get_mctrl	= pl011_get_mctrl,
2264ab4382d2SGreg Kroah-Hartman 	.stop_tx	= pl011_stop_tx,
2265ab4382d2SGreg Kroah-Hartman 	.start_tx	= pl011_start_tx,
2266ab4382d2SGreg Kroah-Hartman 	.stop_rx	= pl011_stop_rx,
2267211565b1SIlpo Järvinen 	.throttle	= pl011_throttle_rx,
2268211565b1SIlpo Järvinen 	.unthrottle	= pl011_unthrottle_rx,
2269ab4382d2SGreg Kroah-Hartman 	.enable_ms	= pl011_enable_ms,
2270ab4382d2SGreg Kroah-Hartman 	.break_ctl	= pl011_break_ctl,
2271ab4382d2SGreg Kroah-Hartman 	.startup	= pl011_startup,
2272ab4382d2SGreg Kroah-Hartman 	.shutdown	= pl011_shutdown,
2273ab4382d2SGreg Kroah-Hartman 	.flush_buffer	= pl011_dma_flush_buffer,
2274ab4382d2SGreg Kroah-Hartman 	.set_termios	= pl011_set_termios,
2275ab4382d2SGreg Kroah-Hartman 	.type		= pl011_type,
2276e643f87fSLinus Walleij 	.config_port	= pl011_config_port,
2277e643f87fSLinus Walleij 	.verify_port	= pl011_verify_port,
2278ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_CONSOLE_POLL
2279b3564c2cSAnton Vorontsov 	.poll_init     = pl011_hwinit,
2280e643f87fSLinus Walleij 	.poll_get_char = pl011_get_poll_char,
2281e643f87fSLinus Walleij 	.poll_put_char = pl011_put_poll_char,
2282ab4382d2SGreg Kroah-Hartman #endif
2283ab4382d2SGreg Kroah-Hartman };
2284ab4382d2SGreg Kroah-Hartman 
sbsa_uart_set_mctrl(struct uart_port * port,unsigned int mctrl)22850dd1e247SAndre Przywara static void sbsa_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
22860dd1e247SAndre Przywara {
22870dd1e247SAndre Przywara }
22880dd1e247SAndre Przywara 
sbsa_uart_get_mctrl(struct uart_port * port)22890dd1e247SAndre Przywara static unsigned int sbsa_uart_get_mctrl(struct uart_port *port)
22900dd1e247SAndre Przywara {
22910dd1e247SAndre Przywara 	return 0;
22920dd1e247SAndre Przywara }
22930dd1e247SAndre Przywara 
22940dd1e247SAndre Przywara static const struct uart_ops sbsa_uart_pops = {
22950dd1e247SAndre Przywara 	.tx_empty	= pl011_tx_empty,
22960dd1e247SAndre Przywara 	.set_mctrl	= sbsa_uart_set_mctrl,
22970dd1e247SAndre Przywara 	.get_mctrl	= sbsa_uart_get_mctrl,
22980dd1e247SAndre Przywara 	.stop_tx	= pl011_stop_tx,
22990dd1e247SAndre Przywara 	.start_tx	= pl011_start_tx,
23000dd1e247SAndre Przywara 	.stop_rx	= pl011_stop_rx,
23010dd1e247SAndre Przywara 	.startup	= sbsa_uart_startup,
23020dd1e247SAndre Przywara 	.shutdown	= sbsa_uart_shutdown,
23030dd1e247SAndre Przywara 	.set_termios	= sbsa_uart_set_termios,
23040dd1e247SAndre Przywara 	.type		= pl011_type,
23050dd1e247SAndre Przywara 	.config_port	= pl011_config_port,
23060dd1e247SAndre Przywara 	.verify_port	= pl011_verify_port,
23070dd1e247SAndre Przywara #ifdef CONFIG_CONSOLE_POLL
23080dd1e247SAndre Przywara 	.poll_init     = pl011_hwinit,
23090dd1e247SAndre Przywara 	.poll_get_char = pl011_get_poll_char,
23100dd1e247SAndre Przywara 	.poll_put_char = pl011_put_poll_char,
23110dd1e247SAndre Przywara #endif
23120dd1e247SAndre Przywara };
23130dd1e247SAndre Przywara 
2314ab4382d2SGreg Kroah-Hartman static struct uart_amba_port *amba_ports[UART_NR];
2315ab4382d2SGreg Kroah-Hartman 
2316ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE
2317ab4382d2SGreg Kroah-Hartman 
pl011_console_putchar(struct uart_port * port,unsigned char ch)23183f8bab17SJiri Slaby static void pl011_console_putchar(struct uart_port *port, unsigned char ch)
2319ab4382d2SGreg Kroah-Hartman {
2320a5820c24SDaniel Thompson 	struct uart_amba_port *uap =
2321a5820c24SDaniel Thompson 	    container_of(port, struct uart_amba_port, port);
2322ab4382d2SGreg Kroah-Hartman 
23239f25bc51SRussell King 	while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
23242f2fd089STimur Tabi 		cpu_relax();
23259f25bc51SRussell King 	pl011_write(ch, uap, REG_DR);
2326ab4382d2SGreg Kroah-Hartman }
2327ab4382d2SGreg Kroah-Hartman 
2328ab4382d2SGreg Kroah-Hartman static void
pl011_console_write(struct console * co,const char * s,unsigned int count)2329ab4382d2SGreg Kroah-Hartman pl011_console_write(struct console *co, const char *s, unsigned int count)
2330ab4382d2SGreg Kroah-Hartman {
2331ab4382d2SGreg Kroah-Hartman 	struct uart_amba_port *uap = amba_ports[co->index];
23322f2fd089STimur Tabi 	unsigned int old_cr = 0, new_cr;
2333ef605fdbSRabin Vincent 	unsigned long flags;
2334ef605fdbSRabin Vincent 	int locked = 1;
2335ab4382d2SGreg Kroah-Hartman 
2336ab4382d2SGreg Kroah-Hartman 	clk_enable(uap->clk);
2337ab4382d2SGreg Kroah-Hartman 
2338ef605fdbSRabin Vincent 	local_irq_save(flags);
2339ef605fdbSRabin Vincent 	if (uap->port.sysrq)
2340ef605fdbSRabin Vincent 		locked = 0;
2341ef605fdbSRabin Vincent 	else if (oops_in_progress)
23425aea1229SThomas Gleixner 		locked = uart_port_trylock(&uap->port);
2343ef605fdbSRabin Vincent 	else
23445aea1229SThomas Gleixner 		uart_port_lock(&uap->port);
2345ef605fdbSRabin Vincent 
2346ab4382d2SGreg Kroah-Hartman 	/*
2347ab4382d2SGreg Kroah-Hartman 	 *	First save the CR then disable the interrupts
2348ab4382d2SGreg Kroah-Hartman 	 */
234971eec483SAndre Przywara 	if (!uap->vendor->always_enabled) {
23509f25bc51SRussell King 		old_cr = pl011_read(uap, REG_CR);
2351ab4382d2SGreg Kroah-Hartman 		new_cr = old_cr & ~UART011_CR_CTSEN;
2352ab4382d2SGreg Kroah-Hartman 		new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
23539f25bc51SRussell King 		pl011_write(new_cr, uap, REG_CR);
235471eec483SAndre Przywara 	}
2355ab4382d2SGreg Kroah-Hartman 
2356ab4382d2SGreg Kroah-Hartman 	uart_console_write(&uap->port, s, count, pl011_console_putchar);
2357ab4382d2SGreg Kroah-Hartman 
2358ab4382d2SGreg Kroah-Hartman 	/*
2359d8a4995bSChristopher Covington 	 *	Finally, wait for transmitter to become empty and restore the
2360d8a4995bSChristopher Covington 	 *	TCR. Allow feature register bits to be inverted to work around
2361d8a4995bSChristopher Covington 	 *	errata.
2362ab4382d2SGreg Kroah-Hartman 	 */
2363d8a4995bSChristopher Covington 	while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr)
2364d8a4995bSChristopher Covington 						& uap->vendor->fr_busy)
23652f2fd089STimur Tabi 		cpu_relax();
236671eec483SAndre Przywara 	if (!uap->vendor->always_enabled)
23679f25bc51SRussell King 		pl011_write(old_cr, uap, REG_CR);
2368ab4382d2SGreg Kroah-Hartman 
2369ef605fdbSRabin Vincent 	if (locked)
23705aea1229SThomas Gleixner 		uart_port_unlock(&uap->port);
2371ef605fdbSRabin Vincent 	local_irq_restore(flags);
2372ef605fdbSRabin Vincent 
2373ab4382d2SGreg Kroah-Hartman 	clk_disable(uap->clk);
2374ab4382d2SGreg Kroah-Hartman }
2375ab4382d2SGreg Kroah-Hartman 
pl011_console_get_options(struct uart_amba_port * uap,int * baud,int * parity,int * bits)237627afac93SLukas Wunner static void pl011_console_get_options(struct uart_amba_port *uap, int *baud,
2377ab4382d2SGreg Kroah-Hartman 				      int *parity, int *bits)
2378ab4382d2SGreg Kroah-Hartman {
23799f25bc51SRussell King 	if (pl011_read(uap, REG_CR) & UART01x_CR_UARTEN) {
2380ab4382d2SGreg Kroah-Hartman 		unsigned int lcr_h, ibrd, fbrd;
2381ab4382d2SGreg Kroah-Hartman 
2382e4df9a80SRussell King 		lcr_h = pl011_read(uap, REG_LCRH_TX);
2383ab4382d2SGreg Kroah-Hartman 
2384ab4382d2SGreg Kroah-Hartman 		*parity = 'n';
2385ab4382d2SGreg Kroah-Hartman 		if (lcr_h & UART01x_LCRH_PEN) {
2386ab4382d2SGreg Kroah-Hartman 			if (lcr_h & UART01x_LCRH_EPS)
2387ab4382d2SGreg Kroah-Hartman 				*parity = 'e';
2388ab4382d2SGreg Kroah-Hartman 			else
2389ab4382d2SGreg Kroah-Hartman 				*parity = 'o';
2390ab4382d2SGreg Kroah-Hartman 		}
2391ab4382d2SGreg Kroah-Hartman 
2392ab4382d2SGreg Kroah-Hartman 		if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)
2393ab4382d2SGreg Kroah-Hartman 			*bits = 7;
2394ab4382d2SGreg Kroah-Hartman 		else
2395ab4382d2SGreg Kroah-Hartman 			*bits = 8;
2396ab4382d2SGreg Kroah-Hartman 
23979f25bc51SRussell King 		ibrd = pl011_read(uap, REG_IBRD);
23989f25bc51SRussell King 		fbrd = pl011_read(uap, REG_FBRD);
2399ab4382d2SGreg Kroah-Hartman 
2400ab4382d2SGreg Kroah-Hartman 		*baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
2401ab4382d2SGreg Kroah-Hartman 
2402ab4382d2SGreg Kroah-Hartman 		if (uap->vendor->oversampling) {
24039f25bc51SRussell King 			if (pl011_read(uap, REG_CR)
2404ab4382d2SGreg Kroah-Hartman 				  & ST_UART011_CR_OVSFACT)
2405ab4382d2SGreg Kroah-Hartman 				*baud *= 2;
2406ab4382d2SGreg Kroah-Hartman 		}
2407ab4382d2SGreg Kroah-Hartman 	}
2408ab4382d2SGreg Kroah-Hartman }
2409ab4382d2SGreg Kroah-Hartman 
pl011_console_setup(struct console * co,char * options)241027afac93SLukas Wunner static int pl011_console_setup(struct console *co, char *options)
2411ab4382d2SGreg Kroah-Hartman {
2412ab4382d2SGreg Kroah-Hartman 	struct uart_amba_port *uap;
2413ab4382d2SGreg Kroah-Hartman 	int baud = 38400;
2414ab4382d2SGreg Kroah-Hartman 	int bits = 8;
2415ab4382d2SGreg Kroah-Hartman 	int parity = 'n';
2416ab4382d2SGreg Kroah-Hartman 	int flow = 'n';
24174b4851c6SRussell King 	int ret;
2418ab4382d2SGreg Kroah-Hartman 
2419ab4382d2SGreg Kroah-Hartman 	/*
2420ab4382d2SGreg Kroah-Hartman 	 * Check whether an invalid uart number has been specified, and
2421ab4382d2SGreg Kroah-Hartman 	 * if so, search for the first available port that does have
2422ab4382d2SGreg Kroah-Hartman 	 * console support.
2423ab4382d2SGreg Kroah-Hartman 	 */
2424ab4382d2SGreg Kroah-Hartman 	if (co->index >= UART_NR)
2425ab4382d2SGreg Kroah-Hartman 		co->index = 0;
2426ab4382d2SGreg Kroah-Hartman 	uap = amba_ports[co->index];
2427ab4382d2SGreg Kroah-Hartman 	if (!uap)
2428ab4382d2SGreg Kroah-Hartman 		return -ENODEV;
2429ab4382d2SGreg Kroah-Hartman 
243078d80c5aSLinus Walleij 	/* Allow pins to be muxed in and configured */
24312b996fc5SLinus Walleij 	pinctrl_pm_select_default_state(uap->port.dev);
243278d80c5aSLinus Walleij 
24334b4851c6SRussell King 	ret = clk_prepare(uap->clk);
24344b4851c6SRussell King 	if (ret)
24354b4851c6SRussell King 		return ret;
24364b4851c6SRussell King 
2437574de559SJingoo Han 	if (dev_get_platdata(uap->port.dev)) {
2438c16d51a3SShreshtha Kumar Sahu 		struct amba_pl011_data *plat;
2439c16d51a3SShreshtha Kumar Sahu 
2440574de559SJingoo Han 		plat = dev_get_platdata(uap->port.dev);
2441c16d51a3SShreshtha Kumar Sahu 		if (plat->init)
2442c16d51a3SShreshtha Kumar Sahu 			plat->init();
2443c16d51a3SShreshtha Kumar Sahu 	}
2444c16d51a3SShreshtha Kumar Sahu 
2445ab4382d2SGreg Kroah-Hartman 	uap->port.uartclk = clk_get_rate(uap->clk);
2446ab4382d2SGreg Kroah-Hartman 
2447cefc2d1dSAndre Przywara 	if (uap->vendor->fixed_options) {
2448cefc2d1dSAndre Przywara 		baud = uap->fixed_baud;
2449cefc2d1dSAndre Przywara 	} else {
2450ab4382d2SGreg Kroah-Hartman 		if (options)
2451cefc2d1dSAndre Przywara 			uart_parse_options(options,
2452cefc2d1dSAndre Przywara 					   &baud, &parity, &bits, &flow);
2453ab4382d2SGreg Kroah-Hartman 		else
2454ab4382d2SGreg Kroah-Hartman 			pl011_console_get_options(uap, &baud, &parity, &bits);
2455cefc2d1dSAndre Przywara 	}
2456ab4382d2SGreg Kroah-Hartman 
2457ab4382d2SGreg Kroah-Hartman 	return uart_set_options(&uap->port, co, baud, parity, bits, flow);
2458ab4382d2SGreg Kroah-Hartman }
2459ab4382d2SGreg Kroah-Hartman 
246010879ae5SAleksey Makarov /**
246110879ae5SAleksey Makarov  *	pl011_console_match - non-standard console matching
246210879ae5SAleksey Makarov  *	@co:	  registering console
246310879ae5SAleksey Makarov  *	@name:	  name from console command line
246410879ae5SAleksey Makarov  *	@idx:	  index from console command line
246510879ae5SAleksey Makarov  *	@options: ptr to option string from console command line
246610879ae5SAleksey Makarov  *
246710879ae5SAleksey Makarov  *	Only attempts to match console command lines of the form:
246810879ae5SAleksey Makarov  *	    console=pl011,mmio|mmio32,<addr>[,<options>]
246910879ae5SAleksey Makarov  *	    console=pl011,0x<addr>[,<options>]
247010879ae5SAleksey Makarov  *	This form is used to register an initial earlycon boot console and
247110879ae5SAleksey Makarov  *	replace it with the amba_console at pl011 driver init.
247210879ae5SAleksey Makarov  *
247310879ae5SAleksey Makarov  *	Performs console setup for a match (as required by interface)
247410879ae5SAleksey Makarov  *	If no <options> are specified, then assume the h/w is already setup.
247510879ae5SAleksey Makarov  *
247610879ae5SAleksey Makarov  *	Returns 0 if console matches; otherwise non-zero to use default matching
247710879ae5SAleksey Makarov  */
pl011_console_match(struct console * co,char * name,int idx,char * options)247827afac93SLukas Wunner static int pl011_console_match(struct console *co, char *name, int idx,
247910879ae5SAleksey Makarov 			       char *options)
248010879ae5SAleksey Makarov {
248110879ae5SAleksey Makarov 	unsigned char iotype;
248210879ae5SAleksey Makarov 	resource_size_t addr;
248310879ae5SAleksey Makarov 	int i;
248410879ae5SAleksey Makarov 
248537ef38f3STimur Tabi 	/*
248637ef38f3STimur Tabi 	 * Systems affected by the Qualcomm Technologies QDF2400 E44 erratum
248737ef38f3STimur Tabi 	 * have a distinct console name, so make sure we check for that.
248837ef38f3STimur Tabi 	 * The actual implementation of the erratum occurs in the probe
248937ef38f3STimur Tabi 	 * function.
249037ef38f3STimur Tabi 	 */
249137ef38f3STimur Tabi 	if ((strcmp(name, "qdf2400_e44") != 0) && (strcmp(name, "pl011") != 0))
249210879ae5SAleksey Makarov 		return -ENODEV;
249310879ae5SAleksey Makarov 
249410879ae5SAleksey Makarov 	if (uart_parse_earlycon(options, &iotype, &addr, &options))
249510879ae5SAleksey Makarov 		return -ENODEV;
249610879ae5SAleksey Makarov 
249710879ae5SAleksey Makarov 	if (iotype != UPIO_MEM && iotype != UPIO_MEM32)
249810879ae5SAleksey Makarov 		return -ENODEV;
249910879ae5SAleksey Makarov 
250010879ae5SAleksey Makarov 	/* try to match the port specified on the command line */
250110879ae5SAleksey Makarov 	for (i = 0; i < ARRAY_SIZE(amba_ports); i++) {
250210879ae5SAleksey Makarov 		struct uart_port *port;
250310879ae5SAleksey Makarov 
250410879ae5SAleksey Makarov 		if (!amba_ports[i])
250510879ae5SAleksey Makarov 			continue;
250610879ae5SAleksey Makarov 
250710879ae5SAleksey Makarov 		port = &amba_ports[i]->port;
250810879ae5SAleksey Makarov 
250910879ae5SAleksey Makarov 		if (port->mapbase != addr)
251010879ae5SAleksey Makarov 			continue;
251110879ae5SAleksey Makarov 
251210879ae5SAleksey Makarov 		co->index = i;
251310879ae5SAleksey Makarov 		port->cons = co;
251410879ae5SAleksey Makarov 		return pl011_console_setup(co, options);
251510879ae5SAleksey Makarov 	}
251610879ae5SAleksey Makarov 
251710879ae5SAleksey Makarov 	return -ENODEV;
251810879ae5SAleksey Makarov }
251910879ae5SAleksey Makarov 
2520ab4382d2SGreg Kroah-Hartman static struct uart_driver amba_reg;
2521ab4382d2SGreg Kroah-Hartman static struct console amba_console = {
2522ab4382d2SGreg Kroah-Hartman 	.name		= "ttyAMA",
2523ab4382d2SGreg Kroah-Hartman 	.write		= pl011_console_write,
2524ab4382d2SGreg Kroah-Hartman 	.device		= uart_console_device,
2525ab4382d2SGreg Kroah-Hartman 	.setup		= pl011_console_setup,
252610879ae5SAleksey Makarov 	.match		= pl011_console_match,
25277951ffc9SAlexander Sverdlin 	.flags		= CON_PRINTBUFFER | CON_ANYTIME,
2528ab4382d2SGreg Kroah-Hartman 	.index		= -1,
2529ab4382d2SGreg Kroah-Hartman 	.data		= &amba_reg,
2530ab4382d2SGreg Kroah-Hartman };
2531ab4382d2SGreg Kroah-Hartman 
2532ab4382d2SGreg Kroah-Hartman #define AMBA_CONSOLE	(&amba_console)
25330d3c673eSRob Herring 
qdf2400_e44_putc(struct uart_port * port,unsigned char c)25343f8bab17SJiri Slaby static void qdf2400_e44_putc(struct uart_port *port, unsigned char c)
2535d8a4995bSChristopher Covington {
2536d8a4995bSChristopher Covington 	while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
2537d8a4995bSChristopher Covington 		cpu_relax();
2538d8a4995bSChristopher Covington 	writel(c, port->membase + UART01x_DR);
2539d8a4995bSChristopher Covington 	while (!(readl(port->membase + UART01x_FR) & UART011_FR_TXFE))
2540d8a4995bSChristopher Covington 		cpu_relax();
2541d8a4995bSChristopher Covington }
2542d8a4995bSChristopher Covington 
qdf2400_e44_early_write(struct console * con,const char * s,unsigned n)2543d8a4995bSChristopher Covington static void qdf2400_e44_early_write(struct console *con, const char *s, unsigned n)
2544d8a4995bSChristopher Covington {
2545d8a4995bSChristopher Covington 	struct earlycon_device *dev = con->data;
2546d8a4995bSChristopher Covington 
2547d8a4995bSChristopher Covington 	uart_console_write(&dev->port, s, n, qdf2400_e44_putc);
2548d8a4995bSChristopher Covington }
2549d8a4995bSChristopher Covington 
pl011_putc(struct uart_port * port,unsigned char c)25503f8bab17SJiri Slaby static void pl011_putc(struct uart_port *port, unsigned char c)
25510d3c673eSRob Herring {
2552cdf091caSRussell King 	while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
25532f2fd089STimur Tabi 		cpu_relax();
25543b78fae7STimur Tabi 	if (port->iotype == UPIO_MEM32)
25553b78fae7STimur Tabi 		writel(c, port->membase + UART01x_DR);
25563b78fae7STimur Tabi 	else
2557cdf091caSRussell King 		writeb(c, port->membase + UART01x_DR);
2558e06690bfSShawn Guo 	while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)
25592f2fd089STimur Tabi 		cpu_relax();
25600d3c673eSRob Herring }
25610d3c673eSRob Herring 
pl011_early_write(struct console * con,const char * s,unsigned n)25620d3c673eSRob Herring static void pl011_early_write(struct console *con, const char *s, unsigned n)
25630d3c673eSRob Herring {
25640d3c673eSRob Herring 	struct earlycon_device *dev = con->data;
25650d3c673eSRob Herring 
25660d3c673eSRob Herring 	uart_console_write(&dev->port, s, n, pl011_putc);
25670d3c673eSRob Herring }
25680d3c673eSRob Herring 
2569195867ffSSumit Garg #ifdef CONFIG_CONSOLE_POLL
pl011_getc(struct uart_port * port)2570195867ffSSumit Garg static int pl011_getc(struct uart_port *port)
2571195867ffSSumit Garg {
2572195867ffSSumit Garg 	if (readl(port->membase + UART01x_FR) & UART01x_FR_RXFE)
2573195867ffSSumit Garg 		return NO_POLL_CHAR;
2574195867ffSSumit Garg 
2575195867ffSSumit Garg 	if (port->iotype == UPIO_MEM32)
2576195867ffSSumit Garg 		return readl(port->membase + UART01x_DR);
2577195867ffSSumit Garg 	else
2578195867ffSSumit Garg 		return readb(port->membase + UART01x_DR);
2579195867ffSSumit Garg }
2580195867ffSSumit Garg 
pl011_early_read(struct console * con,char * s,unsigned int n)2581195867ffSSumit Garg static int pl011_early_read(struct console *con, char *s, unsigned int n)
2582195867ffSSumit Garg {
2583195867ffSSumit Garg 	struct earlycon_device *dev = con->data;
2584195867ffSSumit Garg 	int ch, num_read = 0;
2585195867ffSSumit Garg 
2586195867ffSSumit Garg 	while (num_read < n) {
2587195867ffSSumit Garg 		ch = pl011_getc(&dev->port);
2588195867ffSSumit Garg 		if (ch == NO_POLL_CHAR)
2589195867ffSSumit Garg 			break;
2590195867ffSSumit Garg 
2591195867ffSSumit Garg 		s[num_read++] = ch;
2592195867ffSSumit Garg 	}
2593195867ffSSumit Garg 
2594195867ffSSumit Garg 	return num_read;
2595195867ffSSumit Garg }
2596195867ffSSumit Garg #else
2597195867ffSSumit Garg #define pl011_early_read NULL
2598195867ffSSumit Garg #endif
2599195867ffSSumit Garg 
2600e53e597fSTimur Tabi /*
2601e53e597fSTimur Tabi  * On non-ACPI systems, earlycon is enabled by specifying
2602e53e597fSTimur Tabi  * "earlycon=pl011,<address>" on the kernel command line.
2603e53e597fSTimur Tabi  *
2604e53e597fSTimur Tabi  * On ACPI ARM64 systems, an "early" console is enabled via the SPCR table,
2605e53e597fSTimur Tabi  * by specifying only "earlycon" on the command line.  Because it requires
2606e53e597fSTimur Tabi  * SPCR, the console starts after ACPI is parsed, which is later than a
2607e53e597fSTimur Tabi  * traditional early console.
2608e53e597fSTimur Tabi  *
2609e53e597fSTimur Tabi  * To get the traditional early console that starts before ACPI is parsed,
2610e53e597fSTimur Tabi  * specify the full "earlycon=pl011,<address>" option.
2611e53e597fSTimur Tabi  */
pl011_early_console_setup(struct earlycon_device * device,const char * opt)26120d3c673eSRob Herring static int __init pl011_early_console_setup(struct earlycon_device *device,
26130d3c673eSRob Herring 					    const char *opt)
26140d3c673eSRob Herring {
26150d3c673eSRob Herring 	if (!device->port.membase)
26160d3c673eSRob Herring 		return -ENODEV;
26170d3c673eSRob Herring 
2618e53e597fSTimur Tabi 	device->con->write = pl011_early_write;
2619195867ffSSumit Garg 	device->con->read = pl011_early_read;
2620e53e597fSTimur Tabi 
26210d3c673eSRob Herring 	return 0;
26220d3c673eSRob Herring }
262345e0f0f5SRob Herring OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);
2624fcb32159SKefeng Wang OF_EARLYCON_DECLARE(pl011, "arm,sbsa-uart", pl011_early_console_setup);
26255a0722b8STimur Tabi 
26265a0722b8STimur Tabi /*
26275a0722b8STimur Tabi  * On Qualcomm Datacenter Technologies QDF2400 SOCs affected by
26285a0722b8STimur Tabi  * Erratum 44, traditional earlycon can be enabled by specifying
26295a0722b8STimur Tabi  * "earlycon=qdf2400_e44,<address>".  Any options are ignored.
26305a0722b8STimur Tabi  *
26315a0722b8STimur Tabi  * Alternatively, you can just specify "earlycon", and the early console
26325a0722b8STimur Tabi  * will be enabled with the information from the SPCR table.  In this
26335a0722b8STimur Tabi  * case, the SPCR code will detect the need for the E44 work-around,
26345a0722b8STimur Tabi  * and set the console name to "qdf2400_e44".
26355a0722b8STimur Tabi  */
26365a0722b8STimur Tabi static int __init
qdf2400_e44_early_console_setup(struct earlycon_device * device,const char * opt)26375a0722b8STimur Tabi qdf2400_e44_early_console_setup(struct earlycon_device *device,
26385a0722b8STimur Tabi 				const char *opt)
26395a0722b8STimur Tabi {
26405a0722b8STimur Tabi 	if (!device->port.membase)
26415a0722b8STimur Tabi 		return -ENODEV;
26425a0722b8STimur Tabi 
26435a0722b8STimur Tabi 	device->con->write = qdf2400_e44_early_write;
26445a0722b8STimur Tabi 	return 0;
26455a0722b8STimur Tabi }
26465a0722b8STimur Tabi EARLYCON_DECLARE(qdf2400_e44, qdf2400_e44_early_console_setup);
26470d3c673eSRob Herring 
2648ab4382d2SGreg Kroah-Hartman #else
2649ab4382d2SGreg Kroah-Hartman #define AMBA_CONSOLE	NULL
2650ab4382d2SGreg Kroah-Hartman #endif
2651ab4382d2SGreg Kroah-Hartman 
2652ab4382d2SGreg Kroah-Hartman static struct uart_driver amba_reg = {
2653ab4382d2SGreg Kroah-Hartman 	.owner			= THIS_MODULE,
2654ab4382d2SGreg Kroah-Hartman 	.driver_name		= "ttyAMA",
2655ab4382d2SGreg Kroah-Hartman 	.dev_name		= "ttyAMA",
2656ab4382d2SGreg Kroah-Hartman 	.major			= SERIAL_AMBA_MAJOR,
2657ab4382d2SGreg Kroah-Hartman 	.minor			= SERIAL_AMBA_MINOR,
2658ab4382d2SGreg Kroah-Hartman 	.nr			= UART_NR,
2659ab4382d2SGreg Kroah-Hartman 	.cons			= AMBA_CONSOLE,
2660ab4382d2SGreg Kroah-Hartman };
2661ab4382d2SGreg Kroah-Hartman 
pl011_probe_dt_alias(int index,struct device * dev)266232614aadSMatthew Leach static int pl011_probe_dt_alias(int index, struct device *dev)
266332614aadSMatthew Leach {
266432614aadSMatthew Leach 	struct device_node *np;
266532614aadSMatthew Leach 	static bool seen_dev_with_alias = false;
266632614aadSMatthew Leach 	static bool seen_dev_without_alias = false;
266732614aadSMatthew Leach 	int ret = index;
266832614aadSMatthew Leach 
266932614aadSMatthew Leach 	if (!IS_ENABLED(CONFIG_OF))
267032614aadSMatthew Leach 		return ret;
267132614aadSMatthew Leach 
267232614aadSMatthew Leach 	np = dev->of_node;
267332614aadSMatthew Leach 	if (!np)
267432614aadSMatthew Leach 		return ret;
267532614aadSMatthew Leach 
267632614aadSMatthew Leach 	ret = of_alias_get_id(np, "serial");
2677287980e4SArnd Bergmann 	if (ret < 0) {
267832614aadSMatthew Leach 		seen_dev_without_alias = true;
267932614aadSMatthew Leach 		ret = index;
268032614aadSMatthew Leach 	} else {
268132614aadSMatthew Leach 		seen_dev_with_alias = true;
268232614aadSMatthew Leach 		if (ret >= ARRAY_SIZE(amba_ports) || amba_ports[ret] != NULL) {
268332614aadSMatthew Leach 			dev_warn(dev, "requested serial port %d  not available.\n", ret);
268432614aadSMatthew Leach 			ret = index;
268532614aadSMatthew Leach 		}
268632614aadSMatthew Leach 	}
268732614aadSMatthew Leach 
268832614aadSMatthew Leach 	if (seen_dev_with_alias && seen_dev_without_alias)
268932614aadSMatthew Leach 		dev_warn(dev, "aliased and non-aliased serial devices found in device tree. Serial port enumeration may be unpredictable.\n");
269032614aadSMatthew Leach 
269132614aadSMatthew Leach 	return ret;
269232614aadSMatthew Leach }
269332614aadSMatthew Leach 
269449bb3c86SAndre Przywara /* unregisters the driver also if no more ports are left */
pl011_unregister_port(struct uart_amba_port * uap)269549bb3c86SAndre Przywara static void pl011_unregister_port(struct uart_amba_port *uap)
269649bb3c86SAndre Przywara {
269749bb3c86SAndre Przywara 	int i;
269849bb3c86SAndre Przywara 	bool busy = false;
269949bb3c86SAndre Przywara 
270049bb3c86SAndre Przywara 	for (i = 0; i < ARRAY_SIZE(amba_ports); i++) {
270149bb3c86SAndre Przywara 		if (amba_ports[i] == uap)
270249bb3c86SAndre Przywara 			amba_ports[i] = NULL;
270349bb3c86SAndre Przywara 		else if (amba_ports[i])
270449bb3c86SAndre Przywara 			busy = true;
270549bb3c86SAndre Przywara 	}
270649bb3c86SAndre Przywara 	pl011_dma_remove(uap);
270749bb3c86SAndre Przywara 	if (!busy)
270849bb3c86SAndre Przywara 		uart_unregister_driver(&amba_reg);
270949bb3c86SAndre Przywara }
271049bb3c86SAndre Przywara 
pl011_find_free_port(void)27113873e2d7SAndre Przywara static int pl011_find_free_port(void)
2712ab4382d2SGreg Kroah-Hartman {
27133873e2d7SAndre Przywara 	int i;
2714ab4382d2SGreg Kroah-Hartman 
2715ab4382d2SGreg Kroah-Hartman 	for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
2716ab4382d2SGreg Kroah-Hartman 		if (amba_ports[i] == NULL)
27173873e2d7SAndre Przywara 			return i;
2718ab4382d2SGreg Kroah-Hartman 
27197f6d942aSTushar Behera 	return -EBUSY;
27203873e2d7SAndre Przywara }
2721ab4382d2SGreg Kroah-Hartman 
pl011_get_rs485_mode(struct uart_amba_port * uap)27228d479237SLino Sanfilippo static int pl011_get_rs485_mode(struct uart_amba_port *uap)
27238d479237SLino Sanfilippo {
27248d479237SLino Sanfilippo 	struct uart_port *port = &uap->port;
27258d479237SLino Sanfilippo 	int ret;
27268d479237SLino Sanfilippo 
27278d479237SLino Sanfilippo 	ret = uart_get_rs485_mode(port);
27288d479237SLino Sanfilippo 	if (ret)
27298d479237SLino Sanfilippo 		return ret;
27308d479237SLino Sanfilippo 
27318d479237SLino Sanfilippo 	return 0;
27328d479237SLino Sanfilippo }
27338d479237SLino Sanfilippo 
pl011_setup_port(struct device * dev,struct uart_amba_port * uap,struct resource * mmiobase,int index)27343873e2d7SAndre Przywara static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
27353873e2d7SAndre Przywara 			    struct resource *mmiobase, int index)
27363873e2d7SAndre Przywara {
27373873e2d7SAndre Przywara 	void __iomem *base;
27388d479237SLino Sanfilippo 	int ret;
2739ab4382d2SGreg Kroah-Hartman 
27403873e2d7SAndre Przywara 	base = devm_ioremap_resource(dev, mmiobase);
274197a60eacSKrzysztof Kozlowski 	if (IS_ERR(base))
274297a60eacSKrzysztof Kozlowski 		return PTR_ERR(base);
2743ab4382d2SGreg Kroah-Hartman 
27443873e2d7SAndre Przywara 	index = pl011_probe_dt_alias(index, dev);
2745ab4382d2SGreg Kroah-Hartman 
27463873e2d7SAndre Przywara 	uap->port.dev = dev;
27473873e2d7SAndre Przywara 	uap->port.mapbase = mmiobase->start;
2748ab4382d2SGreg Kroah-Hartman 	uap->port.membase = base;
2749ab4382d2SGreg Kroah-Hartman 	uap->port.fifosize = uap->fifosize;
27505f99fca9SDmitry Safonov 	uap->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_AMBA_PL011_CONSOLE);
2751ab4382d2SGreg Kroah-Hartman 	uap->port.flags = UPF_BOOT_AUTOCONF;
27523873e2d7SAndre Przywara 	uap->port.line = index;
27533873e2d7SAndre Przywara 
27548d479237SLino Sanfilippo 	ret = pl011_get_rs485_mode(uap);
27558d479237SLino Sanfilippo 	if (ret)
27568d479237SLino Sanfilippo 		return ret;
27578d479237SLino Sanfilippo 
27583873e2d7SAndre Przywara 	amba_ports[index] = uap;
27593873e2d7SAndre Przywara 
27603873e2d7SAndre Przywara 	return 0;
27613873e2d7SAndre Przywara }
27623873e2d7SAndre Przywara 
pl011_register_port(struct uart_amba_port * uap)27633873e2d7SAndre Przywara static int pl011_register_port(struct uart_amba_port *uap)
27643873e2d7SAndre Przywara {
276589efbe70SLukas Wunner 	int ret, i;
2766ab4382d2SGreg Kroah-Hartman 
2767c3d8b76fSLinus Walleij 	/* Ensure interrupts from this UART are masked and cleared */
27689f25bc51SRussell King 	pl011_write(0, uap, REG_IMSC);
27699f25bc51SRussell King 	pl011_write(0xffff, uap, REG_ICR);
2770c3d8b76fSLinus Walleij 
2771ef2889f7STushar Behera 	if (!amba_reg.state) {
2772ef2889f7STushar Behera 		ret = uart_register_driver(&amba_reg);
2773ef2889f7STushar Behera 		if (ret < 0) {
27743873e2d7SAndre Przywara 			dev_err(uap->port.dev,
27751c9be310SJorge Ramirez-Ortiz 				"Failed to register AMBA-PL011 driver\n");
277689efbe70SLukas Wunner 			for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
277789efbe70SLukas Wunner 				if (amba_ports[i] == uap)
277889efbe70SLukas Wunner 					amba_ports[i] = NULL;
2779ef2889f7STushar Behera 			return ret;
2780ef2889f7STushar Behera 		}
2781ef2889f7STushar Behera 	}
2782ef2889f7STushar Behera 
2783ab4382d2SGreg Kroah-Hartman 	ret = uart_add_one_port(&amba_reg, &uap->port);
278449bb3c86SAndre Przywara 	if (ret)
278549bb3c86SAndre Przywara 		pl011_unregister_port(uap);
27867f6d942aSTushar Behera 
2787ab4382d2SGreg Kroah-Hartman 	return ret;
2788ab4382d2SGreg Kroah-Hartman }
2789ab4382d2SGreg Kroah-Hartman 
2790ebe2cf73SIlpo Järvinen static const struct serial_rs485 pl011_rs485_supported = {
2791ebe2cf73SIlpo Järvinen 	.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND |
2792ebe2cf73SIlpo Järvinen 		 SER_RS485_RX_DURING_TX,
2793ebe2cf73SIlpo Järvinen 	.delay_rts_before_send = 1,
2794ebe2cf73SIlpo Järvinen 	.delay_rts_after_send = 1,
2795ebe2cf73SIlpo Järvinen };
2796ebe2cf73SIlpo Järvinen 
pl011_probe(struct amba_device * dev,const struct amba_id * id)27973873e2d7SAndre Przywara static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
27983873e2d7SAndre Przywara {
27993873e2d7SAndre Przywara 	struct uart_amba_port *uap;
28003873e2d7SAndre Przywara 	struct vendor_data *vendor = id->data;
28013873e2d7SAndre Przywara 	int portnr, ret;
280281db9e8eSShubhrajyoti Datta 	u32 val;
28033873e2d7SAndre Przywara 
28043873e2d7SAndre Przywara 	portnr = pl011_find_free_port();
28053873e2d7SAndre Przywara 	if (portnr < 0)
28063873e2d7SAndre Przywara 		return portnr;
28073873e2d7SAndre Przywara 
28083873e2d7SAndre Przywara 	uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port),
28093873e2d7SAndre Przywara 			   GFP_KERNEL);
28103873e2d7SAndre Przywara 	if (!uap)
28113873e2d7SAndre Przywara 		return -ENOMEM;
28123873e2d7SAndre Przywara 
28133873e2d7SAndre Przywara 	uap->clk = devm_clk_get(&dev->dev, NULL);
28143873e2d7SAndre Przywara 	if (IS_ERR(uap->clk))
28153873e2d7SAndre Przywara 		return PTR_ERR(uap->clk);
28163873e2d7SAndre Przywara 
2817439403bdSRussell King 	uap->reg_offset = vendor->reg_offset;
28183873e2d7SAndre Przywara 	uap->vendor = vendor;
28193873e2d7SAndre Przywara 	uap->fifosize = vendor->get_fifosize(dev);
28203b78fae7STimur Tabi 	uap->port.iotype = vendor->access_32b ? UPIO_MEM32 : UPIO_MEM;
28213873e2d7SAndre Przywara 	uap->port.irq = dev->irq[0];
28223873e2d7SAndre Przywara 	uap->port.ops = &amba_pl011_pops;
28238d479237SLino Sanfilippo 	uap->port.rs485_config = pl011_rs485_config;
28240139da50SIlpo Järvinen 	uap->port.rs485_supported = pl011_rs485_supported;
28253873e2d7SAndre Przywara 	snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
28263873e2d7SAndre Przywara 
282781db9e8eSShubhrajyoti Datta 	if (device_property_read_u32(&dev->dev, "reg-io-width", &val) == 0) {
282881db9e8eSShubhrajyoti Datta 		switch (val) {
282981db9e8eSShubhrajyoti Datta 		case 1:
283081db9e8eSShubhrajyoti Datta 			uap->port.iotype = UPIO_MEM;
283181db9e8eSShubhrajyoti Datta 			break;
283281db9e8eSShubhrajyoti Datta 		case 4:
283381db9e8eSShubhrajyoti Datta 			uap->port.iotype = UPIO_MEM32;
283481db9e8eSShubhrajyoti Datta 			break;
283581db9e8eSShubhrajyoti Datta 		default:
283681db9e8eSShubhrajyoti Datta 			dev_warn(&dev->dev, "unsupported reg-io-width (%d)\n",
283781db9e8eSShubhrajyoti Datta 				 val);
283881db9e8eSShubhrajyoti Datta 			return -EINVAL;
283981db9e8eSShubhrajyoti Datta 		}
284081db9e8eSShubhrajyoti Datta 	}
284181db9e8eSShubhrajyoti Datta 
28423873e2d7SAndre Przywara 	ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr);
28433873e2d7SAndre Przywara 	if (ret)
28443873e2d7SAndre Przywara 		return ret;
28453873e2d7SAndre Przywara 
28463873e2d7SAndre Przywara 	amba_set_drvdata(dev, uap);
28473873e2d7SAndre Przywara 
28483873e2d7SAndre Przywara 	return pl011_register_port(uap);
28493873e2d7SAndre Przywara }
28503873e2d7SAndre Przywara 
pl011_remove(struct amba_device * dev)28513fd269e7SUwe Kleine-König static void pl011_remove(struct amba_device *dev)
2852ab4382d2SGreg Kroah-Hartman {
2853ab4382d2SGreg Kroah-Hartman 	struct uart_amba_port *uap = amba_get_drvdata(dev);
2854ab4382d2SGreg Kroah-Hartman 
2855ab4382d2SGreg Kroah-Hartman 	uart_remove_one_port(&amba_reg, &uap->port);
285649bb3c86SAndre Przywara 	pl011_unregister_port(uap);
2857ab4382d2SGreg Kroah-Hartman }
2858ab4382d2SGreg Kroah-Hartman 
2859d0ce850dSUlf Hansson #ifdef CONFIG_PM_SLEEP
pl011_suspend(struct device * dev)2860d0ce850dSUlf Hansson static int pl011_suspend(struct device *dev)
2861ab4382d2SGreg Kroah-Hartman {
2862d0ce850dSUlf Hansson 	struct uart_amba_port *uap = dev_get_drvdata(dev);
2863ab4382d2SGreg Kroah-Hartman 
2864ab4382d2SGreg Kroah-Hartman 	if (!uap)
2865ab4382d2SGreg Kroah-Hartman 		return -EINVAL;
2866ab4382d2SGreg Kroah-Hartman 
2867ab4382d2SGreg Kroah-Hartman 	return uart_suspend_port(&amba_reg, &uap->port);
2868ab4382d2SGreg Kroah-Hartman }
2869ab4382d2SGreg Kroah-Hartman 
pl011_resume(struct device * dev)2870d0ce850dSUlf Hansson static int pl011_resume(struct device *dev)
2871ab4382d2SGreg Kroah-Hartman {
2872d0ce850dSUlf Hansson 	struct uart_amba_port *uap = dev_get_drvdata(dev);
2873ab4382d2SGreg Kroah-Hartman 
2874ab4382d2SGreg Kroah-Hartman 	if (!uap)
2875ab4382d2SGreg Kroah-Hartman 		return -EINVAL;
2876ab4382d2SGreg Kroah-Hartman 
2877ab4382d2SGreg Kroah-Hartman 	return uart_resume_port(&amba_reg, &uap->port);
2878ab4382d2SGreg Kroah-Hartman }
2879ab4382d2SGreg Kroah-Hartman #endif
2880ab4382d2SGreg Kroah-Hartman 
2881d0ce850dSUlf Hansson static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume);
2882d0ce850dSUlf Hansson 
sbsa_uart_probe(struct platform_device * pdev)28830dd1e247SAndre Przywara static int sbsa_uart_probe(struct platform_device *pdev)
28840dd1e247SAndre Przywara {
28850dd1e247SAndre Przywara 	struct uart_amba_port *uap;
28860dd1e247SAndre Przywara 	struct resource *r;
28870dd1e247SAndre Przywara 	int portnr, ret;
28880dd1e247SAndre Przywara 	int baudrate;
28890dd1e247SAndre Przywara 
28900dd1e247SAndre Przywara 	/*
28910dd1e247SAndre Przywara 	 * Check the mandatory baud rate parameter in the DT node early
28920dd1e247SAndre Przywara 	 * so that we can easily exit with the error.
28930dd1e247SAndre Przywara 	 */
28940dd1e247SAndre Przywara 	if (pdev->dev.of_node) {
28950dd1e247SAndre Przywara 		struct device_node *np = pdev->dev.of_node;
28960dd1e247SAndre Przywara 
28970dd1e247SAndre Przywara 		ret = of_property_read_u32(np, "current-speed", &baudrate);
28980dd1e247SAndre Przywara 		if (ret)
28990dd1e247SAndre Przywara 			return ret;
29000dd1e247SAndre Przywara 	} else {
29010dd1e247SAndre Przywara 		baudrate = 115200;
29020dd1e247SAndre Przywara 	}
29030dd1e247SAndre Przywara 
29040dd1e247SAndre Przywara 	portnr = pl011_find_free_port();
29050dd1e247SAndre Przywara 	if (portnr < 0)
29060dd1e247SAndre Przywara 		return portnr;
29070dd1e247SAndre Przywara 
29080dd1e247SAndre Przywara 	uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port),
29090dd1e247SAndre Przywara 			   GFP_KERNEL);
29100dd1e247SAndre Przywara 	if (!uap)
29110dd1e247SAndre Przywara 		return -ENOMEM;
29120dd1e247SAndre Przywara 
2913394a9e2cSJiri Slaby 	ret = platform_get_irq(pdev, 0);
29141df21786SStephen Boyd 	if (ret < 0)
2915394a9e2cSJiri Slaby 		return ret;
2916394a9e2cSJiri Slaby 	uap->port.irq	= ret;
2917394a9e2cSJiri Slaby 
291837ef38f3STimur Tabi #ifdef CONFIG_ACPI_SPCR_TABLE
291937ef38f3STimur Tabi 	if (qdf2400_e44_present) {
292037ef38f3STimur Tabi 		dev_info(&pdev->dev, "working around QDF2400 SoC erratum 44\n");
292137ef38f3STimur Tabi 		uap->vendor = &vendor_qdt_qdf2400_e44;
292237ef38f3STimur Tabi 	} else
292337ef38f3STimur Tabi #endif
292437ef38f3STimur Tabi 		uap->vendor = &vendor_sbsa;
292537ef38f3STimur Tabi 
292637ef38f3STimur Tabi 	uap->reg_offset	= uap->vendor->reg_offset;
29270dd1e247SAndre Przywara 	uap->fifosize	= 32;
292837ef38f3STimur Tabi 	uap->port.iotype = uap->vendor->access_32b ? UPIO_MEM32 : UPIO_MEM;
29290dd1e247SAndre Przywara 	uap->port.ops	= &sbsa_uart_pops;
29300dd1e247SAndre Przywara 	uap->fixed_baud = baudrate;
29310dd1e247SAndre Przywara 
29320dd1e247SAndre Przywara 	snprintf(uap->type, sizeof(uap->type), "SBSA");
29330dd1e247SAndre Przywara 
29340dd1e247SAndre Przywara 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
29350dd1e247SAndre Przywara 
29360dd1e247SAndre Przywara 	ret = pl011_setup_port(&pdev->dev, uap, r, portnr);
29370dd1e247SAndre Przywara 	if (ret)
29380dd1e247SAndre Przywara 		return ret;
29390dd1e247SAndre Przywara 
29400dd1e247SAndre Przywara 	platform_set_drvdata(pdev, uap);
29410dd1e247SAndre Przywara 
29420dd1e247SAndre Przywara 	return pl011_register_port(uap);
29430dd1e247SAndre Przywara }
29440dd1e247SAndre Przywara 
sbsa_uart_remove(struct platform_device * pdev)29450dd1e247SAndre Przywara static int sbsa_uart_remove(struct platform_device *pdev)
29460dd1e247SAndre Przywara {
29470dd1e247SAndre Przywara 	struct uart_amba_port *uap = platform_get_drvdata(pdev);
29480dd1e247SAndre Przywara 
29490dd1e247SAndre Przywara 	uart_remove_one_port(&amba_reg, &uap->port);
29500dd1e247SAndre Przywara 	pl011_unregister_port(uap);
29510dd1e247SAndre Przywara 	return 0;
29520dd1e247SAndre Przywara }
29530dd1e247SAndre Przywara 
29540dd1e247SAndre Przywara static const struct of_device_id sbsa_uart_of_match[] = {
29550dd1e247SAndre Przywara 	{ .compatible = "arm,sbsa-uart", },
29560dd1e247SAndre Przywara 	{},
29570dd1e247SAndre Przywara };
29580dd1e247SAndre Przywara MODULE_DEVICE_TABLE(of, sbsa_uart_of_match);
29590dd1e247SAndre Przywara 
29607789c1f1SLee Jones static const struct acpi_device_id __maybe_unused sbsa_uart_acpi_match[] = {
29613db9ab0bSGraeme Gregory 	{ "ARMH0011", 0 },
2962ac442a07SPierre Gondois 	{ "ARMHB000", 0 },
29633db9ab0bSGraeme Gregory 	{},
29643db9ab0bSGraeme Gregory };
29653db9ab0bSGraeme Gregory MODULE_DEVICE_TABLE(acpi, sbsa_uart_acpi_match);
29663db9ab0bSGraeme Gregory 
29670dd1e247SAndre Przywara static struct platform_driver arm_sbsa_uart_platform_driver = {
29680dd1e247SAndre Przywara 	.probe		= sbsa_uart_probe,
29690dd1e247SAndre Przywara 	.remove		= sbsa_uart_remove,
29700dd1e247SAndre Przywara 	.driver	= {
29710dd1e247SAndre Przywara 		.name	= "sbsa-uart",
29722301ec36SShubhrajyoti Datta 		.pm	= &pl011_dev_pm_ops,
29730dd1e247SAndre Przywara 		.of_match_table = of_match_ptr(sbsa_uart_of_match),
29743db9ab0bSGraeme Gregory 		.acpi_match_table = ACPI_PTR(sbsa_uart_acpi_match),
297564609794SAnders Roxell 		.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
29760dd1e247SAndre Przywara 	},
29770dd1e247SAndre Przywara };
29780dd1e247SAndre Przywara 
2979a704ddc2SArvind Yadav static const struct amba_id pl011_ids[] = {
2980ab4382d2SGreg Kroah-Hartman 	{
2981ab4382d2SGreg Kroah-Hartman 		.id	= 0x00041011,
2982ab4382d2SGreg Kroah-Hartman 		.mask	= 0x000fffff,
2983ab4382d2SGreg Kroah-Hartman 		.data	= &vendor_arm,
2984ab4382d2SGreg Kroah-Hartman 	},
2985ab4382d2SGreg Kroah-Hartman 	{
2986ab4382d2SGreg Kroah-Hartman 		.id	= 0x00380802,
2987ab4382d2SGreg Kroah-Hartman 		.mask	= 0x00ffffff,
2988ab4382d2SGreg Kroah-Hartman 		.data	= &vendor_st,
2989ab4382d2SGreg Kroah-Hartman 	},
2990ab4382d2SGreg Kroah-Hartman 	{ 0, 0 },
2991ab4382d2SGreg Kroah-Hartman };
2992ab4382d2SGreg Kroah-Hartman 
299360f7a33bSDave Martin MODULE_DEVICE_TABLE(amba, pl011_ids);
299460f7a33bSDave Martin 
2995ab4382d2SGreg Kroah-Hartman static struct amba_driver pl011_driver = {
2996ab4382d2SGreg Kroah-Hartman 	.drv = {
2997ab4382d2SGreg Kroah-Hartman 		.name	= "uart-pl011",
2998d0ce850dSUlf Hansson 		.pm	= &pl011_dev_pm_ops,
299964609794SAnders Roxell 		.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
3000ab4382d2SGreg Kroah-Hartman 	},
3001ab4382d2SGreg Kroah-Hartman 	.id_table	= pl011_ids,
3002ab4382d2SGreg Kroah-Hartman 	.probe		= pl011_probe,
3003ab4382d2SGreg Kroah-Hartman 	.remove		= pl011_remove,
3004ab4382d2SGreg Kroah-Hartman };
3005ab4382d2SGreg Kroah-Hartman 
pl011_init(void)3006ab4382d2SGreg Kroah-Hartman static int __init pl011_init(void)
3007ab4382d2SGreg Kroah-Hartman {
3008ab4382d2SGreg Kroah-Hartman 	printk(KERN_INFO "Serial: AMBA PL011 UART driver\n");
3009ab4382d2SGreg Kroah-Hartman 
30100dd1e247SAndre Przywara 	if (platform_driver_register(&arm_sbsa_uart_platform_driver))
30110dd1e247SAndre Przywara 		pr_warn("could not register SBSA UART platform driver\n");
3012062a68a5SGreg Kroah-Hartman 	return amba_driver_register(&pl011_driver);
3013ab4382d2SGreg Kroah-Hartman }
3014ab4382d2SGreg Kroah-Hartman 
pl011_exit(void)3015ab4382d2SGreg Kroah-Hartman static void __exit pl011_exit(void)
3016ab4382d2SGreg Kroah-Hartman {
30170dd1e247SAndre Przywara 	platform_driver_unregister(&arm_sbsa_uart_platform_driver);
3018ab4382d2SGreg Kroah-Hartman 	amba_driver_unregister(&pl011_driver);
3019ab4382d2SGreg Kroah-Hartman }
3020ab4382d2SGreg Kroah-Hartman 
3021ab4382d2SGreg Kroah-Hartman /*
3022ab4382d2SGreg Kroah-Hartman  * While this can be a module, if builtin it's most likely the console
3023ab4382d2SGreg Kroah-Hartman  * So let's leave module_exit but move module_init to an earlier place
3024ab4382d2SGreg Kroah-Hartman  */
3025ab4382d2SGreg Kroah-Hartman arch_initcall(pl011_init);
3026ab4382d2SGreg Kroah-Hartman module_exit(pl011_exit);
3027ab4382d2SGreg Kroah-Hartman 
3028ab4382d2SGreg Kroah-Hartman MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
3029ab4382d2SGreg Kroah-Hartman MODULE_DESCRIPTION("ARM AMBA serial port driver");
3030ab4382d2SGreg Kroah-Hartman MODULE_LICENSE("GPL");
3031