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 */ 40 static 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 51 static 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 56 static 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 61 static 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 66 static 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 71 static 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 95 static 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 108 static 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 116 static 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 139 static 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 154 static 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 177 static 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 192 static 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 221 static 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 229 static 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 277 static 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 285 static 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 314 static 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 345 static 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 378 static 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 391 static 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 415 static int generic_suspend(struct mii_phy* phy) 416 { 417 sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN); 418 419 return 0; 420 } 421 422 static 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 if (can_low_power) { 458 /* Enable automatic low-power */ 459 sungem_phy_write(phy, 0x1c, 0x9002); 460 sungem_phy_write(phy, 0x1c, 0xa821); 461 sungem_phy_write(phy, 0x1c, 0x941d); 462 } 463 } 464 #endif /* CONFIG_PPC_PMAC */ 465 466 return 0; 467 } 468 469 static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise) 470 { 471 u16 ctl, adv; 472 473 phy->autoneg = 1; 474 phy->speed = SPEED_10; 475 phy->duplex = DUPLEX_HALF; 476 phy->pause = 0; 477 phy->advertising = advertise; 478 479 /* Setup standard advertise */ 480 adv = sungem_phy_read(phy, MII_ADVERTISE); 481 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); 482 if (advertise & ADVERTISED_10baseT_Half) 483 adv |= ADVERTISE_10HALF; 484 if (advertise & ADVERTISED_10baseT_Full) 485 adv |= ADVERTISE_10FULL; 486 if (advertise & ADVERTISED_100baseT_Half) 487 adv |= ADVERTISE_100HALF; 488 if (advertise & ADVERTISED_100baseT_Full) 489 adv |= ADVERTISE_100FULL; 490 if (advertise & ADVERTISED_Pause) 491 adv |= ADVERTISE_PAUSE_CAP; 492 if (advertise & ADVERTISED_Asym_Pause) 493 adv |= ADVERTISE_PAUSE_ASYM; 494 sungem_phy_write(phy, MII_ADVERTISE, adv); 495 496 /* Setup 1000BT advertise */ 497 adv = sungem_phy_read(phy, MII_1000BASETCONTROL); 498 adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP); 499 if (advertise & SUPPORTED_1000baseT_Half) 500 adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; 501 if (advertise & SUPPORTED_1000baseT_Full) 502 adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; 503 sungem_phy_write(phy, MII_1000BASETCONTROL, adv); 504 505 /* Start/Restart aneg */ 506 ctl = sungem_phy_read(phy, MII_BMCR); 507 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); 508 sungem_phy_write(phy, MII_BMCR, ctl); 509 510 return 0; 511 } 512 513 static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd) 514 { 515 u16 ctl; 516 517 phy->autoneg = 0; 518 phy->speed = speed; 519 phy->duplex = fd; 520 phy->pause = 0; 521 522 ctl = sungem_phy_read(phy, MII_BMCR); 523 ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE); 524 525 /* First reset the PHY */ 526 sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET); 527 528 /* Select speed & duplex */ 529 switch(speed) { 530 case SPEED_10: 531 break; 532 case SPEED_100: 533 ctl |= BMCR_SPEED100; 534 break; 535 case SPEED_1000: 536 ctl |= BMCR_SPD2; 537 } 538 if (fd == DUPLEX_FULL) 539 ctl |= BMCR_FULLDPLX; 540 541 // XXX Should we set the sungem to GII now on 1000BT ? 542 543 sungem_phy_write(phy, MII_BMCR, ctl); 544 545 return 0; 546 } 547 548 static int bcm54xx_read_link(struct mii_phy *phy) 549 { 550 int link_mode; 551 u16 val; 552 553 if (phy->autoneg) { 554 val = sungem_phy_read(phy, MII_BCM5400_AUXSTATUS); 555 link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >> 556 MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT); 557 phy->duplex = phy_BCM5400_link_table[link_mode][0] ? 558 DUPLEX_FULL : DUPLEX_HALF; 559 phy->speed = phy_BCM5400_link_table[link_mode][2] ? 560 SPEED_1000 : 561 (phy_BCM5400_link_table[link_mode][1] ? 562 SPEED_100 : SPEED_10); 563 val = sungem_phy_read(phy, MII_LPA); 564 phy->pause = (phy->duplex == DUPLEX_FULL) && 565 ((val & LPA_PAUSE) != 0); 566 } 567 /* On non-aneg, we assume what we put in BMCR is the speed, 568 * though magic-aneg shouldn't prevent this case from occurring 569 */ 570 571 return 0; 572 } 573 574 static int marvell88e1111_init(struct mii_phy* phy) 575 { 576 u16 rev; 577 578 /* magic init sequence for rev 0 */ 579 rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f; 580 if (rev == 0) { 581 sungem_phy_write(phy, 0x1d, 0x000a); 582 sungem_phy_write(phy, 0x1e, 0x0821); 583 584 sungem_phy_write(phy, 0x1d, 0x0006); 585 sungem_phy_write(phy, 0x1e, 0x8600); 586 587 sungem_phy_write(phy, 0x1d, 0x000b); 588 sungem_phy_write(phy, 0x1e, 0x0100); 589 590 sungem_phy_write(phy, 0x1d, 0x0004); 591 sungem_phy_write(phy, 0x1e, 0x4850); 592 } 593 return 0; 594 } 595 596 #define BCM5421_MODE_MASK (1 << 5) 597 598 static int bcm5421_poll_link(struct mii_phy* phy) 599 { 600 u32 phy_reg; 601 int mode; 602 603 /* find out in what mode we are */ 604 sungem_phy_write(phy, MII_NCONFIG, 0x1000); 605 phy_reg = sungem_phy_read(phy, MII_NCONFIG); 606 607 mode = (phy_reg & BCM5421_MODE_MASK) >> 5; 608 609 if ( mode == BCM54XX_COPPER) 610 return genmii_poll_link(phy); 611 612 /* try to find out whether we have a link */ 613 sungem_phy_write(phy, MII_NCONFIG, 0x2000); 614 phy_reg = sungem_phy_read(phy, MII_NCONFIG); 615 616 if (phy_reg & 0x0020) 617 return 0; 618 else 619 return 1; 620 } 621 622 static int bcm5421_read_link(struct mii_phy* phy) 623 { 624 u32 phy_reg; 625 int mode; 626 627 /* find out in what mode we are */ 628 sungem_phy_write(phy, MII_NCONFIG, 0x1000); 629 phy_reg = sungem_phy_read(phy, MII_NCONFIG); 630 631 mode = (phy_reg & BCM5421_MODE_MASK ) >> 5; 632 633 if ( mode == BCM54XX_COPPER) 634 return bcm54xx_read_link(phy); 635 636 phy->speed = SPEED_1000; 637 638 /* find out whether we are running half- or full duplex */ 639 sungem_phy_write(phy, MII_NCONFIG, 0x2000); 640 phy_reg = sungem_phy_read(phy, MII_NCONFIG); 641 642 if ( (phy_reg & 0x0080) >> 7) 643 phy->duplex |= DUPLEX_HALF; 644 else 645 phy->duplex |= DUPLEX_FULL; 646 647 return 0; 648 } 649 650 static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg) 651 { 652 /* enable fiber mode */ 653 sungem_phy_write(phy, MII_NCONFIG, 0x9020); 654 /* LEDs active in both modes, autosense prio = fiber */ 655 sungem_phy_write(phy, MII_NCONFIG, 0x945f); 656 657 if (!autoneg) { 658 /* switch off fibre autoneg */ 659 sungem_phy_write(phy, MII_NCONFIG, 0xfc01); 660 sungem_phy_write(phy, 0x0b, 0x0004); 661 } 662 663 phy->autoneg = autoneg; 664 665 return 0; 666 } 667 668 #define BCM5461_FIBER_LINK (1 << 2) 669 #define BCM5461_MODE_MASK (3 << 1) 670 671 static int bcm5461_poll_link(struct mii_phy* phy) 672 { 673 u32 phy_reg; 674 int mode; 675 676 /* find out in what mode we are */ 677 sungem_phy_write(phy, MII_NCONFIG, 0x7c00); 678 phy_reg = sungem_phy_read(phy, MII_NCONFIG); 679 680 mode = (phy_reg & BCM5461_MODE_MASK ) >> 1; 681 682 if ( mode == BCM54XX_COPPER) 683 return genmii_poll_link(phy); 684 685 /* find out whether we have a link */ 686 sungem_phy_write(phy, MII_NCONFIG, 0x7000); 687 phy_reg = sungem_phy_read(phy, MII_NCONFIG); 688 689 if (phy_reg & BCM5461_FIBER_LINK) 690 return 1; 691 else 692 return 0; 693 } 694 695 #define BCM5461_FIBER_DUPLEX (1 << 3) 696 697 static int bcm5461_read_link(struct mii_phy* phy) 698 { 699 u32 phy_reg; 700 int mode; 701 702 /* find out in what mode we are */ 703 sungem_phy_write(phy, MII_NCONFIG, 0x7c00); 704 phy_reg = sungem_phy_read(phy, MII_NCONFIG); 705 706 mode = (phy_reg & BCM5461_MODE_MASK ) >> 1; 707 708 if ( mode == BCM54XX_COPPER) { 709 return bcm54xx_read_link(phy); 710 } 711 712 phy->speed = SPEED_1000; 713 714 /* find out whether we are running half- or full duplex */ 715 sungem_phy_write(phy, MII_NCONFIG, 0x7000); 716 phy_reg = sungem_phy_read(phy, MII_NCONFIG); 717 718 if (phy_reg & BCM5461_FIBER_DUPLEX) 719 phy->duplex |= DUPLEX_FULL; 720 else 721 phy->duplex |= DUPLEX_HALF; 722 723 return 0; 724 } 725 726 static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg) 727 { 728 /* select fiber mode, enable 1000 base-X registers */ 729 sungem_phy_write(phy, MII_NCONFIG, 0xfc0b); 730 731 if (autoneg) { 732 /* enable fiber with no autonegotiation */ 733 sungem_phy_write(phy, MII_ADVERTISE, 0x01e0); 734 sungem_phy_write(phy, MII_BMCR, 0x1140); 735 } else { 736 /* enable fiber with autonegotiation */ 737 sungem_phy_write(phy, MII_BMCR, 0x0140); 738 } 739 740 phy->autoneg = autoneg; 741 742 return 0; 743 } 744 745 static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise) 746 { 747 u16 ctl, adv; 748 749 phy->autoneg = 1; 750 phy->speed = SPEED_10; 751 phy->duplex = DUPLEX_HALF; 752 phy->pause = 0; 753 phy->advertising = advertise; 754 755 /* Setup standard advertise */ 756 adv = sungem_phy_read(phy, MII_ADVERTISE); 757 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); 758 if (advertise & ADVERTISED_10baseT_Half) 759 adv |= ADVERTISE_10HALF; 760 if (advertise & ADVERTISED_10baseT_Full) 761 adv |= ADVERTISE_10FULL; 762 if (advertise & ADVERTISED_100baseT_Half) 763 adv |= ADVERTISE_100HALF; 764 if (advertise & ADVERTISED_100baseT_Full) 765 adv |= ADVERTISE_100FULL; 766 if (advertise & ADVERTISED_Pause) 767 adv |= ADVERTISE_PAUSE_CAP; 768 if (advertise & ADVERTISED_Asym_Pause) 769 adv |= ADVERTISE_PAUSE_ASYM; 770 sungem_phy_write(phy, MII_ADVERTISE, adv); 771 772 /* Setup 1000BT advertise & enable crossover detect 773 * XXX How do we advertise 1000BT ? Darwin source is 774 * confusing here, they read from specific control and 775 * write to control... Someone has specs for those 776 * beasts ? 777 */ 778 adv = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL); 779 adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX; 780 adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | 781 MII_1000BASETCONTROL_HALFDUPLEXCAP); 782 if (advertise & SUPPORTED_1000baseT_Half) 783 adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; 784 if (advertise & SUPPORTED_1000baseT_Full) 785 adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; 786 sungem_phy_write(phy, MII_1000BASETCONTROL, adv); 787 788 /* Start/Restart aneg */ 789 ctl = sungem_phy_read(phy, MII_BMCR); 790 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); 791 sungem_phy_write(phy, MII_BMCR, ctl); 792 793 return 0; 794 } 795 796 static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd) 797 { 798 u16 ctl, ctl2; 799 800 phy->autoneg = 0; 801 phy->speed = speed; 802 phy->duplex = fd; 803 phy->pause = 0; 804 805 ctl = sungem_phy_read(phy, MII_BMCR); 806 ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE); 807 ctl |= BMCR_RESET; 808 809 /* Select speed & duplex */ 810 switch(speed) { 811 case SPEED_10: 812 break; 813 case SPEED_100: 814 ctl |= BMCR_SPEED100; 815 break; 816 /* I'm not sure about the one below, again, Darwin source is 817 * quite confusing and I lack chip specs 818 */ 819 case SPEED_1000: 820 ctl |= BMCR_SPD2; 821 } 822 if (fd == DUPLEX_FULL) 823 ctl |= BMCR_FULLDPLX; 824 825 /* Disable crossover. Again, the way Apple does it is strange, 826 * though I don't assume they are wrong ;) 827 */ 828 ctl2 = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL); 829 ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX | 830 MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX | 831 MII_1000BASETCONTROL_FULLDUPLEXCAP | 832 MII_1000BASETCONTROL_HALFDUPLEXCAP); 833 if (speed == SPEED_1000) 834 ctl2 |= (fd == DUPLEX_FULL) ? 835 MII_1000BASETCONTROL_FULLDUPLEXCAP : 836 MII_1000BASETCONTROL_HALFDUPLEXCAP; 837 sungem_phy_write(phy, MII_1000BASETCONTROL, ctl2); 838 839 // XXX Should we set the sungem to GII now on 1000BT ? 840 841 sungem_phy_write(phy, MII_BMCR, ctl); 842 843 return 0; 844 } 845 846 static int marvell_read_link(struct mii_phy *phy) 847 { 848 u16 status, pmask; 849 850 if (phy->autoneg) { 851 status = sungem_phy_read(phy, MII_M1011_PHY_SPEC_STATUS); 852 if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0) 853 return -EAGAIN; 854 if (status & MII_M1011_PHY_SPEC_STATUS_1000) 855 phy->speed = SPEED_1000; 856 else if (status & MII_M1011_PHY_SPEC_STATUS_100) 857 phy->speed = SPEED_100; 858 else 859 phy->speed = SPEED_10; 860 if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) 861 phy->duplex = DUPLEX_FULL; 862 else 863 phy->duplex = DUPLEX_HALF; 864 pmask = MII_M1011_PHY_SPEC_STATUS_TX_PAUSE | 865 MII_M1011_PHY_SPEC_STATUS_RX_PAUSE; 866 phy->pause = (status & pmask) == pmask; 867 } 868 /* On non-aneg, we assume what we put in BMCR is the speed, 869 * though magic-aneg shouldn't prevent this case from occurring 870 */ 871 872 return 0; 873 } 874 875 #define MII_BASIC_FEATURES \ 876 (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \ 877 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ 878 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | \ 879 SUPPORTED_Pause) 880 881 /* On gigabit capable PHYs, we advertise Pause support but not asym pause 882 * support for now as I'm not sure it's supported and Darwin doesn't do 883 * it neither. --BenH. 884 */ 885 #define MII_GBIT_FEATURES \ 886 (MII_BASIC_FEATURES | \ 887 SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full) 888 889 /* Broadcom BCM 5201 */ 890 static const struct mii_phy_ops bcm5201_phy_ops = { 891 .init = bcm5201_init, 892 .suspend = bcm5201_suspend, 893 .setup_aneg = genmii_setup_aneg, 894 .setup_forced = genmii_setup_forced, 895 .poll_link = genmii_poll_link, 896 .read_link = genmii_read_link, 897 }; 898 899 static struct mii_phy_def bcm5201_phy_def = { 900 .phy_id = 0x00406210, 901 .phy_id_mask = 0xfffffff0, 902 .name = "BCM5201", 903 .features = MII_BASIC_FEATURES, 904 .magic_aneg = 1, 905 .ops = &bcm5201_phy_ops 906 }; 907 908 /* Broadcom BCM 5221 */ 909 static const struct mii_phy_ops bcm5221_phy_ops = { 910 .suspend = bcm5221_suspend, 911 .init = bcm5221_init, 912 .setup_aneg = genmii_setup_aneg, 913 .setup_forced = genmii_setup_forced, 914 .poll_link = genmii_poll_link, 915 .read_link = genmii_read_link, 916 }; 917 918 static struct mii_phy_def bcm5221_phy_def = { 919 .phy_id = 0x004061e0, 920 .phy_id_mask = 0xfffffff0, 921 .name = "BCM5221", 922 .features = MII_BASIC_FEATURES, 923 .magic_aneg = 1, 924 .ops = &bcm5221_phy_ops 925 }; 926 927 /* Broadcom BCM 5241 */ 928 static const struct mii_phy_ops bcm5241_phy_ops = { 929 .suspend = bcm5241_suspend, 930 .init = bcm5241_init, 931 .setup_aneg = genmii_setup_aneg, 932 .setup_forced = genmii_setup_forced, 933 .poll_link = genmii_poll_link, 934 .read_link = genmii_read_link, 935 }; 936 static struct mii_phy_def bcm5241_phy_def = { 937 .phy_id = 0x0143bc30, 938 .phy_id_mask = 0xfffffff0, 939 .name = "BCM5241", 940 .features = MII_BASIC_FEATURES, 941 .magic_aneg = 1, 942 .ops = &bcm5241_phy_ops 943 }; 944 945 /* Broadcom BCM 5400 */ 946 static const struct mii_phy_ops bcm5400_phy_ops = { 947 .init = bcm5400_init, 948 .suspend = bcm5400_suspend, 949 .setup_aneg = bcm54xx_setup_aneg, 950 .setup_forced = bcm54xx_setup_forced, 951 .poll_link = genmii_poll_link, 952 .read_link = bcm54xx_read_link, 953 }; 954 955 static struct mii_phy_def bcm5400_phy_def = { 956 .phy_id = 0x00206040, 957 .phy_id_mask = 0xfffffff0, 958 .name = "BCM5400", 959 .features = MII_GBIT_FEATURES, 960 .magic_aneg = 1, 961 .ops = &bcm5400_phy_ops 962 }; 963 964 /* Broadcom BCM 5401 */ 965 static const struct mii_phy_ops bcm5401_phy_ops = { 966 .init = bcm5401_init, 967 .suspend = bcm5401_suspend, 968 .setup_aneg = bcm54xx_setup_aneg, 969 .setup_forced = bcm54xx_setup_forced, 970 .poll_link = genmii_poll_link, 971 .read_link = bcm54xx_read_link, 972 }; 973 974 static struct mii_phy_def bcm5401_phy_def = { 975 .phy_id = 0x00206050, 976 .phy_id_mask = 0xfffffff0, 977 .name = "BCM5401", 978 .features = MII_GBIT_FEATURES, 979 .magic_aneg = 1, 980 .ops = &bcm5401_phy_ops 981 }; 982 983 /* Broadcom BCM 5411 */ 984 static const struct mii_phy_ops bcm5411_phy_ops = { 985 .init = bcm5411_init, 986 .suspend = generic_suspend, 987 .setup_aneg = bcm54xx_setup_aneg, 988 .setup_forced = bcm54xx_setup_forced, 989 .poll_link = genmii_poll_link, 990 .read_link = bcm54xx_read_link, 991 }; 992 993 static struct mii_phy_def bcm5411_phy_def = { 994 .phy_id = 0x00206070, 995 .phy_id_mask = 0xfffffff0, 996 .name = "BCM5411", 997 .features = MII_GBIT_FEATURES, 998 .magic_aneg = 1, 999 .ops = &bcm5411_phy_ops 1000 }; 1001 1002 /* Broadcom BCM 5421 */ 1003 static const struct mii_phy_ops bcm5421_phy_ops = { 1004 .init = bcm5421_init, 1005 .suspend = generic_suspend, 1006 .setup_aneg = bcm54xx_setup_aneg, 1007 .setup_forced = bcm54xx_setup_forced, 1008 .poll_link = bcm5421_poll_link, 1009 .read_link = bcm5421_read_link, 1010 .enable_fiber = bcm5421_enable_fiber, 1011 }; 1012 1013 static struct mii_phy_def bcm5421_phy_def = { 1014 .phy_id = 0x002060e0, 1015 .phy_id_mask = 0xfffffff0, 1016 .name = "BCM5421", 1017 .features = MII_GBIT_FEATURES, 1018 .magic_aneg = 1, 1019 .ops = &bcm5421_phy_ops 1020 }; 1021 1022 /* Broadcom BCM 5421 built-in K2 */ 1023 static const struct mii_phy_ops bcm5421k2_phy_ops = { 1024 .init = bcm5421_init, 1025 .suspend = generic_suspend, 1026 .setup_aneg = bcm54xx_setup_aneg, 1027 .setup_forced = bcm54xx_setup_forced, 1028 .poll_link = genmii_poll_link, 1029 .read_link = bcm54xx_read_link, 1030 }; 1031 1032 static struct mii_phy_def bcm5421k2_phy_def = { 1033 .phy_id = 0x002062e0, 1034 .phy_id_mask = 0xfffffff0, 1035 .name = "BCM5421-K2", 1036 .features = MII_GBIT_FEATURES, 1037 .magic_aneg = 1, 1038 .ops = &bcm5421k2_phy_ops 1039 }; 1040 1041 static const struct mii_phy_ops bcm5461_phy_ops = { 1042 .init = bcm5421_init, 1043 .suspend = generic_suspend, 1044 .setup_aneg = bcm54xx_setup_aneg, 1045 .setup_forced = bcm54xx_setup_forced, 1046 .poll_link = bcm5461_poll_link, 1047 .read_link = bcm5461_read_link, 1048 .enable_fiber = bcm5461_enable_fiber, 1049 }; 1050 1051 static struct mii_phy_def bcm5461_phy_def = { 1052 .phy_id = 0x002060c0, 1053 .phy_id_mask = 0xfffffff0, 1054 .name = "BCM5461", 1055 .features = MII_GBIT_FEATURES, 1056 .magic_aneg = 1, 1057 .ops = &bcm5461_phy_ops 1058 }; 1059 1060 /* Broadcom BCM 5462 built-in Vesta */ 1061 static const struct mii_phy_ops bcm5462V_phy_ops = { 1062 .init = bcm5421_init, 1063 .suspend = generic_suspend, 1064 .setup_aneg = bcm54xx_setup_aneg, 1065 .setup_forced = bcm54xx_setup_forced, 1066 .poll_link = genmii_poll_link, 1067 .read_link = bcm54xx_read_link, 1068 }; 1069 1070 static struct mii_phy_def bcm5462V_phy_def = { 1071 .phy_id = 0x002060d0, 1072 .phy_id_mask = 0xfffffff0, 1073 .name = "BCM5462-Vesta", 1074 .features = MII_GBIT_FEATURES, 1075 .magic_aneg = 1, 1076 .ops = &bcm5462V_phy_ops 1077 }; 1078 1079 /* Marvell 88E1101 amd 88E1111 */ 1080 static const struct mii_phy_ops marvell88e1101_phy_ops = { 1081 .suspend = generic_suspend, 1082 .setup_aneg = marvell_setup_aneg, 1083 .setup_forced = marvell_setup_forced, 1084 .poll_link = genmii_poll_link, 1085 .read_link = marvell_read_link 1086 }; 1087 1088 static const struct mii_phy_ops marvell88e1111_phy_ops = { 1089 .init = marvell88e1111_init, 1090 .suspend = generic_suspend, 1091 .setup_aneg = marvell_setup_aneg, 1092 .setup_forced = marvell_setup_forced, 1093 .poll_link = genmii_poll_link, 1094 .read_link = marvell_read_link 1095 }; 1096 1097 /* two revs in darwin for the 88e1101 ... I could use a datasheet 1098 * to get the proper names... 1099 */ 1100 static struct mii_phy_def marvell88e1101v1_phy_def = { 1101 .phy_id = 0x01410c20, 1102 .phy_id_mask = 0xfffffff0, 1103 .name = "Marvell 88E1101v1", 1104 .features = MII_GBIT_FEATURES, 1105 .magic_aneg = 1, 1106 .ops = &marvell88e1101_phy_ops 1107 }; 1108 static struct mii_phy_def marvell88e1101v2_phy_def = { 1109 .phy_id = 0x01410c60, 1110 .phy_id_mask = 0xfffffff0, 1111 .name = "Marvell 88E1101v2", 1112 .features = MII_GBIT_FEATURES, 1113 .magic_aneg = 1, 1114 .ops = &marvell88e1101_phy_ops 1115 }; 1116 static struct mii_phy_def marvell88e1111_phy_def = { 1117 .phy_id = 0x01410cc0, 1118 .phy_id_mask = 0xfffffff0, 1119 .name = "Marvell 88E1111", 1120 .features = MII_GBIT_FEATURES, 1121 .magic_aneg = 1, 1122 .ops = &marvell88e1111_phy_ops 1123 }; 1124 1125 /* Generic implementation for most 10/100 PHYs */ 1126 static const struct mii_phy_ops generic_phy_ops = { 1127 .setup_aneg = genmii_setup_aneg, 1128 .setup_forced = genmii_setup_forced, 1129 .poll_link = genmii_poll_link, 1130 .read_link = genmii_read_link 1131 }; 1132 1133 static struct mii_phy_def genmii_phy_def = { 1134 .phy_id = 0x00000000, 1135 .phy_id_mask = 0x00000000, 1136 .name = "Generic MII", 1137 .features = MII_BASIC_FEATURES, 1138 .magic_aneg = 0, 1139 .ops = &generic_phy_ops 1140 }; 1141 1142 static struct mii_phy_def* mii_phy_table[] = { 1143 &bcm5201_phy_def, 1144 &bcm5221_phy_def, 1145 &bcm5241_phy_def, 1146 &bcm5400_phy_def, 1147 &bcm5401_phy_def, 1148 &bcm5411_phy_def, 1149 &bcm5421_phy_def, 1150 &bcm5421k2_phy_def, 1151 &bcm5461_phy_def, 1152 &bcm5462V_phy_def, 1153 &marvell88e1101v1_phy_def, 1154 &marvell88e1101v2_phy_def, 1155 &marvell88e1111_phy_def, 1156 &genmii_phy_def, 1157 NULL 1158 }; 1159 1160 int sungem_phy_probe(struct mii_phy *phy, int mii_id) 1161 { 1162 int rc; 1163 u32 id; 1164 struct mii_phy_def* def; 1165 int i; 1166 1167 /* We do not reset the mii_phy structure as the driver 1168 * may re-probe the PHY regulary 1169 */ 1170 phy->mii_id = mii_id; 1171 1172 /* Take PHY out of isloate mode and reset it. */ 1173 rc = reset_one_mii_phy(phy, mii_id); 1174 if (rc) 1175 goto fail; 1176 1177 /* Read ID and find matching entry */ 1178 id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2)); 1179 printk(KERN_DEBUG KBUILD_MODNAME ": " "PHY ID: %x, addr: %x\n", 1180 id, mii_id); 1181 for (i=0; (def = mii_phy_table[i]) != NULL; i++) 1182 if ((id & def->phy_id_mask) == def->phy_id) 1183 break; 1184 /* Should never be NULL (we have a generic entry), but... */ 1185 if (def == NULL) 1186 goto fail; 1187 1188 phy->def = def; 1189 1190 return 0; 1191 fail: 1192 phy->speed = 0; 1193 phy->duplex = 0; 1194 phy->pause = 0; 1195 phy->advertising = 0; 1196 return -ENODEV; 1197 } 1198 1199 EXPORT_SYMBOL(sungem_phy_probe); 1200 MODULE_LICENSE("GPL"); 1201