1 /* $OpenBSD: sfuart.c,v 1.6 2022/07/12 17:14:12 jca Exp $ */ 2 /* 3 * Copyright (c) 2019 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/conf.h> 20 #include <sys/fcntl.h> 21 #include <sys/proc.h> 22 #include <sys/systm.h> 23 #include <sys/tty.h> 24 25 #include <machine/bus.h> 26 #include <machine/fdt.h> 27 28 #include <dev/cons.h> 29 30 #include <dev/ofw/fdt.h> 31 #include <dev/ofw/openfirm.h> 32 #include <dev/ofw/ofw_clock.h> 33 34 #define UART_TXDATA 0x0000 35 #define UART_TXDATA_FULL (1U << 31) 36 #define UART_RXDATA 0x0004 37 #define UART_RXDATA_EMPTY (1U << 31) 38 #define UART_TXCTRL 0x0008 39 #define UART_TXCTRL_TXEN (1 << 0) 40 #define UART_TXCTRL_NSTOP (1 << 1) 41 #define UART_TXCTRL_TXCNT_SHIFT 16 42 #define UART_TXCTRL_TXCNT_MASK (7 << 16) 43 #define UART_RXCTRL 0x000c 44 #define UART_RXCTRL_RXEN (1 << 0) 45 #define UART_RXCTRL_RXCNT_SHIFT 16 46 #define UART_RXCTRL_RXCNT_MASK (7 << 16) 47 #define UART_IE 0x0010 48 #define UART_IE_TXWM (1 << 0) 49 #define UART_IE_RXWM (1 << 1) 50 #define UART_IP 0x0014 51 #define UART_IP_TXWM (1 << 0) 52 #define UART_IP_RXWM (1 << 1) 53 #define UART_DIV 0x0018 54 55 #define UART_SPACE 28 56 #define UART_FIFO_SIZE 8 57 58 #define HREAD4(sc, reg) \ 59 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 60 #define HWRITE4(sc, reg, val) \ 61 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 62 #define HSET4(sc, reg, bits) \ 63 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 64 #define HCLR4(sc, reg, bits) \ 65 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 66 67 cdev_decl(com); 68 cdev_decl(sfuart); 69 70 #define DEVUNIT(x) (minor(x) & 0x7f) 71 #define DEVCUA(x) (minor(x) & 0x80) 72 73 struct cdevsw sfuartdev = cdev_tty_init(2, sfuart); 74 75 struct sfuart_softc { 76 struct device sc_dev; 77 bus_space_tag_t sc_iot; 78 bus_space_handle_t sc_ioh; 79 80 uint32_t sc_frequency; 81 82 struct soft_intrhand *sc_si; 83 void *sc_ih; 84 85 struct tty *sc_tty; 86 int sc_conspeed; 87 int sc_floods; 88 int sc_overflows; 89 int sc_halt; 90 int sc_cua; 91 int *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend; 92 #define SFUART_IBUFSIZE 128 93 #define SFUART_IHIGHWATER 100 94 int sc_ibufs[2][SFUART_IBUFSIZE]; 95 }; 96 97 int sfuart_match(struct device *, void *, void *); 98 void sfuart_attach(struct device *, struct device *, void *); 99 100 struct cfdriver sfuart_cd = { 101 NULL, "sfuart", DV_TTY 102 }; 103 104 const struct cfattach sfuart_ca = { 105 sizeof(struct sfuart_softc), sfuart_match, sfuart_attach 106 }; 107 108 bus_space_tag_t sfuartconsiot; 109 bus_space_handle_t sfuartconsioh; 110 111 struct sfuart_softc *sfuart_sc(dev_t); 112 113 int sfuart_intr(void *); 114 void sfuart_softintr(void *); 115 void sfuart_start(struct tty *); 116 117 int sfuartcnattach(bus_space_tag_t, bus_addr_t); 118 int sfuartcngetc(dev_t); 119 void sfuartcnputc(dev_t, int); 120 void sfuartcnpollc(dev_t, int); 121 122 void 123 sfuart_init_cons(void) 124 { 125 struct fdt_reg reg; 126 void *node; 127 128 if ((node = fdt_find_cons("sifive,uart0")) == NULL) 129 return; 130 if (fdt_get_reg(node, 0, ®)) 131 return; 132 133 sfuartcnattach(fdt_cons_bs_tag, reg.addr); 134 } 135 136 int 137 sfuart_match(struct device *parent, void *match, void *aux) 138 { 139 struct fdt_attach_args *faa = aux; 140 141 return OF_is_compatible(faa->fa_node, "sifive,uart0"); 142 } 143 144 void 145 sfuart_attach(struct device *parent, struct device *self, void *aux) 146 { 147 struct sfuart_softc *sc = (struct sfuart_softc *)self; 148 struct fdt_attach_args *faa = aux; 149 int maj; 150 151 if (faa->fa_nreg < 1) { 152 printf(": no registers\n"); 153 return; 154 } 155 156 sc->sc_iot = faa->fa_iot; 157 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 158 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 159 printf(": can't map registers\n"); 160 return; 161 } 162 163 sc->sc_frequency = clock_get_frequency(faa->fa_node, NULL); 164 if (faa->fa_node == stdout_node) { 165 /* Locate the major number. */ 166 for (maj = 0; maj < nchrdev; maj++) 167 if (cdevsw[maj].d_open == sfuartopen) 168 break; 169 cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit); 170 sc->sc_conspeed = stdout_speed; 171 printf(": console"); 172 } 173 174 sc->sc_si = softintr_establish(IPL_TTY, sfuart_softintr, sc); 175 if (sc->sc_si == NULL) { 176 printf(": can't establish soft interrupt\n"); 177 return; 178 } 179 180 sc->sc_ih = fdt_intr_establish_idx(faa->fa_node, 0, IPL_TTY, 181 sfuart_intr, sc, sc->sc_dev.dv_xname); 182 if (sc->sc_ih == NULL) { 183 printf(": can't establish hard interrupt\n"); 184 return; 185 } 186 187 printf("\n"); 188 } 189 190 int 191 sfuart_intr(void *arg) 192 { 193 struct sfuart_softc *sc = arg; 194 struct tty *tp = sc->sc_tty; 195 int *p; 196 uint32_t val; 197 int c, handled = 0; 198 199 if (tp == NULL) 200 return 0; 201 202 if (!ISSET(HREAD4(sc, UART_TXDATA), UART_TXDATA_FULL) && 203 ISSET(tp->t_state, TS_BUSY)) { 204 CLR(tp->t_state, TS_BUSY | TS_FLUSH); 205 if (sc->sc_halt > 0) 206 wakeup(&tp->t_outq); 207 (*linesw[tp->t_line].l_start)(tp); 208 handled = 1; 209 } 210 211 p = sc->sc_ibufp; 212 val = HREAD4(sc, UART_RXDATA); 213 while (!ISSET(val, UART_RXDATA_EMPTY)) { 214 c = val & 0xff; 215 216 if (p >= sc->sc_ibufend) 217 sc->sc_floods++; 218 else 219 *p++ = c; 220 221 val = HREAD4(sc, UART_RXDATA); 222 handled = 1; 223 } 224 if (sc->sc_ibufp != p) { 225 sc->sc_ibufp = p; 226 softintr_schedule(sc->sc_si); 227 } 228 229 return handled; 230 } 231 232 void 233 sfuart_softintr(void *arg) 234 { 235 struct sfuart_softc *sc = arg; 236 struct tty *tp = sc->sc_tty; 237 int *ibufp, *ibufend; 238 int s; 239 240 if (sc->sc_ibufp == sc->sc_ibuf) 241 return; 242 243 s = spltty(); 244 245 ibufp = sc->sc_ibuf; 246 ibufend = sc->sc_ibufp; 247 248 if (ibufp == ibufend) { 249 splx(s); 250 return; 251 } 252 253 sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ? 254 sc->sc_ibufs[1] : sc->sc_ibufs[0]; 255 sc->sc_ibufhigh = sc->sc_ibuf + SFUART_IHIGHWATER; 256 sc->sc_ibufend = sc->sc_ibuf + SFUART_IBUFSIZE; 257 258 if (tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) { 259 splx(s); 260 return; 261 } 262 263 splx(s); 264 265 while (ibufp < ibufend) { 266 int i = *ibufp++; 267 #ifdef DDB 268 if (tp->t_dev == cn_tab->cn_dev) { 269 int j = db_rint(i); 270 271 if (j == 1) /* Escape received, skip */ 272 continue; 273 if (j == 2) /* Second char wasn't 'D' */ 274 (*linesw[tp->t_line].l_rint)(27, tp); 275 } 276 #endif 277 (*linesw[tp->t_line].l_rint)(i, tp); 278 } 279 } 280 281 int 282 sfuart_param(struct tty *tp, struct termios *t) 283 { 284 struct sfuart_softc *sc = sfuart_sc(tp->t_dev); 285 int ospeed = t->c_ospeed; 286 uint32_t div; 287 288 /* Check requested parameters. */ 289 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 290 return EINVAL; 291 292 switch (ISSET(t->c_cflag, CSIZE)) { 293 case CS5: 294 case CS6: 295 case CS7: 296 return EINVAL; 297 case CS8: 298 break; 299 } 300 301 if (ospeed != 0) { 302 while (ISSET(tp->t_state, TS_BUSY)) { 303 int error; 304 305 sc->sc_halt++; 306 error = ttysleep(tp, &tp->t_outq, 307 TTOPRI | PCATCH, "sfuprm"); 308 sc->sc_halt--; 309 if (error) { 310 sfuart_start(tp); 311 return error; 312 } 313 } 314 315 div = (sc->sc_frequency + ospeed / 2) / ospeed; 316 if (div < 16 || div > 65536) 317 return EINVAL; 318 HWRITE4(sc, UART_DIV, div - 1); 319 } 320 321 tp->t_ispeed = t->c_ispeed; 322 tp->t_ospeed = t->c_ospeed; 323 tp->t_cflag = t->c_cflag; 324 325 /* Just to be sure... */ 326 sfuart_start(tp); 327 return 0; 328 } 329 330 void 331 sfuart_start(struct tty *tp) 332 { 333 struct sfuart_softc *sc = sfuart_sc(tp->t_dev); 334 int stat; 335 int s; 336 337 s = spltty(); 338 if (ISSET(tp->t_state, TS_BUSY)) 339 goto out; 340 if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP) || sc->sc_halt > 0) 341 goto out; 342 ttwakeupwr(tp); 343 if (tp->t_outq.c_cc == 0) { 344 HCLR4(sc, UART_IE, UART_IE_TXWM); 345 goto out; 346 } 347 SET(tp->t_state, TS_BUSY); 348 349 stat = HREAD4(sc, UART_TXDATA); 350 while ((stat & UART_TXDATA_FULL) == 0 && tp->t_outq.c_cc != 0) { 351 HWRITE4(sc, UART_TXDATA, getc(&tp->t_outq)); 352 stat = HREAD4(sc, UART_TXDATA); 353 } 354 HSET4(sc, UART_IE, UART_IE_TXWM); 355 out: 356 splx(s); 357 } 358 359 int 360 sfuartopen(dev_t dev, int flag, int mode, struct proc *p) 361 { 362 struct sfuart_softc *sc = sfuart_sc(dev); 363 struct tty *tp; 364 int error; 365 int s; 366 367 if (sc == NULL) 368 return ENXIO; 369 370 s = spltty(); 371 if (sc->sc_tty == NULL) 372 tp = sc->sc_tty = ttymalloc(0); 373 else 374 tp = sc->sc_tty; 375 splx(s); 376 377 tp->t_oproc = sfuart_start; 378 tp->t_param = sfuart_param; 379 tp->t_dev = dev; 380 381 if (!ISSET(tp->t_state, TS_ISOPEN)) { 382 SET(tp->t_state, TS_WOPEN); 383 ttychars(tp); 384 tp->t_iflag = TTYDEF_IFLAG; 385 tp->t_oflag = TTYDEF_OFLAG; 386 tp->t_cflag = TTYDEF_CFLAG; 387 tp->t_lflag = TTYDEF_LFLAG; 388 tp->t_ispeed = tp->t_ospeed = 389 sc->sc_conspeed ? sc->sc_conspeed : B115200; 390 391 s = spltty(); 392 393 sfuart_param(tp, &tp->t_termios); 394 ttsetwater(tp); 395 396 sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0]; 397 sc->sc_ibufhigh = sc->sc_ibuf + SFUART_IHIGHWATER; 398 sc->sc_ibufend = sc->sc_ibuf + SFUART_IBUFSIZE; 399 400 /* Enable transmit. */ 401 HWRITE4(sc, UART_TXCTRL, UART_TXCTRL_TXEN | 402 ((UART_FIFO_SIZE / 2) << UART_TXCTRL_TXCNT_SHIFT)); 403 404 /* Enable receive. */ 405 HWRITE4(sc, UART_RXCTRL, UART_RXCTRL_RXEN | 406 (0 << UART_RXCTRL_RXCNT_SHIFT)); 407 408 /* Enable interrupts. */ 409 HSET4(sc, UART_IE, UART_IE_RXWM); 410 411 /* No carrier detect support. */ 412 SET(tp->t_state, TS_CARR_ON); 413 } else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0) 414 return EBUSY; 415 else 416 s = spltty(); 417 418 if (DEVCUA(dev)) { 419 if (ISSET(tp->t_state, TS_ISOPEN)) { 420 /* Ah, but someone already is dialed in... */ 421 splx(s); 422 return EBUSY; 423 } 424 sc->sc_cua = 1; /* We go into CUA mode. */ 425 } else { 426 if (ISSET(flag, O_NONBLOCK) && sc->sc_cua) { 427 /* Opening TTY non-blocking... but the CUA is busy. */ 428 splx(s); 429 return EBUSY; 430 } else { 431 while (sc->sc_cua) { 432 SET(tp->t_state, TS_WOPEN); 433 error = ttysleep(tp, &tp->t_rawq, 434 TTIPRI | PCATCH, ttopen); 435 /* 436 * If TS_WOPEN has been reset, that means the 437 * cua device has been closed. 438 * We don't want to fail in that case, 439 * so just go around again. 440 */ 441 if (error && ISSET(tp->t_state, TS_WOPEN)) { 442 CLR(tp->t_state, TS_WOPEN); 443 splx(s); 444 return error; 445 } 446 } 447 } 448 } 449 splx(s); 450 451 return (*linesw[tp->t_line].l_open)(dev, tp, p); 452 } 453 454 int 455 sfuartclose(dev_t dev, int flag, int mode, struct proc *p) 456 { 457 struct sfuart_softc *sc = sfuart_sc(dev); 458 struct tty *tp = sc->sc_tty; 459 int s; 460 461 if (!ISSET(tp->t_state, TS_ISOPEN)) 462 return 0; 463 464 (*linesw[tp->t_line].l_close)(tp, flag, p); 465 s = spltty(); 466 if (!ISSET(tp->t_state, TS_WOPEN)) { 467 /* Disable interrupts */ 468 HCLR4(sc, UART_IE, UART_IE_TXWM | UART_IE_RXWM); 469 } 470 CLR(tp->t_state, TS_BUSY | TS_FLUSH); 471 sc->sc_cua = 0; 472 splx(s); 473 ttyclose(tp); 474 475 return 0; 476 } 477 478 int 479 sfuartread(dev_t dev, struct uio *uio, int flag) 480 { 481 struct tty *tp = sfuarttty(dev); 482 483 if (tp == NULL) 484 return ENODEV; 485 486 return (*linesw[tp->t_line].l_read)(tp, uio, flag); 487 } 488 489 int 490 sfuartwrite(dev_t dev, struct uio *uio, int flag) 491 { 492 struct tty *tp = sfuarttty(dev); 493 494 if (tp == NULL) 495 return ENODEV; 496 497 return (*linesw[tp->t_line].l_write)(tp, uio, flag); 498 } 499 500 int 501 sfuartioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 502 { 503 struct sfuart_softc *sc = sfuart_sc(dev); 504 struct tty *tp; 505 int error; 506 507 if (sc == NULL) 508 return ENODEV; 509 510 tp = sc->sc_tty; 511 if (tp == NULL) 512 return ENXIO; 513 514 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 515 if (error >= 0) 516 return error; 517 518 error = ttioctl(tp, cmd, data, flag, p); 519 if (error >= 0) 520 return error; 521 522 switch(cmd) { 523 case TIOCSBRK: 524 case TIOCCBRK: 525 case TIOCSDTR: 526 case TIOCCDTR: 527 case TIOCMSET: 528 case TIOCMBIS: 529 case TIOCMBIC: 530 case TIOCMGET: 531 case TIOCGFLAGS: 532 break; 533 case TIOCSFLAGS: 534 error = suser(p); 535 if (error != 0) 536 return EPERM; 537 break; 538 default: 539 return ENOTTY; 540 } 541 542 return 0; 543 } 544 545 int 546 sfuartstop(struct tty *tp, int flag) 547 { 548 return 0; 549 } 550 551 struct tty * 552 sfuarttty(dev_t dev) 553 { 554 struct sfuart_softc *sc = sfuart_sc(dev); 555 556 if (sc == NULL) 557 return NULL; 558 return sc->sc_tty; 559 } 560 561 struct sfuart_softc * 562 sfuart_sc(dev_t dev) 563 { 564 int unit = DEVUNIT(dev); 565 566 if (unit >= sfuart_cd.cd_ndevs) 567 return NULL; 568 return (struct sfuart_softc *)sfuart_cd.cd_devs[unit]; 569 } 570 571 int 572 sfuartcnattach(bus_space_tag_t iot, bus_addr_t iobase) 573 { 574 static struct consdev sfuartcons = { 575 NULL, NULL, sfuartcngetc, sfuartcnputc, sfuartcnpollc, NULL, 576 NODEV, CN_MIDPRI 577 }; 578 int maj; 579 580 sfuartconsiot = iot; 581 if (bus_space_map(iot, iobase, UART_SPACE, 0, &sfuartconsioh)) 582 return ENOMEM; 583 584 /* Look for major of com(4) to replace. */ 585 for (maj = 0; maj < nchrdev; maj++) 586 if (cdevsw[maj].d_open == comopen) 587 break; 588 if (maj == nchrdev) 589 return ENXIO; 590 591 cn_tab = &sfuartcons; 592 cn_tab->cn_dev = makedev(maj, 0); 593 cdevsw[maj] = sfuartdev; /* KLUDGE */ 594 595 return 0; 596 } 597 598 int 599 sfuartcngetc(dev_t dev) 600 { 601 uint32_t val; 602 603 do { 604 val = bus_space_read_4(sfuartconsiot, sfuartconsioh, UART_RXDATA); 605 if (val & UART_RXDATA_EMPTY) 606 CPU_BUSY_CYCLE(); 607 } while ((val & UART_RXDATA_EMPTY)); 608 609 return (val & 0xff); 610 } 611 612 void 613 sfuartcnputc(dev_t dev, int c) 614 { 615 while (bus_space_read_4(sfuartconsiot, sfuartconsioh, UART_TXDATA) & 616 UART_TXDATA_FULL) 617 CPU_BUSY_CYCLE(); 618 bus_space_write_4(sfuartconsiot, sfuartconsioh, UART_TXDATA, c); 619 } 620 621 void 622 sfuartcnpollc(dev_t dev, int on) 623 { 624 } 625