[OpenWrt-Devel] [RFC v2 6/6] ar71xx: Reset QCA955x SGMII link on speed change

Sven Eckelmann sven.eckelmann at open-mesh.com
Tue Apr 5 09:32:13 EDT 2016


From: Sven Eckelmann <sven.eckelmann at open-mesh.com>

The SGMII link of the QCA955x seems to be unstable when the PHY changes the
link speed. Reseting the SGMII and the PHY management control seems to
resolve this problem.

This was observed with an AR8033 and QCA9558

Signed-off-by: Sven Eckelmann <sven.eckelmann at open-mesh.com>
---
v2:
 - Split into multiple patches and adjust slightly to look more like an
   OpenWrt patch

The code of this RFC is not meant to be an actual patch. It should show
what the u-boot for QCA955x does and what seemed to work(tm) in my limited
tests. It would be interesting to know whether this was also noticed by
other people and how they fixed it (when they fixed it).

If it is already known than it would maybe good to find a better way to
integrate it with ag71xx. Right now it just uses the set_speed callback to
start the reset.

 .../linux/ar71xx/files/arch/mips/ath79/dev-eth.c   | 77 ++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c b/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c
index bfcc82f..f2e88dd 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c
+++ b/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c
@@ -383,6 +383,81 @@ static void qca955x_set_speed_xmii(int speed)
 	iounmap(base);
 }
 
+static void qca955x_reset_sgmii(void)
+{
+	void __iomem *base;
+	int count = 0;
+	u32 status;
+	u32 t;
+
+	base = ioremap(QCA955X_GMAC_BASE, QCA955X_GMAC_SIZE);
+
+	t = QCA955X_MR_AN_CONTROL_AN_ENABLE |
+	    QCA955X_MR_AN_CONTROL_PHY_RESET;
+	__raw_writel(t, base + QCA955X_GMAC_REG_MR_AN_CONTROL);
+	udelay(10);
+
+	t = QCA955X_MR_AN_CONTROL_AN_ENABLE;
+	__raw_writel(t, base + QCA955X_GMAC_REG_MR_AN_CONTROL);
+
+	t = 0;
+	__raw_writel(t, base + QCA955X_GMAC_REG_SGMII_RESET);
+
+	t = QCA955X_SGMII_RESET_HW_RX_125M;
+	__raw_writel(t, base + QCA955X_GMAC_REG_SGMII_RESET);
+
+	t = QCA955X_SGMII_RESET_HW_RX_125M |
+	    QCA955X_SGMII_RESET_RX_125M;
+	__raw_writel(t, base + QCA955X_GMAC_REG_SGMII_RESET);
+
+	t = QCA955X_SGMII_RESET_HW_RX_125M |
+	    QCA955X_SGMII_RESET_TX_125M |
+	    QCA955X_SGMII_RESET_RX_125M;
+	__raw_writel(t, base + QCA955X_GMAC_REG_SGMII_RESET);
+
+	t = QCA955X_SGMII_RESET_HW_RX_125M |
+	    QCA955X_SGMII_RESET_TX_125M |
+	    QCA955X_SGMII_RESET_RX_125M |
+	    QCA955X_SGMII_RESET_RX_CLK;
+	__raw_writel(t, base + QCA955X_GMAC_REG_SGMII_RESET);
+
+	t = QCA955X_SGMII_RESET_HW_RX_125M |
+	    QCA955X_SGMII_RESET_TX_125M |
+	    QCA955X_SGMII_RESET_RX_125M |
+	    QCA955X_SGMII_RESET_RX_CLK |
+	    QCA955X_SGMII_RESET_TX_CLK;
+	__raw_writel(t, base + QCA955X_GMAC_REG_SGMII_RESET);
+
+	t = __raw_readl(base + QCA955X_GMAC_REG_MR_AN_CONTROL);
+	t &= ~QCA955X_MR_AN_CONTROL_PHY_RESET;
+	__raw_writel(t, base + QCA955X_GMAC_REG_MR_AN_CONTROL);
+	udelay(100);
+
+	status = __raw_readl(base + QCA955X_GMAC_REG_SGMII_DEBUG);
+	status &= 0xff;
+	while (status != 0xf && status != 0x10) {
+		t = __raw_readl(base + QCA955X_GMAC_REG_MR_AN_CONTROL);
+		t |= QCA955X_MR_AN_CONTROL_PHY_RESET;
+		 __raw_writel(t, base + QCA955X_GMAC_REG_MR_AN_CONTROL);
+
+		udelay(100);
+
+		t = __raw_readl(base + QCA955X_GMAC_REG_MR_AN_CONTROL);
+		t &= ~QCA955X_MR_AN_CONTROL_PHY_RESET;
+		 __raw_writel(t, base + QCA955X_GMAC_REG_MR_AN_CONTROL);
+
+		if (count++ >= 20)
+			break;
+
+		mdelay(10);
+
+		status = __raw_readl(base + QCA955X_GMAC_REG_SGMII_DEBUG);
+		status &= 0xff;
+	}
+
+	iounmap(base);
+}
+
 static void qca955x_set_speed_sgmii(int speed)
 {
 	void __iomem *base;
@@ -391,6 +466,8 @@ static void qca955x_set_speed_sgmii(int speed)
 	base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
 	__raw_writel(val, base + QCA955X_PLL_ETH_SGMII_CONTROL_REG);
 	iounmap(base);
+
+	qca955x_reset_sgmii();
 }
 
 static void qca956x_set_speed_sgmii(int speed)
-- 
2.8.0.rc3
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel


More information about the openwrt-devel mailing list