diff --git a/sys/dev/mii/ip1000phy.c b/sys/dev/mii/ip1000phy.c index 73f0ca2b774f..e4f31852182f 100644 --- a/sys/dev/mii/ip1000phy.c +++ b/sys/dev/mii/ip1000phy.c @@ -30,7 +30,7 @@ __FBSDID("$FreeBSD$"); /* - * Driver for the IC Plus IP1000A 10/100/1000 PHY. + * Driver for the IC Plus IP1000A/IP1001 10/100/1000 PHY. */ #include @@ -57,6 +57,12 @@ __FBSDID("$FreeBSD$"); static int ip1000phy_probe(device_t); static int ip1000phy_attach(device_t); +struct ip1000phy_softc { + struct mii_softc mii_sc; + int model; + int revision; +}; + static device_method_t ip1000phy_methods[] = { /* device interface */ DEVMETHOD(device_probe, ip1000phy_probe), @@ -82,6 +88,7 @@ static int ip1000phy_mii_phy_auto(struct mii_softc *); static const struct mii_phydesc ip1000phys[] = { MII_PHY_DESC(ICPLUS, IP1000A), + MII_PHY_DESC(ICPLUS, IP1001), MII_PHY_END }; @@ -95,11 +102,13 @@ ip1000phy_probe(device_t dev) static int ip1000phy_attach(device_t dev) { + struct ip1000phy_softc *isc; struct mii_softc *sc; struct mii_attach_args *ma; struct mii_data *mii; - sc = device_get_softc(dev); + isc = device_get_softc(dev); + sc = &isc->mii_sc; ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); mii = device_get_softc(sc->mii_dev); @@ -114,6 +123,9 @@ ip1000phy_attach(device_t dev) mii->mii_instance++; + isc->model = MII_MODEL(ma->mii_id2); + isc->revision = MII_REV(ma->mii_id2); + device_printf(dev, " "); #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) @@ -302,10 +314,13 @@ done: static void ip1000phy_status(struct mii_softc *sc) { + struct ip1000phy_softc *isc; struct mii_data *mii = sc->mii_pdata; uint32_t bmsr, bmcr, stat; uint32_t ar, lpar; + isc = (struct ip1000phy_softc *)sc; + mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; @@ -326,25 +341,44 @@ ip1000phy_status(struct mii_softc *sc) } } - stat = PHY_READ(sc, STGE_PhyCtrl); - switch (PC_LinkSpeed(stat)) { - case PC_LinkSpeed_Down: - mii->mii_media_active |= IFM_NONE; - return; - case PC_LinkSpeed_10: - mii->mii_media_active |= IFM_10_T; - break; - case PC_LinkSpeed_100: - mii->mii_media_active |= IFM_100_TX; - break; - case PC_LinkSpeed_1000: - mii->mii_media_active |= IFM_1000_T; - break; + if (isc->model == MII_MODEL_ICPLUS_IP1001) { + stat = PHY_READ(sc, IP1000PHY_LSR); + switch (stat & IP1000PHY_LSR_SPEED_MASK) { + case IP1000PHY_LSR_SPEED_10: + mii->mii_media_active |= IFM_10_T; + break; + case IP1000PHY_LSR_SPEED_100: + mii->mii_media_active |= IFM_100_TX; + break; + case IP1000PHY_LSR_SPEED_1000: + mii->mii_media_active |= IFM_1000_T; + break; + } + if ((stat & IP1000PHY_LSR_FULL_DUPLEX) != 0) + mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; + } else { + stat = PHY_READ(sc, STGE_PhyCtrl); + switch (PC_LinkSpeed(stat)) { + case PC_LinkSpeed_Down: + mii->mii_media_active |= IFM_NONE; + return; + case PC_LinkSpeed_10: + mii->mii_media_active |= IFM_10_T; + break; + case PC_LinkSpeed_100: + mii->mii_media_active |= IFM_100_TX; + break; + case PC_LinkSpeed_1000: + mii->mii_media_active |= IFM_1000_T; + break; + } + if ((stat & PC_PhyDuplexStatus) != 0) + mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; } - if ((stat & PC_PhyDuplexStatus) != 0) - mii->mii_media_active |= IFM_FDX; - else - mii->mii_media_active |= IFM_HDX; ar = PHY_READ(sc, IP1000PHY_MII_ANAR); lpar = PHY_READ(sc, IP1000PHY_MII_ANLPAR); @@ -410,10 +444,12 @@ ip1000phy_load_dspcode(struct mii_softc *sc) static void ip1000phy_reset(struct mii_softc *sc) { + struct ip1000phy_softc *isc; struct stge_softc *stge_sc; struct mii_data *mii; uint32_t reg; + isc = (struct ip1000phy_softc *)sc; mii_phy_reset(sc); /* clear autoneg/full-duplex as we don't want it after reset */ @@ -426,7 +462,8 @@ ip1000phy_reset(struct mii_softc *sc) * XXX There should be more general way to pass PHY specific * data via mii interface. */ - if (strcmp(mii->mii_ifp->if_dname, "stge") == 0) { + if (isc->model == MII_MODEL_ICPLUS_IP1000A && + strcmp(mii->mii_ifp->if_dname, "stge") == 0) { stge_sc = mii->mii_ifp->if_softc; if (stge_sc->sc_rev >= 0x40 && stge_sc->sc_rev <= 0x4e) ip1000phy_load_dspcode(sc); diff --git a/sys/dev/mii/ip1000phyreg.h b/sys/dev/mii/ip1000phyreg.h index 26dc84071815..f69ab012cb0d 100644 --- a/sys/dev/mii/ip1000phyreg.h +++ b/sys/dev/mii/ip1000phyreg.h @@ -138,4 +138,49 @@ #define IP1000PHY_EXTSTS_1000X 0x4000 #define IP1000PHY_EXTSTS_1000X_FDX 0x8000 +/* PHY specific control & status register. IP1001 only. */ +#define IP1000PHY_SCSR 0x10 +#define IP1000PHY_SCSR_RXPHASE_SEL 0x0001 +#define IP1000PHY_SCSR_TXPHASE_SEL 0x0002 +#define IP1000PHY_SCSR_REPEATOR_MODE 0x0004 +#define IP1000PHY_SCSR_RESERVED1_DEF 0x0008 +#define IP1000PHY_SCSR_RXCLK_DRV_MASK 0x0060 +#define IP1000PHY_SCSR_RXCLK_DRV_DEF 0x0040 +#define IP1000PHY_SCSR_RXD_DRV_MASK 0x0180 +#define IP1000PHY_SCSR_RXD_DRV_DEF 0x0100 +#define IP1000PHY_SCSR_JABBER_ENB 0x0200 +#define IP1000PHY_SCSR_HEART_BEAT_ENB 0x0400 +#define IP1000PHY_SCSR_DOWNSHIFT_ENB 0x0800 +#define IP1000PHY_SCSR_RESERVED2_DEF 0x1000 +#define IP1000PHY_SCSR_LED_DRV_4MA 0x0000 +#define IP1000PHY_SCSR_LED_DRV_8MA 0x2000 +#define IP1000PHY_SCSR_LED_MODE_MASK 0xC000 +#define IP1000PHY_SCSR_LED_MODE_DEF 0x0000 + +/* PHY link status register. IP1001 only. */ +#define IP1000PHY_LSR 0x11 +#define IP1000PHY_LSR_JABBER_DET 0x0200 +#define IP1000PHY_LSR_APS_SLEEP 0x0400 +#define IP1000PHY_LSR_MDIX 0x0800 +#define IP1000PHY_LSR_FULL_DUPLEX 0x1000 +#define IP1000PHY_LSR_SPEED_10 0x0000 +#define IP1000PHY_LSR_SPEED_100 0x2000 +#define IP1000PHY_LSR_SPEED_1000 0x4000 +#define IP1000PHY_LSR_SPEED_MASK 0x6000 +#define IP1000PHY_LSR_LINKUP 0x8000 + +/* PHY specific control register 2. IP1001 only. */ +#define IP1000PHY_SCR +#define IP1000PHY_SCR_SEW_RATE_MASK 0x0003 +#define IP1000PHY_SCR_SEW_RATE_DEF 0x0003 +#define IP1000PHY_SCR_AUTO_XOVER 0x0004 +#define IP1000PHY_SCR_SPEED_10_100_ENB 0x0040 +#define IP1000PHY_SCR_FIFO_LATENCY_2 0x0000 +#define IP1000PHY_SCR_FIFO_LATENCY_3 0x0080 +#define IP1000PHY_SCR_FIFO_LATENCY_4 0x0100 +#define IP1000PHY_SCR_FIFO_LATENCY_5 0x0180 +#define IP1000PHY_SCR_MDIX_ENB 0x0200 +#define IP1000PHY_SCR_RESERVED_DEF 0x0400 +#define IP1000PHY_SCR_APS_ON 0x0800 + #endif /* _DEV_MII_IP1000PHYREG_H_ */ diff --git a/sys/dev/mii/miidevs b/sys/dev/mii/miidevs index 75eae0640b0d..73f074f04d65 100644 --- a/sys/dev/mii/miidevs +++ b/sys/dev/mii/miidevs @@ -159,6 +159,7 @@ model xxICS 1893 0x0004 ICS1893 10/100 media interface /* IC Plus Corp. PHYs */ model ICPLUS IP101 0x0005 IC Plus 10/100 PHY model ICPLUS IP1000A 0x0008 IC Plus 10/100/1000 media interface +model ICPLUS IP1001 0x0019 IC Plus IP1001 10/100/1000 media interface /* Intel PHYs */ model xxINTEL I82553AB 0x0000 i83553 10/100 media interface