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