1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018-2021 Beijing WangXun Technology Co., Ltd.
3 */
4
5 #include "ngbe_phy_yt.h"
6
7 #define YT_PHY_RST_WAIT_PERIOD 5
8
ngbe_read_phy_reg_yt(struct ngbe_hw * hw,u32 reg_addr,u32 device_type,u16 * phy_data)9 s32 ngbe_read_phy_reg_yt(struct ngbe_hw *hw,
10 u32 reg_addr, u32 device_type, u16 *phy_data)
11 {
12 mdi_reg_t reg;
13 mdi_reg_22_t reg22;
14
15 reg.device_type = device_type;
16 reg.addr = reg_addr;
17
18 ngbe_mdi_map_register(®, ®22);
19
20 /* Read MII reg according to media type */
21 if (hw->phy.media_type == ngbe_media_type_fiber) {
22 ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY,
23 reg22.device_type, YT_SMI_PHY_SDS);
24 ngbe_read_phy_reg_mdi(hw, reg22.addr,
25 reg22.device_type, phy_data);
26 ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY,
27 reg22.device_type, 0);
28 } else {
29 ngbe_read_phy_reg_mdi(hw, reg22.addr,
30 reg22.device_type, phy_data);
31 }
32
33 return 0;
34 }
35
ngbe_write_phy_reg_yt(struct ngbe_hw * hw,u32 reg_addr,u32 device_type,u16 phy_data)36 s32 ngbe_write_phy_reg_yt(struct ngbe_hw *hw,
37 u32 reg_addr, u32 device_type, u16 phy_data)
38 {
39 mdi_reg_t reg;
40 mdi_reg_22_t reg22;
41
42 reg.device_type = device_type;
43 reg.addr = reg_addr;
44
45 ngbe_mdi_map_register(®, ®22);
46
47 /* Write MII reg according to media type */
48 if (hw->phy.media_type == ngbe_media_type_fiber) {
49 ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY,
50 reg22.device_type, YT_SMI_PHY_SDS);
51 ngbe_write_phy_reg_mdi(hw, reg22.addr,
52 reg22.device_type, phy_data);
53 ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY,
54 reg22.device_type, 0);
55 } else {
56 ngbe_write_phy_reg_mdi(hw, reg22.addr,
57 reg22.device_type, phy_data);
58 }
59
60 return 0;
61 }
62
ngbe_read_phy_reg_ext_yt(struct ngbe_hw * hw,u32 reg_addr,u32 device_type,u16 * phy_data)63 s32 ngbe_read_phy_reg_ext_yt(struct ngbe_hw *hw,
64 u32 reg_addr, u32 device_type, u16 *phy_data)
65 {
66 ngbe_write_phy_reg_mdi(hw, 0x1E, device_type, reg_addr);
67 ngbe_read_phy_reg_mdi(hw, 0x1F, device_type, phy_data);
68
69 return 0;
70 }
71
ngbe_write_phy_reg_ext_yt(struct ngbe_hw * hw,u32 reg_addr,u32 device_type,u16 phy_data)72 s32 ngbe_write_phy_reg_ext_yt(struct ngbe_hw *hw,
73 u32 reg_addr, u32 device_type, u16 phy_data)
74 {
75 ngbe_write_phy_reg_mdi(hw, 0x1E, device_type, reg_addr);
76 ngbe_write_phy_reg_mdi(hw, 0x1F, device_type, phy_data);
77
78 return 0;
79 }
80
ngbe_read_phy_reg_sds_ext_yt(struct ngbe_hw * hw,u32 reg_addr,u32 device_type,u16 * phy_data)81 s32 ngbe_read_phy_reg_sds_ext_yt(struct ngbe_hw *hw,
82 u32 reg_addr, u32 device_type, u16 *phy_data)
83 {
84 ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, device_type, YT_SMI_PHY_SDS);
85 ngbe_read_phy_reg_ext_yt(hw, reg_addr, device_type, phy_data);
86 ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, device_type, 0);
87
88 return 0;
89 }
90
ngbe_write_phy_reg_sds_ext_yt(struct ngbe_hw * hw,u32 reg_addr,u32 device_type,u16 phy_data)91 s32 ngbe_write_phy_reg_sds_ext_yt(struct ngbe_hw *hw,
92 u32 reg_addr, u32 device_type, u16 phy_data)
93 {
94 ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, device_type, YT_SMI_PHY_SDS);
95 ngbe_write_phy_reg_ext_yt(hw, reg_addr, device_type, phy_data);
96 ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, device_type, 0);
97
98 return 0;
99 }
100
ngbe_init_phy_yt(struct ngbe_hw * hw)101 s32 ngbe_init_phy_yt(struct ngbe_hw *hw)
102 {
103 u16 value = 0;
104
105 /* close sds area register */
106 ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, 0, 0);
107 /* enable interrupts */
108 ngbe_write_phy_reg_mdi(hw, YT_INTR, 0,
109 YT_INTR_ENA_MASK | YT_SDS_INTR_ENA_MASK);
110
111 /* power down in fiber mode */
112 hw->phy.read_reg(hw, YT_BCR, 0, &value);
113 value |= YT_BCR_PWDN;
114 hw->phy.write_reg(hw, YT_BCR, 0, value);
115
116 /* power down in UTP mode */
117 ngbe_read_phy_reg_mdi(hw, YT_BCR, 0, &value);
118 value |= YT_BCR_PWDN;
119 ngbe_write_phy_reg_mdi(hw, YT_BCR, 0, value);
120
121 return 0;
122 }
123
ngbe_setup_phy_link_yt(struct ngbe_hw * hw,u32 speed,bool autoneg_wait_to_complete)124 s32 ngbe_setup_phy_link_yt(struct ngbe_hw *hw, u32 speed,
125 bool autoneg_wait_to_complete)
126 {
127 u16 value_r4 = 0;
128 u16 value_r9 = 0;
129 u16 value;
130
131 UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
132
133 hw->phy.autoneg_advertised = 0;
134
135 /* check chip_mode first */
136 ngbe_read_phy_reg_ext_yt(hw, YT_CHIP, 0, &value);
137 if ((value & YT_CHIP_MODE_MASK) == YT_CHIP_MODE_SEL(0)) {
138 /* UTP to rgmii */
139 if (!hw->mac.autoneg) {
140 switch (speed) {
141 case NGBE_LINK_SPEED_1GB_FULL:
142 value = YT_BCR_SPEED_SELECT1;
143 break;
144 case NGBE_LINK_SPEED_100M_FULL:
145 value = YT_BCR_SPEED_SELECT0;
146 break;
147 case NGBE_LINK_SPEED_10M_FULL:
148 value = 0;
149 break;
150 default:
151 value = YT_BCR_SPEED_SELECT0 |
152 YT_BCR_SPEED_SELECT1;
153 DEBUGOUT("unknown speed = 0x%x.",
154 speed);
155 break;
156 }
157 /* duplex full */
158 value |= YT_BCR_DUPLEX | YT_BCR_RESET;
159 hw->phy.write_reg(hw, YT_BCR, 0, value);
160
161 goto skip_an;
162 }
163
164 /*disable 100/10base-T Self-negotiation ability*/
165 hw->phy.read_reg(hw, YT_ANA, 0, &value);
166 value &= ~(YT_ANA_100BASET_FULL | YT_ANA_100BASET_HALF |
167 YT_ANA_10BASET_FULL | YT_ANA_10BASET_HALF);
168 hw->phy.write_reg(hw, YT_ANA, 0, value);
169
170 /*disable 1000base-T Self-negotiation ability*/
171 hw->phy.read_reg(hw, YT_MS_CTRL, 0, &value);
172 value &= ~(YT_MS_1000BASET_FULL | YT_MS_1000BASET_HALF);
173 hw->phy.write_reg(hw, YT_MS_CTRL, 0, value);
174
175 if (speed & NGBE_LINK_SPEED_1GB_FULL) {
176 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
177 value_r9 |= YT_MS_1000BASET_FULL;
178 }
179 if (speed & NGBE_LINK_SPEED_100M_FULL) {
180 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL;
181 value_r4 |= YT_ANA_100BASET_FULL;
182 }
183 if (speed & NGBE_LINK_SPEED_10M_FULL) {
184 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL;
185 value_r4 |= YT_ANA_10BASET_FULL;
186 }
187
188 /* enable 1000base-T Self-negotiation ability */
189 hw->phy.read_reg(hw, YT_MS_CTRL, 0, &value);
190 value |= value_r9;
191 hw->phy.write_reg(hw, YT_MS_CTRL, 0, value);
192
193 /* enable 100/10base-T Self-negotiation ability */
194 hw->phy.read_reg(hw, YT_ANA, 0, &value);
195 value |= value_r4;
196 hw->phy.write_reg(hw, YT_ANA, 0, value);
197
198 /* software reset to make the above configuration take effect*/
199 hw->phy.read_reg(hw, YT_BCR, 0, &value);
200 value |= YT_BCR_RESET | YT_BCR_ANE | YT_BCR_RESTART_AN;
201 hw->phy.write_reg(hw, YT_BCR, 0, value);
202 skip_an:
203 /* power on in UTP mode */
204 ngbe_read_phy_reg_mdi(hw, YT_BCR, 0, &value);
205 value &= ~YT_BCR_PWDN;
206 ngbe_write_phy_reg_mdi(hw, YT_BCR, 0, value);
207 } else if ((value & YT_CHIP_MODE_MASK) == YT_CHIP_MODE_SEL(1)) {
208 /* fiber to rgmii */
209 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
210
211 /* RGMII_Config1 : Config rx and tx training delay */
212 value = YT_RGMII_CONF1_RXDELAY |
213 YT_RGMII_CONF1_TXDELAY_FE |
214 YT_RGMII_CONF1_TXDELAY;
215 ngbe_write_phy_reg_ext_yt(hw, YT_RGMII_CONF1, 0, value);
216 value = YT_CHIP_MODE_SEL(1) |
217 YT_CHIP_SW_LDO_EN |
218 YT_CHIP_SW_RST;
219 ngbe_write_phy_reg_ext_yt(hw, YT_CHIP, 0, value);
220
221 /* software reset */
222 ngbe_write_phy_reg_sds_ext_yt(hw, 0x0, 0, 0x9140);
223
224 /* power on phy */
225 hw->phy.read_reg(hw, YT_BCR, 0, &value);
226 value &= ~YT_BCR_PWDN;
227 hw->phy.write_reg(hw, YT_BCR, 0, value);
228 } else if ((value & YT_CHIP_MODE_MASK) == YT_CHIP_MODE_SEL(2)) {
229 /* power on in UTP mode */
230 ngbe_read_phy_reg_mdi(hw, YT_BCR, 0, &value);
231 value &= ~YT_BCR_PWDN;
232 ngbe_write_phy_reg_mdi(hw, YT_BCR, 0, value);
233 /* power down in fiber mode */
234 hw->phy.read_reg(hw, YT_BCR, 0, &value);
235 value &= ~YT_BCR_PWDN;
236 hw->phy.write_reg(hw, YT_BCR, 0, value);
237
238 hw->phy.read_reg(hw, YT_SPST, 0, &value);
239 if (value & YT_SPST_LINK) {
240 /* fiber up */
241 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
242 } else {
243 /* utp up */
244 /*disable 100/10base-T Self-negotiation ability*/
245 hw->phy.read_reg(hw, YT_ANA, 0, &value);
246 value &= ~(YT_ANA_100BASET_FULL | YT_ANA_100BASET_HALF |
247 YT_ANA_10BASET_FULL | YT_ANA_10BASET_HALF);
248 hw->phy.write_reg(hw, YT_ANA, 0, value);
249
250 /*disable 1000base-T Self-negotiation ability*/
251 hw->phy.read_reg(hw, YT_MS_CTRL, 0, &value);
252 value &= ~(YT_MS_1000BASET_FULL | YT_MS_1000BASET_HALF);
253 hw->phy.write_reg(hw, YT_MS_CTRL, 0, value);
254
255 if (speed & NGBE_LINK_SPEED_1GB_FULL) {
256 hw->phy.autoneg_advertised |=
257 NGBE_LINK_SPEED_1GB_FULL;
258 value_r9 |= YT_MS_1000BASET_FULL;
259 }
260 if (speed & NGBE_LINK_SPEED_100M_FULL) {
261 hw->phy.autoneg_advertised |=
262 NGBE_LINK_SPEED_100M_FULL;
263 value_r4 |= YT_ANA_100BASET_FULL;
264 }
265 if (speed & NGBE_LINK_SPEED_10M_FULL) {
266 hw->phy.autoneg_advertised |=
267 NGBE_LINK_SPEED_10M_FULL;
268 value_r4 |= YT_ANA_10BASET_FULL;
269 }
270
271 /* enable 1000base-T Self-negotiation ability */
272 hw->phy.read_reg(hw, YT_MS_CTRL, 0, &value);
273 value |= value_r9;
274 hw->phy.write_reg(hw, YT_MS_CTRL, 0, value);
275
276 /* enable 100/10base-T Self-negotiation ability */
277 hw->phy.read_reg(hw, YT_ANA, 0, &value);
278 value |= value_r4;
279 hw->phy.write_reg(hw, YT_ANA, 0, value);
280
281 /* software reset to make the above configuration
282 * take effect
283 */
284 hw->phy.read_reg(hw, YT_BCR, 0, &value);
285 value |= YT_BCR_RESET;
286 hw->phy.write_reg(hw, YT_BCR, 0, value);
287 }
288 } else if ((value & YT_CHIP_MODE_MASK) == YT_CHIP_MODE_SEL(4)) {
289 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
290
291 ngbe_read_phy_reg_ext_yt(hw, YT_RGMII_CONF1, 0, &value);
292 value |= YT_RGMII_CONF1_MODE;
293 ngbe_write_phy_reg_ext_yt(hw, YT_RGMII_CONF1, 0, value);
294
295 ngbe_read_phy_reg_ext_yt(hw, YT_RGMII_CONF2, 0, &value);
296 value &= ~(YT_RGMII_CONF2_SPEED_MASK | YT_RGMII_CONF2_DUPLEX |
297 YT_RGMII_CONF2_LINKUP);
298 value |= YT_RGMII_CONF2_SPEED(2) | YT_RGMII_CONF2_DUPLEX |
299 YT_RGMII_CONF2_LINKUP;
300 ngbe_write_phy_reg_ext_yt(hw, YT_RGMII_CONF2, 0, value);
301
302 ngbe_read_phy_reg_ext_yt(hw, YT_CHIP, 0, &value);
303 value &= ~YT_SMI_PHY_SW_RST;
304 ngbe_write_phy_reg_ext_yt(hw, YT_CHIP, 0, value);
305
306 /* power on phy */
307 hw->phy.read_reg(hw, YT_BCR, 0, &value);
308 value &= ~YT_BCR_PWDN;
309 hw->phy.write_reg(hw, YT_BCR, 0, value);
310 }
311
312 ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, 0, 0);
313 ngbe_read_phy_reg_mdi(hw, YT_INTR_STATUS, 0, &value);
314
315 return 0;
316 }
317
ngbe_reset_phy_yt(struct ngbe_hw * hw)318 s32 ngbe_reset_phy_yt(struct ngbe_hw *hw)
319 {
320 u32 i;
321 u16 ctrl = 0;
322 s32 status = 0;
323
324 if (hw->phy.type != ngbe_phy_yt8521s &&
325 hw->phy.type != ngbe_phy_yt8521s_sfi)
326 return NGBE_ERR_PHY_TYPE;
327
328 /* check chip_mode first */
329 ngbe_read_phy_reg_ext_yt(hw, YT_CHIP, 0, &ctrl);
330 if (ctrl & YT_CHIP_MODE_MASK) {
331 /* fiber to rgmii */
332 status = hw->phy.read_reg(hw, YT_BCR, 0, &ctrl);
333 /* sds software reset */
334 ctrl |= YT_BCR_RESET;
335 status = hw->phy.write_reg(hw, YT_BCR, 0, ctrl);
336
337 for (i = 0; i < YT_PHY_RST_WAIT_PERIOD; i++) {
338 status = hw->phy.read_reg(hw, YT_BCR, 0, &ctrl);
339 if (!(ctrl & YT_BCR_RESET))
340 break;
341 msleep(1);
342 }
343 } else {
344 /* UTP to rgmii */
345 status = ngbe_read_phy_reg_mdi(hw, YT_BCR, 0, &ctrl);
346 /* sds software reset */
347 ctrl |= YT_BCR_RESET;
348 status = ngbe_write_phy_reg_mdi(hw, YT_BCR, 0, ctrl);
349
350 for (i = 0; i < YT_PHY_RST_WAIT_PERIOD; i++) {
351 status = ngbe_read_phy_reg_mdi(hw, YT_BCR, 0, &ctrl);
352 if (!(ctrl & YT_BCR_RESET))
353 break;
354 msleep(1);
355 }
356 }
357
358 if (i == YT_PHY_RST_WAIT_PERIOD) {
359 DEBUGOUT("PHY reset polling failed to complete.");
360 return NGBE_ERR_RESET_FAILED;
361 }
362
363 return status;
364 }
365
ngbe_get_phy_advertised_pause_yt(struct ngbe_hw * hw,u8 * pause_bit)366 s32 ngbe_get_phy_advertised_pause_yt(struct ngbe_hw *hw, u8 *pause_bit)
367 {
368 u16 value;
369 s32 status = 0;
370
371 status = hw->phy.read_reg(hw, YT_ANA, 0, &value);
372 value &= YT_FANA_PAUSE_MASK;
373 *pause_bit = (u8)(value >> 7);
374
375 return status;
376 }
377
ngbe_get_phy_lp_advertised_pause_yt(struct ngbe_hw * hw,u8 * pause_bit)378 s32 ngbe_get_phy_lp_advertised_pause_yt(struct ngbe_hw *hw, u8 *pause_bit)
379 {
380 u16 value;
381 s32 status = 0;
382
383 status = hw->phy.read_reg(hw, YT_LPAR, 0, &value);
384 value &= YT_FLPAR_PAUSE_MASK;
385 *pause_bit = (u8)(value >> 7);
386
387 return status;
388 }
389
ngbe_set_phy_pause_adv_yt(struct ngbe_hw * hw,u16 pause_bit)390 s32 ngbe_set_phy_pause_adv_yt(struct ngbe_hw *hw, u16 pause_bit)
391 {
392 u16 value;
393 s32 status = 0;
394
395 status = hw->phy.read_reg(hw, YT_ANA, 0, &value);
396 value &= ~YT_FANA_PAUSE_MASK;
397 value |= pause_bit;
398 status = hw->phy.write_reg(hw, YT_ANA, 0, value);
399
400 return status;
401 }
402
ngbe_check_phy_link_yt(struct ngbe_hw * hw,u32 * speed,bool * link_up)403 s32 ngbe_check_phy_link_yt(struct ngbe_hw *hw,
404 u32 *speed, bool *link_up)
405 {
406 s32 status = 0;
407 u16 phy_link = 0;
408 u16 phy_speed = 0;
409 u16 phy_data = 0;
410 u16 insr = 0;
411
412 /* Initialize speed and link to default case */
413 *link_up = false;
414 *speed = NGBE_LINK_SPEED_UNKNOWN;
415
416 ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, 0, 0);
417 ngbe_read_phy_reg_mdi(hw, YT_INTR_STATUS, 0, &insr);
418
419 status = hw->phy.read_reg(hw, YT_SPST, 0, &phy_data);
420 phy_link = phy_data & YT_SPST_LINK;
421 phy_speed = phy_data & YT_SPST_SPEED_MASK;
422
423 if (phy_link) {
424 *link_up = true;
425
426 if (phy_speed == YT_SPST_SPEED_1000M)
427 *speed = NGBE_LINK_SPEED_1GB_FULL;
428 else if (phy_speed == YT_SPST_SPEED_100M)
429 *speed = NGBE_LINK_SPEED_100M_FULL;
430 else if (phy_speed == YT_SPST_SPEED_10M)
431 *speed = NGBE_LINK_SPEED_10M_FULL;
432 }
433
434 return status;
435 }
436
437