* Re: [PATCH net-next v1 1/2] net: phy: realtek: add support for RTL8261 @ 2026-06-03 2:32 Javen 2026-06-03 2:57 ` Andrew Lunn 0 siblings, 1 reply; 10+ messages in thread From: Javen @ 2026-06-03 2:32 UTC (permalink / raw) To: nb Cc: andrew, daniel, davem, edumazet, 顾晓军, hkallweit1, Javen, kuba, linux-kernel, linux, netdev, pabeni, vladimir.oltean Hi, Nicolai >> +/* Concatenated 4-bit speed code values (SPD_H << 2 | SPD_L) */ >> +#define RTL8261X_SPEED_CODE_500M 0x3 /* H=0, L=3 */ >> +#define RTL8261X_SPEED_CODE_1000M 0x7 /* H=1, L=3 */ >> +#define RTL8261X_SPEED_CODE_2500M 0x8 /* H=2, L=0 */ >> +#define RTL8261X_SPEED_CODE_5000M 0x9 /* H=2, L=1 */ >> +#define RTL8261X_SPEED_500 500 > > 500 MBit/s isnt a standard rate which also isnt represented in ethtool. > Is this just for documentation or intended to be used? If yes, how? Giga-lite (500M) is a Realtek-proprietary speed: when two Realtek PHYs supporting Giga-lite are connected and the higher speed is disabled or unstable, auto-negotiation may fall back to 500M. Since ethtool has no SPEED_500 definition, the driver reports SPEED_UNKNOWN for this case. So we add this. >> + >> +static int rtl8261x_get_features(struct phy_device *phydev) >> +{ >> + int ret; >> + >> + ret = genphy_c45_pma_read_abilities(phydev); >> + if (ret) >> + return ret; >> + /* >> + * Supplement Multi-Gig speeds that may not be automatically detected >> + * RTL8261X supports 2.5G/5G in addition to standard 10G >> + */ >> + linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, >> + phydev->supported); >> + linkmode_set_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, >> + phydev->supported); > >Feature bits for 2.5 and 5 GBit/s are set unconditionally - even for the >generic variant. >Do all variants have these capabilities? If not better add check for at l>east the generic one. Thank you for pointing this out. We can confirm that RTL8261C and RTL8261D support 2.5G and 5G. For this patch only support for RTL8261C, I will remove the code associated with RTL8261D. And other suggestions are all accepted. Thanks for your time. BRs, Javen ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next v1 1/2] net: phy: realtek: add support for RTL8261 2026-06-03 2:32 [PATCH net-next v1 1/2] net: phy: realtek: add support for RTL8261 Javen @ 2026-06-03 2:57 ` Andrew Lunn 2026-06-04 7:28 ` Javen 0 siblings, 1 reply; 10+ messages in thread From: Andrew Lunn @ 2026-06-03 2:57 UTC (permalink / raw) To: Javen Cc: nb, daniel, davem, edumazet, 顾晓军, hkallweit1, kuba, linux-kernel, linux, netdev, pabeni, vladimir.oltean On Wed, Jun 03, 2026 at 02:32:37AM +0000, Javen wrote: > Hi, Nicolai > > >> +/* Concatenated 4-bit speed code values (SPD_H << 2 | SPD_L) */ > >> +#define RTL8261X_SPEED_CODE_500M 0x3 /* H=0, L=3 */ > >> +#define RTL8261X_SPEED_CODE_1000M 0x7 /* H=1, L=3 */ > >> +#define RTL8261X_SPEED_CODE_2500M 0x8 /* H=2, L=0 */ > >> +#define RTL8261X_SPEED_CODE_5000M 0x9 /* H=2, L=1 */ > >> +#define RTL8261X_SPEED_500 500 > > > > 500 MBit/s isnt a standard rate which also isnt represented in ethtool. > > Is this just for documentation or intended to be used? If yes, how? > > Giga-lite (500M) is a Realtek-proprietary speed: when two Realtek > PHYs supporting Giga-lite are connected and the higher speed is > disabled or unstable, auto-negotiation may fall back to 500M. Since > ethtool has no SPEED_500 definition, the driver reports > SPEED_UNKNOWN for this case. So we add this. Is it negotiated? What bit does it use in which code word page to accomplish this? Is there a register which can be used to control the advertisement? Can you see the link partner advertisement for this bit? Andrew ^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH net-next v1 1/2] net: phy: realtek: add support for RTL8261 2026-06-03 2:57 ` Andrew Lunn @ 2026-06-04 7:28 ` Javen 0 siblings, 0 replies; 10+ messages in thread From: Javen @ 2026-06-04 7:28 UTC (permalink / raw) To: Andrew Lunn Cc: nb, daniel, davem, edumazet, 顾晓军, hkallweit1, kuba, linux-kernel, linux, netdev, pabeni, vladimir.oltean > >On Wed, Jun 03, 2026 at 02:32:37AM +0000, Javen wrote: >> Hi, Nicolai >> >> >> +/* Concatenated 4-bit speed code values (SPD_H << 2 | SPD_L) */ >> >> +#define RTL8261X_SPEED_CODE_500M 0x3 /* H=0, L=3 */ >> >> +#define RTL8261X_SPEED_CODE_1000M 0x7 /* H=1, L=3 */ >> >> +#define RTL8261X_SPEED_CODE_2500M 0x8 /* H=2, L=0 */ >> >> +#define RTL8261X_SPEED_CODE_5000M 0x9 /* H=2, L=1 */ >> >> +#define RTL8261X_SPEED_500 500 >> > >> > 500 MBit/s isnt a standard rate which also isnt represented in ethtool. >> > Is this just for documentation or intended to be used? If yes, how? >> >> Giga-lite (500M) is a Realtek-proprietary speed: when two Realtek PHYs >> supporting Giga-lite are connected and the higher speed is disabled or >> unstable, auto-negotiation may fall back to 500M. Since ethtool has no >> SPEED_500 definition, the driver reports SPEED_UNKNOWN for this case. >> So we add this. > >Is it negotiated? What bit does it use in which code word page to accomplish >this? Is there a register which can be used to control the advertisement? Can >you see the link partner advertisement for this bit? > > Andrew SPEED 500 is rarely used. So I will remove it in the next patch. Thanks, BRs, Javen ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH net-next v1 0/2] Add support for RTL8261c @ 2026-05-28 7:52 javen 2026-05-28 7:52 ` [PATCH net-next v1 1/2] net: phy: realtek: add support for RTL8261 javen 0 siblings, 1 reply; 10+ messages in thread From: javen @ 2026-05-28 7:52 UTC (permalink / raw) To: andrew, hkallweit1, linux, davem, edumazet, kuba, pabeni, freddy_gu Cc: netdev, linux-kernel, daniel, vladimir.oltean, Javen Xu From: Javen Xu <javen_xu@realsil.com.cn> Add support for RTL8261c and add support for loading firmware. Javen Xu (2): net: phy: realtek: add support for RTL8261 net: phy: realtek: load firmware for RTL8261C drivers/net/phy/realtek/realtek_main.c | 536 +++++++++++++++++++++++++ 1 file changed, 536 insertions(+) -- 2.43.0 ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH net-next v1 1/2] net: phy: realtek: add support for RTL8261 2026-05-28 7:52 [PATCH net-next v1 0/2] Add support for RTL8261c javen @ 2026-05-28 7:52 ` javen 2026-05-28 9:37 ` Nicolai Buchwitz ` (3 more replies) 0 siblings, 4 replies; 10+ messages in thread From: javen @ 2026-05-28 7:52 UTC (permalink / raw) To: andrew, hkallweit1, linux, davem, edumazet, kuba, pabeni, freddy_gu Cc: netdev, linux-kernel, daniel, vladimir.oltean, Javen Xu From: Javen Xu <javen_xu@realsil.com.cn> This patch adds support for Realtek phy chip RTL8261. Its PHY id is 0x001cc898 and 0x001cc899. Signed-off-by: Javen Xu <javen_xu@realsil.com.cn> --- drivers/net/phy/realtek/realtek_main.c | 315 +++++++++++++++++++++++++ 1 file changed, 315 insertions(+) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 27268811f564..fe743fd0421b 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -22,6 +22,9 @@ #include "../phylib.h" #include "realtek.h" +#define RTL_8261C_CG 0x001cc898 +#define RTL_8261CE_CG 0x001cc899 + #define RTL8201F_IER_PAGE 0x07 #define RTL8201F_IER 0x13 #define RTL8201F_IER_LINK BIT(13) @@ -141,6 +144,10 @@ #define RTL8211F_PHYSICAL_ADDR_WORD1 17 #define RTL8211F_PHYSICAL_ADDR_WORD2 18 +#define RTL8261X_EXT_ADDR_REG 0xa436 +#define RTL8261X_EXT_DATA_REG 0xa438 +#define RTL_8261X_SUB_PHY_ID_ADDR 0x801d + #define RTL822X_VND1_SERDES_OPTION 0x697a #define RTL822X_VND1_SERDES_OPTION_MODE_MASK GENMASK(5, 0) #define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII 0 @@ -252,6 +259,57 @@ #define RTL_8251B 0x001cc862 #define RTL_8261C 0x001cc890 +#define RTL8261C_CE_MODEL 0x00 +#define RTL8261D_MODEL 0x81 +#define RTL8261X_PHYSR_REG 0xa434 +#define RTL8261X_GBCR_REG 0xa412 +#define RTL8261X_IMR 0xa4d2 +#define RTL8261X_ISR 0xa4d4 +#define RTL8261X_INT_AUTONEG_ERROR BIT(0) +#define RTL8261X_INT_PAGE_RECV BIT(2) +#define RTL8261X_INT_AUTONEG_DONE BIT(3) +#define RTL8261X_INT_LINK_CHG BIT(4) +#define RTL8261X_INT_PHY_REG_ACCESS BIT(5) +#define RTL8261X_INT_PME BIT(7) +#define RTL8261X_INT_ALDPS_CHG BIT(9) +#define RTL8261X_INT_JABBER BIT(10) +#define RTL8261X_PHYSR_LINK BIT(2) +#define RTL8261X_PHYSR_DUPLEX BIT(3) +#define RTL8261X_PHYSR_SPEED_L GENMASK(5, 4) +#define RTL8261X_PHYSR_SPEED_H GENMASK(10, 9) + +/* Concatenated 4-bit speed code values (SPD_H << 2 | SPD_L) */ +#define RTL8261X_SPEED_CODE_500M 0x3 /* H=0, L=3 */ +#define RTL8261X_SPEED_CODE_1000M 0x7 /* H=1, L=3 */ +#define RTL8261X_SPEED_CODE_2500M 0x8 /* H=2, L=0 */ +#define RTL8261X_SPEED_CODE_5000M 0x9 /* H=2, L=1 */ +#define RTL8261X_SPEED_500 500 + +#define RTL8261X_INT_MASK_DEFAULT (RTL8261X_INT_AUTONEG_DONE | \ + RTL8261X_INT_LINK_CHG) + +#define RTL8261X_INT_MASK_ALL (RTL8261X_INT_AUTONEG_ERROR | \ + RTL8261X_INT_PAGE_RECV | \ + RTL8261X_INT_AUTONEG_DONE | \ + RTL8261X_INT_LINK_CHG | \ + RTL8261X_INT_PHY_REG_ACCESS | \ + RTL8261X_INT_PME | \ + RTL8261X_INT_ALDPS_CHG | \ + RTL8261X_INT_JABBER) + +#define RTL8261X_MULTIG_CTRL 0x0020 +#define RTL8261X_MASTER_SLAVE_MASK GENMASK(15, 14) + +#define RTL8261X_MS_AUTO 0x0000 +#define RTL8261X_MS_SLAVE 0x8000 +#define RTL8261X_MS_MASTER 0xC000 + +enum rtl8261x_chip_model { + RTL8261_MODEL_C_CE = 0, + RTL8261_MODEL_D, + RTL8261_MODEL_GENERIC, +}; + /* RTL8211E and RTL8211F support up to three LEDs */ #define RTL8211x_LED_COUNT 3 @@ -270,6 +328,12 @@ struct rtl821x_priv { u16 iner; }; +struct rtl8261x_priv { + enum rtl8261x_chip_model model; + u8 sub_phy_id; + bool is_generic; +}; + static int rtl821x_read_page(struct phy_device *phydev) { return __phy_read(phydev, RTL821x_PAGE_SELECT); @@ -310,6 +374,233 @@ static int rtl821x_modify_ext_page(struct phy_device *phydev, u16 ext_page, return phy_restore_page(phydev, oldpage, ret); } +static int rtl8261x_soft_reset(struct phy_device *phydev) +{ + int ret, val; + + ret = phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, MDIO_CTRL1_RESET); + if (ret < 0) + return ret; + + return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PMAPMD, + MDIO_CTRL1, val, + !(val & MDIO_CTRL1_RESET), + 5000, 100000, true); +} + +static int rtl8261x_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct rtl8261x_priv *priv; + int sub_phy_id, ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, RTL8261X_EXT_ADDR_REG, + RTL_8261X_SUB_PHY_ID_ADDR); + if (ret < 0) + return ret; + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL8261X_EXT_DATA_REG); + if (ret < 0) + return ret; + + sub_phy_id = (ret >> 8) & 0xff; + priv->sub_phy_id = sub_phy_id; + priv->is_generic = false; + + switch (sub_phy_id) { + case RTL8261C_CE_MODEL: + priv->model = RTL8261_MODEL_C_CE; + phydev_info(phydev, "RTL8261C/CE detected (sub_id 0x%02x)\n", sub_phy_id); + break; + + case RTL8261D_MODEL: + priv->model = RTL8261_MODEL_D; + phydev_info(phydev, "RTL8261D detected (sub_id 0x%02x)\n", sub_phy_id); + break; + + default: + priv->model = RTL8261_MODEL_GENERIC; + priv->is_generic = true; + phydev_warn(phydev, "Unknown sub_id 0x%02x! Using GENERIC mode. Update driver for full support.\n", + sub_phy_id); + break; + } + phydev->priv = priv; + + return 0; +} + +static int rtl8261x_get_features(struct phy_device *phydev) +{ + int ret; + + ret = genphy_c45_pma_read_abilities(phydev); + if (ret) + return ret; + /* + * Supplement Multi-Gig speeds that may not be automatically detected + * RTL8261X supports 2.5G/5G in addition to standard 10G + */ + linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, + phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, + phydev->supported); + + return 0; +} + +static int rtl8261x_config_master_slave(struct phy_device *phydev) +{ + u16 val; + /* + * Configure bits 15:14 of MMD 7.0x0020 + * + * Bit 15 (Enable) | Bit 14 (Value) | Mode + * ----------------|----------------|------------- + * 0 | 0 | Auto (disabled) + * 1 | 0 | Force Slave + * 1 | 1 | Force Master + */ + switch (phydev->master_slave_set) { + case MASTER_SLAVE_CFG_MASTER_FORCE: + val = RTL8261X_MS_MASTER; + break; + case MASTER_SLAVE_CFG_SLAVE_FORCE: + val = RTL8261X_MS_SLAVE; + break; + case MASTER_SLAVE_CFG_UNKNOWN: + case MASTER_SLAVE_CFG_MASTER_PREFERRED: + case MASTER_SLAVE_CFG_SLAVE_PREFERRED: + default: + val = RTL8261X_MS_AUTO; + break; + } + + return phy_modify_mmd(phydev, MDIO_MMD_AN, RTL8261X_MULTIG_CTRL, + RTL8261X_MASTER_SLAVE_MASK, val); +} + +static int rtl8261x_config_intr(struct phy_device *phydev) +{ + int ret; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL8261X_ISR); + if (ret < 0) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, RTL8261X_IMR, + RTL8261X_INT_MASK_DEFAULT); + if (ret < 0) + return ret; + } else { + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, RTL8261X_IMR, 0); + if (ret < 0) + return ret; + } + + return 0; +} + +static irqreturn_t rtl8261x_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + irq_status = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL8261X_ISR); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if (!(irq_status & RTL8261X_INT_MASK_ALL)) + return IRQ_NONE; + + if (irq_status & (RTL8261X_INT_LINK_CHG | RTL8261X_INT_AUTONEG_DONE | + RTL8261X_INT_AUTONEG_ERROR | RTL8261X_INT_JABBER)) + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + +static int rtl8261x_read_status(struct phy_device *phydev) +{ + int ret, val, speed_code; + + ret = genphy_c45_read_status(phydev); + if (ret < 0) + return ret; + + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL8261X_PHYSR_REG); + if (val < 0) + return val; + + phydev->link = !!(val & RTL8261X_PHYSR_LINK); + if (!phydev->link) { + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + return 0; + } + + phydev->duplex = (val & RTL8261X_PHYSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; + speed_code = (FIELD_GET(RTL8261X_PHYSR_SPEED_H, val) << 2) | + FIELD_GET(RTL8261X_PHYSR_SPEED_L, val); + switch (speed_code) { + case RTL8261X_SPEED_CODE_500M: + phydev->speed = RTL8261X_SPEED_500; + break; + case RTL8261X_SPEED_CODE_1000M: + phydev->speed = SPEED_1000; + break; + case RTL8261X_SPEED_CODE_2500M: + phydev->speed = SPEED_2500; + break; + case RTL8261X_SPEED_CODE_5000M: + phydev->speed = SPEED_5000; + break; + default: + phydev_warn(phydev, "unknown speed code 0x%x (PHYSR=0x%04x)\n", speed_code, val); + phydev->speed = SPEED_UNKNOWN; + break; + } + + return 0; +} + +static int rtl8261x_config_aneg(struct phy_device *phydev) +{ + u16 adv_1g = 0; + int ret; + + if (phydev->autoneg == AUTONEG_DISABLE) + return genphy_c45_pma_setup_forced(phydev); + + ret = rtl8261x_config_master_slave(phydev); + if (ret < 0) + return ret; + + ret = genphy_c45_config_aneg(phydev); + if (ret < 0) + return ret; + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + phydev->advertising)) + adv_1g = BIT(9); + + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, + RTL8261X_GBCR_REG, + BIT(9), adv_1g); + if (ret < 0) + return ret; + + if (ret > 0) + return genphy_c45_restart_aneg(phydev); + + return 0; +} + static int rtl821x_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; @@ -3001,6 +3292,30 @@ static struct phy_driver realtek_drvs[] = { .resume = genphy_resume, .read_mmd = genphy_read_mmd_unsupported, .write_mmd = genphy_write_mmd_unsupported, + }, { + PHY_ID_MATCH_EXACT(RTL_8261C_CG), + .name = "Realtek RTL8261C_RTL8261D 10Gbps PHY", + .probe = rtl8261x_probe, + .get_features = rtl8261x_get_features, + .config_aneg = rtl8261x_config_aneg, + .read_status = rtl8261x_read_status, + .config_intr = rtl8261x_config_intr, + .handle_interrupt = rtl8261x_handle_interrupt, + .soft_reset = rtl8261x_soft_reset, + .suspend = genphy_c45_pma_suspend, + .resume = genphy_c45_pma_resume, + }, { + PHY_ID_MATCH_EXACT(RTL_8261CE_CG), + .name = "Realtek RTL8261CE 10Gbps PHY", + .probe = rtl8261x_probe, + .get_features = rtl8261x_get_features, + .config_aneg = rtl8261x_config_aneg, + .read_status = rtl8261x_read_status, + .config_intr = rtl8261x_config_intr, + .handle_interrupt = rtl8261x_handle_interrupt, + .soft_reset = rtl8261x_soft_reset, + .suspend = genphy_c45_pma_suspend, + .resume = genphy_c45_pma_resume, }, }; -- 2.43.0 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next v1 1/2] net: phy: realtek: add support for RTL8261 2026-05-28 7:52 ` [PATCH net-next v1 1/2] net: phy: realtek: add support for RTL8261 javen @ 2026-05-28 9:37 ` Nicolai Buchwitz 2026-05-29 0:51 ` Andrew Lunn 2026-05-28 12:39 ` Andrew Lunn ` (2 subsequent siblings) 3 siblings, 1 reply; 10+ messages in thread From: Nicolai Buchwitz @ 2026-05-28 9:37 UTC (permalink / raw) To: javen Cc: andrew, hkallweit1, linux, davem, edumazet, kuba, pabeni, freddy_gu, netdev, linux-kernel, daniel, vladimir.oltean Hi Javen On 28.5.2026 09:52, javen wrote: > From: Javen Xu <javen_xu@realsil.com.cn> > > This patch adds support for Realtek phy chip RTL8261. Its PHY id is > 0x001cc898 and 0x001cc899. > > Signed-off-by: Javen Xu <javen_xu@realsil.com.cn> > --- > drivers/net/phy/realtek/realtek_main.c | 315 +++++++++++++++++++++++++ > 1 file changed, 315 insertions(+) > > diff --git a/drivers/net/phy/realtek/realtek_main.c > b/drivers/net/phy/realtek/realtek_main.c > index 27268811f564..fe743fd0421b 100644 > --- a/drivers/net/phy/realtek/realtek_main.c > +++ b/drivers/net/phy/realtek/realtek_main.c > @@ -22,6 +22,9 @@ > #include "../phylib.h" > #include "realtek.h" > > +#define RTL_8261C_CG 0x001cc898 > +#define RTL_8261CE_CG 0x001cc899 Imho these should be added below RTL_8261C and not at the top. > + > #define RTL8201F_IER_PAGE 0x07 > #define RTL8201F_IER 0x13 > #define RTL8201F_IER_LINK BIT(13) > @@ -141,6 +144,10 @@ > #define RTL8211F_PHYSICAL_ADDR_WORD1 17 > #define RTL8211F_PHYSICAL_ADDR_WORD2 18 > > +#define RTL8261X_EXT_ADDR_REG 0xa436 > +#define RTL8261X_EXT_DATA_REG 0xa438 > +#define RTL_8261X_SUB_PHY_ID_ADDR 0x801d > + > #define RTL822X_VND1_SERDES_OPTION 0x697a > #define RTL822X_VND1_SERDES_OPTION_MODE_MASK GENMASK(5, 0) > #define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII 0 > @@ -252,6 +259,57 @@ > #define RTL_8251B 0x001cc862 > #define RTL_8261C 0x001cc890 > > +#define RTL8261C_CE_MODEL 0x00 > +#define RTL8261D_MODEL 0x81 > +#define RTL8261X_PHYSR_REG 0xa434 > +#define RTL8261X_GBCR_REG 0xa412 > +#define RTL8261X_IMR 0xa4d2 > +#define RTL8261X_ISR 0xa4d4 > +#define RTL8261X_INT_AUTONEG_ERROR BIT(0) > +#define RTL8261X_INT_PAGE_RECV BIT(2) > +#define RTL8261X_INT_AUTONEG_DONE BIT(3) > +#define RTL8261X_INT_LINK_CHG BIT(4) > +#define RTL8261X_INT_PHY_REG_ACCESS BIT(5) > +#define RTL8261X_INT_PME BIT(7) > +#define RTL8261X_INT_ALDPS_CHG BIT(9) > +#define RTL8261X_INT_JABBER BIT(10) > +#define RTL8261X_PHYSR_LINK BIT(2) > +#define RTL8261X_PHYSR_DUPLEX BIT(3) > +#define RTL8261X_PHYSR_SPEED_L GENMASK(5, 4) > +#define RTL8261X_PHYSR_SPEED_H GENMASK(10, 9) > + > +/* Concatenated 4-bit speed code values (SPD_H << 2 | SPD_L) */ > +#define RTL8261X_SPEED_CODE_500M 0x3 /* H=0, L=3 */ > +#define RTL8261X_SPEED_CODE_1000M 0x7 /* H=1, L=3 */ > +#define RTL8261X_SPEED_CODE_2500M 0x8 /* H=2, L=0 */ > +#define RTL8261X_SPEED_CODE_5000M 0x9 /* H=2, L=1 */ > +#define RTL8261X_SPEED_500 500 500 MBit/s isnt a standard rate which also isnt represented in ethtool. Is this just for documentation or intended to be used? If yes, how? > [...] > + > +static int rtl8261x_get_features(struct phy_device *phydev) > +{ > + int ret; > + > + ret = genphy_c45_pma_read_abilities(phydev); > + if (ret) > + return ret; > + /* > + * Supplement Multi-Gig speeds that may not be automatically detected > + * RTL8261X supports 2.5G/5G in addition to standard 10G > + */ > + linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, > + phydev->supported); > + linkmode_set_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, > + phydev->supported); Feature bits for 2.5 and 5 GBit/s are set unconditionally - even for the generic variant. Do all variants have these capabilities? If not better add check for at least the generic one. > + > + return 0; > +} > + > +static int rtl8261x_config_master_slave(struct phy_device *phydev) > +{ > + u16 val; > + /* > + * Configure bits 15:14 of MMD 7.0x0020 > + * > + * Bit 15 (Enable) | Bit 14 (Value) | Mode > + * ----------------|----------------|------------- > + * 0 | 0 | Auto (disabled) > + * 1 | 0 | Force Slave > + * 1 | 1 | Force Master > + */ > + switch (phydev->master_slave_set) { > + case MASTER_SLAVE_CFG_MASTER_FORCE: > + val = RTL8261X_MS_MASTER; > + break; > + case MASTER_SLAVE_CFG_SLAVE_FORCE: > + val = RTL8261X_MS_SLAVE; > + break; > + case MASTER_SLAVE_CFG_UNKNOWN: > + case MASTER_SLAVE_CFG_MASTER_PREFERRED: > + case MASTER_SLAVE_CFG_SLAVE_PREFERRED: > + default: > + val = RTL8261X_MS_AUTO; > + break; > + } > + > + return phy_modify_mmd(phydev, MDIO_MMD_AN, RTL8261X_MULTIG_CTRL, > + RTL8261X_MASTER_SLAVE_MASK, val); > +} RTL8261X_MULTIG_CTRL is a IEEE-defined register, so it can use MDIO_AN_10GBT_CTRL instead. Also the define for RTL8261X_MULTIG_CTRL can be dropped. While at it I would suggest to add MDIO_AN_10GBT_CTRL_MS_ENABLE (bit 15) and MDIO_AN_10GBT_CTRL_MS_VALUE (bit 14) to include/uapi/linux/mdio.h and also make use of it. RTL8261X_MS_AUTO would become val = MDIO_AN_10GBT_CTRL_MS_ENABLE | MDIO_AN_10GBT_CTRL_MS_VALUE; > [...] > + > +static int rtl8261x_read_status(struct phy_device *phydev) > +{ > + int ret, val, speed_code; > + > + ret = genphy_c45_read_status(phydev); > + if (ret < 0) > + return ret; > + > + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL8261X_PHYSR_REG); > + if (val < 0) > + return val; > + > + phydev->link = !!(val & RTL8261X_PHYSR_LINK); > + if (!phydev->link) { > + phydev->speed = SPEED_UNKNOWN; > + phydev->duplex = DUPLEX_UNKNOWN; > + return 0; > + } Why does it need to overreide the values from genphy_c45_read_status() ? > + > + phydev->duplex = (val & RTL8261X_PHYSR_DUPLEX) ? DUPLEX_FULL : > DUPLEX_HALF; > + speed_code = (FIELD_GET(RTL8261X_PHYSR_SPEED_H, val) << 2) | > + FIELD_GET(RTL8261X_PHYSR_SPEED_L, val); > + switch (speed_code) { > + case RTL8261X_SPEED_CODE_500M: > + phydev->speed = RTL8261X_SPEED_500; See question above (defines). > + break; > + case RTL8261X_SPEED_CODE_1000M: > + phydev->speed = SPEED_1000; > + break; > + case RTL8261X_SPEED_CODE_2500M: > + phydev->speed = SPEED_2500; > + break; > + case RTL8261X_SPEED_CODE_5000M: > + phydev->speed = SPEED_5000; > + break; > + default: > + phydev_warn(phydev, "unknown speed code 0x%x (PHYSR=0x%04x)\n", > speed_code, val); > + phydev->speed = SPEED_UNKNOWN; > + break; > + } > + > + return 0; > +} > + > +static int rtl8261x_config_aneg(struct phy_device *phydev) > +{ > + u16 adv_1g = 0; > + int ret; > + > + if (phydev->autoneg == AUTONEG_DISABLE) > + return genphy_c45_pma_setup_forced(phydev); > + > + ret = rtl8261x_config_master_slave(phydev); > + if (ret < 0) > + return ret; > + > + ret = genphy_c45_config_aneg(phydev); > + if (ret < 0) > + return ret; > + > + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, > + phydev->advertising)) > + adv_1g = BIT(9); > + > + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, > + RTL8261X_GBCR_REG, > + BIT(9), adv_1g); > + if (ret < 0) > + return ret; > + > + if (ret > 0) > + return genphy_c45_restart_aneg(phydev); This does not take rtl8261x_config_master_slave() into account. So maybe change rtl8261x_config_master_slave return phy_modify_mmd_changed ... and keep the result in a bool and also trigger auto nego restart if needed. > + > + return 0; > +} > + > static int rtl821x_probe(struct phy_device *phydev) > { > struct device *dev = &phydev->mdio.dev; > @@ -3001,6 +3292,30 @@ static struct phy_driver realtek_drvs[] = { > .resume = genphy_resume, > .read_mmd = genphy_read_mmd_unsupported, > .write_mmd = genphy_write_mmd_unsupported, > + }, { > + PHY_ID_MATCH_EXACT(RTL_8261C_CG), > + .name = "Realtek RTL8261C_RTL8261D 10Gbps PHY", > + .probe = rtl8261x_probe, RTL8261C/RTL8261D? Or just the c variant as the phy id suggests? > + .get_features = rtl8261x_get_features, > + .config_aneg = rtl8261x_config_aneg, > + .read_status = rtl8261x_read_status, > + .config_intr = rtl8261x_config_intr, > + .handle_interrupt = rtl8261x_handle_interrupt, > + .soft_reset = rtl8261x_soft_reset, > + .suspend = genphy_c45_pma_suspend, > + .resume = genphy_c45_pma_resume, > + }, { > + PHY_ID_MATCH_EXACT(RTL_8261CE_CG), > + .name = "Realtek RTL8261CE 10Gbps PHY", > + .probe = rtl8261x_probe, > + .get_features = rtl8261x_get_features, > + .config_aneg = rtl8261x_config_aneg, > + .read_status = rtl8261x_read_status, > + .config_intr = rtl8261x_config_intr, > + .handle_interrupt = rtl8261x_handle_interrupt, > + .soft_reset = rtl8261x_soft_reset, > + .suspend = genphy_c45_pma_suspend, > + .resume = genphy_c45_pma_resume, > }, > }; Please also make sure for both patches that checkpatch has no further complaints. Thanks. Nicolai ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next v1 1/2] net: phy: realtek: add support for RTL8261 2026-05-28 9:37 ` Nicolai Buchwitz @ 2026-05-29 0:51 ` Andrew Lunn 2026-06-03 2:35 ` Javen 0 siblings, 1 reply; 10+ messages in thread From: Andrew Lunn @ 2026-05-29 0:51 UTC (permalink / raw) To: Nicolai Buchwitz Cc: javen, hkallweit1, linux, davem, edumazet, kuba, pabeni, freddy_gu, netdev, linux-kernel, daniel, vladimir.oltean > > +static int rtl8261x_config_master_slave(struct phy_device *phydev) > > +{ > > + u16 val; > > + /* > > + * Configure bits 15:14 of MMD 7.0x0020 > > + * > > + * Bit 15 (Enable) | Bit 14 (Value) | Mode > > + * ----------------|----------------|------------- > > + * 0 | 0 | Auto (disabled) > > + * 1 | 0 | Force Slave > > + * 1 | 1 | Force Master > > + */ > > + switch (phydev->master_slave_set) { > > + case MASTER_SLAVE_CFG_MASTER_FORCE: > > + val = RTL8261X_MS_MASTER; > > + break; > > + case MASTER_SLAVE_CFG_SLAVE_FORCE: > > + val = RTL8261X_MS_SLAVE; > > + break; > > + case MASTER_SLAVE_CFG_UNKNOWN: > > + case MASTER_SLAVE_CFG_MASTER_PREFERRED: > > + case MASTER_SLAVE_CFG_SLAVE_PREFERRED: > > + default: > > + val = RTL8261X_MS_AUTO; > > + break; > > + } > > + > > + return phy_modify_mmd(phydev, MDIO_MMD_AN, RTL8261X_MULTIG_CTRL, > > + RTL8261X_MASTER_SLAVE_MASK, val); > > +} > > RTL8261X_MULTIG_CTRL is a IEEE-defined register, so it can use > MDIO_AN_10GBT_CTRL instead. > Also the define for RTL8261X_MULTIG_CTRL can be dropped. > > While at it I would suggest to add MDIO_AN_10GBT_CTRL_MS_ENABLE (bit 15) and > MDIO_AN_10GBT_CTRL_MS_VALUE (bit 14) to include/uapi/linux/mdio.h and also > make use of it. > RTL8261X_MS_AUTO would become If this is all just standard 802.3, the function should be added to phy-c45.c, so it can be used by any PHY driver. Andrew ^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH net-next v1 1/2] net: phy: realtek: add support for RTL8261 2026-05-29 0:51 ` Andrew Lunn @ 2026-06-03 2:35 ` Javen 0 siblings, 0 replies; 10+ messages in thread From: Javen @ 2026-06-03 2:35 UTC (permalink / raw) To: Andrew Lunn, Nicolai Buchwitz Cc: hkallweit1, linux, davem, edumazet, kuba, pabeni, 顾晓军, netdev, linux-kernel, daniel, vladimir.oltean > >> > +static int rtl8261x_config_master_slave(struct phy_device *phydev) >> > +{ >> > + u16 val; >> > + /* >> > + * Configure bits 15:14 of MMD 7.0x0020 >> > + * >> > + * Bit 15 (Enable) | Bit 14 (Value) | Mode >> > + * ----------------|----------------|------------- >> > + * 0 | 0 | Auto (disabled) >> > + * 1 | 0 | Force Slave >> > + * 1 | 1 | Force Master >> > + */ >> > + switch (phydev->master_slave_set) { >> > + case MASTER_SLAVE_CFG_MASTER_FORCE: >> > + val = RTL8261X_MS_MASTER; >> > + break; >> > + case MASTER_SLAVE_CFG_SLAVE_FORCE: >> > + val = RTL8261X_MS_SLAVE; >> > + break; >> > + case MASTER_SLAVE_CFG_UNKNOWN: >> > + case MASTER_SLAVE_CFG_MASTER_PREFERRED: >> > + case MASTER_SLAVE_CFG_SLAVE_PREFERRED: >> > + default: >> > + val = RTL8261X_MS_AUTO; >> > + break; >> > + } >> > + >> > + return phy_modify_mmd(phydev, MDIO_MMD_AN, >RTL8261X_MULTIG_CTRL, >> > + RTL8261X_MASTER_SLAVE_MASK, val); } >> >> RTL8261X_MULTIG_CTRL is a IEEE-defined register, so it can use >> MDIO_AN_10GBT_CTRL instead. >> Also the define for RTL8261X_MULTIG_CTRL can be dropped. >> >> While at it I would suggest to add MDIO_AN_10GBT_CTRL_MS_ENABLE (bit >> 15) and MDIO_AN_10GBT_CTRL_MS_VALUE (bit 14) to >> include/uapi/linux/mdio.h and also make use of it. >> RTL8261X_MS_AUTO would become > >If this is all just standard 802.3, the function should be added to phy-c45.c, so >it can be used by any PHY driver. > > Andrew Thanks for you suggestions. All the changes will be added into next version. BRs, Javen ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next v1 1/2] net: phy: realtek: add support for RTL8261 2026-05-28 7:52 ` [PATCH net-next v1 1/2] net: phy: realtek: add support for RTL8261 javen 2026-05-28 9:37 ` Nicolai Buchwitz @ 2026-05-28 12:39 ` Andrew Lunn 2026-05-28 12:42 ` Andrew Lunn 2026-05-28 16:56 ` Aleksander Jan Bajkowski 3 siblings, 0 replies; 10+ messages in thread From: Andrew Lunn @ 2026-05-28 12:39 UTC (permalink / raw) To: javen Cc: hkallweit1, linux, davem, edumazet, kuba, pabeni, freddy_gu, netdev, linux-kernel, daniel, vladimir.oltean > +static int rtl8261x_soft_reset(struct phy_device *phydev) > +{ > + int ret, val; > + > + ret = phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, MDIO_CTRL1_RESET); > + if (ret < 0) > + return ret; > + > + return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PMAPMD, > + MDIO_CTRL1, val, > + !(val & MDIO_CTRL1_RESET), > + 5000, 100000, true); We have a few copies of this function in various PHY drivers. Please add a genphy_c45_soft_reset() helper. > +} > + > +static int rtl8261x_probe(struct phy_device *phydev) > +{ > + struct device *dev = &phydev->mdio.dev; > + struct rtl8261x_priv *priv; > + int sub_phy_id, ret; > + > + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); > + if (!priv) > + return -ENOMEM; > + > + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, RTL8261X_EXT_ADDR_REG, > + RTL_8261X_SUB_PHY_ID_ADDR); > + if (ret < 0) > + return ret; blank line > + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL8261X_EXT_DATA_REG); > + if (ret < 0) > + return ret; > + > + sub_phy_id = (ret >> 8) & 0xff; > + priv->sub_phy_id = sub_phy_id; > + priv->is_generic = false; > + > + switch (sub_phy_id) { > + case RTL8261C_CE_MODEL: > + priv->model = RTL8261_MODEL_C_CE; > + phydev_info(phydev, "RTL8261C/CE detected (sub_id 0x%02x)\n", sub_phy_id); > + break; > + > + case RTL8261D_MODEL: > + priv->model = RTL8261_MODEL_D; > + phydev_info(phydev, "RTL8261D detected (sub_id 0x%02x)\n", sub_phy_id); > + break; > + > + default: > + priv->model = RTL8261_MODEL_GENERIC; > + priv->is_generic = true; > + phydev_warn(phydev, "Unknown sub_id 0x%02x! Using GENERIC mode. Update driver for full support.\n", > + sub_phy_id); > + break; This will get ignored. It is better to return -ENODEV so the probe fails. Andrew ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next v1 1/2] net: phy: realtek: add support for RTL8261 2026-05-28 7:52 ` [PATCH net-next v1 1/2] net: phy: realtek: add support for RTL8261 javen 2026-05-28 9:37 ` Nicolai Buchwitz 2026-05-28 12:39 ` Andrew Lunn @ 2026-05-28 12:42 ` Andrew Lunn 2026-05-28 16:56 ` Aleksander Jan Bajkowski 3 siblings, 0 replies; 10+ messages in thread From: Andrew Lunn @ 2026-05-28 12:42 UTC (permalink / raw) To: javen Cc: hkallweit1, linux, davem, edumazet, kuba, pabeni, freddy_gu, netdev, linux-kernel, daniel, vladimir.oltean > +struct rtl8261x_priv { > + enum rtl8261x_chip_model model; > + u8 sub_phy_id; > + bool is_generic; These don't appear to be used anywhere, just set. Are they really needed? Andrew ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next v1 1/2] net: phy: realtek: add support for RTL8261 2026-05-28 7:52 ` [PATCH net-next v1 1/2] net: phy: realtek: add support for RTL8261 javen ` (2 preceding siblings ...) 2026-05-28 12:42 ` Andrew Lunn @ 2026-05-28 16:56 ` Aleksander Jan Bajkowski 3 siblings, 0 replies; 10+ messages in thread From: Aleksander Jan Bajkowski @ 2026-05-28 16:56 UTC (permalink / raw) To: javen, andrew, hkallweit1, linux, davem, edumazet, kuba, pabeni, freddy_gu Cc: netdev, linux-kernel, daniel, vladimir.oltean Hi Javen, On 28/05/2026 09:52, javen wrote: > From: Javen Xu <javen_xu@realsil.com.cn> > > This patch adds support for Realtek phy chip RTL8261. Its PHY id is > 0x001cc898 and 0x001cc899. > > Signed-off-by: Javen Xu <javen_xu@realsil.com.cn> > --- > drivers/net/phy/realtek/realtek_main.c | 315 +++++++++++++++++++++++++ > 1 file changed, 315 insertions(+) > > diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c > index 27268811f564..fe743fd0421b 100644 > --- a/drivers/net/phy/realtek/realtek_main.c > +++ b/drivers/net/phy/realtek/realtek_main.c > +static int rtl8261x_config_aneg(struct phy_device *phydev) > +{ > + u16 adv_1g = 0; > + int ret; > + > + if (phydev->autoneg == AUTONEG_DISABLE) > + return genphy_c45_pma_setup_forced(phydev); > + > + ret = rtl8261x_config_master_slave(phydev); > + if (ret < 0) > + return ret; > + > + ret = genphy_c45_config_aneg(phydev); > + if (ret < 0) > + return ret; > + > + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, > + phydev->advertising)) > + adv_1g = BIT(9); adv_1g = ADVERTISE_1000FULL; > + > + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, > + RTL8261X_GBCR_REG, > + BIT(9), adv_1g); This is the C22 register mapped in VEND2 page. You can replace it with: ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL822X_VND2_C22_REG(MII_CTRL1000 ), ADVERTISE_1000FULL, adv_1g); Best regards, Aleksander ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-06-04 7:30 UTC | newest] Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-06-03 2:32 [PATCH net-next v1 1/2] net: phy: realtek: add support for RTL8261 Javen 2026-06-03 2:57 ` Andrew Lunn 2026-06-04 7:28 ` Javen -- strict thread matches above, loose matches on Subject: below -- 2026-05-28 7:52 [PATCH net-next v1 0/2] Add support for RTL8261c javen 2026-05-28 7:52 ` [PATCH net-next v1 1/2] net: phy: realtek: add support for RTL8261 javen 2026-05-28 9:37 ` Nicolai Buchwitz 2026-05-29 0:51 ` Andrew Lunn 2026-06-03 2:35 ` Javen 2026-05-28 12:39 ` Andrew Lunn 2026-05-28 12:42 ` Andrew Lunn 2026-05-28 16:56 ` Aleksander Jan Bajkowski
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®