net/ngbe: fix external PHY power down
[dpdk.git] / drivers / net / ngbe / base / ngbe_phy.c
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",
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         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  **/
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  **/
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  **/
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  **/
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  **/
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         /* Don't reset PHY if it's shut down due to overtemp. */
214         if (hw->mac.check_overtemp(hw) == NGBE_ERR_OVERTEMP)
215                 return err;
216
217         /* Blocked by MNG FW so bail */
218         if (ngbe_check_reset_blocked(hw))
219                 return err;
220
221         switch (hw->phy.type) {
222         case ngbe_phy_rtl:
223                 err = ngbe_reset_phy_rtl(hw);
224                 break;
225         case ngbe_phy_mvl:
226         case ngbe_phy_mvl_sfi:
227                 err = ngbe_reset_phy_mvl(hw);
228                 break;
229         case ngbe_phy_yt8521s:
230         case ngbe_phy_yt8521s_sfi:
231                 err = ngbe_reset_phy_yt(hw);
232                 break;
233         default:
234                 break;
235         }
236
237         return err;
238 }
239
240 /**
241  *  ngbe_read_phy_mdi - Reads a value from a specified PHY register without
242  *  the SWFW lock
243  *  @hw: pointer to hardware structure
244  *  @reg_addr: 32 bit address of PHY register to read
245  *  @device_type: 5 bit device type
246  *  @phy_data: Pointer to read data from PHY register
247  **/
248 s32 ngbe_read_phy_reg_mdi(struct ngbe_hw *hw, u32 reg_addr, u32 device_type,
249                            u16 *phy_data)
250 {
251         u32 command, data;
252
253         /* Setup and write the address cycle command */
254         command = NGBE_MDIOSCA_REG(reg_addr) |
255                   NGBE_MDIOSCA_DEV(device_type) |
256                   NGBE_MDIOSCA_PORT(hw->phy.addr);
257         wr32(hw, NGBE_MDIOSCA, command);
258
259         command = NGBE_MDIOSCD_CMD_READ |
260                   NGBE_MDIOSCD_BUSY |
261                   NGBE_MDIOSCD_CLOCK(6);
262         wr32(hw, NGBE_MDIOSCD, command);
263
264         /*
265          * Check every 10 usec to see if the address cycle completed.
266          * The MDI Command bit will clear when the operation is
267          * complete
268          */
269         if (!po32m(hw, NGBE_MDIOSCD, NGBE_MDIOSCD_BUSY,
270                 0, NULL, 100, 100)) {
271                 DEBUGOUT("PHY address command did not complete");
272                 return NGBE_ERR_PHY;
273         }
274
275         data = rd32(hw, NGBE_MDIOSCD);
276         *phy_data = (u16)NGBE_MDIOSCD_DAT_R(data);
277
278         return 0;
279 }
280
281 /**
282  *  ngbe_read_phy_reg - Reads a value from a specified PHY register
283  *  using the SWFW lock - this function is needed in most cases
284  *  @hw: pointer to hardware structure
285  *  @reg_addr: 32 bit address of PHY register to read
286  *  @device_type: 5 bit device type
287  *  @phy_data: Pointer to read data from PHY register
288  **/
289 s32 ngbe_read_phy_reg(struct ngbe_hw *hw, u32 reg_addr,
290                                u32 device_type, u16 *phy_data)
291 {
292         s32 err;
293         u32 gssr = hw->phy.phy_semaphore_mask;
294
295         if (hw->mac.acquire_swfw_sync(hw, gssr))
296                 return NGBE_ERR_SWFW_SYNC;
297
298         err = hw->phy.read_reg_unlocked(hw, reg_addr, device_type,
299                                         phy_data);
300
301         hw->mac.release_swfw_sync(hw, gssr);
302
303         return err;
304 }
305
306 /**
307  *  ngbe_write_phy_reg_mdi - Writes a value to specified PHY register
308  *  without SWFW lock
309  *  @hw: pointer to hardware structure
310  *  @reg_addr: 32 bit PHY register to write
311  *  @device_type: 5 bit device type
312  *  @phy_data: Data to write to the PHY register
313  **/
314 s32 ngbe_write_phy_reg_mdi(struct ngbe_hw *hw, u32 reg_addr,
315                                 u32 device_type, u16 phy_data)
316 {
317         u32 command;
318
319         /* write command */
320         command = NGBE_MDIOSCA_REG(reg_addr) |
321                   NGBE_MDIOSCA_DEV(device_type) |
322                   NGBE_MDIOSCA_PORT(hw->phy.addr);
323         wr32(hw, NGBE_MDIOSCA, command);
324
325         command = NGBE_MDIOSCD_CMD_WRITE |
326                   NGBE_MDIOSCD_DAT(phy_data) |
327                   NGBE_MDIOSCD_BUSY |
328                   NGBE_MDIOSCD_CLOCK(6);
329         wr32(hw, NGBE_MDIOSCD, command);
330
331         /* wait for completion */
332         if (!po32m(hw, NGBE_MDIOSCD, NGBE_MDIOSCD_BUSY,
333                 0, NULL, 100, 100)) {
334                 DEBUGOUT("PHY write cmd didn't complete");
335                 return NGBE_ERR_PHY;
336         }
337
338         return 0;
339 }
340
341 /**
342  *  ngbe_write_phy_reg - Writes a value to specified PHY register
343  *  using SWFW lock- this function is needed in most cases
344  *  @hw: pointer to hardware structure
345  *  @reg_addr: 32 bit PHY register to write
346  *  @device_type: 5 bit device type
347  *  @phy_data: Data to write to the PHY register
348  **/
349 s32 ngbe_write_phy_reg(struct ngbe_hw *hw, u32 reg_addr,
350                                 u32 device_type, u16 phy_data)
351 {
352         s32 err;
353         u32 gssr = hw->phy.phy_semaphore_mask;
354
355         if (hw->mac.acquire_swfw_sync(hw, gssr))
356                 err = NGBE_ERR_SWFW_SYNC;
357
358         err = hw->phy.write_reg_unlocked(hw, reg_addr, device_type,
359                                          phy_data);
360
361         hw->mac.release_swfw_sync(hw, gssr);
362
363         return err;
364 }
365
366 /**
367  *  ngbe_init_phy - PHY specific init
368  *  @hw: pointer to hardware structure
369  *
370  *  Initialize any function pointers that were not able to be
371  *  set during init_shared_code because the PHY type was
372  *  not known.
373  *
374  **/
375 s32 ngbe_init_phy(struct ngbe_hw *hw)
376 {
377         struct ngbe_phy_info *phy = &hw->phy;
378         s32 err = 0;
379
380         hw->phy.addr = 0;
381
382         switch (hw->sub_device_id) {
383         case NGBE_SUB_DEV_ID_EM_RTL_SGMII:
384         case NGBE_SUB_DEV_ID_EM_RTL_YT8521S_SFP:
385                 hw->phy.read_reg_unlocked = ngbe_read_phy_reg_rtl;
386                 hw->phy.write_reg_unlocked = ngbe_write_phy_reg_rtl;
387                 break;
388         case NGBE_SUB_DEV_ID_EM_MVL_RGMII:
389         case NGBE_SUB_DEV_ID_EM_MVL_SFP:
390         case NGBE_SUB_DEV_ID_EM_MVL_MIX:
391                 hw->phy.read_reg_unlocked = ngbe_read_phy_reg_mvl;
392                 hw->phy.write_reg_unlocked = ngbe_write_phy_reg_mvl;
393                 break;
394         case NGBE_SUB_DEV_ID_EM_YT8521S_SFP:
395                 hw->phy.read_reg_unlocked = ngbe_read_phy_reg_yt;
396                 hw->phy.write_reg_unlocked = ngbe_write_phy_reg_yt;
397                 break;
398         default:
399                 break;
400         }
401
402         hw->phy.phy_semaphore_mask = NGBE_MNGSEM_SWPHY;
403
404         /* Identify the PHY */
405         err = phy->identify(hw);
406         if (err == NGBE_ERR_PHY_ADDR_INVALID)
407                 goto init_phy_ops_out;
408
409         /* Set necessary function pointers based on PHY type */
410         switch (hw->phy.type) {
411         case ngbe_phy_rtl:
412                 hw->phy.init_hw = ngbe_init_phy_rtl;
413                 hw->phy.check_link = ngbe_check_phy_link_rtl;
414                 hw->phy.setup_link = ngbe_setup_phy_link_rtl;
415                 hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_rtl;
416                 hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_rtl;
417                 hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_rtl;
418                 break;
419         case ngbe_phy_mvl:
420         case ngbe_phy_mvl_sfi:
421                 hw->phy.init_hw = ngbe_init_phy_mvl;
422                 hw->phy.check_link = ngbe_check_phy_link_mvl;
423                 hw->phy.setup_link = ngbe_setup_phy_link_mvl;
424                 hw->phy.set_phy_power = ngbe_set_phy_power_mvl;
425                 hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_mvl;
426                 hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_mvl;
427                 hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_mvl;
428                 break;
429         case ngbe_phy_yt8521s:
430         case ngbe_phy_yt8521s_sfi:
431                 hw->phy.init_hw = ngbe_init_phy_yt;
432                 hw->phy.check_link = ngbe_check_phy_link_yt;
433                 hw->phy.setup_link = ngbe_setup_phy_link_yt;
434                 hw->phy.set_phy_power = ngbe_set_phy_power_yt;
435                 hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_yt;
436                 hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_yt;
437                 hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_yt;
438         default:
439                 break;
440         }
441
442 init_phy_ops_out:
443         return err;
444 }
445