[PATCH] Support for RTL8201BL PHY on Au1000

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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





[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux