1248843Sadrian/*- 2248843Sadrian * Copyright (c) 2013 Adrian Chadd <adrian@FreeBSD.org> 3248843Sadrian * All rights reserved. 4248843Sadrian * 5248843Sadrian * Redistribution and use in source and binary forms, with or without 6248843Sadrian * modification, are permitted provided that the following conditions 7248843Sadrian * are met: 8248843Sadrian * 9248843Sadrian * 1. Redistributions of source code must retain the above copyright 10248843Sadrian * notice, this list of conditions and the following disclaimer. 11248843Sadrian * 2. Redistributions in binary form must reproduce the above copyright 12248843Sadrian * notice, this list of conditions and the following disclaimer in the 13248843Sadrian * documentation and/or other materials provided with the distribution. 14248843Sadrian * 15248843Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16248843Sadrian * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17248843Sadrian * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18248843Sadrian * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19248843Sadrian * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20248843Sadrian * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21248843Sadrian * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22248843Sadrian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23248843Sadrian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24248843Sadrian * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25248843Sadrian */ 26248843Sadrian 27248843Sadrian#include <sys/cdefs.h> 28248843Sadrian__FBSDID("$FreeBSD: releng/10.3/sys/mips/atheros/uart_dev_ar933x.c 262649 2014-03-01 04:16:54Z imp $"); 29248843Sadrian 30248843Sadrian#include <sys/param.h> 31248843Sadrian#include <sys/systm.h> 32248843Sadrian#include <sys/bus.h> 33248843Sadrian#include <sys/conf.h> 34248843Sadrian#include <machine/bus.h> 35248843Sadrian 36248843Sadrian#include <dev/uart/uart.h> 37248843Sadrian#include <dev/uart/uart_cpu.h> 38248843Sadrian#include <dev/uart/uart_bus.h> 39248843Sadrian 40248843Sadrian#include <mips/atheros/ar933x_uart.h> 41248843Sadrian 42248843Sadrian#include "uart_if.h" 43248843Sadrian 44248926Sadrian/* 45248926Sadrian * Default system clock is 25MHz; see ar933x_chip.c for how 46248926Sadrian * the startup process determines whether it's 25MHz or 40MHz. 47248926Sadrian */ 48248926Sadrian#define DEFAULT_RCLK (25 * 1000 * 1000) 49248843Sadrian 50248843Sadrian#define ar933x_getreg(bas, reg) \ 51248926Sadrian bus_space_read_4((bas)->bst, (bas)->bsh, reg) 52248843Sadrian#define ar933x_setreg(bas, reg, value) \ 53248926Sadrian bus_space_write_4((bas)->bst, (bas)->bsh, reg, value) 54248843Sadrian 55248843Sadrian 56248843Sadrian 57248843Sadrianstatic int 58248843Sadrianar933x_drain(struct uart_bas *bas, int what) 59248843Sadrian{ 60249093Sadrian int limit; 61248843Sadrian 62248843Sadrian if (what & UART_DRAIN_TRANSMITTER) { 63248843Sadrian limit = 10*1024; 64249093Sadrian 65249093Sadrian /* Loop over until the TX FIFO shows entirely clear */ 66249093Sadrian while (--limit) { 67249093Sadrian if ((ar933x_getreg(bas, AR933X_UART_CS_REG) 68249093Sadrian & AR933X_UART_CS_TX_BUSY) == 0) 69249093Sadrian break; 70249093Sadrian } 71248843Sadrian if (limit == 0) { 72248843Sadrian return (EIO); 73248843Sadrian } 74248843Sadrian } 75248843Sadrian 76248843Sadrian if (what & UART_DRAIN_RECEIVER) { 77248843Sadrian limit=10*4096; 78249093Sadrian while (--limit) { 79249093Sadrian 80249093Sadrian /* XXX duplicated from ar933x_getc() */ 81249093Sadrian /* XXX TODO: refactor! */ 82249093Sadrian 83249093Sadrian /* If there's nothing to read, stop! */ 84249093Sadrian if ((ar933x_getreg(bas, AR933X_UART_DATA_REG) & 85249093Sadrian AR933X_UART_DATA_RX_CSR) == 0) { 86249093Sadrian break; 87249093Sadrian } 88249093Sadrian 89249093Sadrian /* Read the top of the RX FIFO */ 90249093Sadrian (void) ar933x_getreg(bas, AR933X_UART_DATA_REG); 91249093Sadrian 92249093Sadrian /* Remove that entry from said RX FIFO */ 93249093Sadrian ar933x_setreg(bas, AR933X_UART_DATA_REG, 94249093Sadrian AR933X_UART_DATA_RX_CSR); 95249093Sadrian 96248843Sadrian uart_barrier(bas); 97249093Sadrian DELAY(2); 98248843Sadrian } 99248843Sadrian if (limit == 0) { 100248843Sadrian return (EIO); 101248843Sadrian } 102248843Sadrian } 103248843Sadrian return (0); 104248843Sadrian} 105248843Sadrian 106248843Sadrian/* 107248927Sadrian * Calculate the baud from the given chip configuration parameters. 108248927Sadrian */ 109248927Sadrianstatic unsigned long 110248927Sadrianar933x_uart_get_baud(unsigned int clk, unsigned int scale, 111248927Sadrian unsigned int step) 112248927Sadrian{ 113248927Sadrian uint64_t t; 114248927Sadrian uint32_t div; 115248927Sadrian 116248927Sadrian div = (2 << 16) * (scale + 1); 117248927Sadrian t = clk; 118248927Sadrian t *= step; 119248927Sadrian t += (div / 2); 120248927Sadrian t = t / div; 121248927Sadrian 122248927Sadrian return (t); 123248927Sadrian} 124248927Sadrian 125248927Sadrian/* 126248927Sadrian * Calculate the scale/step with the lowest possible deviation from 127248927Sadrian * the target baudrate. 128248927Sadrian */ 129248927Sadrianstatic void 130248927Sadrianar933x_uart_get_scale_step(struct uart_bas *bas, unsigned int baud, 131248927Sadrian unsigned int *scale, unsigned int *step) 132248927Sadrian{ 133248927Sadrian unsigned int tscale; 134248927Sadrian uint32_t clk; 135248927Sadrian long min_diff; 136248927Sadrian 137248927Sadrian clk = bas->rclk; 138248927Sadrian *scale = 0; 139248927Sadrian *step = 0; 140248927Sadrian 141248927Sadrian min_diff = baud; 142248927Sadrian for (tscale = 0; tscale < AR933X_UART_MAX_SCALE; tscale++) { 143248927Sadrian uint64_t tstep; 144248927Sadrian int diff; 145248927Sadrian 146248927Sadrian tstep = baud * (tscale + 1); 147248927Sadrian tstep *= (2 << 16); 148248927Sadrian tstep = tstep / clk; 149248927Sadrian 150248927Sadrian if (tstep > AR933X_UART_MAX_STEP) 151248927Sadrian break; 152248927Sadrian 153248927Sadrian diff = abs(ar933x_uart_get_baud(clk, tscale, tstep) - baud); 154248927Sadrian if (diff < min_diff) { 155248927Sadrian min_diff = diff; 156248927Sadrian *scale = tscale; 157248927Sadrian *step = tstep; 158248927Sadrian } 159248927Sadrian } 160248927Sadrian} 161248927Sadrian 162248843Sadrianstatic int 163248843Sadrianar933x_param(struct uart_bas *bas, int baudrate, int databits, int stopbits, 164248843Sadrian int parity) 165248843Sadrian{ 166248927Sadrian /* UART always 8 bits */ 167248843Sadrian 168248927Sadrian /* UART always 1 stop bit */ 169248843Sadrian 170248927Sadrian /* UART parity is controllable by bits 0:1, ignore for now */ 171248927Sadrian 172248927Sadrian /* Set baudrate if required. */ 173248843Sadrian if (baudrate > 0) { 174248927Sadrian uint32_t clock_scale, clock_step; 175248927Sadrian 176248927Sadrian /* Find the best fit for the given baud rate */ 177248927Sadrian ar933x_uart_get_scale_step(bas, baudrate, &clock_scale, 178248927Sadrian &clock_step); 179248927Sadrian 180248927Sadrian /* 181248927Sadrian * Program the clock register in its entirety - no need 182248927Sadrian * for Read-Modify-Write. 183248927Sadrian */ 184248927Sadrian ar933x_setreg(bas, AR933X_UART_CLOCK_REG, 185248927Sadrian ((clock_scale & AR933X_UART_CLOCK_SCALE_M) 186248927Sadrian << AR933X_UART_CLOCK_SCALE_S) | 187248927Sadrian (clock_step & AR933X_UART_CLOCK_STEP_M)); 188248843Sadrian } 189248843Sadrian 190248843Sadrian uart_barrier(bas); 191248843Sadrian return (0); 192248843Sadrian} 193248843Sadrian 194248927Sadrian 195248843Sadrian/* 196248843Sadrian * Low-level UART interface. 197248843Sadrian */ 198248843Sadrianstatic int ar933x_probe(struct uart_bas *bas); 199248843Sadrianstatic void ar933x_init(struct uart_bas *bas, int, int, int, int); 200248843Sadrianstatic void ar933x_term(struct uart_bas *bas); 201248843Sadrianstatic void ar933x_putc(struct uart_bas *bas, int); 202248843Sadrianstatic int ar933x_rxready(struct uart_bas *bas); 203248843Sadrianstatic int ar933x_getc(struct uart_bas *bas, struct mtx *); 204248843Sadrian 205248843Sadrianstatic struct uart_ops uart_ar933x_ops = { 206248843Sadrian .probe = ar933x_probe, 207248843Sadrian .init = ar933x_init, 208248843Sadrian .term = ar933x_term, 209248843Sadrian .putc = ar933x_putc, 210248843Sadrian .rxready = ar933x_rxready, 211248843Sadrian .getc = ar933x_getc, 212248843Sadrian}; 213248843Sadrian 214248843Sadrianstatic int 215248843Sadrianar933x_probe(struct uart_bas *bas) 216248843Sadrian{ 217248843Sadrian 218248927Sadrian /* We always know this will be here */ 219248843Sadrian return (0); 220248843Sadrian} 221248843Sadrian 222248843Sadrianstatic void 223248843Sadrianar933x_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, 224248843Sadrian int parity) 225248843Sadrian{ 226248927Sadrian uint32_t reg; 227248843Sadrian 228248927Sadrian /* Setup default parameters */ 229248843Sadrian ar933x_param(bas, baudrate, databits, stopbits, parity); 230248843Sadrian 231248927Sadrian /* XXX Force enable UART in case it was disabled */ 232248843Sadrian 233248927Sadrian /* Disable all interrupts */ 234248927Sadrian ar933x_setreg(bas, AR933X_UART_INT_EN_REG, 0x00000000); 235248843Sadrian 236248927Sadrian /* Disable the host interrupt */ 237248927Sadrian reg = ar933x_getreg(bas, AR933X_UART_CS_REG); 238248927Sadrian reg &= ~AR933X_UART_CS_HOST_INT_EN; 239248927Sadrian ar933x_setreg(bas, AR933X_UART_CS_REG, reg); 240248927Sadrian 241248843Sadrian uart_barrier(bas); 242248843Sadrian 243248927Sadrian /* XXX Set RTS/DTR? */ 244248843Sadrian} 245248843Sadrian 246248927Sadrian/* 247248927Sadrian * Detach from console. 248248927Sadrian */ 249248843Sadrianstatic void 250248843Sadrianar933x_term(struct uart_bas *bas) 251248843Sadrian{ 252248927Sadrian 253248927Sadrian /* XXX TODO */ 254248843Sadrian} 255248843Sadrian 256248843Sadrianstatic void 257248843Sadrianar933x_putc(struct uart_bas *bas, int c) 258248843Sadrian{ 259248843Sadrian int limit; 260248843Sadrian 261248843Sadrian limit = 250000; 262248843Sadrian 263248843Sadrian /* Wait for space in the TX FIFO */ 264248843Sadrian while ( ((ar933x_getreg(bas, AR933X_UART_DATA_REG) & 265248843Sadrian AR933X_UART_DATA_TX_CSR) == 0) && --limit) 266248843Sadrian DELAY(4); 267248843Sadrian 268248843Sadrian /* Write the actual byte */ 269248843Sadrian ar933x_setreg(bas, AR933X_UART_DATA_REG, 270248843Sadrian (c & 0xff) | AR933X_UART_DATA_TX_CSR); 271248843Sadrian} 272248843Sadrian 273248843Sadrianstatic int 274248843Sadrianar933x_rxready(struct uart_bas *bas) 275248843Sadrian{ 276248843Sadrian 277248843Sadrian /* Wait for a character to come ready */ 278248843Sadrian return (!!(ar933x_getreg(bas, AR933X_UART_DATA_REG) 279248843Sadrian & AR933X_UART_DATA_RX_CSR)); 280248843Sadrian} 281248843Sadrian 282248843Sadrianstatic int 283248843Sadrianar933x_getc(struct uart_bas *bas, struct mtx *hwmtx) 284248843Sadrian{ 285248843Sadrian int c; 286248843Sadrian 287248843Sadrian uart_lock(hwmtx); 288248843Sadrian 289248843Sadrian /* Wait for a character to come ready */ 290248843Sadrian while ((ar933x_getreg(bas, AR933X_UART_DATA_REG) & 291248843Sadrian AR933X_UART_DATA_RX_CSR) == 0) { 292248843Sadrian uart_unlock(hwmtx); 293248843Sadrian DELAY(4); 294248843Sadrian uart_lock(hwmtx); 295248843Sadrian } 296248843Sadrian 297248843Sadrian /* Read the top of the RX FIFO */ 298248843Sadrian c = ar933x_getreg(bas, AR933X_UART_DATA_REG) & 0xff; 299248843Sadrian 300248843Sadrian /* Remove that entry from said RX FIFO */ 301248843Sadrian ar933x_setreg(bas, AR933X_UART_DATA_REG, AR933X_UART_DATA_RX_CSR); 302248843Sadrian 303248843Sadrian uart_unlock(hwmtx); 304248843Sadrian 305248843Sadrian return (c); 306248843Sadrian} 307248843Sadrian 308248843Sadrian/* 309248843Sadrian * High-level UART interface. 310248843Sadrian */ 311248843Sadrianstruct ar933x_softc { 312248843Sadrian struct uart_softc base; 313248926Sadrian 314248843Sadrian uint32_t u_ier; 315248843Sadrian}; 316248843Sadrian 317248843Sadrianstatic int ar933x_bus_attach(struct uart_softc *); 318248843Sadrianstatic int ar933x_bus_detach(struct uart_softc *); 319248843Sadrianstatic int ar933x_bus_flush(struct uart_softc *, int); 320248843Sadrianstatic int ar933x_bus_getsig(struct uart_softc *); 321248843Sadrianstatic int ar933x_bus_ioctl(struct uart_softc *, int, intptr_t); 322248843Sadrianstatic int ar933x_bus_ipend(struct uart_softc *); 323248843Sadrianstatic int ar933x_bus_param(struct uart_softc *, int, int, int, int); 324248843Sadrianstatic int ar933x_bus_probe(struct uart_softc *); 325248843Sadrianstatic int ar933x_bus_receive(struct uart_softc *); 326248843Sadrianstatic int ar933x_bus_setsig(struct uart_softc *, int); 327248843Sadrianstatic int ar933x_bus_transmit(struct uart_softc *); 328262649Simpstatic void ar933x_bus_grab(struct uart_softc *); 329262649Simpstatic void ar933x_bus_ungrab(struct uart_softc *); 330248843Sadrian 331248843Sadrianstatic kobj_method_t ar933x_methods[] = { 332248843Sadrian KOBJMETHOD(uart_attach, ar933x_bus_attach), 333248843Sadrian KOBJMETHOD(uart_detach, ar933x_bus_detach), 334248843Sadrian KOBJMETHOD(uart_flush, ar933x_bus_flush), 335248843Sadrian KOBJMETHOD(uart_getsig, ar933x_bus_getsig), 336248843Sadrian KOBJMETHOD(uart_ioctl, ar933x_bus_ioctl), 337248843Sadrian KOBJMETHOD(uart_ipend, ar933x_bus_ipend), 338248843Sadrian KOBJMETHOD(uart_param, ar933x_bus_param), 339248843Sadrian KOBJMETHOD(uart_probe, ar933x_bus_probe), 340248843Sadrian KOBJMETHOD(uart_receive, ar933x_bus_receive), 341248843Sadrian KOBJMETHOD(uart_setsig, ar933x_bus_setsig), 342248843Sadrian KOBJMETHOD(uart_transmit, ar933x_bus_transmit), 343262649Simp KOBJMETHOD(uart_grab, ar933x_bus_grab), 344262649Simp KOBJMETHOD(uart_ungrab, ar933x_bus_ungrab), 345248843Sadrian { 0, 0 } 346248843Sadrian}; 347248843Sadrian 348248843Sadrianstruct uart_class uart_ar933x_class = { 349248843Sadrian "ar933x", 350248843Sadrian ar933x_methods, 351248843Sadrian sizeof(struct ar933x_softc), 352248843Sadrian .uc_ops = &uart_ar933x_ops, 353248843Sadrian .uc_range = 8, 354248843Sadrian .uc_rclk = DEFAULT_RCLK 355248843Sadrian}; 356248843Sadrian 357248843Sadrian#define SIGCHG(c, i, s, d) \ 358248843Sadrian if (c) { \ 359248843Sadrian i |= (i & s) ? s : s | d; \ 360248843Sadrian } else { \ 361248843Sadrian i = (i & s) ? (i & ~s) | d : i; \ 362248843Sadrian } 363248843Sadrian 364248843Sadrianstatic int 365248843Sadrianar933x_bus_attach(struct uart_softc *sc) 366248843Sadrian{ 367249120Sadrian struct ar933x_softc *u = (struct ar933x_softc *)sc; 368249120Sadrian struct uart_bas *bas = &sc->sc_bas; 369249120Sadrian uint32_t reg; 370249120Sadrian 371249093Sadrian /* XXX TODO: flush transmitter */ 372248843Sadrian 373249120Sadrian /* 374249120Sadrian * Setup initial interrupt notifications. 375249120Sadrian * 376249120Sadrian * XXX for now, just RX FIFO valid. 377249120Sadrian * Later on (when they're handled), also handle 378249120Sadrian * RX errors/overflow. 379249120Sadrian */ 380249120Sadrian u->u_ier = AR933X_UART_INT_RX_VALID; 381248843Sadrian 382249120Sadrian /* Enable RX interrupts to kick-start things */ 383249120Sadrian ar933x_setreg(bas, AR933X_UART_INT_EN_REG, u->u_ier); 384248843Sadrian 385249120Sadrian /* Enable the host interrupt now */ 386249120Sadrian reg = ar933x_getreg(bas, AR933X_UART_CS_REG); 387249120Sadrian reg |= AR933X_UART_CS_HOST_INT_EN; 388249120Sadrian ar933x_setreg(bas, AR933X_UART_CS_REG, reg); 389249120Sadrian 390248843Sadrian return (0); 391248843Sadrian} 392248843Sadrian 393248843Sadrianstatic int 394248843Sadrianar933x_bus_detach(struct uart_softc *sc) 395248843Sadrian{ 396249120Sadrian struct uart_bas *bas = &sc->sc_bas; 397249120Sadrian uint32_t reg; 398248843Sadrian 399249120Sadrian /* Disable all interrupts */ 400249120Sadrian ar933x_setreg(bas, AR933X_UART_INT_EN_REG, 0x00000000); 401249120Sadrian 402249120Sadrian /* Disable the host interrupt */ 403249120Sadrian reg = ar933x_getreg(bas, AR933X_UART_CS_REG); 404249120Sadrian reg &= ~AR933X_UART_CS_HOST_INT_EN; 405249120Sadrian ar933x_setreg(bas, AR933X_UART_CS_REG, reg); 406248843Sadrian uart_barrier(bas); 407249093Sadrian 408248843Sadrian return (0); 409248843Sadrian} 410248843Sadrian 411248843Sadrianstatic int 412248843Sadrianar933x_bus_flush(struct uart_softc *sc, int what) 413248843Sadrian{ 414248843Sadrian struct uart_bas *bas; 415248843Sadrian 416248843Sadrian bas = &sc->sc_bas; 417248843Sadrian uart_lock(sc->sc_hwmtx); 418249093Sadrian ar933x_drain(bas, what); 419248843Sadrian uart_unlock(sc->sc_hwmtx); 420249093Sadrian 421249093Sadrian return (0); 422248843Sadrian} 423248843Sadrian 424248843Sadrianstatic int 425248843Sadrianar933x_bus_getsig(struct uart_softc *sc) 426248843Sadrian{ 427249093Sadrian uint32_t sig = sc->sc_hwsig; 428248843Sadrian 429249093Sadrian /* 430249093Sadrian * For now, let's just return that DSR/DCD/CTS is asserted. 431249093Sadrian * 432249093Sadrian * XXX TODO: actually verify whether this is correct! 433249093Sadrian */ 434249093Sadrian SIGCHG(1, sig, SER_DSR, SER_DDSR); 435249093Sadrian SIGCHG(1, sig, SER_CTS, SER_DCTS); 436249093Sadrian SIGCHG(1, sig, SER_DCD, SER_DDCD); 437249093Sadrian SIGCHG(1, sig, SER_RI, SER_DRI); 438249093Sadrian 439249093Sadrian sc->sc_hwsig = sig & ~SER_MASK_DELTA; 440249093Sadrian 441248843Sadrian return (sig); 442248843Sadrian} 443248843Sadrian 444248843Sadrianstatic int 445248843Sadrianar933x_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) 446248843Sadrian{ 447248843Sadrian#if 0 448248843Sadrian struct uart_bas *bas; 449248843Sadrian int baudrate, divisor, error; 450248843Sadrian uint8_t efr, lcr; 451248843Sadrian 452248843Sadrian bas = &sc->sc_bas; 453248843Sadrian error = 0; 454248843Sadrian uart_lock(sc->sc_hwmtx); 455248843Sadrian switch (request) { 456248843Sadrian case UART_IOCTL_BREAK: 457248843Sadrian lcr = uart_getreg(bas, REG_LCR); 458248843Sadrian if (data) 459248843Sadrian lcr |= LCR_SBREAK; 460248843Sadrian else 461248843Sadrian lcr &= ~LCR_SBREAK; 462248843Sadrian uart_setreg(bas, REG_LCR, lcr); 463248843Sadrian uart_barrier(bas); 464248843Sadrian break; 465248843Sadrian case UART_IOCTL_IFLOW: 466248843Sadrian lcr = uart_getreg(bas, REG_LCR); 467248843Sadrian uart_barrier(bas); 468248843Sadrian uart_setreg(bas, REG_LCR, 0xbf); 469248843Sadrian uart_barrier(bas); 470248843Sadrian efr = uart_getreg(bas, REG_EFR); 471248843Sadrian if (data) 472248843Sadrian efr |= EFR_RTS; 473248843Sadrian else 474248843Sadrian efr &= ~EFR_RTS; 475248843Sadrian uart_setreg(bas, REG_EFR, efr); 476248843Sadrian uart_barrier(bas); 477248843Sadrian uart_setreg(bas, REG_LCR, lcr); 478248843Sadrian uart_barrier(bas); 479248843Sadrian break; 480248843Sadrian case UART_IOCTL_OFLOW: 481248843Sadrian lcr = uart_getreg(bas, REG_LCR); 482248843Sadrian uart_barrier(bas); 483248843Sadrian uart_setreg(bas, REG_LCR, 0xbf); 484248843Sadrian uart_barrier(bas); 485248843Sadrian efr = uart_getreg(bas, REG_EFR); 486248843Sadrian if (data) 487248843Sadrian efr |= EFR_CTS; 488248843Sadrian else 489248843Sadrian efr &= ~EFR_CTS; 490248843Sadrian uart_setreg(bas, REG_EFR, efr); 491248843Sadrian uart_barrier(bas); 492248843Sadrian uart_setreg(bas, REG_LCR, lcr); 493248843Sadrian uart_barrier(bas); 494248843Sadrian break; 495248843Sadrian case UART_IOCTL_BAUD: 496248843Sadrian lcr = uart_getreg(bas, REG_LCR); 497248843Sadrian uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); 498248843Sadrian uart_barrier(bas); 499248843Sadrian divisor = uart_getreg(bas, REG_DLL) | 500248843Sadrian (uart_getreg(bas, REG_DLH) << 8); 501248843Sadrian uart_barrier(bas); 502248843Sadrian uart_setreg(bas, REG_LCR, lcr); 503248843Sadrian uart_barrier(bas); 504248843Sadrian baudrate = (divisor > 0) ? bas->rclk / divisor / 16 : 0; 505248843Sadrian if (baudrate > 0) 506248843Sadrian *(int*)data = baudrate; 507248843Sadrian else 508248843Sadrian error = ENXIO; 509248843Sadrian break; 510248843Sadrian default: 511248843Sadrian error = EINVAL; 512248843Sadrian break; 513248843Sadrian } 514248843Sadrian uart_unlock(sc->sc_hwmtx); 515248843Sadrian return (error); 516248843Sadrian#endif 517248843Sadrian return (ENXIO); 518248843Sadrian} 519248843Sadrian 520249093Sadrian/* 521249093Sadrian * Bus interrupt handler. 522249093Sadrian * 523249093Sadrian * For now, system interrupts are disabled. 524249093Sadrian * So this is just called from a callout in uart_core.c 525249093Sadrian * to poll various state. 526249093Sadrian */ 527248843Sadrianstatic int 528248843Sadrianar933x_bus_ipend(struct uart_softc *sc) 529248843Sadrian{ 530249120Sadrian struct ar933x_softc *u = (struct ar933x_softc *)sc; 531249093Sadrian struct uart_bas *bas = &sc->sc_bas; 532249093Sadrian int ipend = 0; 533249120Sadrian uint32_t isr; 534248843Sadrian 535248843Sadrian uart_lock(sc->sc_hwmtx); 536249093Sadrian 537249093Sadrian /* 538249120Sadrian * Fetch/ACK the ISR status. 539249093Sadrian */ 540249120Sadrian isr = ar933x_getreg(bas, AR933X_UART_INT_REG); 541249120Sadrian ar933x_setreg(bas, AR933X_UART_INT_REG, isr); 542249120Sadrian uart_barrier(bas); 543249120Sadrian 544249120Sadrian /* 545249120Sadrian * RX ready - notify upper layer. 546249120Sadrian */ 547249120Sadrian if (isr & AR933X_UART_INT_RX_VALID) { 548249093Sadrian ipend |= SER_INT_RXREADY; 549248843Sadrian } 550249120Sadrian 551249093Sadrian /* 552249120Sadrian * If we get this interrupt, we should disable 553249120Sadrian * it from the interrupt mask and inform the uart 554249120Sadrian * driver appropriately. 555249120Sadrian * 556249120Sadrian * We can't keep setting SER_INT_TXIDLE or SER_INT_SIGCHG 557249120Sadrian * all the time or IO stops working. So we will always 558249120Sadrian * clear this interrupt if we get it, then we only signal 559249120Sadrian * the upper layer if we were doing active TX in the 560249120Sadrian * first place. 561249120Sadrian * 562249120Sadrian * Also, the name is misleading. This actually means 563249120Sadrian * "the FIFO is almost empty." So if we just write some 564249120Sadrian * more data to the FIFO without checking whether it can 565249120Sadrian * take said data, we'll overflow the thing. 566249120Sadrian * 567249120Sadrian * Unfortunately the FreeBSD uart device has no concept of 568249120Sadrian * partial UART writes - it expects that the whole buffer 569249120Sadrian * is written to the hardware. Thus for now, ar933x_bus_transmit() 570249120Sadrian * will wait for the FIFO to finish draining before it pushes 571249120Sadrian * more frames into it. 572249120Sadrian */ 573249120Sadrian if (isr & AR933X_UART_INT_TX_EMPTY) { 574249120Sadrian /* 575249120Sadrian * Update u_ier to disable TX notifications; update hardware 576249120Sadrian */ 577249120Sadrian u->u_ier &= ~AR933X_UART_INT_TX_EMPTY; 578249120Sadrian ar933x_setreg(bas, AR933X_UART_INT_EN_REG, u->u_ier); 579249120Sadrian uart_barrier(bas); 580249120Sadrian } 581249120Sadrian 582249120Sadrian /* 583249093Sadrian * Only signal TX idle if we're not busy transmitting. 584249093Sadrian */ 585249093Sadrian if (sc->sc_txbusy) { 586249120Sadrian if (isr & AR933X_UART_INT_TX_EMPTY) { 587248843Sadrian ipend |= SER_INT_TXIDLE; 588249093Sadrian } else { 589248843Sadrian ipend |= SER_INT_SIGCHG; 590249093Sadrian } 591248843Sadrian } 592249093Sadrian 593248843Sadrian uart_unlock(sc->sc_hwmtx); 594248843Sadrian return (ipend); 595248843Sadrian} 596248843Sadrian 597248843Sadrianstatic int 598248843Sadrianar933x_bus_param(struct uart_softc *sc, int baudrate, int databits, 599248843Sadrian int stopbits, int parity) 600248843Sadrian{ 601248843Sadrian struct uart_bas *bas; 602248843Sadrian int error; 603248843Sadrian 604248843Sadrian bas = &sc->sc_bas; 605248843Sadrian uart_lock(sc->sc_hwmtx); 606248843Sadrian error = ar933x_param(bas, baudrate, databits, stopbits, parity); 607248843Sadrian uart_unlock(sc->sc_hwmtx); 608248843Sadrian return (error); 609248843Sadrian} 610248843Sadrian 611248843Sadrianstatic int 612248843Sadrianar933x_bus_probe(struct uart_softc *sc) 613248843Sadrian{ 614248843Sadrian struct uart_bas *bas; 615249093Sadrian int error; 616248843Sadrian 617248843Sadrian bas = &sc->sc_bas; 618248843Sadrian 619248843Sadrian error = ar933x_probe(bas); 620248843Sadrian if (error) 621248843Sadrian return (error); 622248843Sadrian 623248843Sadrian /* Reset FIFOs. */ 624249093Sadrian ar933x_drain(bas, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER); 625248843Sadrian 626249093Sadrian /* XXX TODO: actually find out what the FIFO depth is! */ 627249093Sadrian sc->sc_rxfifosz = 16; 628248843Sadrian sc->sc_txfifosz = 16; 629248843Sadrian 630248843Sadrian return (0); 631248843Sadrian} 632248843Sadrian 633248843Sadrianstatic int 634248843Sadrianar933x_bus_receive(struct uart_softc *sc) 635248843Sadrian{ 636249093Sadrian struct uart_bas *bas = &sc->sc_bas; 637248843Sadrian int xc; 638248843Sadrian 639248843Sadrian uart_lock(sc->sc_hwmtx); 640249093Sadrian 641249093Sadrian /* Loop over until we are full, or no data is available */ 642249093Sadrian while (ar933x_rxready(bas)) { 643248843Sadrian if (uart_rx_full(sc)) { 644248843Sadrian sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; 645248843Sadrian break; 646248843Sadrian } 647249093Sadrian 648249093Sadrian /* Read the top of the RX FIFO */ 649249093Sadrian xc = ar933x_getreg(bas, AR933X_UART_DATA_REG) & 0xff; 650249093Sadrian 651249093Sadrian /* Remove that entry from said RX FIFO */ 652249093Sadrian ar933x_setreg(bas, AR933X_UART_DATA_REG, 653249093Sadrian AR933X_UART_DATA_RX_CSR); 654249120Sadrian uart_barrier(bas); 655249093Sadrian 656249093Sadrian /* XXX frame, parity error */ 657248843Sadrian uart_rx_put(sc, xc); 658248843Sadrian } 659249093Sadrian 660249093Sadrian /* 661249093Sadrian * XXX TODO: Discard everything left in the Rx FIFO? 662249093Sadrian * XXX only if we've hit an overrun condition? 663249093Sadrian */ 664249093Sadrian 665248843Sadrian uart_unlock(sc->sc_hwmtx); 666249093Sadrian 667248843Sadrian return (0); 668248843Sadrian} 669248843Sadrian 670248843Sadrianstatic int 671248843Sadrianar933x_bus_setsig(struct uart_softc *sc, int sig) 672248843Sadrian{ 673248843Sadrian#if 0 674248843Sadrian struct ar933x_softc *ns8250 = (struct ar933x_softc*)sc; 675248843Sadrian struct uart_bas *bas; 676248843Sadrian uint32_t new, old; 677248843Sadrian 678248843Sadrian bas = &sc->sc_bas; 679248843Sadrian do { 680248843Sadrian old = sc->sc_hwsig; 681248843Sadrian new = old; 682248843Sadrian if (sig & SER_DDTR) { 683248843Sadrian SIGCHG(sig & SER_DTR, new, SER_DTR, 684248843Sadrian SER_DDTR); 685248843Sadrian } 686248843Sadrian if (sig & SER_DRTS) { 687248843Sadrian SIGCHG(sig & SER_RTS, new, SER_RTS, 688248843Sadrian SER_DRTS); 689248843Sadrian } 690248843Sadrian } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); 691248843Sadrian uart_lock(sc->sc_hwmtx); 692248843Sadrian ns8250->mcr &= ~(MCR_DTR|MCR_RTS); 693248843Sadrian if (new & SER_DTR) 694248843Sadrian ns8250->mcr |= MCR_DTR; 695248843Sadrian if (new & SER_RTS) 696248843Sadrian ns8250->mcr |= MCR_RTS; 697248843Sadrian uart_setreg(bas, REG_MCR, ns8250->mcr); 698248843Sadrian uart_barrier(bas); 699248843Sadrian uart_unlock(sc->sc_hwmtx); 700248843Sadrian#endif 701248843Sadrian return (0); 702248843Sadrian} 703248843Sadrian 704249120Sadrian/* 705249120Sadrian * Write the current transmit buffer to the TX FIFO. 706249120Sadrian * 707249120Sadrian * Unfortunately the FreeBSD uart device has no concept of 708249120Sadrian * partial UART writes - it expects that the whole buffer 709249120Sadrian * is written to the hardware. Thus for now, this will wait for 710249120Sadrian * the FIFO to finish draining before it pushes more frames into it. 711249120Sadrian * 712249120Sadrian * If non-blocking operation is truely needed here, either 713249120Sadrian * the FreeBSD uart device will need to handle partial writes 714249120Sadrian * in xxx_bus_transmit(), or we'll need to do TX FIFO buffering 715249120Sadrian * of our own here. 716249120Sadrian */ 717248843Sadrianstatic int 718248843Sadrianar933x_bus_transmit(struct uart_softc *sc) 719248843Sadrian{ 720249093Sadrian struct uart_bas *bas = &sc->sc_bas; 721249120Sadrian struct ar933x_softc *u = (struct ar933x_softc *)sc; 722248843Sadrian int i; 723248843Sadrian 724248843Sadrian uart_lock(sc->sc_hwmtx); 725249093Sadrian 726249120Sadrian /* Wait for the FIFO to be clear - see above */ 727249120Sadrian while (ar933x_getreg(bas, AR933X_UART_CS_REG) & 728249120Sadrian AR933X_UART_CS_TX_BUSY) 729249120Sadrian ; 730249093Sadrian 731249120Sadrian /* 732249120Sadrian * Write some data! 733249120Sadrian */ 734248843Sadrian for (i = 0; i < sc->sc_txdatasz; i++) { 735249093Sadrian /* Write the TX data */ 736249093Sadrian ar933x_setreg(bas, AR933X_UART_DATA_REG, 737249093Sadrian (sc->sc_txbuf[i] & 0xff) | AR933X_UART_DATA_TX_CSR); 738249120Sadrian uart_barrier(bas); 739248843Sadrian } 740249093Sadrian 741249093Sadrian /* 742249120Sadrian * Now that we're transmitting, get interrupt notification 743249120Sadrian * when the FIFO is (almost) empty - see above. 744249120Sadrian */ 745249120Sadrian u->u_ier |= AR933X_UART_INT_TX_EMPTY; 746249120Sadrian ar933x_setreg(bas, AR933X_UART_INT_EN_REG, u->u_ier); 747249120Sadrian uart_barrier(bas); 748249120Sadrian 749249120Sadrian /* 750249093Sadrian * Inform the upper layer that we are presently transmitting 751249093Sadrian * data to the hardware; this will be cleared when the 752249093Sadrian * TXIDLE interrupt occurs. 753249093Sadrian */ 754248843Sadrian sc->sc_txbusy = 1; 755248843Sadrian uart_unlock(sc->sc_hwmtx); 756249093Sadrian 757248843Sadrian return (0); 758248843Sadrian} 759262649Simp 760262649Simpstatic void 761262649Simpar933x_bus_grab(struct uart_softc *sc) 762262649Simp{ 763262649Simp struct uart_bas *bas = &sc->sc_bas; 764262649Simp uint32_t reg; 765262649Simp 766262649Simp /* Disable the host interrupt now */ 767262649Simp uart_lock(sc->sc_hwmtx); 768262649Simp reg = ar933x_getreg(bas, AR933X_UART_CS_REG); 769262649Simp reg &= ~AR933X_UART_CS_HOST_INT_EN; 770262649Simp ar933x_setreg(bas, AR933X_UART_CS_REG, reg); 771262649Simp uart_unlock(sc->sc_hwmtx); 772262649Simp} 773262649Simp 774262649Simpstatic void 775262649Simpar933x_bus_ungrab(struct uart_softc *sc) 776262649Simp{ 777262649Simp struct uart_bas *bas = &sc->sc_bas; 778262649Simp uint32_t reg; 779262649Simp 780262649Simp /* Enable the host interrupt now */ 781262649Simp uart_lock(sc->sc_hwmtx); 782262649Simp reg = ar933x_getreg(bas, AR933X_UART_CS_REG); 783262649Simp reg |= AR933X_UART_CS_HOST_INT_EN; 784262649Simp ar933x_setreg(bas, AR933X_UART_CS_REG, reg); 785262649Simp uart_unlock(sc->sc_hwmtx); 786262649Simp} 787