diff options
author | Jason Wright <jason@cvs.openbsd.org> | 2000-08-29 23:45:43 +0000 |
---|---|---|
committer | Jason Wright <jason@cvs.openbsd.org> | 2000-08-29 23:45:43 +0000 |
commit | fd3467766d5513a1c9d70e807faaab049eed3554 (patch) | |
tree | d657d5be24b94bd774799bfd478883e0efd9bc99 /sys/dev | |
parent | ba23dd44acc382a9f09e20743d14299e3583246c (diff) |
From FreeBSD: split out the support for XMAC-II phys and other phys
add xmphy & brgphy to GENERIC
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/files.pci | 4 | ||||
-rw-r--r-- | sys/dev/pci/if_sk.c | 438 | ||||
-rw-r--r-- | sys/dev/pci/if_skreg.h | 59 | ||||
-rw-r--r-- | sys/dev/pci/xmaciireg.h | 16 |
4 files changed, 399 insertions, 118 deletions
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci index 796572a98a0..1e1cb2dfff1 100644 --- a/sys/dev/pci/files.pci +++ b/sys/dev/pci/files.pci @@ -1,4 +1,4 @@ -# $OpenBSD: files.pci,v 1.81 2000/08/18 02:25:14 mickey Exp $ +# $OpenBSD: files.pci,v 1.82 2000/08/29 23:45:39 jason Exp $ # $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $ # # Config file and device description for machine-independent PCI code. @@ -276,7 +276,7 @@ file dev/pci/pccbb.c cbb # SysKonnect 984x gigabit ethernet device skc {} attach skc at pci -device sk: ether, ifnet, ifmedia +device sk: ether, ifnet, mii, ifmedia attach sk at skc file dev/pci/if_sk.c skc | sk diff --git a/sys/dev/pci/if_sk.c b/sys/dev/pci/if_sk.c index e6faa720c2a..11e45aa486a 100644 --- a/sys/dev/pci/if_sk.c +++ b/sys/dev/pci/if_sk.c @@ -1,7 +1,7 @@ -/* $OpenBSD: if_sk.c,v 1.6 2000/02/15 02:28:14 jason Exp $ */ +/* $OpenBSD: if_sk.c,v 1.7 2000/08/29 23:45:40 jason Exp $ */ /* - * Copyright (c) 1997, 1998, 1999 + * Copyright (c) 1997, 1998, 1999, 2000 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,16 +31,21 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/pci/if_sk.c,v 1.19 1999/09/25 04:50:27 wpaul Exp $ + * $FreeBSD: /c/ncvs/src/sys/pci/if_sk.c,v 1.20 2000/04/22 02:16:37 wpaul Exp $ */ /* * SysKonnect SK-NET gigabit ethernet driver for FreeBSD. Supports * the SK-984x series adapters, both single port and dual port. * References: - * The XaQti XMAC II datasheet, http://www.xaqti.com + * The XaQti XMAC II datasheet, + * http://www.freebsd.org/~wpaul/SysKonnect/xmacii_datasheet_rev_c_9-29.pdf * The SysKonnect GEnesis manual, http://www.syskonnect.com * + * Note: XaQti has been aquired by Vitesse, and Vitesse does not have the + * XMAC II datasheet online. I have put my copy at www.freebsd.org as a + * convience to others until Vitesse corrects this problem. + * * Written by Bill Paul <wpaul@ee.columbia.edu> * Department of Electrical Engineering * Columbia University, New York City @@ -99,6 +104,10 @@ #include <vm/vm_extern.h> #include <machine/bus.h> +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include <dev/mii/brgphyreg.h> + #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> #include <dev/pci/pcidevs.h> @@ -116,6 +125,7 @@ void sk_attach __P((struct device *, struct device *self, void *aux)); int skcprint __P((void *, const char *)); int sk_attach_xmac __P((struct sk_softc *, int)); int sk_intr __P((void *)); +void sk_intr_bcom __P((struct sk_if_softc *)); void sk_intr_xmac __P((struct sk_if_softc *)); void sk_rxeof __P((struct sk_if_softc *)); void sk_txeof __P((struct sk_if_softc *)); @@ -134,9 +144,7 @@ int sk_newbuf __P((struct sk_if_softc *, struct sk_chain *, struct mbuf *)); int sk_init_rx_ring __P((struct sk_if_softc *)); void sk_init_tx_ring __P((struct sk_if_softc *)); -#ifdef notdef u_int32_t sk_win_read_4 __P((struct sk_softc *, int)); -#endif u_int16_t sk_win_read_2 __P((struct sk_softc *, int)); u_int8_t sk_win_read_1 __P((struct sk_softc *, int)); void sk_win_write_4 __P((struct sk_softc *, int, u_int32_t)); @@ -146,11 +154,15 @@ u_int8_t sk_vpd_readbyte __P((struct sk_softc *, int)); void sk_vpd_read_res __P((struct sk_softc *, struct vpd_res *, int)); void sk_vpd_read __P((struct sk_softc *)); -u_int16_t sk_phy_readreg __P((struct sk_if_softc *, int)); -void sk_phy_writereg __P((struct sk_if_softc *, int, u_int32_t)); + +int sk_miibus_readreg __P((struct device *, int, int)); +void sk_miibus_writereg __P((struct device *, int, int, int)); +void sk_miibus_statchg __P((struct device *)); + u_int32_t sk_calchash __P((caddr_t)); void sk_setfilt __P((struct sk_if_softc *, caddr_t, int)); void sk_setmulti __P((struct sk_if_softc *)); +void sk_tick __P((void *)); #define SK_SETBIT(sc, reg, x) \ CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | x) @@ -170,7 +182,6 @@ void sk_setmulti __P((struct sk_if_softc *)); #define SK_WIN_CLRBIT_2(sc, reg, x) \ sk_win_write_2(sc, reg, sk_win_read_2(sc, reg) & ~x) -#ifdef notdef u_int32_t sk_win_read_4(sc, reg) struct sk_softc *sc; int reg; @@ -178,7 +189,6 @@ u_int32_t sk_win_read_4(sc, reg) CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg)); return(CSR_READ_4(sc, SK_WIN_BASE + SK_REG(reg))); } -#endif u_int16_t sk_win_read_2(sc, reg) struct sk_softc *sc; @@ -316,35 +326,46 @@ void sk_vpd_read(sc) return; } -u_int16_t sk_phy_readreg(sc_if, reg) - struct sk_if_softc *sc_if; - int reg; +int +sk_miibus_readreg(dev, phy, reg) + struct device *dev; + int phy, reg; { - int i; + struct sk_if_softc *sc_if = (struct sk_if_softc *)dev; + int i; - SK_XM_WRITE_2(sc_if, XM_PHY_ADDR, reg); - for (i = 0; i < SK_TIMEOUT; i++) { - if (!(SK_XM_READ_2(sc_if, XM_MMUCMD) & XM_MMUCMD_PHYBUSY)) - break; - } - - if (i == SK_TIMEOUT) { - printf("%s: phy failed to come ready\n", - sc_if->sk_dev.dv_xname); + if (sc_if->sk_phytype == SK_PHYTYPE_XMAC && phy != 0) return(0); - } + SK_XM_WRITE_2(sc_if, XM_PHY_ADDR, reg|(phy << 8)); + SK_XM_READ_2(sc_if, XM_PHY_DATA); + if (sc_if->sk_phytype != SK_PHYTYPE_XMAC) { + for (i = 0; i < SK_TIMEOUT; i++) { + DELAY(1); + if (SK_XM_READ_2(sc_if, XM_MMUCMD) & + XM_MMUCMD_PHYDATARDY) + break; + } + + if (i == SK_TIMEOUT) { + printf("%s: phy failed to come ready\n", + sc_if->sk_dev.dv_xname); + return(0); + } + } + DELAY(1); return(SK_XM_READ_2(sc_if, XM_PHY_DATA)); } -void sk_phy_writereg(sc_if, reg, val) - struct sk_if_softc *sc_if; - int reg; - u_int32_t val; +void +sk_miibus_writereg(dev, phy, reg, val) + struct device *dev; + int phy, reg, val; { - int i; + struct sk_if_softc *sc_if = (struct sk_if_softc *)dev; + int i; - SK_XM_WRITE_2(sc_if, XM_PHY_ADDR, reg); + SK_XM_WRITE_2(sc_if, XM_PHY_ADDR, reg|(phy << 8)); for (i = 0; i < SK_TIMEOUT; i++) { if (!(SK_XM_READ_2(sc_if, XM_MMUCMD) & XM_MMUCMD_PHYBUSY)) break; @@ -358,6 +379,7 @@ void sk_phy_writereg(sc_if, reg, val) SK_XM_WRITE_2(sc_if, XM_PHY_DATA, val); for (i = 0; i < SK_TIMEOUT; i++) { + DELAY(1); if (!(SK_XM_READ_2(sc_if, XM_MMUCMD) & XM_MMUCMD_PHYBUSY)) break; } @@ -368,6 +390,31 @@ void sk_phy_writereg(sc_if, reg, val) return; } +void +sk_miibus_statchg(dev) + struct device *dev; +{ + struct sk_if_softc *sc_if; + struct mii_data *mii; + + sc_if = (struct sk_if_softc *)dev; + mii = &sc_if->sk_mii; + + /* + * If this is a GMII PHY, manually set the XMAC's + * duplex mode accordingly. + */ + if (sc_if->sk_phytype != SK_PHYTYPE_XMAC) { + if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { + SK_XM_SETBIT_2(sc_if, XM_MMUCMD, XM_MMUCMD_GMIIFDX); + } else { + SK_XM_CLRBIT_2(sc_if, XM_MMUCMD, XM_MMUCMD_GMIIFDX); + } + } + + return; +} + #define SK_POLY 0xEDB88320 #define SK_BITS 6 @@ -591,72 +638,30 @@ int sk_newbuf(sc_if, c, m) /* * Set media options. */ -int sk_ifmedia_upd(ifp) - struct ifnet *ifp; +int +sk_ifmedia_upd(ifp) + struct ifnet *ifp; { - struct sk_if_softc *sc_if; - struct ifmedia *ifm; - - sc_if = ifp->if_softc; - ifm = &sc_if->ifmedia; - - if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) - return(EINVAL); - - switch(IFM_SUBTYPE(ifm->ifm_media)) { - case IFM_AUTO: - sk_phy_writereg(sc_if, XM_PHY_BMCR, - XM_BMCR_RENEGOTIATE|XM_BMCR_AUTONEGENBL); - break; - case IFM_1000_LX: - case IFM_1000_SX: - case IFM_1000_CX: - case IFM_1000_TX: - if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) - sk_phy_writereg(sc_if, XM_PHY_BMCR, XM_BMCR_DUPLEX); - else - sk_phy_writereg(sc_if, XM_PHY_BMCR, 0); - break; - default: - printf("%s: invalid media selected\n", sc_if->sk_dev.dv_xname); - return(EINVAL); - break; - } + struct sk_if_softc *sc_if = ifp->if_softc; + sk_init(sc_if); + mii_mediachg(&sc_if->sk_mii); return(0); } /* * Report current media status. */ -void sk_ifmedia_sts(ifp, ifmr) - struct ifnet *ifp; - struct ifmediareq *ifmr; +void +sk_ifmedia_sts(ifp, ifmr) + struct ifnet *ifp; + struct ifmediareq *ifmr; { - struct sk_softc *sc; - struct sk_if_softc *sc_if; - u_int16_t bmsr, extsts; - - sc_if = ifp->if_softc; - sc = sc_if->sk_softc; - - ifmr->ifm_status = IFM_AVALID; - ifmr->ifm_active = IFM_ETHER; - - bmsr = sk_phy_readreg(sc_if, XM_PHY_BMSR); - extsts = sk_phy_readreg(sc_if, XM_PHY_EXTSTS); - - if (!(bmsr & XM_BMSR_LINKSTAT)) - return; - - ifmr->ifm_status |= IFM_ACTIVE; - ifmr->ifm_active |= sc->sk_pmd;; - if (extsts & XM_EXTSTS_FULLDUPLEX) - ifmr->ifm_active |= IFM_FDX; - else - ifmr->ifm_active |= IFM_HDX; + struct sk_if_softc *sc_if = ifp->if_softc; - return; + mii_pollstat(&sc_if->sk_mii); + ifmr->ifm_active = sc_if->sk_mii.mii_media_active; + ifmr->ifm_status = sc_if->sk_mii.mii_media_status; } int @@ -668,6 +673,7 @@ sk_ioctl(ifp, command, data) struct sk_if_softc *sc_if = ifp->if_softc; struct ifreq *ifr = (struct ifreq *) data; struct ifaddr *ifa = (struct ifaddr *) data; + struct mii_data *mii; int s, error = 0; s = splimp(); @@ -732,7 +738,8 @@ sk_ioctl(ifp, command, data) break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: - error = ifmedia_ioctl(ifp, ifr, &sc_if->ifmedia, command); + mii = &sc_if->sk_mii; + error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; default: error = EINVAL; @@ -892,6 +899,21 @@ sk_attach(parent, self, aux) sc_if->sk_tx_ramend = val - 1; } + /* Read and save PHY type and set PHY address */ + sc_if->sk_phytype = sk_win_read_1(sc, SK_EPROM1) & 0xF; + switch (sc_if->sk_phytype) { + case SK_PHYTYPE_XMAC: + sc_if->sk_phyaddr = SK_PHYADDR_XMAC; + break; + case SK_PHYTYPE_BCOM: + sc_if->sk_phyaddr = SK_PHYADDR_BCOM; + break; + default: + printf("%s: unsupported PHY type: %d\n", + sc->sk_dev.dv_xname, sc_if->sk_phytype); + return; + } + /* Allocate the descriptor queues. */ if (bus_dmamem_alloc(sc->sc_dmatag, sizeof(struct sk_ring_data), PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) { @@ -938,14 +960,27 @@ sk_attach(parent, self, aux) bcopy(sc_if->sk_dev.dv_xname, ifp->if_xname, IFNAMSIZ); /* - * Do ifmedia setup. + * Do miibus setup. */ - ifmedia_init(&sc_if->ifmedia, 0, sk_ifmedia_upd, sk_ifmedia_sts); - ifmedia_add(&sc_if->ifmedia, IFM_ETHER|sc->sk_pmd, 0, NULL); - ifmedia_add(&sc_if->ifmedia, IFM_ETHER|sc->sk_pmd|IFM_FDX, 0, NULL); - ifmedia_add(&sc_if->ifmedia, IFM_ETHER|sc->sk_pmd|IFM_HDX, 0, NULL); - ifmedia_add(&sc_if->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); - ifmedia_set(&sc_if->ifmedia, IFM_ETHER|IFM_AUTO); + sk_init_xmac(sc_if); + sc_if->sk_mii.mii_ifp = ifp; + sc_if->sk_mii.mii_readreg = sk_miibus_readreg; + sc_if->sk_mii.mii_writereg = sk_miibus_writereg; + sc_if->sk_mii.mii_statchg = sk_miibus_statchg; + ifmedia_init(&sc_if->sk_mii.mii_media, 0, + sk_ifmedia_upd, sk_ifmedia_sts); + mii_phy_probe(self, &sc_if->sk_mii, 0xffffffff); + if (LIST_FIRST(&sc_if->sk_mii.mii_phys) == NULL) { + printf("%s: no PHY found!\n", sc_if->sk_dev.dv_xname); + ifmedia_add(&sc_if->sk_mii.mii_media, IFM_ETHER|IFM_MANUAL, + 0, NULL); + ifmedia_set(&sc_if->sk_mii.mii_media, IFM_ETHER|IFM_MANUAL); + } + else + ifmedia_set(&sc_if->sk_mii.mii_media, IFM_ETHER|IFM_AUTO); + + timeout_set(&sc_if->sk_tick_ch, sk_tick, sc_if); + timeout_add(&sc_if->sk_tick_ch, hz); /* * Call MI attach routines. @@ -1400,12 +1435,114 @@ void sk_txeof(sc_if) return; } +void +sk_tick(xsc_if) + void *xsc_if; +{ + struct sk_if_softc *sc_if; + struct mii_data *mii; + struct ifnet *ifp; + int i; + + sc_if = xsc_if; + ifp = &sc_if->arpcom.ac_if; + mii = &sc_if->sk_mii; + + if (!(ifp->if_flags & IFF_UP)) + return; + + if (sc_if->sk_phytype == SK_PHYTYPE_BCOM) { + sk_intr_bcom(sc_if); + return; + } + + /* + * According to SysKonnect, the correct way to verify that + * the link has come back up is to poll bit 0 of the GPIO + * register three times. This pin has the signal from the + * link sync pin connected to it; if we read the same link + * state 3 times in a row, we know the link is up. + */ + for (i = 0; i < 3; i++) { + if (SK_XM_READ_2(sc_if, XM_GPIO) & XM_GPIO_GP0_SET) + break; + } + + if (i != 3) { + timeout_add(&sc_if->sk_tick_ch, hz); + return; + } + + /* Turn the GP0 interrupt back on. */ + SK_XM_CLRBIT_2(sc_if, XM_IMR, XM_IMR_GP0_SET); + SK_XM_READ_2(sc_if, XM_ISR); + mii_tick(mii); + mii_pollstat(mii); + timeout_del(&sc_if->sk_tick_ch); +} + +void +sk_intr_bcom(sc_if) + struct sk_if_softc *sc_if; +{ + struct sk_softc *sc; + struct mii_data *mii; + struct ifnet *ifp; + int status; + + sc = sc_if->sk_softc; + mii = &sc_if->sk_mii; + ifp = &sc_if->arpcom.ac_if; + + SK_XM_CLRBIT_2(sc_if, XM_MMUCMD, XM_MMUCMD_TX_ENB|XM_MMUCMD_RX_ENB); + + /* + * Read the PHY interrupt register to make sure + * we clear any pending interrupts. + */ + status = sk_miibus_readreg((struct device *)sc_if, + SK_PHYADDR_BCOM, BRGPHY_MII_ISR); + + if (!(ifp->if_flags & IFF_RUNNING)) { + sk_init_xmac(sc_if); + return; + } + + if (status & (BRGPHY_ISR_LNK_CHG|BRGPHY_ISR_AN_PR)) { + int lstat; + lstat = sk_miibus_readreg((struct device *)sc_if, + SK_PHYADDR_BCOM, BRGPHY_MII_AUXSTS); + + if (!(lstat & BRGPHY_AUXSTS_LINK) && sc_if->sk_link) { + mii_mediachg(mii); + /* Turn off the link LED. */ + SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL, SK_LINKLED_OFF); + sc_if->sk_link = 0; + } else if (status & BRGPHY_ISR_LNK_CHG) { + sk_miibus_writereg((struct device *)sc_if, + SK_PHYADDR_BCOM, BRGPHY_MII_IMR, 0xFF00); + mii_tick(mii); + sc_if->sk_link = 1; + /* Turn on the link LED. */ + SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL, + SK_LINKLED_ON|SK_LINKLED_LINKSYNC_OFF| + SK_LINKLED_BLINK_OFF); + } else { + mii_tick(mii); + timeout_add(&sc_if->sk_tick_ch, hz); + } + } + + SK_XM_SETBIT_2(sc_if, XM_MMUCMD, XM_MMUCMD_TX_ENB|XM_MMUCMD_RX_ENB); + + return; +} + void sk_intr_xmac(sc_if) struct sk_if_softc *sc_if; { struct sk_softc *sc; u_int16_t status; - u_int16_t bmsr; sc = sc_if->sk_softc; status = SK_XM_READ_2(sc_if, XM_ISR); @@ -1416,13 +1553,8 @@ void sk_intr_xmac(sc_if) sc_if->sk_link = 0; } - if (status & XM_ISR_AUTONEG_DONE) { - bmsr = sk_phy_readreg(sc_if, XM_PHY_BMSR); - if (bmsr & XM_BMSR_LINKSTAT) { - sc_if->sk_link = 1; - SK_XM_CLRBIT_2(sc_if, XM_IMR, XM_IMR_LINKEVENT); - } - } + if (status & XM_ISR_AUTONEG_DONE) + timeout_add(&sc_if->sk_tick_ch, hz); if (status & XM_IMR_TX_UNDERRUN) SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_FLUSH_TXFIFO); @@ -1448,7 +1580,7 @@ int sk_intr(xsc) if (sc_if0 != NULL) ifp0 = &sc_if0->arpcom.ac_if; if (sc_if1 != NULL) - ifp1 = &sc_if0->arpcom.ac_if; + ifp1 = &sc_if1->arpcom.ac_if; for (;;) { status = CSR_READ_4(sc, SK_ISSR); @@ -1482,11 +1614,20 @@ int sk_intr(xsc) } /* Then MAC interrupts. */ - if (status & SK_ISR_MAC1) + if (status & SK_ISR_MAC1 && + ifp0->if_flags & IFF_RUNNING) sk_intr_xmac(sc_if0); - if (status & SK_ISR_MAC2) + if (status & SK_ISR_MAC2 && + ifp1->if_flags & IFF_RUNNING) sk_intr_xmac(sc_if1); + + if (status & SK_ISR_EXTERNAL_REG) { + if (ifp0 != NULL) + sk_intr_bcom(sc_if0); + if (ifp1 != NULL) + sk_intr_bcom(sc_if1); + } } CSR_WRITE_4(sc, SK_IMR, sc->sk_intrmask); @@ -1504,6 +1645,11 @@ void sk_init_xmac(sc_if) { struct sk_softc *sc; struct ifnet *ifp; + struct sk_bcom_hack bhack[] = { + { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 }, { 0x17, 0x0013 }, + { 0x15, 0x0404 }, { 0x17, 0x8006 }, { 0x15, 0x0132 }, { 0x17, 0x8006 }, + { 0x15, 0x0232 }, { 0x17, 0x800D }, { 0x15, 0x000F }, { 0x18, 0x0420 }, + { 0, 0 } }; sc = sc_if->sk_softc; ifp = &sc_if->arpcom.ac_if; @@ -1512,9 +1658,55 @@ void sk_init_xmac(sc_if) SK_IF_WRITE_2(sc_if, 0, SK_TXF1_MACCTL, SK_TXMACCTL_XMAC_UNRESET); DELAY(1000); + /* Reset the XMAC's internal state. */ + SK_XM_SETBIT_2(sc_if, XM_GPIO, XM_GPIO_RESETMAC); + /* Save the XMAC II revision */ sc_if->sk_xmac_rev = XM_XMAC_REV(SK_XM_READ_4(sc_if, XM_DEVID)); + /* + * Perform additional initialization for external PHYs, + * namely for the 1000baseTX cards that use the XMAC's + * GMII mode. + */ + if (sc_if->sk_phytype == SK_PHYTYPE_BCOM) { + int i = 0; + u_int32_t val; + + /* Take PHY out of reset. */ + val = sk_win_read_4(sc, SK_GPIO); + if (sc_if->sk_port == SK_PORT_A) + val |= SK_GPIO_DIR0|SK_GPIO_DAT0; + else + val |= SK_GPIO_DIR2|SK_GPIO_DAT2; + sk_win_write_4(sc, SK_GPIO, val); + + /* Enable GMII mode on the XMAC. */ + SK_XM_SETBIT_2(sc_if, XM_HWCFG, XM_HWCFG_GMIIMODE); + + sk_miibus_writereg((struct device *)sc_if, SK_PHYADDR_BCOM, + BRGPHY_MII_BMCR, BRGPHY_BMCR_RESET); + DELAY(10000); + sk_miibus_writereg((struct device *)sc_if, SK_PHYADDR_BCOM, + BRGPHY_MII_IMR, 0xFFF0); + + /* + * Early versions of the BCM5400 apparently have + * a bug that requires them to have their reserved + * registers initialized to some magic values. I don't + * know what the numbers do, I'm just the messenger. + */ + if (sk_miibus_readreg((struct device *)sc_if, + SK_PHYADDR_BCOM, 0x03) == 0x6041) { + while(bhack[i].reg) { + sk_miibus_writereg((struct device *)sc_if, + SK_PHYADDR_BCOM, bhack[i].reg, + bhack[i].val); + i++; + } + } + } + /* Set station address */ SK_XM_WRITE_2(sc_if, XM_PAR0, *(u_int16_t *)(&sc_if->arpcom.ac_enaddr[0])); @@ -1576,9 +1768,10 @@ void sk_init_xmac(sc_if) /* Clear and enable interrupts */ SK_XM_READ_2(sc_if, XM_ISR); - SK_XM_WRITE_2(sc_if, XM_IMR, XM_INTRS); - - sc_if->sk_link = 0; + if (sc_if->sk_phytype == SK_PHYTYPE_XMAC) + SK_XM_WRITE_2(sc_if, XM_IMR, XM_INTRS); + else + SK_XM_WRITE_2(sc_if, XM_IMR, 0xFFFF); /* Configure MAC arbiter */ switch(sc_if->sk_xmac_rev) { @@ -1610,6 +1803,8 @@ void sk_init_xmac(sc_if) sk_win_write_2(sc, SK_MACARB_CTL, SK_MACARBCTL_UNRESET|SK_MACARBCTL_FASTOE_OFF); + sc_if->sk_link = 1; + return; } @@ -1623,12 +1818,14 @@ void sk_init(xsc) struct sk_if_softc *sc_if = xsc; struct sk_softc *sc; struct ifnet *ifp; + struct mii_data *mii; int s; s = splimp(); ifp = &sc_if->arpcom.ac_if; sc = sc_if->sk_softc; + mii = &sc_if->sk_mii; /* Cancel pending I/O and free all RX/TX buffers. */ sk_stop(sc_if); @@ -1647,6 +1844,7 @@ void sk_init(xsc) /* Configure XMAC(s) */ sk_init_xmac(sc_if); + mii_mediachg(mii); /* Configure MAC FIFOs */ SK_IF_WRITE_4(sc_if, 0, SK_RXF1_CTL, SK_FIFO_UNRESET); @@ -1704,6 +1902,9 @@ void sk_init(xsc) sc->sk_intrmask |= SK_INTRS1; else sc->sk_intrmask |= SK_INTRS2; + + sc->sk_intrmask |= SK_ISR_EXTERNAL_REG; + CSR_WRITE_4(sc, SK_IMR, sc->sk_intrmask); /* Start BMUs. */ @@ -1730,7 +1931,25 @@ void sk_stop(sc_if) sc = sc_if->sk_softc; ifp = &sc_if->arpcom.ac_if; + timeout_del(&sc_if->sk_tick_ch); + + if (sc_if->sk_phytype == SK_PHYTYPE_BCOM) { + u_int32_t val; + + /* Put PHY back into reset. */ + val = sk_win_read_4(sc, SK_GPIO); + if (sc_if->sk_port == SK_PORT_A) { + val |= SK_GPIO_DIR0; + val &= ~SK_GPIO_DAT0; + } else { + val |= SK_GPIO_DIR2; + val &= ~SK_GPIO_DAT2; + } + sk_win_write_4(sc, SK_GPIO, val); + } + /* Turn off various components of this interface. */ + SK_XM_SETBIT_2(sc_if, XM_GPIO, XM_GPIO_RESETMAC); SK_IF_WRITE_2(sc_if, 0, SK_TXF1_MACCTL, SK_TXMACCTL_XMAC_RESET); SK_IF_WRITE_4(sc_if, 0, SK_RXF1_CTL, SK_FIFO_RESET); SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_BMU_CSR, SK_RXBMU_OFFLINE); @@ -1750,6 +1969,9 @@ void sk_stop(sc_if) sc->sk_intrmask &= ~SK_INTRS2; CSR_WRITE_4(sc, SK_IMR, sc->sk_intrmask); + SK_XM_READ_2(sc_if, XM_ISR); + SK_XM_WRITE_2(sc_if, XM_IMR, 0xFFFF); + /* Free RX and TX mbufs still in the queues. */ for (i = 0; i < SK_RX_RING_CNT; i++) { if (sc_if->sk_cdata.sk_rx_chain[i].sk_mbuf != NULL) { diff --git a/sys/dev/pci/if_skreg.h b/sys/dev/pci/if_skreg.h index 49666f507b8..06d7feddea7 100644 --- a/sys/dev/pci/if_skreg.h +++ b/sys/dev/pci/if_skreg.h @@ -1,7 +1,7 @@ -/* $OpenBSD: if_skreg.h,v 1.4 1999/10/22 07:14:42 deraadt Exp $ */ +/* $OpenBSD: if_skreg.h,v 1.5 2000/08/29 23:45:40 jason Exp $ */ /* - * Copyright (c) 1997, 1998, 1999 + * Copyright (c) 1997, 1998, 1999, 2000 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,7 +31,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/pci/if_skreg.h,v 1.8 1999/09/18 04:01:31 wpaul Exp $ + * $FreeBSD: /c/ncvs/src/sys/pci/if_skreg.h,v 1.9 2000/04/22 02:16:37 wpaul Exp $ */ /* @@ -321,6 +321,24 @@ #define SK_RBOFF_0 0x0 #define SK_RBOFF_80000 0x80000 +/* + * SK_EEPROM1 contains the PHY type, which may be XMAC for + * fiber-based cards or BCOM for 1000baseT cards with a Broadcom + * PHY. + */ +#define SK_PHYTYPE_XMAC 0 /* integeated XMAC II PHY */ +#define SK_PHYTYPE_BCOM 1 /* Broadcom BCM5400 */ +#define SK_PHYTYPE_LONE 2 /* Level One LXT1000 */ +#define SK_PHYTYPE_NAT 3 /* National DP83891 */ + +/* + * PHY addresses. + */ +#define SK_PHYADDR_XMAC 0x0 +#define SK_PHYADDR_BCOM 0x1 +#define SK_PHYADDR_LONE 0x3 +#define SK_PHYADDR_NAT 0x0 + #define SK_CONFIG_SINGLEMAC 0x01 #define SK_CONFIG_DIS_DSL_CLK 0x02 @@ -329,6 +347,28 @@ #define SK_PMD_1000BASECX 0x43 #define SK_PMD_1000BASETX 0x54 +/* GPIO bits */ +#define SK_GPIO_DAT0 0x00000001 +#define SK_GPIO_DAT1 0x00000002 +#define SK_GPIO_DAT2 0x00000004 +#define SK_GPIO_DAT3 0x00000008 +#define SK_GPIO_DAT4 0x00000010 +#define SK_GPIO_DAT5 0x00000020 +#define SK_GPIO_DAT6 0x00000040 +#define SK_GPIO_DAT7 0x00000080 +#define SK_GPIO_DAT8 0x00000100 +#define SK_GPIO_DAT9 0x00000200 +#define SK_GPIO_DIR0 0x00010000 +#define SK_GPIO_DIR1 0x00020000 +#define SK_GPIO_DIR2 0x00040000 +#define SK_GPIO_DIR3 0x00080000 +#define SK_GPIO_DIR4 0x00100000 +#define SK_GPIO_DIR5 0x00200000 +#define SK_GPIO_DIR6 0x00400000 +#define SK_GPIO_DIR7 0x00800000 +#define SK_GPIO_DIR8 0x01000000 +#define SK_GPIO_DIR9 0x02000000 + /* Block 3 Ram interface and MAC arbiter registers */ #define SK_RAMADDR 0x0180 #define SK_RAMDATA0 0x0184 @@ -1119,6 +1159,11 @@ struct sk_ring_data { struct sk_rx_desc sk_rx_ring[SK_RX_RING_CNT]; }; +struct sk_bcom_hack { + int reg; + int val; +}; + #define SK_INC(x, y) (x) = (x + 1) % y /* Forward decl. */ @@ -1147,14 +1192,18 @@ struct sk_softc { struct sk_if_softc { struct device sk_dev; /* generic device */ struct arpcom arpcom; /* interface info */ - struct ifmedia ifmedia; /* media info */ + struct mii_data sk_mii; u_int8_t sk_port; /* port # on controller */ u_int8_t sk_xmac_rev; /* XMAC chip rev (B2 or C1) */ - u_int8_t sk_link; u_int32_t sk_rx_ramstart; u_int32_t sk_rx_ramend; u_int32_t sk_tx_ramstart; u_int32_t sk_tx_ramend; + int sk_phytype; + int sk_phyaddr; + int sk_cnt; + int sk_link; + struct timeout sk_tick_ch; struct sk_chain_data sk_cdata; struct sk_ring_data *sk_rdata; struct sk_softc *sk_softc; /* parent controller */ diff --git a/sys/dev/pci/xmaciireg.h b/sys/dev/pci/xmaciireg.h index ea296ca74ff..abd43e251fa 100644 --- a/sys/dev/pci/xmaciireg.h +++ b/sys/dev/pci/xmaciireg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: xmaciireg.h,v 1.2 1999/10/01 02:54:15 jason Exp $ */ +/* $OpenBSD: xmaciireg.h,v 1.3 2000/08/29 23:45:40 jason Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -31,7 +31,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/pci/xmaciireg.h,v 1.2 1999/08/28 00:51:08 peter Exp $ + * $FreeBSD: /c/ncvs/src/sys/pci/xmaciireg.h,v 1.3 2000/04/22 02:16:37 wpaul Exp $ */ /* @@ -229,6 +229,12 @@ #define XM_RXCMD_BIGPKTOK 0x0080 #define XM_RXCMD_LENERROK 0x0100 +#define XM_GPIO_GP0_SET 0x0001 +#define XM_GPIO_RESETSTATS 0x0004 +#define XM_GPIO_RESETMAC 0x0008 +#define XM_GPIO_FORCEINT 0x0020 +#define XM_GPIO_ANEGINPROG 0x0040 + #define XM_IMR_RX_EOF 0x0001 #define XM_IMR_TX_EOF 0x0002 #define XM_IMR_TX_UNDERRUN 0x0004 @@ -246,7 +252,7 @@ #define XM_IMR_LINKEVENT 0x4000 #define XM_INTRS \ - (~(XM_IMR_LINKEVENT|XM_IMR_AUTONEG_DONE|XM_IMR_TX_UNDERRUN)) + (~(XM_IMR_GP0_SET|XM_IMR_AUTONEG_DONE|XM_IMR_TX_UNDERRUN)) #define XM_ISR_RX_EOF 0x0001 #define XM_ISR_TX_EOF 0x0002 @@ -264,6 +270,10 @@ #define XM_ISR_TX_ABORT 0x2000 #define XM_ISR_LINKEVENT 0x4000 +#define XM_HWCFG_GENEOP 0x0008 +#define XM_HWCFG_SIGSTATCKH 0x0004 +#define XM_HWCFG_GMIIMODE 0x0001 + #define XM_MODE_FLUSH_RXFIFO 0x00000001 #define XM_MODE_FLUSH_TXFIFO 0x00000002 #define XM_MODE_BIGENDIAN 0x00000004 |