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
--- linux-2.4.21-mycable.orig/drivers/net/au1000_eth.c 2004-11-10 15:54:07.000000000 +0200
+++ linux-2.4.21-mycable/drivers/net/au1000_eth.c 2004-11-12 12:01:10.000000000 +0200
@@ -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)
{
--- linux-2.4.21-mycable.orig/drivers/net/au1000_eth.h 2004-11-10 15:54:07.000000000 +0200
+++ linux-2.4.21-mycable/drivers/net/au1000_eth.h 2004-11-11 17:59:21.000000000 +0200
@@ -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