1/*- 2 * Copyright (c) 2012 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Oleksandr Rybalko under sponsorship 6 * from the FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD$"); 32 33#include "opt_ddb.h" 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/bus.h> 38#include <sys/conf.h> 39#include <sys/kdb.h> 40#include <machine/bus.h> 41#include <machine/fdt.h> 42 43#include <dev/uart/uart.h> 44#include <dev/uart/uart_cpu.h> 45#include <dev/uart/uart_bus.h> 46#include <dev/uart/uart_dev_imx.h> 47#include "uart_if.h" 48 49#include <arm/freescale/imx/imx_ccmvar.h> 50 51/* 52 * Low-level UART interface. 53 */ 54static int imx_uart_probe(struct uart_bas *bas); 55static void imx_uart_init(struct uart_bas *bas, int, int, int, int); 56static void imx_uart_term(struct uart_bas *bas); 57static void imx_uart_putc(struct uart_bas *bas, int); 58static int imx_uart_rxready(struct uart_bas *bas); 59static int imx_uart_getc(struct uart_bas *bas, struct mtx *); 60 61static struct uart_ops uart_imx_uart_ops = { 62 .probe = imx_uart_probe, 63 .init = imx_uart_init, 64 .term = imx_uart_term, 65 .putc = imx_uart_putc, 66 .rxready = imx_uart_rxready, 67 .getc = imx_uart_getc, 68}; 69 70#if 0 /* Handy when debugging. */ 71static void 72dumpregs(struct uart_bas *bas, const char * msg) 73{ 74 75 if (!bootverbose) 76 return; 77 printf("%s bsh 0x%08lx UCR1 0x%08x UCR2 0x%08x " 78 "UCR3 0x%08x UCR4 0x%08x USR1 0x%08x USR2 0x%08x\n", 79 msg, bas->bsh, 80 GETREG(bas, REG(UCR1)), GETREG(bas, REG(UCR2)), 81 GETREG(bas, REG(UCR3)), GETREG(bas, REG(UCR4)), 82 GETREG(bas, REG(USR1)), GETREG(bas, REG(USR2))); 83} 84#endif 85 86static int 87imx_uart_probe(struct uart_bas *bas) 88{ 89 90 return (0); 91} 92 93static void 94imx_uart_init(struct uart_bas *bas, int baudrate, int databits, 95 int stopbits, int parity) 96{ 97 uint32_t baseclk, reg; 98 99 /* Enable the device and the RX/TX channels. */ 100 SET(bas, REG(UCR1), FLD(UCR1, UARTEN)); 101 SET(bas, REG(UCR2), FLD(UCR2, RXEN) | FLD(UCR2, TXEN)); 102 103 if (databits == 7) 104 DIS(bas, UCR2, WS); 105 else 106 ENA(bas, UCR2, WS); 107 108 if (stopbits == 2) 109 ENA(bas, UCR2, STPB); 110 else 111 DIS(bas, UCR2, STPB); 112 113 switch (parity) { 114 case UART_PARITY_ODD: 115 DIS(bas, UCR2, PROE); 116 ENA(bas, UCR2, PREN); 117 break; 118 case UART_PARITY_EVEN: 119 ENA(bas, UCR2, PROE); 120 ENA(bas, UCR2, PREN); 121 break; 122 case UART_PARITY_MARK: 123 case UART_PARITY_SPACE: 124 /* FALLTHROUGH: Hardware doesn't support mark/space. */ 125 case UART_PARITY_NONE: 126 default: 127 DIS(bas, UCR2, PREN); 128 break; 129 } 130 131 /* 132 * The hardware has an extremely flexible baud clock: it allows setting 133 * both the numerator and denominator of the divider, as well as a 134 * separate pre-divider. We simplify the problem of coming up with a 135 * workable pair of numbers by assuming a pre-divider and numerator of 136 * one because our base clock is so fast we can reach virtually any 137 * reasonable speed with a simple divisor. The numerator value actually 138 * includes the 16x over-sampling (so a value of 16 means divide by 1); 139 * the register value is the numerator-1, so we have a hard-coded 15. 140 * Note that a quirk of the hardware requires that both UBIR and UBMR be 141 * set back to back in order for the change to take effect. 142 */ 143 if (baudrate > 0) { 144 baseclk = imx_ccm_uart_hz(); 145 reg = GETREG(bas, REG(UFCR)); 146 reg = (reg & ~IMXUART_UFCR_RFDIV_MASK) | IMXUART_UFCR_RFDIV_DIV1; 147 SETREG(bas, REG(UFCR), reg); 148 SETREG(bas, REG(UBIR), 15); 149 SETREG(bas, REG(UBMR), (baseclk / baudrate) - 1); 150 } 151} 152 153static void 154imx_uart_term(struct uart_bas *bas) 155{ 156 157} 158 159static void 160imx_uart_putc(struct uart_bas *bas, int c) 161{ 162 163 while (!(IS(bas, USR2, TXFE))) 164 ; 165 SETREG(bas, REG(UTXD), c); 166} 167 168static int 169imx_uart_rxready(struct uart_bas *bas) 170{ 171 172 return ((IS(bas, USR2, RDR)) ? 1 : 0); 173} 174 175static int 176imx_uart_getc(struct uart_bas *bas, struct mtx *hwmtx) 177{ 178 int c; 179 180 uart_lock(hwmtx); 181 while (!(IS(bas, USR2, RDR))) 182 ; 183 184 c = GETREG(bas, REG(URXD)); 185 uart_unlock(hwmtx); 186#if defined(KDB) 187 if (c & FLD(URXD, BRK)) { 188 if (kdb_break()) 189 return (0); 190 } 191#endif 192 return (c & 0xff); 193} 194 195/* 196 * High-level UART interface. 197 */ 198struct imx_uart_softc { 199 struct uart_softc base; 200}; 201 202static int imx_uart_bus_attach(struct uart_softc *); 203static int imx_uart_bus_detach(struct uart_softc *); 204static int imx_uart_bus_flush(struct uart_softc *, int); 205static int imx_uart_bus_getsig(struct uart_softc *); 206static int imx_uart_bus_ioctl(struct uart_softc *, int, intptr_t); 207static int imx_uart_bus_ipend(struct uart_softc *); 208static int imx_uart_bus_param(struct uart_softc *, int, int, int, int); 209static int imx_uart_bus_probe(struct uart_softc *); 210static int imx_uart_bus_receive(struct uart_softc *); 211static int imx_uart_bus_setsig(struct uart_softc *, int); 212static int imx_uart_bus_transmit(struct uart_softc *); 213static void imx_uart_bus_grab(struct uart_softc *); 214static void imx_uart_bus_ungrab(struct uart_softc *); 215 216static kobj_method_t imx_uart_methods[] = { 217 KOBJMETHOD(uart_attach, imx_uart_bus_attach), 218 KOBJMETHOD(uart_detach, imx_uart_bus_detach), 219 KOBJMETHOD(uart_flush, imx_uart_bus_flush), 220 KOBJMETHOD(uart_getsig, imx_uart_bus_getsig), 221 KOBJMETHOD(uart_ioctl, imx_uart_bus_ioctl), 222 KOBJMETHOD(uart_ipend, imx_uart_bus_ipend), 223 KOBJMETHOD(uart_param, imx_uart_bus_param), 224 KOBJMETHOD(uart_probe, imx_uart_bus_probe), 225 KOBJMETHOD(uart_receive, imx_uart_bus_receive), 226 KOBJMETHOD(uart_setsig, imx_uart_bus_setsig), 227 KOBJMETHOD(uart_transmit, imx_uart_bus_transmit), 228 KOBJMETHOD(uart_grab, imx_uart_bus_grab), 229 KOBJMETHOD(uart_ungrab, imx_uart_bus_ungrab), 230 { 0, 0 } 231}; 232 233struct uart_class uart_imx_class = { 234 "imx", 235 imx_uart_methods, 236 sizeof(struct imx_uart_softc), 237 .uc_ops = &uart_imx_uart_ops, 238 .uc_range = 0x100, 239 .uc_rclk = 24000000 /* TODO: get value from CCM */ 240}; 241 242#define SIGCHG(c, i, s, d) \ 243 if (c) { \ 244 i |= (i & s) ? s : s | d; \ 245 } else { \ 246 i = (i & s) ? (i & ~s) | d : i; \ 247 } 248 249static int 250imx_uart_bus_attach(struct uart_softc *sc) 251{ 252 struct uart_bas *bas; 253 struct uart_devinfo *di; 254 255 bas = &sc->sc_bas; 256 if (sc->sc_sysdev != NULL) { 257 di = sc->sc_sysdev; 258 imx_uart_init(bas, di->baudrate, di->databits, di->stopbits, 259 di->parity); 260 } else { 261 imx_uart_init(bas, 115200, 8, 1, 0); 262 } 263 264 (void)imx_uart_bus_getsig(sc); 265 266 ENA(bas, UCR4, DREN); 267 DIS(bas, UCR1, RRDYEN); 268 DIS(bas, UCR1, IDEN); 269 DIS(bas, UCR3, RXDSEN); 270 DIS(bas, UCR2, ATEN); 271 DIS(bas, UCR1, TXMPTYEN); 272 DIS(bas, UCR1, TRDYEN); 273 DIS(bas, UCR4, TCEN); 274 DIS(bas, UCR4, OREN); 275 ENA(bas, UCR4, BKEN); 276 DIS(bas, UCR4, WKEN); 277 DIS(bas, UCR1, ADEN); 278 DIS(bas, UCR3, ACIEN); 279 DIS(bas, UCR2, ESCI); 280 DIS(bas, UCR4, ENIRI); 281 DIS(bas, UCR3, AIRINTEN); 282 DIS(bas, UCR3, AWAKEN); 283 DIS(bas, UCR3, FRAERREN); 284 DIS(bas, UCR3, PARERREN); 285 DIS(bas, UCR1, RTSDEN); 286 DIS(bas, UCR2, RTSEN); 287 DIS(bas, UCR3, DTREN); 288 DIS(bas, UCR3, RI); 289 DIS(bas, UCR3, DCD); 290 DIS(bas, UCR3, DTRDEN); 291 ENA(bas, UCR2, IRTS); 292 ENA(bas, UCR3, RXDMUXSEL); 293 294 /* ACK all interrupts */ 295 SETREG(bas, REG(USR1), 0xffff); 296 SETREG(bas, REG(USR2), 0xffff); 297 return (0); 298} 299 300static int 301imx_uart_bus_detach(struct uart_softc *sc) 302{ 303 304 SETREG(&sc->sc_bas, REG(UCR4), 0); 305 306 return (0); 307} 308 309static int 310imx_uart_bus_flush(struct uart_softc *sc, int what) 311{ 312 313 /* TODO */ 314 return (0); 315} 316 317static int 318imx_uart_bus_getsig(struct uart_softc *sc) 319{ 320 uint32_t new, old, sig; 321 uint8_t bes; 322 323 do { 324 old = sc->sc_hwsig; 325 sig = old; 326 uart_lock(sc->sc_hwmtx); 327 bes = GETREG(&sc->sc_bas, REG(USR2)); 328 uart_unlock(sc->sc_hwmtx); 329 /* XXX: chip can show delta */ 330 SIGCHG(bes & FLD(USR2, DCDIN), sig, SER_DCD, SER_DDCD); 331 new = sig & ~SER_MASK_DELTA; 332 } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); 333 334 return (sig); 335} 336 337static int 338imx_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) 339{ 340 struct uart_bas *bas; 341 int error; 342 343 bas = &sc->sc_bas; 344 error = 0; 345 uart_lock(sc->sc_hwmtx); 346 switch (request) { 347 case UART_IOCTL_BREAK: 348 /* TODO */ 349 break; 350 case UART_IOCTL_BAUD: 351 /* TODO */ 352 *(int*)data = 115200; 353 break; 354 default: 355 error = EINVAL; 356 break; 357 } 358 uart_unlock(sc->sc_hwmtx); 359 360 return (error); 361} 362 363static int 364imx_uart_bus_ipend(struct uart_softc *sc) 365{ 366 struct uart_bas *bas; 367 int ipend; 368 uint32_t usr1, usr2; 369 uint32_t ucr1, ucr4; 370 371 bas = &sc->sc_bas; 372 ipend = 0; 373 374 uart_lock(sc->sc_hwmtx); 375 376 /* Read pending interrupts */ 377 usr1 = GETREG(bas, REG(USR1)); 378 usr2 = GETREG(bas, REG(USR2)); 379 /* ACK interrupts */ 380 SETREG(bas, REG(USR1), usr1); 381 SETREG(bas, REG(USR2), usr2); 382 383 ucr1 = GETREG(bas, REG(UCR1)); 384 ucr4 = GETREG(bas, REG(UCR4)); 385 386 if ((usr2 & FLD(USR2, TXFE)) && (ucr1 & FLD(UCR1, TXMPTYEN))) { 387 DIS(bas, UCR1, TXMPTYEN); 388 /* Continue TXing */ 389 ipend |= SER_INT_TXIDLE; 390 } 391 if ((usr2 & FLD(USR2, RDR)) && (ucr4 & FLD(UCR4, DREN))) { 392 DIS(bas, UCR4, DREN); 393 /* Wow, new char on input */ 394 ipend |= SER_INT_RXREADY; 395 } 396 if ((usr2 & FLD(USR2, BRCD)) && (ucr4 & FLD(UCR4, BKEN))) 397 ipend |= SER_INT_BREAK; 398 399 uart_unlock(sc->sc_hwmtx); 400 401 return (ipend); 402} 403 404static int 405imx_uart_bus_param(struct uart_softc *sc, int baudrate, int databits, 406 int stopbits, int parity) 407{ 408 409 uart_lock(sc->sc_hwmtx); 410 imx_uart_init(&sc->sc_bas, baudrate, databits, stopbits, parity); 411 uart_unlock(sc->sc_hwmtx); 412 return (0); 413} 414 415static int 416imx_uart_bus_probe(struct uart_softc *sc) 417{ 418 int error; 419 420 error = imx_uart_probe(&sc->sc_bas); 421 if (error) 422 return (error); 423 424 sc->sc_rxfifosz = 1; 425 sc->sc_txfifosz = 1; 426 427 device_set_desc(sc->sc_dev, "Freescale i.MX UART"); 428 return (0); 429} 430 431static int 432imx_uart_bus_receive(struct uart_softc *sc) 433{ 434 struct uart_bas *bas; 435 int xc, out; 436 437 bas = &sc->sc_bas; 438 uart_lock(sc->sc_hwmtx); 439 440 /* Read while we have anything in FIFO */ 441 while (IS(bas, USR2, RDR)) { 442 if (uart_rx_full(sc)) { 443 /* No space left in input buffer */ 444 sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; 445 break; 446 } 447 out = 0; 448 xc = GETREG(bas, REG(URXD)); 449 450 /* We have valid char */ 451 if (xc & FLD(URXD, CHARRDY)) 452 out = xc & 0x000000ff; 453 454 if (xc & FLD(URXD, FRMERR)) 455 out |= UART_STAT_FRAMERR; 456 if (xc & FLD(URXD, PRERR)) 457 out |= UART_STAT_PARERR; 458 if (xc & FLD(URXD, OVRRUN)) 459 out |= UART_STAT_OVERRUN; 460 if (xc & FLD(URXD, BRK)) 461 out |= UART_STAT_BREAK; 462 463 uart_rx_put(sc, out); 464 } 465 /* Reenable Data Ready interrupt */ 466 ENA(bas, UCR4, DREN); 467 468 uart_unlock(sc->sc_hwmtx); 469 return (0); 470} 471 472static int 473imx_uart_bus_setsig(struct uart_softc *sc, int sig) 474{ 475 476 return (0); 477} 478 479static int 480imx_uart_bus_transmit(struct uart_softc *sc) 481{ 482 struct uart_bas *bas = &sc->sc_bas; 483 int i; 484 485 bas = &sc->sc_bas; 486 uart_lock(sc->sc_hwmtx); 487 488 /* Fill TX FIFO */ 489 for (i = 0; i < sc->sc_txdatasz; i++) { 490 SETREG(bas, REG(UTXD), sc->sc_txbuf[i] & 0xff); 491 } 492 493 sc->sc_txbusy = 1; 494 /* Call me when ready */ 495 ENA(bas, UCR1, TXMPTYEN); 496 497 uart_unlock(sc->sc_hwmtx); 498 499 return (0); 500} 501 502static void 503imx_uart_bus_grab(struct uart_softc *sc) 504{ 505 struct uart_bas *bas = &sc->sc_bas; 506 507 bas = &sc->sc_bas; 508 uart_lock(sc->sc_hwmtx); 509 DIS(bas, UCR4, DREN); 510 uart_unlock(sc->sc_hwmtx); 511} 512 513static void 514imx_uart_bus_ungrab(struct uart_softc *sc) 515{ 516 struct uart_bas *bas = &sc->sc_bas; 517 518 bas = &sc->sc_bas; 519 uart_lock(sc->sc_hwmtx); 520 ENA(bas, UCR4, DREN); 521 uart_unlock(sc->sc_hwmtx); 522} 523