[PATCH net-next v6 4/5] net: ftgmac100: Support rgmii delay in old dts with AST2600
Jacky Chou
jacky_chou at aspeedtech.com
Mon Mar 2 21:24:31 AEDT 2026
Strating to this patch, driver will remind the legacy dts to update the
"phy-mode" to "rgmii-id, and if necessary, add small
"rx-internal-delay-ps" and "tx-internal-delay-ps.
If lack the two properties, driver will accord to the original delay
value from bootloader to disable RGMII delay and to change the phy
interface to phy driver.
Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
drivers/net/ethernet/faraday/ftgmac100.c | 190 +++++++++++++++++++++++++++----
drivers/net/ethernet/faraday/ftgmac100.h | 5 +
2 files changed, 174 insertions(+), 21 deletions(-)
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index 0b2a0bb8a4a9..5f5b9199a9ef 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -1871,10 +1871,40 @@ static int ftgmac100_probe_ncsi(struct net_device *netdev,
return err;
}
+static struct phy_device *ftgmac100_ast2600_phy_get(struct net_device *dev,
+ struct device_node *np,
+ void (*hndlr)(struct net_device *),
+ phy_interface_t phy_intf)
+{
+ struct device_node *phy_np;
+ struct phy_device *phy;
+ int ret;
+
+ if (of_phy_is_fixed_link(np)) {
+ ret = of_phy_register_fixed_link(np);
+ if (ret < 0) {
+ netdev_err(dev, "broken fixed-link specification\n");
+ return NULL;
+ }
+ phy_np = of_node_get(np);
+ } else {
+ phy_np = of_parse_phandle(np, "phy-handle", 0);
+ if (!phy_np)
+ return NULL;
+ }
+
+ phy = of_phy_connect(dev, phy_np, hndlr, 0, phy_intf);
+
+ of_node_put(phy_np);
+
+ return phy;
+}
+
static int ftgmac100_probe_dt(struct net_device *netdev,
struct platform_device *pdev,
struct ftgmac100 *priv,
- struct device_node *np)
+ struct device_node *np,
+ phy_interface_t phy_intf)
{
struct phy_device *phy;
int err;
@@ -1890,8 +1920,16 @@ static int ftgmac100_probe_dt(struct net_device *netdev,
* them. 2600 has an independent MDIO controller, not
* part of the MAC.
*/
- phy = of_phy_get_and_connect(priv->netdev, np,
- &ftgmac100_adjust_link);
+ if (priv->mac_id == FTGMAC100_AST2600)
+ /* Because AST2600 will use the RGMII delay to determine
+ * which phy interface to use.
+ */
+ phy = ftgmac100_ast2600_phy_get(priv->netdev, np,
+ &ftgmac100_adjust_link,
+ phy_intf);
+ else
+ phy = of_phy_get_and_connect(priv->netdev, np,
+ &ftgmac100_adjust_link);
if (!phy) {
dev_err(&pdev->dev, "Failed to connect to phy\n");
return -EINVAL;
@@ -1923,10 +1961,62 @@ static int ftgmac100_probe_dt(struct net_device *netdev,
return 0;
}
+static int ftgmac100_get_ast2600_rgmii_flag(u32 delay)
+{
+ if ((delay > 500 && delay < 1500) ||
+ (delay > 2500 && delay < 7500))
+ return AST2600_RGMII_KEEP_DELAY;
+
+ return AST2600_RGMII_DIS_DELAY;
+}
+
+static int ftgmac100_check_ast2600_rgmii_delay(struct regmap *scu,
+ u32 delay_unit,
+ int mac_id, int dly_reg)
+{
+ u32 delay_value;
+ u32 tx_delay;
+ u32 rx_delay;
+ int tx_flag;
+ int rx_flag;
+
+ regmap_read(scu, dly_reg, &delay_value);
+ if (mac_id == 0 || mac_id == 2) {
+ tx_delay = FIELD_GET(ASPEED_MAC0_2_TX_DLY, delay_value);
+ rx_delay = FIELD_GET(ASPEED_MAC0_2_RX_DLY, delay_value);
+ } else {
+ tx_delay = FIELD_GET(ASPEED_MAC1_3_TX_DLY, delay_value);
+ rx_delay = FIELD_GET(ASPEED_MAC1_3_RX_DLY, delay_value);
+ }
+
+ /* Due to the hardware design reason, for MAC2/3 on AST2600,
+ * the zero delay ns on RX is configured by setting value 0x1a.
+ * List as below:
+ * 0x1a, 0x1b, ... , 0x1f, 0x00, 0x01, ... , 0x19
+ * Covert for calculation purpose.
+ * 0x00, 0x01, ... , 0x19, 0x1a, 0x1b, ... , 0x1f
+ */
+ if (mac_id == 2 || mac_id == 3)
+ rx_delay = (rx_delay + 0x06) & 0x1f;
+
+ tx_delay *= delay_unit;
+ rx_delay *= delay_unit;
+
+ tx_flag = ftgmac100_get_ast2600_rgmii_flag(tx_delay);
+ rx_flag = ftgmac100_get_ast2600_rgmii_flag(rx_delay);
+
+ if (tx_flag == AST2600_RGMII_KEEP_DELAY ||
+ rx_flag == AST2600_RGMII_KEEP_DELAY) {
+ return AST2600_RGMII_KEEP_DELAY;
+ }
+
+ return AST2600_RGMII_DIS_DELAY;
+}
+
static int ftgmac100_set_ast2600_rgmii_delay(struct ftgmac100 *priv,
- u32 rgmii_tx_delay,
- u32 rgmii_rx_delay,
- phy_interface_t phy_intf)
+ s32 rgmii_tx_delay,
+ s32 rgmii_rx_delay,
+ phy_interface_t *phy_intf)
{
struct device *dev = priv->dev;
struct device_node *np;
@@ -1975,13 +2065,59 @@ static int ftgmac100_set_ast2600_rgmii_delay(struct ftgmac100 *priv,
return -EINVAL;
}
- /* Please refer to ethernet-controller.yaml. */
- if (phy_intf == PHY_INTERFACE_MODE_RGMII &&
- (rgmii_tx_delay == 2000 || rgmii_rx_delay == 2000)) {
- dev_warn(dev, "RX/TX delay cannot set to 2000 on 'rgmii'\n");
- return -EINVAL;
+ if (of_phy_is_fixed_link(np)) {
+ if (rgmii_tx_delay < 0 || rgmii_rx_delay < 0) {
+ dev_err(dev,
+ "Add rx/tx-internal-delay-ps for fixed-link\n");
+ /* Keep original RGMII delay value*/
+ return 0;
+ }
+
+ /* Must have both of rx/tx-internal-delay-ps for fixed-link */
+ goto conf_delay;
+ }
+
+ if (*phy_intf == PHY_INTERFACE_MODE_RGMII_RXID ||
+ *phy_intf == PHY_INTERFACE_MODE_RGMII_TXID)
+ goto out_warn;
+
+ /* Both rx/tx-internal-delay-ps are not existed. */
+ if (rgmii_tx_delay < 0 && rgmii_rx_delay < 0) {
+ int flag;
+
+ flag = ftgmac100_check_ast2600_rgmii_delay(scu,
+ rgmii_delay_unit,
+ mac_id,
+ dly_reg);
+ if (flag == AST2600_RGMII_KEEP_DELAY)
+ goto out_warn;
+
+ if (*phy_intf == PHY_INTERFACE_MODE_RGMII) {
+ dev_err(dev, "Update phy-mode to 'rgmii-id'\n");
+ /* Forced phy interface to RGMII_ID and MAC will disable
+ * RGMII delay.
+ */
+ *phy_intf = PHY_INTERFACE_MODE_RGMII_ID;
+ }
+ } else {
+ /* Please refer to ethernet-controller.yaml. */
+ if (*phy_intf == PHY_INTERFACE_MODE_RGMII &&
+ (rgmii_tx_delay == 2000 || rgmii_rx_delay == 2000)) {
+ dev_warn(dev,
+ "RX/TX delay cannot set to 2000 on 'rgmii'\n");
+ return -EINVAL;
+ }
}
+ /* The value is negative, which means the rx/tx-internal-delay-ps
+ * property is not existed in dts. Therefore, set to default 0.
+ */
+ if (rgmii_tx_delay < 0)
+ rgmii_tx_delay = 0;
+ if (rgmii_rx_delay < 0)
+ rgmii_rx_delay = 0;
+
+conf_delay:
tx_delay_index = DIV_ROUND_CLOSEST(rgmii_tx_delay, rgmii_delay_unit);
if (tx_delay_index >= 32) {
dev_err(dev, "The %u ps of TX delay is out of range\n",
@@ -2018,15 +2154,21 @@ static int ftgmac100_set_ast2600_rgmii_delay(struct ftgmac100 *priv,
regmap_update_bits(scu, dly_reg, dly_mask, tx_delay_index | rx_delay_index);
+ return 0;
+
+out_warn:
+ /* Print the warning message. Keep the phy-mode and the RGMII delay value. */
+ dev_warn(dev, "Update phy-mode to 'rgmii-id' and add rx/tx-internal-delay-ps\n");
+
return 0;
}
-static int ftgmac100_config_rgmii_delay(struct ftgmac100 *priv)
+static int ftgmac100_config_rgmii_delay(struct ftgmac100 *priv,
+ phy_interface_t *phy_intf)
{
struct device_node *np = priv->dev->of_node;
- phy_interface_t phy_intf;
- u32 rgmii_tx_delay;
- u32 rgmii_rx_delay;
+ s32 rgmii_tx_delay;
+ s32 rgmii_rx_delay;
int err = 0;
/* Because some old dts using NC-SI mode does not include phy-mode
@@ -2036,20 +2178,23 @@ static int ftgmac100_config_rgmii_delay(struct ftgmac100 *priv)
if (of_get_property(np, "use-ncsi", NULL))
return 0;
- err = of_get_phy_mode(np, &phy_intf);
+ err = of_get_phy_mode(np, phy_intf);
if (err) {
dev_err(priv->dev, "Failed to get phy mode: %d\n", err);
return err;
}
/* RMII does not need to configure RGMII delay */
- if (!phy_interface_mode_is_rgmii(phy_intf))
+ if (!phy_interface_mode_is_rgmii(*phy_intf))
return 0;
+ /* AST2600 needs to know if the "tx/rx-internal-delay-ps" properties
+ * are existed in dts. If not existed, set -1 and delay is equal to 0.
+ */
if (of_property_read_u32(np, "tx-internal-delay-ps", &rgmii_tx_delay))
- rgmii_tx_delay = 0;
+ rgmii_tx_delay = -1;
if (of_property_read_u32(np, "rx-internal-delay-ps", &rgmii_rx_delay))
- rgmii_rx_delay = 0;
+ rgmii_rx_delay = -1;
if (priv->mac_id == FTGMAC100_AST2600)
err = ftgmac100_set_ast2600_rgmii_delay(priv,
@@ -2068,10 +2213,13 @@ static int ftgmac100_probe(struct platform_device *pdev)
struct resource *res;
int irq;
struct net_device *netdev;
+ phy_interface_t phy_intf;
struct ftgmac100 *priv;
struct device_node *np;
int err = 0;
+ phy_intf = PHY_INTERFACE_MODE_NA;
+
np = pdev->dev.of_node;
if (np) {
match_data = of_device_get_match_data(&pdev->dev);
@@ -2151,7 +2299,7 @@ static int ftgmac100_probe(struct platform_device *pdev)
}
if (rgmii_delay_conf) {
- err = ftgmac100_config_rgmii_delay(priv);
+ err = ftgmac100_config_rgmii_delay(priv, &phy_intf);
if (err)
return err;
}
@@ -2165,7 +2313,7 @@ static int ftgmac100_probe(struct platform_device *pdev)
}
if (np) {
- err = ftgmac100_probe_dt(netdev, pdev, priv, np);
+ err = ftgmac100_probe_dt(netdev, pdev, priv, np, phy_intf);
if (err)
goto err;
}
diff --git a/drivers/net/ethernet/faraday/ftgmac100.h b/drivers/net/ethernet/faraday/ftgmac100.h
index d19d44d1b8e0..1b2f79a104ea 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.h
+++ b/drivers/net/ethernet/faraday/ftgmac100.h
@@ -291,4 +291,9 @@ struct ftgmac100_rxdes {
#define AST2600_MAC2_BASE_ADDR 0x1e670000
#define AST2600_MAC3_BASE_ADDR 0x1e690000
+/* Keep original delay */
+#define AST2600_RGMII_KEEP_DELAY 0x01
+/* Need to disable delay on MAC side */
+#define AST2600_RGMII_DIS_DELAY 0x02
+
#endif /* __FTGMAC100_H */
--
2.34.1
More information about the Linux-aspeed
mailing list