linux-mips.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/5] add dsa switch support for ar9331
@ 2019-10-22  5:57 Oleksij Rempel
  2019-10-22  5:57 ` [PATCH v4 1/5] net: ag71xx: port to phylink Oleksij Rempel
                   ` (4 more replies)
  0 siblings, 5 replies; 17+ messages in thread
From: Oleksij Rempel @ 2019-10-22  5:57 UTC (permalink / raw)
  To: Andrew Lunn, Chris Snook, Florian Fainelli, James Hogan,
	Jay Cliburn, Mark Rutland, Paul Burton, Ralf Baechle,
	Rob Herring, Vivien Didelot
  Cc: Oleksij Rempel, Pengutronix Kernel Team, David S. Miller, netdev,
	linux-kernel, devicetree, linux-mips, Russell King

changes v4:
- ag71xx: ag71xx_mac_validate fix always false comparison (&& -> ||)
- tag_ar9331: use skb_pull_rcsum() instead of skb_pull().
- tag_ar9331: drop skb_set_mac_header()

changes v3:
- ag71xx: ag71xx_mac_config: ignore MLO_AN_INBAND mode. It is not
  supported by HW and SW.
- ag71xx: ag71xx_mac_validate: return all supported bits on
  PHY_INTERFACE_MODE_NA

changes v2:
- move Atheros AR9331 TAG format to separate patch
- use netdev_warn_once in the tag driver to reduce potential message spam
- typo fixes
- reorder tag driver alphabetically 
- configure switch to maximal frame size
- use mdiobus_read/write
- fail if mdio sub node is not found
- add comment for post reset state
- remove deprecated comment about device id
- remove phy-handle option for node with fixed-link
- ag71xx: set 1G support only for GMII mode

This patch series provides dsa switch support for Atheros ar9331 WiSoC.
As side effect ag71xx needed to be ported to phylink to make the switch
driver (as well phylink based) work properly.

Oleksij Rempel (5):
  net: ag71xx: port to phylink
  dt-bindings: net: dsa: qca,ar9331 switch documentation
  MIPS: ath79: ar9331: add ar9331-switch node
  net: dsa: add support for Atheros AR9331 TAG format
  net: dsa: add support for Atheros AR9331 build-in switch

 .../devicetree/bindings/net/dsa/ar9331.txt    | 148 ++++
 arch/mips/boot/dts/qca/ar9331.dtsi            | 127 ++-
 arch/mips/boot/dts/qca/ar9331_dpt_module.dts  |  13 +
 drivers/net/dsa/Kconfig                       |   2 +
 drivers/net/dsa/Makefile                      |   1 +
 drivers/net/dsa/qca/Kconfig                   |  11 +
 drivers/net/dsa/qca/Makefile                  |   2 +
 drivers/net/dsa/qca/ar9331.c                  | 823 ++++++++++++++++++
 drivers/net/ethernet/atheros/Kconfig          |   2 +-
 drivers/net/ethernet/atheros/ag71xx.c         | 146 ++--
 include/net/dsa.h                             |   2 +
 net/dsa/Kconfig                               |   6 +
 net/dsa/Makefile                              |   1 +
 net/dsa/tag_ar9331.c                          |  96 ++
 14 files changed, 1320 insertions(+), 60 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/net/dsa/ar9331.txt
 create mode 100644 drivers/net/dsa/qca/Kconfig
 create mode 100644 drivers/net/dsa/qca/Makefile
 create mode 100644 drivers/net/dsa/qca/ar9331.c
 create mode 100644 net/dsa/tag_ar9331.c

-- 
2.23.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v4 1/5] net: ag71xx: port to phylink
  2019-10-22  5:57 [PATCH v4 0/5] add dsa switch support for ar9331 Oleksij Rempel
@ 2019-10-22  5:57 ` Oleksij Rempel
  2019-10-22  5:57 ` [PATCH v4 2/5] dt-bindings: net: dsa: qca,ar9331 switch documentation Oleksij Rempel
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 17+ messages in thread
From: Oleksij Rempel @ 2019-10-22  5:57 UTC (permalink / raw)
  To: Andrew Lunn, Chris Snook, Florian Fainelli, James Hogan,
	Jay Cliburn, Mark Rutland, Paul Burton, Ralf Baechle,
	Rob Herring, Vivien Didelot
  Cc: Oleksij Rempel, Pengutronix Kernel Team, David S. Miller, netdev,
	linux-kernel, devicetree, linux-mips, Russell King

The port to phylink was done as close as possible to initial
functionality.
Theoretically this HW can support flow control, practically seems to be not
enough to just enable it. So, more work should be done.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 drivers/net/ethernet/atheros/Kconfig  |   2 +-
 drivers/net/ethernet/atheros/ag71xx.c | 146 ++++++++++++++++----------
 2 files changed, 89 insertions(+), 59 deletions(-)

diff --git a/drivers/net/ethernet/atheros/Kconfig b/drivers/net/ethernet/atheros/Kconfig
index 0058051ba925..2720bde5034e 100644
--- a/drivers/net/ethernet/atheros/Kconfig
+++ b/drivers/net/ethernet/atheros/Kconfig
@@ -20,7 +20,7 @@ if NET_VENDOR_ATHEROS
 config AG71XX
 	tristate "Atheros AR7XXX/AR9XXX built-in ethernet mac support"
 	depends on ATH79
-	select PHYLIB
+	select PHYLINK
 	help
 	  If you wish to compile a kernel for AR7XXX/91XXX and enable
 	  ethernet support, then you should always answer Y to this.
diff --git a/drivers/net/ethernet/atheros/ag71xx.c b/drivers/net/ethernet/atheros/ag71xx.c
index 1b1a09095c0d..9d766d73a89b 100644
--- a/drivers/net/ethernet/atheros/ag71xx.c
+++ b/drivers/net/ethernet/atheros/ag71xx.c
@@ -32,6 +32,7 @@
 #include <linux/of_mdio.h>
 #include <linux/of_net.h>
 #include <linux/of_platform.h>
+#include <linux/phylink.h>
 #include <linux/regmap.h>
 #include <linux/reset.h>
 #include <linux/clk.h>
@@ -314,6 +315,8 @@ struct ag71xx {
 	dma_addr_t stop_desc_dma;
 
 	int phy_if_mode;
+	struct phylink *phylink;
+	struct phylink_config phylink_config;
 
 	struct delayed_work restart_work;
 	struct timer_list oom_timer;
@@ -845,24 +848,23 @@ static void ag71xx_hw_start(struct ag71xx *ag)
 	netif_wake_queue(ag->ndev);
 }
 
-static void ag71xx_link_adjust(struct ag71xx *ag, bool update)
+static void ag71xx_mac_config(struct phylink_config *config, unsigned int mode,
+			      const struct phylink_link_state *state)
 {
-	struct phy_device *phydev = ag->ndev->phydev;
+	struct ag71xx *ag = netdev_priv(to_net_dev(config->dev));
 	u32 cfg2;
 	u32 ifctl;
 	u32 fifo5;
 
-	if (!phydev->link && update) {
-		ag71xx_hw_stop(ag);
+	if (phylink_autoneg_inband(mode))
 		return;
-	}
 
 	if (!ag71xx_is(ag, AR7100) && !ag71xx_is(ag, AR9130))
 		ag71xx_fast_reset(ag);
 
 	cfg2 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG2);
 	cfg2 &= ~(MAC_CFG2_IF_1000 | MAC_CFG2_IF_10_100 | MAC_CFG2_FDX);
-	cfg2 |= (phydev->duplex) ? MAC_CFG2_FDX : 0;
+	cfg2 |= (state->duplex) ? MAC_CFG2_FDX : 0;
 
 	ifctl = ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL);
 	ifctl &= ~(MAC_IFCTL_SPEED);
@@ -870,7 +872,7 @@ static void ag71xx_link_adjust(struct ag71xx *ag, bool update)
 	fifo5 = ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5);
 	fifo5 &= ~FIFO_CFG5_BM;
 
-	switch (phydev->speed) {
+	switch (state->speed) {
 	case SPEED_1000:
 		cfg2 |= MAC_CFG2_IF_1000;
 		fifo5 |= FIFO_CFG5_BM;
@@ -883,7 +885,6 @@ static void ag71xx_link_adjust(struct ag71xx *ag, bool update)
 		cfg2 |= MAC_CFG2_IF_10_100;
 		break;
 	default:
-		WARN(1, "not supported speed %i\n", phydev->speed);
 		return;
 	}
 
@@ -897,58 +898,79 @@ static void ag71xx_link_adjust(struct ag71xx *ag, bool update)
 	ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2);
 	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5);
 	ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl);
-
-	ag71xx_hw_start(ag);
-
-	if (update)
-		phy_print_status(phydev);
 }
 
-static void ag71xx_phy_link_adjust(struct net_device *ndev)
+static void ag71xx_mac_validate(struct phylink_config *config,
+			    unsigned long *supported,
+			    struct phylink_link_state *state)
 {
-	struct ag71xx *ag = netdev_priv(ndev);
+	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+
+	if (state->interface != PHY_INTERFACE_MODE_NA &&
+	    state->interface != PHY_INTERFACE_MODE_GMII &&
+	    state->interface != PHY_INTERFACE_MODE_MII) {
+		bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+		return;
+	}
+
+	phylink_set(mask, MII);
+
+	/* flow control is not supported */
+
+	phylink_set(mask, 10baseT_Half);
+	phylink_set(mask, 10baseT_Full);
+	phylink_set(mask, 100baseT_Half);
+	phylink_set(mask, 100baseT_Full);
 
-	ag71xx_link_adjust(ag, true);
+	if (state->interface == PHY_INTERFACE_MODE_NA ||
+	    state->interface == PHY_INTERFACE_MODE_GMII) {
+		phylink_set(mask, 1000baseT_Full);
+		phylink_set(mask, 1000baseX_Full);
+	}
+
+	bitmap_and(supported, supported, mask,
+		   __ETHTOOL_LINK_MODE_MASK_NBITS);
+	bitmap_and(state->advertising, state->advertising, mask,
+		   __ETHTOOL_LINK_MODE_MASK_NBITS);
 }
 
-static int ag71xx_phy_connect(struct ag71xx *ag)
+static void ag71xx_mac_link_down(struct phylink_config *config,
+				 unsigned int mode, phy_interface_t interface)
 {
-	struct device_node *np = ag->pdev->dev.of_node;
-	struct net_device *ndev = ag->ndev;
-	struct device_node *phy_node;
-	struct phy_device *phydev;
-	int ret;
+	struct ag71xx *ag = netdev_priv(to_net_dev(config->dev));
 
-	if (of_phy_is_fixed_link(np)) {
-		ret = of_phy_register_fixed_link(np);
-		if (ret < 0) {
-			netif_err(ag, probe, ndev, "Failed to register fixed PHY link: %d\n",
-				  ret);
-			return ret;
-		}
+	ag71xx_hw_stop(ag);
+}
 
-		phy_node = of_node_get(np);
-	} else {
-		phy_node = of_parse_phandle(np, "phy-handle", 0);
-	}
+static void ag71xx_mac_link_up(struct phylink_config *config, unsigned int mode,
+			       phy_interface_t interface,
+			       struct phy_device *phy)
+{
+	struct ag71xx *ag = netdev_priv(to_net_dev(config->dev));
 
-	if (!phy_node) {
-		netif_err(ag, probe, ndev, "Could not find valid phy node\n");
-		return -ENODEV;
-	}
+	ag71xx_hw_start(ag);
+}
 
-	phydev = of_phy_connect(ag->ndev, phy_node, ag71xx_phy_link_adjust,
-				0, ag->phy_if_mode);
+static const struct phylink_mac_ops ag71xx_phylink_mac_ops = {
+	.validate = ag71xx_mac_validate,
+	.mac_config = ag71xx_mac_config,
+	.mac_link_down = ag71xx_mac_link_down,
+	.mac_link_up = ag71xx_mac_link_up,
+};
 
-	of_node_put(phy_node);
+static int ag71xx_phy_setup(struct ag71xx *ag)
+{
+	struct phylink *phylink;
 
-	if (!phydev) {
-		netif_err(ag, probe, ndev, "Could not connect to PHY device\n");
-		return -ENODEV;
-	}
+	ag->phylink_config.dev = &ag->ndev->dev;
+	ag->phylink_config.type = PHYLINK_NETDEV;
 
-	phy_attached_info(phydev);
+	phylink = phylink_create(&ag->phylink_config, ag->pdev->dev.fwnode,
+				 ag->phy_if_mode, &ag71xx_phylink_mac_ops);
+	if (IS_ERR(phylink))
+		return PTR_ERR(phylink);
 
+	ag->phylink = phylink;
 	return 0;
 }
 
@@ -1239,6 +1261,13 @@ static int ag71xx_open(struct net_device *ndev)
 	unsigned int max_frame_len;
 	int ret;
 
