igc_phy.c revision 1.2.2.2 1 1.2.2.2 martin /* $NetBSD: igc_phy.c,v 1.2.2.2 2023/10/08 13:19:34 martin Exp $ */
2 1.2.2.2 martin /* $OpenBSD: igc_phy.c,v 1.3 2023/02/03 11:31:52 mbuhl Exp $ */
3 1.2.2.2 martin /*-
4 1.2.2.2 martin * Copyright 2021 Intel Corp
5 1.2.2.2 martin * Copyright 2021 Rubicon Communications, LLC (Netgate)
6 1.2.2.2 martin * SPDX-License-Identifier: BSD-3-Clause
7 1.2.2.2 martin */
8 1.2.2.2 martin
9 1.2.2.2 martin #include <sys/cdefs.h>
10 1.2.2.2 martin __KERNEL_RCSID(0, "$NetBSD: igc_phy.c,v 1.2.2.2 2023/10/08 13:19:34 martin Exp $");
11 1.2.2.2 martin
12 1.2.2.2 martin #include <dev/pci/igc/igc_api.h>
13 1.2.2.2 martin #include <dev/mii/mii.h>
14 1.2.2.2 martin
15 1.2.2.2 martin /**
16 1.2.2.2 martin * igc_init_phy_ops_generic - Initialize PHY function pointers
17 1.2.2.2 martin * @hw: pointer to the HW structure
18 1.2.2.2 martin *
19 1.2.2.2 martin * Setups up the function pointers to no-op functions
20 1.2.2.2 martin **/
21 1.2.2.2 martin void
22 1.2.2.2 martin igc_init_phy_ops_generic(struct igc_hw *hw)
23 1.2.2.2 martin {
24 1.2.2.2 martin struct igc_phy_info *phy = &hw->phy;
25 1.2.2.2 martin DEBUGFUNC("igc_init_phy_ops_generic");
26 1.2.2.2 martin
27 1.2.2.2 martin /* Initialize function pointers */
28 1.2.2.2 martin phy->ops.init_params = igc_null_ops_generic;
29 1.2.2.2 martin phy->ops.acquire = igc_null_ops_generic;
30 1.2.2.2 martin phy->ops.check_reset_block = igc_null_ops_generic;
31 1.2.2.2 martin phy->ops.force_speed_duplex = igc_null_ops_generic;
32 1.2.2.2 martin phy->ops.get_info = igc_null_ops_generic;
33 1.2.2.2 martin phy->ops.set_page = igc_null_set_page;
34 1.2.2.2 martin phy->ops.read_reg = igc_null_read_reg;
35 1.2.2.2 martin phy->ops.read_reg_locked = igc_null_read_reg;
36 1.2.2.2 martin phy->ops.read_reg_page = igc_null_read_reg;
37 1.2.2.2 martin phy->ops.release = igc_null_phy_generic;
38 1.2.2.2 martin phy->ops.reset = igc_null_ops_generic;
39 1.2.2.2 martin phy->ops.set_d0_lplu_state = igc_null_lplu_state;
40 1.2.2.2 martin phy->ops.set_d3_lplu_state = igc_null_lplu_state;
41 1.2.2.2 martin phy->ops.write_reg = igc_null_write_reg;
42 1.2.2.2 martin phy->ops.write_reg_locked = igc_null_write_reg;
43 1.2.2.2 martin phy->ops.write_reg_page = igc_null_write_reg;
44 1.2.2.2 martin phy->ops.power_up = igc_null_phy_generic;
45 1.2.2.2 martin phy->ops.power_down = igc_null_phy_generic;
46 1.2.2.2 martin }
47 1.2.2.2 martin
48 1.2.2.2 martin /**
49 1.2.2.2 martin * igc_null_set_page - No-op function, return 0
50 1.2.2.2 martin * @hw: pointer to the HW structure
51 1.2.2.2 martin * @data: dummy variable
52 1.2.2.2 martin **/
53 1.2.2.2 martin int
54 1.2.2.2 martin igc_null_set_page(struct igc_hw IGC_UNUSEDARG *hw, uint16_t IGC_UNUSEDARG data)
55 1.2.2.2 martin {
56 1.2.2.2 martin DEBUGFUNC("igc_null_set_page");
57 1.2.2.2 martin return IGC_SUCCESS;
58 1.2.2.2 martin }
59 1.2.2.2 martin
60 1.2.2.2 martin /**
61 1.2.2.2 martin * igc_null_read_reg - No-op function, return 0
62 1.2.2.2 martin * @hw: pointer to the HW structure
63 1.2.2.2 martin * @offset: dummy variable
64 1.2.2.2 martin * @data: dummy variable
65 1.2.2.2 martin **/
66 1.2.2.2 martin int
67 1.2.2.2 martin igc_null_read_reg(struct igc_hw IGC_UNUSEDARG *hw,
68 1.2.2.2 martin uint32_t IGC_UNUSEDARG offset, uint16_t IGC_UNUSEDARG *data)
69 1.2.2.2 martin {
70 1.2.2.2 martin DEBUGFUNC("igc_null_read_reg");
71 1.2.2.2 martin return IGC_SUCCESS;
72 1.2.2.2 martin }
73 1.2.2.2 martin
74 1.2.2.2 martin /**
75 1.2.2.2 martin * igc_null_phy_generic - No-op function, return void
76 1.2.2.2 martin * @hw: pointer to the HW structure
77 1.2.2.2 martin **/
78 1.2.2.2 martin void
79 1.2.2.2 martin igc_null_phy_generic(struct igc_hw IGC_UNUSEDARG *hw)
80 1.2.2.2 martin {
81 1.2.2.2 martin DEBUGFUNC("igc_null_phy_generic");
82 1.2.2.2 martin return;
83 1.2.2.2 martin }
84 1.2.2.2 martin
85 1.2.2.2 martin /**
86 1.2.2.2 martin * igc_null_lplu_state - No-op function, return 0
87 1.2.2.2 martin * @hw: pointer to the HW structure
88 1.2.2.2 martin * @active: dummy variable
89 1.2.2.2 martin **/
90 1.2.2.2 martin int
91 1.2.2.2 martin igc_null_lplu_state(struct igc_hw IGC_UNUSEDARG *hw, bool IGC_UNUSEDARG active)
92 1.2.2.2 martin {
93 1.2.2.2 martin DEBUGFUNC("igc_null_lplu_state");
94 1.2.2.2 martin return IGC_SUCCESS;
95 1.2.2.2 martin }
96 1.2.2.2 martin
97 1.2.2.2 martin /**
98 1.2.2.2 martin * igc_null_write_reg - No-op function, return 0
99 1.2.2.2 martin * @hw: pointer to the HW structure
100 1.2.2.2 martin * @offset: dummy variable
101 1.2.2.2 martin * @data: dummy variable
102 1.2.2.2 martin **/
103 1.2.2.2 martin int
104 1.2.2.2 martin igc_null_write_reg(struct igc_hw IGC_UNUSEDARG *hw,
105 1.2.2.2 martin uint32_t IGC_UNUSEDARG offset, uint16_t IGC_UNUSEDARG data)
106 1.2.2.2 martin {
107 1.2.2.2 martin DEBUGFUNC("igc_null_write_reg");
108 1.2.2.2 martin return IGC_SUCCESS;
109 1.2.2.2 martin }
110 1.2.2.2 martin
111 1.2.2.2 martin /**
112 1.2.2.2 martin * igc_check_reset_block_generic - Check if PHY reset is blocked
113 1.2.2.2 martin * @hw: pointer to the HW structure
114 1.2.2.2 martin *
115 1.2.2.2 martin * Read the PHY management control register and check whether a PHY reset
116 1.2.2.2 martin * is blocked. If a reset is not blocked return IGC_SUCCESS, otherwise
117 1.2.2.2 martin * return IGC_BLK_PHY_RESET (12).
118 1.2.2.2 martin **/
119 1.2.2.2 martin int
120 1.2.2.2 martin igc_check_reset_block_generic(struct igc_hw *hw)
121 1.2.2.2 martin {
122 1.2.2.2 martin uint32_t manc;
123 1.2.2.2 martin
124 1.2.2.2 martin DEBUGFUNC("igc_check_reset_block");
125 1.2.2.2 martin
126 1.2.2.2 martin manc = IGC_READ_REG(hw, IGC_MANC);
127 1.2.2.2 martin
128 1.2.2.2 martin return (manc & IGC_MANC_BLK_PHY_RST_ON_IDE) ?
129 1.2.2.2 martin IGC_BLK_PHY_RESET : IGC_SUCCESS;
130 1.2.2.2 martin }
131 1.2.2.2 martin
132 1.2.2.2 martin /**
133 1.2.2.2 martin * igc_get_phy_id - Retrieve the PHY ID and revision
134 1.2.2.2 martin * @hw: pointer to the HW structure
135 1.2.2.2 martin *
136 1.2.2.2 martin * Reads the PHY registers and stores the PHY ID and possibly the PHY
137 1.2.2.2 martin * revision in the hardware structure.
138 1.2.2.2 martin **/
139 1.2.2.2 martin int
140 1.2.2.2 martin igc_get_phy_id(struct igc_hw *hw)
141 1.2.2.2 martin {
142 1.2.2.2 martin struct igc_phy_info *phy = &hw->phy;
143 1.2.2.2 martin uint16_t phy_id;
144 1.2.2.2 martin int ret_val = IGC_SUCCESS;
145 1.2.2.2 martin
146 1.2.2.2 martin DEBUGFUNC("igc_get_phy_id");
147 1.2.2.2 martin
148 1.2.2.2 martin if (!phy->ops.read_reg)
149 1.2.2.2 martin return IGC_SUCCESS;
150 1.2.2.2 martin
151 1.2.2.2 martin ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
152 1.2.2.2 martin if (ret_val)
153 1.2.2.2 martin return ret_val;
154 1.2.2.2 martin
155 1.2.2.2 martin phy->id = (uint32_t)(phy_id << 16);
156 1.2.2.2 martin DELAY(200);
157 1.2.2.2 martin ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
158 1.2.2.2 martin if (ret_val)
159 1.2.2.2 martin return ret_val;
160 1.2.2.2 martin
161 1.2.2.2 martin phy->id |= (uint32_t)(phy_id & PHY_REVISION_MASK);
162 1.2.2.2 martin phy->revision = (uint32_t)(phy_id & ~PHY_REVISION_MASK);
163 1.2.2.2 martin
164 1.2.2.2 martin return IGC_SUCCESS;
165 1.2.2.2 martin }
166 1.2.2.2 martin
167 1.2.2.2 martin /**
168 1.2.2.2 martin * igc_read_phy_reg_mdic - Read MDI control register
169 1.2.2.2 martin * @hw: pointer to the HW structure
170 1.2.2.2 martin * @offset: register offset to be read
171 1.2.2.2 martin * @data: pointer to the read data
172 1.2.2.2 martin *
173 1.2.2.2 martin * Reads the MDI control register in the PHY at offset and stores the
174 1.2.2.2 martin * information read to data.
175 1.2.2.2 martin **/
176 1.2.2.2 martin int
177 1.2.2.2 martin igc_read_phy_reg_mdic(struct igc_hw *hw, uint32_t offset, uint16_t *data)
178 1.2.2.2 martin {
179 1.2.2.2 martin struct igc_phy_info *phy = &hw->phy;
180 1.2.2.2 martin uint32_t i, mdic = 0;
181 1.2.2.2 martin
182 1.2.2.2 martin DEBUGFUNC("igc_read_phy_reg_mdic");
183 1.2.2.2 martin
184 1.2.2.2 martin if (offset > MAX_PHY_REG_ADDRESS) {
185 1.2.2.2 martin DEBUGOUT1("PHY Address %d is out of range\n", offset);
186 1.2.2.2 martin return -IGC_ERR_PARAM;
187 1.2.2.2 martin }
188 1.2.2.2 martin
189 1.2.2.2 martin /* Set up Op-code, Phy Address, and register offset in the MDI
190 1.2.2.2 martin * Control register. The MAC will take care of interfacing with the
191 1.2.2.2 martin * PHY to retrieve the desired data.
192 1.2.2.2 martin */
193 1.2.2.2 martin mdic = ((offset << IGC_MDIC_REG_SHIFT) |
194 1.2.2.2 martin (phy->addr << IGC_MDIC_PHY_SHIFT) | (IGC_MDIC_OP_READ));
195 1.2.2.2 martin
196 1.2.2.2 martin IGC_WRITE_REG(hw, IGC_MDIC, mdic);
197 1.2.2.2 martin
198 1.2.2.2 martin /* Poll the ready bit to see if the MDI read completed
199 1.2.2.2 martin * Increasing the time out as testing showed failures with
200 1.2.2.2 martin * the lower time out
201 1.2.2.2 martin */
202 1.2.2.2 martin for (i = 0; i < (IGC_GEN_POLL_TIMEOUT * 3); i++) {
203 1.2.2.2 martin DELAY(50);
204 1.2.2.2 martin mdic = IGC_READ_REG(hw, IGC_MDIC);
205 1.2.2.2 martin if (mdic & IGC_MDIC_READY)
206 1.2.2.2 martin break;
207 1.2.2.2 martin }
208 1.2.2.2 martin if (!(mdic & IGC_MDIC_READY)) {
209 1.2.2.2 martin DEBUGOUT("MDI Read did not complete\n");
210 1.2.2.2 martin return -IGC_ERR_PHY;
211 1.2.2.2 martin }
212 1.2.2.2 martin if (mdic & IGC_MDIC_ERROR) {
213 1.2.2.2 martin DEBUGOUT("MDI Error\n");
214 1.2.2.2 martin return -IGC_ERR_PHY;
215 1.2.2.2 martin }
216 1.2.2.2 martin if (((mdic & IGC_MDIC_REG_MASK) >> IGC_MDIC_REG_SHIFT) != offset) {
217 1.2.2.2 martin DEBUGOUT2("MDI Read offset error - requested %d, returned %d\n",
218 1.2.2.2 martin offset, (mdic & IGC_MDIC_REG_MASK) >> IGC_MDIC_REG_SHIFT);
219 1.2.2.2 martin return -IGC_ERR_PHY;
220 1.2.2.2 martin }
221 1.2.2.2 martin *data = (uint16_t)mdic;
222 1.2.2.2 martin
223 1.2.2.2 martin return IGC_SUCCESS;
224 1.2.2.2 martin }
225 1.2.2.2 martin
226 1.2.2.2 martin /**
227 1.2.2.2 martin * igc_write_phy_reg_mdic - Write MDI control register
228 1.2.2.2 martin * @hw: pointer to the HW structure
229 1.2.2.2 martin * @offset: register offset to write to
230 1.2.2.2 martin * @data: data to write to register at offset
231 1.2.2.2 martin *
232 1.2.2.2 martin * Writes data to MDI control register in the PHY at offset.
233 1.2.2.2 martin **/
234 1.2.2.2 martin int
235 1.2.2.2 martin igc_write_phy_reg_mdic(struct igc_hw *hw, uint32_t offset, uint16_t data)
236 1.2.2.2 martin {
237 1.2.2.2 martin struct igc_phy_info *phy = &hw->phy;
238 1.2.2.2 martin uint32_t i, mdic = 0;
239 1.2.2.2 martin
240 1.2.2.2 martin DEBUGFUNC("igc_write_phy_reg_mdic");
241 1.2.2.2 martin
242 1.2.2.2 martin if (offset > MAX_PHY_REG_ADDRESS) {
243 1.2.2.2 martin DEBUGOUT1("PHY Address %d is out of range\n", offset);
244 1.2.2.2 martin return -IGC_ERR_PARAM;
245 1.2.2.2 martin }
246 1.2.2.2 martin
247 1.2.2.2 martin /* Set up Op-code, Phy Address, and register offset in the MDI
248 1.2.2.2 martin * Control register. The MAC will take care of interfacing with the
249 1.2.2.2 martin * PHY to retrieve the desired data.
250 1.2.2.2 martin */
251 1.2.2.2 martin mdic = (((uint32_t)data) | (offset << IGC_MDIC_REG_SHIFT) |
252 1.2.2.2 martin (phy->addr << IGC_MDIC_PHY_SHIFT) | (IGC_MDIC_OP_WRITE));
253 1.2.2.2 martin
254 1.2.2.2 martin IGC_WRITE_REG(hw, IGC_MDIC, mdic);
255 1.2.2.2 martin
256 1.2.2.2 martin /* Poll the ready bit to see if the MDI read completed
257 1.2.2.2 martin * Increasing the time out as testing showed failures with
258 1.2.2.2 martin * the lower time out
259 1.2.2.2 martin */
260 1.2.2.2 martin for (i = 0; i < (IGC_GEN_POLL_TIMEOUT * 3); i++) {
261 1.2.2.2 martin DELAY(50);
262 1.2.2.2 martin mdic = IGC_READ_REG(hw, IGC_MDIC);
263 1.2.2.2 martin if (mdic & IGC_MDIC_READY)
264 1.2.2.2 martin break;
265 1.2.2.2 martin }
266 1.2.2.2 martin if (!(mdic & IGC_MDIC_READY)) {
267 1.2.2.2 martin DEBUGOUT("MDI Write did not complete\n");
268 1.2.2.2 martin return -IGC_ERR_PHY;
269 1.2.2.2 martin }
270 1.2.2.2 martin if (mdic & IGC_MDIC_ERROR) {
271 1.2.2.2 martin DEBUGOUT("MDI Error\n");
272 1.2.2.2 martin return -IGC_ERR_PHY;
273 1.2.2.2 martin }
274 1.2.2.2 martin if (((mdic & IGC_MDIC_REG_MASK) >> IGC_MDIC_REG_SHIFT) != offset)
275 1.2.2.2 martin return -IGC_ERR_PHY;
276 1.2.2.2 martin
277 1.2.2.2 martin return IGC_SUCCESS;
278 1.2.2.2 martin }
279 1.2.2.2 martin
280 1.2.2.2 martin /**
281 1.2.2.2 martin * igc_phy_setup_autoneg - Configure PHY for auto-negotiation
282 1.2.2.2 martin * @hw: pointer to the HW structure
283 1.2.2.2 martin *
284 1.2.2.2 martin * Reads the MII auto-neg advertisement register and/or the 1000T control
285 1.2.2.2 martin * register and if the PHY is already setup for auto-negotiation, then
286 1.2.2.2 martin * return successful. Otherwise, setup advertisement and flow control to
287 1.2.2.2 martin * the appropriate values for the wanted auto-negotiation.
288 1.2.2.2 martin **/
289 1.2.2.2 martin static int
290 1.2.2.2 martin igc_phy_setup_autoneg(struct igc_hw *hw)
291 1.2.2.2 martin {
292 1.2.2.2 martin struct igc_phy_info *phy = &hw->phy;
293 1.2.2.2 martin uint16_t mii_autoneg_adv_reg;
294 1.2.2.2 martin uint16_t mii_1000t_ctrl_reg = 0;
295 1.2.2.2 martin uint16_t aneg_multigbt_an_ctrl = 0;
296 1.2.2.2 martin int ret_val;
297 1.2.2.2 martin
298 1.2.2.2 martin DEBUGFUNC("igc_phy_setup_autoneg");
299 1.2.2.2 martin
300 1.2.2.2 martin phy->autoneg_advertised &= phy->autoneg_mask;
301 1.2.2.2 martin
302 1.2.2.2 martin /* Read the MII Auto-Neg Advertisement Register (Address 4). */
303 1.2.2.2 martin ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
304 1.2.2.2 martin if (ret_val)
305 1.2.2.2 martin return ret_val;
306 1.2.2.2 martin
307 1.2.2.2 martin if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
308 1.2.2.2 martin /* Read the MII 1000Base-T Control Register (Address 9). */
309 1.2.2.2 martin ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
310 1.2.2.2 martin &mii_1000t_ctrl_reg);
311 1.2.2.2 martin if (ret_val)
312 1.2.2.2 martin return ret_val;
313 1.2.2.2 martin }
314 1.2.2.2 martin
315 1.2.2.2 martin if (phy->autoneg_mask & ADVERTISE_2500_FULL) {
316 1.2.2.2 martin /* Read the MULTI GBT AN Control Register - reg 7.32 */
317 1.2.2.2 martin ret_val = phy->ops.read_reg(hw, (STANDARD_AN_REG_MASK <<
318 1.2.2.2 martin MMD_DEVADDR_SHIFT) | ANEG_MULTIGBT_AN_CTRL,
319 1.2.2.2 martin &aneg_multigbt_an_ctrl);
320 1.2.2.2 martin if (ret_val)
321 1.2.2.2 martin return ret_val;
322 1.2.2.2 martin }
323 1.2.2.2 martin
324 1.2.2.2 martin /* Need to parse both autoneg_advertised and fc and set up
325 1.2.2.2 martin * the appropriate PHY registers. First we will parse for
326 1.2.2.2 martin * autoneg_advertised software override. Since we can advertise
327 1.2.2.2 martin * a plethora of combinations, we need to check each bit
328 1.2.2.2 martin * individually.
329 1.2.2.2 martin */
330 1.2.2.2 martin
331 1.2.2.2 martin /* First we clear all the 10/100 mb speed bits in the Auto-Neg
332 1.2.2.2 martin * Advertisement Register (Address 4) and the 1000 mb speed bits in
333 1.2.2.2 martin * the 1000Base-T Control Register (Address 9).
334 1.2.2.2 martin */
335 1.2.2.2 martin mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS | NWAY_AR_100TX_HD_CAPS |
336 1.2.2.2 martin NWAY_AR_10T_FD_CAPS | NWAY_AR_10T_HD_CAPS);
337 1.2.2.2 martin mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
338 1.2.2.2 martin
339 1.2.2.2 martin DEBUGOUT1("autoneg_advertised %x\n", phy->autoneg_advertised);
340 1.2.2.2 martin
341 1.2.2.2 martin /* Do we want to advertise 10 Mb Half Duplex? */
342 1.2.2.2 martin if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
343 1.2.2.2 martin DEBUGOUT("Advertise 10mb Half duplex\n");
344 1.2.2.2 martin mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
345 1.2.2.2 martin }
346 1.2.2.2 martin
347 1.2.2.2 martin /* Do we want to advertise 10 Mb Full Duplex? */
348 1.2.2.2 martin if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
349 1.2.2.2 martin DEBUGOUT("Advertise 10mb Full duplex\n");
350 1.2.2.2 martin mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
351 1.2.2.2 martin }
352 1.2.2.2 martin
353 1.2.2.2 martin /* Do we want to advertise 100 Mb Half Duplex? */
354 1.2.2.2 martin if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
355 1.2.2.2 martin DEBUGOUT("Advertise 100mb Half duplex\n");
356 1.2.2.2 martin mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
357 1.2.2.2 martin }
358 1.2.2.2 martin
359 1.2.2.2 martin /* Do we want to advertise 100 Mb Full Duplex? */
360 1.2.2.2 martin if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
361 1.2.2.2 martin DEBUGOUT("Advertise 100mb Full duplex\n");
362 1.2.2.2 martin mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
363 1.2.2.2 martin }
364 1.2.2.2 martin
365 1.2.2.2 martin /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
366 1.2.2.2 martin if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
367 1.2.2.2 martin DEBUGOUT("Advertise 1000mb Half duplex request denied!\n");
368 1.2.2.2 martin
369 1.2.2.2 martin /* Do we want to advertise 1000 Mb Full Duplex? */
370 1.2.2.2 martin if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
371 1.2.2.2 martin DEBUGOUT("Advertise 1000mb Full duplex\n");
372 1.2.2.2 martin mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
373 1.2.2.2 martin }
374 1.2.2.2 martin
375 1.2.2.2 martin /* We do not allow the Phy to advertise 2500 Mb Half Duplex */
376 1.2.2.2 martin if (phy->autoneg_advertised & ADVERTISE_2500_HALF)
377 1.2.2.2 martin DEBUGOUT("Advertise 2500mb Half duplex request denied!\n");
378 1.2.2.2 martin
379 1.2.2.2 martin /* Do we want to advertise 2500 Mb Full Duplex? */
380 1.2.2.2 martin if (phy->autoneg_advertised & ADVERTISE_2500_FULL) {
381 1.2.2.2 martin DEBUGOUT("Advertise 2500mb Full duplex\n");
382 1.2.2.2 martin aneg_multigbt_an_ctrl |= CR_2500T_FD_CAPS;
383 1.2.2.2 martin } else
384 1.2.2.2 martin aneg_multigbt_an_ctrl &= ~CR_2500T_FD_CAPS;
385 1.2.2.2 martin
386 1.2.2.2 martin /* Check for a software override of the flow control settings, and
387 1.2.2.2 martin * setup the PHY advertisement registers accordingly. If
388 1.2.2.2 martin * auto-negotiation is enabled, then software will have to set the
389 1.2.2.2 martin * "PAUSE" bits to the correct value in the Auto-Negotiation
390 1.2.2.2 martin * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
391 1.2.2.2 martin * negotiation.
392 1.2.2.2 martin *
393 1.2.2.2 martin * The possible values of the "fc" parameter are:
394 1.2.2.2 martin * 0: Flow control is completely disabled
395 1.2.2.2 martin * 1: Rx flow control is enabled (we can receive pause frames
396 1.2.2.2 martin * but not send pause frames).
397 1.2.2.2 martin * 2: Tx flow control is enabled (we can send pause frames
398 1.2.2.2 martin * but we do not support receiving pause frames).
399 1.2.2.2 martin * 3: Both Rx and Tx flow control (symmetric) are enabled.
400 1.2.2.2 martin * other: No software override. The flow control configuration
401 1.2.2.2 martin * in the EEPROM is used.
402 1.2.2.2 martin */
403 1.2.2.2 martin switch (hw->fc.current_mode) {
404 1.2.2.2 martin case igc_fc_none:
405 1.2.2.2 martin /* Flow control (Rx & Tx) is completely disabled by a
406 1.2.2.2 martin * software over-ride.
407 1.2.2.2 martin */
408 1.2.2.2 martin mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
409 1.2.2.2 martin break;
410 1.2.2.2 martin case igc_fc_rx_pause:
411 1.2.2.2 martin /* Rx Flow control is enabled, and Tx Flow control is
412 1.2.2.2 martin * disabled, by a software over-ride.
413 1.2.2.2 martin *
414 1.2.2.2 martin * Since there really isn't a way to advertise that we are
415 1.2.2.2 martin * capable of Rx Pause ONLY, we will advertise that we
416 1.2.2.2 martin * support both symmetric and asymmetric Rx PAUSE. Later
417 1.2.2.2 martin * (in igc_config_fc_after_link_up) we will disable the
418 1.2.2.2 martin * hw's ability to send PAUSE frames.
419 1.2.2.2 martin */
420 1.2.2.2 martin mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
421 1.2.2.2 martin break;
422 1.2.2.2 martin case igc_fc_tx_pause:
423 1.2.2.2 martin /* Tx Flow control is enabled, and Rx Flow control is
424 1.2.2.2 martin * disabled, by a software over-ride.
425 1.2.2.2 martin */
426 1.2.2.2 martin mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
427 1.2.2.2 martin mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
428 1.2.2.2 martin break;
429 1.2.2.2 martin case igc_fc_full:
430 1.2.2.2 martin /* Flow control (both Rx and Tx) is enabled by a software
431 1.2.2.2 martin * over-ride.
432 1.2.2.2 martin */
433 1.2.2.2 martin mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
434 1.2.2.2 martin break;
435 1.2.2.2 martin default:
436 1.2.2.2 martin DEBUGOUT("Flow control param set incorrectly\n");
437 1.2.2.2 martin return -IGC_ERR_CONFIG;
438 1.2.2.2 martin }
439 1.2.2.2 martin
440 1.2.2.2 martin ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
441 1.2.2.2 martin if (ret_val)
442 1.2.2.2 martin return ret_val;
443 1.2.2.2 martin
444 1.2.2.2 martin DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
445 1.2.2.2 martin
446 1.2.2.2 martin if (phy->autoneg_mask & ADVERTISE_1000_FULL)
447 1.2.2.2 martin ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL,
448 1.2.2.2 martin mii_1000t_ctrl_reg);
449 1.2.2.2 martin
450 1.2.2.2 martin if (phy->autoneg_mask & ADVERTISE_2500_FULL)
451 1.2.2.2 martin ret_val = phy->ops.write_reg(hw,
452 1.2.2.2 martin (STANDARD_AN_REG_MASK << MMD_DEVADDR_SHIFT) |
453 1.2.2.2 martin ANEG_MULTIGBT_AN_CTRL, aneg_multigbt_an_ctrl);
454 1.2.2.2 martin
455 1.2.2.2 martin return ret_val;
456 1.2.2.2 martin }
457 1.2.2.2 martin
458 1.2.2.2 martin /**
459 1.2.2.2 martin * igc_copper_link_autoneg - Setup/Enable autoneg for copper link
460 1.2.2.2 martin * @hw: pointer to the HW structure
461 1.2.2.2 martin *
462 1.2.2.2 martin * Performs initial bounds checking on autoneg advertisement parameter, then
463 1.2.2.2 martin * configure to advertise the full capability. Setup the PHY to autoneg
464 1.2.2.2 martin * and restart the negotiation process between the link partner. If
465 1.2.2.2 martin * autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
466 1.2.2.2 martin **/
467 1.2.2.2 martin static int
468 1.2.2.2 martin igc_copper_link_autoneg(struct igc_hw *hw)
469 1.2.2.2 martin {
470 1.2.2.2 martin struct igc_phy_info *phy = &hw->phy;
471 1.2.2.2 martin uint16_t phy_ctrl;
472 1.2.2.2 martin int ret_val;
473 1.2.2.2 martin
474 1.2.2.2 martin DEBUGFUNC("igc_copper_link_autoneg");
475 1.2.2.2 martin
476 1.2.2.2 martin /* Perform some bounds checking on the autoneg advertisement
477 1.2.2.2 martin * parameter.
478 1.2.2.2 martin */
479 1.2.2.2 martin phy->autoneg_advertised &= phy->autoneg_mask;
480 1.2.2.2 martin
481 1.2.2.2 martin /* If autoneg_advertised is zero, we assume it was not defaulted
482 1.2.2.2 martin * by the calling code so we set to advertise full capability.
483 1.2.2.2 martin */
484 1.2.2.2 martin if (!phy->autoneg_advertised)
485 1.2.2.2 martin phy->autoneg_advertised = phy->autoneg_mask;
486 1.2.2.2 martin
487 1.2.2.2 martin DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
488 1.2.2.2 martin ret_val = igc_phy_setup_autoneg(hw);
489 1.2.2.2 martin if (ret_val) {
490 1.2.2.2 martin DEBUGOUT("Error Setting up Auto-Negotiation\n");
491 1.2.2.2 martin return ret_val;
492 1.2.2.2 martin }
493 1.2.2.2 martin DEBUGOUT("Restarting Auto-Neg\n");
494 1.2.2.2 martin
495 1.2.2.2 martin /* Restart auto-negotiation by setting the Auto Neg Enable bit and
496 1.2.2.2 martin * the Auto Neg Restart bit in the PHY control register.
497 1.2.2.2 martin */
498 1.2.2.2 martin ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
499 1.2.2.2 martin if (ret_val)
500 1.2.2.2 martin return ret_val;
501 1.2.2.2 martin
502 1.2.2.2 martin phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
503 1.2.2.2 martin ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
504 1.2.2.2 martin if (ret_val)
505 1.2.2.2 martin return ret_val;
506 1.2.2.2 martin
507 1.2.2.2 martin /* Does the user want to wait for Auto-Neg to complete here, or
508 1.2.2.2 martin * check at a later time (for example, callback routine).
509 1.2.2.2 martin */
510 1.2.2.2 martin if (phy->autoneg_wait_to_complete) {
511 1.2.2.2 martin ret_val = igc_wait_autoneg(hw);
512 1.2.2.2 martin if (ret_val)
513 1.2.2.2 martin return ret_val;
514 1.2.2.2 martin }
515 1.2.2.2 martin
516 1.2.2.2 martin hw->mac.get_link_status = true;
517 1.2.2.2 martin
518 1.2.2.2 martin return ret_val;
519 1.2.2.2 martin }
520 1.2.2.2 martin
521 1.2.2.2 martin /**
522 1.2.2.2 martin * igc_setup_copper_link_generic - Configure copper link settings
523 1.2.2.2 martin * @hw: pointer to the HW structure
524 1.2.2.2 martin *
525 1.2.2.2 martin * Calls the appropriate function to configure the link for auto-neg or forced
526 1.2.2.2 martin * speed and duplex. Then we check for link, once link is established calls
527 1.2.2.2 martin * to configure collision distance and flow control are called. If link is
528 1.2.2.2 martin * not established, we return -IGC_ERR_PHY (-2).
529 1.2.2.2 martin **/
530 1.2.2.2 martin int
531 1.2.2.2 martin igc_setup_copper_link_generic(struct igc_hw *hw)
532 1.2.2.2 martin {
533 1.2.2.2 martin int ret_val;
534 1.2.2.2 martin bool link;
535 1.2.2.2 martin
536 1.2.2.2 martin DEBUGFUNC("igc_setup_copper_link_generic");
537 1.2.2.2 martin
538 1.2.2.2 martin if (hw->mac.autoneg) {
539 1.2.2.2 martin /* Setup autoneg and flow control advertisement and perform
540 1.2.2.2 martin * autonegotiation.
541 1.2.2.2 martin */
542 1.2.2.2 martin ret_val = igc_copper_link_autoneg(hw);
543 1.2.2.2 martin if (ret_val)
544 1.2.2.2 martin return ret_val;
545 1.2.2.2 martin } else {
546 1.2.2.2 martin /* PHY will be set to 10H, 10F, 100H or 100F
547 1.2.2.2 martin * depending on user settings.
548 1.2.2.2 martin */
549 1.2.2.2 martin DEBUGOUT("Forcing Speed and Duplex\n");
550 1.2.2.2 martin ret_val = hw->phy.ops.force_speed_duplex(hw);
551 1.2.2.2 martin if (ret_val) {
552 1.2.2.2 martin DEBUGOUT("Error Forcing Speed and Duplex\n");
553 1.2.2.2 martin return ret_val;
554 1.2.2.2 martin }
555 1.2.2.2 martin }
556 1.2.2.2 martin
557 1.2.2.2 martin /* Check link status. Wait up to 100 microseconds for link to become
558 1.2.2.2 martin * valid.
559 1.2.2.2 martin */
560 1.2.2.2 martin ret_val = igc_phy_has_link_generic(hw, COPPER_LINK_UP_LIMIT, 10,
561 1.2.2.2 martin &link);
562 1.2.2.2 martin if (ret_val)
563 1.2.2.2 martin return ret_val;
564 1.2.2.2 martin
565 1.2.2.2 martin if (link) {
566 1.2.2.2 martin DEBUGOUT("Valid link established!!!\n");
567 1.2.2.2 martin hw->mac.ops.config_collision_dist(hw);
568 1.2.2.2 martin ret_val = igc_config_fc_after_link_up_generic(hw);
569 1.2.2.2 martin } else
570 1.2.2.2 martin DEBUGOUT("Unable to establish link!!!\n");
571 1.2.2.2 martin
572 1.2.2.2 martin return ret_val;
573 1.2.2.2 martin }
574 1.2.2.2 martin
575 1.2.2.2 martin /**
576 1.2.2.2 martin * igc_check_downshift_generic - Checks whether a downshift in speed occurred
577 1.2.2.2 martin * @hw: pointer to the HW structure
578 1.2.2.2 martin *
579 1.2.2.2 martin * Success returns 0, Failure returns 1
580 1.2.2.2 martin *
581 1.2.2.2 martin * A downshift is detected by querying the PHY link health.
582 1.2.2.2 martin **/
583 1.2.2.2 martin int
584 1.2.2.2 martin igc_check_downshift_generic(struct igc_hw *hw)
585 1.2.2.2 martin {
586 1.2.2.2 martin struct igc_phy_info *phy = &hw->phy;
587 1.2.2.2 martin int ret_val;
588 1.2.2.2 martin
589 1.2.2.2 martin DEBUGFUNC("igc_check_downshift_generic");
590 1.2.2.2 martin
591 1.2.2.2 martin switch (phy->type) {
592 1.2.2.2 martin case igc_phy_i225:
593 1.2.2.2 martin default:
594 1.2.2.2 martin /* speed downshift not supported */
595 1.2.2.2 martin phy->speed_downgraded = false;
596 1.2.2.2 martin return IGC_SUCCESS;
597 1.2.2.2 martin }
598 1.2.2.2 martin
599 1.2.2.2 martin return ret_val;
600 1.2.2.2 martin }
601 1.2.2.2 martin
602 1.2.2.2 martin /**
603 1.2.2.2 martin * igc_wait_autoneg - Wait for auto-neg completion
604 1.2.2.2 martin * @hw: pointer to the HW structure
605 1.2.2.2 martin *
606 1.2.2.2 martin * Waits for auto-negotiation to complete or for the auto-negotiation time
607 1.2.2.2 martin * limit to expire, which ever happens first.
608 1.2.2.2 martin **/
609 1.2.2.2 martin int
610 1.2.2.2 martin igc_wait_autoneg(struct igc_hw *hw)
611 1.2.2.2 martin {
612 1.2.2.2 martin uint16_t i, phy_status;
613 1.2.2.2 martin int ret_val = IGC_SUCCESS;
614 1.2.2.2 martin
615 1.2.2.2 martin DEBUGFUNC("igc_wait_autoneg");
616 1.2.2.2 martin
617 1.2.2.2 martin if (!hw->phy.ops.read_reg)
618 1.2.2.2 martin return IGC_SUCCESS;
619 1.2.2.2 martin
620 1.2.2.2 martin /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
621 1.2.2.2 martin for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
622 1.2.2.2 martin ret_val = hw->phy.ops.read_reg(hw, MII_BMSR, &phy_status);
623 1.2.2.2 martin if (ret_val)
624 1.2.2.2 martin break;
625 1.2.2.2 martin ret_val = hw->phy.ops.read_reg(hw, MII_BMSR, &phy_status);
626 1.2.2.2 martin if (ret_val)
627 1.2.2.2 martin break;
628 1.2.2.2 martin if (phy_status & MII_SR_AUTONEG_COMPLETE)
629 1.2.2.2 martin break;
630 1.2.2.2 martin msec_delay(100);
631 1.2.2.2 martin }
632 1.2.2.2 martin
633 1.2.2.2 martin /* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
634 1.2.2.2 martin * has completed.
635 1.2.2.2 martin */
636 1.2.2.2 martin return ret_val;
637 1.2.2.2 martin }
638 1.2.2.2 martin
639 1.2.2.2 martin /**
640 1.2.2.2 martin * igc_phy_has_link_generic - Polls PHY for link
641 1.2.2.2 martin * @hw: pointer to the HW structure
642 1.2.2.2 martin * @iterations: number of times to poll for link
643 1.2.2.2 martin * @usec_interval: delay between polling attempts
644 1.2.2.2 martin * @success: pointer to whether polling was successful or not
645 1.2.2.2 martin *
646 1.2.2.2 martin * Polls the PHY status register for link, 'iterations' number of times.
647 1.2.2.2 martin **/
648 1.2.2.2 martin int
649 1.2.2.2 martin igc_phy_has_link_generic(struct igc_hw *hw, uint32_t iterations,
650 1.2.2.2 martin uint32_t usec_interval, bool *success)
651 1.2.2.2 martin {
652 1.2.2.2 martin uint16_t i, phy_status;
653 1.2.2.2 martin int ret_val = IGC_SUCCESS;
654 1.2.2.2 martin
655 1.2.2.2 martin DEBUGFUNC("igc_phy_has_link_generic");
656 1.2.2.2 martin
657 1.2.2.2 martin if (!hw->phy.ops.read_reg)
658 1.2.2.2 martin return IGC_SUCCESS;
659 1.2.2.2 martin
660 1.2.2.2 martin for (i = 0; i < iterations; i++) {
661 1.2.2.2 martin /* Some PHYs require the MII_BMSR register to be read
662 1.2.2.2 martin * twice due to the link bit being sticky. No harm doing
663 1.2.2.2 martin * it across the board.
664 1.2.2.2 martin */
665 1.2.2.2 martin ret_val = hw->phy.ops.read_reg(hw, MII_BMSR, &phy_status);
666 1.2.2.2 martin if (ret_val) {
667 1.2.2.2 martin /* If the first read fails, another entity may have
668 1.2.2.2 martin * ownership of the resources, wait and try again to
669 1.2.2.2 martin * see if they have relinquished the resources yet.
670 1.2.2.2 martin */
671 1.2.2.2 martin if (usec_interval >= 1000)
672 1.2.2.2 martin msec_delay(usec_interval/1000);
673 1.2.2.2 martin else
674 1.2.2.2 martin DELAY(usec_interval);
675 1.2.2.2 martin }
676 1.2.2.2 martin ret_val = hw->phy.ops.read_reg(hw, MII_BMSR, &phy_status);
677 1.2.2.2 martin if (ret_val)
678 1.2.2.2 martin break;
679 1.2.2.2 martin if (phy_status & MII_SR_LINK_STATUS)
680 1.2.2.2 martin break;
681 1.2.2.2 martin if (usec_interval >= 1000)
682 1.2.2.2 martin msec_delay(usec_interval/1000);
683 1.2.2.2 martin else
684 1.2.2.2 martin DELAY(usec_interval);
685 1.2.2.2 martin }
686 1.2.2.2 martin
687 1.2.2.2 martin *success = (i < iterations);
688 1.2.2.2 martin
689 1.2.2.2 martin return ret_val;
690 1.2.2.2 martin }
691 1.2.2.2 martin
692 1.2.2.2 martin /**
693 1.2.2.2 martin * igc_phy_hw_reset_generic - PHY hardware reset
694 1.2.2.2 martin * @hw: pointer to the HW structure
695 1.2.2.2 martin *
696 1.2.2.2 martin * Verify the reset block is not blocking us from resetting. Acquire
697 1.2.2.2 martin * semaphore (if necessary) and read/set/write the device control reset
698 1.2.2.2 martin * bit in the PHY. Wait the appropriate delay time for the device to
699 1.2.2.2 martin * reset and release the semaphore (if necessary).
700 1.2.2.2 martin **/
701 1.2.2.2 martin int
702 1.2.2.2 martin igc_phy_hw_reset_generic(struct igc_hw *hw)
703 1.2.2.2 martin {
704 1.2.2.2 martin struct igc_phy_info *phy = &hw->phy;
705 1.2.2.2 martin uint32_t ctrl, timeout = 10000, phpm = 0;
706 1.2.2.2 martin int ret_val;
707 1.2.2.2 martin
708 1.2.2.2 martin DEBUGFUNC("igc_phy_hw_reset_generic");
709 1.2.2.2 martin
710 1.2.2.2 martin if (phy->ops.check_reset_block) {
711 1.2.2.2 martin ret_val = phy->ops.check_reset_block(hw);
712 1.2.2.2 martin if (ret_val)
713 1.2.2.2 martin return IGC_SUCCESS;
714 1.2.2.2 martin }
715 1.2.2.2 martin
716 1.2.2.2 martin ret_val = phy->ops.acquire(hw);
717 1.2.2.2 martin if (ret_val)
718 1.2.2.2 martin return ret_val;
719 1.2.2.2 martin
720 1.2.2.2 martin phpm = IGC_READ_REG(hw, IGC_I225_PHPM);
721 1.2.2.2 martin
722 1.2.2.2 martin ctrl = IGC_READ_REG(hw, IGC_CTRL);
723 1.2.2.2 martin IGC_WRITE_REG(hw, IGC_CTRL, ctrl | IGC_CTRL_PHY_RST);
724 1.2.2.2 martin IGC_WRITE_FLUSH(hw);
725 1.2.2.2 martin
726 1.2.2.2 martin DELAY(phy->reset_delay_us);
727 1.2.2.2 martin
728 1.2.2.2 martin IGC_WRITE_REG(hw, IGC_CTRL, ctrl);
729 1.2.2.2 martin IGC_WRITE_FLUSH(hw);
730 1.2.2.2 martin
731 1.2.2.2 martin DELAY(150);
732 1.2.2.2 martin
733 1.2.2.2 martin do {
734 1.2.2.2 martin phpm = IGC_READ_REG(hw, IGC_I225_PHPM);
735 1.2.2.2 martin timeout--;
736 1.2.2.2 martin DELAY(1);
737 1.2.2.2 martin } while (!(phpm & IGC_I225_PHPM_RST_COMPL) && timeout);
738 1.2.2.2 martin
739 1.2.2.2 martin if (!timeout)
740 1.2.2.2 martin DEBUGOUT("Timeout expired after a phy reset\n");
741 1.2.2.2 martin
742 1.2.2.2 martin phy->ops.release(hw);
743 1.2.2.2 martin
744 1.2.2.2 martin return ret_val;
745 1.2.2.2 martin }
746 1.2.2.2 martin
747 1.2.2.2 martin /**
748 1.2.2.2 martin * igc_power_up_phy_copper - Restore copper link in case of PHY power down
749 1.2.2.2 martin * @hw: pointer to the HW structure
750 1.2.2.2 martin *
751 1.2.2.2 martin * In the case of a PHY power down to save power, or to turn off link during a
752 1.2.2.2 martin * driver unload, or wake on lan is not enabled, restore the link to previous
753 1.2.2.2 martin * settings.
754 1.2.2.2 martin **/
755 1.2.2.2 martin void
756 1.2.2.2 martin igc_power_up_phy_copper(struct igc_hw *hw)
757 1.2.2.2 martin {
758 1.2.2.2 martin uint16_t mii_reg = 0;
759 1.2.2.2 martin
760 1.2.2.2 martin /* The PHY will retain its settings across a power down/up cycle */
761 1.2.2.2 martin hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
762 1.2.2.2 martin mii_reg &= ~MII_CR_POWER_DOWN;
763 1.2.2.2 martin hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
764 1.2.2.2 martin DELAY(300);
765 1.2.2.2 martin }
766 1.2.2.2 martin
767 1.2.2.2 martin /**
768 1.2.2.2 martin * igc_power_down_phy_copper - Restore copper link in case of PHY power down
769 1.2.2.2 martin * @hw: pointer to the HW structure
770 1.2.2.2 martin *
771 1.2.2.2 martin * In the case of a PHY power down to save power, or to turn off link during a
772 1.2.2.2 martin * driver unload, or wake on lan is not enabled, restore the link to previous
773 1.2.2.2 martin * settings.
774 1.2.2.2 martin **/
775 1.2.2.2 martin void
776 1.2.2.2 martin igc_power_down_phy_copper(struct igc_hw *hw)
777 1.2.2.2 martin {
778 1.2.2.2 martin uint16_t mii_reg = 0;
779 1.2.2.2 martin
780 1.2.2.2 martin /* The PHY will retain its settings across a power down/up cycle */
781 1.2.2.2 martin hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
782 1.2.2.2 martin mii_reg |= MII_CR_POWER_DOWN;
783 1.2.2.2 martin hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
784 1.2.2.2 martin msec_delay(1);
785 1.2.2.2 martin }
786 1.2.2.2 martin
787 1.2.2.2 martin /**
788 1.2.2.2 martin * igc_write_phy_reg_gpy - Write GPY PHY register
789 1.2.2.2 martin * @hw: pointer to the HW structure
790 1.2.2.2 martin * @offset: register offset to write to
791 1.2.2.2 martin * @data: data to write at register offset
792 1.2.2.2 martin *
793 1.2.2.2 martin * Acquires semaphore, if necessary, then writes the data to PHY register
794 1.2.2.2 martin * at the offset. Release any acquired semaphores before exiting.
795 1.2.2.2 martin **/
796 1.2.2.2 martin int
797 1.2.2.2 martin igc_write_phy_reg_gpy(struct igc_hw *hw, uint32_t offset, uint16_t data)
798 1.2.2.2 martin {
799 1.2.2.2 martin uint8_t dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;
800 1.2.2.2 martin int ret_val;
801 1.2.2.2 martin
802 1.2.2.2 martin DEBUGFUNC("igc_write_phy_reg_gpy");
803 1.2.2.2 martin
804 1.2.2.2 martin offset = offset & GPY_REG_MASK;
805 1.2.2.2 martin
806 1.2.2.2 martin if (!dev_addr) {
807 1.2.2.2 martin ret_val = hw->phy.ops.acquire(hw);
808 1.2.2.2 martin if (ret_val)
809 1.2.2.2 martin return ret_val;
810 1.2.2.2 martin ret_val = igc_write_phy_reg_mdic(hw, offset, data);
811 1.2.2.2 martin if (ret_val)
812 1.2.2.2 martin return ret_val;
813 1.2.2.2 martin hw->phy.ops.release(hw);
814 1.2.2.2 martin } else {
815 1.2.2.2 martin ret_val = igc_write_xmdio_reg(hw, (uint16_t)offset, dev_addr,
816 1.2.2.2 martin data);
817 1.2.2.2 martin }
818 1.2.2.2 martin
819 1.2.2.2 martin return ret_val;
820 1.2.2.2 martin }
821 1.2.2.2 martin
822 1.2.2.2 martin /**
823 1.2.2.2 martin * igc_read_phy_reg_gpy - Read GPY PHY register
824 1.2.2.2 martin * @hw: pointer to the HW structure
825 1.2.2.2 martin * @offset: lower half is register offset to read to
826 1.2.2.2 martin * upper half is MMD to use.
827 1.2.2.2 martin * @data: data to read at register offset
828 1.2.2.2 martin *
829 1.2.2.2 martin * Acquires semaphore, if necessary, then reads the data in the PHY register
830 1.2.2.2 martin * at the offset. Release any acquired semaphores before exiting.
831 1.2.2.2 martin **/
832 1.2.2.2 martin int
833 1.2.2.2 martin igc_read_phy_reg_gpy(struct igc_hw *hw, uint32_t offset, uint16_t *data)
834 1.2.2.2 martin {
835 1.2.2.2 martin uint8_t dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;
836 1.2.2.2 martin int ret_val;
837 1.2.2.2 martin
838 1.2.2.2 martin DEBUGFUNC("igc_read_phy_reg_gpy");
839 1.2.2.2 martin
840 1.2.2.2 martin offset = offset & GPY_REG_MASK;
841 1.2.2.2 martin
842 1.2.2.2 martin if (!dev_addr) {
843 1.2.2.2 martin ret_val = hw->phy.ops.acquire(hw);
844 1.2.2.2 martin if (ret_val)
845 1.2.2.2 martin return ret_val;
846 1.2.2.2 martin ret_val = igc_read_phy_reg_mdic(hw, offset, data);
847 1.2.2.2 martin if (ret_val)
848 1.2.2.2 martin return ret_val;
849 1.2.2.2 martin hw->phy.ops.release(hw);
850 1.2.2.2 martin } else {
851 1.2.2.2 martin ret_val = igc_read_xmdio_reg(hw, (uint16_t)offset, dev_addr,
852 1.2.2.2 martin data);
853 1.2.2.2 martin }
854 1.2.2.2 martin
855 1.2.2.2 martin return ret_val;
856 1.2.2.2 martin }
857 1.2.2.2 martin
858 1.2.2.2 martin /**
859 1.2.2.2 martin * __igc_access_xmdio_reg - Read/write XMDIO register
860 1.2.2.2 martin * @hw: pointer to the HW structure
861 1.2.2.2 martin * @address: XMDIO address to program
862 1.2.2.2 martin * @dev_addr: device address to program
863 1.2.2.2 martin * @data: pointer to value to read/write from/to the XMDIO address
864 1.2.2.2 martin * @read: boolean flag to indicate read or write
865 1.2.2.2 martin **/
866 1.2.2.2 martin static int
867 1.2.2.2 martin __igc_access_xmdio_reg(struct igc_hw *hw, uint16_t address, uint8_t dev_addr,
868 1.2.2.2 martin uint16_t *data, bool read)
869 1.2.2.2 martin {
870 1.2.2.2 martin int ret_val;
871 1.2.2.2 martin
872 1.2.2.2 martin DEBUGFUNC("__igc_access_xmdio_reg");
873 1.2.2.2 martin
874 1.2.2.2 martin ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, dev_addr);
875 1.2.2.2 martin if (ret_val)
876 1.2.2.2 martin return ret_val;
877 1.2.2.2 martin
878 1.2.2.2 martin ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, address);
879 1.2.2.2 martin if (ret_val)
880 1.2.2.2 martin return ret_val;
881 1.2.2.2 martin
882 1.2.2.2 martin ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, IGC_MMDAC_FUNC_DATA |
883 1.2.2.2 martin dev_addr);
884 1.2.2.2 martin if (ret_val)
885 1.2.2.2 martin return ret_val;
886 1.2.2.2 martin
887 1.2.2.2 martin if (read)
888 1.2.2.2 martin ret_val = hw->phy.ops.read_reg(hw, IGC_MMDAAD, data);
889 1.2.2.2 martin else
890 1.2.2.2 martin ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, *data);
891 1.2.2.2 martin if (ret_val)
892 1.2.2.2 martin return ret_val;
893 1.2.2.2 martin
894 1.2.2.2 martin /* Recalibrate the device back to 0 */
895 1.2.2.2 martin ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, 0);
896 1.2.2.2 martin if (ret_val)
897 1.2.2.2 martin return ret_val;
898 1.2.2.2 martin
899 1.2.2.2 martin return ret_val;
900 1.2.2.2 martin }
901 1.2.2.2 martin
902 1.2.2.2 martin /**
903 1.2.2.2 martin * igc_read_xmdio_reg - Read XMDIO register
904 1.2.2.2 martin * @hw: pointer to the HW structure
905 1.2.2.2 martin * @addr: XMDIO address to program
906 1.2.2.2 martin * @dev_addr: device address to program
907 1.2.2.2 martin * @data: value to be read from the EMI address
908 1.2.2.2 martin **/
909 1.2.2.2 martin int
910 1.2.2.2 martin igc_read_xmdio_reg(struct igc_hw *hw, uint16_t addr, uint8_t dev_addr,
911 1.2.2.2 martin uint16_t *data)
912 1.2.2.2 martin {
913 1.2.2.2 martin DEBUGFUNC("igc_read_xmdio_reg");
914 1.2.2.2 martin
915 1.2.2.2 martin return __igc_access_xmdio_reg(hw, addr, dev_addr, data, true);
916 1.2.2.2 martin }
917 1.2.2.2 martin
918 1.2.2.2 martin /**
919 1.2.2.2 martin * igc_write_xmdio_reg - Write XMDIO register
920 1.2.2.2 martin * @hw: pointer to the HW structure
921 1.2.2.2 martin * @addr: XMDIO address to program
922 1.2.2.2 martin * @dev_addr: device address to program
923 1.2.2.2 martin * @data: value to be written to the XMDIO address
924 1.2.2.2 martin **/
925 1.2.2.2 martin int
926 1.2.2.2 martin igc_write_xmdio_reg(struct igc_hw *hw, uint16_t addr, uint8_t dev_addr,
927 1.2.2.2 martin uint16_t data)
928 1.2.2.2 martin {
929 1.2.2.2 martin DEBUGFUNC("igc_write_xmdio_reg");
930 1.2.2.2 martin
931 1.2.2.2 martin return __igc_access_xmdio_reg(hw, addr, dev_addr, &data, false);
932 1.2.2.2 martin }
933