1 /* $OpenBSD: pluart.c,v 1.14 2022/07/02 08:50:42 visa Exp $ */ 2 /* 3 * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se> 4 * Copyright (c) 2005 Dale Rahn <drahn@dalerahn.com> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/ioctl.h> 21 #include <sys/proc.h> 22 #include <sys/tty.h> 23 #include <sys/uio.h> 24 #include <sys/systm.h> 25 #include <sys/time.h> 26 #include <sys/device.h> 27 #include <sys/syslog.h> 28 #include <sys/conf.h> 29 #include <sys/fcntl.h> 30 #include <sys/kernel.h> 31 32 #include <machine/bus.h> 33 34 #include <dev/ic/pluartvar.h> 35 #include <dev/cons.h> 36 37 #ifdef DDB 38 #include <ddb/db_var.h> 39 #endif 40 41 #define DEVUNIT(x) (minor(x) & 0x7f) 42 #define DEVCUA(x) (minor(x) & 0x80) 43 44 #define UART_DR 0x00 /* Data register */ 45 #define UART_DR_DATA(x) ((x) & 0xf) 46 #define UART_DR_FE (1 << 8) /* Framing error */ 47 #define UART_DR_PE (1 << 9) /* Parity error */ 48 #define UART_DR_BE (1 << 10) /* Break error */ 49 #define UART_DR_OE (1 << 11) /* Overrun error */ 50 #define UART_RSR 0x04 /* Receive status register */ 51 #define UART_RSR_FE (1 << 0) /* Framing error */ 52 #define UART_RSR_PE (1 << 1) /* Parity error */ 53 #define UART_RSR_BE (1 << 2) /* Break error */ 54 #define UART_RSR_OE (1 << 3) /* Overrun error */ 55 #define UART_ECR 0x04 /* Error clear register */ 56 #define UART_ECR_FE (1 << 0) /* Framing error */ 57 #define UART_ECR_PE (1 << 1) /* Parity error */ 58 #define UART_ECR_BE (1 << 2) /* Break error */ 59 #define UART_ECR_OE (1 << 3) /* Overrun error */ 60 #define UART_FR 0x18 /* Flag register */ 61 #define UART_FR_CTS (1 << 0) /* Clear to send */ 62 #define UART_FR_DSR (1 << 1) /* Data set ready */ 63 #define UART_FR_DCD (1 << 2) /* Data carrier detect */ 64 #define UART_FR_BUSY (1 << 3) /* UART busy */ 65 #define UART_FR_RXFE (1 << 4) /* Receive FIFO empty */ 66 #define UART_FR_TXFF (1 << 5) /* Transmit FIFO full */ 67 #define UART_FR_RXFF (1 << 6) /* Receive FIFO full */ 68 #define UART_FR_TXFE (1 << 7) /* Transmit FIFO empty */ 69 #define UART_FR_RI (1 << 8) /* Ring indicator */ 70 #define UART_ILPR 0x20 /* IrDA low-power counter register */ 71 #define UART_ILPR_ILPDVSR ((x) & 0xf) /* IrDA low-power divisor */ 72 #define UART_IBRD 0x24 /* Integer baud rate register */ 73 #define UART_IBRD_DIVINT(x) ((x) & 0xffff) /* Integer baud rate divisor */ 74 #define UART_FBRD 0x28 /* Fractional baud rate register */ 75 #define UART_FBRD_DIVFRAC(x) ((x) & 0x3f) /* Fractional baud rate divisor */ 76 #define UART_LCR_H 0x2c /* Line control register */ 77 #define UART_LCR_H_BRK (1 << 0) /* Send break */ 78 #define UART_LCR_H_PEN (1 << 1) /* Parity enable */ 79 #define UART_LCR_H_EPS (1 << 2) /* Even parity select */ 80 #define UART_LCR_H_STP2 (1 << 3) /* Two stop bits select */ 81 #define UART_LCR_H_FEN (1 << 4) /* Enable FIFOs */ 82 #define UART_LCR_H_WLEN5 (0x0 << 5) /* Word length: 5 bits */ 83 #define UART_LCR_H_WLEN6 (0x1 << 5) /* Word length: 6 bits */ 84 #define UART_LCR_H_WLEN7 (0x2 << 5) /* Word length: 7 bits */ 85 #define UART_LCR_H_WLEN8 (0x3 << 5) /* Word length: 8 bits */ 86 #define UART_LCR_H_SPS (1 << 7) /* Stick parity select */ 87 #define UART_CR 0x30 /* Control register */ 88 #define UART_CR_UARTEN (1 << 0) /* UART enable */ 89 #define UART_CR_SIREN (1 << 1) /* SIR enable */ 90 #define UART_CR_SIRLP (1 << 2) /* IrDA SIR low power mode */ 91 #define UART_CR_LBE (1 << 7) /* Loop back enable */ 92 #define UART_CR_TXE (1 << 8) /* Transmit enable */ 93 #define UART_CR_RXE (1 << 9) /* Receive enable */ 94 #define UART_CR_DTR (1 << 10) /* Data transmit enable */ 95 #define UART_CR_RTS (1 << 11) /* Request to send */ 96 #define UART_CR_OUT1 (1 << 12) 97 #define UART_CR_OUT2 (1 << 13) 98 #define UART_CR_CTSE (1 << 14) /* CTS hardware flow control enable */ 99 #define UART_CR_RTSE (1 << 15) /* RTS hardware flow control enable */ 100 #define UART_IFLS 0x34 /* Interrupt FIFO level select register */ 101 #define UART_IFLS_RX_SHIFT 3 /* RX level in bits [5:3] */ 102 #define UART_IFLS_TX_SHIFT 0 /* TX level in bits [2:0] */ 103 #define UART_IFLS_1_8 0 /* FIFO 1/8 full */ 104 #define UART_IFLS_1_4 1 /* FIFO 1/4 full */ 105 #define UART_IFLS_1_2 2 /* FIFO 1/2 full */ 106 #define UART_IFLS_3_4 3 /* FIFO 3/4 full */ 107 #define UART_IFLS_7_8 4 /* FIFO 7/8 full */ 108 #define UART_IMSC 0x38 /* Interrupt mask set/clear register */ 109 #define UART_IMSC_RIMIM (1 << 0) 110 #define UART_IMSC_CTSMIM (1 << 1) 111 #define UART_IMSC_DCDMIM (1 << 2) 112 #define UART_IMSC_DSRMIM (1 << 3) 113 #define UART_IMSC_RXIM (1 << 4) 114 #define UART_IMSC_TXIM (1 << 5) 115 #define UART_IMSC_RTIM (1 << 6) 116 #define UART_IMSC_FEIM (1 << 7) 117 #define UART_IMSC_PEIM (1 << 8) 118 #define UART_IMSC_BEIM (1 << 9) 119 #define UART_IMSC_OEIM (1 << 10) 120 #define UART_RIS 0x3c /* Raw interrupt status register */ 121 #define UART_MIS 0x40 /* Masked interrupt status register */ 122 #define UART_ICR 0x44 /* Interrupt clear register */ 123 #define UART_DMACR 0x48 /* DMA control register */ 124 #define UART_PID0 0xfe0 /* Peripheral identification register 0 */ 125 #define UART_PID1 0xfe4 /* Peripheral identification register 1 */ 126 #define UART_PID2 0xfe8 /* Peripheral identification register 2 */ 127 #define UART_PID2_REV(x) (((x) & 0xf0) >> 4) 128 #define UART_PID3 0xfec /* Peripheral identification register 3 */ 129 #define UART_SPACE 0x100 130 131 #define UART_FIFO_SIZE 16 132 #define UART_FIFO_SIZE_R3 32 133 134 void pluartcnprobe(struct consdev *cp); 135 void pluartcninit(struct consdev *cp); 136 int pluartcngetc(dev_t dev); 137 void pluartcnputc(dev_t dev, int c); 138 void pluartcnpollc(dev_t dev, int on); 139 int pluart_param(struct tty *tp, struct termios *t); 140 void pluart_start(struct tty *); 141 void pluart_diag(void *arg); 142 void pluart_raisedtr(void *arg); 143 void pluart_softint(void *arg); 144 struct pluart_softc *pluart_sc(dev_t dev); 145 146 /* XXX - we imitate 'com' serial ports and take over their entry points */ 147 /* XXX: These belong elsewhere */ 148 cdev_decl(com); 149 cdev_decl(pluart); 150 151 struct cfdriver pluart_cd = { 152 NULL, "pluart", DV_TTY 153 }; 154 155 int pluartdefaultrate = B38400; 156 int pluartconsrate = B38400; 157 bus_space_tag_t pluartconsiot; 158 bus_space_handle_t pluartconsioh; 159 bus_addr_t pluartconsaddr; 160 tcflag_t pluartconscflag = TTYDEF_CFLAG; 161 162 struct cdevsw pluartdev = 163 cdev_tty_init(3/*XXX NUART */ ,pluart); /* 12: serial port */ 164 165 void 166 pluart_attach_common(struct pluart_softc *sc, int console) 167 { 168 int fifolen, fr, lcr, maj; 169 170 if ((sc->sc_hwflags & COM_HW_SBSA) == 0) { 171 if (sc->sc_hwrev == 0) 172 sc->sc_hwrev = UART_PID2_REV(bus_space_read_4(sc->sc_iot, 173 sc->sc_ioh, UART_PID2)); 174 if (sc->sc_hwrev < 3) 175 fifolen = UART_FIFO_SIZE; 176 else 177 fifolen = UART_FIFO_SIZE_R3; 178 printf(": rev %d, %d byte fifo\n", sc->sc_hwrev, fifolen); 179 } else { 180 /* 181 * The SBSA UART is PL011 r1p5 compliant which implies revision 182 * 3 with a 32 byte FIFO. However, we cannot expect to configure 183 * RX/TX interrupt levels using the UARTIFLS register making it 184 * impossible to make assumptions about the number of available 185 * bytes in the FIFO. Therefore disable FIFO support for such 186 * devices. 187 */ 188 fifolen = 0; 189 printf("\n"); 190 } 191 192 if (console) { 193 /* Locate the major number. */ 194 for (maj = 0; maj < nchrdev; maj++) 195 if (cdevsw[maj].d_open == pluartopen) 196 break; 197 cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit); 198 199 printf("%s: console\n", sc->sc_dev.dv_xname); 200 SET(sc->sc_hwflags, COM_HW_CONSOLE); 201 } 202 203 timeout_set(&sc->sc_diag_tmo, pluart_diag, sc); 204 timeout_set(&sc->sc_dtr_tmo, pluart_raisedtr, sc); 205 sc->sc_si = softintr_establish(IPL_TTY, pluart_softint, sc); 206 207 if(sc->sc_si == NULL) 208 panic("%s: can't establish soft interrupt.", 209 sc->sc_dev.dv_xname); 210 211 /* Flush transmit before enabling FIFO. */ 212 for (;;) { 213 fr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_FR); 214 if (fr & UART_FR_TXFE) 215 break; 216 delay(100); 217 } 218 219 if (fifolen > 0) { 220 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IFLS, 221 (UART_IFLS_3_4 << UART_IFLS_RX_SHIFT) | 222 (UART_IFLS_1_4 << UART_IFLS_TX_SHIFT)); 223 } 224 sc->sc_imsc = UART_IMSC_RXIM | UART_IMSC_RTIM; 225 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, sc->sc_imsc); 226 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_ICR, 0x7ff); 227 228 229 lcr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H); 230 if (fifolen > 0) 231 lcr |= UART_LCR_H_FEN; 232 else 233 lcr &= ~UART_LCR_H_FEN; 234 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H, lcr); 235 } 236 237 int 238 pluart_intr(void *arg) 239 { 240 struct pluart_softc *sc = arg; 241 bus_space_tag_t iot = sc->sc_iot; 242 bus_space_handle_t ioh = sc->sc_ioh; 243 struct tty *tp = sc->sc_tty; 244 u_int16_t is; 245 u_int16_t *p; 246 u_int16_t c; 247 248 is = bus_space_read_4(iot, ioh, UART_MIS); 249 bus_space_write_4(iot, ioh, UART_ICR, is & ~UART_IMSC_TXIM); 250 251 if (sc->sc_tty == NULL) 252 return 0; 253 254 if (!ISSET(is, UART_IMSC_RXIM) && !ISSET(is, UART_IMSC_RTIM) && 255 !ISSET(is, UART_IMSC_TXIM)) 256 return 0; 257 258 if (ISSET(is, UART_IMSC_TXIM) && ISSET(tp->t_state, TS_BUSY)) { 259 CLR(tp->t_state, TS_BUSY | TS_FLUSH); 260 if (sc->sc_halt > 0) 261 wakeup(&tp->t_outq); 262 (*linesw[tp->t_line].l_start)(tp); 263 } 264 265 p = sc->sc_ibufp; 266 267 while (!ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFE)) { 268 c = bus_space_read_2(iot, ioh, UART_DR); 269 if (c & UART_DR_BE) { 270 #ifdef DDB 271 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 272 if (db_console) 273 db_enter(); 274 continue; 275 } 276 #endif 277 c = 0; 278 } 279 if (p >= sc->sc_ibufend) { 280 sc->sc_floods++; 281 if (sc->sc_errors++ == 0) 282 timeout_add_sec(&sc->sc_diag_tmo, 60); 283 } else { 284 *p++ = c; 285 if (p == sc->sc_ibufhigh && ISSET(tp->t_cflag, CRTSCTS)) { 286 /* XXX */ 287 //CLR(sc->sc_ucr3, IMXUART_CR3_DSR); 288 //bus_space_write_4(iot, ioh, IMXUART_UCR3, 289 // sc->sc_ucr3); 290 } 291 } 292 /* XXX - msr stuff ? */ 293 } 294 sc->sc_ibufp = p; 295 296 softintr_schedule(sc->sc_si); 297 298 return 1; 299 } 300 301 int 302 pluart_param(struct tty *tp, struct termios *t) 303 { 304 struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)]; 305 int ospeed = t->c_ospeed; 306 int error; 307 tcflag_t oldcflag; 308 309 if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 310 return EINVAL; 311 312 switch (ISSET(t->c_cflag, CSIZE)) { 313 case CS5: 314 return EINVAL; 315 case CS6: 316 return EINVAL; 317 case CS7: 318 //CLR(sc->sc_ucr2, IMXUART_CR2_WS); 319 break; 320 case CS8: 321 //SET(sc->sc_ucr2, IMXUART_CR2_WS); 322 break; 323 } 324 // bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2); 325 326 /* 327 if (ISSET(t->c_cflag, PARENB)) { 328 SET(sc->sc_ucr2, IMXUART_CR2_PREN); 329 bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2); 330 } 331 */ 332 /* STOPB - XXX */ 333 if (ospeed == 0) { 334 /* lower dtr */ 335 } 336 337 if (sc->sc_clkfreq != 0 && ospeed != 0 && ospeed != tp->t_ospeed) { 338 int cr, div, lcr; 339 340 while (ISSET(tp->t_state, TS_BUSY)) { 341 ++sc->sc_halt; 342 error = ttysleep(tp, &tp->t_outq, 343 TTOPRI | PCATCH, "pluartprm"); 344 --sc->sc_halt; 345 if (error) { 346 pluart_start(tp); 347 return (error); 348 } 349 } 350 351 /* 352 * Writes to IBRD and FBRD are made effective first when LCR_H 353 * is written. 354 */ 355 lcr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H); 356 357 /* The UART must be disabled while changing the baud rate. */ 358 cr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_CR); 359 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_CR, 360 cr & ~UART_CR_UARTEN); 361 362 /* 363 * The baud rate divisor is expressed relative to the UART clock 364 * frequency where IBRD represents the quotient using 16 bits 365 * and FBRD the remainder using 6 bits. The PL011 specification 366 * provides the following formula: 367 * 368 * uartclk/(16 * baudrate) 369 * 370 * The formula can be estimated by scaling it with the 371 * precision 64 (2^6) and letting the resulting upper 16 bits 372 * represents the quotient and the lower 6 bits the remainder: 373 * 374 * 64 * uartclk/(16 * baudrate) = 4 * uartclk/baudrate 375 */ 376 div = 4 * sc->sc_clkfreq / ospeed; 377 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IBRD, 378 UART_IBRD_DIVINT(div >> 6)); 379 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_FBRD, 380 UART_FBRD_DIVFRAC(div)); 381 /* Commit baud rate change. */ 382 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H, lcr); 383 /* Enable UART. */ 384 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_CR, cr); 385 } 386 387 /* setup fifo */ 388 389 /* When not using CRTSCTS, RTS follows DTR. */ 390 /* sc->sc_dtr = MCR_DTR; */ 391 392 /* and copy to tty */ 393 tp->t_ispeed = t->c_ispeed; 394 tp->t_ospeed = t->c_ospeed; 395 oldcflag = tp->t_cflag; 396 tp->t_cflag = t->c_cflag; 397 398 /* 399 * If DCD is off and MDMBUF is changed, ask the tty layer if we should 400 * stop the device. 401 */ 402 /* XXX */ 403 404 pluart_start(tp); 405 406 return 0; 407 } 408 409 void 410 pluart_start(struct tty *tp) 411 { 412 struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)]; 413 bus_space_tag_t iot = sc->sc_iot; 414 bus_space_handle_t ioh = sc->sc_ioh; 415 int s; 416 417 s = spltty(); 418 if (ISSET(tp->t_state, TS_BUSY)) 419 goto out; 420 if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP)) 421 goto stopped; 422 ttwakeupwr(tp); 423 if (tp->t_outq.c_cc == 0) 424 goto stopped; 425 SET(tp->t_state, TS_BUSY); 426 427 /* Enable transmit interrupt. */ 428 if (!ISSET(sc->sc_imsc, UART_IMSC_TXIM)) { 429 sc->sc_imsc |= UART_IMSC_TXIM; 430 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, 431 sc->sc_imsc); 432 } 433 434 while (tp->t_outq.c_cc > 0) { 435 uint16_t fr; 436 437 fr = bus_space_read_4(iot, ioh, UART_FR); 438 if (ISSET(fr, UART_FR_TXFF)) 439 break; 440 441 bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq)); 442 } 443 444 out: 445 splx(s); 446 return; 447 448 stopped: 449 /* Disable transmit interrupt. */ 450 if (ISSET(sc->sc_imsc, UART_IMSC_TXIM)) { 451 sc->sc_imsc &= ~UART_IMSC_TXIM; 452 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, 453 sc->sc_imsc); 454 } 455 splx(s); 456 } 457 458 void 459 pluart_diag(void *arg) 460 { 461 struct pluart_softc *sc = arg; 462 int overflows, floods; 463 int s; 464 465 s = spltty(); 466 sc->sc_errors = 0; 467 overflows = sc->sc_overflows; 468 sc->sc_overflows = 0; 469 floods = sc->sc_floods; 470 sc->sc_floods = 0; 471 splx(s); 472 log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n", 473 sc->sc_dev.dv_xname, 474 overflows, overflows == 1 ? "" : "s", 475 floods, floods == 1 ? "" : "s"); 476 } 477 478 void 479 pluart_raisedtr(void *arg) 480 { 481 //struct pluart_softc *sc = arg; 482 483 //SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */ 484 //bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, sc->sc_ucr3); 485 } 486 487 void 488 pluart_softint(void *arg) 489 { 490 struct pluart_softc *sc = arg; 491 struct tty *tp; 492 u_int16_t *ibufp; 493 u_int16_t *ibufend; 494 int c; 495 int err; 496 int s; 497 498 if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf) 499 return; 500 501 tp = sc->sc_tty; 502 s = spltty(); 503 504 ibufp = sc->sc_ibuf; 505 ibufend = sc->sc_ibufp; 506 507 if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) { 508 splx(s); 509 return; 510 } 511 512 sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ? 513 sc->sc_ibufs[1] : sc->sc_ibufs[0]; 514 sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER; 515 sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE; 516 517 #if 0 518 if (ISSET(tp->t_cflag, CRTSCTS) && 519 !ISSET(sc->sc_ucr3, IMXUART_CR3_DSR)) { 520 /* XXX */ 521 SET(sc->sc_ucr3, IMXUART_CR3_DSR); 522 bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, 523 sc->sc_ucr3); 524 } 525 #endif 526 527 splx(s); 528 529 while (ibufp < ibufend) { 530 c = *ibufp++; 531 /* 532 if (ISSET(c, IMXUART_RX_OVERRUN)) { 533 sc->sc_overflows++; 534 if (sc->sc_errors++ == 0) 535 timeout_add_sec(&sc->sc_diag_tmo, 60); 536 } 537 */ 538 /* This is ugly, but fast. */ 539 540 err = 0; 541 /* 542 if (ISSET(c, IMXUART_RX_PRERR)) 543 err |= TTY_PE; 544 if (ISSET(c, IMXUART_RX_FRMERR)) 545 err |= TTY_FE; 546 */ 547 c = (c & 0xff) | err; 548 (*linesw[tp->t_line].l_rint)(c, tp); 549 } 550 } 551 552 int 553 pluartopen(dev_t dev, int flag, int mode, struct proc *p) 554 { 555 int unit = DEVUNIT(dev); 556 struct pluart_softc *sc; 557 bus_space_tag_t iot; 558 bus_space_handle_t ioh; 559 struct tty *tp; 560 int s; 561 int error = 0; 562 563 if (unit >= pluart_cd.cd_ndevs) 564 return ENXIO; 565 sc = pluart_cd.cd_devs[unit]; 566 if (sc == NULL) 567 return ENXIO; 568 569 s = spltty(); 570 if (sc->sc_tty == NULL) 571 tp = sc->sc_tty = ttymalloc(0); 572 else 573 tp = sc->sc_tty; 574 575 splx(s); 576 577 tp->t_oproc = pluart_start; 578 tp->t_param = pluart_param; 579 tp->t_dev = dev; 580 581 if (!ISSET(tp->t_state, TS_ISOPEN)) { 582 SET(tp->t_state, TS_WOPEN); 583 ttychars(tp); 584 tp->t_iflag = TTYDEF_IFLAG; 585 tp->t_oflag = TTYDEF_OFLAG; 586 587 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) 588 tp->t_cflag = pluartconscflag; 589 else 590 tp->t_cflag = TTYDEF_CFLAG; 591 if (ISSET(sc->sc_swflags, COM_SW_CLOCAL)) 592 SET(tp->t_cflag, CLOCAL); 593 if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS)) 594 SET(tp->t_cflag, CRTSCTS); 595 if (ISSET(sc->sc_swflags, COM_SW_MDMBUF)) 596 SET(tp->t_cflag, MDMBUF); 597 tp->t_lflag = TTYDEF_LFLAG; 598 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) 599 tp->t_ispeed = tp->t_ospeed = pluartconsrate; 600 else 601 tp->t_ispeed = tp->t_ospeed = pluartdefaultrate; 602 603 s = spltty(); 604 605 sc->sc_initialize = 1; 606 pluart_param(tp, &tp->t_termios); 607 ttsetwater(tp); 608 sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0]; 609 sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER; 610 sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE; 611 612 iot = sc->sc_iot; 613 ioh = sc->sc_ioh; 614 615 #if 0 616 sc->sc_ucr1 = bus_space_read_4(iot, ioh, IMXUART_UCR1); 617 sc->sc_ucr2 = bus_space_read_4(iot, ioh, IMXUART_UCR2); 618 sc->sc_ucr3 = bus_space_read_4(iot, ioh, IMXUART_UCR3); 619 sc->sc_ucr4 = bus_space_read_4(iot, ioh, IMXUART_UCR4); 620 621 /* interrupt after one char on tx/rx */ 622 /* reference frequency divider: 1 */ 623 bus_space_write_4(iot, ioh, IMXUART_UFCR, 624 1 << IMXUART_FCR_TXTL_SH | 625 5 << IMXUART_FCR_RFDIV_SH | 626 1 << IMXUART_FCR_RXTL_SH); 627 628 SET(sc->sc_ucr1, IMXUART_CR1_EN|IMXUART_CR1_RRDYEN); 629 SET(sc->sc_ucr2, IMXUART_CR2_TXEN|IMXUART_CR2_RXEN); 630 bus_space_write_4(iot, ioh, IMXUART_UCR1, sc->sc_ucr1); 631 bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2); 632 633 /* sc->sc_mcr = MCR_DTR | MCR_RTS; XXX */ 634 SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */ 635 bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3); 636 #endif 637 638 SET(tp->t_state, TS_CARR_ON); /* XXX */ 639 640 641 } else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0) 642 return EBUSY; 643 else 644 s = spltty(); 645 646 if (DEVCUA(dev)) { 647 if (ISSET(tp->t_state, TS_ISOPEN)) { 648 splx(s); 649 return EBUSY; 650 } 651 sc->sc_cua = 1; 652 } else { 653 /* tty (not cua) device; wait for carrier if necessary */ 654 if (ISSET(flag, O_NONBLOCK)) { 655 if (sc->sc_cua) { 656 /* Opening TTY non-blocking... but the CUA is busy */ 657 splx(s); 658 return EBUSY; 659 } 660 } else { 661 while (sc->sc_cua || 662 (!ISSET(tp->t_cflag, CLOCAL) && 663 !ISSET(tp->t_state, TS_CARR_ON))) { 664 SET(tp->t_state, TS_WOPEN); 665 error = ttysleep(tp, &tp->t_rawq, 666 TTIPRI | PCATCH, ttopen); 667 /* 668 * If TS_WOPEN has been reset, that means the 669 * cua device has been closed. We don't want 670 * to fail in that case, 671 * so just go around again. 672 */ 673 if (error && ISSET(tp->t_state, TS_WOPEN)) { 674 CLR(tp->t_state, TS_WOPEN); 675 splx(s); 676 return error; 677 } 678 } 679 } 680 } 681 splx(s); 682 return (*linesw[tp->t_line].l_open)(dev,tp,p); 683 } 684 685 int 686 pluartclose(dev_t dev, int flag, int mode, struct proc *p) 687 { 688 int unit = DEVUNIT(dev); 689 struct pluart_softc *sc = pluart_cd.cd_devs[unit]; 690 //bus_space_tag_t iot = sc->sc_iot; 691 //bus_space_handle_t ioh = sc->sc_ioh; 692 struct tty *tp = sc->sc_tty; 693 int s; 694 695 /* XXX This is for cons.c. */ 696 if (!ISSET(tp->t_state, TS_ISOPEN)) 697 return 0; 698 699 (*linesw[tp->t_line].l_close)(tp, flag, p); 700 s = spltty(); 701 if (ISSET(tp->t_state, TS_WOPEN)) { 702 /* tty device is waiting for carrier; drop dtr then re-raise */ 703 //CLR(sc->sc_ucr3, IMXUART_CR3_DSR); 704 //bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3); 705 timeout_add_sec(&sc->sc_dtr_tmo, 2); 706 } 707 CLR(tp->t_state, TS_BUSY | TS_FLUSH); 708 709 sc->sc_cua = 0; 710 splx(s); 711 ttyclose(tp); 712 713 return 0; 714 } 715 716 int 717 pluartread(dev_t dev, struct uio *uio, int flag) 718 { 719 struct tty *tty; 720 721 tty = pluarttty(dev); 722 if (tty == NULL) 723 return ENODEV; 724 725 return((*linesw[tty->t_line].l_read)(tty, uio, flag)); 726 } 727 728 int 729 pluartwrite(dev_t dev, struct uio *uio, int flag) 730 { 731 struct tty *tty; 732 733 tty = pluarttty(dev); 734 if (tty == NULL) 735 return ENODEV; 736 737 return((*linesw[tty->t_line].l_write)(tty, uio, flag)); 738 } 739 740 int 741 pluartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 742 { 743 struct pluart_softc *sc; 744 struct tty *tp; 745 int error; 746 747 sc = pluart_sc(dev); 748 if (sc == NULL) 749 return (ENODEV); 750 751 tp = sc->sc_tty; 752 if (tp == NULL) 753 return (ENXIO); 754 755 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 756 if (error >= 0) 757 return (error); 758 759 error = ttioctl(tp, cmd, data, flag, p); 760 if (error >= 0) 761 return (error); 762 763 switch(cmd) { 764 case TIOCSBRK: 765 break; 766 case TIOCCBRK: 767 break; 768 case TIOCSDTR: 769 break; 770 case TIOCCDTR: 771 break; 772 case TIOCMSET: 773 break; 774 case TIOCMBIS: 775 break; 776 case TIOCMBIC: 777 break; 778 case TIOCMGET: 779 break; 780 case TIOCGFLAGS: 781 break; 782 case TIOCSFLAGS: 783 error = suser(p); 784 if (error != 0) 785 return(EPERM); 786 break; 787 default: 788 return (ENOTTY); 789 } 790 791 return 0; 792 } 793 794 int 795 pluartstop(struct tty *tp, int flag) 796 { 797 return 0; 798 } 799 800 struct tty * 801 pluarttty(dev_t dev) 802 { 803 int unit; 804 struct pluart_softc *sc; 805 unit = DEVUNIT(dev); 806 if (unit >= pluart_cd.cd_ndevs) 807 return NULL; 808 sc = (struct pluart_softc *)pluart_cd.cd_devs[unit]; 809 if (sc == NULL) 810 return NULL; 811 return sc->sc_tty; 812 } 813 814 struct pluart_softc * 815 pluart_sc(dev_t dev) 816 { 817 int unit; 818 struct pluart_softc *sc; 819 unit = DEVUNIT(dev); 820 if (unit >= pluart_cd.cd_ndevs) 821 return NULL; 822 sc = (struct pluart_softc *)pluart_cd.cd_devs[unit]; 823 return sc; 824 } 825 826 827 /* serial console */ 828 void 829 pluartcnprobe(struct consdev *cp) 830 { 831 } 832 833 void 834 pluartcninit(struct consdev *cp) 835 { 836 } 837 838 int 839 pluartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag) 840 { 841 static struct consdev pluartcons = { 842 NULL, NULL, pluartcngetc, pluartcnputc, pluartcnpollc, NULL, 843 NODEV, CN_MIDPRI 844 }; 845 int maj; 846 847 if (bus_space_map(iot, iobase, UART_SPACE, 0, &pluartconsioh)) 848 return ENOMEM; 849 850 /* Disable FIFO. */ 851 bus_space_write_4(iot, pluartconsioh, UART_LCR_H, 852 bus_space_read_4(iot, pluartconsioh, UART_LCR_H) & ~UART_LCR_H_FEN); 853 854 /* Look for major of com(4) to replace. */ 855 for (maj = 0; maj < nchrdev; maj++) 856 if (cdevsw[maj].d_open == comopen) 857 break; 858 if (maj == nchrdev) 859 return ENXIO; 860 861 cn_tab = &pluartcons; 862 cn_tab->cn_dev = makedev(maj, 0); 863 cdevsw[maj] = pluartdev; /* KLUDGE */ 864 865 pluartconsiot = iot; 866 pluartconsaddr = iobase; 867 pluartconscflag = cflag; 868 pluartconsrate = rate; 869 870 return 0; 871 } 872 873 int 874 pluartcngetc(dev_t dev) 875 { 876 int c; 877 int s; 878 s = splhigh(); 879 while ((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) & 880 UART_FR_RXFE)) 881 ; 882 c = bus_space_read_4(pluartconsiot, pluartconsioh, UART_DR); 883 splx(s); 884 return c; 885 } 886 887 void 888 pluartcnputc(dev_t dev, int c) 889 { 890 int s; 891 s = splhigh(); 892 while ((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) & 893 UART_FR_TXFF)) 894 ; 895 bus_space_write_4(pluartconsiot, pluartconsioh, UART_DR, (uint8_t)c); 896 splx(s); 897 } 898 899 void 900 pluartcnpollc(dev_t dev, int on) 901 { 902 } 903