+	ret = phylink_of_phy_connect(ag->phylink, ag->pdev->dev.of_node, 0);
+	if (ret) {
+		netif_err(ag, link, ndev, "phylink_of_phy_connect filed with err: %i\n",
+			  ret);
+		goto err;
+	}
+
 	max_frame_len = ag71xx_max_frame_len(ndev->mtu);
 	ag->rx_buf_size =
 		SKB_DATA_ALIGN(max_frame_len + NET_SKB_PAD + NET_IP_ALIGN);
@@ -1251,11 +1280,7 @@ static int ag71xx_open(struct net_device *ndev)
 	if (ret)
 		goto err;
 
-	ret = ag71xx_phy_connect(ag);
-	if (ret)
-		goto err;
-
-	phy_start(ndev->phydev);
+	phylink_start(ag->phylink);
 
 	return 0;
 
@@ -1268,8 +1293,7 @@ static int ag71xx_stop(struct net_device *ndev)
 {
 	struct ag71xx *ag = netdev_priv(ndev);
 
-	phy_stop(ndev->phydev);
-	phy_disconnect(ndev->phydev);
+	phylink_stop(ag->phylink);
 	ag71xx_hw_disable(ag);
 
 	return 0;
@@ -1396,10 +1420,9 @@ static netdev_tx_t ag71xx_hard_start_xmit(struct sk_buff *skb,
 
 static int ag71xx_do_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
 {
-	if (!ndev->phydev)
-		return -EINVAL;
+	struct ag71xx *ag = netdev_priv(ndev);
 
-	return phy_mii_ioctl(ndev->phydev, ifr, cmd);
+	return phylink_mii_ioctl(ag->phylink, ifr, cmd);
 }
 
 static void ag71xx_oom_timer_handler(struct timer_list *t)
@@ -1422,13 +1445,14 @@ static void ag71xx_restart_work_func(struct work_struct *work)
 {
 	struct ag71xx *ag = container_of(work, struct ag71xx,
 					 restart_work.work);
-	struct net_device *ndev = ag->ndev;
 
 	rtnl_lock();
 	ag71xx_hw_disable(ag);
 	ag71xx_hw_enable(ag);
-	if (ndev->phydev->link)
-		ag71xx_link_adjust(ag, false);
+
+	phylink_stop(ag->phylink);
+	phylink_start(ag->phylink);
+
 	rtnl_unlock();
 }
 
@@ -1769,6 +1793,12 @@ static int ag71xx_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, ndev);
 
+	err = ag71xx_phy_setup(ag);
+	if (err) {
+		netif_err(ag, probe, ndev, "failed to setup phy (%d)\n", err);
+		goto err_mdio_remove;
+	}
+
 	err = register_netdev(ndev);
 	if (err) {
 		netif_err(ag, probe, ndev, "unable to register net device\n");
-- 
2.23.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v4 2/5] dt-bindings: net: dsa: qca,ar9331 switch documentation
  2019-10-22  5:57 [PATCH v4 0/5] add dsa switch support for ar9331 Oleksij Rempel
  2019-10-22  5:57 ` [PATCH v4 1/5] net: ag71xx: port to phylink Oleksij Rempel
@ 2019-10-22  5:57 ` Oleksij Rempel
  2019-10-23  0:35   ` Andrew Lunn
  2019-10-22  5:57 ` [PATCH v4 3/5] MIPS: ath79: ar9331: add ar9331-switch node Oleksij Rempel
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 17+ messages in thread
From: Oleksij Rempel @ 2019-10-22  5:57 UTC (permalink / raw)
  To: Andrew Lunn, Chris Snook, Florian Fainelli, James Hogan,
	Jay Cliburn, Mark Rutland, Paul Burton, Ralf Baechle,
	Rob Herring, Vivien Didelot
  Cc: Oleksij Rempel, Pengutronix Kernel Team, David S. Miller, netdev,
	linux-kernel, devicetree, linux-mips, Russell King

Atheros AR9331 has built-in 5 port switch. The switch can be configured
to use all 5 or 4 ports. One of built-in PHYs can be used by first built-in
ethernet controller or to be used directly by the switch over second ethernet
controller.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 .../devicetree/bindings/net/dsa/ar9331.txt    | 148 ++++++++++++++++++
 1 file changed, 148 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/dsa/ar9331.txt

diff --git a/Documentation/devicetree/bindings/net/dsa/ar9331.txt b/Documentation/devicetree/bindings/net/dsa/ar9331.txt
new file mode 100644
index 000000000000..40a1f6e1f85f
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/dsa/ar9331.txt
@@ -0,0 +1,148 @@
+Atheros AR9331 built-in switch
+=============================
+
+It is a switch built-in to Atheros AR9331 WiSoC and addressable over internal
+MDIO bus. All PHYs are build-in as well. 
+
+Required properties:
+
+ - compatible: should be: "qca,ar9331-switch" 
+ - reg: Address on the MII bus for the switch.
+ - resets : Must contain an entry for each entry in reset-names.
+ - reset-names : Must include the following entries: "switch"
+ - interrupt-parent: Phandle to the parent interrupt controller
+ - interrupts: IRQ line for the switch
+ - interrupt-controller: Indicates the switch is itself an interrupt
+   controller. This is used for the PHY interrupts.
+ - #interrupt-cells: must be 1
+ - mdio: Container of PHY and devices on the switches MDIO bus.
+
+See Documentation/devicetree/bindings/net/dsa/dsa.txt for a list of additional
+required and optional properties.
+Examples:
+
+eth0: ethernet@19000000 {
+	compatible = "qca,ar9330-eth";
+	reg = <0x19000000 0x200>;
+	interrupts = <4>;
+
+	resets = <&rst 9>, <&rst 22>;
+	reset-names = "mac", "mdio";
+	clocks = <&pll ATH79_CLK_AHB>, <&pll ATH79_CLK_AHB>;
+	clock-names = "eth", "mdio";
+
+	phy-mode = "mii";
+	phy-handle = <&phy_port4>;
+};
+
+eth1: ethernet@1a000000 {
+	compatible = "qca,ar9330-eth";
+	reg = <0x1a000000 0x200>;
+	interrupts = <5>;
+	resets = <&rst 13>, <&rst 23>;
+	reset-names = "mac", "mdio";
+	clocks = <&pll ATH79_CLK_AHB>, <&pll ATH79_CLK_AHB>;
+	clock-names = "eth", "mdio";
+
+	phy-mode = "gmii";
+
+	fixed-link {
+		speed = <1000>;
+		full-duplex;
+	};
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		switch10: switch@10 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			compatible = "qca,ar9331-switch";
+			reg = <0x10>;
+			resets = <&rst 8>;
+			reset-names = "switch";
+
+			interrupt-parent = <&miscintc>;
+			interrupts = <12>;
+
+			interrupt-controller;
+			#interrupt-cells = <1>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				switch_port0: port@0 {
+					reg = <0x0>;
+					label = "cpu";
+					ethernet = <&eth1>;
+
+					phy-mode = "gmii";
+
+					fixed-link {
+						speed = <1000>;
+						full-duplex;
+					};
+				};
+
+				switch_port1: port@1 {
+					reg = <0x1>;
+					phy-handle = <&phy_port0>;
+					phy-mode = "internal";
+				};
+
+				switch_port2: port@2 {
+					reg = <0x2>;
+					phy-handle = <&phy_port1>;
+					phy-mode = "internal";
+				};
+
+				switch_port3: port@3 {
+					reg = <0x3>;
+					phy-handle = <&phy_port2>;
+					phy-mode = "internal";
+				};
+
+				switch_port4: port@4 {
+					reg = <0x4>;
+					phy-handle = <&phy_port3>;
+					phy-mode = "internal";
+				};
+			};
+
+			mdio {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				interrupt-parent = <&switch10>;
+
+				phy_port0: phy@0 {
+					reg = <0x0>;
+					interrupts = <0>;
+				};
+
+				phy_port1: phy@1 {
+					reg = <0x1>;
+					interrupts = <0>;
+				};
+
+				phy_port2: phy@2 {
+					reg = <0x2>;
+					interrupts = <0>;
+				};
+
+				phy_port3: phy@3 {
+					reg = <0x3>;
+					interrupts = <0>;
+				};
+
+				phy_port4: phy@4 {
+					reg = <0x4>;
+					interrupts = <0>;
+				};
+			};
+		};
+	};
+};
-- 
2.23.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v4 3/5] MIPS: ath79: ar9331: add ar9331-switch node
  2019-10-22  5:57 [PATCH v4 0/5] add dsa switch support for ar9331 Oleksij Rempel
  2019-10-22  5:57 ` [PATCH v4 1/5] net: ag71xx: port to phylink Oleksij Rempel
  2019-10-22  5:57 ` [PATCH v4 2/5] dt-bindings: net: dsa: qca,ar9331 switch documentation Oleksij Rempel
