[OpenWrt-Devel] [PATCH 2/4] ath79: add QCA955x SGMII link loss workaround

Christian Lamparter chunkeey at gmail.com
Fri May 31 06:34:34 PDT 2019


On Thursday, April 11, 2019 5:59:43 PM CEST David Bauer wrote:
> This commit adds a workaround for the loss of the SGMII link observed on
> the QCA955x generation of SoCs. The workaround originates part from the
> U-Boot source code, part from the implementation from AVM found in the
> GPL tarball for the AVM FRITZ!WLAN Repeater 450E.
> 
> The bug results in a stuck SGMII link between the PHY device and the SoC
> side. This has only been observed with the Atheros AR8033 PHY and most
> likely all devices using such combination are affected.
> 
> It is worked around by reading a hidden SGMII status register and
> issuing a SGMII PHY reset until the link becomes useable again.
> 
> Signed-off-by: David Bauer <mail at david-bauer.net>
> ---

Not to be a party pooper. The ag71xx is well on its way to upstream.
https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/drivers/net/ethernet/atheros/ag71xx.c?id=d51b6ce441d356369387d20bc1de5f2edb0ab71e

So sadly this all would need to be somehow upstreamed first and then 
backported again. *sight* :(


>  .../net/ethernet/atheros/ag71xx/ag71xx_main.c | 108 ++++++++++++++++++
>  ...9-add-missing-QCA955x-GMAC-registers.patch |  91 +++++++++++++++
>  ...9-add-missing-QCA955x-GMAC-registers.patch |  91 +++++++++++++++
>  3 files changed, 290 insertions(+)
>  create mode 100644 target/linux/ath79/patches-4.14/0038-MIPS-ath79-add-missing-QCA955x-GMAC-registers.patch
>  create mode 100644 target/linux/ath79/patches-4.19/0038-MIPS-ath79-add-missing-QCA955x-GMAC-registers.patch
> 
> diff --git a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
> index 8cff56a11a..a7565e6ffb 100644
> --- a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
> +++ b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
> @@ -559,6 +559,112 @@ static void ath79_set_pll(struct ag71xx *ag)
>  	udelay(100);
>  }
>  
> +static void ag71xx_bit_set(void __iomem *reg, u32 bit)
> +{
> +	u32 val;
> +
> +	val = __raw_readl(reg) | bit;
> +	__raw_writel(val, reg);
> +	__raw_readl(reg);
> +}
> +
> +static void ag71xx_bit_clear(void __iomem *reg, u32 bit)
> +{
> +	u32 val;
> +
> +	val = __raw_readl(reg) & ~bit;
> +	__raw_writel(val, reg);
> +	__raw_readl(reg);
> +}
> +
> +static void ag71xx_sgmii_init_qca955x(struct device_node *np)
> +{
> +	struct device_node *np_dev;
> +	void __iomem *gmac_base;
> +	u32 mr_an_status;
> +	u32 sgmii_status;
> +	u8 tries = 0;
> +	int err = 0;
> +
> +	np = of_get_child_by_name(np, "gmac-config");
> +	if (!np)
> +		return;
> +
> +	np_dev = of_parse_phandle(np, "device", 0);
> +	if (!np_dev)
> +		goto out;
> +
> +	gmac_base = of_iomap(np_dev, 0);
> +	if (!gmac_base) {
> +		pr_err("%pOF: can't map GMAC registers\n", np_dev);
> +		err = -ENOMEM;
> +		goto err_iomap;
> +	}
> +
> +	mr_an_status = __raw_readl(gmac_base + QCA955X_GMAC_REG_MR_AN_STATUS);
> +	if (!(mr_an_status & QCA955X_MR_AN_STATUS_AN_ABILITY))
> +		goto sgmii_out;
> +
> +	/* SGMII reset sequence */
> +	__raw_writel(QCA955X_SGMII_RESET_RX_CLK_N_RESET,
> +		     gmac_base + QCA955X_GMAC_REG_SGMII_RESET);
> +	__raw_readl(gmac_base + QCA955X_GMAC_REG_SGMII_RESET);
> +	udelay(10);
> +
> +	ag71xx_bit_set(gmac_base + QCA955X_GMAC_REG_SGMII_RESET,
> +		       QCA955X_SGMII_RESET_HW_RX_125M_N);
> +	udelay(10);
> +
> +	ag71xx_bit_set(gmac_base + QCA955X_GMAC_REG_SGMII_RESET,
> +		       QCA955X_SGMII_RESET_RX_125M_N);
> +	udelay(10);
> +
> +	ag71xx_bit_set(gmac_base + QCA955X_GMAC_REG_SGMII_RESET,
> +		       QCA955X_SGMII_RESET_TX_125M_N);
> +	udelay(10);
> +
> +	ag71xx_bit_set(gmac_base + QCA955X_GMAC_REG_SGMII_RESET,
> +		       QCA955X_SGMII_RESET_RX_CLK_N);
> +	udelay(10);
> +
> +	ag71xx_bit_set(gmac_base + QCA955X_GMAC_REG_SGMII_RESET,
> +		       QCA955X_SGMII_RESET_TX_CLK_N);
> +	udelay(10);
> +
> +	/*
> +	 * The following is what QCA has to say about what happens here:
> +	 *
> +	 * Across resets SGMII link status goes to weird state.
> +	 * If SGMII_DEBUG register reads other than 0x1f or 0x10,
> +	 * we are for sure in a bad  state.
> +	 *
> +	 * Issue a PHY reset in MR_AN_CONTROL to keep going.
> +	 */
> +	do {
> +		ag71xx_bit_set(gmac_base + QCA955X_GMAC_REG_MR_AN_CONTROL,
> +			       QCA955X_MR_AN_CONTROL_PHY_RESET |
> +			       QCA955X_MR_AN_CONTROL_AN_ENABLE);
> +		udelay(200);
> +		ag71xx_bit_clear(gmac_base + QCA955X_GMAC_REG_MR_AN_CONTROL,
> +				 QCA955X_MR_AN_CONTROL_PHY_RESET);
> +		mdelay(300);
> +		sgmii_status = __raw_readl(gmac_base + QCA955X_GMAC_REG_SGMII_DEBUG) &
> +					   QCA955X_SGMII_DEBUG_TX_STATE_MASK;
> +
> +		if (tries++ >= 20) {
> +			pr_err("ag71xx: max retries for SGMII fixup exceeded\n");
> +			break;
> +		}
> +	} while (!(sgmii_status == 0xf || sgmii_status == 0x10));
> +
> +sgmii_out:
> +	iounmap(gmac_base);
> +err_iomap:
> +	of_node_put(np_dev);
> +out:
> +	of_node_put(np);
> +}
> +
>  static void ath79_mii_ctrl_set_if(struct ag71xx *ag, unsigned int mii_if)
>  {
>  	u32 t;
> @@ -705,6 +811,8 @@ __ag71xx_link_adjust(struct ag71xx *ag, bool update)
>  			   of_device_is_compatible(np, "qca,qca9550-eth") ||
>  			   of_device_is_compatible(np, "qca,qca9560-eth")) {
>  			ath79_set_pllval(ag);
> +			if (of_property_read_bool(np, "qca955x-sgmii-fixup"))
> +				ag71xx_sgmii_init_qca955x(np);
>  		}
>  	}
>  
> diff --git a/target/linux/ath79/patches-4.14/0038-MIPS-ath79-add-missing-QCA955x-GMAC-registers.patch b/target/linux/ath79/patches-4.14/0038-MIPS-ath79-add-missing-QCA955x-GMAC-registers.patch
> new file mode 100644
> index 0000000000..111c1553d3
> --- /dev/null
> +++ b/target/linux/ath79/patches-4.14/0038-MIPS-ath79-add-missing-QCA955x-GMAC-registers.patch
> @@ -0,0 +1,91 @@
> +From 60efe35257b063ce584968f9f80b437030ce6ba6 Mon Sep 17 00:00:00 2001
> +From: David Bauer <mail at david-bauer.net>
> +Date: Mon, 18 Mar 2019 00:54:06 +0100
> +Subject: [PATCH] MIPS: ath79: add missing QCA955x GMAC registers
> +
> +This adds missing GMAC register definitions for the Qualcomm Atheros
> +QCA955X series MIPS SoCs.
> +
> +They originate from the platforms U-Boot code and the AVM FRITZ!WLAN
> +Repeater 450E's GPL tarball.
> +
> +Signed-off-by: David Bauer <mail at david-bauer.net>
> +---
> + .../mips/include/asm/mach-ath79/ar71xx_regs.h | 54 +++++++++++++++++++
> + 1 file changed, 54 insertions(+)
> +
> +--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
> ++++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
> +@@ -1245,7 +1245,12 @@
> +  */
> + 
> + #define QCA955X_GMAC_REG_ETH_CFG	0x00
> ++#define QCA955X_GMAC_REG_SGMII_RESET	0x14
> + #define QCA955X_GMAC_REG_SGMII_SERDES	0x18
> ++#define QCA955X_GMAC_REG_MR_AN_CONTROL	0x1c
> ++#define QCA955X_GMAC_REG_MR_AN_STATUS	0x20
> ++#define QCA955X_GMAC_REG_SGMII_CONFIG	0x34
> ++#define QCA955X_GMAC_REG_SGMII_DEBUG	0x58
> + 
> + #define QCA955X_ETH_CFG_RGMII_EN	BIT(0)
> + #define QCA955X_ETH_CFG_MII_GE0		BIT(1)
> +@@ -1267,9 +1272,58 @@
> + #define QCA955X_ETH_CFG_TXE_DELAY_MASK	0x3
> + #define QCA955X_ETH_CFG_TXE_DELAY_SHIFT	20
> + 
> ++#define QCA955X_SGMII_RESET_RX_CLK_N_RESET	0
> ++#define QCA955X_SGMII_RESET_RX_CLK_N		BIT(0)
> ++#define QCA955X_SGMII_RESET_TX_CLK_N		BIT(1)
> ++#define QCA955X_SGMII_RESET_RX_125M_N		BIT(2)
> ++#define QCA955X_SGMII_RESET_TX_125M_N		BIT(3)
> ++#define QCA955X_SGMII_RESET_HW_RX_125M_N	BIT(4)
> ++
> + #define QCA955X_SGMII_SERDES_LOCK_DETECT_STATUS	BIT(15)
> + #define QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT 23
> + #define QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK 0xf
> ++
> ++#define QCA955X_MR_AN_CONTROL_SPEED_SEL1	BIT(6)
> ++#define QCA955X_MR_AN_CONTROL_DUPLEX_MODE	BIT(8)
> ++#define QCA955X_MR_AN_CONTROL_RESTART_AN	BIT(9)
> ++#define QCA955X_MR_AN_CONTROL_POWER_DOWN	BIT(11)
> ++#define QCA955X_MR_AN_CONTROL_AN_ENABLE		BIT(12)
> ++#define QCA955X_MR_AN_CONTROL_SPEED_SEL0	BIT(13)
> ++#define QCA955X_MR_AN_CONTROL_LOOPBACK		BIT(14)
> ++#define QCA955X_MR_AN_CONTROL_PHY_RESET		BIT(15)
> ++
> ++#define QCA955X_MR_AN_STATUS_EXT_CAP		BIT(0)
> ++#define QCA955X_MR_AN_STATUS_LINK_UP		BIT(2)
> ++#define QCA955X_MR_AN_STATUS_AN_ABILITY		BIT(3)
> ++#define QCA955X_MR_AN_STATUS_REMOTE_FAULT	BIT(4)
> ++#define QCA955X_MR_AN_STATUS_AN_COMPLETE	BIT(5)
> ++#define QCA955X_MR_AN_STATUS_NO_PREAMBLE	BIT(6)
> ++#define QCA955X_MR_AN_STATUS_BASE_PAGE		BIT(7)
> ++
> ++#define QCA955X_SGMII_CONFIG_MODE_CTRL_SHIFT		0
> ++#define QCA955X_SGMII_CONFIG_MODE_CTRL_MASK		0x7
> ++#define QCA955X_SGMII_CONFIG_ENABLE_SGMII_TX_PAUSE	BIT(3)
> ++#define QCA955X_SGMII_CONFIG_MR_REG4_CHANGED		BIT(4)
> ++#define QCA955X_SGMII_CONFIG_FORCE_SPEED		BIT(5)
> ++#define QCA955X_SGMII_CONFIG_SPEED_SHIFT		6
> ++#define QCA955X_SGMII_CONFIG_SPEED_MASK			0xc0
> ++#define QCA955X_SGMII_CONFIG_REMOTE_PHY_LOOPBACK	BIT(8)
> ++#define QCA955X_SGMII_CONFIG_NEXT_PAGE_LOADED		BIT(9)
> ++#define QCA955X_SGMII_CONFIG_MDIO_ENABLE		BIT(10)
> ++#define QCA955X_SGMII_CONFIG_MDIO_PULSE			BIT(11)
> ++#define QCA955X_SGMII_CONFIG_MDIO_COMPLETE		BIT(12)
> ++#define QCA955X_SGMII_CONFIG_PRBS_ENABLE		BIT(13)
> ++#define QCA955X_SGMII_CONFIG_BERT_ENABLE		BIT(14)
> ++
> ++#define QCA955X_SGMII_DEBUG_TX_STATE_MASK	0xff
> ++#define QCA955X_SGMII_DEBUG_TX_STATE_SHIFT	0
> ++#define QCA955X_SGMII_DEBUG_RX_STATE_MASK	0xff00
> ++#define QCA955X_SGMII_DEBUG_RX_STATE_SHIFT	8
> ++#define QCA955X_SGMII_DEBUG_RX_SYNC_STATE_MASK	0xff0000
> ++#define QCA955X_SGMII_DEBUG_RX_SYNC_STATE_SHIFT	16
> ++#define QCA955X_SGMII_DEBUG_ARB_STATE_MASK	0xf000000
> ++#define QCA955X_SGMII_DEBUG_ARB_STATE_SHIFT	24
> ++
> + /*
> +  * QCA956X GMAC Interface
> +  */
> +
> diff --git a/target/linux/ath79/patches-4.19/0038-MIPS-ath79-add-missing-QCA955x-GMAC-registers.patch b/target/linux/ath79/patches-4.19/0038-MIPS-ath79-add-missing-QCA955x-GMAC-registers.patch
> new file mode 100644
> index 0000000000..111c1553d3
> --- /dev/null
> +++ b/target/linux/ath79/patches-4.19/0038-MIPS-ath79-add-missing-QCA955x-GMAC-registers.patch
> @@ -0,0 +1,91 @@
> +From 60efe35257b063ce584968f9f80b437030ce6ba6 Mon Sep 17 00:00:00 2001
> +From: David Bauer <mail at david-bauer.net>
> +Date: Mon, 18 Mar 2019 00:54:06 +0100
> +Subject: [PATCH] MIPS: ath79: add missing QCA955x GMAC registers
> +
> +This adds missing GMAC register definitions for the Qualcomm Atheros
> +QCA955X series MIPS SoCs.
> +
> +They originate from the platforms U-Boot code and the AVM FRITZ!WLAN
> +Repeater 450E's GPL tarball.
> +
> +Signed-off-by: David Bauer <mail at david-bauer.net>
> +---
> + .../mips/include/asm/mach-ath79/ar71xx_regs.h | 54 +++++++++++++++++++
> + 1 file changed, 54 insertions(+)
> +
> +--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
> ++++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
> +@@ -1245,7 +1245,12 @@
> +  */
> + 
> + #define QCA955X_GMAC_REG_ETH_CFG	0x00
> ++#define QCA955X_GMAC_REG_SGMII_RESET	0x14
> + #define QCA955X_GMAC_REG_SGMII_SERDES	0x18
> ++#define QCA955X_GMAC_REG_MR_AN_CONTROL	0x1c
> ++#define QCA955X_GMAC_REG_MR_AN_STATUS	0x20
> ++#define QCA955X_GMAC_REG_SGMII_CONFIG	0x34
> ++#define QCA955X_GMAC_REG_SGMII_DEBUG	0x58
> + 
> + #define QCA955X_ETH_CFG_RGMII_EN	BIT(0)
> + #define QCA955X_ETH_CFG_MII_GE0		BIT(1)
> +@@ -1267,9 +1272,58 @@
> + #define QCA955X_ETH_CFG_TXE_DELAY_MASK	0x3
> + #define QCA955X_ETH_CFG_TXE_DELAY_SHIFT	20
> + 
> ++#define QCA955X_SGMII_RESET_RX_CLK_N_RESET	0
> ++#define QCA955X_SGMII_RESET_RX_CLK_N		BIT(0)
> ++#define QCA955X_SGMII_RESET_TX_CLK_N		BIT(1)
> ++#define QCA955X_SGMII_RESET_RX_125M_N		BIT(2)
> ++#define QCA955X_SGMII_RESET_TX_125M_N		BIT(3)
> ++#define QCA955X_SGMII_RESET_HW_RX_125M_N	BIT(4)
> ++
> + #define QCA955X_SGMII_SERDES_LOCK_DETECT_STATUS	BIT(15)
> + #define QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT 23
> + #define QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK 0xf
> ++
> ++#define QCA955X_MR_AN_CONTROL_SPEED_SEL1	BIT(6)
> ++#define QCA955X_MR_AN_CONTROL_DUPLEX_MODE	BIT(8)
> ++#define QCA955X_MR_AN_CONTROL_RESTART_AN	BIT(9)
> ++#define QCA955X_MR_AN_CONTROL_POWER_DOWN	BIT(11)
> ++#define QCA955X_MR_AN_CONTROL_AN_ENABLE		BIT(12)
> ++#define QCA955X_MR_AN_CONTROL_SPEED_SEL0	BIT(13)
> ++#define QCA955X_MR_AN_CONTROL_LOOPBACK		BIT(14)
> ++#define QCA955X_MR_AN_CONTROL_PHY_RESET		BIT(15)
> ++
> ++#define QCA955X_MR_AN_STATUS_EXT_CAP		BIT(0)
> ++#define QCA955X_MR_AN_STATUS_LINK_UP		BIT(2)
> ++#define QCA955X_MR_AN_STATUS_AN_ABILITY		BIT(3)
> ++#define QCA955X_MR_AN_STATUS_REMOTE_FAULT	BIT(4)
> ++#define QCA955X_MR_AN_STATUS_AN_COMPLETE	BIT(5)
> ++#define QCA955X_MR_AN_STATUS_NO_PREAMBLE	BIT(6)
> ++#define QCA955X_MR_AN_STATUS_BASE_PAGE		BIT(7)
> ++
> ++#define QCA955X_SGMII_CONFIG_MODE_CTRL_SHIFT		0
> ++#define QCA955X_SGMII_CONFIG_MODE_CTRL_MASK		0x7
> ++#define QCA955X_SGMII_CONFIG_ENABLE_SGMII_TX_PAUSE	BIT(3)
> ++#define QCA955X_SGMII_CONFIG_MR_REG4_CHANGED		BIT(4)
> ++#define QCA955X_SGMII_CONFIG_FORCE_SPEED		BIT(5)
> ++#define QCA955X_SGMII_CONFIG_SPEED_SHIFT		6
> ++#define QCA955X_SGMII_CONFIG_SPEED_MASK			0xc0
> ++#define QCA955X_SGMII_CONFIG_REMOTE_PHY_LOOPBACK	BIT(8)
> ++#define QCA955X_SGMII_CONFIG_NEXT_PAGE_LOADED		BIT(9)
> ++#define QCA955X_SGMII_CONFIG_MDIO_ENABLE		BIT(10)
> ++#define QCA955X_SGMII_CONFIG_MDIO_PULSE			BIT(11)
> ++#define QCA955X_SGMII_CONFIG_MDIO_COMPLETE		BIT(12)
> ++#define QCA955X_SGMII_CONFIG_PRBS_ENABLE		BIT(13)
> ++#define QCA955X_SGMII_CONFIG_BERT_ENABLE		BIT(14)
> ++
> ++#define QCA955X_SGMII_DEBUG_TX_STATE_MASK	0xff
> ++#define QCA955X_SGMII_DEBUG_TX_STATE_SHIFT	0
> ++#define QCA955X_SGMII_DEBUG_RX_STATE_MASK	0xff00
> ++#define QCA955X_SGMII_DEBUG_RX_STATE_SHIFT	8
> ++#define QCA955X_SGMII_DEBUG_RX_SYNC_STATE_MASK	0xff0000
> ++#define QCA955X_SGMII_DEBUG_RX_SYNC_STATE_SHIFT	16
> ++#define QCA955X_SGMII_DEBUG_ARB_STATE_MASK	0xf000000
> ++#define QCA955X_SGMII_DEBUG_ARB_STATE_SHIFT	24
> ++
> + /*
> +  * QCA956X GMAC Interface
> +  */
> +
> 







More information about the openwrt-devel mailing list