aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorPyun YongHyeon <yongari@FreeBSD.org>2007-10-29 02:17:07 +0000
committerPyun YongHyeon <yongari@FreeBSD.org>2007-10-29 02:17:07 +0000
commit648bfbe6a72ad45d88d0f89f94f5d2b1b663013f (patch)
tree0b58e636a9bcc36cd768c63d3cd9b7ecf68927ce /sys
parent37fd5f0fed612d6e5b53876b938abdffae575bf2 (diff)
downloadsrc-648bfbe6a72ad45d88d0f89f94f5d2b1b663013f.tar.gz
src-648bfbe6a72ad45d88d0f89f94f5d2b1b663013f.zip
Add support for RealTek RTL8211B(L) PHY. It's based on the patch
made by Michael Eisele and the patch was slightly modified by me. With this change several NVIDIA ethernet controllers(e.g. MCP61) works. RTL8211B(L) is RealTek's new gigabit PHY. The PHY has several features including crossover correction, polarity correction as well as supporting triple speed(10/100/1000bps). Data transfer between MAC and PHY is via RGMII for 1000baseT, MII for 10baseT/100baseTX. Unfortunately, RealTek used the same model number for RTL8211B(L) PHY so there is no way to discriminate between RTL8211B(L) and its predecessors. ATM RTL8211B uses revision number 2 so checking the revision number seems to be only way to identify it. Obtained from: Michael Eisele [1] Tested by: clemens fischer < ino-qc AT spotteswoode DOT de DOT eu DOT org >
Notes
Notes: svn path=/head/; revision=173129
Diffstat (limited to 'sys')
-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 417fa635f1d7..aca7978b6961 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 0ce44dfcd9ac..fd0d32cb3152 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_ */