2 * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx.
4 * Copyright (c) 2003 Intracom S.A.
5 * by Pantelis Antoniou <panto@intracom.gr>
7 * Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com>
8 * and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se>
10 * Released under the GPL
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>
35 #include <asm/8xx_immap.h>
36 #include <asm/pgtable.h>
37 #include <asm/mpc8xx.h>
39 #include <asm/uaccess.h>
40 #include <asm/commproc.h>
42 /*************************************************/
46 /*************************************************/
48 /* Make MII read/write commands for the FEC.
50 #define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18))
51 #define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff))
54 /*************************************************/
56 /* XXX both FECs use the MII interface of FEC1 */
57 static DEFINE_SPINLOCK(fec_mii_lock
);
59 #define FEC_MII_LOOPS 10000
61 int fec_mii_read(struct net_device
*dev
, int phy_id
, int location
)
63 struct fec_enet_private
*fep
= netdev_priv(dev
);
68 /* XXX MII interface is only connected to FEC1 */
69 fecp
= &((immap_t
*) IMAP_ADDR
)->im_cpm
.cp_fec
;
71 spin_lock_irqsave(&fec_mii_lock
, flags
);
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
);
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
));
83 for (i
= 0; i
< FEC_MII_LOOPS
; i
++)
84 if ((FR(fecp
, ievent
) & FEC_ENET_MII
) != 0)
87 if (i
< FEC_MII_LOOPS
) {
88 FW(fecp
, ievent
, FEC_ENET_MII
);
89 ret
= FR(fecp
, mii_data
) & 0xffff;
92 spin_unlock_irqrestore(&fec_mii_lock
, flags
);
97 void fec_mii_write(struct net_device
*dev
, int phy_id
, int location
, int value
)
99 struct fec_enet_private
*fep
= netdev_priv(dev
);
104 /* XXX MII interface is only connected to FEC1 */
105 fecp
= &((immap_t
*) IMAP_ADDR
)->im_cpm
.cp_fec
;
107 spin_lock_irqsave(&fec_mii_lock
, flags
);
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
);
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
));
119 for (i
= 0; i
< FEC_MII_LOOPS
; i
++)
120 if ((FR(fecp
, ievent
) & FEC_ENET_MII
) != 0)
123 if (i
< FEC_MII_LOOPS
)
124 FW(fecp
, ievent
, FEC_ENET_MII
);
126 spin_unlock_irqrestore(&fec_mii_lock
, flags
);
129 /*************************************************/
131 #ifdef CONFIG_FEC_8XX_GENERIC_PHY
134 * Generic PHY support.
135 * Should work for all PHYs, but link change is detected by polling
138 static void generic_timer_callback(unsigned long data
)
140 struct net_device
*dev
= (struct net_device
*)data
;
141 struct fec_enet_private
*fep
= netdev_priv(dev
);
143 fep
->phy_timer_list
.expires
= jiffies
+ HZ
/ 2;
145 add_timer(&fep
->phy_timer_list
);
147 fec_mii_link_status_change_check(dev
, 0);
150 static void generic_startup(struct net_device
*dev
)
152 struct fec_enet_private
*fep
= netdev_priv(dev
);
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
);
160 static void generic_shutdown(struct net_device
*dev
)
162 struct fec_enet_private
*fep
= netdev_priv(dev
);
164 del_timer_sync(&fep
->phy_timer_list
);
169 #ifdef CONFIG_FEC_8XX_DM9161_PHY
171 /* ------------------------------------------------------------------------- */
172 /* The Davicom DM9161 is used on the NETTA board */
174 /* register definitions */
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 */
183 static void dm9161_startup(struct net_device
*dev
)
185 struct fec_enet_private
*fep
= netdev_priv(dev
);
187 fec_mii_write(dev
, fep
->mii_if
.phy_id
, MII_DM9161_INTR
, 0x0000);
190 static void dm9161_ack_int(struct net_device
*dev
)
192 struct fec_enet_private
*fep
= netdev_priv(dev
);
194 fec_mii_read(dev
, fep
->mii_if
.phy_id
, MII_DM9161_INTR
);
197 static void dm9161_shutdown(struct net_device
*dev
)
199 struct fec_enet_private
*fep
= netdev_priv(dev
);
201 fec_mii_write(dev
, fep
->mii_if
.phy_id
, MII_DM9161_INTR
, 0x0f00);
206 /**********************************************************************************/
208 static const struct phy_info phy_info
[] = {
209 #ifdef CONFIG_FEC_8XX_DM9161_PHY
213 .startup
= dm9161_startup
,
214 .ack_int
= dm9161_ack_int
,
215 .shutdown
= dm9161_shutdown
,
218 #ifdef CONFIG_FEC_8XX_GENERIC_PHY
222 .startup
= generic_startup
,
223 .shutdown
= generic_shutdown
,
228 /**********************************************************************************/
230 int fec_mii_phy_id_detect(struct net_device
*dev
)
232 struct fec_enet_private
*fep
= netdev_priv(dev
);
233 const struct fec_platform_info
*fpi
= fep
->fpi
;
234 int i
, r
, start
, end
, phytype
, physubtype
;
235 const struct phy_info
*phy
;
236 int phy_hwid
, phy_id
;
239 if (fpi
->use_mdio
== 0)
246 if (fpi
->phy_addr
== -1) {
249 } else { /* direct */
250 start
= fpi
->phy_addr
;
254 for (phy_id
= start
; phy_id
< end
; phy_id
++) {
255 r
= fec_mii_read(dev
, phy_id
, MII_PHYSID1
);
256 if (r
== -1 || (phytype
= (r
& 0xffff)) == 0xffff)
258 r
= fec_mii_read(dev
, phy_id
, MII_PHYSID2
);
259 if (r
== -1 || (physubtype
= (r
& 0xffff)) == 0xffff)
261 phy_hwid
= (phytype
<< 16) | physubtype
;
266 if (phy_hwid
== -1) {
267 printk(KERN_ERR DRV_MODULE_NAME
268 ": %s No PHY detected!\n", dev
->name
);
272 for (i
= 0, phy
= phy_info
; i
< sizeof(phy_info
) / sizeof(phy_info
[0]);
274 if (phy
->id
== (phy_hwid
>> 4) || phy
->id
== 0)
277 if (i
>= sizeof(phy_info
) / sizeof(phy_info
[0])) {
278 printk(KERN_ERR DRV_MODULE_NAME
279 ": %s PHY id 0x%08x is not supported!\n",
280 dev
->name
, phy_hwid
);
286 printk(KERN_INFO DRV_MODULE_NAME
287 ": %s Phy @ 0x%x, type %s (0x%08x)\n",
288 dev
->name
, phy_id
, fep
->phy
->name
, phy_hwid
);
293 void fec_mii_startup(struct net_device
*dev
)
295 struct fec_enet_private
*fep
= netdev_priv(dev
);
296 const struct fec_platform_info
*fpi
= fep
->fpi
;
298 if (!fpi
->use_mdio
|| fep
->phy
== NULL
)
301 if (fep
->phy
->startup
== NULL
)
304 (*fep
->phy
->startup
) (dev
);
307 void fec_mii_shutdown(struct net_device
*dev
)
309 struct fec_enet_private
*fep
= netdev_priv(dev
);
310 const struct fec_platform_info
*fpi
= fep
->fpi
;
312 if (!fpi
->use_mdio
|| fep
->phy
== NULL
)
315 if (fep
->phy
->shutdown
== NULL
)
318 (*fep
->phy
->shutdown
) (dev
);
321 void fec_mii_ack_int(struct net_device
*dev
)
323 struct fec_enet_private
*fep
= netdev_priv(dev
);
324 const struct fec_platform_info
*fpi
= fep
->fpi
;
326 if (!fpi
->use_mdio
|| fep
->phy
== NULL
)
329 if (fep
->phy
->ack_int
== NULL
)
332 (*fep
->phy
->ack_int
) (dev
);
335 /* helper function */
336 static int mii_negotiated(struct mii_if_info
*mii
)
338 int advert
, lpa
, val
;
340 if (!mii_link_ok(mii
))
343 val
= (*mii
->mdio_read
) (mii
->dev
, mii
->phy_id
, MII_BMSR
);
344 if ((val
& BMSR_ANEGCOMPLETE
) == 0)
347 advert
= (*mii
->mdio_read
) (mii
->dev
, mii
->phy_id
, MII_ADVERTISE
);
348 lpa
= (*mii
->mdio_read
) (mii
->dev
, mii
->phy_id
, MII_LPA
);
350 return mii_nway_result(advert
& lpa
);
353 void fec_mii_link_status_change_check(struct net_device
*dev
, int init_media
)
355 struct fec_enet_private
*fep
= netdev_priv(dev
);
359 if (mii_check_media(&fep
->mii_if
, netif_msg_link(fep
), init_media
) == 0)
362 media
= mii_negotiated(&fep
->mii_if
);
364 if (netif_carrier_ok(dev
)) {
365 spin_lock_irqsave(&fep
->lock
, flags
);
366 fec_restart(dev
, !!(media
& ADVERTISE_FULL
),
367 (media
& (ADVERTISE_100FULL
| ADVERTISE_100HALF
)) ?
369 spin_unlock_irqrestore(&fep
->lock
, flags
);
371 netif_start_queue(dev
);
373 netif_stop_queue(dev
);
375 spin_lock_irqsave(&fep
->lock
, flags
);
377 spin_unlock_irqrestore(&fep
->lock
, flags
);