summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2008-04-05 00:52:07 +0000
committeryongari <yongari@FreeBSD.org>2008-04-05 00:52:07 +0000
commit47012d17257d878b67346ab10fe52d24ed17e6de (patch)
tree1526290fd28b1ea397287fb0cb7351e2d02b65c0
parent98be5d42cbd0a62a396da4528b47db743a1a1746 (diff)
downloadFreeBSD-src-47012d17257d878b67346ab10fe52d24ed17e6de.zip
FreeBSD-src-47012d17257d878b67346ab10fe52d24ed17e6de.tar.gz
Add support for IC Plus IP1001 PHY.
Tested by: Stuart Fraser < stuart AT stuartfraser DOT net >
-rw-r--r--sys/dev/mii/ip1000phy.c79
-rw-r--r--sys/dev/mii/ip1000phyreg.h45
-rw-r--r--sys/dev/mii/miidevs1
3 files changed, 104 insertions, 21 deletions
diff --git a/sys/dev/mii/ip1000phy.c b/sys/dev/mii/ip1000phy.c
index 73f0ca2..e4f3185 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 <sys/param.h>
@@ -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 26dc840..f69ab01 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 75eae064..73f074f 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
OpenPOWER on IntegriCloud