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