]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/mips/rt305x/uart_dev_rt305x.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / mips / rt305x / uart_dev_rt305x.c
1 /* $NetBSD: uart.c,v 1.2 2007/03/23 20:05:47 dogcow Exp $ */
2
3 /*-
4  * Copyright (c) 2010 Aleksandr Rybalko.
5  * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko.
6  * Copyright (c) 2007 Oleksandr Tymoshenko.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or
10  * without modification, are permitted provided that the following
11  * conditions are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above
15  *    copyright notice, this list of conditions and the following
16  *    disclaimer in the documentation and/or other materials provided
17  *    with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
24  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
26  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
28  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30  * OF SUCH DAMAGE.
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include "opt_ddb.h"
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/bus.h>
41 #include <sys/conf.h>
42 #include <sys/kdb.h>
43 #include <sys/reboot.h>
44 #include <sys/sysctl.h>
45 #include <sys/kernel.h>
46 #include <machine/bus.h>
47
48 #include <dev/uart/uart.h>
49 #include <dev/uart/uart_cpu.h>
50 #include <dev/uart/uart_bus.h>
51
52 #include <mips/rt305x/uart_dev_rt305x.h>
53 #include <mips/rt305x/rt305xreg.h>
54
55 #include "uart_if.h"
56 /*
57  * Low-level UART interface.
58  */
59 static int rt305x_uart_probe(struct uart_bas *bas);
60 static void rt305x_uart_init(struct uart_bas *bas, int, int, int, int);
61 static void rt305x_uart_term(struct uart_bas *bas);
62 static void rt305x_uart_putc(struct uart_bas *bas, int);
63 static int rt305x_uart_rxready(struct uart_bas *bas);
64 static int rt305x_uart_getc(struct uart_bas *bas, struct mtx *);
65
66 static struct uart_ops uart_rt305x_uart_ops = {
67         .probe = rt305x_uart_probe,
68         .init = rt305x_uart_init,
69         .term = rt305x_uart_term,
70         .putc = rt305x_uart_putc,
71         .rxready = rt305x_uart_rxready,
72         .getc = rt305x_uart_getc,
73 };
74
75 static int      uart_output = 1;
76 TUNABLE_INT("kern.uart_output", &uart_output);
77 SYSCTL_INT(_kern, OID_AUTO, uart_output, CTLFLAG_RW,
78     &uart_output, 0, "UART output enabled.");
79
80
81
82
83 static int
84 rt305x_uart_probe(struct uart_bas *bas)
85 {
86
87         return (0);
88 }
89
90 static void
91 rt305x_uart_init(struct uart_bas *bas, int baudrate, int databits, 
92     int stopbits, int parity)
93 {
94 #ifdef notyet
95         /* CLKDIV  = 384000000/ 3/ 16/ br */
96         /* for 384MHz CLKDIV = 8000000 / baudrate; */
97         switch (databits) {
98         case 5:
99                 databits = UART_LCR_5B;
100                 break;
101         case 6:
102                 databits = UART_LCR_6B;
103                 break;
104         case 7:
105                 databits = UART_LCR_7B;
106                 break;
107         case 8:
108                 databits = UART_LCR_8B;
109                 break;
110         default:
111                 /* Unsupported */
112                 return;
113         }
114         switch (parity) {
115         case UART_PARITY_EVEN:  parity = (UART_LCR_PEN|UART_LCR_EVEN); break;
116         case UART_PARITY_NONE:  parity = (UART_LCR_PEN); break;
117         case UART_PARITY_ODD:   parity = 0; break;
118         /* Unsupported */
119         default:                return;
120         }
121         uart_setreg(bas, UART_CDDL_REG, 8000000/baudrate);
122         uart_barrier(bas);
123         uart_setreg(bas, UART_LCR_REG, databits | (stopbits==1?0:4) | parity);
124         uart_barrier(bas);
125 #endif
126 }
127
128 static void
129 rt305x_uart_term(struct uart_bas *bas)
130 {
131         uart_setreg(bas, UART_MCR_REG, 0);
132         uart_barrier(bas);
133 }
134
135 static void
136 rt305x_uart_putc(struct uart_bas *bas, int c)
137 {
138         char chr;
139         if (!uart_output) return;
140         chr = c;
141         while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE));
142         uart_setreg(bas, UART_TX_REG, c);
143         uart_barrier(bas);
144         while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE));
145 }
146
147 static int
148 rt305x_uart_rxready(struct uart_bas *bas)
149 {
150 #ifdef notyet
151         if (uart_getreg(bas, UART_LSR_REG) & UART_LSR_DR)
152                 return (1);
153
154         return (0);
155 #else
156         return (1);
157 #endif
158 }
159
160 static int
161 rt305x_uart_getc(struct uart_bas *bas, struct mtx *hwmtx)
162 {
163         int c;
164
165         uart_lock(hwmtx);
166
167         while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_DR)) {
168                 uart_unlock(hwmtx);
169                 DELAY(10);
170                 uart_lock(hwmtx);
171         }
172
173         c = uart_getreg(bas, UART_RX_REG);
174
175         uart_unlock(hwmtx);
176
177         return (c);
178 }
179
180 /*
181  * High-level UART interface.
182  */
183 struct rt305x_uart_softc {
184         struct uart_softc base;
185 };
186
187 static int rt305x_uart_bus_attach(struct uart_softc *);
188 static int rt305x_uart_bus_detach(struct uart_softc *);
189 static int rt305x_uart_bus_flush(struct uart_softc *, int);
190 static int rt305x_uart_bus_getsig(struct uart_softc *);
191 static int rt305x_uart_bus_ioctl(struct uart_softc *, int, intptr_t);
192 static int rt305x_uart_bus_ipend(struct uart_softc *);
193 static int rt305x_uart_bus_param(struct uart_softc *, int, int, int, int);
194 static int rt305x_uart_bus_probe(struct uart_softc *);
195 static int rt305x_uart_bus_receive(struct uart_softc *);
196 static int rt305x_uart_bus_setsig(struct uart_softc *, int);
197 static int rt305x_uart_bus_transmit(struct uart_softc *);
198 static void rt305x_uart_bus_grab(struct uart_softc *);
199 static void rt305x_uart_bus_ungrab(struct uart_softc *);
200
201 static kobj_method_t rt305x_uart_methods[] = {
202         KOBJMETHOD(uart_attach,         rt305x_uart_bus_attach),
203         KOBJMETHOD(uart_detach,         rt305x_uart_bus_detach),
204         KOBJMETHOD(uart_flush,          rt305x_uart_bus_flush),
205         KOBJMETHOD(uart_getsig,         rt305x_uart_bus_getsig),
206         KOBJMETHOD(uart_ioctl,          rt305x_uart_bus_ioctl),
207         KOBJMETHOD(uart_ipend,          rt305x_uart_bus_ipend),
208         KOBJMETHOD(uart_param,          rt305x_uart_bus_param),
209         KOBJMETHOD(uart_probe,          rt305x_uart_bus_probe),
210         KOBJMETHOD(uart_receive,        rt305x_uart_bus_receive),
211         KOBJMETHOD(uart_setsig,         rt305x_uart_bus_setsig),
212         KOBJMETHOD(uart_transmit,       rt305x_uart_bus_transmit),
213         KOBJMETHOD(uart_grab,           rt305x_uart_bus_grab),
214         KOBJMETHOD(uart_ungrab,         rt305x_uart_bus_ungrab),
215         { 0, 0 }
216 };
217
218 struct uart_class uart_rt305x_uart_class = {
219         "rt305x",
220         rt305x_uart_methods,
221         sizeof(struct rt305x_uart_softc),
222         .uc_ops = &uart_rt305x_uart_ops,
223         .uc_range = 1, /* use hinted range */
224         .uc_rclk = SYSTEM_CLOCK
225 };
226
227 #define SIGCHG(c, i, s, d)                              \
228         if (c) {                                        \
229                 i |= (i & s) ? s : s | d;               \
230         } else {                                        \
231                 i = (i & s) ? (i & ~s) | d : i;         \
232         }
233
234 /*
235  * Disable TX interrupt. uart should be locked 
236  */ 
237 static __inline void
238 rt305x_uart_disable_txintr(struct uart_softc *sc)
239 {
240         struct uart_bas *bas = &sc->sc_bas;
241         uint8_t cr;
242
243         cr = uart_getreg(bas, UART_IER_REG);
244         cr &= ~UART_IER_ETBEI;
245         uart_setreg(bas, UART_IER_REG, cr);
246         uart_barrier(bas);
247 }
248
249 /*
250  * Enable TX interrupt. uart should be locked 
251  */ 
252 static __inline void
253 rt305x_uart_enable_txintr(struct uart_softc *sc)
254 {
255         struct uart_bas *bas = &sc->sc_bas;
256         uint8_t cr;
257
258         cr = uart_getreg(bas, UART_IER_REG);
259         cr |= UART_IER_ETBEI;
260         uart_setreg(bas, UART_IER_REG, cr);
261         uart_barrier(bas);
262 }
263
264 static int
265 rt305x_uart_bus_attach(struct uart_softc *sc)
266 {
267         struct uart_bas *bas;
268         struct uart_devinfo *di;
269
270         bas = &sc->sc_bas;
271         if (sc->sc_sysdev != NULL) {
272                 di = sc->sc_sysdev;
273                 rt305x_uart_init(bas, di->baudrate, di->databits, di->stopbits,
274                     di->parity);
275         } else {
276                 rt305x_uart_init(bas, 115200, 8, 1, 0);
277         }
278
279         (void)rt305x_uart_bus_getsig(sc);
280
281         /* Enable FIFO */
282         uart_setreg(bas, UART_FCR_REG, 
283             uart_getreg(bas, UART_FCR_REG) | 
284             UART_FCR_FIFOEN | UART_FCR_TXTGR_1 | UART_FCR_RXTGR_1);
285         uart_barrier(bas);
286         /* Enable interrupts */
287         uart_setreg(bas, UART_IER_REG,
288             UART_IER_EDSSI | UART_IER_ELSI | UART_IER_ERBFI);
289         uart_barrier(bas);
290
291         return (0);
292 }
293
294 static int
295 rt305x_uart_bus_detach(struct uart_softc *sc)
296 {
297
298         return (0);
299 }
300
301 static int
302 rt305x_uart_bus_flush(struct uart_softc *sc, int what)
303 {
304         struct uart_bas *bas = &sc->sc_bas;
305         uint32_t fcr = uart_getreg(bas, UART_FCR_REG);
306         if (what & UART_FLUSH_TRANSMITTER) {
307                 uart_setreg(bas, UART_FCR_REG, fcr|UART_FCR_TXRST);
308                 uart_barrier(bas);
309         }
310         if (what & UART_FLUSH_RECEIVER) {
311                 uart_setreg(bas, UART_FCR_REG, fcr|UART_FCR_RXRST);
312                 uart_barrier(bas);
313         }
314         uart_setreg(bas, UART_FCR_REG, fcr);
315         uart_barrier(bas);
316         return (0);
317 }
318
319 static int
320 rt305x_uart_bus_getsig(struct uart_softc *sc)
321 {
322         uint32_t new, old, sig;
323         uint8_t bes;
324
325         do {
326                 old = sc->sc_hwsig;
327                 sig = old;
328                 uart_lock(sc->sc_hwmtx);
329                 bes = uart_getreg(&sc->sc_bas, UART_MSR_REG);
330                 uart_unlock(sc->sc_hwmtx);
331                 /* XXX: chip can show delta */
332                 SIGCHG(bes & UART_MSR_CTS, sig, SER_CTS, SER_DCTS);
333                 SIGCHG(bes & UART_MSR_DCD, sig, SER_DCD, SER_DDCD);
334                 SIGCHG(bes & UART_MSR_DSR, sig, SER_DSR, SER_DDSR);
335                 new = sig & ~SER_MASK_DELTA;
336         } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
337
338         return (sig);
339 }
340
341 static int
342 rt305x_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
343 {
344         struct uart_bas *bas;
345         int baudrate, divisor, error;
346
347         bas = &sc->sc_bas;
348         error = 0;
349         uart_lock(sc->sc_hwmtx);
350         switch (request) {
351         case UART_IOCTL_BREAK:
352                 /* TODO: Send BREAK */
353                 break;
354         case UART_IOCTL_BAUD:
355                 divisor = uart_getreg(bas, UART_CDDL_REG);
356                 baudrate = bas->rclk / (divisor * 16);
357                 *(int*)data = baudrate;
358                 break;
359         default:
360                 error = EINVAL;
361                 break;
362         }
363         uart_unlock(sc->sc_hwmtx);
364         return (error);
365 }
366
367 static int
368 rt305x_uart_bus_ipend(struct uart_softc *sc)
369 {
370         struct uart_bas *bas;
371         int ipend;
372         uint8_t iir, lsr, msr;
373
374         bas = &sc->sc_bas;
375         ipend = 0;
376
377         uart_lock(sc->sc_hwmtx);
378         iir = uart_getreg(&sc->sc_bas, UART_IIR_REG);
379         lsr = uart_getreg(&sc->sc_bas, UART_LSR_REG);
380         uart_setreg(&sc->sc_bas, UART_LSR_REG, lsr);
381         msr = uart_getreg(&sc->sc_bas, UART_MSR_REG);
382         uart_setreg(&sc->sc_bas, UART_MSR_REG, msr);
383         if (iir & UART_IIR_INTP) {
384                 uart_unlock(sc->sc_hwmtx);
385                 return (0);
386         }
387
388
389         switch ((iir >> 1) & 0x07) {
390         case UART_IIR_ID_THRE:
391                 ipend |= SER_INT_TXIDLE;
392                 break;
393         case UART_IIR_ID_DR2:
394                 rt305x_uart_bus_flush(sc, UART_FLUSH_RECEIVER);
395                 /* passthrough */
396         case UART_IIR_ID_DR:
397                 ipend |= SER_INT_RXREADY;
398                 break;
399         case UART_IIR_ID_MST:
400         case UART_IIR_ID_LINESTATUS:
401                 ipend |= SER_INT_SIGCHG;
402                 if (lsr & UART_LSR_BI)
403                 {
404                         ipend |= SER_INT_BREAK;
405 #ifdef KDB
406                         breakpoint();
407 #endif
408                 }
409                 if (lsr & UART_LSR_OE)
410                         ipend |= SER_INT_OVERRUN;
411                 break;
412         default:
413                 /* XXX: maybe return error here */
414                 break;
415         }
416
417         uart_unlock(sc->sc_hwmtx);
418
419         return (ipend);
420 }
421
422 static int
423 rt305x_uart_bus_param(struct uart_softc *sc, int baudrate, int databits,
424     int stopbits, int parity)
425 {
426         uart_lock(sc->sc_hwmtx);
427         rt305x_uart_init(&sc->sc_bas, baudrate, databits, stopbits, parity);
428         uart_unlock(sc->sc_hwmtx);
429         return (0);
430 }
431
432 static int
433 rt305x_uart_bus_probe(struct uart_softc *sc)
434 {
435         char buf[80];
436         int error;
437
438         error = rt305x_uart_probe(&sc->sc_bas);
439         if (error)
440                 return (error);
441
442         sc->sc_rxfifosz = 16;
443         sc->sc_txfifosz = 16;
444
445         snprintf(buf, sizeof(buf), "rt305x_uart");
446         device_set_desc_copy(sc->sc_dev, buf);
447
448         return (0);
449 }
450
451 static int
452 rt305x_uart_bus_receive(struct uart_softc *sc)
453 {
454         struct uart_bas *bas;
455         int xc;
456         uint8_t lsr;
457
458         bas = &sc->sc_bas;
459         uart_lock(sc->sc_hwmtx);
460         lsr = uart_getreg(bas, UART_LSR_REG);
461         while ((lsr & UART_LSR_DR)) {
462                 if (uart_rx_full(sc)) {
463                         sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
464                         break;
465                 }
466                 xc = 0;
467                 xc = uart_getreg(bas, UART_RX_REG);
468                 if (lsr & UART_LSR_FE)
469                         xc |= UART_STAT_FRAMERR;
470                 if (lsr & UART_LSR_PE)
471                         xc |= UART_STAT_PARERR;
472                 if (lsr & UART_LSR_OE)
473                         xc |= UART_STAT_OVERRUN;
474                 uart_barrier(bas);
475                 uart_rx_put(sc, xc);
476                 lsr = uart_getreg(bas, UART_LSR_REG);
477         }
478
479         uart_unlock(sc->sc_hwmtx);
480         return (0);
481 }
482
483 static int
484 rt305x_uart_bus_setsig(struct uart_softc *sc, int sig)
485 {
486
487         /* TODO: implement (?) */
488         return (0);
489 }
490
491 static int
492 rt305x_uart_bus_transmit(struct uart_softc *sc)
493 {
494         struct uart_bas *bas = &sc->sc_bas;
495         int i;
496
497         if (!uart_output) return (0);
498
499         bas = &sc->sc_bas;
500         uart_lock(sc->sc_hwmtx);
501         while ((uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE) == 0)
502                 ;
503         rt305x_uart_enable_txintr(sc);
504         for (i = 0; i < sc->sc_txdatasz; i++) {
505                 uart_setreg(bas, UART_TX_REG, sc->sc_txbuf[i]);
506                 uart_barrier(bas);
507         }
508         sc->sc_txbusy = 1;
509         uart_unlock(sc->sc_hwmtx);
510         return (0);
511 }
512
513 static void
514 rt305x_uart_bus_grab(struct uart_softc *sc)
515 {
516         struct uart_bas *bas = &sc->sc_bas;
517
518         /* disable interrupts -- XXX not sure which one is RX, so kill them all */
519         uart_lock(sc->sc_hwmtx);
520         uart_setreg(bas, UART_IER_REG, 0);
521         uart_barrier(bas);
522         uart_unlock(sc->sc_hwmtx);
523 }
524
525 static void
526 rt305x_uart_bus_ungrab(struct uart_softc *sc)
527 {
528         struct uart_bas *bas = &sc->sc_bas;
529
530         /* Enable interrupts */
531         uart_lock(sc->sc_hwmtx);
532         uart_setreg(bas, UART_IER_REG,
533             UART_IER_EDSSI | UART_IER_ELSI | UART_IER_ERBFI);
534         uart_barrier(bas);
535         uart_unlock(sc->sc_hwmtx);
536 }