[OpenWrt-Devel,2/4] ath79: add QCA955x SGMII link loss workaround
diff mbox series

Message ID 20190411155945.28600-2-mail@david-bauer.net
State Under Review
Delegated to: David Bauer
Headers show
Series
  • [OpenWrt-Devel,1/4] ath79: fix QCA955x GMAC register size
Related show

Commit Message

David Bauer April 11, 2019, 3:59 p.m. UTC
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@david-bauer.net>
---
 .../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

Comments

Christian Lamparter May 31, 2019, 1:34 p.m. UTC | #1
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@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@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@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@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@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
> +  */
> +
>
Chuanhong Guo May 31, 2019, 2:44 p.m. UTC | #2
Hi!

On Fri, May 31, 2019 at 9:34 PM Christian Lamparter <chunkeey@gmail.com> wrote:
>
> 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* :(
>
The upstream driver is pretty much broken on every SoCs with external
PHY/switch. Getting every ath79 SoC working with that driver is
already a headache.
I think we should just keep maintaining our ag71xx driver until
someone having a pile of ath79 routers get that driver working.
Christian Lamparter May 31, 2019, 4:26 p.m. UTC | #3
On Friday, May 31, 2019 4:44:50 PM CEST Chuanhong Guo wrote:
> Hi!
> 
> On Fri, May 31, 2019 at 9:34 PM Christian Lamparter <chunkeey@gmail.com> wrote:
> >
> > 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* :(
> >
> The upstream driver is pretty much broken on every SoCs with external
> PHY/switch. Getting every ath79 SoC working with that driver is
> already a headache.
>
> I think we should just keep maintaining our ag71xx driver until
> someone having a pile of ath79 routers get that driver working.

Well, look what happend to ar71xx then. The development on it is being
defered in favor of the upstream ath79 dts. So what do you think will
happen to the special out-of-tree ag71xx drivers now?

Cheers,
Christian
Chuanhong Guo June 1, 2019, 2:15 a.m. UTC | #4
On Sat, Jun 1, 2019 at 12:26 AM Christian Lamparter <chunkeey@gmail.com> wrote:
>
> On Friday, May 31, 2019 4:44:50 PM CEST Chuanhong Guo wrote:
> > Hi!
> >
> > On Fri, May 31, 2019 at 9:34 PM Christian Lamparter <chunkeey@gmail.com> wrote:
> > >
> > > 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* :(
> > >
> > The upstream driver is pretty much broken on every SoCs with external
> > PHY/switch. Getting every ath79 SoC working with that driver is
> > already a headache.
> >
> > I think we should just keep maintaining our ag71xx driver until
> > someone having a pile of ath79 routers get that driver working.
>
> Well, look what happend to ar71xx then. The development on it is being
> defered in favor of the upstream ath79 dts. So what do you think will
> happen to the special out-of-tree ag71xx drivers now?

That happens after we got ath79 target working. There is a period of
time when ath79 has broken wireless support, during which ar71xx
patches were still accepted.

Author of upstream ag71xx driver did a 'rework' of OpenWrt ag71xx
driver dropped all mii interface configuration stuff. Unless someone
patches it back, it won't work on qca9558 in this case.
To upstream this particular patch, we need to:
1. patch mii interface configuration code back. (Somehow we named it
PLL and the author thought it's a clock register that doesn't belong
to ethernet driver.)
2. patch the miscellaneous ethernet-related configuration code back.
(gmac-config in our driver which is used by this patch.)
Our current code for both of them will have little chance being
accepted by upstream.

Since this patch depends on gmac-config that doesn't exist in upstream
ag71xx yet and we won't be using the upstream driver in upcoming 19.x
release, I think it's fine to have this problem fixed in our driver
and then port it upstream (likely to be a rework) with gmac-config
code.
Rosen Penev June 2, 2019, 6:31 a.m. UTC | #5
On Fri, May 31, 2019 at 7:16 PM Chuanhong Guo <gch981213@gmail.com> wrote:
>
> On Sat, Jun 1, 2019 at 12:26 AM Christian Lamparter <chunkeey@gmail.com> wrote:
> >
> > On Friday, May 31, 2019 4:44:50 PM CEST Chuanhong Guo wrote:
> > > Hi!
> > >
> > > On Fri, May 31, 2019 at 9:34 PM Christian Lamparter <chunkeey@gmail.com> wrote:
> > > >
> > > > 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* :(
> > > >
> > > The upstream driver is pretty much broken on every SoCs with external
> > > PHY/switch. Getting every ath79 SoC working with that driver is
> > > already a headache.
> > >
> > > I think we should just keep maintaining our ag71xx driver until
> > > someone having a pile of ath79 routers get that driver working.
> >
> > Well, look what happend to ar71xx then. The development on it is being
> > defered in favor of the upstream ath79 dts. So what do you think will
> > happen to the special out-of-tree ag71xx drivers now?
>
> That happens after we got ath79 target working. There is a period of
> time when ath79 has broken wireless support, during which ar71xx
> patches were still accepted.
>
> Author of upstream ag71xx driver did a 'rework' of OpenWrt ag71xx
> driver dropped all mii interface configuration stuff. Unless someone
> patches it back, it won't work on qca9558 in this case.
> To upstream this particular patch, we need to:
> 1. patch mii interface configuration code back. (Somehow we named it
> PLL and the author thought it's a clock register that doesn't belong
> to ethernet driver.)
> 2. patch the miscellaneous ethernet-related configuration code back.
> (gmac-config in our driver which is used by this patch.)
> Our current code for both of them will have little chance being
> accepted by upstream.
>
> Since this patch depends on gmac-config that doesn't exist in upstream
> ag71xx yet and we won't be using the upstream driver in upcoming 19.x
> release, I think it's fine to have this problem fixed in our driver
> and then port it upstream (likely to be a rework) with gmac-config
> code.
That's the current situation with ramips as well.
>
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel@lists.openwrt.org
> https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Patch
diff mbox series

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@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@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@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@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
+  */
+