blob: d3c16b85d9a41fa405b1f2da83ff144f08b521fd [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#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 */
56static DEFINE_SPINLOCK(fec_mii_lock);
57
58#define FEC_MII_LOOPS 10000
59
60int 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
96void 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
137static 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
149static 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
159static 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
182static 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
189static 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
196static 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
Pantelis Antoniou23da0c22005-10-30 01:23:54 +0300205#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
216static 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
223static 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
230static 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238/**********************************************************************************/
239
240static 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
Pantelis Antoniou23da0c22005-10-30 01:23:54 +0300250#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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259#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
271int 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
334void 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
348void 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
362void 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 */
377static 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
394void 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}