code:
/*	$OpenBSD: be.c,v 1.51 2015/06/24 09:40:53 mpi Exp $	*/

/*
 * Copyright (c) 1998 Theo de Raadt and Jason L. Wright.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/syslog.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/timeout.h>

#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/netisr.h>
#include <net/if_media.h>

#include <netinet/in.h>
#include <netinet/if_ether.h>

#include "bpfilter.h"
#if NBPFILTER > 0
#include <net/bpf.h>
#include <net/bpfdesc.h>
#endif

#include <machine/autoconf.h>
#include <machine/cpu.h>

#include <sparc/dev/dmareg.h>
#include <sparc/dev/dmavar.h>

#include <sparc/dev/qecvar.h>
#include <sparc/dev/qecreg.h>
#include <sparc/dev/bereg.h>
#include <sparc/dev/bevar.h>

int	bematch(struct device *, void *, void *);
void	beattach(struct device *, struct device *, void *);

void	beinit(struct besoftc *);
void	bestart(struct ifnet *);
void	bestop(struct besoftc *);
void	bewatchdog(struct ifnet *);
int	beioctl(struct ifnet *, u_long, caddr_t);
void	bereset(struct besoftc *);

int	beintr(void *);
int	berint(struct besoftc *);
int	betint(struct besoftc *);
int	beqint(struct besoftc *, u_int32_t);
int	beeint(struct besoftc *, u_int32_t);
void	be_read(struct besoftc *, int, int);

void	be_tcvr_idle(struct besoftc *);
void	be_tcvr_init(struct besoftc *);
void	be_tcvr_write(struct besoftc *, u_int8_t, u_int16_t);
void	be_tcvr_write_bit(struct besoftc *, int);
int	be_tcvr_read_bit1(struct besoftc *);
int	be_tcvr_read_bit2(struct besoftc *);
int	be_tcvr_read(struct besoftc *, u_int8_t);
void	be_ifmedia_sts(struct ifnet *, struct ifmediareq *);
int	be_ifmedia_upd(struct ifnet *);
void	be_mcreset(struct besoftc *);
void	betick(void *);
void	be_tx_harvest(struct besoftc *);

struct cfdriver be_cd = {
	NULL, "be", DV_IFNET
};

struct cfattach be_ca = {
	sizeof(struct besoftc), bematch, beattach
};

int
bematch(parent, vcf, aux)
	struct device *parent;
	void *vcf, *aux;
{
	struct cfdata *cf = vcf;
	struct confargs *ca = aux;
	register struct romaux *ra = &ca->ca_ra;

	if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
		return (0);
	return (1);
}

void
beattach(parent, self, aux)
	struct device *parent, *self;
	void *aux;
{
	struct qec_softc *qec = (struct qec_softc *)parent;
	struct besoftc *sc = (struct besoftc *)self;
	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
	struct confargs *ca = aux;
	struct bootpath *bp;
	extern void myetheraddr(u_char *);
	int pri, bmsr;

	if (ca->ca_ra.ra_nintr != 1) {
		printf(": expected 1 interrupt, got %d\n", ca->ca_ra.ra_nintr);
		return;
	}
	pri = ca->ca_ra.ra_intr[0].int_pri;
	sc->sc_rev = getpropint(ca->ca_ra.ra_node, "board-version", -1);

	timeout_set(&sc->sc_tick, betick, sc);

	sc->sc_cr = mapiodev(&ca->ca_ra.ra_reg[0], 0, sizeof(struct be_cregs));
	sc->sc_br = mapiodev(&ca->ca_ra.ra_reg[1], 0, sizeof(struct be_bregs));
	sc->sc_tr = mapiodev(&ca->ca_ra.ra_reg[2], 0, sizeof(struct be_tregs));
	sc->sc_qec = qec;
	sc->sc_qr = qec->sc_regs;
	bestop(sc);

	sc->sc_channel = getpropint(ca->ca_ra.ra_node, "channel#", -1);
	if (sc->sc_channel == -1)
		sc->sc_channel = 0;

	sc->sc_burst = getpropint(ca->ca_ra.ra_node, "burst-sizes", -1);
	if (sc->sc_burst == -1)
		sc->sc_burst = qec->sc_burst;

	/* Clamp at parent's burst sizes */
	sc->sc_burst &= qec->sc_burst;

	sc->sc_ih.ih_fun = beintr;
	sc->sc_ih.ih_arg = sc;
	intr_establish(pri, &sc->sc_ih, IPL_NET, sc->sc_dev.dv_xname);

	myetheraddr(sc->sc_arpcom.ac_enaddr);

	be_tcvr_init(sc);

	ifmedia_init(&sc->sc_ifmedia, 0, be_ifmedia_upd, be_ifmedia_sts);
	bmsr = be_tcvr_read(sc, PHY_BMSR);
	if (bmsr == BE_TCVR_READ_INVALID)
		return;

	if (bmsr & PHY_BMSR_10BASET_HALF) {
		ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0, NULL);
		ifmedia_add(&sc->sc_ifmedia,
		    IFM_ETHER | IFM_10_T | IFM_HDX, 0, NULL);
		sc->sc_ifmedia.ifm_media = IFM_ETHER | IFM_10_T | IFM_HDX;
	}

	if (bmsr & PHY_BMSR_10BASET_FULL) {
		ifmedia_add(&sc->sc_ifmedia,
		    IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL);
		sc->sc_ifmedia.ifm_media = IFM_ETHER | IFM_10_T | IFM_FDX;
	}

	if (bmsr & PHY_BMSR_100BASETX_HALF) {
		ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_100_TX, 0, NULL);
		ifmedia_add(&sc->sc_ifmedia,
		    IFM_ETHER | IFM_100_TX | IFM_HDX, 0, NULL);
		sc->sc_ifmedia.ifm_media = IFM_ETHER | IFM_100_TX | IFM_HDX;
	}

	if (bmsr & PHY_BMSR_100BASETX_FULL) {
		ifmedia_add(&sc->sc_ifmedia,
		    IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL);
		sc->sc_ifmedia.ifm_media = IFM_ETHER | IFM_100_TX | IFM_FDX;
	}

	if (bmsr & PHY_BMSR_100BASET4) {
		ifmedia_add(&sc->sc_ifmedia,
		    IFM_ETHER | IFM_100_T4, 0, NULL);
		sc->sc_ifmedia.ifm_media = IFM_ETHER | IFM_100_T4;
	}

	if (bmsr & PHY_BMSR_ANC) {
		ifmedia_add(&sc->sc_ifmedia,
		    IFM_ETHER | IFM_AUTO, 0, NULL);
		sc->sc_ifmedia.ifm_media = IFM_ETHER | IFM_AUTO;
	}

	ifmedia_set(&sc->sc_ifmedia, sc->sc_ifmedia.ifm_media);

	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
	ifp->if_softc = sc;
	ifp->if_start = bestart;
	ifp->if_ioctl = beioctl;
	ifp->if_watchdog = bewatchdog;
	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS |
	    IFF_MULTICAST;

	IFQ_SET_MAXLEN(&ifp->if_snd, BE_TX_RING_SIZE);
	IFQ_SET_READY(&ifp->if_snd);

	/* Attach the interface. */
	if_attach(ifp);
	ether_ifattach(ifp);

	printf(" pri %d: rev %x address %s\n", pri, sc->sc_rev,
	    ether_sprintf(sc->sc_arpcom.ac_enaddr));

	bp = ca->ca_ra.ra_bp;
	if (bp != NULL && strcmp(bp->name, "be") == 0 &&
	    sc->sc_dev.dv_unit == bp->val[1])
		bp->dev = &sc->sc_dev;
}

/*
 * Start output on interface.
 * We make two assumptions here:
 *  1) that the current priority is set to splnet _before_ this code
 *     is called *and* is returned to the appropriate priority after
 *     return
 *  2) that the IFF_OACTIVE flag is checked before this code is called
 *     (i.e. that the output part of the interface is idle)
 */
void
bestart(ifp)
	struct ifnet *ifp;
{
	struct besoftc *sc = (struct besoftc *)ifp->if_softc;
	struct mbuf *m;
	int bix, len, cnt;

	if (sc->sc_no_td > 0) {
		/* Try to free previous stuff */
		be_tx_harvest(sc);
	}

	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
		return;

	bix = sc->sc_last_td;
	cnt = sc->sc_no_td;

	for (;;) {
		IFQ_POLL(&ifp->if_snd, m);
		if (m == NULL)
			break;

		IFQ_DEQUEUE(&ifp->if_snd, m);

#if NBPFILTER > 0
		/*
		 * If BPF is listening on this interface, let it see the
		 * packet before we commit it to the wire.
		 */
		if (ifp->if_bpf)
			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
#endif

		/*
		 * Copy the mbuf chain into the transmit buffer.
		 */
		len = qec_put(sc->sc_bufs->tx_buf[bix & BE_TX_RING_MASK], m);

		/*
		 * Initialize transmit registers and start transmission
		 */
		sc->sc_desc->be_txd[bix].tx_flags =
			BE_TXD_OWN | BE_TXD_SOP | BE_TXD_EOP |
			(len & BE_TXD_LENGTH);
		sc->sc_cr->ctrl = BE_CR_CTRL_TWAKEUP;

		if (++bix == BE_TX_RING_MAXSIZE)
			bix = 0;

		if (++cnt == BE_TX_RING_SIZE) {
			ifp->if_flags |= IFF_OACTIVE;
			break;
		}
	}

	if (cnt > BE_TX_HIGH_WATER) {
		/* turn on interrupt */
		sc->sc_tx_intr = 1;
		sc->sc_cr->timask = 0;
	}

	if (cnt != sc->sc_no_td) {
		ifp->if_timer = 5;
		sc->sc_last_td = bix;
		sc->sc_no_td = cnt;
	}
}

void
bestop(sc)
	struct besoftc *sc;
{
	int tries;

	sc->sc_arpcom.ac_if.if_timer = 0;
	timeout_del(&sc->sc_tick);

	tries = 32;
	sc->sc_br->tx_cfg = 0;
	while (sc->sc_br->tx_cfg != 0 && --tries)
		DELAY(20);

	tries = 32;
	sc->sc_br->rx_cfg = 0;
	while (sc->sc_br->rx_cfg != 0 && --tries)
		DELAY(20);
}

/*
 * Reset interface.
 */
void
bereset(sc)
	struct besoftc *sc;
{
	int s;

	s = splnet();
	bestop(sc);
	beinit(sc);
	splx(s);
}

void
bewatchdog(ifp)
	struct ifnet *ifp;
{
	struct besoftc *sc = ifp->if_softc;

	log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
	++sc->sc_arpcom.ac_if.if_oerrors;

	bereset(sc);
}

int
beintr(v)
	void *v;
{
	struct besoftc *sc = (struct besoftc *)v;
	u_int32_t whyq, whyb, whyc;
	int r = 0;

	whyq = sc->sc_qr->stat;		/* qec status */
	whyc = sc->sc_cr->stat;		/* be channel status */
	whyb = sc->sc_br->stat;		/* be status */

	if (whyq & QEC_STAT_BM)
		r |= beeint(sc, whyb);

	if (whyq & QEC_STAT_ER)
		r |= beqint(sc, whyc);

	if (sc->sc_tx_intr && (whyq & QEC_STAT_TX) && (whyc & BE_CR_STAT_TXIRQ))
		r |= betint(sc);

	if (whyq & QEC_STAT_RX && whyc & BE_CR_STAT_RXIRQ)
		r |= berint(sc);

	return (r);
}

/*
 * QEC Interrupt.
 */
int
beqint(sc, why)
	struct besoftc *sc;
	u_int32_t why;
{
	int r = 0, rst = 0;

	if (why & BE_CR_STAT_TXIRQ)
		r |= 1;
	if (why & BE_CR_STAT_RXIRQ)
		r |= 1;

	if (why & BE_CR_STAT_ERRORS) {
		r |= 1;
		rst = 1;
	}

	if (rst || r == 0) {
		printf("%s:%s qstat=%b\n", sc->sc_dev.dv_xname,
		    (r) ? "" : " unexpected",
		    why, BE_CR_STAT_BITS);
		printf("%s: resetting\n", sc->sc_dev.dv_xname);
		bereset(sc);
	}

	return r;
}

/*
 * Error interrupt.
 */
int
beeint(sc, why)
	struct besoftc *sc;
	u_int32_t why;
{
	int r = 0;

	if (why & (BE_BR_STAT_RFIFOVF | BE_BR_STAT_TFIFO_UND |
		   BE_BR_STAT_MAXPKTERR)) {
		r |= 1;
	}

	printf("%s:%s stat=%b\n", sc->sc_dev.dv_xname,
	    (r) ? "" : " unexpected", why, BE_BR_STAT_BITS);

	printf("%s: resetting\n", sc->sc_dev.dv_xname);
	bereset(sc);

	return r;
}

