Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.19-rc1 800 lines 20 kB view raw
1/* 2 * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. 3 * 4 * Author: Shlomi Gridish <gridish@freescale.com> 5 * 6 * Description: 7 * UCC GETH Driver -- PHY handling 8 * 9 * Changelog: 10 * Jun 28, 2006 Li Yang <LeoLi@freescale.com> 11 * - Rearrange code and style fixes 12 * 13 * This program is free software; you can redistribute it and/or modify it 14 * under the terms of the GNU General Public License as published by the 15 * Free Software Foundation; either version 2 of the License, or (at your 16 * option) any later version. 17 * 18 */ 19 20#include <linux/kernel.h> 21#include <linux/sched.h> 22#include <linux/string.h> 23#include <linux/errno.h> 24#include <linux/slab.h> 25#include <linux/interrupt.h> 26#include <linux/init.h> 27#include <linux/delay.h> 28#include <linux/netdevice.h> 29#include <linux/etherdevice.h> 30#include <linux/skbuff.h> 31#include <linux/spinlock.h> 32#include <linux/mm.h> 33#include <linux/module.h> 34#include <linux/version.h> 35#include <linux/crc32.h> 36#include <linux/mii.h> 37#include <linux/ethtool.h> 38 39#include <asm/io.h> 40#include <asm/irq.h> 41#include <asm/uaccess.h> 42 43#include "ucc_geth.h" 44#include "ucc_geth_phy.h" 45#include <platforms/83xx/mpc8360e_pb.h> 46 47#define ugphy_printk(level, format, arg...) \ 48 printk(level format "\n", ## arg) 49 50#define ugphy_dbg(format, arg...) \ 51 ugphy_printk(KERN_DEBUG, format , ## arg) 52#define ugphy_err(format, arg...) \ 53 ugphy_printk(KERN_ERR, format , ## arg) 54#define ugphy_info(format, arg...) \ 55 ugphy_printk(KERN_INFO, format , ## arg) 56#define ugphy_warn(format, arg...) \ 57 ugphy_printk(KERN_WARNING, format , ## arg) 58 59#ifdef UGETH_VERBOSE_DEBUG 60#define ugphy_vdbg ugphy_dbg 61#else 62#define ugphy_vdbg(fmt, args...) do { } while (0) 63#endif /* UGETH_VERBOSE_DEBUG */ 64 65static void config_genmii_advert(struct ugeth_mii_info *mii_info); 66static void genmii_setup_forced(struct ugeth_mii_info *mii_info); 67static void genmii_restart_aneg(struct ugeth_mii_info *mii_info); 68static int gbit_config_aneg(struct ugeth_mii_info *mii_info); 69static int genmii_config_aneg(struct ugeth_mii_info *mii_info); 70static int genmii_update_link(struct ugeth_mii_info *mii_info); 71static int genmii_read_status(struct ugeth_mii_info *mii_info); 72u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum); 73void phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val); 74 75static u8 *bcsr_regs = NULL; 76 77/* Write value to the PHY for this device to the register at regnum, */ 78/* waiting until the write is done before it returns. All PHY */ 79/* configuration has to be done through the TSEC1 MIIM regs */ 80void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value) 81{ 82 ucc_geth_private_t *ugeth = netdev_priv(dev); 83 ucc_mii_mng_t *mii_regs; 84 enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum; 85 u32 tmp_reg; 86 87 ugphy_vdbg("%s: IN", __FUNCTION__); 88 89 spin_lock_irq(&ugeth->lock); 90 91 mii_regs = ugeth->mii_info->mii_regs; 92 93 /* Set this UCC to be the master of the MII managment */ 94 ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num); 95 96 /* Stop the MII management read cycle */ 97 out_be32(&mii_regs->miimcom, 0); 98 /* Setting up the MII Mangement Address Register */ 99 tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; 100 out_be32(&mii_regs->miimadd, tmp_reg); 101 102 /* Setting up the MII Mangement Control Register with the value */ 103 out_be32(&mii_regs->miimcon, (u32) value); 104 105 /* Wait till MII management write is complete */ 106 while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY) 107 cpu_relax(); 108 109 spin_unlock_irq(&ugeth->lock); 110 111 udelay(10000); 112} 113 114/* Reads from register regnum in the PHY for device dev, */ 115/* returning the value. Clears miimcom first. All PHY */ 116/* configuration has to be done through the TSEC1 MIIM regs */ 117int read_phy_reg(struct net_device *dev, int mii_id, int regnum) 118{ 119 ucc_geth_private_t *ugeth = netdev_priv(dev); 120 ucc_mii_mng_t *mii_regs; 121 enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum; 122 u32 tmp_reg; 123 u16 value; 124 125 ugphy_vdbg("%s: IN", __FUNCTION__); 126 127 spin_lock_irq(&ugeth->lock); 128 129 mii_regs = ugeth->mii_info->mii_regs; 130 131 /* Setting up the MII Mangement Address Register */ 132 tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; 133 out_be32(&mii_regs->miimadd, tmp_reg); 134 135 /* Perform an MII management read cycle */ 136 out_be32(&mii_regs->miimcom, MIIMCOM_READ_CYCLE); 137 138 /* Wait till MII management write is complete */ 139 while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY) 140 cpu_relax(); 141 142 udelay(10000); 143 144 /* Read MII management status */ 145 value = (u16) in_be32(&mii_regs->miimstat); 146 out_be32(&mii_regs->miimcom, 0); 147 if (value == 0xffff) 148 ugphy_warn("read wrong value : mii_id %d,mii_reg %d, base %08x", 149 mii_id, mii_reg, (u32) & (mii_regs->miimcfg)); 150 151 spin_unlock_irq(&ugeth->lock); 152 153 return (value); 154} 155 156void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info) 157{ 158 ugphy_vdbg("%s: IN", __FUNCTION__); 159 160 if (mii_info->phyinfo->ack_interrupt) 161 mii_info->phyinfo->ack_interrupt(mii_info); 162} 163 164void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info, 165 u32 interrupts) 166{ 167 ugphy_vdbg("%s: IN", __FUNCTION__); 168 169 mii_info->interrupts = interrupts; 170 if (mii_info->phyinfo->config_intr) 171 mii_info->phyinfo->config_intr(mii_info); 172} 173 174/* Writes MII_ADVERTISE with the appropriate values, after 175 * sanitizing advertise to make sure only supported features 176 * are advertised 177 */ 178static void config_genmii_advert(struct ugeth_mii_info *mii_info) 179{ 180 u32 advertise; 181 u16 adv; 182 183 ugphy_vdbg("%s: IN", __FUNCTION__); 184 185 /* Only allow advertising what this PHY supports */ 186 mii_info->advertising &= mii_info->phyinfo->features; 187 advertise = mii_info->advertising; 188 189 /* Setup standard advertisement */ 190 adv = phy_read(mii_info, MII_ADVERTISE); 191 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); 192 if (advertise & ADVERTISED_10baseT_Half) 193 adv |= ADVERTISE_10HALF; 194 if (advertise & ADVERTISED_10baseT_Full) 195 adv |= ADVERTISE_10FULL; 196 if (advertise & ADVERTISED_100baseT_Half) 197 adv |= ADVERTISE_100HALF; 198 if (advertise & ADVERTISED_100baseT_Full) 199 adv |= ADVERTISE_100FULL; 200 phy_write(mii_info, MII_ADVERTISE, adv); 201} 202 203static void genmii_setup_forced(struct ugeth_mii_info *mii_info) 204{ 205 u16 ctrl; 206 u32 features = mii_info->phyinfo->features; 207 208 ugphy_vdbg("%s: IN", __FUNCTION__); 209 210 ctrl = phy_read(mii_info, MII_BMCR); 211 212 ctrl &= 213 ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); 214 ctrl |= BMCR_RESET; 215 216 switch (mii_info->speed) { 217 case SPEED_1000: 218 if (features & (SUPPORTED_1000baseT_Half 219 | SUPPORTED_1000baseT_Full)) { 220 ctrl |= BMCR_SPEED1000; 221 break; 222 } 223 mii_info->speed = SPEED_100; 224 case SPEED_100: 225 if (features & (SUPPORTED_100baseT_Half 226 | SUPPORTED_100baseT_Full)) { 227 ctrl |= BMCR_SPEED100; 228 break; 229 } 230 mii_info->speed = SPEED_10; 231 case SPEED_10: 232 if (features & (SUPPORTED_10baseT_Half 233 | SUPPORTED_10baseT_Full)) 234 break; 235 default: /* Unsupported speed! */ 236 ugphy_err("%s: Bad speed!", mii_info->dev->name); 237 break; 238 } 239 240 phy_write(mii_info, MII_BMCR, ctrl); 241} 242 243/* Enable and Restart Autonegotiation */ 244static void genmii_restart_aneg(struct ugeth_mii_info *mii_info) 245{ 246 u16 ctl; 247 248 ugphy_vdbg("%s: IN", __FUNCTION__); 249 250 ctl = phy_read(mii_info, MII_BMCR); 251 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); 252 phy_write(mii_info, MII_BMCR, ctl); 253} 254 255static int gbit_config_aneg(struct ugeth_mii_info *mii_info) 256{ 257 u16 adv; 258 u32 advertise; 259 260 ugphy_vdbg("%s: IN", __FUNCTION__); 261 262 if (mii_info->autoneg) { 263 /* Configure the ADVERTISE register */ 264 config_genmii_advert(mii_info); 265 advertise = mii_info->advertising; 266 267 adv = phy_read(mii_info, MII_1000BASETCONTROL); 268 adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | 269 MII_1000BASETCONTROL_HALFDUPLEXCAP); 270 if (advertise & SUPPORTED_1000baseT_Half) 271 adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; 272 if (advertise & SUPPORTED_1000baseT_Full) 273 adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; 274 phy_write(mii_info, MII_1000BASETCONTROL, adv); 275 276 /* Start/Restart aneg */ 277 genmii_restart_aneg(mii_info); 278 } else 279 genmii_setup_forced(mii_info); 280 281 return 0; 282} 283 284static int genmii_config_aneg(struct ugeth_mii_info *mii_info) 285{ 286 ugphy_vdbg("%s: IN", __FUNCTION__); 287 288 if (mii_info->autoneg) { 289 config_genmii_advert(mii_info); 290 genmii_restart_aneg(mii_info); 291 } else 292 genmii_setup_forced(mii_info); 293 294 return 0; 295} 296 297static int genmii_update_link(struct ugeth_mii_info *mii_info) 298{ 299 u16 status; 300 301 ugphy_vdbg("%s: IN", __FUNCTION__); 302 303 /* Do a fake read */ 304 phy_read(mii_info, MII_BMSR); 305 306 /* Read link and autonegotiation status */ 307 status = phy_read(mii_info, MII_BMSR); 308 if ((status & BMSR_LSTATUS) == 0) 309 mii_info->link = 0; 310 else 311 mii_info->link = 1; 312 313 /* If we are autonegotiating, and not done, 314 * return an error */ 315 if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE)) 316 return -EAGAIN; 317 318 return 0; 319} 320 321static int genmii_read_status(struct ugeth_mii_info *mii_info) 322{ 323 u16 status; 324 int err; 325 326 ugphy_vdbg("%s: IN", __FUNCTION__); 327 328 /* Update the link, but return if there 329 * was an error */ 330 err = genmii_update_link(mii_info); 331 if (err) 332 return err; 333 334 if (mii_info->autoneg) { 335 status = phy_read(mii_info, MII_LPA); 336 337 if (status & (LPA_10FULL | LPA_100FULL)) 338 mii_info->duplex = DUPLEX_FULL; 339 else 340 mii_info->duplex = DUPLEX_HALF; 341 if (status & (LPA_100FULL | LPA_100HALF)) 342 mii_info->speed = SPEED_100; 343 else 344 mii_info->speed = SPEED_10; 345 mii_info->pause = 0; 346 } 347 /* On non-aneg, we assume what we put in BMCR is the speed, 348 * though magic-aneg shouldn't prevent this case from occurring 349 */ 350 351 return 0; 352} 353 354static int marvell_init(struct ugeth_mii_info *mii_info) 355{ 356 ugphy_vdbg("%s: IN", __FUNCTION__); 357 358 phy_write(mii_info, 0x14, 0x0cd2); 359 phy_write(mii_info, MII_BMCR, 360 phy_read(mii_info, MII_BMCR) | BMCR_RESET); 361 msleep(4000); 362 363 return 0; 364} 365 366static int marvell_config_aneg(struct ugeth_mii_info *mii_info) 367{ 368 ugphy_vdbg("%s: IN", __FUNCTION__); 369 370 /* The Marvell PHY has an errata which requires 371 * that certain registers get written in order 372 * to restart autonegotiation */ 373 phy_write(mii_info, MII_BMCR, BMCR_RESET); 374 375 phy_write(mii_info, 0x1d, 0x1f); 376 phy_write(mii_info, 0x1e, 0x200c); 377 phy_write(mii_info, 0x1d, 0x5); 378 phy_write(mii_info, 0x1e, 0); 379 phy_write(mii_info, 0x1e, 0x100); 380 381 gbit_config_aneg(mii_info); 382 383 return 0; 384} 385 386static int marvell_read_status(struct ugeth_mii_info *mii_info) 387{ 388 u16 status; 389 int err; 390 391 ugphy_vdbg("%s: IN", __FUNCTION__); 392 393 /* Update the link, but return if there 394 * was an error */ 395 err = genmii_update_link(mii_info); 396 if (err) 397 return err; 398 399 /* If the link is up, read the speed and duplex */ 400 /* If we aren't autonegotiating, assume speeds 401 * are as set */ 402 if (mii_info->autoneg && mii_info->link) { 403 int speed; 404 status = phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS); 405 406 /* Get the duplexity */ 407 if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) 408 mii_info->duplex = DUPLEX_FULL; 409 else 410 mii_info->duplex = DUPLEX_HALF; 411 412 /* Get the speed */ 413 speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK; 414 switch (speed) { 415 case MII_M1011_PHY_SPEC_STATUS_1000: 416 mii_info->speed = SPEED_1000; 417 break; 418 case MII_M1011_PHY_SPEC_STATUS_100: 419 mii_info->speed = SPEED_100; 420 break; 421 default: 422 mii_info->speed = SPEED_10; 423 break; 424 } 425 mii_info->pause = 0; 426 } 427 428 return 0; 429} 430 431static int marvell_ack_interrupt(struct ugeth_mii_info *mii_info) 432{ 433 ugphy_vdbg("%s: IN", __FUNCTION__); 434 435 /* Clear the interrupts by reading the reg */ 436 phy_read(mii_info, MII_M1011_IEVENT); 437 438 return 0; 439} 440 441static int marvell_config_intr(struct ugeth_mii_info *mii_info) 442{ 443 ugphy_vdbg("%s: IN", __FUNCTION__); 444 445 if (mii_info->interrupts == MII_INTERRUPT_ENABLED) 446 phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); 447 else 448 phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); 449 450 return 0; 451} 452 453static int cis820x_init(struct ugeth_mii_info *mii_info) 454{ 455 ugphy_vdbg("%s: IN", __FUNCTION__); 456 457 phy_write(mii_info, MII_CIS8201_AUX_CONSTAT, 458 MII_CIS8201_AUXCONSTAT_INIT); 459 phy_write(mii_info, MII_CIS8201_EXT_CON1, MII_CIS8201_EXTCON1_INIT); 460 461 return 0; 462} 463 464static int cis820x_read_status(struct ugeth_mii_info *mii_info) 465{ 466 u16 status; 467 int err; 468 469 ugphy_vdbg("%s: IN", __FUNCTION__); 470 471 /* Update the link, but return if there 472 * was an error */ 473 err = genmii_update_link(mii_info); 474 if (err) 475 return err; 476 477 /* If the link is up, read the speed and duplex */ 478 /* If we aren't autonegotiating, assume speeds 479 * are as set */ 480 if (mii_info->autoneg && mii_info->link) { 481 int speed; 482 483 status = phy_read(mii_info, MII_CIS8201_AUX_CONSTAT); 484 if (status & MII_CIS8201_AUXCONSTAT_DUPLEX) 485 mii_info->duplex = DUPLEX_FULL; 486 else 487 mii_info->duplex = DUPLEX_HALF; 488 489 speed = status & MII_CIS8201_AUXCONSTAT_SPEED; 490 491 switch (speed) { 492 case MII_CIS8201_AUXCONSTAT_GBIT: 493 mii_info->speed = SPEED_1000; 494 break; 495 case MII_CIS8201_AUXCONSTAT_100: 496 mii_info->speed = SPEED_100; 497 break; 498 default: 499 mii_info->speed = SPEED_10; 500 break; 501 } 502 } 503 504 return 0; 505} 506 507static int cis820x_ack_interrupt(struct ugeth_mii_info *mii_info) 508{ 509 ugphy_vdbg("%s: IN", __FUNCTION__); 510 511 phy_read(mii_info, MII_CIS8201_ISTAT); 512 513 return 0; 514} 515 516static int cis820x_config_intr(struct ugeth_mii_info *mii_info) 517{ 518 ugphy_vdbg("%s: IN", __FUNCTION__); 519 520 if (mii_info->interrupts == MII_INTERRUPT_ENABLED) 521 phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK); 522 else 523 phy_write(mii_info, MII_CIS8201_IMASK, 0); 524 525 return 0; 526} 527 528#define DM9161_DELAY 10 529 530static int dm9161_read_status(struct ugeth_mii_info *mii_info) 531{ 532 u16 status; 533 int err; 534 535 ugphy_vdbg("%s: IN", __FUNCTION__); 536 537 /* Update the link, but return if there 538 * was an error */ 539 err = genmii_update_link(mii_info); 540 if (err) 541 return err; 542 543 /* If the link is up, read the speed and duplex */ 544 /* If we aren't autonegotiating, assume speeds 545 * are as set */ 546 if (mii_info->autoneg && mii_info->link) { 547 status = phy_read(mii_info, MII_DM9161_SCSR); 548 if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H)) 549 mii_info->speed = SPEED_100; 550 else 551 mii_info->speed = SPEED_10; 552 553 if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F)) 554 mii_info->duplex = DUPLEX_FULL; 555 else 556 mii_info->duplex = DUPLEX_HALF; 557 } 558 559 return 0; 560} 561 562static int dm9161_config_aneg(struct ugeth_mii_info *mii_info) 563{ 564 struct dm9161_private *priv = mii_info->priv; 565 566 ugphy_vdbg("%s: IN", __FUNCTION__); 567 568 if (0 == priv->resetdone) 569 return -EAGAIN; 570 571 return 0; 572} 573 574static void dm9161_timer(unsigned long data) 575{ 576 struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data; 577 struct dm9161_private *priv = mii_info->priv; 578 u16 status = phy_read(mii_info, MII_BMSR); 579 580 ugphy_vdbg("%s: IN", __FUNCTION__); 581 582 if (status & BMSR_ANEGCOMPLETE) { 583 priv->resetdone = 1; 584 } else 585 mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); 586} 587 588static int dm9161_init(struct ugeth_mii_info *mii_info) 589{ 590 struct dm9161_private *priv; 591 592 ugphy_vdbg("%s: IN", __FUNCTION__); 593 594 /* Allocate the private data structure */ 595 priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL); 596 597 if (NULL == priv) 598 return -ENOMEM; 599 600 mii_info->priv = priv; 601 602 /* Reset is not done yet */ 603 priv->resetdone = 0; 604 605 phy_write(mii_info, MII_BMCR, 606 phy_read(mii_info, MII_BMCR) | BMCR_RESET); 607 608 phy_write(mii_info, MII_BMCR, 609 phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE); 610 611 config_genmii_advert(mii_info); 612 /* Start/Restart aneg */ 613 genmii_config_aneg(mii_info); 614 615 /* Start a timer for DM9161_DELAY seconds to wait 616 * for the PHY to be ready */ 617 init_timer(&priv->timer); 618 priv->timer.function = &dm9161_timer; 619 priv->timer.data = (unsigned long)mii_info; 620 mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); 621 622 return 0; 623} 624 625static void dm9161_close(struct ugeth_mii_info *mii_info) 626{ 627 struct dm9161_private *priv = mii_info->priv; 628 629 ugphy_vdbg("%s: IN", __FUNCTION__); 630 631 del_timer_sync(&priv->timer); 632 kfree(priv); 633} 634 635static int dm9161_ack_interrupt(struct ugeth_mii_info *mii_info) 636{ 637/* FIXME: This lines are for BUG fixing in the mpc8325. 638Remove this from here when it's fixed */ 639 if (bcsr_regs == NULL) 640 bcsr_regs = (u8 *) ioremap(BCSR_PHYS_ADDR, BCSR_SIZE); 641 bcsr_regs[14] |= 0x40; 642 ugphy_vdbg("%s: IN", __FUNCTION__); 643 644 /* Clear the interrupts by reading the reg */ 645 phy_read(mii_info, MII_DM9161_INTR); 646 647 648 return 0; 649} 650 651static int dm9161_config_intr(struct ugeth_mii_info *mii_info) 652{ 653/* FIXME: This lines are for BUG fixing in the mpc8325. 654Remove this from here when it's fixed */ 655 if (bcsr_regs == NULL) { 656 bcsr_regs = (u8 *) ioremap(BCSR_PHYS_ADDR, BCSR_SIZE); 657 bcsr_regs[14] &= ~0x40; 658 } 659 ugphy_vdbg("%s: IN", __FUNCTION__); 660 661 if (mii_info->interrupts == MII_INTERRUPT_ENABLED) 662 phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT); 663 else 664 phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP); 665 666 return 0; 667} 668 669/* Cicada 820x */ 670static struct phy_info phy_info_cis820x = { 671 .phy_id = 0x000fc440, 672 .name = "Cicada Cis8204", 673 .phy_id_mask = 0x000fffc0, 674 .features = MII_GBIT_FEATURES, 675 .init = &cis820x_init, 676 .config_aneg = &gbit_config_aneg, 677 .read_status = &cis820x_read_status, 678 .ack_interrupt = &cis820x_ack_interrupt, 679 .config_intr = &cis820x_config_intr, 680}; 681 682static struct phy_info phy_info_dm9161 = { 683 .phy_id = 0x0181b880, 684 .phy_id_mask = 0x0ffffff0, 685 .name = "Davicom DM9161E", 686 .init = dm9161_init, 687 .config_aneg = dm9161_config_aneg, 688 .read_status = dm9161_read_status, 689 .close = dm9161_close, 690}; 691 692static struct phy_info phy_info_dm9161a = { 693 .phy_id = 0x0181b8a0, 694 .phy_id_mask = 0x0ffffff0, 695 .name = "Davicom DM9161A", 696 .features = MII_BASIC_FEATURES, 697 .init = dm9161_init, 698 .config_aneg = dm9161_config_aneg, 699 .read_status = dm9161_read_status, 700 .ack_interrupt = dm9161_ack_interrupt, 701 .config_intr = dm9161_config_intr, 702 .close = dm9161_close, 703}; 704 705static struct phy_info phy_info_marvell = { 706 .phy_id = 0x01410c00, 707 .phy_id_mask = 0xffffff00, 708 .name = "Marvell 88E11x1", 709 .features = MII_GBIT_FEATURES, 710 .init = &marvell_init, 711 .config_aneg = &marvell_config_aneg, 712 .read_status = &marvell_read_status, 713 .ack_interrupt = &marvell_ack_interrupt, 714 .config_intr = &marvell_config_intr, 715}; 716 717static struct phy_info phy_info_genmii = { 718 .phy_id = 0x00000000, 719 .phy_id_mask = 0x00000000, 720 .name = "Generic MII", 721 .features = MII_BASIC_FEATURES, 722 .config_aneg = genmii_config_aneg, 723 .read_status = genmii_read_status, 724}; 725 726static struct phy_info *phy_info[] = { 727 &phy_info_cis820x, 728 &phy_info_marvell, 729 &phy_info_dm9161, 730 &phy_info_dm9161a, 731 &phy_info_genmii, 732 NULL 733}; 734 735u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum) 736{ 737 u16 retval; 738 unsigned long flags; 739 740 ugphy_vdbg("%s: IN", __FUNCTION__); 741 742 spin_lock_irqsave(&mii_info->mdio_lock, flags); 743 retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum); 744 spin_unlock_irqrestore(&mii_info->mdio_lock, flags); 745 746 return retval; 747} 748 749void phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val) 750{ 751 unsigned long flags; 752 753 ugphy_vdbg("%s: IN", __FUNCTION__); 754 755 spin_lock_irqsave(&mii_info->mdio_lock, flags); 756 mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val); 757 spin_unlock_irqrestore(&mii_info->mdio_lock, flags); 758} 759 760/* Use the PHY ID registers to determine what type of PHY is attached 761 * to device dev. return a struct phy_info structure describing that PHY 762 */ 763struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info) 764{ 765 u16 phy_reg; 766 u32 phy_ID; 767 int i; 768 struct phy_info *theInfo = NULL; 769 struct net_device *dev = mii_info->dev; 770 771 ugphy_vdbg("%s: IN", __FUNCTION__); 772 773 /* Grab the bits from PHYIR1, and put them in the upper half */ 774 phy_reg = phy_read(mii_info, MII_PHYSID1); 775 phy_ID = (phy_reg & 0xffff) << 16; 776 777 /* Grab the bits from PHYIR2, and put them in the lower half */ 778 phy_reg = phy_read(mii_info, MII_PHYSID2); 779 phy_ID |= (phy_reg & 0xffff); 780 781 /* loop through all the known PHY types, and find one that */ 782 /* matches the ID we read from the PHY. */ 783 for (i = 0; phy_info[i]; i++) 784 if (phy_info[i]->phy_id == (phy_ID & phy_info[i]->phy_id_mask)){ 785 theInfo = phy_info[i]; 786 break; 787 } 788 789 /* This shouldn't happen, as we have generic PHY support */ 790 if (theInfo == NULL) { 791 ugphy_info("%s: PHY id %x is not supported!", dev->name, 792 phy_ID); 793 return NULL; 794 } else { 795 ugphy_info("%s: PHY is %s (%x)", dev->name, theInfo->name, 796 phy_ID); 797 } 798 799 return theInfo; 800}