aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/fec_8xx/fec_mii.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/fec_8xx/fec_mii.c')
-rw-r--r--drivers/net/fec_8xx/fec_mii.c418
1 files changed, 0 insertions, 418 deletions
diff --git a/drivers/net/fec_8xx/fec_mii.c b/drivers/net/fec_8xx/fec_mii.c
deleted file mode 100644
index 3b6ca29d31f2..000000000000
--- a/drivers/net/fec_8xx/fec_mii.c
+++ /dev/null
@@ -1,418 +0,0 @@
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/cpm1.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 */
54static DEFINE_SPINLOCK(fec_mii_lock);
55
56#define FEC_MII_LOOPS 10000
57
58int 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
94void 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
135static 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
147static 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
157static 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
180static 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
187static 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
194static 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
214static 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
221static 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
228static 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
238static 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
269int 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 < ARRAY_SIZE(phy_info); i++, phy++)
312 if (phy->id == (phy_hwid >> 4) || phy->id == 0)
313 break;
314
315 if (i >= ARRAY_SIZE(phy_info)) {
316 printk(KERN_ERR DRV_MODULE_NAME
317 ": %s PHY id 0x%08x is not supported!\n",
318 dev->name, phy_hwid);
319 return -1;
320 }
321
322 fep->phy = phy;
323
324 printk(KERN_INFO DRV_MODULE_NAME
325 ": %s Phy @ 0x%x, type %s (0x%08x)\n",
326 dev->name, phy_id, fep->phy->name, phy_hwid);
327
328 return phy_id;
329}
330
331void fec_mii_startup(struct net_device *dev)
332{
333 struct fec_enet_private *fep = netdev_priv(dev);
334 const struct fec_platform_info *fpi = fep->fpi;
335
336 if (!fpi->use_mdio || fep->phy == NULL)
337 return;
338
339 if (fep->phy->startup == NULL)
340 return;
341
342 (*fep->phy->startup) (dev);
343}
344
345void fec_mii_shutdown(struct net_device *dev)
346{
347 struct fec_enet_private *fep = netdev_priv(dev);
348 const struct fec_platform_info *fpi = fep->fpi;
349
350 if (!fpi->use_mdio || fep->phy == NULL)
351 return;
352
353 if (fep->phy->shutdown == NULL)
354 return;
355
356 (*fep->phy->shutdown) (dev);
357}
358
359void fec_mii_ack_int(struct net_device *dev)
360{
361 struct fec_enet_private *fep = netdev_priv(dev);
362 const struct fec_platform_info *fpi = fep->fpi;
363
364 if (!fpi->use_mdio || fep->phy == NULL)
365 return;
366
367 if (fep->phy->ack_int == NULL)
368 return;
369
370 (*fep->phy->ack_int) (dev);
371}
372
373/* helper function */
374static int mii_negotiated(struct mii_if_info *mii)
375{
376 int advert, lpa, val;
377
378 if (!mii_link_ok(mii))
379 return 0;
380
381 val = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_BMSR);
382 if ((val & BMSR_ANEGCOMPLETE) == 0)
383 return 0;
384
385 advert = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_ADVERTISE);
386 lpa = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_LPA);
387
388 return mii_nway_result(advert & lpa);
389}
390
391void fec_mii_link_status_change_check(struct net_device *dev, int init_media)
392{
393 struct fec_enet_private *fep = netdev_priv(dev);
394 unsigned int media;
395 unsigned long flags;
396
397 if (mii_check_media(&fep->mii_if, netif_msg_link(fep), init_media) == 0)
398 return;
399
400 media = mii_negotiated(&fep->mii_if);
401
402 if (netif_carrier_ok(dev)) {
403 spin_lock_irqsave(&fep->lock, flags);
404 fec_restart(dev, !!(media & ADVERTISE_FULL),
405 (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)) ?
406 100 : 10);
407 spin_unlock_irqrestore(&fep->lock, flags);
408
409 netif_start_queue(dev);
410 } else {
411 netif_stop_queue(dev);
412
413 spin_lock_irqsave(&fep->lock, flags);
414 fec_stop(dev);
415 spin_unlock_irqrestore(&fep->lock, flags);
416
417 }
418}