blob: d0e749f6f052a5465025aaf2f1327a4a3945c465 [file] [log] [blame]
Wilson Ding30530792016-02-16 19:14:53 +01001/*
2* ***************************************************************************
Paul Gortmaker89ebc272016-03-13 19:48:52 -04003* Marvell Armada-3700 Serial Driver
4* Author: Wilson Ding <dingwei@marvell.com>
Wilson Ding30530792016-02-16 19:14:53 +01005* Copyright (C) 2015 Marvell International Ltd.
6* ***************************************************************************
7* This program is free software: you can redistribute it and/or modify it
8* under the terms of the GNU General Public License as published by the Free
9* Software Foundation, either version 2 of the License, or any later version.
10*
11* This program is distributed in the hope that it will be useful,
12* but WITHOUT ANY WARRANTY; without even the implied warranty of
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14* GNU General Public License for more details.
15*
16* You should have received a copy of the GNU General Public License
17* along with this program. If not, see <http://www.gnu.org/licenses/>.
18* ***************************************************************************
19*/
20
21#include <linux/clk.h>
22#include <linux/console.h>
23#include <linux/delay.h>
24#include <linux/device.h>
25#include <linux/init.h>
26#include <linux/io.h>
27#include <linux/iopoll.h>
Wilson Ding30530792016-02-16 19:14:53 +010028#include <linux/of.h>
29#include <linux/of_address.h>
30#include <linux/of_device.h>
31#include <linux/of_irq.h>
32#include <linux/of_platform.h>
33#include <linux/platform_device.h>
34#include <linux/serial.h>
35#include <linux/serial_core.h>
36#include <linux/slab.h>
37#include <linux/tty.h>
38#include <linux/tty_flip.h>
39
40/* Register Map */
Miquel Raynal5218d762017-10-13 11:01:49 +020041#define UART_STD_RBR 0x00
Wilson Ding30530792016-02-16 19:14:53 +010042
Miquel Raynal5218d762017-10-13 11:01:49 +020043#define UART_STD_TSH 0x04
Wilson Ding30530792016-02-16 19:14:53 +010044
Miquel Raynal5218d762017-10-13 11:01:49 +020045#define UART_STD_CTRL1 0x08
Wilson Ding30530792016-02-16 19:14:53 +010046#define CTRL_SOFT_RST BIT(31)
47#define CTRL_TXFIFO_RST BIT(15)
48#define CTRL_RXFIFO_RST BIT(14)
Wilson Ding30530792016-02-16 19:14:53 +010049#define CTRL_SND_BRK_SEQ BIT(11)
Wilson Ding30530792016-02-16 19:14:53 +010050#define CTRL_BRK_DET_INT BIT(3)
51#define CTRL_FRM_ERR_INT BIT(2)
52#define CTRL_PAR_ERR_INT BIT(1)
53#define CTRL_OVR_ERR_INT BIT(0)
Miquel Raynal5218d762017-10-13 11:01:49 +020054#define CTRL_BRK_INT (CTRL_BRK_DET_INT | CTRL_FRM_ERR_INT | \
55 CTRL_PAR_ERR_INT | CTRL_OVR_ERR_INT)
Wilson Ding30530792016-02-16 19:14:53 +010056
Miquel Raynal5218d762017-10-13 11:01:49 +020057#define UART_STD_CTRL2 UART_STD_CTRL1
58#define CTRL_STD_TX_RDY_INT BIT(5)
59#define CTRL_STD_RX_RDY_INT BIT(4)
60
61#define UART_STAT 0x0C
Wilson Ding30530792016-02-16 19:14:53 +010062#define STAT_TX_FIFO_EMP BIT(13)
Wilson Ding30530792016-02-16 19:14:53 +010063#define STAT_TX_FIFO_FUL BIT(11)
Wilson Ding30530792016-02-16 19:14:53 +010064#define STAT_TX_EMP BIT(6)
Miquel Raynal5218d762017-10-13 11:01:49 +020065#define STAT_STD_TX_RDY BIT(5)
66#define STAT_STD_RX_RDY BIT(4)
Wilson Ding30530792016-02-16 19:14:53 +010067#define STAT_BRK_DET BIT(3)
68#define STAT_FRM_ERR BIT(2)
69#define STAT_PAR_ERR BIT(1)
70#define STAT_OVR_ERR BIT(0)
71#define STAT_BRK_ERR (STAT_BRK_DET | STAT_FRM_ERR | STAT_FRM_ERR\
72 | STAT_PAR_ERR | STAT_OVR_ERR)
73
74#define UART_BRDV 0x10
Allen Yan68a0db12017-10-13 11:01:51 +020075#define BRDV_BAUD_MASK 0x3FF
Wilson Ding30530792016-02-16 19:14:53 +010076
77#define MVEBU_NR_UARTS 1
78
79#define MVEBU_UART_TYPE "mvebu-uart"
Yehuda Yitschak02c33332017-10-13 11:01:47 +020080#define DRIVER_NAME "mvebu_serial"
Wilson Ding30530792016-02-16 19:14:53 +010081
Miquel Raynal95f78762017-10-13 11:01:54 +020082enum {
83 /* Either there is only one summed IRQ... */
84 UART_IRQ_SUM = 0,
85 /* ...or there are two separate IRQ for RX and TX */
86 UART_RX_IRQ = 0,
87 UART_TX_IRQ,
88 UART_IRQ_COUNT
89};
90
91/* Diverging register offsets */
Miquel Raynal5218d762017-10-13 11:01:49 +020092struct uart_regs_layout {
93 unsigned int rbr;
94 unsigned int tsh;
95 unsigned int ctrl;
96 unsigned int intr;
Wilson Ding30530792016-02-16 19:14:53 +010097};
98
Miquel Raynal5218d762017-10-13 11:01:49 +020099/* Diverging flags */
100struct uart_flags {
101 unsigned int ctrl_tx_rdy_int;
102 unsigned int ctrl_rx_rdy_int;
103 unsigned int stat_tx_rdy;
104 unsigned int stat_rx_rdy;
105};
106
107/* Driver data, a structure for each UART port */
108struct mvebu_uart_driver_data {
109 bool is_ext;
110 struct uart_regs_layout regs;
111 struct uart_flags flags;
112};
113
114/* MVEBU UART driver structure */
115struct mvebu_uart {
116 struct uart_port *port;
117 struct clk *clk;
Miquel Raynal95f78762017-10-13 11:01:54 +0200118 int irq[UART_IRQ_COUNT];
119 unsigned char __iomem *nb;
Miquel Raynal5218d762017-10-13 11:01:49 +0200120 struct mvebu_uart_driver_data *data;
121};
122
123static struct mvebu_uart *to_mvuart(struct uart_port *port)
124{
125 return (struct mvebu_uart *)port->private_data;
126}
127
128#define IS_EXTENDED(port) (to_mvuart(port)->data->is_ext)
129
130#define UART_RBR(port) (to_mvuart(port)->data->regs.rbr)
131#define UART_TSH(port) (to_mvuart(port)->data->regs.tsh)
132#define UART_CTRL(port) (to_mvuart(port)->data->regs.ctrl)
133#define UART_INTR(port) (to_mvuart(port)->data->regs.intr)
134
135#define CTRL_TX_RDY_INT(port) (to_mvuart(port)->data->flags.ctrl_tx_rdy_int)
136#define CTRL_RX_RDY_INT(port) (to_mvuart(port)->data->flags.ctrl_rx_rdy_int)
137#define STAT_TX_RDY(port) (to_mvuart(port)->data->flags.stat_tx_rdy)
138#define STAT_RX_RDY(port) (to_mvuart(port)->data->flags.stat_rx_rdy)
139
140static struct uart_port mvebu_uart_ports[MVEBU_NR_UARTS];
141
Wilson Ding30530792016-02-16 19:14:53 +0100142/* Core UART Driver Operations */
143static unsigned int mvebu_uart_tx_empty(struct uart_port *port)
144{
145 unsigned long flags;
146 unsigned int st;
147
148 spin_lock_irqsave(&port->lock, flags);
149 st = readl(port->membase + UART_STAT);
150 spin_unlock_irqrestore(&port->lock, flags);
151
152 return (st & STAT_TX_FIFO_EMP) ? TIOCSER_TEMT : 0;
153}
154
155static unsigned int mvebu_uart_get_mctrl(struct uart_port *port)
156{
157 return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
158}
159
160static void mvebu_uart_set_mctrl(struct uart_port *port,
161 unsigned int mctrl)
162{
163/*
164 * Even if we do not support configuring the modem control lines, this
165 * function must be proided to the serial core
166 */
167}
168
169static void mvebu_uart_stop_tx(struct uart_port *port)
170{
Miquel Raynal5218d762017-10-13 11:01:49 +0200171 unsigned int ctl = readl(port->membase + UART_INTR(port));
Wilson Ding30530792016-02-16 19:14:53 +0100172
Miquel Raynal5218d762017-10-13 11:01:49 +0200173 ctl &= ~CTRL_TX_RDY_INT(port);
174 writel(ctl, port->membase + UART_INTR(port));
Wilson Ding30530792016-02-16 19:14:53 +0100175}
176
177static void mvebu_uart_start_tx(struct uart_port *port)
178{
Allen Yan30434b02017-10-13 11:01:53 +0200179 unsigned int ctl;
180 struct circ_buf *xmit = &port->state->xmit;
Wilson Ding30530792016-02-16 19:14:53 +0100181
Allen Yan30434b02017-10-13 11:01:53 +0200182 if (IS_EXTENDED(port) && !uart_circ_empty(xmit)) {
183 writel(xmit->buf[xmit->tail], port->membase + UART_TSH(port));
184 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
185 port->icount.tx++;
186 }
187
188 ctl = readl(port->membase + UART_INTR(port));
Miquel Raynal5218d762017-10-13 11:01:49 +0200189 ctl |= CTRL_TX_RDY_INT(port);
190 writel(ctl, port->membase + UART_INTR(port));
Wilson Ding30530792016-02-16 19:14:53 +0100191}
192
193static void mvebu_uart_stop_rx(struct uart_port *port)
194{
Miquel Raynal5218d762017-10-13 11:01:49 +0200195 unsigned int ctl;
Wilson Ding30530792016-02-16 19:14:53 +0100196
Miquel Raynal5218d762017-10-13 11:01:49 +0200197 ctl = readl(port->membase + UART_CTRL(port));
198 ctl &= ~CTRL_BRK_INT;
199 writel(ctl, port->membase + UART_CTRL(port));
200
201 ctl = readl(port->membase + UART_INTR(port));
202 ctl &= ~CTRL_RX_RDY_INT(port);
203 writel(ctl, port->membase + UART_INTR(port));
Wilson Ding30530792016-02-16 19:14:53 +0100204}
205
206static void mvebu_uart_break_ctl(struct uart_port *port, int brk)
207{
208 unsigned int ctl;
209 unsigned long flags;
210
211 spin_lock_irqsave(&port->lock, flags);
Miquel Raynal5218d762017-10-13 11:01:49 +0200212 ctl = readl(port->membase + UART_CTRL(port));
Wilson Ding30530792016-02-16 19:14:53 +0100213 if (brk == -1)
214 ctl |= CTRL_SND_BRK_SEQ;
215 else
216 ctl &= ~CTRL_SND_BRK_SEQ;
Miquel Raynal5218d762017-10-13 11:01:49 +0200217 writel(ctl, port->membase + UART_CTRL(port));
Wilson Ding30530792016-02-16 19:14:53 +0100218 spin_unlock_irqrestore(&port->lock, flags);
219}
220
221static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status)
222{
223 struct tty_port *tport = &port->state->port;
224 unsigned char ch = 0;
225 char flag = 0;
226
227 do {
Miquel Raynal5218d762017-10-13 11:01:49 +0200228 if (status & STAT_RX_RDY(port)) {
229 ch = readl(port->membase + UART_RBR(port));
Wilson Ding30530792016-02-16 19:14:53 +0100230 ch &= 0xff;
231 flag = TTY_NORMAL;
232 port->icount.rx++;
233
234 if (status & STAT_PAR_ERR)
235 port->icount.parity++;
236 }
237
238 if (status & STAT_BRK_DET) {
239 port->icount.brk++;
240 status &= ~(STAT_FRM_ERR | STAT_PAR_ERR);
241 if (uart_handle_break(port))
242 goto ignore_char;
243 }
244
245 if (status & STAT_OVR_ERR)
246 port->icount.overrun++;
247
248 if (status & STAT_FRM_ERR)
249 port->icount.frame++;
250
251 if (uart_handle_sysrq_char(port, ch))
252 goto ignore_char;
253
254 if (status & port->ignore_status_mask & STAT_PAR_ERR)
Miquel Raynal5218d762017-10-13 11:01:49 +0200255 status &= ~STAT_RX_RDY(port);
Wilson Ding30530792016-02-16 19:14:53 +0100256
257 status &= port->read_status_mask;
258
259 if (status & STAT_PAR_ERR)
260 flag = TTY_PARITY;
261
262 status &= ~port->ignore_status_mask;
263
Miquel Raynal5218d762017-10-13 11:01:49 +0200264 if (status & STAT_RX_RDY(port))
Wilson Ding30530792016-02-16 19:14:53 +0100265 tty_insert_flip_char(tport, ch, flag);
266
267 if (status & STAT_BRK_DET)
268 tty_insert_flip_char(tport, 0, TTY_BREAK);
269
270 if (status & STAT_FRM_ERR)
271 tty_insert_flip_char(tport, 0, TTY_FRAME);
272
273 if (status & STAT_OVR_ERR)
274 tty_insert_flip_char(tport, 0, TTY_OVERRUN);
275
276ignore_char:
277 status = readl(port->membase + UART_STAT);
Miquel Raynal5218d762017-10-13 11:01:49 +0200278 } while (status & (STAT_RX_RDY(port) | STAT_BRK_DET));
Wilson Ding30530792016-02-16 19:14:53 +0100279
280 tty_flip_buffer_push(tport);
281}
282
283static void mvebu_uart_tx_chars(struct uart_port *port, unsigned int status)
284{
285 struct circ_buf *xmit = &port->state->xmit;
286 unsigned int count;
287 unsigned int st;
288
289 if (port->x_char) {
Miquel Raynal5218d762017-10-13 11:01:49 +0200290 writel(port->x_char, port->membase + UART_TSH(port));
Wilson Ding30530792016-02-16 19:14:53 +0100291 port->icount.tx++;
292 port->x_char = 0;
293 return;
294 }
295
296 if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
297 mvebu_uart_stop_tx(port);
298 return;
299 }
300
301 for (count = 0; count < port->fifosize; count++) {
Miquel Raynal5218d762017-10-13 11:01:49 +0200302 writel(xmit->buf[xmit->tail], port->membase + UART_TSH(port));
Wilson Ding30530792016-02-16 19:14:53 +0100303 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
304 port->icount.tx++;
305
306 if (uart_circ_empty(xmit))
307 break;
308
309 st = readl(port->membase + UART_STAT);
310 if (st & STAT_TX_FIFO_FUL)
311 break;
312 }
313
314 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
315 uart_write_wakeup(port);
316
317 if (uart_circ_empty(xmit))
318 mvebu_uart_stop_tx(port);
319}
320
321static irqreturn_t mvebu_uart_isr(int irq, void *dev_id)
322{
323 struct uart_port *port = (struct uart_port *)dev_id;
324 unsigned int st = readl(port->membase + UART_STAT);
325
Miquel Raynal5218d762017-10-13 11:01:49 +0200326 if (st & (STAT_RX_RDY(port) | STAT_OVR_ERR | STAT_FRM_ERR |
Miquel Raynal95f78762017-10-13 11:01:54 +0200327 STAT_BRK_DET))
328 mvebu_uart_rx_chars(port, st);
329
330 if (st & STAT_TX_RDY(port))
331 mvebu_uart_tx_chars(port, st);
332
333 return IRQ_HANDLED;
334}
335
336static irqreturn_t mvebu_uart_rx_isr(int irq, void *dev_id)
337{
338 struct uart_port *port = (struct uart_port *)dev_id;
339 unsigned int st = readl(port->membase + UART_STAT);
340
341 if (st & (STAT_RX_RDY(port) | STAT_OVR_ERR | STAT_FRM_ERR |
Miquel Raynal5218d762017-10-13 11:01:49 +0200342 STAT_BRK_DET))
Wilson Ding30530792016-02-16 19:14:53 +0100343 mvebu_uart_rx_chars(port, st);
344
Miquel Raynal95f78762017-10-13 11:01:54 +0200345 return IRQ_HANDLED;
346}
347
348static irqreturn_t mvebu_uart_tx_isr(int irq, void *dev_id)
349{
350 struct uart_port *port = (struct uart_port *)dev_id;
351 unsigned int st = readl(port->membase + UART_STAT);
352
Miquel Raynal5218d762017-10-13 11:01:49 +0200353 if (st & STAT_TX_RDY(port))
Wilson Ding30530792016-02-16 19:14:53 +0100354 mvebu_uart_tx_chars(port, st);
355
356 return IRQ_HANDLED;
357}
358
359static int mvebu_uart_startup(struct uart_port *port)
360{
Miquel Raynal95f78762017-10-13 11:01:54 +0200361 struct mvebu_uart *mvuart = to_mvuart(port);
Miquel Raynal5218d762017-10-13 11:01:49 +0200362 unsigned int ctl;
Wilson Ding30530792016-02-16 19:14:53 +0100363 int ret;
364
365 writel(CTRL_TXFIFO_RST | CTRL_RXFIFO_RST,
Miquel Raynal5218d762017-10-13 11:01:49 +0200366 port->membase + UART_CTRL(port));
Wilson Ding30530792016-02-16 19:14:53 +0100367 udelay(1);
Allen Yan2ff23c42017-10-13 11:01:52 +0200368
369 /* Clear the error bits of state register before IRQ request */
370 ret = readl(port->membase + UART_STAT);
371 ret |= STAT_BRK_ERR;
372 writel(ret, port->membase + UART_STAT);
373
Miquel Raynal5218d762017-10-13 11:01:49 +0200374 writel(CTRL_BRK_INT, port->membase + UART_CTRL(port));
375
376 ctl = readl(port->membase + UART_INTR(port));
377 ctl |= CTRL_RX_RDY_INT(port);
378 writel(ctl, port->membase + UART_INTR(port));
Wilson Ding30530792016-02-16 19:14:53 +0100379
Miquel Raynal95f78762017-10-13 11:01:54 +0200380 if (!mvuart->irq[UART_TX_IRQ]) {
381 /* Old bindings with just one interrupt (UART0 only) */
382 ret = devm_request_irq(port->dev, mvuart->irq[UART_IRQ_SUM],
383 mvebu_uart_isr, port->irqflags,
384 dev_name(port->dev), port);
385 if (ret) {
386 dev_err(port->dev, "unable to request IRQ %d\n",
387 mvuart->irq[UART_IRQ_SUM]);
388 return ret;
389 }
390 } else {
391 /* New bindings with an IRQ for RX and TX (both UART) */
392 ret = devm_request_irq(port->dev, mvuart->irq[UART_RX_IRQ],
393 mvebu_uart_rx_isr, port->irqflags,
394 dev_name(port->dev), port);
395 if (ret) {
396 dev_err(port->dev, "unable to request IRQ %d\n",
397 mvuart->irq[UART_RX_IRQ]);
398 return ret;
399 }
400
401 ret = devm_request_irq(port->dev, mvuart->irq[UART_TX_IRQ],
402 mvebu_uart_tx_isr, port->irqflags,
403 dev_name(port->dev),
404 port);
405 if (ret) {
406 dev_err(port->dev, "unable to request IRQ %d\n",
407 mvuart->irq[UART_TX_IRQ]);
408 devm_free_irq(port->dev, mvuart->irq[UART_RX_IRQ],
409 port);
410 return ret;
411 }
Wilson Ding30530792016-02-16 19:14:53 +0100412 }
413
414 return 0;
415}
416
417static void mvebu_uart_shutdown(struct uart_port *port)
418{
Miquel Raynal95f78762017-10-13 11:01:54 +0200419 struct mvebu_uart *mvuart = to_mvuart(port);
420
Miquel Raynal5218d762017-10-13 11:01:49 +0200421 writel(0, port->membase + UART_INTR(port));
Thomas Petazzonic2c16592016-06-16 16:48:52 +0200422
Miquel Raynal95f78762017-10-13 11:01:54 +0200423 if (!mvuart->irq[UART_TX_IRQ]) {
424 devm_free_irq(port->dev, mvuart->irq[UART_IRQ_SUM], port);
425 } else {
426 devm_free_irq(port->dev, mvuart->irq[UART_RX_IRQ], port);
427 devm_free_irq(port->dev, mvuart->irq[UART_TX_IRQ], port);
428 }
Wilson Ding30530792016-02-16 19:14:53 +0100429}
430
Allen Yan68a0db12017-10-13 11:01:51 +0200431static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
432{
433 struct mvebu_uart *mvuart = to_mvuart(port);
434 unsigned int baud_rate_div;
435 u32 brdv;
436
437 if (IS_ERR(mvuart->clk))
438 return -PTR_ERR(mvuart->clk);
439
440 /*
441 * The UART clock is divided by the value of the divisor to generate
442 * UCLK_OUT clock, which is 16 times faster than the baudrate.
443 * This prescaler can achieve all standard baudrates until 230400.
444 * Higher baudrates could be achieved for the extended UART by using the
445 * programmable oversampling stack (also called fractional divisor).
446 */
447 baud_rate_div = DIV_ROUND_UP(port->uartclk, baud * 16);
448 brdv = readl(port->membase + UART_BRDV);
449 brdv &= ~BRDV_BAUD_MASK;
450 brdv |= baud_rate_div;
451 writel(brdv, port->membase + UART_BRDV);
452
453 return 0;
454}
455
Wilson Ding30530792016-02-16 19:14:53 +0100456static void mvebu_uart_set_termios(struct uart_port *port,
457 struct ktermios *termios,
458 struct ktermios *old)
459{
460 unsigned long flags;
461 unsigned int baud;
462
463 spin_lock_irqsave(&port->lock, flags);
464
Miquel Raynal5218d762017-10-13 11:01:49 +0200465 port->read_status_mask = STAT_RX_RDY(port) | STAT_OVR_ERR |
466 STAT_TX_RDY(port) | STAT_TX_FIFO_FUL;
Wilson Ding30530792016-02-16 19:14:53 +0100467
468 if (termios->c_iflag & INPCK)
469 port->read_status_mask |= STAT_FRM_ERR | STAT_PAR_ERR;
470
471 port->ignore_status_mask = 0;
472 if (termios->c_iflag & IGNPAR)
473 port->ignore_status_mask |=
474 STAT_FRM_ERR | STAT_PAR_ERR | STAT_OVR_ERR;
475
476 if ((termios->c_cflag & CREAD) == 0)
Miquel Raynal5218d762017-10-13 11:01:49 +0200477 port->ignore_status_mask |= STAT_RX_RDY(port) | STAT_BRK_ERR;
Wilson Ding30530792016-02-16 19:14:53 +0100478
Allen Yan68a0db12017-10-13 11:01:51 +0200479 /*
480 * Maximum achievable frequency with simple baudrate divisor is 230400.
481 * Since the error per bit frame would be of more than 15%, achieving
482 * higher frequencies would require to implement the fractional divisor
483 * feature.
484 */
485 baud = uart_get_baud_rate(port, termios, old, 0, 230400);
486 if (mvebu_uart_baud_rate_set(port, baud)) {
487 /* No clock available, baudrate cannot be changed */
488 if (old)
489 baud = uart_get_baud_rate(port, old, NULL, 0, 230400);
490 } else {
491 tty_termios_encode_baud_rate(termios, baud, baud);
492 uart_update_timeout(port, termios->c_cflag, baud);
493 }
Wilson Ding30530792016-02-16 19:14:53 +0100494
Allen Yan68a0db12017-10-13 11:01:51 +0200495 /* Only the following flag changes are supported */
496 if (old) {
497 termios->c_iflag &= INPCK | IGNPAR;
498 termios->c_iflag |= old->c_iflag & ~(INPCK | IGNPAR);
499 termios->c_cflag &= CREAD | CBAUD;
500 termios->c_cflag |= old->c_cflag & ~(CREAD | CBAUD);
501 termios->c_lflag = old->c_lflag;
502 }
Wilson Ding30530792016-02-16 19:14:53 +0100503
504 spin_unlock_irqrestore(&port->lock, flags);
505}
506
507static const char *mvebu_uart_type(struct uart_port *port)
508{
509 return MVEBU_UART_TYPE;
510}
511
512static void mvebu_uart_release_port(struct uart_port *port)
513{
514 /* Nothing to do here */
515}
516
517static int mvebu_uart_request_port(struct uart_port *port)
518{
519 return 0;
520}
521
522#ifdef CONFIG_CONSOLE_POLL
523static int mvebu_uart_get_poll_char(struct uart_port *port)
524{
525 unsigned int st = readl(port->membase + UART_STAT);
526
Miquel Raynal5218d762017-10-13 11:01:49 +0200527 if (!(st & STAT_RX_RDY(port)))
Wilson Ding30530792016-02-16 19:14:53 +0100528 return NO_POLL_CHAR;
529
Miquel Raynal5218d762017-10-13 11:01:49 +0200530 return readl(port->membase + UART_RBR(port));
Wilson Ding30530792016-02-16 19:14:53 +0100531}
532
533static void mvebu_uart_put_poll_char(struct uart_port *port, unsigned char c)
534{
535 unsigned int st;
536
537 for (;;) {
538 st = readl(port->membase + UART_STAT);
539
540 if (!(st & STAT_TX_FIFO_FUL))
541 break;
542
543 udelay(1);
544 }
545
Miquel Raynal5218d762017-10-13 11:01:49 +0200546 writel(c, port->membase + UART_TSH(port));
Wilson Ding30530792016-02-16 19:14:53 +0100547}
548#endif
549
550static const struct uart_ops mvebu_uart_ops = {
551 .tx_empty = mvebu_uart_tx_empty,
552 .set_mctrl = mvebu_uart_set_mctrl,
553 .get_mctrl = mvebu_uart_get_mctrl,
554 .stop_tx = mvebu_uart_stop_tx,
555 .start_tx = mvebu_uart_start_tx,
556 .stop_rx = mvebu_uart_stop_rx,
557 .break_ctl = mvebu_uart_break_ctl,
558 .startup = mvebu_uart_startup,
559 .shutdown = mvebu_uart_shutdown,
560 .set_termios = mvebu_uart_set_termios,
561 .type = mvebu_uart_type,
562 .release_port = mvebu_uart_release_port,
563 .request_port = mvebu_uart_request_port,
564#ifdef CONFIG_CONSOLE_POLL
565 .poll_get_char = mvebu_uart_get_poll_char,
566 .poll_put_char = mvebu_uart_put_poll_char,
567#endif
568};
569
570/* Console Driver Operations */
571
572#ifdef CONFIG_SERIAL_MVEBU_CONSOLE
573/* Early Console */
574static void mvebu_uart_putc(struct uart_port *port, int c)
575{
576 unsigned int st;
577
578 for (;;) {
579 st = readl(port->membase + UART_STAT);
580 if (!(st & STAT_TX_FIFO_FUL))
581 break;
582 }
583
Miquel Raynal5218d762017-10-13 11:01:49 +0200584 /* At early stage, DT is not parsed yet, only use UART0 */
585 writel(c, port->membase + UART_STD_TSH);
Wilson Ding30530792016-02-16 19:14:53 +0100586
587 for (;;) {
588 st = readl(port->membase + UART_STAT);
589 if (st & STAT_TX_FIFO_EMP)
590 break;
591 }
592}
593
594static void mvebu_uart_putc_early_write(struct console *con,
595 const char *s,
596 unsigned n)
597{
598 struct earlycon_device *dev = con->data;
599
600 uart_console_write(&dev->port, s, n, mvebu_uart_putc);
601}
602
603static int __init
604mvebu_uart_early_console_setup(struct earlycon_device *device,
605 const char *opt)
606{
607 if (!device->port.membase)
608 return -ENODEV;
609
610 device->con->write = mvebu_uart_putc_early_write;
611
612 return 0;
613}
614
615EARLYCON_DECLARE(ar3700_uart, mvebu_uart_early_console_setup);
616OF_EARLYCON_DECLARE(ar3700_uart, "marvell,armada-3700-uart",
617 mvebu_uart_early_console_setup);
618
619static void wait_for_xmitr(struct uart_port *port)
620{
621 u32 val;
622
623 readl_poll_timeout_atomic(port->membase + UART_STAT, val,
624 (val & STAT_TX_EMP), 1, 10000);
625}
626
627static void mvebu_uart_console_putchar(struct uart_port *port, int ch)
628{
629 wait_for_xmitr(port);
Miquel Raynal5218d762017-10-13 11:01:49 +0200630 writel(ch, port->membase + UART_TSH(port));
Wilson Ding30530792016-02-16 19:14:53 +0100631}
632
633static void mvebu_uart_console_write(struct console *co, const char *s,
634 unsigned int count)
635{
636 struct uart_port *port = &mvebu_uart_ports[co->index];
637 unsigned long flags;
Miquel Raynal5218d762017-10-13 11:01:49 +0200638 unsigned int ier, intr, ctl;
Wilson Ding30530792016-02-16 19:14:53 +0100639 int locked = 1;
640
641 if (oops_in_progress)
642 locked = spin_trylock_irqsave(&port->lock, flags);
643 else
644 spin_lock_irqsave(&port->lock, flags);
645
Miquel Raynal5218d762017-10-13 11:01:49 +0200646 ier = readl(port->membase + UART_CTRL(port)) & CTRL_BRK_INT;
647 intr = readl(port->membase + UART_INTR(port)) &
648 (CTRL_RX_RDY_INT(port) | CTRL_TX_RDY_INT(port));
649 writel(0, port->membase + UART_CTRL(port));
650 writel(0, port->membase + UART_INTR(port));
Wilson Ding30530792016-02-16 19:14:53 +0100651
652 uart_console_write(port, s, count, mvebu_uart_console_putchar);
653
654 wait_for_xmitr(port);
655
656 if (ier)
Miquel Raynal5218d762017-10-13 11:01:49 +0200657 writel(ier, port->membase + UART_CTRL(port));
658
659 if (intr) {
660 ctl = intr | readl(port->membase + UART_INTR(port));
661 writel(ctl, port->membase + UART_INTR(port));
662 }
Wilson Ding30530792016-02-16 19:14:53 +0100663
664 if (locked)
665 spin_unlock_irqrestore(&port->lock, flags);
666}
667
668static int mvebu_uart_console_setup(struct console *co, char *options)
669{
670 struct uart_port *port;
671 int baud = 9600;
672 int bits = 8;
673 int parity = 'n';
674 int flow = 'n';
675
676 if (co->index < 0 || co->index >= MVEBU_NR_UARTS)
677 return -EINVAL;
678
679 port = &mvebu_uart_ports[co->index];
680
681 if (!port->mapbase || !port->membase) {
682 pr_debug("console on ttyMV%i not present\n", co->index);
683 return -ENODEV;
684 }
685
686 if (options)
687 uart_parse_options(options, &baud, &parity, &bits, &flow);
688
689 return uart_set_options(port, co, baud, parity, bits, flow);
690}
691
692static struct uart_driver mvebu_uart_driver;
693
694static struct console mvebu_uart_console = {
695 .name = "ttyMV",
696 .write = mvebu_uart_console_write,
697 .device = uart_console_device,
698 .setup = mvebu_uart_console_setup,
699 .flags = CON_PRINTBUFFER,
700 .index = -1,
701 .data = &mvebu_uart_driver,
702};
703
704static int __init mvebu_uart_console_init(void)
705{
706 register_console(&mvebu_uart_console);
707 return 0;
708}
709
710console_initcall(mvebu_uart_console_init);
711
712
713#endif /* CONFIG_SERIAL_MVEBU_CONSOLE */
714
715static struct uart_driver mvebu_uart_driver = {
716 .owner = THIS_MODULE,
Yehuda Yitschak02c33332017-10-13 11:01:47 +0200717 .driver_name = DRIVER_NAME,
Wilson Ding30530792016-02-16 19:14:53 +0100718 .dev_name = "ttyMV",
719 .nr = MVEBU_NR_UARTS,
720#ifdef CONFIG_SERIAL_MVEBU_CONSOLE
721 .cons = &mvebu_uart_console,
722#endif
723};
724
Miquel Raynal5218d762017-10-13 11:01:49 +0200725static const struct of_device_id mvebu_uart_of_match[];
726
Allen Yan94228f92017-10-13 11:01:48 +0200727/* Counter to keep track of each UART port id when not using CONFIG_OF */
728static int uart_num_counter;
729
Wilson Ding30530792016-02-16 19:14:53 +0100730static int mvebu_uart_probe(struct platform_device *pdev)
731{
732 struct resource *reg = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Miquel Raynal5218d762017-10-13 11:01:49 +0200733 const struct of_device_id *match = of_match_device(mvebu_uart_of_match,
734 &pdev->dev);
Wilson Ding30530792016-02-16 19:14:53 +0100735 struct uart_port *port;
Miquel Raynal5218d762017-10-13 11:01:49 +0200736 struct mvebu_uart *mvuart;
Miquel Raynal95f78762017-10-13 11:01:54 +0200737 int ret, id, irq;
Wilson Ding30530792016-02-16 19:14:53 +0100738
Miquel Raynal95f78762017-10-13 11:01:54 +0200739 if (!reg) {
740 dev_err(&pdev->dev, "no registers defined\n");
Wilson Ding30530792016-02-16 19:14:53 +0100741 return -EINVAL;
742 }
743
Allen Yan94228f92017-10-13 11:01:48 +0200744 /* Assume that all UART ports have a DT alias or none has */
745 id = of_alias_get_id(pdev->dev.of_node, "serial");
746 if (!pdev->dev.of_node || id < 0)
747 pdev->id = uart_num_counter++;
748 else
749 pdev->id = id;
750
751 if (pdev->id >= MVEBU_NR_UARTS) {
752 dev_err(&pdev->dev, "cannot have more than %d UART ports\n",
753 MVEBU_NR_UARTS);
754 return -EINVAL;
755 }
756
757 port = &mvebu_uart_ports[pdev->id];
Wilson Ding30530792016-02-16 19:14:53 +0100758
759 spin_lock_init(&port->lock);
760
761 port->dev = &pdev->dev;
762 port->type = PORT_MVEBU;
763 port->ops = &mvebu_uart_ops;
764 port->regshift = 0;
765
766 port->fifosize = 32;
767 port->iotype = UPIO_MEM32;
768 port->flags = UPF_FIXED_PORT;
Allen Yan94228f92017-10-13 11:01:48 +0200769 port->line = pdev->id;
Wilson Ding30530792016-02-16 19:14:53 +0100770
Miquel Raynal95f78762017-10-13 11:01:54 +0200771 /*
772 * IRQ number is not stored in this structure because we may have two of
773 * them per port (RX and TX). Instead, use the driver UART structure
774 * array so called ->irq[].
775 */
776 port->irq = 0;
Wilson Ding30530792016-02-16 19:14:53 +0100777 port->irqflags = 0;
778 port->mapbase = reg->start;
779
780 port->membase = devm_ioremap_resource(&pdev->dev, reg);
781 if (IS_ERR(port->membase))
782 return -PTR_ERR(port->membase);
783
Miquel Raynal5218d762017-10-13 11:01:49 +0200784 mvuart = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_uart),
785 GFP_KERNEL);
786 if (!mvuart)
Wilson Ding30530792016-02-16 19:14:53 +0100787 return -ENOMEM;
788
Allen Yan68a0db12017-10-13 11:01:51 +0200789 /* Get controller data depending on the compatible string */
Miquel Raynal5218d762017-10-13 11:01:49 +0200790 mvuart->data = (struct mvebu_uart_driver_data *)match->data;
791 mvuart->port = port;
Wilson Ding30530792016-02-16 19:14:53 +0100792
Miquel Raynal5218d762017-10-13 11:01:49 +0200793 port->private_data = mvuart;
794 platform_set_drvdata(pdev, mvuart);
Wilson Ding30530792016-02-16 19:14:53 +0100795
Allen Yan68a0db12017-10-13 11:01:51 +0200796 /* Get fixed clock frequency */
797 mvuart->clk = devm_clk_get(&pdev->dev, NULL);
798 if (IS_ERR(mvuart->clk)) {
799 if (PTR_ERR(mvuart->clk) == -EPROBE_DEFER)
800 return PTR_ERR(mvuart->clk);
801
802 if (IS_EXTENDED(port)) {
803 dev_err(&pdev->dev, "unable to get UART clock\n");
804 return PTR_ERR(mvuart->clk);
805 }
806 } else {
807 if (!clk_prepare_enable(mvuart->clk))
808 port->uartclk = clk_get_rate(mvuart->clk);
809 }
810
Miquel Raynal95f78762017-10-13 11:01:54 +0200811 /* Manage interrupts */
812 memset(mvuart->irq, 0, UART_IRQ_COUNT);
813 if (platform_irq_count(pdev) == 1) {
814 /* Old bindings: no name on the single unamed UART0 IRQ */
815 irq = platform_get_irq(pdev, 0);
816 if (irq < 0) {
817 dev_err(&pdev->dev, "unable to get UART IRQ\n");
818 return irq;
819 }
820
821 mvuart->irq[UART_IRQ_SUM] = irq;
822 } else {
823 /*
824 * New bindings: named interrupts (RX, TX) for both UARTS,
825 * only make use of uart-rx and uart-tx interrupts, do not use
826 * uart-sum of UART0 port.
827 */
828 irq = platform_get_irq_byname(pdev, "uart-rx");
829 if (irq < 0) {
830 dev_err(&pdev->dev, "unable to get 'uart-rx' IRQ\n");
831 return irq;
832 }
833
834 mvuart->irq[UART_RX_IRQ] = irq;
835
836 irq = platform_get_irq_byname(pdev, "uart-tx");
837 if (irq < 0) {
838 dev_err(&pdev->dev, "unable to get 'uart-tx' IRQ\n");
839 return irq;
840 }
841
842 mvuart->irq[UART_TX_IRQ] = irq;
843 }
844
Allen Yan9c3d3ee2017-10-13 11:01:50 +0200845 /* UART Soft Reset*/
846 writel(CTRL_SOFT_RST, port->membase + UART_CTRL(port));
847 udelay(1);
848 writel(0, port->membase + UART_CTRL(port));
849
Wilson Ding30530792016-02-16 19:14:53 +0100850 ret = uart_add_one_port(&mvebu_uart_driver, port);
851 if (ret)
852 return ret;
853 return 0;
854}
855
Miquel Raynal5218d762017-10-13 11:01:49 +0200856static struct mvebu_uart_driver_data uart_std_driver_data = {
857 .is_ext = false,
858 .regs.rbr = UART_STD_RBR,
859 .regs.tsh = UART_STD_TSH,
860 .regs.ctrl = UART_STD_CTRL1,
861 .regs.intr = UART_STD_CTRL2,
862 .flags.ctrl_tx_rdy_int = CTRL_STD_TX_RDY_INT,
863 .flags.ctrl_rx_rdy_int = CTRL_STD_RX_RDY_INT,
864 .flags.stat_tx_rdy = STAT_STD_TX_RDY,
865 .flags.stat_rx_rdy = STAT_STD_RX_RDY,
866};
867
Wilson Ding30530792016-02-16 19:14:53 +0100868/* Match table for of_platform binding */
869static const struct of_device_id mvebu_uart_of_match[] = {
Miquel Raynal5218d762017-10-13 11:01:49 +0200870 {
871 .compatible = "marvell,armada-3700-uart",
872 .data = (void *)&uart_std_driver_data,
873 },
Wilson Ding30530792016-02-16 19:14:53 +0100874 {}
875};
Wilson Ding30530792016-02-16 19:14:53 +0100876
877static struct platform_driver mvebu_uart_platform_driver = {
878 .probe = mvebu_uart_probe,
Wilson Ding30530792016-02-16 19:14:53 +0100879 .driver = {
Wilson Ding30530792016-02-16 19:14:53 +0100880 .name = "mvebu-uart",
881 .of_match_table = of_match_ptr(mvebu_uart_of_match),
Paul Gortmaker89ebc272016-03-13 19:48:52 -0400882 .suppress_bind_attrs = true,
Wilson Ding30530792016-02-16 19:14:53 +0100883 },
884};
885
886static int __init mvebu_uart_init(void)
887{
888 int ret;
889
890 ret = uart_register_driver(&mvebu_uart_driver);
891 if (ret)
892 return ret;
893
894 ret = platform_driver_register(&mvebu_uart_platform_driver);
895 if (ret)
896 uart_unregister_driver(&mvebu_uart_driver);
897
898 return ret;
899}
Wilson Ding30530792016-02-16 19:14:53 +0100900arch_initcall(mvebu_uart_init);