11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Driver for AMBA serial ports
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright 1999 ARM Limited
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 2000 Deep Blue Solutions Ltd.
868b65f7305e54b822b2483c60de7d7b017526a92Russell King *  Copyright (C) 2010 ST-Ericsson SA
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version.
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful,
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details.
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is a generic driver for ARM AMBA-type serial ports.  They
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * have a lot of 16550-like features, but are not register compatible.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that although they do have CTS, DCD and DSR inputs, they do
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not have an RI input, nor do they have DTR or RTS outputs.  If
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * required, these have to be supplied via some other means (eg, GPIO)
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and hooked into this driver.
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SUPPORT_SYSRQ
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/console.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sysrq.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial_core.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h>
46a62c80e559809e6c7851ec04d30575e85ad6f6edRussell King#include <linux/amba/bus.h>
47a62c80e559809e6c7851ec04d30575e85ad6f6edRussell King#include <linux/amba/serial.h>
48f8ce25476d5f12ffa29b885e49c38cd95053437eRussell King#include <linux/clk.h>
495a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
5068b65f7305e54b822b2483c60de7d7b017526a92Russell King#include <linux/dmaengine.h>
5168b65f7305e54b822b2483c60de7d7b017526a92Russell King#include <linux/dma-mapping.h>
5268b65f7305e54b822b2483c60de7d7b017526a92Russell King#include <linux/scatterlist.h>
53c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu#include <linux/delay.h>
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
56c6b8fdad144bbb915d124ffd95011ad55730bf9fRussell King#include <asm/sizes.h>
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_NR			14
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERIAL_AMBA_MAJOR	204
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERIAL_AMBA_MINOR	64
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERIAL_AMBA_NR		UART_NR
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AMBA_ISR_PASS_LIMIT	256
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
66b63d4f0fb80918ab37b6c0ee1adcd49e05c9994cRussell King#define UART_DR_ERROR		(UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
67b63d4f0fb80918ab37b6c0ee1adcd49e05c9994cRussell King#define UART_DUMMY_DR_RX	(1 << 16)
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
69c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
70c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu#define UART_WA_SAVE_NR 14
71c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
72c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahustatic void pl011_lockup_wa(unsigned long data);
73c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahustatic const u32 uart_wa_reg[UART_WA_SAVE_NR] = {
74c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	ST_UART011_DMAWM,
75c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	ST_UART011_TIMEOUT,
76c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	ST_UART011_LCRH_RX,
77c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	UART011_IBRD,
78c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	UART011_FBRD,
79c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	ST_UART011_LCRH_TX,
80c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	UART011_IFLS,
81c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	ST_UART011_XFCR,
82c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	ST_UART011_XON1,
83c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	ST_UART011_XON2,
84c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	ST_UART011_XOFF1,
85c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	ST_UART011_XOFF2,
86c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	UART011_CR,
87c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	UART011_IMSC
88c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu};
89c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
90c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahustatic u32 uart_wa_regdata[UART_WA_SAVE_NR];
91c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahustatic DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0);
92c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
935926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini/* There is by now at least one vendor with differing details, so handle it */
945926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubinistruct vendor_data {
955926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini	unsigned int		ifls;
965926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini	unsigned int		fifosize;
97ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij	unsigned int		lcrh_tx;
98ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij	unsigned int		lcrh_rx;
99ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij	bool			oversampling;
100c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	bool			interrupt_may_hang;   /* vendor-specific */
10138d624361b2a82d6317c379aebf81b1b28210bb0Russell King	bool			dma_threshold;
1025926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini};
1035926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini
1045926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubinistatic struct vendor_data vendor_arm = {
1055926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini	.ifls			= UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
1065926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini	.fifosize		= 16,
107ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij	.lcrh_tx		= UART011_LCRH,
108ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij	.lcrh_rx		= UART011_LCRH,
109ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij	.oversampling		= false,
11038d624361b2a82d6317c379aebf81b1b28210bb0Russell King	.dma_threshold		= false,
1115926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini};
1125926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini
1135926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubinistatic struct vendor_data vendor_st = {
1145926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini	.ifls			= UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
1155926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini	.fifosize		= 64,
116ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij	.lcrh_tx		= ST_UART011_LCRH_TX,
117ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij	.lcrh_rx		= ST_UART011_LCRH_RX,
118ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij	.oversampling		= true,
119c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	.interrupt_may_hang	= true,
12038d624361b2a82d6317c379aebf81b1b28210bb0Russell King	.dma_threshold		= true,
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
123c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahustatic struct uart_amba_port *amba_ports[UART_NR];
124c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
12568b65f7305e54b822b2483c60de7d7b017526a92Russell King/* Deals with DMA transactions */
126ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
127ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstruct pl011_sgbuf {
128ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct scatterlist sg;
129ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	char *buf;
130ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij};
131ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
132ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstruct pl011_dmarx_data {
133ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct dma_chan		*chan;
134ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct completion	complete;
135ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	bool			use_buf_b;
136ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct pl011_sgbuf	sgbuf_a;
137ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct pl011_sgbuf	sgbuf_b;
138ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	dma_cookie_t		cookie;
139ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	bool			running;
140ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij};
141ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
14268b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstruct pl011_dmatx_data {
14368b65f7305e54b822b2483c60de7d7b017526a92Russell King	struct dma_chan		*chan;
14468b65f7305e54b822b2483c60de7d7b017526a92Russell King	struct scatterlist	sg;
14568b65f7305e54b822b2483c60de7d7b017526a92Russell King	char			*buf;
14668b65f7305e54b822b2483c60de7d7b017526a92Russell King	bool			queued;
14768b65f7305e54b822b2483c60de7d7b017526a92Russell King};
14868b65f7305e54b822b2483c60de7d7b017526a92Russell King
149c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King/*
150c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King * We wrap our port structure around the generic uart_port.
151c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King */
152c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell Kingstruct uart_amba_port {
153c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King	struct uart_port	port;
154c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King	struct clk		*clk;
155c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King	const struct vendor_data *vendor;
15668b65f7305e54b822b2483c60de7d7b017526a92Russell King	unsigned int		dmacr;		/* dma control reg */
157c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King	unsigned int		im;		/* interrupt mask */
158c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King	unsigned int		old_status;
159ffca2b114c6a804d1307781df687e877a373a1c2Russell King	unsigned int		fifosize;	/* vendor-specific */
160c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King	unsigned int		lcrh_tx;	/* vendor-specific */
161c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King	unsigned int		lcrh_rx;	/* vendor-specific */
162d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu	unsigned int		old_cr;		/* state during shutdown */
163c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King	bool			autorts;
164c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King	char			type[12];
165c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	bool			interrupt_may_hang; /* vendor-specific */
16668b65f7305e54b822b2483c60de7d7b017526a92Russell King#ifdef CONFIG_DMA_ENGINE
16768b65f7305e54b822b2483c60de7d7b017526a92Russell King	/* DMA stuff */
168ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	bool			using_tx_dma;
169ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	bool			using_rx_dma;
170ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct pl011_dmarx_data dmarx;
17168b65f7305e54b822b2483c60de7d7b017526a92Russell King	struct pl011_dmatx_data	dmatx;
17268b65f7305e54b822b2483c60de7d7b017526a92Russell King#endif
17368b65f7305e54b822b2483c60de7d7b017526a92Russell King};
17468b65f7305e54b822b2483c60de7d7b017526a92Russell King
17568b65f7305e54b822b2483c60de7d7b017526a92Russell King/*
17629772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij * Reads up to 256 characters from the FIFO or until it's empty and
17729772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij * inserts them into the TTY layer. Returns the number of characters
17829772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij * read from the FIFO.
17929772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij */
18029772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleijstatic int pl011_fifo_to_tty(struct uart_amba_port *uap)
18129772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij{
18229772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij	u16 status, ch;
18329772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij	unsigned int flag, max_count = 256;
18429772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij	int fifotaken = 0;
18529772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij
18629772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij	while (max_count--) {
18729772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		status = readw(uap->port.membase + UART01x_FR);
18829772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		if (status & UART01x_FR_RXFE)
18929772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij			break;
19029772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij
19129772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		/* Take chars from the FIFO and update status */
19229772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		ch = readw(uap->port.membase + UART01x_DR) |
19329772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij			UART_DUMMY_DR_RX;
19429772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		flag = TTY_NORMAL;
19529772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		uap->port.icount.rx++;
19629772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		fifotaken++;
19729772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij
19829772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		if (unlikely(ch & UART_DR_ERROR)) {
19929772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij			if (ch & UART011_DR_BE) {
20029772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij				ch &= ~(UART011_DR_FE | UART011_DR_PE);
20129772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij				uap->port.icount.brk++;
20229772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij				if (uart_handle_break(&uap->port))
20329772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij					continue;
20429772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij			} else if (ch & UART011_DR_PE)
20529772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij				uap->port.icount.parity++;
20629772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij			else if (ch & UART011_DR_FE)
20729772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij				uap->port.icount.frame++;
20829772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij			if (ch & UART011_DR_OE)
20929772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij				uap->port.icount.overrun++;
21029772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij
21129772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij			ch &= uap->port.read_status_mask;
21229772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij
21329772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij			if (ch & UART011_DR_BE)
21429772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij				flag = TTY_BREAK;
21529772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij			else if (ch & UART011_DR_PE)
21629772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij				flag = TTY_PARITY;
21729772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij			else if (ch & UART011_DR_FE)
21829772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij				flag = TTY_FRAME;
21929772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		}
22029772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij
22129772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		if (uart_handle_sysrq_char(&uap->port, ch & 255))
22229772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij			continue;
22329772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij
22429772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
22529772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij	}
22629772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij
22729772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij	return fifotaken;
22829772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij}
22929772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij
23029772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij
23129772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij/*
23268b65f7305e54b822b2483c60de7d7b017526a92Russell King * All the DMA operation mode stuff goes inside this ifdef.
23368b65f7305e54b822b2483c60de7d7b017526a92Russell King * This assumes that you have a generic DMA device interface,
23468b65f7305e54b822b2483c60de7d7b017526a92Russell King * no custom DMA interfaces are supported.
23568b65f7305e54b822b2483c60de7d7b017526a92Russell King */
23668b65f7305e54b822b2483c60de7d7b017526a92Russell King#ifdef CONFIG_DMA_ENGINE
23768b65f7305e54b822b2483c60de7d7b017526a92Russell King
23868b65f7305e54b822b2483c60de7d7b017526a92Russell King#define PL011_DMA_BUFFER_SIZE PAGE_SIZE
23968b65f7305e54b822b2483c60de7d7b017526a92Russell King
240ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic int pl011_sgbuf_init(struct dma_chan *chan, struct pl011_sgbuf *sg,
241ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	enum dma_data_direction dir)
242ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{
243ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	sg->buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL);
244ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (!sg->buf)
245ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		return -ENOMEM;
246ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
247ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	sg_init_one(&sg->sg, sg->buf, PL011_DMA_BUFFER_SIZE);
248ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
249ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (dma_map_sg(chan->device->dev, &sg->sg, 1, dir) != 1) {
250ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		kfree(sg->buf);
251ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		return -EINVAL;
252ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	}
253ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	return 0;
254ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij}
255ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
256ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg,
257ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	enum dma_data_direction dir)
258ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{
259ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (sg->buf) {
260ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		dma_unmap_sg(chan->device->dev, &sg->sg, 1, dir);
261ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		kfree(sg->buf);
262ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	}
263ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij}
264ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
26568b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic void pl011_dma_probe_initcall(struct uart_amba_port *uap)
26668b65f7305e54b822b2483c60de7d7b017526a92Russell King{
26768b65f7305e54b822b2483c60de7d7b017526a92Russell King	/* DMA is the sole user of the platform data right now */
26868b65f7305e54b822b2483c60de7d7b017526a92Russell King	struct amba_pl011_data *plat = uap->port.dev->platform_data;
26968b65f7305e54b822b2483c60de7d7b017526a92Russell King	struct dma_slave_config tx_conf = {
27068b65f7305e54b822b2483c60de7d7b017526a92Russell King		.dst_addr = uap->port.mapbase + UART01x_DR,
27168b65f7305e54b822b2483c60de7d7b017526a92Russell King		.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
272a485df4b4404379786c4bdd258bc528b2617449dVinod Koul		.direction = DMA_MEM_TO_DEV,
27368b65f7305e54b822b2483c60de7d7b017526a92Russell King		.dst_maxburst = uap->fifosize >> 1,
27468b65f7305e54b822b2483c60de7d7b017526a92Russell King	};
27568b65f7305e54b822b2483c60de7d7b017526a92Russell King	struct dma_chan *chan;
27668b65f7305e54b822b2483c60de7d7b017526a92Russell King	dma_cap_mask_t mask;
27768b65f7305e54b822b2483c60de7d7b017526a92Russell King
27868b65f7305e54b822b2483c60de7d7b017526a92Russell King	/* We need platform data */
27968b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (!plat || !plat->dma_filter) {
28068b65f7305e54b822b2483c60de7d7b017526a92Russell King		dev_info(uap->port.dev, "no DMA platform data\n");
28168b65f7305e54b822b2483c60de7d7b017526a92Russell King		return;
28268b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
28368b65f7305e54b822b2483c60de7d7b017526a92Russell King
284ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	/* Try to acquire a generic DMA engine slave TX channel */
28568b65f7305e54b822b2483c60de7d7b017526a92Russell King	dma_cap_zero(mask);
28668b65f7305e54b822b2483c60de7d7b017526a92Russell King	dma_cap_set(DMA_SLAVE, mask);
28768b65f7305e54b822b2483c60de7d7b017526a92Russell King
28868b65f7305e54b822b2483c60de7d7b017526a92Russell King	chan = dma_request_channel(mask, plat->dma_filter, plat->dma_tx_param);
28968b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (!chan) {
29068b65f7305e54b822b2483c60de7d7b017526a92Russell King		dev_err(uap->port.dev, "no TX DMA channel!\n");
29168b65f7305e54b822b2483c60de7d7b017526a92Russell King		return;
29268b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
29368b65f7305e54b822b2483c60de7d7b017526a92Russell King
29468b65f7305e54b822b2483c60de7d7b017526a92Russell King	dmaengine_slave_config(chan, &tx_conf);
29568b65f7305e54b822b2483c60de7d7b017526a92Russell King	uap->dmatx.chan = chan;
29668b65f7305e54b822b2483c60de7d7b017526a92Russell King
29768b65f7305e54b822b2483c60de7d7b017526a92Russell King	dev_info(uap->port.dev, "DMA channel TX %s\n",
29868b65f7305e54b822b2483c60de7d7b017526a92Russell King		 dma_chan_name(uap->dmatx.chan));
299ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
300ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	/* Optionally make use of an RX channel as well */
301ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (plat->dma_rx_param) {
302ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		struct dma_slave_config rx_conf = {
303ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			.src_addr = uap->port.mapbase + UART01x_DR,
304ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
305a485df4b4404379786c4bdd258bc528b2617449dVinod Koul			.direction = DMA_DEV_TO_MEM,
306ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			.src_maxburst = uap->fifosize >> 1,
307ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		};
308ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
309ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
310ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		if (!chan) {
311ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			dev_err(uap->port.dev, "no RX DMA channel!\n");
312ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			return;
313ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		}
314ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
315ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		dmaengine_slave_config(chan, &rx_conf);
316ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		uap->dmarx.chan = chan;
317ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
318ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		dev_info(uap->port.dev, "DMA channel RX %s\n",
319ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			 dma_chan_name(uap->dmarx.chan));
320ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	}
32168b65f7305e54b822b2483c60de7d7b017526a92Russell King}
32268b65f7305e54b822b2483c60de7d7b017526a92Russell King
32368b65f7305e54b822b2483c60de7d7b017526a92Russell King#ifndef MODULE
32468b65f7305e54b822b2483c60de7d7b017526a92Russell King/*
32568b65f7305e54b822b2483c60de7d7b017526a92Russell King * Stack up the UARTs and let the above initcall be done at device
32668b65f7305e54b822b2483c60de7d7b017526a92Russell King * initcall time, because the serial driver is called as an arch
32768b65f7305e54b822b2483c60de7d7b017526a92Russell King * initcall, and at this time the DMA subsystem is not yet registered.
32868b65f7305e54b822b2483c60de7d7b017526a92Russell King * At this point the driver will switch over to using DMA where desired.
32968b65f7305e54b822b2483c60de7d7b017526a92Russell King */
33068b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstruct dma_uap {
33168b65f7305e54b822b2483c60de7d7b017526a92Russell King	struct list_head node;
33268b65f7305e54b822b2483c60de7d7b017526a92Russell King	struct uart_amba_port *uap;
333c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King};
334c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King
33568b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic LIST_HEAD(pl011_dma_uarts);
33668b65f7305e54b822b2483c60de7d7b017526a92Russell King
33768b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic int __init pl011_dma_initcall(void)
33868b65f7305e54b822b2483c60de7d7b017526a92Russell King{
33968b65f7305e54b822b2483c60de7d7b017526a92Russell King	struct list_head *node, *tmp;
34068b65f7305e54b822b2483c60de7d7b017526a92Russell King
34168b65f7305e54b822b2483c60de7d7b017526a92Russell King	list_for_each_safe(node, tmp, &pl011_dma_uarts) {
34268b65f7305e54b822b2483c60de7d7b017526a92Russell King		struct dma_uap *dmau = list_entry(node, struct dma_uap, node);
34368b65f7305e54b822b2483c60de7d7b017526a92Russell King		pl011_dma_probe_initcall(dmau->uap);
34468b65f7305e54b822b2483c60de7d7b017526a92Russell King		list_del(node);
34568b65f7305e54b822b2483c60de7d7b017526a92Russell King		kfree(dmau);
34668b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
34768b65f7305e54b822b2483c60de7d7b017526a92Russell King	return 0;
34868b65f7305e54b822b2483c60de7d7b017526a92Russell King}
34968b65f7305e54b822b2483c60de7d7b017526a92Russell King
35068b65f7305e54b822b2483c60de7d7b017526a92Russell Kingdevice_initcall(pl011_dma_initcall);
35168b65f7305e54b822b2483c60de7d7b017526a92Russell King
35268b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic void pl011_dma_probe(struct uart_amba_port *uap)
35368b65f7305e54b822b2483c60de7d7b017526a92Russell King{
35468b65f7305e54b822b2483c60de7d7b017526a92Russell King	struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL);
35568b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (dmau) {
35668b65f7305e54b822b2483c60de7d7b017526a92Russell King		dmau->uap = uap;
35768b65f7305e54b822b2483c60de7d7b017526a92Russell King		list_add_tail(&dmau->node, &pl011_dma_uarts);
35868b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
35968b65f7305e54b822b2483c60de7d7b017526a92Russell King}
36068b65f7305e54b822b2483c60de7d7b017526a92Russell King#else
36168b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic void pl011_dma_probe(struct uart_amba_port *uap)
36268b65f7305e54b822b2483c60de7d7b017526a92Russell King{
36368b65f7305e54b822b2483c60de7d7b017526a92Russell King	pl011_dma_probe_initcall(uap);
36468b65f7305e54b822b2483c60de7d7b017526a92Russell King}
36568b65f7305e54b822b2483c60de7d7b017526a92Russell King#endif
36668b65f7305e54b822b2483c60de7d7b017526a92Russell King
36768b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic void pl011_dma_remove(struct uart_amba_port *uap)
36868b65f7305e54b822b2483c60de7d7b017526a92Russell King{
36968b65f7305e54b822b2483c60de7d7b017526a92Russell King	/* TODO: remove the initcall if it has not yet executed */
37068b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (uap->dmatx.chan)
37168b65f7305e54b822b2483c60de7d7b017526a92Russell King		dma_release_channel(uap->dmatx.chan);
372ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (uap->dmarx.chan)
373ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		dma_release_channel(uap->dmarx.chan);
37468b65f7305e54b822b2483c60de7d7b017526a92Russell King}
37568b65f7305e54b822b2483c60de7d7b017526a92Russell King
37668b65f7305e54b822b2483c60de7d7b017526a92Russell King/* Forward declare this for the refill routine */
37768b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic int pl011_dma_tx_refill(struct uart_amba_port *uap);
37868b65f7305e54b822b2483c60de7d7b017526a92Russell King
37968b65f7305e54b822b2483c60de7d7b017526a92Russell King/*
38068b65f7305e54b822b2483c60de7d7b017526a92Russell King * The current DMA TX buffer has been sent.
38168b65f7305e54b822b2483c60de7d7b017526a92Russell King * Try to queue up another DMA buffer.
38268b65f7305e54b822b2483c60de7d7b017526a92Russell King */
38368b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic void pl011_dma_tx_callback(void *data)
38468b65f7305e54b822b2483c60de7d7b017526a92Russell King{
38568b65f7305e54b822b2483c60de7d7b017526a92Russell King	struct uart_amba_port *uap = data;
38668b65f7305e54b822b2483c60de7d7b017526a92Russell King	struct pl011_dmatx_data *dmatx = &uap->dmatx;
38768b65f7305e54b822b2483c60de7d7b017526a92Russell King	unsigned long flags;
38868b65f7305e54b822b2483c60de7d7b017526a92Russell King	u16 dmacr;
38968b65f7305e54b822b2483c60de7d7b017526a92Russell King
39068b65f7305e54b822b2483c60de7d7b017526a92Russell King	spin_lock_irqsave(&uap->port.lock, flags);
39168b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (uap->dmatx.queued)
39268b65f7305e54b822b2483c60de7d7b017526a92Russell King		dma_unmap_sg(dmatx->chan->device->dev, &dmatx->sg, 1,
39368b65f7305e54b822b2483c60de7d7b017526a92Russell King			     DMA_TO_DEVICE);
39468b65f7305e54b822b2483c60de7d7b017526a92Russell King
39568b65f7305e54b822b2483c60de7d7b017526a92Russell King	dmacr = uap->dmacr;
39668b65f7305e54b822b2483c60de7d7b017526a92Russell King	uap->dmacr = dmacr & ~UART011_TXDMAE;
39768b65f7305e54b822b2483c60de7d7b017526a92Russell King	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
39868b65f7305e54b822b2483c60de7d7b017526a92Russell King
39968b65f7305e54b822b2483c60de7d7b017526a92Russell King	/*
40068b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * If TX DMA was disabled, it means that we've stopped the DMA for
40168b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * some reason (eg, XOFF received, or we want to send an X-char.)
40268b65f7305e54b822b2483c60de7d7b017526a92Russell King	 *
40368b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * Note: we need to be careful here of a potential race between DMA
40468b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * and the rest of the driver - if the driver disables TX DMA while
40568b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * a TX buffer completing, we must update the tx queued status to
40668b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * get further refills (hence we check dmacr).
40768b65f7305e54b822b2483c60de7d7b017526a92Russell King	 */
40868b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) ||
40968b65f7305e54b822b2483c60de7d7b017526a92Russell King	    uart_circ_empty(&uap->port.state->xmit)) {
41068b65f7305e54b822b2483c60de7d7b017526a92Russell King		uap->dmatx.queued = false;
41168b65f7305e54b822b2483c60de7d7b017526a92Russell King		spin_unlock_irqrestore(&uap->port.lock, flags);
41268b65f7305e54b822b2483c60de7d7b017526a92Russell King		return;
41368b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
41468b65f7305e54b822b2483c60de7d7b017526a92Russell King
41568b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (pl011_dma_tx_refill(uap) <= 0) {
41668b65f7305e54b822b2483c60de7d7b017526a92Russell King		/*
41768b65f7305e54b822b2483c60de7d7b017526a92Russell King		 * We didn't queue a DMA buffer for some reason, but we
41868b65f7305e54b822b2483c60de7d7b017526a92Russell King		 * have data pending to be sent.  Re-enable the TX IRQ.
41968b65f7305e54b822b2483c60de7d7b017526a92Russell King		 */
42068b65f7305e54b822b2483c60de7d7b017526a92Russell King		uap->im |= UART011_TXIM;
42168b65f7305e54b822b2483c60de7d7b017526a92Russell King		writew(uap->im, uap->port.membase + UART011_IMSC);
42268b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
42368b65f7305e54b822b2483c60de7d7b017526a92Russell King	spin_unlock_irqrestore(&uap->port.lock, flags);
42468b65f7305e54b822b2483c60de7d7b017526a92Russell King}
42568b65f7305e54b822b2483c60de7d7b017526a92Russell King
42668b65f7305e54b822b2483c60de7d7b017526a92Russell King/*
42768b65f7305e54b822b2483c60de7d7b017526a92Russell King * Try to refill the TX DMA buffer.
42868b65f7305e54b822b2483c60de7d7b017526a92Russell King * Locking: called with port lock held and IRQs disabled.
42968b65f7305e54b822b2483c60de7d7b017526a92Russell King * Returns:
43068b65f7305e54b822b2483c60de7d7b017526a92Russell King *   1 if we queued up a TX DMA buffer.
43168b65f7305e54b822b2483c60de7d7b017526a92Russell King *   0 if we didn't want to handle this by DMA
43268b65f7305e54b822b2483c60de7d7b017526a92Russell King *  <0 on error
43368b65f7305e54b822b2483c60de7d7b017526a92Russell King */
43468b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic int pl011_dma_tx_refill(struct uart_amba_port *uap)
43568b65f7305e54b822b2483c60de7d7b017526a92Russell King{
43668b65f7305e54b822b2483c60de7d7b017526a92Russell King	struct pl011_dmatx_data *dmatx = &uap->dmatx;
43768b65f7305e54b822b2483c60de7d7b017526a92Russell King	struct dma_chan *chan = dmatx->chan;
43868b65f7305e54b822b2483c60de7d7b017526a92Russell King	struct dma_device *dma_dev = chan->device;
43968b65f7305e54b822b2483c60de7d7b017526a92Russell King	struct dma_async_tx_descriptor *desc;
44068b65f7305e54b822b2483c60de7d7b017526a92Russell King	struct circ_buf *xmit = &uap->port.state->xmit;
44168b65f7305e54b822b2483c60de7d7b017526a92Russell King	unsigned int count;
44268b65f7305e54b822b2483c60de7d7b017526a92Russell King
44368b65f7305e54b822b2483c60de7d7b017526a92Russell King	/*
44468b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * Try to avoid the overhead involved in using DMA if the
44568b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * transaction fits in the first half of the FIFO, by using
44668b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * the standard interrupt handling.  This ensures that we
44768b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * issue a uart_write_wakeup() at the appropriate time.
44868b65f7305e54b822b2483c60de7d7b017526a92Russell King	 */
44968b65f7305e54b822b2483c60de7d7b017526a92Russell King	count = uart_circ_chars_pending(xmit);
45068b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (count < (uap->fifosize >> 1)) {
45168b65f7305e54b822b2483c60de7d7b017526a92Russell King		uap->dmatx.queued = false;
45268b65f7305e54b822b2483c60de7d7b017526a92Russell King		return 0;
45368b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
45468b65f7305e54b822b2483c60de7d7b017526a92Russell King
45568b65f7305e54b822b2483c60de7d7b017526a92Russell King	/*
45668b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * Bodge: don't send the last character by DMA, as this
45768b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * will prevent XON from notifying us to restart DMA.
45868b65f7305e54b822b2483c60de7d7b017526a92Russell King	 */
45968b65f7305e54b822b2483c60de7d7b017526a92Russell King	count -= 1;
46068b65f7305e54b822b2483c60de7d7b017526a92Russell King
46168b65f7305e54b822b2483c60de7d7b017526a92Russell King	/* Else proceed to copy the TX chars to the DMA buffer and fire DMA */
46268b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (count > PL011_DMA_BUFFER_SIZE)
46368b65f7305e54b822b2483c60de7d7b017526a92Russell King		count = PL011_DMA_BUFFER_SIZE;
46468b65f7305e54b822b2483c60de7d7b017526a92Russell King
46568b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (xmit->tail < xmit->head)
46668b65f7305e54b822b2483c60de7d7b017526a92Russell King		memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count);
46768b65f7305e54b822b2483c60de7d7b017526a92Russell King	else {
46868b65f7305e54b822b2483c60de7d7b017526a92Russell King		size_t first = UART_XMIT_SIZE - xmit->tail;
46968b65f7305e54b822b2483c60de7d7b017526a92Russell King		size_t second = xmit->head;
47068b65f7305e54b822b2483c60de7d7b017526a92Russell King
47168b65f7305e54b822b2483c60de7d7b017526a92Russell King		memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first);
47268b65f7305e54b822b2483c60de7d7b017526a92Russell King		if (second)
47368b65f7305e54b822b2483c60de7d7b017526a92Russell King			memcpy(&dmatx->buf[first], &xmit->buf[0], second);
47468b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
47568b65f7305e54b822b2483c60de7d7b017526a92Russell King
47668b65f7305e54b822b2483c60de7d7b017526a92Russell King	dmatx->sg.length = count;
47768b65f7305e54b822b2483c60de7d7b017526a92Russell King
47868b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (dma_map_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE) != 1) {
47968b65f7305e54b822b2483c60de7d7b017526a92Russell King		uap->dmatx.queued = false;
48068b65f7305e54b822b2483c60de7d7b017526a92Russell King		dev_dbg(uap->port.dev, "unable to map TX DMA\n");
48168b65f7305e54b822b2483c60de7d7b017526a92Russell King		return -EBUSY;
48268b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
48368b65f7305e54b822b2483c60de7d7b017526a92Russell King
484a485df4b4404379786c4bdd258bc528b2617449dVinod Koul	desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_MEM_TO_DEV,
48568b65f7305e54b822b2483c60de7d7b017526a92Russell King					     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
48668b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (!desc) {
48768b65f7305e54b822b2483c60de7d7b017526a92Russell King		dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE);
48868b65f7305e54b822b2483c60de7d7b017526a92Russell King		uap->dmatx.queued = false;
48968b65f7305e54b822b2483c60de7d7b017526a92Russell King		/*
49068b65f7305e54b822b2483c60de7d7b017526a92Russell King		 * If DMA cannot be used right now, we complete this
49168b65f7305e54b822b2483c60de7d7b017526a92Russell King		 * transaction via IRQ and let the TTY layer retry.
49268b65f7305e54b822b2483c60de7d7b017526a92Russell King		 */
49368b65f7305e54b822b2483c60de7d7b017526a92Russell King		dev_dbg(uap->port.dev, "TX DMA busy\n");
49468b65f7305e54b822b2483c60de7d7b017526a92Russell King		return -EBUSY;
49568b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
49668b65f7305e54b822b2483c60de7d7b017526a92Russell King
49768b65f7305e54b822b2483c60de7d7b017526a92Russell King	/* Some data to go along to the callback */
49868b65f7305e54b822b2483c60de7d7b017526a92Russell King	desc->callback = pl011_dma_tx_callback;
49968b65f7305e54b822b2483c60de7d7b017526a92Russell King	desc->callback_param = uap;
50068b65f7305e54b822b2483c60de7d7b017526a92Russell King
50168b65f7305e54b822b2483c60de7d7b017526a92Russell King	/* All errors should happen at prepare time */
50268b65f7305e54b822b2483c60de7d7b017526a92Russell King	dmaengine_submit(desc);
50368b65f7305e54b822b2483c60de7d7b017526a92Russell King
50468b65f7305e54b822b2483c60de7d7b017526a92Russell King	/* Fire the DMA transaction */
50568b65f7305e54b822b2483c60de7d7b017526a92Russell King	dma_dev->device_issue_pending(chan);
50668b65f7305e54b822b2483c60de7d7b017526a92Russell King
50768b65f7305e54b822b2483c60de7d7b017526a92Russell King	uap->dmacr |= UART011_TXDMAE;
50868b65f7305e54b822b2483c60de7d7b017526a92Russell King	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
50968b65f7305e54b822b2483c60de7d7b017526a92Russell King	uap->dmatx.queued = true;
51068b65f7305e54b822b2483c60de7d7b017526a92Russell King
51168b65f7305e54b822b2483c60de7d7b017526a92Russell King	/*
51268b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * Now we know that DMA will fire, so advance the ring buffer
51368b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * with the stuff we just dispatched.
51468b65f7305e54b822b2483c60de7d7b017526a92Russell King	 */
51568b65f7305e54b822b2483c60de7d7b017526a92Russell King	xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
51668b65f7305e54b822b2483c60de7d7b017526a92Russell King	uap->port.icount.tx += count;
51768b65f7305e54b822b2483c60de7d7b017526a92Russell King
51868b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
51968b65f7305e54b822b2483c60de7d7b017526a92Russell King		uart_write_wakeup(&uap->port);
52068b65f7305e54b822b2483c60de7d7b017526a92Russell King
52168b65f7305e54b822b2483c60de7d7b017526a92Russell King	return 1;
52268b65f7305e54b822b2483c60de7d7b017526a92Russell King}
52368b65f7305e54b822b2483c60de7d7b017526a92Russell King
52468b65f7305e54b822b2483c60de7d7b017526a92Russell King/*
52568b65f7305e54b822b2483c60de7d7b017526a92Russell King * We received a transmit interrupt without a pending X-char but with
52668b65f7305e54b822b2483c60de7d7b017526a92Russell King * pending characters.
52768b65f7305e54b822b2483c60de7d7b017526a92Russell King * Locking: called with port lock held and IRQs disabled.
52868b65f7305e54b822b2483c60de7d7b017526a92Russell King * Returns:
52968b65f7305e54b822b2483c60de7d7b017526a92Russell King *   false if we want to use PIO to transmit
53068b65f7305e54b822b2483c60de7d7b017526a92Russell King *   true if we queued a DMA buffer
53168b65f7305e54b822b2483c60de7d7b017526a92Russell King */
53268b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic bool pl011_dma_tx_irq(struct uart_amba_port *uap)
53368b65f7305e54b822b2483c60de7d7b017526a92Russell King{
534ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (!uap->using_tx_dma)
53568b65f7305e54b822b2483c60de7d7b017526a92Russell King		return false;
53668b65f7305e54b822b2483c60de7d7b017526a92Russell King
53768b65f7305e54b822b2483c60de7d7b017526a92Russell King	/*
53868b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * If we already have a TX buffer queued, but received a
53968b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * TX interrupt, it will be because we've just sent an X-char.
54068b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * Ensure the TX DMA is enabled and the TX IRQ is disabled.
54168b65f7305e54b822b2483c60de7d7b017526a92Russell King	 */
54268b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (uap->dmatx.queued) {
54368b65f7305e54b822b2483c60de7d7b017526a92Russell King		uap->dmacr |= UART011_TXDMAE;
54468b65f7305e54b822b2483c60de7d7b017526a92Russell King		writew(uap->dmacr, uap->port.membase + UART011_DMACR);
54568b65f7305e54b822b2483c60de7d7b017526a92Russell King		uap->im &= ~UART011_TXIM;
54668b65f7305e54b822b2483c60de7d7b017526a92Russell King		writew(uap->im, uap->port.membase + UART011_IMSC);
54768b65f7305e54b822b2483c60de7d7b017526a92Russell King		return true;
54868b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
54968b65f7305e54b822b2483c60de7d7b017526a92Russell King
55068b65f7305e54b822b2483c60de7d7b017526a92Russell King	/*
55168b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * We don't have a TX buffer queued, so try to queue one.
55225985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	 * If we successfully queued a buffer, mask the TX IRQ.
55368b65f7305e54b822b2483c60de7d7b017526a92Russell King	 */
55468b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (pl011_dma_tx_refill(uap) > 0) {
55568b65f7305e54b822b2483c60de7d7b017526a92Russell King		uap->im &= ~UART011_TXIM;
55668b65f7305e54b822b2483c60de7d7b017526a92Russell King		writew(uap->im, uap->port.membase + UART011_IMSC);
55768b65f7305e54b822b2483c60de7d7b017526a92Russell King		return true;
55868b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
55968b65f7305e54b822b2483c60de7d7b017526a92Russell King	return false;
56068b65f7305e54b822b2483c60de7d7b017526a92Russell King}
56168b65f7305e54b822b2483c60de7d7b017526a92Russell King
56268b65f7305e54b822b2483c60de7d7b017526a92Russell King/*
56368b65f7305e54b822b2483c60de7d7b017526a92Russell King * Stop the DMA transmit (eg, due to received XOFF).
56468b65f7305e54b822b2483c60de7d7b017526a92Russell King * Locking: called with port lock held and IRQs disabled.
56568b65f7305e54b822b2483c60de7d7b017526a92Russell King */
56668b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
56768b65f7305e54b822b2483c60de7d7b017526a92Russell King{
56868b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (uap->dmatx.queued) {
56968b65f7305e54b822b2483c60de7d7b017526a92Russell King		uap->dmacr &= ~UART011_TXDMAE;
57068b65f7305e54b822b2483c60de7d7b017526a92Russell King		writew(uap->dmacr, uap->port.membase + UART011_DMACR);
57168b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
57268b65f7305e54b822b2483c60de7d7b017526a92Russell King}
57368b65f7305e54b822b2483c60de7d7b017526a92Russell King
57468b65f7305e54b822b2483c60de7d7b017526a92Russell King/*
57568b65f7305e54b822b2483c60de7d7b017526a92Russell King * Try to start a DMA transmit, or in the case of an XON/OFF
57668b65f7305e54b822b2483c60de7d7b017526a92Russell King * character queued for send, try to get that character out ASAP.
57768b65f7305e54b822b2483c60de7d7b017526a92Russell King * Locking: called with port lock held and IRQs disabled.
57868b65f7305e54b822b2483c60de7d7b017526a92Russell King * Returns:
57968b65f7305e54b822b2483c60de7d7b017526a92Russell King *   false if we want the TX IRQ to be enabled
58068b65f7305e54b822b2483c60de7d7b017526a92Russell King *   true if we have a buffer queued
58168b65f7305e54b822b2483c60de7d7b017526a92Russell King */
58268b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
58368b65f7305e54b822b2483c60de7d7b017526a92Russell King{
58468b65f7305e54b822b2483c60de7d7b017526a92Russell King	u16 dmacr;
58568b65f7305e54b822b2483c60de7d7b017526a92Russell King
586ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (!uap->using_tx_dma)
58768b65f7305e54b822b2483c60de7d7b017526a92Russell King		return false;
58868b65f7305e54b822b2483c60de7d7b017526a92Russell King
58968b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (!uap->port.x_char) {
59068b65f7305e54b822b2483c60de7d7b017526a92Russell King		/* no X-char, try to push chars out in DMA mode */
59168b65f7305e54b822b2483c60de7d7b017526a92Russell King		bool ret = true;
59268b65f7305e54b822b2483c60de7d7b017526a92Russell King
59368b65f7305e54b822b2483c60de7d7b017526a92Russell King		if (!uap->dmatx.queued) {
59468b65f7305e54b822b2483c60de7d7b017526a92Russell King			if (pl011_dma_tx_refill(uap) > 0) {
59568b65f7305e54b822b2483c60de7d7b017526a92Russell King				uap->im &= ~UART011_TXIM;
59668b65f7305e54b822b2483c60de7d7b017526a92Russell King				ret = true;
59768b65f7305e54b822b2483c60de7d7b017526a92Russell King			} else {
59868b65f7305e54b822b2483c60de7d7b017526a92Russell King				uap->im |= UART011_TXIM;
59968b65f7305e54b822b2483c60de7d7b017526a92Russell King				ret = false;
60068b65f7305e54b822b2483c60de7d7b017526a92Russell King			}
60168b65f7305e54b822b2483c60de7d7b017526a92Russell King			writew(uap->im, uap->port.membase + UART011_IMSC);
60268b65f7305e54b822b2483c60de7d7b017526a92Russell King		} else if (!(uap->dmacr & UART011_TXDMAE)) {
60368b65f7305e54b822b2483c60de7d7b017526a92Russell King			uap->dmacr |= UART011_TXDMAE;
60468b65f7305e54b822b2483c60de7d7b017526a92Russell King			writew(uap->dmacr,
60568b65f7305e54b822b2483c60de7d7b017526a92Russell King				       uap->port.membase + UART011_DMACR);
60668b65f7305e54b822b2483c60de7d7b017526a92Russell King		}
60768b65f7305e54b822b2483c60de7d7b017526a92Russell King		return ret;
60868b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
60968b65f7305e54b822b2483c60de7d7b017526a92Russell King
61068b65f7305e54b822b2483c60de7d7b017526a92Russell King	/*
61168b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * We have an X-char to send.  Disable DMA to prevent it loading
61268b65f7305e54b822b2483c60de7d7b017526a92Russell King	 * the TX fifo, and then see if we can stuff it into the FIFO.
61368b65f7305e54b822b2483c60de7d7b017526a92Russell King	 */
61468b65f7305e54b822b2483c60de7d7b017526a92Russell King	dmacr = uap->dmacr;
61568b65f7305e54b822b2483c60de7d7b017526a92Russell King	uap->dmacr &= ~UART011_TXDMAE;
61668b65f7305e54b822b2483c60de7d7b017526a92Russell King	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
61768b65f7305e54b822b2483c60de7d7b017526a92Russell King
61868b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) {
61968b65f7305e54b822b2483c60de7d7b017526a92Russell King		/*
62068b65f7305e54b822b2483c60de7d7b017526a92Russell King		 * No space in the FIFO, so enable the transmit interrupt
62168b65f7305e54b822b2483c60de7d7b017526a92Russell King		 * so we know when there is space.  Note that once we've
62268b65f7305e54b822b2483c60de7d7b017526a92Russell King		 * loaded the character, we should just re-enable DMA.
62368b65f7305e54b822b2483c60de7d7b017526a92Russell King		 */
62468b65f7305e54b822b2483c60de7d7b017526a92Russell King		return false;
62568b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
62668b65f7305e54b822b2483c60de7d7b017526a92Russell King
62768b65f7305e54b822b2483c60de7d7b017526a92Russell King	writew(uap->port.x_char, uap->port.membase + UART01x_DR);
62868b65f7305e54b822b2483c60de7d7b017526a92Russell King	uap->port.icount.tx++;
62968b65f7305e54b822b2483c60de7d7b017526a92Russell King	uap->port.x_char = 0;
63068b65f7305e54b822b2483c60de7d7b017526a92Russell King
63168b65f7305e54b822b2483c60de7d7b017526a92Russell King	/* Success - restore the DMA state */
63268b65f7305e54b822b2483c60de7d7b017526a92Russell King	uap->dmacr = dmacr;
63368b65f7305e54b822b2483c60de7d7b017526a92Russell King	writew(dmacr, uap->port.membase + UART011_DMACR);
63468b65f7305e54b822b2483c60de7d7b017526a92Russell King
63568b65f7305e54b822b2483c60de7d7b017526a92Russell King	return true;
63668b65f7305e54b822b2483c60de7d7b017526a92Russell King}
63768b65f7305e54b822b2483c60de7d7b017526a92Russell King
63868b65f7305e54b822b2483c60de7d7b017526a92Russell King/*
63968b65f7305e54b822b2483c60de7d7b017526a92Russell King * Flush the transmit buffer.
64068b65f7305e54b822b2483c60de7d7b017526a92Russell King * Locking: called with port lock held and IRQs disabled.
64168b65f7305e54b822b2483c60de7d7b017526a92Russell King */
64268b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic void pl011_dma_flush_buffer(struct uart_port *port)
64368b65f7305e54b822b2483c60de7d7b017526a92Russell King{
64468b65f7305e54b822b2483c60de7d7b017526a92Russell King	struct uart_amba_port *uap = (struct uart_amba_port *)port;
64568b65f7305e54b822b2483c60de7d7b017526a92Russell King
646ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (!uap->using_tx_dma)
64768b65f7305e54b822b2483c60de7d7b017526a92Russell King		return;
64868b65f7305e54b822b2483c60de7d7b017526a92Russell King
64968b65f7305e54b822b2483c60de7d7b017526a92Russell King	/* Avoid deadlock with the DMA engine callback */
65068b65f7305e54b822b2483c60de7d7b017526a92Russell King	spin_unlock(&uap->port.lock);
65168b65f7305e54b822b2483c60de7d7b017526a92Russell King	dmaengine_terminate_all(uap->dmatx.chan);
65268b65f7305e54b822b2483c60de7d7b017526a92Russell King	spin_lock(&uap->port.lock);
65368b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (uap->dmatx.queued) {
65468b65f7305e54b822b2483c60de7d7b017526a92Russell King		dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
65568b65f7305e54b822b2483c60de7d7b017526a92Russell King			     DMA_TO_DEVICE);
65668b65f7305e54b822b2483c60de7d7b017526a92Russell King		uap->dmatx.queued = false;
65768b65f7305e54b822b2483c60de7d7b017526a92Russell King		uap->dmacr &= ~UART011_TXDMAE;
65868b65f7305e54b822b2483c60de7d7b017526a92Russell King		writew(uap->dmacr, uap->port.membase + UART011_DMACR);
65968b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
66068b65f7305e54b822b2483c60de7d7b017526a92Russell King}
66168b65f7305e54b822b2483c60de7d7b017526a92Russell King
662ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic void pl011_dma_rx_callback(void *data);
663ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
664ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
665ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{
666ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct dma_chan *rxchan = uap->dmarx.chan;
667ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct dma_device *dma_dev;
668ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct pl011_dmarx_data *dmarx = &uap->dmarx;
669ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct dma_async_tx_descriptor *desc;
670ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct pl011_sgbuf *sgbuf;
671ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
672ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (!rxchan)
673ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		return -EIO;
674ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
675ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	/* Start the RX DMA job */
676ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	sgbuf = uap->dmarx.use_buf_b ?
677ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		&uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
678ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	dma_dev = rxchan->device;
679ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	desc = rxchan->device->device_prep_slave_sg(rxchan, &sgbuf->sg, 1,
680a485df4b4404379786c4bdd258bc528b2617449dVinod Koul					DMA_DEV_TO_MEM,
681ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
682ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	/*
683ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * If the DMA engine is busy and cannot prepare a
684ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * channel, no big deal, the driver will fall back
685ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * to interrupt mode as a result of this error code.
686ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 */
687ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (!desc) {
688ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		uap->dmarx.running = false;
689ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		dmaengine_terminate_all(rxchan);
690ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		return -EBUSY;
691ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	}
692ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
693ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	/* Some data to go along to the callback */
694ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	desc->callback = pl011_dma_rx_callback;
695ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	desc->callback_param = uap;
696ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	dmarx->cookie = dmaengine_submit(desc);
697ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	dma_async_issue_pending(rxchan);
698ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
699ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	uap->dmacr |= UART011_RXDMAE;
700ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
701ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	uap->dmarx.running = true;
702ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
703ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	uap->im &= ~UART011_RXIM;
704ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	writew(uap->im, uap->port.membase + UART011_IMSC);
705ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
706ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	return 0;
707ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij}
708ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
709ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij/*
710ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * This is called when either the DMA job is complete, or
711ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * the FIFO timeout interrupt occurred. This must be called
712ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * with the port spinlock uap->port.lock held.
713ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij */
714ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic void pl011_dma_rx_chars(struct uart_amba_port *uap,
715ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			       u32 pending, bool use_buf_b,
716ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			       bool readfifo)
717ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{
718ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct tty_struct *tty = uap->port.state->port.tty;
719ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct pl011_sgbuf *sgbuf = use_buf_b ?
720ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		&uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
721ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct device *dev = uap->dmarx.chan->device->dev;
722ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	int dma_count = 0;
723ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	u32 fifotaken = 0; /* only used for vdbg() */
724ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
725ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	/* Pick everything from the DMA first */
726ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (pending) {
727ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		/* Sync in buffer */
728ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		dma_sync_sg_for_cpu(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE);
729ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
730ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		/*
731ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		 * First take all chars in the DMA pipe, then look in the FIFO.
732ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		 * Note that tty_insert_flip_buf() tries to take as many chars
733ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		 * as it can.
734ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		 */
735ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		dma_count = tty_insert_flip_string(uap->port.state->port.tty,
736ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij						   sgbuf->buf, pending);
737ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
738ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		/* Return buffer to device */
739ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		dma_sync_sg_for_device(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE);
740ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
741ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		uap->port.icount.rx += dma_count;
742ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		if (dma_count < pending)
743ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			dev_warn(uap->port.dev,
744ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij				 "couldn't insert all characters (TTY is full?)\n");
745ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	}
746ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
747ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	/*
748ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * Only continue with trying to read the FIFO if all DMA chars have
749ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * been taken first.
750ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 */
751ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (dma_count == pending && readfifo) {
752ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		/* Clear any error flags */
753ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS,
754ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		       uap->port.membase + UART011_ICR);
755ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
756ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		/*
757ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		 * If we read all the DMA'd characters, and we had an
75829772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		 * incomplete buffer, that could be due to an rx error, or
75929772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		 * maybe we just timed out. Read any pending chars and check
76029772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		 * the error status.
76129772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		 *
76229772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		 * Error conditions will only occur in the FIFO, these will
76329772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		 * trigger an immediate interrupt and stop the DMA job, so we
76429772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		 * will always find the error in the FIFO, never in the DMA
76529772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		 * buffer.
766ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		 */
76729772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij		fifotaken = pl011_fifo_to_tty(uap);
768ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	}
769ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
770ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	spin_unlock(&uap->port.lock);
771ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	dev_vdbg(uap->port.dev,
772ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		 "Took %d chars from DMA buffer and %d chars from the FIFO\n",
773ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		 dma_count, fifotaken);
774ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	tty_flip_buffer_push(tty);
775ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	spin_lock(&uap->port.lock);
776ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij}
777ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
778ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic void pl011_dma_rx_irq(struct uart_amba_port *uap)
779ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{
780ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct pl011_dmarx_data *dmarx = &uap->dmarx;
781ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct dma_chan *rxchan = dmarx->chan;
782ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct pl011_sgbuf *sgbuf = dmarx->use_buf_b ?
783ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		&dmarx->sgbuf_b : &dmarx->sgbuf_a;
784ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	size_t pending;
785ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct dma_tx_state state;
786ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	enum dma_status dmastat;
787ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
788ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	/*
789ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * Pause the transfer so we can trust the current counter,
790ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * do this before we pause the PL011 block, else we may
791ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * overflow the FIFO.
792ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 */
793ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (dmaengine_pause(rxchan))
794ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		dev_err(uap->port.dev, "unable to pause DMA transfer\n");
795ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	dmastat = rxchan->device->device_tx_status(rxchan,
796ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij						   dmarx->cookie, &state);
797ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (dmastat != DMA_PAUSED)
798ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		dev_err(uap->port.dev, "unable to pause DMA transfer\n");
799ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
800ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	/* Disable RX DMA - incoming data will wait in the FIFO */
801ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	uap->dmacr &= ~UART011_RXDMAE;
802ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
803ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	uap->dmarx.running = false;
804ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
805ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	pending = sgbuf->sg.length - state.residue;
806ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
807ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	/* Then we terminate the transfer - we now know our residue */
808ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	dmaengine_terminate_all(rxchan);
809ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
810ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	/*
811ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * This will take the chars we have so far and insert
812ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * into the framework.
813ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 */
814ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	pl011_dma_rx_chars(uap, pending, dmarx->use_buf_b, true);
815ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
816ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	/* Switch buffer & re-trigger DMA job */
817ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	dmarx->use_buf_b = !dmarx->use_buf_b;
818ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (pl011_dma_rx_trigger_dma(uap)) {
819ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		dev_dbg(uap->port.dev, "could not retrigger RX DMA job "
820ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			"fall back to interrupt mode\n");
821ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		uap->im |= UART011_RXIM;
822ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		writew(uap->im, uap->port.membase + UART011_IMSC);
823ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	}
824ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij}
825ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
826ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic void pl011_dma_rx_callback(void *data)
827ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{
828ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct uart_amba_port *uap = data;
829ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	struct pl011_dmarx_data *dmarx = &uap->dmarx;
830ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	bool lastbuf = dmarx->use_buf_b;
831ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	int ret;
832ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
833ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	/*
834ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * This completion interrupt occurs typically when the
835ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * RX buffer is totally stuffed but no timeout has yet
836ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * occurred. When that happens, we just want the RX
837ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * routine to flush out the secondary DMA buffer while
838ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * we immediately trigger the next DMA job.
839ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 */
840ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	spin_lock_irq(&uap->port.lock);
841ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	uap->dmarx.running = false;
842ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	dmarx->use_buf_b = !lastbuf;
843ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	ret = pl011_dma_rx_trigger_dma(uap);
844ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
845ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	pl011_dma_rx_chars(uap, PL011_DMA_BUFFER_SIZE, lastbuf, false);
846ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	spin_unlock_irq(&uap->port.lock);
847ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	/*
848ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * Do this check after we picked the DMA chars so we don't
849ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * get some IRQ immediately from RX.
850ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 */
851ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (ret) {
852ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		dev_dbg(uap->port.dev, "could not retrigger RX DMA job "
853ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			"fall back to interrupt mode\n");
854ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		uap->im |= UART011_RXIM;
855ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		writew(uap->im, uap->port.membase + UART011_IMSC);
856ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	}
857ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij}
858ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
859ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij/*
860ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * Stop accepting received characters, when we're shutting down or
861ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * suspending this port.
862ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * Locking: called with port lock held and IRQs disabled.
863ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij */
864ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
865ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{
866ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	/* FIXME.  Just disable the DMA enable */
867ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	uap->dmacr &= ~UART011_RXDMAE;
868ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
869ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij}
87068b65f7305e54b822b2483c60de7d7b017526a92Russell King
87168b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic void pl011_dma_startup(struct uart_amba_port *uap)
87268b65f7305e54b822b2483c60de7d7b017526a92Russell King{
873ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	int ret;
874ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
87568b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (!uap->dmatx.chan)
87668b65f7305e54b822b2483c60de7d7b017526a92Russell King		return;
87768b65f7305e54b822b2483c60de7d7b017526a92Russell King
87868b65f7305e54b822b2483c60de7d7b017526a92Russell King	uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL);
87968b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (!uap->dmatx.buf) {
88068b65f7305e54b822b2483c60de7d7b017526a92Russell King		dev_err(uap->port.dev, "no memory for DMA TX buffer\n");
88168b65f7305e54b822b2483c60de7d7b017526a92Russell King		uap->port.fifosize = uap->fifosize;
88268b65f7305e54b822b2483c60de7d7b017526a92Russell King		return;
88368b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
88468b65f7305e54b822b2483c60de7d7b017526a92Russell King
88568b65f7305e54b822b2483c60de7d7b017526a92Russell King	sg_init_one(&uap->dmatx.sg, uap->dmatx.buf, PL011_DMA_BUFFER_SIZE);
88668b65f7305e54b822b2483c60de7d7b017526a92Russell King
88768b65f7305e54b822b2483c60de7d7b017526a92Russell King	/* The DMA buffer is now the FIFO the TTY subsystem can use */
88868b65f7305e54b822b2483c60de7d7b017526a92Russell King	uap->port.fifosize = PL011_DMA_BUFFER_SIZE;
889ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	uap->using_tx_dma = true;
890ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
891ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (!uap->dmarx.chan)
892ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		goto skip_rx;
893ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
894ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	/* Allocate and map DMA RX buffers */
895ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	ret = pl011_sgbuf_init(uap->dmarx.chan, &uap->dmarx.sgbuf_a,
896ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			       DMA_FROM_DEVICE);
897ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (ret) {
898ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		dev_err(uap->port.dev, "failed to init DMA %s: %d\n",
899ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			"RX buffer A", ret);
900ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		goto skip_rx;
901ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	}
90268b65f7305e54b822b2483c60de7d7b017526a92Russell King
903ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	ret = pl011_sgbuf_init(uap->dmarx.chan, &uap->dmarx.sgbuf_b,
904ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			       DMA_FROM_DEVICE);
905ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (ret) {
906ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		dev_err(uap->port.dev, "failed to init DMA %s: %d\n",
907ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			"RX buffer B", ret);
908ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_a,
909ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij				 DMA_FROM_DEVICE);
910ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		goto skip_rx;
911ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	}
912ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
913ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	uap->using_rx_dma = true;
91468b65f7305e54b822b2483c60de7d7b017526a92Russell King
915ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijskip_rx:
91668b65f7305e54b822b2483c60de7d7b017526a92Russell King	/* Turn on DMA error (RX/TX will be enabled on demand) */
91768b65f7305e54b822b2483c60de7d7b017526a92Russell King	uap->dmacr |= UART011_DMAONERR;
91868b65f7305e54b822b2483c60de7d7b017526a92Russell King	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
91938d624361b2a82d6317c379aebf81b1b28210bb0Russell King
92038d624361b2a82d6317c379aebf81b1b28210bb0Russell King	/*
92138d624361b2a82d6317c379aebf81b1b28210bb0Russell King	 * ST Micro variants has some specific dma burst threshold
92238d624361b2a82d6317c379aebf81b1b28210bb0Russell King	 * compensation. Set this to 16 bytes, so burst will only
92338d624361b2a82d6317c379aebf81b1b28210bb0Russell King	 * be issued above/below 16 bytes.
92438d624361b2a82d6317c379aebf81b1b28210bb0Russell King	 */
92538d624361b2a82d6317c379aebf81b1b28210bb0Russell King	if (uap->vendor->dma_threshold)
92638d624361b2a82d6317c379aebf81b1b28210bb0Russell King		writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16,
92738d624361b2a82d6317c379aebf81b1b28210bb0Russell King			       uap->port.membase + ST_UART011_DMAWM);
928ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
929ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (uap->using_rx_dma) {
930ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		if (pl011_dma_rx_trigger_dma(uap))
931ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			dev_dbg(uap->port.dev, "could not trigger initial "
932ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij				"RX DMA job, fall back to interrupt mode\n");
933ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	}
93468b65f7305e54b822b2483c60de7d7b017526a92Russell King}
93568b65f7305e54b822b2483c60de7d7b017526a92Russell King
93668b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic void pl011_dma_shutdown(struct uart_amba_port *uap)
93768b65f7305e54b822b2483c60de7d7b017526a92Russell King{
938ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (!(uap->using_tx_dma || uap->using_rx_dma))
93968b65f7305e54b822b2483c60de7d7b017526a92Russell King		return;
94068b65f7305e54b822b2483c60de7d7b017526a92Russell King
94168b65f7305e54b822b2483c60de7d7b017526a92Russell King	/* Disable RX and TX DMA */
94268b65f7305e54b822b2483c60de7d7b017526a92Russell King	while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
94368b65f7305e54b822b2483c60de7d7b017526a92Russell King		barrier();
94468b65f7305e54b822b2483c60de7d7b017526a92Russell King
94568b65f7305e54b822b2483c60de7d7b017526a92Russell King	spin_lock_irq(&uap->port.lock);
94668b65f7305e54b822b2483c60de7d7b017526a92Russell King	uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
94768b65f7305e54b822b2483c60de7d7b017526a92Russell King	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
94868b65f7305e54b822b2483c60de7d7b017526a92Russell King	spin_unlock_irq(&uap->port.lock);
94968b65f7305e54b822b2483c60de7d7b017526a92Russell King
950ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (uap->using_tx_dma) {
951ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		/* In theory, this should already be done by pl011_dma_flush_buffer */
952ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		dmaengine_terminate_all(uap->dmatx.chan);
953ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		if (uap->dmatx.queued) {
954ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
955ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij				     DMA_TO_DEVICE);
956ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			uap->dmatx.queued = false;
957ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		}
958ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
959ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		kfree(uap->dmatx.buf);
960ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		uap->using_tx_dma = false;
96168b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
96268b65f7305e54b822b2483c60de7d7b017526a92Russell King
963ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (uap->using_rx_dma) {
964ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		dmaengine_terminate_all(uap->dmarx.chan);
965ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		/* Clean up the RX DMA */
966ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_a, DMA_FROM_DEVICE);
967ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_b, DMA_FROM_DEVICE);
968ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		uap->using_rx_dma = false;
969ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	}
970ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij}
97168b65f7305e54b822b2483c60de7d7b017526a92Russell King
972ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic inline bool pl011_dma_rx_available(struct uart_amba_port *uap)
973ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{
974ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	return uap->using_rx_dma;
97568b65f7305e54b822b2483c60de7d7b017526a92Russell King}
97668b65f7305e54b822b2483c60de7d7b017526a92Russell King
977ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
978ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{
979ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	return uap->using_rx_dma && uap->dmarx.running;
980ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij}
981ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
982ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
98368b65f7305e54b822b2483c60de7d7b017526a92Russell King#else
98468b65f7305e54b822b2483c60de7d7b017526a92Russell King/* Blank functions if the DMA engine is not available */
98568b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic inline void pl011_dma_probe(struct uart_amba_port *uap)
98668b65f7305e54b822b2483c60de7d7b017526a92Russell King{
98768b65f7305e54b822b2483c60de7d7b017526a92Russell King}
98868b65f7305e54b822b2483c60de7d7b017526a92Russell King
98968b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic inline void pl011_dma_remove(struct uart_amba_port *uap)
99068b65f7305e54b822b2483c60de7d7b017526a92Russell King{
99168b65f7305e54b822b2483c60de7d7b017526a92Russell King}
99268b65f7305e54b822b2483c60de7d7b017526a92Russell King
99368b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic inline void pl011_dma_startup(struct uart_amba_port *uap)
99468b65f7305e54b822b2483c60de7d7b017526a92Russell King{
99568b65f7305e54b822b2483c60de7d7b017526a92Russell King}
99668b65f7305e54b822b2483c60de7d7b017526a92Russell King
99768b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic inline void pl011_dma_shutdown(struct uart_amba_port *uap)
99868b65f7305e54b822b2483c60de7d7b017526a92Russell King{
99968b65f7305e54b822b2483c60de7d7b017526a92Russell King}
100068b65f7305e54b822b2483c60de7d7b017526a92Russell King
100168b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic inline bool pl011_dma_tx_irq(struct uart_amba_port *uap)
100268b65f7305e54b822b2483c60de7d7b017526a92Russell King{
100368b65f7305e54b822b2483c60de7d7b017526a92Russell King	return false;
100468b65f7305e54b822b2483c60de7d7b017526a92Russell King}
100568b65f7305e54b822b2483c60de7d7b017526a92Russell King
100668b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
100768b65f7305e54b822b2483c60de7d7b017526a92Russell King{
100868b65f7305e54b822b2483c60de7d7b017526a92Russell King}
100968b65f7305e54b822b2483c60de7d7b017526a92Russell King
101068b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
101168b65f7305e54b822b2483c60de7d7b017526a92Russell King{
101268b65f7305e54b822b2483c60de7d7b017526a92Russell King	return false;
101368b65f7305e54b822b2483c60de7d7b017526a92Russell King}
101468b65f7305e54b822b2483c60de7d7b017526a92Russell King
1015ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic inline void pl011_dma_rx_irq(struct uart_amba_port *uap)
1016ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{
1017ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij}
1018ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
1019ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
1020ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{
1021ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij}
1022ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
1023ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic inline int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
1024ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{
1025ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	return -EIO;
1026ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij}
1027ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
1028ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic inline bool pl011_dma_rx_available(struct uart_amba_port *uap)
1029ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{
1030ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	return false;
1031ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij}
1032ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
1033ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
1034ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{
1035ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	return false;
1036ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij}
1037ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
103868b65f7305e54b822b2483c60de7d7b017526a92Russell King#define pl011_dma_flush_buffer	NULL
103968b65f7305e54b822b2483c60de7d7b017526a92Russell King#endif
104068b65f7305e54b822b2483c60de7d7b017526a92Russell King
104168b65f7305e54b822b2483c60de7d7b017526a92Russell King
1042c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu/*
1043c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * pl011_lockup_wa
1044c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * This workaround aims to break the deadlock situation
1045c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * when after long transfer over uart in hardware flow
1046c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * control, uart interrupt registers cannot be cleared.
1047c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * Hence uart transfer gets blocked.
1048c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu *
1049c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * It is seen that during such deadlock condition ICR
1050c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * don't get cleared even on multiple write. This leads
1051c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * pass_counter to decrease and finally reach zero. This
1052c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * can be taken as trigger point to run this UART_BT_WA.
1053c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu *
1054c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu */
1055c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahustatic void pl011_lockup_wa(unsigned long data)
1056c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu{
1057c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	struct uart_amba_port *uap = amba_ports[0];
1058c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	void __iomem *base = uap->port.membase;
1059c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	struct circ_buf *xmit = &uap->port.state->xmit;
1060c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	struct tty_struct *tty = uap->port.state->port.tty;
1061c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	int buf_empty_retries = 200;
1062c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	int loop;
1063c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
1064c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	/* Stop HCI layer from submitting data for tx */
1065c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	tty->hw_stopped = 1;
1066c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	while (!uart_circ_empty(xmit)) {
1067c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu		if (buf_empty_retries-- == 0)
1068c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu			break;
1069c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu		udelay(100);
1070c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	}
1071c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
1072c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	/* Backup registers */
1073c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
1074c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu		uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]);
1075c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
1076c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	/* Disable UART so that FIFO data is flushed out */
1077c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	writew(0x00, uap->port.membase + UART011_CR);
1078c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
1079c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	/* Soft reset UART module */
1080c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	if (uap->port.dev->platform_data) {
1081c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu		struct amba_pl011_data *plat;
1082c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
1083c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu		plat = uap->port.dev->platform_data;
1084c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu		if (plat->reset)
1085c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu			plat->reset();
1086c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	}
1087c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
1088c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	/* Restore registers */
1089c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
1090c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu		writew(uart_wa_regdata[loop] ,
1091c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu				uap->port.membase + uart_wa_reg[loop]);
1092c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
1093c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	/* Initialise the old status of the modem signals */
1094c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	uap->old_status = readw(uap->port.membase + UART01x_FR) &
1095c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu		UART01x_FR_MODEM_ANY;
1096c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
1097c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	if (readl(base + UART011_MIS) & 0x2)
1098c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu		printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n");
1099c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
1100c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	/* Start Tx/Rx */
1101c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	tty->hw_stopped = 0;
1102c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu}
1103c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
1104b129a8ccd53f74c43e4c83c8e0031a4990040830Russell Kingstatic void pl011_stop_tx(struct uart_port *port)
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_amba_port *uap = (struct uart_amba_port *)port;
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uap->im &= ~UART011_TXIM;
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(uap->im, uap->port.membase + UART011_IMSC);
111068b65f7305e54b822b2483c60de7d7b017526a92Russell King	pl011_dma_tx_stop(uap);
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1113b129a8ccd53f74c43e4c83c8e0031a4990040830Russell Kingstatic void pl011_start_tx(struct uart_port *port)
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_amba_port *uap = (struct uart_amba_port *)port;
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
111768b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (!pl011_dma_tx_start(uap)) {
111868b65f7305e54b822b2483c60de7d7b017526a92Russell King		uap->im |= UART011_TXIM;
111968b65f7305e54b822b2483c60de7d7b017526a92Russell King		writew(uap->im, uap->port.membase + UART011_IMSC);
112068b65f7305e54b822b2483c60de7d7b017526a92Russell King	}
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl011_stop_rx(struct uart_port *port)
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_amba_port *uap = (struct uart_amba_port *)port;
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     UART011_PEIM|UART011_BEIM|UART011_OEIM);
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(uap->im, uap->port.membase + UART011_IMSC);
1130ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij
1131ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	pl011_dma_rx_stop(uap);
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl011_enable_ms(struct uart_port *port)
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_amba_port *uap = (struct uart_amba_port *)port;
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM;
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(uap->im, uap->port.membase + UART011_IMSC);
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11427d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl011_rx_chars(struct uart_amba_port *uap)
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1144ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox	struct tty_struct *tty = uap->port.state->port.tty;
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
114629772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij	pl011_fifo_to_tty(uap);
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11482389b272168ceec056ca1d8a870a97fa9c26e11aThomas Gleixner	spin_unlock(&uap->port.lock);
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty_flip_buffer_push(tty);
1150ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	/*
1151ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * If we were temporarily out of DMA mode for a while,
1152ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * attempt to switch back to DMA mode again.
1153ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 */
1154ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (pl011_dma_rx_available(uap)) {
1155ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		if (pl011_dma_rx_trigger_dma(uap)) {
1156ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			dev_dbg(uap->port.dev, "could not trigger RX DMA job "
1157ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij				"fall back to interrupt mode again\n");
1158ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			uap->im |= UART011_RXIM;
1159ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		} else
1160ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			uap->im &= ~UART011_RXIM;
1161ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		writew(uap->im, uap->port.membase + UART011_IMSC);
1162ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	}
11632389b272168ceec056ca1d8a870a97fa9c26e11aThomas Gleixner	spin_lock(&uap->port.lock);
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl011_tx_chars(struct uart_amba_port *uap)
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1168ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox	struct circ_buf *xmit = &uap->port.state->xmit;
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int count;
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (uap->port.x_char) {
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writew(uap->port.x_char, uap->port.membase + UART01x_DR);
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uap->port.icount.tx++;
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uap->port.x_char = 0;
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
1178b129a8ccd53f74c43e4c83c8e0031a4990040830Russell King		pl011_stop_tx(&uap->port);
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
118268b65f7305e54b822b2483c60de7d7b017526a92Russell King	/* If we are using DMA mode, try to send some characters. */
118368b65f7305e54b822b2483c60de7d7b017526a92Russell King	if (pl011_dma_tx_irq(uap))
118468b65f7305e54b822b2483c60de7d7b017526a92Russell King		return;
118568b65f7305e54b822b2483c60de7d7b017526a92Russell King
1186ffca2b114c6a804d1307781df687e877a373a1c2Russell King	count = uap->fifosize >> 1;
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR);
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uap->port.icount.tx++;
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (uart_circ_empty(xmit))
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (--count > 0);
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uart_write_wakeup(&uap->port);
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (uart_circ_empty(xmit))
1199b129a8ccd53f74c43e4c83c8e0031a4990040830Russell King		pl011_stop_tx(&uap->port);
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl011_modem_status(struct uart_amba_port *uap)
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status, delta;
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	delta = status ^ uap->old_status;
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uap->old_status = status;
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!delta)
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (delta & UART01x_FR_DCD)
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (delta & UART01x_FR_DSR)
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uap->port.icount.dsr++;
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (delta & UART01x_FR_CTS)
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS);
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1223bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox	wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12267d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t pl011_int(int irq, void *dev_id)
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_amba_port *uap = dev_id;
1229963cc981af620c7c07b5f6d1ab998b639e90ecb1Russell King	unsigned long flags;
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int handled = 0;
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1233963cc981af620c7c07b5f6d1ab998b639e90ecb1Russell King	spin_lock_irqsave(&uap->port.lock, flags);
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = readw(uap->port.membase + UART011_MIS);
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status) {
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		do {
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			writew(status & ~(UART011_TXIS|UART011_RTIS|
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  UART011_RXIS),
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       uap->port.membase + UART011_ICR);
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1242ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			if (status & (UART011_RTIS|UART011_RXIS)) {
1243ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij				if (pl011_dma_rx_running(uap))
1244ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij					pl011_dma_rx_irq(uap);
1245ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij				else
1246ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij					pl011_rx_chars(uap);
1247ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij			}
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (status & (UART011_DSRMIS|UART011_DCDMIS|
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      UART011_CTSMIS|UART011_RIMIS))
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pl011_modem_status(uap);
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (status & UART011_TXIS)
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pl011_tx_chars(uap);
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1254c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu			if (pass_counter-- == 0) {
1255c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu				if (uap->interrupt_may_hang)
1256c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu					tasklet_schedule(&pl011_lockup_tlet);
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
1258c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu			}
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			status = readw(uap->port.membase + UART011_MIS);
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} while (status != 0);
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		handled = 1;
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1265963cc981af620c7c07b5f6d1ab998b639e90ecb1Russell King	spin_unlock_irqrestore(&uap->port.lock, flags);
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_RETVAL(handled);
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int pl01x_tx_empty(struct uart_port *port)
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_amba_port *uap = (struct uart_amba_port *)port;
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status = readw(uap->port.membase + UART01x_FR);
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int pl01x_get_mctrl(struct uart_port *port)
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_amba_port *uap = (struct uart_amba_port *)port;
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int result = 0;
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status = readw(uap->port.membase + UART01x_FR);
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12835159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby#define TIOCMBIT(uartbit, tiocmbit)	\
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & uartbit)		\
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result |= tiocmbit
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12875159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby	TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR);
12885159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby	TIOCMBIT(UART01x_FR_DSR, TIOCM_DSR);
12895159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby	TIOCMBIT(UART01x_FR_CTS, TIOCM_CTS);
12905159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby	TIOCMBIT(UART011_FR_RI, TIOCM_RNG);
12915159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby#undef TIOCMBIT
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_amba_port *uap = (struct uart_amba_port *)port;
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int cr;
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cr = readw(uap->port.membase + UART011_CR);
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13025159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby#define	TIOCMBIT(tiocmbit, uartbit)		\
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mctrl & tiocmbit)		\
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cr |= uartbit;		\
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else				\
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cr &= ~uartbit
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13085159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby	TIOCMBIT(TIOCM_RTS, UART011_CR_RTS);
13095159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby	TIOCMBIT(TIOCM_DTR, UART011_CR_DTR);
13105159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby	TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1);
13115159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby	TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2);
13125159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby	TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE);
13133b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent
13143b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent	if (uap->autorts) {
13153b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent		/* We need to disable auto-RTS if we want to turn RTS off */
13163b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent		TIOCMBIT(TIOCM_RTS, UART011_CR_RTSEN);
13173b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent	}
13185159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby#undef TIOCMBIT
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(cr, uap->port.membase + UART011_CR);
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl011_break_ctl(struct uart_port *port, int break_state)
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_amba_port *uap = (struct uart_amba_port *)port;
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int lcr_h;
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&uap->port.lock, flags);
1330ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij	lcr_h = readw(uap->port.membase + uap->lcrh_tx);
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (break_state == -1)
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lcr_h |= UART01x_LCRH_BRK;
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lcr_h &= ~UART01x_LCRH_BRK;
1335ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij	writew(lcr_h, uap->port.membase + uap->lcrh_tx);
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&uap->port.lock, flags);
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
133984b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel#ifdef CONFIG_CONSOLE_POLL
134084b5ae15216aa3ea0314f395536ef9829af21e14Jason Wesselstatic int pl010_get_poll_char(struct uart_port *port)
134184b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel{
134284b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel	struct uart_amba_port *uap = (struct uart_amba_port *)port;
134384b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel	unsigned int status;
134484b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel
1345f5316b4aea024da9266d740322a5481657f6ce59Jason Wessel	status = readw(uap->port.membase + UART01x_FR);
1346f5316b4aea024da9266d740322a5481657f6ce59Jason Wessel	if (status & UART01x_FR_RXFE)
1347f5316b4aea024da9266d740322a5481657f6ce59Jason Wessel		return NO_POLL_CHAR;
134884b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel
134984b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel	return readw(uap->port.membase + UART01x_DR);
135084b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel}
135184b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel
135284b5ae15216aa3ea0314f395536ef9829af21e14Jason Wesselstatic void pl010_put_poll_char(struct uart_port *port,
135384b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel			 unsigned char ch)
135484b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel{
135584b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel	struct uart_amba_port *uap = (struct uart_amba_port *)port;
135684b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel
135784b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel	while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
135884b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel		barrier();
135984b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel
136084b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel	writew(ch, uap->port.membase + UART01x_DR);
136184b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel}
136284b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel
136384b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel#endif /* CONFIG_CONSOLE_POLL */
136484b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl011_startup(struct uart_port *port)
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_amba_port *uap = (struct uart_amba_port *)port;
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int cr;
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13714b4851c65d926f46e208e4731409022d986a1355Russell King	retval = clk_prepare(uap->clk);
13724b4851c65d926f46e208e4731409022d986a1355Russell King	if (retval)
13734b4851c65d926f46e208e4731409022d986a1355Russell King		goto out;
13744b4851c65d926f46e208e4731409022d986a1355Russell King
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Try to enable the clock producer.
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = clk_enable(uap->clk);
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
13804b4851c65d926f46e208e4731409022d986a1355Russell King		goto clk_unprep;
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uap->port.uartclk = clk_get_rate(uap->clk);
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Allocate the IRQ
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto clk_dis;
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King	writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Provoke TX FIFO interrupt into asserting.
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE;
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(cr, uap->port.membase + UART011_CR);
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(0, uap->port.membase + UART011_FBRD);
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(1, uap->port.membase + UART011_IBRD);
1400ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij	writew(0, uap->port.membase + uap->lcrh_rx);
1401ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij	if (uap->lcrh_tx != uap->lcrh_rx) {
1402ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij		int i;
1403ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij		/*
1404ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij		 * Wait 10 PCLKs before writing LCRH_TX register,
1405ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij		 * to get this delay write read only register 10 times
1406ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij		 */
1407ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij		for (i = 0; i < 10; ++i)
1408ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij			writew(0xff, uap->port.membase + UART011_MIS);
1409ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij		writew(0, uap->port.membase + uap->lcrh_tx);
1410ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij	}
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(0, uap->port.membase + UART01x_DR);
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1415d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu	/* restore RTS and DTR */
1416d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu	cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR);
1417d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu	cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(cr, uap->port.membase + UART011_CR);
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14205063e2c567ee569cccfc01ebf80c898cb4e6833aRussell King	/* Clear pending error interrupts */
14215063e2c567ee569cccfc01ebf80c898cb4e6833aRussell King	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS,
14225063e2c567ee569cccfc01ebf80c898cb4e6833aRussell King	       uap->port.membase + UART011_ICR);
14235063e2c567ee569cccfc01ebf80c898cb4e6833aRussell King
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * initialise the old status of the modem signals
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
142968b65f7305e54b822b2483c60de7d7b017526a92Russell King	/* Startup DMA */
143068b65f7305e54b822b2483c60de7d7b017526a92Russell King	pl011_dma_startup(uap);
143168b65f7305e54b822b2483c60de7d7b017526a92Russell King
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1433ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * Finally, enable interrupts, only timeouts when using DMA
1434ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * if initial RX DMA job failed, start in interrupt mode
1435ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	 * as well.
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&uap->port.lock);
1438ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	uap->im = UART011_RTIM;
1439ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij	if (!pl011_dma_rx_running(uap))
1440ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij		uap->im |= UART011_RXIM;
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(uap->im, uap->port.membase + UART011_IMSC);
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&uap->port.lock);
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1444c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	if (uap->port.dev->platform_data) {
1445c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu		struct amba_pl011_data *plat;
1446c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
1447c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu		plat = uap->port.dev->platform_data;
1448c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu		if (plat->init)
1449c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu			plat->init();
1450c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	}
1451c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_dis:
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clk_disable(uap->clk);
14564b4851c65d926f46e208e4731409022d986a1355Russell King clk_unprep:
14574b4851c65d926f46e208e4731409022d986a1355Russell King	clk_unprepare(uap->clk);
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1462ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleijstatic void pl011_shutdown_channel(struct uart_amba_port *uap,
1463ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij					unsigned int lcrh)
1464ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij{
1465ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij      unsigned long val;
1466ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij
1467ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij      val = readw(uap->port.membase + lcrh);
1468ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij      val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
1469ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij      writew(val, uap->port.membase + lcrh);
1470ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij}
1471ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl011_shutdown(struct uart_port *port)
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_amba_port *uap = (struct uart_amba_port *)port;
1475d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu	unsigned int cr;
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * disable all interrupts
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&uap->port.lock);
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uap->im = 0;
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(uap->im, uap->port.membase + UART011_IMSC);
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(0xffff, uap->port.membase + UART011_ICR);
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&uap->port.lock);
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
148668b65f7305e54b822b2483c60de7d7b017526a92Russell King	pl011_dma_shutdown(uap);
148768b65f7305e54b822b2483c60de7d7b017526a92Russell King
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Free the interrupt
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_irq(uap->port.irq, uap);
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * disable the port
1495d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu	 * disable the port. It should not disable RTS and DTR.
1496d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu	 * Also RTS and DTR state should be preserved to restore
1497d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu	 * it during startup().
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
14993b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent	uap->autorts = false;
1500d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu	cr = readw(uap->port.membase + UART011_CR);
1501d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu	uap->old_cr = cr;
1502d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu	cr &= UART011_CR_RTS | UART011_CR_DTR;
1503d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu	cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
1504d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu	writew(cr, uap->port.membase + UART011_CR);
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * disable break condition and fifos
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1509ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij	pl011_shutdown_channel(uap, uap->lcrh_rx);
1510ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij	if (uap->lcrh_rx != uap->lcrh_tx)
1511ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij		pl011_shutdown_channel(uap, uap->lcrh_tx);
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Shut down the clock producer
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clk_disable(uap->clk);
15174b4851c65d926f46e208e4731409022d986a1355Russell King	clk_unprepare(uap->clk);
1518c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
1519c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	if (uap->port.dev->platform_data) {
1520c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu		struct amba_pl011_data *plat;
1521c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
1522c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu		plat = uap->port.dev->platform_data;
1523c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu		if (plat->exit)
1524c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu			plat->exit();
1525c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	}
1526c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
1530606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Coxpl011_set_termios(struct uart_port *port, struct ktermios *termios,
1531606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox		     struct ktermios *old)
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15333b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent	struct uart_amba_port *uap = (struct uart_amba_port *)port;
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int lcr_h, old_cr;
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
1536c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King	unsigned int baud, quot, clkdiv;
1537c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King
1538c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King	if (uap->vendor->oversampling)
1539c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King		clkdiv = 8;
1540c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King	else
1541c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King		clkdiv = 16;
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Ask the core to calculate the divisor for us.
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1546ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij	baud = uart_get_baud_rate(port, termios, old, 0,
1547c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King				  port->uartclk / clkdiv);
1548ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij
1549ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij	if (baud > port->uartclk/16)
1550ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij		quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
1551ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij	else
1552ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij		quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud);
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (termios->c_cflag & CSIZE) {
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CS5:
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lcr_h = UART01x_LCRH_WLEN_5;
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CS6:
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lcr_h = UART01x_LCRH_WLEN_6;
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CS7:
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lcr_h = UART01x_LCRH_WLEN_7;
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default: // CS8
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lcr_h = UART01x_LCRH_WLEN_8;
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termios->c_cflag & CSTOPB)
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lcr_h |= UART01x_LCRH_STP2;
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termios->c_cflag & PARENB) {
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lcr_h |= UART01x_LCRH_PEN;
15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(termios->c_cflag & PARODD))
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lcr_h |= UART01x_LCRH_EPS;
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1575ffca2b114c6a804d1307781df687e877a373a1c2Russell King	if (uap->fifosize > 1)
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lcr_h |= UART01x_LCRH_FEN;
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&port->lock, flags);
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Update the per-port timeout.
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uart_update_timeout(port, termios->c_cflag, baud);
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1585b63d4f0fb80918ab37b6c0ee1adcd49e05c9994cRussell King	port->read_status_mask = UART011_DR_OE | 255;
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termios->c_iflag & INPCK)
1587b63d4f0fb80918ab37b6c0ee1adcd49e05c9994cRussell King		port->read_status_mask |= UART011_DR_FE | UART011_DR_PE;
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termios->c_iflag & (BRKINT | PARMRK))
1589b63d4f0fb80918ab37b6c0ee1adcd49e05c9994cRussell King		port->read_status_mask |= UART011_DR_BE;
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Characters to ignore
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->ignore_status_mask = 0;
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termios->c_iflag & IGNPAR)
1596b63d4f0fb80918ab37b6c0ee1adcd49e05c9994cRussell King		port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE;
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termios->c_iflag & IGNBRK) {
1598b63d4f0fb80918ab37b6c0ee1adcd49e05c9994cRussell King		port->ignore_status_mask |= UART011_DR_BE;
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * If we're ignoring parity and break indicators,
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * ignore overruns too (for real raw support).
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (termios->c_iflag & IGNPAR)
1604b63d4f0fb80918ab37b6c0ee1adcd49e05c9994cRussell King			port->ignore_status_mask |= UART011_DR_OE;
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Ignore all characters if CREAD is not set.
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((termios->c_cflag & CREAD) == 0)
1611b63d4f0fb80918ab37b6c0ee1adcd49e05c9994cRussell King		port->ignore_status_mask |= UART_DUMMY_DR_RX;
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (UART_ENABLE_MS(port, termios->c_cflag))
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pl011_enable_ms(port);
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* first, disable everything */
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	old_cr = readw(port->membase + UART011_CR);
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(0, port->membase + UART011_CR);
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16203b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent	if (termios->c_cflag & CRTSCTS) {
16213b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent		if (old_cr & UART011_CR_RTS)
16223b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent			old_cr |= UART011_CR_RTSEN;
16233b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent
16243b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent		old_cr |= UART011_CR_CTSEN;
16253b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent		uap->autorts = true;
16263b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent	} else {
16273b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent		old_cr &= ~(UART011_CR_CTSEN | UART011_CR_RTSEN);
16283b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent		uap->autorts = false;
16293b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent	}
16303b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent
1631c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King	if (uap->vendor->oversampling) {
1632c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King		if (baud > port->uartclk / 16)
1633ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij			old_cr |= ST_UART011_CR_OVSFACT;
1634ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij		else
1635ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij			old_cr &= ~ST_UART011_CR_OVSFACT;
1636ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij	}
1637ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set baud rate */
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(quot & 0x3f, port->membase + UART011_FBRD);
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(quot >> 6, port->membase + UART011_IBRD);
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * ----------v----------v----------v----------v-----
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * ----------^----------^----------^----------^-----
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1647ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij	writew(lcr_h, port->membase + uap->lcrh_rx);
1648ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij	if (uap->lcrh_rx != uap->lcrh_tx) {
1649ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij		int i;
1650ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij		/*
1651ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij		 * Wait 10 PCLKs before writing LCRH_TX register,
1652ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij		 * to get this delay write read only register 10 times
1653ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij		 */
1654ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij		for (i = 0; i < 10; ++i)
1655ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij			writew(0xff, uap->port.membase + UART011_MIS);
1656ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij		writew(lcr_h, port->membase + uap->lcrh_tx);
1657ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij	}
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(old_cr, port->membase + UART011_CR);
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&port->lock, flags);
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *pl011_type(struct uart_port *port)
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1665e8a7ba86ff993311f8712e5b3bb2e3892e82df5fRussell King	struct uart_amba_port *uap = (struct uart_amba_port *)port;
1666e8a7ba86ff993311f8712e5b3bb2e3892e82df5fRussell King	return uap->port.type == PORT_AMBA ? uap->type : NULL;
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Release the memory region(s) being used by 'port'
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl010_release_port(struct uart_port *port)
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_mem_region(port->mapbase, SZ_4K);
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Request the memory region(s) being used by 'port'
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl010_request_port(struct uart_port *port)
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return request_mem_region(port->mapbase, SZ_4K, "uart-pl011")
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			!= NULL ? 0 : -EBUSY;
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Configure/autoconfigure the port.
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl010_config_port(struct uart_port *port, int flags)
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (flags & UART_CONFIG_TYPE) {
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->type = PORT_AMBA;
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pl010_request_port(port);
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * verify the new serial_struct (for TIOCSSERIAL).
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EINVAL;
1705a62c41337356989387d15020dc0f0288aaacfa44Yinghai Lu	if (ser->irq < 0 || ser->irq >= nr_irqs)
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EINVAL;
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ser->baud_base < 9600)
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EINVAL;
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct uart_ops amba_pl011_pops = {
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.tx_empty	= pl01x_tx_empty,
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_mctrl	= pl011_set_mctrl,
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_mctrl	= pl01x_get_mctrl,
17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop_tx	= pl011_stop_tx,
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.start_tx	= pl011_start_tx,
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop_rx	= pl011_stop_rx,
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.enable_ms	= pl011_enable_ms,
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.break_ctl	= pl011_break_ctl,
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.startup	= pl011_startup,
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.shutdown	= pl011_shutdown,
172368b65f7305e54b822b2483c60de7d7b017526a92Russell King	.flush_buffer	= pl011_dma_flush_buffer,
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_termios	= pl011_set_termios,
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.type		= pl011_type,
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release_port	= pl010_release_port,
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.request_port	= pl010_request_port,
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.config_port	= pl010_config_port,
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.verify_port	= pl010_verify_port,
173084b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel#ifdef CONFIG_CONSOLE_POLL
173184b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel	.poll_get_char = pl010_get_poll_char,
173284b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel	.poll_put_char = pl010_put_poll_char,
173384b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel#endif
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct uart_amba_port *amba_ports[UART_NR];
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1740d358788f3f30113e49882187d794832905e42592Russell Kingstatic void pl011_console_putchar(struct uart_port *port, int ch)
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1742d358788f3f30113e49882187d794832905e42592Russell King	struct uart_amba_port *uap = (struct uart_amba_port *)port;
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1744d358788f3f30113e49882187d794832905e42592Russell King	while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
1745d358788f3f30113e49882187d794832905e42592Russell King		barrier();
17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(ch, uap->port.membase + UART01x_DR);
17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldspl011_console_write(struct console *co, const char *s, unsigned int count)
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_amba_port *uap = amba_ports[co->index];
17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status, old_cr, new_cr;
1754ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent	unsigned long flags;
1755ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent	int locked = 1;
17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clk_enable(uap->clk);
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1759ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent	local_irq_save(flags);
1760ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent	if (uap->port.sysrq)
1761ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent		locked = 0;
1762ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent	else if (oops_in_progress)
1763ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent		locked = spin_trylock(&uap->port.lock);
1764ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent	else
1765ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent		spin_lock(&uap->port.lock);
1766ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *	First save the CR then disable the interrupts
17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	old_cr = readw(uap->port.membase + UART011_CR);
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_cr = old_cr & ~UART011_CR_CTSEN;
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(new_cr, uap->port.membase + UART011_CR);
17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1775d358788f3f30113e49882187d794832905e42592Russell King	uart_console_write(&uap->port, s, count, pl011_console_putchar);
17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *	Finally, wait for transmitter to become empty
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *	and restore the TCR
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = readw(uap->port.membase + UART01x_FR);
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (status & UART01x_FR_BUSY);
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writew(old_cr, uap->port.membase + UART011_CR);
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1786ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent	if (locked)
1787ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent		spin_unlock(&uap->port.lock);
1788ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent	local_irq_restore(flags);
1789ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clk_disable(uap->clk);
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __init
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldspl011_console_get_options(struct uart_amba_port *uap, int *baud,
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     int *parity, int *bits)
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) {
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int lcr_h, ibrd, fbrd;
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1800ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij		lcr_h = readw(uap->port.membase + uap->lcrh_tx);
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*parity = 'n';
18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (lcr_h & UART01x_LCRH_PEN) {
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (lcr_h & UART01x_LCRH_EPS)
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				*parity = 'e';
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				*parity = 'o';
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*bits = 7;
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*bits = 8;
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ibrd = readw(uap->port.membase + UART011_IBRD);
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fbrd = readw(uap->port.membase + UART011_FBRD);
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
1819ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij
1820c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King		if (uap->vendor->oversampling) {
1821ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij			if (readw(uap->port.membase + UART011_CR)
1822ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij				  & ST_UART011_CR_OVSFACT)
1823ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij				*baud *= 2;
1824ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij		}
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init pl011_console_setup(struct console *co, char *options)
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_amba_port *uap;
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int baud = 38400;
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bits = 8;
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int parity = 'n';
18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int flow = 'n';
18354b4851c65d926f46e208e4731409022d986a1355Russell King	int ret;
18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Check whether an invalid uart number has been specified, and
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * if so, search for the first available port that does have
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * console support.
18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (co->index >= UART_NR)
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		co->index = 0;
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uap = amba_ports[co->index];
1845d28122a5877cc40350fa801353fd5a9350563ec3Russell King	if (!uap)
1846d28122a5877cc40350fa801353fd5a9350563ec3Russell King		return -ENODEV;
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18484b4851c65d926f46e208e4731409022d986a1355Russell King	ret = clk_prepare(uap->clk);
18494b4851c65d926f46e208e4731409022d986a1355Russell King	if (ret)
18504b4851c65d926f46e208e4731409022d986a1355Russell King		return ret;
18514b4851c65d926f46e208e4731409022d986a1355Russell King
1852c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	if (uap->port.dev->platform_data) {
1853c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu		struct amba_pl011_data *plat;
1854c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
1855c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu		plat = uap->port.dev->platform_data;
1856c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu		if (plat->init)
1857c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu			plat->init();
1858c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	}
1859c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uap->port.uartclk = clk_get_rate(uap->clk);
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (options)
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uart_parse_options(options, &baud, &parity, &bits, &flow);
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pl011_console_get_options(uap, &baud, &parity, &bits);
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return uart_set_options(&uap->port, co, baud, parity, bits, flow);
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18702d93486c6c110cf81db720359b4ec20de9c91450Vincent Sandersstatic struct uart_driver amba_reg;
18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct console amba_console = {
18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name		= "ttyAMA",
18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write		= pl011_console_write,
18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.device		= uart_console_device,
18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.setup		= pl011_console_setup,
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.flags		= CON_PRINTBUFFER,
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.index		= -1,
18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.data		= &amba_reg,
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AMBA_CONSOLE	(&amba_console)
18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AMBA_CONSOLE	NULL
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct uart_driver amba_reg = {
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner			= THIS_MODULE,
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.driver_name		= "ttyAMA",
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dev_name		= "ttyAMA",
18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.major			= SERIAL_AMBA_MAJOR,
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.minor			= SERIAL_AMBA_MINOR,
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.nr			= UART_NR,
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.cons			= AMBA_CONSOLE,
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1896aa25afad2ca60d19457849ea75e9c31236f4e174Russell Kingstatic int pl011_probe(struct amba_device *dev, const struct amba_id *id)
18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_amba_port *uap;
18995926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini	struct vendor_data *vendor = id->data;
19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *base;
19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, ret;
19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (amba_ports[i] == NULL)
19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i == ARRAY_SIZE(amba_ports)) {
19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EBUSY;
19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1912dd00cc486ab1c17049a535413d1751ef3482141cYoann Padioleau	uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (uap == NULL) {
19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOMEM;
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1918dc890c2dcd63a90de68ee5f0253eefbb89d725f0Linus Walleij	base = ioremap(dev->res.start, resource_size(&dev->res));
19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!base) {
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOMEM;
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto free;
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1924ee569c43e340202fb0ba427c57b77568a32b9a3aRussell King	uap->clk = clk_get(&dev->dev, NULL);
19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(uap->clk)) {
19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = PTR_ERR(uap->clk);
19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto unmap;
19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1930c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King	uap->vendor = vendor;
1931ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij	uap->lcrh_rx = vendor->lcrh_rx;
1932ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij	uap->lcrh_tx = vendor->lcrh_tx;
1933d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu	uap->old_cr = 0;
1934ffca2b114c6a804d1307781df687e877a373a1c2Russell King	uap->fifosize = vendor->fifosize;
1935c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu	uap->interrupt_may_hang = vendor->interrupt_may_hang;
19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uap->port.dev = &dev->dev;
19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uap->port.mapbase = dev->res.start;
19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uap->port.membase = base;
19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uap->port.iotype = UPIO_MEM;
19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uap->port.irq = dev->irq[0];
1941ffca2b114c6a804d1307781df687e877a373a1c2Russell King	uap->port.fifosize = uap->fifosize;
19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uap->port.ops = &amba_pl011_pops;
19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uap->port.flags = UPF_BOOT_AUTOCONF;
19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uap->port.line = i;
194568b65f7305e54b822b2483c60de7d7b017526a92Russell King	pl011_dma_probe(uap);
19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1947e8a7ba86ff993311f8712e5b3bb2e3892e82df5fRussell King	snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
1948e8a7ba86ff993311f8712e5b3bb2e3892e82df5fRussell King
19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	amba_ports[i] = uap;
19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	amba_set_drvdata(dev, uap);
19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = uart_add_one_port(&amba_reg, &uap->port);
19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret) {
19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		amba_set_drvdata(dev, NULL);
19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		amba_ports[i] = NULL;
195668b65f7305e54b822b2483c60de7d7b017526a92Russell King		pl011_dma_remove(uap);
19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		clk_put(uap->clk);
19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unmap:
19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iounmap(base);
19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free:
19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(uap);
19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl011_remove(struct amba_device *dev)
19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_amba_port *uap = amba_get_drvdata(dev);
19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	amba_set_drvdata(dev, NULL);
19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uart_remove_one_port(&amba_reg, &uap->port);
19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (amba_ports[i] == uap)
19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			amba_ports[i] = NULL;
19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
198068b65f7305e54b822b2483c60de7d7b017526a92Russell King	pl011_dma_remove(uap);
19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iounmap(uap->port.membase);
19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clk_put(uap->clk);
19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(uap);
19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1987b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen#ifdef CONFIG_PM
1988b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chenstatic int pl011_suspend(struct amba_device *dev, pm_message_t state)
1989b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen{
1990b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen	struct uart_amba_port *uap = amba_get_drvdata(dev);
1991b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen
1992b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen	if (!uap)
1993b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen		return -EINVAL;
1994b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen
1995b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen	return uart_suspend_port(&amba_reg, &uap->port);
1996b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen}
1997b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen
1998b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chenstatic int pl011_resume(struct amba_device *dev)
1999b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen{
2000b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen	struct uart_amba_port *uap = amba_get_drvdata(dev);
2001b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen
2002b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen	if (!uap)
2003b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen		return -EINVAL;
2004b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen
2005b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen	return uart_resume_port(&amba_reg, &uap->port);
2006b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen}
2007b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen#endif
2008b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen
20092c39c9e149f45ec15a6985cb06ec8f6d904bb35eRussell Kingstatic struct amba_id pl011_ids[] = {
20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.id	= 0x00041011,
20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.mask	= 0x000fffff,
20135926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini		.data	= &vendor_arm,
20145926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini	},
20155926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini	{
20165926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini		.id	= 0x00380802,
20175926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini		.mask	= 0x00ffffff,
20185926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini		.data	= &vendor_st,
20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0, 0 },
20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
202360f7a33b826148fd96cfa8a9e10b84ef444e78feDave MartinMODULE_DEVICE_TABLE(amba, pl011_ids);
202460f7a33b826148fd96cfa8a9e10b84ef444e78feDave Martin
20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct amba_driver pl011_driver = {
20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.drv = {
20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.name	= "uart-pl011",
20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table	= pl011_ids,
20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe		= pl011_probe,
20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.remove		= pl011_remove,
2032b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen#ifdef CONFIG_PM
2033b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen	.suspend	= pl011_suspend,
2034b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen	.resume		= pl011_resume,
2035b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen#endif
20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init pl011_init(void)
20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "Serial: AMBA PL011 UART driver\n");
20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = uart_register_driver(&amba_reg);
20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret == 0) {
20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = amba_driver_register(&pl011_driver);
20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret)
20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			uart_unregister_driver(&amba_reg);
20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit pl011_exit(void)
20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	amba_driver_unregister(&pl011_driver);
20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uart_unregister_driver(&amba_reg);
20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20584dd9e742df98f8f600b4302d3adbb087a68237f7Alessandro Rubini/*
20594dd9e742df98f8f600b4302d3adbb087a68237f7Alessandro Rubini * While this can be a module, if builtin it's most likely the console
20604dd9e742df98f8f600b4302d3adbb087a68237f7Alessandro Rubini * So let's leave module_exit but move module_init to an earlier place
20614dd9e742df98f8f600b4302d3adbb087a68237f7Alessandro Rubini */
20624dd9e742df98f8f600b4302d3adbb087a68237f7Alessandro Rubiniarch_initcall(pl011_init);
20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(pl011_exit);
20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("ARM AMBA serial port driver");
20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
2068