[PATCH] prism54: fix potential race in reset scheduling
[linux-2.6] / drivers / net / ibm_emac / ibm_emac_phy.c
1 /*
2  * drivers/net/ibm_emac/ibm_emac_phy.c
3  *
4  * Driver for PowerPC 4xx on-chip ethernet controller, PHY support.
5  * Borrowed from sungem_phy.c, though I only kept the generic MII
6  * driver for now.
7  * 
8  * This file should be shared with other drivers or eventually
9  * merged as the "low level" part of miilib
10  * 
11  * (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org)
12  * (c) 2004-2005, Eugene Surovegin <ebs@ebshome.net>
13  *
14  */
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/types.h>
18 #include <linux/netdevice.h>
19 #include <linux/mii.h>
20 #include <linux/ethtool.h>
21 #include <linux/delay.h>
22
23 #include <asm/ocp.h>
24
25 #include "ibm_emac_phy.h"
26
27 static inline int phy_read(struct mii_phy *phy, int reg)
28 {
29         return phy->mdio_read(phy->dev, phy->address, reg);
30 }
31
32 static inline void phy_write(struct mii_phy *phy, int reg, int val)
33 {
34         phy->mdio_write(phy->dev, phy->address, reg, val);
35 }
36
37 int mii_reset_phy(struct mii_phy *phy)
38 {
39         int val;
40         int limit = 10000;
41
42         val = phy_read(phy, MII_BMCR);
43         val &= ~BMCR_ISOLATE;
44         val |= BMCR_RESET;
45         phy_write(phy, MII_BMCR, val);
46
47         udelay(300);
48
49         while (limit--) {
50                 val = phy_read(phy, MII_BMCR);
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);
57
58         return limit <= 0;
59 }
60
61 static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
62 {
63         int ctl, adv;
64
65         phy->autoneg = AUTONEG_ENABLE;
66         phy->speed = SPEED_10;
67         phy->duplex = DUPLEX_HALF;
68         phy->pause = phy->asym_pause = 0;
69         phy->advertising = advertise;
70
71         /* Setup standard advertise */
72         adv = phy_read(phy, MII_ADVERTISE);
73         if (adv < 0)
74                 return adv;
75         adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
76                  ADVERTISE_PAUSE_ASYM);
77         if (advertise & ADVERTISED_10baseT_Half)
78                 adv |= ADVERTISE_10HALF;
79         if (advertise & ADVERTISED_10baseT_Full)
80                 adv |= ADVERTISE_10FULL;
81         if (advertise & ADVERTISED_100baseT_Half)
82                 adv |= ADVERTISE_100HALF;
83         if (advertise & ADVERTISED_100baseT_Full)
84                 adv |= ADVERTISE_100FULL;
85         if (advertise & ADVERTISED_Pause)
86                 adv |= ADVERTISE_PAUSE_CAP;
87         if (advertise & ADVERTISED_Asym_Pause)
88                 adv |= ADVERTISE_PAUSE_ASYM;
89         phy_write(phy, MII_ADVERTISE, adv);
90
91         if (phy->features &
92             (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {
93                 adv = phy_read(phy, MII_CTRL1000);
94                 if (adv < 0)
95                         return adv;
96                 adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
97                 if (advertise & ADVERTISED_1000baseT_Full)
98                         adv |= ADVERTISE_1000FULL;
99                 if (advertise & ADVERTISED_1000baseT_Half)
100                         adv |= ADVERTISE_1000HALF;
101                 phy_write(phy, MII_CTRL1000, adv);
102         }
103
104         /* Start/Restart aneg */
105         ctl = phy_read(phy, MII_BMCR);
106         ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
107         phy_write(phy, MII_BMCR, ctl);
108
109         return 0;
110 }
111
112 static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
113 {
114         int ctl;
115
116         phy->autoneg = AUTONEG_DISABLE;
117         phy->speed = speed;
118         phy->duplex = fd;
119         phy->pause = phy->asym_pause = 0;
120
121         ctl = phy_read(phy, MII_BMCR);
122         if (ctl < 0)
123                 return ctl;
124         ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE);
125
126         /* First reset the PHY */
127         phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
128
129         /* Select speed & duplex */
130         switch (speed) {
131         case SPEED_10:
132                 break;
133         case SPEED_100:
134                 ctl |= BMCR_SPEED100;
135                 break;
136         case SPEED_1000:
137                 ctl |= BMCR_SPEED1000;
138                 break;
139         default:
140                 return -EINVAL;
141         }
142         if (fd == DUPLEX_FULL)
143                 ctl |= BMCR_FULLDPLX;
144         phy_write(phy, MII_BMCR, ctl);
145
146         return 0;
147 }
148
149 static int genmii_poll_link(struct mii_phy *phy)
150 {
151         int status;
152
153         /* Clear latched value with dummy read */
154         phy_read(phy, MII_BMSR);
155         status = phy_read(phy, MII_BMSR);
156         if (status < 0 || (status & BMSR_LSTATUS) == 0)
157                 return 0;
158         if (phy->autoneg == AUTONEG_ENABLE && !(status & BMSR_ANEGCOMPLETE))
159                 return 0;
160         return 1;
161 }
162
163 static int genmii_read_link(struct mii_phy *phy)
164 {
165         if (phy->autoneg == AUTONEG_ENABLE) {
166                 int glpa = 0;
167                 int lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE);
168                 if (lpa < 0)
169                         return lpa;
170
171                 if (phy->features &
172                     (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {
173                         int adv = phy_read(phy, MII_CTRL1000);
174                         glpa = phy_read(phy, MII_STAT1000);
175
176                         if (glpa < 0 || adv < 0)
177                                 return adv;
178
179                         glpa &= adv << 2;
180                 }
181
182                 phy->speed = SPEED_10;
183                 phy->duplex = DUPLEX_HALF;
184                 phy->pause = phy->asym_pause = 0;
185
186                 if (glpa & (LPA_1000FULL | LPA_1000HALF)) {
187                         phy->speed = SPEED_1000;
188                         if (glpa & LPA_1000FULL)
189                                 phy->duplex = DUPLEX_FULL;
190                 } else if (lpa & (LPA_100FULL | LPA_100HALF)) {
191                         phy->speed = SPEED_100;
192                         if (lpa & LPA_100FULL)
193                                 phy->duplex = DUPLEX_FULL;
194                 } else if (lpa & LPA_10FULL)
195                         phy->duplex = DUPLEX_FULL;
196
197                 if (phy->duplex == DUPLEX_FULL) {
198                         phy->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
199                         phy->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
200                 }
201         } else {
202                 int bmcr = phy_read(phy, MII_BMCR);
203                 if (bmcr < 0)
204                         return bmcr;
205
206                 if (bmcr & BMCR_FULLDPLX)
207                         phy->duplex = DUPLEX_FULL;
208                 else
209                         phy->duplex = DUPLEX_HALF;
210                 if (bmcr & BMCR_SPEED1000)
211                         phy->speed = SPEED_1000;
212                 else if (bmcr & BMCR_SPEED100)
213                         phy->speed = SPEED_100;
214                 else
215                         phy->speed = SPEED_10;
216
217                 phy->pause = phy->asym_pause = 0;
218         }
219         return 0;
220 }
221
222 /* Generic implementation for most 10/100/1000 PHYs */
223 static struct mii_phy_ops generic_phy_ops = {
224         .setup_aneg     = genmii_setup_aneg,
225         .setup_forced   = genmii_setup_forced,
226         .poll_link      = genmii_poll_link,
227         .read_link      = genmii_read_link
228 };
229
230 static struct mii_phy_def genmii_phy_def = {
231         .phy_id         = 0x00000000,
232         .phy_id_mask    = 0x00000000,
233         .name           = "Generic MII",
234         .ops            = &generic_phy_ops
235 };
236
237 /* CIS8201 */
238 #define MII_CIS8201_10BTCSR     0x16
239 #define  TENBTCSR_ECHO_DISABLE  0x2000
240 #define MII_CIS8201_EPCR        0x17
241 #define  EPCR_MODE_MASK         0x3000
242 #define  EPCR_GMII_MODE         0x0000
243 #define  EPCR_RGMII_MODE        0x1000
244 #define  EPCR_TBI_MODE          0x2000
245 #define  EPCR_RTBI_MODE         0x3000
246 #define MII_CIS8201_ACSR        0x1c
247 #define  ACSR_PIN_PRIO_SELECT   0x0004
248
249 static int cis8201_init(struct mii_phy *phy)
250 {
251         int epcr;
252
253         epcr = phy_read(phy, MII_CIS8201_EPCR);
254         if (epcr < 0)
255                 return epcr;
256
257         epcr &= ~EPCR_MODE_MASK;
258
259         switch (phy->mode) {
260         case PHY_MODE_TBI:
261                 epcr |= EPCR_TBI_MODE;
262                 break;
263         case PHY_MODE_RTBI:
264                 epcr |= EPCR_RTBI_MODE;
265                 break;
266         case PHY_MODE_GMII:
267                 epcr |= EPCR_GMII_MODE;
268                 break;
269         case PHY_MODE_RGMII:
270         default:
271                 epcr |= EPCR_RGMII_MODE;
272         }
273
274         phy_write(phy, MII_CIS8201_EPCR, epcr);
275         
276         /* MII regs override strap pins */
277         phy_write(phy, MII_CIS8201_ACSR, 
278                   phy_read(phy, MII_CIS8201_ACSR) | ACSR_PIN_PRIO_SELECT);
279
280         /* Disable TX_EN -> CRS echo mode, otherwise 10/HDX doesn't work */
281         phy_write(phy, MII_CIS8201_10BTCSR,
282                   phy_read(phy, MII_CIS8201_10BTCSR) | TENBTCSR_ECHO_DISABLE);
283
284         return 0;
285 }
286
287 static struct mii_phy_ops cis8201_phy_ops = {
288         .init           = cis8201_init,
289         .setup_aneg     = genmii_setup_aneg,
290         .setup_forced   = genmii_setup_forced,
291         .poll_link      = genmii_poll_link,
292         .read_link      = genmii_read_link
293 };
294
295 static struct mii_phy_def cis8201_phy_def = {
296         .phy_id         = 0x000fc410,
297         .phy_id_mask    = 0x000ffff0,
298         .name           = "CIS8201 Gigabit Ethernet",
299         .ops            = &cis8201_phy_ops
300 };
301
302 static struct mii_phy_def *mii_phy_table[] = {
303         &cis8201_phy_def,
304         &genmii_phy_def,
305         NULL
306 };
307
308 int mii_phy_probe(struct mii_phy *phy, int address)
309 {
310         struct mii_phy_def *def;
311         int i;
312         u32 id;
313
314         phy->autoneg = AUTONEG_DISABLE;
315         phy->advertising = 0;
316         phy->address = address;
317         phy->speed = SPEED_10;
318         phy->duplex = DUPLEX_HALF;
319         phy->pause = phy->asym_pause = 0;
320
321         /* Take PHY out of isolate mode and reset it. */
322         if (mii_reset_phy(phy))
323                 return -ENODEV;
324
325         /* Read ID and find matching entry */
326         id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2);
327         for (i = 0; (def = mii_phy_table[i]) != NULL; i++)
328                 if ((id & def->phy_id_mask) == def->phy_id)
329                         break;
330         /* Should never be NULL (we have a generic entry), but... */
331         if (!def)
332                 return -ENODEV;
333
334         phy->def = def;
335
336         /* Determine PHY features if needed */
337         phy->features = def->features;
338         if (!phy->features) {
339                 u16 bmsr = phy_read(phy, MII_BMSR);
340                 if (bmsr & BMSR_ANEGCAPABLE)
341                         phy->features |= SUPPORTED_Autoneg;
342                 if (bmsr & BMSR_10HALF)
343                         phy->features |= SUPPORTED_10baseT_Half;
344                 if (bmsr & BMSR_10FULL)
345                         phy->features |= SUPPORTED_10baseT_Full;
346                 if (bmsr & BMSR_100HALF)
347                         phy->features |= SUPPORTED_100baseT_Half;
348                 if (bmsr & BMSR_100FULL)
349                         phy->features |= SUPPORTED_100baseT_Full;
350                 if (bmsr & BMSR_ESTATEN) {
351                         u16 esr = phy_read(phy, MII_ESTATUS);
352                         if (esr & ESTATUS_1000_TFULL)
353                                 phy->features |= SUPPORTED_1000baseT_Full;
354                         if (esr & ESTATUS_1000_THALF)
355                                 phy->features |= SUPPORTED_1000baseT_Half;
356                 }
357                 phy->features |= SUPPORTED_MII;
358         }
359
360         /* Setup default advertising */
361         phy->advertising = phy->features;
362
363         return 0;
364 }
365
366 MODULE_LICENSE("GPL");