diff options
Diffstat (limited to 'drivers/net/dsa/mt7530.c')
-rw-r--r-- | drivers/net/dsa/mt7530.c | 499 |
1 files changed, 261 insertions, 238 deletions
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index b82512e5b33b..e74c6b406172 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -24,6 +24,11 @@ #include "mt7530.h" +static struct mt753x_pcs *pcs_to_mt753x_pcs(struct phylink_pcs *pcs) +{ + return container_of(pcs, struct mt753x_pcs, pcs); +} + /* String, offset, and register size in bytes if different from 4 bytes */ static const struct mt7530_mib_desc mt7530_mib[] = { MIB_DESC(1, 0x00, "TxDrop"), @@ -501,14 +506,19 @@ static bool mt7531_dual_sgmii_supported(struct mt7530_priv *priv) static int mt7531_pad_setup(struct dsa_switch *ds, phy_interface_t interface) { - struct mt7530_priv *priv = ds->priv; + return 0; +} + +static void +mt7531_pll_setup(struct mt7530_priv *priv) +{ u32 top_sig; u32 hwstrap; u32 xtal; u32 val; if (mt7531_dual_sgmii_supported(priv)) - return 0; + return; val = mt7530_read(priv, MT7531_CREV); top_sig = mt7530_read(priv, MT7531_TOP_SIG_SR); @@ -587,8 +597,6 @@ mt7531_pad_setup(struct dsa_switch *ds, phy_interface_t interface) val |= EN_COREPLL; mt7530_write(priv, MT7531_PLLGP_EN, val); usleep_range(25, 35); - - return 0; } static void @@ -1033,6 +1041,7 @@ static int mt7530_port_enable(struct dsa_switch *ds, int port, struct phy_device *phy) { + struct dsa_port *dp = dsa_to_port(ds, port); struct mt7530_priv *priv = ds->priv; mutex_lock(&priv->reg_mutex); @@ -1041,7 +1050,11 @@ mt7530_port_enable(struct dsa_switch *ds, int port, * restore the port matrix if the port is the member of a certain * bridge. */ - priv->ports[port].pm |= PCR_MATRIX(BIT(MT7530_CPU_PORT)); + if (dsa_port_is_user(dp)) { + struct dsa_port *cpu_dp = dp->cpu_dp; + + priv->ports[port].pm |= PCR_MATRIX(BIT(cpu_dp->index)); + } priv->ports[port].enable = true; mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, priv->ports[port].pm); @@ -1186,10 +1199,12 @@ mt7530_port_bridge_flags(struct dsa_switch *ds, int port, static int mt7530_port_bridge_join(struct dsa_switch *ds, int port, - struct dsa_bridge bridge, bool *tx_fwd_offload) + struct dsa_bridge bridge, bool *tx_fwd_offload, + struct netlink_ext_ack *extack) { struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; - u32 port_bitmap = BIT(MT7530_CPU_PORT); + struct dsa_port *cpu_dp = dp->cpu_dp; + u32 port_bitmap = BIT(cpu_dp->index); struct mt7530_priv *priv = ds->priv; mutex_lock(&priv->reg_mutex); @@ -1266,9 +1281,12 @@ mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port) * the CPU port get out of VLAN filtering mode. */ if (all_user_ports_removed) { - mt7530_write(priv, MT7530_PCR_P(MT7530_CPU_PORT), + struct dsa_port *dp = dsa_to_port(ds, port); + struct dsa_port *cpu_dp = dp->cpu_dp; + + mt7530_write(priv, MT7530_PCR_P(cpu_dp->index), PCR_MATRIX(dsa_user_ports(priv->ds))); - mt7530_write(priv, MT7530_PVC_P(MT7530_CPU_PORT), PORT_SPEC_TAG + mt7530_write(priv, MT7530_PVC_P(cpu_dp->index), PORT_SPEC_TAG | PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT)); } } @@ -1306,6 +1324,7 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge) { struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; + struct dsa_port *cpu_dp = dp->cpu_dp; struct mt7530_priv *priv = ds->priv; mutex_lock(&priv->reg_mutex); @@ -1334,8 +1353,8 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port, */ if (priv->ports[port].enable) mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, - PCR_MATRIX(BIT(MT7530_CPU_PORT))); - priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT)); + PCR_MATRIX(BIT(cpu_dp->index))); + priv->ports[port].pm = PCR_MATRIX(BIT(cpu_dp->index)); /* When a port is removed from the bridge, the port would be set up * back to the default as is at initial boot which is a VLAN-unaware @@ -1349,7 +1368,8 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port, static int mt7530_port_fdb_add(struct dsa_switch *ds, int port, - const unsigned char *addr, u16 vid) + const unsigned char *addr, u16 vid, + struct dsa_db db) { struct mt7530_priv *priv = ds->priv; int ret; @@ -1365,7 +1385,8 @@ mt7530_port_fdb_add(struct dsa_switch *ds, int port, static int mt7530_port_fdb_del(struct dsa_switch *ds, int port, - const unsigned char *addr, u16 vid) + const unsigned char *addr, u16 vid, + struct dsa_db db) { struct mt7530_priv *priv = ds->priv; int ret; @@ -1416,7 +1437,8 @@ err: static int mt7530_port_mdb_add(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_mdb *mdb) + const struct switchdev_obj_port_mdb *mdb, + struct dsa_db db) { struct mt7530_priv *priv = ds->priv; const u8 *addr = mdb->addr; @@ -1442,7 +1464,8 @@ mt7530_port_mdb_add(struct dsa_switch *ds, int port, static int mt7530_port_mdb_del(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_mdb *mdb) + const struct switchdev_obj_port_mdb *mdb, + struct dsa_db db) { struct mt7530_priv *priv = ds->priv; const u8 *addr = mdb->addr; @@ -1498,6 +1521,9 @@ static int mt7530_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, struct netlink_ext_ack *extack) { + struct dsa_port *dp = dsa_to_port(ds, port); + struct dsa_port *cpu_dp = dp->cpu_dp; + if (vlan_filtering) { /* The port is being kept as VLAN-unaware port when bridge is * set up with vlan_filtering not being set, Otherwise, the @@ -1505,7 +1531,7 @@ mt7530_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, * for becoming a VLAN-aware port. */ mt7530_port_set_vlan_aware(ds, port); - mt7530_port_set_vlan_aware(ds, MT7530_CPU_PORT); + mt7530_port_set_vlan_aware(ds, cpu_dp->index); } else { mt7530_port_set_vlan_unaware(ds, port); } @@ -1517,11 +1543,11 @@ static void mt7530_hw_vlan_add(struct mt7530_priv *priv, struct mt7530_hw_vlan_entry *entry) { + struct dsa_port *dp = dsa_to_port(priv->ds, entry->port); u8 new_members; u32 val; - new_members = entry->old_members | BIT(entry->port) | - BIT(MT7530_CPU_PORT); + new_members = entry->old_members | BIT(entry->port); /* Validate the entry with independent learning, create egress tag per * VLAN and joining the port as one of the port members. @@ -1532,22 +1558,20 @@ mt7530_hw_vlan_add(struct mt7530_priv *priv, /* Decide whether adding tag or not for those outgoing packets from the * port inside the VLAN. - */ - val = entry->untagged ? MT7530_VLAN_EGRESS_UNTAG : - MT7530_VLAN_EGRESS_TAG; - mt7530_rmw(priv, MT7530_VAWD2, - ETAG_CTRL_P_MASK(entry->port), - ETAG_CTRL_P(entry->port, val)); - - /* CPU port is always taken as a tagged port for serving more than one + * CPU port is always taken as a tagged port for serving more than one * VLANs across and also being applied with egress type stack mode for * that VLAN tags would be appended after hardware special tag used as * DSA tag. */ + if (dsa_port_is_cpu(dp)) + val = MT7530_VLAN_EGRESS_STACK; + else if (entry->untagged) + val = MT7530_VLAN_EGRESS_UNTAG; + else + val = MT7530_VLAN_EGRESS_TAG; mt7530_rmw(priv, MT7530_VAWD2, - ETAG_CTRL_P_MASK(MT7530_CPU_PORT), - ETAG_CTRL_P(MT7530_CPU_PORT, - MT7530_VLAN_EGRESS_STACK)); + ETAG_CTRL_P_MASK(entry->port), + ETAG_CTRL_P(entry->port, val)); } static void @@ -1566,11 +1590,7 @@ mt7530_hw_vlan_del(struct mt7530_priv *priv, return; } - /* If certain member apart from CPU port is still alive in the VLAN, - * the entry would be kept valid. Otherwise, the entry is got to be - * disabled. - */ - if (new_members && new_members != BIT(MT7530_CPU_PORT)) { + if (new_members) { val = IVL_MAC | VTAG_EN | PORT_MEM(new_members) | VLAN_VALID; mt7530_write(priv, MT7530_VAWD1, val); @@ -1709,7 +1729,7 @@ static int mt753x_mirror_port_set(unsigned int id, u32 val) static int mt753x_port_mirror_add(struct dsa_switch *ds, int port, struct dsa_mall_mirror_tc_entry *mirror, - bool ingress) + bool ingress, struct netlink_ext_ack *extack) { struct mt7530_priv *priv = ds->priv; int monitor_port; @@ -2074,7 +2094,7 @@ mt7530_setup_mdio(struct mt7530_priv *priv) if (priv->irq) mt7530_setup_mdio_irq(priv); - ret = mdiobus_register(bus); + ret = devm_mdiobus_register(dev, bus); if (ret) { dev_err(dev, "failed to register MDIO bus: %d\n", ret); if (priv->irq) @@ -2088,11 +2108,12 @@ static int mt7530_setup(struct dsa_switch *ds) { struct mt7530_priv *priv = ds->priv; + struct device_node *dn = NULL; struct device_node *phy_node; struct device_node *mac_np; struct mt7530_dummy_poll p; phy_interface_t interface; - struct device_node *dn; + struct dsa_port *cpu_dp; u32 id, val; int ret, i; @@ -2100,7 +2121,19 @@ mt7530_setup(struct dsa_switch *ds) * controller also is the container for two GMACs nodes representing * as two netdev instances. */ - dn = dsa_to_port(ds, MT7530_CPU_PORT)->master->dev.of_node->parent; + dsa_switch_for_each_cpu_port(cpu_dp, ds) { + dn = cpu_dp->master->dev.of_node->parent; + /* It doesn't matter which CPU port is found first, + * their masters should share the same parent OF node + */ + break; + } + + if (!dn) { + dev_err(ds->dev, "parent OF node of DSA master not found"); + return -EINVAL; + } + ds->assisted_learning_on_cpu_port = true; ds->mtu_enforcement_ingress = true; @@ -2224,6 +2257,7 @@ mt7530_setup(struct dsa_switch *ds) ret = of_get_phy_mode(mac_np, &interface); if (ret && ret != -ENODEV) { of_node_put(mac_np); + of_node_put(phy_node); return ret; } id = of_mdio_parse_addr(ds->dev, phy_node); @@ -2261,6 +2295,7 @@ mt7531_setup(struct dsa_switch *ds) { struct mt7530_priv *priv = ds->priv; struct mt7530_dummy_poll p; + struct dsa_port *cpu_dp; u32 val, id; int ret, i; @@ -2294,11 +2329,17 @@ mt7531_setup(struct dsa_switch *ds) return -ENODEV; } + /* all MACs must be forced link-down before sw reset */ + for (i = 0; i < MT7530_NUM_PORTS; i++) + mt7530_write(priv, MT7530_PMCR_P(i), MT7531_FORCE_LNK); + /* Reset the switch through internal reset */ mt7530_write(priv, MT7530_SYS_CTRL, SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST | SYS_CTRL_REG_RST); + mt7531_pll_setup(priv); + if (mt7531_dual_sgmii_supported(priv)) { priv->p5_intf_sel = P5_INTF_SEL_GMAC5_SGMII; @@ -2333,8 +2374,11 @@ mt7531_setup(struct dsa_switch *ds) CORE_PLL_GROUP4, val); /* BPDU to CPU port */ - mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK, - BIT(MT7530_CPU_PORT)); + dsa_switch_for_each_cpu_port(cpu_dp, ds) { + mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK, + BIT(cpu_dp->index)); + break; + } mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK, MT753X_BPDU_CPU_ONLY); @@ -2384,35 +2428,30 @@ mt7531_setup(struct dsa_switch *ds) return 0; } -static bool -mt7530_phy_mode_supported(struct dsa_switch *ds, int port, - const struct phylink_link_state *state) +static void mt7530_mac_port_get_caps(struct dsa_switch *ds, int port, + struct phylink_config *config) { - struct mt7530_priv *priv = ds->priv; - switch (port) { case 0 ... 4: /* Internal phy */ - if (state->interface != PHY_INTERFACE_MODE_GMII) - return false; + __set_bit(PHY_INTERFACE_MODE_GMII, + config->supported_interfaces); break; + case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */ - if (!phy_interface_mode_is_rgmii(state->interface) && - state->interface != PHY_INTERFACE_MODE_MII && - state->interface != PHY_INTERFACE_MODE_GMII) - return false; + phy_interface_set_rgmii(config->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_MII, + config->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_GMII, + config->supported_interfaces); break; + case 6: /* 1st cpu port */ - if (state->interface != PHY_INTERFACE_MODE_RGMII && - state->interface != PHY_INTERFACE_MODE_TRGMII) - return false; + __set_bit(PHY_INTERFACE_MODE_RGMII, + config->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_TRGMII, + config->supported_interfaces); break; - default: - dev_err(priv->dev, "%s: unsupported port: %i\n", __func__, - port); - return false; } - - return true; } static bool mt7531_is_rgmii_port(struct mt7530_priv *priv, u32 port) @@ -2420,42 +2459,35 @@ static bool mt7531_is_rgmii_port(struct mt7530_priv *priv, u32 port) return (port == 5) && (priv->p5_intf_sel != P5_INTF_SEL_GMAC5_SGMII); } -static bool -mt7531_phy_mode_supported(struct dsa_switch *ds, int port, - const struct phylink_link_state *state) +static void mt7531_mac_port_get_caps(struct dsa_switch *ds, int port, + struct phylink_config *config) { struct mt7530_priv *priv = ds->priv; switch (port) { case 0 ... 4: /* Internal phy */ - if (state->interface != PHY_INTERFACE_MODE_GMII) - return false; + __set_bit(PHY_INTERFACE_MODE_GMII, + config->supported_interfaces); break; + case 5: /* 2nd cpu port supports either rgmii or sgmii/8023z */ - if (mt7531_is_rgmii_port(priv, port)) - return phy_interface_mode_is_rgmii(state->interface); + if (mt7531_is_rgmii_port(priv, port)) { + phy_interface_set_rgmii(config->supported_interfaces); + break; + } fallthrough; + case 6: /* 1st cpu port supports sgmii/8023z only */ - if (state->interface != PHY_INTERFACE_MODE_SGMII && - !phy_interface_mode_is_8023z(state->interface)) - return false; + __set_bit(PHY_INTERFACE_MODE_SGMII, + config->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_1000BASEX, + config->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_2500BASEX, + config->supported_interfaces); + + config->mac_capabilities |= MAC_2500FD; break; - default: - dev_err(priv->dev, "%s: unsupported port: %i\n", __func__, - port); - return false; } - - return true; -} - -static bool -mt753x_phy_mode_supported(struct dsa_switch *ds, int port, - const struct phylink_link_state *state) -{ - struct mt7530_priv *priv = ds->priv; - - return priv->info->phy_mode_supported(ds, port, state); } static int @@ -2528,30 +2560,11 @@ static int mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port, return 0; } -static void mt7531_sgmii_validate(struct mt7530_priv *priv, int port, - unsigned long *supported) +static void mt7531_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, + phy_interface_t interface, int speed, int duplex) { - /* Port5 supports ethier RGMII or SGMII. - * Port6 supports SGMII only. - */ - switch (port) { - case 5: - if (mt7531_is_rgmii_port(priv, port)) - break; - fallthrough; - case 6: - phylink_set(supported, 1000baseX_Full); - phylink_set(supported, 2500baseX_Full); - phylink_set(supported, 2500baseT_Full); - } -} - -static void -mt7531_sgmii_link_up_force(struct dsa_switch *ds, int port, - unsigned int mode, phy_interface_t interface, - int speed, int duplex) -{ - struct mt7530_priv *priv = ds->priv; + struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; + int port = pcs_to_mt753x_pcs(pcs)->port; unsigned int val; /* For adjusting speed and duplex of SGMII force mode. */ @@ -2577,6 +2590,9 @@ mt7531_sgmii_link_up_force(struct dsa_switch *ds, int port, /* MT7531 SGMII 1G force mode can only work in full duplex mode, * no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not. + * + * The speed check is unnecessary as the MAC capabilities apply + * this restriction. --rmk */ if ((speed == SPEED_10 || speed == SPEED_100) && duplex != DUPLEX_FULL) @@ -2652,9 +2668,10 @@ static int mt7531_sgmii_setup_mode_an(struct mt7530_priv *priv, int port, return 0; } -static void mt7531_sgmii_restart_an(struct dsa_switch *ds, int port) +static void mt7531_pcs_an_restart(struct phylink_pcs *pcs) { - struct mt7530_priv *priv = ds->priv; + struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; + int port = pcs_to_mt753x_pcs(pcs)->port; u32 val; /* Only restart AN when AN is enabled */ @@ -2691,9 +2708,6 @@ mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode, case PHY_INTERFACE_MODE_NA: case PHY_INTERFACE_MODE_1000BASEX: case PHY_INTERFACE_MODE_2500BASEX: - if (phylink_autoneg_inband(mode)) - return -EINVAL; - return mt7531_sgmii_setup_mode_force(priv, port, interface); default: return -EINVAL; @@ -2711,6 +2725,24 @@ mt753x_mac_config(struct dsa_switch *ds, int port, unsigned int mode, return priv->info->mac_port_config(ds, port, mode, state->interface); } +static struct phylink_pcs * +mt753x_phylink_mac_select_pcs(struct dsa_switch *ds, int port, + phy_interface_t interface) +{ + struct mt7530_priv *priv = ds->priv; + + switch (interface) { + case PHY_INTERFACE_MODE_TRGMII: + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + return &priv->pcs[port].pcs; + + default: + return NULL; + } +} + static void mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, const struct phylink_link_state *state) @@ -2718,9 +2750,6 @@ mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, struct mt7530_priv *priv = ds->priv; u32 mcr_cur, mcr_new; - if (!mt753x_phy_mode_supported(ds, port, state)) - goto unsupported; - switch (port) { case 0 ... 4: /* Internal phy */ if (state->interface != PHY_INTERFACE_MODE_GMII) @@ -2754,13 +2783,6 @@ unsupported: return; } - if (phylink_autoneg_inband(mode) && - state->interface != PHY_INTERFACE_MODE_SGMII) { - dev_err(ds->dev, "%s: in-band negotiation unsupported\n", - __func__); - return; - } - mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port)); mcr_new = mcr_cur; mcr_new &= ~PMCR_LINK_SETTINGS_MASK; @@ -2775,17 +2797,6 @@ unsupported: mt7530_write(priv, MT7530_PMCR_P(port), mcr_new); } -static void -mt753x_phylink_mac_an_restart(struct dsa_switch *ds, int port) -{ - struct mt7530_priv *priv = ds->priv; - - if (!priv->info->mac_pcs_an_restart) - return; - - priv->info->mac_pcs_an_restart(ds, port); -} - static void mt753x_phylink_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, phy_interface_t interface) @@ -2795,16 +2806,13 @@ static void mt753x_phylink_mac_link_down(struct dsa_switch *ds, int port, mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK); } -static void mt753x_mac_pcs_link_up(struct dsa_switch *ds, int port, - unsigned int mode, phy_interface_t interface, - int speed, int duplex) +static void mt753x_phylink_pcs_link_up(struct phylink_pcs *pcs, + unsigned int mode, + phy_interface_t interface, + int speed, int duplex) { - struct mt7530_priv *priv = ds->priv; - - if (!priv->info->mac_pcs_link_up) - return; - - priv->info->mac_pcs_link_up(ds, port, mode, interface, speed, duplex); + if (pcs->ops->pcs_link_up) + pcs->ops->pcs_link_up(pcs, mode, interface, speed, duplex); } static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port, @@ -2817,8 +2825,6 @@ static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port, struct mt7530_priv *priv = ds->priv; u32 mcr; - mt753x_mac_pcs_link_up(ds, port, mode, interface, speed, duplex); - mcr = PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK; /* MT753x MAC works in 1G full duplex mode for all up-clocked @@ -2846,7 +2852,7 @@ static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port, mcr |= PMCR_RX_FC_EN; } - if (mode == MLO_AN_PHY && phydev && phy_init_eee(phydev, 0) >= 0) { + if (mode == MLO_AN_PHY && phydev && phy_init_eee(phydev, false) >= 0) { switch (speed) { case SPEED_1000: mcr |= PMCR_FORCE_EEE1G; @@ -2880,8 +2886,6 @@ mt7531_cpu_port_config(struct dsa_switch *ds, int port) case 6: interface = PHY_INTERFACE_MODE_2500BASEX; - mt7531_pad_setup(ds, interface); - priv->p6_interface = interface; break; default: @@ -2898,81 +2902,54 @@ mt7531_cpu_port_config(struct dsa_switch *ds, int port) return ret; mt7530_write(priv, MT7530_PMCR_P(port), PMCR_CPU_PORT_SETTING(priv->id)); + mt753x_phylink_pcs_link_up(&priv->pcs[port].pcs, MLO_AN_FIXED, + interface, speed, DUPLEX_FULL); mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, interface, NULL, speed, DUPLEX_FULL, true, true); return 0; } -static void -mt7530_mac_port_validate(struct dsa_switch *ds, int port, - unsigned long *supported) -{ - if (port == 5) - phylink_set(supported, 1000baseX_Full); -} - -static void mt7531_mac_port_validate(struct dsa_switch *ds, int port, - unsigned long *supported) +static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port, + struct phylink_config *config) { struct mt7530_priv *priv = ds->priv; - mt7531_sgmii_validate(priv, port, supported); -} + /* This switch only supports full-duplex at 1Gbps */ + config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | + MAC_10 | MAC_100 | MAC_1000FD; -static void -mt753x_phylink_validate(struct dsa_switch *ds, int port, - unsigned long *supported, - struct phylink_link_state *state) -{ - __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; - struct mt7530_priv *priv = ds->priv; - - if (state->interface != PHY_INTERFACE_MODE_NA && - !mt753x_phy_mode_supported(ds, port, state)) { - linkmode_zero(supported); - return; - } - - phylink_set_port_modes(mask); + if ((priv->id == ID_MT7531) && mt753x_is_mac_port(port)) + config->mac_capabilities |= MAC_2500FD; - if (state->interface != PHY_INTERFACE_MODE_TRGMII || - !phy_interface_mode_is_8023z(state->interface)) { - phylink_set(mask, 10baseT_Half); - phylink_set(mask, 10baseT_Full); - phylink_set(mask, 100baseT_Half); - phylink_set(mask, 100baseT_Full); - phylink_set(mask, Autoneg); - } - - /* This switch only supports 1G full-duplex. */ - if (state->interface != PHY_INTERFACE_MODE_MII) - phylink_set(mask, 1000baseT_Full); - - priv->info->mac_port_validate(ds, port, mask); + /* This driver does not make use of the speed, duplex, pause or the + * advertisement in its mac_config, so it is safe to mark this driver + * as non-legacy. + */ + config->legacy_pre_march2020 = false; - phylink_set(mask, Pause); - phylink_set(mask, Asym_Pause); + priv->info->mac_port_get_caps(ds, port, config); +} - linkmode_and(supported, supported, mask); - linkmode_and(state->advertising, state->advertising, mask); +static int mt753x_pcs_validate(struct phylink_pcs *pcs, + unsigned long *supported, + const struct phylink_link_state *state) +{ + /* Autonegotiation is not supported in TRGMII nor 802.3z modes */ + if (state->interface == PHY_INTERFACE_MODE_TRGMII || + phy_interface_mode_is_8023z(state->interface)) + phylink_clear(supported, Autoneg); - /* We can only operate at 2500BaseX or 1000BaseX. If requested - * to advertise both, only report advertising at 2500BaseX. - */ - phylink_helper_basex_speed(state); + return 0; } -static int -mt7530_phylink_mac_link_state(struct dsa_switch *ds, int port, - struct phylink_link_state *state) +static void mt7530_pcs_get_state(struct phylink_pcs *pcs, + struct phylink_link_state *state) { - struct mt7530_priv *priv = ds->priv; + struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; + int port = pcs_to_mt753x_pcs(pcs)->port; u32 pmsr; - if (port < 0 || port >= MT7530_NUM_PORTS) - return -EINVAL; - pmsr = mt7530_read(priv, MT7530_PMSR_P(port)); state->link = (pmsr & PMSR_LINK); @@ -2999,8 +2976,6 @@ mt7530_phylink_mac_link_state(struct dsa_switch *ds, int port, state->pause |= MLO_PAUSE_RX; if (pmsr & PMSR_TX_FC) state->pause |= MLO_PAUSE_TX; - - return 1; } static int @@ -3012,6 +2987,7 @@ mt7531_sgmii_pcs_get_state_an(struct mt7530_priv *priv, int port, status = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); state->link = !!(status & MT7531_SGMII_LINK_STATUS); + state->an_complete = !!(status & MT7531_SGMII_AN_COMPLETE); if (state->interface == PHY_INTERFACE_MODE_SGMII && (status & MT7531_SGMII_AN_ENABLE)) { val = mt7530_read(priv, MT7531_PCS_SPEED_ABILITY(port)); @@ -3042,33 +3018,89 @@ mt7531_sgmii_pcs_get_state_an(struct mt7530_priv *priv, int port, return 0; } -static int -mt7531_phylink_mac_link_state(struct dsa_switch *ds, int port, - struct phylink_link_state *state) +static void +mt7531_sgmii_pcs_get_state_inband(struct mt7530_priv *priv, int port, + struct phylink_link_state *state) { - struct mt7530_priv *priv = ds->priv; + unsigned int val; - if (state->interface == PHY_INTERFACE_MODE_SGMII) - return mt7531_sgmii_pcs_get_state_an(priv, port, state); + val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); + state->link = !!(val & MT7531_SGMII_LINK_STATUS); + if (!state->link) + return; - return -EOPNOTSUPP; + state->an_complete = state->link; + + if (state->interface == PHY_INTERFACE_MODE_2500BASEX) + state->speed = SPEED_2500; + else + state->speed = SPEED_1000; + + state->duplex = DUPLEX_FULL; + state->pause = MLO_PAUSE_NONE; } -static int -mt753x_phylink_mac_link_state(struct dsa_switch *ds, int port, - struct phylink_link_state *state) +static void mt7531_pcs_get_state(struct phylink_pcs *pcs, + struct phylink_link_state *state) { - struct mt7530_priv *priv = ds->priv; + struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; + int port = pcs_to_mt753x_pcs(pcs)->port; + + if (state->interface == PHY_INTERFACE_MODE_SGMII) { + mt7531_sgmii_pcs_get_state_an(priv, port, state); + return; + } else if ((state->interface == PHY_INTERFACE_MODE_1000BASEX) || + (state->interface == PHY_INTERFACE_MODE_2500BASEX)) { + mt7531_sgmii_pcs_get_state_inband(priv, port, state); + return; + } - return priv->info->mac_port_get_state(ds, port, state); + state->link = false; } +static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode, + phy_interface_t interface, + const unsigned long *advertising, + bool permit_pause_to_mac) +{ + return 0; +} + +static void mt7530_pcs_an_restart(struct phylink_pcs *pcs) +{ +} + +static const struct phylink_pcs_ops mt7530_pcs_ops = { + .pcs_validate = mt753x_pcs_validate, + .pcs_get_state = mt7530_pcs_get_state, + .pcs_config = mt753x_pcs_config, + .pcs_an_restart = mt7530_pcs_an_restart, +}; + +static const struct phylink_pcs_ops mt7531_pcs_ops = { + .pcs_validate = mt753x_pcs_validate, + .pcs_get_state = mt7531_pcs_get_state, + .pcs_config = mt753x_pcs_config, + .pcs_an_restart = mt7531_pcs_an_restart, + .pcs_link_up = mt7531_pcs_link_up, +}; + static int mt753x_setup(struct dsa_switch *ds) { struct mt7530_priv *priv = ds->priv; - int ret = priv->info->sw_setup(ds); + int i, ret; + + /* Initialise the PCS devices */ + for (i = 0; i < priv->ds->num_ports; i++) { + priv->pcs[i].pcs.ops = priv->info->pcs_ops; + priv->pcs[i].priv = priv; + priv->pcs[i].port = i; + if (mt753x_is_mac_port(i)) + priv->pcs[i].pcs.poll = 1; + } + ret = priv->info->sw_setup(ds); if (ret) return ret; @@ -3139,10 +3171,9 @@ static const struct dsa_switch_ops mt7530_switch_ops = { .port_vlan_del = mt7530_port_vlan_del, .port_mirror_add = mt753x_port_mirror_add, .port_mirror_del = mt753x_port_mirror_del, - .phylink_validate = mt753x_phylink_validate, - .phylink_mac_link_state = mt753x_phylink_mac_link_state, + .phylink_get_caps = mt753x_phylink_get_caps, + .phylink_mac_select_pcs = mt753x_phylink_mac_select_pcs, .phylink_mac_config = mt753x_phylink_mac_config, - .phylink_mac_an_restart = mt753x_phylink_mac_an_restart, .phylink_mac_link_down = mt753x_phylink_mac_link_down, .phylink_mac_link_up = mt753x_phylink_mac_link_up, .get_mac_eee = mt753x_get_mac_eee, @@ -3152,39 +3183,34 @@ static const struct dsa_switch_ops mt7530_switch_ops = { static const struct mt753x_info mt753x_table[] = { [ID_MT7621] = { .id = ID_MT7621, + .pcs_ops = &mt7530_pcs_ops, .sw_setup = mt7530_setup, .phy_read = mt7530_phy_read, .phy_write = mt7530_phy_write, .pad_setup = mt7530_pad_clk_setup, - .phy_mode_supported = mt7530_phy_mode_supported, - .mac_port_validate = mt7530_mac_port_validate, - .mac_port_get_state = mt7530_phylink_mac_link_state, + .mac_port_get_caps = mt7530_mac_port_get_caps, .mac_port_config = mt7530_mac_config, }, [ID_MT7530] = { .id = ID_MT7530, + .pcs_ops = &mt7530_pcs_ops, .sw_setup = mt7530_setup, .phy_read = mt7530_phy_read, .phy_write = mt7530_phy_write, .pad_setup = mt7530_pad_clk_setup, - .phy_mode_supported = mt7530_phy_mode_supported, - .mac_port_validate = mt7530_mac_port_validate, - .mac_port_get_state = mt7530_phylink_mac_link_state, + .mac_port_get_caps = mt7530_mac_port_get_caps, .mac_port_config = mt7530_mac_config, }, [ID_MT7531] = { .id = ID_MT7531, + .pcs_ops = &mt7531_pcs_ops, .sw_setup = mt7531_setup, .phy_read = mt7531_ind_phy_read, .phy_write = mt7531_ind_phy_write, .pad_setup = mt7531_pad_setup, .cpu_port_config = mt7531_cpu_port_config, - .phy_mode_supported = mt7531_phy_mode_supported, - .mac_port_validate = mt7531_mac_port_validate, - .mac_port_get_state = mt7531_phylink_mac_link_state, + .mac_port_get_caps = mt7531_mac_port_get_caps, .mac_port_config = mt7531_mac_config, - .mac_pcs_an_restart = mt7531_sgmii_restart_an, - .mac_pcs_link_up = mt7531_sgmii_link_up_force, }, }; @@ -3241,9 +3267,8 @@ mt7530_probe(struct mdio_device *mdiodev) */ if (!priv->info->sw_setup || !priv->info->pad_setup || !priv->info->phy_read || !priv->info->phy_write || - !priv->info->phy_mode_supported || - !priv->info->mac_port_validate || - !priv->info->mac_port_get_state || !priv->info->mac_port_config) + !priv->info->mac_port_get_caps || + !priv->info->mac_port_config) return -EINVAL; priv->id = priv->info->id; @@ -3306,8 +3331,6 @@ mt7530_remove(struct mdio_device *mdiodev) dsa_unregister_switch(priv->ds); mutex_destroy(&priv->reg_mutex); - - dev_set_drvdata(&mdiodev->dev, NULL); } static void mt7530_shutdown(struct mdio_device *mdiodev) |