if_fmv_isa.c revision 1.1
11.1Stsutsui/*	$NetBSD: if_fmv_isa.c,v 1.1 2002/10/05 15:16:12 tsutsui Exp $	*/
21.1Stsutsui
31.1Stsutsui/*
41.1Stsutsui * All Rights Reserved, Copyright (C) Fujitsu Limited 1995
51.1Stsutsui *
61.1Stsutsui * This software may be used, modified, copied, distributed, and sold, in
71.1Stsutsui * both source and binary form provided that the above copyright, these
81.1Stsutsui * terms and the following disclaimer are retained.  The name of the author
91.1Stsutsui * and/or the contributor may not be used to endorse or promote products
101.1Stsutsui * derived from this software without specific prior written permission.
111.1Stsutsui *
121.1Stsutsui * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND THE CONTRIBUTOR ``AS IS'' AND
131.1Stsutsui * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
141.1Stsutsui * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
151.1Stsutsui * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTOR BE LIABLE
161.1Stsutsui * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
171.1Stsutsui * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
181.1Stsutsui * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION.
191.1Stsutsui * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
201.1Stsutsui * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
211.1Stsutsui * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
221.1Stsutsui * SUCH DAMAGE.
231.1Stsutsui */
241.1Stsutsui
251.1Stsutsui/*
261.1Stsutsui * Portions copyright (C) 1993, David Greenman.  This software may be used,
271.1Stsutsui * modified, copied, distributed, and sold, in both source and binary form
281.1Stsutsui * provided that the above copyright and these terms are retained.  Under no
291.1Stsutsui * circumstances is the author responsible for the proper functioning of this
301.1Stsutsui * software, nor does the author assume any responsibility for damages
311.1Stsutsui * incurred with its use.
321.1Stsutsui */
331.1Stsutsui
341.1Stsutsui#include <sys/cdefs.h>
351.1Stsutsui__KERNEL_RCSID(0, "$NetBSD: if_fmv_isa.c,v 1.1 2002/10/05 15:16:12 tsutsui Exp $");
361.1Stsutsui
371.1Stsutsui#include <sys/param.h>
381.1Stsutsui#include <sys/systm.h>
391.1Stsutsui#include <sys/device.h>
401.1Stsutsui
411.1Stsutsui#include <net/if.h>
421.1Stsutsui#include <net/if_ether.h>
431.1Stsutsui#include <net/if_media.h>
441.1Stsutsui
451.1Stsutsui#include <machine/bus.h>
461.1Stsutsui#include <machine/intr.h>
471.1Stsutsui
481.1Stsutsui#include <dev/ic/mb86960reg.h>
491.1Stsutsui#include <dev/ic/mb86960var.h>
501.1Stsutsui#include <dev/ic/fmvreg.h>
511.1Stsutsui#include <dev/ic/fmvvar.h>
521.1Stsutsui
531.1Stsutsui#include <dev/isa/isavar.h>
541.1Stsutsui
551.1Stsutsuiint	fmv_isa_match __P((struct device *, struct cfdata *, void *));
561.1Stsutsuivoid	fmv_isa_attach __P((struct device *, struct device *, void *));
571.1Stsutsui
581.1Stsutsuistruct fmv_isa_softc {
591.1Stsutsui	struct	mb86960_softc sc_mb86960;	/* real "mb86960" softc */
601.1Stsutsui
611.1Stsutsui	/* ISA-specific goo. */
621.1Stsutsui	void	*sc_ih;				/* interrupt cookie */
631.1Stsutsui};
641.1Stsutsui
651.1StsutsuiCFATTACH_DECL(fmv_isa, sizeof(struct fmv_isa_softc),
661.1Stsutsui    fmv_isa_match, fmv_isa_attach, NULL, NULL);
671.1Stsutsui
681.1Stsutsuistruct fe_simple_probe_struct {
691.1Stsutsui	u_int8_t port;	/* Offset from the base I/O address. */
701.1Stsutsui	u_int8_t mask;	/* Bits to be checked. */
711.1Stsutsui	u_int8_t bits;	/* Values to be compared against. */
721.1Stsutsui};
731.1Stsutsui
741.1Stsutsuistatic __inline__ int fe_simple_probe __P((bus_space_tag_t,
751.1Stsutsui    bus_space_handle_t, struct fe_simple_probe_struct const *));
761.1Stsutsuistatic int fmv_find __P((bus_space_tag_t, bus_space_handle_t, int *, int *));
771.1Stsutsui
781.1Stsutsuistatic int const fmv_iomap[8] = {
791.1Stsutsui	0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x300, 0x340
801.1Stsutsui};
811.1Stsutsui#define NFMV_IOMAP (sizeof (fmv_iomap) / sizeof (fmv_iomap[0]))
821.1Stsutsui#define FMV_NPORTS 0x20
831.1Stsutsui
841.1Stsutsui/*
851.1Stsutsui * Hardware probe routines.
861.1Stsutsui */
871.1Stsutsui
881.1Stsutsui/*
891.1Stsutsui * Determine if the device is present.
901.1Stsutsui */
911.1Stsutsuiint
921.1Stsutsuifmv_isa_match(parent, match, aux)
931.1Stsutsui	struct device *parent;
941.1Stsutsui	struct cfdata *match;
951.1Stsutsui	void *aux;
961.1Stsutsui{
971.1Stsutsui	struct isa_attach_args *ia = aux;
981.1Stsutsui	bus_space_tag_t iot = ia->ia_iot;
991.1Stsutsui	bus_space_handle_t ioh;
1001.1Stsutsui	int i, iobase, irq, rv = 0;
1011.1Stsutsui	u_int8_t myea[ETHER_ADDR_LEN];
1021.1Stsutsui
1031.1Stsutsui	if (ia->ia_nio < 1)
1041.1Stsutsui		return (0);
1051.1Stsutsui	if (ia->ia_nirq < 1)
1061.1Stsutsui		return (0);
1071.1Stsutsui
1081.1Stsutsui	if (ISA_DIRECT_CONFIG(ia))
1091.1Stsutsui		return (0);
1101.1Stsutsui
1111.1Stsutsui	/* Disallow wildcarded values. */
1121.1Stsutsui	if (ia->ia_io[0].ir_addr == ISACF_PORT_DEFAULT)
1131.1Stsutsui		return (0);
1141.1Stsutsui
1151.1Stsutsui	/*
1161.1Stsutsui	 * See if the sepcified address is valid for FMV-180 series.
1171.1Stsutsui	 */
1181.1Stsutsui	for (i = 0; i < NFMV_IOMAP; i++)
1191.1Stsutsui		if (fmv_iomap[i] == ia->ia_io[0].ir_addr)
1201.1Stsutsui			break;
1211.1Stsutsui	if (i == NFMV_IOMAP) {
1221.1Stsutsui#ifdef FMV_DEBUG
1231.1Stsutsui		printf("fmv_match: unknown iobase 0x%x\n",
1241.1Stsutsui		    ia->ia_io[0].ir_addr);
1251.1Stsutsui#endif
1261.1Stsutsui		return (0);
1271.1Stsutsui	}
1281.1Stsutsui
1291.1Stsutsui	/* Map i/o space. */
1301.1Stsutsui	if (bus_space_map(iot, ia->ia_io[0].ir_addr, FMV_NPORTS, 0, &ioh)) {
1311.1Stsutsui#ifdef FMV_DEBUG
1321.1Stsutsui		printf("fmv_match: couldn't map iospace 0x%x\n",
1331.1Stsutsui		    ia->ia_io[0].ir_addr);
1341.1Stsutsui#endif
1351.1Stsutsui		return (0);
1361.1Stsutsui	}
1371.1Stsutsui
1381.1Stsutsui	if (fmv_find(iot, ioh, &iobase, &irq) == 0) {
1391.1Stsutsui#ifdef FMV_DEBUG
1401.1Stsutsui		printf("fmv_match: fmv_find failed\n");
1411.1Stsutsui#endif
1421.1Stsutsui		goto out;
1431.1Stsutsui	}
1441.1Stsutsui
1451.1Stsutsui	if (iobase != ia->ia_io[0].ir_addr) {
1461.1Stsutsui#ifdef FMV_DEBUG
1471.1Stsutsui		printf("fmv_match: unexpected iobase in board: 0x%x\n",
1481.1Stsutsui		    iobase);
1491.1Stsutsui#endif
1501.1Stsutsui		goto out;
1511.1Stsutsui	}
1521.1Stsutsui
1531.1Stsutsui	if (fmv_detect(iot, ioh, myea) == 0) { /* XXX necessary? */
1541.1Stsutsui#ifdef FMV_DEBUG
1551.1Stsutsui		printf("fmv_match: fmv_detect failed\n");
1561.1Stsutsui#endif
1571.1Stsutsui		goto out;
1581.1Stsutsui	}
1591.1Stsutsui
1601.1Stsutsui	if (ia->ia_irq[0].ir_irq != ISACF_IRQ_DEFAULT) {
1611.1Stsutsui		if (ia->ia_irq[0].ir_irq != irq) {
1621.1Stsutsui			printf("fmv_match: irq mismatch; "
1631.1Stsutsui			    "kernel configured %d != board configured %d\n",
1641.1Stsutsui			    ia->ia_irq[0].ir_irq, irq);
1651.1Stsutsui			goto out;
1661.1Stsutsui		}
1671.1Stsutsui	} else
1681.1Stsutsui		ia->ia_irq[0].ir_irq = irq;
1691.1Stsutsui
1701.1Stsutsui	ia->ia_nio = 1;
1711.1Stsutsui	ia->ia_io[0].ir_size = FMV_NPORTS;
1721.1Stsutsui
1731.1Stsutsui	ia->ia_nirq = 1;
1741.1Stsutsui
1751.1Stsutsui	ia->ia_niomem = 0;
1761.1Stsutsui	ia->ia_ndrq = 0;
1771.1Stsutsui
1781.1Stsutsui	rv = 1;
1791.1Stsutsui
1801.1Stsutsui out:
1811.1Stsutsui	bus_space_unmap(iot, ioh, FMV_NPORTS);
1821.1Stsutsui	return (rv);
1831.1Stsutsui}
1841.1Stsutsui
1851.1Stsutsui/*
1861.1Stsutsui * Check for specific bits in specific registers have specific values.
1871.1Stsutsui */
1881.1Stsutsuistatic __inline__ int
1891.1Stsutsuife_simple_probe (iot, ioh, sp)
1901.1Stsutsui	bus_space_tag_t iot;
1911.1Stsutsui	bus_space_handle_t ioh;
1921.1Stsutsui	struct fe_simple_probe_struct const *sp;
1931.1Stsutsui{
1941.1Stsutsui	u_int8_t val;
1951.1Stsutsui	struct fe_simple_probe_struct const *p;
1961.1Stsutsui
1971.1Stsutsui	for (p = sp; p->mask != 0; p++) {
1981.1Stsutsui		val = bus_space_read_1(iot, ioh, p->port);
1991.1Stsutsui		if ((val & p->mask) != p->bits) {
2001.1Stsutsui#ifdef FMV_DEBUG
2011.1Stsutsui			printf("fe_simple_probe: %x & %x != %x\n",
2021.1Stsutsui			    val, p->mask, p->bits);
2031.1Stsutsui#endif
2041.1Stsutsui			return (0);
2051.1Stsutsui		}
2061.1Stsutsui	}
2071.1Stsutsui
2081.1Stsutsui	return (1);
2091.1Stsutsui}
2101.1Stsutsui
2111.1Stsutsui/*
2121.1Stsutsui * Hardware (vendor) specific probe routines.
2131.1Stsutsui */
2141.1Stsutsui
2151.1Stsutsui/*
2161.1Stsutsui * Probe Fujitsu FMV-180 series boards and get iobase and irq from
2171.1Stsutsui * board.
2181.1Stsutsui */
2191.1Stsutsuistatic int
2201.1Stsutsuifmv_find(iot, ioh, iobase, irq)
2211.1Stsutsui	bus_space_tag_t iot;
2221.1Stsutsui	bus_space_handle_t ioh;
2231.1Stsutsui	int *iobase, *irq;
2241.1Stsutsui{
2251.1Stsutsui	u_int8_t config;
2261.1Stsutsui	static int const fmv_irqmap[4] = { 3, 7, 10, 15 };
2271.1Stsutsui	static struct fe_simple_probe_struct const probe_table[] = {
2281.1Stsutsui		{ FE_DLCR2, 0x70, 0x00 },
2291.1Stsutsui		{ FE_DLCR4, 0x08, 0x00 },
2301.1Stsutsui	    /*	{ FE_DLCR5, 0x80, 0x00 },	Doesn't work. */
2311.1Stsutsui
2321.1Stsutsui		{ FE_FMV0, FE_FMV0_MAGIC_MASK, FE_FMV0_MAGIC_VALUE },
2331.1Stsutsui		{ FE_FMV1, FE_FMV1_MAGIC_MASK, FE_FMV1_MAGIC_VALUE },
2341.1Stsutsui		{ FE_FMV3, FE_FMV3_EXTRA_MASK, FE_FMV3_EXTRA_VALUE },
2351.1Stsutsui#if 1
2361.1Stsutsui	/*
2371.1Stsutsui	 * Test *vendor* part of the station address for Fujitsu.
2381.1Stsutsui	 * The test will gain reliability of probe process, but
2391.1Stsutsui	 * it rejects FMV-180 clone boards manufactured by other vendors.
2401.1Stsutsui	 * We have to turn the test off when such cards are made available.
2411.1Stsutsui	 */
2421.1Stsutsui		{ FE_FMV4, 0xFF, 0x00 },
2431.1Stsutsui		{ FE_FMV5, 0xFF, 0x00 },
2441.1Stsutsui		{ FE_FMV6, 0xFF, 0x0E },
2451.1Stsutsui#else
2461.1Stsutsui	/*
2471.1Stsutsui	 * We can always verify the *first* 2 bits (in Ehternet
2481.1Stsutsui	 * bit order) are "no multicast" and "no local" even for
2491.1Stsutsui	 * unknown vendors.
2501.1Stsutsui	 */
2511.1Stsutsui		{ FE_FMV4, 0x03, 0x00 },
2521.1Stsutsui#endif
2531.1Stsutsui		{ 0 }
2541.1Stsutsui	};
2551.1Stsutsui
2561.1Stsutsui	/* Simple probe. */
2571.1Stsutsui	if (!fe_simple_probe(iot, ioh, probe_table))
2581.1Stsutsui		return (0);
2591.1Stsutsui
2601.1Stsutsui	/* Check if our I/O address matches config info on EEPROM. */
2611.1Stsutsui	config = bus_space_read_1(iot, ioh, FE_FMV2);
2621.1Stsutsui	*iobase = fmv_iomap[(config & FE_FMV2_ADDR) >> FE_FMV2_ADDR_SHIFT];
2631.1Stsutsui
2641.1Stsutsui	/*
2651.1Stsutsui	 * Determine which IRQ to be used.
2661.1Stsutsui	 *
2671.1Stsutsui	 * In this version, we always get an IRQ assignment from the
2681.1Stsutsui	 * FMV-180's configuration EEPROM, ignoring that specified in
2691.1Stsutsui	 * config file.
2701.1Stsutsui	 */
2711.1Stsutsui	*irq = fmv_irqmap[(config & FE_FMV2_IRQ) >> FE_FMV2_IRQ_SHIFT];
2721.1Stsutsui
2731.1Stsutsui	return (1);
2741.1Stsutsui}
2751.1Stsutsui
2761.1Stsutsuivoid
2771.1Stsutsuifmv_isa_attach(parent, self, aux)
2781.1Stsutsui	struct device *parent, *self;
2791.1Stsutsui	void *aux;
2801.1Stsutsui{
2811.1Stsutsui	struct fmv_isa_softc *isc = (struct fmv_isa_softc *)self;
2821.1Stsutsui	struct mb86960_softc *sc = &isc->sc_mb86960;
2831.1Stsutsui	struct isa_attach_args *ia = aux;
2841.1Stsutsui	bus_space_tag_t iot = ia->ia_iot;
2851.1Stsutsui	bus_space_handle_t ioh;
2861.1Stsutsui
2871.1Stsutsui	printf("\n");
2881.1Stsutsui
2891.1Stsutsui	/* Map i/o space. */
2901.1Stsutsui	if (bus_space_map(iot, ia->ia_io[0].ir_addr, FMV_NPORTS, 0, &ioh)) {
2911.1Stsutsui		printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
2921.1Stsutsui		return;
2931.1Stsutsui	}
2941.1Stsutsui
2951.1Stsutsui	sc->sc_bst = iot;
2961.1Stsutsui	sc->sc_bsh = ioh;
2971.1Stsutsui
2981.1Stsutsui	fmv_attach(sc);
2991.1Stsutsui
3001.1Stsutsui	/* Establish the interrupt handler. */
3011.1Stsutsui	isc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
3021.1Stsutsui	    IST_EDGE, IPL_NET, mb86960_intr, sc);
3031.1Stsutsui	if (isc->sc_ih == NULL)
3041.1Stsutsui		printf("%s: couldn't establish interrupt handler\n",
3051.1Stsutsui		    sc->sc_dev.dv_xname);
3061.1Stsutsui}
307