mxl-gpy.c (19869B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* Copyright (C) 2021 Maxlinear Corporation 3 * Copyright (C) 2020 Intel Corporation 4 * 5 * Drivers for Maxlinear Ethernet GPY 6 * 7 */ 8 9#include <linux/module.h> 10#include <linux/bitfield.h> 11#include <linux/phy.h> 12#include <linux/netdevice.h> 13 14/* PHY ID */ 15#define PHY_ID_GPYx15B_MASK 0xFFFFFFFC 16#define PHY_ID_GPY21xB_MASK 0xFFFFFFF9 17#define PHY_ID_GPY2xx 0x67C9DC00 18#define PHY_ID_GPY115B 0x67C9DF00 19#define PHY_ID_GPY115C 0x67C9DF10 20#define PHY_ID_GPY211B 0x67C9DE08 21#define PHY_ID_GPY211C 0x67C9DE10 22#define PHY_ID_GPY212B 0x67C9DE09 23#define PHY_ID_GPY212C 0x67C9DE20 24#define PHY_ID_GPY215B 0x67C9DF04 25#define PHY_ID_GPY215C 0x67C9DF20 26#define PHY_ID_GPY241B 0x67C9DE40 27#define PHY_ID_GPY241BM 0x67C9DE80 28#define PHY_ID_GPY245B 0x67C9DEC0 29 30#define PHY_MIISTAT 0x18 /* MII state */ 31#define PHY_IMASK 0x19 /* interrupt mask */ 32#define PHY_ISTAT 0x1A /* interrupt status */ 33#define PHY_FWV 0x1E /* firmware version */ 34 35#define PHY_MIISTAT_SPD_MASK GENMASK(2, 0) 36#define PHY_MIISTAT_DPX BIT(3) 37#define PHY_MIISTAT_LS BIT(10) 38 39#define PHY_MIISTAT_SPD_10 0 40#define PHY_MIISTAT_SPD_100 1 41#define PHY_MIISTAT_SPD_1000 2 42#define PHY_MIISTAT_SPD_2500 4 43 44#define PHY_IMASK_WOL BIT(15) /* Wake-on-LAN */ 45#define PHY_IMASK_ANC BIT(10) /* Auto-Neg complete */ 46#define PHY_IMASK_ADSC BIT(5) /* Link auto-downspeed detect */ 47#define PHY_IMASK_DXMC BIT(2) /* Duplex mode change */ 48#define PHY_IMASK_LSPC BIT(1) /* Link speed change */ 49#define PHY_IMASK_LSTC BIT(0) /* Link state change */ 50#define PHY_IMASK_MASK (PHY_IMASK_LSTC | \ 51 PHY_IMASK_LSPC | \ 52 PHY_IMASK_DXMC | \ 53 PHY_IMASK_ADSC | \ 54 PHY_IMASK_ANC) 55 56#define PHY_FWV_REL_MASK BIT(15) 57#define PHY_FWV_TYPE_MASK GENMASK(11, 8) 58#define PHY_FWV_MINOR_MASK GENMASK(7, 0) 59 60/* SGMII */ 61#define VSPEC1_SGMII_CTRL 0x08 62#define VSPEC1_SGMII_CTRL_ANEN BIT(12) /* Aneg enable */ 63#define VSPEC1_SGMII_CTRL_ANRS BIT(9) /* Restart Aneg */ 64#define VSPEC1_SGMII_ANEN_ANRS (VSPEC1_SGMII_CTRL_ANEN | \ 65 VSPEC1_SGMII_CTRL_ANRS) 66 67/* WoL */ 68#define VPSPEC2_WOL_CTL 0x0E06 69#define VPSPEC2_WOL_AD01 0x0E08 70#define VPSPEC2_WOL_AD23 0x0E09 71#define VPSPEC2_WOL_AD45 0x0E0A 72#define WOL_EN BIT(0) 73 74static const struct { 75 int type; 76 int minor; 77} ver_need_sgmii_reaneg[] = { 78 {7, 0x6D}, 79 {8, 0x6D}, 80 {9, 0x73}, 81}; 82 83static int gpy_config_init(struct phy_device *phydev) 84{ 85 int ret; 86 87 /* Mask all interrupts */ 88 ret = phy_write(phydev, PHY_IMASK, 0); 89 if (ret) 90 return ret; 91 92 /* Clear all pending interrupts */ 93 ret = phy_read(phydev, PHY_ISTAT); 94 return ret < 0 ? ret : 0; 95} 96 97static int gpy_probe(struct phy_device *phydev) 98{ 99 int ret; 100 101 if (!phydev->is_c45) { 102 ret = phy_get_c45_ids(phydev); 103 if (ret < 0) 104 return ret; 105 } 106 107 /* Show GPY PHY FW version in dmesg */ 108 ret = phy_read(phydev, PHY_FWV); 109 if (ret < 0) 110 return ret; 111 112 phydev_info(phydev, "Firmware Version: 0x%04X (%s)\n", ret, 113 (ret & PHY_FWV_REL_MASK) ? "release" : "test"); 114 115 return 0; 116} 117 118static bool gpy_sgmii_need_reaneg(struct phy_device *phydev) 119{ 120 int fw_ver, fw_type, fw_minor; 121 size_t i; 122 123 fw_ver = phy_read(phydev, PHY_FWV); 124 if (fw_ver < 0) 125 return true; 126 127 fw_type = FIELD_GET(PHY_FWV_TYPE_MASK, fw_ver); 128 fw_minor = FIELD_GET(PHY_FWV_MINOR_MASK, fw_ver); 129 130 for (i = 0; i < ARRAY_SIZE(ver_need_sgmii_reaneg); i++) { 131 if (fw_type != ver_need_sgmii_reaneg[i].type) 132 continue; 133 if (fw_minor < ver_need_sgmii_reaneg[i].minor) 134 return true; 135 break; 136 } 137 138 return false; 139} 140 141static bool gpy_2500basex_chk(struct phy_device *phydev) 142{ 143 int ret; 144 145 ret = phy_read(phydev, PHY_MIISTAT); 146 if (ret < 0) { 147 phydev_err(phydev, "Error: MDIO register access failed: %d\n", 148 ret); 149 return false; 150 } 151 152 if (!(ret & PHY_MIISTAT_LS) || 153 FIELD_GET(PHY_MIISTAT_SPD_MASK, ret) != PHY_MIISTAT_SPD_2500) 154 return false; 155 156 phydev->speed = SPEED_2500; 157 phydev->interface = PHY_INTERFACE_MODE_2500BASEX; 158 phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL, 159 VSPEC1_SGMII_CTRL_ANEN, 0); 160 return true; 161} 162 163static bool gpy_sgmii_aneg_en(struct phy_device *phydev) 164{ 165 int ret; 166 167 ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL); 168 if (ret < 0) { 169 phydev_err(phydev, "Error: MMD register access failed: %d\n", 170 ret); 171 return true; 172 } 173 174 return (ret & VSPEC1_SGMII_CTRL_ANEN) ? true : false; 175} 176 177static int gpy_config_aneg(struct phy_device *phydev) 178{ 179 bool changed = false; 180 u32 adv; 181 int ret; 182 183 if (phydev->autoneg == AUTONEG_DISABLE) { 184 /* Configure half duplex with genphy_setup_forced, 185 * because genphy_c45_pma_setup_forced does not support. 186 */ 187 return phydev->duplex != DUPLEX_FULL 188 ? genphy_setup_forced(phydev) 189 : genphy_c45_pma_setup_forced(phydev); 190 } 191 192 ret = genphy_c45_an_config_aneg(phydev); 193 if (ret < 0) 194 return ret; 195 if (ret > 0) 196 changed = true; 197 198 adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising); 199 ret = phy_modify_changed(phydev, MII_CTRL1000, 200 ADVERTISE_1000FULL | ADVERTISE_1000HALF, 201 adv); 202 if (ret < 0) 203 return ret; 204 if (ret > 0) 205 changed = true; 206 207 ret = genphy_c45_check_and_restart_aneg(phydev, changed); 208 if (ret < 0) 209 return ret; 210 211 if (phydev->interface == PHY_INTERFACE_MODE_USXGMII || 212 phydev->interface == PHY_INTERFACE_MODE_INTERNAL) 213 return 0; 214 215 /* No need to trigger re-ANEG if link speed is 2.5G or SGMII ANEG is 216 * disabled. 217 */ 218 if (!gpy_sgmii_need_reaneg(phydev) || gpy_2500basex_chk(phydev) || 219 !gpy_sgmii_aneg_en(phydev)) 220 return 0; 221 222 /* There is a design constraint in GPY2xx device where SGMII AN is 223 * only triggered when there is change of speed. If, PHY link 224 * partner`s speed is still same even after PHY TPI is down and up 225 * again, SGMII AN is not triggered and hence no new in-band message 226 * from GPY to MAC side SGMII. 227 * This could cause an issue during power up, when PHY is up prior to 228 * MAC. At this condition, once MAC side SGMII is up, MAC side SGMII 229 * wouldn`t receive new in-band message from GPY with correct link 230 * status, speed and duplex info. 231 * 232 * 1) If PHY is already up and TPI link status is still down (such as 233 * hard reboot), TPI link status is polled for 4 seconds before 234 * retriggerring SGMII AN. 235 * 2) If PHY is already up and TPI link status is also up (such as soft 236 * reboot), polling of TPI link status is not needed and SGMII AN is 237 * immediately retriggered. 238 * 3) Other conditions such as PHY is down, speed change etc, skip 239 * retriggering SGMII AN. Note: in case of speed change, GPY FW will 240 * initiate SGMII AN. 241 */ 242 243 if (phydev->state != PHY_UP) 244 return 0; 245 246 ret = phy_read_poll_timeout(phydev, MII_BMSR, ret, ret & BMSR_LSTATUS, 247 20000, 4000000, false); 248 if (ret == -ETIMEDOUT) 249 return 0; 250 else if (ret < 0) 251 return ret; 252 253 /* Trigger SGMII AN. */ 254 return phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL, 255 VSPEC1_SGMII_CTRL_ANRS, VSPEC1_SGMII_CTRL_ANRS); 256} 257 258static void gpy_update_interface(struct phy_device *phydev) 259{ 260 int ret; 261 262 /* Interface mode is fixed for USXGMII and integrated PHY */ 263 if (phydev->interface == PHY_INTERFACE_MODE_USXGMII || 264 phydev->interface == PHY_INTERFACE_MODE_INTERNAL) 265 return; 266 267 /* Automatically switch SERDES interface between SGMII and 2500-BaseX 268 * according to speed. Disable ANEG in 2500-BaseX mode. 269 */ 270 switch (phydev->speed) { 271 case SPEED_2500: 272 phydev->interface = PHY_INTERFACE_MODE_2500BASEX; 273 ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL, 274 VSPEC1_SGMII_CTRL_ANEN, 0); 275 if (ret < 0) 276 phydev_err(phydev, 277 "Error: Disable of SGMII ANEG failed: %d\n", 278 ret); 279 break; 280 case SPEED_1000: 281 case SPEED_100: 282 case SPEED_10: 283 phydev->interface = PHY_INTERFACE_MODE_SGMII; 284 if (gpy_sgmii_aneg_en(phydev)) 285 break; 286 /* Enable and restart SGMII ANEG for 10/100/1000Mbps link speed 287 * if ANEG is disabled (in 2500-BaseX mode). 288 */ 289 ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL, 290 VSPEC1_SGMII_ANEN_ANRS, 291 VSPEC1_SGMII_ANEN_ANRS); 292 if (ret < 0) 293 phydev_err(phydev, 294 "Error: Enable of SGMII ANEG failed: %d\n", 295 ret); 296 break; 297 } 298} 299 300static int gpy_read_status(struct phy_device *phydev) 301{ 302 int ret; 303 304 ret = genphy_update_link(phydev); 305 if (ret) 306 return ret; 307 308 phydev->speed = SPEED_UNKNOWN; 309 phydev->duplex = DUPLEX_UNKNOWN; 310 phydev->pause = 0; 311 phydev->asym_pause = 0; 312 313 if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) { 314 ret = genphy_c45_read_lpa(phydev); 315 if (ret < 0) 316 return ret; 317 318 /* Read the link partner's 1G advertisement */ 319 ret = phy_read(phydev, MII_STAT1000); 320 if (ret < 0) 321 return ret; 322 mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ret); 323 } else if (phydev->autoneg == AUTONEG_DISABLE) { 324 linkmode_zero(phydev->lp_advertising); 325 } 326 327 ret = phy_read(phydev, PHY_MIISTAT); 328 if (ret < 0) 329 return ret; 330 331 phydev->link = (ret & PHY_MIISTAT_LS) ? 1 : 0; 332 phydev->duplex = (ret & PHY_MIISTAT_DPX) ? DUPLEX_FULL : DUPLEX_HALF; 333 switch (FIELD_GET(PHY_MIISTAT_SPD_MASK, ret)) { 334 case PHY_MIISTAT_SPD_10: 335 phydev->speed = SPEED_10; 336 break; 337 case PHY_MIISTAT_SPD_100: 338 phydev->speed = SPEED_100; 339 break; 340 case PHY_MIISTAT_SPD_1000: 341 phydev->speed = SPEED_1000; 342 break; 343 case PHY_MIISTAT_SPD_2500: 344 phydev->speed = SPEED_2500; 345 break; 346 } 347 348 if (phydev->link) 349 gpy_update_interface(phydev); 350 351 return 0; 352} 353 354static int gpy_config_intr(struct phy_device *phydev) 355{ 356 u16 mask = 0; 357 358 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 359 mask = PHY_IMASK_MASK; 360 361 return phy_write(phydev, PHY_IMASK, mask); 362} 363 364static irqreturn_t gpy_handle_interrupt(struct phy_device *phydev) 365{ 366 int reg; 367 368 reg = phy_read(phydev, PHY_ISTAT); 369 if (reg < 0) { 370 phy_error(phydev); 371 return IRQ_NONE; 372 } 373 374 if (!(reg & PHY_IMASK_MASK)) 375 return IRQ_NONE; 376 377 phy_trigger_machine(phydev); 378 379 return IRQ_HANDLED; 380} 381 382static int gpy_set_wol(struct phy_device *phydev, 383 struct ethtool_wolinfo *wol) 384{ 385 struct net_device *attach_dev = phydev->attached_dev; 386 int ret; 387 388 if (wol->wolopts & WAKE_MAGIC) { 389 /* MAC address - Byte0:Byte1:Byte2:Byte3:Byte4:Byte5 390 * VPSPEC2_WOL_AD45 = Byte0:Byte1 391 * VPSPEC2_WOL_AD23 = Byte2:Byte3 392 * VPSPEC2_WOL_AD01 = Byte4:Byte5 393 */ 394 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, 395 VPSPEC2_WOL_AD45, 396 ((attach_dev->dev_addr[0] << 8) | 397 attach_dev->dev_addr[1])); 398 if (ret < 0) 399 return ret; 400 401 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, 402 VPSPEC2_WOL_AD23, 403 ((attach_dev->dev_addr[2] << 8) | 404 attach_dev->dev_addr[3])); 405 if (ret < 0) 406 return ret; 407 408 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, 409 VPSPEC2_WOL_AD01, 410 ((attach_dev->dev_addr[4] << 8) | 411 attach_dev->dev_addr[5])); 412 if (ret < 0) 413 return ret; 414 415 /* Enable the WOL interrupt */ 416 ret = phy_write(phydev, PHY_IMASK, PHY_IMASK_WOL); 417 if (ret < 0) 418 return ret; 419 420 /* Enable magic packet matching */ 421 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, 422 VPSPEC2_WOL_CTL, 423 WOL_EN); 424 if (ret < 0) 425 return ret; 426 427 /* Clear the interrupt status register. 428 * Only WoL is enabled so clear all. 429 */ 430 ret = phy_read(phydev, PHY_ISTAT); 431 if (ret < 0) 432 return ret; 433 } else { 434 /* Disable magic packet matching */ 435 ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, 436 VPSPEC2_WOL_CTL, 437 WOL_EN); 438 if (ret < 0) 439 return ret; 440 } 441 442 if (wol->wolopts & WAKE_PHY) { 443 /* Enable the link state change interrupt */ 444 ret = phy_set_bits(phydev, PHY_IMASK, PHY_IMASK_LSTC); 445 if (ret < 0) 446 return ret; 447 448 /* Clear the interrupt status register */ 449 ret = phy_read(phydev, PHY_ISTAT); 450 if (ret < 0) 451 return ret; 452 453 if (ret & (PHY_IMASK_MASK & ~PHY_IMASK_LSTC)) 454 phy_trigger_machine(phydev); 455 456 return 0; 457 } 458 459 /* Disable the link state change interrupt */ 460 return phy_clear_bits(phydev, PHY_IMASK, PHY_IMASK_LSTC); 461} 462 463static void gpy_get_wol(struct phy_device *phydev, 464 struct ethtool_wolinfo *wol) 465{ 466 int ret; 467 468 wol->supported = WAKE_MAGIC | WAKE_PHY; 469 wol->wolopts = 0; 470 471 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, VPSPEC2_WOL_CTL); 472 if (ret & WOL_EN) 473 wol->wolopts |= WAKE_MAGIC; 474 475 ret = phy_read(phydev, PHY_IMASK); 476 if (ret & PHY_IMASK_LSTC) 477 wol->wolopts |= WAKE_PHY; 478} 479 480static int gpy_loopback(struct phy_device *phydev, bool enable) 481{ 482 int ret; 483 484 ret = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK, 485 enable ? BMCR_LOOPBACK : 0); 486 if (!ret) { 487 /* It takes some time for PHY device to switch 488 * into/out-of loopback mode. 489 */ 490 msleep(100); 491 } 492 493 return ret; 494} 495 496static int gpy115_loopback(struct phy_device *phydev, bool enable) 497{ 498 int ret; 499 int fw_minor; 500 501 if (enable) 502 return gpy_loopback(phydev, enable); 503 504 ret = phy_read(phydev, PHY_FWV); 505 if (ret < 0) 506 return ret; 507 508 fw_minor = FIELD_GET(PHY_FWV_MINOR_MASK, ret); 509 if (fw_minor > 0x0076) 510 return gpy_loopback(phydev, 0); 511 512 return genphy_soft_reset(phydev); 513} 514 515static struct phy_driver gpy_drivers[] = { 516 { 517 PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx), 518 .name = "Maxlinear Ethernet GPY2xx", 519 .get_features = genphy_c45_pma_read_abilities, 520 .config_init = gpy_config_init, 521 .probe = gpy_probe, 522 .suspend = genphy_suspend, 523 .resume = genphy_resume, 524 .config_aneg = gpy_config_aneg, 525 .aneg_done = genphy_c45_aneg_done, 526 .read_status = gpy_read_status, 527 .config_intr = gpy_config_intr, 528 .handle_interrupt = gpy_handle_interrupt, 529 .set_wol = gpy_set_wol, 530 .get_wol = gpy_get_wol, 531 .set_loopback = gpy_loopback, 532 }, 533 { 534 .phy_id = PHY_ID_GPY115B, 535 .phy_id_mask = PHY_ID_GPYx15B_MASK, 536 .name = "Maxlinear Ethernet GPY115B", 537 .get_features = genphy_c45_pma_read_abilities, 538 .config_init = gpy_config_init, 539 .probe = gpy_probe, 540 .suspend = genphy_suspend, 541 .resume = genphy_resume, 542 .config_aneg = gpy_config_aneg, 543 .aneg_done = genphy_c45_aneg_done, 544 .read_status = gpy_read_status, 545 .config_intr = gpy_config_intr, 546 .handle_interrupt = gpy_handle_interrupt, 547 .set_wol = gpy_set_wol, 548 .get_wol = gpy_get_wol, 549 .set_loopback = gpy115_loopback, 550 }, 551 { 552 PHY_ID_MATCH_MODEL(PHY_ID_GPY115C), 553 .name = "Maxlinear Ethernet GPY115C", 554 .get_features = genphy_c45_pma_read_abilities, 555 .config_init = gpy_config_init, 556 .probe = gpy_probe, 557 .suspend = genphy_suspend, 558 .resume = genphy_resume, 559 .config_aneg = gpy_config_aneg, 560 .aneg_done = genphy_c45_aneg_done, 561 .read_status = gpy_read_status, 562 .config_intr = gpy_config_intr, 563 .handle_interrupt = gpy_handle_interrupt, 564 .set_wol = gpy_set_wol, 565 .get_wol = gpy_get_wol, 566 .set_loopback = gpy115_loopback, 567 }, 568 { 569 .phy_id = PHY_ID_GPY211B, 570 .phy_id_mask = PHY_ID_GPY21xB_MASK, 571 .name = "Maxlinear Ethernet GPY211B", 572 .get_features = genphy_c45_pma_read_abilities, 573 .config_init = gpy_config_init, 574 .probe = gpy_probe, 575 .suspend = genphy_suspend, 576 .resume = genphy_resume, 577 .config_aneg = gpy_config_aneg, 578 .aneg_done = genphy_c45_aneg_done, 579 .read_status = gpy_read_status, 580 .config_intr = gpy_config_intr, 581 .handle_interrupt = gpy_handle_interrupt, 582 .set_wol = gpy_set_wol, 583 .get_wol = gpy_get_wol, 584 .set_loopback = gpy_loopback, 585 }, 586 { 587 PHY_ID_MATCH_MODEL(PHY_ID_GPY211C), 588 .name = "Maxlinear Ethernet GPY211C", 589 .get_features = genphy_c45_pma_read_abilities, 590 .config_init = gpy_config_init, 591 .probe = gpy_probe, 592 .suspend = genphy_suspend, 593 .resume = genphy_resume, 594 .config_aneg = gpy_config_aneg, 595 .aneg_done = genphy_c45_aneg_done, 596 .read_status = gpy_read_status, 597 .config_intr = gpy_config_intr, 598 .handle_interrupt = gpy_handle_interrupt, 599 .set_wol = gpy_set_wol, 600 .get_wol = gpy_get_wol, 601 .set_loopback = gpy_loopback, 602 }, 603 { 604 .phy_id = PHY_ID_GPY212B, 605 .phy_id_mask = PHY_ID_GPY21xB_MASK, 606 .name = "Maxlinear Ethernet GPY212B", 607 .get_features = genphy_c45_pma_read_abilities, 608 .config_init = gpy_config_init, 609 .probe = gpy_probe, 610 .suspend = genphy_suspend, 611 .resume = genphy_resume, 612 .config_aneg = gpy_config_aneg, 613 .aneg_done = genphy_c45_aneg_done, 614 .read_status = gpy_read_status, 615 .config_intr = gpy_config_intr, 616 .handle_interrupt = gpy_handle_interrupt, 617 .set_wol = gpy_set_wol, 618 .get_wol = gpy_get_wol, 619 .set_loopback = gpy_loopback, 620 }, 621 { 622 PHY_ID_MATCH_MODEL(PHY_ID_GPY212C), 623 .name = "Maxlinear Ethernet GPY212C", 624 .get_features = genphy_c45_pma_read_abilities, 625 .config_init = gpy_config_init, 626 .probe = gpy_probe, 627 .suspend = genphy_suspend, 628 .resume = genphy_resume, 629 .config_aneg = gpy_config_aneg, 630 .aneg_done = genphy_c45_aneg_done, 631 .read_status = gpy_read_status, 632 .config_intr = gpy_config_intr, 633 .handle_interrupt = gpy_handle_interrupt, 634 .set_wol = gpy_set_wol, 635 .get_wol = gpy_get_wol, 636 .set_loopback = gpy_loopback, 637 }, 638 { 639 .phy_id = PHY_ID_GPY215B, 640 .phy_id_mask = PHY_ID_GPYx15B_MASK, 641 .name = "Maxlinear Ethernet GPY215B", 642 .get_features = genphy_c45_pma_read_abilities, 643 .config_init = gpy_config_init, 644 .probe = gpy_probe, 645 .suspend = genphy_suspend, 646 .resume = genphy_resume, 647 .config_aneg = gpy_config_aneg, 648 .aneg_done = genphy_c45_aneg_done, 649 .read_status = gpy_read_status, 650 .config_intr = gpy_config_intr, 651 .handle_interrupt = gpy_handle_interrupt, 652 .set_wol = gpy_set_wol, 653 .get_wol = gpy_get_wol, 654 .set_loopback = gpy_loopback, 655 }, 656 { 657 PHY_ID_MATCH_MODEL(PHY_ID_GPY215C), 658 .name = "Maxlinear Ethernet GPY215C", 659 .get_features = genphy_c45_pma_read_abilities, 660 .config_init = gpy_config_init, 661 .probe = gpy_probe, 662 .suspend = genphy_suspend, 663 .resume = genphy_resume, 664 .config_aneg = gpy_config_aneg, 665 .aneg_done = genphy_c45_aneg_done, 666 .read_status = gpy_read_status, 667 .config_intr = gpy_config_intr, 668 .handle_interrupt = gpy_handle_interrupt, 669 .set_wol = gpy_set_wol, 670 .get_wol = gpy_get_wol, 671 .set_loopback = gpy_loopback, 672 }, 673 { 674 PHY_ID_MATCH_MODEL(PHY_ID_GPY241B), 675 .name = "Maxlinear Ethernet GPY241B", 676 .get_features = genphy_c45_pma_read_abilities, 677 .config_init = gpy_config_init, 678 .probe = gpy_probe, 679 .suspend = genphy_suspend, 680 .resume = genphy_resume, 681 .config_aneg = gpy_config_aneg, 682 .aneg_done = genphy_c45_aneg_done, 683 .read_status = gpy_read_status, 684 .config_intr = gpy_config_intr, 685 .handle_interrupt = gpy_handle_interrupt, 686 .set_wol = gpy_set_wol, 687 .get_wol = gpy_get_wol, 688 .set_loopback = gpy_loopback, 689 }, 690 { 691 PHY_ID_MATCH_MODEL(PHY_ID_GPY241BM), 692 .name = "Maxlinear Ethernet GPY241BM", 693 .get_features = genphy_c45_pma_read_abilities, 694 .config_init = gpy_config_init, 695 .probe = gpy_probe, 696 .suspend = genphy_suspend, 697 .resume = genphy_resume, 698 .config_aneg = gpy_config_aneg, 699 .aneg_done = genphy_c45_aneg_done, 700 .read_status = gpy_read_status, 701 .config_intr = gpy_config_intr, 702 .handle_interrupt = gpy_handle_interrupt, 703 .set_wol = gpy_set_wol, 704 .get_wol = gpy_get_wol, 705 .set_loopback = gpy_loopback, 706 }, 707 { 708 PHY_ID_MATCH_MODEL(PHY_ID_GPY245B), 709 .name = "Maxlinear Ethernet GPY245B", 710 .get_features = genphy_c45_pma_read_abilities, 711 .config_init = gpy_config_init, 712 .probe = gpy_probe, 713 .suspend = genphy_suspend, 714 .resume = genphy_resume, 715 .config_aneg = gpy_config_aneg, 716 .aneg_done = genphy_c45_aneg_done, 717 .read_status = gpy_read_status, 718 .config_intr = gpy_config_intr, 719 .handle_interrupt = gpy_handle_interrupt, 720 .set_wol = gpy_set_wol, 721 .get_wol = gpy_get_wol, 722 .set_loopback = gpy_loopback, 723 }, 724}; 725module_phy_driver(gpy_drivers); 726 727static struct mdio_device_id __maybe_unused gpy_tbl[] = { 728 {PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx)}, 729 {PHY_ID_GPY115B, PHY_ID_GPYx15B_MASK}, 730 {PHY_ID_MATCH_MODEL(PHY_ID_GPY115C)}, 731 {PHY_ID_GPY211B, PHY_ID_GPY21xB_MASK}, 732 {PHY_ID_MATCH_MODEL(PHY_ID_GPY211C)}, 733 {PHY_ID_GPY212B, PHY_ID_GPY21xB_MASK}, 734 {PHY_ID_MATCH_MODEL(PHY_ID_GPY212C)}, 735 {PHY_ID_GPY215B, PHY_ID_GPYx15B_MASK}, 736 {PHY_ID_MATCH_MODEL(PHY_ID_GPY215C)}, 737 {PHY_ID_MATCH_MODEL(PHY_ID_GPY241B)}, 738 {PHY_ID_MATCH_MODEL(PHY_ID_GPY241BM)}, 739 {PHY_ID_MATCH_MODEL(PHY_ID_GPY245B)}, 740 { } 741}; 742MODULE_DEVICE_TABLE(mdio, gpy_tbl); 743 744MODULE_DESCRIPTION("Maxlinear Ethernet GPY Driver"); 745MODULE_AUTHOR("Xu Liang"); 746MODULE_LICENSE("GPL");