Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018-2021 Beijing WangXun Technology Co., Ltd.
3 : : */
4 : :
5 : : #include "ngbe_phy_mvl.h"
6 : :
7 : : #define MVL_PHY_RST_WAIT_PERIOD 5
8 : :
9 : 0 : s32 ngbe_read_phy_reg_mvl(struct ngbe_hw *hw,
10 : : u32 reg_addr, u32 device_type, u16 *phy_data)
11 : : {
12 : : mdi_reg_t reg;
13 : : mdi_reg_22_t reg22;
14 : :
15 : 0 : reg.device_type = device_type;
16 : 0 : reg.addr = reg_addr;
17 : :
18 [ # # ]: 0 : if (hw->phy.media_type == ngbe_media_type_fiber)
19 : 0 : ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 1);
20 : : else
21 : 0 : ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 0);
22 : :
23 : 0 : ngbe_mdi_map_register(®, ®22);
24 : :
25 : 0 : ngbe_read_phy_reg_mdi(hw, reg22.addr, reg22.device_type, phy_data);
26 : :
27 : 0 : return 0;
28 : : }
29 : :
30 : 0 : s32 ngbe_write_phy_reg_mvl(struct ngbe_hw *hw,
31 : : u32 reg_addr, u32 device_type, u16 phy_data)
32 : : {
33 : : mdi_reg_t reg;
34 : : mdi_reg_22_t reg22;
35 : :
36 : 0 : reg.device_type = device_type;
37 : 0 : reg.addr = reg_addr;
38 : :
39 [ # # ]: 0 : if (hw->phy.media_type == ngbe_media_type_fiber)
40 : 0 : ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 1);
41 : : else
42 : 0 : ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 0);
43 : :
44 : 0 : ngbe_mdi_map_register(®, ®22);
45 : :
46 : 0 : ngbe_write_phy_reg_mdi(hw, reg22.addr, reg22.device_type, phy_data);
47 : :
48 : 0 : return 0;
49 : : }
50 : :
51 : 0 : s32 ngbe_check_phy_mode_mvl(struct ngbe_hw *hw)
52 : : {
53 : : u8 value = 0;
54 : : u32 phy_mode = 0;
55 : :
56 : 0 : phy_mode = ngbe_flash_read_dword(hw, 0xFF010);
57 : 0 : value = (u8)(phy_mode >> (hw->bus.lan_id * 8));
58 : :
59 [ # # ]: 0 : if (MVL_GEN_CTL_MODE(value) == MVL_GEN_CTL_MODE_COPPER) {
60 : : /* mode select to RGMII-to-copper */
61 : 0 : hw->phy.type = ngbe_phy_mvl;
62 : 0 : hw->phy.media_type = ngbe_media_type_copper;
63 : 0 : hw->mac.link_type = ngbe_link_copper;
64 [ # # ]: 0 : } else if (MVL_GEN_CTL_MODE(value) == MVL_GEN_CTL_MODE_FIBER) {
65 : : /* mode select to RGMII-to-sfi */
66 : 0 : hw->phy.type = ngbe_phy_mvl_sfi;
67 : 0 : hw->phy.media_type = ngbe_media_type_fiber;
68 : 0 : hw->mac.link_type = ngbe_link_fiber;
69 : : } else {
70 : 0 : DEBUGOUT("marvell 88E1512 mode %x is not supported.", value);
71 : 0 : return NGBE_ERR_DEVICE_NOT_SUPPORTED;
72 : : }
73 : :
74 : : return 0;
75 : : }
76 : :
77 : 0 : s32 ngbe_init_phy_mvl(struct ngbe_hw *hw)
78 : : {
79 : : s32 ret_val = 0;
80 : 0 : u16 value = 0;
81 : : int i;
82 : :
83 : : /* enable interrupts, only link status change and an done is allowed */
84 : 0 : ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 2);
85 : 0 : ngbe_read_phy_reg_mdi(hw, MVL_RGM_CTL2, 0, &value);
86 : 0 : value &= ~MVL_RGM_CTL2_TTC;
87 : 0 : value |= MVL_RGM_CTL2_RTC;
88 : 0 : ngbe_write_phy_reg_mdi(hw, MVL_RGM_CTL2, 0, value);
89 : :
90 : 0 : hw->phy.write_reg(hw, MVL_CTRL, 0, MVL_CTRL_RESET);
91 [ # # ]: 0 : for (i = 0; i < 15; i++) {
92 : 0 : ngbe_read_phy_reg_mdi(hw, MVL_CTRL, 0, &value);
93 [ # # ]: 0 : if (value & MVL_CTRL_RESET)
94 : : msleep(1);
95 : : else
96 : : break;
97 : : }
98 : :
99 [ # # ]: 0 : if (i == 15) {
100 : 0 : DEBUGOUT("phy reset exceeds maximum waiting period.");
101 : 0 : return NGBE_ERR_TIMEOUT;
102 : : }
103 : :
104 : 0 : ret_val = hw->phy.reset_hw(hw);
105 [ # # ]: 0 : if (ret_val)
106 : : return ret_val;
107 : :
108 : : /* set LED2 to interrupt output and INTn active low */
109 : 0 : ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 3);
110 : 0 : ngbe_read_phy_reg_mdi(hw, MVL_LEDTCR, 0, &value);
111 : 0 : value |= MVL_LEDTCR_INTR_EN;
112 : 0 : value &= ~(MVL_LEDTCR_INTR_POL);
113 : 0 : ngbe_write_phy_reg_mdi(hw, MVL_LEDTCR, 0, value);
114 : :
115 [ # # ]: 0 : if (hw->phy.type == ngbe_phy_mvl_sfi) {
116 : 0 : hw->phy.read_reg(hw, MVL_CTRL1, 0, &value);
117 : 0 : value &= ~MVL_CTRL1_INTR_POL;
118 : 0 : ngbe_write_phy_reg_mdi(hw, MVL_CTRL1, 0, value);
119 : : }
120 : :
121 : : /* enable link status change and AN complete interrupts */
122 : 0 : value = MVL_INTR_EN_ANC | MVL_INTR_EN_LSC;
123 : 0 : hw->phy.write_reg(hw, MVL_INTR_EN, 0, value);
124 : :
125 : 0 : hw->phy.set_phy_power(hw, false);
126 : :
127 : 0 : return ret_val;
128 : : }
129 : :
130 : 0 : s32 ngbe_setup_phy_link_mvl(struct ngbe_hw *hw, u32 speed,
131 : : bool autoneg_wait_to_complete)
132 : : {
133 : : u16 value_r4 = 0;
134 : : u16 value_r9 = 0;
135 : : u16 value;
136 : :
137 : : UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
138 : :
139 [ # # ]: 0 : if (hw->led_conf == 0xFFFF) {
140 : : /* LED control */
141 : 0 : ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 3);
142 : 0 : ngbe_read_phy_reg_mdi(hw, MVL_LEDFCR, 0, &value);
143 : 0 : value &= ~(MVL_LEDFCR_CTL0 | MVL_LEDFCR_CTL1);
144 : 0 : value |= MVL_LEDFCR_CTL0_CONF | MVL_LEDFCR_CTL1_CONF;
145 : 0 : ngbe_write_phy_reg_mdi(hw, MVL_LEDFCR, 0, value);
146 : 0 : ngbe_read_phy_reg_mdi(hw, MVL_LEDPCR, 0, &value);
147 : 0 : value &= ~(MVL_LEDPCR_CTL0 | MVL_LEDPCR_CTL1);
148 : 0 : value |= MVL_LEDPCR_CTL0_CONF | MVL_LEDPCR_CTL1_CONF;
149 : 0 : ngbe_write_phy_reg_mdi(hw, MVL_LEDPCR, 0, value);
150 : : }
151 : :
152 : 0 : hw->phy.autoneg_advertised = 0;
153 : :
154 [ # # ]: 0 : if (hw->phy.type == ngbe_phy_mvl) {
155 [ # # ]: 0 : if (!hw->mac.autoneg) {
156 [ # # # # ]: 0 : switch (speed) {
157 : 0 : case NGBE_LINK_SPEED_1GB_FULL:
158 : 0 : value = MVL_CTRL_SPEED_SELECT1;
159 : 0 : break;
160 : 0 : case NGBE_LINK_SPEED_100M_FULL:
161 : 0 : value = MVL_CTRL_SPEED_SELECT0;
162 : 0 : break;
163 : 0 : case NGBE_LINK_SPEED_10M_FULL:
164 : 0 : value = 0;
165 : 0 : break;
166 : 0 : default:
167 : 0 : value = MVL_CTRL_SPEED_SELECT0 |
168 : : MVL_CTRL_SPEED_SELECT1;
169 : 0 : DEBUGOUT("unknown speed = 0x%x.", speed);
170 : 0 : break;
171 : : }
172 : : /* duplex full */
173 : 0 : value |= MVL_CTRL_DUPLEX | MVL_CTRL_RESET;
174 : 0 : ngbe_write_phy_reg_mdi(hw, MVL_CTRL, 0, value);
175 : :
176 : 0 : goto skip_an;
177 : : }
178 [ # # ]: 0 : if (speed & NGBE_LINK_SPEED_1GB_FULL) {
179 : : value_r9 |= MVL_PHY_1000BASET_FULL;
180 : 0 : hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
181 : : }
182 : :
183 [ # # ]: 0 : if (speed & NGBE_LINK_SPEED_100M_FULL) {
184 : : value_r4 |= MVL_PHY_100BASET_FULL;
185 : 0 : hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL;
186 : : }
187 : :
188 [ # # ]: 0 : if (speed & NGBE_LINK_SPEED_10M_FULL) {
189 : 0 : value_r4 |= MVL_PHY_10BASET_FULL;
190 : 0 : hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL;
191 : : }
192 : :
193 : 0 : hw->phy.read_reg(hw, MVL_ANA, 0, &value);
194 : 0 : value &= ~(MVL_PHY_100BASET_FULL |
195 : : MVL_PHY_100BASET_HALF |
196 : : MVL_PHY_10BASET_FULL |
197 : : MVL_PHY_10BASET_HALF);
198 : 0 : value_r4 |= value;
199 : 0 : hw->phy.write_reg(hw, MVL_ANA, 0, value_r4);
200 : :
201 : 0 : hw->phy.read_reg(hw, MVL_PHY_1000BASET, 0, &value);
202 : 0 : value &= ~(MVL_PHY_1000BASET_FULL |
203 : : MVL_PHY_1000BASET_HALF);
204 : 0 : value_r9 |= value;
205 : 0 : hw->phy.write_reg(hw, MVL_PHY_1000BASET, 0, value_r9);
206 : :
207 : 0 : value = MVL_CTRL_RESTART_AN | MVL_CTRL_ANE |
208 : : MVL_CTRL_RESET | MVL_CTRL_DUPLEX;
209 : 0 : ngbe_write_phy_reg_mdi(hw, MVL_CTRL, 0, value);
210 : : } else {
211 : 0 : hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
212 : :
213 : 0 : hw->phy.read_reg(hw, MVL_ANA, 0, &value);
214 : 0 : value &= ~(MVL_PHY_1000BASEX_HALF | MVL_PHY_1000BASEX_FULL);
215 : 0 : value |= MVL_PHY_1000BASEX_FULL;
216 : 0 : hw->phy.write_reg(hw, MVL_ANA, 0, value);
217 : :
218 [ # # ]: 0 : if (hw->mac.autoneg)
219 : 0 : value = MVL_CTRL_RESTART_AN | MVL_CTRL_ANE |
220 : : MVL_CTRL_RESET | MVL_CTRL_DUPLEX |
221 : : MVL_CTRL_SPEED_SELECT1;
222 : : else
223 : 0 : value = MVL_CTRL_RESET | MVL_CTRL_DUPLEX |
224 : : MVL_CTRL_SPEED_SELECT1;
225 : 0 : ngbe_write_phy_reg_mdi(hw, MVL_CTRL, 0, value);
226 : : }
227 : :
228 : 0 : skip_an:
229 : 0 : hw->phy.set_phy_power(hw, true);
230 : :
231 : 0 : hw->phy.read_reg(hw, MVL_INTR, 0, &value);
232 : :
233 : 0 : return 0;
234 : : }
235 : :
236 : 0 : s32 ngbe_reset_phy_mvl(struct ngbe_hw *hw)
237 : : {
238 : : u32 i;
239 : 0 : u16 ctrl = 0;
240 : : s32 status = 0;
241 : :
242 [ # # ]: 0 : if (hw->phy.type != ngbe_phy_mvl && hw->phy.type != ngbe_phy_mvl_sfi)
243 : : return NGBE_ERR_PHY_TYPE;
244 : :
245 : : /* select page 18 reg 20 */
246 : 0 : status = ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 18);
247 : :
248 : : /* mode select to RGMII-to-copper or RGMII-to-sfi*/
249 [ # # ]: 0 : if (hw->phy.type == ngbe_phy_mvl)
250 : 0 : ctrl = MVL_GEN_CTL_MODE_COPPER;
251 : : else
252 : 0 : ctrl = MVL_GEN_CTL_MODE_FIBER;
253 : 0 : status = ngbe_write_phy_reg_mdi(hw, MVL_GEN_CTL, 0, ctrl);
254 : : /* mode reset */
255 : 0 : ctrl |= MVL_GEN_CTL_RESET;
256 : 0 : status = ngbe_write_phy_reg_mdi(hw, MVL_GEN_CTL, 0, ctrl);
257 : :
258 [ # # ]: 0 : for (i = 0; i < MVL_PHY_RST_WAIT_PERIOD; i++) {
259 : 0 : status = ngbe_read_phy_reg_mdi(hw, MVL_GEN_CTL, 0, &ctrl);
260 [ # # ]: 0 : if (!(ctrl & MVL_GEN_CTL_RESET))
261 : : break;
262 : : msleep(1);
263 : : }
264 : :
265 [ # # ]: 0 : if (i == MVL_PHY_RST_WAIT_PERIOD) {
266 : 0 : DEBUGOUT("PHY reset polling failed to complete.");
267 : 0 : return NGBE_ERR_RESET_FAILED;
268 : : }
269 : :
270 : : return status;
271 : : }
272 : :
273 : 0 : s32 ngbe_get_phy_advertised_pause_mvl(struct ngbe_hw *hw, u8 *pause_bit)
274 : : {
275 : : u16 value;
276 : : s32 status = 0;
277 : :
278 [ # # ]: 0 : if (hw->phy.type == ngbe_phy_mvl) {
279 : 0 : status = hw->phy.read_reg(hw, MVL_ANA, 0, &value);
280 : 0 : value &= MVL_CANA_ASM_PAUSE | MVL_CANA_PAUSE;
281 : 0 : *pause_bit = (u8)(value >> 10);
282 : : } else {
283 : 0 : status = hw->phy.read_reg(hw, MVL_ANA, 0, &value);
284 : 0 : value &= MVL_FANA_PAUSE_MASK;
285 : 0 : *pause_bit = (u8)(value >> 7);
286 : : }
287 : :
288 : 0 : return status;
289 : : }
290 : :
291 : 0 : s32 ngbe_get_phy_lp_advertised_pause_mvl(struct ngbe_hw *hw, u8 *pause_bit)
292 : : {
293 : : u16 value;
294 : : s32 status = 0;
295 : :
296 [ # # ]: 0 : if (hw->phy.type == ngbe_phy_mvl) {
297 : 0 : status = hw->phy.read_reg(hw, MVL_LPAR, 0, &value);
298 : 0 : value &= MVL_CLPAR_ASM_PAUSE | MVL_CLPAR_PAUSE;
299 : 0 : *pause_bit = (u8)(value >> 10);
300 : : } else {
301 : 0 : status = hw->phy.read_reg(hw, MVL_LPAR, 0, &value);
302 : 0 : value &= MVL_FLPAR_PAUSE_MASK;
303 : 0 : *pause_bit = (u8)(value >> 7);
304 : : }
305 : :
306 : 0 : return status;
307 : : }
308 : :
309 : 0 : s32 ngbe_set_phy_pause_adv_mvl(struct ngbe_hw *hw, u16 pause_bit)
310 : : {
311 : : u16 value;
312 : : s32 status = 0;
313 : :
314 [ # # ]: 0 : if (hw->phy.type == ngbe_phy_mvl) {
315 : 0 : status = hw->phy.read_reg(hw, MVL_ANA, 0, &value);
316 : 0 : value &= ~(MVL_CANA_ASM_PAUSE | MVL_CANA_PAUSE);
317 : : } else {
318 : 0 : status = hw->phy.read_reg(hw, MVL_ANA, 0, &value);
319 : 0 : value &= ~MVL_FANA_PAUSE_MASK;
320 : : }
321 : :
322 : 0 : value |= pause_bit;
323 : 0 : status = hw->phy.write_reg(hw, MVL_ANA, 0, value);
324 : :
325 : 0 : return status;
326 : : }
327 : :
328 : 0 : s32 ngbe_check_phy_link_mvl(struct ngbe_hw *hw,
329 : : u32 *speed, bool *link_up)
330 : : {
331 : : s32 status = 0;
332 : : u16 phy_link = 0;
333 : : u16 phy_speed = 0;
334 : 0 : u16 phy_data = 0;
335 : 0 : u16 insr = 0;
336 : :
337 : : /* Initialize speed and link to default case */
338 : 0 : *link_up = false;
339 : 0 : *speed = NGBE_LINK_SPEED_UNKNOWN;
340 : :
341 : 0 : hw->phy.read_reg(hw, MVL_INTR, 0, &insr);
342 : :
343 : : /*
344 : : * Check current speed and link status of the PHY register.
345 : : * This is a vendor specific register and may have to
346 : : * be changed for other copper PHYs.
347 : : */
348 : 0 : status = hw->phy.read_reg(hw, MVL_PHYSR, 0, &phy_data);
349 : 0 : phy_link = phy_data & MVL_PHYSR_LINK;
350 : 0 : phy_speed = phy_data & MVL_PHYSR_SPEED_MASK;
351 : :
352 [ # # ]: 0 : if (phy_link == MVL_PHYSR_LINK) {
353 : 0 : *link_up = true;
354 : :
355 [ # # ]: 0 : if (phy_speed == MVL_PHYSR_SPEED_1000M)
356 : 0 : *speed = NGBE_LINK_SPEED_1GB_FULL;
357 [ # # ]: 0 : else if (phy_speed == MVL_PHYSR_SPEED_100M)
358 : 0 : *speed = NGBE_LINK_SPEED_100M_FULL;
359 [ # # ]: 0 : else if (phy_speed == MVL_PHYSR_SPEED_10M)
360 : 0 : *speed = NGBE_LINK_SPEED_10M_FULL;
361 : : }
362 : :
363 : 0 : return status;
364 : : }
365 : :
366 : 0 : s32 ngbe_set_phy_power_mvl(struct ngbe_hw *hw, bool on)
367 : : {
368 : 0 : u16 value = 0;
369 : :
370 : 0 : hw->phy.read_reg(hw, MVL_CTRL, 0, &value);
371 [ # # ]: 0 : if (on)
372 : 0 : value &= ~MVL_CTRL_PWDN;
373 : : else
374 : 0 : value |= MVL_CTRL_PWDN;
375 : 0 : hw->phy.write_reg(hw, MVL_CTRL, 0, value);
376 : :
377 : 0 : return 0;
378 : : }
|