@ 2019-10-22  5:57 ` Oleksij Rempel
  2019-10-22  5:57 ` [PATCH v4 4/5] net: dsa: add support for Atheros AR9331 TAG format Oleksij Rempel
  2019-10-22  5:57 ` [PATCH v4 5/5] net: dsa: add support for Atheros AR9331 build-in switch Oleksij Rempel
  4 siblings, 0 replies; 17+ messages in thread
From: Oleksij Rempel @ 2019-10-22  5:57 UTC (permalink / raw)
  To: Andrew Lunn, Chris Snook, Florian Fainelli, James Hogan,
	Jay Cliburn, Mark Rutland, Paul Burton, Ralf Baechle,
	Rob Herring, Vivien Didelot
  Cc: Oleksij Rempel, Pengutronix Kernel Team, David S. Miller, netdev,
	linux-kernel, devicetree, linux-mips, Russell King

Add switch node supported by dsa ar9331 driver.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 arch/mips/boot/dts/qca/ar9331.dtsi           | 127 ++++++++++++++++++-
 arch/mips/boot/dts/qca/ar9331_dpt_module.dts |  13 ++
 2 files changed, 139 insertions(+), 1 deletion(-)

diff --git a/arch/mips/boot/dts/qca/ar9331.dtsi b/arch/mips/boot/dts/qca/ar9331.dtsi
index e0f409dd6acf..84a177c0d053 100644
--- a/arch/mips/boot/dts/qca/ar9331.dtsi
+++ b/arch/mips/boot/dts/qca/ar9331.dtsi
@@ -158,6 +158,9 @@
 			clocks = <&pll ATH79_CLK_AHB>, <&pll ATH79_CLK_AHB>;
 			clock-names = "eth", "mdio";
 
+			phy-mode = "mii";
+			phy-handle = <&phy_port4>;
+
 			status = "disabled";
 		};
 
@@ -165,13 +168,135 @@
 			compatible = "qca,ar9330-eth";
 			reg = <0x1a000000 0x200>;
 			interrupts = <5>;
-
 			resets = <&rst 13>, <&rst 23>;
 			reset-names = "mac", "mdio";
 			clocks = <&pll ATH79_CLK_AHB>, <&pll ATH79_CLK_AHB>;
 			clock-names = "eth", "mdio";
 
+			phy-mode = "gmii";
+
 			status = "disabled";
+
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+
+			mdio {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				switch10: switch@10 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					compatible = "qca,ar9331-switch";
+					reg = <0x10>;
+					resets = <&rst 8>;
+					reset-names = "switch";
+
+					interrupt-parent = <&miscintc>;
+					interrupts = <12>;
+
+					interrupt-controller;
+					#interrupt-cells = <1>;
+
+					ports {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						switch_port0: port@0 {
+							reg = <0x0>;
+							label = "cpu";
+							ethernet = <&eth1>;
+
+							phy-mode = "gmii";
+
+							fixed-link {
+								speed = <1000>;
+								full-duplex;
+							};
+						};
+
+						switch_port1: port@1 {
+							reg = <0x1>;
+							phy-handle = <&phy_port0>;
+							phy-mode = "internal";
+
+							status = "disabled";
+						};
+
+						switch_port2: port@2 {
+							reg = <0x2>;
+							phy-handle = <&phy_port1>;
+							phy-mode = "internal";
+
+							status = "disabled";
+						};
+
+						switch_port3: port@3 {
+							reg = <0x3>;
+							phy-handle = <&phy_port2>;
+							phy-mode = "internal";
+
+							status = "disabled";
+						};
+
+						switch_port4: port@4 {
+							reg = <0x4>;
+							phy-handle = <&phy_port3>;
+							phy-mode = "internal";
+
+							status = "disabled";
+						};
+
+						switch_port5: port@5 {
+							reg = <0x5>;
+							phy-handle = <&phy_port4>;
+							phy-mode = "internal";
+
+							status = "disabled";
+						};
+					};
+
+					mdio {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						interrupt-parent = <&switch10>;
+
+						phy_port0: phy@0 {
+							reg = <0x0>;
+							interrupts = <0>;
+							status = "disabled";
+						};
+
+						phy_port1: phy@1 {
+							reg = <0x1>;
+							interrupts = <0>;
+							status = "disabled";
+						};
+
+						phy_port2: phy@2 {
+							reg = <0x2>;
+							interrupts = <0>;
+							status = "disabled";
+						};
+
+						phy_port3: phy@3 {
+							reg = <0x3>;
+							interrupts = <0>;
+							status = "disabled";
+						};
+
+						phy_port4: phy@4 {
+							reg = <0x4>;
+							interrupts = <0>;
+							status = "disabled";
+						};
+					};
+				};
+			};
 		};
 
 		usb: usb@1b000100 {
diff --git a/arch/mips/boot/dts/qca/ar9331_dpt_module.dts b/arch/mips/boot/dts/qca/ar9331_dpt_module.dts
index 77bab823eb3b..0f2b20044834 100644
--- a/arch/mips/boot/dts/qca/ar9331_dpt_module.dts
+++ b/arch/mips/boot/dts/qca/ar9331_dpt_module.dts
@@ -84,3 +84,16 @@
 &eth1 {
 	status = "okay";
 };
+
+&switch_port1 {
+	label = "lan0";
+	status = "okay";
+};
+
+&phy_port0 {
+	status = "okay";
+};
+
+&phy_port4 {
+	status = "okay";
+};
-- 
2.23.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v4 4/5] net: dsa: add support for Atheros AR9331 TAG format
  2019-10-22  5:57 [PATCH v4 0/5] add dsa switch support for ar9331 Oleksij Rempel
                   ` (2 preceding siblings ...)
  2019-10-22  5:57 ` [PATCH v4 3/5] MIPS: ath79: ar9331: add ar9331-switch node Oleksij Rempel
@ 2019-10-22  5:57 ` Oleksij Rempel
  2019-10-22  6:10   ` Randy Dunlap
  2019-10-23  0:37   ` Andrew Lunn
  2019-10-22  5:57 ` [PATCH v4 5/5] net: dsa: add support for Atheros AR9331 build-in switch Oleksij Rempel
  4 siblings, 2 replies; 17+ messages in thread
From: Oleksij Rempel @ 2019-10-22  5:57 UTC (permalink / raw)
  To: Andrew Lunn, Chris Snook, Florian Fainelli, James Hogan,
	Jay Cliburn, Mark Rutland, Paul Burton, Ralf Baechle,
	Rob Herring, Vivien Didelot
  Cc: Oleksij Rempel, Pengutronix Kernel Team, David S. Miller, netdev,
	linux-kernel, devicetree, linux-mips, Russell King

Add support for tag format used in Atheros AR9331 build-in switch.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 include/net/dsa.h    |  2 +
 net/dsa/Kconfig      |  6 +++
 net/dsa/Makefile     |  1 +
 net/dsa/tag_ar9331.c | 96 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 105 insertions(+)
 create mode 100644 net/dsa/tag_ar9331.c

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 541fb514e31d..89a334e68d42 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -42,6 +42,7 @@ struct phylink_link_state;
 #define DSA_TAG_PROTO_8021Q_VALUE		12
 #define DSA_TAG_PROTO_SJA1105_VALUE		13
 #define DSA_TAG_PROTO_KSZ8795_VALUE		14
+#define DSA_TAG_PROTO_AR9331_VALUE		15
 
 enum dsa_tag_protocol {
 	DSA_TAG_PROTO_NONE		= DSA_TAG_PROTO_NONE_VALUE,
@@ -59,6 +60,7 @@ enum dsa_tag_protocol {
 	DSA_TAG_PROTO_8021Q		= DSA_TAG_PROTO_8021Q_VALUE,
 	DSA_TAG_PROTO_SJA1105		= DSA_TAG_PROTO_SJA1105_VALUE,
 	DSA_TAG_PROTO_KSZ8795		= DSA_TAG_PROTO_KSZ8795_VALUE,
+	DSA_TAG_PROTO_AR9331		= DSA_TAG_PROTO_AR9331_VALUE,
 };
 
 struct packet_type;
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index 29e2bd5cc5af..617c9607df5f 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -29,6 +29,12 @@ config NET_DSA_TAG_8021Q
 
 	  Drivers which use these helpers should select this as dependency.
 
+config NET_DSA_TAG_AR9331
+	tristate "Tag driver for Atheros AR9331 SoC with build-in switch"
+	help
+	  Say Y or M if you want to enable support for tagging frames for
+	  the Atheros AR9331 SoC with build-in switch.
+
 config NET_DSA_TAG_BRCM_COMMON
 	tristate
 	default n
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index 2c6d286f0511..6f77bdb5c40c 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -5,6 +5,7 @@ dsa_core-y += dsa.o dsa2.o master.o port.o slave.o switch.o
 
 # tagging formats
 obj-$(CONFIG_NET_DSA_TAG_8021Q) += tag_8021q.o
+obj-$(CONFIG_NET_DSA_TAG_AR9331) += tag_ar9331.o
 obj-$(CONFIG_NET_DSA_TAG_BRCM_COMMON) += tag_brcm.o
 obj-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
 obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
diff --git a/net/dsa/tag_ar9331.c b/net/dsa/tag_ar9331.c
new file mode 100644
index 000000000000..466ffa92a474
--- /dev/null
+++ b/net/dsa/tag_ar9331.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
+ */
+
+
+#include <linux/bitfield.h>
+#include <linux/etherdevice.h>
+
+#include "dsa_priv.h"
+
+#define AR9331_HDR_LEN			2
+#define AR9331_HDR_VERSION		1
+
+#define AR9331_HDR_VERSION_MASK		GENMASK(15, 14)
+#define AR9331_HDR_PRIORITY_MASK	GENMASK(13, 12)
+#define AR9331_HDR_TYPE_MASK		GENMASK(10, 8)
+#define AR9331_HDR_BROADCAST		BIT(7)
+#define AR9331_HDR_FROM_CPU		BIT(6)
+/* AR9331_HDR_RESERVED - not used or may be version field.
+ * According to the AR8216 doc it should 0b10. On AR9331 it is 0b11 on RX path
+ * and should be set to 0b11 to make it work.
+ */
+#define AR9331_HDR_RESERVED_MASK	GENMASK(5, 4)
+#define AR9331_HDR_PORT_NUM_MASK	GENMASK(3, 0)
+
+static struct sk_buff *ar9331_tag_xmit(struct sk_buff *skb,
+				       struct net_device *dev)
+{
+	struct dsa_port *dp = dsa_slave_to_port(dev);
+	__le16 *phdr;
+	u16 hdr;
+
+	if (skb_cow_head(skb, 0) < 0)
+		return NULL;
+
+	phdr = skb_push(skb, AR9331_HDR_LEN);
+
+	hdr = FIELD_PREP(AR9331_HDR_VERSION_MASK, AR9331_HDR_VERSION);
+	hdr |= AR9331_HDR_FROM_CPU | dp->index;
+	/* 0b10 for AR8216 and 0b11 for AR9331 */
+	hdr |= AR9331_HDR_RESERVED_MASK;
+
+	phdr[0] = cpu_to_le16(hdr);
+
+	return skb;
+}
+
+static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb,
+				      struct net_device *ndev,
+				      struct packet_type *pt)
+{
+	u8 ver, port;
+	u16 hdr;
+
+	if (unlikely(!pskb_may_pull(skb, AR9331_HDR_LEN)))
+		return NULL;
+
+	hdr = le16_to_cpu(*(__le16 *)skb_mac_header(skb));
+
+	ver = FIELD_GET(AR9331_HDR_VERSION_MASK, hdr);
+	if (unlikely(ver != AR9331_HDR_VERSION)) {
+		netdev_warn_once(ndev, "%s:%i wrong header version 0x%2x\n",
+				 __func__, __LINE__, hdr);
+		return NULL;
+	}
+
+	if (unlikely(hdr & AR9331_HDR_FROM_CPU)) {
+		netdev_warn_once(ndev, "%s:%i packet should not be from cpu 0x%2x\n",
+				 __func__, __LINE__, hdr);
+		return NULL;
+	}
+
+	skb_pull_rcsum(skb, AR9331_HDR_LEN);
+
+	/* Get source port information */
+	port = FIELD_GET(AR9331_HDR_PORT_NUM_MASK, hdr);
+
+	skb->dev = dsa_master_find_slave(ndev, 0, port);
+	if (!skb->dev)
+		return NULL;
+
+	return skb;
+}
+
+static const struct dsa_device_ops ar9331_netdev_ops = {
+	.name	= "ar9331",
+	.proto	= DSA_TAG_PROTO_AR9331,
+	.xmit	= ar9331_tag_xmit,
+	.rcv	= ar9331_tag_rcv,
+	.overhead = AR9331_HDR_LEN,
+};
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_AR9331);
+module_dsa_tag_driver(ar9331_netdev_ops);
-- 
2.23.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v4 5/5] net: dsa: add support for Atheros AR9331 build-in switch
  2019-10-22  5:57 [PATCH v4 0/5] add dsa switch support for ar9331 Oleksij Rempel
                   ` (3 preceding siblings ...)
  2019-10-22  5:57 ` [PATCH v4 4/5] net: dsa: add support for Atheros AR9331 TAG format Oleksij Rempel
@ 2019-10-22  5:57 ` Oleksij Rempel
  2019-10-22  6:10   ` Randy Dunlap
  2019-10-23  0:58   ` Andrew Lunn
  4 siblings, 2 replies; 17+ messages in thread
From: Oleksij Rempel @ 2019-10-22  5:57 UTC (permalink / raw)
  To: Andrew Lunn, Chris Snook, Florian Fainelli, James Hogan,
	Jay Cliburn, Mark Rutland, Paul Burton, Ralf Baechle,
	Rob Herring, Vivien Didelot
  Cc: Oleksij Rempel, Pengutronix Kernel Team, David S. Miller, netdev,
	linux-kernel, devicetree, linux-mips, Russell King

Provide basic support for Atheros AR9331 build-in switch. So far it
works as port multiplexer without any hardware offloading support.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 drivers/net/dsa/Kconfig      |   2 +
 drivers/net/dsa/Makefile     |   1 +
 drivers/net/dsa/qca/Kconfig  |  11 +
 drivers/net/dsa/qca/Makefile |   2 +
 drivers/net/dsa/qca/ar9331.c | 823 +++++++++++++++++++++++++++++++++++
 5 files changed, 839 insertions(+)
 create mode 100644 drivers/net/dsa/qca/Kconfig
 create mode 100644 drivers/net/dsa/qca/Makefile
 create mode 100644 drivers/net/dsa/qca/ar9331.c

diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index f6232ce8481f..de9610a3dd5c 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -52,6 +52,8 @@ source "drivers/net/dsa/microchip/Kconfig"
 
 source "drivers/net/dsa/mv88e6xxx/Kconfig"
 
+source "drivers/net/dsa/qca/Kconfig"
+
 source "drivers/net/dsa/sja1105/Kconfig"
 
 config NET_DSA_QCA8K
diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
index ae70b79628d6..90e5b1ed69c5 100644
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -20,4 +20,5 @@ obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_SPI) += vitesse-vsc73xx-spi.o
 obj-y				+= b53/
 obj-y				+= microchip/
 obj-y				+= mv88e6xxx/
+obj-y				+= qca/
 obj-y				+= sja1105/
