1297669Ssgalabov/* $NetBSD: uart.c,v 1.2 2007/03/23 20:05:47 dogcow Exp $ */ 2297669Ssgalabov 3297669Ssgalabov/*- 4297669Ssgalabov * Copyright (c) 2013, Alexander A. Mityaev <sansan@adm.ua> 5297669Ssgalabov * Copyright (c) 2010 Aleksandr Rybalko. 6297669Ssgalabov * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko. 7297669Ssgalabov * Copyright (c) 2007 Oleksandr Tymoshenko. 8297669Ssgalabov * All rights reserved. 9297669Ssgalabov * 10297669Ssgalabov * Redistribution and use in source and binary forms, with or 11297669Ssgalabov * without modification, are permitted provided that the following 12297669Ssgalabov * conditions are met: 13297669Ssgalabov * 1. Redistributions of source code must retain the above copyright 14297669Ssgalabov * notice, this list of conditions and the following disclaimer. 15297669Ssgalabov * 2. Redistributions in binary form must reproduce the above 16297669Ssgalabov * copyright notice, this list of conditions and the following 17297669Ssgalabov * disclaimer in the documentation and/or other materials provided 18297669Ssgalabov * with the distribution. 19297669Ssgalabov * 20297669Ssgalabov * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY 21297669Ssgalabov * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22297669Ssgalabov * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23297669Ssgalabov * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS 24297669Ssgalabov * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 25297669Ssgalabov * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26297669Ssgalabov * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 27297669Ssgalabov * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28297669Ssgalabov * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 29297669Ssgalabov * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 30297669Ssgalabov * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 31297669Ssgalabov * OF SUCH DAMAGE. 32297669Ssgalabov */ 33297669Ssgalabov 34297669Ssgalabov#include <sys/cdefs.h> 35297669Ssgalabov__FBSDID("$FreeBSD$"); 36297669Ssgalabov 37297669Ssgalabov#include "opt_ddb.h" 38297669Ssgalabov 39297669Ssgalabov#include <sys/param.h> 40297669Ssgalabov#include <sys/systm.h> 41297669Ssgalabov#include <sys/bus.h> 42297669Ssgalabov#include <sys/conf.h> 43297669Ssgalabov#include <sys/kdb.h> 44297669Ssgalabov#include <sys/reboot.h> 45297669Ssgalabov#include <sys/sysctl.h> 46297669Ssgalabov#include <sys/kernel.h> 47297669Ssgalabov#include <machine/bus.h> 48297669Ssgalabov#include <machine/fdt.h> 49297669Ssgalabov 50297669Ssgalabov#include <dev/uart/uart.h> 51297669Ssgalabov#include <dev/uart/uart_cpu.h> 52297669Ssgalabov#include <dev/uart/uart_cpu_fdt.h> 53297669Ssgalabov#include <dev/uart/uart_bus.h> 54297669Ssgalabov 55297669Ssgalabov#include <mips/mediatek/uart_dev_mtk.h> 56297669Ssgalabov#include <mips/mediatek/mtk_soc.h> 57297669Ssgalabov#include <mips/mediatek/mtk_sysctl.h> 58297669Ssgalabov 59297669Ssgalabov#include "uart_if.h" 60297669Ssgalabov 61297669Ssgalabov/* Set some reference clock value. Real value will be taken from FDT */ 62297669Ssgalabov#define DEFAULT_RCLK (120 * 1000 * 1000) 63297669Ssgalabov 64297669Ssgalabov/* 65297669Ssgalabov * Low-level UART interface. 66297669Ssgalabov */ 67297669Ssgalabovstatic int mtk_uart_probe(struct uart_bas *bas); 68297669Ssgalabovstatic void mtk_uart_init(struct uart_bas *bas, int, int, int, int); 69297669Ssgalabovstatic void mtk_uart_term(struct uart_bas *bas); 70297669Ssgalabovstatic void mtk_uart_putc(struct uart_bas *bas, int); 71297669Ssgalabovstatic int mtk_uart_rxready(struct uart_bas *bas); 72297669Ssgalabovstatic int mtk_uart_getc(struct uart_bas *bas, struct mtx *); 73297669Ssgalabov 74297669Ssgalabovstatic struct uart_ops uart_mtk_ops = { 75297669Ssgalabov .probe = mtk_uart_probe, 76297669Ssgalabov .init = mtk_uart_init, 77297669Ssgalabov .term = mtk_uart_term, 78297669Ssgalabov .putc = mtk_uart_putc, 79297669Ssgalabov .rxready = mtk_uart_rxready, 80297669Ssgalabov .getc = mtk_uart_getc, 81297669Ssgalabov}; 82297669Ssgalabov 83297669Ssgalabovstatic int uart_output = 1; 84297669SsgalabovTUNABLE_INT("kern.uart_output", &uart_output); 85297669SsgalabovSYSCTL_INT(_kern, OID_AUTO, uart_output, CTLFLAG_RW, 86297669Ssgalabov &uart_output, 0, "UART output enabled."); 87297669Ssgalabov 88297669Ssgalabovstatic int 89297669Ssgalabovmtk_uart_probe(struct uart_bas *bas) 90297669Ssgalabov{ 91297669Ssgalabov return (0); 92297669Ssgalabov} 93297669Ssgalabov 94297669Ssgalabovstatic void 95297669Ssgalabovmtk_uart_init(struct uart_bas *bas, int baudrate, int databits, 96297669Ssgalabov int stopbits, int parity) 97297669Ssgalabov{ 98297669Ssgalabov /* CLKDIV = 384000000/ 3/ 16/ br */ 99297669Ssgalabov /* for 384MHz CLKDIV = 8000000 / baudrate; */ 100297669Ssgalabov switch (databits) { 101297669Ssgalabov case 5: 102297669Ssgalabov databits = UART_LCR_5B; 103297669Ssgalabov break; 104297669Ssgalabov case 6: 105297669Ssgalabov databits = UART_LCR_6B; 106297669Ssgalabov break; 107297669Ssgalabov case 7: 108297669Ssgalabov databits = UART_LCR_7B; 109297669Ssgalabov break; 110297669Ssgalabov case 8: 111297669Ssgalabov databits = UART_LCR_8B; 112297669Ssgalabov break; 113297669Ssgalabov default: 114297669Ssgalabov /* Unsupported */ 115297669Ssgalabov return; 116297669Ssgalabov } 117297669Ssgalabov switch (parity) { 118297669Ssgalabov case UART_PARITY_EVEN: parity = (UART_LCR_PEN|UART_LCR_EVEN); break; 119297669Ssgalabov case UART_PARITY_ODD: parity = (UART_LCR_PEN); break; 120297669Ssgalabov case UART_PARITY_NONE: parity = 0; break; 121297669Ssgalabov /* Unsupported */ 122297669Ssgalabov default: return; 123297669Ssgalabov } 124297669Ssgalabov 125297669Ssgalabov if (bas->rclk && baudrate) { 126297669Ssgalabov uart_setreg(bas, UART_CDDL_REG, bas->rclk/16/baudrate); 127297669Ssgalabov uart_barrier(bas); 128297669Ssgalabov } 129297669Ssgalabov 130297669Ssgalabov uart_setreg(bas, UART_LCR_REG, databits | 131297669Ssgalabov (stopbits==1?0:UART_LCR_STB_15) | 132297669Ssgalabov parity); 133297669Ssgalabov uart_barrier(bas); 134297669Ssgalabov} 135297669Ssgalabov 136297669Ssgalabovstatic void 137297669Ssgalabovmtk_uart_term(struct uart_bas *bas) 138297669Ssgalabov{ 139297669Ssgalabov uart_setreg(bas, UART_MCR_REG, 0); 140297669Ssgalabov uart_barrier(bas); 141297669Ssgalabov} 142297669Ssgalabov 143297669Ssgalabovstatic void 144297669Ssgalabovmtk_uart_putc(struct uart_bas *bas, int c) 145297669Ssgalabov{ 146297669Ssgalabov char chr; 147297669Ssgalabov if (!uart_output) return; 148297669Ssgalabov chr = c; 149297669Ssgalabov while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE)); 150297669Ssgalabov uart_setreg(bas, UART_TX_REG, c); 151297669Ssgalabov uart_barrier(bas); 152297669Ssgalabov while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE)); 153297669Ssgalabov} 154297669Ssgalabov 155297669Ssgalabovstatic int 156297669Ssgalabovmtk_uart_rxready(struct uart_bas *bas) 157297669Ssgalabov{ 158297669Ssgalabov if (uart_getreg(bas, UART_LSR_REG) & UART_LSR_DR) 159297669Ssgalabov return (1); 160297669Ssgalabov return (0); 161297669Ssgalabov} 162297669Ssgalabov 163297669Ssgalabovstatic int 164297669Ssgalabovmtk_uart_getc(struct uart_bas *bas, struct mtx *hwmtx) 165297669Ssgalabov{ 166297669Ssgalabov int c; 167297669Ssgalabov 168297669Ssgalabov uart_lock(hwmtx); 169297669Ssgalabov 170297669Ssgalabov while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_DR)) { 171297669Ssgalabov uart_unlock(hwmtx); 172297669Ssgalabov DELAY(10); 173297669Ssgalabov uart_lock(hwmtx); 174297669Ssgalabov } 175297669Ssgalabov 176297669Ssgalabov c = uart_getreg(bas, UART_RX_REG); 177297669Ssgalabov 178297669Ssgalabov uart_unlock(hwmtx); 179297669Ssgalabov 180297669Ssgalabov return (c); 181297669Ssgalabov} 182297669Ssgalabov 183297669Ssgalabov/* 184297669Ssgalabov * High-level UART interface. 185297669Ssgalabov */ 186297669Ssgalabovstruct uart_mtk_softc { 187297669Ssgalabov struct uart_softc base; 188297669Ssgalabov uint8_t ier_mask; 189297669Ssgalabov uint8_t ier; 190297669Ssgalabov}; 191297669Ssgalabov 192297669Ssgalabovstatic int mtk_uart_bus_attach(struct uart_softc *); 193297669Ssgalabovstatic int mtk_uart_bus_detach(struct uart_softc *); 194297669Ssgalabovstatic int mtk_uart_bus_flush(struct uart_softc *, int); 195297669Ssgalabovstatic int mtk_uart_bus_getsig(struct uart_softc *); 196297669Ssgalabovstatic int mtk_uart_bus_ioctl(struct uart_softc *, int, intptr_t); 197297669Ssgalabovstatic int mtk_uart_bus_ipend(struct uart_softc *); 198297669Ssgalabovstatic int mtk_uart_bus_param(struct uart_softc *, int, int, int, int); 199297669Ssgalabovstatic int mtk_uart_bus_probe(struct uart_softc *); 200297669Ssgalabovstatic int mtk_uart_bus_receive(struct uart_softc *); 201297669Ssgalabovstatic int mtk_uart_bus_setsig(struct uart_softc *, int); 202297669Ssgalabovstatic int mtk_uart_bus_transmit(struct uart_softc *); 203297669Ssgalabovstatic void mtk_uart_bus_grab(struct uart_softc *); 204297669Ssgalabovstatic void mtk_uart_bus_ungrab(struct uart_softc *); 205297669Ssgalabov 206297669Ssgalabovstatic kobj_method_t uart_mtk_methods[] = { 207297669Ssgalabov KOBJMETHOD(uart_attach, mtk_uart_bus_attach), 208297669Ssgalabov KOBJMETHOD(uart_detach, mtk_uart_bus_detach), 209297669Ssgalabov KOBJMETHOD(uart_flush, mtk_uart_bus_flush), 210297669Ssgalabov KOBJMETHOD(uart_getsig, mtk_uart_bus_getsig), 211297669Ssgalabov KOBJMETHOD(uart_ioctl, mtk_uart_bus_ioctl), 212297669Ssgalabov KOBJMETHOD(uart_ipend, mtk_uart_bus_ipend), 213297669Ssgalabov KOBJMETHOD(uart_param, mtk_uart_bus_param), 214297669Ssgalabov KOBJMETHOD(uart_probe, mtk_uart_bus_probe), 215297669Ssgalabov KOBJMETHOD(uart_receive, mtk_uart_bus_receive), 216297669Ssgalabov KOBJMETHOD(uart_setsig, mtk_uart_bus_setsig), 217297669Ssgalabov KOBJMETHOD(uart_transmit, mtk_uart_bus_transmit), 218297669Ssgalabov KOBJMETHOD(uart_grab, mtk_uart_bus_grab), 219297669Ssgalabov KOBJMETHOD(uart_ungrab, mtk_uart_bus_ungrab), 220297669Ssgalabov { 0, 0 } 221297669Ssgalabov}; 222297669Ssgalabov 223297669Ssgalabovstruct uart_class uart_mtk_class = { 224297669Ssgalabov "uart_mtk", 225297669Ssgalabov uart_mtk_methods, 226297669Ssgalabov sizeof(struct uart_mtk_softc), 227297669Ssgalabov .uc_ops = &uart_mtk_ops, 228297669Ssgalabov .uc_range = 1, /* use hinted range */ 229297669Ssgalabov .uc_rclk = 0 230297669Ssgalabov}; 231297669Ssgalabov 232297669Ssgalabovstatic struct ofw_compat_data compat_data[] = { 233297669Ssgalabov { "ralink,rt2880-uart", (uintptr_t)&uart_mtk_class }, 234297669Ssgalabov { "ralink,rt3050-uart", (uintptr_t)&uart_mtk_class }, 235297669Ssgalabov { "ralink,rt3352-uart", (uintptr_t)&uart_mtk_class }, 236297669Ssgalabov { "ralink,rt3883-uart", (uintptr_t)&uart_mtk_class }, 237297669Ssgalabov { "ralink,rt5350-uart", (uintptr_t)&uart_mtk_class }, 238297669Ssgalabov { "ralink,mt7620a-uart", (uintptr_t)&uart_mtk_class }, 239297669Ssgalabov { NULL, (uintptr_t)NULL }, 240297669Ssgalabov}; 241297669SsgalabovUART_FDT_CLASS_AND_DEVICE(compat_data); 242297669Ssgalabov 243297669Ssgalabov 244297669Ssgalabov#define SIGCHG(c, i, s, d) \ 245297669Ssgalabov if (c) { \ 246297669Ssgalabov i |= (i & s) ? s : s | d; \ 247297669Ssgalabov } else { \ 248297669Ssgalabov i = (i & s) ? (i & ~s) | d : i; \ 249297669Ssgalabov } 250297669Ssgalabov 251297669Ssgalabov/* 252297669Ssgalabov * Disable TX interrupt. uart should be locked 253297669Ssgalabov */ 254297669Ssgalabovstatic __inline void 255297669Ssgalabovmtk_uart_disable_txintr(struct uart_softc *sc) 256297669Ssgalabov{ 257297669Ssgalabov struct uart_bas *bas = &sc->sc_bas; 258297669Ssgalabov uint8_t cr; 259297669Ssgalabov 260297669Ssgalabov cr = uart_getreg(bas, UART_IER_REG); 261297669Ssgalabov cr &= ~UART_IER_ETBEI; 262297669Ssgalabov uart_setreg(bas, UART_IER_REG, cr); 263297669Ssgalabov uart_barrier(bas); 264297669Ssgalabov} 265297669Ssgalabov 266297669Ssgalabov/* 267297669Ssgalabov * Enable TX interrupt. uart should be locked 268297669Ssgalabov */ 269297669Ssgalabovstatic __inline void 270297669Ssgalabovmtk_uart_enable_txintr(struct uart_softc *sc) 271297669Ssgalabov{ 272297669Ssgalabov struct uart_bas *bas = &sc->sc_bas; 273297669Ssgalabov uint8_t cr; 274297669Ssgalabov 275297669Ssgalabov cr = uart_getreg(bas, UART_IER_REG); 276297669Ssgalabov cr |= UART_IER_ETBEI; 277297669Ssgalabov uart_setreg(bas, UART_IER_REG, cr); 278297669Ssgalabov uart_barrier(bas); 279297669Ssgalabov} 280297669Ssgalabov 281297669Ssgalabovstatic int 282297669Ssgalabovmtk_uart_bus_attach(struct uart_softc *sc) 283297669Ssgalabov{ 284297669Ssgalabov struct uart_bas *bas; 285297669Ssgalabov struct uart_devinfo *di; 286297669Ssgalabov struct uart_mtk_softc *usc = (struct uart_mtk_softc *)sc; 287297669Ssgalabov 288297669Ssgalabov bas = &sc->sc_bas; 289297669Ssgalabov 290297669Ssgalabov if (!bas->rclk) { 291297669Ssgalabov bas->rclk = mtk_soc_get_uartclk(); 292297669Ssgalabov } 293297669Ssgalabov 294297669Ssgalabov if (sc->sc_sysdev != NULL) { 295297669Ssgalabov di = sc->sc_sysdev; 296297669Ssgalabov mtk_uart_init(bas, di->baudrate, di->databits, di->stopbits, 297297669Ssgalabov di->parity); 298297669Ssgalabov } else { 299297669Ssgalabov mtk_uart_init(bas, 57600, 8, 1, 0); 300297669Ssgalabov } 301297669Ssgalabov 302297669Ssgalabov sc->sc_rxfifosz = 16; 303297669Ssgalabov sc->sc_txfifosz = 16; 304297669Ssgalabov 305297669Ssgalabov (void)mtk_uart_bus_getsig(sc); 306297669Ssgalabov 307297669Ssgalabov /* Enable FIFO */ 308297669Ssgalabov uart_setreg(bas, UART_FCR_REG, 309297669Ssgalabov uart_getreg(bas, UART_FCR_REG) | 310297669Ssgalabov UART_FCR_FIFOEN | UART_FCR_TXTGR_1 | UART_FCR_RXTGR_1); 311297669Ssgalabov uart_barrier(bas); 312297669Ssgalabov /* Enable interrupts */ 313297669Ssgalabov usc->ier_mask = 0xf0; 314297669Ssgalabov uart_setreg(bas, UART_IER_REG, 315297669Ssgalabov UART_IER_EDSSI | UART_IER_ELSI | UART_IER_ERBFI); 316297669Ssgalabov uart_barrier(bas); 317297669Ssgalabov 318297669Ssgalabov return (0); 319297669Ssgalabov} 320297669Ssgalabov 321297669Ssgalabovstatic int 322297669Ssgalabovmtk_uart_bus_detach(struct uart_softc *sc) 323297669Ssgalabov{ 324297669Ssgalabov return (0); 325297669Ssgalabov} 326297669Ssgalabov 327297669Ssgalabovstatic int 328297669Ssgalabovmtk_uart_bus_flush(struct uart_softc *sc, int what) 329297669Ssgalabov{ 330297669Ssgalabov struct uart_bas *bas = &sc->sc_bas; 331297669Ssgalabov uint32_t fcr = uart_getreg(bas, UART_FCR_REG); 332297669Ssgalabov 333297669Ssgalabov if (what & UART_FLUSH_TRANSMITTER) { 334297669Ssgalabov uart_setreg(bas, UART_FCR_REG, fcr|UART_FCR_TXRST); 335297669Ssgalabov uart_barrier(bas); 336297669Ssgalabov } 337297669Ssgalabov if (what & UART_FLUSH_RECEIVER) { 338297669Ssgalabov uart_setreg(bas, UART_FCR_REG, fcr|UART_FCR_RXRST); 339297669Ssgalabov uart_barrier(bas); 340297669Ssgalabov } 341297669Ssgalabov uart_setreg(bas, UART_FCR_REG, fcr); 342297669Ssgalabov uart_barrier(bas); 343297669Ssgalabov return (0); 344297669Ssgalabov} 345297669Ssgalabov 346297669Ssgalabovstatic int 347297669Ssgalabovmtk_uart_bus_getsig(struct uart_softc *sc) 348297669Ssgalabov{ 349297669Ssgalabov uint32_t new, old, sig; 350297669Ssgalabov uint8_t bes; 351297669Ssgalabov 352297669Ssgalabov return(0); 353297669Ssgalabov do { 354297669Ssgalabov old = sc->sc_hwsig; 355297669Ssgalabov sig = old; 356297669Ssgalabov uart_lock(sc->sc_hwmtx); 357297669Ssgalabov bes = uart_getreg(&sc->sc_bas, UART_MSR_REG); 358297669Ssgalabov uart_unlock(sc->sc_hwmtx); 359297669Ssgalabov /* XXX: chip can show delta */ 360297669Ssgalabov SIGCHG(bes & UART_MSR_CTS, sig, SER_CTS, SER_DCTS); 361297669Ssgalabov SIGCHG(bes & UART_MSR_DCD, sig, SER_DCD, SER_DDCD); 362297669Ssgalabov SIGCHG(bes & UART_MSR_DSR, sig, SER_DSR, SER_DDSR); 363297669Ssgalabov new = sig & ~SER_MASK_DELTA; 364297669Ssgalabov } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); 365297669Ssgalabov 366297669Ssgalabov return (sig); 367297669Ssgalabov} 368297669Ssgalabov 369297669Ssgalabovstatic int 370297669Ssgalabovmtk_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) 371297669Ssgalabov{ 372297669Ssgalabov struct uart_bas *bas; 373297669Ssgalabov int baudrate, divisor, error; 374297669Ssgalabov 375297669Ssgalabov bas = &sc->sc_bas; 376297669Ssgalabov error = 0; 377297669Ssgalabov uart_lock(sc->sc_hwmtx); 378297669Ssgalabov switch (request) { 379297669Ssgalabov case UART_IOCTL_BREAK: 380297669Ssgalabov /* TODO: Send BREAK */ 381297669Ssgalabov break; 382297669Ssgalabov case UART_IOCTL_BAUD: 383297669Ssgalabov divisor = uart_getreg(bas, UART_CDDL_REG); 384297669Ssgalabov baudrate = bas->rclk / (divisor * 16); 385297669Ssgalabov *(int*)data = baudrate; 386297669Ssgalabov break; 387297669Ssgalabov default: 388297669Ssgalabov error = EINVAL; 389297669Ssgalabov break; 390297669Ssgalabov } 391297669Ssgalabov uart_unlock(sc->sc_hwmtx); 392297669Ssgalabov return (error); 393297669Ssgalabov} 394297669Ssgalabov 395297669Ssgalabovstatic int 396297669Ssgalabovmtk_uart_bus_ipend(struct uart_softc *sc) 397297669Ssgalabov{ 398297669Ssgalabov struct uart_bas *bas; 399297669Ssgalabov int ipend; 400297669Ssgalabov uint8_t iir, lsr, msr; 401297669Ssgalabov 402297669Ssgalabov// breakpoint(); 403297669Ssgalabov 404297669Ssgalabov bas = &sc->sc_bas; 405297669Ssgalabov ipend = 0; 406297669Ssgalabov 407297669Ssgalabov uart_lock(sc->sc_hwmtx); 408297669Ssgalabov iir = uart_getreg(&sc->sc_bas, UART_IIR_REG); 409297669Ssgalabov lsr = uart_getreg(&sc->sc_bas, UART_LSR_REG); 410297669Ssgalabov uart_setreg(&sc->sc_bas, UART_LSR_REG, lsr); 411297669Ssgalabov msr = uart_getreg(&sc->sc_bas, UART_MSR_REG); 412297669Ssgalabov uart_setreg(&sc->sc_bas, UART_MSR_REG, msr); 413297669Ssgalabov if (iir & UART_IIR_INTP) { 414297669Ssgalabov uart_unlock(sc->sc_hwmtx); 415297669Ssgalabov return (0); 416297669Ssgalabov } 417297669Ssgalabov switch ((iir >> 1) & 0x07) { 418297669Ssgalabov case UART_IIR_ID_THRE: 419297669Ssgalabov ipend |= SER_INT_TXIDLE; 420297669Ssgalabov break; 421297669Ssgalabov case UART_IIR_ID_DR2: 422297669Ssgalabov mtk_uart_bus_flush(sc, UART_FLUSH_RECEIVER); 423297669Ssgalabov /* passthrough */ 424297669Ssgalabov case UART_IIR_ID_DR: 425297669Ssgalabov ipend |= SER_INT_RXREADY; 426297669Ssgalabov break; 427297669Ssgalabov case UART_IIR_ID_MST: 428297669Ssgalabov case UART_IIR_ID_LINESTATUS: 429297669Ssgalabov ipend |= SER_INT_SIGCHG; 430297669Ssgalabov if (lsr & UART_LSR_BI) 431297669Ssgalabov ipend |= SER_INT_BREAK; 432297669Ssgalabov if (lsr & UART_LSR_OE) 433297669Ssgalabov ipend |= SER_INT_OVERRUN; 434297669Ssgalabov break; 435297669Ssgalabov default: 436297669Ssgalabov /* XXX: maybe return error here */ 437297669Ssgalabov break; 438297669Ssgalabov } 439297669Ssgalabov 440297669Ssgalabov uart_unlock(sc->sc_hwmtx); 441297669Ssgalabov 442297669Ssgalabov return (ipend); 443297669Ssgalabov} 444297669Ssgalabov 445297669Ssgalabovstatic int 446297669Ssgalabovmtk_uart_bus_param(struct uart_softc *sc, int baudrate, int databits, 447297669Ssgalabov int stopbits, int parity) 448297669Ssgalabov{ 449297669Ssgalabov uart_lock(sc->sc_hwmtx); 450297669Ssgalabov mtk_uart_init(&sc->sc_bas, baudrate, databits, stopbits, parity); 451297669Ssgalabov uart_unlock(sc->sc_hwmtx); 452297669Ssgalabov return (0); 453297669Ssgalabov} 454297669Ssgalabov 455297669Ssgalabovstatic int 456297669Ssgalabovmtk_uart_bus_probe(struct uart_softc *sc) 457297669Ssgalabov{ 458297669Ssgalabov int error; 459297669Ssgalabov 460297669Ssgalabov error = mtk_uart_probe(&sc->sc_bas); 461297669Ssgalabov if (error) 462297669Ssgalabov return (error); 463297669Ssgalabov 464297669Ssgalabov device_set_desc(sc->sc_dev, "MTK UART Controller"); 465297669Ssgalabov 466297669Ssgalabov return (0); 467297669Ssgalabov} 468297669Ssgalabov 469297669Ssgalabovstatic int 470297669Ssgalabovmtk_uart_bus_receive(struct uart_softc *sc) 471297669Ssgalabov{ 472297669Ssgalabov struct uart_bas *bas; 473297669Ssgalabov int xc; 474297669Ssgalabov uint8_t lsr; 475297669Ssgalabov 476297669Ssgalabov bas = &sc->sc_bas; 477297669Ssgalabov uart_lock(sc->sc_hwmtx); 478297669Ssgalabov lsr = uart_getreg(bas, UART_LSR_REG); 479297669Ssgalabov while ((lsr & UART_LSR_DR)) { 480297669Ssgalabov if (uart_rx_full(sc)) { 481297669Ssgalabov sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; 482297669Ssgalabov break; 483297669Ssgalabov } 484297669Ssgalabov xc = 0; 485297669Ssgalabov xc = uart_getreg(bas, UART_RX_REG); 486297669Ssgalabov if (lsr & UART_LSR_FE) 487297669Ssgalabov xc |= UART_STAT_FRAMERR; 488297669Ssgalabov if (lsr & UART_LSR_PE) 489297669Ssgalabov xc |= UART_STAT_PARERR; 490297669Ssgalabov if (lsr & UART_LSR_OE) 491297669Ssgalabov xc |= UART_STAT_OVERRUN; 492297669Ssgalabov uart_barrier(bas); 493297669Ssgalabov uart_rx_put(sc, xc); 494297669Ssgalabov lsr = uart_getreg(bas, UART_LSR_REG); 495297669Ssgalabov } 496297669Ssgalabov 497297669Ssgalabov uart_unlock(sc->sc_hwmtx); 498297669Ssgalabov return (0); 499297669Ssgalabov} 500297669Ssgalabov 501297669Ssgalabovstatic int 502297669Ssgalabovmtk_uart_bus_setsig(struct uart_softc *sc, int sig) 503297669Ssgalabov{ 504297669Ssgalabov /* TODO: implement (?) */ 505297669Ssgalabov return (sig); 506297669Ssgalabov} 507297669Ssgalabov 508297669Ssgalabovstatic int 509297669Ssgalabovmtk_uart_bus_transmit(struct uart_softc *sc) 510297669Ssgalabov{ 511297669Ssgalabov struct uart_bas *bas = &sc->sc_bas; 512297669Ssgalabov int i; 513297669Ssgalabov 514297669Ssgalabov if (!uart_output) return (0); 515297669Ssgalabov 516297669Ssgalabov bas = &sc->sc_bas; 517297669Ssgalabov uart_lock(sc->sc_hwmtx); 518297669Ssgalabov while ((uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE) == 0); 519297669Ssgalabov mtk_uart_enable_txintr(sc); 520297669Ssgalabov for (i = 0; i < sc->sc_txdatasz; i++) { 521297669Ssgalabov uart_setreg(bas, UART_TX_REG, sc->sc_txbuf[i]); 522297669Ssgalabov uart_barrier(bas); 523297669Ssgalabov } 524297669Ssgalabov sc->sc_txbusy = 1; 525297669Ssgalabov uart_unlock(sc->sc_hwmtx); 526297669Ssgalabov return (0); 527297669Ssgalabov} 528297669Ssgalabov 529297669Ssgalabovvoid 530297669Ssgalabovmtk_uart_bus_grab(struct uart_softc *sc) 531297669Ssgalabov{ 532297669Ssgalabov struct uart_bas *bas = &sc->sc_bas; 533297669Ssgalabov struct uart_mtk_softc *usc = (struct uart_mtk_softc *)sc; 534297669Ssgalabov 535297669Ssgalabov uart_lock(sc->sc_hwmtx); 536297669Ssgalabov usc->ier = uart_getreg(bas, UART_IER_REG); 537297669Ssgalabov uart_setreg(bas, UART_IER_REG, usc->ier & usc->ier_mask); 538297669Ssgalabov uart_barrier(bas); 539297669Ssgalabov uart_unlock(sc->sc_hwmtx); 540297669Ssgalabov} 541297669Ssgalabov 542297669Ssgalabovvoid 543297669Ssgalabovmtk_uart_bus_ungrab(struct uart_softc *sc) 544297669Ssgalabov{ 545297669Ssgalabov struct uart_mtk_softc *usc = (struct uart_mtk_softc *)sc; 546297669Ssgalabov struct uart_bas *bas = &sc->sc_bas; 547297669Ssgalabov 548297669Ssgalabov uart_lock(sc->sc_hwmtx); 549297669Ssgalabov uart_setreg(bas, UART_IER_REG, usc->ier); 550297669Ssgalabov uart_barrier(bas); 551297669Ssgalabov uart_unlock(sc->sc_hwmtx); 552297669Ssgalabov} 553