diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 618c8d6a8be1..808419f3b808 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -20,6 +20,27 @@ #define SJA1105_AGEING_TIME_MS(ms) ((ms) / 10) #define SJA1105_NUM_L2_POLICERS SJA1110_MAX_L2_POLICING_COUNT +/* Calculated assuming 1Gbps, where the clock has 125 MHz (8 ns period) + * To avoid floating point operations, we'll multiply the degrees by 10 + * to get a "phase" and get 1 decimal point precision. + */ +#define SJA1105_RGMII_DELAY_PS_TO_PHASE(ps) \ + (((ps) * 360) / 800) +#define SJA1105_RGMII_DELAY_PHASE_TO_PS(phase) \ + ((800 * (phase)) / 360) +#define SJA1105_RGMII_DELAY_PHASE_TO_HW(phase) \ + (((phase) - 738) / 9) +#define SJA1105_RGMII_DELAY_PS_TO_HW(ps) \ + SJA1105_RGMII_DELAY_PHASE_TO_HW(SJA1105_RGMII_DELAY_PS_TO_PHASE(ps)) + +/* Valid range in degrees is a value between 73.8 and 101.7 + * in 0.9 degree increments + */ +#define SJA1105_RGMII_DELAY_MIN_PS \ + SJA1105_RGMII_DELAY_PHASE_TO_PS(738) +#define SJA1105_RGMII_DELAY_MAX_PS \ + SJA1105_RGMII_DELAY_PHASE_TO_PS(1017) + typedef enum { SPI_READ = 0, SPI_WRITE = 1, @@ -222,8 +243,8 @@ struct sja1105_flow_block { struct sja1105_private { struct sja1105_static_config static_config; - bool rgmii_rx_delay[SJA1105_MAX_NUM_PORTS]; - bool rgmii_tx_delay[SJA1105_MAX_NUM_PORTS]; + int rgmii_rx_delay_ps[SJA1105_MAX_NUM_PORTS]; + int rgmii_tx_delay_ps[SJA1105_MAX_NUM_PORTS]; phy_interface_t phy_mode[SJA1105_MAX_NUM_PORTS]; bool fixed_link[SJA1105_MAX_NUM_PORTS]; unsigned long ucast_egress_floods; diff --git a/drivers/net/dsa/sja1105/sja1105_clocking.c b/drivers/net/dsa/sja1105/sja1105_clocking.c index 5bbf1707f2af..e3699f76f6d7 100644 --- a/drivers/net/dsa/sja1105/sja1105_clocking.c +++ b/drivers/net/dsa/sja1105/sja1105_clocking.c @@ -498,17 +498,6 @@ sja1110_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd, sja1105_packing(buf, &cmd->txc_pd, 0, 0, size, op); } -/* Valid range in degrees is an integer between 73.8 and 101.7 */ -static u64 sja1105_rgmii_delay(u64 phase) -{ - /* UM11040.pdf: The delay in degree phase is 73.8 + delay_tune * 0.9. - * To avoid floating point operations we'll multiply by 10 - * and get 1 decimal point precision. - */ - phase *= 10; - return (phase - 738) / 9; -} - /* The RGMII delay setup procedure is 2-step and gets called upon each * .phylink_mac_config. Both are strategic. * The reason is that the RX Tunable Delay Line of the SJA1105 MAC has issues @@ -521,13 +510,15 @@ int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port) const struct sja1105_private *priv = ctx; const struct sja1105_regs *regs = priv->info->regs; struct sja1105_cfg_pad_mii_id pad_mii_id = {0}; + int rx_delay = priv->rgmii_rx_delay_ps[port]; + int tx_delay = priv->rgmii_tx_delay_ps[port]; u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0}; int rc; - if (priv->rgmii_rx_delay[port]) - pad_mii_id.rxc_delay = sja1105_rgmii_delay(90); - if (priv->rgmii_tx_delay[port]) - pad_mii_id.txc_delay = sja1105_rgmii_delay(90); + if (rx_delay) + pad_mii_id.rxc_delay = SJA1105_RGMII_DELAY_PS_TO_HW(rx_delay); + if (tx_delay) + pad_mii_id.txc_delay = SJA1105_RGMII_DELAY_PS_TO_HW(tx_delay); /* Stage 1: Turn the RGMII delay lines off. */ pad_mii_id.rxc_bypass = 1; @@ -542,11 +533,11 @@ int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port) return rc; /* Stage 2: Turn the RGMII delay lines on. */ - if (priv->rgmii_rx_delay[port]) { + if (rx_delay) { pad_mii_id.rxc_bypass = 0; pad_mii_id.rxc_pd = 0; } - if (priv->rgmii_tx_delay[port]) { + if (tx_delay) { pad_mii_id.txc_bypass = 0; pad_mii_id.txc_pd = 0; } @@ -561,20 +552,22 @@ int sja1110_setup_rgmii_delay(const void *ctx, int port) const struct sja1105_private *priv = ctx; const struct sja1105_regs *regs = priv->info->regs; struct sja1105_cfg_pad_mii_id pad_mii_id = {0}; + int rx_delay = priv->rgmii_rx_delay_ps[port]; + int tx_delay = priv->rgmii_tx_delay_ps[port]; u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0}; pad_mii_id.rxc_pd = 1; pad_mii_id.txc_pd = 1; - if (priv->rgmii_rx_delay[port]) { - pad_mii_id.rxc_delay = sja1105_rgmii_delay(90); + if (rx_delay) { + pad_mii_id.rxc_delay = SJA1105_RGMII_DELAY_PS_TO_HW(rx_delay); /* The "BYPASS" bit in SJA1110 is actually a "don't bypass" */ pad_mii_id.rxc_bypass = 1; pad_mii_id.rxc_pd = 0; } - if (priv->rgmii_tx_delay[port]) { - pad_mii_id.txc_delay = sja1105_rgmii_delay(90); + if (tx_delay) { + pad_mii_id.txc_delay = SJA1105_RGMII_DELAY_PS_TO_HW(tx_delay); pad_mii_id.txc_bypass = 1; pad_mii_id.txc_pd = 0; } diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 0f1bba0076a8..1832d4bd3440 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1109,27 +1109,78 @@ static int sja1105_static_config_load(struct sja1105_private *priv) return sja1105_static_config_upload(priv); } -static int sja1105_parse_rgmii_delays(struct sja1105_private *priv) +/* This is the "new way" for a MAC driver to configure its RGMII delay lines, + * based on the explicit "rx-internal-delay-ps" and "tx-internal-delay-ps" + * properties. It has the advantage of working with fixed links and with PHYs + * that apply RGMII delays too, and the MAC driver needs not perform any + * special checks. + * + * Previously we were acting upon the "phy-mode" property when we were + * operating in fixed-link, basically acting as a PHY, but with a reversed + * interpretation: PHY_INTERFACE_MODE_RGMII_TXID means that the MAC should + * behave as if it is connected to a PHY which has applied RGMII delays in the + * TX direction. So if anything, RX delays should have been added by the MAC, + * but we were adding TX delays. + * + * If the "{rx,tx}-internal-delay-ps" properties are not specified, we fall + * back to the legacy behavior and apply delays on fixed-link ports based on + * the reverse interpretation of the phy-mode. This is a deviation from the + * expected default behavior which is to simply apply no delays. To achieve + * that behavior with the new bindings, it is mandatory to specify + * "{rx,tx}-internal-delay-ps" with a value of 0. + */ +static int sja1105_parse_rgmii_delays(struct sja1105_private *priv, int port, + struct device_node *port_dn) { - struct dsa_switch *ds = priv->ds; - int port; + phy_interface_t phy_mode = priv->phy_mode[port]; + struct device *dev = &priv->spidev->dev; + int rx_delay = -1, tx_delay = -1; - for (port = 0; port < ds->num_ports; port++) { - if (!priv->fixed_link[port]) - continue; + if (!phy_interface_mode_is_rgmii(phy_mode)) + return 0; - if (priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_RXID || - priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_ID) - priv->rgmii_rx_delay[port] = true; + of_property_read_u32(port_dn, "rx-internal-delay-ps", &rx_delay); + of_property_read_u32(port_dn, "tx-internal-delay-ps", &tx_delay); - if (priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_TXID || - priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_ID) - priv->rgmii_tx_delay[port] = true; + if (rx_delay == -1 && tx_delay == -1 && priv->fixed_link[port]) { + dev_warn(dev, + "Port %d interpreting RGMII delay settings based on \"phy-mode\" property, " + "please update device tree to specify \"rx-internal-delay-ps\" and " + "\"tx-internal-delay-ps\"", + port); - if ((priv->rgmii_rx_delay[port] || priv->rgmii_tx_delay[port]) && - !priv->info->setup_rgmii_delay) - return -EINVAL; + if (phy_mode == PHY_INTERFACE_MODE_RGMII_RXID || + phy_mode == PHY_INTERFACE_MODE_RGMII_ID) + rx_delay = 2000; + + if (phy_mode == PHY_INTERFACE_MODE_RGMII_TXID || + phy_mode == PHY_INTERFACE_MODE_RGMII_ID) + tx_delay = 2000; } + + if (rx_delay < 0) + rx_delay = 0; + if (tx_delay < 0) + tx_delay = 0; + + if ((rx_delay || tx_delay) && !priv->info->setup_rgmii_delay) { + dev_err(dev, "Chip cannot apply RGMII delays\n"); + return -EINVAL; + } + + if ((rx_delay && rx_delay < SJA1105_RGMII_DELAY_MIN_PS) || + (tx_delay && tx_delay < SJA1105_RGMII_DELAY_MIN_PS) || + (rx_delay > SJA1105_RGMII_DELAY_MAX_PS) || + (tx_delay > SJA1105_RGMII_DELAY_MAX_PS)) { + dev_err(dev, + "port %d RGMII delay values out of range, must be between %d and %d ps\n", + port, SJA1105_RGMII_DELAY_MIN_PS, SJA1105_RGMII_DELAY_MAX_PS); + return -ERANGE; + } + + priv->rgmii_rx_delay_ps[port] = rx_delay; + priv->rgmii_tx_delay_ps[port] = tx_delay; + return 0; } @@ -1180,6 +1231,10 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv, } priv->phy_mode[index] = phy_mode; + + err = sja1105_parse_rgmii_delays(priv, index, child); + if (err) + return err; } return 0; @@ -3317,15 +3372,6 @@ static int sja1105_probe(struct spi_device *spi) return rc; } - /* Error out early if internal delays are required through DT - * and we can't apply them. - */ - rc = sja1105_parse_rgmii_delays(priv); - if (rc < 0) { - dev_err(ds->dev, "RGMII delay not supported\n"); - return rc; - } - if (IS_ENABLED(CONFIG_NET_SCH_CBS)) { priv->cbs = devm_kcalloc(dev, priv->info->num_cbs_shapers, sizeof(struct sja1105_cbs_entry),