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/8.4/sys/mips/adm5120/uart_dev_adm5120.c 215938 2010-11-27 12:26:40Z jchandra $");
   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 
  153 static kobj_method_t adm5120_uart_methods[] = {
  154         KOBJMETHOD(uart_attach,         adm5120_uart_bus_attach),
  155         KOBJMETHOD(uart_detach,         adm5120_uart_bus_detach),
  156         KOBJMETHOD(uart_flush,          adm5120_uart_bus_flush),
  157         KOBJMETHOD(uart_getsig,         adm5120_uart_bus_getsig),
  158         KOBJMETHOD(uart_ioctl,          adm5120_uart_bus_ioctl),
  159         KOBJMETHOD(uart_ipend,          adm5120_uart_bus_ipend),
  160         KOBJMETHOD(uart_param,          adm5120_uart_bus_param),
  161         KOBJMETHOD(uart_probe,          adm5120_uart_bus_probe),
  162         KOBJMETHOD(uart_receive,        adm5120_uart_bus_receive),
  163         KOBJMETHOD(uart_setsig,         adm5120_uart_bus_setsig),
  164         KOBJMETHOD(uart_transmit,       adm5120_uart_bus_transmit),
  165         { 0, 0 }
  166 };
  167 
  168 struct uart_class uart_adm5120_uart_class = {
  169         "adm5120",
  170         adm5120_uart_methods,
  171         sizeof(struct adm5120_uart_softc),
  172         .uc_ops = &uart_adm5120_uart_ops,
  173         .uc_range = 1, /* use hinted range */
  174         .uc_rclk = 62500000
  175 };
  176 
  177 #define SIGCHG(c, i, s, d)                              \
  178         if (c) {                                        \
  179                 i |= (i & s) ? s : s | d;               \
  180         } else {                                        \
  181                 i = (i & s) ? (i & ~s) | d : i;         \
  182         }
  183 
  184 /*
  185  * Disable TX interrupt. uart should be locked 
  186  */ 
  187 static __inline void
  188 adm5120_uart_disable_txintr(struct uart_softc *sc)
  189 {
  190         uint8_t cr;
  191 
  192         cr = uart_getreg(&sc->sc_bas, UART_CR_REG);
  193         cr &= ~UART_CR_TX_INT_EN;
  194         uart_setreg(&sc->sc_bas, UART_CR_REG, cr);
  195 }
  196 
  197 /*
  198  * Enable TX interrupt. uart should be locked 
  199  */ 
  200 static __inline void
  201 adm5120_uart_enable_txintr(struct uart_softc *sc)
  202 {
  203         uint8_t cr;
  204 
  205         cr = uart_getreg(&sc->sc_bas, UART_CR_REG);
  206         cr |= UART_CR_TX_INT_EN;
  207         uart_setreg(&sc->sc_bas, UART_CR_REG, cr);
  208 }
  209 
  210 static int
  211 adm5120_uart_bus_attach(struct uart_softc *sc)
  212 {
  213         struct uart_bas *bas;
  214         struct uart_devinfo *di;
  215 
  216         bas = &sc->sc_bas;
  217         if (sc->sc_sysdev != NULL) {
  218                 di = sc->sc_sysdev;
  219                 /* TODO: set parameters from di */
  220         } else {
  221                 /* TODO: set parameters 115200, 8N1 */
  222         }
  223 
  224         sc->sc_rxfifosz = 16;
  225         sc->sc_txfifosz = 16;
  226 
  227         (void)adm5120_uart_bus_getsig(sc);
  228 
  229 #if 1
  230         /* Enable FIFO */
  231         uart_setreg(bas, UART_LCR_H_REG, 
  232             uart_getreg(bas, UART_LCR_H_REG) | UART_LCR_H_FEN);
  233 #endif
  234         /* Enable interrupts */
  235         uart_setreg(bas, UART_CR_REG,
  236             UART_CR_PORT_EN|UART_CR_RX_INT_EN|UART_CR_RX_TIMEOUT_INT_EN|
  237             UART_CR_MODEM_STATUS_INT_EN);
  238 
  239         return (0);
  240 }
  241 
  242 static int
  243 adm5120_uart_bus_detach(struct uart_softc *sc)
  244 {
  245 
  246         return (0);
  247 }
  248 
  249 static int
  250 adm5120_uart_bus_flush(struct uart_softc *sc, int what)
  251 {
  252 
  253         return (0);
  254 }
  255 
  256 static int
  257 adm5120_uart_bus_getsig(struct uart_softc *sc)
  258 {
  259         uint32_t new, old, sig;
  260         uint8_t bes;
  261 
  262         do {
  263                 old = sc->sc_hwsig;
  264                 sig = old;
  265                 uart_lock(sc->sc_hwmtx);
  266                 bes = uart_getreg(&sc->sc_bas, UART_FR_REG);
  267                 uart_unlock(sc->sc_hwmtx);
  268                 SIGCHG(bes & UART_FR_CTS, sig, SER_CTS, SER_DCTS);
  269                 SIGCHG(bes & UART_FR_DCD, sig, SER_DCD, SER_DDCD);
  270                 SIGCHG(bes & UART_FR_DSR, sig, SER_DSR, SER_DDSR);
  271                 new = sig & ~SER_MASK_DELTA;
  272         } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
  273 
  274         return (sig);
  275 }
  276 
  277 static int
  278 adm5120_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
  279 {
  280         struct uart_bas *bas;
  281         int baudrate, divisor, error;
  282 
  283         bas = &sc->sc_bas;
  284         error = 0;
  285         uart_lock(sc->sc_hwmtx);
  286         switch (request) {
  287         case UART_IOCTL_BREAK:
  288                 /* TODO: Send BREAK */
  289                 break;
  290         case UART_IOCTL_BAUD:
  291                 divisor = uart_getreg(bas, UART_LCR_M_REG);
  292                 divisor = (divisor << 8) | 
  293                     uart_getreg(bas, UART_LCR_L_REG);
  294                 baudrate = bas->rclk / 2 / (divisor + 2);
  295                 *(int*)data = baudrate;
  296                 break;
  297         default:
  298                 error = EINVAL;
  299                 break;
  300         }
  301         uart_unlock(sc->sc_hwmtx);
  302         return (error);
  303 }
  304 
  305 static int
  306 adm5120_uart_bus_ipend(struct uart_softc *sc)
  307 {
  308         struct uart_bas *bas;
  309         int ipend;
  310         uint8_t ir, fr, rsr;
  311 
  312         bas = &sc->sc_bas;
  313         ipend = 0;
  314 
  315         uart_lock(sc->sc_hwmtx);
  316         ir = uart_getreg(&sc->sc_bas, UART_IR_REG);
  317         fr = uart_getreg(&sc->sc_bas, UART_FR_REG);
  318         rsr = uart_getreg(&sc->sc_bas, UART_RSR_REG);
  319 
  320         if (ir & UART_IR_RX_INT)
  321                 ipend |= SER_INT_RXREADY;
  322 
  323         if (ir & UART_IR_RX_TIMEOUT_INT)
  324                 ipend |= SER_INT_RXREADY;
  325 
  326         if (ir & UART_IR_MODEM_STATUS_INT)
  327                 ipend |= SER_INT_SIGCHG;
  328 
  329         if (rsr & UART_RSR_BE)
  330                 ipend |= SER_INT_BREAK;
  331 
  332         if (rsr & UART_RSR_OE)
  333                 ipend |= SER_INT_OVERRUN;
  334 
  335         if (fr & UART_FR_TX_FIFO_EMPTY) {
  336                 if (ir & UART_IR_TX_INT) {
  337                         adm5120_uart_disable_txintr(sc);
  338                         ipend |= SER_INT_TXIDLE;
  339                 }
  340         }
  341 
  342         if (ipend)
  343                 uart_setreg(bas, UART_IR_REG, ir | UART_IR_UICR);
  344 
  345         uart_unlock(sc->sc_hwmtx);
  346 
  347         return (ipend);
  348 }
  349 
  350 static int
  351 adm5120_uart_bus_param(struct uart_softc *sc, int baudrate, int databits,
  352     int stopbits, int parity)
  353 {
  354 
  355         /* TODO: Set parameters for uart, meanwhile stick with 115200 8N1 */
  356         return (0);
  357 }
  358 
  359 static int
  360 adm5120_uart_bus_probe(struct uart_softc *sc)
  361 {
  362         char buf[80];
  363         int error;
  364         char ch;
  365 
  366         error = adm5120_uart_probe(&sc->sc_bas);
  367         if (error)
  368                 return (error);
  369 
  370         ch = sc->sc_bas.chan + 'A';
  371 
  372         snprintf(buf, sizeof(buf), "adm5120_uart, channel %c", ch);
  373         device_set_desc_copy(sc->sc_dev, buf);
  374 
  375         return (0);
  376 }
  377 
  378 static int
  379 adm5120_uart_bus_receive(struct uart_softc *sc)
  380 {
  381         struct uart_bas *bas;
  382         int xc;
  383         uint8_t fr, rsr;
  384 
  385         bas = &sc->sc_bas;
  386         uart_lock(sc->sc_hwmtx);
  387         fr = uart_getreg(bas, UART_FR_REG);
  388         while (!(fr & UART_FR_RX_FIFO_EMPTY)) {
  389                 if (uart_rx_full(sc)) {
  390                         sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
  391                         break;
  392                 }
  393                 xc = 0;
  394                 rsr = uart_getreg(bas, UART_RSR_REG);
  395                 if (rsr & UART_RSR_FE)
  396                         xc |= UART_STAT_FRAMERR;
  397                 if (rsr & UART_RSR_PE)
  398                         xc |= UART_STAT_PARERR;
  399                 if (rsr & UART_RSR_OE)
  400                         xc |= UART_STAT_OVERRUN;
  401                 xc |= uart_getreg(bas, UART_DR_REG);
  402                 uart_barrier(bas);
  403                 uart_rx_put(sc, xc);
  404                 if (rsr & (UART_RSR_FE | UART_RSR_PE | UART_RSR_OE)) {
  405                         uart_setreg(bas, UART_ECR_REG, UART_ECR_RSR);
  406                         uart_barrier(bas);
  407                 }
  408                 fr = uart_getreg(bas, UART_FR_REG);
  409         }
  410 
  411         /* Discard everything left in the Rx FIFO. */
  412         while (!(fr & UART_FR_RX_FIFO_EMPTY)) {
  413                 ( void)uart_getreg(bas, UART_DR_REG);
  414                 uart_barrier(bas);
  415                 rsr = uart_getreg(bas, UART_RSR_REG);
  416                 if (rsr & (UART_RSR_FE | UART_RSR_PE | UART_RSR_OE)) {
  417                         uart_setreg(bas, UART_ECR_REG, UART_ECR_RSR);
  418                         uart_barrier(bas);
  419                 }
  420                 fr = uart_getreg(bas, UART_FR_REG);
  421         }
  422         uart_unlock(sc->sc_hwmtx);
  423         return (0);
  424 }
  425 
  426 static int
  427 adm5120_uart_bus_setsig(struct uart_softc *sc, int sig)
  428 {
  429 
  430         /* TODO: implement (?) */
  431         return (0);
  432 }
  433 
  434 static int
  435 adm5120_uart_bus_transmit(struct uart_softc *sc)
  436 {
  437         struct uart_bas *bas;
  438 
  439         bas = &sc->sc_bas;
  440         uart_lock(sc->sc_hwmtx);
  441         sc->sc_txbusy = 1;
  442         for (int i = 0; i < sc->sc_txdatasz; i++) {
  443                 if (uart_getreg(bas, UART_FR_REG) & UART_FR_TX_FIFO_FULL) 
  444                         break;
  445                 uart_setreg(bas, UART_DR_REG, sc->sc_txbuf[i]);
  446         }
  447 
  448         /* Enable TX interrupt */
  449         adm5120_uart_enable_txintr(sc);
  450         uart_unlock(sc->sc_hwmtx);
  451         return (0);
  452 }

Cache object: 27302e5d30005a4fde3322c72700f4bc


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