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