2 * Copyright (c) 2005 M. Warner Losh
3 * Copyright (c) 2005 Olivier Houchard
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
32 #include <sys/systm.h>
37 #include <machine/bus.h>
39 #include <dev/uart/uart.h>
40 #include <dev/uart/uart_cpu.h>
41 #include <dev/uart/uart_bus.h>
42 #include <arm/at91/at91rm92reg.h>
43 #include <arm/at91/at91_usartreg.h>
44 #include <arm/at91/at91_pdcreg.h>
49 * High-level UART interface.
51 struct at91_usart_softc {
52 struct uart_softc base;
53 bus_dma_tag_t dmatag; /* bus dma tag for mbufs */
58 #define DEFAULT_RCLK AT91C_MASTER_CLOCK
59 #define USART_BUFFER_SIZE 128
61 #define RD4(bas, reg) \
62 bus_space_read_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg))
63 #define WR4(bas, reg, value) \
64 bus_space_write_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg), value)
66 #define SIGCHG(c, i, s, d) \
69 i |= (i & s) ? s : s | d; \
71 i = (i & s) ? (i & ~s) | d : i; \
76 * Low-level UART interface.
78 static int at91_usart_probe(struct uart_bas *bas);
79 static void at91_usart_init(struct uart_bas *bas, int, int, int, int);
80 static void at91_usart_term(struct uart_bas *bas);
81 static void at91_usart_putc(struct uart_bas *bas, int);
82 static int at91_usart_poll(struct uart_bas *bas);
83 static int at91_usart_getc(struct uart_bas *bas, struct mtx *mtx);
85 extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
88 at91_usart_param(struct uart_bas *bas, int baudrate, int databits,
89 int stopbits, int parity)
94 * Assume 3-write RS-232 configuration.
95 * XXX Not sure how uart will present the other modes to us, so
96 * XXX they are unimplemented. maybe ioctl?
98 mr = USART_MR_MODE_NORMAL;
99 mr |= USART_MR_USCLKS_MCK; /* Assume MCK */
102 * Or in the databits requested
105 mr &= ~USART_MR_MODE9;
108 mr |= USART_MR_CHRL_5BITS;
111 mr |= USART_MR_CHRL_6BITS;
114 mr |= USART_MR_CHRL_7BITS;
117 mr |= USART_MR_CHRL_8BITS;
120 mr |= USART_MR_CHRL_8BITS | USART_MR_MODE9;
130 case UART_PARITY_NONE:
131 mr |= USART_MR_PAR_NONE;
133 case UART_PARITY_ODD:
134 mr |= USART_MR_PAR_ODD;
136 case UART_PARITY_EVEN:
137 mr |= USART_MR_PAR_EVEN;
139 case UART_PARITY_MARK:
140 mr |= USART_MR_PAR_MARK;
142 case UART_PARITY_SPACE:
143 mr |= USART_MR_PAR_SPACE;
150 * Or in the stop bits. Note: The hardware supports
151 * 1.5 stop bits in async mode, but there's no way to
152 * specify that AFAICT.
155 mr |= USART_MR_NBSTOP_2;
157 mr |= USART_MR_NBSTOP_2;
158 /* else if (stopbits == 1.5)
159 mr |= USART_MR_NBSTOP_1_5; */
162 * We want normal plumbing mode too, none of this fancy
163 * loopback or echo mode.
165 mr |= USART_MR_CHMODE_NORMAL;
167 mr &= ~USART_MR_MSBF; /* lsb first */
168 mr &= ~USART_MR_CKLO_SCK; /* Don't drive SCK */
170 /* XXX Need to take possible synchronous mode into account */
174 struct uart_ops at91_usart_ops = {
175 .probe = at91_usart_probe,
176 .init = at91_usart_init,
177 .term = at91_usart_term,
178 .putc = at91_usart_putc,
179 .poll = at91_usart_poll,
180 .getc = at91_usart_getc,
184 at91_usart_probe(struct uart_bas *bas)
186 /* We know that this is always here */
191 * Initialize this device (I think as the console)
194 at91_usart_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
199 at91_usart_param(bas, baudrate, databits, stopbits, parity);
201 /* Turn on rx and tx */
202 cr = USART_CR_RSTSTA | USART_CR_RSTRX | USART_CR_RSTTX;
203 WR4(bas, USART_CR, cr);
204 WR4(bas, USART_CR, USART_CR_RXEN | USART_CR_TXEN);
205 WR4(bas, USART_IER, USART_CSR_TIMEOUT |
206 USART_CSR_TXRDY | USART_CSR_RXRDY |
207 USART_CSR_RXBRK | USART_CSR_ENDRX | USART_CSR_ENDTX);
208 /* Set the receive timeout to be 1.5 character times. */
209 WR4(bas, USART_RTOR, 12);
213 * Free resources now that we're no longer the console. This appears to
214 * be never called, and I'm unsure quite what to do if I am called.
217 at91_usart_term(struct uart_bas *bas)
223 * Put a character of console output (so we do it here polling rather than
227 at91_usart_putc(struct uart_bas *bas, int c)
230 while (!(RD4(bas, USART_CSR) &
232 WR4(bas, USART_THR, c);
236 * Poll for a character available
239 at91_usart_poll(struct uart_bas *bas)
242 if (!(RD4(bas, USART_CSR) & USART_CSR_RXRDY))
244 return (RD4(bas, USART_RHR) & 0xff);
248 * Block waiting for a character.
251 at91_usart_getc(struct uart_bas *bas, struct mtx *mtx)
255 while (!(RD4(bas, USART_CSR) & USART_CSR_RXRDY))
257 c = RD4(bas, USART_RHR);
262 static int at91_usart_bus_probe(struct uart_softc *sc);
263 static int at91_usart_bus_attach(struct uart_softc *sc);
264 static int at91_usart_bus_flush(struct uart_softc *, int);
265 static int at91_usart_bus_getsig(struct uart_softc *);
266 static int at91_usart_bus_ioctl(struct uart_softc *, int, intptr_t);
267 static int at91_usart_bus_ipend(struct uart_softc *);
268 static int at91_usart_bus_param(struct uart_softc *, int, int, int, int);
269 static int at91_usart_bus_receive(struct uart_softc *);
270 static int at91_usart_bus_setsig(struct uart_softc *, int);
271 static int at91_usart_bus_transmit(struct uart_softc *);
273 static kobj_method_t at91_usart_methods[] = {
274 KOBJMETHOD(uart_probe, at91_usart_bus_probe),
275 KOBJMETHOD(uart_attach, at91_usart_bus_attach),
276 KOBJMETHOD(uart_flush, at91_usart_bus_flush),
277 KOBJMETHOD(uart_getsig, at91_usart_bus_getsig),
278 KOBJMETHOD(uart_ioctl, at91_usart_bus_ioctl),
279 KOBJMETHOD(uart_ipend, at91_usart_bus_ipend),
280 KOBJMETHOD(uart_param, at91_usart_bus_param),
281 KOBJMETHOD(uart_receive, at91_usart_bus_receive),
282 KOBJMETHOD(uart_setsig, at91_usart_bus_setsig),
283 KOBJMETHOD(uart_transmit, at91_usart_bus_transmit),
289 at91_usart_bus_probe(struct uart_softc *sc)
295 at91_usart_bus_attach(struct uart_softc *sc)
298 struct at91_usart_softc *atsc;
300 atsc = (struct at91_usart_softc *)sc;
302 sc->sc_txfifosz = USART_BUFFER_SIZE;
303 sc->sc_rxfifosz = USART_BUFFER_SIZE;
307 * Allocate DMA tags and maps
309 err = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
310 BUS_SPACE_MAXADDR, NULL, NULL, USART_BUFFER_SIZE, 1,
311 USART_BUFFER_SIZE, BUS_DMA_ALLOCNOW, NULL, NULL, &atsc->dmatag);
314 err = bus_dmamap_create(atsc->dmatag, 0, &atsc->tx_map);
317 err = bus_dmamap_create(atsc->dmatag, 0, &atsc->rx_map);
325 #ifndef SKYEYE_WORKAROUNDS
327 at91_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
331 *(bus_addr_t *)arg = segs[0].ds_addr;
337 at91_usart_bus_transmit(struct uart_softc *sc)
339 #ifndef SKYEYE_WORKAROUNDS
342 struct at91_usart_softc *atsc;
344 atsc = (struct at91_usart_softc *)sc;
345 #ifndef SKYEYE_WORKAROUNDS
346 if (bus_dmamap_load(atsc->dmatag, atsc->tx_map, sc->sc_txbuf,
347 sc->sc_txdatasz, at91_getaddr, &addr, 0) != 0)
349 bus_dmamap_sync(atsc->dmatag, atsc->tx_map, BUS_DMASYNC_PREWRITE);
352 uart_lock(sc->sc_hwmtx);
354 #ifndef SKYEYE_WORKAROUNDS
356 * Setup the PDC to transfer the data and interrupt us when it
357 * is done. We've already requested the interrupt.
359 WR4(&sc->sc_bas, PDC_TPR, addr);
360 WR4(&sc->sc_bas, PDC_TCR, sc->sc_txdatasz);
361 WR4(&sc->sc_bas, PDC_PTCR, PDC_PTCR_TXTEN);
362 uart_unlock(sc->sc_hwmtx);
364 for (int i = 0; i < sc->sc_txdatasz; i++)
365 at91_usart_putc(&sc->sc_bas, sc->sc_txbuf[i]);
367 * XXX: Gross hack : Skyeye doesn't raise an interrupt once the
368 * transfer is done, so simulate it.
370 WR4(&sc->sc_bas, USART_IER, USART_CSR_TXRDY);
375 at91_usart_bus_setsig(struct uart_softc *sc, int sig)
377 uint32_t new, old, cr;
378 struct uart_bas *bas;
384 SIGCHG(sig & SER_DTR, new, SER_DTR, SER_DDTR);
386 SIGCHG(sig & SER_RTS, new, SER_RTS, SER_DRTS);
387 } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
389 uart_lock(sc->sc_hwmtx);
390 cr = RD4(bas, USART_CR);
391 cr &= ~(USART_CR_DTREN | USART_CR_DTRDIS | USART_CR_RTSEN |
394 cr |= USART_CR_DTREN;
396 cr |= USART_CR_DTRDIS;
398 cr |= USART_CR_RTSEN;
400 cr |= USART_CR_RTSDIS;
401 WR4(bas, USART_CR, cr);
402 uart_unlock(sc->sc_hwmtx);
406 at91_usart_bus_receive(struct uart_softc *sc)
409 uart_lock(sc->sc_hwmtx);
410 uart_rx_put(sc, at91_usart_getc(&sc->sc_bas, NULL));
411 uart_unlock(sc->sc_hwmtx);
415 at91_usart_bus_param(struct uart_softc *sc, int baudrate, int databits,
416 int stopbits, int parity)
418 return (at91_usart_param(&sc->sc_bas, baudrate, databits, stopbits,
422 at91_usart_bus_ipend(struct uart_softc *sc)
424 int csr = RD4(&sc->sc_bas, USART_CSR);
426 struct at91_usart_softc *atsc;
428 atsc = (struct at91_usart_softc *)sc;
429 if (csr & USART_CSR_ENDTX) {
430 bus_dmamap_sync(atsc->dmatag, atsc->tx_map,
431 BUS_DMASYNC_POSTWRITE);
432 bus_dmamap_unload(atsc->dmatag, atsc->tx_map);
434 uart_lock(sc->sc_hwmtx);
435 if (csr & USART_CSR_TXRDY && sc->sc_txbusy)
436 ipend |= SER_INT_TXIDLE;
437 if (csr & USART_CSR_ENDTX && sc->sc_txbusy)
438 ipend |= SER_INT_TXIDLE;
439 if (csr & (USART_CSR_RXRDY /* | USART_CSR_ENDRX | USART_CSR_TIMEOUT */))
440 ipend |= SER_INT_RXREADY;
441 if (csr & USART_CSR_RXBRK) {
442 unsigned int cr = USART_CR_RSTSTA;
444 ipend |= SER_INT_BREAK;
445 WR4(&sc->sc_bas, USART_CR, cr);
447 uart_unlock(sc->sc_hwmtx);
451 at91_usart_bus_flush(struct uart_softc *sc, int what)
457 at91_usart_bus_getsig(struct uart_softc *sc)
462 uart_lock(sc->sc_hwmtx);
463 csr = RD4(&sc->sc_bas, USART_CSR);
465 if (csr & USART_CSR_CTS)
467 if (csr & USART_CSR_DCD)
469 if (csr & USART_CSR_DSR)
471 if (csr & USART_CSR_RI)
473 new = sig & ~SER_MASK_DELTA;
475 uart_unlock(sc->sc_hwmtx);
480 at91_usart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
484 struct uart_class at91_usart_class = {
487 sizeof(struct at91_usart_softc),
489 .uc_rclk = DEFAULT_RCLK