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