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