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