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