diff mbox series

[OpenWrt-Devel,1/3] kernel: ar83xx: Add support for three GMAC's connection

Message ID 1539947862-6262-1-git-send-email-rjangir@codeaurora.org
State Changes Requested
Delegated to: John Crispin
Headers show
Series [OpenWrt-Devel,1/3] kernel: ar83xx: Add support for three GMAC's connection | expand

Commit Message

Ram Chandra Jangir Oct. 19, 2018, 11:17 a.m. UTC
We have IPQ8064 AP161 board which has three GMAC's
 * RGMII x2
 * SGMII x1.
The existing ar8327 driver does not have support for
three GMAC's connection, hence this change adds support
for the same. This has been verified on AP148 and AP161
board.

Signed-off-by: xiaofeis <xiaofeis@codeaurora.org>
Signed-off-by: Ram Chandra Jangir <rjangir@codeaurora.org>
---
 .../linux/generic/files/drivers/net/phy/ar8216.c   | 15 +++++++-
 .../linux/generic/files/drivers/net/phy/ar8216.h   |  4 ++
 .../linux/generic/files/drivers/net/phy/ar8327.c   | 43 ++++++++++++++++++++++
 .../linux/generic/files/drivers/net/phy/ar8327.h   |  7 ++++
 4 files changed, 68 insertions(+), 1 deletion(-)

Comments