void
be_tx_harvest(sc)
	struct besoftc *sc;
{
	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
	int bix, cnt;
	struct be_txd txd;

	bix = sc->sc_first_td;
	cnt = sc->sc_no_td;

	for (;;) {
		if (cnt <= 0)
			break;

		txd.tx_flags = sc->sc_desc->be_txd[bix].tx_flags;

		if (txd.tx_flags & BE_TXD_OWN)
			break;

		ifp->if_opackets++;

		if (++bix == BE_TX_RING_MAXSIZE)
			bix = 0;

		--cnt;
	}

	if (cnt <= 0)
		ifp->if_timer = 0;

	if (sc->sc_no_td != cnt) {
		sc->sc_first_td = bix;
		sc->sc_no_td = cnt;
		ifp->if_flags &= ~IFF_OACTIVE;
	}

	if (sc->sc_no_td < BE_TX_LOW_WATER) {
		/* turn off interrupt */
		sc->sc_tx_intr = 0;
		sc->sc_cr->timask = 0xffffffff;
	}
}

/*
 * Transmit interrupt.
 */
int
betint(sc)
	struct besoftc *sc;
{
	struct ifnet *ifp = &sc->sc_arpcom.ac_if;

	bestart(ifp);
	return (1);
}

/*
 * Receive interrupt.
 */
int
berint(sc)
	struct besoftc *sc;
{
	int bix, len;

	bix = sc->sc_last_rd;

	/*
	 * Process all buffers with valid data.
	 */
	for (;;) {
		if (sc->sc_desc->be_rxd[bix].rx_flags & BE_RXD_OWN)
			break;

		len = sc->sc_desc->be_rxd[bix].rx_flags & BE_RXD_LENGTH;
		be_read(sc, bix, len);

		sc->sc_desc->be_rxd[(bix + BE_RX_RING_SIZE) & BE_RX_RING_MAXMASK].rx_flags =
		    BE_RXD_OWN | (BE_PKT_BUF_SZ & BE_RXD_LENGTH);

		if (++bix == BE_RX_RING_MAXSIZE)
			bix = 0;
	}

	sc->sc_last_rd = bix;

	return 1;
}

void
betick(vsc)
	void *vsc;
{
	struct besoftc *sc = vsc;
	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
	struct be_bregs *br = sc->sc_br;
	int s;

	s = splnet();
	/*
	 * Get collision counters
	 */
	ifp->if_collisions += br->nc_ctr + br->fc_ctr + br->ex_ctr + br->lt_ctr;
	br->nc_ctr = 0;
	br->fc_ctr = 0;
	br->ex_ctr = 0;
	br->lt_ctr = 0;
	bestart(ifp);
	splx(s);
	timeout_add_sec(&sc->sc_tick, 1);
}

int
beioctl(ifp, cmd, data)
	struct ifnet *ifp;
	u_long cmd;
	caddr_t data;
{
	struct besoftc *sc = ifp->if_softc;
	struct ifaddr *ifa = (struct ifaddr *)data;
	struct ifreq *ifr = (struct ifreq *)data;
	int s, error = 0;

	s = splnet();

	switch (cmd) {
	case SIOCSIFADDR:
		ifp->if_flags |= IFF_UP;
		switch (ifa->ifa_addr->sa_family) {
		case AF_INET:
			beinit(sc);
			arp_ifinit(&sc->sc_arpcom, ifa);
			break;
		default:
			beinit(sc);
			break;
		}
		break;

	case SIOCSIFFLAGS:
		if ((ifp->if_flags & IFF_UP) == 0 &&
		    (ifp->if_flags & IFF_RUNNING) != 0) {
			/*
			 * If interface is marked down and it is running, then
			 * stop it.
			 */
			bestop(sc);
			ifp->if_flags &= ~IFF_RUNNING;
		} else if ((ifp->if_flags & IFF_UP) != 0 &&
		    (ifp->if_flags & IFF_RUNNING) == 0) {
			/*
			 * If interface is marked up and it is stopped, then
			 * start it.
			 */
			beinit(sc);
		} else {
			/*
			 * Reset the interface to pick up changes in any other
			 * flags that affect hardware registers.
			 */
			bestop(sc);
			beinit(sc);
		}
		break;

	case SIOCGIFMEDIA:
	case SIOCSIFMEDIA:
		error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd);
		break;

	default:
		error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data);
	}

	if (error == ENETRESET) {
		if (ifp->if_flags & IFF_RUNNING)
			be_mcreset(sc);
		error = 0;
	}

	splx(s);
	return error;
}

void
beinit(sc)
	struct besoftc *sc;
{
	struct be_bregs *br = sc->sc_br;
	struct be_cregs *cr = sc->sc_cr;
	struct qec_softc *qec = sc->sc_qec;
	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
	int s = splnet();
	int i;

	/*
	 * Allocate descriptor ring and buffers, if not already done
	 */
	if (sc->sc_desc == NULL)
		sc->sc_desc_dva = (struct be_desc *) dvma_malloc(
			sizeof(struct be_desc), &sc->sc_desc, M_NOWAIT);
	if (sc->sc_bufs == NULL)
		sc->sc_bufs_dva = (struct be_bufs *) dvma_malloc(
			sizeof(struct be_bufs), &sc->sc_bufs, M_NOWAIT);

	for (i = 0; i < BE_TX_RING_MAXSIZE; i++) {
		sc->sc_desc->be_txd[i].tx_addr =
			(u_int32_t)sc->sc_bufs_dva->tx_buf[i & BE_TX_RING_MASK];
		sc->sc_desc->be_txd[i].tx_flags = 0;
	}
	for (i = 0; i < BE_RX_RING_MAXSIZE; i++) {
		sc->sc_desc->be_rxd[i].rx_addr =
		    (u_int32_t)sc->sc_bufs_dva->rx_buf[i & BE_RX_RING_MASK];
		if (i < BE_RX_RING_SIZE)
			sc->sc_desc->be_rxd[i].rx_flags =
			    BE_RXD_OWN | (BE_PKT_BUF_SZ & BE_RXD_LENGTH);
		else
			sc->sc_desc->be_rxd[i].rx_flags = 0;
	}

	sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
	sc->sc_last_rd = 0;

	be_tcvr_init(sc);

	be_ifmedia_upd(ifp);

	bestop(sc);

	br->mac_addr2 = (sc->sc_arpcom.ac_enaddr[4] << 8) |
	    sc->sc_arpcom.ac_enaddr[5];
	br->mac_addr1 = (sc->sc_arpcom.ac_enaddr[2] << 8) |
	    sc->sc_arpcom.ac_enaddr[3];
	br->mac_addr0 = (sc->sc_arpcom.ac_enaddr[0] << 8) |
	    sc->sc_arpcom.ac_enaddr[1];

	br->rx_cfg = BE_BR_RXCFG_HENABLE | BE_BR_RXCFG_FIFO;

	be_mcreset(sc);

	DELAY(20);

	br->tx_cfg = BE_BR_TXCFG_FIFO;
	br->rand_seed = 0xbd;

	br->xif_cfg = BE_BR_XCFG_ODENABLE | BE_BR_XCFG_RESV;

	cr->rxds = (u_int32_t)sc->sc_desc_dva->be_rxd;
	cr->txds = (u_int32_t)sc->sc_desc_dva->be_txd;

	cr->rxwbufptr = cr->rxrbufptr = sc->sc_channel * qec->sc_msize;
	cr->txwbufptr = cr->txrbufptr = cr->rxrbufptr + qec->sc_rsize;

	/*
	 * Turn off counter expiration interrupts as well as
	 * 'gotframe' and 'sentframe'
	 */
	br->imask = BE_BR_IMASK_GOTFRAME	|
		    BE_BR_IMASK_RCNTEXP		|
		    BE_BR_IMASK_ACNTEXP		|
		    BE_BR_IMASK_CCNTEXP		|
		    BE_BR_IMASK_LCNTEXP		|
		    BE_BR_IMASK_CVCNTEXP	|
		    BE_BR_IMASK_SENTFRAME	|
		    BE_BR_IMASK_NCNTEXP		|
		    BE_BR_IMASK_ECNTEXP		|
		    BE_BR_IMASK_LCCNTEXP	|
		    BE_BR_IMASK_FCNTEXP		|
		    BE_BR_IMASK_DTIMEXP;

	cr->rimask = 0;

	/* disable tx interrupts initially */
	cr->timask = 0xffffffff;
	sc->sc_tx_intr = 0;

	cr->qmask = 0;
	cr->bmask = 0;

	br->jsize = 4;

	cr->ccnt = 0;

	br->tx_cfg |= BE_BR_TXCFG_ENABLE;
	br->rx_cfg |= BE_BR_RXCFG_ENABLE;

	ifp->if_flags |= IFF_RUNNING;
	ifp->if_flags &= ~IFF_OACTIVE;
	splx(s);

	timeout_add_sec(&sc->sc_tick, 1);
	bestart(ifp);
}

/*
 * Set the tcvr to an idle state
 */
void
be_tcvr_idle(sc)
	struct besoftc *sc;
{
	struct be_tregs *tr = sc->sc_tr;
	volatile u_int32_t x;
	int i = 20;

	while (i--) {
		tr->mgmt_pal = MGMT_PAL_INT_MDIO | MGMT_PAL_EXT_MDIO |
			       MGMT_PAL_OENAB;
		x = tr->mgmt_pal;
		tr->mgmt_pal = MGMT_PAL_INT_MDIO | MGMT_PAL_EXT_MDIO |
			       MGMT_PAL_OENAB | MGMT_PAL_DCLOCK;
		x = tr->mgmt_pal;
	}
}

/*
 * Initialize the transceiver and figure out whether we're using the
 * external or internal one.
 */
void
be_tcvr_init(sc)
	struct besoftc *sc;
{
	volatile u_int32_t x;
	struct be_tregs *tr = sc->sc_tr;

	be_tcvr_idle(sc);

	if (sc->sc_rev != 1) {
		printf("%s: rev %d PAL not supported.\n",
			sc->sc_dev.dv_xname,
			sc->sc_rev);
		return;
	}

	tr->mgmt_pal = MGMT_PAL_INT_MDIO | MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK;
	x = tr->mgmt_pal;

	tr->mgmt_pal = MGMT_PAL_INT_MDIO | MGMT_PAL_EXT_MDIO;
	x = tr->mgmt_pal;
	DELAY(200);

	if (tr->mgmt_pal & MGMT_PAL_EXT_MDIO) {
		sc->sc_tcvr_type = BE_TCVR_EXTERNAL;
		tr->tcvr_pal = ~(TCVR_PAL_EXTLBACK | TCVR_PAL_MSENSE |
				 TCVR_PAL_LTENABLE);
		x = tr->tcvr_pal;
	}
	else if (tr->mgmt_pal & MGMT_PAL_INT_MDIO) {
		sc->sc_tcvr_type = BE_TCVR_INTERNAL;
		tr->tcvr_pal = ~(TCVR_PAL_EXTLBACK | TCVR_PAL_MSENSE |
				 TCVR_PAL_LTENABLE | TCVR_PAL_SERIAL);
		x = tr->tcvr_pal;
	}
	else {
		printf("%s: no internal or external transceiver found.\n",
			sc->sc_dev.dv_xname);
	}
}

int
be_tcvr_read(sc, reg)
	struct besoftc *sc;
	u_int8_t reg;
{
	int phy, i;
	u_int32_t ret = 0;

	if (sc->sc_tcvr_type == BE_TCVR_INTERNAL)
		phy = BE_PHY_INTERNAL;
	else if (sc->sc_tcvr_type == BE_TCVR_EXTERNAL)
		phy = BE_PHY_EXTERNAL;
	else {
		printf("%s: invalid tcvr type\n", sc->sc_dev.dv_xname);
		return BE_TCVR_READ_INVALID;
	}

	be_tcvr_idle(sc);

	be_tcvr_write_bit(sc, 0);
	be_tcvr_write_bit(sc, 1);
	be_tcvr_write_bit(sc, 1);
	be_tcvr_write_bit(sc, 0);

	for (i = 4; i >= 0; i--)
		be_tcvr_write_bit(sc, (phy >> i) & 1);

	for (i = 4; i >= 0; i--)
		be_tcvr_write_bit(sc, (reg >> i) & 1);

	if (sc->sc_tcvr_type == BE_TCVR_EXTERNAL) {
		(void) be_tcvr_read_bit2(sc);
		(void) be_tcvr_read_bit2(sc);

		for (i = 15; i >= 0; i--) {
			int b;

			b = be_tcvr_read_bit2(sc);
			ret |= (b & 1) << i;
		}

		(void) be_tcvr_read_bit2(sc);
		(void) be_tcvr_read_bit2(sc);
		(void) be_tcvr_read_bit2(sc);
	}
	else {
		(void) be_tcvr_read_bit1(sc);
		(void) be_tcvr_read_bit1(sc);

		for (i = 15; i >= 0; i--) {
			int b;

			b = be_tcvr_read_bit1(sc);
			ret |= (b & 1) << i;
		}

		(void) be_tcvr_read_bit1(sc);
		(void) be_tcvr_read_bit1(sc);
		(void) be_tcvr_read_bit1(sc);
	}
	return ret;
}

