diff options
Diffstat (limited to 'drivers/net/dsa/sja1105/sja1105_main.c')
-rw-r--r-- | drivers/net/dsa/sja1105/sja1105_main.c | 207 |
1 files changed, 110 insertions, 97 deletions
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 2080f36ff25b..84edd054781b 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -80,7 +80,7 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv) /* Always put the MAC speed in automatic mode, where it can be * adjusted at runtime by PHYLINK. */ - .speed = SJA1105_SPEED_AUTO, + .speed = priv->info->port_speed[SJA1105_SPEED_AUTO], /* No static correction for 1-step 1588 events */ .tp_delin = 0, .tp_delout = 0, @@ -143,21 +143,6 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv) return 0; } -static bool sja1105_supports_sgmii(struct sja1105_private *priv, int port) -{ - if (priv->info->part_no != SJA1105R_PART_NO && - priv->info->part_no != SJA1105S_PART_NO) - return false; - - if (port != SJA1105_SGMII_PORT) - return false; - - if (dsa_is_unused_port(priv->ds, port)) - return false; - - return true; -} - static int sja1105_init_mii_settings(struct sja1105_private *priv, struct sja1105_dt_port *ports) { @@ -191,33 +176,56 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv, switch (ports[i].phy_mode) { case PHY_INTERFACE_MODE_MII: + if (!priv->info->supports_mii[i]) + goto unsupported; + mii->xmii_mode[i] = XMII_MODE_MII; break; case PHY_INTERFACE_MODE_RMII: + if (!priv->info->supports_rmii[i]) + goto unsupported; + mii->xmii_mode[i] = XMII_MODE_RMII; break; case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_TXID: + if (!priv->info->supports_rgmii[i]) + goto unsupported; + mii->xmii_mode[i] = XMII_MODE_RGMII; break; case PHY_INTERFACE_MODE_SGMII: - if (!sja1105_supports_sgmii(priv, i)) - return -EINVAL; + if (!priv->info->supports_sgmii[i]) + goto unsupported; + mii->xmii_mode[i] = XMII_MODE_SGMII; break; + case PHY_INTERFACE_MODE_2500BASEX: + if (!priv->info->supports_2500basex[i]) + goto unsupported; + + mii->xmii_mode[i] = XMII_MODE_SGMII; + break; +unsupported: default: - dev_err(dev, "Unsupported PHY mode %s!\n", - phy_modes(ports[i].phy_mode)); + dev_err(dev, "Unsupported PHY mode %s on port %d!\n", + phy_modes(ports[i].phy_mode), i); return -EINVAL; } /* Even though the SerDes port is able to drive SGMII autoneg * like a PHY would, from the perspective of the XMII tables, * the SGMII port should always be put in MAC mode. + * Similarly, RGMII is a symmetric protocol electrically + * speaking, and the 'RGMII PHY' role does not mean anything to + * hardware. Just keep the 'PHY role' notation relevant to the + * driver to mean 'the switch port should apply RGMII delays', + * but unconditionally put the port in the MAC role. */ - if (ports[i].phy_mode == PHY_INTERFACE_MODE_SGMII) + if (ports[i].phy_mode == PHY_INTERFACE_MODE_SGMII || + phy_interface_mode_is_rgmii(ports[i].phy_mode)) mii->phy_mac[i] = XMII_MAC; else mii->phy_mac[i] = ports[i].role; @@ -871,6 +879,8 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv, ports[index].role = XMII_MAC; else if (of_property_read_bool(child, "sja1105,role-phy")) ports[index].role = XMII_PHY; + + priv->phy_mode[index] = phy_mode; } return 0; @@ -885,6 +895,8 @@ static int sja1105_parse_dt(struct sja1105_private *priv, int rc; ports_node = of_get_child_by_name(switch_node, "ports"); + if (!ports_node) + ports_node = of_get_child_by_name(switch_node, "ethernet-ports"); if (!ports_node) { dev_err(dev, "Incorrect bindings: absent \"ports\" node\n"); return -ENODEV; @@ -896,36 +908,41 @@ static int sja1105_parse_dt(struct sja1105_private *priv, return rc; } -static int sja1105_sgmii_read(struct sja1105_private *priv, int pcs_reg) +static int sja1105_sgmii_read(struct sja1105_private *priv, int port, int mmd, + int pcs_reg) { - const struct sja1105_regs *regs = priv->info->regs; + u64 addr = (mmd << 16) | pcs_reg; u32 val; int rc; - rc = sja1105_xfer_u32(priv, SPI_READ, regs->sgmii + pcs_reg, &val, - NULL); + if (port != SJA1105_SGMII_PORT) + return -ENODEV; + + rc = sja1105_xfer_u32(priv, SPI_READ, addr, &val, NULL); if (rc < 0) return rc; return val; } -static int sja1105_sgmii_write(struct sja1105_private *priv, int pcs_reg, - u16 pcs_val) +static int sja1105_sgmii_write(struct sja1105_private *priv, int port, int mmd, + int pcs_reg, u16 pcs_val) { - const struct sja1105_regs *regs = priv->info->regs; + u64 addr = (mmd << 16) | pcs_reg; u32 val = pcs_val; int rc; - rc = sja1105_xfer_u32(priv, SPI_WRITE, regs->sgmii + pcs_reg, &val, - NULL); + if (port != SJA1105_SGMII_PORT) + return -ENODEV; + + rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &val, NULL); if (rc < 0) return rc; return val; } -static void sja1105_sgmii_pcs_config(struct sja1105_private *priv, +static void sja1105_sgmii_pcs_config(struct sja1105_private *priv, int port, bool an_enabled, bool an_master) { u16 ac = SJA1105_AC_AUTONEG_MODE_SGMII; @@ -934,27 +951,29 @@ static void sja1105_sgmii_pcs_config(struct sja1105_private *priv, * stop the clock during LPI mode, make the MAC reconfigure * autonomously after PCS autoneg is done, flush the internal FIFOs. */ - sja1105_sgmii_write(priv, SJA1105_DC1, SJA1105_DC1_EN_VSMMD1 | - SJA1105_DC1_CLOCK_STOP_EN | - SJA1105_DC1_MAC_AUTO_SW | - SJA1105_DC1_INIT); + sja1105_sgmii_write(priv, port, MDIO_MMD_VEND2, SJA1105_DC1, + SJA1105_DC1_EN_VSMMD1 | + SJA1105_DC1_CLOCK_STOP_EN | + SJA1105_DC1_MAC_AUTO_SW | + SJA1105_DC1_INIT); /* DIGITAL_CONTROL_2: No polarity inversion for TX and RX lanes */ - sja1105_sgmii_write(priv, SJA1105_DC2, SJA1105_DC2_TX_POL_INV_DISABLE); + sja1105_sgmii_write(priv, port, MDIO_MMD_VEND2, SJA1105_DC2, + SJA1105_DC2_TX_POL_INV_DISABLE); /* AUTONEG_CONTROL: Use SGMII autoneg */ if (an_master) ac |= SJA1105_AC_PHY_MODE | SJA1105_AC_SGMII_LINK; - sja1105_sgmii_write(priv, SJA1105_AC, ac); + sja1105_sgmii_write(priv, port, MDIO_MMD_VEND2, SJA1105_AC, ac); /* BASIC_CONTROL: enable in-band AN now, if requested. Otherwise, * sja1105_sgmii_pcs_force_speed must be called later for the link * to become operational. */ if (an_enabled) - sja1105_sgmii_write(priv, MII_BMCR, + sja1105_sgmii_write(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1, BMCR_ANENABLE | BMCR_ANRESTART); } static void sja1105_sgmii_pcs_force_speed(struct sja1105_private *priv, - int speed) + int port, int speed) { int pcs_speed; @@ -972,26 +991,32 @@ static void sja1105_sgmii_pcs_force_speed(struct sja1105_private *priv, dev_err(priv->ds->dev, "Invalid speed %d\n", speed); return; } - sja1105_sgmii_write(priv, MII_BMCR, pcs_speed | BMCR_FULLDPLX); + sja1105_sgmii_write(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1, + pcs_speed | BMCR_FULLDPLX); } /* Convert link speed from SJA1105 to ethtool encoding */ -static int sja1105_speed[] = { - [SJA1105_SPEED_AUTO] = SPEED_UNKNOWN, - [SJA1105_SPEED_10MBPS] = SPEED_10, - [SJA1105_SPEED_100MBPS] = SPEED_100, - [SJA1105_SPEED_1000MBPS] = SPEED_1000, -}; +static int sja1105_port_speed_to_ethtool(struct sja1105_private *priv, + u64 speed) +{ + if (speed == priv->info->port_speed[SJA1105_SPEED_10MBPS]) + return SPEED_10; + if (speed == priv->info->port_speed[SJA1105_SPEED_100MBPS]) + return SPEED_100; + if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS]) + return SPEED_1000; + if (speed == priv->info->port_speed[SJA1105_SPEED_2500MBPS]) + return SPEED_2500; + return SPEED_UNKNOWN; +} /* Set link speed in the MAC configuration for a specific port. */ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, int speed_mbps) { - struct sja1105_xmii_params_entry *mii; struct sja1105_mac_config_entry *mac; struct device *dev = priv->ds->dev; - sja1105_phy_interface_t phy_mode; - sja1105_speed_t speed; + u64 speed; int rc; /* On P/Q/R/S, one can read from the device via the MAC reconfiguration @@ -1001,7 +1026,6 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, * reasonable approximation for both E/T and P/Q/R/S. */ mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; - mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries; switch (speed_mbps) { case SPEED_UNKNOWN: @@ -1012,16 +1036,16 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, * ok for power consumption in case AN will never complete - * otherwise PHYLINK should come back with a new update. */ - speed = SJA1105_SPEED_AUTO; + speed = priv->info->port_speed[SJA1105_SPEED_AUTO]; break; case SPEED_10: - speed = SJA1105_SPEED_10MBPS; + speed = priv->info->port_speed[SJA1105_SPEED_10MBPS]; break; case SPEED_100: - speed = SJA1105_SPEED_100MBPS; + speed = priv->info->port_speed[SJA1105_SPEED_100MBPS]; break; case SPEED_1000: - speed = SJA1105_SPEED_1000MBPS; + speed = priv->info->port_speed[SJA1105_SPEED_1000MBPS]; break; default: dev_err(dev, "Invalid speed %iMbps\n", speed_mbps); @@ -1035,8 +1059,8 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, * Actually for the SGMII port, the MAC is fixed at 1 Gbps and * we need to configure the PCS only (if even that). */ - if (sja1105_supports_sgmii(priv, port)) - mac[port].speed = SJA1105_SPEED_1000MBPS; + if (priv->phy_mode[port] == PHY_INTERFACE_MODE_SGMII) + mac[port].speed = priv->info->port_speed[SJA1105_SPEED_1000MBPS]; else mac[port].speed = speed; @@ -1054,8 +1078,7 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, * the clock setup does interrupt the clock signal for a certain time * which causes trouble for all PHYs relying on this signal. */ - phy_mode = mii->xmii_mode[port]; - if (phy_mode != XMII_MODE_RGMII) + if (!phy_interface_mode_is_rgmii(priv->phy_mode[port])) return 0; return sja1105_clocking_setup_port(priv, port); @@ -1071,27 +1094,7 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, static bool sja1105_phy_mode_mismatch(struct sja1105_private *priv, int port, phy_interface_t interface) { - struct sja1105_xmii_params_entry *mii; - sja1105_phy_interface_t phy_mode; - - mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries; - phy_mode = mii->xmii_mode[port]; - - switch (interface) { - case PHY_INTERFACE_MODE_MII: - return (phy_mode != XMII_MODE_MII); - case PHY_INTERFACE_MODE_RMII: - return (phy_mode != XMII_MODE_RMII); - case PHY_INTERFACE_MODE_RGMII: - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_RXID: - case PHY_INTERFACE_MODE_RGMII_TXID: - return (phy_mode != XMII_MODE_RGMII); - case PHY_INTERFACE_MODE_SGMII: - return (phy_mode != XMII_MODE_SGMII); - default: - return true; - } + return priv->phy_mode[port] != interface; } static void sja1105_mac_config(struct dsa_switch *ds, int port, @@ -1099,7 +1102,9 @@ static void sja1105_mac_config(struct dsa_switch *ds, int port, const struct phylink_link_state *state) { struct sja1105_private *priv = ds->priv; - bool is_sgmii = sja1105_supports_sgmii(priv, port); + bool is_sgmii; + + is_sgmii = (state->interface == PHY_INTERFACE_MODE_SGMII); if (sja1105_phy_mode_mismatch(priv, port, state->interface)) { dev_err(ds->dev, "Changing PHY mode to %s not supported!\n", @@ -1113,7 +1118,8 @@ static void sja1105_mac_config(struct dsa_switch *ds, int port, } if (is_sgmii) - sja1105_sgmii_pcs_config(priv, phylink_autoneg_inband(mode), + sja1105_sgmii_pcs_config(priv, port, + phylink_autoneg_inband(mode), false); } @@ -1135,8 +1141,9 @@ static void sja1105_mac_link_up(struct dsa_switch *ds, int port, sja1105_adjust_port_config(priv, port, speed); - if (sja1105_supports_sgmii(priv, port) && !phylink_autoneg_inband(mode)) - sja1105_sgmii_pcs_force_speed(priv, speed); + if (priv->phy_mode[port] == PHY_INTERFACE_MODE_SGMII && + !phylink_autoneg_inband(mode)) + sja1105_sgmii_pcs_force_speed(priv, port, speed); sja1105_inhibit_tx(priv, BIT(port), false); } @@ -1189,7 +1196,7 @@ static int sja1105_mac_pcs_get_state(struct dsa_switch *ds, int port, int ais; /* Read the vendor-specific AUTONEG_INTR_STATUS register */ - ais = sja1105_sgmii_read(priv, SJA1105_AIS); + ais = sja1105_sgmii_read(priv, port, MDIO_MMD_VEND2, SJA1105_AIS); if (ais < 0) return ais; @@ -1871,11 +1878,11 @@ int sja1105_static_config_reload(struct sja1105_private *priv, struct ptp_system_timestamp ptp_sts_before; struct ptp_system_timestamp ptp_sts_after; int speed_mbps[SJA1105_MAX_NUM_PORTS]; + u16 bmcr[SJA1105_MAX_NUM_PORTS] = {0}; struct sja1105_mac_config_entry *mac; struct dsa_switch *ds = priv->ds; s64 t1, t2, t3, t4; s64 t12, t34; - u16 bmcr = 0; int rc, i; s64 now; @@ -1889,12 +1896,15 @@ int sja1105_static_config_reload(struct sja1105_private *priv, * change it through the dynamic interface later. */ for (i = 0; i < ds->num_ports; i++) { - speed_mbps[i] = sja1105_speed[mac[i].speed]; - mac[i].speed = SJA1105_SPEED_AUTO; - } + speed_mbps[i] = sja1105_port_speed_to_ethtool(priv, + mac[i].speed); + mac[i].speed = priv->info->port_speed[SJA1105_SPEED_AUTO]; - if (sja1105_supports_sgmii(priv, SJA1105_SGMII_PORT)) - bmcr = sja1105_sgmii_read(priv, MII_BMCR); + if (priv->phy_mode[i] == PHY_INTERFACE_MODE_SGMII) + bmcr[i] = sja1105_sgmii_read(priv, i, + MDIO_MMD_VEND2, + MDIO_CTRL1); + } /* No PTP operations can run right now */ mutex_lock(&priv->ptp_data.lock); @@ -1941,27 +1951,30 @@ out_unlock_ptp: goto out; for (i = 0; i < ds->num_ports; i++) { + bool an_enabled; + rc = sja1105_adjust_port_config(priv, i, speed_mbps[i]); if (rc < 0) goto out; - } - if (sja1105_supports_sgmii(priv, SJA1105_SGMII_PORT)) { - bool an_enabled = !!(bmcr & BMCR_ANENABLE); + if (priv->phy_mode[i] != PHY_INTERFACE_MODE_SGMII) + continue; + + an_enabled = !!(bmcr[i] & BMCR_ANENABLE); - sja1105_sgmii_pcs_config(priv, an_enabled, false); + sja1105_sgmii_pcs_config(priv, i, an_enabled, false); if (!an_enabled) { int speed = SPEED_UNKNOWN; - if (bmcr & BMCR_SPEED1000) + if (bmcr[i] & BMCR_SPEED1000) speed = SPEED_1000; - else if (bmcr & BMCR_SPEED100) + else if (bmcr[i] & BMCR_SPEED100) speed = SPEED_100; else speed = SPEED_10; - sja1105_sgmii_pcs_force_speed(priv, speed); + sja1105_sgmii_pcs_force_speed(priv, i, speed); } } |