Messages in this thread Patch in this message | | | From | msmulski2@gmail ... | Subject | [PATCH net-next v5 1/1] net: dsa: mv88e6xxx: implement USXGMII mode for mv88e6393x | Date | Thu, 1 Jun 2023 14:52:51 -0700 |
| |
From: Michal Smulski <michal.smulski@ooma.com>
Enable USXGMII mode for mv88e6393x chips. Tested on Marvell 88E6191X.
Signed-off-by: Michal Smulski <michal.smulski@ooma.com> --- drivers/net/dsa/mv88e6xxx/chip.c | 3 +- drivers/net/dsa/mv88e6xxx/port.c | 3 ++ drivers/net/dsa/mv88e6xxx/serdes.c | 70 +++++++++++++++++++++++++++++- drivers/net/dsa/mv88e6xxx/serdes.h | 13 ++++++ 4 files changed, 85 insertions(+), 4 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 8731af6d79de..5a92ccfd08ea 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -815,8 +815,7 @@ static void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, config->mac_capabilities |= MAC_5000FD | MAC_10000FD; } - /* FIXME: USXGMII is not supported yet */ - /* __set_bit(PHY_INTERFACE_MODE_USXGMII, supported); */ + __set_bit(PHY_INTERFACE_MODE_USXGMII, supported); } } diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index e9b4a6ea4d09..dd66ec902d4c 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -566,6 +566,9 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port, case PHY_INTERFACE_MODE_10GBASER: cmode = MV88E6393X_PORT_STS_CMODE_10GBASER; break; + case PHY_INTERFACE_MODE_USXGMII: + cmode = MV88E6393X_PORT_STS_CMODE_USXGMII; + break; default: cmode = 0; } diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index 72faec8f44dc..e4f3dc39bc46 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -683,7 +683,8 @@ int mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX || cmode == MV88E6393X_PORT_STS_CMODE_5GBASER || - cmode == MV88E6393X_PORT_STS_CMODE_10GBASER) + cmode == MV88E6393X_PORT_STS_CMODE_10GBASER || + cmode == MV88E6393X_PORT_STS_CMODE_USXGMII) lane = port; return lane; @@ -984,6 +985,64 @@ static int mv88e6393x_serdes_pcs_get_state_10g(struct mv88e6xxx_chip *chip, state->speed = SPEED_10000; state->duplex = DUPLEX_FULL; } + return 0; +} + +/* USXGMII registers for Marvell switch 88e639x are undocumented and this function is based + * on some educated guesses. It appears that there are no status bits related to + * autonegotiation complete or flow control. + */ +static int mv88e639x_serdes_pcs_get_state_usxgmii(struct mv88e6xxx_chip *chip, + int port, int lane, + struct phylink_link_state *state) +{ + u16 status, lp_status; + int err; + + err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, + MV88E6390_USXGMII_LP_STATUS, &lp_status); + if (err) { + dev_err(chip->dev, "can't read Serdes USXGMII LP status: %d\n", err); + return err; + } + dev_dbg(chip->dev, "USXGMII LP statsus: 0x%x\n", lp_status); + + err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, + MV88E6390_USXGMII_PHY_STATUS, &status); + if (err) { + dev_err(chip->dev, "can't read Serdes USXGMII PHY status: %d\n", err); + return err; + } + dev_dbg(chip->dev, "USXGMII PHY statsus: 0x%x\n", status); + + state->link = !!(status & MV88E6390_USXGMII_PHY_STATUS_LINK); + state->duplex = status & + MV88E6390_USXGMII_PHY_STATUS_DUPLEX_FULL ? + DUPLEX_FULL : DUPLEX_HALF; + + switch (status & MV88E6390_USXGMII_PHY_STATUS_SPEED_MASK) { + case MV88E6390_USXGMII_PHY_STATUS_SPEED_10000: + state->speed = SPEED_10000; + break; + case MV88E6390_USXGMII_PHY_STATUS_SPEED_5000: + state->speed = SPEED_5000; + break; + case MV88E6390_USXGMII_PHY_STATUS_SPEED_2500: + state->speed = SPEED_2500; + break; + case MV88E6390_USXGMII_PHY_STATUS_SPEED_1000: + state->speed = SPEED_1000; + break; + case MV88E6390_USXGMII_PHY_STATUS_SPEED_100: + state->speed = SPEED_100; + break; + case MV88E6390_USXGMII_PHY_STATUS_SPEED_10: + state->speed = SPEED_10; + break; + default: + dev_err(chip->dev, "invalid PHY speed\n"); + return -EINVAL; + } return 0; } @@ -1020,6 +1079,9 @@ int mv88e6393x_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port, case PHY_INTERFACE_MODE_10GBASER: return mv88e6393x_serdes_pcs_get_state_10g(chip, port, lane, state); + case PHY_INTERFACE_MODE_USXGMII: + return mv88e639x_serdes_pcs_get_state_usxgmii(chip, port, lane, + state); default: return -EOPNOTSUPP; @@ -1173,6 +1235,7 @@ int mv88e6393x_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, return mv88e6390_serdes_irq_enable_sgmii(chip, lane, enable); case MV88E6393X_PORT_STS_CMODE_5GBASER: case MV88E6393X_PORT_STS_CMODE_10GBASER: + case MV88E6393X_PORT_STS_CMODE_USXGMII: return mv88e6393x_serdes_irq_enable_10g(chip, lane, enable); } @@ -1213,6 +1276,7 @@ irqreturn_t mv88e6393x_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, break; case MV88E6393X_PORT_STS_CMODE_5GBASER: case MV88E6393X_PORT_STS_CMODE_10GBASER: + case MV88E6393X_PORT_STS_CMODE_USXGMII: err = mv88e6393x_serdes_irq_status_10g(chip, lane, &status); if (err) return err; @@ -1477,7 +1541,8 @@ static int mv88e6393x_serdes_erratum_5_2(struct mv88e6xxx_chip *chip, int lane, * to SERDES operating in 10G mode. These registers only apply to 10G * operation and have no effect on other speeds. */ - if (cmode != MV88E6393X_PORT_STS_CMODE_10GBASER) + if (cmode != MV88E6393X_PORT_STS_CMODE_10GBASER && + cmode != MV88E6393X_PORT_STS_CMODE_USXGMII) return 0; for (i = 0; i < ARRAY_SIZE(fixes); ++i) { @@ -1582,6 +1647,7 @@ int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane, break; case MV88E6393X_PORT_STS_CMODE_5GBASER: case MV88E6393X_PORT_STS_CMODE_10GBASER: + case MV88E6393X_PORT_STS_CMODE_USXGMII: err = mv88e6390_serdes_power_10g(chip, lane, on); break; default: diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h index 29bb4e91e2f6..899b8518113a 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.h +++ b/drivers/net/dsa/mv88e6xxx/serdes.h @@ -48,6 +48,19 @@ #define MV88E6393X_10G_INT_LINK_CHANGE BIT(2) #define MV88E6393X_10G_INT_STATUS 0x9001 +/* USXGMII */ +#define MV88E6390_USXGMII_LP_STATUS 0xf0a2 +#define MV88E6390_USXGMII_PHY_STATUS 0xf0a6 +#define MV88E6390_USXGMII_PHY_STATUS_SPEED_MASK GENMASK(11, 9) +#define MV88E6390_USXGMII_PHY_STATUS_SPEED_5000 0xa00 +#define MV88E6390_USXGMII_PHY_STATUS_SPEED_2500 0x800 +#define MV88E6390_USXGMII_PHY_STATUS_SPEED_10000 0x600 +#define MV88E6390_USXGMII_PHY_STATUS_SPEED_1000 0x400 +#define MV88E6390_USXGMII_PHY_STATUS_SPEED_100 0x200 +#define MV88E6390_USXGMII_PHY_STATUS_SPEED_10 0x000 +#define MV88E6390_USXGMII_PHY_STATUS_DUPLEX_FULL BIT(12) +#define MV88E6390_USXGMII_PHY_STATUS_LINK BIT(15) + /* 1000BASE-X and SGMII */ #define MV88E6390_SGMII_BMCR (0x2000 + MII_BMCR) #define MV88E6390_SGMII_BMSR (0x2000 + MII_BMSR) -- 2.34.1
| |