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