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