summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/mii/rgephy.c114
-rw-r--r--sys/dev/mii/rgephyreg.h13
2 files changed, 99 insertions, 28 deletions
diff --git a/sys/dev/mii/rgephy.c b/sys/dev/mii/rgephy.c
index 417fa63..aca7978 100644
--- a/sys/dev/mii/rgephy.c
+++ b/sys/dev/mii/rgephy.c
@@ -34,7 +34,7 @@
__FBSDID("$FreeBSD$");
/*
- * Driver for the RealTek 8169S/8110S internal 10/100/1000 PHY.
+ * Driver for the RealTek 8169S/8110S/8211B internal 10/100/1000 PHY.
*/
#include <sys/param.h>
@@ -62,6 +62,12 @@ __FBSDID("$FreeBSD$");
static int rgephy_probe(device_t);
static int rgephy_attach(device_t);
+struct rgephy_softc {
+ struct mii_softc mii_sc;
+ int mii_model;
+ int mii_revision;
+};
+
static device_method_t rgephy_methods[] = {
/* device interface */
DEVMETHOD(device_probe, rgephy_probe),
@@ -76,7 +82,7 @@ static devclass_t rgephy_devclass;
static driver_t rgephy_driver = {
"rgephy",
rgephy_methods,
- sizeof(struct mii_softc)
+ sizeof(struct rgephy_softc)
};
DRIVER_MODULE(rgephy, miibus, rgephy_driver, rgephy_devclass, 0, 0);
@@ -103,12 +109,14 @@ rgephy_probe(device_t dev)
static int
rgephy_attach(device_t dev)
{
+ struct rgephy_softc *rsc;
struct mii_softc *sc;
struct mii_attach_args *ma;
struct mii_data *mii;
const char *sep = "";
- sc = device_get_softc(dev);
+ rsc = device_get_softc(dev);
+ sc = &rsc->mii_sc;
ma = device_get_ivars(dev);
sc->mii_dev = device_get_parent(dev);
mii = device_get_softc(sc->mii_dev);
@@ -122,6 +130,9 @@ rgephy_attach(device_t dev)
mii->mii_instance++;
+ rsc->mii_model = MII_MODEL(ma->mii_id2);
+ rsc->mii_revision = MII_REV(ma->mii_id2);
+
#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
#define PRINT(s) printf("%s%s", sep, s); sep = ", "
@@ -153,9 +164,12 @@ rgephy_attach(device_t dev)
static int
rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
+ struct rgephy_softc *rsc;
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
int reg, speed, gig, anar;
+ rsc = (struct rgephy_softc *)sc;
+
switch (cmd) {
case MII_POLLSTAT:
/*
@@ -282,10 +296,19 @@ setit:
* need to restart the autonegotiation process. Read
* the BMSR twice in case it's latched.
*/
- reg = PHY_READ(sc, RL_GMEDIASTAT);
- if (reg & RL_GMEDIASTAT_LINK) {
- sc->mii_ticks = 0;
- break;
+ if (rsc->mii_revision >= 2) {
+ /* RTL8211B(L) */
+ reg = PHY_READ(sc, RGEPHY_MII_SSR);
+ if (reg & RGEPHY_SSR_LINK) {
+ sc->mii_ticks = 0;
+ break;
+ }
+ } else {
+ reg = PHY_READ(sc, RL_GMEDIASTAT);
+ if (reg & RL_GMEDIASTAT_LINK) {
+ sc->mii_ticks = 0;
+ break;
+ }
}
/* Announce link loss right after it happens. */
@@ -321,16 +344,26 @@ setit:
static void
rgephy_status(struct mii_softc *sc)
{
+ struct rgephy_softc *rsc;
struct mii_data *mii = sc->mii_pdata;
int bmsr, bmcr;
+ uint16_t ssr;
mii->mii_media_status = IFM_AVALID;
mii->mii_media_active = IFM_ETHER;
- bmsr = PHY_READ(sc, RL_GMEDIASTAT);
+ rsc = (struct rgephy_softc *)sc;
+ if (rsc->mii_revision >= 2) {
+ ssr = PHY_READ(sc, RGEPHY_MII_SSR);
+ if (ssr & RGEPHY_SSR_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+ } else {
+ bmsr = PHY_READ(sc, RL_GMEDIASTAT);
+ if (bmsr & RL_GMEDIASTAT_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+ }
- if (bmsr & RL_GMEDIASTAT_LINK)
- mii->mii_media_status |= IFM_ACTIVE;
+ PHY_READ(sc, RGEPHY_MII_BMSR);
bmsr = PHY_READ(sc, RGEPHY_MII_BMSR);
bmcr = PHY_READ(sc, RGEPHY_MII_BMCR);
@@ -346,17 +379,41 @@ rgephy_status(struct mii_softc *sc)
}
}
- bmsr = PHY_READ(sc, RL_GMEDIASTAT);
- if (bmsr & RL_GMEDIASTAT_1000MBPS)
- mii->mii_media_active |= IFM_1000_T;
- else if (bmsr & RL_GMEDIASTAT_100MBPS)
- mii->mii_media_active |= IFM_100_TX;
- else if (bmsr & RL_GMEDIASTAT_10MBPS)
- mii->mii_media_active |= IFM_10_T;
- else
- mii->mii_media_active |= IFM_NONE;
- if (bmsr & RL_GMEDIASTAT_FDX)
- mii->mii_media_active |= IFM_FDX;
+ if (rsc->mii_revision >= 2) {
+ ssr = PHY_READ(sc, RGEPHY_MII_SSR);
+ switch (ssr & RGEPHY_SSR_SPD_MASK) {
+ case RGEPHY_SSR_S1000:
+ mii->mii_media_active |= IFM_1000_T;
+ break;
+ case RGEPHY_SSR_S100:
+ mii->mii_media_active |= IFM_100_TX;
+ break;
+ case RGEPHY_SSR_S10:
+ mii->mii_media_active |= IFM_10_T;
+ break;
+ default:
+ mii->mii_media_active |= IFM_NONE;
+ break;
+ }
+ if (ssr & RGEPHY_SSR_FDX)
+ mii->mii_media_active |= IFM_FDX;
+ else
+ mii->mii_media_active |= IFM_HDX;
+ } else {
+ bmsr = PHY_READ(sc, RL_GMEDIASTAT);
+ if (bmsr & RL_GMEDIASTAT_1000MBPS)
+ mii->mii_media_active |= IFM_1000_T;
+ else if (bmsr & RL_GMEDIASTAT_100MBPS)
+ mii->mii_media_active |= IFM_100_TX;
+ else if (bmsr & RL_GMEDIASTAT_10MBPS)
+ mii->mii_media_active |= IFM_10_T;
+ else
+ mii->mii_media_active |= IFM_NONE;
+ if (bmsr & RL_GMEDIASTAT_FDX)
+ mii->mii_media_active |= IFM_FDX;
+ else
+ mii->mii_media_active |= IFM_HDX;
+ }
}
static int
@@ -382,10 +439,14 @@ rgephy_mii_phy_auto(struct mii_softc *mii)
static void
rgephy_loop(struct mii_softc *sc)
{
+ struct rgephy_softc *rsc;
int i;
- PHY_WRITE(sc, RGEPHY_MII_BMCR, RGEPHY_BMCR_PDOWN);
- DELAY(1000);
+ rsc = (struct rgephy_softc *)sc;
+ if (rsc->mii_revision < 2) {
+ PHY_WRITE(sc, RGEPHY_MII_BMCR, RGEPHY_BMCR_PDOWN);
+ DELAY(1000);
+ }
for (i = 0; i < 15000; i++) {
if (!(PHY_READ(sc, RGEPHY_MII_BMSR) & RGEPHY_BMSR_LINK)) {
@@ -413,12 +474,11 @@ rgephy_loop(struct mii_softc *sc)
static void
rgephy_load_dspcode(struct mii_softc *sc)
{
+ struct rgephy_softc *rsc;
int val;
- uint16_t id2;
-
- id2 = PHY_READ(sc, MII_PHYIDR2);
- if (MII_REV(id2) > 1)
+ rsc = (struct rgephy_softc *)sc;
+ if (rsc->mii_revision >= 2)
return;
PHY_WRITE(sc, 31, 0x0001);
diff --git a/sys/dev/mii/rgephyreg.h b/sys/dev/mii/rgephyreg.h
index 0ce44df..fd0d32c 100644
--- a/sys/dev/mii/rgephyreg.h
+++ b/sys/dev/mii/rgephyreg.h
@@ -137,6 +137,17 @@
#define RGEPHY_EXTSTS_T_FD_CAP 0x2000 /* 1000base-T FD capable */
#define RGEPHY_EXTSTS_T_HD_CAP 0x1000 /* 1000base-T HD capable */
-
+/* RTL8211B(L) */
+#define RGEPHY_MII_SSR 0x11 /* PHY Specific status register */
+#define RGEPHY_SSR_S1000 0x8000 /* 1000Mbps */
+#define RGEPHY_SSR_S100 0x4000 /* 100Mbps */
+#define RGEPHY_SSR_S10 0x0000 /* 10Mbps */
+#define RGEPHY_SSR_SPD_MASK 0xc000
+#define RGEPHY_SSR_FDX 0x2000 /* full duplex */
+#define RGEPHY_SSR_PAGE_RECEIVED 0x1000 /* new page received */
+#define RGEPHY_SSR_SPD_DPLX_RESOLVED 0x0800 /* speed/duplex resolved */
+#define RGEPHY_SSR_LINK 0x0400 /* link up */
+#define RGEPHY_SSR_MDI_XOVER 0x0040 /* MDI crossover */
+#define RGEPHY_SSR_JABBER 0x0001 /* Jabber */
#endif /* _DEV_RGEPHY_MIIREG_H_ */
OpenPOWER on IntegriCloud