ba24ca3a1637b11cc9626e87c7129010a68eda40
[openwrt/staging/wigyori.git] /
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
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 The rtl8221b and rtl8226b series support switching SerDes mode between
10 2500base-x and sgmii based on the negotiated copper speed.
11
12 Configure this switching mode according to SerDes modes supported by
13 host.
14
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.
18
19 However, there is no documentation about the meaning of registers
20 and bits, it's literally just magic numbers and pseudo-code.
21
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>
30
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>
34 ---
35 drivers/net/phy/realtek.c | 114 ++++++++++++++++++++++++++++++++++++--
36 1 file changed, 110 insertions(+), 4 deletions(-)
37
38 --- a/drivers/net/phy/realtek.c
39 +++ b/drivers/net/phy/realtek.c
40 @@ -54,6 +54,16 @@
41 RTL8201F_ISR_LINK)
42 #define RTL8201F_IER 0x13
43
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
48 +
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
53 +
54 #define RTL8366RB_POWER_SAVE 0x15
55 #define RTL8366RB_POWER_SAVE_ON BIT(12)
56
57 @@ -659,6 +669,63 @@ static int rtl822x_write_mmd(struct phy_
58 return ret;
59 }
60
61 +static int rtl822xb_config_init(struct phy_device *phydev)
62 +{
63 + bool has_2500, has_sgmii;
64 + u16 mode;
65 + int ret;
66 +
67 + has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX,
68 + phydev->host_interfaces) ||
69 + phydev->interface == PHY_INTERFACE_MODE_2500BASEX;
70 +
71 + has_sgmii = test_bit(PHY_INTERFACE_MODE_SGMII,
72 + phydev->host_interfaces) ||
73 + phydev->interface == PHY_INTERFACE_MODE_SGMII;
74 +
75 + /* fill in possible interfaces */
76 + __assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces,
77 + has_2500);
78 + __assign_bit(PHY_INTERFACE_MODE_SGMII, phydev->possible_interfaces,
79 + has_sgmii);
80 +
81 + if (!has_2500 && !has_sgmii)
82 + return 0;
83 +
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;
88 + } else {
89 + mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII;
90 + phydev->rate_matching = RATE_MATCH_NONE;
91 + }
92 +
93 + /* the following sequence with magic numbers sets up the SerDes
94 + * option mode
95 + */
96 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0);
97 + if (ret < 0)
98 + return ret;
99 +
100 + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1,
101 + RTL822X_VND1_SERDES_OPTION,
102 + RTL822X_VND1_SERDES_OPTION_MODE_MASK,
103 + mode);
104 + if (ret < 0)
105 + return ret;
106 +
107 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503);
108 + if (ret < 0)
109 + return ret;
110 +
111 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455);
112 + if (ret < 0)
113 + return ret;
114 +
115 + return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020);
116 +}
117 +
118 static int rtl822x_get_features(struct phy_device *phydev)
119 {
120 int val;
121 @@ -695,6 +762,28 @@ static int rtl822x_config_aneg(struct ph
122 return __genphy_config_aneg(phydev, ret);
123 }
124
125 +static void rtl822xb_update_interface(struct phy_device *phydev)
126 +{
127 + int val;
128 +
129 + if (!phydev->link)
130 + return;
131 +
132 + /* Change interface according to serdes mode */
133 + val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_CTRL3);
134 + if (val < 0)
135 + return;
136 +
137 + switch (val & RTL822X_VND1_SERDES_CTRL3_MODE_MASK) {
138 + case RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX:
139 + phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
140 + break;
141 + case RTL822X_VND1_SERDES_CTRL3_MODE_SGMII:
142 + phydev->interface = PHY_INTERFACE_MODE_SGMII;
143 + break;
144 + }
145 +}
146 +
147 static int rtl822x_read_status(struct phy_device *phydev)
148 {
149 int ret;
150 @@ -716,6 +805,19 @@ static int rtl822x_read_status(struct ph
151 return rtlgen_get_speed(phydev);
152 }
153
154 +static int rtl822xb_read_status(struct phy_device *phydev)
155 +{
156 + int ret;
157 +
158 + ret = rtl822x_read_status(phydev);
159 + if (ret < 0)
160 + return ret;
161 +
162 + rtl822xb_update_interface(phydev);
163 +
164 + return 0;
165 +}
166 +
167 static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
168 {
169 int val;
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,