1 /* $NetBSD: uart.c,v 1.2 2007/03/23 20:05:47 dogcow Exp $ */
4 * Copyright (c) 2010 Aleksandr Rybalko.
5 * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko.
6 * Copyright (c) 2007 Oleksandr Tymoshenko.
9 * Redistribution and use in source and binary forms, with or
10 * without modification, are permitted provided that the following
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.
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
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
38 #include <sys/param.h>
39 #include <sys/systm.h>
43 #include <sys/reboot.h>
44 #include <sys/sysctl.h>
45 #include <sys/kernel.h>
46 #include <machine/bus.h>
48 #include <dev/uart/uart.h>
49 #include <dev/uart/uart_cpu.h>
50 #include <dev/uart/uart_bus.h>
52 #include <mips/rt305x/uart_dev_rt305x.h>
53 #include <mips/rt305x/rt305xreg.h>
57 * Low-level UART interface.
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
*);
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
,
75 static int uart_output
= 1;
76 SYSCTL_INT(_kern
, OID_AUTO
, uart_output
, CTLFLAG_RWTUN
,
77 &uart_output
, 0, "UART output enabled.");
80 rt305x_uart_probe(struct uart_bas
*bas
)
87 rt305x_uart_init(struct uart_bas
*bas
, int baudrate
, int databits
,
88 int stopbits
, int parity
)
91 /* CLKDIV = 384000000/ 3/ 16/ br */
92 /* for 384MHz CLKDIV = 8000000 / baudrate; */
95 databits
= UART_LCR_5B
;
98 databits
= UART_LCR_6B
;
101 databits
= UART_LCR_7B
;
104 databits
= UART_LCR_8B
;
111 case UART_PARITY_EVEN
: parity
= (UART_LCR_PEN
|UART_LCR_EVEN
); break;
112 case UART_PARITY_NONE
: parity
= (UART_LCR_PEN
); break;
113 case UART_PARITY_ODD
: parity
= 0; break;
117 uart_setreg(bas
, UART_CDDL_REG
, 8000000/baudrate
);
119 uart_setreg(bas
, UART_LCR_REG
, databits
| (stopbits
==1?0:4) | parity
);
125 rt305x_uart_term(struct uart_bas
*bas
)
127 uart_setreg(bas
, UART_MCR_REG
, 0);
132 rt305x_uart_putc(struct uart_bas
*bas
, int c
)
135 if (!uart_output
) return;
137 while (!(uart_getreg(bas
, UART_LSR_REG
) & UART_LSR_THRE
));
138 uart_setreg(bas
, UART_TX_REG
, c
);
140 while (!(uart_getreg(bas
, UART_LSR_REG
) & UART_LSR_THRE
));
144 rt305x_uart_rxready(struct uart_bas
*bas
)
147 if (uart_getreg(bas
, UART_LSR_REG
) & UART_LSR_DR
)
157 rt305x_uart_getc(struct uart_bas
*bas
, struct mtx
*hwmtx
)
163 while (!(uart_getreg(bas
, UART_LSR_REG
) & UART_LSR_DR
)) {
169 c
= uart_getreg(bas
, UART_RX_REG
);
177 * High-level UART interface.
179 struct rt305x_uart_softc
{
180 struct uart_softc base
;
183 static int rt305x_uart_bus_attach(struct uart_softc
*);
184 static int rt305x_uart_bus_detach(struct uart_softc
*);
185 static int rt305x_uart_bus_flush(struct uart_softc
*, int);
186 static int rt305x_uart_bus_getsig(struct uart_softc
*);
187 static int rt305x_uart_bus_ioctl(struct uart_softc
*, int, intptr_t);
188 static int rt305x_uart_bus_ipend(struct uart_softc
*);
189 static int rt305x_uart_bus_param(struct uart_softc
*, int, int, int, int);
190 static int rt305x_uart_bus_probe(struct uart_softc
*);
191 static int rt305x_uart_bus_receive(struct uart_softc
*);
192 static int rt305x_uart_bus_setsig(struct uart_softc
*, int);
193 static int rt305x_uart_bus_transmit(struct uart_softc
*);
194 static void rt305x_uart_bus_grab(struct uart_softc
*);
195 static void rt305x_uart_bus_ungrab(struct uart_softc
*);
197 static kobj_method_t rt305x_uart_methods
[] = {
198 KOBJMETHOD(uart_attach
, rt305x_uart_bus_attach
),
199 KOBJMETHOD(uart_detach
, rt305x_uart_bus_detach
),
200 KOBJMETHOD(uart_flush
, rt305x_uart_bus_flush
),
201 KOBJMETHOD(uart_getsig
, rt305x_uart_bus_getsig
),
202 KOBJMETHOD(uart_ioctl
, rt305x_uart_bus_ioctl
),
203 KOBJMETHOD(uart_ipend
, rt305x_uart_bus_ipend
),
204 KOBJMETHOD(uart_param
, rt305x_uart_bus_param
),
205 KOBJMETHOD(uart_probe
, rt305x_uart_bus_probe
),
206 KOBJMETHOD(uart_receive
, rt305x_uart_bus_receive
),
207 KOBJMETHOD(uart_setsig
, rt305x_uart_bus_setsig
),
208 KOBJMETHOD(uart_transmit
, rt305x_uart_bus_transmit
),
209 KOBJMETHOD(uart_grab
, rt305x_uart_bus_grab
),
210 KOBJMETHOD(uart_ungrab
, rt305x_uart_bus_ungrab
),
214 struct uart_class uart_rt305x_uart_class
= {
217 sizeof(struct rt305x_uart_softc
),
218 .uc_ops
= &uart_rt305x_uart_ops
,
219 .uc_range
= 1, /* use hinted range */
220 .uc_rclk
= SYSTEM_CLOCK
,
224 #define SIGCHG(c, i, s, d) \
226 i |= (i & s) ? s : s | d; \
228 i = (i & s) ? (i & ~s) | d : i; \
232 * Disable TX interrupt. uart should be locked
235 rt305x_uart_disable_txintr(struct uart_softc
*sc
)
237 struct uart_bas
*bas
= &sc
->sc_bas
;
240 cr
= uart_getreg(bas
, UART_IER_REG
);
241 cr
&= ~UART_IER_ETBEI
;
242 uart_setreg(bas
, UART_IER_REG
, cr
);
247 * Enable TX interrupt. uart should be locked
250 rt305x_uart_enable_txintr(struct uart_softc
*sc
)
252 struct uart_bas
*bas
= &sc
->sc_bas
;
255 cr
= uart_getreg(bas
, UART_IER_REG
);
256 cr
|= UART_IER_ETBEI
;
257 uart_setreg(bas
, UART_IER_REG
, cr
);
262 rt305x_uart_bus_attach(struct uart_softc
*sc
)
264 struct uart_bas
*bas
;
265 struct uart_devinfo
*di
;
268 if (sc
->sc_sysdev
!= NULL
) {
270 rt305x_uart_init(bas
, di
->baudrate
, di
->databits
, di
->stopbits
,
273 rt305x_uart_init(bas
, 115200, 8, 1, 0);
276 (void)rt305x_uart_bus_getsig(sc
);
279 uart_setreg(bas
, UART_FCR_REG
,
280 uart_getreg(bas
, UART_FCR_REG
) |
281 UART_FCR_FIFOEN
| UART_FCR_TXTGR_1
| UART_FCR_RXTGR_1
);
283 /* Enable interrupts */
284 uart_setreg(bas
, UART_IER_REG
,
285 UART_IER_EDSSI
| UART_IER_ELSI
| UART_IER_ERBFI
);
292 rt305x_uart_bus_detach(struct uart_softc
*sc
)
299 rt305x_uart_bus_flush(struct uart_softc
*sc
, int what
)
301 struct uart_bas
*bas
= &sc
->sc_bas
;
302 uint32_t fcr
= uart_getreg(bas
, UART_FCR_REG
);
303 if (what
& UART_FLUSH_TRANSMITTER
) {
304 uart_setreg(bas
, UART_FCR_REG
, fcr
|UART_FCR_TXRST
);
307 if (what
& UART_FLUSH_RECEIVER
) {
308 uart_setreg(bas
, UART_FCR_REG
, fcr
|UART_FCR_RXRST
);
311 uart_setreg(bas
, UART_FCR_REG
, fcr
);
317 rt305x_uart_bus_getsig(struct uart_softc
*sc
)
319 uint32_t new, old
, sig
;
325 uart_lock(sc
->sc_hwmtx
);
326 bes
= uart_getreg(&sc
->sc_bas
, UART_MSR_REG
);
327 uart_unlock(sc
->sc_hwmtx
);
328 /* XXX: chip can show delta */
329 SIGCHG(bes
& UART_MSR_CTS
, sig
, SER_CTS
, SER_DCTS
);
330 SIGCHG(bes
& UART_MSR_DCD
, sig
, SER_DCD
, SER_DDCD
);
331 SIGCHG(bes
& UART_MSR_DSR
, sig
, SER_DSR
, SER_DDSR
);
332 new = sig
& ~SER_MASK_DELTA
;
333 } while (!atomic_cmpset_32(&sc
->sc_hwsig
, old
, new));
339 rt305x_uart_bus_ioctl(struct uart_softc
*sc
, int request
, intptr_t data
)
341 struct uart_bas
*bas
;
342 int baudrate
, divisor
, error
;
346 uart_lock(sc
->sc_hwmtx
);
348 case UART_IOCTL_BREAK
:
349 /* TODO: Send BREAK */
351 case UART_IOCTL_BAUD
:
352 divisor
= uart_getreg(bas
, UART_CDDL_REG
);
353 baudrate
= bas
->rclk
/ (divisor
* 16);
354 *(int*)data
= baudrate
;
360 uart_unlock(sc
->sc_hwmtx
);
365 rt305x_uart_bus_ipend(struct uart_softc
*sc
)
367 struct uart_bas
*bas
;
369 uint8_t iir
, lsr
, msr
;
374 uart_lock(sc
->sc_hwmtx
);
375 iir
= uart_getreg(&sc
->sc_bas
, UART_IIR_REG
);
376 lsr
= uart_getreg(&sc
->sc_bas
, UART_LSR_REG
);
377 uart_setreg(&sc
->sc_bas
, UART_LSR_REG
, lsr
);
378 msr
= uart_getreg(&sc
->sc_bas
, UART_MSR_REG
);
379 uart_setreg(&sc
->sc_bas
, UART_MSR_REG
, msr
);
380 if (iir
& UART_IIR_INTP
) {
381 uart_unlock(sc
->sc_hwmtx
);
386 switch ((iir
>> 1) & 0x07) {
387 case UART_IIR_ID_THRE
:
388 ipend
|= SER_INT_TXIDLE
;
390 case UART_IIR_ID_DR2
:
391 rt305x_uart_bus_flush(sc
, UART_FLUSH_RECEIVER
);
394 ipend
|= SER_INT_RXREADY
;
396 case UART_IIR_ID_MST
:
397 case UART_IIR_ID_LINESTATUS
:
398 ipend
|= SER_INT_SIGCHG
;
399 if (lsr
& UART_LSR_BI
)
401 ipend
|= SER_INT_BREAK
;
406 if (lsr
& UART_LSR_OE
)
407 ipend
|= SER_INT_OVERRUN
;
410 /* XXX: maybe return error here */
414 uart_unlock(sc
->sc_hwmtx
);
420 rt305x_uart_bus_param(struct uart_softc
*sc
, int baudrate
, int databits
,
421 int stopbits
, int parity
)
423 uart_lock(sc
->sc_hwmtx
);
424 rt305x_uart_init(&sc
->sc_bas
, baudrate
, databits
, stopbits
, parity
);
425 uart_unlock(sc
->sc_hwmtx
);
430 rt305x_uart_bus_probe(struct uart_softc
*sc
)
435 error
= rt305x_uart_probe(&sc
->sc_bas
);
439 sc
->sc_rxfifosz
= 16;
440 sc
->sc_txfifosz
= 16;
442 snprintf(buf
, sizeof(buf
), "rt305x_uart");
443 device_set_desc_copy(sc
->sc_dev
, buf
);
449 rt305x_uart_bus_receive(struct uart_softc
*sc
)
451 struct uart_bas
*bas
;
456 uart_lock(sc
->sc_hwmtx
);
457 lsr
= uart_getreg(bas
, UART_LSR_REG
);
458 while ((lsr
& UART_LSR_DR
)) {
459 if (uart_rx_full(sc
)) {
460 sc
->sc_rxbuf
[sc
->sc_rxput
] = UART_STAT_OVERRUN
;
464 xc
= uart_getreg(bas
, UART_RX_REG
);
465 if (lsr
& UART_LSR_FE
)
466 xc
|= UART_STAT_FRAMERR
;
467 if (lsr
& UART_LSR_PE
)
468 xc
|= UART_STAT_PARERR
;
469 if (lsr
& UART_LSR_OE
)
470 xc
|= UART_STAT_OVERRUN
;
473 lsr
= uart_getreg(bas
, UART_LSR_REG
);
476 uart_unlock(sc
->sc_hwmtx
);
481 rt305x_uart_bus_setsig(struct uart_softc
*sc
, int sig
)
484 /* TODO: implement (?) */
489 rt305x_uart_bus_transmit(struct uart_softc
*sc
)
491 struct uart_bas
*bas
= &sc
->sc_bas
;
494 if (!uart_output
) return (0);
497 uart_lock(sc
->sc_hwmtx
);
498 while ((uart_getreg(bas
, UART_LSR_REG
) & UART_LSR_THRE
) == 0)
500 rt305x_uart_enable_txintr(sc
);
501 for (i
= 0; i
< sc
->sc_txdatasz
; i
++) {
502 uart_setreg(bas
, UART_TX_REG
, sc
->sc_txbuf
[i
]);
506 uart_unlock(sc
->sc_hwmtx
);
511 rt305x_uart_bus_grab(struct uart_softc
*sc
)
513 struct uart_bas
*bas
= &sc
->sc_bas
;
515 /* disable interrupts -- XXX not sure which one is RX, so kill them all */
516 uart_lock(sc
->sc_hwmtx
);
517 uart_setreg(bas
, UART_IER_REG
, 0);
519 uart_unlock(sc
->sc_hwmtx
);
523 rt305x_uart_bus_ungrab(struct uart_softc
*sc
)
525 struct uart_bas
*bas
= &sc
->sc_bas
;
527 /* Enable interrupts */
528 uart_lock(sc
->sc_hwmtx
);
529 uart_setreg(bas
, UART_IER_REG
,
530 UART_IER_EDSSI
| UART_IER_ELSI
| UART_IER_ERBFI
);
532 uart_unlock(sc
->sc_hwmtx
);