rockchip: configure eth pad driver strength for orangepi r1 plus lts
authorTianling Shen <cnsztl@immortalwrt.org>
Mon, 25 Dec 2023 03:23:58 +0000 (11:23 +0800)
committerHauke Mehrtens <hauke@hauke-m.de>
Thu, 4 Jan 2024 21:07:01 +0000 (22:07 +0100)
The default strength is not enough to provide stable connection
under 3.3v LDO voltage.

Fixes: 32d5921b8b55 ("rockchip: add Orange Pi R1 Plus LTS support")
Fixes: #13117
Fixes: #13759
Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
target/linux/generic/backport-5.15/791-v6.6-11-net-phy-motorcomm-Add-pad-drive-strength-cfg-support.patch [new file with mode: 0644]
target/linux/generic/backport-6.1/791-v6.6-11-net-phy-motorcomm-Add-pad-drive-strength-cfg-support.patch [new file with mode: 0644]
target/linux/rockchip/patches-6.1/015-v6.8-arm64-dts-rockchip-configure-eth-pad-driver-strength-for-.patch [new file with mode: 0644]

diff --git a/target/linux/generic/backport-5.15/791-v6.6-11-net-phy-motorcomm-Add-pad-drive-strength-cfg-support.patch b/target/linux/generic/backport-5.15/791-v6.6-11-net-phy-motorcomm-Add-pad-drive-strength-cfg-support.patch
new file mode 100644 (file)
index 0000000..010ca9b
--- /dev/null
@@ -0,0 +1,170 @@
+From 7a561e9351ae7e3fb1f08584d40b49c1e55dde60 Mon Sep 17 00:00:00 2001
+From: Samin Guo <samin.guo@starfivetech.com>
+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 <hal.feng@starfivetech.com>
+Signed-off-by: Samin Guo <samin.guo@starfivetech.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ 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;
+ }
diff --git a/target/linux/generic/backport-6.1/791-v6.6-11-net-phy-motorcomm-Add-pad-drive-strength-cfg-support.patch b/target/linux/generic/backport-6.1/791-v6.6-11-net-phy-motorcomm-Add-pad-drive-strength-cfg-support.patch
new file mode 100644 (file)
index 0000000..010ca9b
--- /dev/null
@@ -0,0 +1,170 @@
+From 7a561e9351ae7e3fb1f08584d40b49c1e55dde60 Mon Sep 17 00:00:00 2001
+From: Samin Guo <samin.guo@starfivetech.com>
+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 <hal.feng@starfivetech.com>
+Signed-off-by: Samin Guo <samin.guo@starfivetech.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ 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;
+ }
diff --git a/target/linux/rockchip/patches-6.1/015-v6.8-arm64-dts-rockchip-configure-eth-pad-driver-strength-for-.patch b/target/linux/rockchip/patches-6.1/015-v6.8-arm64-dts-rockchip-configure-eth-pad-driver-strength-for-.patch
new file mode 100644 (file)
index 0000000..01efaa3
--- /dev/null
@@ -0,0 +1,33 @@
+From fc5a80a432607d05e85bba37971712405f75c546 Mon Sep 17 00:00:00 2001
+From: Tianling Shen <cnsztl@gmail.com>
+Date: Sat, 16 Dec 2023 12:07:23 +0800
+Subject: [PATCH] arm64: dts: rockchip: configure eth pad driver strength
+ for orangepi r1 plus lts
+
+The default strength is not enough to provide stable connection
+under 3.3v LDO voltage.
+
+Fixes: 387b3bbac5ea ("arm64: dts: rockchip: Add Xunlong OrangePi R1 Plus LTS")
+Cc: stable@vger.kernel.org # 6.6+
+Signed-off-by: Tianling Shen <cnsztl@gmail.com>
+Link: https://lore.kernel.org/r/20231216040723.17864-1-cnsztl@gmail.com
+Signed-off-by: Heiko Stuebner <heiko@sntech.de>
+---
+ arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts
++++ b/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts
+@@ -26,9 +26,11 @@
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       reg = <0>;
++                      motorcomm,auto-sleep-disabled;
+                       motorcomm,clk-out-frequency-hz = <125000000>;
+                       motorcomm,keep-pll-enabled;
+-                      motorcomm,auto-sleep-disabled;
++                      motorcomm,rx-clk-drv-microamp = <5020>;
++                      motorcomm,rx-data-drv-microamp = <5020>;
+                       pinctrl-0 = <&eth_phy_reset_pin>;
+                       pinctrl-names = "default";