int
be_tcvr_read_bit1(sc)
	struct besoftc *sc;
{
	volatile u_int32_t x;
	struct be_tregs *tr = sc->sc_tr;
	int ret = 0;

	if (sc->sc_tcvr_type == BE_TCVR_INTERNAL) {
		tr->mgmt_pal = MGMT_PAL_EXT_MDIO;
		x = tr->mgmt_pal;
		tr->mgmt_pal = MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK;
		x = tr->mgmt_pal;
		DELAY(20);
		ret = (tr->mgmt_pal & MGMT_PAL_INT_MDIO) >> 3;
	} else if (sc->sc_tcvr_type == BE_TCVR_EXTERNAL) {
		tr->mgmt_pal = MGMT_PAL_INT_MDIO;
		x = tr->mgmt_pal;
		tr->mgmt_pal = MGMT_PAL_INT_MDIO | MGMT_PAL_DCLOCK;
		x = tr->mgmt_pal;
		DELAY(20);
		ret = (tr->mgmt_pal & MGMT_PAL_EXT_MDIO) >> 2;
	} else {
		printf("%s: invalid tcvr type\n", sc->sc_dev.dv_xname);
	}
	return (ret & 1);
}

int
be_tcvr_read_bit2(sc)
	struct besoftc *sc;
{
	volatile u_int32_t x;
	struct be_tregs *tr = sc->sc_tr;
	int ret = 0;

	if (sc->sc_tcvr_type == BE_TCVR_INTERNAL) {
		tr->mgmt_pal = MGMT_PAL_EXT_MDIO;
		x = tr->mgmt_pal;
		DELAY(20);
		ret = (tr->mgmt_pal & MGMT_PAL_INT_MDIO) >> 3;
		tr->mgmt_pal = MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK;
		x = tr->mgmt_pal;
	} else if (sc->sc_tcvr_type == BE_TCVR_EXTERNAL) {
		tr->mgmt_pal = MGMT_PAL_INT_MDIO;
		x = tr->mgmt_pal;
		DELAY(20);
		ret = (tr->mgmt_pal & MGMT_PAL_EXT_MDIO) >> 2;
		tr->mgmt_pal = MGMT_PAL_INT_MDIO | MGMT_PAL_DCLOCK;
		x = tr->mgmt_pal;
	} else {
		printf("%s: invalid tcvr type\n", sc->sc_dev.dv_xname);
	}
	return ret;
}

void
be_tcvr_write(sc, reg, val)
	struct besoftc *sc;
	u_int8_t reg;
	u_int16_t val;
{
	int phy, i;

	if (sc->sc_tcvr_type == BE_TCVR_INTERNAL)
		phy = BE_PHY_INTERNAL;
	else if (sc->sc_tcvr_type == BE_TCVR_EXTERNAL)
		phy = BE_PHY_EXTERNAL;
	else {
		printf("%s: invalid tcvr type\n", sc->sc_dev.dv_xname);
		return;
	}

	be_tcvr_idle(sc);

	be_tcvr_write_bit(sc, 0);
	be_tcvr_write_bit(sc, 1);
	be_tcvr_write_bit(sc, 0);
	be_tcvr_write_bit(sc, 1);

	for (i = 4; i >= 0; i--)
		be_tcvr_write_bit(sc, (phy >> i) & 1);

	for (i = 4; i >= 0; i--)
		be_tcvr_write_bit(sc, (reg >> i) & 1);

	be_tcvr_write_bit(sc, 1);
	be_tcvr_write_bit(sc, 0);

	for (i = 15; i >= 0; i--)
		be_tcvr_write_bit(sc, (val >> i) & 1);
}

void
be_tcvr_write_bit(sc, bit)
	struct besoftc *sc;
	int bit;
{
	volatile u_int32_t x;

	if (sc->sc_tcvr_type == BE_TCVR_INTERNAL) {
		bit = ((bit & 1) << 3) | MGMT_PAL_OENAB | MGMT_PAL_EXT_MDIO;
		sc->sc_tr->mgmt_pal = bit;
		x = sc->sc_tr->mgmt_pal;
		sc->sc_tr->mgmt_pal = bit | MGMT_PAL_DCLOCK;
		x = sc->sc_tr->mgmt_pal;
	} else {
		bit = ((bit & 1) << 2) | MGMT_PAL_OENAB | MGMT_PAL_INT_MDIO;
		sc->sc_tr->mgmt_pal = bit;
		x = sc->sc_tr->mgmt_pal;
		sc->sc_tr->mgmt_pal = bit | MGMT_PAL_DCLOCK;
		x = sc->sc_tr->mgmt_pal;
	}
}

/*
 * Pass a packet to the higher levels.
 */
void
be_read(sc, idx, len)
	struct besoftc *sc;
	int idx, len;
{
	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
	struct mbuf *m;

	if (len <= sizeof(struct ether_header) ||
	    len > ETHERMTU + sizeof(struct ether_header)) {

		printf("%s: invalid packet size %d; dropping\n",
			ifp->if_xname, len);

		ifp->if_ierrors++;
		return;
	}

	/*
	 * Pull packet off interface.
	 */
	m = qec_get(sc->sc_bufs->rx_buf[idx & BE_RX_RING_MASK], len);
	if (m == NULL) {
		ifp->if_ierrors++;
		return;
	}

	ml_enqueue(&ml, m);
	if_input(ifp, &ml);
}

/*
 * Get current media settings.
 */
void
be_ifmedia_sts(ifp, ifmr)
	struct ifnet *ifp;
	struct ifmediareq *ifmr;
{
	struct besoftc *sc = ifp->if_softc;
	int bmcr, bmsr;

	bmcr = be_tcvr_read(sc, PHY_BMCR);

	switch (bmcr & (PHY_BMCR_SPEED | PHY_BMCR_DUPLEX)) {
	case (PHY_BMCR_SPEED | PHY_BMCR_DUPLEX):
		ifmr->ifm_active = IFM_ETHER | IFM_100_TX | IFM_FDX;
		break;
	case PHY_BMCR_SPEED:
		ifmr->ifm_active = IFM_ETHER | IFM_100_TX | IFM_HDX;
		break;
	case PHY_BMCR_DUPLEX:
		ifmr->ifm_active = IFM_ETHER | IFM_10_T | IFM_FDX;
		break;
	case 0:
		ifmr->ifm_active = IFM_ETHER | IFM_10_T | IFM_HDX;
		break;
	}

	bmsr = be_tcvr_read(sc, PHY_BMSR);
	if (bmsr & PHY_BMSR_LINKSTATUS)
		ifmr->ifm_status |=  IFM_AVALID | IFM_ACTIVE;
	else {
		ifmr->ifm_status |=  IFM_AVALID;
		ifmr->ifm_status &= ~IFM_ACTIVE;
	}
}

/*
 * Set media options.
 */
int
be_ifmedia_upd(ifp)
	struct ifnet *ifp;
{
	struct besoftc *sc = ifp->if_softc;
	struct ifmedia *ifm = &sc->sc_ifmedia;
	int bmcr, tries;

	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
		return (EINVAL);

	be_tcvr_write(sc, PHY_BMCR,
		PHY_BMCR_LOOPBACK | PHY_BMCR_PDOWN | PHY_BMCR_ISOLATE);
	be_tcvr_write(sc, PHY_BMCR, PHY_BMCR_RESET);

	for (tries = 16; tries >= 0; tries--) {
		bmcr = be_tcvr_read(sc, PHY_BMCR);
		if ((bmcr & PHY_BMCR_RESET) == 0)
			break;
		DELAY(20);
	}
	if (tries == 0) {
		printf("%s: bmcr reset failed\n", sc->sc_dev.dv_xname);
		return (EIO);
	}

	bmcr = be_tcvr_read(sc, PHY_BMCR);

	if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_T4) {
		bmcr |= PHY_BMCR_SPEED;
		bmcr &= ~PHY_BMCR_DUPLEX;
	}

	if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_TX) {
		bmcr |= PHY_BMCR_SPEED;
	}

	if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_T) {
		bmcr &= ~PHY_BMCR_SPEED;
	}

	if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) {
		bmcr |= PHY_BMCR_DUPLEX;
		sc->sc_br->tx_cfg |= BE_BR_TXCFG_FULLDPLX;
	}
	else {
		bmcr &= ~PHY_BMCR_DUPLEX;
		sc->sc_br->tx_cfg &= ~BE_BR_TXCFG_FULLDPLX;
	}

	be_tcvr_write(sc, PHY_BMCR, bmcr & (~PHY_BMCR_ISOLATE));

	for (tries = 32; tries >= 0; tries--) {
		bmcr = be_tcvr_read(sc, PHY_BMCR);
		if ((bmcr & PHY_BMCR_ISOLATE) == 0)
			break;
		DELAY(20);
	}
	if (tries == 0) {
		printf("%s: bmcr unisolate failed\n", sc->sc_dev.dv_xname);
		return (EIO);
	}

	return (0);
}

void
be_mcreset(sc)
	struct besoftc *sc;
{
	struct arpcom *ac = &sc->sc_arpcom;
	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
	struct be_bregs *br = sc->sc_br;
	u_int32_t crc;
	u_int16_t hash[4];
	u_int8_t octet;
	int i, j;
	struct ether_multi *enm;
	struct ether_multistep step;

	if (ifp->if_flags & IFF_PROMISC) {
		br->rx_cfg |= BE_BR_RXCFG_PMISC;
		return;
	}
	else
		br->rx_cfg &= ~BE_BR_RXCFG_PMISC;

	if (ac->ac_multirangecnt > 0)
		ifp->if_flags |= IFF_ALLMULTI;

	if (ifp->if_flags & IFF_ALLMULTI) {
		br->htable3 = 0xffff;
		br->htable2 = 0xffff;
		br->htable1 = 0xffff;
		br->htable0 = 0xffff;
		return;
	}

	hash[3] = hash[2] = hash[1] = hash[0] = 0;

	ETHER_FIRST_MULTI(step, ac, enm);
	while (enm != NULL) {
		crc = 0xffffffff;

		for (i = 0; i < ETHER_ADDR_LEN; i++) {
			octet = enm->enm_addrlo[i];

			for (j = 0; j < 8; j++) {
				if ((crc & 1) ^ (octet & 1)) {
					crc >>= 1;
					crc ^= MC_POLY_LE;
				}
				else
					crc >>= 1;
				octet >>= 1;
			}
		}

		crc >>= 26;
		hash[crc >> 4] |= 1 << (crc & 0xf);
		ETHER_NEXT_MULTI(step, enm);
	}

	br->htable3 = hash[3];
	br->htable2 = hash[2];
	br->htable1 = hash[1];
	br->htable0 = hash[0];
	ifp->if_flags &= ~IFF_ALLMULTI;
}


code:
/*	$OpenBSD: bereg.h,v 1.12 2003/06/02 18:40:59 jason Exp $	*/

/*
 * Copyright (c) 1998 Theo de Raadt and Jason L. Wright.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * BE Global registers
 */
