xref: /dpdk/drivers/net/ngbe/base/ngbe_phy.c (revision 30a1de105a5f40d77b344a891c4a68f79e815c43)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018-2021 Beijing WangXun Technology Co., Ltd.
3  * Copyright(c) 2010-2017 Intel Corporation
4  */
5 
6 #include "ngbe_hw.h"
7 #include "ngbe_phy.h"
8 
9 s32 ngbe_mdi_map_register(mdi_reg_t *reg, mdi_reg_22_t *reg22)
10 {
11 	bool match = 1;
12 	switch (reg->device_type) {
13 	case NGBE_MD_DEV_PMA_PMD:
14 		switch (reg->addr) {
15 		case NGBE_MD_PHY_ID_HIGH:
16 		case NGBE_MD_PHY_ID_LOW:
17 			reg22->page = 0;
18 			reg22->addr = reg->addr;
19 			reg22->device_type = 0;
20 			break;
21 		default:
22 			match = 0;
23 		}
24 		break;
25 	default:
26 		match = 0;
27 		break;
28 	}
29 
30 	if (!match) {
31 		reg22->page = reg->device_type;
32 		reg22->device_type = reg->device_type;
33 		reg22->addr = reg->addr;
34 	}
35 
36 	return 0;
37 }
38 
39 /**
40  * ngbe_probe_phy - Identify a single address for a PHY
41  * @hw: pointer to hardware structure
42  * @phy_addr: PHY address to probe
43  *
44  * Returns true if PHY found
45  */
46 static bool ngbe_probe_phy(struct ngbe_hw *hw, u16 phy_addr)
47 {
48 	if (!ngbe_validate_phy_addr(hw, phy_addr)) {
49 		DEBUGOUT("Unable to validate PHY address 0x%04X\n",
50 			phy_addr);
51 		return false;
52 	}
53 
54 	if (ngbe_get_phy_id(hw))
55 		return false;
56 
57 	if (ngbe_get_phy_type_from_id(hw))
58 		return false;
59 
60 	return true;
61 }
62 
63 /**
64  *  ngbe_identify_phy - Get physical layer module
65  *  @hw: pointer to hardware structure
66  *
67  *  Determines the physical layer module found on the current adapter.
68  **/
69 s32 ngbe_identify_phy(struct ngbe_hw *hw)
70 {
71 	s32 err = NGBE_ERR_PHY_ADDR_INVALID;
72 	u16 phy_addr;
73 
74 	DEBUGFUNC("ngbe_identify_phy");
75 
76 	if (hw->phy.type != ngbe_phy_unknown)
77 		return 0;
78 
79 	/* select clause22 */
80 	wr32(hw, NGBE_MDIOMODE, NGBE_MDIOMODE_MASK);
81 
82 	for (phy_addr = 0; phy_addr < NGBE_MAX_PHY_ADDR; phy_addr++) {
83 		if (ngbe_probe_phy(hw, phy_addr)) {
84 			err = 0;
85 			break;
86 		}
87 	}
88 
89 	return err;
90 }
91 
92 /**
93  * ngbe_check_reset_blocked - check status of MNG FW veto bit
94  * @hw: pointer to the hardware structure
95  *
96  * This function checks the STAT.MNGVETO bit to see if there are
97  * any constraints on link from manageability.  For MAC's that don't
98  * have this bit just return faluse since the link can not be blocked
99  * via this method.
100  **/
101 s32 ngbe_check_reset_blocked(struct ngbe_hw *hw)
102 {
103 	u32 mmngc;
104 
105 	DEBUGFUNC("ngbe_check_reset_blocked");
106 
107 	mmngc = rd32(hw, NGBE_STAT);
108 	if (mmngc & NGBE_STAT_MNGVETO) {
109 		DEBUGOUT("MNG_VETO bit detected.\n");
110 		return true;
111 	}
112 
113 	return false;
114 }
115 
116 /**
117  *  ngbe_validate_phy_addr - Determines phy address is valid
118  *  @hw: pointer to hardware structure
119  *  @phy_addr: PHY address
120  *
121  **/
122 bool ngbe_validate_phy_addr(struct ngbe_hw *hw, u32 phy_addr)
123 {
124 	u16 phy_id = 0;
125 	bool valid = false;
126 
127 	DEBUGFUNC("ngbe_validate_phy_addr");
128 
129 	if (hw->sub_device_id == NGBE_SUB_DEV_ID_EM_YT8521S_SFP)
130 		return true;
131 
132 	hw->phy.addr = phy_addr;
133 	hw->phy.read_reg(hw, NGBE_MD_PHY_ID_HIGH,
134 			     NGBE_MD_DEV_PMA_PMD, &phy_id);
135 
136 	if (phy_id != 0xFFFF && phy_id != 0x0)
137 		valid = true;
138 
139 	DEBUGOUT("PHY ID HIGH is 0x%04X\n", phy_id);
140 
141 	return valid;
142 }
143 
144 /**
145  *  ngbe_get_phy_id - Get the phy ID
146  *  @hw: pointer to hardware structure
147  *
148  **/
149 s32 ngbe_get_phy_id(struct ngbe_hw *hw)
150 {
151 	u32 err;
152 	u16 phy_id_high = 0;
153 	u16 phy_id_low = 0;
154 
155 	DEBUGFUNC("ngbe_get_phy_id");
156 
157 	err = hw->phy.read_reg(hw, NGBE_MD_PHY_ID_HIGH,
158 				      NGBE_MD_DEV_PMA_PMD,
159 				      &phy_id_high);
160 	hw->phy.id = (u32)(phy_id_high << 16);
161 
162 	err = hw->phy.read_reg(hw, NGBE_MD_PHY_ID_LOW,
163 				NGBE_MD_DEV_PMA_PMD,
164 				&phy_id_low);
165 	hw->phy.id |= (u32)(phy_id_low & NGBE_PHY_REVISION_MASK);
166 	hw->phy.revision = (u32)(phy_id_low & ~NGBE_PHY_REVISION_MASK);
167 
168 	DEBUGOUT("PHY_ID_HIGH 0x%04X, PHY_ID_LOW 0x%04X\n",
169 		  phy_id_high, phy_id_low);
170 
171 	return err;
172 }
173 
174 /**
175  *  ngbe_get_phy_type_from_id - Get the phy type
176  *
177  **/
178 s32 ngbe_get_phy_type_from_id(struct ngbe_hw *hw)
179 {
180 	s32 status = 0;
181 
182 	DEBUGFUNC("ngbe_get_phy_type_from_id");
183 
184 	switch (hw->phy.id) {
185 	case NGBE_PHYID_RTL:
186 		hw->phy.type = ngbe_phy_rtl;
187 		break;
188 	case NGBE_PHYID_MVL:
189 		if (hw->phy.media_type == ngbe_media_type_fiber)
190 			hw->phy.type = ngbe_phy_mvl_sfi;
191 		else if (hw->phy.media_type == ngbe_media_type_copper)
192 			hw->phy.type = ngbe_phy_mvl;
193 		else
194 			status = ngbe_check_phy_mode_mvl(hw);
195 		break;
196 	case NGBE_PHYID_YT:
197 		if (hw->phy.media_type == ngbe_media_type_fiber)
198 			hw->phy.type = ngbe_phy_yt8521s_sfi;
199 		else
200 			hw->phy.type = ngbe_phy_yt8521s;
201 		break;
202 	default:
203 		hw->phy.type = ngbe_phy_unknown;
204 		status = NGBE_ERR_DEVICE_NOT_SUPPORTED;
205 		break;
206 	}
207 
208 	return status;
209 }
210 
211 /**
212  *  ngbe_reset_phy - Performs a PHY reset
213  *  @hw: pointer to hardware structure
214  **/
215 s32 ngbe_reset_phy(struct ngbe_hw *hw)
216 {
217 	s32 err = 0;
218 
219 	DEBUGFUNC("ngbe_reset_phy");
220 
221 	if (hw->phy.type == ngbe_phy_unknown)
222 		err = ngbe_identify_phy(hw);
223 
224 	if (err != 0 || hw->phy.type == ngbe_phy_none)
225 		return err;
226 
227 	/* Don't reset PHY if it's shut down due to overtemp. */
228 	if (hw->mac.check_overtemp(hw) == NGBE_ERR_OVERTEMP)
229 		return err;
230 
231 	/* Blocked by MNG FW so bail */
232 	if (ngbe_check_reset_blocked(hw))
233 		return err;
234 
235 	switch (hw->phy.type) {
236 	case ngbe_phy_rtl:
237 		err = ngbe_reset_phy_rtl(hw);
238 		break;
239 	case ngbe_phy_mvl:
240 	case ngbe_phy_mvl_sfi:
241 		err = ngbe_reset_phy_mvl(hw);
242 		break;
243 	case ngbe_phy_yt8521s:
244 	case ngbe_phy_yt8521s_sfi:
245 		err = ngbe_reset_phy_yt(hw);
246 		break;
247 	default:
248 		break;
249 	}
250 
251 	return err;
252 }
253 
254 /**
255  *  ngbe_read_phy_mdi - Reads a value from a specified PHY register without
256  *  the SWFW lock
257  *  @hw: pointer to hardware structure
258  *  @reg_addr: 32 bit address of PHY register to read
259  *  @device_type: 5 bit device type
260  *  @phy_data: Pointer to read data from PHY register
261  **/
262 s32 ngbe_read_phy_reg_mdi(struct ngbe_hw *hw, u32 reg_addr, u32 device_type,
263 			   u16 *phy_data)
264 {
265 	u32 command, data;
266 
267 	/* Setup and write the address cycle command */
268 	command = NGBE_MDIOSCA_REG(reg_addr) |
269 		  NGBE_MDIOSCA_DEV(device_type) |
270 		  NGBE_MDIOSCA_PORT(hw->phy.addr);
271 	wr32(hw, NGBE_MDIOSCA, command);
272 
273 	command = NGBE_MDIOSCD_CMD_READ |
274 		  NGBE_MDIOSCD_BUSY |
275 		  NGBE_MDIOSCD_CLOCK(6);
276 	wr32(hw, NGBE_MDIOSCD, command);
277 
278 	/*
279 	 * Check every 10 usec to see if the address cycle completed.
280 	 * The MDI Command bit will clear when the operation is
281 	 * complete
282 	 */
283 	if (!po32m(hw, NGBE_MDIOSCD, NGBE_MDIOSCD_BUSY,
284 		0, NULL, 100, 100)) {
285 		DEBUGOUT("PHY address command did not complete\n");
286 		return NGBE_ERR_PHY;
287 	}
288 
289 	data = rd32(hw, NGBE_MDIOSCD);
290 	*phy_data = (u16)NGBE_MDIOSCD_DAT_R(data);
291 
292 	return 0;
293 }
294 
295 /**
296  *  ngbe_read_phy_reg - Reads a value from a specified PHY register
297  *  using the SWFW lock - this function is needed in most cases
298  *  @hw: pointer to hardware structure
299  *  @reg_addr: 32 bit address of PHY register to read
300  *  @device_type: 5 bit device type
301  *  @phy_data: Pointer to read data from PHY register
302  **/
303 s32 ngbe_read_phy_reg(struct ngbe_hw *hw, u32 reg_addr,
304 			       u32 device_type, u16 *phy_data)
305 {
306 	s32 err;
307 	u32 gssr = hw->phy.phy_semaphore_mask;
308 
309 	DEBUGFUNC("ngbe_read_phy_reg");
310 
311 	if (hw->mac.acquire_swfw_sync(hw, gssr))
312 		return NGBE_ERR_SWFW_SYNC;
313 
314 	err = hw->phy.read_reg_unlocked(hw, reg_addr, device_type,
315 					phy_data);
316 
317 	hw->mac.release_swfw_sync(hw, gssr);
318 
319 	return err;
320 }
321 
322 /**
323  *  ngbe_write_phy_reg_mdi - Writes a value to specified PHY register
324  *  without SWFW lock
325  *  @hw: pointer to hardware structure
326  *  @reg_addr: 32 bit PHY register to write
327  *  @device_type: 5 bit device type
328  *  @phy_data: Data to write to the PHY register
329  **/
330 s32 ngbe_write_phy_reg_mdi(struct ngbe_hw *hw, u32 reg_addr,
331 				u32 device_type, u16 phy_data)
332 {
333 	u32 command;
334 
335 	/* write command */
336 	command = NGBE_MDIOSCA_REG(reg_addr) |
337 		  NGBE_MDIOSCA_DEV(device_type) |
338 		  NGBE_MDIOSCA_PORT(hw->phy.addr);
339 	wr32(hw, NGBE_MDIOSCA, command);
340 
341 	command = NGBE_MDIOSCD_CMD_WRITE |
342 		  NGBE_MDIOSCD_DAT(phy_data) |
343 		  NGBE_MDIOSCD_BUSY |
344 		  NGBE_MDIOSCD_CLOCK(6);
345 	wr32(hw, NGBE_MDIOSCD, command);
346 
347 	/* wait for completion */
348 	if (!po32m(hw, NGBE_MDIOSCD, NGBE_MDIOSCD_BUSY,
349 		0, NULL, 100, 100)) {
350 		TLOG_DEBUG("PHY write cmd didn't complete\n");
351 		return NGBE_ERR_PHY;
352 	}
353 
354 	return 0;
355 }
356 
357 /**
358  *  ngbe_write_phy_reg - Writes a value to specified PHY register
359  *  using SWFW lock- this function is needed in most cases
360  *  @hw: pointer to hardware structure
361  *  @reg_addr: 32 bit PHY register to write
362  *  @device_type: 5 bit device type
363  *  @phy_data: Data to write to the PHY register
364  **/
365 s32 ngbe_write_phy_reg(struct ngbe_hw *hw, u32 reg_addr,
366 				u32 device_type, u16 phy_data)
367 {
368 	s32 err;
369 	u32 gssr = hw->phy.phy_semaphore_mask;
370 
371 	DEBUGFUNC("ngbe_write_phy_reg");
372 
373 	if (hw->mac.acquire_swfw_sync(hw, gssr))
374 		err = NGBE_ERR_SWFW_SYNC;
375 
376 	err = hw->phy.write_reg_unlocked(hw, reg_addr, device_type,
377 					 phy_data);
378 
379 	hw->mac.release_swfw_sync(hw, gssr);
380 
381 	return err;
382 }
383 
384 /**
385  *  ngbe_init_phy - PHY specific init
386  *  @hw: pointer to hardware structure
387  *
388  *  Initialize any function pointers that were not able to be
389  *  set during init_shared_code because the PHY type was
390  *  not known.
391  *
392  **/
393 s32 ngbe_init_phy(struct ngbe_hw *hw)
394 {
395 	struct ngbe_phy_info *phy = &hw->phy;
396 	s32 err = 0;
397 
398 	DEBUGFUNC("ngbe_init_phy");
399 
400 	hw->phy.addr = 0;
401 
402 	switch (hw->sub_device_id) {
403 	case NGBE_SUB_DEV_ID_EM_RTL_SGMII:
404 	case NGBE_SUB_DEV_ID_EM_RTL_YT8521S_SFP:
405 		hw->phy.read_reg_unlocked = ngbe_read_phy_reg_rtl;
406 		hw->phy.write_reg_unlocked = ngbe_write_phy_reg_rtl;
407 		break;
408 	case NGBE_SUB_DEV_ID_EM_MVL_RGMII:
409 	case NGBE_SUB_DEV_ID_EM_MVL_SFP:
410 	case NGBE_SUB_DEV_ID_EM_MVL_MIX:
411 		hw->phy.read_reg_unlocked = ngbe_read_phy_reg_mvl;
412 		hw->phy.write_reg_unlocked = ngbe_write_phy_reg_mvl;
413 		break;
414 	case NGBE_SUB_DEV_ID_EM_YT8521S_SFP:
415 		hw->phy.read_reg_unlocked = ngbe_read_phy_reg_yt;
416 		hw->phy.write_reg_unlocked = ngbe_write_phy_reg_yt;
417 		break;
418 	default:
419 		break;
420 	}
421 
422 	hw->phy.phy_semaphore_mask = NGBE_MNGSEM_SWPHY;
423 
424 	/* Identify the PHY */
425 	err = phy->identify(hw);
426 	if (err == NGBE_ERR_PHY_ADDR_INVALID)
427 		goto init_phy_ops_out;
428 
429 	/* Set necessary function pointers based on PHY type */
430 	switch (hw->phy.type) {
431 	case ngbe_phy_rtl:
432 		hw->phy.init_hw = ngbe_init_phy_rtl;
433 		hw->phy.check_link = ngbe_check_phy_link_rtl;
434 		hw->phy.setup_link = ngbe_setup_phy_link_rtl;
435 		hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_rtl;
436 		hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_rtl;
437 		hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_rtl;
438 		break;
439 	case ngbe_phy_mvl:
440 	case ngbe_phy_mvl_sfi:
441 		hw->phy.init_hw = ngbe_init_phy_mvl;
442 		hw->phy.check_link = ngbe_check_phy_link_mvl;
443 		hw->phy.setup_link = ngbe_setup_phy_link_mvl;
444 		hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_mvl;
445 		hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_mvl;
446 		hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_mvl;
447 		break;
448 	case ngbe_phy_yt8521s:
449 	case ngbe_phy_yt8521s_sfi:
450 		hw->phy.init_hw = ngbe_init_phy_yt;
451 		hw->phy.check_link = ngbe_check_phy_link_yt;
452 		hw->phy.setup_link = ngbe_setup_phy_link_yt;
453 		hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_yt;
454 		hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_yt;
455 		hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_yt;
456 	default:
457 		break;
458 	}
459 
460 init_phy_ops_out:
461 	return err;
462 }
463 
464