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);
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;
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;
.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,
.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,
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) },
{ }
};
};
/* 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)