struct be_bregs {
	volatile u_int32_t xif_cfg;		/* XIF config */
	volatile u_int32_t _unused[63];		/* reserved */
	volatile u_int32_t stat;		/* status, clear on read */
	volatile u_int32_t imask;		/* interrupt mask */
	volatile u_int32_t _unused2[64];	/* reserved */
	volatile u_int32_t tx_swreset;		/* tx software reset */
	volatile u_int32_t tx_cfg;		/* tx config */
	volatile u_int32_t ipkt_gap1;		/* inter-packet gap 1 */
	volatile u_int32_t ipkt_gap2;		/* inter-packet gap 2 */
	volatile u_int32_t attempt_limit;	/* tx attempt limit */
	volatile u_int32_t stime;		/* tx slot time */
	volatile u_int32_t preamble_len;	/* size of tx preamble */
	volatile u_int32_t preamble_pattern;	/* pattern for tx preamble */
	volatile u_int32_t tx_sframe_delim;	/* tx delimiter */
	volatile u_int32_t jsize;		/* jam length */
	volatile u_int32_t tx_pkt_max;		/* tx max pkt size */
	volatile u_int32_t tx_pkt_min;		/* tx min pkt size */
	volatile u_int32_t peak_attempt;	/* count of tx peak attempts */
	volatile u_int32_t dt_ctr;		/* tx defer timer */
	volatile u_int32_t nc_ctr;		/* tx normal collision cntr */
	volatile u_int32_t fc_ctr;		/* tx first-collision cntr */
	volatile u_int32_t ex_ctr;		/* tx excess-collision cntr */
	volatile u_int32_t lt_ctr;		/* tx late-collision cntr */
	volatile u_int32_t rand_seed;		/* tx random number seed */
	volatile u_int32_t tx_smachine;		/* tx state machine */
	volatile u_int32_t _unused3[44];	/* reserved */
	volatile u_int32_t rx_swreset;		/* rx software reset */
	volatile u_int32_t rx_cfg;		/* rx config register */
	volatile u_int32_t rx_pkt_max;		/* rx max pkt size */
	volatile u_int32_t rx_pkt_min;		/* rx min pkt size */
	volatile u_int32_t mac_addr2;		/* ethernet address 2 (MSB) */
	volatile u_int32_t mac_addr1;		/* ethernet address 1 */
	volatile u_int32_t mac_addr0;		/* ethernet address 0 (LSB) */
	volatile u_int32_t fr_ctr;		/* rx frame receive cntr */
	volatile u_int32_t gle_ctr;		/* rx giant-len error cntr */
	volatile u_int32_t unale_ctr;		/* rx unaligned error cntr */
	volatile u_int32_t rcrce_ctr;		/* rx CRC error cntr */
	volatile u_int32_t rx_smachine;		/* rx state machine */
	volatile u_int32_t rx_cvalid;		/* rx code violation */
	volatile u_int32_t _unused4;		/* reserved */
	volatile u_int32_t htable3;		/* hash table 3 */
	volatile u_int32_t htable2;		/* hash table 2 */
	volatile u_int32_t htable1;		/* hash table 1 */
	volatile u_int32_t htable0;		/* hash table 0 */
	volatile u_int32_t afilter2;		/* address filter 2 */
	volatile u_int32_t afilter1;		/* address filter 1 */
	volatile u_int32_t afilter0;		/* address filter 0 */
	volatile u_int32_t afilter_mask;	/* address filter mask */
};

/* be_bregs.xif_cfg: XIF config. */
#define BE_BR_XCFG_ODENABLE	0x00000001	/* output driver enable */
#define BE_BR_XCFG_RESV		0x00000002	/* reserved, write as 1 */
#define BE_BR_XCFG_MLBACK	0x00000004	/* loopback-mode mii enable */
#define BE_BR_XCFG_SMODE	0x00000008	/* enable serial mode */

/* be_bregs.stat: status, clear on read. */
#define BE_BR_STAT_GOTFRAME	0x00000001	/* received a frame */
#define BE_BR_STAT_RCNTEXP	0x00000002	/* rx frame cntr expired */
#define BE_BR_STAT_ACNTEXP	0x00000004	/* align-error cntr expired */
#define BE_BR_STAT_CCNTEXP	0x00000008	/* crc-error cntr expired */
#define BE_BR_STAT_LCNTEXP	0x00000010	/* length-error cntr expired */
#define BE_BR_STAT_RFIFOVF	0x00000020	/* rx fifo overflow */
#define BE_BR_STAT_CVCNTEXP	0x00000040	/* code-violation cntr exprd */
#define BE_BR_STAT_SENTFRAME	0x00000100	/* transmitted a frame */
#define BE_BR_STAT_TFIFO_UND	0x00000200	/* tx fifo underrun */
#define BE_BR_STAT_MAXPKTERR	0x00000400	/* max-packet size error */
#define BE_BR_STAT_NCNTEXP	0x00000800	/* normal-collision cntr exp */
#define BE_BR_STAT_ECNTEXP	0x00001000	/* excess-collision cntr exp */
#define BE_BR_STAT_LCCNTEXP	0x00002000	/* late-collision cntr exp */
#define BE_BR_STAT_FCNTEXP	0x00004000	/* first-collision cntr exp */
#define BE_BR_STAT_DTIMEXP	0x00008000	/* defer-timer expired */

#define BE_BR_STAT_BITS		"\20\1RX\2RCNT\3ACNT\4CCNT\5LCNT\6RFIFO\7CVCNT\11TX\12TFIFO\13TMAXPKT\14NCNT\15ECNT\16LCCNT\17ECNT\20DTIME"

/* be_bregs.imask: interrupt mask. */
#define BE_BR_IMASK_GOTFRAME	0x00000001	/* received a frame */
#define BE_BR_IMASK_RCNTEXP	0x00000002	/* rx frame cntr expired */
#define BE_BR_IMASK_ACNTEXP	0x00000004	/* align-error cntr expired */
#define BE_BR_IMASK_CCNTEXP	0x00000008	/* crc-error cntr expired */
#define BE_BR_IMASK_LCNTEXP	0x00000010	/* length-error cntr expired */
#define BE_BR_IMASK_RFIFOVF	0x00000020	/* rx fifo overflow */
#define BE_BR_IMASK_CVCNTEXP	0x00000040	/* code-violation cntr exprd */
#define BE_BR_IMASK_SENTFRAME	0x00000100	/* transmitted a frame */
#define BE_BR_IMASK_TFIFO_UND	0x00000200	/* tx fifo underrun */
#define BE_BR_IMASK_MAXPKTERR	0x00000400	/* max-packet size error */
#define BE_BR_IMASK_NCNTEXP	0x00000800	/* normal-collision cntr exp */
#define BE_BR_IMASK_ECNTEXP	0x00001000	/* excess-collision cntr exp */
#define BE_BR_IMASK_LCCNTEXP	0x00002000	/* late-collision cntr exp */
#define BE_BR_IMASK_FCNTEXP	0x00004000	/* first-collision cntr exp */
#define BE_BR_IMASK_DTIMEXP	0x00008000	/* defer-timer expired */

/* be_bregs.tx_cfg: tx config. */
#define BE_BR_TXCFG_ENABLE	0x00000001	/* enable the transmitter */
#define BE_BR_TXCFG_FIFO	0x00000010	/* default tx fthresh */
#define BE_BR_TXCFG_SMODE	0x00000020	/* enable slow transmit mode */
#define BE_BR_TXCFG_CIGN	0x00000040	/* ignore tx collisions */
#define BE_BR_TXCFG_FCSOFF	0x00000080	/* do not emit fcs */
#define BE_BR_TXCFG_DBACKOFF	0x00000100	/* disable backoff */
#define BE_BR_TXCFG_FULLDPLX	0x00000200	/* enable full-duplex */

/* be_bregs.rx_cfg: rx config. */
#define BE_BR_RXCFG_ENABLE	0x00000001	/* enable the receiver */
#define BE_BR_RXCFG_FIFO	0x0000000e	/* default rx fthresh */
#define BE_BR_RXCFG_PSTRIP	0x00000020	/* pad byte strip enable */
#define BE_BR_RXCFG_PMISC	0x00000040	/* enable promiscous mode */
#define BE_BR_RXCFG_DERR	0x00000080	/* disable error checking */
#define BE_BR_RXCFG_DCRCS	0x00000100	/* disable crc stripping */
#define BE_BR_RXCFG_ME		0x00000200	/* receive packets for me */
#define BE_BR_RXCFG_PGRP	0x00000400	/* enable promisc group mode */
#define BE_BR_RXCFG_HENABLE	0x00000800	/* enable hash filter */
#define BE_BR_RXCFG_AENABLE	0x00001000	/* enable address filter */

/*
 * BE Channel registers
 */
struct be_cregs {
	volatile u_int32_t ctrl;		/* control */
	volatile u_int32_t stat;		/* status */
	volatile u_int32_t rxds;		/* rx descriptor ring ptr */
	volatile u_int32_t txds;		/* tx descriptor ring ptr */
	volatile u_int32_t rimask;		/* rx interrupt mask */
	volatile u_int32_t timask;		/* tx interrupt mask */
	volatile u_int32_t qmask;		/* qec error interrupt mask */
	volatile u_int32_t bmask;		/* be error interrupt mask */
	volatile u_int32_t rxwbufptr;		/* local memory rx write ptr */
	volatile u_int32_t rxrbufptr;		/* local memory rx read ptr */
	volatile u_int32_t txwbufptr;		/* local memory tx write ptr */
	volatile u_int32_t txrbufptr;		/* local memory tx read ptr */
	volatile u_int32_t ccnt;		/* collision counter */
};

/* be_cregs.ctrl: control. */
#define	BE_CR_CTRL_TWAKEUP	0x00000001	/* tx dma wakeup */

/* be_cregs.stat: status. */
#define BE_CR_STAT_BERROR	0x80000000	/* be error */
#define BE_CR_STAT_TXIRQ	0x00200000	/* tx interrupt */
#define BE_CR_STAT_TXDERR	0x00080000	/* tx descriptor is bad */
#define BE_CR_STAT_TXLERR	0x00040000	/* tx late error */
#define BE_CR_STAT_TXPERR	0x00020000	/* tx parity error */
#define BE_CR_STAT_TXSERR	0x00010000	/* tx sbus error ack */
#define BE_CR_STAT_RXIRQ	0x00000020	/* rx interrupt */
#define BE_CR_STAT_RXDROP	0x00000010	/* rx packet dropped */
#define BE_CR_STAT_RXSMALL	0x00000008	/* rx buffer too small */
#define BE_CR_STAT_RXLERR	0x00000004	/* rx late error */
#define BE_CR_STAT_RXPERR	0x00000002	/* rx parity error */
#define BE_CR_STAT_RXSERR	0x00000001	/* rx sbus error ack */

/*
 * All bits except rxirq/txirq
 */
#define	BE_CR_STAT_ERRORS	\
			(BE_CR_STAT_BERROR |				\
			 BE_CR_STAT_TXDERR | BE_CR_STAT_TXLERR |	\
			 BE_CR_STAT_TXPERR | BE_CR_STAT_TXSERR |	\
			 BE_CR_STAT_RXDROP | BE_CR_STAT_RXSMALL |	\
			 BE_CR_STAT_RXLERR | BE_CR_STAT_RXPERR |	\
			 BE_CR_STAT_RXSERR)

#define	BE_CR_STAT_BITS		\
    "\20\1RXS\2RXP\3RXL\4RXSMALL\5RXDROP\6RX\21TXS\22TXP\23TXL\24TXD\26TX\40BE"

/* be_cregs.qmask: qec error interrupt mask. */
#define BE_CR_QMASK_TXDERR	0x00080000	/* tx descriptor is bad */
#define BE_CR_QMASK_TXLERR	0x00040000	/* tx late error */
#define BE_CR_QMASK_TXPERR	0x00020000	/* tx parity error */
#define BE_CR_QMASK_TXSERR	0x00010000	/* tx sbus error ack */
#define BE_CR_QMASK_RXDROP	0x00000010	/* rx packet dropped */
#define BE_CR_QMASK_RXSMALL	0x00000008	/* rx buffer too small */
#define BE_CR_QMASK_RXLERR	0x00000004	/* rx late error */
#define BE_CR_QMASK_RXPERR	0x00000002	/* rx parity error */
#define BE_CR_QMASK_RXSERR	0x00000001	/* rx sbus error ack */

/*
 * BE Transceiver registers
 */
struct be_tregs {
	volatile u_int32_t	tcvr_pal;	/* transceiver pal */
	volatile u_int32_t	mgmt_pal;	/* management pal */
};

/* be_tregs.tcvr_pal: transceiver pal */
#define	TCVR_PAL_SERIAL		0x00000001	/* serial mode enable */
#define TCVR_PAL_EXTLBACK	0x00000002	/* external loopback */
#define TCVR_PAL_MSENSE		0x00000004	/* media sense */
#define TCVR_PAL_LTENABLE	0x00000008	/* link test enable */
#define TCVR_PAL_LTSTATUS	0x00000010	/* link test status: p1 only */

/* be_tregs.mgmt_pal: management pal */
#define MGMT_PAL_DCLOCK		0x00000001	/* data clock strobe */
#define MGMT_PAL_OENAB		0x00000002	/* output enable */
#define MGMT_PAL_MDIO		0x00000004	/* MDIO data/attached */
#define MGMT_PAL_EXT_MDIO	MGMT_PAL_MDIO	/* external mdio */
#define MGMT_PAL_TIMEO		0x00000008	/* tx enable timeout error */
#define MGMT_PAL_INT_MDIO	MGMT_PAL_TIMEO	/* internal mdio */

/*
 * BE receive descriptor
 */
struct be_rxd {
	volatile u_int32_t rx_flags;		/* rx descriptor flags */
	volatile u_int32_t rx_addr;		/* rx buffer address */
};

