From 597f87ebf5872a92d6b6a3b5e79537a641d2995c Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Sun, 22 Sep 2024 13:19:22 -0400 Subject: [PATCH] realtek: phy: proper RTL8218B, RTL8214FC, RTL8214FB detection Three PHYs share the same identifier. Until now we simply assume the type depending of the bus address it is attached to. Make it better and check the chip mode register instead. The kernel will either detect by id/mask or by match_phy_device(). Remove the unneeded settings. Signed-off-by: Markus Stockhausen Link: https://github.com/openwrt/openwrt/pull/16457 Signed-off-by: Robert Marko --- .../files-6.6/drivers/net/phy/rtl83xx-phy.c | 103 +++++++++++++----- .../files-6.6/drivers/net/phy/rtl83xx-phy.h | 33 +++--- 2 files changed, 95 insertions(+), 41 deletions(-) diff --git a/target/linux/realtek/files-6.6/drivers/net/phy/rtl83xx-phy.c b/target/linux/realtek/files-6.6/drivers/net/phy/rtl83xx-phy.c index dcb7f1570b..2e52924f80 100644 --- a/target/linux/realtek/files-6.6/drivers/net/phy/rtl83xx-phy.c +++ b/target/linux/realtek/files-6.6/drivers/net/phy/rtl83xx-phy.c @@ -147,6 +147,79 @@ static int resume_polling(u64 saved_state) return 0; } +int rtl821x_match_phy_device(struct phy_device *phydev) +{ + u64 poll_state; + int rawpage, port = phydev->mdio.addr & ~3; + int oldpage, chip_mode, chip_cfg_mode; + + if (phydev->phy_id == PHY_ID_RTL8218B_E) + return PHY_IS_RTL8218B_E; + + if (phydev->phy_id != PHY_ID_RTL8214_OR_8218) + return PHY_IS_NOT_RTL821X; + + if (soc_info.family == RTL8380_FAMILY_ID) + rawpage = RTL838X_PAGE_RAW; + else if (soc_info.family == RTL8390_FAMILY_ID) + rawpage = RTL839X_PAGE_RAW; + else + return PHY_IS_NOT_RTL821X; + + poll_state = disable_polling(port); + /* + * At this stage the write_page()/read_page() PHY functions are not yet + * registered and normal paged access is not possible. The following + * detection routine works because our MDIO bus has all the Realtek + * PHY page handling (register 31) integrated into the port functions. + */ + oldpage = phy_port_read_paged(phydev, port, rawpage, 31); + phy_port_write_paged(phydev, port, rawpage, 31, 0xa42); + phy_port_write_paged(phydev, port, rawpage, 29, 0x008); + phy_port_write_paged(phydev, port, rawpage, 31, 0x278); + phy_port_write_paged(phydev, port, rawpage, 18, 0x455); + phy_port_write_paged(phydev, port, rawpage, 31, 0x260); + chip_mode = phy_port_read_paged(phydev, port, rawpage, 18); + phy_port_write_paged(phydev, port, rawpage, 31, 0xa42); + phy_port_write_paged(phydev, port, rawpage, 29, 0x000); + phy_port_write_paged(phydev, port, rawpage, 31, oldpage); + + resume_polling(poll_state); + + pr_debug("%s(%d): got chip mode %x\n", __func__, phydev->mdio.addr, chip_mode); + + /* we checked the 4th port of a RTL8218B and got no config values */ + if (!chip_mode) + return PHY_IS_RTL8218B_E; + + chip_cfg_mode = (chip_mode >> 4) & 0xf; + chip_mode &= 0xf; + + if (chip_mode == 0xd || chip_mode == 0xf) + return PHY_IS_RTL8218B_E; + + if (chip_mode == 0x4 || chip_mode == 0x6) + return PHY_IS_RTL8214FC; + + if (chip_mode != 0xc && chip_mode != 0xe) + return PHY_IS_NOT_RTL821X; + + if (chip_cfg_mode == 0x4 || chip_cfg_mode == 0x6) + return PHY_IS_RTL8214FC; + + return PHY_IS_RTL8214FB; +} + +static int rtl8218b_ext_match_phy_device(struct phy_device *phydev) +{ + return rtl821x_match_phy_device(phydev) == PHY_IS_RTL8218B_E; +} + +static int rtl8214fc_match_phy_device(struct phy_device *phydev) +{ + return rtl821x_match_phy_device(phydev) == PHY_IS_RTL8214FC; +} + static void rtl8380_int_phy_on_off(struct phy_device *phydev, bool on) { phy_modify(phydev, 0, BMCR_PDOWN, on ? 0 : BMCR_PDOWN); @@ -936,21 +1009,6 @@ static int rtl8380_configure_ext_rtl8218b(struct phy_device *phydev) return 0; } -static int rtl8218b_ext_match_phy_device(struct phy_device *phydev) -{ - int addr = phydev->mdio.addr; - - /* Both the RTL8214FC and the external RTL8218B have the same - * PHY ID. On the RTL838x, the RTL8218B can only be attached_dev - * at PHY IDs 0-7, while the RTL8214FC must be attached via - * the pair of SGMII/1000Base-X with higher PHY-IDs - */ - if (soc_info.family == RTL8380_FAMILY_ID) - return phydev->phy_id == PHY_ID_RTL8218B_E && addr < 8; - else - return phydev->phy_id == PHY_ID_RTL8218B_E; -} - static bool rtl8214fc_media_is_fibre(struct phy_device *phydev) { int mac = phydev->mdio.addr; @@ -1459,13 +1517,6 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev) return 0; } -static int rtl8214fc_match_phy_device(struct phy_device *phydev) -{ - int addr = phydev->mdio.addr; - - return phydev->phy_id == PHY_ID_RTL8214FC && addr >= 24; -} - static int rtl8380_configure_serdes(struct phy_device *phydev) { u32 v; @@ -3856,10 +3907,9 @@ static struct phy_driver rtl83xx_phy_driver[] = { .set_loopback = genphy_loopback, }, { - PHY_ID_MATCH_MODEL(PHY_ID_RTL8214FC), + .match_phy_device = rtl8214fc_match_phy_device, .name = "Realtek RTL8214FC", .features = PHY_GBIT_FIBRE_FEATURES, - .match_phy_device = rtl8214fc_match_phy_device, .probe = rtl8214fc_phy_probe, .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, @@ -3872,10 +3922,9 @@ static struct phy_driver rtl83xx_phy_driver[] = { .get_eee = rtl8214fc_get_eee, }, { - PHY_ID_MATCH_MODEL(PHY_ID_RTL8218B_E), + .match_phy_device = rtl8218b_ext_match_phy_device, .name = "Realtek RTL8218B (external)", .features = PHY_GBIT_FEATURES, - .match_phy_device = rtl8218b_ext_match_phy_device, .probe = rtl8218b_ext_phy_probe, .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, @@ -3991,7 +4040,7 @@ static struct phy_driver rtl83xx_phy_driver[] = { module_phy_driver(rtl83xx_phy_driver); static struct mdio_device_id __maybe_unused rtl83xx_tbl[] = { - { PHY_ID_MATCH_MODEL(PHY_ID_RTL8214FC) }, + { PHY_ID_MATCH_MODEL(PHY_ID_RTL8214_OR_8218) }, { } }; diff --git a/target/linux/realtek/files-6.6/drivers/net/phy/rtl83xx-phy.h b/target/linux/realtek/files-6.6/drivers/net/phy/rtl83xx-phy.h index fb79560e6b..781ecb3c7c 100644 --- a/target/linux/realtek/files-6.6/drivers/net/phy/rtl83xx-phy.h +++ b/target/linux/realtek/files-6.6/drivers/net/phy/rtl83xx-phy.h @@ -19,21 +19,26 @@ struct __attribute__ ((__packed__)) fw_header { }; /* TODO: fixed path? */ -#define FIRMWARE_838X_8380_1 "rtl838x_phy/rtl838x_8380.fw" -#define FIRMWARE_838X_8214FC_1 "rtl838x_phy/rtl838x_8214fc.fw" -#define FIRMWARE_838X_8218b_1 "rtl838x_phy/rtl838x_8218b.fw" +#define FIRMWARE_838X_8380_1 "rtl838x_phy/rtl838x_8380.fw" +#define FIRMWARE_838X_8214FC_1 "rtl838x_phy/rtl838x_8214fc.fw" +#define FIRMWARE_838X_8218b_1 "rtl838x_phy/rtl838x_8218b.fw" -/* External RTL8218B and RTL8214FC IDs are identical */ -#define PHY_ID_RTL8214C 0x001cc942 -#define PHY_ID_RTL8214FC 0x001cc981 -#define PHY_ID_RTL8218B_E 0x001cc981 -#define PHY_ID_RTL8218D 0x001cc983 -#define PHY_ID_RTL8218B_I 0x001cca40 -#define PHY_ID_RTL8221B 0x001cc849 -#define PHY_ID_RTL8226 0x001cc838 -#define PHY_ID_RTL8390_GENERIC 0x001ccab0 -#define PHY_ID_RTL8393_I 0x001c8393 -#define PHY_ID_RTL9300_I 0x70d03106 +#define PHY_ID_RTL8214C 0x001cc942 +#define PHY_ID_RTL8218B_E 0x001cc980 +#define PHY_ID_RTL8214_OR_8218 0x001cc981 +#define PHY_ID_RTL8218D 0x001cc983 +#define PHY_ID_RTL8218B_I 0x001cca40 +#define PHY_ID_RTL8221B 0x001cc849 +#define PHY_ID_RTL8226 0x001cc838 +#define PHY_ID_RTL8390_GENERIC 0x001ccab0 +#define PHY_ID_RTL8393_I 0x001c8393 +#define PHY_ID_RTL9300_I 0x70d03106 + +/* These PHYs share the same id (0x001cc981) */ +#define PHY_IS_NOT_RTL821X 0 +#define PHY_IS_RTL8214FC 1 +#define PHY_IS_RTL8214FB 2 +#define PHY_IS_RTL8218B_E 3 /* Registers of the internal Serdes of the 8380 */ #define RTL838X_SDS_MODE_SEL (0x0028) -- 2.30.2