From 935577e7bc59c8f205f85b2f57814a7c12b96469 Mon Sep 17 00:00:00 2001 From: onoe Date: Thu, 12 Oct 2000 03:15:59 +0000 Subject: [PATCH] Tulip driver for NWB-5852A, which is an APbus board with DEC-21140A chip. without MII. It supports 100BaseTX only. Half duplex/Full duplex can be specified manually, but there are no auto negotiation functionality. XXX: It takes 34 seconds before sending/receiving packets on the wire after initial setup. It is obviously a bug because the board just works fine on NEWS-OS, but I cannot find what's wrong... Once it starts working, it seems there are no problems. --- sys/arch/newsmips/apbus/if_tlp_ap.c | 297 ++++++++++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 sys/arch/newsmips/apbus/if_tlp_ap.c diff --git a/sys/arch/newsmips/apbus/if_tlp_ap.c b/sys/arch/newsmips/apbus/if_tlp_ap.c new file mode 100644 index 000000000000..4b1989c4667b --- /dev/null +++ b/sys/arch/newsmips/apbus/if_tlp_ap.c @@ -0,0 +1,297 @@ +/* $NetBSD: if_tlp_ap.c,v 1.1 2000/10/12 03:15:59 onoe Exp $ */ + +/* + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Atsushi Onoe. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#define TLP_AP_ROM 0x00000000 /* AProm entry address */ +#define TLP_AP_CFG 0x00040000 /* PCI configuration registers */ +#define TLP_AP_CFG_CFID 0x00 /* Identification */ +#define TLP_AP_CFG_CFCS 0x04 /* Command and status */ +#define TLP_AP_CFG_CFRV 0x08 /* Revision */ +#define TLP_AP_CFG_CFLT 0x0c /* Latency timer */ +#define TLP_AP_CFG_CBIO 0x10 /* Base I/O address */ +#define TLP_AP_CFG_CBMA 0x14 /* Base memory address */ +#define TLP_AP_CFG_CFIT 0x3c /* Interrupt */ +#define TLP_AP_CSR 0x00080000 /* CSR base address */ +#define TLP_AP_RST 0x00100000 /* Board Reset */ + + +extern void tlp_idle __P((struct tulip_softc *, u_int32_t)); + +struct tulip_ap_softc { + struct tulip_softc sc_tulip; /* real Tulip softc */ + bus_space_tag_t sc_cfst; + bus_space_handle_t sc_cfsh; +}; + +static int tlp_ap_match __P((struct device *, struct cfdata *, void *)); +static void tlp_ap_attach __P((struct device *, struct device *, void *)); + +struct cfattach tlp_ap_ca = { + sizeof(struct tulip_ap_softc), tlp_ap_match, tlp_ap_attach +}; + +static void tlp_ap_preinit __P((struct tulip_softc *)); +static void tlp_ap_tmsw_init __P((struct tulip_softc *)); +static void tlp_ap_getmedia __P((struct tulip_softc *, struct ifmediareq *)); +static int tlp_ap_setmedia __P((struct tulip_softc *)); + +const struct tulip_mediasw tlp_ap_mediasw = { + tlp_ap_tmsw_init, tlp_ap_getmedia, tlp_ap_setmedia +}; + +static int +tlp_ap_match(parent, cf, aux) + struct device *parent; + struct cfdata *cf; + void *aux; +{ + struct apbus_attach_args *apa = aux; + + if (strcmp(apa->apa_name, "cbasetx") != 0) + return 0; + + return 1; +} + +/* + * Install interface into kernel networking data structures + */ +static void +tlp_ap_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct tulip_ap_softc *psc = (void *) self; + struct tulip_softc *sc = &psc->sc_tulip; + struct apbus_attach_args *apa = aux; + u_int8_t enaddr[ETHER_ADDR_LEN]; + u_int intrmask; + int i; + + printf(" slot%d addr 0x%lx", apa->apa_slotno, apa->apa_hwbase); + + /* PCI configuration register */ + psc->sc_cfst = 0; + psc->sc_cfsh = apa->apa_hwbase + TLP_AP_CFG; + sc->sc_devno = apa->apa_slotno; + sc->sc_rev = bus_space_read_4(psc->sc_cfst, psc->sc_cfsh, + TLP_AP_CFG_CFRV); + switch (bus_space_read_4(psc->sc_cfst, psc->sc_cfsh, TLP_AP_CFG_CFID)) { + case 0x00091011: + if (sc->sc_rev >= 0x20) + sc->sc_chip = TULIP_CHIP_21140A; + else + sc->sc_chip = TULIP_CHIP_21140; + break; + default: + printf(": unable to handle your board\n"); + return; + } + + printf(": %s Ethernet, pass %d.%d\n", + tlp_chip_names[sc->sc_chip], + (sc->sc_rev >> 4) & 0xf, sc->sc_rev & 0xf); + + /* CSR */ + sc->sc_st = 0; + sc->sc_sh = apa->apa_hwbase + TLP_AP_CSR; + sc->sc_dmat = apbus_dmatag_init(apa); + if (sc->sc_dmat == NULL) { + printf("%s: cannot allocate memory\n", sc->sc_dev.dv_xname); + return; + } + + /* + * Initialize bus specific parameters. + */ + if (mips_L2CacheLSize > 0) + sc->sc_cacheline = mips_L2CacheLSize / 4; + else if (mips_L1DCacheLSize > 0) + sc->sc_cacheline = mips_L1DCacheLSize / 4; + else + sc->sc_cacheline = 4; + sc->sc_maxburst = sc->sc_cacheline; /* XXX */ + sc->sc_regshift = 3; + sc->sc_flags |= TULIPF_DBO | TULIPF_BLE; /* Big Endian BUS */ + sc->sc_flags |= TULIPF_ENABLED; /* No Power Mgmt */ + + /* + * Reset hardware. + */ + bus_space_write_4(0, apa->apa_hwbase + TLP_AP_RST, 0, 1); + delay(100); + + /* + * Initialize PCI configuration register + */ + bus_space_write_4(psc->sc_cfst, psc->sc_cfsh, + TLP_AP_CFG_CFCS, 0x00000005); /* Master, IO */ + bus_space_write_4(psc->sc_cfst, psc->sc_cfsh, + TLP_AP_CFG_CFLT, 0x00000100); + bus_space_write_4(psc->sc_cfst, psc->sc_cfsh, + TLP_AP_CFG_CBIO, MIPS_KSEG1_TO_PHYS(sc->sc_sh)); + bus_space_write_4(psc->sc_cfst, psc->sc_cfsh, + TLP_AP_CFG_CFIT, 0x00000101); + + /* + * Initialize general purpose port register. + */ + TULIP_WRITE(sc, CSR_GPP, GPP_GPC | 0xc0); /* read */ + TULIP_WRITE(sc, CSR_GPP, 0x40); /* dipsw port on */ + i = TULIP_READ(sc, CSR_GPP) & GPP_MD; /* dipsw contents */ + TULIP_WRITE(sc, CSR_GPP, 0xc0); /* dipsw port off */ + TULIP_WRITE(sc, CSR_GPP, GPP_GPC | 0xcf); /* read write */ + if (sc->sc_maxburst == 16) { + TULIP_WRITE(sc, CSR_GPP, 0x8f); /* 16word burst */ + TULIP_WRITE(sc, CSR_GPP, 0xcf); + } else { + TULIP_WRITE(sc, CSR_GPP, 0x8e); /* 8word burst */ + TULIP_WRITE(sc, CSR_GPP, 0xce); + } + TULIP_WRITE(sc, CSR_GPP, GPP_GPC | 0xcf); /* read write */ + TULIP_WRITE(sc, CSR_GPP, 0xc3); /* mask abort/dma err */ + TULIP_WRITE(sc, CSR_GPP, 0xcf); /* mask abort/dma err */ + + if (tlp_read_srom(sc) == 0) { + printf("%s: srom read failed\n", sc->sc_dev.dv_xname); + free(sc->sc_dmat, M_DEVBUF); + return; + } + for (i = 0; i < ETHER_ADDR_LEN; i++) + enaddr[i] = sc->sc_srom[0x11 + i * 2]; + + sc->sc_mediasw = &tlp_ap_mediasw; + + /* + * Finish off the attach. + */ + tlp_attach(sc, enaddr); + + intrmask = SLOTTOMASK(apa->apa_slotno); + apbus_intr_establish(0, /* interrupt level (0 or 1) */ + intrmask, + 0, /* priority */ + tlp_intr, sc, apa->apa_name, apa->apa_ctlnum); +} + +static void +tlp_ap_preinit(sc) + struct tulip_softc *sc; +{ + + sc->sc_opmode |= OPMODE_MBO | OPMODE_SCR | OPMODE_PCS | OPMODE_HBD | + OPMODE_PS; + TULIP_WRITE(sc, CSR_OPMODE, sc->sc_opmode); +} + +static void +tlp_ap_tmsw_init(sc) + struct tulip_softc *sc; +{ + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + + sc->sc_preinit = tlp_ap_preinit; + + sc->sc_mii.mii_ifp = ifp; + sc->sc_mii.mii_readreg = NULL; + sc->sc_mii.mii_writereg = NULL; + sc->sc_mii.mii_statchg = sc->sc_statchg; + ifmedia_init(&sc->sc_mii.mii_media, 0, tlp_mediachange, + tlp_mediastatus); + ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_100_TX, 0, NULL); + ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, + NULL); + ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_100_TX); +} + +static void +tlp_ap_getmedia(sc, ifmr) + struct tulip_softc *sc; + struct ifmediareq *ifmr; +{ + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + + ifmr->ifm_status = IFM_AVALID; + if (ifp->if_flags & IFF_RUNNING) + ifmr->ifm_status |= IFM_ACTIVE; + ifmr->ifm_active = sc->sc_mii.mii_media_active; +} + +static int +tlp_ap_setmedia(sc) + struct tulip_softc *sc; +{ + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + + sc->sc_mii.mii_media_active = sc->sc_mii.mii_media.ifm_cur->ifm_media; + + if (ifp->if_flags & IFF_UP) + tlp_idle(sc, OPMODE_ST|OPMODE_SR); + if (sc->sc_mii.mii_media_active & IFM_FDX) + sc->sc_opmode |= OPMODE_FD; + else + sc->sc_opmode &= ~OPMODE_FD; + if (ifp->if_flags & IFF_UP) + TULIP_WRITE(sc, CSR_OPMODE, sc->sc_opmode); + return (0); +}