|
@@ -333,6 +333,7 @@ enum {
|
|
|
NvRegPowerState2 = 0x600,
|
|
|
#define NVREG_POWERSTATE2_POWERUP_MASK 0x0F11
|
|
|
#define NVREG_POWERSTATE2_POWERUP_REV_A3 0x0001
|
|
|
+#define NVREG_POWERSTATE2_PHY_RESET 0x0004
|
|
|
};
|
|
|
|
|
|
/* Big endian: should work, but is untested */
|
|
@@ -529,6 +530,7 @@ union ring_type {
|
|
|
#define PHY_REALTEK_INIT_REG4 0x14
|
|
|
#define PHY_REALTEK_INIT_REG5 0x18
|
|
|
#define PHY_REALTEK_INIT_REG6 0x11
|
|
|
+#define PHY_REALTEK_INIT_REG7 0x01
|
|
|
#define PHY_REALTEK_INIT1 0x0000
|
|
|
#define PHY_REALTEK_INIT2 0x8e00
|
|
|
#define PHY_REALTEK_INIT3 0x0001
|
|
@@ -537,6 +539,9 @@ union ring_type {
|
|
|
#define PHY_REALTEK_INIT6 0xf5c7
|
|
|
#define PHY_REALTEK_INIT7 0x1000
|
|
|
#define PHY_REALTEK_INIT8 0x0003
|
|
|
+#define PHY_REALTEK_INIT9 0x0008
|
|
|
+#define PHY_REALTEK_INIT10 0x0005
|
|
|
+#define PHY_REALTEK_INIT11 0x0200
|
|
|
#define PHY_REALTEK_INIT_MSK1 0x0003
|
|
|
|
|
|
#define PHY_GIGABIT 0x0100
|
|
@@ -1149,6 +1154,42 @@ static int phy_init(struct net_device *dev)
|
|
|
return PHY_ERROR;
|
|
|
}
|
|
|
}
|
|
|
+ if (np->phy_model == PHY_MODEL_REALTEK_8211 &&
|
|
|
+ np->phy_rev == PHY_REV_REALTEK_8211C) {
|
|
|
+ u32 powerstate = readl(base + NvRegPowerState2);
|
|
|
+
|
|
|
+ /* need to perform hw phy reset */
|
|
|
+ powerstate |= NVREG_POWERSTATE2_PHY_RESET;
|
|
|
+ writel(powerstate, base + NvRegPowerState2);
|
|
|
+ msleep(25);
|
|
|
+
|
|
|
+ powerstate &= ~NVREG_POWERSTATE2_PHY_RESET;
|
|
|
+ writel(powerstate, base + NvRegPowerState2);
|
|
|
+ msleep(25);
|
|
|
+
|
|
|
+ reg = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ);
|
|
|
+ reg |= PHY_REALTEK_INIT9;
|
|
|
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, reg)) {
|
|
|
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
|
|
|
+ return PHY_ERROR;
|
|
|
+ }
|
|
|
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT10)) {
|
|
|
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
|
|
|
+ return PHY_ERROR;
|
|
|
+ }
|
|
|
+ reg = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG7, MII_READ);
|
|
|
+ if (!(reg & PHY_REALTEK_INIT11)) {
|
|
|
+ reg |= PHY_REALTEK_INIT11;
|
|
|
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG7, reg)) {
|
|
|
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
|
|
|
+ return PHY_ERROR;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
|
|
|
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
|
|
|
+ return PHY_ERROR;
|
|
|
+ }
|
|
|
+ }
|
|
|
if (np->phy_model == PHY_MODEL_REALTEK_8201) {
|
|
|
if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 ||
|
|
|
np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 ||
|
|
@@ -1201,12 +1242,23 @@ static int phy_init(struct net_device *dev)
|
|
|
mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
|
|
|
mii_control |= BMCR_ANENABLE;
|
|
|
|
|
|
- /* reset the phy
|
|
|
- * (certain phys need bmcr to be setup with reset)
|
|
|
- */
|
|
|
- if (phy_reset(dev, mii_control)) {
|
|
|
- printk(KERN_INFO "%s: phy reset failed\n", pci_name(np->pci_dev));
|
|
|
- return PHY_ERROR;
|
|
|
+ if (np->phy_oui == PHY_OUI_REALTEK &&
|
|
|
+ np->phy_model == PHY_MODEL_REALTEK_8211 &&
|
|
|
+ np->phy_rev == PHY_REV_REALTEK_8211C) {
|
|
|
+ /* start autoneg since we already performed hw reset above */
|
|
|
+ mii_control |= BMCR_ANRESTART;
|
|
|
+ if (mii_rw(dev, np->phyaddr, MII_BMCR, mii_control)) {
|
|
|
+ printk(KERN_INFO "%s: phy init failed\n", pci_name(np->pci_dev));
|
|
|
+ return PHY_ERROR;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* reset the phy
|
|
|
+ * (certain phys need bmcr to be setup with reset)
|
|
|
+ */
|
|
|
+ if (phy_reset(dev, mii_control)) {
|
|
|
+ printk(KERN_INFO "%s: phy reset failed\n", pci_name(np->pci_dev));
|
|
|
+ return PHY_ERROR;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* phy vendor specific configuration */
|