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