root/drivers/net/dsa/mv88e6xxx/serdes.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mv88e6352_serdes_read
  2. mv88e6352_serdes_write
  3. mv88e6390_serdes_read
  4. mv88e6390_serdes_write
  5. mv88e6352_serdes_power
  6. mv88e6352_serdes_get_lane
  7. mv88e6352_port_has_serdes
  8. mv88e6352_serdes_get_sset_count
  9. mv88e6352_serdes_get_strings
  10. mv88e6352_serdes_get_stat
  11. mv88e6352_serdes_get_stats
  12. mv88e6352_serdes_irq_link
  13. mv88e6352_serdes_irq_status
  14. mv88e6352_serdes_irq_enable
  15. mv88e6352_serdes_irq_mapping
  16. mv88e6341_serdes_get_lane
  17. mv88e6390_serdes_get_lane
  18. mv88e6390x_serdes_get_lane
  19. mv88e6390_serdes_power_10g
  20. mv88e6390_serdes_power_sgmii
  21. mv88e6390_serdes_power
  22. mv88e6390_serdes_irq_link_sgmii
  23. mv88e6390_serdes_irq_enable_sgmii
  24. mv88e6390_serdes_irq_enable
  25. mv88e6390_serdes_irq_status_sgmii
  26. mv88e6390_serdes_irq_status
  27. mv88e6390_serdes_irq_mapping

   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, &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, &reg);
 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 int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
 409                            bool up)
 410 {
 411         u8 cmode = chip->ports[port].cmode;
 412 
 413         switch (cmode) {
 414         case MV88E6XXX_PORT_STS_CMODE_SGMII:
 415         case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
 416         case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
 417                 return mv88e6390_serdes_power_sgmii(chip, lane, up);
 418         case MV88E6XXX_PORT_STS_CMODE_XAUI:
 419         case MV88E6XXX_PORT_STS_CMODE_RXAUI:
 420                 return mv88e6390_serdes_power_10g(chip, lane, up);
 421         }
 422 
 423         return 0;
 424 }
 425 
 426 static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
 427                                             int port, u8 lane)
 428 {
 429         u8 cmode = chip->ports[port].cmode;
 430         struct dsa_switch *ds = chip->ds;
 431         int duplex = DUPLEX_UNKNOWN;
 432         int speed = SPEED_UNKNOWN;
 433         phy_interface_t mode;
 434         int link, err;
 435         u16 status;
 436 
 437         err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
 438                                     MV88E6390_SGMII_PHY_STATUS, &status);
 439         if (err) {
 440                 dev_err(chip->dev, "can't read SGMII PHY status: %d\n", err);
 441                 return;
 442         }
 443 
 444         link = status & MV88E6390_SGMII_PHY_STATUS_LINK ?
 445                LINK_FORCED_UP : LINK_FORCED_DOWN;
 446 
 447         if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) {
 448                 duplex = status & MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ?
 449                          DUPLEX_FULL : DUPLEX_HALF;
 450 
 451                 switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) {
 452                 case MV88E6390_SGMII_PHY_STATUS_SPEED_1000:
 453                         if (cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
 454                                 speed = SPEED_2500;
 455                         else
 456                                 speed = SPEED_1000;
 457                         break;
 458                 case MV88E6390_SGMII_PHY_STATUS_SPEED_100:
 459                         speed = SPEED_100;
 460                         break;
 461                 case MV88E6390_SGMII_PHY_STATUS_SPEED_10:
 462                         speed = SPEED_10;
 463                         break;
 464                 default:
 465                         dev_err(chip->dev, "invalid PHY speed\n");
 466                         return;
 467                 }
 468         }
 469 
 470         switch (cmode) {
 471         case MV88E6XXX_PORT_STS_CMODE_SGMII:
 472                 mode = PHY_INTERFACE_MODE_SGMII;
 473                 break;
 474         case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
 475                 mode = PHY_INTERFACE_MODE_1000BASEX;
 476                 break;
 477         case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
 478                 mode = PHY_INTERFACE_MODE_2500BASEX;
 479                 break;
 480         default:
 481                 mode = PHY_INTERFACE_MODE_NA;
 482         }
 483 
 484         err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex,
 485                                        PAUSE_OFF, mode);
 486         if (err)
 487                 dev_err(chip->dev, "can't propagate PHY settings to MAC: %d\n",
 488                         err);
 489         else
 490                 dsa_port_phylink_mac_change(ds, port, link == LINK_FORCED_UP);
 491 }
 492 
 493 static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
 494                                              u8 lane, bool enable)
 495 {
 496         u16 val = 0;
 497 
 498         if (enable)
 499                 val |= MV88E6390_SGMII_INT_LINK_DOWN |
 500                         MV88E6390_SGMII_INT_LINK_UP;
 501 
 502         return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
 503                                       MV88E6390_SGMII_INT_ENABLE, val);
 504 }
 505 
 506 int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
 507                                 bool enable)
 508 {
 509         u8 cmode = chip->ports[port].cmode;
 510 
 511         switch (cmode) {
 512         case MV88E6XXX_PORT_STS_CMODE_SGMII:
 513         case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
 514         case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
 515                 return mv88e6390_serdes_irq_enable_sgmii(chip, lane, enable);
 516         }
 517 
 518         return 0;
 519 }
 520 
 521 static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
 522                                              u8 lane, u16 *status)
 523 {
 524         int err;
 525 
 526         err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
 527                                     MV88E6390_SGMII_INT_STATUS, status);
 528 
 529         return err;
 530 }
 531 
 532 irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
 533                                         u8 lane)
 534 {
 535         u8 cmode = chip->ports[port].cmode;
 536         irqreturn_t ret = IRQ_NONE;
 537         u16 status;
 538         int err;
 539 
 540         switch (cmode) {
 541         case MV88E6XXX_PORT_STS_CMODE_SGMII:
 542         case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
 543         case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
 544                 err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status);
 545                 if (err)
 546                         return ret;
 547                 if (status & (MV88E6390_SGMII_INT_LINK_DOWN |
 548                               MV88E6390_SGMII_INT_LINK_UP)) {
 549                         ret = IRQ_HANDLED;
 550                         mv88e6390_serdes_irq_link_sgmii(chip, port, lane);
 551                 }
 552         }
 553 
 554         return ret;
 555 }
 556 
 557 unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
 558 {
 559         return irq_find_mapping(chip->g2_irq.domain, port);
 560 }

/* [<][>][^][v][top][bottom][index][help] */