1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Marvell 88E6xxx SERDES manipulation, via SMI bus 4 * 5 * Copyright (c) 2008 Marvell Semiconductor 6 * 7 * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch> 8 */ 9 10 #include <linux/interrupt.h> 11 #include <linux/irqdomain.h> 12 #include <linux/mii.h> 13 14 #include "chip.h" 15 #include "global2.h" 16 #include "phy.h" 17 #include "port.h" 18 #include "serdes.h" 19 20 static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int reg, 21 u16 *val) 22 { 23 return mv88e6xxx_phy_page_read(chip, MV88E6352_ADDR_SERDES, 24 MV88E6352_SERDES_PAGE_FIBER, 25 reg, val); 26 } 27 28 static int mv88e6352_serdes_write(struct mv88e6xxx_chip *chip, int reg, 29 u16 val) 30 { 31 return mv88e6xxx_phy_page_write(chip, MV88E6352_ADDR_SERDES, 32 MV88E6352_SERDES_PAGE_FIBER, 33 reg, val); 34 } 35 36 static int mv88e6390_serdes_read(struct mv88e6xxx_chip *chip, 37 int lane, int device, int reg, u16 *val) 38 { 39 int reg_c45 = MII_ADDR_C45 | device << 16 | reg; 40 41 return mv88e6xxx_phy_read(chip, lane, reg_c45, val); 42 } 43 44 static int mv88e6390_serdes_write(struct mv88e6xxx_chip *chip, 45 int lane, int device, int reg, u16 val) 46 { 47 int reg_c45 = MII_ADDR_C45 | device << 16 | reg; 48 49 return mv88e6xxx_phy_write(chip, lane, reg_c45, val); 50 } 51 52 int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane, 53 bool up) 54 { 55 u16 val, new_val; 56 int err; 57 58 err = mv88e6352_serdes_read(chip, MII_BMCR, &val); 59 if (err) 60 return err; 61 62 if (up) 63 new_val = val & ~BMCR_PDOWN; 64 else 65 new_val = val | BMCR_PDOWN; 66 67 if (val != new_val) 68 err = mv88e6352_serdes_write(chip, MII_BMCR, new_val); 69 70 return err; 71 } 72 73 u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) 74 { 75 u8 cmode = chip->ports[port].cmode; 76 u8 lane = 0; 77 78 if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASEX) || 79 (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX) || 80 (cmode == MV88E6XXX_PORT_STS_CMODE_SGMII)) 81 lane = 0xff; /* Unused */ 82 83 return lane; 84 } 85 86 static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip *chip, int port) 87 { 88 if (mv88e6xxx_serdes_get_lane(chip, port)) 89 return true; 90 91 return false; 92 } 93 94 struct mv88e6352_serdes_hw_stat { 95 char string[ETH_GSTRING_LEN]; 96 int sizeof_stat; 97 int reg; 98 }; 99 100 static struct mv88e6352_serdes_hw_stat mv88e6352_serdes_hw_stats[] = { 101 { "serdes_fibre_rx_error", 16, 21 }, 102 { "serdes_PRBS_error", 32, 24 }, 103 }; 104 105 int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port) 106 { 107 if (mv88e6352_port_has_serdes(chip, port)) 108 return ARRAY_SIZE(mv88e6352_serdes_hw_stats); 109 110 return 0; 111 } 112 113 int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, 114 int port, uint8_t *data) 115 { 116 struct mv88e6352_serdes_hw_stat *stat; 117 int i; 118 119 if (!mv88e6352_port_has_serdes(chip, port)) 120 return 0; 121 122 for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) { 123 stat = &mv88e6352_serdes_hw_stats[i]; 124 memcpy(data + i * ETH_GSTRING_LEN, stat->string, 125 ETH_GSTRING_LEN); 126 } 127 return ARRAY_SIZE(mv88e6352_serdes_hw_stats); 128 } 129 130 static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip *chip, 131 struct mv88e6352_serdes_hw_stat *stat) 132 { 133 u64 val = 0; 134 u16 reg; 135 int err; 136 137 err = mv88e6352_serdes_read(chip, stat->reg, ®); 138 if (err) { 139 dev_err(chip->dev, "failed to read statistic\n"); 140 return 0; 141 } 142 143 val = reg; 144 145 if (stat->sizeof_stat == 32) { 146 err = mv88e6352_serdes_read(chip, stat->reg + 1, ®); 147 if (err) { 148 dev_err(chip->dev, "failed to read statistic\n"); 149 return 0; 150 } 151 val = val << 16 | reg; 152 } 153 154 return val; 155 } 156 157 int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, 158 uint64_t *data) 159 { 160 struct mv88e6xxx_port *mv88e6xxx_port = &chip->ports[port]; 161 struct mv88e6352_serdes_hw_stat *stat; 162 u64 value; 163 int i; 164 165 if (!mv88e6352_port_has_serdes(chip, port)) 166 return 0; 167 168 BUILD_BUG_ON(ARRAY_SIZE(mv88e6352_serdes_hw_stats) > 169 ARRAY_SIZE(mv88e6xxx_port->serdes_stats)); 170 171 for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) { 172 stat = &mv88e6352_serdes_hw_stats[i]; 173 value = mv88e6352_serdes_get_stat(chip, stat); 174 mv88e6xxx_port->serdes_stats[i] += value; 175 data[i] = mv88e6xxx_port->serdes_stats[i]; 176 } 177 178 return ARRAY_SIZE(mv88e6352_serdes_hw_stats); 179 } 180 181 static void mv88e6352_serdes_irq_link(struct mv88e6xxx_chip *chip, int port) 182 { 183 struct dsa_switch *ds = chip->ds; 184 u16 status; 185 bool up; 186 int err; 187 188 err = mv88e6352_serdes_read(chip, MII_BMSR, &status); 189 if (err) 190 return; 191 192 /* Status must be read twice in order to give the current link 193 * status. Otherwise the change in link status since the last 194 * read of the register is returned. 195 */ 196 err = mv88e6352_serdes_read(chip, MII_BMSR, &status); 197 if (err) 198 return; 199 200 up = status & BMSR_LSTATUS; 201 202 dsa_port_phylink_mac_change(ds, port, up); 203 } 204 205 irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, 206 u8 lane) 207 { 208 irqreturn_t ret = IRQ_NONE; 209 u16 status; 210 int err; 211 212 err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_INT_STATUS, &status); 213 if (err) 214 return ret; 215 216 if (status & MV88E6352_SERDES_INT_LINK_CHANGE) { 217 ret = IRQ_HANDLED; 218 mv88e6352_serdes_irq_link(chip, port); 219 } 220 221 return ret; 222 } 223 224 int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane, 225 bool enable) 226 { 227 u16 val = 0; 228 229 if (enable) 230 val |= MV88E6352_SERDES_INT_LINK_CHANGE; 231 232 return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE, val); 233 } 234 235 unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port) 236 { 237 return irq_find_mapping(chip->g2_irq.domain, MV88E6352_SERDES_IRQ); 238 } 239 240 u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) 241 { 242 u8 cmode = chip->ports[port].cmode; 243 u8 lane = 0; 244 245 switch (port) { 246 case 5: 247 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 248 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || 249 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 250 lane = MV88E6341_PORT5_LANE; 251 break; 252 } 253 254 return lane; 255 } 256 257 u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) 258 { 259 u8 cmode = chip->ports[port].cmode; 260 u8 lane = 0; 261 262 switch (port) { 263 case 9: 264 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 265 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || 266 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 267 lane = MV88E6390_PORT9_LANE0; 268 break; 269 case 10: 270 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 271 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || 272 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 273 lane = MV88E6390_PORT10_LANE0; 274 break; 275 } 276 277 return lane; 278 } 279 280 u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) 281 { 282 u8 cmode_port = chip->ports[port].cmode; 283 u8 cmode_port10 = chip->ports[10].cmode; 284 u8 cmode_port9 = chip->ports[9].cmode; 285 u8 lane = 0; 286 287 switch (port) { 288 case 2: 289 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 290 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 291 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 292 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) 293 lane = MV88E6390_PORT9_LANE1; 294 break; 295 case 3: 296 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 297 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 298 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 299 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 300 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) 301 lane = MV88E6390_PORT9_LANE2; 302 break; 303 case 4: 304 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 305 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 306 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 307 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 308 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) 309 lane = MV88E6390_PORT9_LANE3; 310 break; 311 case 5: 312 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 313 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 314 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 315 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) 316 lane = MV88E6390_PORT10_LANE1; 317 break; 318 case 6: 319 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 320 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 321 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 322 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 323 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) 324 lane = MV88E6390_PORT10_LANE2; 325 break; 326 case 7: 327 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 328 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 329 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 330 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 331 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) 332 lane = MV88E6390_PORT10_LANE3; 333 break; 334 case 9: 335 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 336 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 337 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 338 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI || 339 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 340 lane = MV88E6390_PORT9_LANE0; 341 break; 342 case 10: 343 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 344 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 345 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 346 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI || 347 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 348 lane = MV88E6390_PORT10_LANE0; 349 break; 350 } 351 352 return lane; 353 } 354 355 /* Set power up/down for 10GBASE-R and 10GBASE-X4/X2 */ 356 static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane, 357 bool up) 358 { 359 u16 val, new_val; 360 int err; 361 362 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, 363 MV88E6390_PCS_CONTROL_1, &val); 364 365 if (err) 366 return err; 367 368 if (up) 369 new_val = val & ~(MV88E6390_PCS_CONTROL_1_RESET | 370 MV88E6390_PCS_CONTROL_1_LOOPBACK | 371 MV88E6390_PCS_CONTROL_1_PDOWN); 372 else 373 new_val = val | MV88E6390_PCS_CONTROL_1_PDOWN; 374 375 if (val != new_val) 376 err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, 377 MV88E6390_PCS_CONTROL_1, new_val); 378 379 return err; 380 } 381 382 /* Set power up/down for SGMII and 1000Base-X */ 383 static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, u8 lane, 384 bool up) 385 { 386 u16 val, new_val; 387 int err; 388 389 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, 390 MV88E6390_SGMII_CONTROL, &val); 391 if (err) 392 return err; 393 394 if (up) 395 new_val = val & ~(MV88E6390_SGMII_CONTROL_RESET | 396 MV88E6390_SGMII_CONTROL_LOOPBACK | 397 MV88E6390_SGMII_CONTROL_PDOWN); 398 else 399 new_val = val | MV88E6390_SGMII_CONTROL_PDOWN; 400 401 if (val != new_val) 402 err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, 403 MV88E6390_SGMII_CONTROL, new_val); 404 405 return err; 406 } 407 408 struct mv88e6390_serdes_hw_stat { 409 char string[ETH_GSTRING_LEN]; 410 int reg; 411 }; 412 413 static struct mv88e6390_serdes_hw_stat mv88e6390_serdes_hw_stats[] = { 414 { "serdes_rx_pkts", 0xf021 }, 415 { "serdes_rx_bytes", 0xf024 }, 416 { "serdes_rx_pkts_error", 0xf027 }, 417 }; 418 419 int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port) 420 { 421 if (mv88e6390_serdes_get_lane(chip, port) == 0) 422 return 0; 423 424 return ARRAY_SIZE(mv88e6390_serdes_hw_stats); 425 } 426 427 int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip, 428 int port, uint8_t *data) 429 { 430 struct mv88e6390_serdes_hw_stat *stat; 431 int i; 432 433 if (mv88e6390_serdes_get_lane(chip, port) == 0) 434 return 0; 435 436 for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) { 437 stat = &mv88e6390_serdes_hw_stats[i]; 438 memcpy(data + i * ETH_GSTRING_LEN, stat->string, 439 ETH_GSTRING_LEN); 440 } 441 return ARRAY_SIZE(mv88e6390_serdes_hw_stats); 442 } 443 444 static uint64_t mv88e6390_serdes_get_stat(struct mv88e6xxx_chip *chip, int lane, 445 struct mv88e6390_serdes_hw_stat *stat) 446 { 447 u16 reg[3]; 448 int err, i; 449 450 for (i = 0; i < 3; i++) { 451 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, 452 stat->reg + i, ®[i]); 453 if (err) { 454 dev_err(chip->dev, "failed to read statistic\n"); 455 return 0; 456 } 457 } 458 459 return reg[0] | ((u64)reg[1] << 16) | ((u64)reg[2] << 32); 460 } 461 462 int mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, 463 uint64_t *data) 464 { 465 struct mv88e6390_serdes_hw_stat *stat; 466 int lane; 467 int i; 468 469 lane = mv88e6390_serdes_get_lane(chip, port); 470 if (lane == 0) 471 return 0; 472 473 for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) { 474 stat = &mv88e6390_serdes_hw_stats[i]; 475 data[i] = mv88e6390_serdes_get_stat(chip, lane, stat); 476 } 477 478 return ARRAY_SIZE(mv88e6390_serdes_hw_stats); 479 } 480 481 static int mv88e6390_serdes_enable_checker(struct mv88e6xxx_chip *chip, u8 lane) 482 { 483 u16 reg; 484 int err; 485 486 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, 487 MV88E6390_PG_CONTROL, ®); 488 if (err) 489 return err; 490 491 reg |= MV88E6390_PG_CONTROL_ENABLE_PC; 492 return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, 493 MV88E6390_PG_CONTROL, reg); 494 } 495 496 int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane, 497 bool up) 498 { 499 u8 cmode = chip->ports[port].cmode; 500 int err = 0; 501 502 switch (cmode) { 503 case MV88E6XXX_PORT_STS_CMODE_SGMII: 504 case MV88E6XXX_PORT_STS_CMODE_1000BASEX: 505 case MV88E6XXX_PORT_STS_CMODE_2500BASEX: 506 err = mv88e6390_serdes_power_sgmii(chip, lane, up); 507 break; 508 case MV88E6XXX_PORT_STS_CMODE_XAUI: 509 case MV88E6XXX_PORT_STS_CMODE_RXAUI: 510 err = mv88e6390_serdes_power_10g(chip, lane, up); 511 break; 512 } 513 514 if (!err && up) 515 err = mv88e6390_serdes_enable_checker(chip, lane); 516 517 return err; 518 } 519 520 static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip, 521 int port, u8 lane) 522 { 523 u8 cmode = chip->ports[port].cmode; 524 struct dsa_switch *ds = chip->ds; 525 int duplex = DUPLEX_UNKNOWN; 526 int speed = SPEED_UNKNOWN; 527 phy_interface_t mode; 528 int link, err; 529 u16 status; 530 531 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, 532 MV88E6390_SGMII_PHY_STATUS, &status); 533 if (err) { 534 dev_err(chip->dev, "can't read SGMII PHY status: %d\n", err); 535 return; 536 } 537 538 link = status & MV88E6390_SGMII_PHY_STATUS_LINK ? 539 LINK_FORCED_UP : LINK_FORCED_DOWN; 540 541 if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) { 542 duplex = status & MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ? 543 DUPLEX_FULL : DUPLEX_HALF; 544 545 switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) { 546 case MV88E6390_SGMII_PHY_STATUS_SPEED_1000: 547 if (cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 548 speed = SPEED_2500; 549 else 550 speed = SPEED_1000; 551 break; 552 case MV88E6390_SGMII_PHY_STATUS_SPEED_100: 553 speed = SPEED_100; 554 break; 555 case MV88E6390_SGMII_PHY_STATUS_SPEED_10: 556 speed = SPEED_10; 557 break; 558 default: 559 dev_err(chip->dev, "invalid PHY speed\n"); 560 return; 561 } 562 } 563 564 switch (cmode) { 565 case MV88E6XXX_PORT_STS_CMODE_SGMII: 566 mode = PHY_INTERFACE_MODE_SGMII; 567 break; 568 case MV88E6XXX_PORT_STS_CMODE_1000BASEX: 569 mode = PHY_INTERFACE_MODE_1000BASEX; 570 break; 571 case MV88E6XXX_PORT_STS_CMODE_2500BASEX: 572 mode = PHY_INTERFACE_MODE_2500BASEX; 573 break; 574 default: 575 mode = PHY_INTERFACE_MODE_NA; 576 } 577 578 err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex, 579 PAUSE_OFF, mode); 580 if (err) 581 dev_err(chip->dev, "can't propagate PHY settings to MAC: %d\n", 582 err); 583 else 584 dsa_port_phylink_mac_change(ds, port, link == LINK_FORCED_UP); 585 } 586 587 static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip, 588 u8 lane, bool enable) 589 { 590 u16 val = 0; 591 592 if (enable) 593 val |= MV88E6390_SGMII_INT_LINK_DOWN | 594 MV88E6390_SGMII_INT_LINK_UP; 595 596 return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, 597 MV88E6390_SGMII_INT_ENABLE, val); 598 } 599 600 int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane, 601 bool enable) 602 { 603 u8 cmode = chip->ports[port].cmode; 604 605 switch (cmode) { 606 case MV88E6XXX_PORT_STS_CMODE_SGMII: 607 case MV88E6XXX_PORT_STS_CMODE_1000BASEX: 608 case MV88E6XXX_PORT_STS_CMODE_2500BASEX: 609 return mv88e6390_serdes_irq_enable_sgmii(chip, lane, enable); 610 } 611 612 return 0; 613 } 614 615 static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip, 616 u8 lane, u16 *status) 617 { 618 int err; 619 620 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, 621 MV88E6390_SGMII_INT_STATUS, status); 622 623 return err; 624 } 625 626 irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, 627 u8 lane) 628 { 629 u8 cmode = chip->ports[port].cmode; 630 irqreturn_t ret = IRQ_NONE; 631 u16 status; 632 int err; 633 634 switch (cmode) { 635 case MV88E6XXX_PORT_STS_CMODE_SGMII: 636 case MV88E6XXX_PORT_STS_CMODE_1000BASEX: 637 case MV88E6XXX_PORT_STS_CMODE_2500BASEX: 638 err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status); 639 if (err) 640 return ret; 641 if (status & (MV88E6390_SGMII_INT_LINK_DOWN | 642 MV88E6390_SGMII_INT_LINK_UP)) { 643 ret = IRQ_HANDLED; 644 mv88e6390_serdes_irq_link_sgmii(chip, port, lane); 645 } 646 } 647 648 return ret; 649 } 650 651 unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port) 652 { 653 return irq_find_mapping(chip->g2_irq.domain, port); 654 } 655