[openwrt/openwrt] realtek: phy: proper RTL8218B, RTL8214FC, RTL8214FB detection

LEDE Commits lede-commits at lists.infradead.org
Sun Oct 27 14:26:34 PDT 2024


robimarko pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/597f87ebf5872a92d6b6a3b5e79537a641d2995c

commit 597f87ebf5872a92d6b6a3b5e79537a641d2995c
Author: Markus Stockhausen <markus.stockhausen at gmx.de>
AuthorDate: Sun Sep 22 13:19:22 2024 -0400

    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 <markus.stockhausen at gmx.de>
    Link: https://github.com/openwrt/openwrt/pull/16457
    Signed-off-by: Robert Marko <robimarko at gmail.com>
---
 .../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)




More information about the lede-commits mailing list