diff --git a/drivers/net/dsa/qca/Kconfig b/drivers/net/dsa/qca/Kconfig
new file mode 100644
index 000000000000..7e4978f46642
--- /dev/null
+++ b/drivers/net/dsa/qca/Kconfig
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config NET_DSA_AR9331
+	tristate "Atheros AR9331 Ethernet switch support"
+	depends on NET_DSA
+	select NET_DSA_TAG_AR9331
+	select REGMAP
+	---help---
+	  This enables support for the Atheros AR9331 build-in Ethernet
+	  switch.
+
+
diff --git a/drivers/net/dsa/qca/Makefile b/drivers/net/dsa/qca/Makefile
new file mode 100644
index 000000000000..274022319066
--- /dev/null
+++ b/drivers/net/dsa/qca/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_NET_DSA_AR9331)	+= ar9331.o
diff --git a/drivers/net/dsa/qca/ar9331.c b/drivers/net/dsa/qca/ar9331.c
new file mode 100644
index 000000000000..299c1a966756
--- /dev/null
+++ b/drivers/net/dsa/qca/ar9331.c
@@ -0,0 +1,823 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2019 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
+
+#include <linux/bitfield.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_mdio.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <net/dsa.h>
+
+#define AR9331_SW_NAME				"ar9331_switch"
+#define AR9331_SW_PORTS				6
+
+/* dummy reg to change page */
+#define AR9331_SW_REG_PAGE			BIT(18)
+
+/* Global Interrupt */
+#define AR9331_SW_REG_GINT			0x10
+#define AR9331_SW_REG_GINT_MASK			0x14
+#define AR9331_SW_GINT_PHY_INT			BIT(2)
+
+#define AR9331_SW_REG_FLOOD_MASK		0x2c
+#define AR9331_SW_FLOOD_MASK_BROAD_TO_CPU	BIT(26)
+
+#define AR9331_SW_REG_GLOBAL_CTRL		0x30
+#define AR9331_SW_GLOBAL_CTRL_MFS_M		GENMASK(13, 0)
+
+#define AR9331_SW_REG_MDIO_CTRL			0x98
+#define AR9331_SW_MDIO_CTRL_BUSY		BIT(31)
+#define AR9331_SW_MDIO_CTRL_MASTER_EN		BIT(30)
+#define AR9331_SW_MDIO_CTRL_CMD_READ		BIT(27)
+#define AR9331_SW_MDIO_CTRL_PHY_ADDR_M		GENMASK(25, 21)
+#define AR9331_SW_MDIO_CTRL_REG_ADDR_M		GENMASK(20, 16)
+#define AR9331_SW_MDIO_CTRL_DATA_M		GENMASK(16, 0)
+
+#define AR9331_SW_REG_PORT_STATUS(_port)	(0x100 + (_port) * 0x100)
+
+/* FLOW_LINK_EN - enable mac flow control config auto-neg with phy.
+ * If not set, mac can be config by software.
+ */
+#define AR9331_SW_PORT_STATUS_FLOW_LINK_EN	BIT(12)
+
+/* LINK_EN - If set, MAC is configured from PHY link status.
+ * If not set, MAC should be configured by software.
+ */
+#define AR9331_SW_PORT_STATUS_LINK_EN		BIT(9)
+#define AR9331_SW_PORT_STATUS_DUPLEX_MODE	BIT(6)
+#define AR9331_SW_PORT_STATUS_RX_FLOW_EN	BIT(5)
+#define AR9331_SW_PORT_STATUS_TX_FLOW_EN	BIT(4)
+#define AR9331_SW_PORT_STATUS_RXMAC		BIT(3)
+#define AR9331_SW_PORT_STATUS_TXMAC		BIT(2)
+#define AR9331_SW_PORT_STATUS_SPEED_M		GENMASK(1, 0)
+#define AR9331_SW_PORT_STATUS_SPEED_1000	2
+#define AR9331_SW_PORT_STATUS_SPEED_100		1
+#define AR9331_SW_PORT_STATUS_SPEED_10		0
+
+#define AR9331_SW_PORT_STATUS_MAC_MASK \
+	(AR9331_SW_PORT_STATUS_TXMAC | AR9331_SW_PORT_STATUS_RXMAC)
+
+#define AR9331_SW_PORT_STATUS_LINK_MASK \
+	(AR9331_SW_PORT_STATUS_LINK_EN | AR9331_SW_PORT_STATUS_FLOW_LINK_EN | \
+	 AR9331_SW_PORT_STATUS_DUPLEX_MODE | \
+	 AR9331_SW_PORT_STATUS_RX_FLOW_EN | AR9331_SW_PORT_STATUS_TX_FLOW_EN | \
+	 AR9331_SW_PORT_STATUS_SPEED_M)
+
+/* Phy bypass mode
+ * ------------------------------------------------------------------------
+ * Bit:   | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |11 |12 |13 |14 |15 |
+ *
+ * real   | start |   OP  | PhyAddr           |  Reg Addr         |  TA   |
+ * atheros| start |   OP  | 2'b00 |PhyAdd[2:0]|  Reg Addr[4:0]    |  TA   |
+ *
+ *
+ * Bit:   |16 |17 |18 |19 |20 |21 |22 |23 |24 |25 |26 |27 |28 |29 |30 |31 |
+ * real   |  Data                                                         |
+ * atheros|  Data                                                         |
+ *
+ * ------------------------------------------------------------------------
+ * Page address mode
+ * ------------------------------------------------------------------------
+ * Bit:   | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |11 |12 |13 |14 |15 |
+ * real   | start |   OP  | PhyAddr           |  Reg Addr         |  TA   |
+ * atheros| start |   OP  | 2'b11 |                          8'b0 |  TA   |
+ *
+ * Bit:   |16 |17 |18 |19 |20 |21 |22 |23 |24 |25 |26 |27 |28 |29 |30 |31 |
+ * real   |  Data                                                         |
+ * atheros|                       | Page [9:0]                            |
+ */
+/* In case of Page Address mode, Bit[18:9] of 32 bit register address should be
+ * written to bits[9:0] of mdio data register.
+ */
+#define AR9331_SW_ADDR_PAGE			GENMASK(18, 9)
+
+/* ------------------------------------------------------------------------
+ * Normal register access mode
+ * ------------------------------------------------------------------------
+ * Bit:   | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |11 |12 |13 |14 |15 |
+ * real   | start |   OP  | PhyAddr           |  Reg Addr         |  TA   |
+ * atheros| start |   OP  | 2'b10 |  low_addr[7:0]                |  TA   |
+ *
+ * Bit:   |16 |17 |18 |19 |20 |21 |22 |23 |24 |25 |26 |27 |28 |29 |30 |31 |
+ * real   |  Data                                                         |
+ * atheros|  Data                                                         |
+ * ------------------------------------------------------------------------
+ */
+#define AR9331_SW_LOW_ADDR_PHY			GENMASK(8, 6)
+#define AR9331_SW_LOW_ADDR_REG			GENMASK(5, 1)
+
+#define AR9331_SW_MDIO_PHY_MODE_M		GENMASK(4, 3)
+#define AR9331_SW_MDIO_PHY_MODE_PAGE		3
+#define AR9331_SW_MDIO_PHY_MODE_REG		2
+#define AR9331_SW_MDIO_PHY_MODE_BYPASS		0
+#define AR9331_SW_MDIO_PHY_ADDR_M		GENMASK(2, 0)
+
+/* Empirical determined values */
+#define AR9331_SW_MDIO_POLL_SLEEP_US		1
+#define AR9331_SW_MDIO_POLL_TIMEOUT_US		20
+
+struct ar9331_sw_priv {
+	struct device *dev;
+	struct dsa_switch *ds;
+	struct dsa_switch_ops ops;
+	struct irq_domain *irqdomain;
+	struct mii_bus *mbus; /* mdio master */
+	struct mii_bus *sbus; /* mdio slave */
+	struct regmap *regmap;
+	struct reset_control *sw_reset;
+};
+
+/* Warning: switch reset will reset last AR9331_SW_MDIO_PHY_MODE_PAGE request
+ * If some kind of optimization is used, the request should be repeated.
+ */
+static int ar9331_sw_reset(struct ar9331_sw_priv *priv)
+{
+	int ret;
+
+	ret = reset_control_assert(priv->sw_reset);
+	if (ret)
+		goto error;
+
+	/* AR9331 doc do not provide any information about proper reset
+	 * sequence. The AR8136 (the closes switch to the AR9331) doc says:
+	 * reset duration should be greater than 10ms. So, let's use this value
+	 * for now.
+	 */
+	usleep_range(10000, 15000);
+	ret = reset_control_deassert(priv->sw_reset);
+	if (ret)
+		goto error;
+	/* There is no information on how long should we wait after reset.
+	 * AR8136 has an EEPROM and there is an Interrupt for EEPROM load
+	 * status. AR9331 has no EEPROM support.
+	 * For now, do not wait. In case AR8136 will be needed, the after
+	 * reset delay can be added as well.
+	 */
+
+	return 0;
+error:
+	dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
+	return ret;
+}
+
+static int ar9331_sw_mbus_write(struct mii_bus *mbus, int port, int regnum,
+				u16 data)
+{
+	struct ar9331_sw_priv *priv = mbus->priv;
+	struct regmap *regmap = priv->regmap;
+	u32 val;
+	int ret;
+
+	ret = regmap_write(regmap, AR9331_SW_REG_MDIO_CTRL,
+			   AR9331_SW_MDIO_CTRL_BUSY |
+			   AR9331_SW_MDIO_CTRL_MASTER_EN |
+			   FIELD_PREP(AR9331_SW_MDIO_CTRL_PHY_ADDR_M, port) |
+			   FIELD_PREP(AR9331_SW_MDIO_CTRL_REG_ADDR_M, regnum) |
+			   FIELD_PREP(AR9331_SW_MDIO_CTRL_DATA_M, data));
+	if (ret)
+		goto error;
+
+	ret = regmap_read_poll_timeout(regmap, AR9331_SW_REG_MDIO_CTRL, val,
+				       !(val & AR9331_SW_MDIO_CTRL_BUSY),
+				       AR9331_SW_MDIO_POLL_SLEEP_US,
+				       AR9331_SW_MDIO_POLL_TIMEOUT_US);
+	if (ret)
+		goto error;
+
+	return 0;
+error:
+	dev_err_ratelimited(priv->dev, "PHY write error: %i\n", ret);
+	return ret;
+}
+
+static int ar9331_sw_mbus_read(struct mii_bus *mbus, int port, int regnum)
+{
+	struct ar9331_sw_priv *priv = mbus->priv;
+	struct regmap *regmap = priv->regmap;
+	u32 val;
+	int ret;
+
+	ret = regmap_write(regmap, AR9331_SW_REG_MDIO_CTRL,
+			   AR9331_SW_MDIO_CTRL_BUSY |
+			   AR9331_SW_MDIO_CTRL_MASTER_EN |
+			   AR9331_SW_MDIO_CTRL_CMD_READ |
+			   FIELD_PREP(AR9331_SW_MDIO_CTRL_PHY_ADDR_M, port) |
+			   FIELD_PREP(AR9331_SW_MDIO_CTRL_REG_ADDR_M, regnum));
+	if (ret)
+		goto error;
+
+	ret = regmap_read_poll_timeout(regmap, AR9331_SW_REG_MDIO_CTRL, val,
+				       !(val & AR9331_SW_MDIO_CTRL_BUSY),
+				       AR9331_SW_MDIO_POLL_SLEEP_US,
+				       AR9331_SW_MDIO_POLL_TIMEOUT_US);
+	if (ret)
+		goto error;
+
+	ret = regmap_read(regmap, AR9331_SW_REG_MDIO_CTRL, &val);
+	if (ret)
+		goto error;
+
+	return FIELD_GET(AR9331_SW_MDIO_CTRL_DATA_M, val);
+
+error:
+	dev_err_ratelimited(priv->dev, "PHY read error: %i\n", ret);
+	return ret;
+}
+
+static int ar9331_sw_mbus_init(struct ar9331_sw_priv *priv)
+{
+	struct device *dev = priv->dev;
+	static struct mii_bus *mbus;
+	struct device_node *np, *mnp;
+	int ret;
+
+	np = dev->of_node;
+
+	mbus = devm_mdiobus_alloc(dev);
+	if (!mbus)
+		return -ENOMEM;
+
+	mbus->name = np->full_name;
+	snprintf(mbus->id, MII_BUS_ID_SIZE, "%pOF", np);
+
+	mbus->read = ar9331_sw_mbus_read;
+	mbus->write = ar9331_sw_mbus_write;
+	mbus->priv = priv;
+	mbus->parent = dev;
+
+	mnp = of_get_child_by_name(np, "mdio");
+	if (!mnp)
+		return -ENODEV;
+
+	ret = of_mdiobus_register(mbus, mnp);
+	of_node_put(mnp);
+	if (ret)
+		return ret;
+
+	priv->mbus = mbus;
+
+	return 0;
+}
+
+static int ar9331_sw_setup(struct dsa_switch *ds)
+{
+	struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv;
+	struct regmap *regmap = priv->regmap;
+	int ret;
+
+	ret = ar9331_sw_reset(priv);
+	if (ret)
+		return ret;
+
+	/* Reset will set proper defaults. CPU - Port0 will be enabled and
+	 * configured. All other ports (ports 1 - 5) are disabled
+	 */
+	ret = ar9331_sw_mbus_init(priv);
+	if (ret)
+		return ret;
+
+	/* Do not drop broadcast frames */
+	ret = regmap_write_bits(regmap, AR9331_SW_REG_FLOOD_MASK,
+				AR9331_SW_FLOOD_MASK_BROAD_TO_CPU,
+				AR9331_SW_FLOOD_MASK_BROAD_TO_CPU);
+	if (ret)
+		goto error;
+
+	/* Set max frame size to the maximum supported value */
+	ret = regmap_write_bits(regmap, AR9331_SW_REG_GLOBAL_CTRL,
+				AR9331_SW_GLOBAL_CTRL_MFS_M,
+				AR9331_SW_GLOBAL_CTRL_MFS_M);
+	if (ret)
+		goto error;
+
+	return 0;
+error:
+	dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
+	return ret;
+}
+
+static int ar9331_sw_port_enable(struct dsa_switch *ds, int port,
+				 struct phy_device *phy)
+{
+	struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv;
+	struct regmap *regmap = priv->regmap;
+	int ret;
+
+	/* nothing to enable. Just set link to initial state */
+	ret = regmap_write(regmap, AR9331_SW_REG_PORT_STATUS(port), 0);
+	if (ret)
+		dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
+
+	return ret;
+}
+
+static void ar9331_sw_port_disable(struct dsa_switch *ds, int port)
+{
+	struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv;
+	struct regmap *regmap = priv->regmap;
+	int ret;
+
+	ret = regmap_write(regmap, AR9331_SW_REG_PORT_STATUS(port), 0);
+	if (ret)
+		dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
+}
+
+static enum dsa_tag_protocol ar9331_sw_get_tag_protocol(struct dsa_switch *ds,
+							int port)
+{
+	return DSA_TAG_PROTO_AR9331;
+}
+
+static void ar9331_sw_phylink_validate(struct dsa_switch *ds, int port,
+				       unsigned long *supported,
+				       struct phylink_link_state *state)
+{
+	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+
+	switch (port) {
+	case 0:
+		if (state->interface != PHY_INTERFACE_MODE_GMII)
+			goto unsupported;
+
+		phylink_set(mask, 1000baseT_Full);
+		phylink_set(mask, 1000baseT_Half);
+		break;
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+		if (state->interface != PHY_INTERFACE_MODE_INTERNAL)
+			goto unsupported;
+		break;
+	default:
+		bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+		dev_err(ds->dev, "Unsupported port: %i\n", port);
+		return;
+	}
+
+	phylink_set_port_modes(mask);
+	phylink_set(mask, Pause);
+	phylink_set(mask, Asym_Pause);
+
+	phylink_set(mask, 10baseT_Half);
+	phylink_set(mask, 10baseT_Full);
+	phylink_set(mask, 100baseT_Half);
+	phylink_set(mask, 100baseT_Full);
+
+	bitmap_and(supported, supported, mask,
+		   __ETHTOOL_LINK_MODE_MASK_NBITS);
+	bitmap_and(state->advertising, state->advertising, mask,
+		   __ETHTOOL_LINK_MODE_MASK_NBITS);
+
+	return;
+
+unsupported:
+	bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+	dev_err(ds->dev, "Unsupported interface: %d, port: %d\n",
+		state->interface, port);
+}
+
+static void ar9331_sw_phylink_mac_config(struct dsa_switch *ds, int port,
+					 unsigned int mode,
+					 const struct phylink_link_state *state)
+{
+	struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv;
+	struct regmap *regmap = priv->regmap;
+	int ret;
+	u32 val;
+
+	switch (state->speed) {
+	case SPEED_1000:
+		val = AR9331_SW_PORT_STATUS_SPEED_1000;
+		break;
+	case SPEED_100:
+		val = AR9331_SW_PORT_STATUS_SPEED_100;
+		break;
+	case SPEED_10:
+		val = AR9331_SW_PORT_STATUS_SPEED_10;
+		break;
+	default:
+		return;
+	}
+
+	if (state->duplex)
+		val |= AR9331_SW_PORT_STATUS_DUPLEX_MODE;
+
+	if (state->pause & MLO_PAUSE_TX)
+		val |= AR9331_SW_PORT_STATUS_TX_FLOW_EN;
+
+	if (state->pause & MLO_PAUSE_RX)
+		val |= AR9331_SW_PORT_STATUS_RX_FLOW_EN;
+
+	ret = regmap_update_bits(regmap, AR9331_SW_REG_PORT_STATUS(port),
+				 AR9331_SW_PORT_STATUS_LINK_MASK, val);
+	if (ret)
+		dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
+}
+
+static void ar9331_sw_phylink_mac_link_down(struct dsa_switch *ds, int port,
+					    unsigned int mode,
+					    phy_interface_t interface)
+{
+	struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv;
+	struct regmap *regmap = priv->regmap;
+	int ret;
+
+	ret = regmap_update_bits(regmap, AR9331_SW_REG_PORT_STATUS(port),
+				 AR9331_SW_PORT_STATUS_MAC_MASK, 0);
+	if (ret)
+		dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
+}
+
+static void ar9331_sw_phylink_mac_link_up(struct dsa_switch *ds, int port,
+					  unsigned int mode,
+					  phy_interface_t interface,
+					  struct phy_device *phydev)
+{
+	struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv;
+	struct regmap *regmap = priv->regmap;
+	int ret;
+
+	ret = regmap_update_bits(regmap, AR9331_SW_REG_PORT_STATUS(port),
+				 AR9331_SW_PORT_STATUS_MAC_MASK,
+				 AR9331_SW_PORT_STATUS_MAC_MASK);
+	if (ret)
+		dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
+}
+
+static const struct dsa_switch_ops ar9331_sw_ops = {
+	.get_tag_protocol = ar9331_sw_get_tag_protocol,
+	.setup = ar9331_sw_setup,
+	.port_enable = ar9331_sw_port_enable,
+	.port_disable = ar9331_sw_port_disable,
+	.phylink_validate	= ar9331_sw_phylink_validate,
+	.phylink_mac_config	= ar9331_sw_phylink_mac_config,
+	.phylink_mac_link_down	= ar9331_sw_phylink_mac_link_down,
+	.phylink_mac_link_up	= ar9331_sw_phylink_mac_link_up,
+};
+
+static irqreturn_t ar9331_sw_irq(int irq, void *data)
+{
+	struct ar9331_sw_priv *priv = data;
+	struct regmap *regmap = priv->regmap;
+	u32 stat;
+	int ret;
+
+	ret = regmap_read(regmap, AR9331_SW_REG_GINT, &stat);
+	if (ret) {
+		dev_err(priv->dev, "can't read interrupt status\n");
+		return IRQ_NONE;
+	}
+
+	if (!stat)
+		return IRQ_NONE;
+
+	if (stat & AR9331_SW_GINT_PHY_INT) {
+		int child_irq;
+
+		child_irq = irq_find_mapping(priv->irqdomain, 0);
+		handle_nested_irq(child_irq);
+	}
+
+	ret = regmap_write(regmap, AR9331_SW_REG_GINT, stat);
+	if (ret) {
+		dev_err(priv->dev, "can't write interrupt status\n");
+		return IRQ_NONE;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void ar9331_sw_mask_irq(struct irq_data *d)
+{
+	struct ar9331_sw_priv *priv = irq_data_get_irq_chip_data(d);
+	struct regmap *regmap = priv->regmap;
+	int ret;
+
+	ret = regmap_update_bits(regmap, AR9331_SW_REG_GINT_MASK,
+				 AR9331_SW_GINT_PHY_INT, 0);
+	if (ret)
+		dev_err(priv->dev, "could not mask IRQ\n");
+}
+
+static void ar9331_sw_unmask_irq(struct irq_data *d)
+{
+	struct ar9331_sw_priv *priv = irq_data_get_irq_chip_data(d);
+	struct regmap *regmap = priv->regmap;
+	int ret;
+
+	ret = regmap_update_bits(regmap, AR9331_SW_REG_GINT_MASK,
+				 AR9331_SW_GINT_PHY_INT,
+				 AR9331_SW_GINT_PHY_INT);
+	if (ret)
+		dev_err(priv->dev, "could not unmask IRQ\n");
+}
+
+static struct irq_chip ar9331_sw_irq_chip = {
+	.name = AR9331_SW_NAME,
+	.irq_mask = ar9331_sw_mask_irq,
+	.irq_unmask = ar9331_sw_unmask_irq,
+};
+
+static int ar9331_sw_irq_map(struct irq_domain *domain, unsigned int irq,
+			     irq_hw_number_t hwirq)
+{
+	irq_set_chip_data(irq, domain->host_data);
+	irq_set_chip_and_handler(irq, &ar9331_sw_irq_chip, handle_simple_irq);
+	irq_set_nested_thread(irq, 1);
+	irq_set_noprobe(irq);
+
+	return 0;
+}
+
+static void ar9331_sw_irq_unmap(struct irq_domain *d, unsigned int irq)
+{
+	irq_set_nested_thread(irq, 0);
+	irq_set_chip_and_handler(irq, NULL, NULL);
+	irq_set_chip_data(irq, NULL);
+}
+
+static const struct irq_domain_ops ar9331_sw_irqdomain_ops = {
+	.map = ar9331_sw_irq_map,
+	.unmap = ar9331_sw_irq_unmap,
+	.xlate = irq_domain_xlate_onecell,
+};
+
+static int ar9331_sw_irq_init(struct ar9331_sw_priv *priv)
+{
+	struct device_node *np = priv->dev->of_node;
+	struct device *dev = priv->dev;
+	int ret, irq;
+
+	irq = of_irq_get(np, 0);
+	if (irq <= 0) {
+		dev_err(dev, "failed to get parent IRQ\n");
+		return irq ? irq : -EINVAL;
+	}
+
+	ret = devm_request_threaded_irq(dev, irq, NULL, ar9331_sw_irq,
+					IRQF_ONESHOT, AR9331_SW_NAME, priv);
+	if (ret) {
+		dev_err(dev, "unable to request irq: %d\n", ret);
+		return ret;
+	}
+
+	priv->irqdomain = irq_domain_add_linear(np, 1, &ar9331_sw_irqdomain_ops,
+						priv);
+	if (!priv->irqdomain) {
+		dev_err(dev, "failed to create IRQ domain\n");
+		return -EINVAL;
+	}
+
+	irq_set_parent(irq_create_mapping(priv->irqdomain, 0), irq);
+
+	return 0;
+}
+
+static int __ar9331_mdio_write(struct mii_bus *sbus, u8 mode, u16 reg, u16 val)
+{
+	u8 r, p;
+
+	p = FIELD_PREP(AR9331_SW_MDIO_PHY_MODE_M, mode) |
+		FIELD_GET(AR9331_SW_LOW_ADDR_PHY, reg);
+	r = FIELD_GET(AR9331_SW_LOW_ADDR_REG, reg);
+
+	return mdiobus_write(sbus, p, r, val);
+}
+
+static int __ar9331_mdio_read(struct mii_bus *sbus, u16 reg)
+{
+	u8 r, p;
+
+	p = FIELD_PREP(AR9331_SW_MDIO_PHY_MODE_M, AR9331_SW_MDIO_PHY_MODE_REG) |
+		FIELD_GET(AR9331_SW_LOW_ADDR_PHY, reg);
+	r = FIELD_GET(AR9331_SW_LOW_ADDR_REG, reg);
+
+	return mdiobus_read(sbus, p, r);
+}
+
+static int ar9331_mdio_read(void *ctx, const void *reg_buf, size_t reg_len,
+			    void *val_buf, size_t val_len)
+{
+	struct ar9331_sw_priv *priv = ctx;
+	struct mii_bus *sbus = priv->sbus;
+	u32 reg = *(u32 *)reg_buf;
+	int ret;
+
+	if (reg == AR9331_SW_REG_PAGE) {
+		/* We cannot read the page selector register from hardware and
+		 * we cache its value in regmap. Return all bits set here,
+		 * that regmap will always write the page on first use.
+		 */
+		*(u32 *)val_buf = GENMASK(9, 0);
+		return 0;
+	}
+
+	ret = __ar9331_mdio_read(sbus, reg);
+	if (ret < 0)
+		goto error;
+
+	*(u32 *)val_buf = ret;
+	ret = __ar9331_mdio_read(sbus, reg + 2);
+	if (ret < 0)
+		goto error;
+
+	*(u32 *)val_buf |= ret << 16;
+
+	return 0;
+error:
+	dev_err_ratelimited(&sbus->dev, "Bus error. Failed to read register.\n");
+	return ret;
+}
+
+static int ar9331_mdio_write(void *ctx, u32 reg, u32 val)
+{
+	struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ctx;
+	struct mii_bus *sbus = priv->sbus;
+	int ret;
+
+	if (reg == AR9331_SW_REG_PAGE) {
+		ret = __ar9331_mdio_write(sbus, AR9331_SW_MDIO_PHY_MODE_PAGE,
+					  0, val);
+		if (ret < 0)
+			goto error;
+
+		return 0;
+	}
+
+	ret = __ar9331_mdio_write(sbus, AR9331_SW_MDIO_PHY_MODE_REG, reg, val);
+	if (ret < 0)
+		goto error;
+
+	ret = __ar9331_mdio_write(sbus, AR9331_SW_MDIO_PHY_MODE_REG, reg + 2,
+				  val >> 16);
+	if (ret < 0)
+		goto error;
+
+	return 0;
+error:
+	dev_err_ratelimited(&sbus->dev, "Bus error. Failed to write register.\n");
+	return ret;
+}
+
+static int ar9331_sw_bus_write(void *context, const void *data, size_t count)
+{
+	u32 reg = *(u32 *)data;
+	u32 val = *((u32 *)data + 1);
+
+	return ar9331_mdio_write(context, reg, val);
+}
+
+static const struct regmap_range ar9331_valid_regs[] = {
+	regmap_reg_range(0x0, 0x0),
+	regmap_reg_range(0x10, 0x14),
+	regmap_reg_range(0x20, 0x24),
+	regmap_reg_range(0x2c, 0x30),
+	regmap_reg_range(0x40, 0x44),
+	regmap_reg_range(0x50, 0x78),
+	regmap_reg_range(0x80, 0x98),
+
+	regmap_reg_range(0x100, 0x120),
+	regmap_reg_range(0x200, 0x220),
+	regmap_reg_range(0x300, 0x320),
+	regmap_reg_range(0x400, 0x420),
+	regmap_reg_range(0x500, 0x520),
+	regmap_reg_range(0x600, 0x620),
+
+	regmap_reg_range(0x20000, 0x200a4),
+	regmap_reg_range(0x20100, 0x201a4),
+	regmap_reg_range(0x20200, 0x202a4),
+	regmap_reg_range(0x20300, 0x203a4),
+	regmap_reg_range(0x20400, 0x204a4),
+	regmap_reg_range(0x20500, 0x205a4),
+
+	/* dummy page selector reg */
+	regmap_reg_range(AR9331_SW_REG_PAGE, AR9331_SW_REG_PAGE),
+};
+
+static const struct regmap_range ar9331_nonvolatile_regs[] = {
+	regmap_reg_range(AR9331_SW_REG_PAGE, AR9331_SW_REG_PAGE),
+};
+
+static const struct regmap_range_cfg ar9331_regmap_range[] = {
+	{
+		.selector_reg = AR9331_SW_REG_PAGE,
+		.selector_mask = GENMASK(9, 0),
+		.selector_shift = 0,
+
+		.window_start = 0,
+		.window_len = 512,
+
+		.range_min = 0,
+		.range_max = AR9331_SW_REG_PAGE - 4,
+	},
+};
+
+static const struct regmap_access_table ar9331_register_set = {
+	.yes_ranges = ar9331_valid_regs,
+	.n_yes_ranges = ARRAY_SIZE(ar9331_valid_regs),
+};
+
+static const struct regmap_access_table ar9331_volatile_set = {
+	.no_ranges = ar9331_nonvolatile_regs,
+	.n_no_ranges = ARRAY_SIZE(ar9331_nonvolatile_regs),
+};
+
+static const struct regmap_config ar9331_mdio_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.max_register = AR9331_SW_REG_PAGE,
+
+	.ranges = ar9331_regmap_range,
+	.num_ranges = ARRAY_SIZE(ar9331_regmap_range),
+
+	.volatile_table = &ar9331_volatile_set,
+	.wr_table = &ar9331_register_set,
+	.rd_table = &ar9331_register_set,
+
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static struct regmap_bus ar9331_sw_bus = {
+	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+	.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+	.read = ar9331_mdio_read,
+	.write = ar9331_sw_bus_write,
+	.max_raw_read = 4,
+	.max_raw_write = 4,
+};
+
+static int ar9331_sw_probe(struct mdio_device *mdiodev)
+{
+	struct ar9331_sw_priv *priv;
+	int ret;
+
+	priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->regmap = devm_regmap_init(&mdiodev->dev, &ar9331_sw_bus, priv,
+					&ar9331_mdio_regmap_config);
+	if (IS_ERR(priv->regmap)) {
+		ret = PTR_ERR(priv->regmap);
+		dev_err(&mdiodev->dev, "regmap init failed: %d\n", ret);
+		return ret;
+	}
+
+	priv->sw_reset = devm_reset_control_get(&mdiodev->dev, "switch");
+	if (IS_ERR(priv->sw_reset)) {
+		dev_err(&mdiodev->dev, "missing switch reset\n");
+		return PTR_ERR(priv->sw_reset);
+	}
+
+	priv->sbus = mdiodev->bus;
+	priv->dev = &mdiodev->dev;
+
+	ret = ar9331_sw_irq_init(priv);
+	if (ret)
+		return ret;
+
+	priv->ds = dsa_switch_alloc(&mdiodev->dev, AR9331_SW_PORTS);
+	if (!priv->ds)
+		return -ENOMEM;
+
+	priv->ds->priv = priv;
+	priv->ops = ar9331_sw_ops;
+	priv->ds->ops = &priv->ops;
+	dev_set_drvdata(&mdiodev->dev, priv);
+
+	return dsa_register_switch(priv->ds);
+}
+
+static void ar9331_sw_remove(struct mdio_device *mdiodev)
+{
+	struct ar9331_sw_priv *priv = dev_get_drvdata(&mdiodev->dev);
+
+	mdiobus_unregister(priv->mbus);
+	dsa_unregister_switch(priv->ds);
+
+	reset_control_assert(priv->sw_reset);
+}
+
+static const struct of_device_id ar9331_sw_of_match[] = {
+	{ .compatible = "qca,ar9331-switch" },
+	{ },
+};
+
+static struct mdio_driver ar9331_sw_mdio_driver = {
+	.probe = ar9331_sw_probe,
+	.remove = ar9331_sw_remove,
+	.mdiodrv.driver = {
+		.name = AR9331_SW_NAME,
+		.of_match_table = ar9331_sw_of_match,
+	},
+};
+
+mdio_module_driver(ar9331_sw_mdio_driver);
+
+MODULE_AUTHOR("Oleksij Rempel <kernel@pengutronix.de>");
+MODULE_DESCRIPTION("Driver for Atheros AR9331 switch");
+MODULE_LICENSE("GPL v2");
-- 
2.23.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 4/5] net: dsa: add support for Atheros AR9331 TAG format
  2019-10-22  5:57 ` [PATCH v4 4/5] net: dsa: add support for Atheros AR9331 TAG format Oleksij Rempel
@ 2019-10-22  6:10   ` Randy Dunlap
  2019-10-23  0:37   ` Andrew Lunn
  1 sibling, 0 replies; 17+ messages in thread
From: Randy Dunlap @ 2019-10-22  6:10 UTC (permalink / raw)
  To: Oleksij Rempel, Andrew Lunn, Chris Snook, Florian Fainelli,
	James Hogan, Jay Cliburn, Mark Rutland, Paul Burton,
	Ralf Baechle, Rob Herring, Vivien Didelot
  Cc: Pengutronix Kernel Team, David S. Miller, netdev, linux-kernel,
	devicetree, linux-mips, Russell King

On 10/21/19 10:57 PM, Oleksij Rempel wrote:
> Add support for tag format used in Atheros AR9331 build-in switch.

                                                    built-in

> 
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---
>  include/net/dsa.h    |  2 +
>  net/dsa/Kconfig      |  6 +++
>  net/dsa/Makefile     |  1 +
>  net/dsa/tag_ar9331.c | 96 ++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 105 insertions(+)
>  create mode 100644 net/dsa/tag_ar9331.c
> 

> diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
> index 29e2bd5cc5af..617c9607df5f 100644
> --- a/net/dsa/Kconfig
> +++ b/net/dsa/Kconfig
> @@ -29,6 +29,12 @@ config NET_DSA_TAG_8021Q
>  
>  	  Drivers which use these helpers should select this as dependency.
>  
> +config NET_DSA_TAG_AR9331
> +	tristate "Tag driver for Atheros AR9331 SoC with build-in switch"

	                                                 built-in

> +	help
> +	  Say Y or M if you want to enable support for tagging frames for
> +	  the Atheros AR9331 SoC with build-in switch.

	                              built-in

> +
>  config NET_DSA_TAG_BRCM_COMMON
>  	tristate
>  	default n


thanks.
-- 
~Randy


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 5/5] net: dsa: add support for Atheros AR9331 build-in switch
  2019-10-22  5:57 ` [PATCH v4 5/5] net: dsa: add support for Atheros AR9331 build-in switch Oleksij Rempel
@ 2019-10-22  6:10   ` Randy Dunlap
  2019-10-23  0:58   ` Andrew Lunn
  1 sibling, 0 replies; 17+ messages in thread
From: Randy Dunlap @ 2019-10-22  6:10 UTC (permalink / raw)
  To: Oleksij Rempel, Andrew Lunn, Chris Snook, Florian Fainelli,
	James Hogan, Jay Cliburn, Mark Rutland, Paul Burton,
	Ralf Baechle, Rob Herring, Vivien Didelot
  Cc: Pengutronix Kernel Team, David S. Miller, netdev, linux-kernel,
	devicetree, linux-mips, Russell King

On 10/21/19 10:57 PM, Oleksij Rempel wrote:
> Provide basic support for Atheros AR9331 build-in switch. So far it

                                           built-in

> works as port multiplexer without any hardware offloading support.
> 
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---

> diff --git a/drivers/net/dsa/qca/Kconfig b/drivers/net/dsa/qca/Kconfig
> new file mode 100644
> index 000000000000..7e4978f46642
> --- /dev/null
> +++ b/drivers/net/dsa/qca/Kconfig
> @@ -0,0 +1,11 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +config NET_DSA_AR9331
> +	tristate "Atheros AR9331 Ethernet switch support"
> +	depends on NET_DSA
> +	select NET_DSA_TAG_AR9331
> +	select REGMAP
> +	---help---
> +	  This enables support for the Atheros AR9331 build-in Ethernet

	                                              built-in

> +	  switch.
> +
> +

Thanks.
-- 
~Randy


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 2/5] dt-bindings: net: dsa: qca,ar9331 switch documentation
  2019-10-22  5:57 ` [PATCH v4 2/5] dt-bindings: net: dsa: qca,ar9331 switch documentation Oleksij Rempel
@ 2019-10-23  0:35   ` Andrew Lunn
  2019-10-29  7:34     ` Oleksij Rempel
  0 siblings, 1 reply; 17+ messages in thread
From: Andrew Lunn @ 2019-10-23  0:35 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: Chris Snook, Florian Fainelli, James Hogan, Jay Cliburn,
	Mark Rutland, Paul Burton, Ralf Baechle, Rob Herring,
	Vivien Didelot, Pengutronix Kernel Team, David S. Miller, netdev,
	linux-kernel, devicetree, linux-mips, Russell King

On Tue, Oct 22, 2019 at 07:57:40AM +0200, Oleksij Rempel wrote:
> Atheros AR9331 has built-in 5 port switch. The switch can be configured
> to use all 5 or 4 ports. One of built-in PHYs can be used by first built-in
> ethernet controller or to be used directly by the switch over second ethernet
> controller.
> 
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>

Hi Oleksij

What we never really discussed is how this MUXing of the PHY works.

What i'm worried about is that when we do understand how it works, we
cannot properly support it using this binding.

Please could you try to find information about this.

Thanks
	Andrew

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 4/5] net: dsa: add support for Atheros AR9331 TAG format
  2019-10-22  5:57 ` [PATCH v4 4/5] net: dsa: add support for Atheros AR9331 TAG format Oleksij Rempel
  2019-10-22  6:10   ` Randy Dunlap
@ 2019-10-23  0:37   ` Andrew Lunn
  1 sibling, 0 replies; 17+ messages in thread
