kernel: 5.10: backport qca8k feature additions
[openwrt/openwrt.git] / target / linux / generic / backport-5.10 / 797-v5.16-06-net-dsa-qca8k-rework-rgmii-delay-logic-and-scan-for-.patch
diff --git a/target/linux/generic/backport-5.10/797-v5.16-06-net-dsa-qca8k-rework-rgmii-delay-logic-and-scan-for-.patch b/target/linux/generic/backport-5.10/797-v5.16-06-net-dsa-qca8k-rework-rgmii-delay-logic-and-scan-for-.patch
new file mode 100644 (file)
index 0000000..de20176
--- /dev/null
@@ -0,0 +1,295 @@
+From 5654ec78dd7e64b1e04777b24007344329e6a63b Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Thu, 14 Oct 2021 00:39:11 +0200
+Subject: net: dsa: qca8k: rework rgmii delay logic and scan for cpu port 6
+
+Future proof commit. This switch have 2 CPU ports and one valid
+configuration is first CPU port set to sgmii and second CPU port set to
+rgmii-id. The current implementation detects delay only for CPU port
+zero set to rgmii and doesn't count any delay set in a secondary CPU
+port. Drop the current delay scan function and move it to the sgmii
+parser function to generalize and implicitly add support for secondary
+CPU port set to rgmii-id. Introduce new logic where delay is enabled
+also with internal delay binding declared and rgmii set as PHY mode.
+
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/qca8k.c | 165 ++++++++++++++++++++++++------------------------
+ drivers/net/dsa/qca8k.h |  10 ++-
+ 2 files changed, 89 insertions(+), 86 deletions(-)
+
+--- a/drivers/net/dsa/qca8k.c
++++ b/drivers/net/dsa/qca8k.c
+@@ -889,68 +889,6 @@ 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_mac_pwr_sel(struct qca8k_priv *priv)
+ {
+       u32 mask = 0;
+@@ -996,19 +934,21 @@ static int qca8k_find_cpu_port(struct ds
+ static int
+ qca8k_parse_port_config(struct qca8k_priv *priv)
+ {
++      int port, cpu_port_index = 0, ret;
+       struct device_node *port_dn;
+       phy_interface_t mode;
+       struct dsa_port *dp;
+-      int port, ret;
++      u32 delay;
+       /* We have 2 CPU port. Check them */
+-      for (port = 0; port < QCA8K_NUM_PORTS; port++) {
++      for (port = 0; port < QCA8K_NUM_PORTS && cpu_port_index < QCA8K_NUM_CPU_PORTS; port++) {
+               /* Skip every other port */
+               if (port != 0 && port != 6)
+                       continue;
+               dp = dsa_to_port(priv->ds, port);
+               port_dn = dp->dn;
++              cpu_port_index++;
+               if (!of_device_is_available(port_dn))
+                       continue;
+@@ -1017,12 +957,54 @@ qca8k_parse_port_config(struct qca8k_pri
+               if (ret)
+                       continue;
+-              if (mode == PHY_INTERFACE_MODE_SGMII) {
++              switch (mode) {
++              case PHY_INTERFACE_MODE_RGMII:
++              case PHY_INTERFACE_MODE_RGMII_ID:
++              case PHY_INTERFACE_MODE_RGMII_TXID:
++              case PHY_INTERFACE_MODE_RGMII_RXID:
++                      delay = 0;
++
++                      if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay))
++                              /* Switch regs accept value in ns, convert ps to ns */
++                              delay = delay / 1000;
++                      else if (mode == PHY_INTERFACE_MODE_RGMII_ID ||
++                               mode == PHY_INTERFACE_MODE_RGMII_TXID)
++                              delay = 1;
++
++                      if (delay > QCA8K_MAX_DELAY) {
++                              dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value");
++                              delay = 3;
++                      }
++
++                      priv->rgmii_tx_delay[cpu_port_index] = delay;
++
++                      delay = 0;
++
++                      if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay))
++                              /* Switch regs accept value in ns, convert ps to ns */
++                              delay = delay / 1000;
++                      else if (mode == PHY_INTERFACE_MODE_RGMII_ID ||
++                               mode == PHY_INTERFACE_MODE_RGMII_RXID)
++                              delay = 2;
++
++                      if (delay > QCA8K_MAX_DELAY) {
++                              dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value");
++                              delay = 3;
++                      }
++
++                      priv->rgmii_rx_delay[cpu_port_index] = delay;
++
++                      break;
++              case PHY_INTERFACE_MODE_SGMII:
+                       if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge"))
+                               priv->sgmii_tx_clk_falling_edge = true;
+                       if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge"))
+                               priv->sgmii_rx_clk_falling_edge = true;
++
++                      break;
++              default:
++                      continue;
+               }
+       }
+@@ -1059,10 +1041,6 @@ qca8k_setup(struct dsa_switch *ds)
+       if (ret)
+               return ret;
+-      ret = qca8k_setup_of_rgmii_delay(priv);
+-      if (ret)
+-              return ret;
+-
+       ret = qca8k_setup_mac_pwr_sel(priv);
+       if (ret)
+               return ret;
+@@ -1229,8 +1207,8 @@ qca8k_phylink_mac_config(struct dsa_swit
+                        const struct phylink_link_state *state)
+ {
+       struct qca8k_priv *priv = ds->priv;
+-      u32 reg, val;
+-      int ret;
++      int cpu_port_index, ret;
++      u32 reg, val, delay;
+       switch (port) {
+       case 0: /* 1st CPU port */
+@@ -1242,6 +1220,7 @@ qca8k_phylink_mac_config(struct dsa_swit
+                       return;
+               reg = QCA8K_REG_PORT0_PAD_CTRL;
++              cpu_port_index = QCA8K_CPU_PORT0;
+               break;
+       case 1:
+       case 2:
+@@ -1260,6 +1239,7 @@ qca8k_phylink_mac_config(struct dsa_swit
+                       return;
+               reg = QCA8K_REG_PORT6_PAD_CTRL;
++              cpu_port_index = QCA8K_CPU_PORT6;
+               break;
+       default:
+               dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port);
+@@ -1274,23 +1254,40 @@ qca8k_phylink_mac_config(struct dsa_swit
+       switch (state->interface) {
+       case PHY_INTERFACE_MODE_RGMII:
+-              /* RGMII mode means no delay so don't enable the delay */
+-              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
++              val = QCA8K_PORT_PAD_RGMII_EN;
++
++              /* Delay can be declared in 3 different way.
++               * Mode to rgmii and internal-delay standard binding defined
++               * rgmii-id or rgmii-tx/rx phy mode set.
++               * The parse logic set a delay different than 0 only when one
++               * of the 3 different way is used. In all other case delay is
++               * not enabled. With ID or TX/RXID delay is enabled and set
++               * to the default and recommended value.
++               */
++              if (priv->rgmii_tx_delay[cpu_port_index]) {
++                      delay = priv->rgmii_tx_delay[cpu_port_index];
++
++                      val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) |
++                             QCA8K_PORT_PAD_RGMII_TX_DELAY_EN;
++              }
++
++              if (priv->rgmii_rx_delay[cpu_port_index]) {
++                      delay = priv->rgmii_rx_delay[cpu_port_index];
++
++                      val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) |
++                             QCA8K_PORT_PAD_RGMII_RX_DELAY_EN;
++              }
++
++              /* Set RGMII delay based on the selected values */
++              qca8k_write(priv, reg, val);
++
++              /* QCA8337 requires to set rgmii rx delay for all ports.
++               * 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(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,
+                                   QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);
+--- a/drivers/net/dsa/qca8k.h
++++ b/drivers/net/dsa/qca8k.h
+@@ -13,6 +13,7 @@
+ #include <linux/gpio.h>
+ #define QCA8K_NUM_PORTS                                       7
++#define QCA8K_NUM_CPU_PORTS                           2
+ #define QCA8K_MAX_MTU                                 9000
+ #define PHY_ID_QCA8327                                        0x004dd034
+@@ -255,13 +256,18 @@ struct qca8k_match_data {
+       u8 id;
+ };
++enum {
++      QCA8K_CPU_PORT0,
++      QCA8K_CPU_PORT6,
++};
++
+ struct qca8k_priv {
+       u8 switch_id;
+       u8 switch_revision;
+-      u8 rgmii_tx_delay;
+-      u8 rgmii_rx_delay;
+       bool sgmii_rx_clk_falling_edge;
+       bool sgmii_tx_clk_falling_edge;
++      u8 rgmii_rx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */
++      u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */
+       bool legacy_phy_port_mapping;
+       struct regmap *regmap;
+       struct mii_bus *bus;