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