132516Sgibbs/*- 232516Sgibbs * Copyright (c) 2003 Marcel Moolenaar 332516Sgibbs * All rights reserved. 432516Sgibbs * 532516Sgibbs * Redistribution and use in source and binary forms, with or without 632516Sgibbs * modification, are permitted provided that the following conditions 732516Sgibbs * are met: 832516Sgibbs * 932516Sgibbs * 1. Redistributions of source code must retain the above copyright 1032516Sgibbs * notice, this list of conditions and the following disclaimer. 1132516Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1232516Sgibbs * notice, this list of conditions and the following disclaimer in the 1332516Sgibbs * documentation and/or other materials provided with the distribution. 1432516Sgibbs * 1532516Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1632516Sgibbs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1732516Sgibbs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1832516Sgibbs * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1932516Sgibbs * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2032516Sgibbs * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2132516Sgibbs * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2232516Sgibbs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2332516Sgibbs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2432516Sgibbs * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2532516Sgibbs */ 2635256Sdes 2732516Sgibbs#include <sys/cdefs.h> 2832516Sgibbs__FBSDID("$FreeBSD$"); 2932516Sgibbs 3032516Sgibbs#include <sys/param.h> 3132516Sgibbs#include <sys/systm.h> 3232516Sgibbs#include <sys/bus.h> 3332516Sgibbs#include <sys/conf.h> 3432516Sgibbs#include <machine/bus.h> 3532516Sgibbs 3632516Sgibbs#include <dev/uart/uart.h> 3732516Sgibbs#include <dev/uart/uart_cpu.h> 3832516Sgibbs#include <dev/uart/uart_bus.h> 3932516Sgibbs 4032516Sgibbs#include <dev/ic/z8530.h> 4132516Sgibbs 4232516Sgibbs#include "uart_if.h" 4332516Sgibbs 4432516Sgibbs#define DEFAULT_RCLK 307200 4532516Sgibbs 4632516Sgibbs/* Hack! */ 4732516Sgibbs#ifdef __powerpc__ 4832516Sgibbs#define UART_PCLK 0 4932516Sgibbs#else 5032516Sgibbs#define UART_PCLK MCB2_PCLK 5132516Sgibbs#endif 5232516Sgibbs 5332516Sgibbs/* Multiplexed I/O. */ 5432516Sgibbsstatic __inline void 5532516Sgibbsuart_setmreg(struct uart_bas *bas, int reg, int val) 5632516Sgibbs{ 5732516Sgibbs 5832516Sgibbs uart_setreg(bas, REG_CTRL, reg); 5932516Sgibbs uart_barrier(bas); 6032516Sgibbs uart_setreg(bas, REG_CTRL, val); 6132516Sgibbs} 6232516Sgibbs 6332516Sgibbsstatic __inline uint8_t 6432516Sgibbsuart_getmreg(struct uart_bas *bas, int reg) 6532516Sgibbs{ 6632516Sgibbs 6732516Sgibbs uart_setreg(bas, REG_CTRL, reg); 6832516Sgibbs uart_barrier(bas); 6932516Sgibbs return (uart_getreg(bas, REG_CTRL)); 7032516Sgibbs} 7132516Sgibbs 7232516Sgibbsstatic int 7332516Sgibbsz8530_divisor(int rclk, int baudrate) 7432516Sgibbs{ 7532516Sgibbs int act_baud, divisor, error; 7632516Sgibbs 7732516Sgibbs if (baudrate == 0) 7832516Sgibbs return (-1); 7932516Sgibbs 8032516Sgibbs divisor = (rclk + baudrate) / (baudrate << 1) - 2; 8132516Sgibbs if (divisor < 0 || divisor >= 65536) 8232516Sgibbs return (-1); 8332516Sgibbs act_baud = rclk / 2 / (divisor + 2); 8432516Sgibbs 8532516Sgibbs /* 10 times error in percent: */ 8632516Sgibbs error = ((act_baud - baudrate) * 2000 / baudrate + 1) >> 1; 8732516Sgibbs 8832516Sgibbs /* 3.0% maximum error tolerance: */ 8932516Sgibbs if (error < -30 || error > 30) 9032516Sgibbs return (-1); 9132516Sgibbs 9232516Sgibbs return (divisor); 9332516Sgibbs} 9432516Sgibbs 9532516Sgibbsstatic int 9632516Sgibbsz8530_param(struct uart_bas *bas, int baudrate, int databits, int stopbits, 9732516Sgibbs int parity, uint8_t *tpcp) 9832516Sgibbs{ 9932516Sgibbs int divisor; 10032516Sgibbs uint8_t mpm, rpc, tpc; 10132516Sgibbs 10232516Sgibbs rpc = RPC_RXE; 10332516Sgibbs mpm = MPM_CM16; 10432516Sgibbs tpc = TPC_TXE | (*tpcp & (TPC_DTR | TPC_RTS)); 10532516Sgibbs 10632516Sgibbs if (databits >= 8) { 10732516Sgibbs rpc |= RPC_RB8; 10832516Sgibbs tpc |= TPC_TB8; 10932516Sgibbs } else if (databits == 7) { 11032516Sgibbs rpc |= RPC_RB7; 11132516Sgibbs tpc |= TPC_TB7; 11232516Sgibbs } else if (databits == 6) { 11332516Sgibbs rpc |= RPC_RB6; 11432516Sgibbs tpc |= TPC_TB6; 11532516Sgibbs } else { 11632516Sgibbs rpc |= RPC_RB5; 11732516Sgibbs tpc |= TPC_TB5; 11832516Sgibbs } 11932516Sgibbs mpm |= (stopbits > 1) ? MPM_SB2 : MPM_SB1; 12032516Sgibbs switch (parity) { 12132516Sgibbs case UART_PARITY_EVEN: mpm |= MPM_PE | MPM_EVEN; break; 12232516Sgibbs case UART_PARITY_NONE: break; 12332516Sgibbs case UART_PARITY_ODD: mpm |= MPM_PE; break; 12432516Sgibbs default: return (EINVAL); 12532516Sgibbs } 12632516Sgibbs 12732516Sgibbs if (baudrate > 0) { 12832516Sgibbs divisor = z8530_divisor(bas->rclk, baudrate); 12932516Sgibbs if (divisor == -1) 13032516Sgibbs return (EINVAL); 13132516Sgibbs } else 13232516Sgibbs divisor = -1; 13332516Sgibbs 13432516Sgibbs uart_setmreg(bas, WR_MCB2, UART_PCLK); 13532516Sgibbs uart_barrier(bas); 13632516Sgibbs 13732516Sgibbs if (divisor >= 0) { 13832516Sgibbs uart_setmreg(bas, WR_TCL, divisor & 0xff); 13932516Sgibbs uart_barrier(bas); 14032516Sgibbs uart_setmreg(bas, WR_TCH, (divisor >> 8) & 0xff); 14132516Sgibbs uart_barrier(bas); 14232516Sgibbs } 14332516Sgibbs 14432516Sgibbs uart_setmreg(bas, WR_RPC, rpc); 14532516Sgibbs uart_barrier(bas); 14632516Sgibbs uart_setmreg(bas, WR_MPM, mpm); 14732516Sgibbs uart_barrier(bas); 14832516Sgibbs uart_setmreg(bas, WR_TPC, tpc); 14932516Sgibbs uart_barrier(bas); 15032516Sgibbs uart_setmreg(bas, WR_MCB2, UART_PCLK | MCB2_BRGE); 15132516Sgibbs uart_barrier(bas); 15232516Sgibbs *tpcp = tpc; 15332516Sgibbs return (0); 15432516Sgibbs} 15532516Sgibbs 15632516Sgibbsstatic int 15732516Sgibbsz8530_setup(struct uart_bas *bas, int baudrate, int databits, int stopbits, 15832516Sgibbs int parity) 15932516Sgibbs{ 16032516Sgibbs uint8_t tpc; 16132516Sgibbs 16235256Sdes if (bas->rclk == 0) 16332516Sgibbs bas->rclk = DEFAULT_RCLK; 16432516Sgibbs 16532516Sgibbs /* Assume we don't need to perform a full hardware reset. */ 16632516Sgibbs switch (bas->chan) { 16732516Sgibbs case 1: 16832516Sgibbs uart_setmreg(bas, WR_MIC, MIC_NV | MIC_CRA); 16932516Sgibbs break; 17032516Sgibbs case 2: 17132516Sgibbs uart_setmreg(bas, WR_MIC, MIC_NV | MIC_CRB); 17232516Sgibbs break; 17332516Sgibbs } 17432516Sgibbs uart_barrier(bas); 17532516Sgibbs /* Set clock sources. */ 17632516Sgibbs uart_setmreg(bas, WR_CMC, CMC_RC_BRG | CMC_TC_BRG); 17732516Sgibbs uart_setmreg(bas, WR_MCB2, UART_PCLK); 17832516Sgibbs uart_barrier(bas); 17932516Sgibbs /* Set data encoding. */ 18032516Sgibbs uart_setmreg(bas, WR_MCB1, MCB1_NRZ); 18132516Sgibbs uart_barrier(bas); 18232516Sgibbs 18332516Sgibbs tpc = TPC_DTR | TPC_RTS; 18432516Sgibbs z8530_param(bas, baudrate, databits, stopbits, parity, &tpc); 18532516Sgibbs return (int)tpc; 18632516Sgibbs} 18732516Sgibbs 18832516Sgibbs/* 18932516Sgibbs * Low-level UART interface. 19032516Sgibbs */ 19132516Sgibbsstatic int z8530_probe(struct uart_bas *bas); 19232516Sgibbsstatic void z8530_init(struct uart_bas *bas, int, int, int, int); 19332516Sgibbsstatic void z8530_term(struct uart_bas *bas); 19432516Sgibbsstatic void z8530_putc(struct uart_bas *bas, int); 19532516Sgibbsstatic int z8530_rxready(struct uart_bas *bas); 19632516Sgibbsstatic int z8530_getc(struct uart_bas *bas, struct mtx *); 19732516Sgibbs 19832516Sgibbsstatic struct uart_ops uart_z8530_ops = { 19932516Sgibbs .probe = z8530_probe, 20032516Sgibbs .init = z8530_init, 20132516Sgibbs .term = z8530_term, 20232516Sgibbs .putc = z8530_putc, 20332516Sgibbs .rxready = z8530_rxready, 20432516Sgibbs .getc = z8530_getc, 20532516Sgibbs}; 20632516Sgibbs 20732516Sgibbsstatic int 20832516Sgibbsz8530_probe(struct uart_bas *bas) 20932516Sgibbs{ 21032516Sgibbs 21132516Sgibbs return (0); 21232516Sgibbs} 21332516Sgibbs 21432516Sgibbsstatic void 21532516Sgibbsz8530_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, 21632516Sgibbs int parity) 21732516Sgibbs{ 21832516Sgibbs 21932516Sgibbs z8530_setup(bas, baudrate, databits, stopbits, parity); 22032516Sgibbs} 22132516Sgibbs 22232516Sgibbsstatic void 22332516Sgibbsz8530_term(struct uart_bas *bas) 22432516Sgibbs{ 22532516Sgibbs} 22632516Sgibbs 22732516Sgibbsstatic void 22832516Sgibbsz8530_putc(struct uart_bas *bas, int c) 22932516Sgibbs{ 23032516Sgibbs 23132516Sgibbs while (!(uart_getreg(bas, REG_CTRL) & BES_TXE)) 23232516Sgibbs ; 23332516Sgibbs uart_setreg(bas, REG_DATA, c); 23432516Sgibbs uart_barrier(bas); 23532516Sgibbs} 23632516Sgibbs 23732516Sgibbsstatic int 23832516Sgibbsz8530_rxready(struct uart_bas *bas) 23932516Sgibbs{ 24032516Sgibbs 24132516Sgibbs return ((uart_getreg(bas, REG_CTRL) & BES_RXA) != 0 ? 1 : 0); 24232516Sgibbs} 24332516Sgibbs 24432516Sgibbsstatic int 24532516Sgibbsz8530_getc(struct uart_bas *bas, struct mtx *hwmtx) 24632516Sgibbs{ 24732516Sgibbs int c; 24832516Sgibbs 24932516Sgibbs uart_lock(hwmtx); 25032516Sgibbs 25132516Sgibbs while (!(uart_getreg(bas, REG_CTRL) & BES_RXA)) { 25232516Sgibbs uart_unlock(hwmtx); 25332516Sgibbs DELAY(10); 25432516Sgibbs uart_lock(hwmtx); 25532516Sgibbs } 25632516Sgibbs 25732516Sgibbs c = uart_getreg(bas, REG_DATA); 25832516Sgibbs 25932516Sgibbs uart_unlock(hwmtx); 26032516Sgibbs 26132516Sgibbs return (c); 26232516Sgibbs} 26332516Sgibbs 26432516Sgibbs/* 26532516Sgibbs * High-level UART interface. 26632516Sgibbs */ 26732516Sgibbsstruct z8530_softc { 26832516Sgibbs struct uart_softc base; 26932516Sgibbs uint8_t tpc; 27032516Sgibbs uint8_t txidle; 27132516Sgibbs}; 27232516Sgibbs 27332516Sgibbsstatic int z8530_bus_attach(struct uart_softc *); 27432516Sgibbsstatic int z8530_bus_detach(struct uart_softc *); 27532516Sgibbsstatic int z8530_bus_flush(struct uart_softc *, int); 27632516Sgibbsstatic int z8530_bus_getsig(struct uart_softc *); 27732516Sgibbsstatic int z8530_bus_ioctl(struct uart_softc *, int, intptr_t); 27832516Sgibbsstatic int z8530_bus_ipend(struct uart_softc *); 27932516Sgibbsstatic int z8530_bus_param(struct uart_softc *, int, int, int, int); 28032516Sgibbsstatic int z8530_bus_probe(struct uart_softc *); 28132516Sgibbsstatic int z8530_bus_receive(struct uart_softc *); 28232516Sgibbsstatic int z8530_bus_setsig(struct uart_softc *, int); 28332516Sgibbsstatic int z8530_bus_transmit(struct uart_softc *); 28432516Sgibbsstatic void z8530_bus_grab(struct uart_softc *); 28532516Sgibbsstatic void z8530_bus_ungrab(struct uart_softc *); 28632516Sgibbs 28732516Sgibbsstatic kobj_method_t z8530_methods[] = { 28832516Sgibbs KOBJMETHOD(uart_attach, z8530_bus_attach), 28932516Sgibbs KOBJMETHOD(uart_detach, z8530_bus_detach), 29032516Sgibbs KOBJMETHOD(uart_flush, z8530_bus_flush), 29132516Sgibbs KOBJMETHOD(uart_getsig, z8530_bus_getsig), 29232516Sgibbs KOBJMETHOD(uart_ioctl, z8530_bus_ioctl), 29332516Sgibbs KOBJMETHOD(uart_ipend, z8530_bus_ipend), 29432516Sgibbs KOBJMETHOD(uart_param, z8530_bus_param), 29532516Sgibbs KOBJMETHOD(uart_probe, z8530_bus_probe), 29632516Sgibbs KOBJMETHOD(uart_receive, z8530_bus_receive), 29732516Sgibbs KOBJMETHOD(uart_setsig, z8530_bus_setsig), 29832516Sgibbs KOBJMETHOD(uart_transmit, z8530_bus_transmit), 29932516Sgibbs KOBJMETHOD(uart_grab, z8530_bus_grab), 30032516Sgibbs KOBJMETHOD(uart_ungrab, z8530_bus_ungrab), 30132516Sgibbs { 0, 0 } 30232516Sgibbs}; 30332516Sgibbs 30432516Sgibbsstruct uart_class uart_z8530_class = { 30532516Sgibbs "z8530", 30632516Sgibbs z8530_methods, 30732516Sgibbs sizeof(struct z8530_softc), 30832516Sgibbs .uc_ops = &uart_z8530_ops, 30932516Sgibbs .uc_range = 2, 31032516Sgibbs .uc_rclk = DEFAULT_RCLK, 31132516Sgibbs .uc_rshift = 0 31232516Sgibbs}; 31332516Sgibbs 31432516Sgibbs#define SIGCHG(c, i, s, d) \ 31532516Sgibbs if (c) { \ 31632516Sgibbs i |= (i & s) ? s : s | d; \ 31732516Sgibbs } else { \ 31832516Sgibbs i = (i & s) ? (i & ~s) | d : i; \ 31932516Sgibbs } 32032516Sgibbs 32132516Sgibbsstatic int 32232516Sgibbsz8530_bus_attach(struct uart_softc *sc) 32332516Sgibbs{ 32432516Sgibbs struct z8530_softc *z8530 = (struct z8530_softc*)sc; 32532516Sgibbs struct uart_bas *bas; 32632516Sgibbs struct uart_devinfo *di; 32732516Sgibbs 32832516Sgibbs bas = &sc->sc_bas; 32932516Sgibbs if (sc->sc_sysdev != NULL) { 33032516Sgibbs di = sc->sc_sysdev; 33132516Sgibbs z8530->tpc = TPC_DTR|TPC_RTS; 33232516Sgibbs z8530_param(bas, di->baudrate, di->databits, di->stopbits, 33332516Sgibbs di->parity, &z8530->tpc); 33432516Sgibbs } else { 33532516Sgibbs z8530->tpc = z8530_setup(bas, 9600, 8, 1, UART_PARITY_NONE); 33632516Sgibbs z8530->tpc &= ~(TPC_DTR|TPC_RTS); 33732516Sgibbs } 33832516Sgibbs z8530->txidle = 1; /* Report SER_INT_TXIDLE. */ 33932516Sgibbs 34032516Sgibbs (void)z8530_bus_getsig(sc); 34132516Sgibbs 34232516Sgibbs uart_setmreg(bas, WR_IC, IC_BRK | IC_CTS | IC_DCD); 34332516Sgibbs uart_barrier(bas); 34432516Sgibbs uart_setmreg(bas, WR_IDT, IDT_XIE | IDT_TIE | IDT_RIA); 34532516Sgibbs uart_barrier(bas); 34632516Sgibbs uart_setmreg(bas, WR_IV, 0); 34732516Sgibbs uart_barrier(bas); 34832516Sgibbs uart_setmreg(bas, WR_TPC, z8530->tpc); 34932516Sgibbs uart_barrier(bas); 35032516Sgibbs uart_setmreg(bas, WR_MIC, MIC_NV | MIC_MIE); 35132516Sgibbs uart_barrier(bas); 35232516Sgibbs return (0); 35332516Sgibbs} 35432516Sgibbs 35532516Sgibbsstatic int 35632516Sgibbsz8530_bus_detach(struct uart_softc *sc) 35732516Sgibbs{ 35832516Sgibbs 35932516Sgibbs return (0); 36032516Sgibbs} 36132516Sgibbs 36232516Sgibbsstatic int 36332516Sgibbsz8530_bus_flush(struct uart_softc *sc, int what) 36432516Sgibbs{ 36532516Sgibbs 36632516Sgibbs return (0); 36732516Sgibbs} 36832516Sgibbs 36932516Sgibbsstatic int 37032516Sgibbsz8530_bus_getsig(struct uart_softc *sc) 37132516Sgibbs{ 37232516Sgibbs uint32_t new, old, sig; 37332516Sgibbs uint8_t bes; 37432516Sgibbs 37532516Sgibbs do { 37632516Sgibbs old = sc->sc_hwsig; 37732516Sgibbs sig = old; 37832516Sgibbs uart_lock(sc->sc_hwmtx); 37932516Sgibbs bes = uart_getmreg(&sc->sc_bas, RR_BES); 38032516Sgibbs uart_unlock(sc->sc_hwmtx); 38132516Sgibbs SIGCHG(bes & BES_CTS, sig, SER_CTS, SER_DCTS); 38232516Sgibbs SIGCHG(bes & BES_DCD, sig, SER_DCD, SER_DDCD); 38332516Sgibbs SIGCHG(bes & BES_SYNC, sig, SER_DSR, SER_DDSR); 38432516Sgibbs new = sig & ~SER_MASK_DELTA; 38532516Sgibbs } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); 38632516Sgibbs return (sig); 38732516Sgibbs} 38832516Sgibbs 38932516Sgibbsstatic int 39032516Sgibbsz8530_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) 39132516Sgibbs{ 39232516Sgibbs struct z8530_softc *z8530 = (struct z8530_softc*)sc; 39332516Sgibbs struct uart_bas *bas; 39432516Sgibbs int baudrate, divisor, error; 39532516Sgibbs 39632516Sgibbs bas = &sc->sc_bas; 39732516Sgibbs error = 0; 39832516Sgibbs uart_lock(sc->sc_hwmtx); 39932516Sgibbs switch (request) { 40032516Sgibbs case UART_IOCTL_BREAK: 40132516Sgibbs if (data) 40232516Sgibbs z8530->tpc |= TPC_BRK; 40332516Sgibbs else 40432516Sgibbs z8530->tpc &= ~TPC_BRK; 40532516Sgibbs uart_setmreg(bas, WR_TPC, z8530->tpc); 40632516Sgibbs uart_barrier(bas); 40732516Sgibbs break; 40832516Sgibbs case UART_IOCTL_BAUD: 40932516Sgibbs divisor = uart_getmreg(bas, RR_TCH); 41032516Sgibbs divisor = (divisor << 8) | uart_getmreg(bas, RR_TCL); 41132516Sgibbs baudrate = bas->rclk / 2 / (divisor + 2); 41232516Sgibbs *(int*)data = baudrate; 41332516Sgibbs break; 41432516Sgibbs default: 41532516Sgibbs error = EINVAL; 41632516Sgibbs break; 41732516Sgibbs } 41832516Sgibbs uart_unlock(sc->sc_hwmtx); 41932516Sgibbs return (error); 42032516Sgibbs} 42132516Sgibbs 42232516Sgibbsstatic int 42332516Sgibbsz8530_bus_ipend(struct uart_softc *sc) 42432516Sgibbs{ 42532516Sgibbs struct z8530_softc *z8530 = (struct z8530_softc*)sc; 42632516Sgibbs struct uart_bas *bas; 42732516Sgibbs int ipend; 42832516Sgibbs uint32_t sig; 42932516Sgibbs uint8_t bes, ip, iv, src; 43032516Sgibbs 43132516Sgibbs bas = &sc->sc_bas; 43232516Sgibbs ipend = 0; 43332516Sgibbs 43432516Sgibbs uart_lock(sc->sc_hwmtx); 43532516Sgibbs switch (bas->chan) { 43632516Sgibbs case 1: 43732516Sgibbs ip = uart_getmreg(bas, RR_IP); 43832516Sgibbs break; 43932516Sgibbs case 2: /* XXX hack!!! */ 44032516Sgibbs iv = uart_getmreg(bas, RR_IV) & 0x0E; 44132516Sgibbs switch (iv) { 44232516Sgibbs case IV_TEB: ip = IP_TIA; break; 44332516Sgibbs case IV_XSB: ip = IP_SIA; break; 44432516Sgibbs case IV_RAB: ip = IP_RIA; break; 44532516Sgibbs default: ip = 0; break; 44632516Sgibbs } 44732516Sgibbs break; 44832516Sgibbs default: 44932516Sgibbs ip = 0; 45032516Sgibbs break; 45132516Sgibbs } 45232516Sgibbs 45332516Sgibbs if (ip & IP_RIA) 45432516Sgibbs ipend |= SER_INT_RXREADY; 45532516Sgibbs 45632516Sgibbs if (ip & IP_TIA) { 45732516Sgibbs uart_setreg(bas, REG_CTRL, CR_RSTTXI); 45832516Sgibbs uart_barrier(bas); 45932516Sgibbs if (z8530->txidle) { 46032516Sgibbs ipend |= SER_INT_TXIDLE; 46132516Sgibbs z8530->txidle = 0; /* Mask SER_INT_TXIDLE. */ 46232516Sgibbs } 46332516Sgibbs } 46432516Sgibbs 46532516Sgibbs if (ip & IP_SIA) { 46632516Sgibbs uart_setreg(bas, REG_CTRL, CR_RSTXSI); 46732516Sgibbs uart_barrier(bas); 46832516Sgibbs bes = uart_getmreg(bas, RR_BES); 46932516Sgibbs if (bes & BES_BRK) 47032516Sgibbs ipend |= SER_INT_BREAK; 47132516Sgibbs sig = sc->sc_hwsig; 47232516Sgibbs SIGCHG(bes & BES_CTS, sig, SER_CTS, SER_DCTS); 47332516Sgibbs SIGCHG(bes & BES_DCD, sig, SER_DCD, SER_DDCD); 47432516Sgibbs SIGCHG(bes & BES_SYNC, sig, SER_DSR, SER_DDSR); 47532516Sgibbs if (sig & SER_MASK_DELTA) 47632516Sgibbs ipend |= SER_INT_SIGCHG; 47732516Sgibbs src = uart_getmreg(bas, RR_SRC); 47832516Sgibbs if (src & SRC_OVR) { 47932516Sgibbs uart_setreg(bas, REG_CTRL, CR_RSTERR); 48032516Sgibbs uart_barrier(bas); 48132516Sgibbs ipend |= SER_INT_OVERRUN; 48232516Sgibbs } 48332516Sgibbs } 48432516Sgibbs 48532516Sgibbs if (ipend) { 48632516Sgibbs uart_setreg(bas, REG_CTRL, CR_RSTIUS); 48732516Sgibbs uart_barrier(bas); 48832516Sgibbs } 48932516Sgibbs 49032516Sgibbs uart_unlock(sc->sc_hwmtx); 49132516Sgibbs 49232516Sgibbs return (ipend); 49332516Sgibbs} 49432516Sgibbs 49532516Sgibbsstatic int 49632516Sgibbsz8530_bus_param(struct uart_softc *sc, int baudrate, int databits, 49732516Sgibbs int stopbits, int parity) 49832516Sgibbs{ 49932516Sgibbs struct z8530_softc *z8530 = (struct z8530_softc*)sc; 50032516Sgibbs int error; 50132516Sgibbs 50232516Sgibbs uart_lock(sc->sc_hwmtx); 50332516Sgibbs error = z8530_param(&sc->sc_bas, baudrate, databits, stopbits, parity, 50432516Sgibbs &z8530->tpc); 50532516Sgibbs uart_unlock(sc->sc_hwmtx); 50632516Sgibbs return (error); 50732516Sgibbs} 50832516Sgibbs 50932516Sgibbsstatic int 51032516Sgibbsz8530_bus_probe(struct uart_softc *sc) 51132516Sgibbs{ 51232516Sgibbs char buf[80]; 51332516Sgibbs int error; 51432516Sgibbs char ch; 51532516Sgibbs 51632516Sgibbs error = z8530_probe(&sc->sc_bas); 51732516Sgibbs if (error) 51832516Sgibbs return (error); 51932516Sgibbs 52032516Sgibbs sc->sc_rxfifosz = 3; 52132516Sgibbs sc->sc_txfifosz = 1; 52232516Sgibbs 52332516Sgibbs ch = sc->sc_bas.chan - 1 + 'A'; 52432516Sgibbs 52532516Sgibbs snprintf(buf, sizeof(buf), "z8530, channel %c", ch); 52632516Sgibbs device_set_desc_copy(sc->sc_dev, buf); 52732516Sgibbs return (0); 52832516Sgibbs} 52932516Sgibbs 53032516Sgibbsstatic int 53132516Sgibbsz8530_bus_receive(struct uart_softc *sc) 53232516Sgibbs{ 53332516Sgibbs struct uart_bas *bas; 53432516Sgibbs int xc; 53532516Sgibbs uint8_t bes, src; 53632516Sgibbs 53732516Sgibbs bas = &sc->sc_bas; 53832516Sgibbs uart_lock(sc->sc_hwmtx); 53932516Sgibbs bes = uart_getmreg(bas, RR_BES); 54032516Sgibbs while (bes & BES_RXA) { 54132516Sgibbs if (uart_rx_full(sc)) { 54232516Sgibbs sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; 54332516Sgibbs break; 54432516Sgibbs } 54532516Sgibbs xc = uart_getreg(bas, REG_DATA); 54632516Sgibbs uart_barrier(bas); 54732516Sgibbs src = uart_getmreg(bas, RR_SRC); 54832516Sgibbs if (src & SRC_FE) 54932516Sgibbs xc |= UART_STAT_FRAMERR; 55032516Sgibbs if (src & SRC_PE) 55132516Sgibbs xc |= UART_STAT_PARERR; 55232516Sgibbs if (src & SRC_OVR) 55332516Sgibbs xc |= UART_STAT_OVERRUN; 55432516Sgibbs uart_rx_put(sc, xc); 55532516Sgibbs if (src & (SRC_FE | SRC_PE | SRC_OVR)) { 55632516Sgibbs uart_setreg(bas, REG_CTRL, CR_RSTERR); 55732516Sgibbs uart_barrier(bas); 55832516Sgibbs } 55932516Sgibbs bes = uart_getmreg(bas, RR_BES); 56032516Sgibbs } 56132516Sgibbs /* Discard everything left in the Rx FIFO. */ 56232516Sgibbs while (bes & BES_RXA) { 56332516Sgibbs (void)uart_getreg(bas, REG_DATA); 56432516Sgibbs uart_barrier(bas); 56532516Sgibbs src = uart_getmreg(bas, RR_SRC); 56632516Sgibbs if (src & (SRC_FE | SRC_PE | SRC_OVR)) { 56732516Sgibbs uart_setreg(bas, REG_CTRL, CR_RSTERR); 56832516Sgibbs uart_barrier(bas); 56932516Sgibbs } 57032516Sgibbs bes = uart_getmreg(bas, RR_BES); 57132516Sgibbs } 57232516Sgibbs uart_unlock(sc->sc_hwmtx); 57332516Sgibbs return (0); 57432516Sgibbs} 57532516Sgibbs 57632516Sgibbsstatic int 57732516Sgibbsz8530_bus_setsig(struct uart_softc *sc, int sig) 57832516Sgibbs{ 57932516Sgibbs struct z8530_softc *z8530 = (struct z8530_softc*)sc; 58032516Sgibbs struct uart_bas *bas; 58132516Sgibbs uint32_t new, old; 58232516Sgibbs 58332516Sgibbs bas = &sc->sc_bas; 58432516Sgibbs do { 585 old = sc->sc_hwsig; 586 new = old; 587 if (sig & SER_DDTR) { 588 SIGCHG(sig & SER_DTR, new, SER_DTR, 589 SER_DDTR); 590 } 591 if (sig & SER_DRTS) { 592 SIGCHG(sig & SER_RTS, new, SER_RTS, 593 SER_DRTS); 594 } 595 } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); 596 597 uart_lock(sc->sc_hwmtx); 598 if (new & SER_DTR) 599 z8530->tpc |= TPC_DTR; 600 else 601 z8530->tpc &= ~TPC_DTR; 602 if (new & SER_RTS) 603 z8530->tpc |= TPC_RTS; 604 else 605 z8530->tpc &= ~TPC_RTS; 606 uart_setmreg(bas, WR_TPC, z8530->tpc); 607 uart_barrier(bas); 608 uart_unlock(sc->sc_hwmtx); 609 return (0); 610} 611 612static int 613z8530_bus_transmit(struct uart_softc *sc) 614{ 615 struct z8530_softc *z8530 = (struct z8530_softc*)sc; 616 struct uart_bas *bas; 617 618 bas = &sc->sc_bas; 619 uart_lock(sc->sc_hwmtx); 620 while (!(uart_getmreg(bas, RR_BES) & BES_TXE)) 621 ; 622 uart_setreg(bas, REG_DATA, sc->sc_txbuf[0]); 623 uart_barrier(bas); 624 sc->sc_txbusy = 1; 625 z8530->txidle = 1; /* Report SER_INT_TXIDLE again. */ 626 uart_unlock(sc->sc_hwmtx); 627 return (0); 628} 629 630static void 631z8530_bus_grab(struct uart_softc *sc) 632{ 633 struct uart_bas *bas; 634 635 bas = &sc->sc_bas; 636 uart_lock(sc->sc_hwmtx); 637 uart_setmreg(bas, WR_IDT, IDT_XIE | IDT_TIE); 638 uart_barrier(bas); 639 uart_unlock(sc->sc_hwmtx); 640} 641 642static void 643z8530_bus_ungrab(struct uart_softc *sc) 644{ 645 struct uart_bas *bas; 646 647 bas = &sc->sc_bas; 648 uart_lock(sc->sc_hwmtx); 649 uart_setmreg(bas, WR_IDT, IDT_XIE | IDT_TIE | IDT_RIA); 650 uart_barrier(bas); 651 uart_unlock(sc->sc_hwmtx); 652} 653