#define BE_RXD_OWN		0x80000000	/* ownership: 1=hw, 0=sw */
#define BE_RXD_UPDATE		0x10000000	/* being updated? */
#define BE_RXD_LENGTH		0x00001fff	/* packet length */

/*
 * BE transmit descriptor
 */
struct be_txd {
	volatile u_int32_t tx_flags;		/* tx descriptor flags */
	volatile u_int32_t tx_addr;		/* tx buffer address */
};

#define BE_TXD_OWN		0x80000000	/* ownership: 1=hw, 0=sw */
#define BE_TXD_SOP		0x40000000	/* start of packet marker */
#define BE_TXD_EOP		0x20000000	/* end of packet marker */
#define BE_TXD_UPDATE		0x10000000	/* being updated? */
#define BE_TXD_LENGTH		0x00001fff	/* packet length */

/* Buffer and Ring sizes: fixed ring size */
#define BE_TX_RING_MAXSIZE	256		/* maximum tx ring size */
#define BE_RX_RING_MAXSIZE	256		/* maximum rx ring size */
#define BE_TX_RING_SIZE		32		/* power of 2, <= MAXSIZE */
#define BE_RX_RING_SIZE		32		/* power of 2, <= MAXSIZE */
#define BE_PKT_BUF_SZ		2048
#define	BE_TX_HIGH_WATER	27		/* enable tx interrupt */
#define	BE_TX_LOW_WATER		5		/* disable tx interrupt */

#define	BE_TX_RING_MAXMASK	(BE_TX_RING_MAXSIZE-1)
#define	BE_RX_RING_MAXMASK	(BE_RX_RING_MAXSIZE-1)
#define	BE_TX_RING_MASK		(BE_TX_RING_SIZE-1)
#define	BE_RX_RING_MASK		(BE_RX_RING_SIZE-1)

/*
 * BE descriptor rings
 */
struct be_desc {
	struct be_rxd be_rxd[BE_RX_RING_MAXSIZE];
	struct be_txd be_txd[BE_TX_RING_MAXSIZE];
};

/*
 * BE packet buffers
 */
struct be_bufs {
	char	rx_buf[BE_RX_RING_SIZE][BE_PKT_BUF_SZ];
	char	tx_buf[BE_TX_RING_SIZE][BE_PKT_BUF_SZ];
};

#define	MC_POLY_BE		0x04c11db7UL	/* mcast crc, big endian */
#define	MC_POLY_LE		0xedb88320UL	/* mcast crc, little endian */

/* PHY addresses */
#define BE_PHY_EXTERNAL		0
#define BE_PHY_INTERNAL		1

/* Transceiver types */
#define BE_TCVR_NONE		0
#define BE_TCVR_INTERNAL	1
#define BE_TCVR_EXTERNAL	2

#define BE_TCVR_READ_INVALID	0xff000000

#define BE_NEGOTIATE_MAXTICKS	16

#define PHY_BMCR		0x00	/* Basic Mode Control Register */
#define PHY_BMSR		0x01	/* Basic Mode Status Register */

/*
 * Basic Mode Control Register (BMCR)
 */
#define PHY_BMCR_RESET		0x8000	/* Software reset		*/
#define PHY_BMCR_LOOPBACK	0x4000	/* Lookback enable		*/
#define PHY_BMCR_SPEED		0x2000	/* 1=100Mb, 0=10Mb		*/
#define PHY_BMCR_ANE		0x1000	/* Auto-Negiation enable	*/
#define PHY_BMCR_PDOWN		0x0800	/* power down the chip		*/
#define PHY_BMCR_ISOLATE	0x0400	/* Isolate the chip		*/
#define PHY_BMCR_RAN		0x0200	/* Restart autonegotiation	*/
#define PHY_BMCR_DUPLEX		0x0100	/* 1=full, 0=half		*/
#define PHY_BMCR_COLLISONTEST	0x0080	/* Create collisions on TX	*/

/*
 * Basic Mode Status Register (BMSR)
 */
#define PHY_BMSR_100BASET4	0x8000	/* 100BaseT4 capable?		*/
#define PHY_BMSR_100BASETX_FULL	0x4000	/* 100BaseTX full duplex cap?	*/
#define PHY_BMSR_100BASETX_HALF	0x2000	/* 100BaseTX half duplex cap?	*/
#define PHY_BMSR_10BASET_FULL	0x1000	/* 10BaseT full duplex cap?	*/
#define PHY_BMSR_10BASET_HALF	0x0800	/* 10BaseT half duplex cap?	*/
#define PHY_BMSR_ANCOMPLETE	0x0020	/* auto-negotiation complete?	*/
#define PHY_BMSR_REMOTEFAULT	0x0010	/* Fault condition seen?	*/
#define PHY_BMSR_ANC		0x0008	/* Can auto-negotiate?		*/
#define PHY_BMSR_LINKSTATUS	0x0004	/* Link established?		*/
#define PHY_BMSR_JABBER		0x0002	/* Jabber detected?		*/
#define PHY_BMSR_EXTENDED	0x0001	/* Extended registers?		*/

license: unknown


code:
/*	$OpenBSD: bevar.h,v 1.14 2006/06/02 20:00:54 miod Exp $	*/

/*
 * Copyright (c) 1998 Theo de Raadt and Jason L. Wright.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

struct besoftc {
	struct	device sc_dev;
	struct	intrhand sc_ih;		/* interrupt vectoring */
	struct	arpcom sc_arpcom;	/* ethernet common */
	struct	ifmedia sc_ifmedia;	/* interface media */

	struct	qec_softc *sc_qec;	/* QEC parent */
	struct	qecregs *sc_qr;		/* QEC registers */
	struct	be_bregs *sc_br;	/* be registers */
	struct	be_cregs *sc_cr;	/* channel registers */
	struct	be_tregs *sc_tr;	/* transceiver registers */

	u_int	sc_rev;

	int	sc_channel;		/* channel number */
	int	sc_burst;
	int	sc_tcvr_type;
	int	sc_tx_intr;

	struct	be_bufs *sc_bufs, *sc_bufs_dva;
	struct	be_desc *sc_desc, *sc_desc_dva;

	int	sc_no_td, sc_first_td, sc_last_td;
	int	sc_last_rd;

	struct timeout sc_tick;
};


code:
/*	$OpenBSD: bpp.c,v 1.6 2015/02/10 21:56:09 miod Exp $	*/

/*
 * Copyright (c) 1997, Jason Downs.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/buf.h>
#include <sys/kernel.h>
#include <sys/uio.h>
#include <sys/device.h>
#include <sys/conf.h>
#include <sys/systm.h>

#include <machine/autoconf.h>
#include <machine/conf.h>

#include <sparc/dev/bppreg.h>

#define BPP_BSIZE	1024

#define LONG_TIMEOUT	30		/* XXX */
#define SHORT_TIMEOUT	3		/* XXX */

struct bpp_softc {
	struct device sc_dev;

	size_t sc_count;
	struct buf *sc_inbuf;
	u_int8_t *sc_cp;

	char sc_open;

	volatile struct bppregs *sc_regs;
};

static int bppmatch(struct device *, void *, void *);
static void bppattach(struct device *, struct device *, void *);

#define BPPUNIT(s)	minor(s)

struct cfattach bpp_ca = {
	sizeof(struct bpp_softc), bppmatch, bppattach
};

struct cfdriver bpp_cd = {
	NULL, "bpp", DV_DULL
};

static __inline__ void bpp_outb(struct bpp_softc *, u_int8_t);
static __inline__ u_int8_t bpp_inb(struct bpp_softc *);
static void bppreset(struct bpp_softc *, int);
static void bppresetmode(struct bpp_softc *);
static int bpppushbytes(struct bpp_softc *);

static int
bppmatch(parent, vcf, aux)
	struct device *parent;
	void *aux, *vcf;
{
	register struct confargs *ca = aux;

	if (strcmp(ca->ca_ra.ra_name, "SUNW,bpp"))
		return (0);

	return (1);
}

static void
bppattach(parent, self, aux)
	struct device *parent, *self;
	void *aux;
{
	struct confargs *ca = aux;
	struct romaux *ra = &ca->ca_ra;
	struct bpp_softc *bpp = (void *)self;

	bpp->sc_regs = mapiodev(ra->ra_reg, 0, ra->ra_len);

	bppreset(bpp, 0);

	switch (bpp->sc_regs->bpp_csr & BPP_DEV_ID_MASK) {
	case BPP_DEV_ID_ZEBRA:
		printf(": Zebra\n");
		break;
	case BPP_DEV_ID_L64854:
		printf(": DMA2\n");
		break;
	default:
		printf(": Unknown type\n");
		break;
	}

	bppresetmode(bpp);
}

static void
bppreset(bpp, verbose)
	struct bpp_softc *bpp;
	int verbose;
{
	volatile u_int32_t bpp_csr;

	/* Reset hardware. */
	bpp_csr = bpp->sc_regs->bpp_csr;
	if ((bpp_csr & BPP_DRAINING) && !(bpp_csr & BPP_ERR_PEND)) {
		delay(20);

		bpp_csr = bpp->sc_regs->bpp_csr;
		if (verbose && (bpp_csr & BPP_DRAINING) &&
		    !(bpp_csr & BPP_ERR_PEND))
			printf("%s: draining still active (0x%08x)\n",
			    bpp->sc_dev.dv_xname, bpp_csr);
	}
	bpp->sc_regs->bpp_csr = (bpp_csr | BPP_RESET) & ~BPP_INT_EN;
	delay(500);
	bpp->sc_regs->bpp_csr &= ~BPP_RESET;
}

static void
bppresetmode(bpp)
	struct bpp_softc *bpp;
{
	bpp->sc_regs->bpp_or = BPP_OR_AFXN|BPP_OR_SLCT_IN;
	bpp->sc_regs->bpp_tcr = BPP_TCR_DS;
}

static __inline__ void
bpp_outb(bpp, byte)
	struct bpp_softc *bpp;
	u_int8_t byte;
{
	bpp->sc_regs->bpp_dr = byte;
}

static __inline__ u_int8_t
bpp_inb(bpp)
	struct bpp_softc *bpp;
{
	return (bpp->sc_regs->bpp_dr);
}

int
bppopen(dev, flag, mode, p)
	dev_t dev;
	int flag, mode;
	struct proc *p;
{
	int unit = BPPUNIT(dev);
	struct bpp_softc *bpp;

	if (unit >= bpp_cd.cd_ndevs)
		return (ENXIO);
	bpp = bpp_cd.cd_devs[unit];
	if (!bpp)
		return (ENXIO);

	if (bpp->sc_open)
		return (EBUSY);

	bpp->sc_inbuf = geteblk(BPP_BSIZE);
	bpp->sc_count = 0;
	bpp->sc_open = 1;

	/* bppreset(bpp, 1); */
	bppresetmode(bpp);

	return (0);
}

int
bppclose(dev, flag, mode, p)
	dev_t dev;
	int flag, mode;
	struct proc *p;
{
	struct bpp_softc *bpp = bpp_cd.cd_devs[BPPUNIT(dev)];
	int error = 0;

	if (bpp->sc_count)
		(void) bpppushbytes(bpp);

	/* XXX */
	bppresetmode(bpp);
	delay(100);
	bppreset(bpp, 1);
	delay(100);
	bppresetmode(bpp);

	brelse(bpp->sc_inbuf);

	bpp->sc_open = 0;
	return (error);
}

int
bpppushbytes(bpp)
	struct bpp_softc *bpp;
{
	int spin, error;

	while (bpp->sc_count > 0) {
		error = 0;

		/* Wait for BPP_TCR_ACK and BPP_TCR_BUSY to clear. */
		spin = 0;
		while ((bpp->sc_regs->bpp_tcr & BPP_TCR_ACK) ||
		    (bpp->sc_regs->bpp_tcr & BPP_TCR_BUSY)) {
			delay(1000);
			if (++spin >= LONG_TIMEOUT)
				break;
		}

		if ((bpp->sc_regs->bpp_tcr & BPP_TCR_ACK) ||
		    (bpp->sc_regs->bpp_tcr & BPP_TCR_BUSY))
			return (EBUSY);

		bpp_outb(bpp, *bpp->sc_cp++);

		/* Clear BPP_TCR_DS. */
		bpp->sc_regs->bpp_tcr &= ~BPP_TCR_DS;

		/* Short wait for BPP_TCR_BUSY. */
		spin = 0;
		while (!(bpp->sc_regs->bpp_tcr & BPP_TCR_BUSY)) {
			delay(1000);
			if (++spin >= SHORT_TIMEOUT)
				break;
		}
		if (!(bpp->sc_regs->bpp_tcr & BPP_TCR_BUSY))
			error = EIO;

		/* Set BPP_TCR_DS. */
		bpp->sc_regs->bpp_tcr |= BPP_TCR_DS;

		if (error)
			return (error);

		bpp->sc_count--;
	}
	return (error);
}

