From 590ee6d514d557a6f6751324a36e0941fe45f351 Mon Sep 17 00:00:00 2001 From: Tanya Singh Date: Tue, 13 May 2025 17:00:48 +0800 Subject: [PATCH] mediatek: Update ethernet driver to support PHY AN8801 on Edgecore EAP111 Fixes: WIFI-14576 Signed-off-by: Tanya Singh --- .../dts/mediatek/mt7981-edgecore-eap111.dts | 24 +- .../files-5.4/drivers/net/phy/an8801.c | 397 +++++++++--------- .../files-5.4/drivers/net/phy/an8801.h | 9 +- .../files-5.4/drivers/net/phy/en8801sc.c | 22 +- feeds/mediatek-sdk/mediatek/mt7981/config-5.4 | 1 - .../999-2738-an8801sb-gphy-support.patch | 78 +++- 6 files changed, 297 insertions(+), 234 deletions(-) diff --git a/feeds/mediatek-sdk/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-edgecore-eap111.dts b/feeds/mediatek-sdk/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-edgecore-eap111.dts index 60cf5ec58..45305d119 100755 --- a/feeds/mediatek-sdk/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-edgecore-eap111.dts +++ b/feeds/mediatek-sdk/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-edgecore-eap111.dts @@ -169,7 +169,8 @@ compatible = "mediatek,eth-mac"; reg = <0>; phy-mode = "sgmii"; - phy-handle = <&phy1>; // add phy handler + phy-handle = <&phy30>; + phy-handle2 = <&phy1>; mtd-mac-address = <&factory 0x24>; }; @@ -181,9 +182,9 @@ mtd-mac-address = <&factory 0x2a>; }; - mdio: mdio-bus { - #address-cells = <1>; - #size-cells = <0>; + mdio: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; phy0: ethernet-phy@0 { compatible = "ethernet-phy-id03a2.9461"; @@ -193,6 +194,16 @@ nvmem-cell-names = "phy-cal-data"; }; + phy30: ethernet-phy@30 { // AN8801SB + compatible = "ethernet-phy-idc0ff.0421"; + reg = <30>; //0x1e + phy-mode = "sgmii"; + full-duplex; + pause; + airoha,surge = <1>; + airoha,polarity = <2>; + }; + phy1: ethernet-phy@1 { compatible = "ethernet-phy-id03a2.9471"; reg = <24>; // set phy address to 0x18 @@ -200,9 +211,8 @@ reset-assert-us = <600>; reset-deassert-us = <20000>; phy-mode = "sgmii"; - }; - - }; + }; + }; }; &hnat { diff --git a/feeds/mediatek-sdk/mediatek/files-5.4/drivers/net/phy/an8801.c b/feeds/mediatek-sdk/mediatek/files-5.4/drivers/net/phy/an8801.c index a366d23bf..3089a1012 100644 --- a/feeds/mediatek-sdk/mediatek/files-5.4/drivers/net/phy/an8801.c +++ b/feeds/mediatek-sdk/mediatek/files-5.4/drivers/net/phy/an8801.c @@ -113,7 +113,6 @@ static const struct AIR_LED_CFG_T led_cfg_dlt[MAX_LED_SIZE] = { /* LED2 */ {LED_ENABLE, AIR_LED_GPIO9, AIR_ACTIVE_LOW, AIR_LED2_ON, AIR_LED2_BLK}, }; - static const u16 led_blink_cfg_dlt = AIR_LED_BLK_DUR_64M; /* RGMII delay */ static const u8 rxdelay_force = FALSE; @@ -140,7 +139,6 @@ static int __air_buckpbus_reg_write(struct phy_device *phydev, u32 addr, err |= mbus->write(mbus, phy_addr, 0x13, (u16)(data >> 16)); err |= mbus->write(mbus, phy_addr, 0x14, (u16)(data & 0xffff)); err |= mbus->write(mbus, phy_addr, 0x1F, 0); - return err; } @@ -167,6 +165,41 @@ static u32 __air_buckpbus_reg_read(struct phy_device *phydev, u32 addr) return data; } +static u32 __air_buckpbus_reg_modify(struct phy_device *phydev, u32 addr, + u32 mask, u32 set) +{ + int err = 0; + u32 data_h, data_l, data_old, data_new; + int phy_addr = phydev_phy_addr(phydev); + struct mii_bus *mbus = phydev_mdiobus(phydev); + + err = mbus->write(mbus, phy_addr, 0x1F, 4); + err |= mbus->write(mbus, phy_addr, 0x10, 0); + err |= mbus->write(mbus, phy_addr, 0x15, (u16)(addr >> 16)); + err |= mbus->write(mbus, phy_addr, 0x16, (u16)(addr & 0xffff)); + data_h = mbus->read(mbus, phy_addr, 0x17); + data_l = mbus->read(mbus, phy_addr, 0x18); + if (err < 0) { + mbus->write(mbus, phy_addr, 0x1F, 0); + return INVALID_DATA; + } + + data_old = ((data_h & 0xffff) << 16) | (data_l & 0xffff); + data_new = (data_old & ~mask) | set; + if (data_new == data_old) { + mbus->write(mbus, phy_addr, 0x1F, 0); + return 0; + } + + err |= mbus->write(mbus, phy_addr, 0x11, (u16)(addr >> 16)); + err |= mbus->write(mbus, phy_addr, 0x12, (u16)(addr & 0xffff)); + err |= mbus->write(mbus, phy_addr, 0x13, (u16)(data_new >> 16)); + err |= mbus->write(mbus, phy_addr, 0x14, (u16)(data_new & 0xffff)); + err |= mbus->write(mbus, phy_addr, 0x1F, 0); + + return err; +} + static int air_buckpbus_reg_write(struct phy_device *phydev, u32 addr, u32 data) { int err = 0; @@ -189,82 +222,18 @@ static u32 air_buckpbus_reg_read(struct phy_device *phydev, u32 addr) return data; } -static int __an8801_cl45_write(struct phy_device *phydev, int devad, u16 reg, - u16 val) -{ - u32 addr = (AN8801_EPHY_ADDR | AN8801_CL22 | (devad << 18) | - (reg << 2)); - - return __air_buckpbus_reg_write(phydev, addr, val); -} - -static int __an8801_cl45_read(struct phy_device *phydev, int devad, u16 reg) -{ - u32 addr = (AN8801_EPHY_ADDR | AN8801_CL22 | (devad << 18) | - (reg << 2)); - - return __air_buckpbus_reg_read(phydev, addr); -} - -int __an8801_modify_cl45_changed(struct phy_device *phydev, int devad, u32 regnum, - u16 mask, u16 set) -{ - int new, ret; - - ret = __an8801_cl45_read(phydev, devad, regnum); - if (ret < 0) - return ret; - - new = (ret & ~mask) | set; - if (new == ret) - return 0; - - ret = __an8801_cl45_write(phydev, devad, regnum, new); - - return ret < 0 ? ret : 1; -} - -static int an8801_modify_cl45_changed(struct phy_device *phydev, int devad, - u32 regnum, u16 mask, u16 set) +static int air_buckpbus_reg_modify(struct phy_device *phydev, u32 addr, + u32 mask, u32 set) { int err = 0; mdiobus_lock(phydev); - err = __an8801_modify_cl45_changed(phydev, devad, regnum, mask, set); + err = __air_buckpbus_reg_modify(phydev, addr, mask, set); mdiobus_unlock(phydev); return err; } -static int an8801_cl45_write(struct phy_device *phydev, int devad, u16 reg, - u16 val) -{ - int err = 0; - - mdiobus_lock(phydev); - err = __an8801_cl45_write(phydev, devad, reg, val); - mdiobus_unlock(phydev); - - return err; -} - -static int an8801_cl45_read(struct phy_device *phydev, int devad, u16 reg, - u16 *read_data) -{ - int data = 0; - - mdiobus_lock(phydev); - data = __an8801_cl45_read(phydev, devad, reg); - mdiobus_unlock(phydev); - - if (data == INVALID_DATA) - return -EINVAL; - - *read_data = data; - - return 0; -} - static int air_sw_reset(struct phy_device *phydev) { u32 reg_value; @@ -298,50 +267,36 @@ static int an8801_led_set_usr_def(struct phy_device *phydev, u8 entity, on_evt |= LED_ON_EN; - err = an8801_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), on_evt); + err = phy_write_mmd(phydev, 0x1f, LED_ON_CTRL(entity), on_evt); if (err) return -1; - return an8801_cl45_write(phydev, 0x1f, LED_BLK_CTRL(entity), blk_evt); + return phy_write_mmd(phydev, 0x1f, LED_BLK_CTRL(entity), blk_evt); } static int an8801_led_set_mode(struct phy_device *phydev, u8 mode) { - int err; - u16 data; - - err = an8801_cl45_read(phydev, 0x1f, LED_BCR, &data); - if (err) - return -1; - switch (mode) { case AIR_LED_MODE_DISABLE: - data &= ~LED_BCR_EXT_CTRL; - data &= ~LED_BCR_MODE_MASK; - data |= LED_BCR_MODE_DISABLE; - break; + return phy_modify_mmd(phydev, 0x1f, LED_BCR, + (LED_BCR_EXT_CTRL | LED_BCR_CLK_EN), + 0x0); case AIR_LED_MODE_USER_DEFINE: - data |= (LED_BCR_EXT_CTRL | LED_BCR_CLK_EN); + return phy_modify_mmd(phydev, 0x1f, LED_BCR, + (LED_BCR_EXT_CTRL | LED_BCR_CLK_EN), + (LED_BCR_EXT_CTRL | LED_BCR_CLK_EN)); + default: break; } - return an8801_cl45_write(phydev, 0x1f, LED_BCR, data); + dev_err(phydev_dev(phydev), + "LED mode %d is not supported\n", mode); + return -EINVAL; } static int an8801_led_set_state(struct phy_device *phydev, u8 entity, u8 state) { - u16 data; - int err; - - err = an8801_cl45_read(phydev, 0x1f, LED_ON_CTRL(entity), &data); - if (err) - return err; - - if (state) - data |= LED_ON_EN; - else - data &= ~LED_ON_EN; - - return an8801_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), data); + return phy_modify_mmd(phydev, 0x1f, LED_ON_CTRL(entity), LED_ON_EN, + (state) ? LED_ON_EN : 0x0); } static int an8801_led_init(struct phy_device *phydev) @@ -352,12 +307,12 @@ static int an8801_led_init(struct phy_device *phydev) u32 data; u16 led_blink_cfg = priv->led_blink_cfg; - ret = an8801_cl45_write(phydev, 0x1f, LED_BLK_DUR, + ret = phy_write_mmd(phydev, 0x1f, LED_BLK_DUR, LED_BLINK_DURATION(led_blink_cfg)); if (ret < 0) return ret; - ret = an8801_cl45_write(phydev, 0x1f, LED_ON_DUR, + ret = phy_write_mmd(phydev, 0x1f, LED_ON_DUR, (LED_BLINK_DURATION(led_blink_cfg) >> 1)); if (ret < 0) return ret; @@ -406,6 +361,56 @@ static int an8801_led_init(struct phy_device *phydev) return 0; } +static int an8801_ack_interrupt(struct phy_device *phydev) +{ + u32 reg_val = 0; + + air_buckpbus_reg_write(phydev, 0x10285404, 0x102); + reg_val = air_buckpbus_reg_read(phydev, 0x10285400); + air_buckpbus_reg_write(phydev, 0x10285400, 0x0); + air_buckpbus_reg_write(phydev, 0x10285400, reg_val | 0x10); + air_buckpbus_reg_write(phydev, 0x10285404, 0x12); + air_buckpbus_reg_write(phydev, 0x10285704, 0x1f); + return 0; +} + +static int an8801_config_intr(struct phy_device *phydev) +{ + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + air_buckpbus_reg_write(phydev, 0x1000007c, BIT(AIR_INTERRUPT_GPIO) << 16); + air_buckpbus_reg_modify(phydev, 0x10285700, 0x1, 0x1); + } else { + air_buckpbus_reg_write(phydev, 0x1000007c, 0x0); + air_buckpbus_reg_modify(phydev, 0x10285700, 0x1, 0x0); + } + an8801_ack_interrupt(phydev); + return 0; +} + +static int an8801_did_interrupt(struct phy_device *phydev) +{ + u32 reg_val = 0; + + reg_val = air_buckpbus_reg_read(phydev, 0x10285704); + + if (reg_val & 0x11) + return 1; + + return 0; +} + +#if (KERNEL_VERSION(5, 11, 0) < LINUX_VERSION_CODE) +static irqreturn_t an8801_handle_interrupt(struct phy_device *phydev) +{ + if (!an8801_did_interrupt(phydev)) + return IRQ_NONE; + + an8801_ack_interrupt(phydev); + phy_trigger_machine(phydev); + return IRQ_HANDLED; +} +#endif + static int findClosestNumber(const u16 *arr, u16 size, u16 target) { int left = 0, right = size - 1; @@ -431,77 +436,77 @@ static int findClosestNumber(const u16 *arr, u16 size, u16 target) static int an8801sb_i2mpb_config(struct phy_device *phydev) { int ret = 0; - u16 cl45_value = 0, temp_cl45 = 0, set = 0; + u16 cl45_value = 0, temp_cl45 = 0; u16 mask = 0; - ret = an8801_cl45_read(phydev, MMD_DEV_VSPEC1, 0x12, &cl45_value); + cl45_value = phy_read_mmd(phydev, MMD_DEV_VSPEC1, 0x12); dev_dbg(phydev_dev(phydev), "%s:%d cl45_value 0x%x!\n", __func__, __LINE__, cl45_value); cl45_value = (cl45_value & GENMASK(15, 10)) + (6 << 10); - ret = an8801_modify_cl45_changed(phydev, MMD_DEV_VSPEC1, 0x12, GENMASK(15, 10), cl45_value); + ret = phy_modify_mmd(phydev, MMD_DEV_VSPEC1, 0x12, GENMASK(15, 10), cl45_value); if (ret < 0) return ret; - ret = an8801_cl45_read(phydev, MMD_DEV_VSPEC1, 0x16, &temp_cl45); + temp_cl45 = phy_read_mmd(phydev, MMD_DEV_VSPEC1, 0x16); dev_dbg(phydev_dev(phydev), "%s:%d cl45_value 0x%x!\n", __func__, __LINE__, temp_cl45); mask = GENMASK(15, 10) | GENMASK(5, 0); cl45_value = (temp_cl45 & GENMASK(15, 10)) + (9 << 10); cl45_value = ((temp_cl45 & GENMASK(5, 0)) + 6) | cl45_value; - ret = an8801_modify_cl45_changed(phydev, MMD_DEV_VSPEC1, 0x16, mask, cl45_value); + ret = phy_modify_mmd(phydev, MMD_DEV_VSPEC1, 0x16, mask, cl45_value); if (ret < 0) return ret; - ret = an8801_cl45_read(phydev, MMD_DEV_VSPEC1, 0x17, &cl45_value); + cl45_value = phy_read_mmd(phydev, MMD_DEV_VSPEC1, 0x17); dev_dbg(phydev_dev(phydev), "%s:%d cl45_value 0x%x!\n", __func__, __LINE__, cl45_value); cl45_value = (cl45_value & GENMASK(13, 8)) + (6 << 8); - ret = an8801_modify_cl45_changed(phydev, MMD_DEV_VSPEC1, 0x17, GENMASK(13, 8), cl45_value); + ret = phy_modify_mmd(phydev, MMD_DEV_VSPEC1, 0x17, GENMASK(13, 8), cl45_value); if (ret < 0) return ret; - ret = an8801_cl45_read(phydev, MMD_DEV_VSPEC1, 0x18, &temp_cl45); + temp_cl45 = phy_read_mmd(phydev, MMD_DEV_VSPEC1, 0x18); dev_dbg(phydev_dev(phydev), "%s:%d cl45_value 0x%x!\n", __func__, __LINE__, temp_cl45); mask = GENMASK(13, 8) | GENMASK(5, 0); cl45_value = (temp_cl45 & GENMASK(13, 8)) + (9 << 8); cl45_value = ((temp_cl45 & GENMASK(5, 0)) + 6) | cl45_value; - ret = an8801_modify_cl45_changed(phydev, MMD_DEV_VSPEC1, 0x18, mask, cl45_value); + ret = phy_modify_mmd(phydev, MMD_DEV_VSPEC1, 0x18, mask, cl45_value); if (ret < 0) return ret; - ret = an8801_cl45_read(phydev, MMD_DEV_VSPEC1, 0x19, &cl45_value); + cl45_value = phy_read_mmd(phydev, MMD_DEV_VSPEC1, 0x19); dev_dbg(phydev_dev(phydev), "%s:%d cl45_value 0x%x!\n", __func__, __LINE__, cl45_value); cl45_value = (cl45_value & GENMASK(13, 8)) + (6 << 8); - ret = an8801_modify_cl45_changed(phydev, MMD_DEV_VSPEC1, 0x19, GENMASK(13, 8), cl45_value); + ret = phy_modify_mmd(phydev, MMD_DEV_VSPEC1, 0x19, GENMASK(13, 8), cl45_value); if (ret < 0) return ret; - ret = an8801_cl45_read(phydev, MMD_DEV_VSPEC1, 0x20, &cl45_value); + cl45_value = phy_read_mmd(phydev, MMD_DEV_VSPEC1, 0x20); dev_dbg(phydev_dev(phydev), "%s:%d cl45_value 0x%x!\n", __func__, __LINE__, cl45_value); cl45_value = (cl45_value & GENMASK(5, 0)) + 6; - ret = an8801_modify_cl45_changed(phydev, MMD_DEV_VSPEC1, 0x20, GENMASK(5, 0), cl45_value); + ret = phy_modify_mmd(phydev, MMD_DEV_VSPEC1, 0x20, GENMASK(5, 0), cl45_value); if (ret < 0) return ret; - ret = an8801_cl45_read(phydev, MMD_DEV_VSPEC1, 0x21, &cl45_value); + cl45_value = phy_read_mmd(phydev, MMD_DEV_VSPEC1, 0x21); dev_dbg(phydev_dev(phydev), "%s:%d cl45_value 0x%x!\n", __func__, __LINE__, cl45_value); cl45_value = (cl45_value & GENMASK(13, 8)) + (6 << 8); - ret = an8801_modify_cl45_changed(phydev, MMD_DEV_VSPEC1, 0x21, GENMASK(13, 8), cl45_value); + ret = phy_modify_mmd(phydev, MMD_DEV_VSPEC1, 0x21, GENMASK(13, 8), cl45_value); if (ret < 0) return ret; - ret = an8801_cl45_read(phydev, MMD_DEV_VSPEC1, 0x22, &cl45_value); + cl45_value = phy_read_mmd(phydev, MMD_DEV_VSPEC1, 0x22); dev_dbg(phydev_dev(phydev), "%s:%d cl45_value 0x%x!\n", __func__, __LINE__, cl45_value); cl45_value = (cl45_value & GENMASK(5, 0)) + 6; - ret = an8801_modify_cl45_changed(phydev, MMD_DEV_VSPEC1, 0x22, GENMASK(5, 0), cl45_value); + ret = phy_modify_mmd(phydev, MMD_DEV_VSPEC1, 0x22, GENMASK(5, 0), cl45_value); if (ret < 0) return ret; - ret = an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x23, 0x883); - ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x24, 0x883); - ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x25, 0x883); - ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x26, 0x883); - ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x0, 0x100); - ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x1, 0x1bc); - ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x2, 0x1d0); - ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x3, 0x186); - ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x4, 0x202); - ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x5, 0x20e); - ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x6, 0x300); - ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x7, 0x3c0); - ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x8, 0x3d0); - ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0x9, 0x317); - ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0xa, 0x206); - ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC1, 0xb, 0xe); + ret = phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x23, 0x883); + ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x24, 0x883); + ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x25, 0x883); + ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x26, 0x883); + ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x0, 0x100); + ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x1, 0x1bc); + ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x2, 0x1d0); + ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x3, 0x186); + ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x4, 0x202); + ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x5, 0x20e); + ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x6, 0x300); + ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x7, 0x3c0); + ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x8, 0x3d0); + ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0x9, 0x317); + ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0xa, 0x206); + ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC1, 0xb, 0xe); if (ret < 0) return ret; @@ -510,14 +515,14 @@ static int an8801sb_i2mpb_config(struct phy_device *phydev) } void update_r50_value(struct phy_device *phydev, - u16 *cl45_value, int pos1, int pos2) + u16 *cl45_value, int pos1, int pos2) { *cl45_value &= ~(0x007f << 8); *cl45_value |= ((r50ohm_table[pos1]) & 0x007f) << 8; *cl45_value &= ~(0x007f); *cl45_value |= (r50ohm_table[pos2]) & 0x007f; dev_dbg(phydev_dev(phydev), "Read: r50ohm_tx_1=%d r50ohm_tx_2=%d\n", - r50ohm_table[pos1], r50ohm_table[pos2]); + r50ohm_table[pos1], r50ohm_table[pos2]); } int calculate_position(int pos, int shift, int table_size) @@ -529,7 +534,7 @@ int calculate_position(int pos, int shift, int table_size) } int process_r50(struct phy_device *phydev, int reg, - u16 *cl45_value, u16 *r50ohm_tx_a, u16 *r50ohm_tx_b) + u16 *cl45_value, u16 *r50ohm_tx_a, u16 *r50ohm_tx_b) { int pos1 = findClosestNumber(r50ohm_table, r50ohm_table_size, *r50ohm_tx_a); int pos2 = findClosestNumber(r50ohm_table, r50ohm_table_size, *r50ohm_tx_b); @@ -539,7 +544,7 @@ int process_r50(struct phy_device *phydev, int reg, pos2 = calculate_position(pos2, R50_SHIFT, r50ohm_table_size); update_r50_value(phydev, cl45_value, pos1, pos2); - return an8801_cl45_write(phydev, 0x1e, reg, *cl45_value); + return phy_write_mmd(phydev, 0x1e, reg, *cl45_value); } return 0; } @@ -558,10 +563,10 @@ static int an8801r_of_init(struct phy_device *phydev) return -1; } if (val < AIR_RGMII_DELAY_NOSTEP || - val > AIR_RGMII_DELAY_STEP_7) { + val > AIR_RGMII_DELAY_STEP_7) { dev_err(phydev_dev(phydev), - "airoha,rxclk-delay value %u out of range.", - val); + "airoha,rxclk-delay value %u out of range.", + val); return -1; } priv->rxdelay_force = TRUE; @@ -574,14 +579,14 @@ static int an8801r_of_init(struct phy_device *phydev) if (of_property_read_u32(of_node, "airoha,txclk-delay", &val) != 0) { dev_err(phydev_dev(phydev), - "airoha,txclk-delay value is invalid."); + "airoha,txclk-delay value is invalid."); return -1; } if (val < AIR_RGMII_DELAY_NOSTEP || - val > AIR_RGMII_DELAY_STEP_7) { + val > AIR_RGMII_DELAY_STEP_7) { dev_err(phydev_dev(phydev), - "airoha,txclk-delay value %u out of range.", - val); + "airoha,txclk-delay value %u out of range.", + val); return -1; } priv->txdelay_force = TRUE; @@ -603,10 +608,10 @@ static int an8801sb_of_init(struct phy_device *phydev) return -1; } if (val < AIR_POL_TX_NOR_RX_REV || - val > AIR_POL_TX_REV_RX_NOR) { + val > AIR_POL_TX_REV_RX_NOR) { dev_err(phydev_dev(phydev), - "airoha,polarity value %u out of range.", - val); + "airoha,polarity value %u out of range.", + val); return -1; } priv->pol = val; @@ -615,15 +620,15 @@ static int an8801sb_of_init(struct phy_device *phydev) if (of_find_property(of_node, "airoha,surge", NULL)) { if (of_property_read_u32(of_node, "airoha,surge", - &val) != 0) { + &val) != 0) { dev_err(phydev_dev(phydev), "airoha,surge value is invalid."); return -1; } if (val < AIR_SURGE_0R || val > AIR_SURGE_5R) { dev_err(phydev_dev(phydev), - "airoha,surge value %u out of range.", - val); + "airoha,surge value %u out of range.", + val); return -1; } priv->surge = val; @@ -693,23 +698,19 @@ int an8801sb_surge_protect_cfg(struct phy_device *phydev) u16 cl45_value = 0; if (priv->surge) { - ret = an8801_cl45_read(phydev, 0x1e, 0x174, &cl45_value); - if (ret < 0) - return ret; + cl45_value = phy_read_mmd(phydev, 0x1e, 0x174); r50ohm_tx_a = (cl45_value >> 8) & 0x007f; r50ohm_tx_b = cl45_value & 0x007f; dev_dbg(phydev_dev(phydev), "Read: (0x174) value=0x%04x r50ohm_tx_a=%d r50ohm_tx_b=%d\n", - cl45_value, r50ohm_tx_a, r50ohm_tx_b); + cl45_value, r50ohm_tx_a, r50ohm_tx_b); ret = process_r50(phydev, 0x174, &cl45_value, &r50ohm_tx_a, &r50ohm_tx_b); if (ret < 0) return ret; - ret = an8801_cl45_read(phydev, 0x1e, 0x175, &cl45_value); - if (ret < 0) - return ret; + cl45_value = phy_read_mmd(phydev, 0x1e, 0x175); r50ohm_tx_c = (cl45_value >> 8) & 0x007f; r50ohm_tx_d = cl45_value & 0x007f; dev_dbg(phydev_dev(phydev), "Read: (0x175) value=0x%04x r50ohm_tx_c=%d r50ohm_tx_d=%d\n", - cl45_value, r50ohm_tx_c, r50ohm_tx_d); + cl45_value, r50ohm_tx_c, r50ohm_tx_d); ret = process_r50(phydev, 0x175, &cl45_value, &r50ohm_tx_c, &r50ohm_tx_d); if (ret < 0) return ret; @@ -764,10 +765,10 @@ static int an8801sb_config_init(struct phy_device *phydev) dev_info(phydev_dev(phydev), "Tx, Rx Polarity : %08x\n", pbus_value); - ret = an8801_cl45_write(phydev, MMD_DEV_VSPEC2, 0x600, 0x1e); - ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC2, 0x601, 0x02); + ret = phy_write_mmd(phydev, MMD_DEV_VSPEC2, 0x600, 0x1e); + ret |= phy_write_mmd(phydev, MMD_DEV_VSPEC2, 0x601, 0x02); - ret |= an8801_cl45_write(phydev, 7, 60, 0x0); + ret |= phy_write_mmd(phydev, 7, 60, 0x0); if (ret != 0) { dev_err(phydev_dev(phydev), "AN8801SB initialize fail, ret %d !\n", ret); @@ -940,7 +941,7 @@ static ssize_t an8801_polarity_write(struct file *file, const char __user *ptr, } static ssize_t an8801_mdio_write(struct file *file, const char __user *ptr, - size_t len, loff_t *off) + size_t len, loff_t *off) { struct phy_device *phydev = file->private_data; char buf[64], param1[32], param2[32]; @@ -955,7 +956,7 @@ static ssize_t an8801_mdio_write(struct file *file, const char __user *ptr, if (count > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, ptr, len)) - return -EFAULT; + return -EFAULT; ret = sscanf(buf, "%s %s", param1, param2); if (ret < 0) @@ -991,16 +992,16 @@ static ssize_t an8801_mdio_write(struct file *file, const char __user *ptr, pr_notice("\nphy=0x%x, devad=0x%x, reg=0x%x, val=0x%x\n", phydev_phy_addr(phydev), devad, reg, val); - ret = an8801_cl45_write(phydev, devad, reg, val); + ret = phy_write_mmd(phydev, devad, reg, val); if (ret < 0) return ret; - an8801_cl45_read(phydev, devad, reg, ®_val); + reg_val = phy_read_mmd(phydev, devad, reg); pr_notice("\nphy=0x%x, devad=0x%x, reg=0x%x, val=0x%x confirm..\n", phydev_phy_addr(phydev), devad, reg, reg_val); } else if (!strncmp("r", param2, strlen("r"))) { if (sscanf(buf, "cl45 r %x %x", &devad, ®) == -1) return -EFAULT; - an8801_cl45_read(phydev, devad, reg, ®_val); + reg_val = phy_read_mmd(phydev, devad, reg); pr_notice("\nphy=0x%x, devad=0x%x, reg=0x%x, val=0x%x\n", phydev_phy_addr(phydev), devad, reg, reg_val); } else { @@ -1020,7 +1021,6 @@ static int an8801_counter_show(struct seq_file *seq, void *v) struct phy_device *phydev = seq->private; int ret = 0; u32 pkt_cnt = 0; - struct mii_bus *mbus = phydev_mdiobus(phydev); seq_puts(seq, "==========AIR PHY COUNTER==========\n"); seq_puts(seq, "|\t<>\n"); @@ -1143,8 +1143,9 @@ static ssize_t an8801_debugfs_pbus(struct file *file, if (buf[0] == 'w') { if (sscanf(buf, "w %x %x", ®, &val) == -1) return -EFAULT; + pr_notice("\nphy=0x%x, reg=0x%x, val=0x%x\n", - phydev_phy_addr(phydev), reg, val); + phydev_phy_addr(phydev), reg, val); ret = air_buckpbus_reg_write(phydev, reg, val); if (ret < 0) @@ -1188,10 +1189,9 @@ int an8801_info_show(struct seq_file *seq, void *v) for (reg = MII_BMCR; reg <= MII_STAT1000; reg++) { if ((reg <= MII_LPA) || (reg >= MII_CTRL1000)) seq_printf(seq, "| RG_MII 0x%02x : 0x%08x\n", - reg, phy_read(phydev, reg)); + reg, phy_read(phydev, reg)); } seq_puts(seq, "\n"); - return 0; } @@ -1231,10 +1231,10 @@ static const struct file_operations an8801_polarity_fops = { }; static const struct file_operations an8801_mdio_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .write = an8801_mdio_write, - .llseek = noop_llseek, + .owner = THIS_MODULE, + .open = simple_open, + .write = an8801_mdio_write, + .llseek = noop_llseek, }; int an8801_debugfs_init(struct phy_device *phydev) @@ -1354,13 +1354,22 @@ static int an8801sb_read_status(struct phy_device *phydev) if (phydev->link == LINK_DOWN) { prespeed = 0; phydev->speed = 0; - ret |= an8801_cl45_write( + ret |= phy_write_mmd( phydev, MMD_DEV_VSPEC2, PHY_PRE_SPEED_REG, prespeed); + + mdelay(10); /* delay 10 ms */ + reg_value = air_buckpbus_reg_read(phydev, 0x10220010); + reg_value &= 0x7fff; + air_buckpbus_reg_write(phydev, 0x10220010, reg_value); + + reg_value = air_buckpbus_reg_read(phydev, 0x10220000); + reg_value |= AN8801SB_SGMII_AN0_ANRESTART; + air_buckpbus_reg_write(phydev, 0x10220000, reg_value); } if (prespeed != phydev->speed && phydev->link == LINK_UP) { prespeed = phydev->speed; - ret |= an8801_cl45_write( + ret |= phy_write_mmd( phydev, MMD_DEV_VSPEC2, PHY_PRE_SPEED_REG, prespeed); dev_info(phydev_dev(phydev), "AN8801SB SPEED %d\n", prespeed); while (an_retry > 0) { @@ -1374,28 +1383,19 @@ static int an8801sb_read_status(struct phy_device *phydev) mdelay(10); /* delay 10 ms */ - if (phydev->autoneg == AUTONEG_DISABLE) { - dev_info(phydev_dev(phydev), - "AN8801SB force speed = %d\n", prespeed); - if (prespeed == SPEED_1000) { - air_buckpbus_reg_write( - phydev, 0x10220010, 0xd801); - } else if (prespeed == SPEED_100) { - air_buckpbus_reg_write( - phydev, 0x10220010, 0xd401); - } else { - air_buckpbus_reg_write( - phydev, 0x10220010, 0xd001); - } - - reg_value = air_buckpbus_reg_read( - phydev, 0x10220000); - reg_value |= AN8801SB_SGMII_AN0_ANRESTART; + if (prespeed == SPEED_1000) { air_buckpbus_reg_write( - phydev, 0x10220000, reg_value); + phydev, 0x10220010, 0xd801); + } else if (prespeed == SPEED_100) { + air_buckpbus_reg_write( + phydev, 0x10220010, 0xd401); + } else { + air_buckpbus_reg_write( + phydev, 0x10220010, 0xd001); } + reg_value = air_buckpbus_reg_read(phydev, 0x10220000); - reg_value |= AN8801SB_SGMII_AN0_RESET; + reg_value |= (AN8801SB_SGMII_AN0_RESET | AN8801SB_SGMII_AN0_ANRESTART); air_buckpbus_reg_write(phydev, 0x10220000, reg_value); } return ret; @@ -1451,9 +1451,12 @@ static struct phy_driver airoha_driver[] = { .probe = an8801_phy_probe, .remove = an8801_phy_remove, .read_status = an8801_read_status, -#if (KERNEL_VERSION(4, 5, 0) < LINUX_VERSION_CODE) - .read_mmd = __an8801_cl45_read, - .write_mmd = __an8801_cl45_write, + .config_intr = an8801_config_intr, +#if (KERNEL_VERSION(5, 11, 0) < LINUX_VERSION_CODE) + .handle_interrupt = an8801_handle_interrupt, +#else + .did_interrupt = an8801_did_interrupt, + .ack_interrupt = an8801_ack_interrupt, #endif } }; diff --git a/feeds/mediatek-sdk/mediatek/files-5.4/drivers/net/phy/an8801.h b/feeds/mediatek-sdk/mediatek/files-5.4/drivers/net/phy/an8801.h index c98c9e098..06234a256 100644 --- a/feeds/mediatek-sdk/mediatek/files-5.4/drivers/net/phy/an8801.h +++ b/feeds/mediatek-sdk/mediatek/files-5.4/drivers/net/phy/an8801.h @@ -12,10 +12,10 @@ /* NAMING DECLARATIONS */ -#define AN8801_DRIVER_VERSION "1.1.4" +#define AN8801_DRIVER_VERSION "1.1.6" #define DEBUGFS_COUNTER "counter" -#define DEBUGFS_INFO "driver_info" +#define DEBUGFS_INFO "driver_info" #define DEBUGFS_PBUS_OP "pbus_op" #define DEBUGFS_POLARITY "polarity" #define DEBUGFS_MDIO "mdio" @@ -88,7 +88,7 @@ #define LED_BLK_EVT_1000M_RX BIT(1) #define LED_BLK_EVT_1000M_TX BIT(0) -#define UNIT_LED_BLINK_DURATION 1024 +#define UNIT_LED_BLINK_DURATION 780 /* Serdes auto negotation restart */ #define AN8801SB_SGMII_AN0_ANRESTART (0x0200) @@ -135,6 +135,9 @@ For reference only #define LED_BLINK_DURATION(f) (UNIT_LED_BLINK_DURATION << (f)) #define LED_GPIO_SEL(led, gpio) ((led) << ((gpio) * 3)) +/* Interrupt GPIO number, should not conflict with LED */ +#define AIR_INTERRUPT_GPIO 3 + /* DATA TYPE DECLARATIONS */ enum AIR_LED_GPIO_PIN_T { diff --git a/feeds/mediatek-sdk/mediatek/files-5.4/drivers/net/phy/en8801sc.c b/feeds/mediatek-sdk/mediatek/files-5.4/drivers/net/phy/en8801sc.c index 2cbea7229..12c8a0f86 100644 --- a/feeds/mediatek-sdk/mediatek/files-5.4/drivers/net/phy/en8801sc.c +++ b/feeds/mediatek-sdk/mediatek/files-5.4/drivers/net/phy/en8801sc.c @@ -587,7 +587,7 @@ static int en8801s_phase1_init(struct phy_device *phydev) phydev->dev_flags = PHY_STATE_INIT; - dev_info(dev, "Phase1 initialize OK ! (%s)\n", EN8801S_DRIVER_VERSION); + dev_info(dev, "Phase1 initialize OK ! (%s) 10Te TP_IDL fixed.\n", EN8801S_DRIVER_VERSION); if (priv->pro_version == 4) { ret = en8801s_phase2_init(phydev); if (ret != 0) { @@ -811,14 +811,7 @@ static int en8801s_phase2_init(struct phy_device *phydev) retry--; } pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C38); /* RAW#2 */ - ret = airoha_cl45_read(mbus, phy_addr, 0x1E, 0x12, &cl45_value); - if (ret < 0) - return ret; - GPHY_RG_1E_012.DATA = cl45_value; - GPHY_RG_1E_012.DataBitField.da_tx_i2mpb_a_tbt = - (u16)(pbus_data & 0x03f); - ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x12, - GPHY_RG_1E_012.DATA); + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x12, 0xA018); if (ret < 0) return ret; ret = airoha_cl45_read(mbus, phy_addr, 0x1E, 0x17, &cl45_value); @@ -893,6 +886,17 @@ static int en8801s_phase2_init(struct phy_device *phydev) } } + //Fix 10Te TP_IDL + ret = airoha_cl45_read(mbus, phy_addr, 0x1E, + 0x1A3, &cl45_value); + if (ret < 0) + return ret; + cl45_value &= ~0xf0; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, + 0x1A3, cl45_value); + if (ret < 0) + return ret; + priv->first_init = false; dev_info(phydev_dev(phydev), "Phase2 initialize OK !\n"); return 0; diff --git a/feeds/mediatek-sdk/mediatek/mt7981/config-5.4 b/feeds/mediatek-sdk/mediatek/mt7981/config-5.4 index aa0f6ee88..2cc5dc41d 100644 --- a/feeds/mediatek-sdk/mediatek/mt7981/config-5.4 +++ b/feeds/mediatek-sdk/mediatek/mt7981/config-5.4 @@ -2,7 +2,6 @@ CONFIG_64BIT=y CONFIG_AHCI_MTK=y CONFIG_AIROHA_EN8801SC_PHY=y # CONFIG_AIROHA_EN8811H_PHY is not set -# CONFIG_AIROHA_AN8801_PHY is not set CONFIG_AN8855_GSW=y CONFIG_ARCH_CLOCKSOURCE_DATA=y CONFIG_ARCH_DMA_ADDR_T_64BIT=y diff --git a/feeds/mediatek-sdk/mediatek/patches-5.4/999-2738-an8801sb-gphy-support.patch b/feeds/mediatek-sdk/mediatek/patches-5.4/999-2738-an8801sb-gphy-support.patch index 1a7fbf15e..0419cbafb 100644 --- a/feeds/mediatek-sdk/mediatek/patches-5.4/999-2738-an8801sb-gphy-support.patch +++ b/feeds/mediatek-sdk/mediatek/patches-5.4/999-2738-an8801sb-gphy-support.patch @@ -1,15 +1,3 @@ -From 535fdc6dfce7def996a5188819ffc96231c36f98 Mon Sep 17 00:00:00 2001 -From: Bo-Cun Chen -Date: Tue, 2 Jan 2024 18:13:43 +0800 -Subject: [PATCH] [networking][999-2738-an8801sb-gphy-support.patch] - ---- - drivers/net/phy/Kconfig | 5 + - drivers/net/phy/Makefile | 1 + - 2 files changed, 6 insertions(+) - -diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig -index ccd3f3f..5dbfb17 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -345,6 +345,11 @@ config SFP @@ -24,8 +12,6 @@ index ccd3f3f..5dbfb17 100644 config AIROHA_EN8801SC_PHY tristate "Drivers for Airoha EN8801S Gigabit PHYs for MediaTek SoC." ---help--- -diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile -index 1e8d67b..d39e54b 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -74,6 +74,7 @@ endif @@ -36,6 +22,64 @@ index 1e8d67b..d39e54b 100644 obj-$(CONFIG_AIROHA_EN8801SC_PHY) += en8801sc.o air_en8811h-y := air_en8811h_main.o air_en8811h_api.o obj-$(CONFIG_AIROHA_EN8811H_PHY) += air_en8811h.o --- -2.18.0 - +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -870,12 +870,17 @@ + of_node_put(phy_node); + + if (!phy_dev) +- return -ENODEV; +- ++ { ++ phylink_info(pl, "[phylink] reload phy-handle2. %s %d\n",__func__, __LINE__); ++ phy_node = of_parse_phandle(dn, "phy-handle2", 0); ++ phy_dev = of_phy_attach(pl->netdev, phy_node, flags, pl->link_interface); ++ if (!phy_dev) ++ return -ENODEV; ++ } ++ + ret = phylink_bringup_phy(pl, phy_dev, pl->link_config.interface); + if (ret) + phy_detach(phy_dev); +- + return ret; + } + EXPORT_SYMBOL_GPL(phylink_of_phy_connect); +--- a/drivers/of/of_mdio.c ++++ b/drivers/of/of_mdio.c +@@ -226,7 +226,9 @@ + return rc; + + /* Loop over the child nodes and register a phy_device for each phy */ ++ int an8801=0; + for_each_available_child_of_node(np, child) { ++ if(an8801==1)break; + addr = of_mdio_parse_addr(&mdio->dev, child); + if (addr < 0) { + scanphys = true; +@@ -234,7 +236,25 @@ + } + + if (of_mdiobus_child_is_phy(child)) ++ { ++ if(addr==30) ++ { ++ int phy_id ; ++ ++ phy_id = mdiobus_read(mdio, addr, MII_PHYSID1) << 16 ; ++ phy_id = phy_id + mdiobus_read(mdio, addr, MII_PHYSID2); ++ dev_info(&mdio->dev, "[of_mdio] %s %d addr:%d phy_id:0x%x \n",__func__, __LINE__, addr, phy_id); ++ ++ if (phy_id==0 || phy_id==0x1a750000) ++ { ++ dev_info(&mdio->dev, "[of_mdio] %s %d continue \n",__func__, __LINE__); ++ continue; ++ } ++ else ++ an8801=1; ++ } + rc = of_mdiobus_register_phy(mdio, child, addr); ++ } + else + rc = of_mdiobus_register_device(mdio, child, addr); +