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