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