John Crispin Nov. 26, 2018, 9:45 a.m. UTC | #1
On 19/10/2018 13:17, Ram Chandra Jangir wrote:
> We have IPQ8064 AP161 board which has three GMAC's
>   * RGMII x2
>   * SGMII x1.
> The existing ar8327 driver does not have support for
> three GMAC's connection, hence this change adds support
> for the same. This has been verified on AP148 and AP161
> board.
>
> Signed-off-by: xiaofeis <xiaofeis@codeaurora.org>
> Signed-off-by: Ram Chandra Jangir <rjangir@codeaurora.org>
> ---
>   .../linux/generic/files/drivers/net/phy/ar8216.c   | 15 +++++++-
>   .../linux/generic/files/drivers/net/phy/ar8216.h   |  4 ++
>   .../linux/generic/files/drivers/net/phy/ar8327.c   | 43 ++++++++++++++++++++++
>   .../linux/generic/files/drivers/net/phy/ar8327.h   |  7 ++++
>   4 files changed, 68 insertions(+), 1 deletion(-)
>
> diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c
> index 7512ee1..4c9c9ae 100644
> --- a/target/linux/generic/files/drivers/net/phy/ar8216.c
> +++ b/target/linux/generic/files/drivers/net/phy/ar8216.c
> @@ -295,6 +295,17 @@ ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
>   
>   	return ret;
>   }
> +void
> +ar8xxx_phy_dbg_read(struct ar8xxx_priv *priv, int phy_addr,
> +           u16 dbg_addr, u16 *dbg_data)
> +{
> +       struct mii_bus *bus = priv->mii_bus;
> +
> +       mutex_lock(&bus->mdio_lock);
> +       bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr);
> +       *dbg_data = bus->read(bus, phy_addr, MII_ATH_DBG_DATA);
> +       mutex_unlock(&bus->mdio_lock);
> +}
>   
>   void
>   ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr,
> @@ -2167,7 +2178,7 @@ ar8xxx_phy_probe(struct phy_device *phydev)
>   	int ret;
>   
>   	/* skip PHYs at unused adresses */
> -	if (phydev->mdio.addr != 0 && phydev->mdio.addr != 4)
> +	if (phydev->mdio.addr != 0 && phydev->mdio.addr != 3 && phydev->mdio.addr != 4)
>   		return -ENODEV;
>   
>   	if (!ar8xxx_is_possible(phydev->mdio.bus))
> @@ -2226,6 +2237,8 @@ found:
>   			phydev->supported |= SUPPORTED_1000baseT_Full;
>   			phydev->advertising |= ADVERTISED_1000baseT_Full;
>   		}
> +		if (priv->chip->phy_rgmii_set)
> +			priv->chip->phy_rgmii_set(priv, phydev);
>   	}
>   
>   	phydev->priv = priv;
> diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.h b/target/linux/generic/files/drivers/net/phy/ar8216.h
> index ba0e0dd..ecb91f4 100644
> --- a/target/linux/generic/files/drivers/net/phy/ar8216.h
> +++ b/target/linux/generic/files/drivers/net/phy/ar8216.h
> @@ -412,6 +412,7 @@ struct ar8xxx_chip {
>   	void (*get_arl_entry)(struct ar8xxx_priv *priv, struct arl_entry *a,
>   			      u32 *status, enum arl_op op);
>   	int (*sw_hw_apply)(struct switch_dev *dev);
> +	void (*phy_rgmii_set)(struct ar8xxx_priv *priv, struct phy_device *phydev);
>   
>   	const struct ar8xxx_mib_desc *mib_decs;
>   	unsigned num_mibs;
> @@ -477,6 +478,9 @@ u32
>   ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val);
>   
>   void
> +ar8xxx_phy_dbg_read(struct ar8xxx_priv *priv, int phy_addr,
> +		u16 dbg_addr, u16 *dbg_data);
> +void
>   ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr,
>   		     u16 dbg_addr, u16 dbg_data);
>   void
> diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.c b/target/linux/generic/files/drivers/net/phy/ar8327.c
> index 74f0a08..6fe7bb1 100644
> --- a/target/linux/generic/files/drivers/net/phy/ar8327.c
> +++ b/target/linux/generic/files/drivers/net/phy/ar8327.c
> @@ -128,6 +128,48 @@ ar8327_get_pad_cfg(struct ar8327_pad_cfg *cfg)
>   }
>   
>   static void
> +ar8327_phy_rgmii_set(struct ar8xxx_priv *priv, struct phy_device *phydev)
> +{
> +	u32 rgmii = 0, tx_delay = 0, rx_delay = 0;
> +	u16 phy_val = 0;
> +	int phyaddr = phydev->mdio.addr;
> +	struct device_node *np = phydev->mdio.dev.of_node;
> +
> +	if (!np)
> +		return;
> +
> +	if (!of_property_read_u32(np, "phy_rgmii_en", &rgmii)) {
> +		if (!rgmii)
> +		return;
> +		ar8xxx_phy_dbg_read(priv, phyaddr,
> +		AR8327_PHY_MODE_SEL, &phy_val);
> +		phy_val |= AR8327_PHY_MODE_SEL_RGMII;
> +		ar8xxx_phy_dbg_write(priv, phyaddr,
> +				AR8327_PHY_MODE_SEL, phy_val);
> +
> +		/* set rgmii tx clock delay if needed */
> +		if (!of_property_read_u32(np, "txclk_delay_en", &tx_delay)

property names need to be prefixed by qca, and use dashes and not 
underscores. please make these properties boolean and return directly 
when they are not present, rather than indenting the code block

     John



> +						&& tx_delay == 1) {
> +			ar8xxx_phy_dbg_read(priv, phyaddr,
> +			AR8327_PHY_SYS_CTRL, &phy_val);
> +			phy_val |= AR8327_PHY_SYS_CTRL_RGMII_TX_DELAY;
> +			ar8xxx_phy_dbg_write(priv, phyaddr,
> +						AR8327_PHY_SYS_CTRL, phy_val);
> +		}
> +
> +		/* set rgmii rx clock delay if needed */
> +		if (!of_property_read_u32(np, "rxclk_delay_en", &rx_delay)
> +						&& rx_delay == 1) {
> +			ar8xxx_phy_dbg_read(priv, phyaddr,
> +						AR8327_PHY_TEST_CTRL, &phy_val);
> +			phy_val |= AR8327_PHY_TEST_CTRL_RGMII_RX_DELAY;
> +			ar8xxx_phy_dbg_write(priv, phyaddr,
> +						AR8327_PHY_TEST_CTRL, phy_val);
> +		}
> +	}
> +}
> +
> +static void
>   ar8327_phy_fixup(struct ar8xxx_priv *priv, int phy)
>   {
>   	switch (priv->chip_rev) {
> @@ -1496,6 +1538,7 @@ const struct ar8xxx_chip ar8337_chip = {
>   	.set_mirror_regs = ar8327_set_mirror_regs,
>   	.get_arl_entry = ar8327_get_arl_entry,
>   	.sw_hw_apply = ar8327_sw_hw_apply,
> +	.phy_rgmii_set = ar8327_phy_rgmii_set,
>   
>   	.num_mibs = ARRAY_SIZE(ar8236_mibs),
>   	.mib_decs = ar8236_mibs,
> diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.h b/target/linux/generic/files/drivers/net/phy/ar8327.h
> index d53ef88..d79f14a 100644
> --- a/target/linux/generic/files/drivers/net/phy/ar8327.h
> +++ b/target/linux/generic/files/drivers/net/phy/ar8327.h
> @@ -283,6 +283,13 @@
>   
>   #define AR8337_PAD_MAC06_EXCHANGE_EN		BIT(31)
>   
> +#define AR8327_PHY_MODE_SEL			0x12
> +#define   AR8327_PHY_MODE_SEL_RGMII		BIT(3)
> +#define AR8327_PHY_TEST_CTRL			0x0
> +#define   AR8327_PHY_TEST_CTRL_RGMII_RX_DELAY	BIT(15)
> +#define AR8327_PHY_SYS_CTRL			0x5
> +#define   AR8327_PHY_SYS_CTRL_RGMII_TX_DELAY	BIT(8)
> +
>   enum ar8327_led_pattern {
>   	AR8327_LED_PATTERN_OFF = 0,
>   	AR8327_LED_PATTERN_BLINK,
Ram Chandra Jangir Nov. 28, 2018, 12:49 p.m. UTC | #2
On 11/26/2018 3:15 PM, John Crispin wrote:
> 
> On 19/10/2018 13:17, Ram Chandra Jangir wrote:
>> We have IPQ8064 AP161 board which has three GMAC's
>>   * RGMII x2
>>   * SGMII x1.
>> The existing ar8327 driver does not have support for
>> three GMAC's connection, hence this change adds support
>> for the same. This has been verified on AP148 and AP161
>> board.
>>
>> Signed-off-by: xiaofeis <xiaofeis@codeaurora.org>
>> Signed-off-by: Ram Chandra Jangir <rjangir@codeaurora.org>
>> ---
>>   .../linux/generic/files/drivers/net/phy/ar8216.c   | 15 +++++++-
>>   .../linux/generic/files/drivers/net/phy/ar8216.h   |  4 ++
>>   .../linux/generic/files/drivers/net/phy/ar8327.c   | 43 
>> ++++++++++++++++++++++
>>   .../linux/generic/files/drivers/net/phy/ar8327.h   |  7 ++++
>>   4 files changed, 68 insertions(+), 1 deletion(-)
>>
>> diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c 
>> b/target/linux/generic/files/drivers/net/phy/ar8216.c
>> index 7512ee1..4c9c9ae 100644
>> --- a/target/linux/generic/files/drivers/net/phy/ar8216.c
>> +++ b/target/linux/generic/files/drivers/net/phy/ar8216.c
>> @@ -295,6 +295,17 @@ ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 
>> mask, u32 val)
>>
>>       return ret;
>>   }
>> +void
>> +ar8xxx_phy_dbg_read(struct ar8xxx_priv *priv, int phy_addr,
>> +           u16 dbg_addr, u16 *dbg_data)
>> +{
>> +       struct mii_bus *bus = priv->mii_bus;
>> +
>> +       mutex_lock(&bus->mdio_lock);
>> +       bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr);
>> +       *dbg_data = bus->read(bus, phy_addr, MII_ATH_DBG_DATA);
>> +       mutex_unlock(&bus->mdio_lock);
>> +}
>>
>>   void
>>   ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr,
>> @@ -2167,7 +2178,7 @@ ar8xxx_phy_probe(struct phy_device *phydev)
>>       int ret;
>>
>>       /* skip PHYs at unused adresses */
>> -    if (phydev->mdio.addr != 0 && phydev->mdio.addr != 4)
>> +    if (phydev->mdio.addr != 0 && phydev->mdio.addr != 3 && 
>> phydev->mdio.addr != 4)
>>           return -ENODEV;
>>
>>       if (!ar8xxx_is_possible(phydev->mdio.bus))
>> @@ -2226,6 +2237,8 @@ found:
>>               phydev->supported |= SUPPORTED_1000baseT_Full;
>>               phydev->advertising |= ADVERTISED_1000baseT_Full;
>>           }
>> +        if (priv->chip->phy_rgmii_set)
>> +            priv->chip->phy_rgmii_set(priv, phydev);
>>       }
>>
>>       phydev->priv = priv;
>> diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.h 
>> b/target/linux/generic/files/drivers/net/phy/ar8216.h
>> index ba0e0dd..ecb91f4 100644
>> --- a/target/linux/generic/files/drivers/net/phy/ar8216.h
>> +++ b/target/linux/generic/files/drivers/net/phy/ar8216.h
>> @@ -412,6 +412,7 @@ struct ar8xxx_chip {
>>       void (*get_arl_entry)(struct ar8xxx_priv *priv, struct arl_entry 
>> *a,
>>                     u32 *status, enum arl_op op);
>>       int (*sw_hw_apply)(struct switch_dev *dev);
>> +    void (*phy_rgmii_set)(struct ar8xxx_priv *priv, struct phy_device 
>> *phydev);
>>
>>       const struct ar8xxx_mib_desc *mib_decs;
>>       unsigned num_mibs;
>> @@ -477,6 +478,9 @@ u32
>>   ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val);
>>
>>   void
>> +ar8xxx_phy_dbg_read(struct ar8xxx_priv *priv, int phy_addr,
>> +        u16 dbg_addr, u16 *dbg_data);
>> +void
>>   ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr,
>>                u16 dbg_addr, u16 dbg_data);
>>   void
>> diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.c 
>> b/target/linux/generic/files/drivers/net/phy/ar8327.c
>> index 74f0a08..6fe7bb1 100644
>> --- a/target/linux/generic/files/drivers/net/phy/ar8327.c
>> +++ b/target/linux/generic/files/drivers/net/phy/ar8327.c
>> @@ -128,6 +128,48 @@ ar8327_get_pad_cfg(struct ar8327_pad_cfg *cfg)
>>   }
>>
>>   static void
>> +ar8327_phy_rgmii_set(struct ar8xxx_priv *priv, struct phy_device 
>> *phydev)
>> +{
>> +    u32 rgmii = 0, tx_delay = 0, rx_delay = 0;
>> +    u16 phy_val = 0;
>> +    int phyaddr = phydev->mdio.addr;
>> +    struct device_node *np = phydev->mdio.dev.of_node;
>> +
>> +    if (!np)
>> +        return;
>> +
>> +    if (!of_property_read_u32(np, "phy_rgmii_en", &rgmii)) {
>> +        if (!rgmii)
>> +        return;
>> +        ar8xxx_phy_dbg_read(priv, phyaddr,
>> +        AR8327_PHY_MODE_SEL, &phy_val);
>> +        phy_val |= AR8327_PHY_MODE_SEL_RGMII;
>> +        ar8xxx_phy_dbg_write(priv, phyaddr,
>> +                AR8327_PHY_MODE_SEL, phy_val);
>> +
>> +        /* set rgmii tx clock delay if needed */
>> +        if (!of_property_read_u32(np, "txclk_delay_en", &tx_delay)
> 
> property names need to be prefixed by qca, and use dashes and not
> underscores. please make these properties boolean and return directly
> when they are not present, rather than indenting the code block
> 
>      John
Thanks John,
Sure, will update it in next patchset.

Thanks,
Ram
> 
> 
> 
>> +                        && tx_delay == 1) {
>> +            ar8xxx_phy_dbg_read(priv, phyaddr,
>> +            AR8327_PHY_SYS_CTRL, &phy_val);
>> +            phy_val |= AR8327_PHY_SYS_CTRL_RGMII_TX_DELAY;
>> +            ar8xxx_phy_dbg_write(priv, phyaddr,
>> +                        AR8327_PHY_SYS_CTRL, phy_val);
>> +        }
>> +
>> +        /* set rgmii rx clock delay if needed */
>> +        if (!of_property_read_u32(np, "rxclk_delay_en", &rx_delay)
>> +                        && rx_delay == 1) {
>> +            ar8xxx_phy_dbg_read(priv, phyaddr,
>> +                        AR8327_PHY_TEST_CTRL, &phy_val);
>> +            phy_val |= AR8327_PHY_TEST_CTRL_RGMII_RX_DELAY;
>> +            ar8xxx_phy_dbg_write(priv, phyaddr,
>> +                        AR8327_PHY_TEST_CTRL, phy_val);
>> +        }
>> +    }
>> +}
>> +
>> +static void
>>   ar8327_phy_fixup(struct ar8xxx_priv *priv, int phy)
>>   {
>>       switch (priv->chip_rev) {
>> @@ -1496,6 +1538,7 @@ const struct ar8xxx_chip ar8337_chip = {
>>       .set_mirror_regs = ar8327_set_mirror_regs,
>>       .get_arl_entry = ar8327_get_arl_entry,
>>       .sw_hw_apply = ar8327_sw_hw_apply,
>> +    .phy_rgmii_set = ar8327_phy_rgmii_set,
>>
>>       .num_mibs = ARRAY_SIZE(ar8236_mibs),
>>       .mib_decs = ar8236_mibs,
>> diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.h 
>> b/target/linux/generic/files/drivers/net/phy/ar8327.h
>> index d53ef88..d79f14a 100644
>> --- a/target/linux/generic/files/drivers/net/phy/ar8327.h
>> +++ b/target/linux/generic/files/drivers/net/phy/ar8327.h
>> @@ -283,6 +283,13 @@
>>
>>   #define AR8337_PAD_MAC06_EXCHANGE_EN        BIT(31)
>>
>> +#define AR8327_PHY_MODE_SEL            0x12
>> +#define   AR8327_PHY_MODE_SEL_RGMII        BIT(3)
>> +#define AR8327_PHY_TEST_CTRL            0x0
>> +#define   AR8327_PHY_TEST_CTRL_RGMII_RX_DELAY    BIT(15)
>> +#define AR8327_PHY_SYS_CTRL            0x5
>> +#define   AR8327_PHY_SYS_CTRL_RGMII_TX_DELAY    BIT(8)
>> +
>>   enum ar8327_led_pattern {
>>       AR8327_LED_PATTERN_OFF = 0,
>>       AR8327_LED_PATTERN_BLINK,
> 
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel@lists.openwrt.org
> https://lists.openwrt.org/mailman/listinfo/openwrt-devel
diff mbox series

Patch

diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c
index 7512ee1..4c9c9ae 100644
--- a/target/linux/generic/files/drivers/net/phy/ar8216.c
+++ b/target/linux/generic/files/drivers/net/phy/ar8216.c
@@ -295,6 +295,17 @@  ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
 
 	return ret;
 }
+void
+ar8xxx_phy_dbg_read(struct ar8xxx_priv *priv, int phy_addr,
+           u16 dbg_addr, u16 *dbg_data)
+{
+       struct mii_bus *bus = priv->mii_bus;
+
+       mutex_lock(&bus->mdio_lock);
+       bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr);
+       *dbg_data = bus->read(bus, phy_addr, MII_ATH_DBG_DATA);
+       mutex_unlock(&bus->mdio_lock);
+}
 
 void
 ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr,
@@ -2167,7 +2178,7 @@  ar8xxx_phy_probe(struct phy_device *phydev)
 	int ret;
 
 	/* skip PHYs at unused adresses */
-	if (phydev->mdio.addr != 0 && phydev->mdio.addr != 4)
+	if (phydev->mdio.addr != 0 && phydev->mdio.addr != 3 && phydev->mdio.addr != 4)
 		return -ENODEV;
 
 	if (!ar8xxx_is_possible(phydev->mdio.bus))
@@ -2226,6 +2237,8 @@  found:
 			phydev->supported |= SUPPORTED_1000baseT_Full;
 			phydev->advertising |= ADVERTISED_1000baseT_Full;
 		}
+		if (priv->chip->phy_rgmii_set)
+			priv->chip->phy_rgmii_set(priv, phydev);
 	}
 
 	phydev->priv = priv;
diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.h b/target/linux/generic/files/drivers/net/phy/ar8216.h
index ba0e0dd..ecb91f4 100644
--- a/target/linux/generic/files/drivers/net/phy/ar8216.h
+++ b/target/linux/generic/files/drivers/net/phy/ar8216.h
@@ -412,6 +412,7 @@  struct ar8xxx_chip {
 	void (*get_arl_entry)(struct ar8xxx_priv *priv, struct arl_entry *a,
 			      u32 *status, enum arl_op op);
 	int (*sw_hw_apply)(struct switch_dev *dev);
+	void (*phy_rgmii_set)(struct ar8xxx_priv *priv, struct phy_device *phydev);
 
 	const struct ar8xxx_mib_desc *mib_decs;
 	unsigned num_mibs;
@@ -477,6 +478,9 @@  u32
 ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val);
 
 void
+ar8xxx_phy_dbg_read(struct ar8xxx_priv *priv, int phy_addr,
+		u16 dbg_addr, u16 *dbg_data);
+void
 ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr,
 		     u16 dbg_addr, u16 dbg_data);
 void
diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.c b/target/linux/generic/files/drivers/net/phy/ar8327.c
index 74f0a08..6fe7bb1 100644
--- a/target/linux/generic/files/drivers/net/phy/ar8327.c
+++ b/target/linux/generic/files/drivers/net/phy/ar8327.c
@@ -128,6 +128,48 @@  ar8327_get_pad_cfg(struct ar8327_pad_cfg *cfg)
 }
 
 static void
