1 From deb8af5243504e379878ae3f9a091b21422d65b2 Mon Sep 17 00:00:00 2001
2 From: Alexander Couzens <lynxis@fe80.eu>
3 Date: Tue, 9 Apr 2024 09:30:11 +0200
4 Subject: [PATCH] net: phy: realtek: configure SerDes mode for rtl822xb PHYs
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
9 The rtl8221b and rtl8226b series support switching SerDes mode between
10 2500base-x and sgmii based on the negotiated copper speed.
12 Configure this switching mode according to SerDes modes supported by
15 There is an additional datasheet for RTL8226B/RTL8221B called
16 "SERDES MODE SETTING FLOW APPLICATION NOTE" where a sequence is
17 described to setup interface and rate adapter mode.
19 However, there is no documentation about the meaning of registers
20 and bits, it's literally just magic numbers and pseudo-code.
22 Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
23 [ refactored, dropped HiSGMII mode and changed commit message ]
24 Signed-off-by: Marek BehĂșn <kabel@kernel.org>
25 [ changed rtl822x_update_interface() to use vendor register ]
26 [ always fill in possible interfaces ]
27 [ only apply to rtl8221b and rtl8226b phy's ]
28 [ set phydev->rate_matching in .config_init() ]
29 Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
31 Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
32 Reviewed-by: should come before them, without any blank lines. As the
33 Signed-off-by: David S. Miller <davem@davemloft.net>
35 drivers/net/phy/realtek.c | 114 ++++++++++++++++++++++++++++++++++++--
36 1 file changed, 110 insertions(+), 4 deletions(-)
38 --- a/drivers/net/phy/realtek.c
39 +++ b/drivers/net/phy/realtek.c
42 #define RTL8201F_IER 0x13
44 +#define RTL822X_VND1_SERDES_OPTION 0x697a
45 +#define RTL822X_VND1_SERDES_OPTION_MODE_MASK GENMASK(5, 0)
46 +#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII 0
47 +#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX 2
49 +#define RTL822X_VND1_SERDES_CTRL3 0x7580
50 +#define RTL822X_VND1_SERDES_CTRL3_MODE_MASK GENMASK(5, 0)
51 +#define RTL822X_VND1_SERDES_CTRL3_MODE_SGMII 0x02
52 +#define RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX 0x16
54 #define RTL8366RB_POWER_SAVE 0x15
55 #define RTL8366RB_POWER_SAVE_ON BIT(12)
57 @@ -659,6 +669,63 @@ static int rtl822x_write_mmd(struct phy_
61 +static int rtl822xb_config_init(struct phy_device *phydev)
63 + bool has_2500, has_sgmii;
67 + has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX,
68 + phydev->host_interfaces) ||
69 + phydev->interface == PHY_INTERFACE_MODE_2500BASEX;
71 + has_sgmii = test_bit(PHY_INTERFACE_MODE_SGMII,
72 + phydev->host_interfaces) ||
73 + phydev->interface == PHY_INTERFACE_MODE_SGMII;
75 + /* fill in possible interfaces */
76 + __assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces,
78 + __assign_bit(PHY_INTERFACE_MODE_SGMII, phydev->possible_interfaces,
81 + if (!has_2500 && !has_sgmii)
84 + /* determine SerDes option mode */
85 + if (has_2500 && !has_sgmii) {
86 + mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX;
87 + phydev->rate_matching = RATE_MATCH_PAUSE;
89 + mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII;
90 + phydev->rate_matching = RATE_MATCH_NONE;
93 + /* the following sequence with magic numbers sets up the SerDes
96 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0);
100 + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1,
101 + RTL822X_VND1_SERDES_OPTION,
102 + RTL822X_VND1_SERDES_OPTION_MODE_MASK,
107 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503);
111 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455);
115 + return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020);
118 static int rtl822x_get_features(struct phy_device *phydev)
121 @@ -695,6 +762,28 @@ static int rtl822x_config_aneg(struct ph
122 return __genphy_config_aneg(phydev, ret);
125 +static void rtl822xb_update_interface(struct phy_device *phydev)
132 + /* Change interface according to serdes mode */
133 + val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_CTRL3);
137 + switch (val & RTL822X_VND1_SERDES_CTRL3_MODE_MASK) {
138 + case RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX:
139 + phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
141 + case RTL822X_VND1_SERDES_CTRL3_MODE_SGMII:
142 + phydev->interface = PHY_INTERFACE_MODE_SGMII;
147 static int rtl822x_read_status(struct phy_device *phydev)
150 @@ -716,6 +805,19 @@ static int rtl822x_read_status(struct ph
151 return rtlgen_get_speed(phydev);
154 +static int rtl822xb_read_status(struct phy_device *phydev)
158 + ret = rtl822x_read_status(phydev);
162 + rtl822xb_update_interface(phydev);
167 static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
170 @@ -988,7 +1090,8 @@ static struct phy_driver realtek_drvs[]
171 .name = "RTL8226B_RTL8221B 2.5Gbps PHY",
172 .get_features = rtl822x_get_features,
173 .config_aneg = rtl822x_config_aneg,
174 - .read_status = rtl822x_read_status,
175 + .config_init = rtl822xb_config_init,
176 + .read_status = rtl822xb_read_status,
177 .suspend = genphy_suspend,
178 .resume = rtlgen_resume,
179 .read_page = rtl821x_read_page,
180 @@ -1010,7 +1113,8 @@ static struct phy_driver realtek_drvs[]
181 .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY",
182 .get_features = rtl822x_get_features,
183 .config_aneg = rtl822x_config_aneg,
184 - .read_status = rtl822x_read_status,
185 + .config_init = rtl822xb_config_init,
186 + .read_status = rtl822xb_read_status,
187 .suspend = genphy_suspend,
188 .resume = rtlgen_resume,
189 .read_page = rtl821x_read_page,
190 @@ -1020,7 +1124,8 @@ static struct phy_driver realtek_drvs[]
191 .name = "RTL8221B-VB-CG 2.5Gbps PHY",
192 .get_features = rtl822x_get_features,
193 .config_aneg = rtl822x_config_aneg,
194 - .read_status = rtl822x_read_status,
195 + .config_init = rtl822xb_config_init,
196 + .read_status = rtl822xb_read_status,
197 .suspend = genphy_suspend,
198 .resume = rtlgen_resume,
199 .read_page = rtl821x_read_page,
200 @@ -1030,7 +1135,8 @@ static struct phy_driver realtek_drvs[]
201 .name = "RTL8221B-VM-CG 2.5Gbps PHY",
202 .get_features = rtl822x_get_features,
203 .config_aneg = rtl822x_config_aneg,
204 - .read_status = rtl822x_read_status,
205 + .config_init = rtl822xb_config_init,
206 + .read_status = rtl822xb_read_status,
207 .suspend = genphy_suspend,
208 .resume = rtlgen_resume,
209 .read_page = rtl821x_read_page,