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_pl011.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) 2012 Semihalf.
    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 #include "opt_acpi.h"
   30 #include "opt_platform.h"
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD$");
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/kernel.h>
   38 #include <sys/bus.h>
   39 
   40 #include <machine/bus.h>
   41 #include <machine/machdep.h>
   42 
   43 #include <dev/uart/uart.h>
   44 #include <dev/uart/uart_cpu.h>
   45 #ifdef FDT
   46 #include <dev/uart/uart_cpu_fdt.h>
   47 #include <dev/ofw/ofw_bus.h>
   48 #endif
   49 #include <dev/uart/uart_bus.h>
   50 #include "uart_if.h"
   51 
   52 #ifdef DEV_ACPI
   53 #include <dev/uart/uart_cpu_acpi.h>
   54 #include <contrib/dev/acpica/include/acpi.h>
   55 #include <contrib/dev/acpica/include/accommon.h>
   56 #include <contrib/dev/acpica/include/actables.h>
   57 #endif
   58 
   59 #include <sys/kdb.h>
   60 
   61 #ifdef __aarch64__
   62 #define IS_FDT  (arm64_bus_method == ARM64_BUS_FDT)
   63 #elif defined(FDT)
   64 #define IS_FDT  1
   65 #else
   66 #error Unsupported configuration
   67 #endif
   68 
   69 /* PL011 UART registers and masks*/
   70 #define UART_DR         0x00            /* Data register */
   71 #define DR_FE           (1 << 8)        /* Framing error */
   72 #define DR_PE           (1 << 9)        /* Parity error */
   73 #define DR_BE           (1 << 10)       /* Break error */
   74 #define DR_OE           (1 << 11)       /* Overrun error */
   75 
   76 #define UART_FR         0x06            /* Flag register */
   77 #define FR_RXFE         (1 << 4)        /* Receive FIFO/reg empty */
   78 #define FR_TXFF         (1 << 5)        /* Transmit FIFO/reg full */
   79 #define FR_RXFF         (1 << 6)        /* Receive FIFO/reg full */
   80 #define FR_TXFE         (1 << 7)        /* Transmit FIFO/reg empty */
   81 
   82 #define UART_IBRD       0x09            /* Integer baud rate register */
   83 #define IBRD_BDIVINT    0xffff  /* Significant part of int. divisor value */
   84 
   85 #define UART_FBRD       0x0a            /* Fractional baud rate register */
   86 #define FBRD_BDIVFRAC   0x3f    /* Significant part of frac. divisor value */
   87 
   88 #define UART_LCR_H      0x0b            /* Line control register */
   89 #define LCR_H_WLEN8     (0x3 << 5)
   90 #define LCR_H_WLEN7     (0x2 << 5)
   91 #define LCR_H_WLEN6     (0x1 << 5)
   92 #define LCR_H_FEN       (1 << 4)        /* FIFO mode enable */
   93 #define LCR_H_STP2      (1 << 3)        /* 2 stop frames at the end */
   94 #define LCR_H_EPS       (1 << 2)        /* Even parity select */
   95 #define LCR_H_PEN       (1 << 1)        /* Parity enable */
   96 
   97 #define UART_CR         0x0c            /* Control register */
   98 #define CR_RXE          (1 << 9)        /* Receive enable */
   99 #define CR_TXE          (1 << 8)        /* Transmit enable */
  100 #define CR_UARTEN       (1 << 0)        /* UART enable */
  101 
  102 #define UART_IFLS       0x0d            /* FIFO level select register */
  103 #define IFLS_RX_SHIFT   3               /* RX level in bits [5:3] */
  104 #define IFLS_TX_SHIFT   0               /* TX level in bits [2:0] */
  105 #define IFLS_MASK       0x07            /* RX/TX level is 3 bits */
  106 #define IFLS_LVL_1_8th  0               /* Interrupt at 1/8 full */
  107 #define IFLS_LVL_2_8th  1               /* Interrupt at 1/4 full */
  108 #define IFLS_LVL_4_8th  2               /* Interrupt at 1/2 full */
  109 #define IFLS_LVL_6_8th  3               /* Interrupt at 3/4 full */
  110 #define IFLS_LVL_7_8th  4               /* Interrupt at 7/8 full */
  111 
  112 #define UART_IMSC       0x0e            /* Interrupt mask set/clear register */
  113 #define IMSC_MASK_ALL   0x7ff           /* Mask all interrupts */
  114 
  115 #define UART_RIS        0x0f            /* Raw interrupt status register */
  116 #define UART_RXREADY    (1 << 4)        /* RX buffer full */
  117 #define UART_TXEMPTY    (1 << 5)        /* TX buffer empty */
  118 #define RIS_RTIM        (1 << 6)        /* Receive timeout */
  119 #define RIS_FE          (1 << 7)        /* Framing error interrupt status */
  120 #define RIS_PE          (1 << 8)        /* Parity error interrupt status */
  121 #define RIS_BE          (1 << 9)        /* Break error interrupt status */
  122 #define RIS_OE          (1 << 10)       /* Overrun interrupt status */
  123 
  124 #define UART_MIS        0x10            /* Masked interrupt status register */
  125 #define UART_ICR        0x11            /* Interrupt clear register */
  126 
  127 #define UART_PIDREG_0   0x3f8           /* Peripheral ID register 0 */
  128 #define UART_PIDREG_1   0x3f9           /* Peripheral ID register 1 */
  129 #define UART_PIDREG_2   0x3fa           /* Peripheral ID register 2 */
  130 #define UART_PIDREG_3   0x3fb           /* Peripheral ID register 3 */
  131 
  132 /*
  133  * The hardware FIFOs are 16 bytes each on rev 2 and earlier hardware, 32 bytes
  134  * on rev 3 and later.  We configure them to interrupt when 3/4 full/empty.  For
  135  * RX we set the size to the full hardware capacity so that the uart core
  136  * allocates enough buffer space to hold a complete fifo full of incoming data.
  137  * For TX, we need to limit the size to the capacity we know will be available
  138  * when the interrupt occurs; uart_core will feed exactly that many bytes to
  139  * uart_pl011_bus_transmit() which must consume them all.
  140  */
  141 #define FIFO_RX_SIZE_R2 16
  142 #define FIFO_TX_SIZE_R2 12
  143 #define FIFO_RX_SIZE_R3 32
  144 #define FIFO_TX_SIZE_R3 24
  145 #define FIFO_IFLS_BITS  ((IFLS_LVL_6_8th << IFLS_RX_SHIFT) | (IFLS_LVL_2_8th))
  146 
  147 /*
  148  * FIXME: actual register size is SoC-dependent, we need to handle it
  149  */
  150 #define __uart_getreg(bas, reg)         \
  151         bus_space_read_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg))
  152 #define __uart_setreg(bas, reg, value)  \
  153         bus_space_write_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg), value)
  154 
  155 /*
  156  * Low-level UART interface.
  157  */
  158 static int uart_pl011_probe(struct uart_bas *bas);
  159 static void uart_pl011_init(struct uart_bas *bas, int, int, int, int);
  160 static void uart_pl011_term(struct uart_bas *bas);
  161 static void uart_pl011_putc(struct uart_bas *bas, int);
  162 static int uart_pl011_rxready(struct uart_bas *bas);
  163 static int uart_pl011_getc(struct uart_bas *bas, struct mtx *);
  164 
  165 static struct uart_ops uart_pl011_ops = {
  166         .probe = uart_pl011_probe,
  167         .init = uart_pl011_init,
  168         .term = uart_pl011_term,
  169         .putc = uart_pl011_putc,
  170         .rxready = uart_pl011_rxready,
  171         .getc = uart_pl011_getc,
  172 };
  173 
  174 static int
  175 uart_pl011_probe(struct uart_bas *bas)
  176 {
  177 
  178         return (0);
  179 }
  180 
  181 static void
  182 uart_pl011_param(struct uart_bas *bas, int baudrate, int databits, int stopbits,
  183     int parity)
  184 {
  185         uint32_t ctrl, line;
  186         uint32_t baud;
  187 
  188         /*
  189          * Zero all settings to make sure
  190          * UART is disabled and not configured
  191          */
  192         ctrl = line = 0x0;
  193         __uart_setreg(bas, UART_CR, ctrl);
  194 
  195         /* As we know UART is disabled we may setup the line */
  196         switch (databits) {
  197         case 7:
  198                 line |= LCR_H_WLEN7;
  199                 break;
  200         case 6:
  201                 line |= LCR_H_WLEN6;
  202                 break;
  203         case 8:
  204         default:
  205                 line |= LCR_H_WLEN8;
  206                 break;
  207         }
  208 
  209         if (stopbits == 2)
  210                 line |= LCR_H_STP2;
  211         else
  212                 line &= ~LCR_H_STP2;
  213 
  214         if (parity)
  215                 line |= LCR_H_PEN;
  216         else
  217                 line &= ~LCR_H_PEN;
  218         line |= LCR_H_FEN;
  219 
  220         /* Configure the rest */
  221         ctrl |= (CR_RXE | CR_TXE | CR_UARTEN);
  222 
  223         if (bas->rclk != 0 && baudrate != 0) {
  224                 baud = bas->rclk * 4 / baudrate;
  225                 __uart_setreg(bas, UART_IBRD, ((uint32_t)(baud >> 6)) & IBRD_BDIVINT);
  226                 __uart_setreg(bas, UART_FBRD, (uint32_t)(baud & 0x3F) & FBRD_BDIVFRAC);
  227         }
  228 
  229         /* Add config. to line before reenabling UART */
  230         __uart_setreg(bas, UART_LCR_H, (__uart_getreg(bas, UART_LCR_H) &
  231             ~0xff) | line);
  232 
  233         /* Set rx and tx fifo levels. */
  234         __uart_setreg(bas, UART_IFLS, FIFO_IFLS_BITS);
  235 
  236         __uart_setreg(bas, UART_CR, ctrl);
  237 }
  238 
  239 static void
  240 uart_pl011_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
  241     int parity)
  242 {
  243         /* Mask all interrupts */
  244         __uart_setreg(bas, UART_IMSC, __uart_getreg(bas, UART_IMSC) &
  245             ~IMSC_MASK_ALL);
  246 
  247         uart_pl011_param(bas, baudrate, databits, stopbits, parity);
  248 }
  249 
  250 static void
  251 uart_pl011_term(struct uart_bas *bas)
  252 {
  253 }
  254 
  255 static void
  256 uart_pl011_putc(struct uart_bas *bas, int c)
  257 {
  258 
  259         /* Wait when TX FIFO full. Push character otherwise. */
  260         while (__uart_getreg(bas, UART_FR) & FR_TXFF)
  261                 ;
  262         __uart_setreg(bas, UART_DR, c & 0xff);
  263 }
  264 
  265 static int
  266 uart_pl011_rxready(struct uart_bas *bas)
  267 {
  268 
  269         return !(__uart_getreg(bas, UART_FR) & FR_RXFE);
  270 }
  271 
  272 static int
  273 uart_pl011_getc(struct uart_bas *bas, struct mtx *hwmtx)
  274 {
  275         int c;
  276 
  277         while (!uart_pl011_rxready(bas))
  278                 ;
  279         c = __uart_getreg(bas, UART_DR) & 0xff;
  280 
  281         return (c);
  282 }
  283 
  284 /*
  285  * High-level UART interface.
  286  */
  287 struct uart_pl011_softc {
  288         struct uart_softc       base;
  289         uint16_t                imsc; /* Interrupt mask */
  290 };
  291 
  292 static int uart_pl011_bus_attach(struct uart_softc *);
  293 static int uart_pl011_bus_detach(struct uart_softc *);
  294 static int uart_pl011_bus_flush(struct uart_softc *, int);
  295 static int uart_pl011_bus_getsig(struct uart_softc *);
  296 static int uart_pl011_bus_ioctl(struct uart_softc *, int, intptr_t);
  297 static int uart_pl011_bus_ipend(struct uart_softc *);
  298 static int uart_pl011_bus_param(struct uart_softc *, int, int, int, int);
  299 static int uart_pl011_bus_probe(struct uart_softc *);
  300 static int uart_pl011_bus_receive(struct uart_softc *);
  301 static int uart_pl011_bus_setsig(struct uart_softc *, int);
  302 static int uart_pl011_bus_transmit(struct uart_softc *);
  303 static void uart_pl011_bus_grab(struct uart_softc *);
  304 static void uart_pl011_bus_ungrab(struct uart_softc *);
  305 
  306 static kobj_method_t uart_pl011_methods[] = {
  307         KOBJMETHOD(uart_attach,         uart_pl011_bus_attach),
  308         KOBJMETHOD(uart_detach,         uart_pl011_bus_detach),
  309         KOBJMETHOD(uart_flush,          uart_pl011_bus_flush),
  310         KOBJMETHOD(uart_getsig,         uart_pl011_bus_getsig),
  311         KOBJMETHOD(uart_ioctl,          uart_pl011_bus_ioctl),
  312         KOBJMETHOD(uart_ipend,          uart_pl011_bus_ipend),
  313         KOBJMETHOD(uart_param,          uart_pl011_bus_param),
  314         KOBJMETHOD(uart_probe,          uart_pl011_bus_probe),
  315         KOBJMETHOD(uart_receive,        uart_pl011_bus_receive),
  316         KOBJMETHOD(uart_setsig,         uart_pl011_bus_setsig),
  317         KOBJMETHOD(uart_transmit,       uart_pl011_bus_transmit),
  318         KOBJMETHOD(uart_grab,           uart_pl011_bus_grab),
  319         KOBJMETHOD(uart_ungrab,         uart_pl011_bus_ungrab),
  320         { 0, 0 }
  321 };
  322 
  323 static struct uart_class uart_pl011_class = {
  324         "uart_pl011",
  325         uart_pl011_methods,
  326         sizeof(struct uart_pl011_softc),
  327         .uc_ops = &uart_pl011_ops,
  328         .uc_range = 0x48,
  329         .uc_rclk = 0,
  330         .uc_rshift = 2
  331 };
  332 
  333 #ifdef FDT
  334 static struct ofw_compat_data fdt_compat_data[] = {
  335         {"arm,pl011",           (uintptr_t)&uart_pl011_class},
  336         {NULL,                  (uintptr_t)NULL},
  337 };
  338 UART_FDT_CLASS_AND_DEVICE(fdt_compat_data);
  339 #endif
  340 
  341 #ifdef DEV_ACPI
  342 static struct acpi_uart_compat_data acpi_compat_data[] = {
  343         {"ARMH0011", &uart_pl011_class, ACPI_DBG2_ARM_PL011, 2, 0, 0, UART_F_IGNORE_SPCR_REGSHFT, "uart pl011"},
  344         {"ARMHB000", &uart_pl011_class, ACPI_DBG2_ARM_SBSA_GENERIC, 2, 0, 0, UART_F_IGNORE_SPCR_REGSHFT, "uart pl011"},
  345         {"ARMHB000", &uart_pl011_class, ACPI_DBG2_ARM_SBSA_32BIT, 2, 0, 0, UART_F_IGNORE_SPCR_REGSHFT, "uart pl011"},
  346         {NULL, NULL, 0, 0, 0, 0, 0, NULL},
  347 };
  348 UART_ACPI_CLASS_AND_DEVICE(acpi_compat_data);
  349 #endif
  350 
  351 static int
  352 uart_pl011_bus_attach(struct uart_softc *sc)
  353 {
  354         struct uart_pl011_softc *psc;
  355         struct uart_bas *bas;
  356 
  357         psc = (struct uart_pl011_softc *)sc;
  358         bas = &sc->sc_bas;
  359 
  360         /* Enable interrupts */
  361         psc->imsc = (UART_RXREADY | RIS_RTIM | UART_TXEMPTY);
  362         __uart_setreg(bas, UART_IMSC, psc->imsc);
  363 
  364         /* Clear interrupts */
  365         __uart_setreg(bas, UART_ICR, IMSC_MASK_ALL);
  366 
  367         return (0);
  368 }
  369 
  370 static int
  371 uart_pl011_bus_detach(struct uart_softc *sc)
  372 {
  373 
  374         return (0);
  375 }
  376 
  377 static int
  378 uart_pl011_bus_flush(struct uart_softc *sc, int what)
  379 {
  380 
  381         return (0);
  382 }
  383 
  384 static int
  385 uart_pl011_bus_getsig(struct uart_softc *sc)
  386 {
  387 
  388         return (0);
  389 }
  390 
  391 static int
  392 uart_pl011_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
  393 {
  394         int error;
  395 
  396         error = 0;
  397         uart_lock(sc->sc_hwmtx);
  398         switch (request) {
  399         case UART_IOCTL_BREAK:
  400                 break;
  401         case UART_IOCTL_BAUD:
  402                 *(int*)data = 115200;
  403                 break;
  404         default:
  405                 error = EINVAL;
  406                 break;
  407         }
  408         uart_unlock(sc->sc_hwmtx);
  409 
  410         return (error);
  411 }
  412 
  413 static int
  414 uart_pl011_bus_ipend(struct uart_softc *sc)
  415 {
  416         struct uart_pl011_softc *psc;
  417         struct uart_bas *bas;
  418         uint32_t ints;
  419         int ipend;
  420 
  421         psc = (struct uart_pl011_softc *)sc;
  422         bas = &sc->sc_bas;
  423 
  424         uart_lock(sc->sc_hwmtx);
  425         ints = __uart_getreg(bas, UART_MIS);
  426         ipend = 0;
  427 
  428         if (ints & (UART_RXREADY | RIS_RTIM))
  429                 ipend |= SER_INT_RXREADY;
  430         if (ints & RIS_BE)
  431                 ipend |= SER_INT_BREAK;
  432         if (ints & RIS_OE)
  433                 ipend |= SER_INT_OVERRUN;
  434         if (ints & UART_TXEMPTY) {
  435                 if (sc->sc_txbusy)
  436                         ipend |= SER_INT_TXIDLE;
  437 
  438                 /* Disable TX interrupt */
  439                 __uart_setreg(bas, UART_IMSC, psc->imsc & ~UART_TXEMPTY);
  440         }
  441 
  442         uart_unlock(sc->sc_hwmtx);
  443 
  444         return (ipend);
  445 }
  446 
  447 static int
  448 uart_pl011_bus_param(struct uart_softc *sc, int baudrate, int databits,
  449     int stopbits, int parity)
  450 {
  451 
  452         uart_lock(sc->sc_hwmtx);
  453         uart_pl011_param(&sc->sc_bas, baudrate, databits, stopbits, parity);
  454         uart_unlock(sc->sc_hwmtx);
  455 
  456         return (0);
  457 }
  458 
  459 #ifdef FDT
  460 static int
  461 uart_pl011_bus_hwrev_fdt(struct uart_softc *sc)
  462 {
  463         pcell_t node;
  464         uint32_t periphid;
  465 
  466         /*
  467          * The FIFO sizes vary depending on hardware; rev 2 and below have 16
  468          * byte FIFOs, rev 3 and up are 32 byte.  The hardware rev is in the
  469          * primecell periphid register, but we get a bit of drama, as always,
  470          * with the bcm2835 (rpi), which claims to be rev 3, but has 16 byte
  471          * FIFOs.  We check for both the old freebsd-historic and the proper
  472          * bindings-defined compatible strings for bcm2835, and also check the
  473          * workaround the linux drivers use for rpi3, which is to override the
  474          * primecell periphid register value with a property.
  475          */
  476         if (ofw_bus_is_compatible(sc->sc_dev, "brcm,bcm2835-pl011") ||
  477             ofw_bus_is_compatible(sc->sc_dev, "broadcom,bcm2835-uart")) {
  478                 return (2);
  479         } else {
  480                 node = ofw_bus_get_node(sc->sc_dev);
  481                 if (OF_getencprop(node, "arm,primecell-periphid", &periphid,
  482                     sizeof(periphid)) > 0) {
  483                         return ((periphid >> 20) & 0x0f);
  484                 }
  485         }
  486 
  487         return (-1);
  488 }
  489 #endif
  490 
  491 static int
  492 uart_pl011_bus_probe(struct uart_softc *sc)
  493 {
  494         int hwrev;
  495 
  496         hwrev = -1;
  497 #ifdef FDT
  498         if (IS_FDT)
  499                 hwrev = uart_pl011_bus_hwrev_fdt(sc);
  500 #endif
  501         if (hwrev < 0)
  502                 hwrev = __uart_getreg(&sc->sc_bas, UART_PIDREG_2) >> 4;
  503 
  504         if (hwrev <= 2) {
  505                 sc->sc_rxfifosz = FIFO_RX_SIZE_R2;
  506                 sc->sc_txfifosz = FIFO_TX_SIZE_R2;
  507         } else {
  508                 sc->sc_rxfifosz = FIFO_RX_SIZE_R3;
  509                 sc->sc_txfifosz = FIFO_TX_SIZE_R3;
  510         }
  511 
  512         device_set_desc(sc->sc_dev, "PrimeCell UART (PL011)");
  513 
  514         return (0);
  515 }
  516 
  517 static int
  518 uart_pl011_bus_receive(struct uart_softc *sc)
  519 {
  520         struct uart_bas *bas;
  521         uint32_t ints, xc;
  522         int rx;
  523 
  524         bas = &sc->sc_bas;
  525         uart_lock(sc->sc_hwmtx);
  526 
  527         for (;;) {
  528                 ints = __uart_getreg(bas, UART_FR);
  529                 if (ints & FR_RXFE)
  530                         break;
  531                 if (uart_rx_full(sc)) {
  532                         sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
  533                         break;
  534                 }
  535 
  536                 xc = __uart_getreg(bas, UART_DR);
  537                 rx = xc & 0xff;
  538 
  539                 if (xc & DR_FE)
  540                         rx |= UART_STAT_FRAMERR;
  541                 if (xc & DR_PE)
  542                         rx |= UART_STAT_PARERR;
  543 
  544                 uart_rx_put(sc, rx);
  545         }
  546 
  547         uart_unlock(sc->sc_hwmtx);
  548 
  549         return (0);
  550 }
  551 
  552 static int
  553 uart_pl011_bus_setsig(struct uart_softc *sc, int sig)
  554 {
  555 
  556         return (0);
  557 }
  558 
  559 static int
  560 uart_pl011_bus_transmit(struct uart_softc *sc)
  561 {
  562         struct uart_pl011_softc *psc;
  563         struct uart_bas *bas;
  564         int i;
  565 
  566         psc = (struct uart_pl011_softc *)sc;
  567         bas = &sc->sc_bas;
  568         uart_lock(sc->sc_hwmtx);
  569 
  570         for (i = 0; i < sc->sc_txdatasz; i++) {
  571                 __uart_setreg(bas, UART_DR, sc->sc_txbuf[i]);
  572                 uart_barrier(bas);
  573         }
  574 
  575         /* Mark busy and enable TX interrupt */
  576         sc->sc_txbusy = 1;
  577         __uart_setreg(bas, UART_IMSC, psc->imsc);
  578 
  579         uart_unlock(sc->sc_hwmtx);
  580 
  581         return (0);
  582 }
  583 
  584 static void
  585 uart_pl011_bus_grab(struct uart_softc *sc)
  586 {
  587         struct uart_pl011_softc *psc;
  588         struct uart_bas *bas;
  589 
  590         psc = (struct uart_pl011_softc *)sc;
  591         bas = &sc->sc_bas;
  592 
  593         /* Disable interrupts on switch to polling */
  594         uart_lock(sc->sc_hwmtx);
  595         __uart_setreg(bas, UART_IMSC, psc->imsc & ~IMSC_MASK_ALL);
  596         uart_unlock(sc->sc_hwmtx);
  597 }
  598 
  599 static void
  600 uart_pl011_bus_ungrab(struct uart_softc *sc)
  601 {
  602         struct uart_pl011_softc *psc;
  603         struct uart_bas *bas;
  604 
  605         psc = (struct uart_pl011_softc *)sc;
  606         bas = &sc->sc_bas;
  607 
  608         /* Switch to using interrupts while not grabbed */
  609         uart_lock(sc->sc_hwmtx);
  610         __uart_setreg(bas, UART_IMSC, psc->imsc);
  611         uart_unlock(sc->sc_hwmtx);
  612 }

Cache object: 7a903c24e6b6bb91a253b331964ff7ff


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