#define RTL821X_PAGE_MAC 0x0a43
#define RTL821X_PAGE_STATE 0x0b80
#define RTL821X_PAGE_PATCH 0x0b82
+#define RTL821X_MAC_SDS_PAGE(sds, page) (0x404 + (sds) * 0x20 + (page))
/* Using the special page 0xfff with the MDIO controller found in
* RealTek SoCs allows to access the PHY in RAW mode, ie. bypassing
return 0;
}
+static void rtl8218b_cmu_reset(struct phy_device *phydev, int reset_id)
+{
+ int bitpos = reset_id * 2;
+
+ /* CMU seems to have 8 pairs of reset bits that always work the same way */
+ phy_modify_paged(phydev, 0x467, 0x14, 0, BIT(bitpos));
+ phy_modify_paged(phydev, 0x467, 0x14, 0, BIT(bitpos + 1));
+ phy_write_paged(phydev, 0x467, 0x14, 0x0);
+}
+
+static int rtl8218b_config_init(struct phy_device *phydev)
+{
+ int oldpage, oldxpage;
+
+ rtl821x_config_init(phydev);
+
+ if (phydev->mdio.addr % 8)
+ return 0;
+ /*
+ * Realtek provides two ways of initializing the PHY package. Either by U-Boot or via
+ * vendor software and SDK. In case U-Boot setup is missing, run basic configuration
+ * so that ports at least get link up and pass traffic.
+ */
+
+ oldpage = phy_read(phydev, RTL8XXX_PAGE_SELECT);
+ oldxpage = phy_read(phydev, RTL821XEXT_MEDIA_PAGE_SELECT);
+ phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, 0x8);
+
+ /* activate 32/40 bit redundancy algorithm for first MAC serdes */
+ phy_modify_paged(phydev, RTL821X_MAC_SDS_PAGE(0, 1), 0x14, 0, BIT(3));
+ /* magic CMU setting for stable connectivity of first MAC serdes */
+ phy_write_paged(phydev, 0x462, 0x15, 0x6e58);
+ rtl8218b_cmu_reset(phydev, 0);
+
+ for (int sds = 0; sds < 2; sds++) {
+ /* force negative clock edge */
+ phy_modify_paged(phydev, RTL821X_MAC_SDS_PAGE(sds, 0), 0x17, 0, BIT(14));
+ rtl8218b_cmu_reset(phydev, 5 + sds);
+ /* soft reset */
+ phy_modify_paged(phydev, RTL821X_MAC_SDS_PAGE(sds, 0), 0x13, 0, BIT(6));
+ phy_modify_paged(phydev, RTL821X_MAC_SDS_PAGE(sds, 0), 0x13, BIT(6), 0);
+ }
+
+ phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, oldxpage);
+ phy_write(phydev, RTL8XXX_PAGE_SELECT, oldpage);
+
+ return 0;
+}
+
static int rtl838x_serdes_probe(struct phy_device *phydev)
{
int addr = phydev->mdio.addr;
{
.match_phy_device = rtl8218b_ext_match_phy_device,
.name = "Realtek RTL8218B (external)",
- .config_init = rtl821x_config_init,
+ .config_init = rtl8218b_config_init,
.features = PHY_GBIT_FEATURES,
.probe = rtl8218b_ext_phy_probe,
.read_mmd = rtl821x_read_mmd,