Branch data Line data Source code
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 : 0 : s32 ngbe_mdi_map_register(mdi_reg_t *reg, mdi_reg_22_t *reg22)
10 : : {
11 : : bool match = 1;
12 [ # # ]: 0 : switch (reg->device_type) {
13 : 0 : case NGBE_MD_DEV_PMA_PMD:
14 [ # # ]: 0 : switch (reg->addr) {
15 : 0 : case NGBE_MD_PHY_ID_HIGH:
16 : : case NGBE_MD_PHY_ID_LOW:
17 : 0 : reg22->page = 0;
18 : 0 : reg22->addr = reg->addr;
19 : 0 : 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 : 0 : reg22->page = reg->device_type;
32 : 0 : reg22->device_type = reg->device_type;
33 : 0 : reg22->addr = reg->addr;
34 : : }
35 : :
36 : 0 : 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 : 0 : static bool ngbe_probe_phy(struct ngbe_hw *hw, u16 phy_addr)
47 : : {
48 [ # # ]: 0 : if (!ngbe_validate_phy_addr(hw, phy_addr)) {
49 : 0 : DEBUGOUT("Unable to validate PHY address 0x%04X",
50 : : phy_addr);
51 : 0 : return false;
52 : : }
53 : :
54 [ # # ]: 0 : if (ngbe_get_phy_id(hw))
55 : : return false;
56 : :
57 [ # # ]: 0 : if (ngbe_get_phy_type_from_id(hw))
58 : 0 : 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 : 0 : s32 ngbe_identify_phy(struct ngbe_hw *hw)
70 : : {
71 : : s32 err = NGBE_ERR_PHY_ADDR_INVALID;
72 : : u16 phy_addr;
73 : :
74 [ # # ]: 0 : if (hw->phy.type != ngbe_phy_unknown)
75 : : return 0;
76 : :
77 : : /* select clause22 */
78 : : wr32(hw, NGBE_MDIOMODE, NGBE_MDIOMODE_MASK);
79 : :
80 [ # # ]: 0 : for (phy_addr = 0; phy_addr < NGBE_MAX_PHY_ADDR; phy_addr++) {
81 [ # # ]: 0 : 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 : : **/
99 : 0 : s32 ngbe_check_reset_blocked(struct ngbe_hw *hw)
100 : : {
101 : : u32 mmngc;
102 : :
103 : : mmngc = rd32(hw, NGBE_STAT);
104 [ # # ]: 0 : if (mmngc & NGBE_STAT_MNGVETO) {
105 : 0 : DEBUGOUT("MNG_VETO bit detected.");
106 : 0 : 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 : : **/
118 : 0 : bool ngbe_validate_phy_addr(struct ngbe_hw *hw, u32 phy_addr)
119 : : {
120 : 0 : u16 phy_id = 0;
121 : : bool valid = false;
122 : :
123 : 0 : hw->phy.addr = phy_addr;
124 : 0 : hw->phy.read_reg(hw, NGBE_MD_PHY_ID_LOW,
125 : : NGBE_MD_DEV_PMA_PMD, &phy_id);
126 : :
127 [ # # ]: 0 : if (phy_id != 0xFFFF && phy_id != 0x0)
128 : : valid = true;
129 : :
130 : 0 : DEBUGOUT("PHY ID LOW is 0x%04X", phy_id);
131 : :
132 : 0 : return valid;
133 : : }
134 : :
135 : : /**
136 : : * ngbe_get_phy_id - Get the phy ID
137 : : * @hw: pointer to hardware structure
138 : : *
139 : : **/
140 : 0 : s32 ngbe_get_phy_id(struct ngbe_hw *hw)
141 : : {
142 : : u32 err;
143 : 0 : u16 phy_id_high = 0;
144 : 0 : u16 phy_id_low = 0;
145 : :
146 : 0 : err = hw->phy.read_reg(hw, NGBE_MD_PHY_ID_HIGH,
147 : : NGBE_MD_DEV_PMA_PMD,
148 : : &phy_id_high);
149 : 0 : hw->phy.id = (u32)(phy_id_high << 16);
150 : :
151 : 0 : err = hw->phy.read_reg(hw, NGBE_MD_PHY_ID_LOW,
152 : : NGBE_MD_DEV_PMA_PMD,
153 : : &phy_id_low);
154 : 0 : hw->phy.id |= (u32)(phy_id_low & NGBE_PHY_REVISION_MASK);
155 : 0 : hw->phy.revision = (u32)(phy_id_low & ~NGBE_PHY_REVISION_MASK);
156 : :
157 : 0 : DEBUGOUT("PHY_ID_HIGH 0x%04X, PHY_ID_LOW 0x%04X",
158 : : phy_id_high, phy_id_low);
159 : :
160 : 0 : return err;
161 : : }
162 : :
163 : : /**
164 : : * ngbe_get_phy_type_from_id - Get the phy type
165 : : *
166 : : **/
167 : 0 : s32 ngbe_get_phy_type_from_id(struct ngbe_hw *hw)
168 : : {
169 : : s32 status = 0;
170 : :
171 [ # # # # ]: 0 : switch (hw->phy.id) {
172 : 0 : case NGBE_PHYID_RTL:
173 : 0 : hw->phy.type = ngbe_phy_rtl;
174 : 0 : break;
175 : 0 : case NGBE_PHYID_MVL:
176 [ # # ]: 0 : if (hw->phy.media_type == ngbe_media_type_fiber)
177 : 0 : hw->phy.type = ngbe_phy_mvl_sfi;
178 [ # # ]: 0 : else if (hw->phy.media_type == ngbe_media_type_copper)
179 : 0 : hw->phy.type = ngbe_phy_mvl;
180 : : else
181 : 0 : status = ngbe_check_phy_mode_mvl(hw);
182 : : break;
183 : 0 : case NGBE_PHYID_YT8521:
184 : : case NGBE_PHYID_YT8531:
185 [ # # ]: 0 : if (hw->phy.media_type == ngbe_media_type_fiber)
186 : 0 : hw->phy.type = ngbe_phy_yt8521s_sfi;
187 : : else
188 : 0 : hw->phy.type = ngbe_phy_yt8521s;
189 : : break;
190 : 0 : default:
191 : 0 : hw->phy.type = ngbe_phy_unknown;
192 : : status = NGBE_ERR_DEVICE_NOT_SUPPORTED;
193 : 0 : break;
194 : : }
195 : :
196 : 0 : return status;
197 : : }
198 : :
199 : : /**
200 : : * ngbe_reset_phy - Performs a PHY reset
201 : : * @hw: pointer to hardware structure
202 : : **/
203 : 0 : s32 ngbe_reset_phy(struct ngbe_hw *hw)
204 : : {
205 : : s32 err = 0;
206 : :
207 [ # # ]: 0 : if (hw->phy.type == ngbe_phy_unknown)
208 : 0 : err = ngbe_identify_phy(hw);
209 : :
210 [ # # # # ]: 0 : if (err != 0 || hw->phy.type == ngbe_phy_none)
211 : 0 : return err;
212 : :
213 [ # # ]: 0 : if (hw->ncsi_enabled)
214 : : return err;
215 : :
216 : : /* Don't reset PHY if it's shut down due to overtemp. */
217 [ # # ]: 0 : if (hw->mac.check_overtemp(hw) == NGBE_ERR_OVERTEMP)
218 : : return err;
219 : :
220 : : /* Blocked by MNG FW so bail */
221 [ # # ]: 0 : if (ngbe_check_reset_blocked(hw))
222 : : return err;
223 : :
224 [ # # # # ]: 0 : switch (hw->phy.type) {
225 : 0 : case ngbe_phy_rtl:
226 : 0 : err = ngbe_reset_phy_rtl(hw);
227 : 0 : break;
228 : 0 : case ngbe_phy_mvl:
229 : : case ngbe_phy_mvl_sfi:
230 : 0 : err = ngbe_reset_phy_mvl(hw);
231 : 0 : break;
232 : 0 : case ngbe_phy_yt8521s:
233 : : case ngbe_phy_yt8521s_sfi:
234 : 0 : err = ngbe_reset_phy_yt(hw);
235 : 0 : 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 : : **/
251 : 0 : 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 : 0 : command = NGBE_MDIOSCA_REG(reg_addr) |
258 : 0 : NGBE_MDIOSCA_DEV(device_type) |
259 : 0 : 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 [ # # ]: 0 : if (!po32m(hw, NGBE_MDIOSCD, NGBE_MDIOSCD_BUSY,
273 : : 0, NULL, 100, 100)) {
274 : 0 : DEBUGOUT("PHY address command did not complete");
275 : 0 : return NGBE_ERR_PHY;
276 : : }
277 : :
278 : : data = rd32(hw, NGBE_MDIOSCD);
279 : 0 : *phy_data = (u16)NGBE_MDIOSCD_DAT_R(data);
280 : :
281 : 0 : 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 : : **/
292 : 0 : 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 : 0 : err = hw->phy.read_reg_unlocked(hw, reg_addr, device_type,
298 : : phy_data);
299 : :
300 : 0 : 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 : : **/
311 : 0 : 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 : 0 : command = NGBE_MDIOSCA_REG(reg_addr) |
318 : 0 : NGBE_MDIOSCA_DEV(device_type) |
319 : 0 : NGBE_MDIOSCA_PORT(hw->phy.addr);
320 : : wr32(hw, NGBE_MDIOSCA, command);
321 : :
322 : 0 : command = NGBE_MDIOSCD_CMD_WRITE |
323 : 0 : 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 [ # # ]: 0 : if (!po32m(hw, NGBE_MDIOSCD, NGBE_MDIOSCD_BUSY,
330 : : 0, NULL, 100, 100)) {
331 : 0 : DEBUGOUT("PHY write cmd didn't complete");
332 : 0 : 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 : : **/
346 : 0 : 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 : 0 : err = hw->phy.write_reg_unlocked(hw, reg_addr, device_type,
352 : : phy_data);
353 : :
354 : 0 : 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 : : **/
366 : 0 : s32 ngbe_init_phy(struct ngbe_hw *hw)
367 : : {
368 : : struct ngbe_phy_info *phy = &hw->phy;
369 : : s32 err = 0;
370 : :
371 : 0 : hw->phy.addr = 0;
372 : :
373 [ # # # # ]: 0 : switch (hw->sub_device_id) {
374 : 0 : case NGBE_SUB_DEV_ID_EM_RTL_SGMII:
375 : : case NGBE_SUB_DEV_ID_EM_RTL_YT8521S_SFP:
376 : 0 : hw->phy.read_reg_unlocked = ngbe_read_phy_reg_rtl;
377 : 0 : hw->phy.write_reg_unlocked = ngbe_write_phy_reg_rtl;
378 : 0 : break;
379 : 0 : 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 : 0 : hw->phy.read_reg_unlocked = ngbe_read_phy_reg_mvl;
383 : 0 : hw->phy.write_reg_unlocked = ngbe_write_phy_reg_mvl;
384 : 0 : break;
385 : 0 : case NGBE_SUB_DEV_ID_EM_YT8521S_SFP:
386 : 0 : hw->phy.read_reg_unlocked = ngbe_read_phy_reg_yt;
387 : 0 : hw->phy.write_reg_unlocked = ngbe_write_phy_reg_yt;
388 : 0 : break;
389 : : default:
390 : : break;
391 : : }
392 : :
393 : 0 : hw->phy.phy_semaphore_mask = NGBE_MNGSEM_SWPHY;
394 : :
395 : : /* Identify the PHY */
396 : 0 : err = phy->identify(hw);
397 [ # # ]: 0 : if (err == NGBE_ERR_PHY_ADDR_INVALID)
398 : 0 : goto init_phy_ops_out;
399 : :
400 : : /* Set necessary function pointers based on PHY type */
401 [ # # # # ]: 0 : switch (hw->phy.type) {
402 : 0 : case ngbe_phy_rtl:
403 : 0 : hw->phy.init_hw = ngbe_init_phy_rtl;
404 : 0 : hw->phy.check_link = ngbe_check_phy_link_rtl;
405 : 0 : hw->phy.setup_link = ngbe_setup_phy_link_rtl;
406 : 0 : hw->phy.set_phy_power = ngbe_set_phy_power_rtl;
407 : 0 : hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_rtl;
408 : 0 : hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_rtl;
409 : 0 : hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_rtl;
410 : 0 : break;
411 : 0 : case ngbe_phy_mvl:
412 : : case ngbe_phy_mvl_sfi:
413 : 0 : hw->phy.init_hw = ngbe_init_phy_mvl;
414 : 0 : hw->phy.check_link = ngbe_check_phy_link_mvl;
415 : 0 : hw->phy.setup_link = ngbe_setup_phy_link_mvl;
416 : 0 : hw->phy.set_phy_power = ngbe_set_phy_power_mvl;
417 : 0 : hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_mvl;
418 : 0 : hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_mvl;
419 : 0 : hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_mvl;
420 : 0 : break;
421 : 0 : case ngbe_phy_yt8521s:
422 : : case ngbe_phy_yt8521s_sfi:
423 : 0 : hw->phy.init_hw = ngbe_init_phy_yt;
424 : 0 : hw->phy.check_link = ngbe_check_phy_link_yt;
425 : 0 : hw->phy.setup_link = ngbe_setup_phy_link_yt;
426 : 0 : hw->phy.set_phy_power = ngbe_set_phy_power_yt;
427 : 0 : hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_yt;
428 : 0 : hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_yt;
429 : 0 : hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_yt;
430 : : default:
431 : : break;
432 : : }
433 : :
434 [ # # ]: 0 : if (hw->wol_enabled || hw->ncsi_enabled)
435 : 0 : hw->phy.reset_disable = true;
436 : :
437 : 0 : init_phy_ops_out:
438 : 0 : return err;
439 : : }
440 : :
|