[][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(ð->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(ð->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(ð->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(ð->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
+