uart_dev_rt305x.c revision 262649
1/* $NetBSD: uart.c,v 1.2 2007/03/23 20:05:47 dogcow Exp $ */ 2 3/*- 4 * Copyright (c) 2010 Aleksandr Rybalko. 5 * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko. 6 * Copyright (c) 2007 Oleksandr Tymoshenko. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or 10 * without modification, are permitted provided that the following 11 * conditions 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 15 * copyright notice, this list of conditions and the following 16 * disclaimer in the documentation and/or other materials provided 17 * with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 24 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 26 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 28 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 30 * OF SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD: stable/10/sys/mips/rt305x/uart_dev_rt305x.c 262649 2014-03-01 04:16:54Z imp $"); 35 36#include "opt_ddb.h" 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/bus.h> 41#include <sys/conf.h> 42#include <sys/kdb.h> 43#include <sys/reboot.h> 44#include <sys/sysctl.h> 45#include <sys/kernel.h> 46#include <machine/bus.h> 47 48#include <dev/uart/uart.h> 49#include <dev/uart/uart_cpu.h> 50#include <dev/uart/uart_bus.h> 51 52#include <mips/rt305x/uart_dev_rt305x.h> 53#include <mips/rt305x/rt305xreg.h> 54 55#include "uart_if.h" 56/* 57 * Low-level UART interface. 58 */ 59static int rt305x_uart_probe(struct uart_bas *bas); 60static void rt305x_uart_init(struct uart_bas *bas, int, int, int, int); 61static void rt305x_uart_term(struct uart_bas *bas); 62static void rt305x_uart_putc(struct uart_bas *bas, int); 63static int rt305x_uart_rxready(struct uart_bas *bas); 64static int rt305x_uart_getc(struct uart_bas *bas, struct mtx *); 65 66static struct uart_ops uart_rt305x_uart_ops = { 67 .probe = rt305x_uart_probe, 68 .init = rt305x_uart_init, 69 .term = rt305x_uart_term, 70 .putc = rt305x_uart_putc, 71 .rxready = rt305x_uart_rxready, 72 .getc = rt305x_uart_getc, 73}; 74 75static int uart_output = 1; 76TUNABLE_INT("kern.uart_output", &uart_output); 77SYSCTL_INT(_kern, OID_AUTO, uart_output, CTLFLAG_RW, 78 &uart_output, 0, "UART output enabled."); 79 80 81 82 83static int 84rt305x_uart_probe(struct uart_bas *bas) 85{ 86 87 return (0); 88} 89 90static void 91rt305x_uart_init(struct uart_bas *bas, int baudrate, int databits, 92 int stopbits, int parity) 93{ 94#ifdef notyet 95 /* CLKDIV = 384000000/ 3/ 16/ br */ 96 /* for 384MHz CLKDIV = 8000000 / baudrate; */ 97 switch (databits) { 98 case 5: 99 databits = UART_LCR_5B; 100 break; 101 case 6: 102 databits = UART_LCR_6B; 103 break; 104 case 7: 105 databits = UART_LCR_7B; 106 break; 107 case 8: 108 databits = UART_LCR_8B; 109 break; 110 default: 111 /* Unsupported */ 112 return; 113 } 114 switch (parity) { 115 case UART_PARITY_EVEN: parity = (UART_LCR_PEN|UART_LCR_EVEN); break; 116 case UART_PARITY_NONE: parity = (UART_LCR_PEN); break; 117 case UART_PARITY_ODD: parity = 0; break; 118 /* Unsupported */ 119 default: return; 120 } 121 uart_setreg(bas, UART_CDDL_REG, 8000000/baudrate); 122 uart_barrier(bas); 123 uart_setreg(bas, UART_LCR_REG, databits | (stopbits==1?0:4) | parity); 124 uart_barrier(bas); 125#endif 126} 127 128static void 129rt305x_uart_term(struct uart_bas *bas) 130{ 131 uart_setreg(bas, UART_MCR_REG, 0); 132 uart_barrier(bas); 133} 134 135static void 136rt305x_uart_putc(struct uart_bas *bas, int c) 137{ 138 char chr; 139 if (!uart_output) return; 140 chr = c; 141 while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE)); 142 uart_setreg(bas, UART_TX_REG, c); 143 uart_barrier(bas); 144 while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE)); 145} 146 147static int 148rt305x_uart_rxready(struct uart_bas *bas) 149{ 150#ifdef notyet 151 if (uart_getreg(bas, UART_LSR_REG) & UART_LSR_DR) 152 return (1); 153 154 return (0); 155#else 156 return (1); 157#endif 158} 159 160static int 161rt305x_uart_getc(struct uart_bas *bas, struct mtx *hwmtx) 162{ 163 int c; 164 165 uart_lock(hwmtx); 166 167 while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_DR)) { 168 uart_unlock(hwmtx); 169 DELAY(10); 170 uart_lock(hwmtx); 171 } 172 173 c = uart_getreg(bas, UART_RX_REG); 174 175 uart_unlock(hwmtx); 176 177 return (c); 178} 179 180/* 181 * High-level UART interface. 182 */ 183struct rt305x_uart_softc { 184 struct uart_softc base; 185}; 186 187static int rt305x_uart_bus_attach(struct uart_softc *); 188static int rt305x_uart_bus_detach(struct uart_softc *); 189static int rt305x_uart_bus_flush(struct uart_softc *, int); 190static int rt305x_uart_bus_getsig(struct uart_softc *); 191static int rt305x_uart_bus_ioctl(struct uart_softc *, int, intptr_t); 192static int rt305x_uart_bus_ipend(struct uart_softc *); 193static int rt305x_uart_bus_param(struct uart_softc *, int, int, int, int); 194static int rt305x_uart_bus_probe(struct uart_softc *); 195static int rt305x_uart_bus_receive(struct uart_softc *); 196static int rt305x_uart_bus_setsig(struct uart_softc *, int); 197static int rt305x_uart_bus_transmit(struct uart_softc *); 198static void rt305x_uart_bus_grab(struct uart_softc *); 199static void rt305x_uart_bus_ungrab(struct uart_softc *); 200 201static kobj_method_t rt305x_uart_methods[] = { 202 KOBJMETHOD(uart_attach, rt305x_uart_bus_attach), 203 KOBJMETHOD(uart_detach, rt305x_uart_bus_detach), 204 KOBJMETHOD(uart_flush, rt305x_uart_bus_flush), 205 KOBJMETHOD(uart_getsig, rt305x_uart_bus_getsig), 206 KOBJMETHOD(uart_ioctl, rt305x_uart_bus_ioctl), 207 KOBJMETHOD(uart_ipend, rt305x_uart_bus_ipend), 208 KOBJMETHOD(uart_param, rt305x_uart_bus_param), 209 KOBJMETHOD(uart_probe, rt305x_uart_bus_probe), 210 KOBJMETHOD(uart_receive, rt305x_uart_bus_receive), 211 KOBJMETHOD(uart_setsig, rt305x_uart_bus_setsig), 212 KOBJMETHOD(uart_transmit, rt305x_uart_bus_transmit), 213 KOBJMETHOD(uart_grab, rt305x_uart_bus_grab), 214 KOBJMETHOD(uart_ungrab, rt305x_uart_bus_ungrab), 215 { 0, 0 } 216}; 217 218struct uart_class uart_rt305x_uart_class = { 219 "rt305x", 220 rt305x_uart_methods, 221 sizeof(struct rt305x_uart_softc), 222 .uc_ops = &uart_rt305x_uart_ops, 223 .uc_range = 1, /* use hinted range */ 224 .uc_rclk = SYSTEM_CLOCK 225}; 226 227#define SIGCHG(c, i, s, d) \ 228 if (c) { \ 229 i |= (i & s) ? s : s | d; \ 230 } else { \ 231 i = (i & s) ? (i & ~s) | d : i; \ 232 } 233 234/* 235 * Disable TX interrupt. uart should be locked 236 */ 237static __inline void 238rt305x_uart_disable_txintr(struct uart_softc *sc) 239{ 240 struct uart_bas *bas = &sc->sc_bas; 241 uint8_t cr; 242 243 cr = uart_getreg(bas, UART_IER_REG); 244 cr &= ~UART_IER_ETBEI; 245 uart_setreg(bas, UART_IER_REG, cr); 246 uart_barrier(bas); 247} 248 249/* 250 * Enable TX interrupt. uart should be locked 251 */ 252static __inline void 253rt305x_uart_enable_txintr(struct uart_softc *sc) 254{ 255 struct uart_bas *bas = &sc->sc_bas; 256 uint8_t cr; 257 258 cr = uart_getreg(bas, UART_IER_REG); 259 cr |= UART_IER_ETBEI; 260 uart_setreg(bas, UART_IER_REG, cr); 261 uart_barrier(bas); 262} 263 264static int 265rt305x_uart_bus_attach(struct uart_softc *sc) 266{ 267 struct uart_bas *bas; 268 struct uart_devinfo *di; 269 270 bas = &sc->sc_bas; 271 if (sc->sc_sysdev != NULL) { 272 di = sc->sc_sysdev; 273 rt305x_uart_init(bas, di->baudrate, di->databits, di->stopbits, 274 di->parity); 275 } else { 276 rt305x_uart_init(bas, 115200, 8, 1, 0); 277 } 278 279 (void)rt305x_uart_bus_getsig(sc); 280 281 /* Enable FIFO */ 282 uart_setreg(bas, UART_FCR_REG, 283 uart_getreg(bas, UART_FCR_REG) | 284 UART_FCR_FIFOEN | UART_FCR_TXTGR_1 | UART_FCR_RXTGR_1); 285 uart_barrier(bas); 286 /* Enable interrupts */ 287 uart_setreg(bas, UART_IER_REG, 288 UART_IER_EDSSI | UART_IER_ELSI | UART_IER_ERBFI); 289 uart_barrier(bas); 290 291 return (0); 292} 293 294static int 295rt305x_uart_bus_detach(struct uart_softc *sc) 296{ 297 298 return (0); 299} 300 301static int 302rt305x_uart_bus_flush(struct uart_softc *sc, int what) 303{ 304 struct uart_bas *bas = &sc->sc_bas; 305 uint32_t fcr = uart_getreg(bas, UART_FCR_REG); 306 if (what & UART_FLUSH_TRANSMITTER) { 307 uart_setreg(bas, UART_FCR_REG, fcr|UART_FCR_TXRST); 308 uart_barrier(bas); 309 } 310 if (what & UART_FLUSH_RECEIVER) { 311 uart_setreg(bas, UART_FCR_REG, fcr|UART_FCR_RXRST); 312 uart_barrier(bas); 313 } 314 uart_setreg(bas, UART_FCR_REG, fcr); 315 uart_barrier(bas); 316 return (0); 317} 318 319static int 320rt305x_uart_bus_getsig(struct uart_softc *sc) 321{ 322 uint32_t new, old, sig; 323 uint8_t bes; 324 325 do { 326 old = sc->sc_hwsig; 327 sig = old; 328 uart_lock(sc->sc_hwmtx); 329 bes = uart_getreg(&sc->sc_bas, UART_MSR_REG); 330 uart_unlock(sc->sc_hwmtx); 331 /* XXX: chip can show delta */ 332 SIGCHG(bes & UART_MSR_CTS, sig, SER_CTS, SER_DCTS); 333 SIGCHG(bes & UART_MSR_DCD, sig, SER_DCD, SER_DDCD); 334 SIGCHG(bes & UART_MSR_DSR, sig, SER_DSR, SER_DDSR); 335 new = sig & ~SER_MASK_DELTA; 336 } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); 337 338 return (sig); 339} 340 341static int 342rt305x_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) 343{ 344 struct uart_bas *bas; 345 int baudrate, divisor, error; 346 347 bas = &sc->sc_bas; 348 error = 0; 349 uart_lock(sc->sc_hwmtx); 350 switch (request) { 351 case UART_IOCTL_BREAK: 352 /* TODO: Send BREAK */ 353 break; 354 case UART_IOCTL_BAUD: 355 divisor = uart_getreg(bas, UART_CDDL_REG); 356 baudrate = bas->rclk / (divisor * 16); 357 *(int*)data = baudrate; 358 break; 359 default: 360 error = EINVAL; 361 break; 362 } 363 uart_unlock(sc->sc_hwmtx); 364 return (error); 365} 366 367static int 368rt305x_uart_bus_ipend(struct uart_softc *sc) 369{ 370 struct uart_bas *bas; 371 int ipend; 372 uint8_t iir, lsr, msr; 373 374 bas = &sc->sc_bas; 375 ipend = 0; 376 377 uart_lock(sc->sc_hwmtx); 378 iir = uart_getreg(&sc->sc_bas, UART_IIR_REG); 379 lsr = uart_getreg(&sc->sc_bas, UART_LSR_REG); 380 uart_setreg(&sc->sc_bas, UART_LSR_REG, lsr); 381 msr = uart_getreg(&sc->sc_bas, UART_MSR_REG); 382 uart_setreg(&sc->sc_bas, UART_MSR_REG, msr); 383 if (iir & UART_IIR_INTP) { 384 uart_unlock(sc->sc_hwmtx); 385 return (0); 386 } 387 388 389 switch ((iir >> 1) & 0x07) { 390 case UART_IIR_ID_THRE: 391 ipend |= SER_INT_TXIDLE; 392 break; 393 case UART_IIR_ID_DR2: 394 rt305x_uart_bus_flush(sc, UART_FLUSH_RECEIVER); 395 /* passthrough */ 396 case UART_IIR_ID_DR: 397 ipend |= SER_INT_RXREADY; 398 break; 399 case UART_IIR_ID_MST: 400 case UART_IIR_ID_LINESTATUS: 401 ipend |= SER_INT_SIGCHG; 402 if (lsr & UART_LSR_BI) 403 { 404 ipend |= SER_INT_BREAK; 405#ifdef KDB 406 breakpoint(); 407#endif 408 } 409 if (lsr & UART_LSR_OE) 410 ipend |= SER_INT_OVERRUN; 411 break; 412 default: 413 /* XXX: maybe return error here */ 414 break; 415 } 416 417 uart_unlock(sc->sc_hwmtx); 418 419 return (ipend); 420} 421 422static int 423rt305x_uart_bus_param(struct uart_softc *sc, int baudrate, int databits, 424 int stopbits, int parity) 425{ 426 uart_lock(sc->sc_hwmtx); 427 rt305x_uart_init(&sc->sc_bas, baudrate, databits, stopbits, parity); 428 uart_unlock(sc->sc_hwmtx); 429 return (0); 430} 431 432static int 433rt305x_uart_bus_probe(struct uart_softc *sc) 434{ 435 char buf[80]; 436 int error; 437 438 error = rt305x_uart_probe(&sc->sc_bas); 439 if (error) 440 return (error); 441 442 sc->sc_rxfifosz = 16; 443 sc->sc_txfifosz = 16; 444 445 snprintf(buf, sizeof(buf), "rt305x_uart"); 446 device_set_desc_copy(sc->sc_dev, buf); 447 448 return (0); 449} 450 451static int 452rt305x_uart_bus_receive(struct uart_softc *sc) 453{ 454 struct uart_bas *bas; 455 int xc; 456 uint8_t lsr; 457 458 bas = &sc->sc_bas; 459 uart_lock(sc->sc_hwmtx); 460 lsr = uart_getreg(bas, UART_LSR_REG); 461 while ((lsr & UART_LSR_DR)) { 462 if (uart_rx_full(sc)) { 463 sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; 464 break; 465 } 466 xc = 0; 467 xc = uart_getreg(bas, UART_RX_REG); 468 if (lsr & UART_LSR_FE) 469 xc |= UART_STAT_FRAMERR; 470 if (lsr & UART_LSR_PE) 471 xc |= UART_STAT_PARERR; 472 if (lsr & UART_LSR_OE) 473 xc |= UART_STAT_OVERRUN; 474 uart_barrier(bas); 475 uart_rx_put(sc, xc); 476 lsr = uart_getreg(bas, UART_LSR_REG); 477 } 478 479 uart_unlock(sc->sc_hwmtx); 480 return (0); 481} 482 483static int 484rt305x_uart_bus_setsig(struct uart_softc *sc, int sig) 485{ 486 487 /* TODO: implement (?) */ 488 return (0); 489} 490 491static int 492rt305x_uart_bus_transmit(struct uart_softc *sc) 493{ 494 struct uart_bas *bas = &sc->sc_bas; 495 int i; 496 497 if (!uart_output) return (0); 498 499 bas = &sc->sc_bas; 500 uart_lock(sc->sc_hwmtx); 501 while ((uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE) == 0) 502 ; 503 rt305x_uart_enable_txintr(sc); 504 for (i = 0; i < sc->sc_txdatasz; i++) { 505 uart_setreg(bas, UART_TX_REG, sc->sc_txbuf[i]); 506 uart_barrier(bas); 507 } 508 sc->sc_txbusy = 1; 509 uart_unlock(sc->sc_hwmtx); 510 return (0); 511} 512 513static void 514rt305x_uart_bus_grab(struct uart_softc *sc) 515{ 516 struct uart_bas *bas = &sc->sc_bas; 517 518 /* disable interrupts -- XXX not sure which one is RX, so kill them all */ 519 uart_lock(sc->sc_hwmtx); 520 uart_setreg(bas, UART_IER_REG, 0); 521 uart_barrier(bas); 522 uart_unlock(sc->sc_hwmtx); 523} 524 525static void 526rt305x_uart_bus_ungrab(struct uart_softc *sc) 527{ 528 struct uart_bas *bas = &sc->sc_bas; 529 530 /* Enable interrupts */ 531 uart_lock(sc->sc_hwmtx); 532 uart_setreg(bas, UART_IER_REG, 533 UART_IER_EDSSI | UART_IER_ELSI | UART_IER_ERBFI); 534 uart_barrier(bas); 535 uart_unlock(sc->sc_hwmtx); 536} 537