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

Cache object: 6dacb1817f9430997060731ec9e550d6


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