1/*- 2 * Copyright 2013-2015 John Wehle <john@feith.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27/* 28 * Amlogic aml8726 UART driver. 29 * 30 * The current implementation only targets features common to all 31 * uarts. For example ... though UART A as a 128 byte FIFO, the 32 * others only have a 64 byte FIFO. 33 * 34 * Also, it's assumed that the USE_XTAL_CLK feature (available on 35 * the aml8726-m6 and later) has not been activated. 36 */ 37 38#include <sys/cdefs.h> 39__FBSDID("$FreeBSD$"); 40 41#include <sys/param.h> 42#include <sys/systm.h> 43#include <sys/bus.h> 44#include <sys/conf.h> 45#include <sys/kernel.h> 46#include <sys/sysctl.h> 47 48#include <machine/bus.h> 49#include <machine/cpu.h> 50 51#include <dev/fdt/fdt_common.h> 52#include <dev/ofw/ofw_bus.h> 53#include <dev/ofw/ofw_bus_subr.h> 54 55#include <dev/uart/uart.h> 56#include <dev/uart/uart_cpu.h> 57#include <dev/uart/uart_cpu_fdt.h> 58#include <dev/uart/uart_bus.h> 59 60#include <arm/amlogic/aml8726/aml8726_soc.h> 61#include <arm/amlogic/aml8726/aml8726_uart.h> 62 63#include "uart_if.h" 64 65#undef uart_getreg 66#undef uart_setreg 67 68#define uart_getreg(bas, reg) \ 69 bus_space_read_4((bas)->bst, (bas)->bsh, reg) 70#define uart_setreg(bas, reg, value) \ 71 bus_space_write_4((bas)->bst, (bas)->bsh, reg, value) 72 73#define SIGCHG(c, i, s, d) \ 74 do { \ 75 if (c) { \ 76 i |= (i & s) ? s : s | d; \ 77 } else { \ 78 i = (i & s) ? (i & ~s) | d : i; \ 79 } \ 80 } while (0) 81 82static int 83aml8726_uart_divisor(int rclk, int baudrate) 84{ 85 int actual_baud, divisor; 86 int error; 87 88 if (baudrate == 0) 89 return (0); 90 91 /* integer version of (rclk / baudrate + .5) */ 92 divisor = ((rclk << 1) + baudrate) / (baudrate << 1); 93 if (divisor == 0) 94 return (0); 95 actual_baud = rclk / divisor; 96 97 /* 10 times error in percent: */ 98 error = (((actual_baud - baudrate) * 2000) / baudrate + 1) >> 1; 99 100 /* 3.0% maximum error tolerance: */ 101 if (error < -30 || error > 30) 102 return (0); 103 104 return (divisor); 105} 106 107static int 108aml8726_uart_param(struct uart_bas *bas, int baudrate, int databits, int stopbits, 109 int parity) 110{ 111 uint32_t cr; 112 uint32_t mr; 113 uint32_t nbr; 114 int divisor; 115 116 cr = uart_getreg(bas, AML_UART_CONTROL_REG); 117 118 cr &= ~(AML_UART_CONTROL_DB_MASK | AML_UART_CONTROL_SB_MASK | 119 AML_UART_CONTROL_P_MASK); 120 121 switch (databits) { 122 case 5: cr |= AML_UART_CONTROL_5_DB; break; 123 case 6: cr |= AML_UART_CONTROL_6_DB; break; 124 case 7: cr |= AML_UART_CONTROL_7_DB; break; 125 case 8: cr |= AML_UART_CONTROL_8_DB; break; 126 default: return (EINVAL); 127 } 128 129 switch (stopbits) { 130 case 1: cr |= AML_UART_CONTROL_1_SB; break; 131 case 2: cr |= AML_UART_CONTROL_2_SB; break; 132 default: return (EINVAL); 133 } 134 135 switch (parity) { 136 case UART_PARITY_EVEN: cr |= AML_UART_CONTROL_P_EVEN; 137 cr |= AML_UART_CONTROL_P_EN; 138 break; 139 140 case UART_PARITY_ODD: cr |= AML_UART_CONTROL_P_ODD; 141 cr |= AML_UART_CONTROL_P_EN; 142 break; 143 144 case UART_PARITY_NONE: break; 145 146 default: return (EINVAL); 147 } 148 149 /* Set baudrate. */ 150 if (baudrate > 0 && bas->rclk != 0) { 151 divisor = aml8726_uart_divisor(bas->rclk / 4, baudrate) - 1; 152 153 switch (aml8726_soc_hw_rev) { 154 case AML_SOC_HW_REV_M6: 155 case AML_SOC_HW_REV_M8: 156 case AML_SOC_HW_REV_M8B: 157 if (divisor > (AML_UART_NEW_BAUD_RATE_MASK >> 158 AML_UART_NEW_BAUD_RATE_SHIFT)) 159 return (EINVAL); 160 161 nbr = uart_getreg(bas, AML_UART_NEW_BAUD_REG); 162 nbr &= ~(AML_UART_NEW_BAUD_USE_XTAL_CLK | 163 AML_UART_NEW_BAUD_RATE_MASK); 164 nbr |= AML_UART_NEW_BAUD_RATE_EN | 165 (divisor << AML_UART_NEW_BAUD_RATE_SHIFT); 166 uart_setreg(bas, AML_UART_NEW_BAUD_REG, nbr); 167 168 divisor = 0; 169 break; 170 default: 171 if (divisor > 0xffff) 172 return (EINVAL); 173 break; 174 } 175 176 cr &= ~AML_UART_CONTROL_BAUD_MASK; 177 cr |= (divisor & AML_UART_CONTROL_BAUD_MASK); 178 179 divisor >>= AML_UART_CONTROL_BAUD_WIDTH; 180 181 mr = uart_getreg(bas, AML_UART_MISC_REG); 182 mr &= ~(AML_UART_MISC_OLD_RX_BAUD | 183 AML_UART_MISC_BAUD_EXT_MASK); 184 mr |= ((divisor << AML_UART_MISC_BAUD_EXT_SHIFT) & 185 AML_UART_MISC_BAUD_EXT_MASK); 186 uart_setreg(bas, AML_UART_MISC_REG, mr); 187 } 188 189 uart_setreg(bas, AML_UART_CONTROL_REG, cr); 190 uart_barrier(bas); 191 192 return (0); 193} 194 195/* 196 * Low-level UART interface. 197 */ 198 199static int 200aml8726_uart_probe(struct uart_bas *bas) 201{ 202 203 return (0); 204} 205 206static void 207aml8726_uart_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, 208 int parity) 209{ 210 uint32_t cr; 211 uint32_t mr; 212 213 (void)aml8726_uart_param(bas, baudrate, databits, stopbits, parity); 214 215 cr = uart_getreg(bas, AML_UART_CONTROL_REG); 216 /* Disable all interrupt sources. */ 217 cr &= ~(AML_UART_CONTROL_TX_INT_EN | AML_UART_CONTROL_RX_INT_EN); 218 /* Reset the transmitter and receiver. */ 219 cr |= (AML_UART_CONTROL_TX_RST | AML_UART_CONTROL_RX_RST); 220 /* Enable the transmitter and receiver. */ 221 cr |= (AML_UART_CONTROL_TX_EN | AML_UART_CONTROL_RX_EN); 222 uart_setreg(bas, AML_UART_CONTROL_REG, cr); 223 uart_barrier(bas); 224 225 /* Clear RX FIFO level for generating interrupts. */ 226 mr = uart_getreg(bas, AML_UART_MISC_REG); 227 mr &= ~AML_UART_MISC_RECV_IRQ_CNT_MASK; 228 uart_setreg(bas, AML_UART_MISC_REG, mr); 229 uart_barrier(bas); 230 231 /* Ensure the reset bits are clear. */ 232 cr &= ~(AML_UART_CONTROL_TX_RST | AML_UART_CONTROL_RX_RST); 233 uart_setreg(bas, AML_UART_CONTROL_REG, cr); 234 uart_barrier(bas); 235} 236 237static void 238aml8726_uart_term(struct uart_bas *bas) 239{ 240} 241 242static void 243aml8726_uart_putc(struct uart_bas *bas, int c) 244{ 245 246 while ((uart_getreg(bas, AML_UART_STATUS_REG) & 247 AML_UART_STATUS_TX_FIFO_FULL) != 0) 248 cpu_spinwait(); 249 250 uart_setreg(bas, AML_UART_WFIFO_REG, c); 251 uart_barrier(bas); 252} 253 254static int 255aml8726_uart_rxready(struct uart_bas *bas) 256{ 257 258 return ((uart_getreg(bas, AML_UART_STATUS_REG) & 259 AML_UART_STATUS_RX_FIFO_EMPTY) == 0 ? 1 : 0); 260} 261 262static int 263aml8726_uart_getc(struct uart_bas *bas, struct mtx *hwmtx) 264{ 265 int c; 266 267 uart_lock(hwmtx); 268 269 while ((uart_getreg(bas, AML_UART_STATUS_REG) & 270 AML_UART_STATUS_RX_FIFO_EMPTY) != 0) { 271 uart_unlock(hwmtx); 272 DELAY(4); 273 uart_lock(hwmtx); 274 } 275 276 c = uart_getreg(bas, AML_UART_RFIFO_REG) & 0xff; 277 278 uart_unlock(hwmtx); 279 280 return (c); 281} 282 283struct uart_ops aml8726_uart_ops = { 284 .probe = aml8726_uart_probe, 285 .init = aml8726_uart_init, 286 .term = aml8726_uart_term, 287 .putc = aml8726_uart_putc, 288 .rxready = aml8726_uart_rxready, 289 .getc = aml8726_uart_getc, 290}; 291 292static unsigned int 293aml8726_uart_bus_clk(phandle_t node) 294{ 295 pcell_t prop; 296 ssize_t len; 297 phandle_t clk_node; 298 299 len = OF_getencprop(node, "clocks", &prop, sizeof(prop)); 300 if ((len / sizeof(prop)) != 1 || prop == 0 || 301 (clk_node = OF_node_from_xref(prop)) == 0) 302 return (0); 303 304 len = OF_getencprop(clk_node, "clock-frequency", &prop, sizeof(prop)); 305 if ((len / sizeof(prop)) != 1 || prop == 0) 306 return (0); 307 308 return ((unsigned int)prop); 309} 310 311static int 312aml8726_uart_bus_probe(struct uart_softc *sc) 313{ 314 int error; 315 316 error = aml8726_uart_probe(&sc->sc_bas); 317 if (error) 318 return (error); 319 320 sc->sc_rxfifosz = 64; 321 sc->sc_txfifosz = 64; 322 sc->sc_hwiflow = 1; 323 sc->sc_hwoflow = 1; 324 325 device_set_desc(sc->sc_dev, "Amlogic aml8726 UART"); 326 327 return (0); 328} 329 330static int 331aml8726_uart_bus_getsig(struct uart_softc *sc) 332{ 333 uint32_t new, old, sig; 334 335 /* 336 * Treat DSR, DCD, and CTS as always on. 337 */ 338 339 do { 340 old = sc->sc_hwsig; 341 sig = old; 342 SIGCHG(1, sig, SER_DSR, SER_DDSR); 343 SIGCHG(1, sig, SER_DCD, SER_DDCD); 344 SIGCHG(1, sig, SER_CTS, SER_DCTS); 345 new = sig & ~SER_MASK_DELTA; 346 } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); 347 348 return (sig); 349} 350 351static int 352aml8726_uart_bus_setsig(struct uart_softc *sc, int sig) 353{ 354 uint32_t new, old; 355 356 do { 357 old = sc->sc_hwsig; 358 new = old; 359 if (sig & SER_DDTR) { 360 SIGCHG(sig & SER_DTR, new, SER_DTR, SER_DDTR); 361 } 362 if (sig & SER_DRTS) { 363 SIGCHG(sig & SER_RTS, new, SER_RTS, SER_DRTS); 364 } 365 } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); 366 367 return (0); 368} 369 370static int 371aml8726_uart_bus_attach(struct uart_softc *sc) 372{ 373 struct uart_bas *bas; 374 uint32_t cr; 375 uint32_t mr; 376 377 bas = &sc->sc_bas; 378 379 bas->rclk = aml8726_uart_bus_clk(ofw_bus_get_node(sc->sc_dev)); 380 381 if (bas->rclk == 0) { 382 device_printf(sc->sc_dev, "missing clocks attribute in FDT\n"); 383 return (ENXIO); 384 } 385 386 cr = uart_getreg(bas, AML_UART_CONTROL_REG); 387 /* Disable all interrupt sources. */ 388 cr &= ~(AML_UART_CONTROL_TX_INT_EN | AML_UART_CONTROL_RX_INT_EN); 389 /* Ensure the reset bits are clear. */ 390 cr &= ~(AML_UART_CONTROL_TX_RST | AML_UART_CONTROL_RX_RST); 391 392 /* 393 * Reset the transmitter and receiver only if not acting as a 394 * console, otherwise it means that: 395 * 396 * 1) aml8726_uart_init was already called which did the reset 397 * 398 * 2) there may be console bytes sitting in the transmit fifo 399 */ 400 if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) 401 ; 402 else 403 cr |= (AML_UART_CONTROL_TX_RST | AML_UART_CONTROL_RX_RST); 404 405 /* Default to two wire mode. */ 406 cr |= AML_UART_CONTROL_TWO_WIRE_EN; 407 /* Enable the transmitter and receiver. */ 408 cr |= (AML_UART_CONTROL_TX_EN | AML_UART_CONTROL_RX_EN); 409 /* Reset error bits. */ 410 cr |= AML_UART_CONTROL_CLR_ERR; 411 uart_setreg(bas, AML_UART_CONTROL_REG, cr); 412 uart_barrier(bas); 413 414 /* Set FIFO levels for generating interrupts. */ 415 mr = uart_getreg(bas, AML_UART_MISC_REG); 416 mr &= ~AML_UART_MISC_XMIT_IRQ_CNT_MASK; 417 mr |= (0 << AML_UART_MISC_XMIT_IRQ_CNT_SHIFT); 418 mr &= ~AML_UART_MISC_RECV_IRQ_CNT_MASK; 419 mr |= (1 << AML_UART_MISC_RECV_IRQ_CNT_SHIFT); 420 uart_setreg(bas, AML_UART_MISC_REG, mr); 421 uart_barrier(bas); 422 423 aml8726_uart_bus_getsig(sc); 424 425 /* Ensure the reset bits are clear. */ 426 cr &= ~(AML_UART_CONTROL_TX_RST | AML_UART_CONTROL_RX_RST); 427 cr &= ~AML_UART_CONTROL_CLR_ERR; 428 /* Enable the receive interrupt. */ 429 cr |= AML_UART_CONTROL_RX_INT_EN; 430 uart_setreg(bas, AML_UART_CONTROL_REG, cr); 431 uart_barrier(bas); 432 433 return (0); 434} 435 436static int 437aml8726_uart_bus_detach(struct uart_softc *sc) 438{ 439 struct uart_bas *bas; 440 uint32_t cr; 441 uint32_t mr; 442 443 bas = &sc->sc_bas; 444 445 /* Disable all interrupt sources. */ 446 cr = uart_getreg(bas, AML_UART_CONTROL_REG); 447 cr &= ~(AML_UART_CONTROL_TX_INT_EN | AML_UART_CONTROL_RX_INT_EN); 448 uart_setreg(bas, AML_UART_CONTROL_REG, cr); 449 uart_barrier(bas); 450 451 /* Clear RX FIFO level for generating interrupts. */ 452 mr = uart_getreg(bas, AML_UART_MISC_REG); 453 mr &= ~AML_UART_MISC_RECV_IRQ_CNT_MASK; 454 uart_setreg(bas, AML_UART_MISC_REG, mr); 455 uart_barrier(bas); 456 457 return (0); 458} 459 460static int 461aml8726_uart_bus_flush(struct uart_softc *sc, int what) 462{ 463 struct uart_bas *bas; 464 uint32_t cr; 465 466 bas = &sc->sc_bas; 467 uart_lock(sc->sc_hwmtx); 468 469 cr = uart_getreg(bas, AML_UART_CONTROL_REG); 470 if (what & UART_FLUSH_TRANSMITTER) 471 cr |= AML_UART_CONTROL_TX_RST; 472 if (what & UART_FLUSH_RECEIVER) 473 cr |= AML_UART_CONTROL_RX_RST; 474 uart_setreg(bas, AML_UART_CONTROL_REG, cr); 475 uart_barrier(bas); 476 477 /* Ensure the reset bits are clear. */ 478 cr &= ~(AML_UART_CONTROL_TX_RST | AML_UART_CONTROL_RX_RST); 479 uart_setreg(bas, AML_UART_CONTROL_REG, cr); 480 uart_barrier(bas); 481 482 uart_unlock(sc->sc_hwmtx); 483 484 return (0); 485} 486 487static int 488aml8726_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) 489{ 490 struct uart_bas *bas; 491 int baudrate, divisor, error; 492 uint32_t cr, mr, nbr; 493 494 bas = &sc->sc_bas; 495 uart_lock(sc->sc_hwmtx); 496 497 error = 0; 498 switch (request) { 499 case UART_IOCTL_BAUD: 500 cr = uart_getreg(bas, AML_UART_CONTROL_REG); 501 cr &= AML_UART_CONTROL_BAUD_MASK; 502 503 mr = uart_getreg(bas, AML_UART_MISC_REG); 504 mr &= AML_UART_MISC_BAUD_EXT_MASK; 505 506 divisor = ((mr >> AML_UART_MISC_BAUD_EXT_SHIFT) << 507 AML_UART_CONTROL_BAUD_WIDTH) | cr; 508 509 switch (aml8726_soc_hw_rev) { 510 case AML_SOC_HW_REV_M6: 511 case AML_SOC_HW_REV_M8: 512 case AML_SOC_HW_REV_M8B: 513 nbr = uart_getreg(bas, AML_UART_NEW_BAUD_REG); 514 if ((nbr & AML_UART_NEW_BAUD_RATE_EN) != 0) { 515 divisor = (nbr & AML_UART_NEW_BAUD_RATE_MASK) >> 516 AML_UART_NEW_BAUD_RATE_SHIFT; 517 } 518 break; 519 default: 520 break; 521 } 522 523 baudrate = bas->rclk / 4 / (divisor + 1); 524 if (baudrate > 0) 525 *(int*)data = baudrate; 526 else 527 error = ENXIO; 528 break; 529 530 case UART_IOCTL_IFLOW: 531 case UART_IOCTL_OFLOW: 532 cr = uart_getreg(bas, AML_UART_CONTROL_REG); 533 if (data) 534 cr &= ~AML_UART_CONTROL_TWO_WIRE_EN; 535 else 536 cr |= AML_UART_CONTROL_TWO_WIRE_EN; 537 uart_setreg(bas, AML_UART_CONTROL_REG, cr); 538 break; 539 540 default: 541 error = EINVAL; 542 break; 543 } 544 545 uart_unlock(sc->sc_hwmtx); 546 547 return (error); 548} 549 550static int 551aml8726_uart_bus_ipend(struct uart_softc *sc) 552{ 553 struct uart_bas *bas; 554 int ipend; 555 uint32_t sr; 556 uint32_t cr; 557 558 bas = &sc->sc_bas; 559 uart_lock(sc->sc_hwmtx); 560 561 ipend = 0; 562 sr = uart_getreg(bas, AML_UART_STATUS_REG); 563 cr = uart_getreg(bas, AML_UART_CONTROL_REG); 564 565 if ((sr & AML_UART_STATUS_RX_FIFO_OVERFLOW) != 0) 566 ipend |= SER_INT_OVERRUN; 567 568 if ((sr & AML_UART_STATUS_TX_FIFO_EMPTY) != 0 && 569 (cr & AML_UART_CONTROL_TX_INT_EN) != 0) { 570 ipend |= SER_INT_TXIDLE; 571 572 cr &= ~AML_UART_CONTROL_TX_INT_EN; 573 uart_setreg(bas, AML_UART_CONTROL_REG, cr); 574 uart_barrier(bas); 575 } 576 577 if ((sr & AML_UART_STATUS_RX_FIFO_EMPTY) == 0) 578 ipend |= SER_INT_RXREADY; 579 580 uart_unlock(sc->sc_hwmtx); 581 582 return (ipend); 583} 584 585static int 586aml8726_uart_bus_param(struct uart_softc *sc, int baudrate, int databits, 587 int stopbits, int parity) 588{ 589 struct uart_bas *bas; 590 int error; 591 592 bas = &sc->sc_bas; 593 uart_lock(sc->sc_hwmtx); 594 595 error = aml8726_uart_param(bas, baudrate, databits, stopbits, parity); 596 597 uart_unlock(sc->sc_hwmtx); 598 599 return (error); 600} 601 602static int 603aml8726_uart_bus_receive(struct uart_softc *sc) 604{ 605 struct uart_bas *bas; 606 int xc; 607 uint32_t sr; 608 609 bas = &sc->sc_bas; 610 uart_lock(sc->sc_hwmtx); 611 612 sr = uart_getreg(bas, AML_UART_STATUS_REG); 613 while ((sr & AML_UART_STATUS_RX_FIFO_EMPTY) == 0) { 614 if (uart_rx_full(sc)) { 615 sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; 616 break; 617 } 618 xc = uart_getreg(bas, AML_UART_RFIFO_REG) & 0xff; 619 if (sr & AML_UART_STATUS_FRAME_ERR) 620 xc |= UART_STAT_FRAMERR; 621 if (sr & AML_UART_STATUS_PARITY_ERR) 622 xc |= UART_STAT_PARERR; 623 uart_rx_put(sc, xc); 624 sr = uart_getreg(bas, AML_UART_STATUS_REG); 625 } 626 /* Discard everything left in the RX FIFO. */ 627 while ((sr & AML_UART_STATUS_RX_FIFO_EMPTY) == 0) { 628 (void)uart_getreg(bas, AML_UART_RFIFO_REG); 629 sr = uart_getreg(bas, AML_UART_STATUS_REG); 630 } 631 /* Reset error bits */ 632 if ((sr & (AML_UART_STATUS_FRAME_ERR | AML_UART_STATUS_PARITY_ERR)) != 0) { 633 uart_setreg(bas, AML_UART_CONTROL_REG, 634 (uart_getreg(bas, AML_UART_CONTROL_REG) | 635 AML_UART_CONTROL_CLR_ERR)); 636 uart_barrier(bas); 637 uart_setreg(bas, AML_UART_CONTROL_REG, 638 (uart_getreg(bas, AML_UART_CONTROL_REG) & 639 ~AML_UART_CONTROL_CLR_ERR)); 640 uart_barrier(bas); 641 } 642 643 uart_unlock(sc->sc_hwmtx); 644 645 return (0); 646} 647 648static int 649aml8726_uart_bus_transmit(struct uart_softc *sc) 650{ 651 struct uart_bas *bas; 652 int i; 653 uint32_t cr; 654 655 bas = &sc->sc_bas; 656 uart_lock(sc->sc_hwmtx); 657 658 /* 659 * Wait for sufficient space since aml8726_uart_putc 660 * may have been called after SER_INT_TXIDLE occurred. 661 */ 662 while ((uart_getreg(bas, AML_UART_STATUS_REG) & 663 AML_UART_STATUS_TX_FIFO_EMPTY) == 0) 664 cpu_spinwait(); 665 666 for (i = 0; i < sc->sc_txdatasz; i++) { 667 uart_setreg(bas, AML_UART_WFIFO_REG, sc->sc_txbuf[i]); 668 uart_barrier(bas); 669 } 670 671 sc->sc_txbusy = 1; 672 673 cr = uart_getreg(bas, AML_UART_CONTROL_REG); 674 cr |= AML_UART_CONTROL_TX_INT_EN; 675 uart_setreg(bas, AML_UART_CONTROL_REG, cr); 676 uart_barrier(bas); 677 678 uart_unlock(sc->sc_hwmtx); 679 680 return (0); 681} 682 683static void 684aml8726_uart_bus_grab(struct uart_softc *sc) 685{ 686 struct uart_bas *bas; 687 uint32_t cr; 688 689 /* 690 * Disable the receive interrupt to avoid a race between 691 * aml8726_uart_getc and aml8726_uart_bus_receive which 692 * can trigger: 693 * 694 * panic: bad stray interrupt 695 * 696 * due to the RX FIFO receiving a character causing an 697 * interrupt which gets serviced after aml8726_uart_getc 698 * has been called (meaning the RX FIFO is now empty). 699 */ 700 701 bas = &sc->sc_bas; 702 uart_lock(sc->sc_hwmtx); 703 704 cr = uart_getreg(bas, AML_UART_CONTROL_REG); 705 cr &= ~AML_UART_CONTROL_RX_INT_EN; 706 uart_setreg(bas, AML_UART_CONTROL_REG, cr); 707 uart_barrier(bas); 708 709 uart_unlock(sc->sc_hwmtx); 710} 711 712static void 713aml8726_uart_bus_ungrab(struct uart_softc *sc) 714{ 715 struct uart_bas *bas; 716 uint32_t cr; 717 uint32_t mr; 718 719 /* 720 * The RX FIFO level being set indicates that the device 721 * is currently attached meaning the receive interrupt 722 * should be enabled. 723 */ 724 725 bas = &sc->sc_bas; 726 uart_lock(sc->sc_hwmtx); 727 728 mr = uart_getreg(bas, AML_UART_MISC_REG); 729 mr &= AML_UART_MISC_RECV_IRQ_CNT_MASK; 730 731 if (mr != 0) { 732 cr = uart_getreg(bas, AML_UART_CONTROL_REG); 733 cr |= AML_UART_CONTROL_RX_INT_EN; 734 uart_setreg(bas, AML_UART_CONTROL_REG, cr); 735 uart_barrier(bas); 736 } 737 738 uart_unlock(sc->sc_hwmtx); 739} 740 741static kobj_method_t aml8726_uart_methods[] = { 742 KOBJMETHOD(uart_probe, aml8726_uart_bus_probe), 743 KOBJMETHOD(uart_attach, aml8726_uart_bus_attach), 744 KOBJMETHOD(uart_detach, aml8726_uart_bus_detach), 745 KOBJMETHOD(uart_flush, aml8726_uart_bus_flush), 746 KOBJMETHOD(uart_getsig, aml8726_uart_bus_getsig), 747 KOBJMETHOD(uart_setsig, aml8726_uart_bus_setsig), 748 KOBJMETHOD(uart_ioctl, aml8726_uart_bus_ioctl), 749 KOBJMETHOD(uart_ipend, aml8726_uart_bus_ipend), 750 KOBJMETHOD(uart_param, aml8726_uart_bus_param), 751 KOBJMETHOD(uart_receive, aml8726_uart_bus_receive), 752 KOBJMETHOD(uart_transmit, aml8726_uart_bus_transmit), 753 KOBJMETHOD(uart_grab, aml8726_uart_bus_grab), 754 KOBJMETHOD(uart_ungrab, aml8726_uart_bus_ungrab), 755 { 0, 0 } 756}; 757 758struct uart_class uart_aml8726_class = { 759 "uart", 760 aml8726_uart_methods, 761 sizeof(struct uart_softc), 762 .uc_ops = &aml8726_uart_ops, 763 .uc_range = 24, 764 .uc_rclk = 0, 765 .uc_rshift = 0 766}; 767 768static struct ofw_compat_data compat_data[] = { 769 { "amlogic,meson-uart", (uintptr_t)&uart_aml8726_class }, 770 { NULL, (uintptr_t)NULL } 771}; 772UART_FDT_CLASS_AND_DEVICE(compat_data); 773