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 47 #include <dev/uart/uart_dev_imx5xx.h> 48 49 #include "uart_if.h" 50 /* 51 * Low-level UART interface. 52 */ 53 static int imx_uart_probe(struct uart_bas *bas); 54 static void imx_uart_init(struct uart_bas *bas, int, int, int, int); 55 static void imx_uart_term(struct uart_bas *bas); 56 static void imx_uart_putc(struct uart_bas *bas, int); 57 static int imx_uart_rxready(struct uart_bas *bas); 58 static int imx_uart_getc(struct uart_bas *bas, struct mtx *); 59 60 static struct uart_ops uart_imx_uart_ops = { 61 .probe = imx_uart_probe, 62 .init = imx_uart_init, 63 .term = imx_uart_term, 64 .putc = imx_uart_putc, 65 .rxready = imx_uart_rxready, 66 .getc = imx_uart_getc, 67 }; 68 69 static int 70 imx_uart_probe(struct uart_bas *bas) 71 { 72 73 return (0); 74 } 75 76 static void 77 imx_uart_init(struct uart_bas *bas, int baudrate, int databits, 78 int stopbits, int parity) 79 { 80 81 } 82 83 static void 84 imx_uart_term(struct uart_bas *bas) 85 { 86 87 } 88 89 static void 90 imx_uart_putc(struct uart_bas *bas, int c) 91 { 92 93 while (!(IS(bas, USR2, TXFE))) 94 ; 95 SETREG(bas, REG(UTXD), c); 96 } 97 98 static int 99 imx_uart_rxready(struct uart_bas *bas) 100 { 101 102 return ((IS(bas, USR2, RDR)) ? 1 : 0); 103 } 104 105 static int 106 imx_uart_getc(struct uart_bas *bas, struct mtx *hwmtx) 107 { 108 int c; 109 110 uart_lock(hwmtx); 111 while (!(IS(bas, USR2, RDR))) 112 ; 113 114 c = GETREG(bas, REG(URXD)); 115 uart_unlock(hwmtx); 116 #if defined(KDB) 117 if (c & FLD(URXD, BRK)) { 118 if (kdb_break()) 119 return (0); 120 } 121 #endif 122 return (c & 0xff); 123 } 124 125 /* 126 * High-level UART interface. 127 */ 128 struct imx_uart_softc { 129 struct uart_softc base; 130 }; 131 132 static int imx_uart_bus_attach(struct uart_softc *); 133 static int imx_uart_bus_detach(struct uart_softc *); 134 static int imx_uart_bus_flush(struct uart_softc *, int); 135 static int imx_uart_bus_getsig(struct uart_softc *); 136 static int imx_uart_bus_ioctl(struct uart_softc *, int, intptr_t); 137 static int imx_uart_bus_ipend(struct uart_softc *); 138 static int imx_uart_bus_param(struct uart_softc *, int, int, int, int); 139 static int imx_uart_bus_probe(struct uart_softc *); 140 static int imx_uart_bus_receive(struct uart_softc *); 141 static int imx_uart_bus_setsig(struct uart_softc *, int); 142 static int imx_uart_bus_transmit(struct uart_softc *); 143 144 static kobj_method_t imx_uart_methods[] = { 145 KOBJMETHOD(uart_attach, imx_uart_bus_attach), 146 KOBJMETHOD(uart_detach, imx_uart_bus_detach), 147 KOBJMETHOD(uart_flush, imx_uart_bus_flush), 148 KOBJMETHOD(uart_getsig, imx_uart_bus_getsig), 149 KOBJMETHOD(uart_ioctl, imx_uart_bus_ioctl), 150 KOBJMETHOD(uart_ipend, imx_uart_bus_ipend), 151 KOBJMETHOD(uart_param, imx_uart_bus_param), 152 KOBJMETHOD(uart_probe, imx_uart_bus_probe), 153 KOBJMETHOD(uart_receive, imx_uart_bus_receive), 154 KOBJMETHOD(uart_setsig, imx_uart_bus_setsig), 155 KOBJMETHOD(uart_transmit, imx_uart_bus_transmit), 156 { 0, 0 } 157 }; 158 159 struct uart_class uart_imx_class = { 160 "imx", 161 imx_uart_methods, 162 sizeof(struct imx_uart_softc), 163 .uc_ops = &uart_imx_uart_ops, 164 .uc_range = 0x100, 165 .uc_rclk = 24000000 /* TODO: get value from CCM */ 166 }; 167 168 #define SIGCHG(c, i, s, d) \ 169 if (c) { \ 170 i |= (i & s) ? s : s | d; \ 171 } else { \ 172 i = (i & s) ? (i & ~s) | d : i; \ 173 } 174 175 static int 176 imx_uart_bus_attach(struct uart_softc *sc) 177 { 178 struct uart_bas *bas; 179 struct uart_devinfo *di; 180 181 bas = &sc->sc_bas; 182 if (sc->sc_sysdev != NULL) { 183 di = sc->sc_sysdev; 184 imx_uart_init(bas, di->baudrate, di->databits, di->stopbits, 185 di->parity); 186 } else { 187 imx_uart_init(bas, 115200, 8, 1, 0); 188 } 189 190 (void)imx_uart_bus_getsig(sc); 191 192 /* XXX workaround to have working console on mount prompt */ 193 if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE){ 194 DIS(bas, UCR4, DREN); 195 } else { 196 ENA(bas, UCR4, DREN); 197 } 198 DIS(bas, UCR1, RRDYEN); 199 DIS(bas, UCR1, IDEN); 200 DIS(bas, UCR3, RXDSEN); 201 DIS(bas, UCR2, ATEN); 202 DIS(bas, UCR1, TXMPTYEN); 203 DIS(bas, UCR1, TRDYEN); 204 DIS(bas, UCR4, TCEN); 205 DIS(bas, UCR4, OREN); 206 ENA(bas, UCR4, BKEN); 207 DIS(bas, UCR4, WKEN); 208 DIS(bas, UCR1, ADEN); 209 DIS(bas, UCR3, ACIEN); 210 DIS(bas, UCR2, ESCI); 211 DIS(bas, UCR4, ENIRI); 212 DIS(bas, UCR3, AIRINTEN); 213 DIS(bas, UCR3, AWAKEN); 214 DIS(bas, UCR3, FRAERREN); 215 DIS(bas, UCR3, PARERREN); 216 DIS(bas, UCR1, RTSDEN); 217 DIS(bas, UCR2, RTSEN); 218 DIS(bas, UCR3, DTREN); 219 DIS(bas, UCR3, RI); 220 DIS(bas, UCR3, DCD); 221 DIS(bas, UCR3, DTRDEN); 222 223 /* ACK all interrupts */ 224 SETREG(bas, REG(USR1), 0xffff); 225 SETREG(bas, REG(USR2), 0xffff); 226 return (0); 227 } 228 229 static int 230 imx_uart_bus_detach(struct uart_softc *sc) 231 { 232 233 SETREG(&sc->sc_bas, REG(UCR4), 0); 234 235 return (0); 236 } 237 238 static int 239 imx_uart_bus_flush(struct uart_softc *sc, int what) 240 { 241 242 /* TODO */ 243 return (0); 244 } 245 246 static int 247 imx_uart_bus_getsig(struct uart_softc *sc) 248 { 249 uint32_t new, old, sig; 250 uint8_t bes; 251 252 do { 253 old = sc->sc_hwsig; 254 sig = old; 255 uart_lock(sc->sc_hwmtx); 256 bes = GETREG(&sc->sc_bas, REG(USR2)); 257 uart_unlock(sc->sc_hwmtx); 258 /* XXX: chip can show delta */ 259 SIGCHG(bes & FLD(USR2, DCDIN), sig, SER_DCD, SER_DDCD); 260 new = sig & ~SER_MASK_DELTA; 261 } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); 262 263 return (sig); 264 } 265 266 static int 267 imx_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) 268 { 269 struct uart_bas *bas; 270 int error; 271 272 bas = &sc->sc_bas; 273 error = 0; 274 uart_lock(sc->sc_hwmtx); 275 switch (request) { 276 case UART_IOCTL_BREAK: 277 /* TODO */ 278 break; 279 case UART_IOCTL_BAUD: 280 /* TODO */ 281 *(int*)data = 115200; 282 break; 283 default: 284 error = EINVAL; 285 break; 286 } 287 uart_unlock(sc->sc_hwmtx); 288 289 return (error); 290 } 291 292 static int 293 imx_uart_bus_ipend(struct uart_softc *sc) 294 { 295 struct uart_bas *bas; 296 int ipend; 297 uint32_t usr1, usr2; 298 uint32_t ucr1, ucr4; 299 300 bas = &sc->sc_bas; 301 ipend = 0; 302 303 uart_lock(sc->sc_hwmtx); 304 305 /* Read pending interrupts */ 306 usr1 = GETREG(bas, REG(USR1)); 307 usr2 = GETREG(bas, REG(USR2)); 308 /* ACK interrupts */ 309 SETREG(bas, REG(USR1), usr1); 310 SETREG(bas, REG(USR2), usr2); 311 312 ucr1 = GETREG(bas, REG(UCR1)); 313 ucr4 = GETREG(bas, REG(UCR4)); 314 315 if ((usr2 & FLD(USR2, TXFE)) && (ucr1 & FLD(UCR1, TXMPTYEN))) { 316 DIS(bas, UCR1, TXMPTYEN); 317 /* Continue TXing */ 318 ipend |= SER_INT_TXIDLE; 319 } 320 if ((usr2 & FLD(USR2, RDR)) && (ucr4 & FLD(UCR4, DREN))) { 321 DIS(bas, UCR4, DREN); 322 /* Wow, new char on input */ 323 ipend |= SER_INT_RXREADY; 324 } 325 if ((usr2 & FLD(USR2, BRCD)) && (ucr4 & FLD(UCR4, BKEN))) 326 ipend |= SER_INT_BREAK; 327 328 uart_unlock(sc->sc_hwmtx); 329 330 return (ipend); 331 } 332 333 static int 334 imx_uart_bus_param(struct uart_softc *sc, int baudrate, int databits, 335 int stopbits, int parity) 336 { 337 338 uart_lock(sc->sc_hwmtx); 339 imx_uart_init(&sc->sc_bas, baudrate, databits, stopbits, parity); 340 uart_unlock(sc->sc_hwmtx); 341 return (0); 342 } 343 344 static int 345 imx_uart_bus_probe(struct uart_softc *sc) 346 { 347 int error; 348 349 error = imx_uart_probe(&sc->sc_bas); 350 if (error) 351 return (error); 352 353 sc->sc_rxfifosz = 1; 354 sc->sc_txfifosz = 1; 355 356 device_set_desc(sc->sc_dev, "imx_uart"); 357 return (0); 358 } 359 360 static int 361 imx_uart_bus_receive(struct uart_softc *sc) 362 { 363 struct uart_bas *bas; 364 int xc, out; 365 366 bas = &sc->sc_bas; 367 uart_lock(sc->sc_hwmtx); 368 369 /* Read while we have anything in FIFO */ 370 while (IS(bas, USR2, RDR)) { 371 if (uart_rx_full(sc)) { 372 /* No space left in input buffer */ 373 sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; 374 break; 375 } 376 out = 0; 377 xc = GETREG(bas, REG(URXD)); 378 379 /* We have valid char */ 380 if (xc & FLD(URXD, CHARRDY)) 381 out = xc & 0x000000ff; 382 383 if (xc & FLD(URXD, FRMERR)) 384 out |= UART_STAT_FRAMERR; 385 if (xc & FLD(URXD, PRERR)) 386 out |= UART_STAT_PARERR; 387 if (xc & FLD(URXD, OVRRUN)) 388 out |= UART_STAT_OVERRUN; 389 if (xc & FLD(URXD, BRK)) 390 out |= UART_STAT_BREAK; 391 392 uart_rx_put(sc, out); 393 } 394 /* Reenable Data Ready interrupt */ 395 ENA(bas, UCR4, DREN); 396 397 uart_unlock(sc->sc_hwmtx); 398 return (0); 399 } 400 401 static int 402 imx_uart_bus_setsig(struct uart_softc *sc, int sig) 403 { 404 405 /* TODO: implement (?) */ 406 407 /* XXX workaround to have working console on mount prompt */ 408 /* Enable RX interrupt */ 409 if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) 410 if (!IS(&sc->sc_bas, UCR4, DREN)) 411 ENA(&sc->sc_bas, UCR4, DREN); 412 return (0); 413 } 414 415 static int 416 imx_uart_bus_transmit(struct uart_softc *sc) 417 { 418 struct uart_bas *bas = &sc->sc_bas; 419 int i; 420 421 bas = &sc->sc_bas; 422 uart_lock(sc->sc_hwmtx); 423 424 /* Fill TX FIFO */ 425 for (i = 0; i < sc->sc_txdatasz; i++) { 426 SETREG(bas, REG(UTXD), sc->sc_txbuf[i] & 0xff); 427 } 428 429 sc->sc_txbusy = 1; 430 /* Call me when ready */ 431 ENA(bas, UCR1, TXMPTYEN); 432 433 uart_unlock(sc->sc_hwmtx); 434 435 return (0); 436 } 437