From: Andrew Lunn @ 2019-10-23  0:37 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: Chris Snook, Florian Fainelli, James Hogan, Jay Cliburn,
	Mark Rutland, Paul Burton, Ralf Baechle, Rob Herring,
	Vivien Didelot, Pengutronix Kernel Team, David S. Miller, netdev,
	linux-kernel, devicetree, linux-mips, Russell King

On Tue, Oct 22, 2019 at 07:57:42AM +0200, Oleksij Rempel wrote:
> Add support for tag format used in Atheros AR9331 build-in switch.
> 
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 5/5] net: dsa: add support for Atheros AR9331 build-in switch
  2019-10-22  5:57 ` [PATCH v4 5/5] net: dsa: add support for Atheros AR9331 build-in switch Oleksij Rempel
  2019-10-22  6:10   ` Randy Dunlap
@ 2019-10-23  0:58   ` Andrew Lunn
  2019-10-29  7:14     ` Oleksij Rempel
  1 sibling, 1 reply; 17+ messages in thread
From: Andrew Lunn @ 2019-10-23  0:58 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: Chris Snook, Florian Fainelli, James Hogan, Jay Cliburn,
	Mark Rutland, Paul Burton, Ralf Baechle, Rob Herring,
	Vivien Didelot, Pengutronix Kernel Team, David S. Miller, netdev,
	linux-kernel, devicetree, linux-mips, Russell King

