JLSemi (JingLue Semiconductor) JL2101 and JL2121 Gigabit Ethernet PHYs are register-compatible second-source alternatives to the Realtek RTL8211F. They share the same paged register layout (page select at register 0x1f), RGMII TX/RX internal delay registers (page 0xd08 regs 11/15), specific status register (0x1a), and LED control registers (page 0xd04 reg 0x10). In the IEEE 802.3 PHY ID allocation, JL2101 (0x937c4032) and JL2121 (0x937c4030) share the same Model number 0x03 (bits [9:4] of register 3), differing only in revision number bits [3:0] (0x2 vs 0x0). Both chips share identical operational characteristics. Consolidate them under a single PHY_ID_MATCH_MODEL(0x937c4030) entry covering all revisions of this model. Unlike RTL8211F where PHYSR (0x1a) can be read directly on page 0, JL21xx requires reading PHYSR from page 0xa43 via phy_read_paged(). Reading 0x1a on page 0 yields 0x0000, which causes rtlgen_decode_physr() to erroneously downshift to 10Mbps half duplex. Introduce jlsemi_read_status() to read PHYSR from page 0xa43. Extend the Realtek PHY driver to bind JLSemi JL21xx by its Model ID to the RTL8211F-compatible driver operations, using the generic rtl821x probe and suspend/resume routines to avoid touching unverified WoL registers. Add the ID to the MDIO module device table. Signed-off-by: Pufan Jin --- Changes in v4: - Consolidate JL2101 and JL2121 into a single PHY_ID_MATCH_MODEL entry since both share Model 0x03 in IEEE 802.3 PHY ID allocation. (Andrew Lunn) - Drop unverified WoL callbacks (.set_wol, .get_wol) and switch .probe to rtl821x_probe and .suspend/.resume to rtl821x_* to avoid touching unverified WoL registers (page 0xd8a). Tested on hardware: page 0xd8a/0xd8c read back as 0x0000 on JL2121. (Andrew Lunn) - Retain hardware LED callbacks (.led_hw_*) after thorough validation on hardware (ALINX AX7Z020B): Mode B page 0xd04 reg 0x10 bitfields verified via single/dual LED blinking tests and netdev trigger hardware offload. Changes in v3: - Drop standalone driver drivers/net/phy/jlsemi.c and extend the Realtek PHY driver directly as suggested by Andrew Lunn. - Add jlsemi_read_status() to read PHYSR (0x1a) from page 0xa43, avoiding erroneous downshift to 10Mbps half duplex (verified on physical ALINX AX7Z020B). Changes in v2: - Drop redundant phy_interface_is_rgmii() check in jlsemi_config_init() (Andrew Lunn) - Check device_can_wakeup() and configure wakeup capability and wake IRQ in probe() when 'wakeup-source' is present (Andrew Lunn) - Drop redundant .features = PHY_GBIT_FEATURES (Andrew Lunn) - Use PHY_ID_MATCH_VENDOR() for generic driver and mdio table (Andrew Lunn) drivers/net/phy/realtek/realtek_main.c | 38 ++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 4927ee838..355135143 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -270,6 +270,9 @@ #define RTL_8261CE_CG 0x001cc899 #define RTL_8261D_VM 0x001cc89a +#define JLSEMI_JL21XX_PHYID 0x937c4030 +#define JLSEMI_STATUS_PAGE 0xa43 + #define RTL8261C_CE_MODEL 0x00 #define RTL8261D_MODEL 0x81 #define RTL8261X_INT_AUTONEG_ERROR BIT(0) @@ -1755,6 +1758,23 @@ static int rtlgen_read_status(struct phy_device *phydev) return 0; } +static int jlsemi_read_status(struct phy_device *phydev) +{ + int ret, val; + + ret = genphy_read_status(phydev); + if (ret < 0 || !phydev->link) + return ret; + + val = phy_read_paged(phydev, JLSEMI_STATUS_PAGE, RTL_PHYSR); + if (val < 0) + return val; + + rtlgen_decode_physr(phydev, val); + + return 0; +} + static int rtlgen_read_vend2(struct phy_device *phydev, int regnum) { return __mdiobus_c45_read(phydev->mdio.bus, 0, MDIO_MMD_VEND2, regnum); @@ -3283,6 +3303,23 @@ static struct phy_driver realtek_drvs[] = { .led_hw_control_get = rtl8211f_led_hw_control_get, .led_hw_control_set = rtl8211f_led_hw_control_set, .disable_autonomous_eee = rtl8211f_disable_autonomous_eee, + }, { + PHY_ID_MATCH_MODEL(JLSEMI_JL21XX_PHYID), + .name = "JLSemi JL2101/JL2121 Gigabit Ethernet", + .probe = rtl821x_probe, + .config_init = &rtl8211f_config_init, + .read_status = jlsemi_read_status, + .config_intr = &rtl8211f_config_intr, + .handle_interrupt = rtl8211f_handle_interrupt, + .suspend = rtl821x_suspend, + .resume = rtl821x_resume, + .read_page = rtl821x_read_page, + .write_page = rtl821x_write_page, + .flags = PHY_ALWAYS_CALL_SUSPEND, + .led_hw_is_supported = rtl8211x_led_hw_is_supported, + .led_hw_control_get = rtl8211f_led_hw_control_get, + .led_hw_control_set = rtl8211f_led_hw_control_set, + .disable_autonomous_eee = rtl8211f_disable_autonomous_eee, }, { .name = "Generic FE-GE Realtek PHY", .match_phy_device = rtlgen_match_phy_device, @@ -3527,6 +3564,7 @@ module_phy_driver(realtek_drvs); static const struct mdio_device_id __maybe_unused realtek_tbl[] = { { PHY_ID_MATCH_VENDOR(0x001cc800) }, + { PHY_ID_MATCH_MODEL(JLSEMI_JL21XX_PHYID) }, { } }; -- 2.56.0