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/dev/uart/uart_dev_mu.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) 2018 Diane Bruce 
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   23  * SUCH DAMAGE.
   24  */
   25 
   26 /*
   27  * Based on uart_dev_pl011.c
   28  * Copyright (c) 2012 Semihalf.
   29  * All rights reserved.
   30  */
   31 /*
   32  * The mini Uart has the following features: 
   33  * - 7 or 8 bit operation. 
   34  * - 1 start and 1 stop bit. 
   35  * - No parities. 
   36  * - Break generation. 
   37  * - 8 symbols deep FIFOs for receive and transmit. 
   38  * - SW controlled RTS, SW readable CTS. 
   39  * - Auto flow control with programmable FIFO level. 
   40  * - 16550 like registers. 
   41  * - Baudrate derived from system clock. 
   42  * This is a mini UART and it does NOT have the following capabilities: 
   43  * - Break detection 
   44  * - Framing errors detection. 
   45  * - Parity bit 
   46  * - Receive Time-out interrupt 
   47  * - DCD, DSR, DTR or RI signals. 
   48  * The implemented UART is not a 16650 compatible UART However as far
   49  * as possible the first 8 control and status registers are laid out 
   50  * like a 16550 UART. All 16550 register bits which are not supported can
   51  * be written but will be ignored and read back as 0. All control bits
   52  * for simple UART receive/transmit operations are available.
   53  */
   54 
   55 #include "opt_acpi.h"
   56 #include "opt_platform.h"
   57 
   58 #include <sys/cdefs.h>
   59 __FBSDID("$FreeBSD$");
   60 
   61 #include <sys/param.h>
   62 #include <sys/systm.h>
   63 #include <sys/kernel.h>
   64 #include <sys/bus.h>
   65 
   66 #include <machine/bus.h>
   67 #include <machine/machdep.h>
   68 #include <machine/pcpu.h>
   69 
   70 #include <dev/uart/uart.h>
   71 #include <dev/uart/uart_cpu.h>
   72 #ifdef FDT
   73 #include <dev/uart/uart_cpu_fdt.h>
   74 #include <dev/ofw/ofw_bus.h>
   75 #endif
   76 #include <dev/uart/uart_bus.h>
   77 #include "uart_if.h"
   78 
   79 /* BCM2835 Micro UART registers and masks*/
   80 #define AUX_MU_IO_REG           0x00            /* I/O register */
   81 
   82 /*
   83  * According to errata bits 1 and 2 are swapped,
   84  * Also bits 2 and 3 are required to enable interrupts.
   85  */
   86 #define AUX_MU_IER_REG          0x01
   87 #define IER_RXENABLE            (1)
   88 #define IER_TXENABLE            (1<<1)
   89 #define IER_REQUIRED            (3<<2)
   90 #define IER_MASK_ALL            (IER_TXENABLE|IER_RXENABLE)
   91 
   92 #define AUX_MU_IIR_REG          0x02
   93 #define IIR_READY               (1)
   94 #define IIR_TXREADY             (1<<1)
   95 #define IIR_RXREADY             (1<<2)
   96 #define IIR_CLEAR               (3<<1)
   97 
   98 #define AUX_MU_LCR_REG          0x03
   99 #define LCR_WLEN7               (0)
  100 #define LCR_WLEN8               (3)
  101 
  102 #define AUX_MU_MCR_REG          0x04
  103 #define AUX_MCR_RTS             (1<<1)
  104 
  105 #define AUX_MU_LSR_REG          0x05
  106 #define LSR_RXREADY             (1)
  107 #define LSR_OVRRUN              (1<<1)
  108 #define LSR_TXEMPTY             (1<<5)
  109 #define LSR_TXIDLE              (1<<6)
  110 
  111 #define AUX_MU_MSR_REG          0x06
  112 #define MSR_CTS                 (1<<5)
  113 
  114 #define AUX_MU_SCRATCH_REG      0x07
  115 
  116 #define AUX_MU_CNTL_REG         0x08
  117 #define CNTL_RXENAB             (1)
  118 #define CNTL_TXENAB             (1<<1)
  119 
  120 #define AUX_MU_STAT_REG         0x09
  121 #define STAT_TX_SA              (1<<1)
  122 #define STAT_RX_SA              (1)
  123 
  124 #define AUX_MU_BAUD_REG         0x0a
  125 
  126 /*
  127  * FIXME: actual register size is SoC-dependent, we need to handle it
  128  */
  129 #define __uart_getreg(bas, reg)         \
  130         bus_space_read_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg))
  131 #define __uart_setreg(bas, reg, value)  \
  132         bus_space_write_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg), value)
  133 
  134 /*
  135  * Low-level UART interface.
  136  */
  137 static int uart_mu_probe(struct uart_bas *bas);
  138 static void uart_mu_init(struct uart_bas *bas, int, int, int, int);
  139 static void uart_mu_term(struct uart_bas *bas);
  140 static void uart_mu_putc(struct uart_bas *bas, int);
  141 static int uart_mu_rxready(struct uart_bas *bas);
  142 static int uart_mu_getc(struct uart_bas *bas, struct mtx *);
  143 
  144 static struct uart_ops uart_mu_ops = {
  145         .probe = uart_mu_probe,
  146         .init = uart_mu_init,
  147         .term = uart_mu_term,
  148         .putc = uart_mu_putc,
  149         .rxready = uart_mu_rxready,
  150         .getc = uart_mu_getc,
  151 };
  152 
  153 static int
  154 uart_mu_probe(struct uart_bas *bas)
  155 {
  156 
  157         return (0);
  158 }
  159 
  160 /* 
  161  * According to the docs, the cpu clock is locked to 250Mhz when
  162  * the micro-uart is used 
  163  */
  164 #define CPU_CLOCK       250000000
  165 
  166 static void
  167 uart_mu_param(struct uart_bas *bas, int baudrate, int databits, int stopbits,
  168     int parity)
  169 {
  170         uint32_t line;
  171         uint32_t baud;
  172 
  173         /*
  174          * Zero all settings to make sure
  175          * UART is disabled and not configured
  176          */
  177         line = 0x0;
  178         __uart_setreg(bas, AUX_MU_CNTL_REG, line);
  179 
  180         /* As I know UART is disabled I can setup the line */
  181         switch (databits) {
  182         case 7:
  183                 line |= LCR_WLEN7;
  184                 break;
  185         case 6:
  186         case 8:
  187         default:
  188                 line |= LCR_WLEN8;
  189                 break;
  190         }
  191 
  192         __uart_setreg(bas, AUX_MU_LCR_REG, line);
  193 
  194         /* See 2.2.1 BCM2835-ARM-Peripherals baudrate */
  195         if (baudrate != 0) {
  196                 baud = CPU_CLOCK / (8 * baudrate);
  197                 /* XXX  
  198                  *  baud = cpu_clock() / (8 * baudrate);
  199                  */
  200                 __uart_setreg(bas, AUX_MU_BAUD_REG, ((uint32_t)(baud & 0xFFFF)));
  201         }
  202 
  203         /* re-enable UART */
  204         __uart_setreg(bas, AUX_MU_CNTL_REG, CNTL_RXENAB|CNTL_TXENAB);
  205 }
  206 
  207 static void
  208 uart_mu_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
  209     int parity)
  210 {
  211 
  212         /* Mask all interrupts */
  213         __uart_setreg(bas, AUX_MU_IER_REG, 0);
  214         uart_mu_param(bas, baudrate, databits, stopbits, parity);
  215 }
  216 
  217 static void
  218 uart_mu_term(struct uart_bas *bas)
  219 {
  220 }
  221 
  222 static void
  223 uart_mu_putc(struct uart_bas *bas, int c)
  224 {
  225 
  226         /* Wait when TX FIFO full. Push character otherwise. */
  227         while ((__uart_getreg(bas, AUX_MU_LSR_REG) & LSR_TXEMPTY) == 0)
  228                 ;
  229         __uart_setreg(bas, AUX_MU_IO_REG, c & 0xff);
  230 }
  231 
  232 static int
  233 uart_mu_rxready(struct uart_bas *bas)
  234 {
  235 
  236         return ((__uart_getreg(bas, AUX_MU_LSR_REG) & LSR_RXREADY) != 0);
  237 }
  238 
  239 static int
  240 uart_mu_getc(struct uart_bas *bas, struct mtx *hwmtx)
  241 {
  242         int c;
  243 
  244         while(!uart_mu_rxready(bas))
  245                 ;
  246         c = __uart_getreg(bas, AUX_MU_IO_REG) & 0xff;
  247         return (c);
  248 }
  249 
  250 /*
  251  * High-level UART interface.
  252  */
  253 struct uart_mu_softc {
  254         struct uart_softc       bas;
  255         uint16_t                aux_ier; /* Interrupt mask */
  256 };
  257 
  258 static int uart_mu_bus_attach(struct uart_softc *);
  259 static int uart_mu_bus_detach(struct uart_softc *);
  260 static int uart_mu_bus_flush(struct uart_softc *, int);
  261 static int uart_mu_bus_getsig(struct uart_softc *);
  262 static int uart_mu_bus_ioctl(struct uart_softc *, int, intptr_t);
  263 static int uart_mu_bus_ipend(struct uart_softc *);
  264 static int uart_mu_bus_param(struct uart_softc *, int, int, int, int);
  265 static int uart_mu_bus_probe(struct uart_softc *);
  266 static int uart_mu_bus_receive(struct uart_softc *);
  267 static int uart_mu_bus_setsig(struct uart_softc *, int);
  268 static int uart_mu_bus_transmit(struct uart_softc *);
  269 static void uart_mu_bus_grab(struct uart_softc *);
  270 static void uart_mu_bus_ungrab(struct uart_softc *);
  271 
  272 static kobj_method_t uart_mu_methods[] = {
  273         KOBJMETHOD(uart_attach,         uart_mu_bus_attach),
  274         KOBJMETHOD(uart_detach,         uart_mu_bus_detach),
  275         KOBJMETHOD(uart_flush,          uart_mu_bus_flush),
  276         KOBJMETHOD(uart_getsig,         uart_mu_bus_getsig),
  277         KOBJMETHOD(uart_ioctl,          uart_mu_bus_ioctl),
  278         KOBJMETHOD(uart_ipend,          uart_mu_bus_ipend),
  279         KOBJMETHOD(uart_param,          uart_mu_bus_param),
  280         KOBJMETHOD(uart_probe,          uart_mu_bus_probe),
  281         KOBJMETHOD(uart_receive,        uart_mu_bus_receive),
  282         KOBJMETHOD(uart_setsig,         uart_mu_bus_setsig),
  283         KOBJMETHOD(uart_transmit,       uart_mu_bus_transmit),
  284         KOBJMETHOD(uart_grab,           uart_mu_bus_grab),
  285         KOBJMETHOD(uart_ungrab,         uart_mu_bus_ungrab),
  286         { 0, 0 }
  287 };
  288 
  289 static struct uart_class uart_mu_class = {
  290         "aux-uart",
  291         uart_mu_methods,
  292         sizeof(struct uart_mu_softc),
  293         .uc_ops = &uart_mu_ops,
  294         .uc_range = 0x48,
  295         .uc_rclk = 0,
  296         .uc_rshift = 2
  297 };
  298 
  299 #ifdef FDT
  300 static struct ofw_compat_data fdt_compat_data[] = {
  301         {"brcm,bcm2835-aux-uart" , (uintptr_t)&uart_mu_class},
  302         {NULL,                     (uintptr_t)NULL},
  303 };
  304 UART_FDT_CLASS_AND_DEVICE(fdt_compat_data);
  305 #endif
  306 
  307 static int
  308 uart_mu_bus_attach(struct uart_softc *sc)
  309 {
  310         struct uart_mu_softc *psc;
  311         struct uart_bas *bas;
  312 
  313         psc = (struct uart_mu_softc *)sc;
  314         bas = &sc->sc_bas;
  315         /* Clear interrupts */
  316         __uart_setreg(bas, AUX_MU_IIR_REG, IIR_CLEAR);
  317         /* Enable interrupts */
  318         psc->aux_ier = (IER_RXENABLE|IER_TXENABLE|IER_REQUIRED);
  319         __uart_setreg(bas, AUX_MU_IER_REG, psc->aux_ier);
  320         sc->sc_txbusy = 0;
  321 
  322         return (0);
  323 }
  324 
  325 static int
  326 uart_mu_bus_detach(struct uart_softc *sc)
  327 {
  328 
  329         return (0);
  330 }
  331 
  332 static int
  333 uart_mu_bus_flush(struct uart_softc *sc, int what)
  334 {
  335 
  336         return (0);
  337 }
  338 
  339 static int
  340 uart_mu_bus_getsig(struct uart_softc *sc)
  341 {
  342 
  343         return (0);
  344 }
  345 
  346 static int
  347 uart_mu_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
  348 {
  349         struct uart_bas *bas;
  350         int error;
  351 
  352         bas = &sc->sc_bas;
  353         error = 0;
  354         uart_lock(sc->sc_hwmtx);
  355         switch (request) {
  356         case UART_IOCTL_BREAK:
  357                 break;
  358         case UART_IOCTL_BAUD:
  359                 *(int*)data = 115200;
  360                 break;
  361         default:
  362                 error = EINVAL;
  363                 break;
  364         }
  365         uart_unlock(sc->sc_hwmtx);
  366 
  367         return (error);
  368 }
  369 
  370 static int
  371 uart_mu_bus_ipend(struct uart_softc *sc)
  372 {
  373         struct uart_mu_softc *psc;
  374         struct uart_bas *bas;
  375         uint32_t ints;
  376         int ipend;
  377 
  378         psc = (struct uart_mu_softc *)sc;
  379         bas = &sc->sc_bas;
  380 
  381         uart_lock(sc->sc_hwmtx);
  382         ints = __uart_getreg(bas, AUX_MU_IIR_REG);
  383         ipend = 0;
  384 
  385         /*
  386          * According to docs only one of IIR_RXREADY
  387          * or IIR_TXREADY are valid eg. Only one or the other.
  388          */
  389         if (ints & IIR_RXREADY) {
  390                 ipend |= SER_INT_RXREADY;
  391         } else if (ints & IIR_TXREADY) {
  392                 if (__uart_getreg(bas, AUX_MU_LSR_REG) & LSR_TXIDLE) {
  393                         if (sc->sc_txbusy)
  394                                 ipend |= SER_INT_TXIDLE;
  395 
  396                         /* Disable TX interrupt */
  397                         __uart_setreg(bas, AUX_MU_IER_REG,
  398                                       psc->aux_ier & ~IER_TXENABLE);
  399                 }
  400         }
  401 
  402         uart_unlock(sc->sc_hwmtx);
  403 
  404         return (ipend);
  405 }
  406 
  407 static int
  408 uart_mu_bus_param(struct uart_softc *sc, int baudrate, int databits,
  409     int stopbits, int parity)
  410 {
  411 
  412         uart_lock(sc->sc_hwmtx);
  413         uart_mu_param(&sc->sc_bas, baudrate, databits, stopbits, parity);
  414         uart_unlock(sc->sc_hwmtx);
  415 
  416         return (0);
  417 }
  418 
  419 static int
  420 uart_mu_bus_probe(struct uart_softc *sc)
  421 {
  422 
  423         /* MU always has 8 byte deep fifo */
  424         sc->sc_rxfifosz = 8;
  425         sc->sc_txfifosz = 8;
  426         device_set_desc(sc->sc_dev, "BCM2835 Mini-UART");
  427 
  428         return (0);
  429 }
  430 
  431 static int
  432 uart_mu_bus_receive(struct uart_softc *sc)
  433 {
  434         struct uart_mu_softc *psc;
  435         struct uart_bas *bas;
  436         uint32_t lsr, xc;
  437         int rx;
  438 
  439         bas = &sc->sc_bas;
  440         uart_lock(sc->sc_hwmtx);
  441         psc = (struct uart_mu_softc *)sc;
  442 
  443         lsr = __uart_getreg(bas, AUX_MU_LSR_REG);
  444         while (lsr & LSR_RXREADY) {
  445                 xc = __uart_getreg(bas, AUX_MU_IO_REG);
  446                 rx = xc & 0xff;
  447                 if (uart_rx_full(sc)) {
  448                         sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
  449                         break;
  450                 }
  451                 uart_rx_put(sc, rx);
  452                 lsr = __uart_getreg(bas, AUX_MU_LSR_REG);
  453         }
  454         uart_unlock(sc->sc_hwmtx);
  455 
  456         return (0);
  457 }
  458 
  459 static int
  460 uart_mu_bus_setsig(struct uart_softc *sc, int sig)
  461 {
  462 
  463         return (0);
  464 }
  465 
  466 static int
  467 uart_mu_bus_transmit(struct uart_softc *sc)
  468 {
  469         struct uart_mu_softc *psc;
  470         struct uart_bas *bas;
  471         int i;
  472 
  473         psc = (struct uart_mu_softc *)sc;
  474         bas = &sc->sc_bas;
  475         uart_lock(sc->sc_hwmtx);
  476 
  477         for (i = 0; i < sc->sc_txdatasz; i++) {
  478                 __uart_setreg(bas, AUX_MU_IO_REG, sc->sc_txbuf[i] & 0xff);
  479                 uart_barrier(bas);
  480         }
  481 
  482         /* Mark busy and enable TX interrupt */
  483         sc->sc_txbusy = 1;
  484         __uart_setreg(bas, AUX_MU_IER_REG, psc->aux_ier);
  485                 
  486         uart_unlock(sc->sc_hwmtx);
  487 
  488         return (0);
  489 }
  490 
  491 static void
  492 uart_mu_bus_grab(struct uart_softc *sc)
  493 {
  494         struct uart_mu_softc *psc;
  495         struct uart_bas *bas;
  496 
  497         psc = (struct uart_mu_softc *)sc;
  498         bas = &sc->sc_bas;
  499 
  500         /* Disable interrupts on switch to polling */
  501         uart_lock(sc->sc_hwmtx);
  502         __uart_setreg(bas, AUX_MU_IER_REG, psc->aux_ier &~IER_MASK_ALL);
  503         uart_unlock(sc->sc_hwmtx);
  504 }
  505 
  506 static void
  507 uart_mu_bus_ungrab(struct uart_softc *sc)
  508 {
  509         struct uart_mu_softc *psc;
  510         struct uart_bas *bas;
  511 
  512         psc = (struct uart_mu_softc *)sc;
  513         bas = &sc->sc_bas;
  514 
  515         /* Switch to using interrupts while not grabbed */
  516         uart_lock(sc->sc_hwmtx);
  517         __uart_setreg(bas, AUX_MU_CNTL_REG, CNTL_RXENAB|CNTL_TXENAB);
  518         __uart_setreg(bas, AUX_MU_IER_REG, psc->aux_ier);
  519         uart_unlock(sc->sc_hwmtx);
  520 }

Cache object: 401c39f6024f6e56497961ae6913fd24


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