+ar8327_phy_rgmii_set(struct ar8xxx_priv *priv, struct phy_device *phydev)
+{
+	u32 rgmii = 0, tx_delay = 0, rx_delay = 0;
+	u16 phy_val = 0;
+	int phyaddr = phydev->mdio.addr;
+	struct device_node *np = phydev->mdio.dev.of_node;
+
+	if (!np)
+		return;
+
+	if (!of_property_read_u32(np, "phy_rgmii_en", &rgmii)) {
+		if (!rgmii)
+		return;
+		ar8xxx_phy_dbg_read(priv, phyaddr,
+		AR8327_PHY_MODE_SEL, &phy_val);
+		phy_val |= AR8327_PHY_MODE_SEL_RGMII;
+		ar8xxx_phy_dbg_write(priv, phyaddr,
+				AR8327_PHY_MODE_SEL, phy_val);
+
+		/* set rgmii tx clock delay if needed */
+		if (!of_property_read_u32(np, "txclk_delay_en", &tx_delay)
+						&& tx_delay == 1) {
+			ar8xxx_phy_dbg_read(priv, phyaddr,
+			AR8327_PHY_SYS_CTRL, &phy_val);
+			phy_val |= AR8327_PHY_SYS_CTRL_RGMII_TX_DELAY;
+			ar8xxx_phy_dbg_write(priv, phyaddr,
+						AR8327_PHY_SYS_CTRL, phy_val);
+		}
+
+		/* set rgmii rx clock delay if needed */
+		if (!of_property_read_u32(np, "rxclk_delay_en", &rx_delay)
+						&& rx_delay == 1) {
+			ar8xxx_phy_dbg_read(priv, phyaddr,
+						AR8327_PHY_TEST_CTRL, &phy_val);
+			phy_val |= AR8327_PHY_TEST_CTRL_RGMII_RX_DELAY;
+			ar8xxx_phy_dbg_write(priv, phyaddr,
+						AR8327_PHY_TEST_CTRL, phy_val);
+		}
+	}
+}
+
+static void
 ar8327_phy_fixup(struct ar8xxx_priv *priv, int phy)
 {
 	switch (priv->chip_rev) {
@@ -1496,6 +1538,7 @@  const struct ar8xxx_chip ar8337_chip = {
 	.set_mirror_regs = ar8327_set_mirror_regs,
 	.get_arl_entry = ar8327_get_arl_entry,
 	.sw_hw_apply = ar8327_sw_hw_apply,
+	.phy_rgmii_set = ar8327_phy_rgmii_set,
 
 	.num_mibs = ARRAY_SIZE(ar8236_mibs),
 	.mib_decs = ar8236_mibs,
diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.h b/target/linux/generic/files/drivers/net/phy/ar8327.h
index d53ef88..d79f14a 100644
--- a/target/linux/generic/files/drivers/net/phy/ar8327.h
+++ b/target/linux/generic/files/drivers/net/phy/ar8327.h
@@ -283,6 +283,13 @@ 
 
 #define AR8337_PAD_MAC06_EXCHANGE_EN		BIT(31)
 
+#define AR8327_PHY_MODE_SEL			0x12
+#define   AR8327_PHY_MODE_SEL_RGMII		BIT(3)
+#define AR8327_PHY_TEST_CTRL			0x0
+#define   AR8327_PHY_TEST_CTRL_RGMII_RX_DELAY	BIT(15)
+#define AR8327_PHY_SYS_CTRL			0x5
+#define   AR8327_PHY_SYS_CTRL_RGMII_TX_DELAY	BIT(8)
+
 enum ar8327_led_pattern {
 	AR8327_LED_PATTERN_OFF = 0,
 	AR8327_LED_PATTERN_BLINK,