Linux-2.6.12-rc2
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / net / fec_8xx / fec_mii.c
blob803eb095cf8e60a3c708ff91d6c6440e5df7a171
1 /*
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>
38 #include <asm/irq.h>
39 #include <asm/uaccess.h>
40 #include <asm/commproc.h>
42 /*************************************************/
44 #include "fec_8xx.h"
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))
52 #define mk_mii_end 0
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);
64 fec_t *fecp;
65 int i, ret = -1;
66 unsigned long flags;
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)
85 break;
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);
94 return ret;
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);
100 fec_t *fecp;
101 unsigned long flags;
102 int i;
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)
121 break;
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);
167 #endif
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);
204 #endif
206 /**********************************************************************************/
208 static const struct phy_info phy_info[] = {
209 #ifdef CONFIG_FEC_8XX_DM9161_PHY
211 .id = 0x00181b88,
212 .name = "DM9161",
213 .startup = dm9161_startup,
214 .ack_int = dm9161_ack_int,
215 .shutdown = dm9161_shutdown,
217 #endif
218 #ifdef CONFIG_FEC_8XX_GENERIC_PHY
220 .id = 0,
221 .name = "GENERIC",
222 .startup = generic_startup,
223 .shutdown = generic_shutdown,
225 #endif
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;
238 /* if no MDIO */
239 if (fpi->use_mdio == 0)
240 return -1;
242 phy_hwid = -1;
243 fep->phy = NULL;
245 /* auto-detect? */
246 if (fpi->phy_addr == -1) {
247 start = 0;
248 end = 32;
249 } else { /* direct */
250 start = fpi->phy_addr;
251 end = start + 1;
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)
257 continue;
258 r = fec_mii_read(dev, phy_id, MII_PHYSID2);
259 if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff)
260 continue;
261 phy_hwid = (phytype << 16) | physubtype;
262 if (phy_hwid != -1)
263 break;
266 if (phy_hwid == -1) {
267 printk(KERN_ERR DRV_MODULE_NAME
268 ": %s No PHY detected!\n", dev->name);
269 return -1;
272 for (i = 0, phy = phy_info; i < sizeof(phy_info) / sizeof(phy_info[0]);
273 i++, phy++)
274 if (phy->id == (phy_hwid >> 4) || phy->id == 0)
275 break;
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);
281 return -1;
284 fep->phy = phy;
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);
290 return phy_id;
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)
299 return;
301 if (fep->phy->startup == NULL)
302 return;
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)
313 return;
315 if (fep->phy->shutdown == NULL)
316 return;
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)
327 return;
329 if (fep->phy->ack_int == NULL)
330 return;
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))
341 return 0;
343 val = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_BMSR);
344 if ((val & BMSR_ANEGCOMPLETE) == 0)
345 return 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);
356 unsigned int media;
357 unsigned long flags;
359 if (mii_check_media(&fep->mii_if, netif_msg_link(fep), init_media) == 0)
360 return;
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)) ?
368 100 : 10);
369 spin_unlock_irqrestore(&fep->lock, flags);
371 netif_start_queue(dev);
372 } else {
373 netif_stop_queue(dev);
375 spin_lock_irqsave(&fep->lock, flags);
376 fec_stop(dev);
377 spin_unlock_irqrestore(&fep->lock, flags);