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 int mv88e6352_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port) 241 { 242 if (!mv88e6352_port_has_serdes(chip, port)) 243 return 0; 244 245 return 32 * sizeof(u16); 246 } 247 248 void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p) 249 { 250 u16 *p = _p; 251 u16 reg; 252 int i; 253 254 if (!mv88e6352_port_has_serdes(chip, port)) 255 return; 256 257 for (i = 0 ; i < 32; i++) { 258 mv88e6352_serdes_read(chip, i, ®); 259 p[i] = reg; 260 } 261 } 262 263 u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) 264 { 265 u8 cmode = chip->ports[port].cmode; 266 u8 lane = 0; 267 268 switch (port) { 269 case 5: 270 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 271 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || 272 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 273 lane = MV88E6341_PORT5_LANE; 274 break; 275 } 276 277 return lane; 278 } 279 280 u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) 281 { 282 u8 cmode = chip->ports[port].cmode; 283 u8 lane = 0; 284 285 switch (port) { 286 case 9: 287 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 288 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || 289 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 290 lane = MV88E6390_PORT9_LANE0; 291 break; 292 case 10: 293 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 294 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || 295 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 296 lane = MV88E6390_PORT10_LANE0; 297 break; 298 } 299 300 return lane; 301 } 302 303 u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) 304 { 305 u8 cmode_port = chip->ports[port].cmode; 306 u8 cmode_port10 = chip->ports[10].cmode; 307 u8 cmode_port9 = chip->ports[9].cmode; 308 u8 lane = 0; 309 310 switch (port) { 311 case 2: 312 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 313 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 314 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 315 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) 316 lane = MV88E6390_PORT9_LANE1; 317 break; 318 case 3: 319 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 320 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 321 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 322 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 323 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) 324 lane = MV88E6390_PORT9_LANE2; 325 break; 326 case 4: 327 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 328 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 329 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 330 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 331 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) 332 lane = MV88E6390_PORT9_LANE3; 333 break; 334 case 5: 335 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 336 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 337 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 338 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) 339 lane = MV88E6390_PORT10_LANE1; 340 break; 341 case 6: 342 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 343 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 344 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 345 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 346 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) 347 lane = MV88E6390_PORT10_LANE2; 348 break; 349 case 7: 350 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 351 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 352 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 353 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 354 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) 355 lane = MV88E6390_PORT10_LANE3; 356 break; 357 case 9: 358 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 359 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 360 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 361 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI || 362 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 363 lane = MV88E6390_PORT9_LANE0; 364 break; 365 case 10: 366 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 367 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 368 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 369 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI || 370 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 371 lane = MV88E6390_PORT10_LANE0; 372 break; 373 } 374 375 return lane; 376 } 377 378 /* Set power up/down for 10GBASE-R and 10GBASE-X4/X2 */ 379 static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane, 380 bool up) 381 { 382 u16 val, new_val; 383 int err; 384 385 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, 386 MV88E6390_PCS_CONTROL_1, &val); 387 388 if (err) 389 return err; 390 391 if (up) 392 new_val = val & ~(MV88E6390_PCS_CONTROL_1_RESET | 393 MV88E6390_PCS_CONTROL_1_LOOPBACK | 394 MV88E6390_PCS_CONTROL_1_PDOWN); 395 else 396 new_val = val | MV88E6390_PCS_CONTROL_1_PDOWN; 397 398 if (val != new_val) 399 err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, 400 MV88E6390_PCS_CONTROL_1, new_val); 401 402 return err; 403 } 404 405 /* Set power up/down for SGMII and 1000Base-X */ 406 static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, u8 lane, 407 bool up) 408 { 409 u16 val, new_val; 410 int err; 411 412 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, 413 MV88E6390_SGMII_BMCR, &val); 414 if (err) 415 return err; 416 417 if (up) 418 new_val = val & ~(BMCR_RESET | BMCR_LOOPBACK | BMCR_PDOWN); 419 else 420 new_val = val | BMCR_PDOWN; 421 422 if (val != new_val) 423 err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, 424 MV88E6390_SGMII_BMCR, new_val); 425 426 return err; 427 } 428 429 struct mv88e6390_serdes_hw_stat { 430 char string[ETH_GSTRING_LEN]; 431 int reg; 432 }; 433 434 static struct mv88e6390_serdes_hw_stat mv88e6390_serdes_hw_stats[] = { 435 { "serdes_rx_pkts", 0xf021 }, 436 { "serdes_rx_bytes", 0xf024 }, 437 { "serdes_rx_pkts_error", 0xf027 }, 438 }; 439 440 int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port) 441 { 442 if (mv88e6390_serdes_get_lane(chip, port) == 0) 443 return 0; 444 445 return ARRAY_SIZE(mv88e6390_serdes_hw_stats); 446 } 447 448 int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip, 449 int port, uint8_t *data) 450 { 451 struct mv88e6390_serdes_hw_stat *stat; 452 int i; 453 454 if (mv88e6390_serdes_get_lane(chip, port) == 0) 455 return 0; 456 457 for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) { 458 stat = &mv88e6390_serdes_hw_stats[i]; 459 memcpy(data + i * ETH_GSTRING_LEN, stat->string, 460 ETH_GSTRING_LEN); 461 } 462 return ARRAY_SIZE(mv88e6390_serdes_hw_stats); 463 } 464 465 static uint64_t mv88e6390_serdes_get_stat(struct mv88e6xxx_chip *chip, int lane, 466 struct mv88e6390_serdes_hw_stat *stat) 467 { 468 u16 reg[3]; 469 int err, i; 470 471 for (i = 0; i < 3; i++) { 472 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, 473 stat->reg + i, ®[i]); 474 if (err) { 475 dev_err(chip->dev, "failed to read statistic\n"); 476 return 0; 477 } 478 } 479 480 return reg[0] | ((u64)reg[1] << 16) | ((u64)reg[2] << 32); 481 } 482 483 int mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, 484 uint64_t *data) 485 { 486 struct mv88e6390_serdes_hw_stat *stat; 487 int lane; 488 int i; 489 490 lane = mv88e6390_serdes_get_lane(chip, port); 491 if (lane == 0) 492 return 0; 493 494 for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) { 495 stat = &mv88e6390_serdes_hw_stats[i]; 496 data[i] = mv88e6390_serdes_get_stat(chip, lane, stat); 497 } 498 499 return ARRAY_SIZE(mv88e6390_serdes_hw_stats); 500 } 501 502 static int mv88e6390_serdes_enable_checker(struct mv88e6xxx_chip *chip, u8 lane) 503 { 504 u16 reg; 505 int err; 506 507 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, 508 MV88E6390_PG_CONTROL, ®); 509 if (err) 510 return err; 511 512 reg |= MV88E6390_PG_CONTROL_ENABLE_PC; 513 return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, 514 MV88E6390_PG_CONTROL, reg); 515 } 516 517 int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane, 518 bool up) 519 { 520 u8 cmode = chip->ports[port].cmode; 521 int err = 0; 522 523 switch (cmode) { 524 case MV88E6XXX_PORT_STS_CMODE_SGMII: 525 case MV88E6XXX_PORT_STS_CMODE_1000BASEX: 526 case MV88E6XXX_PORT_STS_CMODE_2500BASEX: 527 err = mv88e6390_serdes_power_sgmii(chip, lane, up); 528 break; 529 case MV88E6XXX_PORT_STS_CMODE_XAUI: 530 case MV88E6XXX_PORT_STS_CMODE_RXAUI: 531 err = mv88e6390_serdes_power_10g(chip, lane, up); 532 break; 533 } 534 535 if (!err && up) 536 err = mv88e6390_serdes_enable_checker(chip, lane); 537 538 return err; 539 } 540 541 static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip, 542 int port, u8 lane) 543 { 544 u8 cmode = chip->ports[port].cmode; 545 struct dsa_switch *ds = chip->ds; 546 int duplex = DUPLEX_UNKNOWN; 547 int speed = SPEED_UNKNOWN; 548 phy_interface_t mode; 549 int link, err; 550 u16 status; 551 552 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, 553 MV88E6390_SGMII_PHY_STATUS, &status); 554 if (err) { 555 dev_err(chip->dev, "can't read SGMII PHY status: %d\n", err); 556 return; 557 } 558 559 link = status & MV88E6390_SGMII_PHY_STATUS_LINK ? 560 LINK_FORCED_UP : LINK_FORCED_DOWN; 561 562 if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) { 563 duplex = status & MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ? 564 DUPLEX_FULL : DUPLEX_HALF; 565 566 switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) { 567 case MV88E6390_SGMII_PHY_STATUS_SPEED_1000: 568 if (cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 569 speed = SPEED_2500; 570 else 571 speed = SPEED_1000; 572 break; 573 case MV88E6390_SGMII_PHY_STATUS_SPEED_100: 574 speed = SPEED_100; 575 break; 576 case MV88E6390_SGMII_PHY_STATUS_SPEED_10: 577 speed = SPEED_10; 578 break; 579 default: 580 dev_err(chip->dev, "invalid PHY speed\n"); 581 return; 582 } 583 } 584 585 switch (cmode) { 586 case MV88E6XXX_PORT_STS_CMODE_SGMII: 587 mode = PHY_INTERFACE_MODE_SGMII; 588 break; 589 case MV88E6XXX_PORT_STS_CMODE_1000BASEX: 590 mode = PHY_INTERFACE_MODE_1000BASEX; 591 break; 592 case MV88E6XXX_PORT_STS_CMODE_2500BASEX: 593 mode = PHY_INTERFACE_MODE_2500BASEX; 594 break; 595 default: 596 mode = PHY_INTERFACE_MODE_NA; 597 } 598 599 err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex, 600 PAUSE_OFF, mode); 601 if (err) 602 dev_err(chip->dev, "can't propagate PHY settings to MAC: %d\n", 603 err); 604 else 605 dsa_port_phylink_mac_change(ds, port, link == LINK_FORCED_UP); 606 } 607 608 static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip, 609 u8 lane, bool enable) 610 { 611 u16 val = 0; 612 613 if (enable) 614 val |= MV88E6390_SGMII_INT_LINK_DOWN | 615 MV88E6390_SGMII_INT_LINK_UP; 616 617 return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, 618 MV88E6390_SGMII_INT_ENABLE, val); 619 } 620 621 int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane, 622 bool enable) 623 { 624 u8 cmode = chip->ports[port].cmode; 625 626 switch (cmode) { 627 case MV88E6XXX_PORT_STS_CMODE_SGMII: 628 case MV88E6XXX_PORT_STS_CMODE_1000BASEX: 629 case MV88E6XXX_PORT_STS_CMODE_2500BASEX: 630 return mv88e6390_serdes_irq_enable_sgmii(chip, lane, enable); 631 } 632 633 return 0; 634 } 635 636 static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip, 637 u8 lane, u16 *status) 638 { 639 int err; 640 641 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, 642 MV88E6390_SGMII_INT_STATUS, status); 643 644 return err; 645 } 646 647 irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, 648 u8 lane) 649 { 650 u8 cmode = chip->ports[port].cmode; 651 irqreturn_t ret = IRQ_NONE; 652 u16 status; 653 int err; 654 655 switch (cmode) { 656 case MV88E6XXX_PORT_STS_CMODE_SGMII: 657 case MV88E6XXX_PORT_STS_CMODE_1000BASEX: 658 case MV88E6XXX_PORT_STS_CMODE_2500BASEX: 659 err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status); 660 if (err) 661 return ret; 662 if (status & (MV88E6390_SGMII_INT_LINK_DOWN | 663 MV88E6390_SGMII_INT_LINK_UP)) { 664 ret = IRQ_HANDLED; 665 mv88e6390_serdes_irq_link_sgmii(chip, port, lane); 666 } 667 } 668 669 return ret; 670 } 671 672 unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port) 673 { 674 return irq_find_mapping(chip->g2_irq.domain, port); 675 } 676 677 static const u16 mv88e6390_serdes_regs[] = { 678 /* SERDES common registers */ 679 0xf00a, 0xf00b, 0xf00c, 680 0xf010, 0xf011, 0xf012, 0xf013, 681 0xf016, 0xf017, 0xf018, 682 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f, 683 0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027, 684 0xf028, 0xf029, 685 0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037, 686 0xf038, 0xf039, 687 /* SGMII */ 688 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 689 0x2008, 690 0x200f, 691 0xa000, 0xa001, 0xa002, 0xa003, 692 /* 10Gbase-X */ 693 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 694 0x1008, 695 0x100e, 0x100f, 696 0x1018, 0x1019, 697 0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 698 0x9006, 699 0x9010, 0x9011, 0x9012, 0x9013, 0x9014, 0x9015, 0x9016, 700 /* 10Gbase-R */ 701 0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027, 702 0x1028, 0x1029, 0x102a, 0x102b, 703 }; 704 705 int mv88e6390_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port) 706 { 707 if (mv88e6xxx_serdes_get_lane(chip, port) == 0) 708 return 0; 709 710 return ARRAY_SIZE(mv88e6390_serdes_regs) * sizeof(u16); 711 } 712 713 void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p) 714 { 715 u16 *p = _p; 716 int lane; 717 u16 reg; 718 int i; 719 720 lane = mv88e6xxx_serdes_get_lane(chip, port); 721 if (lane == 0) 722 return; 723 724 for (i = 0 ; i < ARRAY_SIZE(mv88e6390_serdes_regs); i++) { 725 mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, 726 mv88e6390_serdes_regs[i], ®); 727 p[i] = reg; 728 } 729 } 730