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/mips/adm5120/uart_dev_adm5120.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 /* $NetBSD: uart.c,v 1.2 2007/03/23 20:05:47 dogcow Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko.
    5  * Copyright (c) 2007 Oleksandr Tymoshenko.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or
    9  * without modification, are permitted provided that the following
   10  * conditions are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above
   14  *    copyright notice, this list of conditions and the following
   15  *    disclaimer in the documentation and/or other materials provided
   16  *    with the distribution.
   17  * 3. The names of the authors may not be used to endorse or promote
   18  *    products derived from this software without specific prior
   19  *    written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
   22  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
   23  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
   24  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS
   25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
   26  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
   28  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
   30  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
   32  * OF SUCH DAMAGE.
   33  */
   34 
   35 #include <sys/cdefs.h>
   36 __FBSDID("$FreeBSD: releng/11.2/sys/mips/adm5120/uart_dev_adm5120.c 331722 2018-03-29 02:50:57Z eadler $");
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/bus.h>
   41 #include <sys/conf.h>
   42 #include <machine/bus.h>
   43 
   44 #include <dev/uart/uart.h>
   45 #include <dev/uart/uart_cpu.h>
   46 #include <dev/uart/uart_bus.h>
   47 
   48 #include <mips/adm5120/uart_dev_adm5120.h>
   49 
   50 #include "uart_if.h"
   51 
   52 /*
   53  * Low-level UART interface.
   54  */
   55 static int adm5120_uart_probe(struct uart_bas *bas);
   56 static void adm5120_uart_init(struct uart_bas *bas, int, int, int, int);
   57 static void adm5120_uart_term(struct uart_bas *bas);
   58 static void adm5120_uart_putc(struct uart_bas *bas, int);
   59 static int adm5120_uart_rxready(struct uart_bas *bas);
   60 static int adm5120_uart_getc(struct uart_bas *bas, struct mtx *);
   61 
   62 static struct uart_ops uart_adm5120_uart_ops = {
   63         .probe = adm5120_uart_probe,
   64         .init = adm5120_uart_init,
   65         .term = adm5120_uart_term,
   66         .putc = adm5120_uart_putc,
   67         .rxready = adm5120_uart_rxready,
   68         .getc = adm5120_uart_getc,
   69 };
   70 
   71 static int
   72 adm5120_uart_probe(struct uart_bas *bas)
   73 {
   74 
   75         return (0);
   76 }
   77 
   78 static void
   79 adm5120_uart_init(struct uart_bas *bas, int baudrate, int databits, 
   80     int stopbits, int parity)
   81 {
   82 
   83         /* TODO: Set parameters for uart, meanwhile stick with 115200N1 */
   84 }
   85 
   86 static void
   87 adm5120_uart_term(struct uart_bas *bas)
   88 {
   89 
   90 }
   91 
   92 static void
   93 adm5120_uart_putc(struct uart_bas *bas, int c)
   94 {
   95         char chr;
   96         chr = c;
   97         while (uart_getreg(bas, UART_FR_REG) & UART_FR_TX_FIFO_FULL)
   98                 ;
   99         uart_setreg(bas, UART_DR_REG, c);
  100         while (uart_getreg(bas, UART_FR_REG) & UART_FR_BUSY)
  101                 ;
  102         uart_barrier(bas);
  103 }
  104 
  105 static int
  106 adm5120_uart_rxready(struct uart_bas *bas)
  107 {
  108         if (uart_getreg(bas, UART_FR_REG) & UART_FR_RX_FIFO_EMPTY)
  109                 return (0);
  110 
  111         return (1);
  112 }
  113 
  114 static int
  115 adm5120_uart_getc(struct uart_bas *bas, struct mtx *hwmtx)
  116 {
  117         int c;
  118 
  119         uart_lock(hwmtx);
  120 
  121         while (uart_getreg(bas, UART_FR_REG) & UART_FR_RX_FIFO_EMPTY) {
  122                 uart_unlock(hwmtx);
  123                 DELAY(10);
  124                 uart_lock(hwmtx);
  125         }
  126 
  127         c = uart_getreg(bas, UART_DR_REG);
  128 
  129         uart_unlock(hwmtx);
  130 
  131         return (c);
  132 }
  133 
  134 /*
  135  * High-level UART interface.
  136  */
  137 struct adm5120_uart_softc {
  138         struct uart_softc base;
  139 };
  140 
  141 static int adm5120_uart_bus_attach(struct uart_softc *);
  142 static int adm5120_uart_bus_detach(struct uart_softc *);
  143 static int adm5120_uart_bus_flush(struct uart_softc *, int);
  144 static int adm5120_uart_bus_getsig(struct uart_softc *);
  145 static int adm5120_uart_bus_ioctl(struct uart_softc *, int, intptr_t);
  146 static int adm5120_uart_bus_ipend(struct uart_softc *);
  147 static int adm5120_uart_bus_param(struct uart_softc *, int, int, int, int);
  148 static int adm5120_uart_bus_probe(struct uart_softc *);
  149 static int adm5120_uart_bus_receive(struct uart_softc *);
  150 static int adm5120_uart_bus_setsig(struct uart_softc *, int);
  151 static int adm5120_uart_bus_transmit(struct uart_softc *);
  152 static void adm5120_uart_bus_grab(struct uart_softc *);
  153 static void adm5120_uart_bus_ungrab(struct uart_softc *);
  154 
  155 static kobj_method_t adm5120_uart_methods[] = {
  156         KOBJMETHOD(uart_attach,         adm5120_uart_bus_attach),
  157         KOBJMETHOD(uart_detach,         adm5120_uart_bus_detach),
  158         KOBJMETHOD(uart_flush,          adm5120_uart_bus_flush),
  159         KOBJMETHOD(uart_getsig,         adm5120_uart_bus_getsig),
  160         KOBJMETHOD(uart_ioctl,          adm5120_uart_bus_ioctl),
  161         KOBJMETHOD(uart_ipend,          adm5120_uart_bus_ipend),
  162         KOBJMETHOD(uart_param,          adm5120_uart_bus_param),
  163         KOBJMETHOD(uart_probe,          adm5120_uart_bus_probe),
  164         KOBJMETHOD(uart_receive,        adm5120_uart_bus_receive),
  165         KOBJMETHOD(uart_setsig,         adm5120_uart_bus_setsig),
  166         KOBJMETHOD(uart_transmit,       adm5120_uart_bus_transmit),
  167         KOBJMETHOD(uart_grab,           adm5120_uart_bus_grab),
  168         KOBJMETHOD(uart_ungrab,         adm5120_uart_bus_ungrab),
  169         { 0, 0 }
  170 };
  171 
  172 struct uart_class uart_adm5120_uart_class = {
  173         "adm5120",
  174         adm5120_uart_methods,
  175         sizeof(struct adm5120_uart_softc),
  176         .uc_ops = &uart_adm5120_uart_ops,
  177         .uc_range = 1, /* use hinted range */
  178         .uc_rclk = 62500000,
  179         .uc_rshift = 0
  180 };
  181 
  182 #define SIGCHG(c, i, s, d)                              \
  183         if (c) {                                        \
  184                 i |= (i & s) ? s : s | d;               \
  185         } else {                                        \
  186                 i = (i & s) ? (i & ~s) | d : i;         \
  187         }
  188 
  189 /*
  190  * Disable TX interrupt. uart should be locked 
  191  */ 
  192 static __inline void
  193 adm5120_uart_disable_txintr(struct uart_softc *sc)
  194 {
  195         uint8_t cr;
  196 
  197         cr = uart_getreg(&sc->sc_bas, UART_CR_REG);
  198         cr &= ~UART_CR_TX_INT_EN;
  199         uart_setreg(&sc->sc_bas, UART_CR_REG, cr);
  200 }
  201 
  202 /*
  203  * Enable TX interrupt. uart should be locked 
  204  */ 
  205 static __inline void
  206 adm5120_uart_enable_txintr(struct uart_softc *sc)
  207 {
  208         uint8_t cr;
  209 
  210         cr = uart_getreg(&sc->sc_bas, UART_CR_REG);
  211         cr |= UART_CR_TX_INT_EN;
  212         uart_setreg(&sc->sc_bas, UART_CR_REG, cr);
  213 }
  214 
  215 static int
  216 adm5120_uart_bus_attach(struct uart_softc *sc)
  217 {
  218         struct uart_bas *bas;
  219         struct uart_devinfo *di;
  220 
  221         bas = &sc->sc_bas;
  222         if (sc->sc_sysdev != NULL) {
  223                 di = sc->sc_sysdev;
  224                 /* TODO: set parameters from di */
  225         } else {
  226                 /* TODO: set parameters 115200, 8N1 */
  227         }
  228 
  229         (void)adm5120_uart_bus_getsig(sc);
  230 
  231 #if 1
  232         /* Enable FIFO */
  233         uart_setreg(bas, UART_LCR_H_REG, 
  234             uart_getreg(bas, UART_LCR_H_REG) | UART_LCR_H_FEN);
  235 #endif
  236         /* Enable interrupts */
  237         uart_setreg(bas, UART_CR_REG,
  238             UART_CR_PORT_EN|UART_CR_RX_INT_EN|UART_CR_RX_TIMEOUT_INT_EN|
  239             UART_CR_MODEM_STATUS_INT_EN);
  240 
  241         return (0);
  242 }
  243 
  244 static int
  245 adm5120_uart_bus_detach(struct uart_softc *sc)
  246 {
  247 
  248         return (0);
  249 }
  250 
  251 static int
  252 adm5120_uart_bus_flush(struct uart_softc *sc, int what)
  253 {
  254 
  255         return (0);
  256 }
  257 
  258 static int
  259 adm5120_uart_bus_getsig(struct uart_softc *sc)
  260 {
  261         uint32_t new, old, sig;
  262         uint8_t bes;
  263 
  264         do {
  265                 old = sc->sc_hwsig;
  266                 sig = old;
  267                 uart_lock(sc->sc_hwmtx);
  268                 bes = uart_getreg(&sc->sc_bas, UART_FR_REG);
  269                 uart_unlock(sc->sc_hwmtx);
  270                 SIGCHG(bes & UART_FR_CTS, sig, SER_CTS, SER_DCTS);
  271                 SIGCHG(bes & UART_FR_DCD, sig, SER_DCD, SER_DDCD);
  272                 SIGCHG(bes & UART_FR_DSR, sig, SER_DSR, SER_DDSR);
  273                 new = sig & ~SER_MASK_DELTA;
  274         } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
  275 
  276         return (sig);
  277 }
  278 
  279 static int
  280 adm5120_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
  281 {
  282         struct uart_bas *bas;
  283         int baudrate, divisor, error;
  284 
  285         bas = &sc->sc_bas;
  286         error = 0;
  287         uart_lock(sc->sc_hwmtx);
  288         switch (request) {
  289         case UART_IOCTL_BREAK:
  290                 /* TODO: Send BREAK */
  291                 break;
  292         case UART_IOCTL_BAUD:
  293                 divisor = uart_getreg(bas, UART_LCR_M_REG);
  294                 divisor = (divisor << 8) | 
  295                     uart_getreg(bas, UART_LCR_L_REG);
  296                 baudrate = bas->rclk / 2 / (divisor + 2);
  297                 *(int*)data = baudrate;
  298                 break;
  299         default:
  300                 error = EINVAL;
  301                 break;
  302         }
  303         uart_unlock(sc->sc_hwmtx);
  304         return (error);
  305 }
  306 
  307 static int
  308 adm5120_uart_bus_ipend(struct uart_softc *sc)
  309 {
  310         struct uart_bas *bas;
  311         int ipend;
  312         uint8_t ir, fr, rsr;
  313 
  314         bas = &sc->sc_bas;
  315         ipend = 0;
  316 
  317         uart_lock(sc->sc_hwmtx);
  318         ir = uart_getreg(&sc->sc_bas, UART_IR_REG);
  319         fr = uart_getreg(&sc->sc_bas, UART_FR_REG);
  320         rsr = uart_getreg(&sc->sc_bas, UART_RSR_REG);
  321 
  322         if (ir & UART_IR_RX_INT)
  323                 ipend |= SER_INT_RXREADY;
  324 
  325         if (ir & UART_IR_RX_TIMEOUT_INT)
  326                 ipend |= SER_INT_RXREADY;
  327 
  328         if (ir & UART_IR_MODEM_STATUS_INT)
  329                 ipend |= SER_INT_SIGCHG;
  330 
  331         if (rsr & UART_RSR_BE)
  332                 ipend |= SER_INT_BREAK;
  333 
  334         if (rsr & UART_RSR_OE)
  335                 ipend |= SER_INT_OVERRUN;
  336 
  337         if (fr & UART_FR_TX_FIFO_EMPTY) {
  338                 if (ir & UART_IR_TX_INT) {
  339                         adm5120_uart_disable_txintr(sc);
  340                         ipend |= SER_INT_TXIDLE;
  341                 }
  342         }
  343 
  344         if (ipend)
  345                 uart_setreg(bas, UART_IR_REG, ir | UART_IR_UICR);
  346 
  347         uart_unlock(sc->sc_hwmtx);
  348 
  349         return (ipend);
  350 }
  351 
  352 static int
  353 adm5120_uart_bus_param(struct uart_softc *sc, int baudrate, int databits,
  354     int stopbits, int parity)
  355 {
  356 
  357         /* TODO: Set parameters for uart, meanwhile stick with 115200 8N1 */
  358         return (0);
  359 }
  360 
  361 static int
  362 adm5120_uart_bus_probe(struct uart_softc *sc)
  363 {
  364         char buf[80];
  365         int error;
  366         char ch;
  367 
  368         error = adm5120_uart_probe(&sc->sc_bas);
  369         if (error)
  370                 return (error);
  371 
  372         sc->sc_rxfifosz = 16;
  373         sc->sc_txfifosz = 16;
  374 
  375         ch = sc->sc_bas.chan + 'A';
  376 
  377         snprintf(buf, sizeof(buf), "adm5120_uart, channel %c", ch);
  378         device_set_desc_copy(sc->sc_dev, buf);
  379 
  380         return (0);
  381 }
  382 
  383 static int
  384 adm5120_uart_bus_receive(struct uart_softc *sc)
  385 {
  386         struct uart_bas *bas;
  387         int xc;
  388         uint8_t fr, rsr;
  389 
  390         bas = &sc->sc_bas;
  391         uart_lock(sc->sc_hwmtx);
  392         fr = uart_getreg(bas, UART_FR_REG);
  393         while (!(fr & UART_FR_RX_FIFO_EMPTY)) {
  394                 if (uart_rx_full(sc)) {
  395                         sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
  396                         break;
  397                 }
  398                 xc = 0;
  399                 rsr = uart_getreg(bas, UART_RSR_REG);
  400                 if (rsr & UART_RSR_FE)
  401                         xc |= UART_STAT_FRAMERR;
  402                 if (rsr & UART_RSR_PE)
  403                         xc |= UART_STAT_PARERR;
  404                 if (rsr & UART_RSR_OE)
  405                         xc |= UART_STAT_OVERRUN;
  406                 xc |= uart_getreg(bas, UART_DR_REG);
  407                 uart_barrier(bas);
  408                 uart_rx_put(sc, xc);
  409                 if (rsr & (UART_RSR_FE | UART_RSR_PE | UART_RSR_OE)) {
  410                         uart_setreg(bas, UART_ECR_REG, UART_ECR_RSR);
  411                         uart_barrier(bas);
  412                 }
  413                 fr = uart_getreg(bas, UART_FR_REG);
  414         }
  415 
  416         /* Discard everything left in the Rx FIFO. */
  417         while (!(fr & UART_FR_RX_FIFO_EMPTY)) {
  418                 ( void)uart_getreg(bas, UART_DR_REG);
  419                 uart_barrier(bas);
  420                 rsr = uart_getreg(bas, UART_RSR_REG);
  421                 if (rsr & (UART_RSR_FE | UART_RSR_PE | UART_RSR_OE)) {
  422                         uart_setreg(bas, UART_ECR_REG, UART_ECR_RSR);
  423                         uart_barrier(bas);
  424                 }
  425                 fr = uart_getreg(bas, UART_FR_REG);
  426         }
  427         uart_unlock(sc->sc_hwmtx);
  428         return (0);
  429 }
  430 
  431 static int
  432 adm5120_uart_bus_setsig(struct uart_softc *sc, int sig)
  433 {
  434 
  435         /* TODO: implement (?) */
  436         return (0);
  437 }
  438 
  439 static int
  440 adm5120_uart_bus_transmit(struct uart_softc *sc)
  441 {
  442         struct uart_bas *bas;
  443 
  444         bas = &sc->sc_bas;
  445         uart_lock(sc->sc_hwmtx);
  446         sc->sc_txbusy = 1;
  447         for (int i = 0; i < sc->sc_txdatasz; i++) {
  448                 if (uart_getreg(bas, UART_FR_REG) & UART_FR_TX_FIFO_FULL) 
  449                         break;
  450                 uart_setreg(bas, UART_DR_REG, sc->sc_txbuf[i]);
  451         }
  452 
  453         /* Enable TX interrupt */
  454         adm5120_uart_enable_txintr(sc);
  455         uart_unlock(sc->sc_hwmtx);
  456         return (0);
  457 }
  458 
  459 static void
  460 adm5120_uart_bus_grab(struct uart_softc *sc)
  461 {
  462 
  463         /* Enable interrupts - no RX_INT or RX_TIMEOUT */
  464         uart_lock(sc->sc_hwmtx);
  465         uart_setreg(&sc->sc_bas, UART_CR_REG,
  466             UART_CR_PORT_EN | UART_CR_MODEM_STATUS_INT_EN);
  467         uart_unlock(sc->sc_hwmtx);
  468 }
  469 
  470 static void
  471 adm5120_uart_bus_ungrab(struct uart_softc *sc)
  472 {
  473 
  474         /* Enable interrupts */
  475         uart_lock(sc->sc_hwmtx);
  476         uart_setreg(&sc->sc_bas, UART_CR_REG,
  477             UART_CR_PORT_EN|UART_CR_RX_INT_EN|UART_CR_RX_TIMEOUT_INT_EN|
  478             UART_CR_MODEM_STATUS_INT_EN);
  479         uart_unlock(sc->sc_hwmtx);
  480 }

Cache object: 88364abd81744a1f0e84e5b4968c4ac6


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