From: Tianling Shen Date: Mon, 25 Dec 2023 03:23:58 +0000 (+0800) Subject: rockchip: configure eth pad driver strength for orangepi r1 plus lts X-Git-Url: http://git.openwrt.org/?a=commitdiff_plain;h=3645ac8a10d9abb1451343beaf7d65b53eeecffd;hp=438a97fab69b41387e25cbec45271e7fe159a330;p=openwrt%2Fopenwrt.git 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: 32d5921b8b55 ("rockchip: add Orange Pi R1 Plus LTS support") Fixes: #13117 Fixes: #13759 Signed-off-by: Tianling Shen --- 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 index 0000000000..010ca9b68a --- /dev/null +++ b/target/linux/generic/backport-5.15/791-v6.6-11-net-phy-motorcomm-Add-pad-drive-strength-cfg-support.patch @@ -0,0 +1,170 @@ +From 7a561e9351ae7e3fb1f08584d40b49c1e55dde60 Mon Sep 17 00:00:00 2001 +From: Samin Guo +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 +Signed-off-by: Samin Guo +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + 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 index 0000000000..010ca9b68a --- /dev/null +++ b/target/linux/generic/backport-6.1/791-v6.6-11-net-phy-motorcomm-Add-pad-drive-strength-cfg-support.patch @@ -0,0 +1,170 @@ +From 7a561e9351ae7e3fb1f08584d40b49c1e55dde60 Mon Sep 17 00:00:00 2001 +From: Samin Guo +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 +Signed-off-by: Samin Guo +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + 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 index 0000000000..01efaa3a9d --- /dev/null +++ b/target/linux/rockchip/patches-6.1/015-v6.8-arm64-dts-rockchip-configure-eth-pad-driver-strength-for-.patch @@ -0,0 +1,33 @@ +From fc5a80a432607d05e85bba37971712405f75c546 Mon Sep 17 00:00:00 2001 +From: Tianling Shen +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 +Link: https://lore.kernel.org/r/20231216040723.17864-1-cnsztl@gmail.com +Signed-off-by: Heiko Stuebner +--- + 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 = <ð_phy_reset_pin>; + pinctrl-names = "default";