[][Update Ethernet MDIO CL45 programming sequence]

[Description]
Change Ethernet MDIO CL45 programming sequence.
Note: These patches porting from upstream Linux-5.18.

[Release-log]
N/A

Change-Id: I1025a3f17caed2d69536dae03ded0743935be812
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/6023025
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
index ab411d9..7ba9a01 100755
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
@@ -400,12 +400,12 @@
 
 static void mii_mgr_read_cl45(struct mtk_eth *eth, u16 port, u16 devad, u16 reg, u16 *data)
 {
-	mtk_cl45_ind_read(eth, port, devad, reg, data);
+	*data = _mtk_mdio_read(eth, port, mdiobus_c45_addr(devad, reg));
 }
 
 static void mii_mgr_write_cl45(struct mtk_eth *eth, u16 port, u16 devad, u16 reg, u16 data)
 {
-	mtk_cl45_ind_write(eth, port, devad, reg, data);
+	_mtk_mdio_write(eth, port, mdiobus_c45_addr(devad, reg), data);
 }
 
 int mtk_do_priv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.h b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.h
index 43f4838..2113c1f 100755
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.h
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.h
@@ -267,12 +267,10 @@
 }
 #endif
 
-extern u32 _mtk_mdio_read(struct mtk_eth *eth, u16 phy_addr, u16 phy_reg);
-extern u32 _mtk_mdio_write(struct mtk_eth *eth, u16 phy_addr,
-		    u16 phy_register, u16 write_data);
+extern u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg);
+extern u32 _mtk_mdio_write(struct mtk_eth *eth, int phy_addr,
+		    int phy_reg, u16 write_data);
 
-extern u32 mtk_cl45_ind_read(struct mtk_eth *eth, u16 port, u16 devad, u16 reg, u16 *data);
-extern u32 mtk_cl45_ind_write(struct mtk_eth *eth, u16 port, u16 devad, u16 reg, u16 data);
 extern atomic_t force;
 
 int debug_proc_init(struct mtk_eth *eth);
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 40d840e..84cabce 100755
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -103,18 +103,33 @@
 	return -1;
 }
 
-u32 _mtk_mdio_write(struct mtk_eth *eth, u16 phy_addr,
-			   u16 phy_register, u16 write_data)
+u32 _mtk_mdio_write(struct mtk_eth *eth, int phy_addr,
+			   int phy_reg, u16 write_data)
 {
 	if (mtk_mdio_busy_wait(eth))
 		return -1;
 
 	write_data &= 0xffff;
 
-	mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START | PHY_IAC_WRITE |
-		((phy_register & 0x1f) << PHY_IAC_REG_SHIFT) |
-		((phy_addr & 0x1f) << PHY_IAC_ADDR_SHIFT) | write_data,
-		MTK_PHY_IAC);
+	if (phy_reg & MII_ADDR_C45) {
+		mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START_C45 | PHY_IAC_ADDR_C45 |
+			((mdiobus_c45_devad(phy_reg) & 0x1f) << PHY_IAC_REG_SHIFT) |
+			((phy_addr & 0x1f) << PHY_IAC_ADDR_SHIFT) | mdiobus_c45_regad(phy_reg),
+			MTK_PHY_IAC);
+
+		if (mtk_mdio_busy_wait(eth))
+			return -1;
+
+		mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START_C45 | PHY_IAC_WRITE |
+			((mdiobus_c45_devad(phy_reg) & 0x1f) << PHY_IAC_REG_SHIFT) |
+			((phy_addr & 0x1f) << PHY_IAC_ADDR_SHIFT) | write_data,
+			MTK_PHY_IAC);
+	} else {
+		mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START | PHY_IAC_WRITE |
+			((phy_reg & 0x1f) << PHY_IAC_REG_SHIFT) |
+			((phy_addr & 0x1f) << PHY_IAC_ADDR_SHIFT) | write_data,
+			MTK_PHY_IAC);
+	}
 
 	if (mtk_mdio_busy_wait(eth))
 		return -1;
@@ -122,17 +137,32 @@
 	return 0;
 }
 
-u32 _mtk_mdio_read(struct mtk_eth *eth, u16 phy_addr, u16 phy_reg)
+u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg)
 {
 	u32 d;
 
 	if (mtk_mdio_busy_wait(eth))
 		return 0xffff;
 
+	if (phy_reg & MII_ADDR_C45) {
+		mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START_C45 | PHY_IAC_ADDR_C45 |
+			((mdiobus_c45_devad(phy_reg) & 0x1f) << PHY_IAC_REG_SHIFT) |
+			((phy_addr & 0x1f) << PHY_IAC_ADDR_SHIFT) | mdiobus_c45_regad(phy_reg),
+			MTK_PHY_IAC);
+
+		if (mtk_mdio_busy_wait(eth))
+			return 0xffff;
+
-	mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START | PHY_IAC_READ |
-		((phy_reg & 0x1f) << PHY_IAC_REG_SHIFT) |
-		((phy_addr & 0x1f) << PHY_IAC_ADDR_SHIFT),
-		MTK_PHY_IAC);
+		mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START_C45 | PHY_IAC_READ_C45 |
+			((mdiobus_c45_devad(phy_reg) & 0x1f) << PHY_IAC_REG_SHIFT) |
+			((phy_addr & 0x1f) << PHY_IAC_ADDR_SHIFT),
+			MTK_PHY_IAC);
+	} else {
+		mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START | PHY_IAC_READ |
+			((phy_reg & 0x1f) << PHY_IAC_REG_SHIFT) |
+			((phy_addr & 0x1f) << PHY_IAC_ADDR_SHIFT),
+			MTK_PHY_IAC);
+	}
 
 	if (mtk_mdio_busy_wait(eth))
 		return 0xffff;
