1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Derived from many drivers using generic_serial interface.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Serial driver for BCM63xx integrated UART.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Hardware flow control was _not_ tested since I only have RX/TX on
10*4882a593Smuzhiyun * my board.
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/platform_device.h>
15*4882a593Smuzhiyun #include <linux/init.h>
16*4882a593Smuzhiyun #include <linux/delay.h>
17*4882a593Smuzhiyun #include <linux/module.h>
18*4882a593Smuzhiyun #include <linux/console.h>
19*4882a593Smuzhiyun #include <linux/clk.h>
20*4882a593Smuzhiyun #include <linux/tty.h>
21*4882a593Smuzhiyun #include <linux/tty_flip.h>
22*4882a593Smuzhiyun #include <linux/sysrq.h>
23*4882a593Smuzhiyun #include <linux/serial.h>
24*4882a593Smuzhiyun #include <linux/serial_core.h>
25*4882a593Smuzhiyun #include <linux/serial_bcm63xx.h>
26*4882a593Smuzhiyun #include <linux/io.h>
27*4882a593Smuzhiyun #include <linux/of.h>
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #define BCM63XX_NR_UARTS 2
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun static struct uart_port ports[BCM63XX_NR_UARTS];
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun /*
34*4882a593Smuzhiyun * rx interrupt mask / stat
35*4882a593Smuzhiyun *
36*4882a593Smuzhiyun * mask:
37*4882a593Smuzhiyun * - rx fifo full
38*4882a593Smuzhiyun * - rx fifo above threshold
39*4882a593Smuzhiyun * - rx fifo not empty for too long
40*4882a593Smuzhiyun */
41*4882a593Smuzhiyun #define UART_RX_INT_MASK (UART_IR_MASK(UART_IR_RXOVER) | \
42*4882a593Smuzhiyun UART_IR_MASK(UART_IR_RXTHRESH) | \
43*4882a593Smuzhiyun UART_IR_MASK(UART_IR_RXTIMEOUT))
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun #define UART_RX_INT_STAT (UART_IR_STAT(UART_IR_RXOVER) | \
46*4882a593Smuzhiyun UART_IR_STAT(UART_IR_RXTHRESH) | \
47*4882a593Smuzhiyun UART_IR_STAT(UART_IR_RXTIMEOUT))
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun /*
50*4882a593Smuzhiyun * tx interrupt mask / stat
51*4882a593Smuzhiyun *
52*4882a593Smuzhiyun * mask:
53*4882a593Smuzhiyun * - tx fifo empty
54*4882a593Smuzhiyun * - tx fifo below threshold
55*4882a593Smuzhiyun */
56*4882a593Smuzhiyun #define UART_TX_INT_MASK (UART_IR_MASK(UART_IR_TXEMPTY) | \
57*4882a593Smuzhiyun UART_IR_MASK(UART_IR_TXTRESH))
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun #define UART_TX_INT_STAT (UART_IR_STAT(UART_IR_TXEMPTY) | \
60*4882a593Smuzhiyun UART_IR_STAT(UART_IR_TXTRESH))
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /*
63*4882a593Smuzhiyun * external input interrupt
64*4882a593Smuzhiyun *
65*4882a593Smuzhiyun * mask: any edge on CTS, DCD
66*4882a593Smuzhiyun */
67*4882a593Smuzhiyun #define UART_EXTINP_INT_MASK (UART_EXTINP_IRMASK(UART_EXTINP_IR_CTS) | \
68*4882a593Smuzhiyun UART_EXTINP_IRMASK(UART_EXTINP_IR_DCD))
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun /*
71*4882a593Smuzhiyun * handy uart register accessor
72*4882a593Smuzhiyun */
bcm_uart_readl(struct uart_port * port,unsigned int offset)73*4882a593Smuzhiyun static inline unsigned int bcm_uart_readl(struct uart_port *port,
74*4882a593Smuzhiyun unsigned int offset)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun return __raw_readl(port->membase + offset);
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun
bcm_uart_writel(struct uart_port * port,unsigned int value,unsigned int offset)79*4882a593Smuzhiyun static inline void bcm_uart_writel(struct uart_port *port,
80*4882a593Smuzhiyun unsigned int value, unsigned int offset)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun __raw_writel(value, port->membase + offset);
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun /*
86*4882a593Smuzhiyun * serial core request to check if uart tx fifo is empty
87*4882a593Smuzhiyun */
bcm_uart_tx_empty(struct uart_port * port)88*4882a593Smuzhiyun static unsigned int bcm_uart_tx_empty(struct uart_port *port)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun unsigned int val;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_IR_REG);
93*4882a593Smuzhiyun return (val & UART_IR_STAT(UART_IR_TXEMPTY)) ? 1 : 0;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun /*
97*4882a593Smuzhiyun * serial core request to set RTS and DTR pin state and loopback mode
98*4882a593Smuzhiyun */
bcm_uart_set_mctrl(struct uart_port * port,unsigned int mctrl)99*4882a593Smuzhiyun static void bcm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun unsigned int val;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_MCTL_REG);
104*4882a593Smuzhiyun val &= ~(UART_MCTL_DTR_MASK | UART_MCTL_RTS_MASK);
105*4882a593Smuzhiyun /* invert of written value is reflected on the pin */
106*4882a593Smuzhiyun if (!(mctrl & TIOCM_DTR))
107*4882a593Smuzhiyun val |= UART_MCTL_DTR_MASK;
108*4882a593Smuzhiyun if (!(mctrl & TIOCM_RTS))
109*4882a593Smuzhiyun val |= UART_MCTL_RTS_MASK;
110*4882a593Smuzhiyun bcm_uart_writel(port, val, UART_MCTL_REG);
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_CTL_REG);
113*4882a593Smuzhiyun if (mctrl & TIOCM_LOOP)
114*4882a593Smuzhiyun val |= UART_CTL_LOOPBACK_MASK;
115*4882a593Smuzhiyun else
116*4882a593Smuzhiyun val &= ~UART_CTL_LOOPBACK_MASK;
117*4882a593Smuzhiyun bcm_uart_writel(port, val, UART_CTL_REG);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun /*
121*4882a593Smuzhiyun * serial core request to return RI, CTS, DCD and DSR pin state
122*4882a593Smuzhiyun */
bcm_uart_get_mctrl(struct uart_port * port)123*4882a593Smuzhiyun static unsigned int bcm_uart_get_mctrl(struct uart_port *port)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun unsigned int val, mctrl;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun mctrl = 0;
128*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_EXTINP_REG);
129*4882a593Smuzhiyun if (val & UART_EXTINP_RI_MASK)
130*4882a593Smuzhiyun mctrl |= TIOCM_RI;
131*4882a593Smuzhiyun if (val & UART_EXTINP_CTS_MASK)
132*4882a593Smuzhiyun mctrl |= TIOCM_CTS;
133*4882a593Smuzhiyun if (val & UART_EXTINP_DCD_MASK)
134*4882a593Smuzhiyun mctrl |= TIOCM_CD;
135*4882a593Smuzhiyun if (val & UART_EXTINP_DSR_MASK)
136*4882a593Smuzhiyun mctrl |= TIOCM_DSR;
137*4882a593Smuzhiyun return mctrl;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun /*
141*4882a593Smuzhiyun * serial core request to disable tx ASAP (used for flow control)
142*4882a593Smuzhiyun */
bcm_uart_stop_tx(struct uart_port * port)143*4882a593Smuzhiyun static void bcm_uart_stop_tx(struct uart_port *port)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun unsigned int val;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_CTL_REG);
148*4882a593Smuzhiyun val &= ~(UART_CTL_TXEN_MASK);
149*4882a593Smuzhiyun bcm_uart_writel(port, val, UART_CTL_REG);
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_IR_REG);
152*4882a593Smuzhiyun val &= ~UART_TX_INT_MASK;
153*4882a593Smuzhiyun bcm_uart_writel(port, val, UART_IR_REG);
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun /*
157*4882a593Smuzhiyun * serial core request to (re)enable tx
158*4882a593Smuzhiyun */
bcm_uart_start_tx(struct uart_port * port)159*4882a593Smuzhiyun static void bcm_uart_start_tx(struct uart_port *port)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun unsigned int val;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_IR_REG);
164*4882a593Smuzhiyun val |= UART_TX_INT_MASK;
165*4882a593Smuzhiyun bcm_uart_writel(port, val, UART_IR_REG);
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_CTL_REG);
168*4882a593Smuzhiyun val |= UART_CTL_TXEN_MASK;
169*4882a593Smuzhiyun bcm_uart_writel(port, val, UART_CTL_REG);
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun /*
173*4882a593Smuzhiyun * serial core request to stop rx, called before port shutdown
174*4882a593Smuzhiyun */
bcm_uart_stop_rx(struct uart_port * port)175*4882a593Smuzhiyun static void bcm_uart_stop_rx(struct uart_port *port)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun unsigned int val;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_IR_REG);
180*4882a593Smuzhiyun val &= ~UART_RX_INT_MASK;
181*4882a593Smuzhiyun bcm_uart_writel(port, val, UART_IR_REG);
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun /*
185*4882a593Smuzhiyun * serial core request to enable modem status interrupt reporting
186*4882a593Smuzhiyun */
bcm_uart_enable_ms(struct uart_port * port)187*4882a593Smuzhiyun static void bcm_uart_enable_ms(struct uart_port *port)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun unsigned int val;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_IR_REG);
192*4882a593Smuzhiyun val |= UART_IR_MASK(UART_IR_EXTIP);
193*4882a593Smuzhiyun bcm_uart_writel(port, val, UART_IR_REG);
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun /*
197*4882a593Smuzhiyun * serial core request to start/stop emitting break char
198*4882a593Smuzhiyun */
bcm_uart_break_ctl(struct uart_port * port,int ctl)199*4882a593Smuzhiyun static void bcm_uart_break_ctl(struct uart_port *port, int ctl)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun unsigned long flags;
202*4882a593Smuzhiyun unsigned int val;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_CTL_REG);
207*4882a593Smuzhiyun if (ctl)
208*4882a593Smuzhiyun val |= UART_CTL_XMITBRK_MASK;
209*4882a593Smuzhiyun else
210*4882a593Smuzhiyun val &= ~UART_CTL_XMITBRK_MASK;
211*4882a593Smuzhiyun bcm_uart_writel(port, val, UART_CTL_REG);
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun /*
217*4882a593Smuzhiyun * return port type in string format
218*4882a593Smuzhiyun */
bcm_uart_type(struct uart_port * port)219*4882a593Smuzhiyun static const char *bcm_uart_type(struct uart_port *port)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun return (port->type == PORT_BCM63XX) ? "bcm63xx_uart" : NULL;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun /*
225*4882a593Smuzhiyun * read all chars in rx fifo and send them to core
226*4882a593Smuzhiyun */
bcm_uart_do_rx(struct uart_port * port)227*4882a593Smuzhiyun static void bcm_uart_do_rx(struct uart_port *port)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun struct tty_port *tty_port = &port->state->port;
230*4882a593Smuzhiyun unsigned int max_count;
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun /* limit number of char read in interrupt, should not be
233*4882a593Smuzhiyun * higher than fifo size anyway since we're much faster than
234*4882a593Smuzhiyun * serial port */
235*4882a593Smuzhiyun max_count = 32;
236*4882a593Smuzhiyun do {
237*4882a593Smuzhiyun unsigned int iestat, c, cstat;
238*4882a593Smuzhiyun char flag;
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun /* get overrun/fifo empty information from ier
241*4882a593Smuzhiyun * register */
242*4882a593Smuzhiyun iestat = bcm_uart_readl(port, UART_IR_REG);
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) {
245*4882a593Smuzhiyun unsigned int val;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun /* fifo reset is required to clear
248*4882a593Smuzhiyun * interrupt */
249*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_CTL_REG);
250*4882a593Smuzhiyun val |= UART_CTL_RSTRXFIFO_MASK;
251*4882a593Smuzhiyun bcm_uart_writel(port, val, UART_CTL_REG);
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun port->icount.overrun++;
254*4882a593Smuzhiyun tty_insert_flip_char(tty_port, 0, TTY_OVERRUN);
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY)))
258*4882a593Smuzhiyun break;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun cstat = c = bcm_uart_readl(port, UART_FIFO_REG);
261*4882a593Smuzhiyun port->icount.rx++;
262*4882a593Smuzhiyun flag = TTY_NORMAL;
263*4882a593Smuzhiyun c &= 0xff;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun if (unlikely((cstat & UART_FIFO_ANYERR_MASK))) {
266*4882a593Smuzhiyun /* do stats first */
267*4882a593Smuzhiyun if (cstat & UART_FIFO_BRKDET_MASK) {
268*4882a593Smuzhiyun port->icount.brk++;
269*4882a593Smuzhiyun if (uart_handle_break(port))
270*4882a593Smuzhiyun continue;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun if (cstat & UART_FIFO_PARERR_MASK)
274*4882a593Smuzhiyun port->icount.parity++;
275*4882a593Smuzhiyun if (cstat & UART_FIFO_FRAMEERR_MASK)
276*4882a593Smuzhiyun port->icount.frame++;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun /* update flag wrt read_status_mask */
279*4882a593Smuzhiyun cstat &= port->read_status_mask;
280*4882a593Smuzhiyun if (cstat & UART_FIFO_BRKDET_MASK)
281*4882a593Smuzhiyun flag = TTY_BREAK;
282*4882a593Smuzhiyun if (cstat & UART_FIFO_FRAMEERR_MASK)
283*4882a593Smuzhiyun flag = TTY_FRAME;
284*4882a593Smuzhiyun if (cstat & UART_FIFO_PARERR_MASK)
285*4882a593Smuzhiyun flag = TTY_PARITY;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun if (uart_handle_sysrq_char(port, c))
289*4882a593Smuzhiyun continue;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun if ((cstat & port->ignore_status_mask) == 0)
293*4882a593Smuzhiyun tty_insert_flip_char(tty_port, c, flag);
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun } while (--max_count);
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun spin_unlock(&port->lock);
298*4882a593Smuzhiyun tty_flip_buffer_push(tty_port);
299*4882a593Smuzhiyun spin_lock(&port->lock);
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun /*
303*4882a593Smuzhiyun * fill tx fifo with chars to send, stop when fifo is about to be full
304*4882a593Smuzhiyun * or when all chars have been sent.
305*4882a593Smuzhiyun */
bcm_uart_do_tx(struct uart_port * port)306*4882a593Smuzhiyun static void bcm_uart_do_tx(struct uart_port *port)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun struct circ_buf *xmit;
309*4882a593Smuzhiyun unsigned int val, max_count;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun if (port->x_char) {
312*4882a593Smuzhiyun bcm_uart_writel(port, port->x_char, UART_FIFO_REG);
313*4882a593Smuzhiyun port->icount.tx++;
314*4882a593Smuzhiyun port->x_char = 0;
315*4882a593Smuzhiyun return;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun if (uart_tx_stopped(port)) {
319*4882a593Smuzhiyun bcm_uart_stop_tx(port);
320*4882a593Smuzhiyun return;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun xmit = &port->state->xmit;
324*4882a593Smuzhiyun if (uart_circ_empty(xmit))
325*4882a593Smuzhiyun goto txq_empty;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_MCTL_REG);
328*4882a593Smuzhiyun val = (val & UART_MCTL_TXFIFOFILL_MASK) >> UART_MCTL_TXFIFOFILL_SHIFT;
329*4882a593Smuzhiyun max_count = port->fifosize - val;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun while (max_count--) {
332*4882a593Smuzhiyun unsigned int c;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun c = xmit->buf[xmit->tail];
335*4882a593Smuzhiyun bcm_uart_writel(port, c, UART_FIFO_REG);
336*4882a593Smuzhiyun xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
337*4882a593Smuzhiyun port->icount.tx++;
338*4882a593Smuzhiyun if (uart_circ_empty(xmit))
339*4882a593Smuzhiyun break;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
343*4882a593Smuzhiyun uart_write_wakeup(port);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun if (uart_circ_empty(xmit))
346*4882a593Smuzhiyun goto txq_empty;
347*4882a593Smuzhiyun return;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun txq_empty:
350*4882a593Smuzhiyun /* nothing to send, disable transmit interrupt */
351*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_IR_REG);
352*4882a593Smuzhiyun val &= ~UART_TX_INT_MASK;
353*4882a593Smuzhiyun bcm_uart_writel(port, val, UART_IR_REG);
354*4882a593Smuzhiyun return;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun /*
358*4882a593Smuzhiyun * process uart interrupt
359*4882a593Smuzhiyun */
bcm_uart_interrupt(int irq,void * dev_id)360*4882a593Smuzhiyun static irqreturn_t bcm_uart_interrupt(int irq, void *dev_id)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun struct uart_port *port;
363*4882a593Smuzhiyun unsigned int irqstat;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun port = dev_id;
366*4882a593Smuzhiyun spin_lock(&port->lock);
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun irqstat = bcm_uart_readl(port, UART_IR_REG);
369*4882a593Smuzhiyun if (irqstat & UART_RX_INT_STAT)
370*4882a593Smuzhiyun bcm_uart_do_rx(port);
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun if (irqstat & UART_TX_INT_STAT)
373*4882a593Smuzhiyun bcm_uart_do_tx(port);
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun if (irqstat & UART_IR_MASK(UART_IR_EXTIP)) {
376*4882a593Smuzhiyun unsigned int estat;
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun estat = bcm_uart_readl(port, UART_EXTINP_REG);
379*4882a593Smuzhiyun if (estat & UART_EXTINP_IRSTAT(UART_EXTINP_IR_CTS))
380*4882a593Smuzhiyun uart_handle_cts_change(port,
381*4882a593Smuzhiyun estat & UART_EXTINP_CTS_MASK);
382*4882a593Smuzhiyun if (estat & UART_EXTINP_IRSTAT(UART_EXTINP_IR_DCD))
383*4882a593Smuzhiyun uart_handle_dcd_change(port,
384*4882a593Smuzhiyun estat & UART_EXTINP_DCD_MASK);
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun spin_unlock(&port->lock);
388*4882a593Smuzhiyun return IRQ_HANDLED;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun /*
392*4882a593Smuzhiyun * enable rx & tx operation on uart
393*4882a593Smuzhiyun */
bcm_uart_enable(struct uart_port * port)394*4882a593Smuzhiyun static void bcm_uart_enable(struct uart_port *port)
395*4882a593Smuzhiyun {
396*4882a593Smuzhiyun unsigned int val;
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_CTL_REG);
399*4882a593Smuzhiyun val |= (UART_CTL_BRGEN_MASK | UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK);
400*4882a593Smuzhiyun bcm_uart_writel(port, val, UART_CTL_REG);
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun /*
404*4882a593Smuzhiyun * disable rx & tx operation on uart
405*4882a593Smuzhiyun */
bcm_uart_disable(struct uart_port * port)406*4882a593Smuzhiyun static void bcm_uart_disable(struct uart_port *port)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun unsigned int val;
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_CTL_REG);
411*4882a593Smuzhiyun val &= ~(UART_CTL_BRGEN_MASK | UART_CTL_TXEN_MASK |
412*4882a593Smuzhiyun UART_CTL_RXEN_MASK);
413*4882a593Smuzhiyun bcm_uart_writel(port, val, UART_CTL_REG);
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun /*
417*4882a593Smuzhiyun * clear all unread data in rx fifo and unsent data in tx fifo
418*4882a593Smuzhiyun */
bcm_uart_flush(struct uart_port * port)419*4882a593Smuzhiyun static void bcm_uart_flush(struct uart_port *port)
420*4882a593Smuzhiyun {
421*4882a593Smuzhiyun unsigned int val;
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun /* empty rx and tx fifo */
424*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_CTL_REG);
425*4882a593Smuzhiyun val |= UART_CTL_RSTRXFIFO_MASK | UART_CTL_RSTTXFIFO_MASK;
426*4882a593Smuzhiyun bcm_uart_writel(port, val, UART_CTL_REG);
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun /* read any pending char to make sure all irq status are
429*4882a593Smuzhiyun * cleared */
430*4882a593Smuzhiyun (void)bcm_uart_readl(port, UART_FIFO_REG);
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun /*
434*4882a593Smuzhiyun * serial core request to initialize uart and start rx operation
435*4882a593Smuzhiyun */
bcm_uart_startup(struct uart_port * port)436*4882a593Smuzhiyun static int bcm_uart_startup(struct uart_port *port)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun unsigned int val;
439*4882a593Smuzhiyun int ret;
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun /* mask all irq and flush port */
442*4882a593Smuzhiyun bcm_uart_disable(port);
443*4882a593Smuzhiyun bcm_uart_writel(port, 0, UART_IR_REG);
444*4882a593Smuzhiyun bcm_uart_flush(port);
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun /* clear any pending external input interrupt */
447*4882a593Smuzhiyun (void)bcm_uart_readl(port, UART_EXTINP_REG);
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun /* set rx/tx fifo thresh to fifo half size */
450*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_MCTL_REG);
451*4882a593Smuzhiyun val &= ~(UART_MCTL_RXFIFOTHRESH_MASK | UART_MCTL_TXFIFOTHRESH_MASK);
452*4882a593Smuzhiyun val |= (port->fifosize / 2) << UART_MCTL_RXFIFOTHRESH_SHIFT;
453*4882a593Smuzhiyun val |= (port->fifosize / 2) << UART_MCTL_TXFIFOTHRESH_SHIFT;
454*4882a593Smuzhiyun bcm_uart_writel(port, val, UART_MCTL_REG);
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun /* set rx fifo timeout to 1 char time */
457*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_CTL_REG);
458*4882a593Smuzhiyun val &= ~UART_CTL_RXTMOUTCNT_MASK;
459*4882a593Smuzhiyun val |= 1 << UART_CTL_RXTMOUTCNT_SHIFT;
460*4882a593Smuzhiyun bcm_uart_writel(port, val, UART_CTL_REG);
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun /* report any edge on dcd and cts */
463*4882a593Smuzhiyun val = UART_EXTINP_INT_MASK;
464*4882a593Smuzhiyun val |= UART_EXTINP_DCD_NOSENSE_MASK;
465*4882a593Smuzhiyun val |= UART_EXTINP_CTS_NOSENSE_MASK;
466*4882a593Smuzhiyun bcm_uart_writel(port, val, UART_EXTINP_REG);
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun /* register irq and enable rx interrupts */
469*4882a593Smuzhiyun ret = request_irq(port->irq, bcm_uart_interrupt, 0,
470*4882a593Smuzhiyun dev_name(port->dev), port);
471*4882a593Smuzhiyun if (ret)
472*4882a593Smuzhiyun return ret;
473*4882a593Smuzhiyun bcm_uart_writel(port, UART_RX_INT_MASK, UART_IR_REG);
474*4882a593Smuzhiyun bcm_uart_enable(port);
475*4882a593Smuzhiyun return 0;
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun /*
479*4882a593Smuzhiyun * serial core request to flush & disable uart
480*4882a593Smuzhiyun */
bcm_uart_shutdown(struct uart_port * port)481*4882a593Smuzhiyun static void bcm_uart_shutdown(struct uart_port *port)
482*4882a593Smuzhiyun {
483*4882a593Smuzhiyun unsigned long flags;
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
486*4882a593Smuzhiyun bcm_uart_writel(port, 0, UART_IR_REG);
487*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun bcm_uart_disable(port);
490*4882a593Smuzhiyun bcm_uart_flush(port);
491*4882a593Smuzhiyun free_irq(port->irq, port);
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun /*
495*4882a593Smuzhiyun * serial core request to change current uart setting
496*4882a593Smuzhiyun */
bcm_uart_set_termios(struct uart_port * port,struct ktermios * new,struct ktermios * old)497*4882a593Smuzhiyun static void bcm_uart_set_termios(struct uart_port *port,
498*4882a593Smuzhiyun struct ktermios *new,
499*4882a593Smuzhiyun struct ktermios *old)
500*4882a593Smuzhiyun {
501*4882a593Smuzhiyun unsigned int ctl, baud, quot, ier;
502*4882a593Smuzhiyun unsigned long flags;
503*4882a593Smuzhiyun int tries;
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun /* Drain the hot tub fully before we power it off for the winter. */
508*4882a593Smuzhiyun for (tries = 3; !bcm_uart_tx_empty(port) && tries; tries--)
509*4882a593Smuzhiyun mdelay(10);
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun /* disable uart while changing speed */
512*4882a593Smuzhiyun bcm_uart_disable(port);
513*4882a593Smuzhiyun bcm_uart_flush(port);
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun /* update Control register */
516*4882a593Smuzhiyun ctl = bcm_uart_readl(port, UART_CTL_REG);
517*4882a593Smuzhiyun ctl &= ~UART_CTL_BITSPERSYM_MASK;
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun switch (new->c_cflag & CSIZE) {
520*4882a593Smuzhiyun case CS5:
521*4882a593Smuzhiyun ctl |= (0 << UART_CTL_BITSPERSYM_SHIFT);
522*4882a593Smuzhiyun break;
523*4882a593Smuzhiyun case CS6:
524*4882a593Smuzhiyun ctl |= (1 << UART_CTL_BITSPERSYM_SHIFT);
525*4882a593Smuzhiyun break;
526*4882a593Smuzhiyun case CS7:
527*4882a593Smuzhiyun ctl |= (2 << UART_CTL_BITSPERSYM_SHIFT);
528*4882a593Smuzhiyun break;
529*4882a593Smuzhiyun default:
530*4882a593Smuzhiyun ctl |= (3 << UART_CTL_BITSPERSYM_SHIFT);
531*4882a593Smuzhiyun break;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun ctl &= ~UART_CTL_STOPBITS_MASK;
535*4882a593Smuzhiyun if (new->c_cflag & CSTOPB)
536*4882a593Smuzhiyun ctl |= UART_CTL_STOPBITS_2;
537*4882a593Smuzhiyun else
538*4882a593Smuzhiyun ctl |= UART_CTL_STOPBITS_1;
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun ctl &= ~(UART_CTL_RXPAREN_MASK | UART_CTL_TXPAREN_MASK);
541*4882a593Smuzhiyun if (new->c_cflag & PARENB)
542*4882a593Smuzhiyun ctl |= (UART_CTL_RXPAREN_MASK | UART_CTL_TXPAREN_MASK);
543*4882a593Smuzhiyun ctl &= ~(UART_CTL_RXPAREVEN_MASK | UART_CTL_TXPAREVEN_MASK);
544*4882a593Smuzhiyun if (new->c_cflag & PARODD)
545*4882a593Smuzhiyun ctl |= (UART_CTL_RXPAREVEN_MASK | UART_CTL_TXPAREVEN_MASK);
546*4882a593Smuzhiyun bcm_uart_writel(port, ctl, UART_CTL_REG);
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun /* update Baudword register */
549*4882a593Smuzhiyun baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
550*4882a593Smuzhiyun quot = uart_get_divisor(port, baud) - 1;
551*4882a593Smuzhiyun bcm_uart_writel(port, quot, UART_BAUD_REG);
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun /* update Interrupt register */
554*4882a593Smuzhiyun ier = bcm_uart_readl(port, UART_IR_REG);
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun ier &= ~UART_IR_MASK(UART_IR_EXTIP);
557*4882a593Smuzhiyun if (UART_ENABLE_MS(port, new->c_cflag))
558*4882a593Smuzhiyun ier |= UART_IR_MASK(UART_IR_EXTIP);
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun bcm_uart_writel(port, ier, UART_IR_REG);
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun /* update read/ignore mask */
563*4882a593Smuzhiyun port->read_status_mask = UART_FIFO_VALID_MASK;
564*4882a593Smuzhiyun if (new->c_iflag & INPCK) {
565*4882a593Smuzhiyun port->read_status_mask |= UART_FIFO_FRAMEERR_MASK;
566*4882a593Smuzhiyun port->read_status_mask |= UART_FIFO_PARERR_MASK;
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun if (new->c_iflag & (IGNBRK | BRKINT))
569*4882a593Smuzhiyun port->read_status_mask |= UART_FIFO_BRKDET_MASK;
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun port->ignore_status_mask = 0;
572*4882a593Smuzhiyun if (new->c_iflag & IGNPAR)
573*4882a593Smuzhiyun port->ignore_status_mask |= UART_FIFO_PARERR_MASK;
574*4882a593Smuzhiyun if (new->c_iflag & IGNBRK)
575*4882a593Smuzhiyun port->ignore_status_mask |= UART_FIFO_BRKDET_MASK;
576*4882a593Smuzhiyun if (!(new->c_cflag & CREAD))
577*4882a593Smuzhiyun port->ignore_status_mask |= UART_FIFO_VALID_MASK;
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun uart_update_timeout(port, new->c_cflag, baud);
580*4882a593Smuzhiyun bcm_uart_enable(port);
581*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun /*
585*4882a593Smuzhiyun * serial core request to claim uart iomem
586*4882a593Smuzhiyun */
bcm_uart_request_port(struct uart_port * port)587*4882a593Smuzhiyun static int bcm_uart_request_port(struct uart_port *port)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun /* UARTs always present */
590*4882a593Smuzhiyun return 0;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun /*
594*4882a593Smuzhiyun * serial core request to release uart iomem
595*4882a593Smuzhiyun */
bcm_uart_release_port(struct uart_port * port)596*4882a593Smuzhiyun static void bcm_uart_release_port(struct uart_port *port)
597*4882a593Smuzhiyun {
598*4882a593Smuzhiyun /* Nothing to release ... */
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun /*
602*4882a593Smuzhiyun * serial core request to do any port required autoconfiguration
603*4882a593Smuzhiyun */
bcm_uart_config_port(struct uart_port * port,int flags)604*4882a593Smuzhiyun static void bcm_uart_config_port(struct uart_port *port, int flags)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun if (flags & UART_CONFIG_TYPE) {
607*4882a593Smuzhiyun if (bcm_uart_request_port(port))
608*4882a593Smuzhiyun return;
609*4882a593Smuzhiyun port->type = PORT_BCM63XX;
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun }
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun /*
614*4882a593Smuzhiyun * serial core request to check that port information in serinfo are
615*4882a593Smuzhiyun * suitable
616*4882a593Smuzhiyun */
bcm_uart_verify_port(struct uart_port * port,struct serial_struct * serinfo)617*4882a593Smuzhiyun static int bcm_uart_verify_port(struct uart_port *port,
618*4882a593Smuzhiyun struct serial_struct *serinfo)
619*4882a593Smuzhiyun {
620*4882a593Smuzhiyun if (port->type != PORT_BCM63XX)
621*4882a593Smuzhiyun return -EINVAL;
622*4882a593Smuzhiyun if (port->irq != serinfo->irq)
623*4882a593Smuzhiyun return -EINVAL;
624*4882a593Smuzhiyun if (port->iotype != serinfo->io_type)
625*4882a593Smuzhiyun return -EINVAL;
626*4882a593Smuzhiyun if (port->mapbase != (unsigned long)serinfo->iomem_base)
627*4882a593Smuzhiyun return -EINVAL;
628*4882a593Smuzhiyun return 0;
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun /* serial core callbacks */
632*4882a593Smuzhiyun static const struct uart_ops bcm_uart_ops = {
633*4882a593Smuzhiyun .tx_empty = bcm_uart_tx_empty,
634*4882a593Smuzhiyun .get_mctrl = bcm_uart_get_mctrl,
635*4882a593Smuzhiyun .set_mctrl = bcm_uart_set_mctrl,
636*4882a593Smuzhiyun .start_tx = bcm_uart_start_tx,
637*4882a593Smuzhiyun .stop_tx = bcm_uart_stop_tx,
638*4882a593Smuzhiyun .stop_rx = bcm_uart_stop_rx,
639*4882a593Smuzhiyun .enable_ms = bcm_uart_enable_ms,
640*4882a593Smuzhiyun .break_ctl = bcm_uart_break_ctl,
641*4882a593Smuzhiyun .startup = bcm_uart_startup,
642*4882a593Smuzhiyun .shutdown = bcm_uart_shutdown,
643*4882a593Smuzhiyun .set_termios = bcm_uart_set_termios,
644*4882a593Smuzhiyun .type = bcm_uart_type,
645*4882a593Smuzhiyun .release_port = bcm_uart_release_port,
646*4882a593Smuzhiyun .request_port = bcm_uart_request_port,
647*4882a593Smuzhiyun .config_port = bcm_uart_config_port,
648*4882a593Smuzhiyun .verify_port = bcm_uart_verify_port,
649*4882a593Smuzhiyun };
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun
653*4882a593Smuzhiyun #ifdef CONFIG_SERIAL_BCM63XX_CONSOLE
wait_for_xmitr(struct uart_port * port)654*4882a593Smuzhiyun static void wait_for_xmitr(struct uart_port *port)
655*4882a593Smuzhiyun {
656*4882a593Smuzhiyun unsigned int tmout;
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun /* Wait up to 10ms for the character(s) to be sent. */
659*4882a593Smuzhiyun tmout = 10000;
660*4882a593Smuzhiyun while (--tmout) {
661*4882a593Smuzhiyun unsigned int val;
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_IR_REG);
664*4882a593Smuzhiyun if (val & UART_IR_STAT(UART_IR_TXEMPTY))
665*4882a593Smuzhiyun break;
666*4882a593Smuzhiyun udelay(1);
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun
669*4882a593Smuzhiyun /* Wait up to 1s for flow control if necessary */
670*4882a593Smuzhiyun if (port->flags & UPF_CONS_FLOW) {
671*4882a593Smuzhiyun tmout = 1000000;
672*4882a593Smuzhiyun while (--tmout) {
673*4882a593Smuzhiyun unsigned int val;
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun val = bcm_uart_readl(port, UART_EXTINP_REG);
676*4882a593Smuzhiyun if (val & UART_EXTINP_CTS_MASK)
677*4882a593Smuzhiyun break;
678*4882a593Smuzhiyun udelay(1);
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun }
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun /*
684*4882a593Smuzhiyun * output given char
685*4882a593Smuzhiyun */
bcm_console_putchar(struct uart_port * port,int ch)686*4882a593Smuzhiyun static void bcm_console_putchar(struct uart_port *port, int ch)
687*4882a593Smuzhiyun {
688*4882a593Smuzhiyun wait_for_xmitr(port);
689*4882a593Smuzhiyun bcm_uart_writel(port, ch, UART_FIFO_REG);
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun /*
693*4882a593Smuzhiyun * console core request to output given string
694*4882a593Smuzhiyun */
bcm_console_write(struct console * co,const char * s,unsigned int count)695*4882a593Smuzhiyun static void bcm_console_write(struct console *co, const char *s,
696*4882a593Smuzhiyun unsigned int count)
697*4882a593Smuzhiyun {
698*4882a593Smuzhiyun struct uart_port *port;
699*4882a593Smuzhiyun unsigned long flags;
700*4882a593Smuzhiyun int locked;
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun port = &ports[co->index];
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun local_irq_save(flags);
705*4882a593Smuzhiyun if (port->sysrq) {
706*4882a593Smuzhiyun /* bcm_uart_interrupt() already took the lock */
707*4882a593Smuzhiyun locked = 0;
708*4882a593Smuzhiyun } else if (oops_in_progress) {
709*4882a593Smuzhiyun locked = spin_trylock(&port->lock);
710*4882a593Smuzhiyun } else {
711*4882a593Smuzhiyun spin_lock(&port->lock);
712*4882a593Smuzhiyun locked = 1;
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun
715*4882a593Smuzhiyun /* call helper to deal with \r\n */
716*4882a593Smuzhiyun uart_console_write(port, s, count, bcm_console_putchar);
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun /* and wait for char to be transmitted */
719*4882a593Smuzhiyun wait_for_xmitr(port);
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun if (locked)
722*4882a593Smuzhiyun spin_unlock(&port->lock);
723*4882a593Smuzhiyun local_irq_restore(flags);
724*4882a593Smuzhiyun }
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun /*
727*4882a593Smuzhiyun * console core request to setup given console, find matching uart
728*4882a593Smuzhiyun * port and setup it.
729*4882a593Smuzhiyun */
bcm_console_setup(struct console * co,char * options)730*4882a593Smuzhiyun static int bcm_console_setup(struct console *co, char *options)
731*4882a593Smuzhiyun {
732*4882a593Smuzhiyun struct uart_port *port;
733*4882a593Smuzhiyun int baud = 9600;
734*4882a593Smuzhiyun int bits = 8;
735*4882a593Smuzhiyun int parity = 'n';
736*4882a593Smuzhiyun int flow = 'n';
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun if (co->index < 0 || co->index >= BCM63XX_NR_UARTS)
739*4882a593Smuzhiyun return -EINVAL;
740*4882a593Smuzhiyun port = &ports[co->index];
741*4882a593Smuzhiyun if (!port->membase)
742*4882a593Smuzhiyun return -ENODEV;
743*4882a593Smuzhiyun if (options)
744*4882a593Smuzhiyun uart_parse_options(options, &baud, &parity, &bits, &flow);
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun return uart_set_options(port, co, baud, parity, bits, flow);
747*4882a593Smuzhiyun }
748*4882a593Smuzhiyun
749*4882a593Smuzhiyun static struct uart_driver bcm_uart_driver;
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun static struct console bcm63xx_console = {
752*4882a593Smuzhiyun .name = "ttyS",
753*4882a593Smuzhiyun .write = bcm_console_write,
754*4882a593Smuzhiyun .device = uart_console_device,
755*4882a593Smuzhiyun .setup = bcm_console_setup,
756*4882a593Smuzhiyun .flags = CON_PRINTBUFFER,
757*4882a593Smuzhiyun .index = -1,
758*4882a593Smuzhiyun .data = &bcm_uart_driver,
759*4882a593Smuzhiyun };
760*4882a593Smuzhiyun
bcm63xx_console_init(void)761*4882a593Smuzhiyun static int __init bcm63xx_console_init(void)
762*4882a593Smuzhiyun {
763*4882a593Smuzhiyun register_console(&bcm63xx_console);
764*4882a593Smuzhiyun return 0;
765*4882a593Smuzhiyun }
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun console_initcall(bcm63xx_console_init);
768*4882a593Smuzhiyun
bcm_early_write(struct console * con,const char * s,unsigned n)769*4882a593Smuzhiyun static void bcm_early_write(struct console *con, const char *s, unsigned n)
770*4882a593Smuzhiyun {
771*4882a593Smuzhiyun struct earlycon_device *dev = con->data;
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun uart_console_write(&dev->port, s, n, bcm_console_putchar);
774*4882a593Smuzhiyun wait_for_xmitr(&dev->port);
775*4882a593Smuzhiyun }
776*4882a593Smuzhiyun
bcm_early_console_setup(struct earlycon_device * device,const char * opt)777*4882a593Smuzhiyun static int __init bcm_early_console_setup(struct earlycon_device *device,
778*4882a593Smuzhiyun const char *opt)
779*4882a593Smuzhiyun {
780*4882a593Smuzhiyun if (!device->port.membase)
781*4882a593Smuzhiyun return -ENODEV;
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun device->con->write = bcm_early_write;
784*4882a593Smuzhiyun return 0;
785*4882a593Smuzhiyun }
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun OF_EARLYCON_DECLARE(bcm63xx_uart, "brcm,bcm6345-uart", bcm_early_console_setup);
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun #define BCM63XX_CONSOLE (&bcm63xx_console)
790*4882a593Smuzhiyun #else
791*4882a593Smuzhiyun #define BCM63XX_CONSOLE NULL
792*4882a593Smuzhiyun #endif /* CONFIG_SERIAL_BCM63XX_CONSOLE */
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun static struct uart_driver bcm_uart_driver = {
795*4882a593Smuzhiyun .owner = THIS_MODULE,
796*4882a593Smuzhiyun .driver_name = "bcm63xx_uart",
797*4882a593Smuzhiyun .dev_name = "ttyS",
798*4882a593Smuzhiyun .major = TTY_MAJOR,
799*4882a593Smuzhiyun .minor = 64,
800*4882a593Smuzhiyun .nr = BCM63XX_NR_UARTS,
801*4882a593Smuzhiyun .cons = BCM63XX_CONSOLE,
802*4882a593Smuzhiyun };
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun /*
805*4882a593Smuzhiyun * platform driver probe/remove callback
806*4882a593Smuzhiyun */
bcm_uart_probe(struct platform_device * pdev)807*4882a593Smuzhiyun static int bcm_uart_probe(struct platform_device *pdev)
808*4882a593Smuzhiyun {
809*4882a593Smuzhiyun struct resource *res_mem, *res_irq;
810*4882a593Smuzhiyun struct uart_port *port;
811*4882a593Smuzhiyun struct clk *clk;
812*4882a593Smuzhiyun int ret;
813*4882a593Smuzhiyun
814*4882a593Smuzhiyun if (pdev->dev.of_node) {
815*4882a593Smuzhiyun pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun if (pdev->id < 0)
818*4882a593Smuzhiyun pdev->id = of_alias_get_id(pdev->dev.of_node, "uart");
819*4882a593Smuzhiyun }
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS)
822*4882a593Smuzhiyun return -EINVAL;
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun port = &ports[pdev->id];
825*4882a593Smuzhiyun if (port->membase)
826*4882a593Smuzhiyun return -EBUSY;
827*4882a593Smuzhiyun memset(port, 0, sizeof(*port));
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
830*4882a593Smuzhiyun if (!res_mem)
831*4882a593Smuzhiyun return -ENODEV;
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun port->mapbase = res_mem->start;
834*4882a593Smuzhiyun port->membase = devm_ioremap_resource(&pdev->dev, res_mem);
835*4882a593Smuzhiyun if (IS_ERR(port->membase))
836*4882a593Smuzhiyun return PTR_ERR(port->membase);
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
839*4882a593Smuzhiyun if (!res_irq)
840*4882a593Smuzhiyun return -ENODEV;
841*4882a593Smuzhiyun
842*4882a593Smuzhiyun clk = clk_get(&pdev->dev, "refclk");
843*4882a593Smuzhiyun if (IS_ERR(clk) && pdev->dev.of_node)
844*4882a593Smuzhiyun clk = of_clk_get(pdev->dev.of_node, 0);
845*4882a593Smuzhiyun
846*4882a593Smuzhiyun if (IS_ERR(clk))
847*4882a593Smuzhiyun return -ENODEV;
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun port->iotype = UPIO_MEM;
850*4882a593Smuzhiyun port->irq = res_irq->start;
851*4882a593Smuzhiyun port->ops = &bcm_uart_ops;
852*4882a593Smuzhiyun port->flags = UPF_BOOT_AUTOCONF;
853*4882a593Smuzhiyun port->dev = &pdev->dev;
854*4882a593Smuzhiyun port->fifosize = 16;
855*4882a593Smuzhiyun port->uartclk = clk_get_rate(clk) / 2;
856*4882a593Smuzhiyun port->line = pdev->id;
857*4882a593Smuzhiyun port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_BCM63XX_CONSOLE);
858*4882a593Smuzhiyun clk_put(clk);
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun ret = uart_add_one_port(&bcm_uart_driver, port);
861*4882a593Smuzhiyun if (ret) {
862*4882a593Smuzhiyun ports[pdev->id].membase = NULL;
863*4882a593Smuzhiyun return ret;
864*4882a593Smuzhiyun }
865*4882a593Smuzhiyun platform_set_drvdata(pdev, port);
866*4882a593Smuzhiyun return 0;
867*4882a593Smuzhiyun }
868*4882a593Smuzhiyun
bcm_uart_remove(struct platform_device * pdev)869*4882a593Smuzhiyun static int bcm_uart_remove(struct platform_device *pdev)
870*4882a593Smuzhiyun {
871*4882a593Smuzhiyun struct uart_port *port;
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun port = platform_get_drvdata(pdev);
874*4882a593Smuzhiyun uart_remove_one_port(&bcm_uart_driver, port);
875*4882a593Smuzhiyun /* mark port as free */
876*4882a593Smuzhiyun ports[pdev->id].membase = NULL;
877*4882a593Smuzhiyun return 0;
878*4882a593Smuzhiyun }
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun static const struct of_device_id bcm63xx_of_match[] = {
881*4882a593Smuzhiyun { .compatible = "brcm,bcm6345-uart" },
882*4882a593Smuzhiyun { /* sentinel */ }
883*4882a593Smuzhiyun };
884*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, bcm63xx_of_match);
885*4882a593Smuzhiyun
886*4882a593Smuzhiyun /*
887*4882a593Smuzhiyun * platform driver stuff
888*4882a593Smuzhiyun */
889*4882a593Smuzhiyun static struct platform_driver bcm_uart_platform_driver = {
890*4882a593Smuzhiyun .probe = bcm_uart_probe,
891*4882a593Smuzhiyun .remove = bcm_uart_remove,
892*4882a593Smuzhiyun .driver = {
893*4882a593Smuzhiyun .name = "bcm63xx_uart",
894*4882a593Smuzhiyun .of_match_table = bcm63xx_of_match,
895*4882a593Smuzhiyun },
896*4882a593Smuzhiyun };
897*4882a593Smuzhiyun
bcm_uart_init(void)898*4882a593Smuzhiyun static int __init bcm_uart_init(void)
899*4882a593Smuzhiyun {
900*4882a593Smuzhiyun int ret;
901*4882a593Smuzhiyun
902*4882a593Smuzhiyun ret = uart_register_driver(&bcm_uart_driver);
903*4882a593Smuzhiyun if (ret)
904*4882a593Smuzhiyun return ret;
905*4882a593Smuzhiyun
906*4882a593Smuzhiyun ret = platform_driver_register(&bcm_uart_platform_driver);
907*4882a593Smuzhiyun if (ret)
908*4882a593Smuzhiyun uart_unregister_driver(&bcm_uart_driver);
909*4882a593Smuzhiyun
910*4882a593Smuzhiyun return ret;
911*4882a593Smuzhiyun }
912*4882a593Smuzhiyun
bcm_uart_exit(void)913*4882a593Smuzhiyun static void __exit bcm_uart_exit(void)
914*4882a593Smuzhiyun {
915*4882a593Smuzhiyun platform_driver_unregister(&bcm_uart_platform_driver);
916*4882a593Smuzhiyun uart_unregister_driver(&bcm_uart_driver);
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun module_init(bcm_uart_init);
920*4882a593Smuzhiyun module_exit(bcm_uart_exit);
921*4882a593Smuzhiyun
922*4882a593Smuzhiyun MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
923*4882a593Smuzhiyun MODULE_DESCRIPTION("Broadcom 63xx integrated uart driver");
924*4882a593Smuzhiyun MODULE_LICENSE("GPL");
925