The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm/at91/uart_dev_at91usart.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2005 M. Warner Losh
    3  * Copyright (c) 2005 Olivier Houchard
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  *
   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.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/bus.h>
   35 #include <sys/conf.h>
   36 #include <sys/cons.h>
   37 #include <sys/tty.h>
   38 #include <machine/bus.h>
   39 
   40 #include <dev/uart/uart.h>
   41 #include <dev/uart/uart_cpu.h>
   42 #include <dev/uart/uart_bus.h>
   43 #include <arm/at91/at91_usartreg.h>
   44 #include <arm/at91/at91_pdcreg.h>
   45 #include <arm/at91/at91var.h>
   46 
   47 #include "uart_if.h"
   48 
   49 #define DEFAULT_RCLK            at91_master_clock
   50 #define USART_BUFFER_SIZE       128
   51 
   52 /*
   53  * High-level UART interface.
   54  */
   55 struct at91_usart_rx {
   56         bus_addr_t      pa;
   57         uint8_t         *buffer;
   58         bus_dmamap_t    map;
   59 };
   60 
   61 struct at91_usart_softc {
   62         struct uart_softc base;
   63         bus_dma_tag_t tx_tag;
   64         bus_dmamap_t tx_map;
   65         uint32_t flags;
   66 #define HAS_TIMEOUT             0x1
   67 #define NEEDS_RXRDY             0x4
   68         bus_dma_tag_t rx_tag;
   69         struct at91_usart_rx ping_pong[2];
   70         struct at91_usart_rx *ping;
   71         struct at91_usart_rx *pong;
   72 };
   73 
   74 #define RD4(bas, reg)           \
   75         bus_space_read_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg))
   76 #define WR4(bas, reg, value)    \
   77         bus_space_write_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg), value)
   78 
   79 #define SIGCHG(c, i, s, d)                              \
   80         do {                                            \
   81                 if (c) {                                \
   82                         i |= (i & s) ? s : s | d;       \
   83                 } else {                                \
   84                         i = (i & s) ? (i & ~s) | d : i; \
   85                 }                                       \
   86         } while (0);
   87 
   88 #define BAUD2DIVISOR(b) \
   89         ((((DEFAULT_RCLK * 10) / ((b) * 16)) + 5) / 10)
   90 
   91 /*
   92  * Low-level UART interface.
   93  */
   94 static int at91_usart_probe(struct uart_bas *bas);
   95 static void at91_usart_init(struct uart_bas *bas, int, int, int, int);
   96 static void at91_usart_term(struct uart_bas *bas);
   97 static void at91_usart_putc(struct uart_bas *bas, int);
   98 static int at91_usart_rxready(struct uart_bas *bas);
   99 static int at91_usart_getc(struct uart_bas *bas, struct mtx *hwmtx);
  100 
  101 extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
  102 
  103 static int
  104 at91_usart_param(struct uart_bas *bas, int baudrate, int databits,
  105     int stopbits, int parity)
  106 {
  107         uint32_t mr;
  108 
  109         /*
  110          * Assume 3-wire RS-232 configuration.
  111          * XXX Not sure how uart will present the other modes to us, so
  112          * XXX they are unimplemented.  maybe ioctl?
  113          */
  114         mr = USART_MR_MODE_NORMAL;
  115         mr |= USART_MR_USCLKS_MCK;      /* Assume MCK */
  116 
  117         /*
  118          * Or in the databits requested
  119          */
  120         if (databits < 9)
  121                 mr &= ~USART_MR_MODE9;
  122         switch (databits) {
  123         case 5:
  124                 mr |= USART_MR_CHRL_5BITS;
  125                 break;
  126         case 6:
  127                 mr |= USART_MR_CHRL_6BITS;
  128                 break;
  129         case 7:
  130                 mr |= USART_MR_CHRL_7BITS;
  131                 break;
  132         case 8:
  133                 mr |= USART_MR_CHRL_8BITS;
  134                 break;
  135         case 9:
  136                 mr |= USART_MR_CHRL_8BITS | USART_MR_MODE9;
  137                 break;
  138         default:
  139                 return (EINVAL);
  140         }
  141 
  142         /*
  143          * Or in the parity
  144          */
  145         switch (parity) {
  146         case UART_PARITY_NONE:
  147                 mr |= USART_MR_PAR_NONE;
  148                 break;
  149         case UART_PARITY_ODD:
  150                 mr |= USART_MR_PAR_ODD;
  151                 break;
  152         case UART_PARITY_EVEN:
  153                 mr |= USART_MR_PAR_EVEN;
  154                 break;
  155         case UART_PARITY_MARK:
  156                 mr |= USART_MR_PAR_MARK;
  157                 break;
  158         case UART_PARITY_SPACE:
  159                 mr |= USART_MR_PAR_SPACE;
  160                 break;
  161         default:
  162                 return (EINVAL);
  163         }
  164 
  165         /*
  166          * Or in the stop bits.  Note: The hardware supports 1.5 stop
  167          * bits in async mode, but there's no way to specify that
  168          * AFAICT.  Instead, rely on the convention documented at
  169          * http://www.lammertbies.nl/comm/info/RS-232_specs.html which
  170          * states that 1.5 stop bits are used for 5 bit bytes and
  171          * 2 stop bits only for longer bytes.
  172          */
  173         if (stopbits == 1)
  174                 mr |= USART_MR_NBSTOP_1;
  175         else if (databits > 5)
  176                 mr |= USART_MR_NBSTOP_2;
  177         else
  178                 mr |= USART_MR_NBSTOP_1_5;
  179 
  180         /*
  181          * We want normal plumbing mode too, none of this fancy
  182          * loopback or echo mode.
  183          */
  184         mr |= USART_MR_CHMODE_NORMAL;
  185 
  186         mr &= ~USART_MR_MSBF;   /* lsb first */
  187         mr &= ~USART_MR_CKLO_SCK;       /* Don't drive SCK */
  188 
  189         WR4(bas, USART_MR, mr);
  190 
  191         /*
  192          * Set the baud rate (only if we know our master clock rate)
  193          */
  194         if (DEFAULT_RCLK != 0)
  195                 WR4(bas, USART_BRGR, BAUD2DIVISOR(baudrate));
  196 
  197         /* XXX Need to take possible synchronous mode into account */
  198         return (0);
  199 }
  200 
  201 static struct uart_ops at91_usart_ops = {
  202         .probe = at91_usart_probe,
  203         .init = at91_usart_init,
  204         .term = at91_usart_term,
  205         .putc = at91_usart_putc,
  206         .rxready = at91_usart_rxready,
  207         .getc = at91_usart_getc,
  208 };
  209 
  210 static int
  211 at91_usart_probe(struct uart_bas *bas)
  212 {
  213 
  214         /* We know that this is always here */
  215         return (0);
  216 }
  217 
  218 /*
  219  * Initialize this device for use as a console.
  220  */
  221 static void
  222 at91_usart_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
  223     int parity)
  224 {
  225 
  226         at91_usart_param(bas, baudrate, databits, stopbits, parity);
  227 
  228         /* Reset the rx and tx buffers and turn on rx and tx */
  229         WR4(bas, USART_CR, USART_CR_RSTSTA | USART_CR_RSTRX | USART_CR_RSTTX);
  230         WR4(bas, USART_CR, USART_CR_RXEN | USART_CR_TXEN);
  231         WR4(bas, USART_IDR, 0xffffffff);
  232 }
  233 
  234 /*
  235  * Free resources now that we're no longer the console.  This appears to
  236  * be never called, and I'm unsure quite what to do if I am called.
  237  */
  238 static void
  239 at91_usart_term(struct uart_bas *bas)
  240 {
  241 
  242         /* XXX */
  243 }
  244 
  245 /*
  246  * Put a character of console output (so we do it here polling rather than
  247  * interrutp driven).
  248  */
  249 static void
  250 at91_usart_putc(struct uart_bas *bas, int c)
  251 {
  252 
  253         while (!(RD4(bas, USART_CSR) & USART_CSR_TXRDY))
  254                 continue;
  255         WR4(bas, USART_THR, c);
  256 }
  257 
  258 /*
  259  * Check for a character available.
  260  */
  261 static int
  262 at91_usart_rxready(struct uart_bas *bas)
  263 {
  264 
  265         return ((RD4(bas, USART_CSR) & USART_CSR_RXRDY) != 0 ? 1 : 0);
  266 }
  267 
  268 /*
  269  * Block waiting for a character.
  270  */
  271 static int
  272 at91_usart_getc(struct uart_bas *bas, struct mtx *hwmtx)
  273 {
  274         int c;
  275 
  276         uart_lock(hwmtx);
  277         while (!(RD4(bas, USART_CSR) & USART_CSR_RXRDY)) {
  278                 uart_unlock(hwmtx);
  279                 DELAY(4);
  280                 uart_lock(hwmtx);
  281         }
  282         c = RD4(bas, USART_RHR) & 0xff;
  283         uart_unlock(hwmtx);
  284         return (c);
  285 }
  286 
  287 static int at91_usart_bus_probe(struct uart_softc *sc);
  288 static int at91_usart_bus_attach(struct uart_softc *sc);
  289 static int at91_usart_bus_flush(struct uart_softc *, int);
  290 static int at91_usart_bus_getsig(struct uart_softc *);
  291 static int at91_usart_bus_ioctl(struct uart_softc *, int, intptr_t);
  292 static int at91_usart_bus_ipend(struct uart_softc *);
  293 static int at91_usart_bus_param(struct uart_softc *, int, int, int, int);
  294 static int at91_usart_bus_receive(struct uart_softc *);
  295 static int at91_usart_bus_setsig(struct uart_softc *, int);
  296 static int at91_usart_bus_transmit(struct uart_softc *);
  297 
  298 static kobj_method_t at91_usart_methods[] = {
  299         KOBJMETHOD(uart_probe,          at91_usart_bus_probe),
  300         KOBJMETHOD(uart_attach,         at91_usart_bus_attach),
  301         KOBJMETHOD(uart_flush,          at91_usart_bus_flush),
  302         KOBJMETHOD(uart_getsig,         at91_usart_bus_getsig),
  303         KOBJMETHOD(uart_ioctl,          at91_usart_bus_ioctl),
  304         KOBJMETHOD(uart_ipend,          at91_usart_bus_ipend),
  305         KOBJMETHOD(uart_param,          at91_usart_bus_param),
  306         KOBJMETHOD(uart_receive,        at91_usart_bus_receive),
  307         KOBJMETHOD(uart_setsig,         at91_usart_bus_setsig),
  308         KOBJMETHOD(uart_transmit,       at91_usart_bus_transmit),
  309 
  310         KOBJMETHOD_END
  311 };
  312 
  313 int
  314 at91_usart_bus_probe(struct uart_softc *sc)
  315 {
  316 
  317         sc->sc_txfifosz = USART_BUFFER_SIZE;
  318         sc->sc_rxfifosz = USART_BUFFER_SIZE;
  319         sc->sc_hwiflow = 0;
  320         return (0);
  321 }
  322 
  323 static void
  324 at91_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
  325 {
  326 
  327         if (error != 0)
  328                 return;
  329         *(bus_addr_t *)arg = segs[0].ds_addr;
  330 }
  331 
  332 static int
  333 at91_usart_bus_attach(struct uart_softc *sc)
  334 {
  335         int err;
  336         int i;
  337         uint32_t cr;
  338         struct at91_usart_softc *atsc;
  339 
  340         atsc = (struct at91_usart_softc *)sc;
  341 
  342         /*
  343          * See if we have a TIMEOUT bit.  We disable all interrupts as
  344          * a side effect.  Boot loaders may have enabled them.  Since
  345          * a TIMEOUT interrupt can't happen without other setup, the
  346          * apparent race here can't actually happen.
  347          */
  348         WR4(&sc->sc_bas, USART_IDR, 0xffffffff);
  349         WR4(&sc->sc_bas, USART_IER, USART_CSR_TIMEOUT);
  350         if (RD4(&sc->sc_bas, USART_IMR) & USART_CSR_TIMEOUT)
  351                 atsc->flags |= HAS_TIMEOUT;
  352         WR4(&sc->sc_bas, USART_IDR, 0xffffffff);
  353 
  354         /*
  355          * Allocate transmit DMA tag and map.  We allow a transmit buffer
  356          * to be any size, but it must map to a single contiguous physical
  357          * extent.
  358          */
  359         err = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0,
  360             BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
  361             BUS_SPACE_MAXSIZE_32BIT, 1, BUS_SPACE_MAXSIZE_32BIT, 0, NULL,
  362             NULL, &atsc->tx_tag);
  363         if (err != 0)
  364                 goto errout;
  365         err = bus_dmamap_create(atsc->tx_tag, 0, &atsc->tx_map);
  366         if (err != 0)
  367                 goto errout;
  368 
  369         if (atsc->flags & HAS_TIMEOUT) {
  370                 /*
  371                  * Allocate receive DMA tags, maps, and buffers.
  372                  * The receive buffers should be aligned to arm_dcache_align,
  373                  * otherwise partial cache line flushes on every receive
  374                  * interrupt are pretty much guaranteed.
  375                  */
  376                 err = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev),
  377                     arm_dcache_align, 0, BUS_SPACE_MAXADDR_32BIT,
  378                     BUS_SPACE_MAXADDR, NULL, NULL, sc->sc_rxfifosz, 1,
  379                     sc->sc_rxfifosz, BUS_DMA_ALLOCNOW, NULL, NULL,
  380                     &atsc->rx_tag);
  381                 if (err != 0)
  382                         goto errout;
  383                 for (i = 0; i < 2; i++) {
  384                         err = bus_dmamem_alloc(atsc->rx_tag,
  385                             (void **)&atsc->ping_pong[i].buffer,
  386                             BUS_DMA_NOWAIT, &atsc->ping_pong[i].map);
  387                         if (err != 0)
  388                                 goto errout;
  389                         err = bus_dmamap_load(atsc->rx_tag,
  390                             atsc->ping_pong[i].map,
  391                             atsc->ping_pong[i].buffer, sc->sc_rxfifosz,
  392                             at91_getaddr, &atsc->ping_pong[i].pa, 0);
  393                         if (err != 0)
  394                                 goto errout;
  395                         bus_dmamap_sync(atsc->rx_tag, atsc->ping_pong[i].map,
  396                             BUS_DMASYNC_PREREAD);
  397                 }
  398                 atsc->ping = &atsc->ping_pong[0];
  399                 atsc->pong = &atsc->ping_pong[1];
  400         }
  401 
  402         /* Turn on rx and tx */
  403         cr = USART_CR_RSTSTA | USART_CR_RSTRX | USART_CR_RSTTX;
  404         WR4(&sc->sc_bas, USART_CR, cr);
  405         WR4(&sc->sc_bas, USART_CR, USART_CR_RXEN | USART_CR_TXEN);
  406 
  407         /*
  408          * Setup the PDC to receive data.  We use the ping-pong buffers
  409          * so that we can more easily bounce between the two and so that
  410          * we get an interrupt 1/2 way through the software 'fifo' we have
  411          * to avoid overruns.
  412          */
  413         if (atsc->flags & HAS_TIMEOUT) {
  414                 WR4(&sc->sc_bas, PDC_RPR, atsc->ping->pa);
  415                 WR4(&sc->sc_bas, PDC_RCR, sc->sc_rxfifosz);
  416                 WR4(&sc->sc_bas, PDC_RNPR, atsc->pong->pa);
  417                 WR4(&sc->sc_bas, PDC_RNCR, sc->sc_rxfifosz);
  418                 WR4(&sc->sc_bas, PDC_PTCR, PDC_PTCR_RXTEN);
  419 
  420                 /*
  421                  * Set the receive timeout to be 1.5 character times
  422                  * assuming 8N1.
  423                  */
  424                 WR4(&sc->sc_bas, USART_RTOR, 15);
  425                 WR4(&sc->sc_bas, USART_CR, USART_CR_STTTO);
  426                 WR4(&sc->sc_bas, USART_IER, USART_CSR_TIMEOUT |
  427                     USART_CSR_RXBUFF | USART_CSR_ENDRX);
  428         } else {
  429                 /*
  430                  * Defer turning on the RXRDY bit until we're opened. This is to make the
  431                  * mountroot prompt work before we've opened the console. This is a workaround
  432                  * for not being able to change the UART interface for the 10.0 release.
  433                  */
  434                 atsc->flags |= NEEDS_RXRDY;
  435                 /* WR4(&sc->sc_bas, USART_IER, USART_CSR_RXRDY); */
  436         }
  437         WR4(&sc->sc_bas, USART_IER, USART_CSR_RXBRK);
  438 errout:
  439         return (err);
  440 }
  441 
  442 static int
  443 at91_usart_bus_transmit(struct uart_softc *sc)
  444 {
  445         bus_addr_t addr;
  446         struct at91_usart_softc *atsc;
  447         int err;
  448 
  449         err = 0;
  450         atsc = (struct at91_usart_softc *)sc;
  451         uart_lock(sc->sc_hwmtx);
  452         if (bus_dmamap_load(atsc->tx_tag, atsc->tx_map, sc->sc_txbuf,
  453             sc->sc_txdatasz, at91_getaddr, &addr, 0) != 0) {
  454                 err = EAGAIN;
  455                 goto errout;
  456         }
  457         bus_dmamap_sync(atsc->tx_tag, atsc->tx_map, BUS_DMASYNC_PREWRITE);
  458         sc->sc_txbusy = 1;
  459         /*
  460          * Setup the PDC to transfer the data and interrupt us when it
  461          * is done.  We've already requested the interrupt.
  462          */
  463         WR4(&sc->sc_bas, PDC_TPR, addr);
  464         WR4(&sc->sc_bas, PDC_TCR, sc->sc_txdatasz);
  465         WR4(&sc->sc_bas, PDC_PTCR, PDC_PTCR_TXTEN);
  466         WR4(&sc->sc_bas, USART_IER, USART_CSR_ENDTX);
  467 errout:
  468         uart_unlock(sc->sc_hwmtx);
  469         return (err);
  470 }
  471 
  472 static int
  473 at91_usart_bus_setsig(struct uart_softc *sc, int sig)
  474 {
  475         uint32_t new, old, cr;
  476         struct uart_bas *bas;
  477 
  478         do {
  479                 old = sc->sc_hwsig;
  480                 new = old;
  481                 if (sig & SER_DDTR)
  482                         SIGCHG(sig & SER_DTR, new, SER_DTR, SER_DDTR);
  483                 if (sig & SER_DRTS)
  484                         SIGCHG(sig & SER_RTS, new, SER_RTS, SER_DRTS);
  485         } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
  486         bas = &sc->sc_bas;
  487         uart_lock(sc->sc_hwmtx);
  488         cr = 0;
  489         if (new & SER_DTR)
  490                 cr |= USART_CR_DTREN;
  491         else
  492                 cr |= USART_CR_DTRDIS;
  493         if (new & SER_RTS)
  494                 cr |= USART_CR_RTSEN;
  495         else
  496                 cr |= USART_CR_RTSDIS;
  497         WR4(bas, USART_CR, cr);
  498         uart_unlock(sc->sc_hwmtx);
  499         return (0);
  500 }
  501 
  502 static int
  503 at91_usart_bus_receive(struct uart_softc *sc)
  504 {
  505 
  506         return (0);
  507 }
  508 
  509 static int
  510 at91_usart_bus_param(struct uart_softc *sc, int baudrate, int databits,
  511     int stopbits, int parity)
  512 {
  513 
  514         return (at91_usart_param(&sc->sc_bas, baudrate, databits, stopbits,
  515             parity));
  516 }
  517 
  518 static __inline void
  519 at91_rx_put(struct uart_softc *sc, int key)
  520 {
  521 
  522 #if defined(KDB)
  523         if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE)
  524                 kdb_alt_break(key, &sc->sc_altbrk);
  525 #endif
  526         uart_rx_put(sc, key);
  527 }
  528 
  529 static int
  530 at91_usart_bus_ipend(struct uart_softc *sc)
  531 {
  532         struct at91_usart_softc *atsc;
  533         struct at91_usart_rx *p;
  534         int i, ipend, len;
  535         uint32_t csr;
  536 
  537         ipend = 0;
  538         atsc = (struct at91_usart_softc *)sc;
  539         uart_lock(sc->sc_hwmtx);
  540 
  541         /* Kludge -- Enable the RXRDY we deferred in attach */
  542         if (sc->sc_opened && (atsc->flags & NEEDS_RXRDY)) {
  543                 WR4(&sc->sc_bas, USART_IER, USART_CSR_RXRDY);
  544                 atsc->flags &= ~NEEDS_RXRDY;
  545         }
  546 
  547         csr = RD4(&sc->sc_bas, USART_CSR);
  548         if (csr & USART_CSR_ENDTX) {
  549                 bus_dmamap_sync(atsc->tx_tag, atsc->tx_map,
  550                     BUS_DMASYNC_POSTWRITE);
  551                 bus_dmamap_unload(atsc->tx_tag, atsc->tx_map);
  552         }
  553         if (csr & (USART_CSR_TXRDY | USART_CSR_ENDTX)) {
  554                 if (sc->sc_txbusy)
  555                         ipend |= SER_INT_TXIDLE;
  556                 WR4(&sc->sc_bas, USART_IDR, csr & (USART_CSR_TXRDY |
  557                     USART_CSR_ENDTX));
  558         }
  559 
  560         /*
  561          * Due to the contraints of the DMA engine present in the
  562          * atmel chip, I can't just say I have a rx interrupt pending
  563          * and do all the work elsewhere.  I need to look at the CSR
  564          * bits right now and do things based on them to avoid races.
  565          */
  566         if (atsc->flags & HAS_TIMEOUT) {
  567                 if (csr & USART_CSR_RXBUFF) {
  568                         /*
  569                          * We have a buffer overflow.  Copy all data from both
  570                          * ping and pong.  Insert overflow character.  Reset
  571                          * ping and pong and re-enable the PDC to receive
  572                          * characters again.
  573                          */
  574                         bus_dmamap_sync(atsc->rx_tag, atsc->ping->map,
  575                             BUS_DMASYNC_POSTREAD);
  576                         bus_dmamap_sync(atsc->rx_tag, atsc->pong->map,
  577                             BUS_DMASYNC_POSTREAD);
  578                         for (i = 0; i < sc->sc_rxfifosz; i++)
  579                                 at91_rx_put(sc, atsc->ping->buffer[i]);
  580                         for (i = 0; i < sc->sc_rxfifosz; i++)
  581                                 at91_rx_put(sc, atsc->pong->buffer[i]);
  582                         uart_rx_put(sc, UART_STAT_OVERRUN);
  583                         bus_dmamap_sync(atsc->rx_tag, atsc->ping->map,
  584                             BUS_DMASYNC_PREREAD);
  585                         bus_dmamap_sync(atsc->rx_tag, atsc->pong->map,
  586                             BUS_DMASYNC_PREREAD);
  587                         WR4(&sc->sc_bas, PDC_RPR, atsc->ping->pa);
  588                         WR4(&sc->sc_bas, PDC_RCR, sc->sc_rxfifosz);
  589                         WR4(&sc->sc_bas, PDC_RNPR, atsc->pong->pa);
  590                         WR4(&sc->sc_bas, PDC_RNCR, sc->sc_rxfifosz);
  591                         WR4(&sc->sc_bas, PDC_PTCR, PDC_PTCR_RXTEN);
  592                         ipend |= SER_INT_RXREADY;
  593                 } else if (csr & USART_CSR_ENDRX) {
  594                         /*
  595                          * Shuffle data from ping of ping pong buffer, but
  596                          * leave current pong in place, as it has become the
  597                          * new ping.  We need to copy data and setup the old
  598                          * ping as the new pong when we're done.
  599                          */
  600                         bus_dmamap_sync(atsc->rx_tag, atsc->ping->map,
  601                             BUS_DMASYNC_POSTREAD);
  602                         for (i = 0; i < sc->sc_rxfifosz; i++)
  603                                 at91_rx_put(sc, atsc->ping->buffer[i]);
  604                         p = atsc->ping;
  605                         atsc->ping = atsc->pong;
  606                         atsc->pong = p;
  607                         bus_dmamap_sync(atsc->rx_tag, atsc->pong->map,
  608                             BUS_DMASYNC_PREREAD);
  609                         WR4(&sc->sc_bas, PDC_RNPR, atsc->pong->pa);
  610                         WR4(&sc->sc_bas, PDC_RNCR, sc->sc_rxfifosz);
  611                         ipend |= SER_INT_RXREADY;
  612                 } else if (csr & USART_CSR_TIMEOUT) {
  613                         /*
  614                          * We have one partial buffer.  We need to stop the
  615                          * PDC, get the number of characters left and from
  616                          * that compute number of valid characters.  We then
  617                          * need to reset ping and pong and reenable the PDC.
  618                          * Not sure if there's a race here at fast baud rates
  619                          * we need to worry about.
  620                          */
  621                         WR4(&sc->sc_bas, PDC_PTCR, PDC_PTCR_RXTDIS);
  622                         bus_dmamap_sync(atsc->rx_tag, atsc->ping->map,
  623                             BUS_DMASYNC_POSTREAD);
  624                         len = sc->sc_rxfifosz - RD4(&sc->sc_bas, PDC_RCR);
  625                         for (i = 0; i < len; i++)
  626                                 at91_rx_put(sc, atsc->ping->buffer[i]);
  627                         bus_dmamap_sync(atsc->rx_tag, atsc->ping->map,
  628                             BUS_DMASYNC_PREREAD);
  629                         WR4(&sc->sc_bas, PDC_RPR, atsc->ping->pa);
  630                         WR4(&sc->sc_bas, PDC_RCR, sc->sc_rxfifosz);
  631                         WR4(&sc->sc_bas, USART_CR, USART_CR_STTTO);
  632                         WR4(&sc->sc_bas, PDC_PTCR, PDC_PTCR_RXTEN);
  633                         ipend |= SER_INT_RXREADY;
  634                 }
  635         } else if (csr & USART_CSR_RXRDY) {
  636                 /*
  637                  * We have another charater in a device that doesn't support
  638                  * timeouts, so we do it one character at a time.
  639                  */
  640                 at91_rx_put(sc, RD4(&sc->sc_bas, USART_RHR) & 0xff);
  641                 ipend |= SER_INT_RXREADY;
  642         }
  643 
  644         if (csr & USART_CSR_RXBRK) {
  645                 ipend |= SER_INT_BREAK;
  646                 WR4(&sc->sc_bas, USART_CR, USART_CR_RSTSTA);
  647         }
  648         uart_unlock(sc->sc_hwmtx);
  649         return (ipend);
  650 }
  651 
  652 static int
  653 at91_usart_bus_flush(struct uart_softc *sc, int what)
  654 {
  655 
  656         return (0);
  657 }
  658 
  659 static int
  660 at91_usart_bus_getsig(struct uart_softc *sc)
  661 {
  662         uint32_t csr, new, sig;
  663 
  664         uart_lock(sc->sc_hwmtx);
  665         csr = RD4(&sc->sc_bas, USART_CSR);
  666         sig = 0;
  667         if (csr & USART_CSR_CTS)
  668                 sig |= SER_CTS;
  669         if (csr & USART_CSR_DCD)
  670                 sig |= SER_DCD;
  671         if (csr & USART_CSR_DSR)
  672                 sig |= SER_DSR;
  673         if (csr & USART_CSR_RI)
  674                 sig |= SER_RI;
  675         new = sig & ~SER_MASK_DELTA;
  676         sc->sc_hwsig = new;
  677         uart_unlock(sc->sc_hwmtx);
  678         return (sig);
  679 }
  680 
  681 static int
  682 at91_usart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
  683 {
  684 
  685         switch (request) {
  686         case UART_IOCTL_BREAK:
  687         case UART_IOCTL_IFLOW:
  688         case UART_IOCTL_OFLOW:
  689                 break;
  690         case UART_IOCTL_BAUD:
  691                 /* only if we know our master clock rate */
  692                 if (DEFAULT_RCLK != 0)
  693                         WR4(&sc->sc_bas, USART_BRGR,
  694                             BAUD2DIVISOR(*(int *)data));
  695                 return (0);
  696         }
  697         return (EINVAL);
  698 }
  699 
  700 struct uart_class at91_usart_class = {
  701         "at91_usart",
  702         at91_usart_methods,
  703         sizeof(struct at91_usart_softc),
  704         .uc_ops = &at91_usart_ops,
  705         .uc_range = 8
  706 };

Cache object: fc86d6822f046a933f8e516f3e8530b1


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.