uart_dev_quicc.c revision 185187
125603Skjc/*- 2139749Simp * Copyright (c) 2006 Juniper Networks 325603Skjc * All rights reserved. 425603Skjc * 525603Skjc * Redistribution and use in source and binary forms, with or without 625603Skjc * modification, are permitted provided that the following conditions 725603Skjc * are met: 825603Skjc * 925603Skjc * 1. Redistributions of source code must retain the above copyright 1025603Skjc * notice, this list of conditions and the following disclaimer. 1125603Skjc * 2. Redistributions in binary form must reproduce the above copyright 1225603Skjc * notice, this list of conditions and the following disclaimer in the 1325603Skjc * documentation and/or other materials provided with the distribution. 1425603Skjc * 1525603Skjc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1625603Skjc * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1725603Skjc * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1825603Skjc * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1925603Skjc * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2025603Skjc * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2125603Skjc * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2225603Skjc * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2325603Skjc * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2425603Skjc * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2525603Skjc */ 2625603Skjc 2725603Skjc#include <sys/cdefs.h> 2825603Skjc__FBSDID("$FreeBSD: head/sys/dev/uart/uart_dev_quicc.c 185187 2008-11-22 21:22:53Z marcel $"); 2925603Skjc 3025603Skjc#include <sys/param.h> 3146814Speter#include <sys/systm.h> 3225603Skjc#include <sys/bus.h> 3325603Skjc#include <sys/conf.h> 34119418Sobrien#include <sys/endian.h> 35119418Sobrien#include <machine/bus.h> 36119418Sobrien 3725603Skjc#include <dev/ic/quicc.h> 3825603Skjc 3925603Skjc#include <dev/uart/uart.h> 4025603Skjc#include <dev/uart/uart_cpu.h> 4125603Skjc#include <dev/uart/uart_bus.h> 4225603Skjc 4325603Skjc#include "uart_if.h" 4425603Skjc 4525603Skjc#define DEFAULT_RCLK ((266000000 * 2) / 16) 46116192Sobrien 4725603Skjc#define quicc_read2(bas, reg) \ 4825603Skjc bus_space_read_2((bas)->bst, (bas)->bsh, reg) 49129879Sphk#define quicc_read4(bas, reg) \ 5025603Skjc bus_space_read_4((bas)->bst, (bas)->bsh, reg) 5125603Skjc 52114018Sharti#define quicc_write2(bas, reg, val) \ 53118494Sharti bus_space_write_2((bas)->bst, (bas)->bsh, reg, val) 5425603Skjc#define quicc_write4(bas, reg, val) \ 5568433Skjc bus_space_write_4((bas)->bst, (bas)->bsh, reg, val) 5668317Sbde 5768433Skjcstatic int 5868433Skjcquicc_divisor(int rclk, int baudrate) 5925603Skjc{ 60114018Sharti int act_baud, divisor, error; 61114018Sharti 6225603Skjc if (baudrate == 0) 63114018Sharti return (-1); 64116294Sharti 65147256Sbrooks divisor = rclk / baudrate / 16; 6625603Skjc if (divisor > 4096) 67119277Simp divisor = ((divisor >> 3) - 2) | 1; 68119277Simp else if (divisor >= 0) 6925603Skjc divisor = (divisor - 1) << 1; 70116294Sharti if (divisor < 0 || divisor >= 8192) 7125603Skjc return (-1); 7225603Skjc act_baud = rclk / (((divisor >> 1) + 1) << ((divisor & 1) ? 8 : 4)); 7325603Skjc 74114201Sharti /* 10 times error in percent: */ 75114201Sharti error = ((act_baud - baudrate) * 2000 / baudrate + 1) >> 1; 76116294Sharti 77114201Sharti /* 3.0% maximum error tolerance: */ 7825603Skjc if (error < -30 || error > 30) 7925603Skjc return (-1); 8025603Skjc 8125603Skjc return (divisor); 82114018Sharti} 83114018Sharti 8425603Skjcstatic int 85114018Shartiquicc_param(struct uart_bas *bas, int baudrate, int databits, int stopbits, 86114018Sharti int parity) 87114018Sharti{ 88114018Sharti int divisor; 8925603Skjc uint16_t psmr; 9025603Skjc 9192739Salfred if (baudrate > 0) { 9292739Salfred divisor = quicc_divisor(bas->rclk, baudrate); 9342426Skjc if (divisor == -1) 9425603Skjc return (EINVAL); 9525603Skjc quicc_write4(bas, QUICC_REG_BRG(bas->chan - 1), 9625603Skjc divisor | 0x10000); 9725603Skjc } 98150712Sjhb 9925603Skjc psmr = 0; 10025603Skjc switch (databits) { 10125603Skjc case 5: psmr |= 0x0000; break; 10225603Skjc case 6: psmr |= 0x1000; break; 10325603Skjc case 7: psmr |= 0x2000; break; 10425603Skjc case 8: psmr |= 0x3000; break; 10525603Skjc default: return (EINVAL); 10625603Skjc } 10725603Skjc switch (stopbits) { 108114018Sharti case 1: psmr |= 0x0000; break; 109114018Sharti case 2: psmr |= 0x4000; break; 110114018Sharti default: return (EINVAL); 111114018Sharti } 11225603Skjc switch (parity) { 11325603Skjc case UART_PARITY_EVEN: psmr |= 0x1a; break; 11425603Skjc case UART_PARITY_MARK: psmr |= 0x1f; break; 11525603Skjc case UART_PARITY_NONE: psmr |= 0x00; break; 11625603Skjc case UART_PARITY_ODD: psmr |= 0x10; break; 11725603Skjc case UART_PARITY_SPACE: psmr |= 0x15; break; 11825603Skjc default: return (EINVAL); 11925603Skjc } 12025603Skjc quicc_write2(bas, QUICC_REG_SCC_PSMR(bas->chan - 1), psmr); 12125603Skjc return (0); 12225603Skjc} 12325603Skjc 12425603Skjcstatic void 12525603Skjcquicc_setup(struct uart_bas *bas, int baudrate, int databits, int stopbits, 12625603Skjc int parity) 12725603Skjc{ 12825603Skjc 12925603Skjc if (bas->rclk == 0) 13025603Skjc bas->rclk = DEFAULT_RCLK; 13125603Skjc 13225603Skjc /* 13325603Skjc * GSMR_L = 0x00028034 13425603Skjc * GSMR_H = 0x00000020 135114018Sharti */ 136114018Sharti quicc_param(bas, baudrate, databits, stopbits, parity); 13725603Skjc 138114018Sharti quicc_write2(bas, QUICC_REG_SCC_SCCE(bas->chan - 1), ~0); 139114018Sharti quicc_write2(bas, QUICC_REG_SCC_SCCM(bas->chan - 1), 0x0027); 14025603Skjc} 141114018Sharti 142114018Sharti/* 143114018Sharti * Low-level UART interface. 144114018Sharti */ 145114018Shartistatic int quicc_probe(struct uart_bas *bas); 146114018Shartistatic void quicc_init(struct uart_bas *bas, int, int, int, int); 147114018Shartistatic void quicc_term(struct uart_bas *bas); 148114018Shartistatic void quicc_putc(struct uart_bas *bas, int); 149114018Shartistatic int quicc_rxready(struct uart_bas *bas); 150162321Sglebiusstatic int quicc_getc(struct uart_bas *bas, struct mtx *); 151162321Sglebius 15225603Skjcstatic struct uart_ops uart_quicc_ops = { 15325603Skjc .probe = quicc_probe, 15425603Skjc .init = quicc_init, 15525603Skjc .term = quicc_term, 15625603Skjc .putc = quicc_putc, 15725603Skjc .rxready = quicc_rxready, 15825603Skjc .getc = quicc_getc, 15968433Skjc}; 16068433Skjc 16125603Skjcstatic int 162118487Shartiquicc_probe(struct uart_bas *bas) 163114018Sharti{ 164114018Sharti 165114018Sharti return (0); 166114018Sharti} 167114018Sharti 168114018Shartistatic void 169114018Shartiquicc_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, 170114018Sharti int parity) 171143161Simp{ 172114018Sharti 173114018Sharti quicc_setup(bas, baudrate, databits, stopbits, parity); 174114018Sharti} 175114018Sharti 176114018Shartistatic void 177114018Shartiquicc_term(struct uart_bas *bas) 178114018Sharti{ 179114018Sharti} 180114018Sharti 181143161Simpstatic void 182114018Shartiquicc_putc(struct uart_bas *bas, int c) 183114018Sharti{ 184114018Sharti int unit; 185114018Sharti uint16_t toseq; 18625603Skjc 18725603Skjc unit = bas->chan - 1; 18868433Skjc while (quicc_read2(bas, QUICC_PRAM_SCC_UART_TOSEQ(unit)) & 0x2000) 18968433Skjc DELAY(10); 19025603Skjc 191114018Sharti toseq = 0x2000 | (c & 0xff); 192114018Sharti quicc_write2(bas, QUICC_PRAM_SCC_UART_TOSEQ(unit), toseq); 193121816Sbrooks} 19425603Skjc 195114018Shartistatic int 196114018Shartiquicc_rxready(struct uart_bas *bas) 197162321Sglebius{ 198147256Sbrooks uint16_t rb; 199150215Sru 200150215Sru rb = quicc_read2(bas, QUICC_PRAM_SCC_RBASE(bas->chan - 1)); 201150215Sru return ((quicc_read2(bas, rb) & 0x8000) ? 0 : 1); 202150215Sru} 203150215Sru 20425603Skjcstatic int 205147256Sbrooksquicc_getc(struct uart_bas *bas, struct mtx *hwmtx) 206121816Sbrooks{ 20725603Skjc volatile char *buf; 208114018Sharti int c; 209114018Sharti uint16_t rb, sc; 210114018Sharti 211150712Sjhb uart_lock(hwmtx); 21225603Skjc 213114018Sharti rb = quicc_read2(bas, QUICC_PRAM_SCC_RBASE(bas->chan - 1)); 214114018Sharti 215114018Sharti while ((sc = quicc_read2(bas, rb)) & 0x8000) { 216114018Sharti uart_unlock(hwmtx); 217127135Snjl DELAY(4); 218127135Snjl uart_lock(hwmtx); 219114018Sharti } 220114018Sharti 221150215Sru buf = (void *)(uintptr_t)quicc_read4(bas, rb + 4); 222114018Sharti c = *buf; 223114018Sharti quicc_write2(bas, rb, sc | 0x8000); 224114018Sharti 22525603Skjc uart_unlock(hwmtx); 226114018Sharti 227114018Sharti return (c); 22825603Skjc} 229114018Sharti 230114018Sharti/* 231114018Sharti * High-level UART interface. 232114018Sharti */ 233127135Snjlstruct quicc_softc { 234114018Sharti struct uart_softc base; 235114018Sharti}; 236114018Sharti 237114018Shartistatic int quicc_bus_attach(struct uart_softc *); 238150215Srustatic int quicc_bus_detach(struct uart_softc *); 239114018Shartistatic int quicc_bus_flush(struct uart_softc *, int); 240114018Shartistatic int quicc_bus_getsig(struct uart_softc *); 241114018Shartistatic int quicc_bus_ioctl(struct uart_softc *, int, intptr_t); 24225603Skjcstatic int quicc_bus_ipend(struct uart_softc *); 243114018Shartistatic int quicc_bus_param(struct uart_softc *, int, int, int, int); 24468433Skjcstatic int quicc_bus_probe(struct uart_softc *); 245114018Shartistatic int quicc_bus_receive(struct uart_softc *); 246114018Shartistatic int quicc_bus_setsig(struct uart_softc *, int); 24725603Skjcstatic int quicc_bus_transmit(struct uart_softc *); 248114018Sharti 249114018Shartistatic kobj_method_t quicc_methods[] = { 250114018Sharti KOBJMETHOD(uart_attach, quicc_bus_attach), 251114018Sharti KOBJMETHOD(uart_detach, quicc_bus_detach), 252114018Sharti KOBJMETHOD(uart_flush, quicc_bus_flush), 253114018Sharti KOBJMETHOD(uart_getsig, quicc_bus_getsig), 254114018Sharti KOBJMETHOD(uart_ioctl, quicc_bus_ioctl), 255114018Sharti KOBJMETHOD(uart_ipend, quicc_bus_ipend), 256114018Sharti KOBJMETHOD(uart_param, quicc_bus_param), 257114018Sharti KOBJMETHOD(uart_probe, quicc_bus_probe), 258114018Sharti KOBJMETHOD(uart_receive, quicc_bus_receive), 259114018Sharti KOBJMETHOD(uart_setsig, quicc_bus_setsig), 26025603Skjc KOBJMETHOD(uart_transmit, quicc_bus_transmit), 261114018Sharti { 0, 0 } 262114018Sharti}; 263114018Sharti 264114018Shartistruct uart_class uart_quicc_class = { 265114018Sharti "quicc", 266114018Sharti quicc_methods, 267114018Sharti sizeof(struct quicc_softc), 268114018Sharti .uc_ops = &uart_quicc_ops, 269150215Sru .uc_range = 2, 270114018Sharti .uc_rclk = DEFAULT_RCLK 271114018Sharti}; 27225603Skjc 273114018Sharti#define SIGCHG(c, i, s, d) \ 274114018Sharti if (c) { \ 275114018Sharti i |= (i & s) ? s : s | d; \ 276114018Sharti } else { \ 277166901Spiso i = (i & s) ? (i & ~s) | d : i; \ 278114018Sharti } 279114018Sharti 280147256Sbrooksstatic int 281114018Shartiquicc_bus_attach(struct uart_softc *sc) 282114018Sharti{ 283114018Sharti struct uart_bas *bas; 284114018Sharti struct uart_devinfo *di; 285150215Sru uint16_t st, rb; 286114018Sharti 287114018Sharti bas = &sc->sc_bas; 28825603Skjc if (sc->sc_sysdev != NULL) { 289114018Sharti di = sc->sc_sysdev; 29068433Skjc quicc_param(bas, di->baudrate, di->databits, di->stopbits, 291114018Sharti di->parity); 292114018Sharti } else { 29325603Skjc quicc_setup(bas, 9600, 8, 1, UART_PARITY_NONE); 29425603Skjc } 295114018Sharti 296114018Sharti sc->sc_rxfifosz = 1; 297114018Sharti sc->sc_txfifosz = 1; 29868433Skjc 29968433Skjc /* Enable interrupts on the receive buffer. */ 30025603Skjc rb = quicc_read2(bas, QUICC_PRAM_SCC_RBASE(bas->chan - 1)); 30168433Skjc st = quicc_read2(bas, rb); 30268433Skjc quicc_write2(bas, rb, st | 0x9000); 30368433Skjc 30468433Skjc (void)quicc_bus_getsig(sc); 305114018Sharti 30668433Skjc return (0); 307148887Srwatson} 308162321Sglebius 309148887Srwatsonstatic int 310114018Shartiquicc_bus_detach(struct uart_softc *sc) 31168433Skjc{ 31268433Skjc 313114018Sharti return (0); 31468433Skjc} 31568433Skjc 316147256Sbrooksstatic int 31768433Skjcquicc_bus_flush(struct uart_softc *sc, int what) 31868433Skjc{ 31968433Skjc 32068433Skjc return (0); 32168433Skjc} 32268433Skjc 32368433Skjcstatic int 32468433Skjcquicc_bus_getsig(struct uart_softc *sc) 32568433Skjc{ 32668433Skjc uint32_t new, old, sig; 32768433Skjc uint32_t dummy; 328114018Sharti 329150306Simp do { 33068433Skjc old = sc->sc_hwsig; 331114018Sharti sig = old; 33268433Skjc uart_lock(sc->sc_hwmtx); 33368433Skjc /* XXX SIGNALS */ 33468433Skjc dummy = 0; 33568433Skjc uart_unlock(sc->sc_hwmtx); 33668433Skjc SIGCHG(dummy, sig, SER_CTS, SER_DCTS); 337114018Sharti SIGCHG(dummy, sig, SER_DCD, SER_DDCD); 33868433Skjc SIGCHG(dummy, sig, SER_DSR, SER_DDSR); 339114018Sharti new = sig & ~SER_MASK_DELTA; 340114018Sharti } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); 341114018Sharti return (sig); 342114018Sharti} 34325603Skjc 34425603Skjcstatic int 345114018Shartiquicc_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) 346114018Sharti{ 347114018Sharti struct uart_bas *bas; 348114018Sharti uint32_t brg; 349114018Sharti int baudrate, error; 35042426Skjc 351114018Sharti bas = &sc->sc_bas; 35225603Skjc error = 0; 353114018Sharti uart_lock(sc->sc_hwmtx); 354114018Sharti switch (request) { 35542426Skjc case UART_IOCTL_BREAK: 356147256Sbrooks break; 357147256Sbrooks case UART_IOCTL_BAUD: 358114739Sharti brg = quicc_read4(bas, QUICC_REG_BRG(bas->chan - 1)) & 0x1fff; 35942426Skjc brg = (brg & 1) ? (brg + 1) << 3 : (brg + 2) >> 1; 36042426Skjc baudrate = bas->rclk / (brg * 16); 36142426Skjc *(int*)data = baudrate; 36242426Skjc break; 36342426Skjc default: 36442426Skjc error = EINVAL; 365114018Sharti break; 366114018Sharti } 367114018Sharti uart_unlock(sc->sc_hwmtx); 368114018Sharti return (error); 369114018Sharti} 37042426Skjc 371114018Shartistatic int 372114018Shartiquicc_bus_ipend(struct uart_softc *sc) 373114018Sharti{ 374114018Sharti struct uart_bas *bas; 375114018Sharti int ipend; 376114018Sharti uint16_t scce; 377114018Sharti 378114018Sharti bas = &sc->sc_bas; 379114018Sharti ipend = 0; 380114018Sharti 381114018Sharti uart_lock(sc->sc_hwmtx); 382114018Sharti scce = quicc_read2(bas, QUICC_REG_SCC_SCCE(bas->chan - 1)); 383114018Sharti quicc_write2(bas, QUICC_REG_SCC_SCCE(bas->chan - 1), ~0); 384114018Sharti uart_unlock(sc->sc_hwmtx); 385114018Sharti if (scce & 0x0001) 386114018Sharti ipend |= SER_INT_RXREADY; 387114018Sharti if (scce & 0x0002) 388114018Sharti ipend |= SER_INT_TXIDLE; 389114018Sharti if (scce & 0x0004) 390114018Sharti ipend |= SER_INT_OVERRUN; 391114018Sharti if (scce & 0x0020) 392114018Sharti ipend |= SER_INT_BREAK; 393114018Sharti /* XXX SIGNALS */ 394114018Sharti return (ipend); 395114018Sharti} 396114018Sharti 397114018Shartistatic int 398114018Shartiquicc_bus_param(struct uart_softc *sc, int baudrate, int databits, 399114018Sharti int stopbits, int parity) 400114018Sharti{ 401114018Sharti int error; 402114018Sharti 403114018Sharti uart_lock(sc->sc_hwmtx); 404114018Sharti error = quicc_param(&sc->sc_bas, baudrate, databits, stopbits, 405114018Sharti parity); 406114018Sharti uart_unlock(sc->sc_hwmtx); 407114018Sharti return (error); 408114018Sharti} 409114018Sharti 410114018Shartistatic int 411114018Shartiquicc_bus_probe(struct uart_softc *sc) 412114018Sharti{ 413114018Sharti char buf[80]; 414114018Sharti int error; 415114018Sharti 416114018Sharti error = quicc_probe(&sc->sc_bas); 417114018Sharti if (error) 418114018Sharti return (error); 419114018Sharti 420114018Sharti snprintf(buf, sizeof(buf), "quicc, channel %d", sc->sc_bas.chan); 421114018Sharti device_set_desc_copy(sc->sc_dev, buf); 422114018Sharti return (0); 423114018Sharti} 424114018Sharti 425114018Shartistatic int 426114018Shartiquicc_bus_receive(struct uart_softc *sc) 427114018Sharti{ 428114018Sharti struct uart_bas *bas; 429114018Sharti volatile char *buf; 430114018Sharti uint16_t st, rb; 431114018Sharti 432114018Sharti bas = &sc->sc_bas; 433114018Sharti uart_lock(sc->sc_hwmtx); 434114018Sharti rb = quicc_read2(bas, QUICC_PRAM_SCC_RBASE(bas->chan - 1)); 435114018Sharti st = quicc_read2(bas, rb); 436114018Sharti buf = (void *)(uintptr_t)quicc_read4(bas, rb + 4); 437114018Sharti uart_rx_put(sc, *buf); 438114018Sharti quicc_write2(bas, rb, st | 0x9000); 439114018Sharti uart_unlock(sc->sc_hwmtx); 440114018Sharti return (0); 441114018Sharti} 442114018Sharti 443114018Shartistatic int 44442426Skjcquicc_bus_setsig(struct uart_softc *sc, int sig) 44568433Skjc{ 44642426Skjc struct uart_bas *bas; 447114018Sharti uint32_t new, old; 448114018Sharti 449114018Sharti bas = &sc->sc_bas; 45042426Skjc do { 451114018Sharti old = sc->sc_hwsig; 45242426Skjc new = old; 453114018Sharti if (sig & SER_DDTR) { 454114018Sharti SIGCHG(sig & SER_DTR, new, SER_DTR, 45542426Skjc SER_DDTR); 456147256Sbrooks } 457147256Sbrooks if (sig & SER_DRTS) { 45842426Skjc SIGCHG(sig & SER_RTS, new, SER_RTS, 459147256Sbrooks SER_DRTS); 460114018Sharti } 461147256Sbrooks } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); 462147256Sbrooks 463114018Sharti uart_lock(sc->sc_hwmtx); 464114018Sharti /* XXX SIGNALS */ 465114018Sharti uart_unlock(sc->sc_hwmtx); 466114018Sharti return (0); 467114018Sharti} 468114018Sharti 469114018Shartistatic int 470114018Shartiquicc_bus_transmit(struct uart_softc *sc) 471114018Sharti{ 47225603Skjc volatile char *buf; 47342426Skjc struct uart_bas *bas; 474114018Sharti uint16_t st, tb; 475114018Sharti 476114018Sharti bas = &sc->sc_bas; 47768433Skjc uart_lock(sc->sc_hwmtx); 47868433Skjc tb = quicc_read2(bas, QUICC_PRAM_SCC_TBASE(bas->chan - 1)); 47968433Skjc st = quicc_read2(bas, tb); 48068433Skjc buf = (void *)(uintptr_t)quicc_read4(bas, tb + 4); 48168433Skjc *buf = sc->sc_txbuf[0]; 48268433Skjc quicc_write2(bas, tb + 2, 1); 48368433Skjc quicc_write2(bas, tb, st | 0x9000); 48468433Skjc sc->sc_txbusy = 1; 48568433Skjc uart_unlock(sc->sc_hwmtx); 48668433Skjc return (0); 48768433Skjc} 48868433Skjc