int
bppwrite(dev, uio, flags)
	dev_t dev;
	struct uio *uio;
	int flags;
{
	struct bpp_softc *bpp = bpp_cd.cd_devs[BPPUNIT(dev)];
	size_t n;
	int error = 0;

	while ((n = min(BPP_BSIZE, uio->uio_resid)) != 0) {
		error = uiomovei(bpp->sc_cp = bpp->sc_inbuf->b_data, n, uio);
		if (error != 0)
			return error;
		bpp->sc_count = n;
		error = bpppushbytes(bpp);
		if (error) {
			/*
			 * Return accurate residual if interrupted or timed
			 * out.
			 */
			uio->uio_resid += bpp->sc_count;
			bpp->sc_count = 0;
			return (error);
		}
	}
	return (0);
}

int
bppioctl(dev, cmd, data, flag, p)
	dev_t dev;
	u_long cmd;
	caddr_t data;
	int flag;
	struct proc *p;
{
	return (ENODEV);
}


code:
/*	$OpenBSD: bppreg.h,v 1.3 2003/06/03 21:09:02 deraadt Exp $	*/

/*
 * Copyright (c) 1997, Jason Downs.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * based on work by Stephen Williams, Gus Baldauf, and Peter Zaitcev
 */

/*
 * BPP Register Block
 */
struct bppregs {

	volatile u_int32_t	bpp_csr;
	volatile u_int32_t	bpp_addr;
	volatile u_int32_t	bpp_bcnt;
	volatile u_int32_t	bpp_tst_csr;

	volatile u_int16_t	bpp_hcr;
	volatile u_int16_t	bpp_ocr;
	volatile u_int8_t	bpp_dr;
	volatile u_int8_t	bpp_tcr;
	volatile u_int8_t	bpp_or;
	volatile u_int8_t	bpp_ir;
	volatile u_int16_t	bpp_icr;
};

#define BPP_DEV_ID_MASK		0xf0000000
#define BPP_DEV_ID_ZEBRA	0x40000000
#define BPP_DEV_ID_L64854	0xa0000000
#define BPP_NA_LOADED		0x08000000
#define BPP_A_LOADED		0x04000000
#define BPP_DMA_ON		0x02000000
#define BPP_EN_NEXT		0x01000000
#define BPP_TCI_DIS		0x00800000
#define BPP_DIAG		0x00100000

#define BPP_BURST_SIZE		0x000c0000
#define BPP_BURST_8		0x00000000
#define BPP_BURST_4		0x00040000
#define BPP_BURST_1		0x00080000
#define BPP_TC			0x00004000

#define BPP_EN_CNT		0x00002000
#define BPP_EN_DMA		0x00000200
#define BPP_WRITE		0x00000100
#define BPP_RESET		0x00000080
#define BPP_SLAVE_ERR		0x00000040
#define BPP_INVALIDATE		0x00000020
#define BPP_INT_EN		0x00000010
#define BPP_DRAINING		0x0000000c

#define BPP_ERR_PEND		0x00000002
#define BPP_INT_PEND		0x00000001

#define BPP_HCR_TEST		0x8000
#define BPP_HCR_DSW		0x7f00
#define BPP_HCR_DDS		0x007f

#define BPP_OCR_MEM_CLR		0x8000
#define BPP_OCR_DATA_SRC	0x4000
#define BPP_OCR_DS_DSEL		0x2000
#define BPP_OCR_BUSY_DSEL	0x1000
#define BPP_OCR_ACK_DSEL	0x0800
#define BPP_OCR_EN_DIAG		0x0400
#define BPP_OCR_BUSY_OP		0x0200
#define BPP_OCR_ACK_OP		0x0100
#define BPP_OCR_SRST		0x0080
#define BPP_OCR_IDLE		0x0008
#define BPP_OCR_V_ILCK		0x0002
#define BPP_OCR_EN_VER		0x0001

#define BPP_TCR_DIR		0x08
#define BPP_TCR_BUSY		0x04
#define BPP_TCR_ACK		0x02
#define BPP_TCR_DS		0x01

#define BPP_OR_V3		0x20
#define BPP_OR_V2		0x10
#define BPP_OR_V1		0x08
#define BPP_OR_INIT		0x04
#define BPP_OR_AFXN		0x02
#define BPP_OR_SLCT_IN		0x01

#define BPP_IR_PE		0x04
#define BPP_IR_SLCT		0x02
#define BPP_IR_ERR		0x01

#define BPP_DS_IRQ		0x8000
#define BPP_ACK_IRQ		0x4000
#define BPP_BUSY_IRQ		0x2000
#define BPP_PE_IRQ		0x1000
#define BPP_SLCT_IRQ		0x0800
#define BPP_ERR_IRQ		0x0400
#define BPP_DS_IRQ_EN		0x0200
#define BPP_ACK_IRQ_EN		0x0100
#define BPP_BUSY_IRP		0x0080
#define BPP_BUSY_IRQ_EN		0x0040
#define BPP_PE_IRP		0x0020
#define BPP_PE_IRQ_EN		0x0010
#define BPP_SLCT_IRP		0x0008
#define BPP_SLCT_IRQ_EN		0x0004
#define BPP_ERR_IRP		0x0002
#define BPP_ERR_IRQ_EN		0x0001


code:
/*	$OpenBSD: bt445.c,v 1.2 2008/12/26 15:33:40 miod Exp $	*/
/*
 * Copyright (c) 2003, Miodrag Vallat.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * A skeleton driver for the Brooktree BT445 ``Chameleon'' RAMDAC found
 * on the early Tadpole SPARCbook 3 machines.
 *
 * It will not perform anything by itself, but frame buffer drivers can use
 * its softc structure to be able to access the RAMDAC themselves - creating
 * a ramdac API for just this specific case of separate attachments is not
 * worth doing.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/conf.h>

#include <machine/autoconf.h>

#include <sparc/dev/bt445reg.h>
#include <sparc/dev/bt445var.h>

void	btcham_attach(struct device *, struct device *, void *);
int	btcham_match(struct device *, void *, void *);

struct	cfattach btcham_ca = {
	sizeof(struct bt445_softc), btcham_match, btcham_attach
};

struct	cfdriver btcham_cd = {
	NULL, "btcham", DV_DULL
};

/*
 * Match a chameleon
 */
int
btcham_match(struct device *parent, void *vcf, void *aux)
{
	struct confargs *ca = aux;
	struct romaux *ra = &ca->ca_ra;

	if (strcmp("bt445", ra->ra_name) != 0)
		return (0);

	return (1);
}

/*
 * Attach a chameleon
 */
void
btcham_attach(struct device *parent, struct device *self, void *args)
{
	struct confargs *ca = args;
	struct bt445_softc *sc = (struct bt445_softc *)self;
	int id, rev;

	/*
	 * Map the registers
	 */
	sc->sc_regs = mapiodev(ca->ca_ra.ra_reg, 0, ca->ca_ra.ra_len);

	/*
	 * Report a few values to please the user.
	 */
	sc->sc_regs[BT445_ADDRESS] = BT445_REGISTER_OFFSET(BT445_ID);
	id = sc->sc_regs[BT445_REGISTER_INDEX(BT445_ID)];

	sc->sc_regs[BT445_ADDRESS] = BT445_REGISTER_OFFSET(BT445_REVISION);
	rev = sc->sc_regs[BT445_REGISTER_INDEX(BT445_REVISION)];

	printf(": id 0x%x, revision 0x%x\n", id, rev);
}


code:
/*	$OpenBSD: bt445reg.h,v 1.1 2003/06/17 21:21:31 miod Exp $	*/
/*
 * Copyright (c) 2003, Miodrag Vallat.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Actual BT445 register layout
 */

/* Read/write address */
#define	BT445_ADDRESS				0

/*
 * Access to a register is done by programming the address register with
 * the low 8 bits, and then reading or writing at the register pointed out
 * by the high 8 bits.
 */
#define	BT445_REGISTER_OFFSET(x)		((x) & 0xff)
#define	BT445_REGISTER_INDEX(x)			(((x) >> 8) & 0xff)

/* Palette data - 3 r/w cycles par address, and autoincrement */
#define	BT445_PALDATA				1

/* Overlay palette data - 3 r/w cycles par address, and autoincrement */
#define	BT445_OVPALDATA				3

/*
 * Various registers (very incomplete...)
 */
#define	BT445_ID				0x0200
#define	BT445_REVISION				0x0201


code:
/*	$OpenBSD: bt445var.h,v 1.1 2003/06/17 21:21:31 miod Exp $	*/
/*
 * Copyright (c) 2003, Miodrag Vallat.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

struct	bt445_softc {
	struct device sc_dev;

	volatile u_int8_t *sc_regs;	/* RAMDAC registers */
};


code:
/*	$OpenBSD: bt_subr.c,v 1.9 2003/06/02 23:27:53 millert Exp $	*/
/*	$NetBSD: bt_subr.c,v 1.5 1996/03/14 19:44:32 christos Exp $ */

/*
 * Copyright (c) 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Lawrence Berkeley Laboratory.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)bt_subr.c	8.2 (Berkeley) 1/21/94
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/errno.h>

#include <uvm/uvm_extern.h>

#include <dev/wscons/wsconsio.h>

#include <sparc/dev/btreg.h>
#include <sparc/dev/btvar.h>

/*
 * Common code for dealing with Brooktree video DACs.
 */

int
bt_getcmap(bcm, rcm)
	union bt_cmap *bcm;
	struct wsdisplay_cmap *rcm;
{
	u_int index = rcm->index, count = rcm->count, i;
	int error;

	if (index >= 256 || count > 256 - index)
		return (EINVAL);
	for (i = 0; i < count; i++) {
		if ((error = copyout(&bcm->cm_map[index + i][0],
		    &rcm->red[i], 1)) != 0)
			return (error);
		if ((error = copyout(&bcm->cm_map[index + i][1],
		    &rcm->green[i], 1)) != 0)
			return (error);
		if ((error = copyout(&bcm->cm_map[index + i][2],
		    &rcm->blue[i], 1)) != 0)
			return (error);
	}
	return (0);
}

int
bt_putcmap(bcm, rcm)
	union bt_cmap *bcm;
	struct wsdisplay_cmap *rcm;
{
	u_int index = rcm->index, count = rcm->count, i;
	int error;

	if (index >= 256 || count > 256 - index)
		return (EINVAL);
	for (i = 0; i < count; i++) {
		if ((error = copyin(&rcm->red[i],
		    &bcm->cm_map[index + i][0], 1)) != 0)
			return (error);
		if ((error = copyin(&rcm->green[i],
		    &bcm->cm_map[index + i][1], 1)) != 0)
			return (error);
		if ((error = copyin(&rcm->blue[i],
		    &bcm->cm_map[index + i][2], 1)) != 0)
			return (error);
	}
	return (0);
}

void
bt_loadcmap(cm, bt, start, ncolors, cgsix)
	union bt_cmap *cm;
	volatile struct bt_regs *bt;
	u_int start, ncolors;
	int cgsix;
{
	u_int *ip, i;
	int count;

	ip = &cm->cm_chip[BT_D4M3(start)];	/* start/4 * 3 */
	count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3;

	if (cgsix) {
		/* hardware that makes one want to pound boards with hammers */
		bt->bt_addr = BT_D4M4(start) << 24;
		while (--count >= 0) {
			i = *ip++;
			bt->bt_cmap = i;
			bt->bt_cmap = i << 8;
			bt->bt_cmap = i << 16;
			bt->bt_cmap = i << 24;
		}
	} else {
		bt->bt_addr = BT_D4M4(start);
		while (--count >= 0)
			bt->bt_cmap = *ip++;
	}
}

void
bt_setcolor(cm, bt, index, r, g, b, cgsix)
	union bt_cmap *cm;
	volatile struct bt_regs *bt;
	u_int index;
	u_int8_t r, g, b;
	int cgsix;
{

	cm->cm_map[index][0] = r;
	cm->cm_map[index][1] = g;
	cm->cm_map[index][2] = b;
	bt_loadcmap(cm, bt, index, 1, cgsix);
}


code:
/*	$OpenBSD: btreg.h,v 1.6 2008/12/26 15:34:33 miod Exp $	*/
/*	$NetBSD: btreg.h,v 1.4 1996/02/27 22:09:21 thorpej Exp $ */

/*
 * Copyright (c) 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Lawrence Berkeley Laboratory.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)btreg.h	8.2 (Berkeley) 1/21/94
 */

