1*f3003a0dSAndrew Turner /*- 2*f3003a0dSAndrew Turner * SPDX-License-Identifier: BSD-2-Clause 3*f3003a0dSAndrew Turner * 4*f3003a0dSAndrew Turner * Copyright (c) 2020 Andrew Turner 5*f3003a0dSAndrew Turner * 6*f3003a0dSAndrew Turner * This work was supported by Innovate UK project 105694, "Digital Security 7*f3003a0dSAndrew Turner * by Design (DSbD) Technology Platform Prototype". 8*f3003a0dSAndrew Turner * 9*f3003a0dSAndrew Turner * Redistribution and use in source and binary forms, with or without 10*f3003a0dSAndrew Turner * modification, are permitted provided that the following conditions 11*f3003a0dSAndrew Turner * are met: 12*f3003a0dSAndrew Turner * 1. Redistributions of source code must retain the above copyright 13*f3003a0dSAndrew Turner * notice, this list of conditions and the following disclaimer. 14*f3003a0dSAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright 15*f3003a0dSAndrew Turner * notice, this list of conditions and the following disclaimer in the 16*f3003a0dSAndrew Turner * documentation and/or other materials provided with the distribution. 17*f3003a0dSAndrew Turner * 18*f3003a0dSAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19*f3003a0dSAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*f3003a0dSAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*f3003a0dSAndrew Turner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22*f3003a0dSAndrew Turner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23*f3003a0dSAndrew Turner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24*f3003a0dSAndrew Turner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25*f3003a0dSAndrew Turner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26*f3003a0dSAndrew Turner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27*f3003a0dSAndrew Turner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28*f3003a0dSAndrew Turner * SUCH DAMAGE. 29*f3003a0dSAndrew Turner */ 30*f3003a0dSAndrew Turner 31*f3003a0dSAndrew Turner #include <sys/param.h> 32*f3003a0dSAndrew Turner 33*f3003a0dSAndrew Turner #include <assert.h> 34*f3003a0dSAndrew Turner #include <pthread.h> 35*f3003a0dSAndrew Turner #include <stdbool.h> 36*f3003a0dSAndrew Turner #include <stdio.h> 37*f3003a0dSAndrew Turner #include <stdlib.h> 38*f3003a0dSAndrew Turner 39*f3003a0dSAndrew Turner #include "uart_backend.h" 40*f3003a0dSAndrew Turner #include "uart_emul.h" 41*f3003a0dSAndrew Turner 42*f3003a0dSAndrew Turner #define UART_FIFO_SIZE 16 43*f3003a0dSAndrew Turner 44*f3003a0dSAndrew Turner #define UARTDR 0x00 45*f3003a0dSAndrew Turner #define UARTDR_RSR_SHIFT 8 46*f3003a0dSAndrew Turner 47*f3003a0dSAndrew Turner #define UARTRSR 0x01 48*f3003a0dSAndrew Turner #define UARTRSR_OE (1 << 3) 49*f3003a0dSAndrew Turner 50*f3003a0dSAndrew Turner #define UARTFR 0x06 51*f3003a0dSAndrew Turner #define UARTFR_TXFE (1 << 7) 52*f3003a0dSAndrew Turner #define UARTFR_RXFF (1 << 6) 53*f3003a0dSAndrew Turner #define UARTFR_TXFF (1 << 5) 54*f3003a0dSAndrew Turner #define UARTFR_RXFE (1 << 4) 55*f3003a0dSAndrew Turner 56*f3003a0dSAndrew Turner #define UARTRTINTR (1 << 6) 57*f3003a0dSAndrew Turner #define UARTTXINTR (1 << 5) 58*f3003a0dSAndrew Turner #define UARTRXINTR (1 << 4) 59*f3003a0dSAndrew Turner 60*f3003a0dSAndrew Turner #define UARTIBRD 0x09 61*f3003a0dSAndrew Turner 62*f3003a0dSAndrew Turner #define UARTFBRD 0x0a 63*f3003a0dSAndrew Turner #define UARTFBRD_MASK 0x003f 64*f3003a0dSAndrew Turner 65*f3003a0dSAndrew Turner #define UARTLCR_H 0x0b 66*f3003a0dSAndrew Turner #define UARTLCR_H_MASK 0x00ff 67*f3003a0dSAndrew Turner #define UARTLCR_H_FEN (1 << 4) 68*f3003a0dSAndrew Turner 69*f3003a0dSAndrew Turner #define UARTCR 0x0c 70*f3003a0dSAndrew Turner /* TODO: Check the flags in the UARTCR register */ 71*f3003a0dSAndrew Turner #define UARTCR_MASK 0xffc7 72*f3003a0dSAndrew Turner #define UARTCR_LBE (1 << 7) 73*f3003a0dSAndrew Turner 74*f3003a0dSAndrew Turner #define UARTIFLS 0x0d 75*f3003a0dSAndrew Turner #define UARTIFLS_MASK 0x003f 76*f3003a0dSAndrew Turner #define UARTIFLS_RXIFLSEL(x) (((x) >> 3) & 0x7) 77*f3003a0dSAndrew Turner #define UARTIFLS_TXIFLSEL(x) (((x) >> 0) & 0x7) 78*f3003a0dSAndrew Turner 79*f3003a0dSAndrew Turner #define UARTIMSC 0x0e 80*f3003a0dSAndrew Turner #define UARTIMSC_MASK 0x07ff 81*f3003a0dSAndrew Turner 82*f3003a0dSAndrew Turner #define UARTRIS 0x0f 83*f3003a0dSAndrew Turner #define UARTMIS 0x10 84*f3003a0dSAndrew Turner 85*f3003a0dSAndrew Turner #define UARTICR 0x11 86*f3003a0dSAndrew Turner 87*f3003a0dSAndrew Turner #define UARTPeriphID 0x00241011 88*f3003a0dSAndrew Turner #define UARTPeriphID0 0x3f8 89*f3003a0dSAndrew Turner #define UARTPeriphID0_VAL (((UARTPeriphID) >> 0) & 0xff) 90*f3003a0dSAndrew Turner #define UARTPeriphID1 0x3f9 91*f3003a0dSAndrew Turner #define UARTPeriphID1_VAL (((UARTPeriphID) >> 8) & 0xff) 92*f3003a0dSAndrew Turner #define UARTPeriphID2 0x3fa 93*f3003a0dSAndrew Turner #define UARTPeriphID2_VAL (((UARTPeriphID) >> 16) & 0xff) 94*f3003a0dSAndrew Turner #define UARTPeriphID3 0x3fb 95*f3003a0dSAndrew Turner #define UARTPeriphID3_VAL (((UARTPeriphID) >> 24) & 0xff) 96*f3003a0dSAndrew Turner 97*f3003a0dSAndrew Turner #define UARTPCellID 0xb105f00d 98*f3003a0dSAndrew Turner #define UARTPCellID0 0x3fc 99*f3003a0dSAndrew Turner #define UARTPCellID0_VAL (((UARTPCellID) >> 0) & 0xff) 100*f3003a0dSAndrew Turner #define UARTPCellID1 0x3fd 101*f3003a0dSAndrew Turner #define UARTPCellID1_VAL (((UARTPCellID) >> 8) & 0xff) 102*f3003a0dSAndrew Turner #define UARTPCellID2 0x3fe 103*f3003a0dSAndrew Turner #define UARTPCellID2_VAL (((UARTPCellID) >> 16) & 0xff) 104*f3003a0dSAndrew Turner #define UARTPCellID3 0x3ff 105*f3003a0dSAndrew Turner #define UARTPCellID3_VAL (((UARTPCellID) >> 24) & 0xff) 106*f3003a0dSAndrew Turner 107*f3003a0dSAndrew Turner struct uart_pl011_softc { 108*f3003a0dSAndrew Turner struct uart_softc *backend; 109*f3003a0dSAndrew Turner pthread_mutex_t mtx; /* protects all softc elements */ 110*f3003a0dSAndrew Turner 111*f3003a0dSAndrew Turner uint16_t irq_state; 112*f3003a0dSAndrew Turner 113*f3003a0dSAndrew Turner uint16_t rsr; 114*f3003a0dSAndrew Turner 115*f3003a0dSAndrew Turner uint16_t cr; 116*f3003a0dSAndrew Turner uint16_t ifls; 117*f3003a0dSAndrew Turner uint16_t imsc; 118*f3003a0dSAndrew Turner uint16_t lcr_h; 119*f3003a0dSAndrew Turner 120*f3003a0dSAndrew Turner uint16_t ibrd; 121*f3003a0dSAndrew Turner uint16_t fbrd; 122*f3003a0dSAndrew Turner 123*f3003a0dSAndrew Turner void *arg; 124*f3003a0dSAndrew Turner uart_intr_func_t intr_assert; 125*f3003a0dSAndrew Turner uart_intr_func_t intr_deassert; 126*f3003a0dSAndrew Turner }; 127*f3003a0dSAndrew Turner 128*f3003a0dSAndrew Turner static void 129*f3003a0dSAndrew Turner uart_reset(struct uart_pl011_softc *sc) 130*f3003a0dSAndrew Turner { 131*f3003a0dSAndrew Turner sc->ifls = 0x12; 132*f3003a0dSAndrew Turner 133*f3003a0dSAndrew Turner /* no fifo until enabled by software */ 134*f3003a0dSAndrew Turner uart_rxfifo_reset(sc->backend, 1); 135*f3003a0dSAndrew Turner } 136*f3003a0dSAndrew Turner 137*f3003a0dSAndrew Turner static int 138*f3003a0dSAndrew Turner uart_rx_trigger_level(struct uart_pl011_softc *sc) 139*f3003a0dSAndrew Turner { 140*f3003a0dSAndrew Turner /* If the FIFO is disabled trigger when we have any data */ 141*f3003a0dSAndrew Turner if ((sc->lcr_h & UARTLCR_H_FEN) != 0) 142*f3003a0dSAndrew Turner return (1); 143*f3003a0dSAndrew Turner 144*f3003a0dSAndrew Turner /* Trigger base on how full the fifo is */ 145*f3003a0dSAndrew Turner switch (UARTIFLS_RXIFLSEL(sc->ifls)) { 146*f3003a0dSAndrew Turner case 0: 147*f3003a0dSAndrew Turner return (UART_FIFO_SIZE / 8); 148*f3003a0dSAndrew Turner case 1: 149*f3003a0dSAndrew Turner return (UART_FIFO_SIZE / 4); 150*f3003a0dSAndrew Turner case 2: 151*f3003a0dSAndrew Turner return (UART_FIFO_SIZE / 2); 152*f3003a0dSAndrew Turner case 3: 153*f3003a0dSAndrew Turner return (UART_FIFO_SIZE * 3 / 4); 154*f3003a0dSAndrew Turner case 4: 155*f3003a0dSAndrew Turner return (UART_FIFO_SIZE * 7 / 8); 156*f3003a0dSAndrew Turner default: 157*f3003a0dSAndrew Turner /* TODO: Find out what happens in this case */ 158*f3003a0dSAndrew Turner return (UART_FIFO_SIZE); 159*f3003a0dSAndrew Turner } 160*f3003a0dSAndrew Turner } 161*f3003a0dSAndrew Turner 162*f3003a0dSAndrew Turner static void 163*f3003a0dSAndrew Turner uart_toggle_intr(struct uart_pl011_softc *sc) 164*f3003a0dSAndrew Turner { 165*f3003a0dSAndrew Turner if ((sc->irq_state & sc->imsc) == 0) 166*f3003a0dSAndrew Turner (*sc->intr_deassert)(sc->arg); 167*f3003a0dSAndrew Turner else 168*f3003a0dSAndrew Turner (*sc->intr_assert)(sc->arg); 169*f3003a0dSAndrew Turner } 170*f3003a0dSAndrew Turner 171*f3003a0dSAndrew Turner static void 172*f3003a0dSAndrew Turner uart_drain(int fd __unused, enum ev_type ev, void *arg) 173*f3003a0dSAndrew Turner { 174*f3003a0dSAndrew Turner struct uart_pl011_softc *sc; 175*f3003a0dSAndrew Turner int old_size, trig_lvl; 176*f3003a0dSAndrew Turner bool loopback; 177*f3003a0dSAndrew Turner 178*f3003a0dSAndrew Turner sc = arg; 179*f3003a0dSAndrew Turner 180*f3003a0dSAndrew Turner assert(ev == EVF_READ); 181*f3003a0dSAndrew Turner 182*f3003a0dSAndrew Turner /* 183*f3003a0dSAndrew Turner * This routine is called in the context of the mevent thread 184*f3003a0dSAndrew Turner * to take out the softc lock to protect against concurrent 185*f3003a0dSAndrew Turner * access from a vCPU i/o exit 186*f3003a0dSAndrew Turner */ 187*f3003a0dSAndrew Turner pthread_mutex_lock(&sc->mtx); 188*f3003a0dSAndrew Turner 189*f3003a0dSAndrew Turner old_size = uart_rxfifo_numchars(sc->backend); 190*f3003a0dSAndrew Turner 191*f3003a0dSAndrew Turner loopback = (sc->cr & UARTCR_LBE) != 0; 192*f3003a0dSAndrew Turner uart_rxfifo_drain(sc->backend, loopback); 193*f3003a0dSAndrew Turner 194*f3003a0dSAndrew Turner /* If we cross the trigger level raise UARTRXINTR */ 195*f3003a0dSAndrew Turner trig_lvl = uart_rx_trigger_level(sc); 196*f3003a0dSAndrew Turner if (old_size < trig_lvl && 197*f3003a0dSAndrew Turner uart_rxfifo_numchars(sc->backend) >= trig_lvl) 198*f3003a0dSAndrew Turner sc->irq_state |= UARTRXINTR; 199*f3003a0dSAndrew Turner 200*f3003a0dSAndrew Turner if (uart_rxfifo_numchars(sc->backend) > 0) 201*f3003a0dSAndrew Turner sc->irq_state |= UARTRTINTR; 202*f3003a0dSAndrew Turner if (!loopback) 203*f3003a0dSAndrew Turner uart_toggle_intr(sc); 204*f3003a0dSAndrew Turner 205*f3003a0dSAndrew Turner pthread_mutex_unlock(&sc->mtx); 206*f3003a0dSAndrew Turner } 207*f3003a0dSAndrew Turner 208*f3003a0dSAndrew Turner void 209*f3003a0dSAndrew Turner uart_pl011_write(struct uart_pl011_softc *sc, int offset, uint32_t value) 210*f3003a0dSAndrew Turner { 211*f3003a0dSAndrew Turner bool loopback; 212*f3003a0dSAndrew Turner 213*f3003a0dSAndrew Turner pthread_mutex_lock(&sc->mtx); 214*f3003a0dSAndrew Turner switch (offset) { 215*f3003a0dSAndrew Turner case UARTDR: 216*f3003a0dSAndrew Turner loopback = (sc->cr & UARTCR_LBE) != 0; 217*f3003a0dSAndrew Turner if (uart_rxfifo_putchar(sc->backend, value & 0xff, loopback)) 218*f3003a0dSAndrew Turner sc->rsr |= UARTRSR_OE; 219*f3003a0dSAndrew Turner 220*f3003a0dSAndrew Turner /* We don't have a TX fifo, so trigger when we have data */ 221*f3003a0dSAndrew Turner sc->irq_state |= UARTTXINTR; 222*f3003a0dSAndrew Turner break; 223*f3003a0dSAndrew Turner case UARTRSR: 224*f3003a0dSAndrew Turner /* Any write clears this register */ 225*f3003a0dSAndrew Turner sc->rsr = 0; 226*f3003a0dSAndrew Turner break; 227*f3003a0dSAndrew Turner case UARTFR: 228*f3003a0dSAndrew Turner /* UARTFR is a read-only register */ 229*f3003a0dSAndrew Turner break; 230*f3003a0dSAndrew Turner /* TODO: UARTILPR */ 231*f3003a0dSAndrew Turner case UARTIBRD: 232*f3003a0dSAndrew Turner sc->ibrd = value; 233*f3003a0dSAndrew Turner break; 234*f3003a0dSAndrew Turner case UARTFBRD: 235*f3003a0dSAndrew Turner sc->fbrd = value & UARTFBRD_MASK; 236*f3003a0dSAndrew Turner break; 237*f3003a0dSAndrew Turner case UARTLCR_H: 238*f3003a0dSAndrew Turner /* Check if the FIFO enable bit changed */ 239*f3003a0dSAndrew Turner if (((sc->lcr_h ^ value) & UARTLCR_H_FEN) != 0) { 240*f3003a0dSAndrew Turner if ((value & UARTLCR_H_FEN) != 0) { 241*f3003a0dSAndrew Turner uart_rxfifo_reset(sc->backend, UART_FIFO_SIZE); 242*f3003a0dSAndrew Turner } else { 243*f3003a0dSAndrew Turner uart_rxfifo_reset(sc->backend, 1); 244*f3003a0dSAndrew Turner } 245*f3003a0dSAndrew Turner } 246*f3003a0dSAndrew Turner sc->lcr_h = value & UARTLCR_H_MASK; 247*f3003a0dSAndrew Turner break; 248*f3003a0dSAndrew Turner case UARTCR: 249*f3003a0dSAndrew Turner sc->cr = value & UARTCR_MASK; 250*f3003a0dSAndrew Turner break; 251*f3003a0dSAndrew Turner case UARTIFLS: 252*f3003a0dSAndrew Turner sc->ifls = value & UARTCR_MASK; 253*f3003a0dSAndrew Turner break; 254*f3003a0dSAndrew Turner case UARTIMSC: 255*f3003a0dSAndrew Turner sc->imsc = value & UARTIMSC_MASK; 256*f3003a0dSAndrew Turner break; 257*f3003a0dSAndrew Turner case UARTRIS: 258*f3003a0dSAndrew Turner case UARTMIS: 259*f3003a0dSAndrew Turner /* UARTRIS and UARTMIS are read-only registers */ 260*f3003a0dSAndrew Turner break; 261*f3003a0dSAndrew Turner case UARTICR: 262*f3003a0dSAndrew Turner sc->irq_state &= ~value; 263*f3003a0dSAndrew Turner break; 264*f3003a0dSAndrew Turner default: 265*f3003a0dSAndrew Turner /* Ignore writes to unassigned/ID registers */ 266*f3003a0dSAndrew Turner break; 267*f3003a0dSAndrew Turner } 268*f3003a0dSAndrew Turner uart_toggle_intr(sc); 269*f3003a0dSAndrew Turner pthread_mutex_unlock(&sc->mtx); 270*f3003a0dSAndrew Turner } 271*f3003a0dSAndrew Turner 272*f3003a0dSAndrew Turner uint32_t 273*f3003a0dSAndrew Turner uart_pl011_read(struct uart_pl011_softc *sc, int offset) 274*f3003a0dSAndrew Turner { 275*f3003a0dSAndrew Turner uint32_t reg; 276*f3003a0dSAndrew Turner int fifo_sz; 277*f3003a0dSAndrew Turner 278*f3003a0dSAndrew Turner reg = 0; 279*f3003a0dSAndrew Turner pthread_mutex_lock(&sc->mtx); 280*f3003a0dSAndrew Turner switch (offset) { 281*f3003a0dSAndrew Turner case UARTDR: 282*f3003a0dSAndrew Turner reg = uart_rxfifo_getchar(sc->backend); 283*f3003a0dSAndrew Turner /* Deassert the irq if below the trigger level */ 284*f3003a0dSAndrew Turner fifo_sz = uart_rxfifo_numchars(sc->backend); 285*f3003a0dSAndrew Turner if (fifo_sz < uart_rx_trigger_level(sc)) 286*f3003a0dSAndrew Turner sc->irq_state &= ~UARTRXINTR; 287*f3003a0dSAndrew Turner if (fifo_sz == 0) 288*f3003a0dSAndrew Turner sc->irq_state &= ~UARTRTINTR; 289*f3003a0dSAndrew Turner 290*f3003a0dSAndrew Turner reg |= sc->rsr << UARTDR_RSR_SHIFT; 291*f3003a0dSAndrew Turner 292*f3003a0dSAndrew Turner /* After reading from the fifo there is now space in it */ 293*f3003a0dSAndrew Turner sc->rsr &= UARTRSR_OE; 294*f3003a0dSAndrew Turner break; 295*f3003a0dSAndrew Turner case UARTRSR: 296*f3003a0dSAndrew Turner /* Any write clears this register */ 297*f3003a0dSAndrew Turner reg = sc->rsr; 298*f3003a0dSAndrew Turner break; 299*f3003a0dSAndrew Turner case UARTFR: 300*f3003a0dSAndrew Turner /* Transmit is intstant, so the fifo is always empty */ 301*f3003a0dSAndrew Turner reg = UARTFR_TXFE; 302*f3003a0dSAndrew Turner 303*f3003a0dSAndrew Turner /* Set the receive fifo full/empty flags */ 304*f3003a0dSAndrew Turner fifo_sz = uart_rxfifo_numchars(sc->backend); 305*f3003a0dSAndrew Turner if (fifo_sz == UART_FIFO_SIZE) 306*f3003a0dSAndrew Turner reg |= UARTFR_RXFF; 307*f3003a0dSAndrew Turner else if (fifo_sz == 0) 308*f3003a0dSAndrew Turner reg |= UARTFR_RXFE; 309*f3003a0dSAndrew Turner break; 310*f3003a0dSAndrew Turner /* TODO: UARTILPR */ 311*f3003a0dSAndrew Turner case UARTIBRD: 312*f3003a0dSAndrew Turner reg = sc->ibrd; 313*f3003a0dSAndrew Turner break; 314*f3003a0dSAndrew Turner case UARTFBRD: 315*f3003a0dSAndrew Turner reg = sc->fbrd; 316*f3003a0dSAndrew Turner break; 317*f3003a0dSAndrew Turner case UARTLCR_H: 318*f3003a0dSAndrew Turner reg = sc->lcr_h; 319*f3003a0dSAndrew Turner break; 320*f3003a0dSAndrew Turner case UARTCR: 321*f3003a0dSAndrew Turner reg = sc->cr; 322*f3003a0dSAndrew Turner break; 323*f3003a0dSAndrew Turner case UARTIMSC: 324*f3003a0dSAndrew Turner reg = sc->imsc; 325*f3003a0dSAndrew Turner break; 326*f3003a0dSAndrew Turner case UARTRIS: 327*f3003a0dSAndrew Turner reg = sc->irq_state; 328*f3003a0dSAndrew Turner break; 329*f3003a0dSAndrew Turner case UARTMIS: 330*f3003a0dSAndrew Turner reg = sc->irq_state & sc->imsc; 331*f3003a0dSAndrew Turner break; 332*f3003a0dSAndrew Turner case UARTICR: 333*f3003a0dSAndrew Turner reg = 0; 334*f3003a0dSAndrew Turner break; 335*f3003a0dSAndrew Turner case UARTPeriphID0: 336*f3003a0dSAndrew Turner reg = UARTPeriphID0_VAL; 337*f3003a0dSAndrew Turner break; 338*f3003a0dSAndrew Turner case UARTPeriphID1: 339*f3003a0dSAndrew Turner reg =UARTPeriphID1_VAL; 340*f3003a0dSAndrew Turner break; 341*f3003a0dSAndrew Turner case UARTPeriphID2: 342*f3003a0dSAndrew Turner reg = UARTPeriphID2_VAL; 343*f3003a0dSAndrew Turner break; 344*f3003a0dSAndrew Turner case UARTPeriphID3: 345*f3003a0dSAndrew Turner reg = UARTPeriphID3_VAL; 346*f3003a0dSAndrew Turner break; 347*f3003a0dSAndrew Turner case UARTPCellID0: 348*f3003a0dSAndrew Turner reg = UARTPCellID0_VAL; 349*f3003a0dSAndrew Turner break; 350*f3003a0dSAndrew Turner case UARTPCellID1: 351*f3003a0dSAndrew Turner reg = UARTPCellID1_VAL; 352*f3003a0dSAndrew Turner break; 353*f3003a0dSAndrew Turner case UARTPCellID2: 354*f3003a0dSAndrew Turner reg = UARTPCellID2_VAL; 355*f3003a0dSAndrew Turner break; 356*f3003a0dSAndrew Turner case UARTPCellID3: 357*f3003a0dSAndrew Turner reg = UARTPCellID3_VAL; 358*f3003a0dSAndrew Turner break; 359*f3003a0dSAndrew Turner default: 360*f3003a0dSAndrew Turner /* Return 0 in reads from unasigned registers */ 361*f3003a0dSAndrew Turner reg = 0; 362*f3003a0dSAndrew Turner break; 363*f3003a0dSAndrew Turner } 364*f3003a0dSAndrew Turner uart_toggle_intr(sc); 365*f3003a0dSAndrew Turner pthread_mutex_unlock(&sc->mtx); 366*f3003a0dSAndrew Turner 367*f3003a0dSAndrew Turner return (reg); 368*f3003a0dSAndrew Turner } 369*f3003a0dSAndrew Turner 370*f3003a0dSAndrew Turner struct uart_pl011_softc * 371*f3003a0dSAndrew Turner uart_pl011_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert, 372*f3003a0dSAndrew Turner void *arg) 373*f3003a0dSAndrew Turner { 374*f3003a0dSAndrew Turner struct uart_pl011_softc *sc; 375*f3003a0dSAndrew Turner 376*f3003a0dSAndrew Turner sc = calloc(1, sizeof(struct uart_pl011_softc)); 377*f3003a0dSAndrew Turner 378*f3003a0dSAndrew Turner sc->arg = arg; 379*f3003a0dSAndrew Turner sc->intr_assert = intr_assert; 380*f3003a0dSAndrew Turner sc->intr_deassert = intr_deassert; 381*f3003a0dSAndrew Turner sc->backend = uart_init(); 382*f3003a0dSAndrew Turner 383*f3003a0dSAndrew Turner pthread_mutex_init(&sc->mtx, NULL); 384*f3003a0dSAndrew Turner 385*f3003a0dSAndrew Turner uart_reset(sc); 386*f3003a0dSAndrew Turner 387*f3003a0dSAndrew Turner return (sc); 388*f3003a0dSAndrew Turner } 389*f3003a0dSAndrew Turner 390*f3003a0dSAndrew Turner int 391*f3003a0dSAndrew Turner uart_pl011_tty_open(struct uart_pl011_softc *sc, const char *device) 392*f3003a0dSAndrew Turner { 393*f3003a0dSAndrew Turner return (uart_tty_open(sc->backend, device, uart_drain, sc)); 394*f3003a0dSAndrew Turner } 395