Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6] / drivers / net / phy / broadcom.c
1 /*
2  *      drivers/net/phy/broadcom.c
3  *
4  *      Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet
5  *      transceivers.
6  *
7  *      Copyright (c) 2006  Maciej W. Rozycki
8  *
9  *      Inspired by code written by Amy Fong.
10  *
11  *      This program is free software; you can redistribute it and/or
12  *      modify it under the terms of the GNU General Public License
13  *      as published by the Free Software Foundation; either version
14  *      2 of the License, or (at your option) any later version.
15  */
16
17 #include <linux/module.h>
18 #include <linux/phy.h>
19
20 #define MII_BCM54XX_ECR         0x10    /* BCM54xx extended control register */
21 #define MII_BCM54XX_ECR_IM      0x1000  /* Interrupt mask */
22 #define MII_BCM54XX_ECR_IF      0x0800  /* Interrupt force */
23
24 #define MII_BCM54XX_ESR         0x11    /* BCM54xx extended status register */
25 #define MII_BCM54XX_ESR_IS      0x1000  /* Interrupt status */
26
27 #define MII_BCM54XX_EXP_DATA    0x15    /* Expansion register data */
28 #define MII_BCM54XX_EXP_SEL     0x17    /* Expansion register select */
29 #define MII_BCM54XX_EXP_SEL_SSD 0x0e00  /* Secondary SerDes select */
30 #define MII_BCM54XX_EXP_SEL_ER  0x0f00  /* Expansion register select */
31
32 #define MII_BCM54XX_AUX_CTL     0x18    /* Auxiliary control register */
33 #define MII_BCM54XX_ISR         0x1a    /* BCM54xx interrupt status register */
34 #define MII_BCM54XX_IMR         0x1b    /* BCM54xx interrupt mask register */
35 #define MII_BCM54XX_INT_CRCERR  0x0001  /* CRC error */
36 #define MII_BCM54XX_INT_LINK    0x0002  /* Link status changed */
37 #define MII_BCM54XX_INT_SPEED   0x0004  /* Link speed change */
38 #define MII_BCM54XX_INT_DUPLEX  0x0008  /* Duplex mode changed */
39 #define MII_BCM54XX_INT_LRS     0x0010  /* Local receiver status changed */
40 #define MII_BCM54XX_INT_RRS     0x0020  /* Remote receiver status changed */
41 #define MII_BCM54XX_INT_SSERR   0x0040  /* Scrambler synchronization error */
42 #define MII_BCM54XX_INT_UHCD    0x0080  /* Unsupported HCD negotiated */
43 #define MII_BCM54XX_INT_NHCD    0x0100  /* No HCD */
44 #define MII_BCM54XX_INT_NHCDL   0x0200  /* No HCD link */
45 #define MII_BCM54XX_INT_ANPR    0x0400  /* Auto-negotiation page received */
46 #define MII_BCM54XX_INT_LC      0x0800  /* All counters below 128 */
47 #define MII_BCM54XX_INT_HC      0x1000  /* Counter above 32768 */
48 #define MII_BCM54XX_INT_MDIX    0x2000  /* MDIX status change */
49 #define MII_BCM54XX_INT_PSERR   0x4000  /* Pair swap error */
50
51 #define MII_BCM54XX_SHD         0x1c    /* 0x1c shadow registers */
52 #define MII_BCM54XX_SHD_WRITE   0x8000
53 #define MII_BCM54XX_SHD_VAL(x)  ((x & 0x1f) << 10)
54 #define MII_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0)
55
56 /*
57  * Broadcom LED source encodings.  These are used in BCM5461, BCM5481,
58  * BCM5482, and possibly some others.
59  */
60 #define BCM_LED_SRC_LINKSPD1    0x0
61 #define BCM_LED_SRC_LINKSPD2    0x1
62 #define BCM_LED_SRC_XMITLED     0x2
63 #define BCM_LED_SRC_ACTIVITYLED 0x3
64 #define BCM_LED_SRC_FDXLED      0x4
65 #define BCM_LED_SRC_SLAVE       0x5
66 #define BCM_LED_SRC_INTR        0x6
67 #define BCM_LED_SRC_QUALITY     0x7
68 #define BCM_LED_SRC_RCVLED      0x8
69 #define BCM_LED_SRC_MULTICOLOR1 0xa
70 #define BCM_LED_SRC_OPENSHORT   0xb
71 #define BCM_LED_SRC_OFF         0xe     /* Tied high */
72 #define BCM_LED_SRC_ON          0xf     /* Tied low */
73
74 /*
75  * BCM5482: Shadow registers
76  * Shadow values go into bits [14:10] of register 0x1c to select a shadow
77  * register to access.
78  */
79 #define BCM5482_SHD_LEDS1       0x0d    /* 01101: LED Selector 1 */
80                                         /* LED3 / ~LINKSPD[2] selector */
81 #define BCM5482_SHD_LEDS1_LED3(src)     ((src & 0xf) << 4)
82                                         /* LED1 / ~LINKSPD[1] selector */
83 #define BCM5482_SHD_LEDS1_LED1(src)     ((src & 0xf) << 0)
84 #define BCM5482_SHD_SSD         0x14    /* 10100: Secondary SerDes control */
85 #define BCM5482_SHD_SSD_LEDM    0x0008  /* SSD LED Mode enable */
86 #define BCM5482_SHD_SSD_EN      0x0001  /* SSD enable */
87 #define BCM5482_SHD_MODE        0x1f    /* 11111: Mode Control Register */
88 #define BCM5482_SHD_MODE_1000BX 0x0001  /* Enable 1000BASE-X registers */
89
90 /*
91  * BCM5482: Secondary SerDes registers
92  */
93 #define BCM5482_SSD_1000BX_CTL          0x00    /* 1000BASE-X Control */
94 #define BCM5482_SSD_1000BX_CTL_PWRDOWN  0x0800  /* Power-down SSD */
95 #define BCM5482_SSD_SGMII_SLAVE         0x15    /* SGMII Slave Register */
96 #define BCM5482_SSD_SGMII_SLAVE_EN      0x0002  /* Slave mode enable */
97 #define BCM5482_SSD_SGMII_SLAVE_AD      0x0001  /* Slave auto-detection */
98
99 /*
100  * Device flags for PHYs that can be configured for different operating
101  * modes.
102  */
103 #define PHY_BCM_FLAGS_VALID             0x80000000
104 #define PHY_BCM_FLAGS_INTF_XAUI         0x00000020
105 #define PHY_BCM_FLAGS_INTF_SGMII        0x00000010
106 #define PHY_BCM_FLAGS_MODE_1000BX       0x00000002
107 #define PHY_BCM_FLAGS_MODE_COPPER       0x00000001
108
109 MODULE_DESCRIPTION("Broadcom PHY driver");
110 MODULE_AUTHOR("Maciej W. Rozycki");
111 MODULE_LICENSE("GPL");
112
113 /*
114  * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T
115  * 0x1c shadow registers.
116  */
117 static int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow)
118 {
119         phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
120         return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
121 }
122
123 static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val)
124 {
125         return phy_write(phydev, MII_BCM54XX_SHD,
126                          MII_BCM54XX_SHD_WRITE |
127                          MII_BCM54XX_SHD_VAL(shadow) |
128                          MII_BCM54XX_SHD_DATA(val));
129 }
130
131 /*
132  * Indirect register access functions for the Expansion Registers
133  * and Secondary SerDes registers (when sec_serdes=1).
134  */
135 static int bcm54xx_exp_read(struct phy_device *phydev,
136                             int sec_serdes, u8 regnum)
137 {
138         int val;
139
140         phy_write(phydev, MII_BCM54XX_EXP_SEL,
141                   (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD :
142                                 MII_BCM54XX_EXP_SEL_ER) |
143                   regnum);
144         val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
145         phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
146
147         return val;
148 }
149
150 static int bcm54xx_exp_write(struct phy_device *phydev,
151                              int sec_serdes, u8 regnum, u16 val)
152 {
153         int ret;
154
155         phy_write(phydev, MII_BCM54XX_EXP_SEL,
156                   (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD :
157                                 MII_BCM54XX_EXP_SEL_ER) |
158                   regnum);
159         ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
160         phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
161
162         return ret;
163 }
164
165 static int bcm54xx_config_init(struct phy_device *phydev)
166 {
167         int reg, err;
168
169         reg = phy_read(phydev, MII_BCM54XX_ECR);
170         if (reg < 0)
171                 return reg;
172
173         /* Mask interrupts globally.  */
174         reg |= MII_BCM54XX_ECR_IM;
175         err = phy_write(phydev, MII_BCM54XX_ECR, reg);
176         if (err < 0)
177                 return err;
178
179         /* Unmask events we are interested in.  */
180         reg = ~(MII_BCM54XX_INT_DUPLEX |
181                 MII_BCM54XX_INT_SPEED |
182                 MII_BCM54XX_INT_LINK);
183         err = phy_write(phydev, MII_BCM54XX_IMR, reg);
184         if (err < 0)
185                 return err;
186         return 0;
187 }
188
189 static int bcm5482_config_init(struct phy_device *phydev)
190 {
191         int err, reg;
192
193         err = bcm54xx_config_init(phydev);
194
195         if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
196                 /*
197                  * Enable secondary SerDes and its use as an LED source
198                  */
199                 reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_SSD);
200                 bcm54xx_shadow_write(phydev, BCM5482_SHD_SSD,
201                                      reg |
202                                      BCM5482_SHD_SSD_LEDM |
203                                      BCM5482_SHD_SSD_EN);
204
205                 /*
206                  * Enable SGMII slave mode and auto-detection
207                  */
208                 reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_SGMII_SLAVE);
209                 bcm54xx_exp_write(phydev, 1, BCM5482_SSD_SGMII_SLAVE,
210                                   reg |
211                                   BCM5482_SSD_SGMII_SLAVE_EN |
212                                   BCM5482_SSD_SGMII_SLAVE_AD);
213
214                 /*
215                  * Disable secondary SerDes powerdown
216                  */
217                 reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_1000BX_CTL);
218                 bcm54xx_exp_write(phydev, 1, BCM5482_SSD_1000BX_CTL,
219                                   reg & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
220
221                 /*
222                  * Select 1000BASE-X register set (primary SerDes)
223                  */
224                 reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_MODE);
225                 bcm54xx_shadow_write(phydev, BCM5482_SHD_MODE,
226                                      reg | BCM5482_SHD_MODE_1000BX);
227
228                 /*
229                  * LED1=ACTIVITYLED, LED3=LINKSPD[2]
230                  * (Use LED1 as secondary SerDes ACTIVITY LED)
231                  */
232                 bcm54xx_shadow_write(phydev, BCM5482_SHD_LEDS1,
233                         BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
234                         BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2));
235
236                 /*
237                  * Auto-negotiation doesn't seem to work quite right
238                  * in this mode, so we disable it and force it to the
239                  * right speed/duplex setting.  Only 'link status'
240                  * is important.
241                  */
242                 phydev->autoneg = AUTONEG_DISABLE;
243                 phydev->speed = SPEED_1000;
244                 phydev->duplex = DUPLEX_FULL;
245         }
246
247         return err;
248 }
249
250 static int bcm5482_read_status(struct phy_device *phydev)
251 {
252         int err;
253
254         err = genphy_read_status(phydev);
255
256         if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
257                 /*
258                  * Only link status matters for 1000Base-X mode, so force
259                  * 1000 Mbit/s full-duplex status
260                  */
261                 if (phydev->link) {
262                         phydev->speed = SPEED_1000;
263                         phydev->duplex = DUPLEX_FULL;
264                 }
265         }
266
267         return err;
268 }
269
270 static int bcm54xx_ack_interrupt(struct phy_device *phydev)
271 {
272         int reg;
273
274         /* Clear pending interrupts.  */
275         reg = phy_read(phydev, MII_BCM54XX_ISR);
276         if (reg < 0)
277                 return reg;
278
279         return 0;
280 }
281
282 static int bcm54xx_config_intr(struct phy_device *phydev)
283 {
284         int reg, err;
285
286         reg = phy_read(phydev, MII_BCM54XX_ECR);
287         if (reg < 0)
288                 return reg;
289
290         if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
291                 reg &= ~MII_BCM54XX_ECR_IM;
292         else
293                 reg |= MII_BCM54XX_ECR_IM;
294
295         err = phy_write(phydev, MII_BCM54XX_ECR, reg);
296         return err;
297 }
298
299 static int bcm5481_config_aneg(struct phy_device *phydev)
300 {
301         int ret;
302
303         /* Aneg firsly. */
304         ret = genphy_config_aneg(phydev);
305
306         /* Then we can set up the delay. */
307         if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
308                 u16 reg;
309
310                 /*
311                  * There is no BCM5481 specification available, so down
312                  * here is everything we know about "register 0x18". This
313                  * at least helps BCM5481 to successfuly receive packets
314                  * on MPC8360E-RDK board. Peter Barada <peterb@logicpd.com>
315                  * says: "This sets delay between the RXD and RXC signals
316                  * instead of using trace lengths to achieve timing".
317                  */
318
319                 /* Set RDX clk delay. */
320                 reg = 0x7 | (0x7 << 12);
321                 phy_write(phydev, 0x18, reg);
322
323                 reg = phy_read(phydev, 0x18);
324                 /* Set RDX-RXC skew. */
325                 reg |= (1 << 8);
326                 /* Write bits 14:0. */
327                 reg |= (1 << 15);
328                 phy_write(phydev, 0x18, reg);
329         }
330
331         return ret;
332 }
333
334 static struct phy_driver bcm5411_driver = {
335         .phy_id         = 0x00206070,
336         .phy_id_mask    = 0xfffffff0,
337         .name           = "Broadcom BCM5411",
338         .features       = PHY_GBIT_FEATURES,
339         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
340         .config_init    = bcm54xx_config_init,
341         .config_aneg    = genphy_config_aneg,
342         .read_status    = genphy_read_status,
343         .ack_interrupt  = bcm54xx_ack_interrupt,
344         .config_intr    = bcm54xx_config_intr,
345         .driver         = { .owner = THIS_MODULE },
346 };
347
348 static struct phy_driver bcm5421_driver = {
349         .phy_id         = 0x002060e0,
350         .phy_id_mask    = 0xfffffff0,
351         .name           = "Broadcom BCM5421",
352         .features       = PHY_GBIT_FEATURES,
353         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
354         .config_init    = bcm54xx_config_init,
355         .config_aneg    = genphy_config_aneg,
356         .read_status    = genphy_read_status,
357         .ack_interrupt  = bcm54xx_ack_interrupt,
358         .config_intr    = bcm54xx_config_intr,
359         .driver         = { .owner = THIS_MODULE },
360 };
361
362 static struct phy_driver bcm5461_driver = {
363         .phy_id         = 0x002060c0,
364         .phy_id_mask    = 0xfffffff0,
365         .name           = "Broadcom BCM5461",
366         .features       = PHY_GBIT_FEATURES,
367         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
368         .config_init    = bcm54xx_config_init,
369         .config_aneg    = genphy_config_aneg,
370         .read_status    = genphy_read_status,
371         .ack_interrupt  = bcm54xx_ack_interrupt,
372         .config_intr    = bcm54xx_config_intr,
373         .driver         = { .owner = THIS_MODULE },
374 };
375
376 static struct phy_driver bcm5464_driver = {
377         .phy_id         = 0x002060b0,
378         .phy_id_mask    = 0xfffffff0,
379         .name           = "Broadcom BCM5464",
380         .features       = PHY_GBIT_FEATURES,
381         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
382         .config_init    = bcm54xx_config_init,
383         .config_aneg    = genphy_config_aneg,
384         .read_status    = genphy_read_status,
385         .ack_interrupt  = bcm54xx_ack_interrupt,
386         .config_intr    = bcm54xx_config_intr,
387         .driver         = { .owner = THIS_MODULE },
388 };
389
390 static struct phy_driver bcm5481_driver = {
391         .phy_id         = 0x0143bca0,
392         .phy_id_mask    = 0xfffffff0,
393         .name           = "Broadcom BCM5481",
394         .features       = PHY_GBIT_FEATURES,
395         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
396         .config_init    = bcm54xx_config_init,
397         .config_aneg    = bcm5481_config_aneg,
398         .read_status    = genphy_read_status,
399         .ack_interrupt  = bcm54xx_ack_interrupt,
400         .config_intr    = bcm54xx_config_intr,
401         .driver         = { .owner = THIS_MODULE },
402 };
403
404 static struct phy_driver bcm5482_driver = {
405         .phy_id         = 0x0143bcb0,
406         .phy_id_mask    = 0xfffffff0,
407         .name           = "Broadcom BCM5482",
408         .features       = PHY_GBIT_FEATURES,
409         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
410         .config_init    = bcm5482_config_init,
411         .config_aneg    = genphy_config_aneg,
412         .read_status    = bcm5482_read_status,
413         .ack_interrupt  = bcm54xx_ack_interrupt,
414         .config_intr    = bcm54xx_config_intr,
415         .driver         = { .owner = THIS_MODULE },
416 };
417
418 static int __init broadcom_init(void)
419 {
420         int ret;
421
422         ret = phy_driver_register(&bcm5411_driver);
423         if (ret)
424                 goto out_5411;
425         ret = phy_driver_register(&bcm5421_driver);
426         if (ret)
427                 goto out_5421;
428         ret = phy_driver_register(&bcm5461_driver);
429         if (ret)
430                 goto out_5461;
431         ret = phy_driver_register(&bcm5464_driver);
432         if (ret)
433                 goto out_5464;
434         ret = phy_driver_register(&bcm5481_driver);
435         if (ret)
436                 goto out_5481;
437         ret = phy_driver_register(&bcm5482_driver);
438         if (ret)
439                 goto out_5482;
440         return ret;
441
442 out_5482:
443         phy_driver_unregister(&bcm5481_driver);
444 out_5481:
445         phy_driver_unregister(&bcm5464_driver);
446 out_5464:
447         phy_driver_unregister(&bcm5461_driver);
448 out_5461:
449         phy_driver_unregister(&bcm5421_driver);
450 out_5421:
451         phy_driver_unregister(&bcm5411_driver);
452 out_5411:
453         return ret;
454 }
455
456 static void __exit broadcom_exit(void)
457 {
458         phy_driver_unregister(&bcm5482_driver);
459         phy_driver_unregister(&bcm5481_driver);
460         phy_driver_unregister(&bcm5464_driver);
461         phy_driver_unregister(&bcm5461_driver);
462         phy_driver_unregister(&bcm5421_driver);
463         phy_driver_unregister(&bcm5411_driver);
464 }
465
466 module_init(broadcom_init);
467 module_exit(broadcom_exit);