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

Cache object: 0990c4a50a7597d16c71c4cae012c142


[ 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.