diff options
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/chip.c | 350 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/chip.h | 5 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/global2.h | 3 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/global2_scratch.c | 28 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/port.h | 5 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/serdes.c | 43 |
6 files changed, 294 insertions, 140 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 22391f8d4169..7670796c2aa1 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -570,133 +570,249 @@ static int mv88e6xxx_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port, return 0; } -static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port, - unsigned long *mask, - struct phylink_link_state *state) -{ - if (!phy_interface_mode_is_8023z(state->interface)) { - /* 10M and 100M are only supported in non-802.3z mode */ - phylink_set(mask, 10baseT_Half); - phylink_set(mask, 10baseT_Full); - phylink_set(mask, 100baseT_Half); - phylink_set(mask, 100baseT_Full); - } -} +static const u8 mv88e6185_phy_interface_modes[] = { + [MV88E6185_PORT_STS_CMODE_GMII_FD] = PHY_INTERFACE_MODE_GMII, + [MV88E6185_PORT_STS_CMODE_MII_100_FD_PS] = PHY_INTERFACE_MODE_MII, + [MV88E6185_PORT_STS_CMODE_MII_100] = PHY_INTERFACE_MODE_MII, + [MV88E6185_PORT_STS_CMODE_MII_10] = PHY_INTERFACE_MODE_MII, + [MV88E6185_PORT_STS_CMODE_SERDES] = PHY_INTERFACE_MODE_1000BASEX, + [MV88E6185_PORT_STS_CMODE_1000BASE_X] = PHY_INTERFACE_MODE_1000BASEX, + [MV88E6185_PORT_STS_CMODE_PHY] = PHY_INTERFACE_MODE_SGMII, +}; -static void mv88e6185_phylink_validate(struct mv88e6xxx_chip *chip, int port, - unsigned long *mask, - struct phylink_link_state *state) +static void mv88e6185_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, + struct phylink_config *config) { - /* FIXME: if the port is in 1000Base-X mode, then it only supports - * 1000M FD speeds. In this case, CMODE will indicate 5. + u8 cmode = chip->ports[port].cmode; + + if (cmode <= ARRAY_SIZE(mv88e6185_phy_interface_modes) && + mv88e6185_phy_interface_modes[cmode]) + __set_bit(mv88e6185_phy_interface_modes[cmode], + config->supported_interfaces); + + config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | + MAC_1000FD; +} + +static const u8 mv88e6xxx_phy_interface_modes[] = { + [MV88E6XXX_PORT_STS_CMODE_MII_PHY] = PHY_INTERFACE_MODE_MII, + [MV88E6XXX_PORT_STS_CMODE_MII] = PHY_INTERFACE_MODE_MII, + [MV88E6XXX_PORT_STS_CMODE_GMII] = PHY_INTERFACE_MODE_GMII, + [MV88E6XXX_PORT_STS_CMODE_RMII_PHY] = PHY_INTERFACE_MODE_RMII, + [MV88E6XXX_PORT_STS_CMODE_RMII] = PHY_INTERFACE_MODE_RMII, + [MV88E6XXX_PORT_STS_CMODE_100BASEX] = PHY_INTERFACE_MODE_100BASEX, + [MV88E6XXX_PORT_STS_CMODE_1000BASEX] = PHY_INTERFACE_MODE_1000BASEX, + [MV88E6XXX_PORT_STS_CMODE_SGMII] = PHY_INTERFACE_MODE_SGMII, + /* higher interface modes are not needed here, since ports supporting + * them are writable, and so the supported interfaces are filled in the + * corresponding .phylink_set_interfaces() implementation below */ - phylink_set(mask, 1000baseT_Full); - phylink_set(mask, 1000baseX_Full); +}; - mv88e6065_phylink_validate(chip, port, mask, state); +static void mv88e6xxx_translate_cmode(u8 cmode, unsigned long *supported) +{ + if (cmode < ARRAY_SIZE(mv88e6xxx_phy_interface_modes) && + mv88e6xxx_phy_interface_modes[cmode]) + __set_bit(mv88e6xxx_phy_interface_modes[cmode], supported); + else if (cmode == MV88E6XXX_PORT_STS_CMODE_RGMII) + phy_interface_set_rgmii(supported); } -static void mv88e6341_phylink_validate(struct mv88e6xxx_chip *chip, int port, - unsigned long *mask, - struct phylink_link_state *state) +static void mv88e6250_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, + struct phylink_config *config) { - if (port >= 5) - phylink_set(mask, 2500baseX_Full); + unsigned long *supported = config->supported_interfaces; - /* No ethtool bits for 200Mbps */ - phylink_set(mask, 1000baseT_Full); - phylink_set(mask, 1000baseX_Full); + /* Translate the default cmode */ + mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported); - mv88e6065_phylink_validate(chip, port, mask, state); + config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100; } -static void mv88e6352_phylink_validate(struct mv88e6xxx_chip *chip, int port, - unsigned long *mask, - struct phylink_link_state *state) +static int mv88e6352_get_port4_serdes_cmode(struct mv88e6xxx_chip *chip) { - /* No ethtool bits for 200Mbps */ - phylink_set(mask, 1000baseT_Full); - phylink_set(mask, 1000baseX_Full); + u16 reg, val; + int err; + + err = mv88e6xxx_port_read(chip, 4, MV88E6XXX_PORT_STS, ®); + if (err) + return err; + + /* If PHY_DETECT is zero, then we are not in auto-media mode */ + if (!(reg & MV88E6XXX_PORT_STS_PHY_DETECT)) + return 0xf; - mv88e6065_phylink_validate(chip, port, mask, state); + val = reg & ~MV88E6XXX_PORT_STS_PHY_DETECT; + err = mv88e6xxx_port_write(chip, 4, MV88E6XXX_PORT_STS, val); + if (err) + return err; + + err = mv88e6xxx_port_read(chip, 4, MV88E6XXX_PORT_STS, &val); + if (err) + return err; + + /* Restore PHY_DETECT value */ + err = mv88e6xxx_port_write(chip, 4, MV88E6XXX_PORT_STS, reg); + if (err) + return err; + + return val & MV88E6XXX_PORT_STS_CMODE_MASK; } -static void mv88e6390_phylink_validate(struct mv88e6xxx_chip *chip, int port, - unsigned long *mask, - struct phylink_link_state *state) +static void mv88e6352_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, + struct phylink_config *config) { - if (port >= 9) { - phylink_set(mask, 2500baseX_Full); - phylink_set(mask, 2500baseT_Full); + unsigned long *supported = config->supported_interfaces; + int err, cmode; + + /* Translate the default cmode */ + mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported); + + config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | + MAC_1000FD; + + /* Port 4 supports automedia if the serdes is associated with it. */ + if (port == 4) { + mv88e6xxx_reg_lock(chip); + err = mv88e6352_g2_scratch_port_has_serdes(chip, port); + if (err < 0) + dev_err(chip->dev, "p%d: failed to read scratch\n", + port); + if (err <= 0) + goto unlock; + + cmode = mv88e6352_get_port4_serdes_cmode(chip); + if (cmode < 0) + dev_err(chip->dev, "p%d: failed to read serdes cmode\n", + port); + else + mv88e6xxx_translate_cmode(cmode, supported); +unlock: + mv88e6xxx_reg_unlock(chip); } +} + +static void mv88e6341_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, + struct phylink_config *config) +{ + unsigned long *supported = config->supported_interfaces; + + /* Translate the default cmode */ + mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported); /* No ethtool bits for 200Mbps */ - phylink_set(mask, 1000baseT_Full); - phylink_set(mask, 1000baseX_Full); + config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | + MAC_1000FD; - mv88e6065_phylink_validate(chip, port, mask, state); + /* The C_Mode field is programmable on port 5 */ + if (port == 5) { + __set_bit(PHY_INTERFACE_MODE_SGMII, supported); + __set_bit(PHY_INTERFACE_MODE_1000BASEX, supported); + __set_bit(PHY_INTERFACE_MODE_2500BASEX, supported); + + config->mac_capabilities |= MAC_2500FD; + } } -static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port, - unsigned long *mask, - struct phylink_link_state *state) +static void mv88e6390_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, + struct phylink_config *config) { - if (port >= 9) { - phylink_set(mask, 10000baseT_Full); - phylink_set(mask, 10000baseKR_Full); + unsigned long *supported = config->supported_interfaces; + + /* Translate the default cmode */ + mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported); + + /* No ethtool bits for 200Mbps */ + config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | + MAC_1000FD; + + /* The C_Mode field is programmable on ports 9 and 10 */ + if (port == 9 || port == 10) { + __set_bit(PHY_INTERFACE_MODE_SGMII, supported); + __set_bit(PHY_INTERFACE_MODE_1000BASEX, supported); + __set_bit(PHY_INTERFACE_MODE_2500BASEX, supported); + + config->mac_capabilities |= MAC_2500FD; } +} + +static void mv88e6390x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, + struct phylink_config *config) +{ + unsigned long *supported = config->supported_interfaces; - mv88e6390_phylink_validate(chip, port, mask, state); + mv88e6390_phylink_get_caps(chip, port, config); + + /* For the 6x90X, ports 2-7 can be in automedia mode. + * (Note that 6x90 doesn't support RXAUI nor XAUI). + * + * Port 2 can also support 1000BASE-X in automedia mode if port 9 is + * configured for 1000BASE-X, SGMII or 2500BASE-X. + * Port 3-4 can also support 1000BASE-X in automedia mode if port 9 is + * configured for RXAUI, 1000BASE-X, SGMII or 2500BASE-X. + * + * Port 5 can also support 1000BASE-X in automedia mode if port 10 is + * configured for 1000BASE-X, SGMII or 2500BASE-X. + * Port 6-7 can also support 1000BASE-X in automedia mode if port 10 is + * configured for RXAUI, 1000BASE-X, SGMII or 2500BASE-X. + * + * For now, be permissive (as the old code was) and allow 1000BASE-X + * on ports 2..7. + */ + if (port >= 2 && port <= 7) + __set_bit(PHY_INTERFACE_MODE_1000BASEX, supported); + + /* The C_Mode field can also be programmed for 10G speeds */ + if (port == 9 || port == 10) { + __set_bit(PHY_INTERFACE_MODE_XAUI, supported); + __set_bit(PHY_INTERFACE_MODE_RXAUI, supported); + + config->mac_capabilities |= MAC_10000FD; + } } -static void mv88e6393x_phylink_validate(struct mv88e6xxx_chip *chip, int port, - unsigned long *mask, - struct phylink_link_state *state) +static void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, + struct phylink_config *config) { + unsigned long *supported = config->supported_interfaces; bool is_6191x = chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6191X; - if (((port == 0 || port == 9) && !is_6191x) || port == 10) { - phylink_set(mask, 10000baseT_Full); - phylink_set(mask, 10000baseKR_Full); - phylink_set(mask, 10000baseCR_Full); - phylink_set(mask, 10000baseSR_Full); - phylink_set(mask, 10000baseLR_Full); - phylink_set(mask, 10000baseLRM_Full); - phylink_set(mask, 10000baseER_Full); - phylink_set(mask, 5000baseT_Full); - phylink_set(mask, 2500baseX_Full); - phylink_set(mask, 2500baseT_Full); - } + mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported); + + config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | + MAC_1000FD; - phylink_set(mask, 1000baseT_Full); - phylink_set(mask, 1000baseX_Full); + /* The C_Mode field can be programmed for ports 0, 9 and 10 */ + if (port == 0 || port == 9 || port == 10) { + __set_bit(PHY_INTERFACE_MODE_SGMII, supported); + __set_bit(PHY_INTERFACE_MODE_1000BASEX, supported); - mv88e6065_phylink_validate(chip, port, mask, state); + /* 6191X supports >1G modes only on port 10 */ + if (!is_6191x || port == 10) { + __set_bit(PHY_INTERFACE_MODE_2500BASEX, supported); + __set_bit(PHY_INTERFACE_MODE_5GBASER, supported); + __set_bit(PHY_INTERFACE_MODE_10GBASER, supported); + /* FIXME: USXGMII is not supported yet */ + /* __set_bit(PHY_INTERFACE_MODE_USXGMII, supported); */ + + config->mac_capabilities |= MAC_2500FD | MAC_5000FD | + MAC_10000FD; + } + } } -static void mv88e6xxx_validate(struct dsa_switch *ds, int port, - unsigned long *supported, - struct phylink_link_state *state) +static void mv88e6xxx_get_caps(struct dsa_switch *ds, int port, + struct phylink_config *config) { - __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; struct mv88e6xxx_chip *chip = ds->priv; - /* Allow all the expected bits */ - phylink_set(mask, Autoneg); - phylink_set(mask, Pause); - phylink_set_port_modes(mask); - - if (chip->info->ops->phylink_validate) - chip->info->ops->phylink_validate(chip, port, mask, state); + chip->info->ops->phylink_get_caps(chip, port, config); - linkmode_and(supported, supported, mask); - linkmode_and(state->advertising, state->advertising, mask); - - /* We can only operate at 2500BaseX or 1000BaseX. If requested - * to advertise both, only report advertising at 2500BaseX. - */ - phylink_helper_basex_speed(state); + /* Internal ports need GMII for PHYLIB */ + if (mv88e6xxx_phy_is_internal(ds, port)) + __set_bit(PHY_INTERFACE_MODE_GMII, + config->supported_interfaces); } static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, @@ -3628,7 +3744,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = { .rmu_disable = mv88e6085_g1_rmu_disable, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, - .phylink_validate = mv88e6185_phylink_validate, + .phylink_get_caps = mv88e6185_phylink_get_caps, .set_max_frame_size = mv88e6185_g1_set_max_frame_size, }; @@ -3662,7 +3778,7 @@ static const struct mv88e6xxx_ops mv88e6095_ops = { .reset = mv88e6185_g1_reset, .vtu_getnext = mv88e6185_g1_vtu_getnext, .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, - .phylink_validate = mv88e6185_phylink_validate, + .phylink_get_caps = mv88e6185_phylink_get_caps, .set_max_frame_size = mv88e6185_g1_set_max_frame_size, }; @@ -3709,7 +3825,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = { .rmu_disable = mv88e6085_g1_rmu_disable, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, - .phylink_validate = mv88e6185_phylink_validate, + .phylink_get_caps = mv88e6185_phylink_get_caps, .set_max_frame_size = mv88e6185_g1_set_max_frame_size, }; @@ -3746,7 +3862,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = { .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, - .phylink_validate = mv88e6185_phylink_validate, + .phylink_get_caps = mv88e6185_phylink_get_caps, .set_max_frame_size = mv88e6185_g1_set_max_frame_size, }; @@ -3787,7 +3903,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = { .reset = mv88e6185_g1_reset, .vtu_getnext = mv88e6185_g1_vtu_getnext, .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, - .phylink_validate = mv88e6185_phylink_validate, + .phylink_get_caps = mv88e6185_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6141_ops = { @@ -3851,7 +3967,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { .serdes_get_stats = mv88e6390_serdes_get_stats, .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, .serdes_get_regs = mv88e6390_serdes_get_regs, - .phylink_validate = mv88e6341_phylink_validate, + .phylink_get_caps = mv88e6341_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6161_ops = { @@ -3893,7 +4009,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = { .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .avb_ops = &mv88e6165_avb_ops, .ptp_ops = &mv88e6165_ptp_ops, - .phylink_validate = mv88e6185_phylink_validate, + .phylink_get_caps = mv88e6185_phylink_get_caps, .set_max_frame_size = mv88e6185_g1_set_max_frame_size, }; @@ -3929,7 +4045,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = { .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .avb_ops = &mv88e6165_avb_ops, .ptp_ops = &mv88e6165_ptp_ops, - .phylink_validate = mv88e6185_phylink_validate, + .phylink_get_caps = mv88e6185_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6171_ops = { @@ -3971,7 +4087,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = { .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, - .phylink_validate = mv88e6185_phylink_validate, + .phylink_get_caps = mv88e6185_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6172_ops = { @@ -4026,7 +4142,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, .serdes_get_regs = mv88e6352_serdes_get_regs, .gpio_ops = &mv88e6352_gpio_ops, - .phylink_validate = mv88e6352_phylink_validate, + .phylink_get_caps = mv88e6352_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6175_ops = { @@ -4068,7 +4184,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = { .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, - .phylink_validate = mv88e6185_phylink_validate, + .phylink_get_caps = mv88e6185_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6176_ops = { @@ -4126,7 +4242,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, .serdes_get_regs = mv88e6352_serdes_get_regs, .gpio_ops = &mv88e6352_gpio_ops, - .phylink_validate = mv88e6352_phylink_validate, + .phylink_get_caps = mv88e6352_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6185_ops = { @@ -4165,7 +4281,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = { .reset = mv88e6185_g1_reset, .vtu_getnext = mv88e6185_g1_vtu_getnext, .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, - .phylink_validate = mv88e6185_phylink_validate, + .phylink_get_caps = mv88e6185_phylink_get_caps, .set_max_frame_size = mv88e6185_g1_set_max_frame_size, }; @@ -4227,7 +4343,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, .serdes_get_regs = mv88e6390_serdes_get_regs, .gpio_ops = &mv88e6352_gpio_ops, - .phylink_validate = mv88e6390_phylink_validate, + .phylink_get_caps = mv88e6390_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6190x_ops = { @@ -4288,7 +4404,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, .serdes_get_regs = mv88e6390_serdes_get_regs, .gpio_ops = &mv88e6352_gpio_ops, - .phylink_validate = mv88e6390x_phylink_validate, + .phylink_get_caps = mv88e6390x_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6191_ops = { @@ -4348,7 +4464,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = { .serdes_get_regs = mv88e6390_serdes_get_regs, .avb_ops = &mv88e6390_avb_ops, .ptp_ops = &mv88e6352_ptp_ops, - .phylink_validate = mv88e6390_phylink_validate, + .phylink_get_caps = mv88e6390_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6240_ops = { @@ -4408,7 +4524,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .gpio_ops = &mv88e6352_gpio_ops, .avb_ops = &mv88e6352_avb_ops, .ptp_ops = &mv88e6352_ptp_ops, - .phylink_validate = mv88e6352_phylink_validate, + .phylink_get_caps = mv88e6352_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6250_ops = { @@ -4448,7 +4564,7 @@ static const struct mv88e6xxx_ops mv88e6250_ops = { .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, .avb_ops = &mv88e6352_avb_ops, .ptp_ops = &mv88e6250_ptp_ops, - .phylink_validate = mv88e6065_phylink_validate, + .phylink_get_caps = mv88e6250_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6290_ops = { @@ -4510,7 +4626,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = { .gpio_ops = &mv88e6352_gpio_ops, .avb_ops = &mv88e6390_avb_ops, .ptp_ops = &mv88e6352_ptp_ops, - .phylink_validate = mv88e6390_phylink_validate, + .phylink_get_caps = mv88e6390_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6320_ops = { @@ -4554,7 +4670,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { .gpio_ops = &mv88e6352_gpio_ops, .avb_ops = &mv88e6352_avb_ops, .ptp_ops = &mv88e6352_ptp_ops, - .phylink_validate = mv88e6185_phylink_validate, + .phylink_get_caps = mv88e6185_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6321_ops = { @@ -4596,7 +4712,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { .gpio_ops = &mv88e6352_gpio_ops, .avb_ops = &mv88e6352_avb_ops, .ptp_ops = &mv88e6352_ptp_ops, - .phylink_validate = mv88e6185_phylink_validate, + .phylink_get_caps = mv88e6185_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6341_ops = { @@ -4662,7 +4778,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { .serdes_get_stats = mv88e6390_serdes_get_stats, .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, .serdes_get_regs = mv88e6390_serdes_get_regs, - .phylink_validate = mv88e6341_phylink_validate, + .phylink_get_caps = mv88e6341_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6350_ops = { @@ -4704,7 +4820,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = { .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, - .phylink_validate = mv88e6185_phylink_validate, + .phylink_get_caps = mv88e6185_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6351_ops = { @@ -4748,7 +4864,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = { .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .avb_ops = &mv88e6352_avb_ops, .ptp_ops = &mv88e6352_ptp_ops, - .phylink_validate = mv88e6185_phylink_validate, + .phylink_get_caps = mv88e6185_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6352_ops = { @@ -4811,7 +4927,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .serdes_get_stats = mv88e6352_serdes_get_stats, .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, .serdes_get_regs = mv88e6352_serdes_get_regs, - .phylink_validate = mv88e6352_phylink_validate, + .phylink_get_caps = mv88e6352_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6390_ops = { @@ -4876,7 +4992,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { .serdes_get_stats = mv88e6390_serdes_get_stats, .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, .serdes_get_regs = mv88e6390_serdes_get_regs, - .phylink_validate = mv88e6390_phylink_validate, + .phylink_get_caps = mv88e6390_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6390x_ops = { @@ -4940,7 +5056,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { .gpio_ops = &mv88e6352_gpio_ops, .avb_ops = &mv88e6390_avb_ops, .ptp_ops = &mv88e6352_ptp_ops, - .phylink_validate = mv88e6390x_phylink_validate, + .phylink_get_caps = mv88e6390x_phylink_get_caps, }; static const struct mv88e6xxx_ops mv88e6393x_ops = { @@ -5004,7 +5120,7 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = { .gpio_ops = &mv88e6352_gpio_ops, .avb_ops = &mv88e6390_avb_ops, .ptp_ops = &mv88e6352_ptp_ops, - .phylink_validate = mv88e6393x_phylink_validate, + .phylink_get_caps = mv88e6393x_phylink_get_caps, }; static const struct mv88e6xxx_info mv88e6xxx_table[] = { @@ -6273,7 +6389,7 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = { .teardown = mv88e6xxx_teardown, .port_setup = mv88e6xxx_port_setup, .port_teardown = mv88e6xxx_port_teardown, - .phylink_validate = mv88e6xxx_validate, + .phylink_get_caps = mv88e6xxx_get_caps, .phylink_mac_link_state = mv88e6xxx_serdes_pcs_get_state, .phylink_mac_config = mv88e6xxx_mac_config, .phylink_mac_an_restart = mv88e6xxx_serdes_pcs_an_restart, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 80dc7b549e81..12aa637779f5 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -611,9 +611,8 @@ struct mv88e6xxx_ops { const struct mv88e6xxx_ptp_ops *ptp_ops; /* Phylink */ - void (*phylink_validate)(struct mv88e6xxx_chip *chip, int port, - unsigned long *mask, - struct phylink_link_state *state); + void (*phylink_get_caps)(struct mv88e6xxx_chip *chip, int port, + struct phylink_config *config); /* Max Frame Size */ int (*set_max_frame_size)(struct mv88e6xxx_chip *chip, int mtu); diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index f3e27573a386..807aeaad9830 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -299,6 +299,8 @@ #define MV88E6352_G2_SCRATCH_CONFIG_DATA1_NO_CPU BIT(2) #define MV88E6352_G2_SCRATCH_CONFIG_DATA2 0x72 #define MV88E6352_G2_SCRATCH_CONFIG_DATA2_P0_MODE_MASK 0x3 +#define MV88E6352_G2_SCRATCH_CONFIG_DATA3 0x73 +#define MV88E6352_G2_SCRATCH_CONFIG_DATA3_S_SEL BIT(1) #define MV88E6352_G2_SCRATCH_GPIO_PCTL_GPIO 0 #define MV88E6352_G2_SCRATCH_GPIO_PCTL_TRIG 1 @@ -370,6 +372,7 @@ extern const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops; int mv88e6xxx_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip, bool external); +int mv88e6352_g2_scratch_port_has_serdes(struct mv88e6xxx_chip *chip, int port); int mv88e6xxx_g2_atu_stats_set(struct mv88e6xxx_chip *chip, u16 kind, u16 bin); int mv88e6xxx_g2_atu_stats_get(struct mv88e6xxx_chip *chip, u16 *stats); diff --git a/drivers/net/dsa/mv88e6xxx/global2_scratch.c b/drivers/net/dsa/mv88e6xxx/global2_scratch.c index eda710062933..a9d6e40321a2 100644 --- a/drivers/net/dsa/mv88e6xxx/global2_scratch.c +++ b/drivers/net/dsa/mv88e6xxx/global2_scratch.c @@ -289,3 +289,31 @@ int mv88e6xxx_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip, return mv88e6xxx_g2_scratch_write(chip, misc_cfg, val); } + +/** + * mv88e6352_g2_scratch_port_has_serdes - indicate if a port can have a serdes + * @chip: chip private data + * @port: port number to check for serdes + * + * Indicates whether the port may have a serdes attached according to the + * pin strapping. Returns negative error number, 0 if the port is not + * configured to have a serdes, and 1 if the port is configured to have a + * serdes attached. + */ +int mv88e6352_g2_scratch_port_has_serdes(struct mv88e6xxx_chip *chip, int port) +{ + u8 config3, p; + int err; + + err = mv88e6xxx_g2_scratch_read(chip, MV88E6352_G2_SCRATCH_CONFIG_DATA3, + &config3); + if (err) + return err; + + if (config3 & MV88E6352_G2_SCRATCH_CONFIG_DATA3_S_SEL) + p = 5; + else + p = 4; + + return port == p; +} diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 5c347cc58baf..3a13db2ec27b 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -42,6 +42,11 @@ #define MV88E6XXX_PORT_STS_TX_PAUSED 0x0020 #define MV88E6XXX_PORT_STS_FLOW_CTL 0x0010 #define MV88E6XXX_PORT_STS_CMODE_MASK 0x000f +#define MV88E6XXX_PORT_STS_CMODE_MII_PHY 0x0001 +#define MV88E6XXX_PORT_STS_CMODE_MII 0x0002 +#define MV88E6XXX_PORT_STS_CMODE_GMII 0x0003 +#define MV88E6XXX_PORT_STS_CMODE_RMII_PHY 0x0004 +#define MV88E6XXX_PORT_STS_CMODE_RMII 0x0005 #define MV88E6XXX_PORT_STS_CMODE_RGMII 0x0007 #define MV88E6XXX_PORT_STS_CMODE_100BASEX 0x0008 #define MV88E6XXX_PORT_STS_CMODE_1000BASEX 0x0009 diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index 2b05ead515cd..6a177bf654ee 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -272,14 +272,6 @@ int mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) return lane; } -static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip *chip, int port) -{ - if (mv88e6xxx_serdes_get_lane(chip, port) >= 0) - return true; - - return false; -} - struct mv88e6352_serdes_hw_stat { char string[ETH_GSTRING_LEN]; int sizeof_stat; @@ -293,20 +285,24 @@ static struct mv88e6352_serdes_hw_stat mv88e6352_serdes_hw_stats[] = { int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port) { - if (mv88e6352_port_has_serdes(chip, port)) - return ARRAY_SIZE(mv88e6352_serdes_hw_stats); + int err; - return 0; + err = mv88e6352_g2_scratch_port_has_serdes(chip, port); + if (err <= 0) + return err; + + return ARRAY_SIZE(mv88e6352_serdes_hw_stats); } int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, int port, uint8_t *data) { struct mv88e6352_serdes_hw_stat *stat; - int i; + int err, i; - if (!mv88e6352_port_has_serdes(chip, port)) - return 0; + err = mv88e6352_g2_scratch_port_has_serdes(chip, port); + if (err <= 0) + return err; for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) { stat = &mv88e6352_serdes_hw_stats[i]; @@ -348,11 +344,12 @@ int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, { struct mv88e6xxx_port *mv88e6xxx_port = &chip->ports[port]; struct mv88e6352_serdes_hw_stat *stat; + int i, err; u64 value; - int i; - if (!mv88e6352_port_has_serdes(chip, port)) - return 0; + err = mv88e6352_g2_scratch_port_has_serdes(chip, port); + if (err <= 0) + return err; BUILD_BUG_ON(ARRAY_SIZE(mv88e6352_serdes_hw_stats) > ARRAY_SIZE(mv88e6xxx_port->serdes_stats)); @@ -419,8 +416,13 @@ unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port) int mv88e6352_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port) { - if (!mv88e6352_port_has_serdes(chip, port)) - return 0; + int err; + + mv88e6xxx_reg_lock(chip); + err = mv88e6352_g2_scratch_port_has_serdes(chip, port); + mv88e6xxx_reg_unlock(chip); + if (err <= 0) + return err; return 32 * sizeof(u16); } @@ -432,7 +434,8 @@ void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p) int err; int i; - if (!mv88e6352_port_has_serdes(chip, port)) + err = mv88e6352_g2_scratch_port_has_serdes(chip, port); + if (err <= 0) return; for (i = 0 ; i < 32; i++) { |