]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/amlogic/aml8726/uart_dev_aml8726.c
Update tcpdump to 4.9.2
[FreeBSD/FreeBSD.git] / sys / arm / amlogic / aml8726 / uart_dev_aml8726.c
1 /*-
2  * Copyright 2013-2015 John Wehle <john@feith.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 /*
28  * Amlogic aml8726 UART driver.
29  *
30  * The current implementation only targets features common to all
31  * uarts.  For example ... though UART A as a 128 byte FIFO, the
32  * others only have a 64 byte FIFO.
33  *
34  * Also, it's assumed that the USE_XTAL_CLK feature (available on
35  * the aml8726-m6 and later) has not been activated.
36  */
37
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/bus.h>
44 #include <sys/conf.h>
45 #include <sys/kernel.h>
46 #include <sys/sysctl.h>
47
48 #include <machine/bus.h>
49 #include <machine/cpu.h>
50
51 #include <dev/ofw/ofw_bus.h>
52 #include <dev/ofw/ofw_bus_subr.h>
53
54 #include <dev/uart/uart.h>
55 #include <dev/uart/uart_cpu.h>
56 #include <dev/uart/uart_cpu_fdt.h>
57 #include <dev/uart/uart_bus.h>
58
59 #include <arm/amlogic/aml8726/aml8726_soc.h>
60 #include <arm/amlogic/aml8726/aml8726_uart.h>
61
62 #include "uart_if.h"
63
64 #undef  uart_getreg
65 #undef  uart_setreg
66
67 #define uart_getreg(bas, reg)           \
68     bus_space_read_4((bas)->bst, (bas)->bsh, reg)
69 #define uart_setreg(bas, reg, value)    \
70     bus_space_write_4((bas)->bst, (bas)->bsh, reg, value)
71
72 #define SIGCHG(c, i, s, d)                              \
73         do {                                            \
74                 if (c) {                                \
75                         i |= (i & s) ? s : s | d;       \
76                 } else {                                \
77                         i = (i & s) ? (i & ~s) | d : i; \
78                 }                                       \
79         } while (0)
80
81 static int
82 aml8726_uart_divisor(int rclk, int baudrate)
83 {
84         int actual_baud, divisor;
85         int error;
86
87         if (baudrate == 0)
88                 return (0);
89
90         /* integer version of (rclk / baudrate + .5) */
91         divisor = ((rclk << 1) + baudrate) / (baudrate << 1);
92         if (divisor == 0)
93                 return (0);
94         actual_baud = rclk / divisor;
95
96         /* 10 times error in percent: */
97         error = (((actual_baud - baudrate) * 2000) / baudrate + 1) >> 1;
98
99         /* 3.0% maximum error tolerance: */
100         if (error < -30 || error > 30)
101                 return (0);
102
103         return (divisor);
104 }
105
106 static int
107 aml8726_uart_param(struct uart_bas *bas, int baudrate, int databits, int stopbits,
108     int parity)
109 {
110         uint32_t cr;
111         uint32_t mr;
112         uint32_t nbr;
113         int divisor;
114
115         cr = uart_getreg(bas, AML_UART_CONTROL_REG);
116
117         cr &= ~(AML_UART_CONTROL_DB_MASK | AML_UART_CONTROL_SB_MASK |
118             AML_UART_CONTROL_P_MASK);
119
120         switch (databits) {
121         case 5:         cr |= AML_UART_CONTROL_5_DB; break;
122         case 6:         cr |= AML_UART_CONTROL_6_DB; break;
123         case 7:         cr |= AML_UART_CONTROL_7_DB; break;
124         case 8:         cr |= AML_UART_CONTROL_8_DB; break;
125         default:        return (EINVAL);
126         }
127
128         switch (stopbits) {
129         case 1:         cr |= AML_UART_CONTROL_1_SB; break;
130         case 2:         cr |= AML_UART_CONTROL_2_SB; break;
131         default:        return (EINVAL);
132         }
133
134         switch (parity) {
135         case UART_PARITY_EVEN:  cr |= AML_UART_CONTROL_P_EVEN;
136                                 cr |= AML_UART_CONTROL_P_EN;
137                                 break;
138
139         case UART_PARITY_ODD:   cr |= AML_UART_CONTROL_P_ODD;
140                                 cr |= AML_UART_CONTROL_P_EN;
141                                 break;
142
143         case UART_PARITY_NONE:  break;
144
145         default:        return (EINVAL);
146         }
147
148         /* Set baudrate. */
149         if (baudrate > 0 && bas->rclk != 0) {
150                 divisor = aml8726_uart_divisor(bas->rclk / 4, baudrate) - 1;
151
152                 switch (aml8726_soc_hw_rev) {
153                 case AML_SOC_HW_REV_M6:
154                 case AML_SOC_HW_REV_M8:
155                 case AML_SOC_HW_REV_M8B:
156                         if (divisor > (AML_UART_NEW_BAUD_RATE_MASK >>
157                             AML_UART_NEW_BAUD_RATE_SHIFT))
158                                 return (EINVAL);
159
160                         nbr = uart_getreg(bas, AML_UART_NEW_BAUD_REG);
161                         nbr &= ~(AML_UART_NEW_BAUD_USE_XTAL_CLK |
162                             AML_UART_NEW_BAUD_RATE_MASK);
163                         nbr |= AML_UART_NEW_BAUD_RATE_EN |
164                             (divisor << AML_UART_NEW_BAUD_RATE_SHIFT);
165                         uart_setreg(bas, AML_UART_NEW_BAUD_REG, nbr);
166
167                         divisor = 0;
168                         break;
169                 default:
170                         if (divisor > 0xffff)
171                                 return (EINVAL);
172                         break;
173                 }
174
175                 cr &= ~AML_UART_CONTROL_BAUD_MASK;
176                 cr |= (divisor & AML_UART_CONTROL_BAUD_MASK);
177
178                 divisor >>= AML_UART_CONTROL_BAUD_WIDTH;
179
180                 mr = uart_getreg(bas, AML_UART_MISC_REG);
181                 mr &= ~(AML_UART_MISC_OLD_RX_BAUD |
182                     AML_UART_MISC_BAUD_EXT_MASK);
183                 mr |= ((divisor << AML_UART_MISC_BAUD_EXT_SHIFT) &
184                     AML_UART_MISC_BAUD_EXT_MASK);
185                 uart_setreg(bas, AML_UART_MISC_REG, mr);
186         }
187
188         uart_setreg(bas, AML_UART_CONTROL_REG, cr);
189         uart_barrier(bas);
190
191         return (0);
192 }
193
194 /*
195  * Low-level UART interface.
196  */
197
198 static int
199 aml8726_uart_probe(struct uart_bas *bas)
200 {
201
202         return (0);
203 }
204
205 static void
206 aml8726_uart_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
207     int parity)
208 {
209         uint32_t cr;
210         uint32_t mr;
211
212         (void)aml8726_uart_param(bas, baudrate, databits, stopbits, parity);
213
214         cr = uart_getreg(bas, AML_UART_CONTROL_REG);
215         /* Disable all interrupt sources. */
216         cr &= ~(AML_UART_CONTROL_TX_INT_EN | AML_UART_CONTROL_RX_INT_EN);
217         /* Reset the transmitter and receiver. */
218         cr |= (AML_UART_CONTROL_TX_RST | AML_UART_CONTROL_RX_RST);
219         /* Enable the transmitter and receiver. */
220         cr |= (AML_UART_CONTROL_TX_EN | AML_UART_CONTROL_RX_EN);
221         uart_setreg(bas, AML_UART_CONTROL_REG, cr);
222         uart_barrier(bas);
223
224         /* Clear RX FIFO level for generating interrupts. */
225         mr = uart_getreg(bas, AML_UART_MISC_REG);
226         mr &= ~AML_UART_MISC_RECV_IRQ_CNT_MASK;
227         uart_setreg(bas, AML_UART_MISC_REG, mr);
228         uart_barrier(bas);
229
230         /* Ensure the reset bits are clear. */
231         cr &= ~(AML_UART_CONTROL_TX_RST | AML_UART_CONTROL_RX_RST);
232         uart_setreg(bas, AML_UART_CONTROL_REG, cr);
233         uart_barrier(bas);
234 }
235
236 static void
237 aml8726_uart_term(struct uart_bas *bas)
238 {
239 }
240
241 static void
242 aml8726_uart_putc(struct uart_bas *bas, int c)
243 {
244
245         while ((uart_getreg(bas, AML_UART_STATUS_REG) &
246             AML_UART_STATUS_TX_FIFO_FULL) != 0)
247                 cpu_spinwait();
248
249         uart_setreg(bas, AML_UART_WFIFO_REG, c);
250         uart_barrier(bas);
251 }
252
253 static int
254 aml8726_uart_rxready(struct uart_bas *bas)
255 {
256
257         return ((uart_getreg(bas, AML_UART_STATUS_REG) &
258             AML_UART_STATUS_RX_FIFO_EMPTY) == 0 ? 1 : 0);
259 }
260
261 static int
262 aml8726_uart_getc(struct uart_bas *bas, struct mtx *hwmtx)
263 {
264         int c;
265
266         uart_lock(hwmtx);
267
268         while ((uart_getreg(bas, AML_UART_STATUS_REG) &
269             AML_UART_STATUS_RX_FIFO_EMPTY) != 0) {
270                 uart_unlock(hwmtx);
271                 DELAY(4);
272                 uart_lock(hwmtx);
273         }
274
275         c = uart_getreg(bas, AML_UART_RFIFO_REG) & 0xff;
276
277         uart_unlock(hwmtx);
278
279         return (c);
280 }
281
282 struct uart_ops aml8726_uart_ops = {
283         .probe = aml8726_uart_probe,
284         .init = aml8726_uart_init,
285         .term = aml8726_uart_term,
286         .putc = aml8726_uart_putc,
287         .rxready = aml8726_uart_rxready,
288         .getc = aml8726_uart_getc,
289 };
290
291 static unsigned int
292 aml8726_uart_bus_clk(phandle_t node)
293 {
294         pcell_t prop;
295         ssize_t len;
296         phandle_t clk_node;
297
298         len = OF_getencprop(node, "clocks", &prop, sizeof(prop));
299         if ((len / sizeof(prop)) != 1 || prop == 0 ||
300             (clk_node = OF_node_from_xref(prop)) == 0)
301                 return (0);
302
303         len = OF_getencprop(clk_node, "clock-frequency", &prop, sizeof(prop));
304         if ((len / sizeof(prop)) != 1 || prop == 0)
305                 return (0);
306
307         return ((unsigned int)prop);
308 }
309
310 static int
311 aml8726_uart_bus_probe(struct uart_softc *sc)
312 {
313         int error;
314
315         error = aml8726_uart_probe(&sc->sc_bas);
316         if (error)
317                 return (error);
318
319         sc->sc_rxfifosz = 64;
320         sc->sc_txfifosz = 64;
321         sc->sc_hwiflow = 1;
322         sc->sc_hwoflow = 1;
323
324         device_set_desc(sc->sc_dev, "Amlogic aml8726 UART");
325
326         return (0);
327 }
328
329 static int
330 aml8726_uart_bus_getsig(struct uart_softc *sc)
331 {
332         uint32_t new, old, sig;
333
334         /*
335          * Treat DSR, DCD, and CTS as always on.
336          */
337
338         do {
339                 old = sc->sc_hwsig;
340                 sig = old;
341                 SIGCHG(1, sig, SER_DSR, SER_DDSR);
342                 SIGCHG(1, sig, SER_DCD, SER_DDCD);
343                 SIGCHG(1, sig, SER_CTS, SER_DCTS);
344                 new = sig & ~SER_MASK_DELTA;
345         } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
346
347         return (sig);
348 }
349
350 static int
351 aml8726_uart_bus_setsig(struct uart_softc *sc, int sig)
352 {
353         uint32_t new, old;
354
355         do {
356                 old = sc->sc_hwsig;
357                 new = old;
358                 if (sig & SER_DDTR) {
359                         SIGCHG(sig & SER_DTR, new, SER_DTR, SER_DDTR);
360                 }
361                 if (sig & SER_DRTS) {
362                         SIGCHG(sig & SER_RTS, new, SER_RTS, SER_DRTS);
363                 }
364          } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
365
366         return (0);
367 }
368
369 static int
370 aml8726_uart_bus_attach(struct uart_softc *sc)
371 {
372         struct uart_bas *bas;
373         uint32_t cr;
374         uint32_t mr;
375
376         bas = &sc->sc_bas;
377
378         bas->rclk = aml8726_uart_bus_clk(ofw_bus_get_node(sc->sc_dev));
379
380         if (bas->rclk == 0) {
381                 device_printf(sc->sc_dev, "missing clocks attribute in FDT\n");
382                 return (ENXIO);
383         }
384
385         cr = uart_getreg(bas, AML_UART_CONTROL_REG);
386         /* Disable all interrupt sources. */
387         cr &= ~(AML_UART_CONTROL_TX_INT_EN | AML_UART_CONTROL_RX_INT_EN);
388         /* Ensure the reset bits are clear. */
389         cr &= ~(AML_UART_CONTROL_TX_RST | AML_UART_CONTROL_RX_RST);
390
391         /*
392          * Reset the transmitter and receiver only if not acting as a
393          * console, otherwise it means that:
394          *
395          * 1) aml8726_uart_init was already called which did the reset
396          *
397          * 2) there may be console bytes sitting in the transmit fifo
398          */
399         if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE)
400                 ;
401         else
402                 cr |= (AML_UART_CONTROL_TX_RST | AML_UART_CONTROL_RX_RST);
403
404         /* Default to two wire mode. */
405         cr |= AML_UART_CONTROL_TWO_WIRE_EN;
406         /* Enable the transmitter and receiver. */
407         cr |= (AML_UART_CONTROL_TX_EN | AML_UART_CONTROL_RX_EN);
408         /* Reset error bits. */
409         cr |= AML_UART_CONTROL_CLR_ERR;
410         uart_setreg(bas, AML_UART_CONTROL_REG, cr);
411         uart_barrier(bas);
412
413         /* Set FIFO levels for generating interrupts. */
414         mr = uart_getreg(bas, AML_UART_MISC_REG);
415         mr &= ~AML_UART_MISC_XMIT_IRQ_CNT_MASK;
416         mr |= (0 << AML_UART_MISC_XMIT_IRQ_CNT_SHIFT);
417         mr &= ~AML_UART_MISC_RECV_IRQ_CNT_MASK;
418         mr |= (1 << AML_UART_MISC_RECV_IRQ_CNT_SHIFT);
419         uart_setreg(bas, AML_UART_MISC_REG, mr);
420         uart_barrier(bas);
421
422         aml8726_uart_bus_getsig(sc);
423
424         /* Ensure the reset bits are clear. */
425         cr &= ~(AML_UART_CONTROL_TX_RST | AML_UART_CONTROL_RX_RST);
426         cr &= ~AML_UART_CONTROL_CLR_ERR;
427         /* Enable the receive interrupt. */
428         cr |= AML_UART_CONTROL_RX_INT_EN;
429         uart_setreg(bas, AML_UART_CONTROL_REG, cr);
430         uart_barrier(bas);
431
432         return (0);
433 }
434
435 static int
436 aml8726_uart_bus_detach(struct uart_softc *sc)
437 {
438         struct uart_bas *bas;
439         uint32_t cr;
440         uint32_t mr;
441
442         bas = &sc->sc_bas;
443
444         /* Disable all interrupt sources. */
445         cr = uart_getreg(bas, AML_UART_CONTROL_REG);
446         cr &= ~(AML_UART_CONTROL_TX_INT_EN | AML_UART_CONTROL_RX_INT_EN);
447         uart_setreg(bas, AML_UART_CONTROL_REG, cr);
448         uart_barrier(bas);
449
450         /* Clear RX FIFO level for generating interrupts. */
451         mr = uart_getreg(bas, AML_UART_MISC_REG);
452         mr &= ~AML_UART_MISC_RECV_IRQ_CNT_MASK;
453         uart_setreg(bas, AML_UART_MISC_REG, mr);
454         uart_barrier(bas);
455
456         return (0);
457 }
458
459 static int
460 aml8726_uart_bus_flush(struct uart_softc *sc, int what)
461 {
462         struct uart_bas *bas;
463         uint32_t cr;
464
465         bas = &sc->sc_bas;
466         uart_lock(sc->sc_hwmtx);
467
468         cr = uart_getreg(bas, AML_UART_CONTROL_REG);
469         if (what & UART_FLUSH_TRANSMITTER)
470                 cr |= AML_UART_CONTROL_TX_RST;
471         if (what & UART_FLUSH_RECEIVER)
472                 cr |= AML_UART_CONTROL_RX_RST;
473         uart_setreg(bas, AML_UART_CONTROL_REG, cr);
474         uart_barrier(bas);
475
476         /* Ensure the reset bits are clear. */
477         cr &= ~(AML_UART_CONTROL_TX_RST | AML_UART_CONTROL_RX_RST);
478         uart_setreg(bas, AML_UART_CONTROL_REG, cr);
479         uart_barrier(bas);
480
481         uart_unlock(sc->sc_hwmtx);
482
483         return (0);
484 }
485
486 static int
487 aml8726_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
488 {
489         struct uart_bas *bas;
490         int baudrate, divisor, error;
491         uint32_t cr, mr, nbr;
492
493         bas = &sc->sc_bas;
494         uart_lock(sc->sc_hwmtx);
495
496         error = 0;
497         switch (request) {
498         case UART_IOCTL_BAUD:
499                 cr = uart_getreg(bas, AML_UART_CONTROL_REG);
500                 cr &= AML_UART_CONTROL_BAUD_MASK;
501
502                 mr = uart_getreg(bas, AML_UART_MISC_REG);
503                 mr &= AML_UART_MISC_BAUD_EXT_MASK;
504
505                 divisor = ((mr >> AML_UART_MISC_BAUD_EXT_SHIFT) <<
506                     AML_UART_CONTROL_BAUD_WIDTH) | cr;
507
508                 switch (aml8726_soc_hw_rev) {
509                 case AML_SOC_HW_REV_M6:
510                 case AML_SOC_HW_REV_M8:
511                 case AML_SOC_HW_REV_M8B:
512                         nbr = uart_getreg(bas, AML_UART_NEW_BAUD_REG);
513                         if ((nbr & AML_UART_NEW_BAUD_RATE_EN) != 0) {
514                                 divisor = (nbr & AML_UART_NEW_BAUD_RATE_MASK) >>
515                                     AML_UART_NEW_BAUD_RATE_SHIFT;
516                         }
517                         break;
518                 default:
519                         break;
520                 }
521
522                 baudrate = bas->rclk / 4 / (divisor + 1);
523                 if (baudrate > 0)
524                         *(int*)data = baudrate;
525                 else
526                         error = ENXIO;
527                 break;
528
529         case UART_IOCTL_IFLOW:
530         case UART_IOCTL_OFLOW:
531                 cr = uart_getreg(bas, AML_UART_CONTROL_REG);
532                 if (data)
533                         cr &= ~AML_UART_CONTROL_TWO_WIRE_EN;
534                 else
535                         cr |= AML_UART_CONTROL_TWO_WIRE_EN;
536                 uart_setreg(bas, AML_UART_CONTROL_REG, cr);
537                 break;
538
539         default:
540                 error = EINVAL;
541                 break;
542         }
543
544         uart_unlock(sc->sc_hwmtx);
545
546         return (error);
547 }
548
549 static int
550 aml8726_uart_bus_ipend(struct uart_softc *sc)
551 {
552         struct uart_bas *bas;
553         int ipend;
554         uint32_t sr;
555         uint32_t cr;
556
557         bas = &sc->sc_bas;
558         uart_lock(sc->sc_hwmtx);
559
560         ipend = 0;
561         sr = uart_getreg(bas, AML_UART_STATUS_REG);
562         cr = uart_getreg(bas, AML_UART_CONTROL_REG);
563
564         if ((sr & AML_UART_STATUS_RX_FIFO_OVERFLOW) != 0)
565                 ipend |= SER_INT_OVERRUN;
566
567         if ((sr & AML_UART_STATUS_TX_FIFO_EMPTY) != 0 &&
568             (cr & AML_UART_CONTROL_TX_INT_EN) != 0) {
569                 ipend |= SER_INT_TXIDLE;
570
571                 cr &= ~AML_UART_CONTROL_TX_INT_EN;
572                 uart_setreg(bas, AML_UART_CONTROL_REG, cr);
573                 uart_barrier(bas);
574         }
575
576         if ((sr & AML_UART_STATUS_RX_FIFO_EMPTY) == 0)
577                 ipend |= SER_INT_RXREADY;
578
579         uart_unlock(sc->sc_hwmtx);
580
581         return (ipend);
582 }
583
584 static int
585 aml8726_uart_bus_param(struct uart_softc *sc, int baudrate, int databits,
586     int stopbits, int parity)
587 {
588         struct uart_bas *bas;
589         int error;
590
591         bas = &sc->sc_bas;
592         uart_lock(sc->sc_hwmtx);
593
594         error = aml8726_uart_param(bas, baudrate, databits, stopbits, parity);
595
596         uart_unlock(sc->sc_hwmtx);
597
598         return (error);
599 }
600
601 static int
602 aml8726_uart_bus_receive(struct uart_softc *sc)
603 {
604         struct uart_bas *bas;
605         int xc;
606         uint32_t sr;
607
608         bas = &sc->sc_bas;
609         uart_lock(sc->sc_hwmtx);
610
611         sr = uart_getreg(bas, AML_UART_STATUS_REG);
612         while ((sr & AML_UART_STATUS_RX_FIFO_EMPTY) == 0) {
613                 if (uart_rx_full(sc)) {
614                         sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
615                         break;
616                 }
617                 xc = uart_getreg(bas, AML_UART_RFIFO_REG) & 0xff;
618                 if (sr & AML_UART_STATUS_FRAME_ERR)
619                         xc |= UART_STAT_FRAMERR;
620                 if (sr & AML_UART_STATUS_PARITY_ERR)
621                         xc |= UART_STAT_PARERR;
622                 uart_rx_put(sc, xc);
623                 sr = uart_getreg(bas, AML_UART_STATUS_REG);
624         }
625         /* Discard everything left in the RX FIFO. */
626         while ((sr & AML_UART_STATUS_RX_FIFO_EMPTY) == 0) {
627                 (void)uart_getreg(bas, AML_UART_RFIFO_REG);
628                 sr = uart_getreg(bas, AML_UART_STATUS_REG);
629         }
630         /* Reset error bits */
631         if ((sr & (AML_UART_STATUS_FRAME_ERR | AML_UART_STATUS_PARITY_ERR)) != 0) {
632                 uart_setreg(bas, AML_UART_CONTROL_REG,
633                     (uart_getreg(bas, AML_UART_CONTROL_REG) |
634                     AML_UART_CONTROL_CLR_ERR));
635                 uart_barrier(bas);
636                 uart_setreg(bas, AML_UART_CONTROL_REG,
637                     (uart_getreg(bas, AML_UART_CONTROL_REG) &
638                     ~AML_UART_CONTROL_CLR_ERR));
639                 uart_barrier(bas);
640         }
641
642         uart_unlock(sc->sc_hwmtx);
643
644         return (0);
645 }
646
647 static int
648 aml8726_uart_bus_transmit(struct uart_softc *sc)
649 {
650         struct uart_bas *bas;
651         int i;
652         uint32_t cr;
653
654         bas = &sc->sc_bas;
655         uart_lock(sc->sc_hwmtx);
656
657         /*
658          * Wait for sufficient space since aml8726_uart_putc
659          * may have been called after SER_INT_TXIDLE occurred.
660          */
661         while ((uart_getreg(bas, AML_UART_STATUS_REG) &
662             AML_UART_STATUS_TX_FIFO_EMPTY) == 0)
663                 cpu_spinwait();
664
665         for (i = 0; i < sc->sc_txdatasz; i++) {
666                 uart_setreg(bas, AML_UART_WFIFO_REG, sc->sc_txbuf[i]);
667                 uart_barrier(bas);
668         }
669
670         sc->sc_txbusy = 1;
671
672         cr = uart_getreg(bas, AML_UART_CONTROL_REG);
673         cr |= AML_UART_CONTROL_TX_INT_EN;
674         uart_setreg(bas, AML_UART_CONTROL_REG, cr);
675         uart_barrier(bas);
676
677         uart_unlock(sc->sc_hwmtx);
678
679         return (0);
680 }
681
682 static void
683 aml8726_uart_bus_grab(struct uart_softc *sc)
684 {
685         struct uart_bas *bas;
686         uint32_t cr;
687
688         /*
689          * Disable the receive interrupt to avoid a race between
690          * aml8726_uart_getc and aml8726_uart_bus_receive which
691          * can trigger:
692          *
693          *   panic: bad stray interrupt
694          *
695          * due to the RX FIFO receiving a character causing an
696          * interrupt which gets serviced after aml8726_uart_getc
697          * has been called (meaning the RX FIFO is now empty).
698          */
699
700         bas = &sc->sc_bas;
701         uart_lock(sc->sc_hwmtx);
702
703         cr = uart_getreg(bas, AML_UART_CONTROL_REG);
704         cr &= ~AML_UART_CONTROL_RX_INT_EN;
705         uart_setreg(bas, AML_UART_CONTROL_REG, cr);
706         uart_barrier(bas);
707
708         uart_unlock(sc->sc_hwmtx);
709 }
710
711 static void
712 aml8726_uart_bus_ungrab(struct uart_softc *sc)
713 {
714         struct uart_bas *bas;
715         uint32_t cr;
716         uint32_t mr;
717
718         /*
719          * The RX FIFO level being set indicates that the device
720          * is currently attached meaning the receive interrupt
721          * should be enabled.
722          */
723
724         bas = &sc->sc_bas;
725         uart_lock(sc->sc_hwmtx);
726
727         mr = uart_getreg(bas, AML_UART_MISC_REG);
728         mr &= AML_UART_MISC_RECV_IRQ_CNT_MASK;
729
730         if (mr != 0) {
731                 cr = uart_getreg(bas, AML_UART_CONTROL_REG);
732                 cr |= AML_UART_CONTROL_RX_INT_EN;
733                 uart_setreg(bas, AML_UART_CONTROL_REG, cr);
734                 uart_barrier(bas);
735         }
736
737         uart_unlock(sc->sc_hwmtx);
738 }
739
740 static kobj_method_t aml8726_uart_methods[] = {
741         KOBJMETHOD(uart_probe,          aml8726_uart_bus_probe),
742         KOBJMETHOD(uart_attach,         aml8726_uart_bus_attach),
743         KOBJMETHOD(uart_detach,         aml8726_uart_bus_detach),
744         KOBJMETHOD(uart_flush,          aml8726_uart_bus_flush),
745         KOBJMETHOD(uart_getsig,         aml8726_uart_bus_getsig),
746         KOBJMETHOD(uart_setsig,         aml8726_uart_bus_setsig),
747         KOBJMETHOD(uart_ioctl,          aml8726_uart_bus_ioctl),
748         KOBJMETHOD(uart_ipend,          aml8726_uart_bus_ipend),
749         KOBJMETHOD(uart_param,          aml8726_uart_bus_param),
750         KOBJMETHOD(uart_receive,        aml8726_uart_bus_receive),
751         KOBJMETHOD(uart_transmit,       aml8726_uart_bus_transmit),
752         KOBJMETHOD(uart_grab,           aml8726_uart_bus_grab),
753         KOBJMETHOD(uart_ungrab,         aml8726_uart_bus_ungrab),
754         { 0, 0 }
755 };
756
757 struct uart_class uart_aml8726_class = {
758         "uart",
759         aml8726_uart_methods,
760         sizeof(struct uart_softc),
761         .uc_ops = &aml8726_uart_ops,
762         .uc_range = 24,
763         .uc_rclk = 0,
764         .uc_rshift = 0
765 };
766
767 static struct ofw_compat_data compat_data[] = {
768         { "amlogic,meson-uart",         (uintptr_t)&uart_aml8726_class },
769         { NULL,                         (uintptr_t)NULL }
770 };
771 UART_FDT_CLASS_AND_DEVICE(compat_data);