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
|