aboutsummaryrefslogtreecommitdiff
path: root/pkgs/patches-linux-5.15/747-v5.16-06-net-dsa-qca8k-rework-rgmii-delay-logic-and-scan-for-.patch
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/patches-linux-5.15/747-v5.16-06-net-dsa-qca8k-rework-rgmii-delay-logic-and-scan-for-.patch')
-rw-r--r--pkgs/patches-linux-5.15/747-v5.16-06-net-dsa-qca8k-rework-rgmii-delay-logic-and-scan-for-.patch295
1 files changed, 295 insertions, 0 deletions
diff --git a/pkgs/patches-linux-5.15/747-v5.16-06-net-dsa-qca8k-rework-rgmii-delay-logic-and-scan-for-.patch b/pkgs/patches-linux-5.15/747-v5.16-06-net-dsa-qca8k-rework-rgmii-delay-logic-and-scan-for-.patch
new file mode 100644
index 0000000..de20176
--- /dev/null
+++ b/pkgs/patches-linux-5.15/747-v5.16-06-net-dsa-qca8k-rework-rgmii-delay-logic-and-scan-for-.patch
@@ -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;