Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / drivers / net / fec_8xx / fec_mii.c
1 /*
2  * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx.
3  *
4  * Copyright (c) 2003 Intracom S.A. 
5  *  by Pantelis Antoniou <panto@intracom.gr>
6  *
7  * Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com>
8  * and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se>
9  *
10  * Released under the GPL
11  */
12
13 #include <linux/module.h>
14 #include <linux/types.h>
15 #include <linux/kernel.h>
16 #include <linux/sched.h>
17 #include <linux/string.h>
18 #include <linux/ptrace.h>
19 #include <linux/errno.h>
20 #include <linux/ioport.h>
21 #include <linux/slab.h>
22 #include <linux/interrupt.h>
23 #include <linux/pci.h>
24 #include <linux/init.h>
25 #include <linux/delay.h>
26 #include <linux/netdevice.h>
27 #include <linux/etherdevice.h>
28 #include <linux/skbuff.h>
29 #include <linux/spinlock.h>
30 #include <linux/mii.h>
31 #include <linux/ethtool.h>
32 #include <linux/bitops.h>
33
34 #include <asm/8xx_immap.h>
35 #include <asm/pgtable.h>
36 #include <asm/mpc8xx.h>
37 #include <asm/irq.h>
38 #include <asm/uaccess.h>
39 #include <asm/commproc.h>
40
41 /*************************************************/
42
43 #include "fec_8xx.h"
44
45 /*************************************************/
46
47 /* Make MII read/write commands for the FEC.
48 */
49 #define mk_mii_read(REG)        (0x60020000 | ((REG & 0x1f) << 18))
50 #define mk_mii_write(REG, VAL)  (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff))
51 #define mk_mii_end              0
52
53 /*************************************************/
54
55 /* XXX both FECs use the MII interface of FEC1 */
56 static DEFINE_SPINLOCK(fec_mii_lock);
57
58 #define FEC_MII_LOOPS   10000
59
60 int fec_mii_read(struct net_device *dev, int phy_id, int location)
61 {
62         struct fec_enet_private *fep = netdev_priv(dev);
63         fec_t *fecp;
64         int i, ret = -1;
65         unsigned long flags;
66
67         /* XXX MII interface is only connected to FEC1 */
68         fecp = &((immap_t *) IMAP_ADDR)->im_cpm.cp_fec;
69
70         spin_lock_irqsave(&fec_mii_lock, flags);
71
72         if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) {
73                 FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
74                 FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
75                 FW(fecp, ievent, FEC_ENET_MII);
76         }
77
78         /* Add PHY address to register command.  */
79         FW(fecp, mii_speed, fep->fec_phy_speed);
80         FW(fecp, mii_data, (phy_id << 23) | mk_mii_read(location));
81
82         for (i = 0; i < FEC_MII_LOOPS; i++)
83                 if ((FR(fecp, ievent) & FEC_ENET_MII) != 0)
84                         break;
85
86         if (i < FEC_MII_LOOPS) {
87                 FW(fecp, ievent, FEC_ENET_MII);
88                 ret = FR(fecp, mii_data) & 0xffff;
89         }
90
91         spin_unlock_irqrestore(&fec_mii_lock, flags);
92
93         return ret;
94 }
95
96 void fec_mii_write(struct net_device *dev, int phy_id, int location, int value)
97 {
98         struct fec_enet_private *fep = netdev_priv(dev);
99         fec_t *fecp;
100         unsigned long flags;
101         int i;
102
103         /* XXX MII interface is only connected to FEC1 */
104         fecp = &((immap_t *) IMAP_ADDR)->im_cpm.cp_fec;
105
106         spin_lock_irqsave(&fec_mii_lock, flags);
107
108         if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) {
109                 FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
110                 FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
111                 FW(fecp, ievent, FEC_ENET_MII);
112         }
113
114         /* Add PHY address to register command.  */
115         FW(fecp, mii_speed, fep->fec_phy_speed);        /* always adapt mii speed */
116         FW(fecp, mii_data, (phy_id << 23) | mk_mii_write(location, value));
117
118         for (i = 0; i < FEC_MII_LOOPS; i++)
119                 if ((FR(fecp, ievent) & FEC_ENET_MII) != 0)
120                         break;
121
122         if (i < FEC_MII_LOOPS)
123                 FW(fecp, ievent, FEC_ENET_MII);
124
125         spin_unlock_irqrestore(&fec_mii_lock, flags);
126 }
127
128 /*************************************************/
129
130 #ifdef CONFIG_FEC_8XX_GENERIC_PHY
131
132 /*
133  * Generic PHY support.
134  * Should work for all PHYs, but link change is detected by polling
135  */
136
137 static void generic_timer_callback(unsigned long data)
138 {
139         struct net_device *dev = (struct net_device *)data;
140         struct fec_enet_private *fep = netdev_priv(dev);
141
142         fep->phy_timer_list.expires = jiffies + HZ / 2;
143
144         add_timer(&fep->phy_timer_list);
145
146         fec_mii_link_status_change_check(dev, 0);
147 }
148
149 static void generic_startup(struct net_device *dev)
150 {
151         struct fec_enet_private *fep = netdev_priv(dev);
152
153         fep->phy_timer_list.expires = jiffies + HZ / 2; /* every 500ms */
154         fep->phy_timer_list.data = (unsigned long)dev;
155         fep->phy_timer_list.function = generic_timer_callback;
156         add_timer(&fep->phy_timer_list);
157 }
158
159 static void generic_shutdown(struct net_device *dev)
160 {
161         struct fec_enet_private *fep = netdev_priv(dev);
162
163         del_timer_sync(&fep->phy_timer_list);
164 }
165
166 #endif
167
168 #ifdef CONFIG_FEC_8XX_DM9161_PHY
169
170 /* ------------------------------------------------------------------------- */
171 /* The Davicom DM9161 is used on the NETTA board                             */
172
173 /* register definitions */
174
175 #define MII_DM9161_ACR          16      /* Aux. Config Register         */
176 #define MII_DM9161_ACSR         17      /* Aux. Config/Status Register  */
177 #define MII_DM9161_10TCSR       18      /* 10BaseT Config/Status Reg.   */
178 #define MII_DM9161_INTR         21      /* Interrupt Register           */
179 #define MII_DM9161_RECR         22      /* Receive Error Counter Reg.   */
180 #define MII_DM9161_DISCR        23      /* Disconnect Counter Register  */
181
182 static void dm9161_startup(struct net_device *dev)
183 {
184         struct fec_enet_private *fep = netdev_priv(dev);
185
186         fec_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0000);
187 }
188
189 static void dm9161_ack_int(struct net_device *dev)
190 {
191         struct fec_enet_private *fep = netdev_priv(dev);
192
193         fec_mii_read(dev, fep->mii_if.phy_id, MII_DM9161_INTR);
194 }
195
196 static void dm9161_shutdown(struct net_device *dev)
197 {
198         struct fec_enet_private *fep = netdev_priv(dev);
199
200         fec_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0f00);
201 }
202
203 #endif
204
205 #ifdef CONFIG_FEC_8XX_LXT971_PHY
206
207 /* Support for LXT971/972 PHY */
208
209 #define MII_LXT971_PCR          16 /* Port Control Register */
210 #define MII_LXT971_SR2          17 /* Status Register 2 */
211 #define MII_LXT971_IER          18 /* Interrupt Enable Register */
212 #define MII_LXT971_ISR          19 /* Interrupt Status Register */
213 #define MII_LXT971_LCR          20 /* LED Control Register */
214 #define MII_LXT971_TCR          30 /* Transmit Control Register */
215
216 static void lxt971_startup(struct net_device *dev)
217 {
218         struct fec_enet_private *fep = netdev_priv(dev);
219
220         fec_mii_write(dev, fep->mii_if.phy_id, MII_LXT971_IER, 0x00F2);
221 }
222
223 static void lxt971_ack_int(struct net_device *dev)
224 {
225         struct fec_enet_private *fep = netdev_priv(dev);
226
227         fec_mii_read(dev, fep->mii_if.phy_id, MII_LXT971_ISR);
228 }
229
230 static void lxt971_shutdown(struct net_device *dev)
231 {
232         struct fec_enet_private *fep = netdev_priv(dev);
233
234         fec_mii_write(dev, fep->mii_if.phy_id, MII_LXT971_IER, 0x0000);
235 }
236 #endif
237
238 /**********************************************************************************/
239
240 static const struct phy_info phy_info[] = {
241 #ifdef CONFIG_FEC_8XX_DM9161_PHY
242         {
243          .id = 0x00181b88,
244          .name = "DM9161",
245          .startup = dm9161_startup,
246          .ack_int = dm9161_ack_int,
247          .shutdown = dm9161_shutdown,
248          },
249 #endif
250 #ifdef CONFIG_FEC_8XX_LXT971_PHY
251         {
252          .id = 0x0001378e,
253          .name = "LXT971/972",
254          .startup = lxt971_startup,
255          .ack_int = lxt971_ack_int,
256          .shutdown = lxt971_shutdown,
257         },
258 #endif
259 #ifdef CONFIG_FEC_8XX_GENERIC_PHY
260         {
261          .id = 0,
262          .name = "GENERIC",
263          .startup = generic_startup,
264          .shutdown = generic_shutdown,
265          },
266 #endif
267 };
268
269 /**********************************************************************************/
270
271 int fec_mii_phy_id_detect(struct net_device *dev)
272 {
273         struct fec_enet_private *fep = netdev_priv(dev);
274         const struct fec_platform_info *fpi = fep->fpi;
275         int i, r, start, end, phytype, physubtype;
276         const struct phy_info *phy;
277         int phy_hwid, phy_id;
278
279         /* if no MDIO */
280         if (fpi->use_mdio == 0)
281                 return -1;
282
283         phy_hwid = -1;
284         fep->phy = NULL;
285
286         /* auto-detect? */
287         if (fpi->phy_addr == -1) {
288                 start = 0;
289                 end = 32;
290         } else {                /* direct */
291                 start = fpi->phy_addr;
292                 end = start + 1;
293         }
294
295         for (phy_id = start; phy_id < end; phy_id++) {
296                 r = fec_mii_read(dev, phy_id, MII_PHYSID1);
297                 if (r == -1 || (phytype = (r & 0xffff)) == 0xffff)
298                         continue;
299                 r = fec_mii_read(dev, phy_id, MII_PHYSID2);
300                 if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff)
301                         continue;
302                 phy_hwid = (phytype << 16) | physubtype;
303                 if (phy_hwid != -1)
304                         break;
305         }
306
307         if (phy_hwid == -1) {
308                 printk(KERN_ERR DRV_MODULE_NAME
309                        ": %s No PHY detected!\n", dev->name);
310                 return -1;
311         }
312
313         for (i = 0, phy = phy_info; i < sizeof(phy_info) / sizeof(phy_info[0]);
314              i++, phy++)
315                 if (phy->id == (phy_hwid >> 4) || phy->id == 0)
316                         break;
317
318         if (i >= sizeof(phy_info) / sizeof(phy_info[0])) {
319                 printk(KERN_ERR DRV_MODULE_NAME
320                        ": %s PHY id 0x%08x is not supported!\n",
321                        dev->name, phy_hwid);
322                 return -1;
323         }
324
325         fep->phy = phy;
326
327         printk(KERN_INFO DRV_MODULE_NAME
328                ": %s Phy @ 0x%x, type %s (0x%08x)\n",
329                dev->name, phy_id, fep->phy->name, phy_hwid);
330
331         return phy_id;
332 }
333
334 void fec_mii_startup(struct net_device *dev)
335 {
336         struct fec_enet_private *fep = netdev_priv(dev);
337         const struct fec_platform_info *fpi = fep->fpi;
338
339         if (!fpi->use_mdio || fep->phy == NULL)
340                 return;
341
342         if (fep->phy->startup == NULL)
343                 return;
344
345         (*fep->phy->startup) (dev);
346 }
347
348 void fec_mii_shutdown(struct net_device *dev)
349 {
350         struct fec_enet_private *fep = netdev_priv(dev);
351         const struct fec_platform_info *fpi = fep->fpi;
352
353         if (!fpi->use_mdio || fep->phy == NULL)
354                 return;
355
356         if (fep->phy->shutdown == NULL)
357                 return;
358
359         (*fep->phy->shutdown) (dev);
360 }
361
362 void fec_mii_ack_int(struct net_device *dev)
363 {
364         struct fec_enet_private *fep = netdev_priv(dev);
365         const struct fec_platform_info *fpi = fep->fpi;
366
367         if (!fpi->use_mdio || fep->phy == NULL)
368                 return;
369
370         if (fep->phy->ack_int == NULL)
371                 return;
372
373         (*fep->phy->ack_int) (dev);
374 }
375
376 /* helper function */
377 static int mii_negotiated(struct mii_if_info *mii)
378 {
379         int advert, lpa, val;
380
381         if (!mii_link_ok(mii))
382                 return 0;
383
384         val = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_BMSR);
385         if ((val & BMSR_ANEGCOMPLETE) == 0)
386                 return 0;
387
388         advert = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_ADVERTISE);
389         lpa = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_LPA);
390
391         return mii_nway_result(advert & lpa);
392 }
393
394 void fec_mii_link_status_change_check(struct net_device *dev, int init_media)
395 {
396         struct fec_enet_private *fep = netdev_priv(dev);
397         unsigned int media;
398         unsigned long flags;
399
400         if (mii_check_media(&fep->mii_if, netif_msg_link(fep), init_media) == 0)
401                 return;
402
403         media = mii_negotiated(&fep->mii_if);
404
405         if (netif_carrier_ok(dev)) {
406                 spin_lock_irqsave(&fep->lock, flags);
407                 fec_restart(dev, !!(media & ADVERTISE_FULL),
408                             (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)) ?
409                             100 : 10);
410                 spin_unlock_irqrestore(&fep->lock, flags);
411
412                 netif_start_queue(dev);
413         } else {
414                 netif_stop_queue(dev);
415
416                 spin_lock_irqsave(&fep->lock, flags);
417                 fec_stop(dev);
418                 spin_unlock_irqrestore(&fep->lock, flags);
419
420         }
421 }