diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/ibm_emac/ibm_emac_phy.c | 60 |
1 files changed, 45 insertions, 15 deletions
diff --git a/drivers/net/ibm_emac/ibm_emac_phy.c b/drivers/net/ibm_emac/ibm_emac_phy.c index 9074f76ee2bf..e57862b34cae 100644 --- a/drivers/net/ibm_emac/ibm_emac_phy.c +++ b/drivers/net/ibm_emac/ibm_emac_phy.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <asm/ocp.h> | 23 | #include <asm/ocp.h> |
24 | 24 | ||
25 | #include "ibm_emac_core.h" | ||
25 | #include "ibm_emac_phy.h" | 26 | #include "ibm_emac_phy.h" |
26 | 27 | ||
27 | static inline int phy_read(struct mii_phy *phy, int reg) | 28 | static inline int phy_read(struct mii_phy *phy, int reg) |
@@ -34,11 +35,39 @@ static inline void phy_write(struct mii_phy *phy, int reg, int val) | |||
34 | phy->mdio_write(phy->dev, phy->address, reg, val); | 35 | phy->mdio_write(phy->dev, phy->address, reg, val); |
35 | } | 36 | } |
36 | 37 | ||
37 | int mii_reset_phy(struct mii_phy *phy) | 38 | /* |
39 | * polls MII_BMCR until BMCR_RESET bit clears or operation times out. | ||
40 | * | ||
41 | * returns: | ||
42 | * >= 0 => success, value in BMCR returned to caller | ||
43 | * -EBUSY => failure, RESET bit never cleared | ||
44 | * otherwise => failure, lower level PHY read failed | ||
45 | */ | ||
46 | static int mii_spin_reset_complete(struct mii_phy *phy) | ||
38 | { | 47 | { |
39 | int val; | 48 | int val; |
40 | int limit = 10000; | 49 | int limit = 10000; |
41 | 50 | ||
51 | while (limit--) { | ||
52 | val = phy_read(phy, MII_BMCR); | ||
53 | if (val >= 0 && !(val & BMCR_RESET)) | ||
54 | return val; /* success */ | ||
55 | udelay(10); | ||
56 | } | ||
57 | if (val & BMCR_RESET) | ||
58 | val = -EBUSY; | ||
59 | |||
60 | if (net_ratelimit()) | ||
61 | printk(KERN_ERR "emac%d: PHY reset timeout (%d)\n", | ||
62 | ((struct ocp_enet_private *)phy->dev->priv)->def->index, | ||
63 | val); | ||
64 | return val; | ||
65 | } | ||
66 | |||
67 | int mii_reset_phy(struct mii_phy *phy) | ||
68 | { | ||
69 | int val; | ||
70 | |||
42 | val = phy_read(phy, MII_BMCR); | 71 | val = phy_read(phy, MII_BMCR); |
43 | val &= ~BMCR_ISOLATE; | 72 | val &= ~BMCR_ISOLATE; |
44 | val |= BMCR_RESET; | 73 | val |= BMCR_RESET; |
@@ -46,16 +75,11 @@ int mii_reset_phy(struct mii_phy *phy) | |||
46 | 75 | ||
47 | udelay(300); | 76 | udelay(300); |
48 | 77 | ||
49 | while (limit--) { | 78 | val = mii_spin_reset_complete(phy); |
50 | val = phy_read(phy, MII_BMCR); | 79 | if (val >= 0 && (val & BMCR_ISOLATE)) |
51 | if (val >= 0 && (val & BMCR_RESET) == 0) | ||
52 | break; | ||
53 | udelay(10); | ||
54 | } | ||
55 | if ((val & BMCR_ISOLATE) && limit > 0) | ||
56 | phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE); | 80 | phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE); |
57 | 81 | ||
58 | return limit <= 0; | 82 | return val < 0; |
59 | } | 83 | } |
60 | 84 | ||
61 | static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) | 85 | static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) |
@@ -102,8 +126,14 @@ static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) | |||
102 | } | 126 | } |
103 | 127 | ||
104 | /* Start/Restart aneg */ | 128 | /* Start/Restart aneg */ |
105 | ctl = phy_read(phy, MII_BMCR); | 129 | /* on some PHYs (e.g. National DP83843) a write to MII_ADVERTISE |
106 | ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); | 130 | * causes BMCR_RESET to be set on the next read of MII_BMCR, which |
131 | * if not checked for causes the PHY to be reset below */ | ||
132 | ctl = mii_spin_reset_complete(phy); | ||
133 | if (ctl < 0) | ||
134 | return ctl; | ||
135 | |||
136 | ctl |= BMCR_ANENABLE | BMCR_ANRESTART; | ||
107 | phy_write(phy, MII_BMCR, ctl); | 137 | phy_write(phy, MII_BMCR, ctl); |
108 | 138 | ||
109 | return 0; | 139 | return 0; |
@@ -118,13 +148,13 @@ static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) | |||
118 | phy->duplex = fd; | 148 | phy->duplex = fd; |
119 | phy->pause = phy->asym_pause = 0; | 149 | phy->pause = phy->asym_pause = 0; |
120 | 150 | ||
151 | /* First reset the PHY */ | ||
152 | mii_reset_phy(phy); | ||
153 | |||
121 | ctl = phy_read(phy, MII_BMCR); | 154 | ctl = phy_read(phy, MII_BMCR); |
122 | if (ctl < 0) | 155 | if (ctl < 0) |
123 | return ctl; | 156 | return ctl; |
124 | ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE); | 157 | ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE | BMCR_SPEED1000); |
125 | |||
126 | /* First reset the PHY */ | ||
127 | phy_write(phy, MII_BMCR, ctl | BMCR_RESET); | ||
128 | 158 | ||
129 | /* Select speed & duplex */ | 159 | /* Select speed & duplex */ |
130 | switch (speed) { | 160 | switch (speed) { |