@@ -38,6 +38,7 @@ extern int phy_package_read_paged(struct phy_device *phydev, int page, u32 regnu
3838#define RTL821X_PAGE_MAC 0x0a43
3939#define RTL821X_PAGE_STATE 0x0b80
4040#define RTL821X_PAGE_PATCH 0x0b82
41+ #define RTL821X_MAC_SDS_PAGE (sds , page ) (0x404 + (sds) * 0x20 + (page))
4142
4243/* Using the special page 0xfff with the MDIO controller found in
4344 * RealTek SoCs allows to access the PHY in RAW mode, ie. bypassing
@@ -3811,6 +3812,55 @@ static int rtl821x_config_init(struct phy_device *phydev)
38113812 return 0 ;
38123813}
38133814
3815+ static void rtl8218b_cmu_reset (struct phy_device * phydev , int reset_id )
3816+ {
3817+ int bitpos = reset_id * 2 ;
3818+
3819+ /* CMU seems to have 8 pairs of reset bits that always work the same way */
3820+ phy_modify_paged (phydev , 0x467 , 0x14 , 0 , BIT (bitpos ));
3821+ phy_modify_paged (phydev , 0x467 , 0x14 , 0 , BIT (bitpos + 1 ));
3822+ phy_write_paged (phydev , 0x467 , 0x14 , 0x0 );
3823+ }
3824+
3825+ static int rtl8218b_config_init (struct phy_device * phydev )
3826+ {
3827+ int oldpage , oldxpage ;
3828+
3829+ rtl821x_config_init (phydev );
3830+
3831+ if (phydev -> mdio .addr % 8 )
3832+ return 0 ;
3833+ /*
3834+ * Realtek provides two ways of initializing the PHY package. Either by U-Boot or via
3835+ * vendor software and SDK. In case U-Boot setup is missing, run basic configuration
3836+ * so that ports at least get link up and pass traffic.
3837+ */
3838+
3839+ oldpage = phy_read (phydev , RTL8XXX_PAGE_SELECT );
3840+ oldxpage = phy_read (phydev , RTL821XEXT_MEDIA_PAGE_SELECT );
3841+ phy_write (phydev , RTL821XEXT_MEDIA_PAGE_SELECT , 0x8 );
3842+
3843+ /* activate 32/40 bit redundancy algorithm for first MAC serdes */
3844+ phy_modify_paged (phydev , RTL821X_MAC_SDS_PAGE (0 , 1 ), 0x14 , 0 , BIT (3 ));
3845+ /* magic CMU setting for stable connectivity of first MAC serdes */
3846+ phy_write_paged (phydev , 0x462 , 0x15 , 0x6e58 );
3847+ rtl8218b_cmu_reset (phydev , 0 );
3848+
3849+ for (int sds = 0 ; sds < 2 ; sds ++ ) {
3850+ /* force negative clock edge */
3851+ phy_modify_paged (phydev , RTL821X_MAC_SDS_PAGE (sds , 0 ), 0x17 , 0 , BIT (14 ));
3852+ rtl8218b_cmu_reset (phydev , 5 + sds );
3853+ /* soft reset */
3854+ phy_modify_paged (phydev , RTL821X_MAC_SDS_PAGE (sds , 0 ), 0x13 , 0 , BIT (6 ));
3855+ phy_modify_paged (phydev , RTL821X_MAC_SDS_PAGE (sds , 0 ), 0x13 , BIT (6 ), 0 );
3856+ }
3857+
3858+ phy_write (phydev , RTL821XEXT_MEDIA_PAGE_SELECT , oldxpage );
3859+ phy_write (phydev , RTL8XXX_PAGE_SELECT , oldpage );
3860+
3861+ return 0 ;
3862+ }
3863+
38143864static int rtl838x_serdes_probe (struct phy_device * phydev )
38153865{
38163866 int addr = phydev -> mdio .addr ;
@@ -3898,7 +3948,7 @@ static struct phy_driver rtl83xx_phy_driver[] = {
38983948 {
38993949 .match_phy_device = rtl8218b_ext_match_phy_device ,
39003950 .name = "Realtek RTL8218B (external)" ,
3901- .config_init = rtl821x_config_init ,
3951+ .config_init = rtl8218b_config_init ,
39023952 .features = PHY_GBIT_FEATURES ,
39033953 .probe = rtl8218b_ext_phy_probe ,
39043954 .read_mmd = rtl821x_read_mmd ,
0 commit comments