diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 50ab9282c4f1..87dee6794d98 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -48,11 +48,14 @@ struct sja1105_info { const struct sja1105_table_ops *static_ops; const struct sja1105_regs *regs; int (*reset_cmd)(const void *ctx, const void *data); + int (*setup_rgmii_delay)(const void *ctx, int port); const char *name; }; struct sja1105_private { struct sja1105_static_config static_config; + bool rgmii_rx_delay[SJA1105_NUM_PORTS]; + bool rgmii_tx_delay[SJA1105_NUM_PORTS]; const struct sja1105_info *info; struct gpio_desc *reset_gpio; struct spi_device *spidev; diff --git a/drivers/net/dsa/sja1105/sja1105_clocking.c b/drivers/net/dsa/sja1105/sja1105_clocking.c index 598544297931..94bfe0ee50a8 100644 --- a/drivers/net/dsa/sja1105/sja1105_clocking.c +++ b/drivers/net/dsa/sja1105/sja1105_clocking.c @@ -427,7 +427,10 @@ static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port) dev_err(dev, "Failed to configure Tx pad registers\n"); return rc; } - return 0; + if (!priv->info->setup_rgmii_delay) + return 0; + + return priv->info->setup_rgmii_delay(priv, port); } static int sja1105_cgu_rmii_ref_clk_config(struct sja1105_private *priv, diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index ec8137eff223..d27b9c178cba 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -518,6 +518,30 @@ 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, + const struct sja1105_dt_port *ports) +{ + int i; + + for (i = 0; i < SJA1105_NUM_PORTS; i++) { + if (ports->role == XMII_MAC) + continue; + + if (ports->phy_mode == PHY_INTERFACE_MODE_RGMII_RXID || + ports->phy_mode == PHY_INTERFACE_MODE_RGMII_ID) + priv->rgmii_rx_delay[i] = true; + + if (ports->phy_mode == PHY_INTERFACE_MODE_RGMII_TXID || + ports->phy_mode == PHY_INTERFACE_MODE_RGMII_ID) + priv->rgmii_tx_delay[i] = true; + + if ((priv->rgmii_rx_delay[i] || priv->rgmii_tx_delay[i]) && + !priv->info->setup_rgmii_delay) + return -EINVAL; + } + return 0; +} + static int sja1105_parse_ports_node(struct sja1105_private *priv, struct sja1105_dt_port *ports, struct device_node *ports_node) @@ -959,6 +983,16 @@ static int sja1105_setup(struct dsa_switch *ds) dev_err(ds->dev, "Failed to parse DT: %d\n", rc); return rc; } + + /* Error out early if internal delays are required through DT + * and we can't apply them. + */ + rc = sja1105_parse_rgmii_delays(priv, ports); + if (rc < 0) { + dev_err(ds->dev, "RGMII delay not supported\n"); + return rc; + } + /* Create and send configuration down to device */ rc = sja1105_static_config_load(priv, ports); if (rc < 0) {