1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2018 Ruslan Bukin <br@bsdpad.com> 5 * All rights reserved. 6 * 7 * This software was developed by SRI International and the University of 8 * Cambridge Computer Laboratory (Department of Computer Science and 9 * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the 10 * DARPA SSITH research programme. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 #include "opt_ddb.h" 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/bus.h> 42 #include <sys/conf.h> 43 #include <sys/kdb.h> 44 #include <machine/bus.h> 45 #include <machine/sbi.h> 46 47 #include <dev/uart/uart.h> 48 #include <dev/uart/uart_cpu.h> 49 #include <dev/uart/uart_cpu_fdt.h> 50 #include <dev/uart/uart_bus.h> 51 #include <dev/uart/uart_dev_lowrisc.h> 52 53 #include "uart_if.h" 54 55 #define DEFAULT_BAUD_RATE 115200 56 57 /* 58 * Low-level UART interface. 59 */ 60 static int lowrisc_uart_probe(struct uart_bas *bas); 61 static void lowrisc_uart_init(struct uart_bas *bas, int, int, int, int); 62 static void lowrisc_uart_term(struct uart_bas *bas); 63 static void lowrisc_uart_putc(struct uart_bas *bas, int); 64 static int lowrisc_uart_rxready(struct uart_bas *bas); 65 static int lowrisc_uart_getc(struct uart_bas *bas, struct mtx *); 66 67 static struct uart_ops uart_lowrisc_uart_ops = { 68 .probe = lowrisc_uart_probe, 69 .init = lowrisc_uart_init, 70 .term = lowrisc_uart_term, 71 .putc = lowrisc_uart_putc, 72 .rxready = lowrisc_uart_rxready, 73 .getc = lowrisc_uart_getc, 74 }; 75 76 static int 77 lowrisc_uart_probe(struct uart_bas *bas) 78 { 79 80 return (0); 81 } 82 83 static u_int 84 lowrisc_uart_getbaud(struct uart_bas *bas) 85 { 86 87 return (DEFAULT_BAUD_RATE); 88 } 89 90 static void 91 lowrisc_uart_init(struct uart_bas *bas, int baudrate, int databits, 92 int stopbits, int parity) 93 { 94 95 /* TODO */ 96 } 97 98 static void 99 lowrisc_uart_term(struct uart_bas *bas) 100 { 101 102 /* TODO */ 103 } 104 105 static void 106 lowrisc_uart_putc(struct uart_bas *bas, int c) 107 { 108 109 while (GETREG(bas, UART_DR) & DR_TX_FIFO_FULL) 110 ; 111 112 SETREG(bas, UART_DR, c); 113 } 114 115 static int 116 lowrisc_uart_rxready(struct uart_bas *bas) 117 { 118 119 if (GETREG(bas, UART_DR) & DR_RX_FIFO_EMPTY) 120 return (0); 121 122 return (1); 123 } 124 125 static int 126 lowrisc_uart_getc(struct uart_bas *bas, struct mtx *hwmtx) 127 { 128 uint32_t reg; 129 130 uart_lock(hwmtx); 131 SETREG(bas, UART_INT_STATUS, INT_STATUS_ACK); 132 reg = GETREG(bas, UART_DR); 133 uart_unlock(hwmtx); 134 135 return (reg & 0xff); 136 } 137 138 /* 139 * High-level UART interface. 140 */ 141 struct lowrisc_uart_softc { 142 struct uart_softc base; 143 }; 144 145 static int lowrisc_uart_bus_attach(struct uart_softc *); 146 static int lowrisc_uart_bus_detach(struct uart_softc *); 147 static int lowrisc_uart_bus_flush(struct uart_softc *, int); 148 static int lowrisc_uart_bus_getsig(struct uart_softc *); 149 static int lowrisc_uart_bus_ioctl(struct uart_softc *, int, intptr_t); 150 static int lowrisc_uart_bus_ipend(struct uart_softc *); 151 static int lowrisc_uart_bus_param(struct uart_softc *, int, int, int, int); 152 static int lowrisc_uart_bus_probe(struct uart_softc *); 153 static int lowrisc_uart_bus_receive(struct uart_softc *); 154 static int lowrisc_uart_bus_setsig(struct uart_softc *, int); 155 static int lowrisc_uart_bus_transmit(struct uart_softc *); 156 static void lowrisc_uart_bus_grab(struct uart_softc *); 157 static void lowrisc_uart_bus_ungrab(struct uart_softc *); 158 159 static kobj_method_t lowrisc_uart_methods[] = { 160 KOBJMETHOD(uart_attach, lowrisc_uart_bus_attach), 161 KOBJMETHOD(uart_detach, lowrisc_uart_bus_detach), 162 KOBJMETHOD(uart_flush, lowrisc_uart_bus_flush), 163 KOBJMETHOD(uart_getsig, lowrisc_uart_bus_getsig), 164 KOBJMETHOD(uart_ioctl, lowrisc_uart_bus_ioctl), 165 KOBJMETHOD(uart_ipend, lowrisc_uart_bus_ipend), 166 KOBJMETHOD(uart_param, lowrisc_uart_bus_param), 167 KOBJMETHOD(uart_probe, lowrisc_uart_bus_probe), 168 KOBJMETHOD(uart_receive, lowrisc_uart_bus_receive), 169 KOBJMETHOD(uart_setsig, lowrisc_uart_bus_setsig), 170 KOBJMETHOD(uart_transmit, lowrisc_uart_bus_transmit), 171 KOBJMETHOD(uart_grab, lowrisc_uart_bus_grab), 172 KOBJMETHOD(uart_ungrab, lowrisc_uart_bus_ungrab), 173 { 0, 0 } 174 }; 175 176 static struct uart_class uart_lowrisc_class = { 177 "lowrisc", 178 lowrisc_uart_methods, 179 sizeof(struct lowrisc_uart_softc), 180 .uc_ops = &uart_lowrisc_uart_ops, 181 .uc_range = 0x100, 182 .uc_rclk = 12500000, /* TODO: get value from clock manager */ 183 .uc_rshift = 0 184 }; 185 186 static struct ofw_compat_data compat_data[] = { 187 {"lowrisc-fake", (uintptr_t)&uart_lowrisc_class}, 188 {NULL, (uintptr_t)NULL}, 189 }; 190 UART_FDT_CLASS_AND_DEVICE(compat_data); 191 192 static int 193 lowrisc_uart_bus_attach(struct uart_softc *sc) 194 { 195 struct uart_bas *bas; 196 struct uart_devinfo *di; 197 198 bas = &sc->sc_bas; 199 if (sc->sc_sysdev != NULL) { 200 di = sc->sc_sysdev; 201 lowrisc_uart_init(bas, di->baudrate, di->databits, di->stopbits, 202 di->parity); 203 } else 204 lowrisc_uart_init(bas, DEFAULT_BAUD_RATE, 8, 1, 0); 205 206 (void)lowrisc_uart_bus_getsig(sc); 207 208 /* TODO: clear all pending interrupts. */ 209 210 return (0); 211 } 212 213 static int 214 lowrisc_uart_bus_detach(struct uart_softc *sc) 215 { 216 217 /* TODO */ 218 219 return (0); 220 } 221 222 static int 223 lowrisc_uart_bus_flush(struct uart_softc *sc, int what) 224 { 225 226 /* TODO */ 227 228 return (0); 229 } 230 231 static int 232 lowrisc_uart_bus_getsig(struct uart_softc *sc) 233 { 234 235 /* TODO */ 236 237 return (0); 238 } 239 240 static int 241 lowrisc_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) 242 { 243 struct uart_bas *bas; 244 int error; 245 246 bas = &sc->sc_bas; 247 error = 0; 248 uart_lock(sc->sc_hwmtx); 249 switch (request) { 250 case UART_IOCTL_BREAK: 251 /* TODO */ 252 break; 253 case UART_IOCTL_BAUD: 254 *(u_int*)data = lowrisc_uart_getbaud(bas); 255 break; 256 default: 257 error = EINVAL; 258 break; 259 } 260 uart_unlock(sc->sc_hwmtx); 261 262 return (error); 263 } 264 265 static int 266 lowrisc_uart_bus_ipend(struct uart_softc *sc) 267 { 268 struct uart_bas *bas; 269 int ipend; 270 271 bas = &sc->sc_bas; 272 273 ipend = 0; 274 275 uart_lock(sc->sc_hwmtx); 276 if ((GETREG(bas, UART_DR) & DR_RX_FIFO_EMPTY) == 0) 277 ipend |= SER_INT_RXREADY; 278 SETREG(bas, UART_INT_STATUS, INT_STATUS_ACK); 279 uart_unlock(sc->sc_hwmtx); 280 281 return (ipend); 282 } 283 284 static int 285 lowrisc_uart_bus_param(struct uart_softc *sc, int baudrate, int databits, 286 int stopbits, int parity) 287 { 288 289 uart_lock(sc->sc_hwmtx); 290 lowrisc_uart_init(&sc->sc_bas, baudrate, databits, stopbits, parity); 291 uart_unlock(sc->sc_hwmtx); 292 293 return (0); 294 } 295 296 static int 297 lowrisc_uart_bus_probe(struct uart_softc *sc) 298 { 299 int error; 300 301 error = lowrisc_uart_probe(&sc->sc_bas); 302 if (error) 303 return (error); 304 305 /* 306 * On input we can read up to the full fifo size at once. On output, we 307 * want to write only as much as the programmed tx low water level, 308 * because that's all we can be certain we have room for in the fifo 309 * when we get a tx-ready interrupt. 310 */ 311 sc->sc_rxfifosz = 2048; 312 sc->sc_txfifosz = 2048; 313 314 device_set_desc(sc->sc_dev, "lowRISC UART"); 315 316 return (0); 317 } 318 319 static int 320 lowrisc_uart_bus_receive(struct uart_softc *sc) 321 { 322 struct uart_bas *bas; 323 uint32_t reg; 324 325 bas = &sc->sc_bas; 326 327 uart_lock(sc->sc_hwmtx); 328 329 do { 330 if (uart_rx_full(sc)) { 331 /* No space left in the input buffer */ 332 sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; 333 break; 334 } 335 reg = GETREG(bas, UART_DR); 336 SETREG(bas, UART_INT_STATUS, INT_STATUS_ACK); 337 uart_rx_put(sc, reg & 0xff); 338 } while ((reg & DR_RX_FIFO_EMPTY) == 0); 339 340 uart_unlock(sc->sc_hwmtx); 341 342 return (0); 343 } 344 345 static int 346 lowrisc_uart_bus_setsig(struct uart_softc *sc, int sig) 347 { 348 349 return (0); 350 } 351 352 static int 353 lowrisc_uart_bus_transmit(struct uart_softc *sc) 354 { 355 struct uart_bas *bas; 356 int i; 357 358 bas = &sc->sc_bas; 359 360 uart_lock(sc->sc_hwmtx); 361 for (i = 0; i < sc->sc_txdatasz; i++) { 362 while (GETREG(bas, UART_DR) & DR_TX_FIFO_FULL) 363 ; 364 SETREG(bas, UART_DR, sc->sc_txbuf[i] & 0xff); 365 } 366 uart_unlock(sc->sc_hwmtx); 367 368 return (0); 369 } 370 371 static void 372 lowrisc_uart_bus_grab(struct uart_softc *sc) 373 { 374 struct uart_bas *bas; 375 376 bas = &sc->sc_bas; 377 378 uart_lock(sc->sc_hwmtx); 379 /* TODO */ 380 uart_unlock(sc->sc_hwmtx); 381 } 382 383 static void 384 lowrisc_uart_bus_ungrab(struct uart_softc *sc) 385 { 386 struct uart_bas *bas; 387 388 bas = &sc->sc_bas; 389 390 uart_lock(sc->sc_hwmtx); 391 /* TODO */ 392 uart_unlock(sc->sc_hwmtx); 393 } 394