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

2016-06-27 Thread Sven Eckelmann
On Tuesday 05 April 2016 15:32:13 Sven Eckelmann wrote:
> From: Sven Eckelmann 
>
> 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 
> ---
> 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).

Just because asked if this is also required for the RGMII - short answer:
yes, it is.

Slightly longer answer: Yes, the link seems to desync(?) too when RGMII
changes the link speed. Unfortunately, there is also no real fix and the
workaround is even more terrible. The basic idea behind it is that the PHY has
to be changed into its digital loopback mode on each link change. And then the
SoC has to transfer some ethernet frames to the PHY and check if it receives
these packets again. If not, then it has to toggle the TX_INVERT bit of
ETH_CFG and retest. If it still doesn't work then the only solution for the
SoC is to jump out of the window (this part is not yet implemented).

I have just implemented a PoC in case somebody wants to play around with it.
Not that I would recommend that to anyone.

Kind regards,
SvenFrom: Sven Eckelmann 
Date: Tue, 26 Apr 2016 16:14:47 +0200
Subject: [RFC 7/6] ag71xx: Test link on QCA955x for PHY connectivity problems

The link between MAC and PHY on a QCA955x tends to break down after carrier
changes. This can be worked around by setting the PHY (AR803x only
supported) into digital loopback mode and then sending packets via this
link. If no data is returned then the TX_INVERT bit has to be toggled to
get the link working again.

No information was received from QCA what actually is broken.
---
 .../linux/ar71xx/files/arch/mips/ath79/dev-eth.c   |  44 +++-
 .../ar71xx/files/arch/mips/ath79/mach-mr1750.c |   1 +
 .../ar71xx/files/arch/mips/ath79/mach-om5pac.c |   2 +
 .../ar71xx/files/arch/mips/ath79/mach-om5pacv2.c   |   2 +
 .../mips/include/asm/mach-ath79/ag71xx_platform.h  |   2 +
 .../drivers/net/ethernet/atheros/ag71xx/ag71xx.h   |  13 +
 .../net/ethernet/atheros/ag71xx/ag71xx_main.c  | 283 +
 .../net/ethernet/atheros/ag71xx/ag71xx_phy.c   |  17 +-
 .../999-dont-set-down-on-loopback.patch|  30 +++
 .../999-dont-set-down-on-loopback.patch|  30 +++
 .../999-dont-set-down-on-loopback.patch|  30 +++
 11 files changed, 451 insertions(+), 3 deletions(-)
 create mode 100644 target/linux/generic/patches-3.18/999-dont-set-down-on-loopback.patch
 create mode 100644 target/linux/generic/patches-4.1/999-dont-set-down-on-loopback.patch
 create mode 100644 target/linux/generic/patches-4.4/999-dont-set-down-on-loopback.patch

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 b43c80a..d1d3be7 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c
+++ b/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c
@@ -373,10 +373,50 @@ static void ar934x_set_speed_ge0(int speed)
 	iounmap(base);
 }

+static u32 qca955x_get_eth_pll(unsigned int mac, int speed)
+{
+	struct ag71xx_platform_data *pdata;
+	struct ath79_eth_pll_data *pll_data;
+	u32 pll_val;
+	u32 tx_invert = 0;
+
+	switch (mac) {
+	case 0:
+		pll_data = _eth0_pll_data;
+		pdata = _eth0_data;
+		break;
+	case 1:
+		pll_data = _eth1_pll_data;
+		pdata = _eth1_data;
+		break;
+	default:
+		BUG();
+	}
+
+	switch (speed) {
+	case SPEED_10:
+		pll_val = pll_data->pll_10;
+		break;
+	case SPEED_100:
+		pll_val = pll_data->pll_100;
+		break;
+	case SPEED_1000:
+		pll_val = pll_data->pll_1000;
+		break;
+	default:
+		BUG();
+	}
+
+	/* toggle TX_INVERT when required by ag71xx */
+	if (pdata->tx_invert_war && pdata->tx_invert_active)
+		tx_invert =  BIT(31);
+
+	return pll_val ^ tx_invert;
+}
 static void qca955x_set_speed_xmii(int speed)
 {
 	void __iomem *base;
-	u32 val = ath79_get_eth_pll(0, speed);
+	u32 val = qca955x_get_eth_pll(0, speed);

 	base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
 	__raw_writel(val, base + QCA955X_PLL_ETH_XMII_CONTROL_REG);
@@ -386,7 +426,7 @@ static void qca955x_set_speed_xmii(int speed)
 static void qca955x_set_speed_sgmii(int speed)
 {
 	void __iomem *base;
-	u32 val = ath79_get_eth_pll(1, speed);
+	u32 val = qca955x_get_eth_pll(1, speed);

 	base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
 	__raw_writel(val, base + QCA955X_PLL_ETH_SGMII_CONTROL_REG);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-mr1750.c 

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

2016-04-05 Thread Sven Eckelmann
From: Sven Eckelmann 

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 
---
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@lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel