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: releng/9.0/sys/arm/at91/uart_dev_at91usart.c 225214 2011-08-27 14:24:27Z rwatson $");
   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/at91rm92reg.h>
   44 #include <arm/at91/at91_usartreg.h>
   45 #include <arm/at91/at91_pdcreg.h>
   46 #include <arm/at91/at91var.h>
   47 
   48 #include "uart_if.h"
   49 
   50 #define DEFAULT_RCLK            at91_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 (only if we know our master clock rate)
  192          */
  193         if (DEFAULT_RCLK != 0)
  194                 WR4(bas, USART_BRGR, BAUD2DIVISOR(baudrate));
  195 
  196         /* XXX Need to take possible synchronous mode into account */
  197         return (0);
  198 }
  199 
  200 static struct uart_ops at91_usart_ops = {
  201         .probe = at91_usart_probe,
  202         .init = at91_usart_init,
  203         .term = at91_usart_term,
  204         .putc = at91_usart_putc,
  205         .rxready = at91_usart_rxready,
  206         .getc = at91_usart_getc,
  207 };
  208 
  209 static int
  210 at91_usart_probe(struct uart_bas *bas)
  211 {
  212         /* We know that this is always here */
  213         return (0);
  214 }
  215 
  216 /*
  217  * Initialize this device for use as a console.
  218  */
  219 static void
  220 at91_usart_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
  221     int parity)
  222 {
  223 
  224         at91_usart_param(bas, baudrate, databits, stopbits, parity);
  225 
  226         /* Reset the rx and tx buffers and turn on rx and tx */
  227         WR4(bas, USART_CR, USART_CR_RSTSTA | USART_CR_RSTRX | USART_CR_RSTTX);
  228         WR4(bas, USART_CR, USART_CR_RXEN | USART_CR_TXEN);
  229         WR4(bas, USART_IDR, 0xffffffff);
  230 }
  231 
  232 /*
  233  * Free resources now that we're no longer the console.  This appears to
  234  * be never called, and I'm unsure quite what to do if I am called.
  235  */
  236 static void
  237 at91_usart_term(struct uart_bas *bas)
  238 {
  239         /* XXX */
  240 }
  241 
  242 /*
  243  * Put a character of console output (so we do it here polling rather than
  244  * interrutp driven).
  245  */
  246 static void
  247 at91_usart_putc(struct uart_bas *bas, int c)
  248 {
  249 
  250     while (!(RD4(bas, USART_CSR) & USART_CSR_TXRDY))
  251                 continue;
  252         WR4(bas, USART_THR, c);
  253 }
  254 
  255 /*
  256  * Check for a character available.
  257  */
  258 static int
  259 at91_usart_rxready(struct uart_bas *bas)
  260 {
  261 
  262         return ((RD4(bas, USART_CSR) & USART_CSR_RXRDY) != 0 ? 1 : 0);
  263 }
  264 
  265 /*
  266  * Block waiting for a character.
  267  */
  268 static int
  269 at91_usart_getc(struct uart_bas *bas, struct mtx *mtx)
  270 {
  271         int c;
  272 
  273         while (!(RD4(bas, USART_CSR) & USART_CSR_RXRDY))
  274                 continue;
  275         c = RD4(bas, USART_RHR);
  276         c &= 0xff;
  277         return (c);
  278 }
  279 
  280 static int at91_usart_bus_probe(struct uart_softc *sc);
  281 static int at91_usart_bus_attach(struct uart_softc *sc);
  282 static int at91_usart_bus_flush(struct uart_softc *, int);
  283 static int at91_usart_bus_getsig(struct uart_softc *);
  284 static int at91_usart_bus_ioctl(struct uart_softc *, int, intptr_t);
  285 static int at91_usart_bus_ipend(struct uart_softc *);
  286 static int at91_usart_bus_param(struct uart_softc *, int, int, int, int);
  287 static int at91_usart_bus_receive(struct uart_softc *);
  288 static int at91_usart_bus_setsig(struct uart_softc *, int);
  289 static int at91_usart_bus_transmit(struct uart_softc *);
  290 
  291 static kobj_method_t at91_usart_methods[] = {
  292         KOBJMETHOD(uart_probe,          at91_usart_bus_probe),
  293         KOBJMETHOD(uart_attach,         at91_usart_bus_attach),
  294         KOBJMETHOD(uart_flush,          at91_usart_bus_flush),
  295         KOBJMETHOD(uart_getsig,         at91_usart_bus_getsig),
  296         KOBJMETHOD(uart_ioctl,          at91_usart_bus_ioctl),
  297         KOBJMETHOD(uart_ipend,          at91_usart_bus_ipend),
  298         KOBJMETHOD(uart_param,          at91_usart_bus_param),
  299         KOBJMETHOD(uart_receive,        at91_usart_bus_receive),
  300         KOBJMETHOD(uart_setsig,         at91_usart_bus_setsig),
  301         KOBJMETHOD(uart_transmit,       at91_usart_bus_transmit),
  302         
  303         { 0, 0 }
  304 };
  305 
  306 int
  307 at91_usart_bus_probe(struct uart_softc *sc)
  308 {
  309 
  310         sc->sc_txfifosz = USART_BUFFER_SIZE;
  311         sc->sc_rxfifosz = USART_BUFFER_SIZE;
  312         sc->sc_hwiflow = 0;
  313         return (0);
  314 }
  315 
  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 
  324 static int
  325 at91_usart_bus_attach(struct uart_softc *sc)
  326 {
  327         int err;
  328         int i;
  329         uint32_t cr;
  330         struct at91_usart_softc *atsc;
  331 
  332         atsc = (struct at91_usart_softc *)sc;
  333 
  334         /*
  335          * See if we have a TIMEOUT bit.  We disable all interrupts as
  336          * a side effect.  Boot loaders may have enabled them.  Since
  337          * a TIMEOUT interrupt can't happen without other setup, the
  338          * apparent race here can't actually happen.
  339          */
  340         WR4(&sc->sc_bas, USART_IDR, 0xffffffff);
  341         WR4(&sc->sc_bas, USART_IER, USART_CSR_TIMEOUT);
  342         if (RD4(&sc->sc_bas, USART_IMR) & USART_CSR_TIMEOUT)
  343                 atsc->flags |= HAS_TIMEOUT;
  344         WR4(&sc->sc_bas, USART_IDR, 0xffffffff);
  345 
  346         /*
  347          * Allocate DMA tags and maps
  348          */
  349         err = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0,
  350             BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
  351             USART_BUFFER_SIZE, 1, USART_BUFFER_SIZE, BUS_DMA_ALLOCNOW, NULL,
  352             NULL, &atsc->dmatag);
  353         if (err != 0)
  354                 goto errout;
  355         err = bus_dmamap_create(atsc->dmatag, 0, &atsc->tx_map);
  356         if (err != 0)
  357                 goto errout;
  358         if (atsc->flags & HAS_TIMEOUT) {
  359                 for (i = 0; i < 2; i++) {
  360                         err = bus_dmamap_create(atsc->dmatag, 0,
  361                             &atsc->ping_pong[i].map);
  362                         if (err != 0)
  363                                 goto errout;
  364                         err = bus_dmamap_load(atsc->dmatag,
  365                             atsc->ping_pong[i].map,
  366                             atsc->ping_pong[i].buffer, sc->sc_rxfifosz,
  367                             at91_getaddr, &atsc->ping_pong[i].pa, 0);
  368                         if (err != 0)
  369                                 goto errout;
  370                         bus_dmamap_sync(atsc->dmatag, atsc->ping_pong[i].map,
  371                             BUS_DMASYNC_PREREAD);
  372                 }
  373                 atsc->ping = &atsc->ping_pong[0];
  374                 atsc->pong = &atsc->ping_pong[1];
  375         }
  376 
  377         /*
  378          * Prime the pump with the RX buffer.  We use two 64 byte bounce
  379          * buffers here to avoid data overflow.
  380          */
  381 
  382         /* Turn on rx and tx */
  383         cr = USART_CR_RSTSTA | USART_CR_RSTRX | USART_CR_RSTTX;
  384         WR4(&sc->sc_bas, USART_CR, cr);
  385         WR4(&sc->sc_bas, USART_CR, USART_CR_RXEN | USART_CR_TXEN);
  386 
  387         /*
  388          * Setup the PDC to receive data.  We use the ping-pong buffers
  389          * so that we can more easily bounce between the two and so that
  390          * we get an interrupt 1/2 way through the software 'fifo' we have
  391          * to avoid overruns.
  392          */
  393         if (atsc->flags & HAS_TIMEOUT) {
  394                 WR4(&sc->sc_bas, PDC_RPR, atsc->ping->pa);
  395                 WR4(&sc->sc_bas, PDC_RCR, sc->sc_rxfifosz);
  396                 WR4(&sc->sc_bas, PDC_RNPR, atsc->pong->pa);
  397                 WR4(&sc->sc_bas, PDC_RNCR, sc->sc_rxfifosz);
  398                 WR4(&sc->sc_bas, PDC_PTCR, PDC_PTCR_RXTEN);
  399 
  400                 /* Set the receive timeout to be 1.5 character times. */
  401                 WR4(&sc->sc_bas, USART_RTOR, 12);
  402                 WR4(&sc->sc_bas, USART_CR, USART_CR_STTTO);
  403                 WR4(&sc->sc_bas, USART_IER, USART_CSR_TIMEOUT |
  404                     USART_CSR_RXBUFF | USART_CSR_ENDRX);
  405         } else {
  406                 WR4(&sc->sc_bas, USART_IER, USART_CSR_RXRDY);
  407         }
  408         WR4(&sc->sc_bas, USART_IER, USART_CSR_RXBRK);
  409 errout:;
  410         // XXX bad
  411         return (err);
  412 }
  413 
  414 static int
  415 at91_usart_bus_transmit(struct uart_softc *sc)
  416 {
  417         bus_addr_t addr;
  418         struct at91_usart_softc *atsc;
  419 
  420         atsc = (struct at91_usart_softc *)sc;
  421         if (bus_dmamap_load(atsc->dmatag, atsc->tx_map, sc->sc_txbuf,
  422             sc->sc_txdatasz, at91_getaddr, &addr, 0) != 0)
  423                 return (EAGAIN);
  424         bus_dmamap_sync(atsc->dmatag, atsc->tx_map, BUS_DMASYNC_PREWRITE);
  425 
  426         uart_lock(sc->sc_hwmtx);
  427         sc->sc_txbusy = 1;
  428         /*
  429          * Setup the PDC to transfer the data and interrupt us when it
  430          * is done.  We've already requested the interrupt.
  431          */
  432         WR4(&sc->sc_bas, PDC_TPR, addr);
  433         WR4(&sc->sc_bas, PDC_TCR, sc->sc_txdatasz);
  434         WR4(&sc->sc_bas, PDC_PTCR, PDC_PTCR_TXTEN);
  435         WR4(&sc->sc_bas, USART_IER, USART_CSR_ENDTX);
  436         uart_unlock(sc->sc_hwmtx);
  437         return (0);
  438 }
  439 static int
  440 at91_usart_bus_setsig(struct uart_softc *sc, int sig)
  441 {
  442         uint32_t new, old, cr;
  443         struct uart_bas *bas;
  444 
  445         do {
  446                 old = sc->sc_hwsig;
  447                 new = old;
  448                 if (sig & SER_DDTR)
  449                         SIGCHG(sig & SER_DTR, new, SER_DTR, SER_DDTR);
  450                 if (sig & SER_DRTS)
  451                         SIGCHG(sig & SER_RTS, new, SER_RTS, SER_DRTS);
  452         } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
  453         bas = &sc->sc_bas;
  454         uart_lock(sc->sc_hwmtx);
  455         cr = 0;
  456         if (new & SER_DTR)
  457                 cr |= USART_CR_DTREN;
  458         else
  459                 cr |= USART_CR_DTRDIS;
  460         if (new & SER_RTS)
  461                 cr |= USART_CR_RTSEN;
  462         else
  463                 cr |= USART_CR_RTSDIS;
  464         WR4(bas, USART_CR, cr);
  465         uart_unlock(sc->sc_hwmtx);
  466         return (0);
  467 }
  468 static int
  469 at91_usart_bus_receive(struct uart_softc *sc)
  470 {
  471 
  472         return (0);
  473 }
  474 static int
  475 at91_usart_bus_param(struct uart_softc *sc, int baudrate, int databits,
  476     int stopbits, int parity)
  477 {
  478 
  479         return (at91_usart_param(&sc->sc_bas, baudrate, databits, stopbits,
  480             parity));
  481 }
  482 
  483 static __inline void
  484 at91_rx_put(struct uart_softc *sc, int key)
  485 {
  486 
  487 #if defined(KDB)
  488         if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE)
  489                 kdb_alt_break(key, &sc->sc_altbrk);
  490 #endif
  491         uart_rx_put(sc, key);   
  492 }
  493 
  494 static int
  495 at91_usart_bus_ipend(struct uart_softc *sc)
  496 {
  497         int csr = RD4(&sc->sc_bas, USART_CSR);
  498         int ipend = 0, i, len;
  499         struct at91_usart_softc *atsc;
  500         struct at91_usart_rx *p;
  501 
  502         atsc = (struct at91_usart_softc *)sc;      
  503         if (csr & USART_CSR_ENDTX) {
  504                 bus_dmamap_sync(atsc->dmatag, atsc->tx_map,
  505                     BUS_DMASYNC_POSTWRITE);
  506                 bus_dmamap_unload(atsc->dmatag, atsc->tx_map);
  507         }
  508         uart_lock(sc->sc_hwmtx);
  509         if (csr & USART_CSR_TXRDY) {
  510                 if (sc->sc_txbusy)
  511                         ipend |= SER_INT_TXIDLE;
  512                 WR4(&sc->sc_bas, USART_IDR, USART_CSR_TXRDY);
  513         }
  514         if (csr & USART_CSR_ENDTX) {
  515                 if (sc->sc_txbusy)
  516                         ipend |= SER_INT_TXIDLE;
  517                 WR4(&sc->sc_bas, USART_IDR, USART_CSR_ENDTX);
  518         }
  519 
  520         /*
  521          * Due to the contraints of the DMA engine present in the
  522          * atmel chip, I can't just say I have a rx interrupt pending
  523          * and do all the work elsewhere.  I need to look at the CSR
  524          * bits right now and do things based on them to avoid races.
  525          */
  526         if ((atsc->flags & HAS_TIMEOUT) && (csr & USART_CSR_RXBUFF)) {
  527                 // Have a buffer overflow.  Copy all data from both
  528                 // ping and pong.  Insert overflow character.  Reset
  529                 // ping and pong and re-enable the PDC to receive
  530                 // characters again.
  531                 bus_dmamap_sync(atsc->dmatag, atsc->ping->map,
  532                     BUS_DMASYNC_POSTREAD);
  533                 bus_dmamap_sync(atsc->dmatag, atsc->pong->map,
  534                     BUS_DMASYNC_POSTREAD);
  535                 for (i = 0; i < sc->sc_rxfifosz; i++)
  536                         at91_rx_put(sc, atsc->ping->buffer[i]);
  537                 for (i = 0; i < sc->sc_rxfifosz; i++)
  538                         at91_rx_put(sc, atsc->pong->buffer[i]);
  539                 uart_rx_put(sc, UART_STAT_OVERRUN);
  540                 csr &= ~(USART_CSR_ENDRX | USART_CSR_TIMEOUT);
  541                 WR4(&sc->sc_bas, PDC_RPR, atsc->ping->pa);
  542                 WR4(&sc->sc_bas, PDC_RCR, sc->sc_rxfifosz);
  543                 WR4(&sc->sc_bas, PDC_RNPR, atsc->pong->pa);
  544                 WR4(&sc->sc_bas, PDC_RNCR, sc->sc_rxfifosz);
  545                 WR4(&sc->sc_bas, PDC_PTCR, PDC_PTCR_RXTEN);
  546                 ipend |= SER_INT_RXREADY;
  547         }
  548         if ((atsc->flags & HAS_TIMEOUT) && (csr & USART_CSR_ENDRX)) {
  549                 // Shuffle data from 'ping' of ping pong buffer, but
  550                 // leave current 'pong' in place, as it has become the
  551                 // new 'ping'.  We need to copy data and setup the old
  552                 // 'ping' as the new 'pong' when we're done.
  553                 bus_dmamap_sync(atsc->dmatag, atsc->ping->map,
  554                     BUS_DMASYNC_POSTREAD);
  555                 for (i = 0; i < sc->sc_rxfifosz; i++)
  556                         at91_rx_put(sc, atsc->ping->buffer[i]);
  557                 p = atsc->ping;
  558                 atsc->ping = atsc->pong;
  559                 atsc->pong = p;
  560                 WR4(&sc->sc_bas, PDC_RNPR, atsc->pong->pa);
  561                 WR4(&sc->sc_bas, PDC_RNCR, sc->sc_rxfifosz);
  562                 ipend |= SER_INT_RXREADY;
  563         }
  564         if ((atsc->flags & HAS_TIMEOUT) && (csr & USART_CSR_TIMEOUT)) {
  565                 // We have one partial buffer.  We need to stop the
  566                 // PDC, get the number of characters left and from
  567                 // that compute number of valid characters.  We then
  568                 // need to reset ping and pong and reenable the PDC.
  569                 // Not sure if there's a race here at fast baud rates
  570                 // we need to worry about.
  571                 WR4(&sc->sc_bas, PDC_PTCR, PDC_PTCR_RXTDIS);
  572                 bus_dmamap_sync(atsc->dmatag, atsc->ping->map,
  573                     BUS_DMASYNC_POSTREAD);
  574                 len = sc->sc_rxfifosz - RD4(&sc->sc_bas, PDC_RCR);
  575                 for (i = 0; i < len; i++)
  576                         at91_rx_put(sc, atsc->ping->buffer[i]);
  577                 WR4(&sc->sc_bas, PDC_RPR, atsc->ping->pa);
  578                 WR4(&sc->sc_bas, PDC_RCR, sc->sc_rxfifosz);
  579                 WR4(&sc->sc_bas, USART_CR, USART_CR_STTTO);
  580                 WR4(&sc->sc_bas, PDC_PTCR, PDC_PTCR_RXTEN);
  581                 ipend |= SER_INT_RXREADY;
  582         }
  583         if (!(atsc->flags & HAS_TIMEOUT) && (csr & USART_CSR_RXRDY)) {
  584                 // We have another charater in a device that doesn't support
  585                 // timeouts, so we do it one character at a time.
  586                 at91_rx_put(sc, RD4(&sc->sc_bas, USART_RHR) & 0xff);
  587                 ipend |= SER_INT_RXREADY;
  588         }
  589 
  590         if (csr & USART_CSR_RXBRK) {
  591                 unsigned int cr = USART_CR_RSTSTA;
  592 
  593                 ipend |= SER_INT_BREAK;
  594                 WR4(&sc->sc_bas, USART_CR, cr);
  595         }
  596         uart_unlock(sc->sc_hwmtx);
  597         return (ipend);
  598 }
  599 static int
  600 at91_usart_bus_flush(struct uart_softc *sc, int what)
  601 {
  602         return (0);
  603 }
  604 
  605 static int
  606 at91_usart_bus_getsig(struct uart_softc *sc)
  607 {
  608         uint32_t new, sig;
  609         uint8_t csr;
  610 
  611         uart_lock(sc->sc_hwmtx);
  612         csr = RD4(&sc->sc_bas, USART_CSR);
  613         sig = 0;
  614         if (csr & USART_CSR_CTS)
  615                 sig |= SER_CTS;
  616         if (csr & USART_CSR_DCD)
  617                 sig |= SER_DCD;
  618         if (csr & USART_CSR_DSR)
  619                 sig |= SER_DSR;
  620         if (csr & USART_CSR_RI)
  621                 sig |= SER_RI;
  622         new = sig & ~SER_MASK_DELTA;
  623         sc->sc_hwsig = new;
  624         uart_unlock(sc->sc_hwmtx);
  625         return (sig);
  626 }
  627 
  628 static int
  629 at91_usart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
  630 {
  631         switch (request) {
  632         case UART_IOCTL_BREAK:
  633         case UART_IOCTL_IFLOW:
  634         case UART_IOCTL_OFLOW:
  635                 break;
  636         case UART_IOCTL_BAUD:
  637                 /* only if we know our master clock rate */
  638                 if (DEFAULT_RCLK != 0)
  639                         WR4(&sc->sc_bas, USART_BRGR,
  640                                 BAUD2DIVISOR(*(int *)data));
  641                 return (0);
  642         }
  643         return (EINVAL);
  644 }
  645 
  646 struct uart_class at91_usart_class = {
  647         "at91_usart",
  648         at91_usart_methods,
  649         sizeof(struct at91_usart_softc),
  650         .uc_ops = &at91_usart_ops,
  651         .uc_range = 8
  652 };

Cache object: 3dd824a4ae3b6f47a2d00c58645928dc


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