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