uart_dev_rt305x.c revision 220297
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: head/sys/mips/rt305x/uart_dev_rt305x.c 220297 2011-04-03 14:39:55Z adrian $"); 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 *); 198 199static kobj_method_t rt305x_uart_methods[] = { 200 KOBJMETHOD(uart_attach, rt305x_uart_bus_attach), 201 KOBJMETHOD(uart_detach, rt305x_uart_bus_detach), 202 KOBJMETHOD(uart_flush, rt305x_uart_bus_flush), 203 KOBJMETHOD(uart_getsig, rt305x_uart_bus_getsig), 204 KOBJMETHOD(uart_ioctl, rt305x_uart_bus_ioctl), 205 KOBJMETHOD(uart_ipend, rt305x_uart_bus_ipend), 206 KOBJMETHOD(uart_param, rt305x_uart_bus_param), 207 KOBJMETHOD(uart_probe, rt305x_uart_bus_probe), 208 KOBJMETHOD(uart_receive, rt305x_uart_bus_receive), 209 KOBJMETHOD(uart_setsig, rt305x_uart_bus_setsig), 210 KOBJMETHOD(uart_transmit, rt305x_uart_bus_transmit), 211 { 0, 0 } 212}; 213 214struct uart_class uart_rt305x_uart_class = { 215 "rt305x", 216 rt305x_uart_methods, 217 sizeof(struct rt305x_uart_softc), 218 .uc_ops = &uart_rt305x_uart_ops, 219 .uc_range = 1, /* use hinted range */ 220 .uc_rclk = SYSTEM_CLOCK 221}; 222 223#define SIGCHG(c, i, s, d) \ 224 if (c) { \ 225 i |= (i & s) ? s : s | d; \ 226 } else { \ 227 i = (i & s) ? (i & ~s) | d : i; \ 228 } 229 230/* 231 * Disable TX interrupt. uart should be locked 232 */ 233static __inline void 234rt305x_uart_disable_txintr(struct uart_softc *sc) 235{ 236 struct uart_bas *bas = &sc->sc_bas; 237 uint8_t cr; 238 239 cr = uart_getreg(bas, UART_IER_REG); 240 cr &= ~UART_IER_ETBEI; 241 uart_setreg(bas, UART_IER_REG, cr); 242 uart_barrier(bas); 243} 244 245/* 246 * Enable TX interrupt. uart should be locked 247 */ 248static __inline void 249rt305x_uart_enable_txintr(struct uart_softc *sc) 250{ 251 struct uart_bas *bas = &sc->sc_bas; 252 uint8_t cr; 253 254 cr = uart_getreg(bas, UART_IER_REG); 255 cr |= UART_IER_ETBEI; 256 uart_setreg(bas, UART_IER_REG, cr); 257 uart_barrier(bas); 258} 259 260static int 261rt305x_uart_bus_attach(struct uart_softc *sc) 262{ 263 struct uart_bas *bas; 264 struct uart_devinfo *di; 265 266 bas = &sc->sc_bas; 267 if (sc->sc_sysdev != NULL) { 268 di = sc->sc_sysdev; 269 rt305x_uart_init(bas, di->baudrate, di->databits, di->stopbits, 270 di->parity); 271 } else { 272 rt305x_uart_init(bas, 115200, 8, 1, 0); 273 } 274 275 sc->sc_rxfifosz = 16; 276 sc->sc_txfifosz = 16; 277 278 (void)rt305x_uart_bus_getsig(sc); 279 280 /* Enable FIFO */ 281 uart_setreg(bas, UART_FCR_REG, 282 uart_getreg(bas, UART_FCR_REG) | 283 UART_FCR_FIFOEN | UART_FCR_TXTGR_1 | UART_FCR_RXTGR_1); 284 uart_barrier(bas); 285 /* Enable interrupts */ 286 uart_setreg(bas, UART_IER_REG, 287 UART_IER_EDSSI | UART_IER_ELSI | UART_IER_ERBFI); 288 uart_barrier(bas); 289 290 return (0); 291} 292 293static int 294rt305x_uart_bus_detach(struct uart_softc *sc) 295{ 296 297 return (0); 298} 299 300static int 301rt305x_uart_bus_flush(struct uart_softc *sc, int what) 302{ 303 struct uart_bas *bas = &sc->sc_bas; 304 uint32_t fcr = uart_getreg(bas, UART_FCR_REG); 305 if (what & UART_FLUSH_TRANSMITTER) { 306 uart_setreg(bas, UART_FCR_REG, fcr|UART_FCR_TXRST); 307 uart_barrier(bas); 308 } 309 if (what & UART_FLUSH_RECEIVER) { 310 uart_setreg(bas, UART_FCR_REG, fcr|UART_FCR_RXRST); 311 uart_barrier(bas); 312 } 313 uart_setreg(bas, UART_FCR_REG, fcr); 314 uart_barrier(bas); 315 return (0); 316} 317 318static int 319rt305x_uart_bus_getsig(struct uart_softc *sc) 320{ 321 uint32_t new, old, sig; 322 uint8_t bes; 323 324 do { 325 old = sc->sc_hwsig; 326 sig = old; 327 uart_lock(sc->sc_hwmtx); 328 bes = uart_getreg(&sc->sc_bas, UART_MSR_REG); 329 uart_unlock(sc->sc_hwmtx); 330 /* XXX: chip can show delta */ 331 SIGCHG(bes & UART_MSR_CTS, sig, SER_CTS, SER_DCTS); 332 SIGCHG(bes & UART_MSR_DCD, sig, SER_DCD, SER_DDCD); 333 SIGCHG(bes & UART_MSR_DSR, sig, SER_DSR, SER_DDSR); 334 new = sig & ~SER_MASK_DELTA; 335 } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); 336 337 return (sig); 338} 339 340static int 341rt305x_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) 342{ 343 struct uart_bas *bas; 344 int baudrate, divisor, error; 345 346 bas = &sc->sc_bas; 347 error = 0; 348 uart_lock(sc->sc_hwmtx); 349 switch (request) { 350 case UART_IOCTL_BREAK: 351 /* TODO: Send BREAK */ 352 break; 353 case UART_IOCTL_BAUD: 354 divisor = uart_getreg(bas, UART_CDDL_REG); 355 baudrate = bas->rclk / (divisor * 16); 356 *(int*)data = baudrate; 357 break; 358 default: 359 error = EINVAL; 360 break; 361 } 362 uart_unlock(sc->sc_hwmtx); 363 return (error); 364} 365 366static int 367rt305x_uart_bus_ipend(struct uart_softc *sc) 368{ 369 struct uart_bas *bas; 370 int ipend; 371 uint8_t iir, lsr, msr; 372 373 bas = &sc->sc_bas; 374 ipend = 0; 375 376 uart_lock(sc->sc_hwmtx); 377 iir = uart_getreg(&sc->sc_bas, UART_IIR_REG); 378 lsr = uart_getreg(&sc->sc_bas, UART_LSR_REG); 379 uart_setreg(&sc->sc_bas, UART_LSR_REG, lsr); 380 msr = uart_getreg(&sc->sc_bas, UART_MSR_REG); 381 uart_setreg(&sc->sc_bas, UART_MSR_REG, msr); 382 if (iir & UART_IIR_INTP) { 383 uart_unlock(sc->sc_hwmtx); 384 return (0); 385 } 386 387 388 switch ((iir >> 1) & 0x07) { 389 case UART_IIR_ID_THRE: 390 ipend |= SER_INT_TXIDLE; 391 break; 392 case UART_IIR_ID_DR2: 393 rt305x_uart_bus_flush(sc, UART_FLUSH_RECEIVER); 394 /* passthrough */ 395 case UART_IIR_ID_DR: 396 ipend |= SER_INT_RXREADY; 397 break; 398 case UART_IIR_ID_MST: 399 case UART_IIR_ID_LINESTATUS: 400 ipend |= SER_INT_SIGCHG; 401 if (lsr & UART_LSR_BI) 402 { 403 ipend |= SER_INT_BREAK; 404#ifdef KDB 405 breakpoint(); 406#endif 407 } 408 if (lsr & UART_LSR_OE) 409 ipend |= SER_INT_OVERRUN; 410 break; 411 default: 412 /* XXX: maybe return error here */ 413 break; 414 } 415 416 uart_unlock(sc->sc_hwmtx); 417 418 return (ipend); 419} 420 421static int 422rt305x_uart_bus_param(struct uart_softc *sc, int baudrate, int databits, 423 int stopbits, int parity) 424{ 425 uart_lock(sc->sc_hwmtx); 426 rt305x_uart_init(&sc->sc_bas, baudrate, databits, stopbits, parity); 427 uart_unlock(sc->sc_hwmtx); 428 return (0); 429} 430 431static int 432rt305x_uart_bus_probe(struct uart_softc *sc) 433{ 434 char buf[80]; 435 int error; 436 437 error = rt305x_uart_probe(&sc->sc_bas); 438 if (error) 439 return (error); 440 441 snprintf(buf, sizeof(buf), "rt305x_uart"); 442 device_set_desc_copy(sc->sc_dev, buf); 443 444 return (0); 445} 446 447static int 448rt305x_uart_bus_receive(struct uart_softc *sc) 449{ 450 struct uart_bas *bas; 451 int xc; 452 uint8_t lsr; 453 454 bas = &sc->sc_bas; 455 uart_lock(sc->sc_hwmtx); 456 lsr = uart_getreg(bas, UART_LSR_REG); 457 while ((lsr & UART_LSR_DR)) { 458 if (uart_rx_full(sc)) { 459 sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; 460 break; 461 } 462 xc = 0; 463 xc = uart_getreg(bas, UART_RX_REG); 464 if (lsr & UART_LSR_FE) 465 xc |= UART_STAT_FRAMERR; 466 if (lsr & UART_LSR_PE) 467 xc |= UART_STAT_PARERR; 468 if (lsr & UART_LSR_OE) 469 xc |= UART_STAT_OVERRUN; 470 uart_barrier(bas); 471 uart_rx_put(sc, xc); 472 lsr = uart_getreg(bas, UART_LSR_REG); 473 } 474 475 uart_unlock(sc->sc_hwmtx); 476 return (0); 477} 478 479static int 480rt305x_uart_bus_setsig(struct uart_softc *sc, int sig) 481{ 482 483 /* TODO: implement (?) */ 484 return (0); 485} 486 487static int 488rt305x_uart_bus_transmit(struct uart_softc *sc) 489{ 490 struct uart_bas *bas = &sc->sc_bas; 491 int i; 492 493 if (!uart_output) return (0); 494 495 bas = &sc->sc_bas; 496 uart_lock(sc->sc_hwmtx); 497 while ((uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE) == 0) 498 ; 499 rt305x_uart_enable_txintr(sc); 500 for (i = 0; i < sc->sc_txdatasz; i++) { 501 uart_setreg(bas, UART_TX_REG, sc->sc_txbuf[i]); 502 uart_barrier(bas); 503 } 504 sc->sc_txbusy = 1; 505 uart_unlock(sc->sc_hwmtx); 506 return (0); 507} 508