/*
 * Several Sun color frame buffers use some kind of Brooktree video
 * DAC (e.g., the Bt458, -- in any case, Brooktree make the only
 * decent color frame buffer chips).
 *
 * Color map control on these is a bit funky in a SPARCstation.
 * To update the color map one would normally do byte writes, but
 * the hardware takes longword writes.  Since there are three
 * registers for each color map entry (R, then G, then B), we have
 * to set color 1 with a write to address 0 (setting 0's R/G/B and
 * color 1's R) followed by a second write to address 1 (setting
 * color 1's G/B and color 2's R/G).  Software must therefore keep
 * a copy of the current map.
 *
 * The colormap address register increments automatically, so the
 * above write is done as:
 *
 *	bt->bt_addr = 0;
 *	bt->bt_cmap = R0G0B0R1;
 *	bt->bt_cmap = G1B1R2G2;
 *	...
 *
 * Yow!
 *
 * Bonus complication: on the cg6, only the top 8 bits of each 32 bit
 * register matter, even though the cg3 takes all the bits from all
 * bytes written to it.
 */
struct bt_regs {
	u_int	bt_addr;		/* map address register */
	u_int	bt_cmap;		/* colormap data register */
	u_int	bt_ctrl;		/* control register */
	u_int	bt_omap;		/* overlay (cursor) map register */
};
#define BT_INIT(bt, shift) do { /* whatever this means.. */ \
	(bt)->bt_addr = 0x06 << (shift);	/* command reg */ \
	(bt)->bt_ctrl = 0x73 << (shift);	/* overlay plane */ \
	(bt)->bt_addr = 0x04 << (shift);	/* read mask */ \
	(bt)->bt_ctrl = 0xff << (shift);	/* color planes */ \
} while(0)

/*
 * SBus framebuffer control look like this (usually at offset 0x400000).
 */
struct fbcontrol {
	struct	bt_regs fbc_dac;
	u_char	fbc_ctrl;
	u_char	fbc_status;
	u_char	fbc_cursor_start;
	u_char	fbc_cursor_end;
	u_char	fbc_vcontrol[12];	/* 12 bytes of video timing goo */
};
/* fbc_ctrl bits: */
#define FBC_IENAB	0x80		/* Interrupt enable */
#define FBC_VENAB	0x40		/* Video enable */
#define FBC_TIMING	0x20		/* Master timing enable */
#define FBC_CURSOR	0x10		/* Cursor compare enable */
#define FBC_XTALMSK	0x0c		/* Xtal select (0,1,2,test) */
#define FBC_DIVMSK	0x03		/* Divisor (1,2,3,4) */

/* fbc_status bits: */
#define FBS_INTR	0x80		/* Interrupt pending */
#define FBS_MSENSE	0x70		/* Monitor sense mask */
#define		FBS_1024X768	0x10
#define		FBS_1152X900	0x30
#define		FBS_1280X1024	0x40
#define		FBS_1600X1280	0x50
#define FBS_ID_MASK	0x0f		/* ID mask */
#define		FBS_ID_COLOR	0x01
#define		FBS_ID_MONO	0x02
#define		FBS_ID_MONO_ECL	0x03	/* ? */


code:
/*	$OpenBSD: btvar.h,v 1.5 2003/06/02 23:27:53 millert Exp $	*/
/*	$NetBSD: btvar.h,v 1.2 1994/11/20 20:51:56 deraadt Exp $ */

/*
 * Copyright (c) 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Lawrence Berkeley Laboratory.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)btvar.h	8.2 (Berkeley) 1/21/94
 */

/*
 * Brooktree color frame buffer state variables (see btreg.h).
 *
 * Unfortunately, remarkably little code can be shared between the
 * cg3 and cg6 drivers here, as the cg3 registers do longword-ops
 * `as expected', but the cg6 ones use only the upper byte.
 *
 * Still, the software color map manipulation is not completely trivial.
 */
union bt_cmap {
	u_char  cm_map[256][3];		/* 256 R/G/B entries */
	u_int   cm_chip[256 * 3 / 4];	/* the way the chip gets loaded */
};

/*
 * Routines in bt_subr.c.
 */
int	bt_getcmap(union bt_cmap *, struct wsdisplay_cmap *);
int	bt_putcmap(union bt_cmap *, struct wsdisplay_cmap *);
void	bt_loadcmap(union bt_cmap *, volatile struct bt_regs *,
    u_int, u_int, int);
void	bt_setcolor(union bt_cmap *, volatile struct bt_regs *,
    u_int, u_int8_t, u_int8_t, u_int8_t, int);

/*
 * Compute (x / 4) * 3 and (x / 4) * 4.  These are used in turning
 * RGB indices (which are in multiples of three) into `chip RGB' values
 * (which are in multiples of four).
 */
#define	BT_D4M3(x) ((((x) >> 2) << 1) + ((x) >> 2))	/* (x / 4) * 3 */
#define	BT_D4M4(x) ((x) & ~3)				/* (x / 4) * 4 */


code:
/*	$OpenBSD: bwtwo.c,v 1.40 2015/03/28 19:07:07 miod Exp $	*/
/*	$NetBSD: bwtwo.c,v 1.33 1997/05/24 20:16:02 pk Exp $ */

/*
 * Copyright (c) 2002 Miodrag Vallat.  All rights reserved.
 * Copyright (c) 1996 Jason R. Thorpe.  All rights reserved.
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Lawrence Berkeley Laboratory.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)bwtwo.c	8.1 (Berkeley) 6/11/93
 */

/*
 * black&white display (bwtwo) driver.
 *
 * P4 and overlay plane support by Jason R. Thorpe <thorpej@NetBSD.ORG>.
 * Overlay plane handling hints and ideas provided by Brad Spencer.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/mman.h>
#include <sys/tty.h>
#include <sys/conf.h>

#include <uvm/uvm_extern.h>

#include <machine/autoconf.h>
#include <machine/eeprom.h>
#include <machine/ctlreg.h>
#include <machine/conf.h>
#include <sparc/sparc/asm.h>

#include <sparc/dev/btreg.h>
#include <sparc/dev/bwtworeg.h>
#if defined(SUN4)
#include <sparc/dev/pfourreg.h>
#endif

#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsdisplayvar.h>
#include <dev/rasops/rasops.h>
#include <machine/fbvar.h>

#include <machine/pmap.h>

/* per-display variables */
struct bwtwo_softc {
	struct	sunfb sc_sunfb;		/* common base part */
	volatile struct fbcontrol *sc_reg;/* control registers */
	struct rom_reg	sc_phys;	/* phys address description */
	int	sc_bustype;		/* type of bus we live on */
	int	sc_pixeloffset;		/* offset to framebuffer */
};

void	bwtwo_burner(void *, u_int, u_int);
int	bwtwo_intr(void *);
int	bwtwo_ioctl(void *, u_long, caddr_t, int, struct proc *);
paddr_t	bwtwo_mmap(void *, off_t, int);

struct wsdisplay_accessops bwtwo_accessops = {
	.ioctl = bwtwo_ioctl,
	.mmap = bwtwo_mmap,
	.burn_screen = bwtwo_burner
};

/* autoconfiguration driver */
void	bwtwoattach(struct device *, struct device *, void *);
int	bwtwomatch(struct device *, void *, void *);

struct cfattach bwtwo_ca = {
	sizeof(struct bwtwo_softc), bwtwomatch, bwtwoattach
};

struct cfdriver bwtwo_cd = {
	NULL, "bwtwo", DV_DULL
};

int
bwtwomatch(struct device *parent, void *vcf, void *aux)
{
	struct cfdata *cf = vcf;
	struct confargs *ca = aux;
	struct romaux *ra = &ca->ca_ra;

	if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
		return (0);

#if 0
	if (CPU_ISSUN4 && cf->cf_unit != 0)
		return (0);
#endif

	if (ca->ca_bustype == BUS_SBUS)
		return (1);

	/*
	 * Make sure there's hardware there.
	 */
	if (probeget(ra->ra_vaddr, 4) == -1)
		return (0);

	switch (ca->ca_bustype) {
	case BUS_VME16:
	case BUS_VME32:
		return (1);
	case BUS_OBIO:
#if defined(SUN4)
		if (CPU_ISSUN4) {
			/*
			 * Check for a pfour framebuffer, but do not match the
			 * overlay planes for color pfour framebuffers.
			 */
			switch (fb_pfour_id(ra->ra_vaddr)) {
			case PFOUR_ID_BW:
			case PFOUR_NOTPFOUR:
				return (1);
			case PFOUR_ID_COLOR8P1:		/* bwtwo in ... */
			case PFOUR_ID_COLOR24:		/* ...overlay plane */
			default:
				return (0);
			}
		}
#endif
		return (1);
	default:
		return (0);
	}
}

void
bwtwoattach(struct device *parent, struct device *self, void *args)
{
	struct bwtwo_softc *sc = (struct bwtwo_softc *)self;
	struct confargs *ca = args;
	int node = ca->ca_ra.ra_node;
	int isconsole = 0;
	int sbus = 1;
	char *nam;

	printf(": ");

	/*
	 * Check if this is a P4 attachment, and map the P4 control
	 * register if necessary.
	 */
#if defined(SUN4)
	if (CPU_ISSUN4 && ca->ca_bustype == BUS_OBIO) {
		sc->sc_sunfb.sf_pfour = (volatile u_int32_t *)
		    mapiodev(ca->ca_ra.ra_reg, 0, sizeof(u_int32_t));
		if (fb_pfour_id(sc->sc_sunfb.sf_pfour) != PFOUR_NOTPFOUR)
			SET(sc->sc_sunfb.sf_flags, FB_PFOUR);
		else {
			/* XXX unmapiodev */
			sc->sc_sunfb.sf_pfour = NULL;
		}
	}
#endif

	/*
	 * Map the control register (unless done above for a P4 device).
	 */
#if defined(SUN4)
	if (!CPU_ISSUN4 || !ISSET(sc->sc_sunfb.sf_flags, FB_PFOUR))
#endif
	{
		sc->sc_reg = (volatile struct fbcontrol *)
		    mapiodev(ca->ca_ra.ra_reg, BWREG_REG,
			     sizeof(struct fbcontrol));
	}

	/* Set up default pixel offset.  May be changed below. */
	sc->sc_pixeloffset = BWREG_MEM;

	switch (ca->ca_bustype) {
	case BUS_OBIO:
		if (CPU_ISSUN4M)	/* 4m has framebuffer on obio */
			goto obp_name;

		sbus = node = 0;
#if defined(SUN4)
		if (ISSET(sc->sc_sunfb.sf_flags, FB_PFOUR)) {
			nam = "p4";
			sc->sc_pixeloffset = PFOUR_BW_OFF;
		} else
#endif
			nam = NULL;
		break;

	case BUS_VME32:
	case BUS_VME16:
		sbus = node = 0;
		nam = NULL;
		break;

	case BUS_SBUS:
obp_name:
#if defined(SUN4C) || defined(SUN4D) || defined(SUN4E) || defined(SUN4M)
		nam = getpropstring(node, "model");
#endif
		break;
	}

	if (nam != NULL && *nam != '\0')
		printf("%s, ", nam);

#if defined(SUN4)
	if (CPU_ISSUN4) {
		struct eeprom *eep = (struct eeprom *)eeprom_va;
		int constype = ISSET(sc->sc_sunfb.sf_flags, FB_PFOUR) ?
		    EED_CONS_P4 : EED_CONS_BW;
		/*
		 * Assume this is the console if there's no eeprom info
		 * to be found.
		 */
		if (eep == NULL || eep->ee_diag.eed_console == constype)
			isconsole = 1;
		else
		/*
		 * On sun4 systems without on-board framebuffers (such as
		 * the 4/3xx models), the PROM will accept the EED_CONS_BW
		 * setting although the framebuffer is a P4.
		 * Accept this setting as well.
		 */
		if (eep->ee_diag.eed_console == EED_CONS_BW)
			isconsole = 1;
	}
#endif

	if (!CPU_ISSUN4)
		isconsole = node == fbnode;

	sc->sc_phys = ca->ca_ra.ra_reg[0];
	sc->sc_bustype = ca->ca_bustype;

	/* enable video */
	bwtwo_burner(sc, 1, 0);

	fb_setsize(&sc->sc_sunfb, 1, 1152, 900, node, ca->ca_bustype);
	printf("%dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);

	sc->sc_sunfb.sf_ro.ri_bits = mapiodev(ca->ca_ra.ra_reg,
	    sc->sc_pixeloffset, round_page(sc->sc_sunfb.sf_fbsize));
	sc->sc_sunfb.sf_ro.ri_hw = sc;
	fbwscons_init(&sc->sc_sunfb, isconsole);

	if (isconsole)
		fbwscons_console_init(&sc->sc_sunfb, -1);

	fbwscons_attach(&sc->sc_sunfb, &bwtwo_accessops, isconsole);
}

int
bwtwo_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
{
	struct bwtwo_softc *sc = v;
	struct wsdisplay_fbinfo *wdf;

	switch (cmd) {
	case WSDISPLAYIO_GTYPE:
		*(u_int *)data = WSDISPLAY_TYPE_SUNBW;
		break;
	case WSDISPLAYIO_GINFO:
		wdf = (struct wsdisplay_fbinfo *)data;
		wdf->height = sc->sc_sunfb.sf_height;
		wdf->width = sc->sc_sunfb.sf_width;
		wdf->depth = sc->sc_sunfb.sf_depth;
		wdf->cmsize = 0;	/* no colormap */
		break;
	case WSDISPLAYIO_LINEBYTES:
		*(u_int *)data = sc->sc_sunfb.sf_linebytes;
		break;

	case WSDISPLAYIO_GETCMAP:
	case WSDISPLAYIO_PUTCMAP:
		break;

	case WSDISPLAYIO_SVIDEO:
	case WSDISPLAYIO_GVIDEO:
		break;

	case WSDISPLAYIO_GCURPOS:
	case WSDISPLAYIO_SCURPOS:
	case WSDISPLAYIO_GCURMAX:
	case WSDISPLAYIO_GCURSOR:
	case WSDISPLAYIO_SCURSOR:
	default:
		return (-1);	/* not supported yet */
	}

	return (0);
}

paddr_t
bwtwo_mmap(void *v, off_t offset, int prot)
{
	struct bwtwo_softc *sc = v;

	if (offset & PGOFSET)
		return (-1);

	if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) {
		return (REG2PHYS(&sc->sc_phys, sc->sc_pixeloffset + offset) |
		    PMAP_NC);
	}

	return (-1);
}