> --- a/drivers/net/dsa/Kconfig
> +++ b/drivers/net/dsa/Kconfig
> @@ -52,6 +52,8 @@ source "drivers/net/dsa/microchip/Kconfig"
>  
>  source "drivers/net/dsa/mv88e6xxx/Kconfig"
>  
> +source "drivers/net/dsa/qca/Kconfig"
> +
>  source "drivers/net/dsa/sja1105/Kconfig"
>  
>  config NET_DSA_QCA8K

> diff --git a/drivers/net/dsa/qca/Kconfig b/drivers/net/dsa/qca/Kconfig
> new file mode 100644
> index 000000000000..7e4978f46642
> --- /dev/null
> +++ b/drivers/net/dsa/qca/Kconfig
> @@ -0,0 +1,11 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +config NET_DSA_AR9331
> +	tristate "Atheros AR9331 Ethernet switch support"

This is where things are a little bit unobvious. If you do
make menu

and go into the DSA menu, you will find the drivers are all sorted
into Alphabetic order, based on the tristate text. But you have
inserted your "Atheros AR9331", after "NXP SJA1105".

It would probably be best if you make the tristate "Qualcomm Atheros
AR9331 ...". The order would be correct then,

> +static int ar9331_sw_port_enable(struct dsa_switch *ds, int port,
> +				 struct phy_device *phy)
> +{
> +	struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv;
> +	struct regmap *regmap = priv->regmap;
> +	int ret;
> +
> +	/* nothing to enable. Just set link to initial state */
> +	ret = regmap_write(regmap, AR9331_SW_REG_PORT_STATUS(port), 0);
> +	if (ret)
> +		dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
> +
> +	return ret;
> +}
> +
> +static void ar9331_sw_port_disable(struct dsa_switch *ds, int port)
> +{
> +	struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv;
> +	struct regmap *regmap = priv->regmap;
> +	int ret;
> +
> +	ret = regmap_write(regmap, AR9331_SW_REG_PORT_STATUS(port), 0);
> +	if (ret)
> +		dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
> +}

