mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-30 10:39:04 +00:00
189 lines
6.6 KiB
Diff
189 lines
6.6 KiB
Diff
|
From e4b9977cee1583da38a6e9118078bb728aaccf7b Mon Sep 17 00:00:00 2001
|
||
|
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||
|
Date: Fri, 14 May 2021 23:00:06 +0200
|
||
|
Subject: [PATCH] net: dsa: qca8k: make rgmii delay configurable
|
||
|
|
||
|
The legacy qsdk code used a different delay instead of the max value.
|
||
|
Qsdk use 1 ns for rx and 2 ns for tx. Make these values configurable
|
||
|
using the standard rx/tx-internal-delay-ps ethernet binding and apply
|
||
|
qsdk values by default. The connected gmac doesn't add any delay so no
|
||
|
additional delay is added to tx/rx.
|
||
|
On this switch the delay is actually in ns so value should be in the
|
||
|
1000 order. Any value converted from ps to ns by dividing it by 1000
|
||
|
as the switch max value for delay is 3ns.
|
||
|
|
||
|
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||
|
---
|
||
|
drivers/net/dsa/qca8k.c | 82 ++++++++++++++++++++++++++++++++++++++++-
|
||
|
drivers/net/dsa/qca8k.h | 11 +++---
|
||
|
2 files changed, 86 insertions(+), 7 deletions(-)
|
||
|
|
||
|
--- a/drivers/net/dsa/qca8k.c
|
||
|
+++ b/drivers/net/dsa/qca8k.c
|
||
|
@@ -778,6 +778,68 @@ qca8k_setup_mdio_bus(struct qca8k_priv *
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
+qca8k_setup_of_rgmii_delay(struct qca8k_priv *priv)
|
||
|
+{
|
||
|
+ struct device_node *port_dn;
|
||
|
+ phy_interface_t mode;
|
||
|
+ struct dsa_port *dp;
|
||
|
+ u32 val;
|
||
|
+
|
||
|
+ /* CPU port is already checked */
|
||
|
+ dp = dsa_to_port(priv->ds, 0);
|
||
|
+
|
||
|
+ port_dn = dp->dn;
|
||
|
+
|
||
|
+ /* Check if port 0 is set to the correct type */
|
||
|
+ of_get_phy_mode(port_dn, &mode);
|
||
|
+ if (mode != PHY_INTERFACE_MODE_RGMII_ID &&
|
||
|
+ mode != PHY_INTERFACE_MODE_RGMII_RXID &&
|
||
|
+ mode != PHY_INTERFACE_MODE_RGMII_TXID) {
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ switch (mode) {
|
||
|
+ case PHY_INTERFACE_MODE_RGMII_ID:
|
||
|
+ case PHY_INTERFACE_MODE_RGMII_RXID:
|
||
|
+ if (of_property_read_u32(port_dn, "rx-internal-delay-ps", &val))
|
||
|
+ val = 2;
|
||
|
+ else
|
||
|
+ /* Switch regs accept value in ns, convert ps to ns */
|
||
|
+ val = val / 1000;
|
||
|
+
|
||
|
+ if (val > QCA8K_MAX_DELAY) {
|
||
|
+ dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value");
|
||
|
+ val = 3;
|
||
|
+ }
|
||
|
+
|
||
|
+ priv->rgmii_rx_delay = val;
|
||
|
+ /* Stop here if we need to check only for rx delay */
|
||
|
+ if (mode != PHY_INTERFACE_MODE_RGMII_ID)
|
||
|
+ break;
|
||
|
+
|
||
|
+ fallthrough;
|
||
|
+ case PHY_INTERFACE_MODE_RGMII_TXID:
|
||
|
+ if (of_property_read_u32(port_dn, "tx-internal-delay-ps", &val))
|
||
|
+ val = 1;
|
||
|
+ else
|
||
|
+ /* Switch regs accept value in ns, convert ps to ns */
|
||
|
+ val = val / 1000;
|
||
|
+
|
||
|
+ if (val > QCA8K_MAX_DELAY) {
|
||
|
+ dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value");
|
||
|
+ val = 3;
|
||
|
+ }
|
||
|
+
|
||
|
+ priv->rgmii_tx_delay = val;
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
qca8k_setup(struct dsa_switch *ds)
|
||
|
{
|
||
|
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||
|
@@ -802,6 +864,10 @@ qca8k_setup(struct dsa_switch *ds)
|
||
|
if (ret)
|
||
|
return ret;
|
||
|
|
||
|
+ ret = qca8k_setup_of_rgmii_delay(priv);
|
||
|
+ if (ret)
|
||
|
+ return ret;
|
||
|
+
|
||
|
/* Enable CPU Port */
|
||
|
ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0,
|
||
|
QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
|
||
|
@@ -970,6 +1036,8 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||
|
case 0: /* 1st CPU port */
|
||
|
if (state->interface != PHY_INTERFACE_MODE_RGMII &&
|
||
|
state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
|
||
|
+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID &&
|
||
|
+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID &&
|
||
|
state->interface != PHY_INTERFACE_MODE_SGMII)
|
||
|
return;
|
||
|
|
||
|
@@ -985,6 +1053,8 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||
|
case 6: /* 2nd CPU port / external PHY */
|
||
|
if (state->interface != PHY_INTERFACE_MODE_RGMII &&
|
||
|
state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
|
||
|
+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID &&
|
||
|
+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID &&
|
||
|
state->interface != PHY_INTERFACE_MODE_SGMII &&
|
||
|
state->interface != PHY_INTERFACE_MODE_1000BASEX)
|
||
|
return;
|
||
|
@@ -1008,14 +1078,18 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||
|
qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN);
|
||
|
break;
|
||
|
case PHY_INTERFACE_MODE_RGMII_ID:
|
||
|
+ case PHY_INTERFACE_MODE_RGMII_TXID:
|
||
|
+ case PHY_INTERFACE_MODE_RGMII_RXID:
|
||
|
/* RGMII_ID needs internal delay. This is enabled through
|
||
|
* PORT5_PAD_CTRL for all ports, rather than individual port
|
||
|
* registers
|
||
|
*/
|
||
|
qca8k_write(priv, reg,
|
||
|
QCA8K_PORT_PAD_RGMII_EN |
|
||
|
- QCA8K_PORT_PAD_RGMII_TX_DELAY(QCA8K_MAX_DELAY) |
|
||
|
- QCA8K_PORT_PAD_RGMII_RX_DELAY(QCA8K_MAX_DELAY));
|
||
|
+ QCA8K_PORT_PAD_RGMII_TX_DELAY(priv->rgmii_tx_delay) |
|
||
|
+ QCA8K_PORT_PAD_RGMII_RX_DELAY(priv->rgmii_rx_delay) |
|
||
|
+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN |
|
||
|
+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);
|
||
|
/* QCA8337 requires to set rgmii rx delay */
|
||
|
if (priv->switch_id == QCA8K_ID_QCA8337)
|
||
|
qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,
|
||
|
@@ -1073,6 +1147,8 @@ qca8k_phylink_validate(struct dsa_switch
|
||
|
if (state->interface != PHY_INTERFACE_MODE_NA &&
|
||
|
state->interface != PHY_INTERFACE_MODE_RGMII &&
|
||
|
state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
|
||
|
+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID &&
|
||
|
+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID &&
|
||
|
state->interface != PHY_INTERFACE_MODE_SGMII)
|
||
|
goto unsupported;
|
||
|
break;
|
||
|
@@ -1090,6 +1166,8 @@ qca8k_phylink_validate(struct dsa_switch
|
||
|
if (state->interface != PHY_INTERFACE_MODE_NA &&
|
||
|
state->interface != PHY_INTERFACE_MODE_RGMII &&
|
||
|
state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
|
||
|
+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID &&
|
||
|
+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID &&
|
||
|
state->interface != PHY_INTERFACE_MODE_SGMII &&
|
||
|
state->interface != PHY_INTERFACE_MODE_1000BASEX)
|
||
|
goto unsupported;
|
||
|
--- a/drivers/net/dsa/qca8k.h
|
||
|
+++ b/drivers/net/dsa/qca8k.h
|
||
|
@@ -38,12 +38,11 @@
|
||
|
#define QCA8K_REG_PORT5_PAD_CTRL 0x008
|
||
|
#define QCA8K_REG_PORT6_PAD_CTRL 0x00c
|
||
|
#define QCA8K_PORT_PAD_RGMII_EN BIT(26)
|
||
|
-#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) \
|
||
|
- ((0x8 + (x & 0x3)) << 22)
|
||
|
-#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) \
|
||
|
- ((0x10 + (x & 0x3)) << 20)
|
||
|
-#define QCA8K_MAX_DELAY 3
|
||
|
+#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) ((x) << 22)
|
||
|
+#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) ((x) << 20)
|
||
|
+#define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25)
|
||
|
#define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24)
|
||
|
+#define QCA8K_MAX_DELAY 3
|
||
|
#define QCA8K_PORT_PAD_SGMII_EN BIT(7)
|
||
|
#define QCA8K_REG_PWS 0x010
|
||
|
#define QCA8K_PWS_SERDES_AEN_DIS BIT(7)
|
||
|
@@ -254,6 +253,8 @@ struct qca8k_match_data {
|
||
|
struct qca8k_priv {
|
||
|
u8 switch_id;
|
||
|
u8 switch_revision;
|
||
|
+ u8 rgmii_tx_delay;
|
||
|
+ u8 rgmii_rx_delay;
|
||
|
struct regmap *regmap;
|
||
|
struct mii_bus *bus;
|
||
|
struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS];
|