@@ -157,34 +187,6 @@
 	return _mtk_mdio_read(eth, phy_addr, phy_reg);
 }
 
-u32 mtk_cl45_ind_read(struct mtk_eth *eth, u16 port, u16 devad, u16 reg, u16 *data)
-{
-        mutex_lock(&eth->mii_bus->mdio_lock);
-
-        _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, devad);
-        _mtk_mdio_write(eth, port, MII_MMD_ADDR_DATA_REG, reg);
-        _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
-        *data = _mtk_mdio_read(eth, port, MII_MMD_ADDR_DATA_REG);
-
-        mutex_unlock(&eth->mii_bus->mdio_lock);
-
-        return 0;
-}
-
-u32 mtk_cl45_ind_write(struct mtk_eth *eth, u16 port, u16 devad, u16 reg, u16 data)
-{
-        mutex_lock(&eth->mii_bus->mdio_lock);
-
-        _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, devad);
-        _mtk_mdio_write(eth, port, MII_MMD_ADDR_DATA_REG, reg);
-        _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
-        _mtk_mdio_write(eth, port, MII_MMD_ADDR_DATA_REG, data);
-
-        mutex_unlock(&eth->mii_bus->mdio_lock);
-
-        return 0;
-}
-
 static int mt7621_gmac0_rgmii_adjust(struct mtk_eth *eth,
 				     phy_interface_t interface)
 {
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 367f7f1..56db8c7 100755
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -570,8 +570,11 @@
 #define MTK_PHY_IAC		0x10004
 #define PHY_IAC_ACCESS		BIT(31)
 #define PHY_IAC_READ		BIT(19)
+#define PHY_IAC_READ_C45	(3 << 18)
+#define PHY_IAC_ADDR_C45	(0 << 18)
 #define PHY_IAC_WRITE		BIT(18)
 #define PHY_IAC_START		BIT(16)
+#define PHY_IAC_START_C45	(0 << 16)
 #define PHY_IAC_ADDR_SHIFT	20
 #define PHY_IAC_REG_SHIFT	25
 #define PHY_IAC_TIMEOUT		HZ
diff --git a/target/linux/mediatek/patches-5.4/745-mdiobus-add-c45.patch b/target/linux/mediatek/patches-5.4/745-mdiobus-add-c45.patch
new file mode 100644
index 0000000..93c00b8
--- /dev/null
+++ b/target/linux/mediatek/patches-5.4/745-mdiobus-add-c45.patch
@@ -0,0 +1,72 @@
+diff --git a/include/linux/mdio.h b/include/linux/mdio.h
+index 0f1f784de..006d1c1e9 100644
+--- a/include/linux/mdio.h
++++ b/include/linux/mdio.h
+@@ -7,8 +7,17 @@
+ #define __LINUX_MDIO_H__
+ 
+ #include <uapi/linux/mdio.h>
++#include <linux/bitfield.h>
+ #include <linux/mod_devicetable.h>
+ 
++/* Or MII_ADDR_C45 into regnum for read/write on mii_bus to enable the 21 bit
++ * IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips.
++ */
++#define MII_ADDR_C45		(1<<30)
++#define MII_DEVADDR_C45_SHIFT	16
++#define MII_DEVADDR_C45_MASK	GENMASK(20, 16)
++#define MII_REGADDR_C45_MASK	GENMASK(15, 0)
++
+ struct gpio_desc;
+ struct mii_bus;
+ 
+@@ -325,6 +334,46 @@ int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum);
+ int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val);
+ int mdiobus_write_nested(struct mii_bus *bus, int addr, u32 regnum, u16 val);
+ 
++static inline u32 mdiobus_c45_addr(int devad, u16 regnum)
++{
++	return MII_ADDR_C45 | devad << MII_DEVADDR_C45_SHIFT | regnum;
++}
++
++static inline u16 mdiobus_c45_regad(u32 regnum)
++{
++	return FIELD_GET(MII_REGADDR_C45_MASK, regnum);
++}
++
++static inline u16 mdiobus_c45_devad(u32 regnum)
++{
++	return FIELD_GET(MII_DEVADDR_C45_MASK, regnum);
++}
++
++static inline int __mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad,
++				     u16 regnum)
++{
++	return __mdiobus_read(bus, prtad, mdiobus_c45_addr(devad, regnum));
++}
++
++static inline int __mdiobus_c45_write(struct mii_bus *bus, int prtad, int devad,
++				      u16 regnum, u16 val)
++{
++	return __mdiobus_write(bus, prtad, mdiobus_c45_addr(devad, regnum),
++			       val);
++}
++
++static inline int mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad,
++				   u16 regnum)
++{
++	return mdiobus_read(bus, prtad, mdiobus_c45_addr(devad, regnum));
++}
++
++static inline int mdiobus_c45_write(struct mii_bus *bus, int prtad, int devad,
++				    u16 regnum, u16 val)
++{
++	return mdiobus_write(bus, prtad, mdiobus_c45_addr(devad, regnum), val);
++}
++
+ int mdiobus_register_device(struct mdio_device *mdiodev);
+ int mdiobus_unregister_device(struct mdio_device *mdiodev);
+ bool mdiobus_is_registered_device(struct mii_bus *bus, int addr);
+-- 
+2.18.0
+