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