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/freescale/vybrid/vf_uart.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2013 Ruslan Bukin <br@bsdpad.com>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   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 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 THE 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 /*
   30  * Vybrid Family Universal Asynchronous Receiver/Transmitter
   31  * Chapter 49, Vybrid Reference Manual, Rev. 5, 07/2013
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD: releng/12.0/sys/arm/freescale/vybrid/vf_uart.c 326258 2017-11-27 15:04:10Z pfg $");
   36 
   37 #include "opt_ddb.h"
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/bus.h>
   42 #include <sys/conf.h>
   43 #include <sys/kdb.h>
   44 #include <machine/bus.h>
   45 
   46 #include <dev/uart/uart.h>
   47 #include <dev/uart/uart_cpu.h>
   48 #include <dev/uart/uart_cpu_fdt.h>
   49 #include <dev/uart/uart_bus.h>
   50 
   51 #include "uart_if.h"
   52 
   53 #define UART_BDH        0x00    /* Baud Rate Registers: High */
   54 #define UART_BDL        0x01    /* Baud Rate Registers: Low */
   55 #define UART_C1         0x02    /* Control Register 1 */
   56 #define UART_C2         0x03    /* Control Register 2 */
   57 #define UART_S1         0x04    /* Status Register 1 */
   58 #define UART_S2         0x05    /* Status Register 2 */
   59 #define UART_C3         0x06    /* Control Register 3 */
   60 #define UART_D          0x07    /* Data Register */
   61 #define UART_MA1        0x08    /* Match Address Registers 1 */
   62 #define UART_MA2        0x09    /* Match Address Registers 2 */
   63 #define UART_C4         0x0A    /* Control Register 4 */
   64 #define UART_C5         0x0B    /* Control Register 5 */
   65 #define UART_ED         0x0C    /* Extended Data Register */
   66 #define UART_MODEM      0x0D    /* Modem Register */
   67 #define UART_IR         0x0E    /* Infrared Register */
   68 #define UART_PFIFO      0x10    /* FIFO Parameters */
   69 #define UART_CFIFO      0x11    /* FIFO Control Register */
   70 #define UART_SFIFO      0x12    /* FIFO Status Register */
   71 #define UART_TWFIFO     0x13    /* FIFO Transmit Watermark */
   72 #define UART_TCFIFO     0x14    /* FIFO Transmit Count */
   73 #define UART_RWFIFO     0x15    /* FIFO Receive Watermark */
   74 #define UART_RCFIFO     0x16    /* FIFO Receive Count */
   75 #define UART_C7816      0x18    /* 7816 Control Register */
   76 #define UART_IE7816     0x19    /* 7816 Interrupt Enable Register */
   77 #define UART_IS7816     0x1A    /* 7816 Interrupt Status Register */
   78 #define UART_WP7816T0   0x1B    /* 7816 Wait Parameter Register */
   79 #define UART_WP7816T1   0x1B    /* 7816 Wait Parameter Register */
   80 #define UART_WN7816     0x1C    /* 7816 Wait N Register */
   81 #define UART_WF7816     0x1D    /* 7816 Wait FD Register */
   82 #define UART_ET7816     0x1E    /* 7816 Error Threshold Register */
   83 #define UART_TL7816     0x1F    /* 7816 Transmit Length Register */
   84 #define UART_C6         0x21    /* CEA709.1-B Control Register 6 */
   85 #define UART_PCTH       0x22    /* CEA709.1-B Packet Cycle Time Counter High */
   86 #define UART_PCTL       0x23    /* CEA709.1-B Packet Cycle Time Counter Low */
   87 #define UART_B1T        0x24    /* CEA709.1-B Beta1 Timer */
   88 #define UART_SDTH       0x25    /* CEA709.1-B Secondary Delay Timer High */
   89 #define UART_SDTL       0x26    /* CEA709.1-B Secondary Delay Timer Low */
   90 #define UART_PRE        0x27    /* CEA709.1-B Preamble */
   91 #define UART_TPL        0x28    /* CEA709.1-B Transmit Packet Length */
   92 #define UART_IE         0x29    /* CEA709.1-B Interrupt Enable Register */
   93 #define UART_WB         0x2A    /* CEA709.1-B WBASE */
   94 #define UART_S3         0x2B    /* CEA709.1-B Status Register */
   95 #define UART_S4         0x2C    /* CEA709.1-B Status Register */
   96 #define UART_RPL        0x2D    /* CEA709.1-B Received Packet Length */
   97 #define UART_RPREL      0x2E    /* CEA709.1-B Received Preamble Length */
   98 #define UART_CPW        0x2F    /* CEA709.1-B Collision Pulse Width */
   99 #define UART_RIDT       0x30    /* CEA709.1-B Receive Indeterminate Time */
  100 #define UART_TIDT       0x31    /* CEA709.1-B Transmit Indeterminate Time */
  101 
  102 #define UART_C2_TE      (1 << 3)        /* Transmitter Enable */
  103 #define UART_C2_TIE     (1 << 7)        /* Transmitter Interrupt Enable */
  104 #define UART_C2_RE      (1 << 2)        /* Receiver Enable */
  105 #define UART_C2_RIE     (1 << 5)        /* Receiver Interrupt Enable */
  106 #define UART_S1_TDRE    (1 << 7)        /* Transmit Data Register Empty Flag */
  107 #define UART_S1_RDRF    (1 << 5)        /* Receive Data Register Full Flag */
  108 #define UART_S2_LBKDIF  (1 << 7)        /* LIN Break Detect Interrupt Flag */
  109 
  110 #define UART_C4_BRFA    0x1f    /* Baud Rate Fine Adjust */
  111 #define UART_BDH_SBR    0x1f    /* UART Baud Rate Bits */
  112 
  113 /*
  114  * Low-level UART interface.
  115  */
  116 static int vf_uart_probe(struct uart_bas *bas);
  117 static void vf_uart_init(struct uart_bas *bas, int, int, int, int);
  118 static void vf_uart_term(struct uart_bas *bas);
  119 static void vf_uart_putc(struct uart_bas *bas, int);
  120 static int vf_uart_rxready(struct uart_bas *bas);
  121 static int vf_uart_getc(struct uart_bas *bas, struct mtx *);
  122 
  123 void uart_reinit(struct uart_softc *,int,int);
  124 
  125 static struct uart_ops uart_vybrid_ops = {
  126         .probe = vf_uart_probe,
  127         .init = vf_uart_init,
  128         .term = vf_uart_term,
  129         .putc = vf_uart_putc,
  130         .rxready = vf_uart_rxready,
  131         .getc = vf_uart_getc,
  132 };
  133 
  134 static int
  135 vf_uart_probe(struct uart_bas *bas)
  136 {
  137 
  138         return (0);
  139 }
  140 
  141 static void
  142 vf_uart_init(struct uart_bas *bas, int baudrate, int databits,
  143     int stopbits, int parity)
  144 {
  145 
  146 }
  147 
  148 static void
  149 vf_uart_term(struct uart_bas *bas)
  150 {
  151 
  152 }
  153 
  154 static void
  155 vf_uart_putc(struct uart_bas *bas, int c)
  156 {
  157 
  158         while (!(uart_getreg(bas, UART_S1) & UART_S1_TDRE))
  159                 ;
  160 
  161         uart_setreg(bas, UART_D, c);
  162 }
  163 
  164 static int
  165 vf_uart_rxready(struct uart_bas *bas)
  166 {
  167         int usr1;
  168 
  169         usr1 = uart_getreg(bas, UART_S1);
  170         if (usr1 & UART_S1_RDRF) {
  171                 return (1);
  172         }
  173 
  174         return (0);
  175 }
  176 
  177 static int
  178 vf_uart_getc(struct uart_bas *bas, struct mtx *hwmtx)
  179 {
  180         int c;
  181 
  182         uart_lock(hwmtx);
  183 
  184         while (!(uart_getreg(bas, UART_S1) & UART_S1_RDRF))
  185                 ;
  186 
  187         c = uart_getreg(bas, UART_D);
  188         uart_unlock(hwmtx);
  189 
  190         return (c & 0xff);
  191 }
  192 
  193 /*
  194  * High-level UART interface.
  195  */
  196 struct vf_uart_softc {
  197         struct uart_softc base;
  198 };
  199 
  200 void
  201 uart_reinit(struct uart_softc *sc, int clkspeed, int baud)
  202 {
  203         struct uart_bas *bas;
  204         int sbr;
  205         int brfa;
  206         int reg;
  207 
  208         bas = &sc->sc_bas;
  209         if (!bas) {
  210                 printf("Error: can't reconfigure bas\n");
  211                 return;
  212         }
  213 
  214         uart_setreg(bas, UART_MODEM, 0x00);
  215 
  216         /*
  217          * Disable transmitter and receiver
  218          * for a while.
  219          */
  220         reg = uart_getreg(bas, UART_C2);
  221         reg &= ~(UART_C2_RE | UART_C2_TE);
  222         uart_setreg(bas, UART_C2, 0x00);
  223 
  224         uart_setreg(bas, UART_C1, 0x00);
  225 
  226         sbr = (uint16_t) (clkspeed / (baud * 16));
  227         brfa = (clkspeed / baud) - (sbr * 16);
  228 
  229         reg = uart_getreg(bas, UART_BDH);
  230         reg &= ~UART_BDH_SBR;
  231         reg |= ((sbr & 0x1f00) >> 8);
  232         uart_setreg(bas, UART_BDH, reg);
  233 
  234         reg = sbr & 0x00ff;
  235         uart_setreg(bas, UART_BDL, reg);
  236 
  237         reg = uart_getreg(bas, UART_C4);
  238         reg &= ~UART_C4_BRFA;
  239         reg |= (brfa & UART_C4_BRFA);
  240         uart_setreg(bas, UART_C4, reg);
  241 
  242         reg = uart_getreg(bas, UART_C2);
  243         reg |= (UART_C2_RE | UART_C2_TE);
  244         uart_setreg(bas, UART_C2, reg);
  245 
  246 }
  247 
  248 static int vf_uart_bus_attach(struct uart_softc *);
  249 static int vf_uart_bus_detach(struct uart_softc *);
  250 static int vf_uart_bus_flush(struct uart_softc *, int);
  251 static int vf_uart_bus_getsig(struct uart_softc *);
  252 static int vf_uart_bus_ioctl(struct uart_softc *, int, intptr_t);
  253 static int vf_uart_bus_ipend(struct uart_softc *);
  254 static int vf_uart_bus_param(struct uart_softc *, int, int, int, int);
  255 static int vf_uart_bus_probe(struct uart_softc *);
  256 static int vf_uart_bus_receive(struct uart_softc *);
  257 static int vf_uart_bus_setsig(struct uart_softc *, int);
  258 static int vf_uart_bus_transmit(struct uart_softc *);
  259 
  260 static kobj_method_t vf_uart_methods[] = {
  261         KOBJMETHOD(uart_attach,         vf_uart_bus_attach),
  262         KOBJMETHOD(uart_detach,         vf_uart_bus_detach),
  263         KOBJMETHOD(uart_flush,          vf_uart_bus_flush),
  264         KOBJMETHOD(uart_getsig,         vf_uart_bus_getsig),
  265         KOBJMETHOD(uart_ioctl,          vf_uart_bus_ioctl),
  266         KOBJMETHOD(uart_ipend,          vf_uart_bus_ipend),
  267         KOBJMETHOD(uart_param,          vf_uart_bus_param),
  268         KOBJMETHOD(uart_probe,          vf_uart_bus_probe),
  269         KOBJMETHOD(uart_receive,        vf_uart_bus_receive),
  270         KOBJMETHOD(uart_setsig,         vf_uart_bus_setsig),
  271         KOBJMETHOD(uart_transmit,       vf_uart_bus_transmit),
  272         { 0, 0 }
  273 };
  274 
  275 static struct uart_class uart_vybrid_class = {
  276         "vybrid",
  277         vf_uart_methods,
  278         sizeof(struct vf_uart_softc),
  279         .uc_ops = &uart_vybrid_ops,
  280         .uc_range = 0x100,
  281         .uc_rclk = 24000000, /* TODO: get value from CCM */
  282         .uc_rshift = 0
  283 };
  284 
  285 static struct ofw_compat_data compat_data[] = {
  286         {"fsl,mvf600-uart",     (uintptr_t)&uart_vybrid_class},
  287         {NULL,                  (uintptr_t)NULL},
  288 };
  289 UART_FDT_CLASS_AND_DEVICE(compat_data);
  290 
  291 static int
  292 vf_uart_bus_attach(struct uart_softc *sc)
  293 {
  294         struct uart_bas *bas;
  295         int reg;
  296 
  297         bas = &sc->sc_bas;
  298 
  299         sc->sc_hwiflow = 0;
  300         sc->sc_hwoflow = 0;
  301 
  302         uart_reinit(sc, 66000000, 115200);
  303 
  304         reg = uart_getreg(bas, UART_C2);
  305         if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
  306                 reg &= ~UART_C2_RIE;
  307         } else {
  308                 reg |= UART_C2_RIE;
  309         }
  310         uart_setreg(bas, UART_C2, reg);
  311 
  312         return (0);
  313 }
  314 
  315 static int
  316 vf_uart_bus_detach(struct uart_softc *sc)
  317 {
  318 
  319         /* TODO */
  320         return (0);
  321 }
  322 
  323 static int
  324 vf_uart_bus_flush(struct uart_softc *sc, int what)
  325 {
  326 
  327         /* TODO */
  328         return (0);
  329 }
  330 
  331 static int
  332 vf_uart_bus_getsig(struct uart_softc *sc)
  333 {
  334 
  335         /* TODO */
  336         return (0);
  337 }
  338 
  339 static int
  340 vf_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
  341 {
  342         struct uart_bas *bas;
  343         int error;
  344 
  345         bas = &sc->sc_bas;
  346         error = 0;
  347         uart_lock(sc->sc_hwmtx);
  348         switch (request) {
  349         case UART_IOCTL_BREAK:
  350         /* TODO */
  351                 break;
  352         case UART_IOCTL_BAUD:
  353         /* TODO */
  354                 *(int*)data = 115200;
  355                 break;
  356         default:
  357                 error = EINVAL;
  358                 break;
  359         }
  360         uart_unlock(sc->sc_hwmtx);
  361 
  362         return (error);
  363 }
  364 
  365 static int
  366 vf_uart_bus_ipend(struct uart_softc *sc)
  367 {
  368         struct uart_bas *bas;
  369         int ipend;
  370         uint32_t usr1, usr2;
  371         int reg;
  372         int sfifo;
  373 
  374         bas = &sc->sc_bas;
  375         ipend = 0;
  376 
  377         uart_lock(sc->sc_hwmtx);
  378 
  379         usr1 = uart_getreg(bas, UART_S1);
  380         usr2 = uart_getreg(bas, UART_S2);
  381         sfifo = uart_getreg(bas, UART_SFIFO);
  382 
  383         /* ack usr2 */
  384         uart_setreg(bas, UART_S2, usr2);
  385 
  386         if (usr1 & UART_S1_TDRE) {
  387                 reg = uart_getreg(bas, UART_C2);
  388                 reg &= ~(UART_C2_TIE);
  389                 uart_setreg(bas, UART_C2, reg);
  390 
  391                 if (sc->sc_txbusy != 0) {
  392                         ipend |= SER_INT_TXIDLE;
  393                 }
  394         }
  395 
  396         if (usr1 & UART_S1_RDRF) {
  397                 reg = uart_getreg(bas, UART_C2);
  398                 reg &= ~(UART_C2_RIE);
  399                 uart_setreg(bas, UART_C2, reg);
  400 
  401                 ipend |= SER_INT_RXREADY;
  402         }
  403 
  404         if (usr2 & UART_S2_LBKDIF) {
  405                 ipend |= SER_INT_BREAK;
  406         }
  407 
  408         uart_unlock(sc->sc_hwmtx);
  409 
  410         return (ipend);
  411 }
  412 
  413 static int
  414 vf_uart_bus_param(struct uart_softc *sc, int baudrate, int databits,
  415     int stopbits, int parity)
  416 {
  417 
  418         uart_lock(sc->sc_hwmtx);
  419         vf_uart_init(&sc->sc_bas, baudrate, databits, stopbits, parity);
  420         uart_unlock(sc->sc_hwmtx);
  421 
  422         return (0);
  423 }
  424 
  425 static int
  426 vf_uart_bus_probe(struct uart_softc *sc)
  427 {
  428         int error;
  429 
  430         error = vf_uart_probe(&sc->sc_bas);
  431         if (error)
  432                 return (error);
  433 
  434         sc->sc_rxfifosz = 1;
  435         sc->sc_txfifosz = 1;
  436 
  437         device_set_desc(sc->sc_dev, "Vybrid Family UART");
  438         return (0);
  439 }
  440 
  441 static int
  442 vf_uart_bus_receive(struct uart_softc *sc)
  443 {
  444         struct uart_bas *bas;
  445         int reg;
  446         int c;
  447 
  448         bas = &sc->sc_bas;
  449         uart_lock(sc->sc_hwmtx);
  450 
  451         /* Read FIFO */
  452         while (uart_getreg(bas, UART_S1) & UART_S1_RDRF) {
  453                 if (uart_rx_full(sc)) {
  454                 /* No space left in input buffer */
  455                         sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
  456                         break;
  457                 }
  458 
  459                 c = uart_getreg(bas, UART_D);
  460                 uart_rx_put(sc, c);
  461         }
  462 
  463         /* Reenable Data Ready interrupt */
  464         reg = uart_getreg(bas, UART_C2);
  465         reg |= (UART_C2_RIE);
  466         uart_setreg(bas, UART_C2, reg);
  467 
  468         uart_unlock(sc->sc_hwmtx);
  469         return (0);
  470 }
  471 
  472 static int
  473 vf_uart_bus_setsig(struct uart_softc *sc, int sig)
  474 {
  475         struct uart_bas *bas;
  476         int reg;
  477 
  478         /* TODO: implement (?) */
  479 
  480         /* XXX workaround to have working console on mount prompt */
  481         /* Enable RX interrupt */
  482         bas = &sc->sc_bas;
  483         if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
  484                 reg = uart_getreg(bas, UART_C2);
  485                 reg |= (UART_C2_RIE);
  486                 uart_setreg(bas, UART_C2, reg);
  487         }
  488 
  489         return (0);
  490 }
  491 
  492 static int
  493 vf_uart_bus_transmit(struct uart_softc *sc)
  494 {
  495         struct uart_bas *bas = &sc->sc_bas;
  496         int i;
  497         int reg;
  498 
  499         bas = &sc->sc_bas;
  500         uart_lock(sc->sc_hwmtx);
  501 
  502         /* Fill TX FIFO */
  503         for (i = 0; i < sc->sc_txdatasz; i++) {
  504                 uart_setreg(bas, UART_D, sc->sc_txbuf[i] & 0xff);
  505                 uart_barrier(&sc->sc_bas);
  506         }
  507 
  508         sc->sc_txbusy = 1;
  509 
  510         /* Call me when ready */
  511         reg = uart_getreg(bas, UART_C2);
  512         reg |= (UART_C2_TIE);
  513         uart_setreg(bas, UART_C2, reg);
  514 
  515         uart_unlock(sc->sc_hwmtx);
  516 
  517         return (0);
  518 }

Cache object: 9913e974a0dee16b2f3ce8cd7b75de27


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