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/s3c2xx0/uart_dev_s3c2410.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) 2003 Marcel Moolenaar
    3  * Copyright (c) 2007-2009 Andrew Turner
    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/9.0/sys/arm/s3c2xx0/uart_dev_s3c2410.c 205354 2010-03-20 03:39:35Z imp $");
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/bus.h>
   34 #include <sys/conf.h>
   35 #include <sys/cons.h>
   36 #include <sys/tty.h>
   37 #include <sys/rman.h>
   38 #include <machine/bus.h>
   39 #include <machine/intr.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/s3c2xx0/s3c2440reg.h>
   45 #include <arm/s3c2xx0/uart_dev_s3c2410.h>
   46 #include <arm/s3c2xx0/s3c2xx0reg.h>
   47 #include <arm/s3c2xx0/s3c2xx0var.h>
   48 #include "uart_if.h"
   49 
   50 /* Finds the subirq from the parent */
   51 #define get_sub_irq(parent, offset) \
   52         ((parent == S3C24X0_INT_UART0) ? S3C24X0_SUBIRQ_MIN + offset : \
   53         ((parent == S3C24X0_INT_UART1) ? S3C24X0_SUBIRQ_MIN + 3 + offset : \
   54           S3C24X0_SUBIRQ_MIN + 6 + offset))
   55 #define RX_OFF  0
   56 #define TX_OFF  1
   57 #define ERR_OFF 2
   58 
   59 extern unsigned int s3c2410_pclk;
   60 
   61 static int sscomspeed(long, long);
   62 static int s3c24x0_uart_param(struct uart_bas *, int, int, int, int);
   63 
   64 /*
   65  * Low-level UART interface.
   66  */
   67 static int s3c2410_probe(struct uart_bas *bas);
   68 static void s3c2410_init(struct uart_bas *bas, int, int, int, int);
   69 static void s3c2410_term(struct uart_bas *bas);
   70 static void s3c2410_putc(struct uart_bas *bas, int);
   71 static int s3c2410_rxready(struct uart_bas *bas);
   72 static int s3c2410_getc(struct uart_bas *bas, struct mtx *mtx);
   73 
   74 extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
   75 
   76 static int
   77 sscomspeed(long speed, long frequency)
   78 {
   79         int x;
   80 
   81         if (speed <= 0 || frequency <= 0)
   82                 return -1;
   83         x = (frequency / 16) / speed;
   84         return x-1;
   85 }
   86 
   87 static int
   88 s3c24x0_uart_param(struct uart_bas *bas, int baudrate, int databits,
   89     int stopbits, int parity)
   90 {
   91         int brd, ulcon;
   92 
   93         ulcon = 0;
   94 
   95         switch(databits) {
   96         case 5:
   97                 ulcon |= ULCON_LENGTH_5;
   98                 break;
   99         case 6:
  100                 ulcon |= ULCON_LENGTH_6;
  101                 break;
  102         case 7:
  103                 ulcon |= ULCON_LENGTH_7;
  104                 break;
  105         case 8:
  106                 ulcon |= ULCON_LENGTH_8;
  107                 break;
  108         default:
  109                 return (EINVAL);
  110         }
  111 
  112         switch (parity) {
  113         case UART_PARITY_NONE:
  114                 ulcon |= ULCON_PARITY_NONE;
  115                 break;
  116         case UART_PARITY_ODD:
  117                 ulcon |= ULCON_PARITY_ODD;
  118                 break;
  119         case UART_PARITY_EVEN:
  120                 ulcon |= ULCON_PARITY_EVEN;
  121                 break;
  122         case UART_PARITY_MARK:
  123         case UART_PARITY_SPACE:
  124         default:
  125                 return (EINVAL);
  126         }
  127 
  128         if (stopbits == 2)
  129                 ulcon |= ULCON_STOP;
  130 
  131         uart_setreg(bas, SSCOM_ULCON, ulcon);
  132 
  133         brd = sscomspeed(baudrate, bas->rclk);
  134         uart_setreg(bas, SSCOM_UBRDIV, brd);
  135 
  136         return (0);
  137 }
  138 
  139 struct uart_ops uart_s3c2410_ops = {
  140         .probe = s3c2410_probe,
  141         .init = s3c2410_init,
  142         .term = s3c2410_term,
  143         .putc = s3c2410_putc,
  144         .rxready = s3c2410_rxready,
  145         .getc = s3c2410_getc,
  146 };
  147 
  148 static int
  149 s3c2410_probe(struct uart_bas *bas)
  150 {
  151         return (0);
  152 }
  153 
  154 static void
  155 s3c2410_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
  156     int parity)
  157 {
  158         if (bas->rclk == 0)
  159                 bas->rclk = s3c2410_pclk;
  160         KASSERT(bas->rclk != 0, ("s3c2410_init: Invalid rclk"));
  161 
  162         uart_setreg(bas, SSCOM_UCON, 0);
  163         uart_setreg(bas, SSCOM_UFCON,
  164             UFCON_TXTRIGGER_8 | UFCON_RXTRIGGER_8 |
  165             UFCON_TXFIFO_RESET | UFCON_RXFIFO_RESET |
  166             UFCON_FIFO_ENABLE);
  167         s3c24x0_uart_param(bas, baudrate, databits, stopbits, parity);
  168 
  169         /* Enable UART. */
  170         uart_setreg(bas, SSCOM_UCON, UCON_TXMODE_INT | UCON_RXMODE_INT |
  171             UCON_TOINT);
  172         uart_setreg(bas, SSCOM_UMCON, UMCON_RTS);
  173 }
  174 
  175 static void
  176 s3c2410_term(struct uart_bas *bas)
  177 {
  178         /* XXX */
  179 }
  180 
  181 static void
  182 s3c2410_putc(struct uart_bas *bas, int c)
  183 {
  184         while ((bus_space_read_4(bas->bst, bas->bsh, SSCOM_UFSTAT) &
  185             UFSTAT_TXFULL) == UFSTAT_TXFULL)
  186                 continue;
  187 
  188         uart_setreg(bas, SSCOM_UTXH, c);
  189 }
  190 
  191 static int
  192 s3c2410_rxready(struct uart_bas *bas)
  193 {
  194         return ((uart_getreg(bas, SSCOM_UTRSTAT) & UTRSTAT_RXREADY) ==
  195             UTRSTAT_RXREADY);
  196 }
  197 
  198 static int
  199 s3c2410_getc(struct uart_bas *bas, struct mtx *mtx)
  200 {
  201         while (!sscom_rxrdy(bas->bst, bas->bsh))
  202                 continue;
  203 
  204         return sscom_getc(bas->bst, bas->bsh);
  205 }
  206 
  207 static int s3c2410_bus_probe(struct uart_softc *sc);
  208 static int s3c2410_bus_attach(struct uart_softc *sc);
  209 static int s3c2410_bus_flush(struct uart_softc *, int);
  210 static int s3c2410_bus_getsig(struct uart_softc *);
  211 static int s3c2410_bus_ioctl(struct uart_softc *, int, intptr_t);
  212 static int s3c2410_bus_ipend(struct uart_softc *);
  213 static int s3c2410_bus_param(struct uart_softc *, int, int, int, int);
  214 static int s3c2410_bus_receive(struct uart_softc *);
  215 static int s3c2410_bus_setsig(struct uart_softc *, int);
  216 static int s3c2410_bus_transmit(struct uart_softc *);
  217 
  218 static kobj_method_t s3c2410_methods[] = {
  219         KOBJMETHOD(uart_probe,          s3c2410_bus_probe),
  220         KOBJMETHOD(uart_attach,         s3c2410_bus_attach),
  221         KOBJMETHOD(uart_flush,          s3c2410_bus_flush),
  222         KOBJMETHOD(uart_getsig,         s3c2410_bus_getsig),
  223         KOBJMETHOD(uart_ioctl,          s3c2410_bus_ioctl),
  224         KOBJMETHOD(uart_ipend,          s3c2410_bus_ipend),
  225         KOBJMETHOD(uart_param,          s3c2410_bus_param),
  226         KOBJMETHOD(uart_receive,        s3c2410_bus_receive),
  227         KOBJMETHOD(uart_setsig,         s3c2410_bus_setsig),
  228         KOBJMETHOD(uart_transmit,       s3c2410_bus_transmit),
  229         
  230         {0, 0 }
  231 };
  232 
  233 int
  234 s3c2410_bus_probe(struct uart_softc *sc)
  235 {
  236         return (0);
  237 }
  238 
  239 static int
  240 s3c2410_bus_attach(struct uart_softc *sc)
  241 {
  242         uintptr_t irq;
  243 
  244         switch(s3c2xx0_softc->sc_cpu) {
  245         case CPU_S3C2410:
  246                 sc->sc_txfifosz = 16;
  247                 sc->sc_rxfifosz = 16;
  248                 break;
  249         case CPU_S3C2440:
  250                 sc->sc_txfifosz = 64;
  251                 sc->sc_rxfifosz = 64;
  252                 break;
  253         default:
  254                 return (ENXIO);
  255         }
  256                 
  257         sc->sc_hwiflow = 0;
  258         sc->sc_hwoflow = 0;
  259 
  260         irq = rman_get_start(sc->sc_ires);
  261         arm_unmask_irq(irq);
  262         arm_unmask_irq(get_sub_irq(irq, RX_OFF));
  263         arm_unmask_irq(get_sub_irq(irq, TX_OFF));
  264         arm_unmask_irq(get_sub_irq(irq, ERR_OFF));
  265 
  266         return (0);
  267 }
  268 
  269 static int
  270 s3c2410_bus_transmit(struct uart_softc *sc)
  271 {
  272         uintptr_t irq;
  273 
  274         uart_lock(sc->sc_hwmtx);
  275 
  276         for (int i = 0; i < sc->sc_txdatasz; i++) {
  277                 s3c2410_putc(&sc->sc_bas, sc->sc_txbuf[i]);
  278                 uart_barrier(&sc->sc_bas);
  279         }
  280 
  281         sc->sc_txbusy = 1;
  282 
  283         uart_unlock(sc->sc_hwmtx);
  284 
  285         irq = rman_get_start(sc->sc_ires);
  286         arm_unmask_irq(get_sub_irq(irq, TX_OFF));
  287 
  288         return (0);
  289 }
  290 
  291 static int
  292 s3c2410_bus_setsig(struct uart_softc *sc, int sig)
  293 {
  294         return (0);
  295 }
  296 
  297 static int
  298 s3c2410_bus_receive(struct uart_softc *sc)
  299 {
  300         
  301         uart_rx_put(sc, uart_getreg(&sc->sc_bas, SSCOM_URXH));
  302         return (0);
  303 }
  304 
  305 static int
  306 s3c2410_bus_param(struct uart_softc *sc, int baudrate, int databits,
  307     int stopbits, int parity)
  308 {
  309         int error;
  310 
  311         if (sc->sc_bas.rclk == 0)
  312                 sc->sc_bas.rclk = s3c2410_pclk;
  313         KASSERT(sc->sc_bas.rclk != 0, ("s3c2410_init: Invalid rclk"));
  314 
  315         uart_lock(sc->sc_hwmtx);
  316         error = s3c24x0_uart_param(&sc->sc_bas, baudrate, databits, stopbits,
  317             parity);
  318         uart_unlock(sc->sc_hwmtx);
  319 
  320         return (error);
  321 }
  322 
  323 static int
  324 s3c2410_bus_ipend(struct uart_softc *sc)
  325 {
  326         uint32_t ufstat, txmask, rxmask;
  327         uintptr_t irq;
  328         int ipend = 0;
  329 
  330         uart_lock(sc->sc_hwmtx);
  331         ufstat = bus_space_read_4(sc->sc_bas.bst, sc->sc_bas.bsh, SSCOM_UFSTAT);
  332         uart_unlock(sc->sc_hwmtx);
  333 
  334         txmask = rxmask = 0;
  335         switch (s3c2xx0_softc->sc_cpu) {
  336         case CPU_S3C2410:
  337                 txmask = UFSTAT_TXCOUNT;
  338                 rxmask = UFSTAT_RXCOUNT;
  339                 break;
  340         case CPU_S3C2440:
  341                 txmask = S3C2440_UFSTAT_TXCOUNT;
  342                 rxmask = S3C2440_UFSTAT_RXCOUNT;
  343                 break;
  344         }
  345         if ((ufstat & txmask) == 0) {
  346                 if (sc->sc_txbusy != 0)
  347                         ipend |= SER_INT_TXIDLE;
  348                 irq = rman_get_start(sc->sc_ires);
  349                 arm_mask_irq(get_sub_irq(irq, TX_OFF));
  350         }
  351         if ((ufstat & rxmask) > 0) {
  352                 ipend |= SER_INT_RXREADY;
  353         }
  354 
  355         return (ipend);
  356 }
  357 
  358 static int
  359 s3c2410_bus_flush(struct uart_softc *sc, int what)
  360 {
  361         return (0);
  362 }
  363 
  364 static int
  365 s3c2410_bus_getsig(struct uart_softc *sc)
  366 {
  367         return (0);
  368 }
  369 
  370 static int
  371 s3c2410_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
  372 {
  373         return (EINVAL);
  374 }
  375 
  376 struct uart_class uart_s3c2410_class = {
  377         "s3c2410 class",
  378         s3c2410_methods,
  379         1,
  380         .uc_ops = &uart_s3c2410_ops,
  381         .uc_range = 8,
  382         .uc_rclk = 0,
  383 };

Cache object: f2bbf76b37b1d0b31c0b80c55a301107


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