I've asked this before, but i don't remember the answer. Why are
port_enable and port_disable the same?

> +static int ar9331_sw_irq_init(struct ar9331_sw_priv *priv)
> +{
> +	struct device_node *np = priv->dev->of_node;
> +	struct device *dev = priv->dev;
> +	int ret, irq;
> +
> +	irq = of_irq_get(np, 0);
> +	if (irq <= 0) {
> +		dev_err(dev, "failed to get parent IRQ\n");
> +		return irq ? irq : -EINVAL;
> +	}
> +
> +	ret = devm_request_threaded_irq(dev, irq, NULL, ar9331_sw_irq,
> +					IRQF_ONESHOT, AR9331_SW_NAME, priv);
> +	if (ret) {
> +		dev_err(dev, "unable to request irq: %d\n", ret);
> +		return ret;
> +	}
> +
> +	priv->irqdomain = irq_domain_add_linear(np, 1, &ar9331_sw_irqdomain_ops,
> +						priv);
> +	if (!priv->irqdomain) {
> +		dev_err(dev, "failed to create IRQ domain\n");
> +		return -EINVAL;
> +	}
> +
> +	irq_set_parent(irq_create_mapping(priv->irqdomain, 0), irq);
> +
> +	return 0;
> +}


> +static int ar9331_sw_probe(struct mdio_device *mdiodev)
> +{
> +	struct ar9331_sw_priv *priv;
> +	int ret;
> +
> +	priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->regmap = devm_regmap_init(&mdiodev->dev, &ar9331_sw_bus, priv,
> +					&ar9331_mdio_regmap_config);
> +	if (IS_ERR(priv->regmap)) {
> +		ret = PTR_ERR(priv->regmap);
> +		dev_err(&mdiodev->dev, "regmap init failed: %d\n", ret);
> +		return ret;
> +	}
> +
> +	priv->sw_reset = devm_reset_control_get(&mdiodev->dev, "switch");
> +	if (IS_ERR(priv->sw_reset)) {
> +		dev_err(&mdiodev->dev, "missing switch reset\n");
> +		return PTR_ERR(priv->sw_reset);
> +	}
> +
> +	priv->sbus = mdiodev->bus;
> +	priv->dev = &mdiodev->dev;
> +
> +	ret = ar9331_sw_irq_init(priv);
> +	if (ret)
> +		return ret;
> +
> +	priv->ds = dsa_switch_alloc(&mdiodev->dev, AR9331_SW_PORTS);
> +	if (!priv->ds)
> +		return -ENOMEM;
> +
> +	priv->ds->priv = priv;
> +	priv->ops = ar9331_sw_ops;
> +	priv->ds->ops = &priv->ops;
> +	dev_set_drvdata(&mdiodev->dev, priv);
> +
> +	return dsa_register_switch(priv->ds);

If there is an error here, you need to undo the IRQ code, etc.

> +}
> +
> +static void ar9331_sw_remove(struct mdio_device *mdiodev)
> +{
> +	struct ar9331_sw_priv *priv = dev_get_drvdata(&mdiodev->dev);
> +
> +	mdiobus_unregister(priv->mbus);
> +	dsa_unregister_switch(priv->ds);
> +
> +	reset_control_assert(priv->sw_reset);

You also need to clean up the IRQ code here.

Thanks
    Andrew

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 5/5] net: dsa: add support for Atheros AR9331 build-in switch
  2019-10-23  0:58   ` Andrew Lunn
@ 2019-10-29  7:14     ` Oleksij Rempel
  2019-10-29 12:38       ` Andrew Lunn
  0 siblings, 1 reply; 17+ messages in thread
From: Oleksij Rempel @ 2019-10-29  7:14 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Mark Rutland, devicetree, Jay Cliburn, Florian Fainelli,
	Chris Snook, linux-kernel, Ralf Baechle, David S. Miller,
	Paul Burton, Rob Herring, Pengutronix Kernel Team, James Hogan,
	Russell King, netdev, linux-mips, Vivien Didelot

[-- Attachment #1: Type: text/plain, Size: 5375 bytes --]

Hi,

On Wed, Oct 23, 2019 at 02:58:50AM +0200, Andrew Lunn wrote:
> > --- a/drivers/net/dsa/Kconfig
> > +++ b/drivers/net/dsa/Kconfig
> > @@ -52,6 +52,8 @@ source "drivers/net/dsa/microchip/Kconfig"
> >  
> >  source "drivers/net/dsa/mv88e6xxx/Kconfig"
> >  
> > +source "drivers/net/dsa/qca/Kconfig"
> > +
> >  source "drivers/net/dsa/sja1105/Kconfig"
> >  
> >  config NET_DSA_QCA8K
> 
> > diff --git a/drivers/net/dsa/qca/Kconfig b/drivers/net/dsa/qca/Kconfig
> > new file mode 100644
> > index 000000000000..7e4978f46642
> > --- /dev/null
> > +++ b/drivers/net/dsa/qca/Kconfig
> > @@ -0,0 +1,11 @@
> > +# SPDX-License-Identifier: GPL-2.0-only
> > +config NET_DSA_AR9331
> > +	tristate "Atheros AR9331 Ethernet switch support"
> 
> This is where things are a little bit unobvious. If you do
> make menu
> 
> and go into the DSA menu, you will find the drivers are all sorted
> into Alphabetic order, based on the tristate text. But you have
> inserted your "Atheros AR9331", after "NXP SJA1105".
> 
> It would probably be best if you make the tristate "Qualcomm Atheros
> AR9331 ...". The order would be correct then,

done

> > +static int ar9331_sw_port_enable(struct dsa_switch *ds, int port,
> > +				 struct phy_device *phy)
> > +{
> > +	struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv;
> > +	struct regmap *regmap = priv->regmap;
> > +	int ret;
> > +
> > +	/* nothing to enable. Just set link to initial state */
> > +	ret = regmap_write(regmap, AR9331_SW_REG_PORT_STATUS(port), 0);
> > +	if (ret)
> > +		dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
> > +
> > +	return ret;
> > +}
> > +
> > +static void ar9331_sw_port_disable(struct dsa_switch *ds, int port)
> > +{
> > +	struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv;
> > +	struct regmap *regmap = priv->regmap;
> > +	int ret;
> > +
> > +	ret = regmap_write(regmap, AR9331_SW_REG_PORT_STATUS(port), 0);
> > +	if (ret)
> > +		dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
> > +}
> 
> I've asked this before, but i don't remember the answer. Why are
> port_enable and port_disable the same?

I have only MAC TX/RX enable bit. This bit is set by phylink_mac_link_up and
removed by phylink_mac_link_down.
The port enable I use only to set predictable state of the port
register: all bits cleared. May be i should just drop port enable
function? What do you think? 

> > +static int ar9331_sw_irq_init(struct ar9331_sw_priv *priv)
> > +{
> > +	struct device_node *np = priv->dev->of_node;
> > +	struct device *dev = priv->dev;
> > +	int ret, irq;
> > +
> > +	irq = of_irq_get(np, 0);
> > +	if (irq <= 0) {
> > +		dev_err(dev, "failed to get parent IRQ\n");
> > +		return irq ? irq : -EINVAL;
> > +	}
> > +
> > +	ret = devm_request_threaded_irq(dev, irq, NULL, ar9331_sw_irq,
> > +					IRQF_ONESHOT, AR9331_SW_NAME, priv);
> > +	if (ret) {
> > +		dev_err(dev, "unable to request irq: %d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	priv->irqdomain = irq_domain_add_linear(np, 1, &ar9331_sw_irqdomain_ops,
> > +						priv);
> > +	if (!priv->irqdomain) {
> > +		dev_err(dev, "failed to create IRQ domain\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	irq_set_parent(irq_create_mapping(priv->irqdomain, 0), irq);
> > +
> > +	return 0;
> > +}
> 
> 
> > +static int ar9331_sw_probe(struct mdio_device *mdiodev)
> > +{
> > +	struct ar9331_sw_priv *priv;
> > +	int ret;
> > +
> > +	priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
> > +	if (!priv)
> > +		return -ENOMEM;
> > +
> > +	priv->regmap = devm_regmap_init(&mdiodev->dev, &ar9331_sw_bus, priv,
> > +					&ar9331_mdio_regmap_config);
> > +	if (IS_ERR(priv->regmap)) {
> > +		ret = PTR_ERR(priv->regmap);
> > +		dev_err(&mdiodev->dev, "regmap init failed: %d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	priv->sw_reset = devm_reset_control_get(&mdiodev->dev, "switch");
> > +	if (IS_ERR(priv->sw_reset)) {
> > +		dev_err(&mdiodev->dev, "missing switch reset\n");
> > +		return PTR_ERR(priv->sw_reset);
> > +	}
> > +
> > +	priv->sbus = mdiodev->bus;
> > +	priv->dev = &mdiodev->dev;
> > +
> > +	ret = ar9331_sw_irq_init(priv);
> > +	if (ret)
> > +		return ret;
> > +
> > +	priv->ds = dsa_switch_alloc(&mdiodev->dev, AR9331_SW_PORTS);
> > +	if (!priv->ds)
> > +		return -ENOMEM;
> > +
> > +	priv->ds->priv = priv;
> > +	priv->ops = ar9331_sw_ops;
> > +	priv->ds->ops = &priv->ops;
> > +	dev_set_drvdata(&mdiodev->dev, priv);
> > +
> > +	return dsa_register_switch(priv->ds);
> 
> If there is an error here, you need to undo the IRQ code, etc.

done

> > +}
> > +
> > +static void ar9331_sw_remove(struct mdio_device *mdiodev)
> > +{
> > +	struct ar9331_sw_priv *priv = dev_get_drvdata(&mdiodev->dev);
> > +
> > +	mdiobus_unregister(priv->mbus);
> > +	dsa_unregister_switch(priv->ds);
> > +
> > +	reset_control_assert(priv->sw_reset);
> 
> You also need to clean up the IRQ code here.

ok, thx!

Regards,
Oleksij

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 2/5] dt-bindings: net: dsa: qca,ar9331 switch documentation
  2019-10-23  0:35   ` Andrew Lunn
@ 2019-10-29  7:34     ` Oleksij Rempel
  2019-12-15 14:57       ` Oleksij Rempel
  0 siblings, 1 reply; 17+ messages in thread
From: Oleksij Rempel @ 2019-10-29  7:34 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Mark Rutland, devicetree, Jay Cliburn, Florian Fainelli,
	Chris Snook, linux-kernel, Ralf Baechle, David S. Miller,
	Paul Burton, Rob Herring, Pengutronix Kernel Team, James Hogan,
	Russell King, netdev, linux-mips, Vivien Didelot

