aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/intel/igc/igc_phy.c
diff options
context:
space:
mode:
authorSasha Neftin <sasha.neftin@intel.com>2018-10-11 03:17:31 -0400
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2018-10-17 16:55:18 -0400
commit5586838fe9ced0980e210b39d635ff3842297448 (patch)
tree1646f8cca19ced662aac1f065426d27344ec5fa9 /drivers/net/ethernet/intel/igc/igc_phy.c
parentab4056126813c889ee6c8fb24ca8f75b84c981ab (diff)
igc: Add code for PHY support
Add PHY's ID support Add support for initialization, acquire and release of PHY Enable register access Signed-off-by: Sasha Neftin <sasha.neftin@intel.com> Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com> Tested-by: Aaron Brown <aaron.f.brown@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/igc/igc_phy.c')
-rw-r--r--drivers/net/ethernet/intel/igc/igc_phy.c457
1 files changed, 457 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c
new file mode 100644
index 000000000000..88583c1d4970
--- /dev/null
+++ b/drivers/net/ethernet/intel/igc/igc_phy.c
@@ -0,0 +1,457 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2018 Intel Corporation */
3
4#include "igc_phy.h"
5
6/**
7 * igc_check_reset_block - Check if PHY reset is blocked
8 * @hw: pointer to the HW structure
9 *
10 * Read the PHY management control register and check whether a PHY reset
11 * is blocked. If a reset is not blocked return 0, otherwise
12 * return IGC_ERR_BLK_PHY_RESET (12).
13 */
14s32 igc_check_reset_block(struct igc_hw *hw)
15{
16 u32 manc;
17
18 manc = rd32(IGC_MANC);
19
20 return (manc & IGC_MANC_BLK_PHY_RST_ON_IDE) ?
21 IGC_ERR_BLK_PHY_RESET : 0;
22}
23
24/**
25 * igc_get_phy_id - Retrieve the PHY ID and revision
26 * @hw: pointer to the HW structure
27 *
28 * Reads the PHY registers and stores the PHY ID and possibly the PHY
29 * revision in the hardware structure.
30 */
31s32 igc_get_phy_id(struct igc_hw *hw)
32{
33 struct igc_phy_info *phy = &hw->phy;
34 s32 ret_val = 0;
35 u16 phy_id;
36
37 ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
38 if (ret_val)
39 goto out;
40
41 phy->id = (u32)(phy_id << 16);
42 usleep_range(200, 500);
43 ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
44 if (ret_val)
45 goto out;
46
47 phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
48 phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
49
50out:
51 return ret_val;
52}
53
54/**
55 * igc_phy_has_link - Polls PHY for link
56 * @hw: pointer to the HW structure
57 * @iterations: number of times to poll for link
58 * @usec_interval: delay between polling attempts
59 * @success: pointer to whether polling was successful or not
60 *
61 * Polls the PHY status register for link, 'iterations' number of times.
62 */
63s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations,
64 u32 usec_interval, bool *success)
65{
66 u16 i, phy_status;
67 s32 ret_val = 0;
68
69 for (i = 0; i < iterations; i++) {
70 /* Some PHYs require the PHY_STATUS register to be read
71 * twice due to the link bit being sticky. No harm doing
72 * it across the board.
73 */
74 ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
75 if (ret_val && usec_interval > 0) {
76 /* If the first read fails, another entity may have
77 * ownership of the resources, wait and try again to
78 * see if they have relinquished the resources yet.
79 */
80 if (usec_interval >= 1000)
81 mdelay(usec_interval / 1000);
82 else
83 udelay(usec_interval);
84 }
85 ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
86 if (ret_val)
87 break;
88 if (phy_status & MII_SR_LINK_STATUS)
89 break;
90 if (usec_interval >= 1000)
91 mdelay(usec_interval / 1000);
92 else
93 udelay(usec_interval);
94 }
95
96 *success = (i < iterations) ? true : false;
97
98 return ret_val;
99}
100
101/**
102 * igc_power_up_phy_copper - Restore copper link in case of PHY power down
103 * @hw: pointer to the HW structure
104 *
105 * In the case of a PHY power down to save power, or to turn off link during a
106 * driver unload, restore the link to previous settings.
107 */
108void igc_power_up_phy_copper(struct igc_hw *hw)
109{
110 u16 mii_reg = 0;
111
112 /* The PHY will retain its settings across a power down/up cycle */
113 hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
114 mii_reg &= ~MII_CR_POWER_DOWN;
115 hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
116}
117
118/**
119 * igc_power_down_phy_copper - Power down copper PHY
120 * @hw: pointer to the HW structure
121 *
122 * Power down PHY to save power when interface is down and wake on lan
123 * is not enabled.
124 */
125void igc_power_down_phy_copper(struct igc_hw *hw)
126{
127 u16 mii_reg = 0;
128
129 /* The PHY will retain its settings across a power down/up cycle */
130 hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
131 mii_reg |= MII_CR_POWER_DOWN;
132
133 /* Temporary workaround - should be removed when PHY will implement
134 * IEEE registers as properly
135 */
136 /* hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);*/
137 usleep_range(1000, 2000);
138}
139
140/**
141 * igc_check_downshift - Checks whether a downshift in speed occurred
142 * @hw: pointer to the HW structure
143 *
144 * Success returns 0, Failure returns 1
145 *
146 * A downshift is detected by querying the PHY link health.
147 */
148s32 igc_check_downshift(struct igc_hw *hw)
149{
150 struct igc_phy_info *phy = &hw->phy;
151 u16 phy_data, offset, mask;
152 s32 ret_val;
153
154 switch (phy->type) {
155 case igc_phy_i225:
156 default:
157 /* speed downshift not supported */
158 phy->speed_downgraded = false;
159 ret_val = 0;
160 goto out;
161 }
162
163 ret_val = phy->ops.read_reg(hw, offset, &phy_data);
164
165 if (!ret_val)
166 phy->speed_downgraded = (phy_data & mask) ? true : false;
167
168out:
169 return ret_val;
170}
171
172/**
173 * igc_phy_hw_reset - PHY hardware reset
174 * @hw: pointer to the HW structure
175 *
176 * Verify the reset block is not blocking us from resetting. Acquire
177 * semaphore (if necessary) and read/set/write the device control reset
178 * bit in the PHY. Wait the appropriate delay time for the device to
179 * reset and release the semaphore (if necessary).
180 */
181s32 igc_phy_hw_reset(struct igc_hw *hw)
182{
183 struct igc_phy_info *phy = &hw->phy;
184 s32 ret_val;
185 u32 ctrl;
186
187 ret_val = igc_check_reset_block(hw);
188 if (ret_val) {
189 ret_val = 0;
190 goto out;
191 }
192
193 ret_val = phy->ops.acquire(hw);
194 if (ret_val)
195 goto out;
196
197 ctrl = rd32(IGC_CTRL);
198 wr32(IGC_CTRL, ctrl | IGC_CTRL_PHY_RST);
199 wrfl();
200
201 udelay(phy->reset_delay_us);
202
203 wr32(IGC_CTRL, ctrl);
204 wrfl();
205
206 usleep_range(1500, 2000);
207
208 phy->ops.release(hw);
209
210out:
211 return ret_val;
212}
213
214/**
215 * igc_read_phy_reg_mdic - Read MDI control register
216 * @hw: pointer to the HW structure
217 * @offset: register offset to be read
218 * @data: pointer to the read data
219 *
220 * Reads the MDI control register in the PHY at offset and stores the
221 * information read to data.
222 */
223static s32 igc_read_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 *data)
224{
225 struct igc_phy_info *phy = &hw->phy;
226 u32 i, mdic = 0;
227 s32 ret_val = 0;
228
229 if (offset > MAX_PHY_REG_ADDRESS) {
230 hw_dbg("PHY Address %d is out of range\n", offset);
231 ret_val = -IGC_ERR_PARAM;
232 goto out;
233 }
234
235 /* Set up Op-code, Phy Address, and register offset in the MDI
236 * Control register. The MAC will take care of interfacing with the
237 * PHY to retrieve the desired data.
238 */
239 mdic = ((offset << IGC_MDIC_REG_SHIFT) |
240 (phy->addr << IGC_MDIC_PHY_SHIFT) |
241 (IGC_MDIC_OP_READ));
242
243 wr32(IGC_MDIC, mdic);
244
245 /* Poll the ready bit to see if the MDI read completed
246 * Increasing the time out as testing showed failures with
247 * the lower time out
248 */
249 for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) {
250 usleep_range(500, 1000);
251 mdic = rd32(IGC_MDIC);
252 if (mdic & IGC_MDIC_READY)
253 break;
254 }
255 if (!(mdic & IGC_MDIC_READY)) {
256 hw_dbg("MDI Read did not complete\n");
257 ret_val = -IGC_ERR_PHY;
258 goto out;
259 }
260 if (mdic & IGC_MDIC_ERROR) {
261 hw_dbg("MDI Error\n");
262 ret_val = -IGC_ERR_PHY;
263 goto out;
264 }
265 *data = (u16)mdic;
266
267out:
268 return ret_val;
269}
270
271/**
272 * igc_write_phy_reg_mdic - Write MDI control register
273 * @hw: pointer to the HW structure
274 * @offset: register offset to write to
275 * @data: data to write to register at offset
276 *
277 * Writes data to MDI control register in the PHY at offset.
278 */
279static s32 igc_write_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 data)
280{
281 struct igc_phy_info *phy = &hw->phy;
282 u32 i, mdic = 0;
283 s32 ret_val = 0;
284
285 if (offset > MAX_PHY_REG_ADDRESS) {
286 hw_dbg("PHY Address %d is out of range\n", offset);
287 ret_val = -IGC_ERR_PARAM;
288 goto out;
289 }
290
291 /* Set up Op-code, Phy Address, and register offset in the MDI
292 * Control register. The MAC will take care of interfacing with the
293 * PHY to write the desired data.
294 */
295 mdic = (((u32)data) |
296 (offset << IGC_MDIC_REG_SHIFT) |
297 (phy->addr << IGC_MDIC_PHY_SHIFT) |
298 (IGC_MDIC_OP_WRITE));
299
300 wr32(IGC_MDIC, mdic);
301
302 /* Poll the ready bit to see if the MDI read completed
303 * Increasing the time out as testing showed failures with
304 * the lower time out
305 */
306 for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) {
307 usleep_range(500, 1000);
308 mdic = rd32(IGC_MDIC);
309 if (mdic & IGC_MDIC_READY)
310 break;
311 }
312 if (!(mdic & IGC_MDIC_READY)) {
313 hw_dbg("MDI Write did not complete\n");
314 ret_val = -IGC_ERR_PHY;
315 goto out;
316 }
317 if (mdic & IGC_MDIC_ERROR) {
318 hw_dbg("MDI Error\n");
319 ret_val = -IGC_ERR_PHY;
320 goto out;
321 }
322
323out:
324 return ret_val;
325}
326
327/**
328 * __igc_access_xmdio_reg - Read/write XMDIO register
329 * @hw: pointer to the HW structure
330 * @address: XMDIO address to program
331 * @dev_addr: device address to program
332 * @data: pointer to value to read/write from/to the XMDIO address
333 * @read: boolean flag to indicate read or write
334 */
335static s32 __igc_access_xmdio_reg(struct igc_hw *hw, u16 address,
336 u8 dev_addr, u16 *data, bool read)
337{
338 s32 ret_val;
339
340 ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, dev_addr);
341 if (ret_val)
342 return ret_val;
343
344 ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, address);
345 if (ret_val)
346 return ret_val;
347
348 ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, IGC_MMDAC_FUNC_DATA |
349 dev_addr);
350 if (ret_val)
351 return ret_val;
352
353 if (read)
354 ret_val = hw->phy.ops.read_reg(hw, IGC_MMDAAD, data);
355 else
356 ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, *data);
357 if (ret_val)
358 return ret_val;
359
360 /* Recalibrate the device back to 0 */
361 ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, 0);
362 if (ret_val)
363 return ret_val;
364
365 return ret_val;
366}
367
368/**
369 * igc_read_xmdio_reg - Read XMDIO register
370 * @hw: pointer to the HW structure
371 * @addr: XMDIO address to program
372 * @dev_addr: device address to program
373 * @data: value to be read from the EMI address
374 */
375static s32 igc_read_xmdio_reg(struct igc_hw *hw, u16 addr,
376 u8 dev_addr, u16 *data)
377{
378 return __igc_access_xmdio_reg(hw, addr, dev_addr, data, true);
379}
380
381/**
382 * igc_write_xmdio_reg - Write XMDIO register
383 * @hw: pointer to the HW structure
384 * @addr: XMDIO address to program
385 * @dev_addr: device address to program
386 * @data: value to be written to the XMDIO address
387 */
388static s32 igc_write_xmdio_reg(struct igc_hw *hw, u16 addr,
389 u8 dev_addr, u16 data)
390{
391 return __igc_access_xmdio_reg(hw, addr, dev_addr, &data, false);
392}
393
394/**
395 * igc_write_phy_reg_gpy - Write GPY PHY register
396 * @hw: pointer to the HW structure
397 * @offset: register offset to write to
398 * @data: data to write at register offset
399 *
400 * Acquires semaphore, if necessary, then writes the data to PHY register
401 * at the offset. Release any acquired semaphores before exiting.
402 */
403s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data)
404{
405 u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;
406 s32 ret_val;
407
408 offset = offset & GPY_REG_MASK;
409
410 if (!dev_addr) {
411 ret_val = hw->phy.ops.acquire(hw);
412 if (ret_val)
413 return ret_val;
414 ret_val = igc_write_phy_reg_mdic(hw, offset, data);
415 if (ret_val)
416 return ret_val;
417 hw->phy.ops.release(hw);
418 } else {
419 ret_val = igc_write_xmdio_reg(hw, (u16)offset, dev_addr,
420 data);
421 }
422
423 return ret_val;
424}
425
426/**
427 * igc_read_phy_reg_gpy - Read GPY PHY register
428 * @hw: pointer to the HW structure
429 * @offset: lower half is register offset to read to
430 * upper half is MMD to use.
431 * @data: data to read at register offset
432 *
433 * Acquires semaphore, if necessary, then reads the data in the PHY register
434 * at the offset. Release any acquired semaphores before exiting.
435 */
436s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data)
437{
438 u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;
439 s32 ret_val;
440
441 offset = offset & GPY_REG_MASK;
442
443 if (!dev_addr) {
444 ret_val = hw->phy.ops.acquire(hw);
445 if (ret_val)
446 return ret_val;
447 ret_val = igc_read_phy_reg_mdic(hw, offset, data);
448 if (ret_val)
449 return ret_val;
450 hw->phy.ops.release(hw);
451 } else {
452 ret_val = igc_read_xmdio_reg(hw, (u16)offset, dev_addr,
453 data);
454 }
455
456 return ret_val;
457}