Support for RTL8201BL PHY on Au1000
Subsystems (2)
PATCH 1/1 Support for RTL8201BL PHY on Au1000
Hello All,
Attached is a patch to support the RTL8201BL Phyceiver on the AMD Alchemy Au1x, if anyone is interested. We use it here for our own custom design.
Thank you,
Gilad Rom
Romat Telecom
drivers/net/au1000_eth.c 2004-11-12 12:01:10.000000000 +0200 renamed from drivers/net/au1000_eth.c 2004-11-10 15:54:07.000000000 +0200 +0 -0
@@ -330,8 +330,98 @@
{
return 0;
}
+int rtl8201_init(struct net_device *dev, int phy_addr) +{
+ s16 data;
+
+ /* Stop auto-negotiation */ + data = mdio_read(dev, phy_addr, MII_CONTROL); + mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO); + + /* Set advertisement to 10/100 and Half/Full duplex + * (full capabilities) */ + data = mdio_read(dev, phy_addr, MII_ANADV); + data |= MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_T_FDX | MII_NWAY_T; + mdio_write(dev, phy_addr, MII_ANADV, data); + + /* Restart auto-negotiation */ + data = mdio_read(dev, phy_addr, MII_CONTROL); + data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO; + mdio_write(dev, phy_addr, MII_CONTROL, data);
+
+ if (au1000_debug > 4) dump_mii(dev, phy_addr);
+ return 0;
+}
+
+int rtl8201_reset(struct net_device *dev, int phy_addr) +{
+ s16 mii_control, timeout;
+
+ if (au1000_debug > 4) {
+ printk("rtl8201_reset\n");
+ dump_mii(dev, phy_addr);
+ }
+
+ mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+ mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
+ mdelay(1);
+ for (timeout = 100; timeout > 0; --timeout) {+ mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+ if ((mii_control & MII_CNTL_RESET) == 0)
+ break;
+ mdelay(1);
+ }
+ if (mii_control & MII_CNTL_RESET) {
+ printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
+ return -1;
+ }
+ return 0;
+}
+
+int
+rtl8201_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed) +{
+ u16 mii_data;
+ struct au1000_private *aup;
+
+ if (!dev) {
+ printk(KERN_ERR "rtl8201_status error: NULL dev\n");
+ return -1;
+ }
+
+ aup = (struct au1000_private *) dev->priv;
+ mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
+
+ if (mii_data & MII_STAT_LINK) {
+ *link = 1;
+ mii_data = mdio_read(dev, aup->phy_addr, MII_ANLPAR);
+
+ if (mii_data & MII_RTL_PHY_STAT_SPD) {
+ if (mii_data & MII_RTL_PHY_STAT_FDX) {
+ *speed = IF_PORT_100BASEFX;
+ dev->if_port = IF_PORT_100BASEFX;
+ }
+ else {
+ *speed = IF_PORT_100BASETX;
+ dev->if_port = IF_PORT_100BASETX;
+ }
+ }
+ else {
+ *speed = IF_PORT_10BASET;
+ dev->if_port = IF_PORT_10BASET;
+ }
+
+ }
+ else {
+ *link = 0; + *speed = 0; + dev->if_port = IF_PORT_UNKNOWN;
+ }
+ return 0;
+}
+
int am79c874_init(struct net_device *dev, int phy_addr) {
s16 data;
@@ -627,8 +717,14 @@
am79c874_reset,
am79c874_status,
};
+struct phy_ops rtl8201_ops = {
+ rtl8201_init, + rtl8201_reset, + rtl8201_status,
+};
+
struct phy_ops am79c901_ops = {
am79c901_init,
am79c901_reset,
am79c901_status,
@@ -671,8 +767,9 @@
{"Broadcom BCM5221 10/100 BaseT PHY",0x0040,0x61e4, &bcm_5201_ops,0}, {"Broadcom BCM5222 10/100 BaseT PHY",0x0040,0x6322, &bcm_5201_ops,1}, {"AMD 79C901 HomePNA PHY",0x0000,0x35c8, &am79c901_ops,0}, {"AMD 79C874 10/100 BaseT PHY",0x0022,0x561b, &am79c874_ops,0},
+ {"RealTek 8201BL 10/100 BaseT Phyceiver",0x0000,0x8201, &rtl8201_ops, 0}, {"LSI 80227 10/100 BaseT PHY",0x0016,0xf840, &lsi_80227_ops,0}, {"Intel LXT971A Dual Speed PHY",0x0013,0x78e2, &lxt971a_ops,0}, {"Kendin KS8995M 10/100 BaseT PHY",0x0022,0x1450, &ks8995m_ops,0},
#ifdef CONFIG_MIPS_BOSPORUS
@@ -801,11 +898,9 @@
static int mii_probe (struct net_device * dev)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv; int phy_addr;
-#ifdef CONFIG_MIPS_BOSPORUS
int phy_found=0;
-#endif
/* search for total of 32 possible mii phy addresses */ for (phy_addr = 0; phy_addr < 32; phy_addr++) {
u16 mii_status;
@@ -820,9 +915,9 @@
}
#endif
mii_status = mdio_read(dev, phy_addr, MII_STATUS);
- if (mii_status == 0xffff || mii_status == 0x0000) + if (mii_status == 0xffff || mii_status == 0x0000)
/* the mii is not accessable, try next one */
continue;
phy_id0 = mdio_read(dev, phy_addr, MII_PHY_ID0);
@@ -836,11 +931,9 @@
printk(KERN_INFO "%s: %s at phy address %d\n",
dev->name, mii_chip_table[i].name,
phy_addr);
-#ifdef CONFIG_MIPS_BOSPORUS
phy_found = 1;
-#endif
mii_phy->chip_info = mii_chip_table+i;
aup->phy_addr = phy_addr;
aup->phy_ops = mii_chip_table[i].phy_ops;
aup->phy_ops->phy_init(dev,phy_addr);
@@ -932,11 +1025,15 @@
dev->name); return -1;
}
- printk(KERN_INFO "%s: Using %s as default\n",
+ if ( (!phy_found) ) {
+ printk(KERN_INFO "%s: No PHY information available!\n",
+ dev->name);
+ } else {
+ printk(KERN_INFO "%s: Using %s as default\n", dev->name, aup->mii->chip_info->name);
-
+ }
return 0;
}
@@ -1361,8 +1458,9 @@
}
au_sync();
aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed);
+
control = MAC_DISABLE_RX_OWN | MAC_RX_ENABLE | MAC_TX_ENABLE;
#ifndef CONFIG_CPU_LITTLE_ENDIAN
control |= MAC_BIG_ENDIAN;
#endif
@@ -1428,9 +1526,8 @@
aup->timer.expires = RUN_AT((1*HZ)); aup->timer.data = (unsigned long)dev; aup->timer.function = &au1000_timer; /* timer handler */ add_timer(&aup->timer);
-
}
static int au1000_open(struct net_device *dev)
{
drivers/net/au1000_eth.h 2004-11-11 17:59:21.000000000 +0200 renamed from drivers/net/au1000_eth.h 2004-11-10 15:54:07.000000000 +0200 +0 -0
@@ -129,8 +129,12 @@
/* amd phy status register */
#define MII_AMD_PHY_STAT_FDX 0x0800
#define MII_AMD_PHY_STAT_SPD 0x0400
+/* realtek phy status register */
+#define MII_RTL_PHY_STAT_FDX 0x0100
+#define MII_RTL_PHY_STAT_SPD 0x0080
+
/* intel phy status register */
#define MII_INTEL_PHY_STAT_FDX 0x0200
#define MII_INTEL_PHY_STAT_SPD 0x4000