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

Cache object: 6460d1cc5d2d3f849eb0600a53ae948f


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