From: Michal Smulski <[email protected]>
Enable USXGMII mode for mv88e6393x chips. Tested on Marvell 88E6191X.
Signed-off-by: Michal Smulski <[email protected]>
---
drivers/net/dsa/mv88e6xxx/chip.c | 3 +-
drivers/net/dsa/mv88e6xxx/port.c | 3 ++
drivers/net/dsa/mv88e6xxx/serdes.c | 47 ++++++++++++++++++++++++++++--
drivers/net/dsa/mv88e6xxx/serdes.h | 4 +++
4 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 2af0c1145d36..8b51756bd805 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -812,11 +812,10 @@ static void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
if (!is_6361) {
__set_bit(PHY_INTERFACE_MODE_5GBASER, supported);
__set_bit(PHY_INTERFACE_MODE_10GBASER, supported);
+ __set_bit(PHY_INTERFACE_MODE_USXGMII, supported);
config->mac_capabilities |= MAC_5000FD |
MAC_10000FD;
}
- /* FIXME: USXGMII is not supported yet */
- /* __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..a28b368ed016 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,7 +985,42 @@ 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_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 status: 0x%x\n", status);
+
+ state->link = !!(status & MDIO_USXGMII_LINK);
+ state->an_complete = state->link;
+
+ if (state->link) {
+ 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 status: 0x%x\n", lp_status);
+ phylink_decode_usxgmii_word(state, lp_status);
+ }
return 0;
}
@@ -1020,6 +1056,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 +1212,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 +1253,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 +1518,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 +1624,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..e245687ddb1d 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.h
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -48,6 +48,10 @@
#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
+
/* 1000BASE-X and SGMII */
#define MV88E6390_SGMII_BMCR (0x2000 + MII_BMCR)
#define MV88E6390_SGMII_BMSR (0x2000 + MII_BMSR)
--
2.34.1
On Sun, Jun 04, 2023 at 10:39:54PM -0700, [email protected] wrote:
> From: Michal Smulski <[email protected]>
>
> Enable USXGMII mode for mv88e6393x chips. Tested on Marvell 88E6191X.
>
> Signed-off-by: Michal Smulski <[email protected]>
> ---
> drivers/net/dsa/mv88e6xxx/chip.c | 3 +-
> drivers/net/dsa/mv88e6xxx/port.c | 3 ++
> drivers/net/dsa/mv88e6xxx/serdes.c | 47 ++++++++++++++++++++++++++++--
> drivers/net/dsa/mv88e6xxx/serdes.h | 4 +++
> 4 files changed, 53 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
> index 2af0c1145d36..8b51756bd805 100644
> --- a/drivers/net/dsa/mv88e6xxx/chip.c
> +++ b/drivers/net/dsa/mv88e6xxx/chip.c
> @@ -812,11 +812,10 @@ static void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
> if (!is_6361) {
> __set_bit(PHY_INTERFACE_MODE_5GBASER, supported);
> __set_bit(PHY_INTERFACE_MODE_10GBASER, supported);
> + __set_bit(PHY_INTERFACE_MODE_USXGMII, supported);
> config->mac_capabilities |= MAC_5000FD |
> MAC_10000FD;
> }
> - /* FIXME: USXGMII is not supported yet */
> - /* __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..a28b368ed016 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,7 +985,42 @@ 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_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 status: 0x%x\n", status);
> +
> + state->link = !!(status & MDIO_USXGMII_LINK);
> + state->an_complete = state->link;
> +
> + if (state->link) {
> + 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 status: 0x%x\n", lp_status);
>
Please put a comment here that lp_status appears to include the "link"
bit as per USXGMII spec.
We don't know about pcs-lynx yet, which doesn't _seem_ to with the
AR113C, and we don't know why - if we made phylink_decode_usxgmii_word()
parse this bit as well, we need to keep track of which implementations
do provide that bit and which do not (and may be buggy.)
> + phylink_decode_usxgmii_word(state, lp_status);
> + }
> return 0;
> }
>
> @@ -1020,6 +1056,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 +1212,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 +1253,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 +1518,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 +1624,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..e245687ddb1d 100644
> --- a/drivers/net/dsa/mv88e6xxx/serdes.h
> +++ b/drivers/net/dsa/mv88e6xxx/serdes.h
> @@ -48,6 +48,10 @@
> #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
> +
> /* 1000BASE-X and SGMII */
> #define MV88E6390_SGMII_BMCR (0x2000 + MII_BMCR)
> #define MV88E6390_SGMII_BMSR (0x2000 + MII_BMSR)
> --
> 2.34.1
>
>
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!