xref: /OK3568_Linux_fs/kernel/drivers/tty/serial/meson_uart.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  Based on meson_uart.c, by AMLOGIC, INC.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2014 Carlo Caione <carlo@caione.org>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/clk.h>
9*4882a593Smuzhiyun #include <linux/console.h>
10*4882a593Smuzhiyun #include <linux/delay.h>
11*4882a593Smuzhiyun #include <linux/init.h>
12*4882a593Smuzhiyun #include <linux/io.h>
13*4882a593Smuzhiyun #include <linux/iopoll.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/kernel.h>
16*4882a593Smuzhiyun #include <linux/of.h>
17*4882a593Smuzhiyun #include <linux/platform_device.h>
18*4882a593Smuzhiyun #include <linux/serial.h>
19*4882a593Smuzhiyun #include <linux/serial_core.h>
20*4882a593Smuzhiyun #include <linux/tty.h>
21*4882a593Smuzhiyun #include <linux/tty_flip.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun /* Register offsets */
24*4882a593Smuzhiyun #define AML_UART_WFIFO			0x00
25*4882a593Smuzhiyun #define AML_UART_RFIFO			0x04
26*4882a593Smuzhiyun #define AML_UART_CONTROL		0x08
27*4882a593Smuzhiyun #define AML_UART_STATUS			0x0c
28*4882a593Smuzhiyun #define AML_UART_MISC			0x10
29*4882a593Smuzhiyun #define AML_UART_REG5			0x14
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /* AML_UART_CONTROL bits */
32*4882a593Smuzhiyun #define AML_UART_TX_EN			BIT(12)
33*4882a593Smuzhiyun #define AML_UART_RX_EN			BIT(13)
34*4882a593Smuzhiyun #define AML_UART_TWO_WIRE_EN		BIT(15)
35*4882a593Smuzhiyun #define AML_UART_STOP_BIT_LEN_MASK	(0x03 << 16)
36*4882a593Smuzhiyun #define AML_UART_STOP_BIT_1SB		(0x00 << 16)
37*4882a593Smuzhiyun #define AML_UART_STOP_BIT_2SB		(0x01 << 16)
38*4882a593Smuzhiyun #define AML_UART_PARITY_TYPE		BIT(18)
39*4882a593Smuzhiyun #define AML_UART_PARITY_EN		BIT(19)
40*4882a593Smuzhiyun #define AML_UART_TX_RST			BIT(22)
41*4882a593Smuzhiyun #define AML_UART_RX_RST			BIT(23)
42*4882a593Smuzhiyun #define AML_UART_CLEAR_ERR		BIT(24)
43*4882a593Smuzhiyun #define AML_UART_RX_INT_EN		BIT(27)
44*4882a593Smuzhiyun #define AML_UART_TX_INT_EN		BIT(28)
45*4882a593Smuzhiyun #define AML_UART_DATA_LEN_MASK		(0x03 << 20)
46*4882a593Smuzhiyun #define AML_UART_DATA_LEN_8BIT		(0x00 << 20)
47*4882a593Smuzhiyun #define AML_UART_DATA_LEN_7BIT		(0x01 << 20)
48*4882a593Smuzhiyun #define AML_UART_DATA_LEN_6BIT		(0x02 << 20)
49*4882a593Smuzhiyun #define AML_UART_DATA_LEN_5BIT		(0x03 << 20)
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun /* AML_UART_STATUS bits */
52*4882a593Smuzhiyun #define AML_UART_PARITY_ERR		BIT(16)
53*4882a593Smuzhiyun #define AML_UART_FRAME_ERR		BIT(17)
54*4882a593Smuzhiyun #define AML_UART_TX_FIFO_WERR		BIT(18)
55*4882a593Smuzhiyun #define AML_UART_RX_EMPTY		BIT(20)
56*4882a593Smuzhiyun #define AML_UART_TX_FULL		BIT(21)
57*4882a593Smuzhiyun #define AML_UART_TX_EMPTY		BIT(22)
58*4882a593Smuzhiyun #define AML_UART_XMIT_BUSY		BIT(25)
59*4882a593Smuzhiyun #define AML_UART_ERR			(AML_UART_PARITY_ERR | \
60*4882a593Smuzhiyun 					 AML_UART_FRAME_ERR  | \
61*4882a593Smuzhiyun 					 AML_UART_TX_FIFO_WERR)
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun /* AML_UART_MISC bits */
64*4882a593Smuzhiyun #define AML_UART_XMIT_IRQ(c)		(((c) & 0xff) << 8)
65*4882a593Smuzhiyun #define AML_UART_RECV_IRQ(c)		((c) & 0xff)
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun /* AML_UART_REG5 bits */
68*4882a593Smuzhiyun #define AML_UART_BAUD_MASK		0x7fffff
69*4882a593Smuzhiyun #define AML_UART_BAUD_USE		BIT(23)
70*4882a593Smuzhiyun #define AML_UART_BAUD_XTAL		BIT(24)
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun #define AML_UART_PORT_NUM		12
73*4882a593Smuzhiyun #define AML_UART_PORT_OFFSET		6
74*4882a593Smuzhiyun #define AML_UART_DEV_NAME		"ttyAML"
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun #define AML_UART_POLL_USEC		5
77*4882a593Smuzhiyun #define AML_UART_TIMEOUT_USEC		10000
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun static struct uart_driver meson_uart_driver;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun static struct uart_port *meson_ports[AML_UART_PORT_NUM];
82*4882a593Smuzhiyun 
meson_uart_set_mctrl(struct uart_port * port,unsigned int mctrl)83*4882a593Smuzhiyun static void meson_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
meson_uart_get_mctrl(struct uart_port * port)87*4882a593Smuzhiyun static unsigned int meson_uart_get_mctrl(struct uart_port *port)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun 	return TIOCM_CTS;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
meson_uart_tx_empty(struct uart_port * port)92*4882a593Smuzhiyun static unsigned int meson_uart_tx_empty(struct uart_port *port)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	u32 val;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	val = readl(port->membase + AML_UART_STATUS);
97*4882a593Smuzhiyun 	val &= (AML_UART_TX_EMPTY | AML_UART_XMIT_BUSY);
98*4882a593Smuzhiyun 	return (val == AML_UART_TX_EMPTY) ? TIOCSER_TEMT : 0;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun 
meson_uart_stop_tx(struct uart_port * port)101*4882a593Smuzhiyun static void meson_uart_stop_tx(struct uart_port *port)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun 	u32 val;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	val = readl(port->membase + AML_UART_CONTROL);
106*4882a593Smuzhiyun 	val &= ~AML_UART_TX_INT_EN;
107*4882a593Smuzhiyun 	writel(val, port->membase + AML_UART_CONTROL);
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun 
meson_uart_stop_rx(struct uart_port * port)110*4882a593Smuzhiyun static void meson_uart_stop_rx(struct uart_port *port)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun 	u32 val;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	val = readl(port->membase + AML_UART_CONTROL);
115*4882a593Smuzhiyun 	val &= ~AML_UART_RX_EN;
116*4882a593Smuzhiyun 	writel(val, port->membase + AML_UART_CONTROL);
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
meson_uart_shutdown(struct uart_port * port)119*4882a593Smuzhiyun static void meson_uart_shutdown(struct uart_port *port)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun 	unsigned long flags;
122*4882a593Smuzhiyun 	u32 val;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	free_irq(port->irq, port);
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	spin_lock_irqsave(&port->lock, flags);
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	val = readl(port->membase + AML_UART_CONTROL);
129*4882a593Smuzhiyun 	val &= ~AML_UART_RX_EN;
130*4882a593Smuzhiyun 	val &= ~(AML_UART_RX_INT_EN | AML_UART_TX_INT_EN);
131*4882a593Smuzhiyun 	writel(val, port->membase + AML_UART_CONTROL);
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	spin_unlock_irqrestore(&port->lock, flags);
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
meson_uart_start_tx(struct uart_port * port)136*4882a593Smuzhiyun static void meson_uart_start_tx(struct uart_port *port)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	struct circ_buf *xmit = &port->state->xmit;
139*4882a593Smuzhiyun 	unsigned int ch;
140*4882a593Smuzhiyun 	u32 val;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	if (uart_tx_stopped(port)) {
143*4882a593Smuzhiyun 		meson_uart_stop_tx(port);
144*4882a593Smuzhiyun 		return;
145*4882a593Smuzhiyun 	}
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	while (!(readl(port->membase + AML_UART_STATUS) & AML_UART_TX_FULL)) {
148*4882a593Smuzhiyun 		if (port->x_char) {
149*4882a593Smuzhiyun 			writel(port->x_char, port->membase + AML_UART_WFIFO);
150*4882a593Smuzhiyun 			port->icount.tx++;
151*4882a593Smuzhiyun 			port->x_char = 0;
152*4882a593Smuzhiyun 			continue;
153*4882a593Smuzhiyun 		}
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 		if (uart_circ_empty(xmit))
156*4882a593Smuzhiyun 			break;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 		ch = xmit->buf[xmit->tail];
159*4882a593Smuzhiyun 		writel(ch, port->membase + AML_UART_WFIFO);
160*4882a593Smuzhiyun 		xmit->tail = (xmit->tail+1) & (SERIAL_XMIT_SIZE - 1);
161*4882a593Smuzhiyun 		port->icount.tx++;
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (!uart_circ_empty(xmit)) {
165*4882a593Smuzhiyun 		val = readl(port->membase + AML_UART_CONTROL);
166*4882a593Smuzhiyun 		val |= AML_UART_TX_INT_EN;
167*4882a593Smuzhiyun 		writel(val, port->membase + AML_UART_CONTROL);
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
171*4882a593Smuzhiyun 		uart_write_wakeup(port);
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun 
meson_receive_chars(struct uart_port * port)174*4882a593Smuzhiyun static void meson_receive_chars(struct uart_port *port)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun 	struct tty_port *tport = &port->state->port;
177*4882a593Smuzhiyun 	char flag;
178*4882a593Smuzhiyun 	u32 ostatus, status, ch, mode;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	do {
181*4882a593Smuzhiyun 		flag = TTY_NORMAL;
182*4882a593Smuzhiyun 		port->icount.rx++;
183*4882a593Smuzhiyun 		ostatus = status = readl(port->membase + AML_UART_STATUS);
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 		if (status & AML_UART_ERR) {
186*4882a593Smuzhiyun 			if (status & AML_UART_TX_FIFO_WERR)
187*4882a593Smuzhiyun 				port->icount.overrun++;
188*4882a593Smuzhiyun 			else if (status & AML_UART_FRAME_ERR)
189*4882a593Smuzhiyun 				port->icount.frame++;
190*4882a593Smuzhiyun 			else if (status & AML_UART_PARITY_ERR)
191*4882a593Smuzhiyun 				port->icount.frame++;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 			mode = readl(port->membase + AML_UART_CONTROL);
194*4882a593Smuzhiyun 			mode |= AML_UART_CLEAR_ERR;
195*4882a593Smuzhiyun 			writel(mode, port->membase + AML_UART_CONTROL);
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 			/* It doesn't clear to 0 automatically */
198*4882a593Smuzhiyun 			mode &= ~AML_UART_CLEAR_ERR;
199*4882a593Smuzhiyun 			writel(mode, port->membase + AML_UART_CONTROL);
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 			status &= port->read_status_mask;
202*4882a593Smuzhiyun 			if (status & AML_UART_FRAME_ERR)
203*4882a593Smuzhiyun 				flag = TTY_FRAME;
204*4882a593Smuzhiyun 			else if (status & AML_UART_PARITY_ERR)
205*4882a593Smuzhiyun 				flag = TTY_PARITY;
206*4882a593Smuzhiyun 		}
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 		ch = readl(port->membase + AML_UART_RFIFO);
209*4882a593Smuzhiyun 		ch &= 0xff;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 		if ((ostatus & AML_UART_FRAME_ERR) && (ch == 0)) {
212*4882a593Smuzhiyun 			port->icount.brk++;
213*4882a593Smuzhiyun 			flag = TTY_BREAK;
214*4882a593Smuzhiyun 			if (uart_handle_break(port))
215*4882a593Smuzhiyun 				continue;
216*4882a593Smuzhiyun 		}
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 		if (uart_handle_sysrq_char(port, ch))
219*4882a593Smuzhiyun 			continue;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 		if ((status & port->ignore_status_mask) == 0)
222*4882a593Smuzhiyun 			tty_insert_flip_char(tport, ch, flag);
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 		if (status & AML_UART_TX_FIFO_WERR)
225*4882a593Smuzhiyun 			tty_insert_flip_char(tport, 0, TTY_OVERRUN);
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	} while (!(readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY));
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	spin_unlock(&port->lock);
230*4882a593Smuzhiyun 	tty_flip_buffer_push(tport);
231*4882a593Smuzhiyun 	spin_lock(&port->lock);
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
meson_uart_interrupt(int irq,void * dev_id)234*4882a593Smuzhiyun static irqreturn_t meson_uart_interrupt(int irq, void *dev_id)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun 	struct uart_port *port = (struct uart_port *)dev_id;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	spin_lock(&port->lock);
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	if (!(readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY))
241*4882a593Smuzhiyun 		meson_receive_chars(port);
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	if (!(readl(port->membase + AML_UART_STATUS) & AML_UART_TX_FULL)) {
244*4882a593Smuzhiyun 		if (readl(port->membase + AML_UART_CONTROL) & AML_UART_TX_INT_EN)
245*4882a593Smuzhiyun 			meson_uart_start_tx(port);
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	spin_unlock(&port->lock);
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	return IRQ_HANDLED;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun 
meson_uart_type(struct uart_port * port)253*4882a593Smuzhiyun static const char *meson_uart_type(struct uart_port *port)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun 	return (port->type == PORT_MESON) ? "meson_uart" : NULL;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun /*
259*4882a593Smuzhiyun  * This function is called only from probe() using a temporary io mapping
260*4882a593Smuzhiyun  * in order to perform a reset before setting up the device. Since the
261*4882a593Smuzhiyun  * temporarily mapped region was successfully requested, there can be no
262*4882a593Smuzhiyun  * console on this port at this time. Hence it is not necessary for this
263*4882a593Smuzhiyun  * function to acquire the port->lock. (Since there is no console on this
264*4882a593Smuzhiyun  * port at this time, the port->lock is not initialized yet.)
265*4882a593Smuzhiyun  */
meson_uart_reset(struct uart_port * port)266*4882a593Smuzhiyun static void meson_uart_reset(struct uart_port *port)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun 	u32 val;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	val = readl(port->membase + AML_UART_CONTROL);
271*4882a593Smuzhiyun 	val |= (AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLEAR_ERR);
272*4882a593Smuzhiyun 	writel(val, port->membase + AML_UART_CONTROL);
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	val &= ~(AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLEAR_ERR);
275*4882a593Smuzhiyun 	writel(val, port->membase + AML_UART_CONTROL);
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
meson_uart_startup(struct uart_port * port)278*4882a593Smuzhiyun static int meson_uart_startup(struct uart_port *port)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun 	unsigned long flags;
281*4882a593Smuzhiyun 	u32 val;
282*4882a593Smuzhiyun 	int ret = 0;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	spin_lock_irqsave(&port->lock, flags);
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	val = readl(port->membase + AML_UART_CONTROL);
287*4882a593Smuzhiyun 	val |= AML_UART_CLEAR_ERR;
288*4882a593Smuzhiyun 	writel(val, port->membase + AML_UART_CONTROL);
289*4882a593Smuzhiyun 	val &= ~AML_UART_CLEAR_ERR;
290*4882a593Smuzhiyun 	writel(val, port->membase + AML_UART_CONTROL);
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	val |= (AML_UART_RX_EN | AML_UART_TX_EN);
293*4882a593Smuzhiyun 	writel(val, port->membase + AML_UART_CONTROL);
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	val |= (AML_UART_RX_INT_EN | AML_UART_TX_INT_EN);
296*4882a593Smuzhiyun 	writel(val, port->membase + AML_UART_CONTROL);
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	val = (AML_UART_RECV_IRQ(1) | AML_UART_XMIT_IRQ(port->fifosize / 2));
299*4882a593Smuzhiyun 	writel(val, port->membase + AML_UART_MISC);
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	spin_unlock_irqrestore(&port->lock, flags);
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	ret = request_irq(port->irq, meson_uart_interrupt, 0,
304*4882a593Smuzhiyun 			  port->name, port);
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	return ret;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun 
meson_uart_change_speed(struct uart_port * port,unsigned long baud)309*4882a593Smuzhiyun static void meson_uart_change_speed(struct uart_port *port, unsigned long baud)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun 	u32 val;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	while (!meson_uart_tx_empty(port))
314*4882a593Smuzhiyun 		cpu_relax();
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	if (port->uartclk == 24000000) {
317*4882a593Smuzhiyun 		val = ((port->uartclk / 3) / baud) - 1;
318*4882a593Smuzhiyun 		val |= AML_UART_BAUD_XTAL;
319*4882a593Smuzhiyun 	} else {
320*4882a593Smuzhiyun 		val = ((port->uartclk * 10 / (baud * 4) + 5) / 10) - 1;
321*4882a593Smuzhiyun 	}
322*4882a593Smuzhiyun 	val |= AML_UART_BAUD_USE;
323*4882a593Smuzhiyun 	writel(val, port->membase + AML_UART_REG5);
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun 
meson_uart_set_termios(struct uart_port * port,struct ktermios * termios,struct ktermios * old)326*4882a593Smuzhiyun static void meson_uart_set_termios(struct uart_port *port,
327*4882a593Smuzhiyun 				   struct ktermios *termios,
328*4882a593Smuzhiyun 				   struct ktermios *old)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun 	unsigned int cflags, iflags, baud;
331*4882a593Smuzhiyun 	unsigned long flags;
332*4882a593Smuzhiyun 	u32 val;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	spin_lock_irqsave(&port->lock, flags);
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	cflags = termios->c_cflag;
337*4882a593Smuzhiyun 	iflags = termios->c_iflag;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	val = readl(port->membase + AML_UART_CONTROL);
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	val &= ~AML_UART_DATA_LEN_MASK;
342*4882a593Smuzhiyun 	switch (cflags & CSIZE) {
343*4882a593Smuzhiyun 	case CS8:
344*4882a593Smuzhiyun 		val |= AML_UART_DATA_LEN_8BIT;
345*4882a593Smuzhiyun 		break;
346*4882a593Smuzhiyun 	case CS7:
347*4882a593Smuzhiyun 		val |= AML_UART_DATA_LEN_7BIT;
348*4882a593Smuzhiyun 		break;
349*4882a593Smuzhiyun 	case CS6:
350*4882a593Smuzhiyun 		val |= AML_UART_DATA_LEN_6BIT;
351*4882a593Smuzhiyun 		break;
352*4882a593Smuzhiyun 	case CS5:
353*4882a593Smuzhiyun 		val |= AML_UART_DATA_LEN_5BIT;
354*4882a593Smuzhiyun 		break;
355*4882a593Smuzhiyun 	}
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	if (cflags & PARENB)
358*4882a593Smuzhiyun 		val |= AML_UART_PARITY_EN;
359*4882a593Smuzhiyun 	else
360*4882a593Smuzhiyun 		val &= ~AML_UART_PARITY_EN;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	if (cflags & PARODD)
363*4882a593Smuzhiyun 		val |= AML_UART_PARITY_TYPE;
364*4882a593Smuzhiyun 	else
365*4882a593Smuzhiyun 		val &= ~AML_UART_PARITY_TYPE;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	val &= ~AML_UART_STOP_BIT_LEN_MASK;
368*4882a593Smuzhiyun 	if (cflags & CSTOPB)
369*4882a593Smuzhiyun 		val |= AML_UART_STOP_BIT_2SB;
370*4882a593Smuzhiyun 	else
371*4882a593Smuzhiyun 		val |= AML_UART_STOP_BIT_1SB;
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	if (cflags & CRTSCTS)
374*4882a593Smuzhiyun 		val &= ~AML_UART_TWO_WIRE_EN;
375*4882a593Smuzhiyun 	else
376*4882a593Smuzhiyun 		val |= AML_UART_TWO_WIRE_EN;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	writel(val, port->membase + AML_UART_CONTROL);
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	baud = uart_get_baud_rate(port, termios, old, 50, 4000000);
381*4882a593Smuzhiyun 	meson_uart_change_speed(port, baud);
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	port->read_status_mask = AML_UART_TX_FIFO_WERR;
384*4882a593Smuzhiyun 	if (iflags & INPCK)
385*4882a593Smuzhiyun 		port->read_status_mask |= AML_UART_PARITY_ERR |
386*4882a593Smuzhiyun 					  AML_UART_FRAME_ERR;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	port->ignore_status_mask = 0;
389*4882a593Smuzhiyun 	if (iflags & IGNPAR)
390*4882a593Smuzhiyun 		port->ignore_status_mask |= AML_UART_PARITY_ERR |
391*4882a593Smuzhiyun 					    AML_UART_FRAME_ERR;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	uart_update_timeout(port, termios->c_cflag, baud);
394*4882a593Smuzhiyun 	spin_unlock_irqrestore(&port->lock, flags);
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun 
meson_uart_verify_port(struct uart_port * port,struct serial_struct * ser)397*4882a593Smuzhiyun static int meson_uart_verify_port(struct uart_port *port,
398*4882a593Smuzhiyun 				  struct serial_struct *ser)
399*4882a593Smuzhiyun {
400*4882a593Smuzhiyun 	int ret = 0;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	if (port->type != PORT_MESON)
403*4882a593Smuzhiyun 		ret = -EINVAL;
404*4882a593Smuzhiyun 	if (port->irq != ser->irq)
405*4882a593Smuzhiyun 		ret = -EINVAL;
406*4882a593Smuzhiyun 	if (ser->baud_base < 9600)
407*4882a593Smuzhiyun 		ret = -EINVAL;
408*4882a593Smuzhiyun 	return ret;
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun 
meson_uart_release_port(struct uart_port * port)411*4882a593Smuzhiyun static void meson_uart_release_port(struct uart_port *port)
412*4882a593Smuzhiyun {
413*4882a593Smuzhiyun 	devm_iounmap(port->dev, port->membase);
414*4882a593Smuzhiyun 	port->membase = NULL;
415*4882a593Smuzhiyun 	devm_release_mem_region(port->dev, port->mapbase, port->mapsize);
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun 
meson_uart_request_port(struct uart_port * port)418*4882a593Smuzhiyun static int meson_uart_request_port(struct uart_port *port)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun 	if (!devm_request_mem_region(port->dev, port->mapbase, port->mapsize,
421*4882a593Smuzhiyun 				     dev_name(port->dev))) {
422*4882a593Smuzhiyun 		dev_err(port->dev, "Memory region busy\n");
423*4882a593Smuzhiyun 		return -EBUSY;
424*4882a593Smuzhiyun 	}
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	port->membase = devm_ioremap(port->dev, port->mapbase,
427*4882a593Smuzhiyun 					     port->mapsize);
428*4882a593Smuzhiyun 	if (!port->membase)
429*4882a593Smuzhiyun 		return -ENOMEM;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	return 0;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun 
meson_uart_config_port(struct uart_port * port,int flags)434*4882a593Smuzhiyun static void meson_uart_config_port(struct uart_port *port, int flags)
435*4882a593Smuzhiyun {
436*4882a593Smuzhiyun 	if (flags & UART_CONFIG_TYPE) {
437*4882a593Smuzhiyun 		port->type = PORT_MESON;
438*4882a593Smuzhiyun 		meson_uart_request_port(port);
439*4882a593Smuzhiyun 	}
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun #ifdef CONFIG_CONSOLE_POLL
443*4882a593Smuzhiyun /*
444*4882a593Smuzhiyun  * Console polling routines for writing and reading from the uart while
445*4882a593Smuzhiyun  * in an interrupt or debug context (i.e. kgdb).
446*4882a593Smuzhiyun  */
447*4882a593Smuzhiyun 
meson_uart_poll_get_char(struct uart_port * port)448*4882a593Smuzhiyun static int meson_uart_poll_get_char(struct uart_port *port)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun 	u32 c;
451*4882a593Smuzhiyun 	unsigned long flags;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	spin_lock_irqsave(&port->lock, flags);
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	if (readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY)
456*4882a593Smuzhiyun 		c = NO_POLL_CHAR;
457*4882a593Smuzhiyun 	else
458*4882a593Smuzhiyun 		c = readl(port->membase + AML_UART_RFIFO);
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	spin_unlock_irqrestore(&port->lock, flags);
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	return c;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun 
meson_uart_poll_put_char(struct uart_port * port,unsigned char c)465*4882a593Smuzhiyun static void meson_uart_poll_put_char(struct uart_port *port, unsigned char c)
466*4882a593Smuzhiyun {
467*4882a593Smuzhiyun 	unsigned long flags;
468*4882a593Smuzhiyun 	u32 reg;
469*4882a593Smuzhiyun 	int ret;
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	spin_lock_irqsave(&port->lock, flags);
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	/* Wait until FIFO is empty or timeout */
474*4882a593Smuzhiyun 	ret = readl_poll_timeout_atomic(port->membase + AML_UART_STATUS, reg,
475*4882a593Smuzhiyun 					reg & AML_UART_TX_EMPTY,
476*4882a593Smuzhiyun 					AML_UART_POLL_USEC,
477*4882a593Smuzhiyun 					AML_UART_TIMEOUT_USEC);
478*4882a593Smuzhiyun 	if (ret == -ETIMEDOUT) {
479*4882a593Smuzhiyun 		dev_err(port->dev, "Timeout waiting for UART TX EMPTY\n");
480*4882a593Smuzhiyun 		goto out;
481*4882a593Smuzhiyun 	}
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	/* Write the character */
484*4882a593Smuzhiyun 	writel(c, port->membase + AML_UART_WFIFO);
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	/* Wait until FIFO is empty or timeout */
487*4882a593Smuzhiyun 	ret = readl_poll_timeout_atomic(port->membase + AML_UART_STATUS, reg,
488*4882a593Smuzhiyun 					reg & AML_UART_TX_EMPTY,
489*4882a593Smuzhiyun 					AML_UART_POLL_USEC,
490*4882a593Smuzhiyun 					AML_UART_TIMEOUT_USEC);
491*4882a593Smuzhiyun 	if (ret == -ETIMEDOUT)
492*4882a593Smuzhiyun 		dev_err(port->dev, "Timeout waiting for UART TX EMPTY\n");
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun out:
495*4882a593Smuzhiyun 	spin_unlock_irqrestore(&port->lock, flags);
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun #endif /* CONFIG_CONSOLE_POLL */
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun static const struct uart_ops meson_uart_ops = {
501*4882a593Smuzhiyun 	.set_mctrl      = meson_uart_set_mctrl,
502*4882a593Smuzhiyun 	.get_mctrl      = meson_uart_get_mctrl,
503*4882a593Smuzhiyun 	.tx_empty	= meson_uart_tx_empty,
504*4882a593Smuzhiyun 	.start_tx	= meson_uart_start_tx,
505*4882a593Smuzhiyun 	.stop_tx	= meson_uart_stop_tx,
506*4882a593Smuzhiyun 	.stop_rx	= meson_uart_stop_rx,
507*4882a593Smuzhiyun 	.startup	= meson_uart_startup,
508*4882a593Smuzhiyun 	.shutdown	= meson_uart_shutdown,
509*4882a593Smuzhiyun 	.set_termios	= meson_uart_set_termios,
510*4882a593Smuzhiyun 	.type		= meson_uart_type,
511*4882a593Smuzhiyun 	.config_port	= meson_uart_config_port,
512*4882a593Smuzhiyun 	.request_port	= meson_uart_request_port,
513*4882a593Smuzhiyun 	.release_port	= meson_uart_release_port,
514*4882a593Smuzhiyun 	.verify_port	= meson_uart_verify_port,
515*4882a593Smuzhiyun #ifdef CONFIG_CONSOLE_POLL
516*4882a593Smuzhiyun 	.poll_get_char	= meson_uart_poll_get_char,
517*4882a593Smuzhiyun 	.poll_put_char	= meson_uart_poll_put_char,
518*4882a593Smuzhiyun #endif
519*4882a593Smuzhiyun };
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun #ifdef CONFIG_SERIAL_MESON_CONSOLE
meson_uart_enable_tx_engine(struct uart_port * port)522*4882a593Smuzhiyun static void meson_uart_enable_tx_engine(struct uart_port *port)
523*4882a593Smuzhiyun {
524*4882a593Smuzhiyun 	u32 val;
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	val = readl(port->membase + AML_UART_CONTROL);
527*4882a593Smuzhiyun 	val |= AML_UART_TX_EN;
528*4882a593Smuzhiyun 	writel(val, port->membase + AML_UART_CONTROL);
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun 
meson_console_putchar(struct uart_port * port,int ch)531*4882a593Smuzhiyun static void meson_console_putchar(struct uart_port *port, int ch)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun 	if (!port->membase)
534*4882a593Smuzhiyun 		return;
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	while (readl(port->membase + AML_UART_STATUS) & AML_UART_TX_FULL)
537*4882a593Smuzhiyun 		cpu_relax();
538*4882a593Smuzhiyun 	writel(ch, port->membase + AML_UART_WFIFO);
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun 
meson_serial_port_write(struct uart_port * port,const char * s,u_int count)541*4882a593Smuzhiyun static void meson_serial_port_write(struct uart_port *port, const char *s,
542*4882a593Smuzhiyun 				    u_int count)
543*4882a593Smuzhiyun {
544*4882a593Smuzhiyun 	unsigned long flags;
545*4882a593Smuzhiyun 	int locked;
546*4882a593Smuzhiyun 	u32 val, tmp;
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	local_irq_save(flags);
549*4882a593Smuzhiyun 	if (port->sysrq) {
550*4882a593Smuzhiyun 		locked = 0;
551*4882a593Smuzhiyun 	} else if (oops_in_progress) {
552*4882a593Smuzhiyun 		locked = spin_trylock(&port->lock);
553*4882a593Smuzhiyun 	} else {
554*4882a593Smuzhiyun 		spin_lock(&port->lock);
555*4882a593Smuzhiyun 		locked = 1;
556*4882a593Smuzhiyun 	}
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 	val = readl(port->membase + AML_UART_CONTROL);
559*4882a593Smuzhiyun 	tmp = val & ~(AML_UART_TX_INT_EN | AML_UART_RX_INT_EN);
560*4882a593Smuzhiyun 	writel(tmp, port->membase + AML_UART_CONTROL);
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	uart_console_write(port, s, count, meson_console_putchar);
563*4882a593Smuzhiyun 	writel(val, port->membase + AML_UART_CONTROL);
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	if (locked)
566*4882a593Smuzhiyun 		spin_unlock(&port->lock);
567*4882a593Smuzhiyun 	local_irq_restore(flags);
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun 
meson_serial_console_write(struct console * co,const char * s,u_int count)570*4882a593Smuzhiyun static void meson_serial_console_write(struct console *co, const char *s,
571*4882a593Smuzhiyun 				       u_int count)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun 	struct uart_port *port;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	port = meson_ports[co->index];
576*4882a593Smuzhiyun 	if (!port)
577*4882a593Smuzhiyun 		return;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	meson_serial_port_write(port, s, count);
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun 
meson_serial_console_setup(struct console * co,char * options)582*4882a593Smuzhiyun static int meson_serial_console_setup(struct console *co, char *options)
583*4882a593Smuzhiyun {
584*4882a593Smuzhiyun 	struct uart_port *port;
585*4882a593Smuzhiyun 	int baud = 115200;
586*4882a593Smuzhiyun 	int bits = 8;
587*4882a593Smuzhiyun 	int parity = 'n';
588*4882a593Smuzhiyun 	int flow = 'n';
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	if (co->index < 0 || co->index >= AML_UART_PORT_NUM)
591*4882a593Smuzhiyun 		return -EINVAL;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	port = meson_ports[co->index];
594*4882a593Smuzhiyun 	if (!port || !port->membase)
595*4882a593Smuzhiyun 		return -ENODEV;
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	meson_uart_enable_tx_engine(port);
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	if (options)
600*4882a593Smuzhiyun 		uart_parse_options(options, &baud, &parity, &bits, &flow);
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	return uart_set_options(port, co, baud, parity, bits, flow);
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun static struct console meson_serial_console = {
606*4882a593Smuzhiyun 	.name		= AML_UART_DEV_NAME,
607*4882a593Smuzhiyun 	.write		= meson_serial_console_write,
608*4882a593Smuzhiyun 	.device		= uart_console_device,
609*4882a593Smuzhiyun 	.setup		= meson_serial_console_setup,
610*4882a593Smuzhiyun 	.flags		= CON_PRINTBUFFER,
611*4882a593Smuzhiyun 	.index		= -1,
612*4882a593Smuzhiyun 	.data		= &meson_uart_driver,
613*4882a593Smuzhiyun };
614*4882a593Smuzhiyun 
meson_serial_console_init(void)615*4882a593Smuzhiyun static int __init meson_serial_console_init(void)
616*4882a593Smuzhiyun {
617*4882a593Smuzhiyun 	register_console(&meson_serial_console);
618*4882a593Smuzhiyun 	return 0;
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun 
meson_serial_early_console_write(struct console * co,const char * s,u_int count)621*4882a593Smuzhiyun static void meson_serial_early_console_write(struct console *co,
622*4882a593Smuzhiyun 					     const char *s,
623*4882a593Smuzhiyun 					     u_int count)
624*4882a593Smuzhiyun {
625*4882a593Smuzhiyun 	struct earlycon_device *dev = co->data;
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun 	meson_serial_port_write(&dev->port, s, count);
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun static int __init
meson_serial_early_console_setup(struct earlycon_device * device,const char * opt)631*4882a593Smuzhiyun meson_serial_early_console_setup(struct earlycon_device *device, const char *opt)
632*4882a593Smuzhiyun {
633*4882a593Smuzhiyun 	if (!device->port.membase)
634*4882a593Smuzhiyun 		return -ENODEV;
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	meson_uart_enable_tx_engine(&device->port);
637*4882a593Smuzhiyun 	device->con->write = meson_serial_early_console_write;
638*4882a593Smuzhiyun 	return 0;
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun /* Legacy bindings, should be removed when no more used */
641*4882a593Smuzhiyun OF_EARLYCON_DECLARE(meson, "amlogic,meson-uart",
642*4882a593Smuzhiyun 		    meson_serial_early_console_setup);
643*4882a593Smuzhiyun /* Stable bindings */
644*4882a593Smuzhiyun OF_EARLYCON_DECLARE(meson, "amlogic,meson-ao-uart",
645*4882a593Smuzhiyun 		    meson_serial_early_console_setup);
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun #define MESON_SERIAL_CONSOLE	(&meson_serial_console)
648*4882a593Smuzhiyun #else
meson_serial_console_init(void)649*4882a593Smuzhiyun static int __init meson_serial_console_init(void) {
650*4882a593Smuzhiyun 	return 0;
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun #define MESON_SERIAL_CONSOLE	NULL
653*4882a593Smuzhiyun #endif
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun static struct uart_driver meson_uart_driver = {
656*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
657*4882a593Smuzhiyun 	.driver_name	= "meson_uart",
658*4882a593Smuzhiyun 	.dev_name	= AML_UART_DEV_NAME,
659*4882a593Smuzhiyun 	.nr		= AML_UART_PORT_NUM,
660*4882a593Smuzhiyun 	.cons		= MESON_SERIAL_CONSOLE,
661*4882a593Smuzhiyun };
662*4882a593Smuzhiyun 
meson_uart_probe_clock(struct device * dev,const char * id)663*4882a593Smuzhiyun static inline struct clk *meson_uart_probe_clock(struct device *dev,
664*4882a593Smuzhiyun 						 const char *id)
665*4882a593Smuzhiyun {
666*4882a593Smuzhiyun 	struct clk *clk = NULL;
667*4882a593Smuzhiyun 	int ret;
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	clk = devm_clk_get(dev, id);
670*4882a593Smuzhiyun 	if (IS_ERR(clk))
671*4882a593Smuzhiyun 		return clk;
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun 	ret = clk_prepare_enable(clk);
674*4882a593Smuzhiyun 	if (ret) {
675*4882a593Smuzhiyun 		dev_err(dev, "couldn't enable clk\n");
676*4882a593Smuzhiyun 		return ERR_PTR(ret);
677*4882a593Smuzhiyun 	}
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	devm_add_action_or_reset(dev,
680*4882a593Smuzhiyun 			(void(*)(void *))clk_disable_unprepare,
681*4882a593Smuzhiyun 			clk);
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	return clk;
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun /*
687*4882a593Smuzhiyun  * This function gets clocks in the legacy non-stable DT bindings.
688*4882a593Smuzhiyun  * This code will be remove once all the platforms switch to the
689*4882a593Smuzhiyun  * new DT bindings.
690*4882a593Smuzhiyun  */
meson_uart_probe_clocks_legacy(struct platform_device * pdev,struct uart_port * port)691*4882a593Smuzhiyun static int meson_uart_probe_clocks_legacy(struct platform_device *pdev,
692*4882a593Smuzhiyun 					  struct uart_port *port)
693*4882a593Smuzhiyun {
694*4882a593Smuzhiyun 	struct clk *clk = NULL;
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	clk = meson_uart_probe_clock(&pdev->dev, NULL);
697*4882a593Smuzhiyun 	if (IS_ERR(clk))
698*4882a593Smuzhiyun 		return PTR_ERR(clk);
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	port->uartclk = clk_get_rate(clk);
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	return 0;
703*4882a593Smuzhiyun }
704*4882a593Smuzhiyun 
meson_uart_probe_clocks(struct platform_device * pdev,struct uart_port * port)705*4882a593Smuzhiyun static int meson_uart_probe_clocks(struct platform_device *pdev,
706*4882a593Smuzhiyun 				   struct uart_port *port)
707*4882a593Smuzhiyun {
708*4882a593Smuzhiyun 	struct clk *clk_xtal = NULL;
709*4882a593Smuzhiyun 	struct clk *clk_pclk = NULL;
710*4882a593Smuzhiyun 	struct clk *clk_baud = NULL;
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	clk_pclk = meson_uart_probe_clock(&pdev->dev, "pclk");
713*4882a593Smuzhiyun 	if (IS_ERR(clk_pclk))
714*4882a593Smuzhiyun 		return PTR_ERR(clk_pclk);
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 	clk_xtal = meson_uart_probe_clock(&pdev->dev, "xtal");
717*4882a593Smuzhiyun 	if (IS_ERR(clk_xtal))
718*4882a593Smuzhiyun 		return PTR_ERR(clk_xtal);
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun 	clk_baud = meson_uart_probe_clock(&pdev->dev, "baud");
721*4882a593Smuzhiyun 	if (IS_ERR(clk_baud))
722*4882a593Smuzhiyun 		return PTR_ERR(clk_baud);
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	port->uartclk = clk_get_rate(clk_baud);
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun 	return 0;
727*4882a593Smuzhiyun }
728*4882a593Smuzhiyun 
meson_uart_probe(struct platform_device * pdev)729*4882a593Smuzhiyun static int meson_uart_probe(struct platform_device *pdev)
730*4882a593Smuzhiyun {
731*4882a593Smuzhiyun 	struct resource *res_mem, *res_irq;
732*4882a593Smuzhiyun 	struct uart_port *port;
733*4882a593Smuzhiyun 	int ret = 0;
734*4882a593Smuzhiyun 	int id = -1;
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	if (pdev->dev.of_node)
737*4882a593Smuzhiyun 		pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 	if (pdev->id < 0) {
740*4882a593Smuzhiyun 		for (id = AML_UART_PORT_OFFSET; id < AML_UART_PORT_NUM; id++) {
741*4882a593Smuzhiyun 			if (!meson_ports[id]) {
742*4882a593Smuzhiyun 				pdev->id = id;
743*4882a593Smuzhiyun 				break;
744*4882a593Smuzhiyun 			}
745*4882a593Smuzhiyun 		}
746*4882a593Smuzhiyun 	}
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 	if (pdev->id < 0 || pdev->id >= AML_UART_PORT_NUM)
749*4882a593Smuzhiyun 		return -EINVAL;
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun 	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
752*4882a593Smuzhiyun 	if (!res_mem)
753*4882a593Smuzhiyun 		return -ENODEV;
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 	res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
756*4882a593Smuzhiyun 	if (!res_irq)
757*4882a593Smuzhiyun 		return -ENODEV;
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	if (meson_ports[pdev->id]) {
760*4882a593Smuzhiyun 		dev_err(&pdev->dev, "port %d already allocated\n", pdev->id);
761*4882a593Smuzhiyun 		return -EBUSY;
762*4882a593Smuzhiyun 	}
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 	port = devm_kzalloc(&pdev->dev, sizeof(struct uart_port), GFP_KERNEL);
765*4882a593Smuzhiyun 	if (!port)
766*4882a593Smuzhiyun 		return -ENOMEM;
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun 	/* Use legacy way until all platforms switch to new bindings */
769*4882a593Smuzhiyun 	if (of_device_is_compatible(pdev->dev.of_node, "amlogic,meson-uart"))
770*4882a593Smuzhiyun 		ret = meson_uart_probe_clocks_legacy(pdev, port);
771*4882a593Smuzhiyun 	else
772*4882a593Smuzhiyun 		ret = meson_uart_probe_clocks(pdev, port);
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 	if (ret)
775*4882a593Smuzhiyun 		return ret;
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun 	port->iotype = UPIO_MEM;
778*4882a593Smuzhiyun 	port->mapbase = res_mem->start;
779*4882a593Smuzhiyun 	port->mapsize = resource_size(res_mem);
780*4882a593Smuzhiyun 	port->irq = res_irq->start;
781*4882a593Smuzhiyun 	port->flags = UPF_BOOT_AUTOCONF | UPF_LOW_LATENCY;
782*4882a593Smuzhiyun 	port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_MESON_CONSOLE);
783*4882a593Smuzhiyun 	port->dev = &pdev->dev;
784*4882a593Smuzhiyun 	port->line = pdev->id;
785*4882a593Smuzhiyun 	port->type = PORT_MESON;
786*4882a593Smuzhiyun 	port->x_char = 0;
787*4882a593Smuzhiyun 	port->ops = &meson_uart_ops;
788*4882a593Smuzhiyun 	port->fifosize = 64;
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun 	meson_ports[pdev->id] = port;
791*4882a593Smuzhiyun 	platform_set_drvdata(pdev, port);
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun 	/* reset port before registering (and possibly registering console) */
794*4882a593Smuzhiyun 	if (meson_uart_request_port(port) >= 0) {
795*4882a593Smuzhiyun 		meson_uart_reset(port);
796*4882a593Smuzhiyun 		meson_uart_release_port(port);
797*4882a593Smuzhiyun 	}
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun 	ret = uart_add_one_port(&meson_uart_driver, port);
800*4882a593Smuzhiyun 	if (ret)
801*4882a593Smuzhiyun 		meson_ports[pdev->id] = NULL;
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun 	return ret;
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun 
meson_uart_remove(struct platform_device * pdev)806*4882a593Smuzhiyun static int meson_uart_remove(struct platform_device *pdev)
807*4882a593Smuzhiyun {
808*4882a593Smuzhiyun 	struct uart_port *port;
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	port = platform_get_drvdata(pdev);
811*4882a593Smuzhiyun 	uart_remove_one_port(&meson_uart_driver, port);
812*4882a593Smuzhiyun 	meson_ports[pdev->id] = NULL;
813*4882a593Smuzhiyun 
814*4882a593Smuzhiyun 	return 0;
815*4882a593Smuzhiyun }
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun static const struct of_device_id meson_uart_dt_match[] = {
818*4882a593Smuzhiyun 	/* Legacy bindings, should be removed when no more used */
819*4882a593Smuzhiyun 	{ .compatible = "amlogic,meson-uart" },
820*4882a593Smuzhiyun 	/* Stable bindings */
821*4882a593Smuzhiyun 	{ .compatible = "amlogic,meson6-uart" },
822*4882a593Smuzhiyun 	{ .compatible = "amlogic,meson8-uart" },
823*4882a593Smuzhiyun 	{ .compatible = "amlogic,meson8b-uart" },
824*4882a593Smuzhiyun 	{ .compatible = "amlogic,meson-gx-uart" },
825*4882a593Smuzhiyun 	{ /* sentinel */ },
826*4882a593Smuzhiyun };
827*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, meson_uart_dt_match);
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun static  struct platform_driver meson_uart_platform_driver = {
830*4882a593Smuzhiyun 	.probe		= meson_uart_probe,
831*4882a593Smuzhiyun 	.remove		= meson_uart_remove,
832*4882a593Smuzhiyun 	.driver		= {
833*4882a593Smuzhiyun 		.name		= "meson_uart",
834*4882a593Smuzhiyun 		.of_match_table	= meson_uart_dt_match,
835*4882a593Smuzhiyun 	},
836*4882a593Smuzhiyun };
837*4882a593Smuzhiyun 
meson_uart_init(void)838*4882a593Smuzhiyun static int __init meson_uart_init(void)
839*4882a593Smuzhiyun {
840*4882a593Smuzhiyun 	int ret;
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun 	ret = meson_serial_console_init();
843*4882a593Smuzhiyun 	if (ret)
844*4882a593Smuzhiyun 		return ret;
845*4882a593Smuzhiyun 
846*4882a593Smuzhiyun 	ret = uart_register_driver(&meson_uart_driver);
847*4882a593Smuzhiyun 	if (ret)
848*4882a593Smuzhiyun 		return ret;
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun 	ret = platform_driver_register(&meson_uart_platform_driver);
851*4882a593Smuzhiyun 	if (ret)
852*4882a593Smuzhiyun 		uart_unregister_driver(&meson_uart_driver);
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun 	return ret;
855*4882a593Smuzhiyun }
856*4882a593Smuzhiyun 
meson_uart_exit(void)857*4882a593Smuzhiyun static void __exit meson_uart_exit(void)
858*4882a593Smuzhiyun {
859*4882a593Smuzhiyun 	platform_driver_unregister(&meson_uart_platform_driver);
860*4882a593Smuzhiyun 	uart_unregister_driver(&meson_uart_driver);
861*4882a593Smuzhiyun }
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun module_init(meson_uart_init);
864*4882a593Smuzhiyun module_exit(meson_uart_exit);
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
867*4882a593Smuzhiyun MODULE_DESCRIPTION("Amlogic Meson serial port driver");
868*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
869