|
@@ -0,0 +1,170 @@
|
|
|
+From 7a561e9351ae7e3fb1f08584d40b49c1e55dde60 Mon Sep 17 00:00:00 2001
|
|
|
+From: Samin Guo <[email protected]>
|
|
|
+Date: Thu, 20 Jul 2023 19:15:09 +0800
|
|
|
+Subject: [PATCH] net: phy: motorcomm: Add pad drive strength cfg support
|
|
|
+
|
|
|
+The motorcomm phy (YT8531) supports the ability to adjust the drive
|
|
|
+strength of the rx_clk/rx_data, and the default strength may not be
|
|
|
+suitable for all boards. So add configurable options to better match
|
|
|
+the boards.(e.g. StarFive VisionFive 2)
|
|
|
+
|
|
|
+When we configure the drive strength, we need to read the current
|
|
|
+LDO voltage value to ensure that it is a legal value at that LDO
|
|
|
+voltage.
|
|
|
+
|
|
|
+Reviewed-by: Hal Feng <[email protected]>
|
|
|
+Signed-off-by: Samin Guo <[email protected]>
|
|
|
+Reviewed-by: Andrew Lunn <[email protected]>
|
|
|
+Signed-off-by: David S. Miller <[email protected]>
|
|
|
+---
|
|
|
+ drivers/net/phy/motorcomm.c | 118 ++++++++++++++++++++++++++++++++++++
|
|
|
+ 1 file changed, 118 insertions(+)
|
|
|
+
|
|
|
+--- a/drivers/net/phy/motorcomm.c
|
|
|
++++ b/drivers/net/phy/motorcomm.c
|
|
|
+@@ -163,6 +163,10 @@
|
|
|
+
|
|
|
+ #define YT8521_CHIP_CONFIG_REG 0xA001
|
|
|
+ #define YT8521_CCR_SW_RST BIT(15)
|
|
|
++#define YT8531_RGMII_LDO_VOL_MASK GENMASK(5, 4)
|
|
|
++#define YT8531_LDO_VOL_3V3 0x0
|
|
|
++#define YT8531_LDO_VOL_1V8 0x2
|
|
|
++
|
|
|
+ /* 1b0 disable 1.9ns rxc clock delay *default*
|
|
|
+ * 1b1 enable 1.9ns rxc clock delay
|
|
|
+ */
|
|
|
+@@ -236,6 +240,12 @@
|
|
|
+ */
|
|
|
+ #define YTPHY_WCR_TYPE_PULSE BIT(0)
|
|
|
+
|
|
|
++#define YTPHY_PAD_DRIVE_STRENGTH_REG 0xA010
|
|
|
++#define YT8531_RGMII_RXC_DS_MASK GENMASK(15, 13)
|
|
|
++#define YT8531_RGMII_RXD_DS_HI_MASK BIT(12) /* Bit 2 of rxd_ds */
|
|
|
++#define YT8531_RGMII_RXD_DS_LOW_MASK GENMASK(5, 4) /* Bit 1/0 of rxd_ds */
|
|
|
++#define YT8531_RGMII_RX_DS_DEFAULT 0x3
|
|
|
++
|
|
|
+ #define YTPHY_SYNCE_CFG_REG 0xA012
|
|
|
+ #define YT8521_SCR_SYNCE_ENABLE BIT(5)
|
|
|
+ /* 1b0 output 25m clock
|
|
|
+@@ -835,6 +845,110 @@ static int ytphy_rgmii_clk_delay_config_
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
++ * struct ytphy_ldo_vol_map - map a current value to a register value
|
|
|
++ * @vol: ldo voltage
|
|
|
++ * @ds: value in the register
|
|
|
++ * @cur: value in device configuration
|
|
|
++ */
|
|
|
++struct ytphy_ldo_vol_map {
|
|
|
++ u32 vol;
|
|
|
++ u32 ds;
|
|
|
++ u32 cur;
|
|
|
++};
|
|
|
++
|
|
|
++static const struct ytphy_ldo_vol_map yt8531_ldo_vol[] = {
|
|
|
++ {.vol = YT8531_LDO_VOL_1V8, .ds = 0, .cur = 1200},
|
|
|
++ {.vol = YT8531_LDO_VOL_1V8, .ds = 1, .cur = 2100},
|
|
|
++ {.vol = YT8531_LDO_VOL_1V8, .ds = 2, .cur = 2700},
|
|
|
++ {.vol = YT8531_LDO_VOL_1V8, .ds = 3, .cur = 2910},
|
|
|
++ {.vol = YT8531_LDO_VOL_1V8, .ds = 4, .cur = 3110},
|
|
|
++ {.vol = YT8531_LDO_VOL_1V8, .ds = 5, .cur = 3600},
|
|
|
++ {.vol = YT8531_LDO_VOL_1V8, .ds = 6, .cur = 3970},
|
|
|
++ {.vol = YT8531_LDO_VOL_1V8, .ds = 7, .cur = 4350},
|
|
|
++ {.vol = YT8531_LDO_VOL_3V3, .ds = 0, .cur = 3070},
|
|
|
++ {.vol = YT8531_LDO_VOL_3V3, .ds = 1, .cur = 4080},
|
|
|
++ {.vol = YT8531_LDO_VOL_3V3, .ds = 2, .cur = 4370},
|
|
|
++ {.vol = YT8531_LDO_VOL_3V3, .ds = 3, .cur = 4680},
|
|
|
++ {.vol = YT8531_LDO_VOL_3V3, .ds = 4, .cur = 5020},
|
|
|
++ {.vol = YT8531_LDO_VOL_3V3, .ds = 5, .cur = 5450},
|
|
|
++ {.vol = YT8531_LDO_VOL_3V3, .ds = 6, .cur = 5740},
|
|
|
++ {.vol = YT8531_LDO_VOL_3V3, .ds = 7, .cur = 6140},
|
|
|
++};
|
|
|
++
|
|
|
++static u32 yt8531_get_ldo_vol(struct phy_device *phydev)
|
|
|
++{
|
|
|
++ u32 val;
|
|
|
++
|
|
|
++ val = ytphy_read_ext_with_lock(phydev, YT8521_CHIP_CONFIG_REG);
|
|
|
++ val = FIELD_GET(YT8531_RGMII_LDO_VOL_MASK, val);
|
|
|
++
|
|
|
++ return val <= YT8531_LDO_VOL_1V8 ? val : YT8531_LDO_VOL_1V8;
|
|
|
++}
|
|
|
++
|
|
|
++static int yt8531_get_ds_map(struct phy_device *phydev, u32 cur)
|
|
|
++{
|
|
|
++ u32 vol;
|
|
|
++ int i;
|
|
|
++
|
|
|
++ vol = yt8531_get_ldo_vol(phydev);
|
|
|
++ for (i = 0; i < ARRAY_SIZE(yt8531_ldo_vol); i++) {
|
|
|
++ if (yt8531_ldo_vol[i].vol == vol && yt8531_ldo_vol[i].cur == cur)
|
|
|
++ return yt8531_ldo_vol[i].ds;
|
|
|
++ }
|
|
|
++
|
|
|
++ return -EINVAL;
|
|
|
++}
|
|
|
++
|
|
|
++static int yt8531_set_ds(struct phy_device *phydev)
|
|
|
++{
|
|
|
++ struct device_node *node = phydev->mdio.dev.of_node;
|
|
|
++ u32 ds_field_low, ds_field_hi, val;
|
|
|
++ int ret, ds;
|
|
|
++
|
|
|
++ /* set rgmii rx clk driver strength */
|
|
|
++ if (!of_property_read_u32(node, "motorcomm,rx-clk-drv-microamp", &val)) {
|
|
|
++ ds = yt8531_get_ds_map(phydev, val);
|
|
|
++ if (ds < 0)
|
|
|
++ return dev_err_probe(&phydev->mdio.dev, ds,
|
|
|
++ "No matching current value was found.\n");
|
|
|
++ } else {
|
|
|
++ ds = YT8531_RGMII_RX_DS_DEFAULT;
|
|
|
++ }
|
|
|
++
|
|
|
++ ret = ytphy_modify_ext_with_lock(phydev,
|
|
|
++ YTPHY_PAD_DRIVE_STRENGTH_REG,
|
|
|
++ YT8531_RGMII_RXC_DS_MASK,
|
|
|
++ FIELD_PREP(YT8531_RGMII_RXC_DS_MASK, ds));
|
|
|
++ if (ret < 0)
|
|
|
++ return ret;
|
|
|
++
|
|
|
++ /* set rgmii rx data driver strength */
|
|
|
++ if (!of_property_read_u32(node, "motorcomm,rx-data-drv-microamp", &val)) {
|
|
|
++ ds = yt8531_get_ds_map(phydev, val);
|
|
|
++ if (ds < 0)
|
|
|
++ return dev_err_probe(&phydev->mdio.dev, ds,
|
|
|
++ "No matching current value was found.\n");
|
|
|
++ } else {
|
|
|
++ ds = YT8531_RGMII_RX_DS_DEFAULT;
|
|
|
++ }
|
|
|
++
|
|
|
++ ds_field_hi = FIELD_GET(BIT(2), ds);
|
|
|
++ ds_field_hi = FIELD_PREP(YT8531_RGMII_RXD_DS_HI_MASK, ds_field_hi);
|
|
|
++
|
|
|
++ ds_field_low = FIELD_GET(GENMASK(1, 0), ds);
|
|
|
++ ds_field_low = FIELD_PREP(YT8531_RGMII_RXD_DS_LOW_MASK, ds_field_low);
|
|
|
++
|
|
|
++ ret = ytphy_modify_ext_with_lock(phydev,
|
|
|
++ YTPHY_PAD_DRIVE_STRENGTH_REG,
|
|
|
++ YT8531_RGMII_RXD_DS_LOW_MASK | YT8531_RGMII_RXD_DS_HI_MASK,
|
|
|
++ ds_field_low | ds_field_hi);
|
|
|
++ if (ret < 0)
|
|
|
++ return ret;
|
|
|
++
|
|
|
++ return 0;
|
|
|
++}
|
|
|
++
|
|
|
++/**
|
|
|
+ * yt8521_probe() - read chip config then set suitable polling_mode
|
|
|
+ * @phydev: a pointer to a &struct phy_device
|
|
|
+ *
|
|
|
+@@ -1518,6 +1632,10 @@ static int yt8531_config_init(struct phy
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
++ ret = yt8531_set_ds(phydev);
|
|
|
++ if (ret < 0)
|
|
|
++ return ret;
|
|
|
++
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|