[-- Attachment #1: Type: text/plain, Size: 2105 bytes --]

On Wed, Oct 23, 2019 at 02:35:43AM +0200, Andrew Lunn wrote:
> On Tue, Oct 22, 2019 at 07:57:40AM +0200, Oleksij Rempel wrote:
> > Atheros AR9331 has built-in 5 port switch. The switch can be configured
> > to use all 5 or 4 ports. One of built-in PHYs can be used by first built-in
> > ethernet controller or to be used directly by the switch over second ethernet
> > controller.
> > 
> > Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> 
> Hi Oleksij
> 
> What we never really discussed is how this MUXing of the PHY works.
> 
> What i'm worried about is that when we do understand how it works, we
> cannot properly support it using this binding.

good point. i would prefer to make it properly.

> Please could you try to find information about this.

Documentation says:
The PHY interfaces (PHY0, PHY1, PHY2, PHY3 and PHY4) can connect to the switch
in bridge mode. In this case GE0 must be under reset. All five LAN ports are
switched together and connect to the CPU through the GMII interface (MAC0),
which is controlled by the ETH_CFG register bit SW_ONLY_MODE. If GE0 connects
separately to PHY, then MAC5 should be under reset.

There is no SW_ONLY_MODE bit in the documentation.
I found:
CFG_SW_PHY_SWAP - Used to switch the wires connection of PHY port 0 with that of
port 4 in the Ethernet switch. MAC1 and PHY4 are paired while MAC5 and PHY0 are
paired.

CFG_SW_PHY_ADDR_SWAP - Exchanges the address of PHY port 0 with that of
PHY port 4 in the Ethernet switch.

It feels like this are the right bits. I'll try to test it after ELC-E
conference (If you are here, please ping me).
If this are the right bits, should it be registered as separate driver? This
register is on MMIO and not part of the switches MDIO.

Regards,
Oleksij
-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 5/5] net: dsa: add support for Atheros AR9331 build-in switch
  2019-10-29  7:14     ` Oleksij Rempel
@ 2019-10-29 12:38       ` Andrew Lunn
  0 siblings, 0 replies; 17+ messages in thread
From: Andrew Lunn @ 2019-10-29 12:38 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: Mark Rutland, devicetree, Jay Cliburn, Florian Fainelli,
	Chris Snook, linux-kernel, Ralf Baechle, David S. Miller,
	Paul Burton, Rob Herring, Pengutronix Kernel Team, James Hogan,
	Russell King, netdev, linux-mips, Vivien Didelot

Hi Oleksij

> > > +static void ar9331_sw_port_disable(struct dsa_switch *ds, int port)
> > > +{
> > > +	struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv;
> > > +	struct regmap *regmap = priv->regmap;
> > > +	int ret;
> > > +
> > > +	ret = regmap_write(regmap, AR9331_SW_REG_PORT_STATUS(port), 0);
> > > +	if (ret)
> > > +		dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
> > > +}
> > 
> > I've asked this before, but i don't remember the answer. Why are
> > port_enable and port_disable the same?
> 
> I have only MAC TX/RX enable bit. This bit is set by phylink_mac_link_up and
> removed by phylink_mac_link_down.
> The port enable I use only to set predictable state of the port
> register: all bits cleared. May be i should just drop port enable
> function? What do you think? 

At minimum, it needs a comment about why enable and disable are the
same. If i keep asking, others will as well.

If there is nothing useful to do, then drop it.

   Andrew


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 2/5] dt-bindings: net: dsa: qca,ar9331 switch documentation
  2019-10-29  7:34     ` Oleksij Rempel
@ 2019-12-15 14:57       ` Oleksij Rempel
  2019-12-17  8:44         ` Andrew Lunn
  0 siblings, 1 reply; 17+ messages in thread
From: Oleksij Rempel @ 2019-12-15 14:57 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Mark Rutland, devicetree, Jay Cliburn, Florian Fainelli,
	Chris Snook, linux-kernel, Ralf Baechle, David S. Miller,
	Paul Burton, Rob Herring, Pengutronix Kernel Team, James Hogan,
	Russell King, netdev, linux-mips, Vivien Didelot

[-- Attachment #1: Type: text/plain, Size: 2847 bytes --]

Hi Andrew,

On Tue, Oct 29, 2019 at 08:34:19AM +0100, Oleksij Rempel wrote:
> On Wed, Oct 23, 2019 at 02:35:43AM +0200, Andrew Lunn wrote:
> > On Tue, Oct 22, 2019 at 07:57:40AM +0200, Oleksij Rempel wrote:
> > > Atheros AR9331 has built-in 5 port switch. The switch can be configured
> > > to use all 5 or 4 ports. One of built-in PHYs can be used by first built-in
> > > ethernet controller or to be used directly by the switch over second ethernet
> > > controller.
> > > 
> > > Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> > 
> > Hi Oleksij
> > 
> > What we never really discussed is how this MUXing of the PHY works.
> > 
> > What i'm worried about is that when we do understand how it works, we
> > cannot properly support it using this binding.
> 
> good point. i would prefer to make it properly.
> 
> > Please could you try to find information about this.
> 
> Documentation says:
> The PHY interfaces (PHY0, PHY1, PHY2, PHY3 and PHY4) can connect to the switch
> in bridge mode. In this case GE0 must be under reset. All five LAN ports are
> switched together and connect to the CPU through the GMII interface (MAC0),
> which is controlled by the ETH_CFG register bit SW_ONLY_MODE. If GE0 connects
> separately to PHY, then MAC5 should be under reset.
> 
> There is no SW_ONLY_MODE bit in the documentation.
> I found:
> CFG_SW_PHY_SWAP - Used to switch the wires connection of PHY port 0 with that of
> port 4 in the Ethernet switch. MAC1 and PHY4 are paired while MAC5 and PHY0 are
> paired.
> 
> CFG_SW_PHY_ADDR_SWAP - Exchanges the address of PHY port 0 with that of
> PHY port 4 in the Ethernet switch.
> 
> It feels like this are the right bits. I'll try to test it after ELC-E
> conference (If you are here, please ping me).
> If this are the right bits, should it be registered as separate driver? This
> register is on MMIO and not part of the switches MDIO.

I spend some tine on investigating and testing it. So, the result is
pretty simple. It looks like *MII lines of ethernet controller GMAC0 and
MAC of switch port5 are just connected together and wired to the PHY4.
Something like this:

GMAC1-->switch--mac5-+--->phy4
                     ^
GMAC0---------------/


So, both of MACs can be enabled at same time and introduce resource
conflict. If one is enabled, other one should be set in to reset mode.

The questions are:
- how this can be reflected in devicetree?
- how this can be properly implemented in kernel?

Regards,
Oleksij
-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 2/5] dt-bindings: net: dsa: qca,ar9331 switch documentation
  2019-12-15 14:57       ` Oleksij Rempel
@ 2019-12-17  8:44         ` Andrew Lunn
  0 siblings, 0 replies; 17+ messages in thread
From: Andrew Lunn @ 2019-12-17  8:44 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: Mark Rutland, devicetree, Jay Cliburn, Florian Fainelli,
	Chris Snook, linux-kernel, Ralf Baechle, David S. Miller,
	Paul Burton, Rob Herring, Pengutronix Kernel Team, James Hogan,
	Russell King, netdev, linux-mips, Vivien Didelot

> I spend some tine on investigating and testing it. So, the result is
> pretty simple. It looks like *MII lines of ethernet controller GMAC0 and
> MAC of switch port5 are just connected together and wired to the PHY4.
> Something like this:
> 
> GMAC1-->switch--mac5-+--->phy4
>                      ^
> GMAC0---------------/
> 
> 
> So, both of MACs can be enabled at same time and introduce resource
> conflict. If one is enabled, other one should be set in to reset mode.
> 
> The questions are:
> - how this can be reflected in devicetree?
> - how this can be properly implemented in kernel?

That is, er, interesting.

So in device tree, i would use a phy-handle in GMAC1 or GMAC0 to point
to phy4. I don't think there is anything you can do in DT to prevent
both GMAC0 and GMAC1 having a phandle to phy4, other than adding a
comment in the binding. You could ask Rob if DT schema provides any
sorts of checks like this? But i doubt it.

In the driver, it would be good to check if two MACs try to connect to
one PHY. This in general should not happen, so maybe you can add a
check to the core, in phylib and/or phylink. Just watch out for
cpsw. It connects two PHYs to one MAC. Just don't make the assumption
one MAC and one PHY is correct, everything else is wrong.

    Andrew

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v4 0/5] add dsa switch support for ar9331
@ 2019-10-22  5:57 Oleksij Rempel
  0 siblings, 0 replies; 17+ messages in thread
From: Oleksij Rempel @ 2019-10-22  5:57 UTC (permalink / raw)
  To: Andrew Lunn, Chris Snook, Florian Fainelli, James Hogan,
	Jay Cliburn, Mark Rutland, Paul Burton, Ralf Baechle,
	Rob Herring, Vivien Didelot
  Cc: Oleksij Rempel, Pengutronix Kernel Team, David S. Miller, netdev,
	linux-kernel, devicetree, linux-mips, Russell King

changes v4:
- ag71xx: ag71xx_mac_validate fix always false comparison (&& -> ||)
- tag_ar9331: use skb_pull_rcsum() instead of skb_pull().
- tag_ar9331: drop skb_set_mac_header()

changes v3:
- ag71xx: ag71xx_mac_config: ignore MLO_AN_INBAND mode. It is not
  supported by HW and SW.
- ag71xx: ag71xx_mac_validate: return all supported bits on
  PHY_INTERFACE_MODE_NA

changes v2:
- move Atheros AR9331 TAG format to separate patch
- use netdev_warn_once in the tag driver to reduce potential message spam
- typo fixes
- reorder tag driver alphabetically 
- configure switch to maximal frame size
- use mdiobus_read/write
- fail if mdio sub node is not found
- add comment for post reset state
- remove deprecated comment about device id
- remove phy-handle option for node with fixed-link
- ag71xx: set 1G support only for GMII mode

This patch series provides dsa switch support for Atheros ar9331 WiSoC.
As side effect ag71xx needed to be ported to phylink to make the switch
driver (as well phylink based) work properly.

Oleksij Rempel (5):
  net: ag71xx: port to phylink
  dt-bindings: net: dsa: qca,ar9331 switch documentation
  MIPS: ath79: ar9331: add ar9331-switch node
  net: dsa: add support for Atheros AR9331 TAG format
  net: dsa: add support for Atheros AR9331 build-in switch

 .../devicetree/bindings/net/dsa/ar9331.txt    | 148 ++++
 arch/mips/boot/dts/qca/ar9331.dtsi            | 127 ++-
 arch/mips/boot/dts/qca/ar9331_dpt_module.dts  |  13 +
 drivers/net/dsa/Kconfig                       |   2 +
 drivers/net/dsa/Makefile                      |   1 +
 drivers/net/dsa/qca/Kconfig                   |  11 +
 drivers/net/dsa/qca/Makefile                  |   2 +
 drivers/net/dsa/qca/ar9331.c                  | 823 ++++++++++++++++++
 drivers/net/ethernet/atheros/Kconfig          |   2 +-
 drivers/net/ethernet/atheros/ag71xx.c         | 146 ++--
 include/net/dsa.h                             |   2 +
 net/dsa/Kconfig                               |   6 +
 net/dsa/Makefile                              |   1 +
 net/dsa/tag_ar9331.c                          |  96 ++
 14 files changed, 1320 insertions(+), 60 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/net/dsa/ar9331.txt
 create mode 100644 drivers/net/dsa/qca/Kconfig
 create mode 100644 drivers/net/dsa/qca/Makefile
 create mode 100644 drivers/net/dsa/qca/ar9331.c
 create mode 100644 net/dsa/tag_ar9331.c

-- 
2.23.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2019-12-17  8:44 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-22  5:57 [PATCH v4 0/5] add dsa switch support for ar9331 Oleksij Rempel
2019-10-22  5:57 ` [PATCH v4 1/5] net: ag71xx: port to phylink Oleksij Rempel
2019-10-22  5:57 ` [PATCH v4 2/5] dt-bindings: net: dsa: qca,ar9331 switch documentation Oleksij Rempel
2019-10-23  0:35   ` Andrew Lunn
2019-10-29  7:34     ` Oleksij Rempel
2019-12-15 14:57       ` Oleksij Rempel
2019-12-17  8:44         ` Andrew Lunn
2019-10-22  5:57 ` [PATCH v4 3/5] MIPS: ath79: ar9331: add ar9331-switch node Oleksij Rempel
2019-10-22  5:57 ` [PATCH v4 4/5] net: dsa: add support for Atheros AR9331 TAG format Oleksij Rempel
2019-10-22  6:10   ` Randy Dunlap
2019-10-23  0:37   ` Andrew Lunn
2019-10-22  5:57 ` [PATCH v4 5/5] net: dsa: add support for Atheros AR9331 build-in switch Oleksij Rempel
2019-10-22  6:10   ` Randy Dunlap
2019-10-23  0:58   ` Andrew Lunn
2019-10-29  7:14     ` Oleksij Rempel
2019-10-29 12:38       ` Andrew Lunn
  -- strict thread matches above, loose matches on Subject: below --
2019-10-22  5:57 [PATCH v4 0/5] add dsa switch support for ar9331 Oleksij Rempel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).