net: phy: motorcomm: Add pad drive strength cfg support
[platform/kernel/linux-starfive.git] / drivers / net / phy / motorcomm.c
index 2fa5a90..e5d6b49 100644 (file)
  */
 #define YTPHY_WCR_TYPE_PULSE                   BIT(0)
 
+#define YTPHY_PAD_DRIVE_STRENGTH_REG           0xA010
+#define YT8531_RGMII_RXC_DS_DEFAULT            0x3
+#define YT8531_RGMII_RXC_DS_MAX                        0x7
+#define YT8531_RGMII_RXC_DS                    GENMASK(15, 13)
+#define YT8531_RGMII_RXD_DS_DEFAULT            0x3
+#define YT8531_RGMII_RXD_DS_MAX                        0x7
+#define YT8531_RGMII_RXD_DS_LOW                        GENMASK(5, 4) /* Bit 1/0 of rxd_ds */
+#define YT8531_RGMII_RXD_DS_HI                 BIT(12) /* Bit 2 of rxd_ds */
+
 #define YTPHY_SYNCE_CFG_REG                    0xA012
 #define YT8521_SCR_SYNCE_ENABLE                        BIT(5)
 /* 1b0 output 25m clock
@@ -1494,6 +1503,7 @@ err_restore_page:
 static int yt8531_config_init(struct phy_device *phydev)
 {
        struct device_node *node = phydev->mdio.dev.of_node;
+       u32 ds, val;
        int ret;
 
        ret = ytphy_rgmii_clk_delay_config_with_lock(phydev);
@@ -1518,6 +1528,42 @@ static int yt8531_config_init(struct phy_device *phydev)
                        return ret;
        }
 
+       ds = YT8531_RGMII_RXC_DS_DEFAULT;
+       if (!of_property_read_u32(node, "motorcomm,rx-clk-driver-strength", &val)) {
+               if (val > YT8531_RGMII_RXC_DS_MAX)
+                       return -EINVAL;
+
+               ds = val;
+       }
+
+       ret = ytphy_modify_ext_with_lock(phydev,
+                                        YTPHY_PAD_DRIVE_STRENGTH_REG,
+                                        YT8531_RGMII_RXC_DS,
+                                        FIELD_PREP(YT8531_RGMII_RXC_DS, ds));
+       if (ret < 0)
+               return ret;
+
+       ds = FIELD_PREP(YT8531_RGMII_RXD_DS_LOW, YT8531_RGMII_RXD_DS_DEFAULT);
+       if (!of_property_read_u32(node, "motorcomm,rx-data-driver-strength", &val)) {
+               if (val > YT8531_RGMII_RXD_DS_MAX)
+                       return -EINVAL;
+
+               if (val > FIELD_MAX(YT8531_RGMII_RXD_DS_LOW)) {
+                       ds = val & FIELD_MAX(YT8531_RGMII_RXD_DS_LOW);
+                       ds = FIELD_PREP(YT8531_RGMII_RXD_DS_LOW, ds);
+                       ds |= YT8531_RGMII_RXD_DS_HI;
+               } else {
+                       ds = FIELD_PREP(YT8531_RGMII_RXD_DS_LOW, val);
+               }
+       }
+
+       ret = ytphy_modify_ext_with_lock(phydev,
+                                        YTPHY_PAD_DRIVE_STRENGTH_REG,
+                                        YT8531_RGMII_RXD_DS_LOW | YT8531_RGMII_RXD_DS_HI,
+                                        ds);
+       if (ret < 0)
+               return ret;
+
        return 0;
 }