void
bwtwo_burner(void *v, u_int on, u_int flags)
{
	struct bwtwo_softc *sc = v;
	int s;

#if defined(SUN4)
	if (CPU_ISSUN4 && (sc->sc_bustype == BUS_OBIO)) {
		if (ISSET(sc->sc_sunfb.sf_flags, FB_PFOUR)) {
			fb_pfour_burner(v, on, flags);
			return;
		}
		if (on)
			stba(AC_SYSENABLE, ASI_CONTROL,
			    lduba(AC_SYSENABLE, ASI_CONTROL) | SYSEN_VIDEO);
		else
			stba(AC_SYSENABLE, ASI_CONTROL,
			    lduba(AC_SYSENABLE, ASI_CONTROL) & ~SYSEN_VIDEO);

		return;
	}
#endif

	s = splhigh();
	if (on)
		sc->sc_reg->fbc_ctrl |= FBC_VENAB | FBC_TIMING;
	else {
		sc->sc_reg->fbc_ctrl &= ~FBC_VENAB;
		if (flags & WSDISPLAY_BURN_VBLANK)
			sc->sc_reg->fbc_ctrl &= ~FBC_TIMING;
	}
	splx(s);
}


code:
/*	$OpenBSD: bwtworeg.h,v 1.4 2003/06/02 23:27:53 millert Exp $	*/
/*	$NetBSD: bwtworeg.h,v 1.3 1996/02/27 00:32:39 pk Exp $ */

/*
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Lawrence Berkeley Laboratory.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)bwtworeg.h	8.1 (Berkeley) 6/11/93
 */

/*
 * bwtwo display registers.
 *
 * The registers start at offset 0x400000 and repeat every 32 bytes
 * (presumably only the low order address lines are decoded).  Video RAM
 * starts at offset 0x800000.  We use separate pointers to each so that
 * the sparc addressing modes work well.
 */
struct bwtworeg {
	struct fbcontrol bw_fbc;
};

/* offsets */
#define	BWREG_ID	0
#define	BWREG_REG	0x400000
#define	BWREG_MEM	0x800000

/* same, but for gdb */
struct bwtwo_all {
	long	ba_id;			/* ID = 0xfe010104 on my IPC */
	char	ba_xxx0[0x400000-4];
	struct	fbcontrol ba_reg;	/* control registers */
	char	ba_xxx1[0x400000-32];
	char	ba_ram[4096];		/* actually larger */
};


code:
/*	$OpenBSD: cgeight.c,v 1.31 2013/10/20 20:07:25 miod Exp $	*/
/*	$NetBSD: cgeight.c,v 1.13 1997/05/24 20:16:04 pk Exp $	*/

/*
 * Copyright (c) 2002 Miodrag Vallat.  All rights reserved.
 * Copyright (c) 1996 Jason R. Thorpe.  All rights reserved.
 * Copyright (c) 1995 Theo de Raadt
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Lawrence Berkeley Laboratory.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	from @(#)cgthree.c	8.2 (Berkeley) 10/30/93
 */

/*
 * color display (cgeight) driver.
 *
 * For performance reasons, we run the emulation mode in the (monochrome)
 * overlay plane, but X11 in the 24-bit color plane.
 *
 * Does not handle interrupts, even though they can occur.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/device.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/mman.h>
#include <sys/tty.h>
#include <sys/conf.h>

#include <uvm/uvm_extern.h>

#include <machine/autoconf.h>
#include <machine/pmap.h>
#include <machine/eeprom.h>
#include <machine/conf.h>

#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsdisplayvar.h>
#include <dev/rasops/rasops.h>
#include <machine/fbvar.h>

#include <sparc/dev/btreg.h>
#include <sparc/dev/btvar.h>
#include <sparc/dev/pfourreg.h>

/* per-display variables */
struct cgeight_softc {
	struct	sunfb sc_sunfb;			/* common base device */
	struct	rom_reg	sc_phys;
	volatile struct fbcontrol *sc_fbc;	/* Brooktree registers */
	volatile u_char *sc_enable;		/* enable plane */
};

int	cgeight_ioctl(void *, u_long, caddr_t, int, struct proc *);
paddr_t	cgeight_mmap(void *, off_t, int);
void	cgeight_reset(struct cgeight_softc *, int);

struct wsdisplay_accessops cgeight_accessops = {
	.ioctl = cgeight_ioctl,
	.mmap = cgeight_mmap,
	.burn_screen = fb_pfour_burner
};

void	cgeightattach(struct device *, struct device *, void *);
int	cgeightmatch(struct device *, void *, void *);

struct cfattach cgeight_ca = {
	sizeof(struct cgeight_softc), cgeightmatch, cgeightattach
};

struct cfdriver cgeight_cd = {
	NULL, "cgeight", DV_DULL
};

int
cgeightmatch(struct device *parent, void *vcf, void *aux)
{
	struct cfdata *cf = vcf;
	struct confargs *ca = aux;
	struct romaux *ra = &ca->ca_ra;

	if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
		return (0);

	if (!CPU_ISSUN4 || ca->ca_bustype != BUS_OBIO)
		return (0);

	/*
	 * Make sure there's hardware there.
	 */
	if (probeget(ra->ra_vaddr, 4) == -1)
		return (0);

	/*
	 * Check the pfour register.
	 */
	if (fb_pfour_id(ra->ra_vaddr) == PFOUR_ID_COLOR24)
		return (1);

	return (0);
}

void
cgeightattach(struct device *parent, struct device *self, void *args)
{
	struct cgeight_softc *sc = (struct cgeight_softc *)self;
	struct confargs *ca = args;
	int node = 0;
	volatile struct bt_regs *bt;
	int isconsole = 0;

	/* Map the pfour register. */
	SET(sc->sc_sunfb.sf_flags, FB_PFOUR);
	sc->sc_sunfb.sf_pfour = (volatile u_int32_t *)
	    mapiodev(ca->ca_ra.ra_reg, 0, sizeof(u_int32_t));

	if (cputyp == CPU_SUN4) {
		struct eeprom *eep = (struct eeprom *)eeprom_va;

		/*
		 * Assume this is the console if there's no eeprom info
		 * to be found.
		 */
		if (eep == NULL || eep->ee_diag.eed_console == EED_CONS_P4)
			isconsole = 1;
	}

	/* Map the Brooktree. */
	sc->sc_fbc = (volatile struct fbcontrol *)
	    mapiodev(ca->ca_ra.ra_reg,
		     PFOUR_COLOR_OFF_CMAP, sizeof(struct fbcontrol));

	sc->sc_phys = ca->ca_ra.ra_reg[0];

	/* enable video */
	fb_pfour_burner(sc, 1, 0);
	bt = &sc->sc_fbc->fbc_dac;
	BT_INIT(bt, 0);

	fb_setsize(&sc->sc_sunfb, 1, 1152, 900, node, ca->ca_bustype);
	sc->sc_sunfb.sf_ro.ri_hw = sc;

	/*
	 * Map the overlay and overlay enable planes.
	 */
	sc->sc_enable = (volatile u_char *)mapiodev(ca->ca_ra.ra_reg,
	    PFOUR_COLOR_OFF_ENABLE, round_page(sc->sc_sunfb.sf_fbsize));
	sc->sc_sunfb.sf_ro.ri_bits =  mapiodev(ca->ca_ra.ra_reg,
	    PFOUR_COLOR_OFF_OVERLAY, round_page(sc->sc_sunfb.sf_fbsize));

	cgeight_reset(sc, WSDISPLAYIO_MODE_EMUL);
	printf(": p4, %dx%d", sc->sc_sunfb.sf_width,
	    sc->sc_sunfb.sf_height);

	fbwscons_init(&sc->sc_sunfb, isconsole);
	if (isconsole)
		fbwscons_console_init(&sc->sc_sunfb, -1);

	fbwscons_attach(&sc->sc_sunfb, &cgeight_accessops, isconsole);
}

void
cgeight_reset(struct cgeight_softc *sc, int mode)
{
	volatile struct bt_regs *bt;
	union bt_cmap cm;
	u_int c;

	bt = &sc->sc_fbc->fbc_dac;

	/*
	 * Depending on the mode requested, disable or enable
	 * the overlay plane.
	 */
	if (mode == WSDISPLAYIO_MODE_EMUL) {
		memset((void *)sc->sc_enable, 0xff,
		    round_page(sc->sc_sunfb.sf_fbsize));

		/* Setup a strict mono colormap */
		cm.cm_map[0][0] = cm.cm_map[0][1] = cm.cm_map[0][2] = 0x00;
		for (c = 1; c < 256; c++) {
			cm.cm_map[c][0] = cm.cm_map[c][1] = cm.cm_map[c][2] =
			    0xff;
		}
	} else {
		memset((void *)sc->sc_enable, 0x00,
		    round_page(sc->sc_sunfb.sf_fbsize));

		/* Setup a ramp colormap (direct color) */
		for (c = 0; c < 256; c++) {
			cm.cm_map[c][0] = cm.cm_map[c][1] = cm.cm_map[c][2] = c;
		}
	}

	/* Upload the colormap into the DAC */
	bt_loadcmap(&cm, bt, 0, 256, 0);
}

int
cgeight_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
{
	struct cgeight_softc *sc = v;
	struct wsdisplay_fbinfo *wdf;

	switch (cmd) {
	case WSDISPLAYIO_GTYPE:
		*(u_int *)data = WSDISPLAY_TYPE_SUNCG8;
		break;
	case WSDISPLAYIO_GINFO:
		wdf = (struct wsdisplay_fbinfo *)data;
		wdf->height = sc->sc_sunfb.sf_height;
		wdf->width = sc->sc_sunfb.sf_width;
		wdf->depth = 24;
		wdf->cmsize = 0;
		break;
	case WSDISPLAYIO_SMODE:
		cgeight_reset(sc, *(int *)data);
		break;
	case WSDISPLAYIO_SVIDEO:
	case WSDISPLAYIO_GVIDEO:
		break;

	case WSDISPLAYIO_GETCMAP:	/* nothing to do */
	case WSDISPLAYIO_PUTCMAP:	/* nothing to do */
	case WSDISPLAYIO_GCURPOS:	/* not supported */
	case WSDISPLAYIO_SCURPOS:	/* not supported */
	case WSDISPLAYIO_GCURMAX:	/* not supported */
	case WSDISPLAYIO_GCURSOR:	/* not supported */
	case WSDISPLAYIO_SCURSOR:	/* not supported */
	default:
		return (-1);
	}

	return (0);
}

paddr_t
cgeight_mmap(void *v, off_t offset, int prot)
{
	struct cgeight_softc *sc = v;

	if (offset & PGOFSET)
		return (-1);

	/* Allow mapping of the 24-bit color planes */
	if (offset >= 0 && offset < round_page(24 * sc->sc_sunfb.sf_fbsize)) {
		return (REG2PHYS(&sc->sc_phys,
		    offset + PFOUR_COLOR_OFF_COLOR) | PMAP_NC);
	}

	return (-1);
}