1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * PHY drivers for the sungem ethernet driver. 4 * 5 * This file could be shared with other drivers. 6 * 7 * (c) 2002-2007, Benjamin Herrenscmidt (benh@kernel.crashing.org) 8 * 9 * TODO: 10 * - Add support for PHYs that provide an IRQ line 11 * - Eventually moved the entire polling state machine in 12 * there (out of the eth driver), so that it can easily be 13 * skipped on PHYs that implement it in hardware. 14 * - On LXT971 & BCM5201, Apple uses some chip specific regs 15 * to read the link status. Figure out why and if it makes 16 * sense to do the same (magic aneg ?) 17 * - Apple has some additional power management code for some 18 * Broadcom PHYs that they "hide" from the OpenSource version 19 * of darwin, still need to reverse engineer that 20 */ 21 22 23#include <linux/module.h> 24 25#include <linux/kernel.h> 26#include <linux/types.h> 27#include <linux/netdevice.h> 28#include <linux/etherdevice.h> 29#include <linux/mii.h> 30#include <linux/ethtool.h> 31#include <linux/delay.h> 32 33#ifdef CONFIG_PPC_PMAC 34#include <asm/prom.h> 35#endif 36 37#include <linux/sungem_phy.h> 38 39/* Link modes of the BCM5400 PHY */ 40static const int phy_BCM5400_link_table[8][3] = { 41 { 0, 0, 0 }, /* No link */ 42 { 0, 0, 0 }, /* 10BT Half Duplex */ 43 { 1, 0, 0 }, /* 10BT Full Duplex */ 44 { 0, 1, 0 }, /* 100BT Half Duplex */ 45 { 0, 1, 0 }, /* 100BT Half Duplex */ 46 { 1, 1, 0 }, /* 100BT Full Duplex*/ 47 { 1, 0, 1 }, /* 1000BT */ 48 { 1, 0, 1 }, /* 1000BT */ 49}; 50 51static inline int __sungem_phy_read(struct mii_phy* phy, int id, int reg) 52{ 53 return phy->mdio_read(phy->dev, id, reg); 54} 55 56static inline void __sungem_phy_write(struct mii_phy* phy, int id, int reg, int val) 57{ 58 phy->mdio_write(phy->dev, id, reg, val); 59} 60 61static inline int sungem_phy_read(struct mii_phy* phy, int reg) 62{ 63 return phy->mdio_read(phy->dev, phy->mii_id, reg); 64} 65 66static inline void sungem_phy_write(struct mii_phy* phy, int reg, int val) 67{ 68 phy->mdio_write(phy->dev, phy->mii_id, reg, val); 69} 70 71static int reset_one_mii_phy(struct mii_phy* phy, int phy_id) 72{ 73 u16 val; 74 int limit = 10000; 75 76 val = __sungem_phy_read(phy, phy_id, MII_BMCR); 77 val &= ~(BMCR_ISOLATE | BMCR_PDOWN); 78 val |= BMCR_RESET; 79 __sungem_phy_write(phy, phy_id, MII_BMCR, val); 80 81 udelay(100); 82 83 while (--limit) { 84 val = __sungem_phy_read(phy, phy_id, MII_BMCR); 85 if ((val & BMCR_RESET) == 0) 86 break; 87 udelay(10); 88 } 89 if ((val & BMCR_ISOLATE) && limit > 0) 90 __sungem_phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE); 91 92 return limit <= 0; 93} 94 95static int bcm5201_init(struct mii_phy* phy) 96{ 97 u16 data; 98 99 data = sungem_phy_read(phy, MII_BCM5201_MULTIPHY); 100 data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE; 101 sungem_phy_write(phy, MII_BCM5201_MULTIPHY, data); 102 103 sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0); 104 105 return 0; 106} 107 108static int bcm5201_suspend(struct mii_phy* phy) 109{ 110 sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0); 111 sungem_phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE); 112 113 return 0; 114} 115 116static int bcm5221_init(struct mii_phy* phy) 117{ 118 u16 data; 119 120 data = sungem_phy_read(phy, MII_BCM5221_TEST); 121 sungem_phy_write(phy, MII_BCM5221_TEST, 122 data | MII_BCM5221_TEST_ENABLE_SHADOWS); 123 124 data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2); 125 sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2, 126 data | MII_BCM5221_SHDOW_AUX_STAT2_APD); 127 128 data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4); 129 sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4, 130 data | MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR); 131 132 data = sungem_phy_read(phy, MII_BCM5221_TEST); 133 sungem_phy_write(phy, MII_BCM5221_TEST, 134 data & ~MII_BCM5221_TEST_ENABLE_SHADOWS); 135 136 return 0; 137} 138 139static int bcm5221_suspend(struct mii_phy* phy) 140{ 141 u16 data; 142 143 data = sungem_phy_read(phy, MII_BCM5221_TEST); 144 sungem_phy_write(phy, MII_BCM5221_TEST, 145 data | MII_BCM5221_TEST_ENABLE_SHADOWS); 146 147 data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4); 148 sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4, 149 data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE); 150 151 return 0; 152} 153 154static int bcm5241_init(struct mii_phy* phy) 155{ 156 u16 data; 157 158 data = sungem_phy_read(phy, MII_BCM5221_TEST); 159 sungem_phy_write(phy, MII_BCM5221_TEST, 160 data | MII_BCM5221_TEST_ENABLE_SHADOWS); 161 162 data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2); 163 sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2, 164 data | MII_BCM5221_SHDOW_AUX_STAT2_APD); 165 166 data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4); 167 sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4, 168 data & ~MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR); 169 170 data = sungem_phy_read(phy, MII_BCM5221_TEST); 171 sungem_phy_write(phy, MII_BCM5221_TEST, 172 data & ~MII_BCM5221_TEST_ENABLE_SHADOWS); 173 174 return 0; 175} 176 177static int bcm5241_suspend(struct mii_phy* phy) 178{ 179 u16 data; 180 181 data = sungem_phy_read(phy, MII_BCM5221_TEST); 182 sungem_phy_write(phy, MII_BCM5221_TEST, 183 data | MII_BCM5221_TEST_ENABLE_SHADOWS); 184 185 data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4); 186 sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4, 187 data | MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR); 188 189 return 0; 190} 191 192static int bcm5400_init(struct mii_phy* phy) 193{ 194 u16 data; 195 196 /* Configure for gigabit full duplex */ 197 data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL); 198 data |= MII_BCM5400_AUXCONTROL_PWR10BASET; 199 sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data); 200 201 data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL); 202 data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; 203 sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data); 204 205 udelay(100); 206 207 /* Reset and configure cascaded 10/100 PHY */ 208 (void)reset_one_mii_phy(phy, 0x1f); 209 210 data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY); 211 data |= MII_BCM5201_MULTIPHY_SERIALMODE; 212 __sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data); 213 214 data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL); 215 data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET; 216 sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data); 217 218 return 0; 219} 220 221static int bcm5400_suspend(struct mii_phy* phy) 222{ 223#if 0 /* Commented out in Darwin... someone has those dawn docs ? */ 224 sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN); 225#endif 226 return 0; 227} 228 229static int bcm5401_init(struct mii_phy* phy) 230{ 231 u16 data; 232 int rev; 233 234 rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f; 235 if (rev == 0 || rev == 3) { 236 /* Some revisions of 5401 appear to need this 237 * initialisation sequence to disable, according 238 * to OF, "tap power management" 239 * 240 * WARNING ! OF and Darwin don't agree on the 241 * register addresses. OF seem to interpret the 242 * register numbers below as decimal 243 * 244 * Note: This should (and does) match tg3_init_5401phy_dsp 245 * in the tg3.c driver. -DaveM 246 */ 247 sungem_phy_write(phy, 0x18, 0x0c20); 248 sungem_phy_write(phy, 0x17, 0x0012); 249 sungem_phy_write(phy, 0x15, 0x1804); 250 sungem_phy_write(phy, 0x17, 0x0013); 251 sungem_phy_write(phy, 0x15, 0x1204); 252 sungem_phy_write(phy, 0x17, 0x8006); 253 sungem_phy_write(phy, 0x15, 0x0132); 254 sungem_phy_write(phy, 0x17, 0x8006); 255 sungem_phy_write(phy, 0x15, 0x0232); 256 sungem_phy_write(phy, 0x17, 0x201f); 257 sungem_phy_write(phy, 0x15, 0x0a20); 258 } 259 260 /* Configure for gigabit full duplex */ 261 data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL); 262 data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; 263 sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data); 264 265 udelay(10); 266 267 /* Reset and configure cascaded 10/100 PHY */ 268 (void)reset_one_mii_phy(phy, 0x1f); 269 270 data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY); 271 data |= MII_BCM5201_MULTIPHY_SERIALMODE; 272 __sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data); 273 274 return 0; 275} 276 277static int bcm5401_suspend(struct mii_phy* phy) 278{ 279#if 0 /* Commented out in Darwin... someone has those dawn docs ? */ 280 sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN); 281#endif 282 return 0; 283} 284 285static int bcm5411_init(struct mii_phy* phy) 286{ 287 u16 data; 288 289 /* Here's some more Apple black magic to setup 290 * some voltage stuffs. 291 */ 292 sungem_phy_write(phy, 0x1c, 0x8c23); 293 sungem_phy_write(phy, 0x1c, 0x8ca3); 294 sungem_phy_write(phy, 0x1c, 0x8c23); 295 296 /* Here, Apple seems to want to reset it, do 297 * it as well 298 */ 299 sungem_phy_write(phy, MII_BMCR, BMCR_RESET); 300 sungem_phy_write(phy, MII_BMCR, 0x1340); 301 302 data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL); 303 data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; 304 sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data); 305 306 udelay(10); 307 308 /* Reset and configure cascaded 10/100 PHY */ 309 (void)reset_one_mii_phy(phy, 0x1f); 310 311 return 0; 312} 313 314static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) 315{ 316 u16 ctl, adv; 317 318 phy->autoneg = 1; 319 phy->speed = SPEED_10; 320 phy->duplex = DUPLEX_HALF; 321 phy->pause = 0; 322 phy->advertising = advertise; 323 324 /* Setup standard advertise */ 325 adv = sungem_phy_read(phy, MII_ADVERTISE); 326 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); 327 if (advertise & ADVERTISED_10baseT_Half) 328 adv |= ADVERTISE_10HALF; 329 if (advertise & ADVERTISED_10baseT_Full) 330 adv |= ADVERTISE_10FULL; 331 if (advertise & ADVERTISED_100baseT_Half) 332 adv |= ADVERTISE_100HALF; 333 if (advertise & ADVERTISED_100baseT_Full) 334 adv |= ADVERTISE_100FULL; 335 sungem_phy_write(phy, MII_ADVERTISE, adv); 336 337 /* Start/Restart aneg */ 338 ctl = sungem_phy_read(phy, MII_BMCR); 339 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); 340 sungem_phy_write(phy, MII_BMCR, ctl); 341 342 return 0; 343} 344 345static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) 346{ 347 u16 ctl; 348 349 phy->autoneg = 0; 350 phy->speed = speed; 351 phy->duplex = fd; 352 phy->pause = 0; 353 354 ctl = sungem_phy_read(phy, MII_BMCR); 355 ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE); 356 357 /* First reset the PHY */ 358 sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET); 359 360 /* Select speed & duplex */ 361 switch(speed) { 362 case SPEED_10: 363 break; 364 case SPEED_100: 365 ctl |= BMCR_SPEED100; 366 break; 367 case SPEED_1000: 368 default: 369 return -EINVAL; 370 } 371 if (fd == DUPLEX_FULL) 372 ctl |= BMCR_FULLDPLX; 373 sungem_phy_write(phy, MII_BMCR, ctl); 374 375 return 0; 376} 377 378static int genmii_poll_link(struct mii_phy *phy) 379{ 380 u16 status; 381 382 (void)sungem_phy_read(phy, MII_BMSR); 383 status = sungem_phy_read(phy, MII_BMSR); 384 if ((status & BMSR_LSTATUS) == 0) 385 return 0; 386 if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE)) 387 return 0; 388 return 1; 389} 390 391static int genmii_read_link(struct mii_phy *phy) 392{ 393 u16 lpa; 394 395 if (phy->autoneg) { 396 lpa = sungem_phy_read(phy, MII_LPA); 397 398 if (lpa & (LPA_10FULL | LPA_100FULL)) 399 phy->duplex = DUPLEX_FULL; 400 else 401 phy->duplex = DUPLEX_HALF; 402 if (lpa & (LPA_100FULL | LPA_100HALF)) 403 phy->speed = SPEED_100; 404 else 405 phy->speed = SPEED_10; 406 phy->pause = 0; 407 } 408 /* On non-aneg, we assume what we put in BMCR is the speed, 409 * though magic-aneg shouldn't prevent this case from occurring 410 */ 411 412 return 0; 413} 414 415static int generic_suspend(struct mii_phy* phy) 416{ 417 sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN); 418 419 return 0; 420} 421 422static int bcm5421_init(struct mii_phy* phy) 423{ 424 u16 data; 425 unsigned int id; 426 427 id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2)); 428 429 /* Revision 0 of 5421 needs some fixups */ 430 if (id == 0x002060e0) { 431 /* This is borrowed from MacOS 432 */ 433 sungem_phy_write(phy, 0x18, 0x1007); 434 data = sungem_phy_read(phy, 0x18); 435 sungem_phy_write(phy, 0x18, data | 0x0400); 436 sungem_phy_write(phy, 0x18, 0x0007); 437 data = sungem_phy_read(phy, 0x18); 438 sungem_phy_write(phy, 0x18, data | 0x0800); 439 sungem_phy_write(phy, 0x17, 0x000a); 440 data = sungem_phy_read(phy, 0x15); 441 sungem_phy_write(phy, 0x15, data | 0x0200); 442 } 443 444 /* Pick up some init code from OF for K2 version */ 445 if ((id & 0xfffffff0) == 0x002062e0) { 446 sungem_phy_write(phy, 4, 0x01e1); 447 sungem_phy_write(phy, 9, 0x0300); 448 } 449 450 /* Check if we can enable automatic low power */ 451#ifdef CONFIG_PPC_PMAC 452 if (phy->platform_data) { 453 struct device_node *np = of_get_parent(phy->platform_data); 454 int can_low_power = 1; 455 if (np == NULL || of_get_property(np, "no-autolowpower", NULL)) 456 can_low_power = 0; 457 of_node_put(np); 458 if (can_low_power) { 459 /* Enable automatic low-power */ 460 sungem_phy_write(phy, 0x1c, 0x9002); 461 sungem_phy_write(phy, 0x1c, 0xa821); 462 sungem_phy_write(phy, 0x1c, 0x941d); 463 } 464 } 465#endif /* CONFIG_PPC_PMAC */ 466 467 return 0; 468} 469 470static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise) 471{ 472 u16 ctl, adv; 473 474 phy->autoneg = 1; 475 phy->speed = SPEED_10; 476 phy->duplex = DUPLEX_HALF; 477 phy->pause = 0; 478 phy->advertising = advertise; 479 480 /* Setup standard advertise */ 481 adv = sungem_phy_read(phy, MII_ADVERTISE); 482 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); 483 if (advertise & ADVERTISED_10baseT_Half) 484 adv |= ADVERTISE_10HALF; 485 if (advertise & ADVERTISED_10baseT_Full) 486 adv |= ADVERTISE_10FULL; 487 if (advertise & ADVERTISED_100baseT_Half) 488 adv |= ADVERTISE_100HALF; 489 if (advertise & ADVERTISED_100baseT_Full) 490 adv |= ADVERTISE_100FULL; 491 if (advertise & ADVERTISED_Pause) 492 adv |= ADVERTISE_PAUSE_CAP; 493 if (advertise & ADVERTISED_Asym_Pause) 494 adv |= ADVERTISE_PAUSE_ASYM; 495 sungem_phy_write(phy, MII_ADVERTISE, adv); 496 497 /* Setup 1000BT advertise */ 498 adv = sungem_phy_read(phy, MII_1000BASETCONTROL); 499 adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP); 500 if (advertise & SUPPORTED_1000baseT_Half) 501 adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; 502 if (advertise & SUPPORTED_1000baseT_Full) 503 adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; 504 sungem_phy_write(phy, MII_1000BASETCONTROL, adv); 505 506 /* Start/Restart aneg */ 507 ctl = sungem_phy_read(phy, MII_BMCR); 508 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); 509 sungem_phy_write(phy, MII_BMCR, ctl); 510 511 return 0; 512} 513 514static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd) 515{ 516 u16 ctl; 517 518 phy->autoneg = 0; 519 phy->speed = speed; 520 phy->duplex = fd; 521 phy->pause = 0; 522 523 ctl = sungem_phy_read(phy, MII_BMCR); 524 ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE); 525 526 /* First reset the PHY */ 527 sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET); 528 529 /* Select speed & duplex */ 530 switch(speed) { 531 case SPEED_10: 532 break; 533 case SPEED_100: 534 ctl |= BMCR_SPEED100; 535 break; 536 case SPEED_1000: 537 ctl |= BMCR_SPD2; 538 } 539 if (fd == DUPLEX_FULL) 540 ctl |= BMCR_FULLDPLX; 541 542 // XXX Should we set the sungem to GII now on 1000BT ? 543 544 sungem_phy_write(phy, MII_BMCR, ctl); 545 546 return 0; 547} 548 549static int bcm54xx_read_link(struct mii_phy *phy) 550{ 551 int link_mode; 552 u16 val; 553 554 if (phy->autoneg) { 555 val = sungem_phy_read(phy, MII_BCM5400_AUXSTATUS); 556 link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >> 557 MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT); 558 phy->duplex = phy_BCM5400_link_table[link_mode][0] ? 559 DUPLEX_FULL : DUPLEX_HALF; 560 phy->speed = phy_BCM5400_link_table[link_mode][2] ? 561 SPEED_1000 : 562 (phy_BCM5400_link_table[link_mode][1] ? 563 SPEED_100 : SPEED_10); 564 val = sungem_phy_read(phy, MII_LPA); 565 phy->pause = (phy->duplex == DUPLEX_FULL) && 566 ((val & LPA_PAUSE) != 0); 567 } 568 /* On non-aneg, we assume what we put in BMCR is the speed, 569 * though magic-aneg shouldn't prevent this case from occurring 570 */ 571 572 return 0; 573} 574 575static int marvell88e1111_init(struct mii_phy* phy) 576{ 577 u16 rev; 578 579 /* magic init sequence for rev 0 */ 580 rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f; 581 if (rev == 0) { 582 sungem_phy_write(phy, 0x1d, 0x000a); 583 sungem_phy_write(phy, 0x1e, 0x0821); 584 585 sungem_phy_write(phy, 0x1d, 0x0006); 586 sungem_phy_write(phy, 0x1e, 0x8600); 587 588 sungem_phy_write(phy, 0x1d, 0x000b); 589 sungem_phy_write(phy, 0x1e, 0x0100); 590 591 sungem_phy_write(phy, 0x1d, 0x0004); 592 sungem_phy_write(phy, 0x1e, 0x4850); 593 } 594 return 0; 595} 596 597#define BCM5421_MODE_MASK (1 << 5) 598 599static int bcm5421_poll_link(struct mii_phy* phy) 600{ 601 u32 phy_reg; 602 int mode; 603 604 /* find out in what mode we are */ 605 sungem_phy_write(phy, MII_NCONFIG, 0x1000); 606 phy_reg = sungem_phy_read(phy, MII_NCONFIG); 607 608 mode = (phy_reg & BCM5421_MODE_MASK) >> 5; 609 610 if ( mode == BCM54XX_COPPER) 611 return genmii_poll_link(phy); 612 613 /* try to find out whether we have a link */ 614 sungem_phy_write(phy, MII_NCONFIG, 0x2000); 615 phy_reg = sungem_phy_read(phy, MII_NCONFIG); 616 617 if (phy_reg & 0x0020) 618 return 0; 619 else 620 return 1; 621} 622 623static int bcm5421_read_link(struct mii_phy* phy) 624{ 625 u32 phy_reg; 626 int mode; 627 628 /* find out in what mode we are */ 629 sungem_phy_write(phy, MII_NCONFIG, 0x1000); 630 phy_reg = sungem_phy_read(phy, MII_NCONFIG); 631 632 mode = (phy_reg & BCM5421_MODE_MASK ) >> 5; 633 634 if ( mode == BCM54XX_COPPER) 635 return bcm54xx_read_link(phy); 636 637 phy->speed = SPEED_1000; 638 639 /* find out whether we are running half- or full duplex */ 640 sungem_phy_write(phy, MII_NCONFIG, 0x2000); 641 phy_reg = sungem_phy_read(phy, MII_NCONFIG); 642 643 if ( (phy_reg & 0x0080) >> 7) 644 phy->duplex |= DUPLEX_HALF; 645 else 646 phy->duplex |= DUPLEX_FULL; 647 648 return 0; 649} 650 651static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg) 652{ 653 /* enable fiber mode */ 654 sungem_phy_write(phy, MII_NCONFIG, 0x9020); 655 /* LEDs active in both modes, autosense prio = fiber */ 656 sungem_phy_write(phy, MII_NCONFIG, 0x945f); 657 658 if (!autoneg) { 659 /* switch off fibre autoneg */ 660 sungem_phy_write(phy, MII_NCONFIG, 0xfc01); 661 sungem_phy_write(phy, 0x0b, 0x0004); 662 } 663 664 phy->autoneg = autoneg; 665 666 return 0; 667} 668 669#define BCM5461_FIBER_LINK (1 << 2) 670#define BCM5461_MODE_MASK (3 << 1) 671 672static int bcm5461_poll_link(struct mii_phy* phy) 673{ 674 u32 phy_reg; 675 int mode; 676 677 /* find out in what mode we are */ 678 sungem_phy_write(phy, MII_NCONFIG, 0x7c00); 679 phy_reg = sungem_phy_read(phy, MII_NCONFIG); 680 681 mode = (phy_reg & BCM5461_MODE_MASK ) >> 1; 682 683 if ( mode == BCM54XX_COPPER) 684 return genmii_poll_link(phy); 685 686 /* find out whether we have a link */ 687 sungem_phy_write(phy, MII_NCONFIG, 0x7000); 688 phy_reg = sungem_phy_read(phy, MII_NCONFIG); 689 690 if (phy_reg & BCM5461_FIBER_LINK) 691 return 1; 692 else 693 return 0; 694} 695 696#define BCM5461_FIBER_DUPLEX (1 << 3) 697 698static int bcm5461_read_link(struct mii_phy* phy) 699{ 700 u32 phy_reg; 701 int mode; 702 703 /* find out in what mode we are */ 704 sungem_phy_write(phy, MII_NCONFIG, 0x7c00); 705 phy_reg = sungem_phy_read(phy, MII_NCONFIG); 706 707 mode = (phy_reg & BCM5461_MODE_MASK ) >> 1; 708 709 if ( mode == BCM54XX_COPPER) { 710 return bcm54xx_read_link(phy); 711 } 712 713 phy->speed = SPEED_1000; 714 715 /* find out whether we are running half- or full duplex */ 716 sungem_phy_write(phy, MII_NCONFIG, 0x7000); 717 phy_reg = sungem_phy_read(phy, MII_NCONFIG); 718 719 if (phy_reg & BCM5461_FIBER_DUPLEX) 720 phy->duplex |= DUPLEX_FULL; 721 else 722 phy->duplex |= DUPLEX_HALF; 723 724 return 0; 725} 726 727static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg) 728{ 729 /* select fiber mode, enable 1000 base-X registers */ 730 sungem_phy_write(phy, MII_NCONFIG, 0xfc0b); 731 732 if (autoneg) { 733 /* enable fiber with no autonegotiation */ 734 sungem_phy_write(phy, MII_ADVERTISE, 0x01e0); 735 sungem_phy_write(phy, MII_BMCR, 0x1140); 736 } else { 737 /* enable fiber with autonegotiation */ 738 sungem_phy_write(phy, MII_BMCR, 0x0140); 739 } 740 741 phy->autoneg = autoneg; 742 743 return 0; 744} 745 746static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise) 747{ 748 u16 ctl, adv; 749 750 phy->autoneg = 1; 751 phy->speed = SPEED_10; 752 phy->duplex = DUPLEX_HALF; 753 phy->pause = 0; 754 phy->advertising = advertise; 755 756 /* Setup standard advertise */ 757 adv = sungem_phy_read(phy, MII_ADVERTISE); 758 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); 759 if (advertise & ADVERTISED_10baseT_Half) 760 adv |= ADVERTISE_10HALF; 761 if (advertise & ADVERTISED_10baseT_Full) 762 adv |= ADVERTISE_10FULL; 763 if (advertise & ADVERTISED_100baseT_Half) 764 adv |= ADVERTISE_100HALF; 765 if (advertise & ADVERTISED_100baseT_Full) 766 adv |= ADVERTISE_100FULL; 767 if (advertise & ADVERTISED_Pause) 768 adv |= ADVERTISE_PAUSE_CAP; 769 if (advertise & ADVERTISED_Asym_Pause) 770 adv |= ADVERTISE_PAUSE_ASYM; 771 sungem_phy_write(phy, MII_ADVERTISE, adv); 772 773 /* Setup 1000BT advertise & enable crossover detect 774 * XXX How do we advertise 1000BT ? Darwin source is 775 * confusing here, they read from specific control and 776 * write to control... Someone has specs for those 777 * beasts ? 778 */ 779 adv = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL); 780 adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX; 781 adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | 782 MII_1000BASETCONTROL_HALFDUPLEXCAP); 783 if (advertise & SUPPORTED_1000baseT_Half) 784 adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; 785 if (advertise & SUPPORTED_1000baseT_Full) 786 adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; 787 sungem_phy_write(phy, MII_1000BASETCONTROL, adv); 788 789 /* Start/Restart aneg */ 790 ctl = sungem_phy_read(phy, MII_BMCR); 791 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); 792 sungem_phy_write(phy, MII_BMCR, ctl); 793 794 return 0; 795} 796 797static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd) 798{ 799 u16 ctl, ctl2; 800 801 phy->autoneg = 0; 802 phy->speed = speed; 803 phy->duplex = fd; 804 phy->pause = 0; 805 806 ctl = sungem_phy_read(phy, MII_BMCR); 807 ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE); 808 ctl |= BMCR_RESET; 809 810 /* Select speed & duplex */ 811 switch(speed) { 812 case SPEED_10: 813 break; 814 case SPEED_100: 815 ctl |= BMCR_SPEED100; 816 break; 817 /* I'm not sure about the one below, again, Darwin source is 818 * quite confusing and I lack chip specs 819 */ 820 case SPEED_1000: 821 ctl |= BMCR_SPD2; 822 } 823 if (fd == DUPLEX_FULL) 824 ctl |= BMCR_FULLDPLX; 825 826 /* Disable crossover. Again, the way Apple does it is strange, 827 * though I don't assume they are wrong ;) 828 */ 829 ctl2 = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL); 830 ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX | 831 MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX | 832 MII_1000BASETCONTROL_FULLDUPLEXCAP | 833 MII_1000BASETCONTROL_HALFDUPLEXCAP); 834 if (speed == SPEED_1000) 835 ctl2 |= (fd == DUPLEX_FULL) ? 836 MII_1000BASETCONTROL_FULLDUPLEXCAP : 837 MII_1000BASETCONTROL_HALFDUPLEXCAP; 838 sungem_phy_write(phy, MII_1000BASETCONTROL, ctl2); 839 840 // XXX Should we set the sungem to GII now on 1000BT ? 841 842 sungem_phy_write(phy, MII_BMCR, ctl); 843 844 return 0; 845} 846 847static int marvell_read_link(struct mii_phy *phy) 848{ 849 u16 status, pmask; 850 851 if (phy->autoneg) { 852 status = sungem_phy_read(phy, MII_M1011_PHY_SPEC_STATUS); 853 if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0) 854 return -EAGAIN; 855 if (status & MII_M1011_PHY_SPEC_STATUS_1000) 856 phy->speed = SPEED_1000; 857 else if (status & MII_M1011_PHY_SPEC_STATUS_100) 858 phy->speed = SPEED_100; 859 else 860 phy->speed = SPEED_10; 861 if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) 862 phy->duplex = DUPLEX_FULL; 863 else 864 phy->duplex = DUPLEX_HALF; 865 pmask = MII_M1011_PHY_SPEC_STATUS_TX_PAUSE | 866 MII_M1011_PHY_SPEC_STATUS_RX_PAUSE; 867 phy->pause = (status & pmask) == pmask; 868 } 869 /* On non-aneg, we assume what we put in BMCR is the speed, 870 * though magic-aneg shouldn't prevent this case from occurring 871 */ 872 873 return 0; 874} 875 876#define MII_BASIC_FEATURES \ 877 (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \ 878 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ 879 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | \ 880 SUPPORTED_Pause) 881 882/* On gigabit capable PHYs, we advertise Pause support but not asym pause 883 * support for now as I'm not sure it's supported and Darwin doesn't do 884 * it neither. --BenH. 885 */ 886#define MII_GBIT_FEATURES \ 887 (MII_BASIC_FEATURES | \ 888 SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full) 889 890/* Broadcom BCM 5201 */ 891static const struct mii_phy_ops bcm5201_phy_ops = { 892 .init = bcm5201_init, 893 .suspend = bcm5201_suspend, 894 .setup_aneg = genmii_setup_aneg, 895 .setup_forced = genmii_setup_forced, 896 .poll_link = genmii_poll_link, 897 .read_link = genmii_read_link, 898}; 899 900static struct mii_phy_def bcm5201_phy_def = { 901 .phy_id = 0x00406210, 902 .phy_id_mask = 0xfffffff0, 903 .name = "BCM5201", 904 .features = MII_BASIC_FEATURES, 905 .magic_aneg = 1, 906 .ops = &bcm5201_phy_ops 907}; 908 909/* Broadcom BCM 5221 */ 910static const struct mii_phy_ops bcm5221_phy_ops = { 911 .suspend = bcm5221_suspend, 912 .init = bcm5221_init, 913 .setup_aneg = genmii_setup_aneg, 914 .setup_forced = genmii_setup_forced, 915 .poll_link = genmii_poll_link, 916 .read_link = genmii_read_link, 917}; 918 919static struct mii_phy_def bcm5221_phy_def = { 920 .phy_id = 0x004061e0, 921 .phy_id_mask = 0xfffffff0, 922 .name = "BCM5221", 923 .features = MII_BASIC_FEATURES, 924 .magic_aneg = 1, 925 .ops = &bcm5221_phy_ops 926}; 927 928/* Broadcom BCM 5241 */ 929static const struct mii_phy_ops bcm5241_phy_ops = { 930 .suspend = bcm5241_suspend, 931 .init = bcm5241_init, 932 .setup_aneg = genmii_setup_aneg, 933 .setup_forced = genmii_setup_forced, 934 .poll_link = genmii_poll_link, 935 .read_link = genmii_read_link, 936}; 937static struct mii_phy_def bcm5241_phy_def = { 938 .phy_id = 0x0143bc30, 939 .phy_id_mask = 0xfffffff0, 940 .name = "BCM5241", 941 .features = MII_BASIC_FEATURES, 942 .magic_aneg = 1, 943 .ops = &bcm5241_phy_ops 944}; 945 946/* Broadcom BCM 5400 */ 947static const struct mii_phy_ops bcm5400_phy_ops = { 948 .init = bcm5400_init, 949 .suspend = bcm5400_suspend, 950 .setup_aneg = bcm54xx_setup_aneg, 951 .setup_forced = bcm54xx_setup_forced, 952 .poll_link = genmii_poll_link, 953 .read_link = bcm54xx_read_link, 954}; 955 956static struct mii_phy_def bcm5400_phy_def = { 957 .phy_id = 0x00206040, 958 .phy_id_mask = 0xfffffff0, 959 .name = "BCM5400", 960 .features = MII_GBIT_FEATURES, 961 .magic_aneg = 1, 962 .ops = &bcm5400_phy_ops 963}; 964 965/* Broadcom BCM 5401 */ 966static const struct mii_phy_ops bcm5401_phy_ops = { 967 .init = bcm5401_init, 968 .suspend = bcm5401_suspend, 969 .setup_aneg = bcm54xx_setup_aneg, 970 .setup_forced = bcm54xx_setup_forced, 971 .poll_link = genmii_poll_link, 972 .read_link = bcm54xx_read_link, 973}; 974 975static struct mii_phy_def bcm5401_phy_def = { 976 .phy_id = 0x00206050, 977 .phy_id_mask = 0xfffffff0, 978 .name = "BCM5401", 979 .features = MII_GBIT_FEATURES, 980 .magic_aneg = 1, 981 .ops = &bcm5401_phy_ops 982}; 983 984/* Broadcom BCM 5411 */ 985static const struct mii_phy_ops bcm5411_phy_ops = { 986 .init = bcm5411_init, 987 .suspend = generic_suspend, 988 .setup_aneg = bcm54xx_setup_aneg, 989 .setup_forced = bcm54xx_setup_forced, 990 .poll_link = genmii_poll_link, 991 .read_link = bcm54xx_read_link, 992}; 993 994static struct mii_phy_def bcm5411_phy_def = { 995 .phy_id = 0x00206070, 996 .phy_id_mask = 0xfffffff0, 997 .name = "BCM5411", 998 .features = MII_GBIT_FEATURES, 999 .magic_aneg = 1, 1000 .ops = &bcm5411_phy_ops 1001}; 1002 1003/* Broadcom BCM 5421 */ 1004static const struct mii_phy_ops bcm5421_phy_ops = { 1005 .init = bcm5421_init, 1006 .suspend = generic_suspend, 1007 .setup_aneg = bcm54xx_setup_aneg, 1008 .setup_forced = bcm54xx_setup_forced, 1009 .poll_link = bcm5421_poll_link, 1010 .read_link = bcm5421_read_link, 1011 .enable_fiber = bcm5421_enable_fiber, 1012}; 1013 1014static struct mii_phy_def bcm5421_phy_def = { 1015 .phy_id = 0x002060e0, 1016 .phy_id_mask = 0xfffffff0, 1017 .name = "BCM5421", 1018 .features = MII_GBIT_FEATURES, 1019 .magic_aneg = 1, 1020 .ops = &bcm5421_phy_ops 1021}; 1022 1023/* Broadcom BCM 5421 built-in K2 */ 1024static const struct mii_phy_ops bcm5421k2_phy_ops = { 1025 .init = bcm5421_init, 1026 .suspend = generic_suspend, 1027 .setup_aneg = bcm54xx_setup_aneg, 1028 .setup_forced = bcm54xx_setup_forced, 1029 .poll_link = genmii_poll_link, 1030 .read_link = bcm54xx_read_link, 1031}; 1032 1033static struct mii_phy_def bcm5421k2_phy_def = { 1034 .phy_id = 0x002062e0, 1035 .phy_id_mask = 0xfffffff0, 1036 .name = "BCM5421-K2", 1037 .features = MII_GBIT_FEATURES, 1038 .magic_aneg = 1, 1039 .ops = &bcm5421k2_phy_ops 1040}; 1041 1042static const struct mii_phy_ops bcm5461_phy_ops = { 1043 .init = bcm5421_init, 1044 .suspend = generic_suspend, 1045 .setup_aneg = bcm54xx_setup_aneg, 1046 .setup_forced = bcm54xx_setup_forced, 1047 .poll_link = bcm5461_poll_link, 1048 .read_link = bcm5461_read_link, 1049 .enable_fiber = bcm5461_enable_fiber, 1050}; 1051 1052static struct mii_phy_def bcm5461_phy_def = { 1053 .phy_id = 0x002060c0, 1054 .phy_id_mask = 0xfffffff0, 1055 .name = "BCM5461", 1056 .features = MII_GBIT_FEATURES, 1057 .magic_aneg = 1, 1058 .ops = &bcm5461_phy_ops 1059}; 1060 1061/* Broadcom BCM 5462 built-in Vesta */ 1062static const struct mii_phy_ops bcm5462V_phy_ops = { 1063 .init = bcm5421_init, 1064 .suspend = generic_suspend, 1065 .setup_aneg = bcm54xx_setup_aneg, 1066 .setup_forced = bcm54xx_setup_forced, 1067 .poll_link = genmii_poll_link, 1068 .read_link = bcm54xx_read_link, 1069}; 1070 1071static struct mii_phy_def bcm5462V_phy_def = { 1072 .phy_id = 0x002060d0, 1073 .phy_id_mask = 0xfffffff0, 1074 .name = "BCM5462-Vesta", 1075 .features = MII_GBIT_FEATURES, 1076 .magic_aneg = 1, 1077 .ops = &bcm5462V_phy_ops 1078}; 1079 1080/* Marvell 88E1101 amd 88E1111 */ 1081static const struct mii_phy_ops marvell88e1101_phy_ops = { 1082 .suspend = generic_suspend, 1083 .setup_aneg = marvell_setup_aneg, 1084 .setup_forced = marvell_setup_forced, 1085 .poll_link = genmii_poll_link, 1086 .read_link = marvell_read_link 1087}; 1088 1089static const struct mii_phy_ops marvell88e1111_phy_ops = { 1090 .init = marvell88e1111_init, 1091 .suspend = generic_suspend, 1092 .setup_aneg = marvell_setup_aneg, 1093 .setup_forced = marvell_setup_forced, 1094 .poll_link = genmii_poll_link, 1095 .read_link = marvell_read_link 1096}; 1097 1098/* two revs in darwin for the 88e1101 ... I could use a datasheet 1099 * to get the proper names... 1100 */ 1101static struct mii_phy_def marvell88e1101v1_phy_def = { 1102 .phy_id = 0x01410c20, 1103 .phy_id_mask = 0xfffffff0, 1104 .name = "Marvell 88E1101v1", 1105 .features = MII_GBIT_FEATURES, 1106 .magic_aneg = 1, 1107 .ops = &marvell88e1101_phy_ops 1108}; 1109static struct mii_phy_def marvell88e1101v2_phy_def = { 1110 .phy_id = 0x01410c60, 1111 .phy_id_mask = 0xfffffff0, 1112 .name = "Marvell 88E1101v2", 1113 .features = MII_GBIT_FEATURES, 1114 .magic_aneg = 1, 1115 .ops = &marvell88e1101_phy_ops 1116}; 1117static struct mii_phy_def marvell88e1111_phy_def = { 1118 .phy_id = 0x01410cc0, 1119 .phy_id_mask = 0xfffffff0, 1120 .name = "Marvell 88E1111", 1121 .features = MII_GBIT_FEATURES, 1122 .magic_aneg = 1, 1123 .ops = &marvell88e1111_phy_ops 1124}; 1125 1126/* Generic implementation for most 10/100 PHYs */ 1127static const struct mii_phy_ops generic_phy_ops = { 1128 .setup_aneg = genmii_setup_aneg, 1129 .setup_forced = genmii_setup_forced, 1130 .poll_link = genmii_poll_link, 1131 .read_link = genmii_read_link 1132}; 1133 1134static struct mii_phy_def genmii_phy_def = { 1135 .phy_id = 0x00000000, 1136 .phy_id_mask = 0x00000000, 1137 .name = "Generic MII", 1138 .features = MII_BASIC_FEATURES, 1139 .magic_aneg = 0, 1140 .ops = &generic_phy_ops 1141}; 1142 1143static struct mii_phy_def* mii_phy_table[] = { 1144 &bcm5201_phy_def, 1145 &bcm5221_phy_def, 1146 &bcm5241_phy_def, 1147 &bcm5400_phy_def, 1148 &bcm5401_phy_def, 1149 &bcm5411_phy_def, 1150 &bcm5421_phy_def, 1151 &bcm5421k2_phy_def, 1152 &bcm5461_phy_def, 1153 &bcm5462V_phy_def, 1154 &marvell88e1101v1_phy_def, 1155 &marvell88e1101v2_phy_def, 1156 &marvell88e1111_phy_def, 1157 &genmii_phy_def, 1158 NULL 1159}; 1160 1161int sungem_phy_probe(struct mii_phy *phy, int mii_id) 1162{ 1163 int rc; 1164 u32 id; 1165 struct mii_phy_def* def; 1166 int i; 1167 1168 /* We do not reset the mii_phy structure as the driver 1169 * may re-probe the PHY regulary 1170 */ 1171 phy->mii_id = mii_id; 1172 1173 /* Take PHY out of isloate mode and reset it. */ 1174 rc = reset_one_mii_phy(phy, mii_id); 1175 if (rc) 1176 goto fail; 1177 1178 /* Read ID and find matching entry */ 1179 id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2)); 1180 printk(KERN_DEBUG KBUILD_MODNAME ": " "PHY ID: %x, addr: %x\n", 1181 id, mii_id); 1182 for (i=0; (def = mii_phy_table[i]) != NULL; i++) 1183 if ((id & def->phy_id_mask) == def->phy_id) 1184 break; 1185 /* Should never be NULL (we have a generic entry), but... */ 1186 if (def == NULL) 1187 goto fail; 1188 1189 phy->def = def; 1190 1191 return 0; 1192fail: 1193 phy->speed = 0; 1194 phy->duplex = 0; 1195 phy->pause = 0; 1196 phy->advertising = 0; 1197 return -ENODEV; 1198} 1199 1200EXPORT_SYMBOL(sungem_phy_probe); 1201MODULE_LICENSE("GPL"); 1202