--- /dev/null
+From d8b6f5bae6d3b648a67b6958cb98e4e97256d652 Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Thu, 14 Oct 2021 00:39:06 +0200
+Subject: dsa: qca8k: add mac_power_sel support
+
+Add missing mac power sel support needed for ipq8064/5 SoC that require
+1.8v for the internal regulator port instead of the default 1.5v.
+If other device needs this, consider adding a dedicated binding to
+support this.
+
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/qca8k.c | 31 +++++++++++++++++++++++++++++++
+ drivers/net/dsa/qca8k.h | 5 +++++
+ 2 files changed, 36 insertions(+)
+
+--- a/drivers/net/dsa/qca8k.c
++++ b/drivers/net/dsa/qca8k.c
+@@ -951,6 +951,33 @@ qca8k_setup_of_rgmii_delay(struct qca8k_
+ }
+
+ static int
++qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv)
++{
++ u32 mask = 0;
++ int ret = 0;
++
++ /* SoC specific settings for ipq8064.
++ * If more device require this consider adding
++ * a dedicated binding.
++ */
++ if (of_machine_is_compatible("qcom,ipq8064"))
++ mask |= QCA8K_MAC_PWR_RGMII0_1_8V;
++
++ /* SoC specific settings for ipq8065 */
++ if (of_machine_is_compatible("qcom,ipq8065"))
++ mask |= QCA8K_MAC_PWR_RGMII1_1_8V;
++
++ if (mask) {
++ ret = qca8k_rmw(priv, QCA8K_REG_MAC_PWR_SEL,
++ QCA8K_MAC_PWR_RGMII0_1_8V |
++ QCA8K_MAC_PWR_RGMII1_1_8V,
++ mask);
++ }
++
++ return ret;
++}
++
++static int
+ qca8k_setup(struct dsa_switch *ds)
+ {
+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
+@@ -979,6 +1006,10 @@ qca8k_setup(struct dsa_switch *ds)
+ if (ret)
+ return ret;
+
++ ret = qca8k_setup_mac_pwr_sel(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);
+--- a/drivers/net/dsa/qca8k.h
++++ b/drivers/net/dsa/qca8k.h
+@@ -100,6 +100,11 @@
+ #define QCA8K_SGMII_MODE_CTRL_PHY (1 << 22)
+ #define QCA8K_SGMII_MODE_CTRL_MAC (2 << 22)
+
++/* MAC_PWR_SEL registers */
++#define QCA8K_REG_MAC_PWR_SEL 0x0e4
++#define QCA8K_MAC_PWR_RGMII1_1_8V BIT(18)
++#define QCA8K_MAC_PWR_RGMII0_1_8V BIT(19)
++
+ /* EEE control registers */
+ #define QCA8K_REG_EEE_CTRL 0x100
+ #define QCA8K_REG_EEE_CTRL_LPI_EN(_i) ((_i + 1) * 2)
--- /dev/null
+From fdbf35df9c091db9c46e57e9938e3f7a4f603a7c Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Thu, 14 Oct 2021 00:39:07 +0200
+Subject: dt-bindings: net: dsa: qca8k: Add SGMII clock phase properties
+
+Add names and descriptions of additional PORT0_PAD_CTRL properties.
+qca,sgmii-(rx|tx)clk-falling-edge are for setting the respective clock
+phase to failling edge.
+
+Co-developed-by: Matthew Hagan <mnhagan88@gmail.com>
+Signed-off-by: Matthew Hagan <mnhagan88@gmail.com>
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ Documentation/devicetree/bindings/net/dsa/qca8k.txt | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt
++++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt
+@@ -37,6 +37,10 @@ A CPU port node has the following option
+ managed entity. See
+ Documentation/devicetree/bindings/net/fixed-link.txt
+ for details.
++- qca,sgmii-rxclk-falling-edge: Set the receive clock phase to falling edge.
++ Mostly used in qca8327 with CPU port 0 set to
++ sgmii.
++- qca,sgmii-txclk-falling-edge: Set the transmit clock phase to falling edge.
+
+ For QCA8K the 'fixed-link' sub-node supports only the following properties:
+
--- /dev/null
+From 6c43809bf1bee76c434e365a26546a92a5fbec14 Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Thu, 14 Oct 2021 00:39:08 +0200
+Subject: net: dsa: qca8k: add support for sgmii falling edge
+
+Add support for this in the qca8k driver. Also add support for SGMII
+rx/tx clock falling edge. This is only present for pad0, pad5 and
+pad6 have these bit reserved from Documentation. Add a comment that this
+is hardcoded to PAD0 as qca8327/28/34/37 have an unique sgmii line and
+setting falling in port0 applies to both configuration with sgmii used
+for port0 or port6.
+
+Co-developed-by: Matthew Hagan <mnhagan88@gmail.com>
+Signed-off-by: Matthew Hagan <mnhagan88@gmail.com>
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/qca8k.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/net/dsa/qca8k.h | 4 ++++
+ 2 files changed, 67 insertions(+)
+
+--- a/drivers/net/dsa/qca8k.c
++++ b/drivers/net/dsa/qca8k.c
+@@ -978,6 +978,42 @@ qca8k_setup_mac_pwr_sel(struct qca8k_pri
+ }
+
+ static int
++qca8k_parse_port_config(struct qca8k_priv *priv)
++{
++ struct device_node *port_dn;
++ phy_interface_t mode;
++ struct dsa_port *dp;
++ int port, ret;
++
++ /* We have 2 CPU port. Check them */
++ for (port = 0; port < QCA8K_NUM_PORTS; port++) {
++ /* Skip every other port */
++ if (port != 0 && port != 6)
++ continue;
++
++ dp = dsa_to_port(priv->ds, port);
++ port_dn = dp->dn;
++
++ if (!of_device_is_available(port_dn))
++ continue;
++
++ ret = of_get_phy_mode(port_dn, &mode);
++ if (ret)
++ continue;
++
++ if (mode == 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;
++ }
++ }
++
++ return 0;
++}
++
++static int
+ qca8k_setup(struct dsa_switch *ds)
+ {
+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
+@@ -990,6 +1026,11 @@ qca8k_setup(struct dsa_switch *ds)
+ return -EINVAL;
+ }
+
++ /* Parse CPU port config to be later used in phy_link mac_config */
++ ret = qca8k_parse_port_config(priv);
++ if (ret)
++ return ret;
++
+ mutex_init(&priv->reg_mutex);
+
+ /* Start by setting up the register mapping */
+@@ -1274,6 +1315,28 @@ qca8k_phylink_mac_config(struct dsa_swit
+ }
+
+ qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val);
++
++ /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and
++ * falling edge is set writing in the PORT0 PAD reg
++ */
++ if (priv->switch_id == QCA8K_ID_QCA8327 ||
++ priv->switch_id == QCA8K_ID_QCA8337)
++ reg = QCA8K_REG_PORT0_PAD_CTRL;
++
++ val = 0;
++
++ /* SGMII Clock phase configuration */
++ if (priv->sgmii_rx_clk_falling_edge)
++ val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE;
++
++ if (priv->sgmii_tx_clk_falling_edge)
++ val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE;
++
++ if (val)
++ ret = qca8k_rmw(priv, reg,
++ QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE |
++ QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE,
++ val);
+ break;
+ default:
+ dev_err(ds->dev, "xMII mode %s not supported for port %d\n",
+--- a/drivers/net/dsa/qca8k.h
++++ b/drivers/net/dsa/qca8k.h
+@@ -35,6 +35,8 @@
+ #define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8)
+ #define QCA8K_MASK_CTRL_DEVICE_ID(x) ((x) >> 8)
+ #define QCA8K_REG_PORT0_PAD_CTRL 0x004
++#define QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE BIT(19)
++#define QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE BIT(18)
+ #define QCA8K_REG_PORT5_PAD_CTRL 0x008
+ #define QCA8K_REG_PORT6_PAD_CTRL 0x00c
+ #define QCA8K_PORT_PAD_RGMII_EN BIT(26)
+@@ -260,6 +262,8 @@ struct qca8k_priv {
+ u8 switch_revision;
+ u8 rgmii_tx_delay;
+ u8 rgmii_rx_delay;
++ bool sgmii_rx_clk_falling_edge;
++ bool sgmii_tx_clk_falling_edge;
+ bool legacy_phy_port_mapping;
+ struct regmap *regmap;
+ struct mii_bus *bus;
--- /dev/null
+From 731d613338ec6de482053ffa3f71be2325b0f8eb Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Thu, 14 Oct 2021 00:39:09 +0200
+Subject: dt-bindings: net: dsa: qca8k: Document support for CPU port 6
+
+The switch now support CPU port to be set 6 instead of be hardcoded to
+0. Document support for it and describe logic selection.
+
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ Documentation/devicetree/bindings/net/dsa/qca8k.txt | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt
++++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt
+@@ -29,7 +29,11 @@ the mdio MASTER is used as communication
+ Don't use mixed external and internal mdio-bus configurations, as this is
+ not supported by the hardware.
+
+-The CPU port of this switch is always port 0.
++This switch support 2 CPU port. Normally and advised configuration is with
++CPU port set to port 0. It is also possible to set the CPU port to port 6
++if the device requires it. The driver will configure the switch to the defined
++port. With both CPU port declared the first CPU port is selected as primary
++and the secondary CPU ignored.
+
+ A CPU port node has the following optional node:
+
--- /dev/null
+From 3fcf734aa482487df83cf8f18608438fcf59127f Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Thu, 14 Oct 2021 00:39:10 +0200
+Subject: net: dsa: qca8k: add support for cpu port 6
+
+Currently CPU port is always hardcoded to port 0. This switch have 2 CPU
+ports. The original intention of this driver seems to be use the
+mac06_exchange bit to swap MAC0 with MAC6 in the strange configuration
+where device have connected only the CPU port 6. To skip the
+introduction of a new binding, rework the driver to address the
+secondary CPU port as primary and drop any reference of hardcoded port.
+With configuration of mac06 exchange, just skip the definition of port0
+and define the CPU port as a secondary. The driver will autoconfigure
+the switch to use that as the primary CPU port.
+
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/qca8k.c | 51 ++++++++++++++++++++++++++++++++++---------------
+ drivers/net/dsa/qca8k.h | 2 --
+ 2 files changed, 36 insertions(+), 17 deletions(-)
+
+--- a/drivers/net/dsa/qca8k.c
++++ b/drivers/net/dsa/qca8k.c
+@@ -977,6 +977,22 @@ qca8k_setup_mac_pwr_sel(struct qca8k_pri
+ return ret;
+ }
+
++static int qca8k_find_cpu_port(struct dsa_switch *ds)
++{
++ struct qca8k_priv *priv = ds->priv;
++
++ /* Find the connected cpu port. Valid port are 0 or 6 */
++ if (dsa_is_cpu_port(ds, 0))
++ return 0;
++
++ dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6");
++
++ if (dsa_is_cpu_port(ds, 6))
++ return 6;
++
++ return -EINVAL;
++}
++
+ static int
+ qca8k_parse_port_config(struct qca8k_priv *priv)
+ {
+@@ -1017,13 +1033,13 @@ static int
+ qca8k_setup(struct dsa_switch *ds)
+ {
+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
+- int ret, i;
++ int cpu_port, ret, i;
+ u32 mask;
+
+- /* Make sure that port 0 is the cpu port */
+- if (!dsa_is_cpu_port(ds, 0)) {
+- dev_err(priv->dev, "port 0 is not the CPU port");
+- return -EINVAL;
++ cpu_port = qca8k_find_cpu_port(ds);
++ if (cpu_port < 0) {
++ dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6");
++ return cpu_port;
+ }
+
+ /* Parse CPU port config to be later used in phy_link mac_config */
+@@ -1065,7 +1081,7 @@ qca8k_setup(struct dsa_switch *ds)
+ dev_warn(priv->dev, "mib init failed");
+
+ /* Enable QCA header mode on the cpu port */
+- ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(QCA8K_CPU_PORT),
++ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(cpu_port),
+ QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S |
+ QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S);
+ if (ret) {
+@@ -1087,10 +1103,10 @@ qca8k_setup(struct dsa_switch *ds)
+
+ /* Forward all unknown frames to CPU port for Linux processing */
+ ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1,
+- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S |
+- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S |
+- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S |
+- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S);
++ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S |
++ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S |
++ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S |
++ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S);
+ if (ret)
+ return ret;
+
+@@ -1098,7 +1114,7 @@ qca8k_setup(struct dsa_switch *ds)
+ for (i = 0; i < QCA8K_NUM_PORTS; i++) {
+ /* CPU port gets connected to all user ports of the switch */
+ if (dsa_is_cpu_port(ds, i)) {
+- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(QCA8K_CPU_PORT),
++ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(cpu_port),
+ QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds));
+ if (ret)
+ return ret;
+@@ -1110,7 +1126,7 @@ qca8k_setup(struct dsa_switch *ds)
+
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
+ QCA8K_PORT_LOOKUP_MEMBER,
+- BIT(QCA8K_CPU_PORT));
++ BIT(cpu_port));
+ if (ret)
+ return ret;
+
+@@ -1616,9 +1632,12 @@ static int
+ qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br)
+ {
+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
+- int port_mask = BIT(QCA8K_CPU_PORT);
++ int port_mask, cpu_port;
+ int i, ret;
+
++ cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
++ port_mask = BIT(cpu_port);
++
+ for (i = 1; i < QCA8K_NUM_PORTS; i++) {
+ if (dsa_to_port(ds, i)->bridge_dev != br)
+ continue;
+@@ -1645,7 +1664,9 @@ static void
+ qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br)
+ {
+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
+- int i;
++ int cpu_port, i;
++
++ cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
+
+ for (i = 1; i < QCA8K_NUM_PORTS; i++) {
+ if (dsa_to_port(ds, i)->bridge_dev != br)
+@@ -1662,7 +1683,7 @@ qca8k_port_bridge_leave(struct dsa_switc
+ * this port
+ */
+ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
+- QCA8K_PORT_LOOKUP_MEMBER, BIT(QCA8K_CPU_PORT));
++ QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port));
+ }
+
+ static int
+--- a/drivers/net/dsa/qca8k.h
++++ b/drivers/net/dsa/qca8k.h
+@@ -24,8 +24,6 @@
+
+ #define QCA8K_NUM_FDB_RECORDS 2048
+
+-#define QCA8K_CPU_PORT 0
+-
+ #define QCA8K_PORT_VID_DEF 1
+
+ /* Global control registers */
--- /dev/null
+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;
--- /dev/null
+From 13ad5ccc093ff448b99ac7e138e91e78796adb48 Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Thu, 14 Oct 2021 00:39:12 +0200
+Subject: dt-bindings: net: dsa: qca8k: Document qca,sgmii-enable-pll
+
+Document qca,sgmii-enable-pll binding used in the CPU nodes to
+enable SGMII PLL on MAC config.
+
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ Documentation/devicetree/bindings/net/dsa/qca8k.txt | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt
++++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt
+@@ -45,6 +45,16 @@ A CPU port node has the following option
+ Mostly used in qca8327 with CPU port 0 set to
+ sgmii.
+ - qca,sgmii-txclk-falling-edge: Set the transmit clock phase to falling edge.
++- qca,sgmii-enable-pll : For SGMII CPU port, explicitly enable PLL, TX and RX
++ chain along with Signal Detection.
++ This should NOT be enabled for qca8327. If enabled with
++ qca8327 the sgmii port won't correctly init and an err
++ is printed.
++ This can be required for qca8337 switch with revision 2.
++ A warning is displayed when used with revision greater
++ 2.
++ With CPU port set to sgmii and qca8337 it is advised
++ to set this unless a communication problem is observed.
+
+ For QCA8K the 'fixed-link' sub-node supports only the following properties:
+
--- /dev/null
+From bbc4799e8bb6c397e3b3fec13de68e179f5db9ff Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Thu, 14 Oct 2021 00:39:13 +0200
+Subject: net: dsa: qca8k: add explicit SGMII PLL enable
+
+Support enabling PLL on the SGMII CPU port. Some device require this
+special configuration or no traffic is transmitted and the switch
+doesn't work at all. A dedicated binding is added to the CPU node
+port to apply the correct reg on mac config.
+Fail to correctly configure sgmii with qca8327 switch and warn if pll is
+used on qca8337 with a revision greater than 1.
+
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/qca8k.c | 19 +++++++++++++++++--
+ drivers/net/dsa/qca8k.h | 1 +
+ 2 files changed, 18 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/dsa/qca8k.c
++++ b/drivers/net/dsa/qca8k.c
+@@ -1002,6 +1002,18 @@ qca8k_parse_port_config(struct qca8k_pri
+ if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge"))
+ priv->sgmii_rx_clk_falling_edge = true;
+
++ if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) {
++ priv->sgmii_enable_pll = true;
++
++ if (priv->switch_id == QCA8K_ID_QCA8327) {
++ dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling");
++ priv->sgmii_enable_pll = false;
++ }
++
++ if (priv->switch_revision < 2)
++ dev_warn(priv->dev, "SGMII PLL should NOT be enabled for qca8337 with revision 2 or more.");
++ }
++
+ break;
+ default:
+ continue;
+@@ -1312,8 +1324,11 @@ qca8k_phylink_mac_config(struct dsa_swit
+ if (ret)
+ return;
+
+- val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX |
+- QCA8K_SGMII_EN_TX | QCA8K_SGMII_EN_SD;
++ val |= QCA8K_SGMII_EN_SD;
++
++ if (priv->sgmii_enable_pll)
++ val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX |
++ QCA8K_SGMII_EN_TX;
+
+ if (dsa_is_cpu_port(ds, port)) {
+ /* CPU port, we're talking to the CPU MAC, be a PHY */
+--- a/drivers/net/dsa/qca8k.h
++++ b/drivers/net/dsa/qca8k.h
+@@ -266,6 +266,7 @@ struct qca8k_priv {
+ u8 switch_revision;
+ bool sgmii_rx_clk_falling_edge;
+ bool sgmii_tx_clk_falling_edge;
++ bool sgmii_enable_pll;
+ 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;
--- /dev/null
+From 924087c5c3d41553700b0eb83ca2a53b91643dca Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Thu, 14 Oct 2021 00:39:14 +0200
+Subject: dt-bindings: net: dsa: qca8k: Document qca,led-open-drain binding
+
+Document new binding qca,ignore-power-on-sel used to ignore
+power on strapping and use sw regs instead.
+Document qca,led-open.drain to set led to open drain mode, the
+qca,ignore-power-on-sel is mandatory with this enabled or an error will
+be reported.
+
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ Documentation/devicetree/bindings/net/dsa/qca8k.txt | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt
++++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt
+@@ -13,6 +13,17 @@ Required properties:
+ Optional properties:
+
+ - reset-gpios: GPIO to be used to reset the whole device
++- qca,ignore-power-on-sel: Ignore power on pin strapping to configure led open
++ drain or eeprom presence. This is needed for broken
++ devices that have wrong configuration or when the oem
++ decided to not use pin strapping and fallback to sw
++ regs.
++- qca,led-open-drain: Set leds to open-drain mode. This requires the
++ qca,ignore-power-on-sel to be set or the driver will fail
++ to probe. This is needed if the oem doesn't use pin
++ strapping to set this mode and prefers to set it using sw
++ regs. The pin strapping related to led open drain mode is
++ the pin B68 for QCA832x and B49 for QCA833x
+
+ Subnodes:
+
--- /dev/null
+From 362bb238d8bf1470424214a8a5968d9c6cce68fa Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Thu, 14 Oct 2021 00:39:15 +0200
+Subject: net: dsa: qca8k: add support for pws config reg
+
+Some qca8327 switch require to force the ignore of power on sel
+strapping. Some switch require to set the led open drain mode in regs
+instead of using strapping. While most of the device implements this
+using the correct way using pin strapping, there are still some broken
+device that require to be set using sw regs.
+Introduce a new binding and support these special configuration.
+As led open drain require to ignore pin strapping to work, the probe
+fails with EINVAL error with incorrect configuration.
+
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/qca8k.c | 39 +++++++++++++++++++++++++++++++++++++++
+ drivers/net/dsa/qca8k.h | 6 ++++++
+ 2 files changed, 45 insertions(+)
+
+--- a/drivers/net/dsa/qca8k.c
++++ b/drivers/net/dsa/qca8k.c
+@@ -932,6 +932,41 @@ static int qca8k_find_cpu_port(struct ds
+ }
+
+ static int
++qca8k_setup_of_pws_reg(struct qca8k_priv *priv)
++{
++ struct device_node *node = priv->dev->of_node;
++ u32 val = 0;
++ int ret;
++
++ /* QCA8327 require to set to the correct mode.
++ * His bigger brother QCA8328 have the 172 pin layout.
++ * Should be applied by default but we set this just to make sure.
++ */
++ if (priv->switch_id == QCA8K_ID_QCA8327) {
++ ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN,
++ QCA8327_PWS_PACKAGE148_EN);
++ if (ret)
++ return ret;
++ }
++
++ if (of_property_read_bool(node, "qca,ignore-power-on-sel"))
++ val |= QCA8K_PWS_POWER_ON_SEL;
++
++ if (of_property_read_bool(node, "qca,led-open-drain")) {
++ if (!(val & QCA8K_PWS_POWER_ON_SEL)) {
++ dev_err(priv->dev, "qca,led-open-drain require qca,ignore-power-on-sel to be set.");
++ return -EINVAL;
++ }
++
++ val |= QCA8K_PWS_LED_OPEN_EN_CSR;
++ }
++
++ return qca8k_rmw(priv, QCA8K_REG_PWS,
++ QCA8K_PWS_LED_OPEN_EN_CSR | QCA8K_PWS_POWER_ON_SEL,
++ val);
++}
++
++static int
+ qca8k_parse_port_config(struct qca8k_priv *priv)
+ {
+ int port, cpu_port_index = 0, ret;
+@@ -1053,6 +1088,10 @@ qca8k_setup(struct dsa_switch *ds)
+ if (ret)
+ return ret;
+
++ ret = qca8k_setup_of_pws_reg(priv);
++ if (ret)
++ return ret;
++
+ ret = qca8k_setup_mac_pwr_sel(priv);
+ if (ret)
+ return ret;
+--- a/drivers/net/dsa/qca8k.h
++++ b/drivers/net/dsa/qca8k.h
+@@ -46,6 +46,12 @@
+ #define QCA8K_MAX_DELAY 3
+ #define QCA8K_PORT_PAD_SGMII_EN BIT(7)
+ #define QCA8K_REG_PWS 0x010
++#define QCA8K_PWS_POWER_ON_SEL BIT(31)
++/* This reg is only valid for QCA832x and toggle the package
++ * type from 176 pin (by default) to 148 pin used on QCA8327
++ */
++#define QCA8327_PWS_PACKAGE148_EN BIT(30)
++#define QCA8K_PWS_LED_OPEN_EN_CSR BIT(24)
+ #define QCA8K_PWS_SERDES_AEN_DIS BIT(7)
+ #define QCA8K_REG_MODULE_EN 0x030
+ #define QCA8K_MODULE_EN_MIB BIT(0)
--- /dev/null
+From ed7988d77fbfb79366b68f9e7fa60a6080da23d4 Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Thu, 14 Oct 2021 00:39:16 +0200
+Subject: dt-bindings: net: dsa: qca8k: document support for qca8328
+
+QCA8328 is the bigger brother of qca8327. Document the new compatible
+binding and add some information to understand the various switch
+compatible.
+
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ Documentation/devicetree/bindings/net/dsa/qca8k.txt | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt
++++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt
+@@ -3,9 +3,10 @@
+ Required properties:
+
+ - compatible: should be one of:
+- "qca,qca8327"
+- "qca,qca8334"
+- "qca,qca8337"
++ "qca,qca8328": referenced as AR8328(N)-AK1(A/B) QFN 176 pin package
++ "qca,qca8327": referenced as AR8327(N)-AL1A DR-QFN 148 pin package
++ "qca,qca8334": referenced as QCA8334-AL3C QFN 88 pin package
++ "qca,qca8337": referenced as QCA8337N-AL3(B/C) DR-QFN 148 pin package
+
+ - #size-cells: must be 0
+ - #address-cells: must be 1
--- /dev/null
+From f477d1c8bdbef4f400718238e350f16f521d2a3e Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Thu, 14 Oct 2021 00:39:17 +0200
+Subject: net: dsa: qca8k: add support for QCA8328
+
+QCA8328 switch is the bigger brother of the qca8327. Same regs different
+chip. Change the function to set the correct pin layout and introduce a
+new match_data to differentiate the 2 switch as they have the same ID
+and their internal PHY have the same ID.
+
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/qca8k.c | 19 ++++++++++++++++---
+ drivers/net/dsa/qca8k.h | 1 +
+ 2 files changed, 17 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/dsa/qca8k.c
++++ b/drivers/net/dsa/qca8k.c
+@@ -935,6 +935,7 @@ static int
+ qca8k_setup_of_pws_reg(struct qca8k_priv *priv)
+ {
+ struct device_node *node = priv->dev->of_node;
++ const struct qca8k_match_data *data;
+ u32 val = 0;
+ int ret;
+
+@@ -943,8 +944,14 @@ qca8k_setup_of_pws_reg(struct qca8k_priv
+ * Should be applied by default but we set this just to make sure.
+ */
+ if (priv->switch_id == QCA8K_ID_QCA8327) {
++ data = of_device_get_match_data(priv->dev);
++
++ /* Set the correct package of 148 pin for QCA8327 */
++ if (data->reduced_package)
++ val |= QCA8327_PWS_PACKAGE148_EN;
++
+ ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN,
+- QCA8327_PWS_PACKAGE148_EN);
++ val);
+ if (ret)
+ return ret;
+ }
+@@ -2098,7 +2105,12 @@ static int qca8k_resume(struct device *d
+ static SIMPLE_DEV_PM_OPS(qca8k_pm_ops,
+ qca8k_suspend, qca8k_resume);
+
+-static const struct qca8k_match_data qca832x = {
++static const struct qca8k_match_data qca8327 = {
++ .id = QCA8K_ID_QCA8327,
++ .reduced_package = true,
++};
++
++static const struct qca8k_match_data qca8328 = {
+ .id = QCA8K_ID_QCA8327,
+ };
+
+@@ -2107,7 +2119,8 @@ static const struct qca8k_match_data qca
+ };
+
+ static const struct of_device_id qca8k_of_match[] = {
+- { .compatible = "qca,qca8327", .data = &qca832x },
++ { .compatible = "qca,qca8327", .data = &qca8327 },
++ { .compatible = "qca,qca8328", .data = &qca8328 },
+ { .compatible = "qca,qca8334", .data = &qca833x },
+ { .compatible = "qca,qca8337", .data = &qca833x },
+ { /* sentinel */ },
+--- a/drivers/net/dsa/qca8k.h
++++ b/drivers/net/dsa/qca8k.h
+@@ -260,6 +260,7 @@ struct ar8xxx_port_status {
+
+ struct qca8k_match_data {
+ u8 id;
++ bool reduced_package;
+ };
+
+ enum {
--- /dev/null
+From cef08115846e581f80ff99abf7bf218da1840616 Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Thu, 14 Oct 2021 00:39:18 +0200
+Subject: net: dsa: qca8k: set internal delay also for sgmii
+
+QCA original code report port instability and sa that SGMII also require
+to set internal delay. Generalize the rgmii delay function and apply the
+advised value if they are not defined in DT.
+
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/qca8k.c | 88 +++++++++++++++++++++++++++++++++----------------
+ drivers/net/dsa/qca8k.h | 2 ++
+ 2 files changed, 62 insertions(+), 28 deletions(-)
+
+--- a/drivers/net/dsa/qca8k.c
++++ b/drivers/net/dsa/qca8k.c
+@@ -1004,6 +1004,7 @@ qca8k_parse_port_config(struct qca8k_pri
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
++ case PHY_INTERFACE_MODE_SGMII:
+ delay = 0;
+
+ if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay))
+@@ -1036,8 +1037,13 @@ qca8k_parse_port_config(struct qca8k_pri
+
+ priv->rgmii_rx_delay[cpu_port_index] = delay;
+
+- break;
+- case PHY_INTERFACE_MODE_SGMII:
++ /* Skip sgmii parsing for rgmii* mode */
++ if (mode == PHY_INTERFACE_MODE_RGMII ||
++ mode == PHY_INTERFACE_MODE_RGMII_ID ||
++ mode == PHY_INTERFACE_MODE_RGMII_TXID ||
++ mode == PHY_INTERFACE_MODE_RGMII_RXID)
++ break;
++
+ if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge"))
+ priv->sgmii_tx_clk_falling_edge = true;
+
+@@ -1261,12 +1267,53 @@ qca8k_setup(struct dsa_switch *ds)
+ }
+
+ static void
++qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index,
++ u32 reg)
++{
++ u32 delay, val = 0;
++ int ret;
++
++ /* 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 */
++ ret = qca8k_rmw(priv, reg,
++ QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK |
++ QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK |
++ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN |
++ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN,
++ val);
++ if (ret)
++ dev_err(priv->dev, "Failed to set internal delay for CPU port%d",
++ cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6);
++}
++
++static void
+ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
+ const struct phylink_link_state *state)
+ {
+ struct qca8k_priv *priv = ds->priv;
+ int cpu_port_index, ret;
+- u32 reg, val, delay;
++ u32 reg, val;
+
+ switch (port) {
+ case 0: /* 1st CPU port */
+@@ -1315,32 +1362,10 @@ qca8k_phylink_mac_config(struct dsa_swit
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+- 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;
+- }
++ qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN);
+
+- /* Set RGMII delay based on the selected values */
+- qca8k_write(priv, reg, val);
++ /* Configure rgmii delay */
++ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg);
+
+ /* QCA8337 requires to set rgmii rx delay for all ports.
+ * This is enabled through PORT5_PAD_CTRL for all ports,
+@@ -1411,6 +1436,13 @@ qca8k_phylink_mac_config(struct dsa_swit
+ QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE |
+ QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE,
+ val);
++
++ /* From original code is reported port instability as SGMII also
++ * require delay set. Apply advised values here or take them from DT.
++ */
++ if (state->interface == PHY_INTERFACE_MODE_SGMII)
++ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg);
++
+ break;
+ default:
+ dev_err(ds->dev, "xMII mode %s not supported for port %d\n",
+--- a/drivers/net/dsa/qca8k.h
++++ b/drivers/net/dsa/qca8k.h
+@@ -39,7 +39,9 @@
+ #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_MASK GENMASK(23, 22)
+ #define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) ((x) << 22)
++#define QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK GENMASK(21, 20)
+ #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)
--- /dev/null
+From fd0bb28c547f7c8affb1691128cece38f5b626a1 Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Thu, 14 Oct 2021 00:39:19 +0200
+Subject: net: dsa: qca8k: move port config to dedicated struct
+
+Move ports related config to dedicated struct to keep things organized.
+
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/qca8k.c | 26 +++++++++++++-------------
+ drivers/net/dsa/qca8k.h | 10 +++++++---
+ 2 files changed, 20 insertions(+), 16 deletions(-)
+
+--- a/drivers/net/dsa/qca8k.c
++++ b/drivers/net/dsa/qca8k.c
+@@ -1019,7 +1019,7 @@ qca8k_parse_port_config(struct qca8k_pri
+ delay = 3;
+ }
+
+- priv->rgmii_tx_delay[cpu_port_index] = delay;
++ priv->ports_config.rgmii_tx_delay[cpu_port_index] = delay;
+
+ delay = 0;
+
+@@ -1035,7 +1035,7 @@ qca8k_parse_port_config(struct qca8k_pri
+ delay = 3;
+ }
+
+- priv->rgmii_rx_delay[cpu_port_index] = delay;
++ priv->ports_config.rgmii_rx_delay[cpu_port_index] = delay;
+
+ /* Skip sgmii parsing for rgmii* mode */
+ if (mode == PHY_INTERFACE_MODE_RGMII ||
+@@ -1045,17 +1045,17 @@ qca8k_parse_port_config(struct qca8k_pri
+ break;
+
+ if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge"))
+- priv->sgmii_tx_clk_falling_edge = true;
++ priv->ports_config.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;
++ priv->ports_config.sgmii_rx_clk_falling_edge = true;
+
+ if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) {
+- priv->sgmii_enable_pll = true;
++ priv->ports_config.sgmii_enable_pll = true;
+
+ if (priv->switch_id == QCA8K_ID_QCA8327) {
+ dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling");
+- priv->sgmii_enable_pll = false;
++ priv->ports_config.sgmii_enable_pll = false;
+ }
+
+ if (priv->switch_revision < 2)
+@@ -1281,15 +1281,15 @@ qca8k_mac_config_setup_internal_delay(st
+ * 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];
++ if (priv->ports_config.rgmii_tx_delay[cpu_port_index]) {
++ delay = priv->ports_config.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];
++ if (priv->ports_config.rgmii_rx_delay[cpu_port_index]) {
++ delay = priv->ports_config.rgmii_rx_delay[cpu_port_index];
+
+ val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) |
+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN;
+@@ -1397,7 +1397,7 @@ qca8k_phylink_mac_config(struct dsa_swit
+
+ val |= QCA8K_SGMII_EN_SD;
+
+- if (priv->sgmii_enable_pll)
++ if (priv->ports_config.sgmii_enable_pll)
+ val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX |
+ QCA8K_SGMII_EN_TX;
+
+@@ -1425,10 +1425,10 @@ qca8k_phylink_mac_config(struct dsa_swit
+ val = 0;
+
+ /* SGMII Clock phase configuration */
+- if (priv->sgmii_rx_clk_falling_edge)
++ if (priv->ports_config.sgmii_rx_clk_falling_edge)
+ val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE;
+
+- if (priv->sgmii_tx_clk_falling_edge)
++ if (priv->ports_config.sgmii_tx_clk_falling_edge)
+ val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE;
+
+ if (val)
+--- a/drivers/net/dsa/qca8k.h
++++ b/drivers/net/dsa/qca8k.h
+@@ -270,15 +270,19 @@ enum {
+ QCA8K_CPU_PORT6,
+ };
+
+-struct qca8k_priv {
+- u8 switch_id;
+- u8 switch_revision;
++struct qca8k_ports_config {
+ bool sgmii_rx_clk_falling_edge;
+ bool sgmii_tx_clk_falling_edge;
+ bool sgmii_enable_pll;
+ 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 */
++};
++
++struct qca8k_priv {
++ u8 switch_id;
++ u8 switch_revision;
+ bool legacy_phy_port_mapping;
++ struct qca8k_ports_config ports_config;
+ struct regmap *regmap;
+ struct mii_bus *bus;
+ struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS];
--- /dev/null
+From e52073a8e3086046a098b8a7cbeb282ff0cdb424 Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Thu, 14 Oct 2021 00:39:20 +0200
+Subject: dt-bindings: net: ipq8064-mdio: fix warning with new qca8k switch
+
+Fix warning now that we have qca8k switch Documentation using yaml.
+
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ Documentation/devicetree/bindings/net/qcom,ipq8064-mdio.yaml | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/Documentation/devicetree/bindings/net/qcom,ipq8064-mdio.yaml
++++ b/Documentation/devicetree/bindings/net/qcom,ipq8064-mdio.yaml
+@@ -51,6 +51,9 @@ examples:
+ switch@10 {
+ compatible = "qca,qca8337";
+ reg = <0x10>;
+- /* ... */
++
++ ports {
++ /* ... */
++ };
+ };
+ };
--- /dev/null
+From d291fbb8245d5ba04979fed85575860a5cea7196 Mon Sep 17 00:00:00 2001
+From: Matthew Hagan <mnhagan88@gmail.com>
+Date: Thu, 14 Oct 2021 00:39:21 +0200
+Subject: dt-bindings: net: dsa: qca8k: convert to YAML schema
+
+Convert the qca8k bindings to YAML format.
+
+Signed-off-by: Matthew Hagan <mnhagan88@gmail.com>
+Co-developed-by: Ansuel Smith <ansuelsmth@gmail.com>
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ .../devicetree/bindings/net/dsa/qca8k.txt | 245 --------------
+ .../devicetree/bindings/net/dsa/qca8k.yaml | 362 +++++++++++++++++++++
+ 2 files changed, 362 insertions(+), 245 deletions(-)
+ delete mode 100644 Documentation/devicetree/bindings/net/dsa/qca8k.txt
+ create mode 100644 Documentation/devicetree/bindings/net/dsa/qca8k.yaml
+
+--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt
++++ /dev/null
+@@ -1,245 +0,0 @@
+-* Qualcomm Atheros QCA8xxx switch family
+-
+-Required properties:
+-
+-- compatible: should be one of:
+- "qca,qca8328": referenced as AR8328(N)-AK1(A/B) QFN 176 pin package
+- "qca,qca8327": referenced as AR8327(N)-AL1A DR-QFN 148 pin package
+- "qca,qca8334": referenced as QCA8334-AL3C QFN 88 pin package
+- "qca,qca8337": referenced as QCA8337N-AL3(B/C) DR-QFN 148 pin package
+-
+-- #size-cells: must be 0
+-- #address-cells: must be 1
+-
+-Optional properties:
+-
+-- reset-gpios: GPIO to be used to reset the whole device
+-- qca,ignore-power-on-sel: Ignore power on pin strapping to configure led open
+- drain or eeprom presence. This is needed for broken
+- devices that have wrong configuration or when the oem
+- decided to not use pin strapping and fallback to sw
+- regs.
+-- qca,led-open-drain: Set leds to open-drain mode. This requires the
+- qca,ignore-power-on-sel to be set or the driver will fail
+- to probe. This is needed if the oem doesn't use pin
+- strapping to set this mode and prefers to set it using sw
+- regs. The pin strapping related to led open drain mode is
+- the pin B68 for QCA832x and B49 for QCA833x
+-
+-Subnodes:
+-
+-The integrated switch subnode should be specified according to the binding
+-described in dsa/dsa.txt. If the QCA8K switch is connect to a SoC's external
+-mdio-bus each subnode describing a port needs to have a valid phandle
+-referencing the internal PHY it is connected to. This is because there's no
+-N:N mapping of port and PHY id.
+-To declare the internal mdio-bus configuration, declare a mdio node in the
+-switch node and declare the phandle for the port referencing the internal
+-PHY is connected to. In this config a internal mdio-bus is registered and
+-the mdio MASTER is used as communication.
+-
+-Don't use mixed external and internal mdio-bus configurations, as this is
+-not supported by the hardware.
+-
+-This switch support 2 CPU port. Normally and advised configuration is with
+-CPU port set to port 0. It is also possible to set the CPU port to port 6
+-if the device requires it. The driver will configure the switch to the defined
+-port. With both CPU port declared the first CPU port is selected as primary
+-and the secondary CPU ignored.
+-
+-A CPU port node has the following optional node:
+-
+-- fixed-link : Fixed-link subnode describing a link to a non-MDIO
+- managed entity. See
+- Documentation/devicetree/bindings/net/fixed-link.txt
+- for details.
+-- qca,sgmii-rxclk-falling-edge: Set the receive clock phase to falling edge.
+- Mostly used in qca8327 with CPU port 0 set to
+- sgmii.
+-- qca,sgmii-txclk-falling-edge: Set the transmit clock phase to falling edge.
+-- qca,sgmii-enable-pll : For SGMII CPU port, explicitly enable PLL, TX and RX
+- chain along with Signal Detection.
+- This should NOT be enabled for qca8327. If enabled with
+- qca8327 the sgmii port won't correctly init and an err
+- is printed.
+- This can be required for qca8337 switch with revision 2.
+- A warning is displayed when used with revision greater
+- 2.
+- With CPU port set to sgmii and qca8337 it is advised
+- to set this unless a communication problem is observed.
+-
+-For QCA8K the 'fixed-link' sub-node supports only the following properties:
+-
+-- 'speed' (integer, mandatory), to indicate the link speed. Accepted
+- values are 10, 100 and 1000
+-- 'full-duplex' (boolean, optional), to indicate that full duplex is
+- used. When absent, half duplex is assumed.
+-
+-Examples:
+-
+-for the external mdio-bus configuration:
+-
+- &mdio0 {
+- phy_port1: phy@0 {
+- reg = <0>;
+- };
+-
+- phy_port2: phy@1 {
+- reg = <1>;
+- };
+-
+- phy_port3: phy@2 {
+- reg = <2>;
+- };
+-
+- phy_port4: phy@3 {
+- reg = <3>;
+- };
+-
+- phy_port5: phy@4 {
+- reg = <4>;
+- };
+-
+- switch@10 {
+- compatible = "qca,qca8337";
+- #address-cells = <1>;
+- #size-cells = <0>;
+-
+- reset-gpios = <&gpio 42 GPIO_ACTIVE_LOW>;
+- reg = <0x10>;
+-
+- ports {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- port@0 {
+- reg = <0>;
+- label = "cpu";
+- ethernet = <&gmac1>;
+- phy-mode = "rgmii";
+- fixed-link {
+- speed = 1000;
+- full-duplex;
+- };
+- };
+-
+- port@1 {
+- reg = <1>;
+- label = "lan1";
+- phy-handle = <&phy_port1>;
+- };
+-
+- port@2 {
+- reg = <2>;
+- label = "lan2";
+- phy-handle = <&phy_port2>;
+- };
+-
+- port@3 {
+- reg = <3>;
+- label = "lan3";
+- phy-handle = <&phy_port3>;
+- };
+-
+- port@4 {
+- reg = <4>;
+- label = "lan4";
+- phy-handle = <&phy_port4>;
+- };
+-
+- port@5 {
+- reg = <5>;
+- label = "wan";
+- phy-handle = <&phy_port5>;
+- };
+- };
+- };
+- };
+-
+-for the internal master mdio-bus configuration:
+-
+- &mdio0 {
+- switch@10 {
+- compatible = "qca,qca8337";
+- #address-cells = <1>;
+- #size-cells = <0>;
+-
+- reset-gpios = <&gpio 42 GPIO_ACTIVE_LOW>;
+- reg = <0x10>;
+-
+- ports {
+- #address-cells = <1>;
+- #size-cells = <0>;
+-
+- port@0 {
+- reg = <0>;
+- label = "cpu";
+- ethernet = <&gmac1>;
+- phy-mode = "rgmii";
+- fixed-link {
+- speed = 1000;
+- full-duplex;
+- };
+- };
+-
+- port@1 {
+- reg = <1>;
+- label = "lan1";
+- phy-mode = "internal";
+- phy-handle = <&phy_port1>;
+- };
+-
+- port@2 {
+- reg = <2>;
+- label = "lan2";
+- phy-mode = "internal";
+- phy-handle = <&phy_port2>;
+- };
+-
+- port@3 {
+- reg = <3>;
+- label = "lan3";
+- phy-mode = "internal";
+- phy-handle = <&phy_port3>;
+- };
+-
+- port@4 {
+- reg = <4>;
+- label = "lan4";
+- phy-mode = "internal";
+- phy-handle = <&phy_port4>;
+- };
+-
+- port@5 {
+- reg = <5>;
+- label = "wan";
+- phy-mode = "internal";
+- phy-handle = <&phy_port5>;
+- };
+- };
+-
+- mdio {
+- #address-cells = <1>;
+- #size-cells = <0>;
+-
+- phy_port1: phy@0 {
+- reg = <0>;
+- };
+-
+- phy_port2: phy@1 {
+- reg = <1>;
+- };
+-
+- phy_port3: phy@2 {
+- reg = <2>;
+- };
+-
+- phy_port4: phy@3 {
+- reg = <3>;
+- };
+-
+- phy_port5: phy@4 {
+- reg = <4>;
+- };
+- };
+- };
+- };
+--- /dev/null
++++ b/Documentation/devicetree/bindings/net/dsa/qca8k.yaml
+@@ -0,0 +1,362 @@
++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/net/dsa/qca8k.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Qualcomm Atheros QCA83xx switch family
++
++maintainers:
++ - John Crispin <john@phrozen.org>
++
++description:
++ If the QCA8K switch is connect to an SoC's external mdio-bus, each subnode
++ describing a port needs to have a valid phandle referencing the internal PHY
++ it is connected to. This is because there is no N:N mapping of port and PHY
++ ID. To declare the internal mdio-bus configuration, declare an MDIO node in
++ the switch node and declare the phandle for the port, referencing the internal
++ PHY it is connected to. In this config, an internal mdio-bus is registered and
++ the MDIO master is used for communication. Mixed external and internal
++ mdio-bus configurations are not supported by the hardware.
++
++properties:
++ compatible:
++ oneOf:
++ - enum:
++ - qca,qca8327
++ - qca,qca8328
++ - qca,qca8334
++ - qca,qca8337
++ description: |
++ qca,qca8328: referenced as AR8328(N)-AK1(A/B) QFN 176 pin package
++ qca,qca8327: referenced as AR8327(N)-AL1A DR-QFN 148 pin package
++ qca,qca8334: referenced as QCA8334-AL3C QFN 88 pin package
++ qca,qca8337: referenced as QCA8337N-AL3(B/C) DR-QFN 148 pin package
++
++ reg:
++ maxItems: 1
++
++ reset-gpios:
++ description:
++ GPIO to be used to reset the whole device
++ maxItems: 1
++
++ qca,ignore-power-on-sel:
++ $ref: /schemas/types.yaml#/definitions/flag
++ description:
++ Ignore power-on pin strapping to configure LED open-drain or EEPROM
++ presence. This is needed for devices with incorrect configuration or when
++ the OEM has decided not to use pin strapping and falls back to SW regs.
++
++ qca,led-open-drain:
++ $ref: /schemas/types.yaml#/definitions/flag
++ description:
++ Set LEDs to open-drain mode. This requires the qca,ignore-power-on-sel to
++ be set, otherwise the driver will fail at probe. This is required if the
++ OEM does not use pin strapping to set this mode and prefers to set it
++ using SW regs. The pin strappings related to LED open-drain mode are
++ B68 on the QCA832x and B49 on the QCA833x.
++
++ mdio:
++ type: object
++ description: Qca8k switch have an internal mdio to access switch port.
++ If this is not present, the legacy mapping is used and the
++ internal mdio access is used.
++ With the legacy mapping the reg corresponding to the internal
++ mdio is the switch reg with an offset of -1.
++
++ properties:
++ '#address-cells':
++ const: 1
++ '#size-cells':
++ const: 0
++
++ patternProperties:
++ "^(ethernet-)?phy@[0-4]$":
++ type: object
++
++ allOf:
++ - $ref: "http://devicetree.org/schemas/net/mdio.yaml#"
++
++ properties:
++ reg:
++ maxItems: 1
++
++ required:
++ - reg
++
++patternProperties:
++ "^(ethernet-)?ports$":
++ type: object
++ properties:
++ '#address-cells':
++ const: 1
++ '#size-cells':
++ const: 0
++
++ patternProperties:
++ "^(ethernet-)?port@[0-6]$":
++ type: object
++ description: Ethernet switch ports
++
++ properties:
++ reg:
++ description: Port number
++
++ label:
++ description:
++ Describes the label associated with this port, which will become
++ the netdev name
++ $ref: /schemas/types.yaml#/definitions/string
++
++ link:
++ description:
++ Should be a list of phandles to other switch's DSA port. This
++ port is used as the outgoing port towards the phandle ports. The
++ full routing information must be given, not just the one hop
++ routes to neighbouring switches
++ $ref: /schemas/types.yaml#/definitions/phandle-array
++
++ ethernet:
++ description:
++ Should be a phandle to a valid Ethernet device node. This host
++ device is what the switch port is connected to
++ $ref: /schemas/types.yaml#/definitions/phandle
++
++ phy-handle: true
++
++ phy-mode: true
++
++ fixed-link: true
++
++ mac-address: true
++
++ sfp: true
++
++ qca,sgmii-rxclk-falling-edge:
++ $ref: /schemas/types.yaml#/definitions/flag
++ description:
++ Set the receive clock phase to falling edge. Mostly commonly used on
++ the QCA8327 with CPU port 0 set to SGMII.
++
++ qca,sgmii-txclk-falling-edge:
++ $ref: /schemas/types.yaml#/definitions/flag
++ description:
++ Set the transmit clock phase to falling edge.
++
++ qca,sgmii-enable-pll:
++ $ref: /schemas/types.yaml#/definitions/flag
++ description:
++ For SGMII CPU port, explicitly enable PLL, TX and RX chain along with
++ Signal Detection. On the QCA8327 this should not be enabled, otherwise
++ the SGMII port will not initialize. When used on the QCA8337, revision 3
++ or greater, a warning will be displayed. When the CPU port is set to
++ SGMII on the QCA8337, it is advised to set this unless a communication
++ issue is observed.
++
++ required:
++ - reg
++
++ additionalProperties: false
++
++oneOf:
++ - required:
++ - ports
++ - required:
++ - ethernet-ports
++
++required:
++ - compatible
++ - reg
++
++additionalProperties: true
++
++examples:
++ - |
++ #include <dt-bindings/gpio/gpio.h>
++
++ mdio {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ external_phy_port1: ethernet-phy@0 {
++ reg = <0>;
++ };
++
++ external_phy_port2: ethernet-phy@1 {
++ reg = <1>;
++ };
++
++ external_phy_port3: ethernet-phy@2 {
++ reg = <2>;
++ };
++
++ external_phy_port4: ethernet-phy@3 {
++ reg = <3>;
++ };
++
++ external_phy_port5: ethernet-phy@4 {
++ reg = <4>;
++ };
++
++ switch@10 {
++ compatible = "qca,qca8337";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reset-gpios = <&gpio 42 GPIO_ACTIVE_LOW>;
++ reg = <0x10>;
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ reg = <0>;
++ label = "cpu";
++ ethernet = <&gmac1>;
++ phy-mode = "rgmii";
++
++ fixed-link {
++ speed = <1000>;
++ full-duplex;
++ };
++ };
++
++ port@1 {
++ reg = <1>;
++ label = "lan1";
++ phy-handle = <&external_phy_port1>;
++ };
++
++ port@2 {
++ reg = <2>;
++ label = "lan2";
++ phy-handle = <&external_phy_port2>;
++ };
++
++ port@3 {
++ reg = <3>;
++ label = "lan3";
++ phy-handle = <&external_phy_port3>;
++ };
++
++ port@4 {
++ reg = <4>;
++ label = "lan4";
++ phy-handle = <&external_phy_port4>;
++ };
++
++ port@5 {
++ reg = <5>;
++ label = "wan";
++ phy-handle = <&external_phy_port5>;
++ };
++ };
++ };
++ };
++ - |
++ #include <dt-bindings/gpio/gpio.h>
++
++ mdio {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ switch@10 {
++ compatible = "qca,qca8337";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reset-gpios = <&gpio 42 GPIO_ACTIVE_LOW>;
++ reg = <0x10>;
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ reg = <0>;
++ label = "cpu";
++ ethernet = <&gmac1>;
++ phy-mode = "rgmii";
++
++ fixed-link {
++ speed = <1000>;
++ full-duplex;
++ };
++ };
++
++ port@1 {
++ reg = <1>;
++ label = "lan1";
++ phy-mode = "internal";
++ phy-handle = <&internal_phy_port1>;
++ };
++
++ port@2 {
++ reg = <2>;
++ label = "lan2";
++ phy-mode = "internal";
++ phy-handle = <&internal_phy_port2>;
++ };
++
++ port@3 {
++ reg = <3>;
++ label = "lan3";
++ phy-mode = "internal";
++ phy-handle = <&internal_phy_port3>;
++ };
++
++ port@4 {
++ reg = <4>;
++ label = "lan4";
++ phy-mode = "internal";
++ phy-handle = <&internal_phy_port4>;
++ };
++
++ port@5 {
++ reg = <5>;
++ label = "wan";
++ phy-mode = "internal";
++ phy-handle = <&internal_phy_port5>;
++ };
++
++ port@6 {
++ reg = <0>;
++ label = "cpu";
++ ethernet = <&gmac1>;
++ phy-mode = "sgmii";
++
++ qca,sgmii-rxclk-falling-edge;
++
++ fixed-link {
++ speed = <1000>;
++ full-duplex;
++ };
++ };
++ };
++
++ mdio {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ internal_phy_port1: ethernet-phy@0 {
++ reg = <0>;
++ };
++
++ internal_phy_port2: ethernet-phy@1 {
++ reg = <1>;
++ };
++
++ internal_phy_port3: ethernet-phy@2 {
++ reg = <2>;
++ };
++
++ internal_phy_port4: ethernet-phy@3 {
++ reg = <3>;
++ };
++
++ internal_phy_port5: ethernet-phy@4 {
++ reg = <4>;
++ };
++ };
++ };
++ };