xref: /freebsd/sys/dev/al_eth/al_init_eth_lm.c (revision 9768746b)
1 /*-
2  * Copyright (c) 2015,2016 Annapurna Labs Ltd. and affiliates
3  * All rights reserved.
4  *
5  * Developed by Semihalf.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include "al_init_eth_lm.h"
33 #include "al_serdes.h"
34 #include "al_hal_eth.h"
35 #include "al_init_eth_kr.h"
36 
37 /**
38  *  @{
39  * @file   al_init_eth_lm.c
40  *
41  * @brief ethernet link management common utilities
42  *
43  */
44 
45 /* delay before checking link status with new serdes parameters (uSec) */
46 #define	AL_ETH_LM_LINK_STATUS_DELAY	1000
47 /* delay before checking link status after reconfiguring the retimer (uSec) */
48 #define	AL_ETH_LM_RETIMER_LINK_STATUS_DELAY 50000
49 
50 #define	AL_ETH_LM_EQ_ITERATIONS		15
51 #define	AL_ETH_LM_MAX_DCGAIN		8
52 
53 /* num of link training failures till serdes reset */
54 #define	AL_ETH_LT_FAILURES_TO_RESET	10
55 
56 #define	MODULE_IDENTIFIER_IDX		0
57 #define	MODULE_IDENTIFIER_SFP		0x3
58 #define	MODULE_IDENTIFIER_QSFP		0xd
59 
60 #define	SFP_PRESENT			0
61 #define	SFP_NOT_PRESENT			1
62 
63 /* SFP+ module */
64 #define	SFP_I2C_HEADER_10G_IDX		3
65 #define	SFP_I2C_HEADER_10G_DA_IDX	8
66 #define	SFP_I2C_HEADER_10G_DA_LEN_IDX	18
67 #define	SFP_I2C_HEADER_1G_IDX		6
68 #define	SFP_I2C_HEADER_SIGNAL_RATE	12 /* Nominal signaling rate, units of 100MBd. */
69 
70 #define	SFP_MIN_SIGNAL_RATE_25G		250
71 #define	SFP_MIN_SIGNAL_RATE_10G		100
72 
73 /* QSFP+ module */
74 #define	QSFP_COMPLIANCE_CODE_IDX	131
75 /* 40GBASE-LR4 and 40GBASE-SR4 are optic modules */
76 #define	QSFP_COMPLIANCE_CODE_OPTIC	((1 << 1) | (1 << 2))
77 #define	QSFP_COMPLIANCE_CODE_DAC	(1 << 3)
78 #define	QSFP_CABLE_LEN_IDX		146
79 
80 /* TODO: need to check the necessary delay */
81 #define	AL_ETH_LM_RETIMER_WAIT_FOR_LOCK	500 /* delay after retimer reset to lock (mSec) */
82 #define	AL_ETH_LM_SERDES_WAIT_FOR_LOCK	50 /* delay after signal detect to lock (mSec) */
83 
84 #define AL_ETH_LM_GEARBOX_RESET_DELAY	1000 /* (uSec) */
85 
86 static const uint32_t
87 al_eth_retimer_boost_addr[AL_ETH_RETIMER_CHANNEL_MAX][AL_ETH_RETIMER_TYPE_MAX] = {
88 					/* BR_210  |  BR_410 */
89 	/* AL_ETH_RETIMER_CHANNEL_A */	{0xf,		0x1a},
90 	/* AL_ETH_RETIMER_CHANNEL_B */	{0x16,		0x18},
91 	/* AL_ETH_RETIMER_CHANNEL_C */	{0x0,		0x16},
92 	/* AL_ETH_RETIMER_CHANNEL_D */	{0x0,		0x14},
93 };
94 
95 #define	RETIMER_LENS_MAX		5
96 static const uint32_t
97 al_eth_retimer_boost_lens[RETIMER_LENS_MAX] = {0, 1, 2, 3, 5};
98 
99 static const uint32_t
100 al_eth_retimer_boost_value[RETIMER_LENS_MAX + 1][AL_ETH_RETIMER_TYPE_MAX] = {
101 		/* BR_210  |  BR_410 */
102 	/* 0 */	{0x0,		0x0},
103 	/* 1 */	{0x1,		0x1},
104 	/* 2 */	{0x2,		0x1},
105 	/* 3 */	{0x3,		0x3},
106 	/* 5 */	{0x7,		0x3},
107 	/* 5+ */{0xb,		0x7},
108 };
109 
110 struct retimer_config_reg {
111 	uint8_t addr;
112 	uint8_t value;
113 	uint8_t mask;
114 };
115 
116 static struct retimer_config_reg retimer_ds25_25g_mode_tx_ch[] = {
117 	{.addr = 0x0A, .value = 0x0C, .mask = 0xff },
118 	{.addr = 0x2F, .value = 0x54, .mask = 0xff },
119 	{.addr = 0x31, .value = 0x20, .mask = 0xff },
120 	{.addr = 0x1E, .value = 0xE9, .mask = 0xff },
121 	{.addr = 0x1F, .value = 0x0B, .mask = 0xff },
122 	{.addr = 0xA6, .value = 0x43, .mask = 0xff },
123 	{.addr = 0x2A, .value = 0x5A, .mask = 0xff },
124 	{.addr = 0x2B, .value = 0x0A, .mask = 0xff },
125 	{.addr = 0x2C, .value = 0xF6, .mask = 0xff },
126 	{.addr = 0x70, .value = 0x05, .mask = 0xff },
127 	{.addr = 0x6A, .value = 0x21, .mask = 0xff },
128 	{.addr = 0x35, .value = 0x0F, .mask = 0xff },
129 	{.addr = 0x12, .value = 0x83, .mask = 0xff },
130 	{.addr = 0x9C, .value = 0x24, .mask = 0xff },
131 	{.addr = 0x98, .value = 0x00, .mask = 0xff },
132 	{.addr = 0x42, .value = 0x50, .mask = 0xff },
133 	{.addr = 0x44, .value = 0x90, .mask = 0xff },
134 	{.addr = 0x45, .value = 0xC0, .mask = 0xff },
135 	{.addr = 0x46, .value = 0xD0, .mask = 0xff },
136 	{.addr = 0x47, .value = 0xD1, .mask = 0xff },
137 	{.addr = 0x48, .value = 0xD5, .mask = 0xff },
138 	{.addr = 0x49, .value = 0xD8, .mask = 0xff },
139 	{.addr = 0x4A, .value = 0xEA, .mask = 0xff },
140 	{.addr = 0x4B, .value = 0xF7, .mask = 0xff },
141 	{.addr = 0x4C, .value = 0xFD, .mask = 0xff },
142 	{.addr = 0x8E, .value = 0x00, .mask = 0xff },
143 	{.addr = 0x3D, .value = 0x94, .mask = 0xff },
144 	{.addr = 0x3F, .value = 0x40, .mask = 0xff },
145 	{.addr = 0x3E, .value = 0x43, .mask = 0xff },
146 	{.addr = 0x0A, .value = 0x00, .mask = 0xff },
147 };
148 
149 static struct retimer_config_reg retimer_ds25_25g_mode_rx_ch[] = {
150 	{.addr = 0x0A, .value = 0x0C, .mask = 0xff},
151 	{.addr = 0x2F, .value = 0x54, .mask = 0xff},
152 	{.addr = 0x31, .value = 0x40, .mask = 0xff},
153 	{.addr = 0x1E, .value = 0xE3, .mask = 0xff},
154 	{.addr = 0x1F, .value = 0x0B, .mask = 0xff},
155 	{.addr = 0xA6, .value = 0x43, .mask = 0xff},
156 	{.addr = 0x2A, .value = 0x5A, .mask = 0xff},
157 	{.addr = 0x2B, .value = 0x0A, .mask = 0xff},
158 	{.addr = 0x2C, .value = 0xF6, .mask = 0xff},
159 	{.addr = 0x70, .value = 0x05, .mask = 0xff},
160 	{.addr = 0x6A, .value = 0x21, .mask = 0xff},
161 	{.addr = 0x35, .value = 0x0F, .mask = 0xff},
162 	{.addr = 0x12, .value = 0x83, .mask = 0xff},
163 	{.addr = 0x9C, .value = 0x24, .mask = 0xff},
164 	{.addr = 0x98, .value = 0x00, .mask = 0xff},
165 	{.addr = 0x42, .value = 0x50, .mask = 0xff},
166 	{.addr = 0x44, .value = 0x90, .mask = 0xff},
167 	{.addr = 0x45, .value = 0xC0, .mask = 0xff},
168 	{.addr = 0x46, .value = 0xD0, .mask = 0xff},
169 	{.addr = 0x47, .value = 0xD1, .mask = 0xff},
170 	{.addr = 0x48, .value = 0xD5, .mask = 0xff},
171 	{.addr = 0x49, .value = 0xD8, .mask = 0xff},
172 	{.addr = 0x4A, .value = 0xEA, .mask = 0xff},
173 	{.addr = 0x4B, .value = 0xF7, .mask = 0xff},
174 	{.addr = 0x4C, .value = 0xFD, .mask = 0xff},
175 	{.addr = 0x8E, .value = 0x00, .mask = 0xff},
176 	{.addr = 0x3D, .value = 0x94, .mask = 0xff},
177 	{.addr = 0x3F, .value = 0x40, .mask = 0xff},
178 	{.addr = 0x3E, .value = 0x43, .mask = 0xff},
179 	{.addr = 0x0A, .value = 0x00, .mask = 0xff},
180 };
181 
182 static struct retimer_config_reg retimer_ds25_10g_mode[] = {
183 	/* Assert CDR reset (6.3) */
184 	{.addr = 0x0A, .value = 0x0C, .mask = 0x0C},
185 	/* Select 10.3125Gbps standard rate mode (6.6) */
186 	{.addr = 0x2F, .value = 0x00, .mask = 0xF0},
187 	/* Enable loop filter auto-adjust */
188 	{.addr = 0x1F, .value = 0x08, .mask = 0x08},
189 	/* Set Adapt Mode 1 (6.13) */
190 	{.addr = 0x31, .value = 0x20, .mask = 0x60},
191 	/* Disable the DFE since most applications do not need it (6.18) */
192 	{.addr = 0x1E, .value = 0x08, .mask = 0x08},
193 	/* Release CDR reset (6.4) */
194 	{.addr = 0x0A, .value = 0x00, .mask = 0x0C},
195 	/* Enable FIR (6.12) */
196 	{.addr = 0x3D, .value = 0x80, .mask = 0x80},
197 	/* Set Main-cursor tap sign to positive (6.12) */
198 	{.addr = 0x3D, .value = 0x00, .mask = 0x40},
199 	/* Set Post-cursor tap sign to negative (6.12) */
200 	{.addr = 0x3F, .value = 0x40, .mask = 0x40},
201 	/* Set Pre-cursor tap sign to negative (6.12) */
202 	{.addr = 0x3E, .value = 0x40, .mask = 0x40},
203 	/* Set Main-cursor tap magnitude to 13 (6.12) */
204 	{.addr = 0x3D, .value = 0x0D, .mask = 0x1F},
205 };
206 
207 static int al_eth_lm_retimer_boost_config(struct al_eth_lm_context *lm_context);
208 static int al_eth_lm_retimer_ds25_full_config(struct al_eth_lm_context *lm_context);
209 static al_bool al_eth_lm_retimer_ds25_signal_detect(
210 		struct al_eth_lm_context *lm_context, uint32_t channel);
211 static int al_eth_lm_retimer_ds25_cdr_reset(struct al_eth_lm_context *lm_context, uint32_t channel);
212 static al_bool al_eth_lm_retimer_ds25_cdr_lock(
213 		struct al_eth_lm_context *lm_context, uint32_t channel);
214 static int al_eth_lm_retimer_25g_rx_adaptation(struct al_eth_lm_context *lm_context);
215 
216 struct al_eth_lm_retimer {
217 	int (*config)(struct al_eth_lm_context *lm_context);
218 	int (*reset)(struct al_eth_lm_context *lm_context, uint32_t channel);
219 	int (*signal_detect)(struct al_eth_lm_context *lm_context, uint32_t channel);
220 	int (*cdr_lock)(struct al_eth_lm_context *lm_context, uint32_t channel);
221 	int (*rx_adaptation)(struct al_eth_lm_context *lm_context);
222 };
223 
224 static struct al_eth_lm_retimer retimer[] = {
225 	{.config = al_eth_lm_retimer_boost_config, .signal_detect = NULL,
226 		.reset = NULL, .cdr_lock = NULL, .rx_adaptation = NULL},
227 	{.config = al_eth_lm_retimer_boost_config, .signal_detect = NULL,
228 		.reset = NULL, .cdr_lock = NULL, .rx_adaptation = NULL},
229 	{.config = al_eth_lm_retimer_ds25_full_config,
230 		.signal_detect = al_eth_lm_retimer_ds25_signal_detect,
231 		.reset = al_eth_lm_retimer_ds25_cdr_reset,
232 		.cdr_lock = al_eth_lm_retimer_ds25_cdr_lock,
233 		.rx_adaptation = al_eth_lm_retimer_25g_rx_adaptation},
234 };
235 
236 #define SFP_10G_DA_ACTIVE		0x8
237 #define SFP_10G_DA_PASSIVE		0x4
238 
239 #define lm_debug(...)				\
240 	do {					\
241 		if (lm_context->debug)		\
242 			al_warn(__VA_ARGS__);	\
243 		else				\
244 			al_dbg(__VA_ARGS__);	\
245 	} while (0)
246 
247 static int
248 al_eth_sfp_detect(struct al_eth_lm_context *lm_context,
249     enum al_eth_lm_link_mode *new_mode)
250 {
251 	int rc = 0;
252 	uint8_t sfp_10g;
253 	uint8_t sfp_1g;
254 	uint8_t sfp_cable_tech;
255 	uint8_t sfp_da_len;
256 	uint8_t signal_rate;
257 
258 	do {
259 		rc = lm_context->i2c_read(lm_context->i2c_context,
260 		    lm_context->sfp_bus_id, lm_context->sfp_i2c_addr,
261 		    SFP_I2C_HEADER_10G_IDX, &sfp_10g);
262 		if (rc != 0)
263 			break;
264 
265 		rc = lm_context->i2c_read(lm_context->i2c_context,
266 		    lm_context->sfp_bus_id, lm_context->sfp_i2c_addr,
267 		    SFP_I2C_HEADER_1G_IDX, &sfp_1g);
268 		if (rc != 0)
269 			break;
270 
271 		rc = lm_context->i2c_read(lm_context->i2c_context,
272 		    lm_context->sfp_bus_id, lm_context->sfp_i2c_addr,
273 		    SFP_I2C_HEADER_10G_DA_IDX, &sfp_cable_tech);
274 		if (rc != 0)
275 			break;
276 
277 		rc = lm_context->i2c_read(lm_context->i2c_context,
278 		    lm_context->sfp_bus_id, lm_context->sfp_i2c_addr,
279 		    SFP_I2C_HEADER_10G_DA_LEN_IDX, &sfp_da_len);
280 		if (rc != 0)
281 			break;
282 
283 		rc = lm_context->i2c_read(lm_context->i2c_context,
284 					  lm_context->sfp_bus_id,
285 					  lm_context->sfp_i2c_addr,
286 					  SFP_I2C_HEADER_SIGNAL_RATE,
287 					  &signal_rate);
288 	} while (0);
289 
290 	if (rc != 0) {
291 		if (rc == ETIMEDOUT) {
292 			/* ETIMEDOUT is returned when no SFP is connected */
293 			if (lm_context->mode != AL_ETH_LM_MODE_DISCONNECTED)
294 				lm_debug("%s: SFP Disconnected\n", __func__);
295 			*new_mode = AL_ETH_LM_MODE_DISCONNECTED;
296 		} else {
297 			return (rc);
298 		}
299 	} else if ((sfp_cable_tech & (SFP_10G_DA_PASSIVE | SFP_10G_DA_ACTIVE)) != 0) {
300 		if ((signal_rate >= SFP_MIN_SIGNAL_RATE_25G) &&
301 			((lm_context->max_speed == AL_ETH_LM_MAX_SPEED_25G) ||
302 			(lm_context->max_speed == AL_ETH_LM_MAX_SPEED_MAX)))
303 			*new_mode = AL_ETH_LM_MODE_25G;
304 		else if ((signal_rate >= SFP_MIN_SIGNAL_RATE_10G) &&
305 			((lm_context->max_speed == AL_ETH_LM_MAX_SPEED_10G) ||
306 			(lm_context->max_speed == AL_ETH_LM_MAX_SPEED_MAX)))
307 			*new_mode = AL_ETH_LM_MODE_10G_DA;
308 		else
309 			*new_mode = AL_ETH_LM_MODE_1G;
310 
311 		lm_debug("%s: %s DAC (%d M) detected (max signal rate %d)\n",
312 			 __func__,
313 			 (sfp_cable_tech & SFP_10G_DA_PASSIVE) ? "Passive" : "Active",
314 			  sfp_da_len,
315 			  signal_rate);
316 
317 		/* for active direct attached need to use len 0 in the retimer configuration */
318 		lm_context->da_len = (sfp_cable_tech & SFP_10G_DA_PASSIVE) ? sfp_da_len : 0;
319 	} else if (sfp_10g != 0) {
320 		lm_debug("%s: 10 SFP detected\n", __func__);
321 		*new_mode = AL_ETH_LM_MODE_10G_OPTIC;
322 	} else if (sfp_1g != 0) {
323 		lm_debug("%s: 1G SFP detected\n", __func__);
324 		*new_mode = AL_ETH_LM_MODE_1G;
325 	} else {
326 		al_warn("%s: unknown SFP inserted. eeprom content: 10G compliance 0x%x,"
327 		    " 1G compliance 0x%x, sfp+cable 0x%x. default to %s\n",
328 		    __func__, sfp_10g, sfp_1g, sfp_cable_tech,
329 		    al_eth_lm_mode_convert_to_str(lm_context->default_mode));
330 		*new_mode = lm_context->default_mode;
331 		lm_context->da_len = lm_context->default_dac_len;
332 	}
333 
334 	if ((lm_context->sfp_detect_force_mode) && (*new_mode != AL_ETH_LM_MODE_DISCONNECTED) &&
335 	    (*new_mode != lm_context->default_mode)) {
336 		al_warn("%s: Force mode to default (%s). mode based of the SFP EEPROM %s\n",
337 			__func__, al_eth_lm_mode_convert_to_str(lm_context->default_mode),
338 			al_eth_lm_mode_convert_to_str(*new_mode));
339 
340 		*new_mode = lm_context->default_mode;
341 	}
342 
343 	lm_context->mode = *new_mode;
344 
345 	return (0);
346 }
347 
348 static int
349 al_eth_qsfp_detect(struct al_eth_lm_context *lm_context,
350     enum al_eth_lm_link_mode *new_mode)
351 {
352 	int rc = 0;
353 	uint8_t qsfp_comp_code;
354 	uint8_t qsfp_da_len;
355 
356 	do {
357 		rc = lm_context->i2c_read(lm_context->i2c_context,
358 		    lm_context->sfp_bus_id, lm_context->sfp_i2c_addr,
359 		    QSFP_COMPLIANCE_CODE_IDX, &qsfp_comp_code);
360 		if (rc != 0)
361 			break;
362 
363 		rc = lm_context->i2c_read(lm_context->i2c_context,
364 		    lm_context->sfp_bus_id, lm_context->sfp_i2c_addr,
365 		    QSFP_CABLE_LEN_IDX, &qsfp_da_len);
366 		if (rc != 0)
367 			break;
368 	} while (0);
369 
370 	if (rc != 0) {
371 		if (rc == ETIMEDOUT) {
372 			/* ETIMEDOUT is returned when no SFP is connected */
373 			lm_debug("%s: SFP Disconnected\n", __func__);
374 			*new_mode = AL_ETH_LM_MODE_DISCONNECTED;
375 		} else {
376 			return (rc);
377 		}
378 	} else if ((qsfp_comp_code & QSFP_COMPLIANCE_CODE_DAC) != 0) {
379 		lm_debug("%s: 10G passive DAC (%d M) detected\n",
380 		    __func__, qsfp_da_len);
381 		*new_mode = AL_ETH_LM_MODE_10G_DA;
382 		lm_context->da_len = qsfp_da_len;
383 	} else if ((qsfp_comp_code & QSFP_COMPLIANCE_CODE_OPTIC) != 0) {
384 		lm_debug("%s: 10G optic module detected\n", __func__);
385 		*new_mode = AL_ETH_LM_MODE_10G_OPTIC;
386 	} else {
387 		al_warn("%s: unknown QSFP inserted. eeprom content: 10G "
388 		    "compliance 0x%x default to %s\n", __func__, qsfp_comp_code,
389 		    al_eth_lm_mode_convert_to_str(lm_context->default_mode));
390 		*new_mode = lm_context->default_mode;
391 		lm_context->da_len = lm_context->default_dac_len;
392 	}
393 
394 	lm_context->mode = *new_mode;
395 
396 	return (0);
397 }
398 
399 static int
400 al_eth_module_detect(struct al_eth_lm_context *lm_context,
401     enum al_eth_lm_link_mode *new_mode)
402 {
403 	int rc = 0;
404 	uint8_t module_idx;
405 	int sfp_present = SFP_PRESENT;
406 
407 	if ((lm_context->gpio_get) && (lm_context->gpio_present != 0))
408 		sfp_present = lm_context->gpio_get(lm_context->gpio_present);
409 
410 	if (sfp_present == SFP_NOT_PRESENT) {
411 		lm_debug("%s: SFP not exist\n", __func__);
412 		*new_mode = AL_ETH_LM_MODE_DISCONNECTED;
413 
414 		return 0;
415 	}
416 
417 	rc = lm_context->i2c_read(lm_context->i2c_context,
418 	    lm_context->sfp_bus_id, lm_context->sfp_i2c_addr,
419 	    MODULE_IDENTIFIER_IDX, &module_idx);
420 	if (rc != 0) {
421 		if (rc == ETIMEDOUT) {
422 			/* ETIMEDOUT is returned when no SFP is connected */
423 			if (lm_context->mode != AL_ETH_LM_MODE_DISCONNECTED)
424 				lm_debug("%s: SFP Disconnected\n", __func__);
425 			*new_mode = AL_ETH_LM_MODE_DISCONNECTED;
426 			return (0);
427 		} else {
428 			return (rc);
429 		}
430 	}
431 
432 	if (module_idx == MODULE_IDENTIFIER_QSFP)
433 		return (al_eth_qsfp_detect(lm_context, new_mode));
434 	else
435 		return (al_eth_sfp_detect(lm_context, new_mode));
436 
437 	return (0);
438 }
439 
440 static struct al_serdes_adv_tx_params da_tx_params = {
441 	.override		= TRUE,
442 	.amp			= 0x1,
443 	.total_driver_units	= 0x13,
444 	.c_plus_1		= 0x2,
445 	.c_plus_2		= 0,
446 	.c_minus_1		= 0x2,
447 	.slew_rate		= 0,
448 };
449 
450 static struct al_serdes_adv_rx_params da_rx_params = {
451 	.override		= TRUE,
452 	.dcgain			= 0x4,
453 	.dfe_3db_freq		= 0x4,
454 	.dfe_gain		= 0x3,
455 	.dfe_first_tap_ctrl	= 0x5,
456 	.dfe_secound_tap_ctrl	= 0x1,
457 	.dfe_third_tap_ctrl	= 0x8,
458 	.dfe_fourth_tap_ctrl	= 0x1,
459 	.low_freq_agc_gain	= 0x7,
460 	.precal_code_sel	= 0,
461 	.high_freq_agc_boost	= 0x1d,
462 };
463 
464 static struct al_serdes_adv_tx_params optic_tx_params = {
465 	.override		= TRUE,
466 	.amp			= 0x1,
467 	.total_driver_units	= 0x13,
468 	.c_plus_1		= 0x2,
469 	.c_plus_2		= 0,
470 	.c_minus_1		= 0,
471 	.slew_rate		= 0,
472 };
473 
474 static struct al_serdes_adv_rx_params optic_rx_params = {
475 	.override		= TRUE,
476 	.dcgain			= 0x0,
477 	.dfe_3db_freq		= 0x7,
478 	.dfe_gain		= 0x0,
479 	.dfe_first_tap_ctrl	= 0x0,
480 	.dfe_secound_tap_ctrl	= 0x8,
481 	.dfe_third_tap_ctrl	= 0x0,
482 	.dfe_fourth_tap_ctrl	= 0x8,
483 	.low_freq_agc_gain	= 0x7,
484 	.precal_code_sel	= 0,
485 	.high_freq_agc_boost	= 0x4,
486 };
487 
488 static void
489 al_eth_serdes_static_tx_params_set(struct al_eth_lm_context *lm_context)
490 {
491 
492 	if (lm_context->tx_param_dirty == 0)
493 		return;
494 
495 	if (lm_context->serdes_tx_params_valid != 0) {
496 		lm_context->tx_param_dirty = 0;
497 
498 		lm_context->tx_params_override.override = TRUE;
499 
500 		if ((lm_context->serdes_obj->tx_advanced_params_set) == 0) {
501 			al_err("tx_advanced_params_set is not supported for this serdes group\n");
502 			return;
503 		}
504 
505 		lm_context->serdes_obj->tx_advanced_params_set(
506 					lm_context->serdes_obj,
507 					lm_context->lane,
508 					&lm_context->tx_params_override);
509 
510 	} else if (lm_context->static_values != 0) {
511 		lm_context->tx_param_dirty = 0;
512 
513 		if ((lm_context->serdes_obj->tx_advanced_params_set) == 0) {
514 			al_err("tx_advanced_params_set is not supported for this serdes group\n");
515 			return;
516 		}
517 
518 		if ((lm_context->retimer_exist == 0) &&
519 		    (lm_context->mode == AL_ETH_LM_MODE_10G_DA))
520 			lm_context->serdes_obj->tx_advanced_params_set(
521 						lm_context->serdes_obj,
522 						lm_context->lane,
523 						&da_tx_params);
524 		else
525 			lm_context->serdes_obj->tx_advanced_params_set(
526 						lm_context->serdes_obj,
527 						lm_context->lane,
528 						&optic_tx_params);
529 	}
530 }
531 
532 static void
533 al_eth_serdes_static_rx_params_set(struct al_eth_lm_context *lm_context)
534 {
535 
536 	if (lm_context->rx_param_dirty == 0)
537 		return;
538 
539 	if (lm_context->serdes_rx_params_valid != 0) {
540 		lm_context->rx_param_dirty = 0;
541 
542 		lm_context->rx_params_override.override = TRUE;
543 
544 		if ((lm_context->serdes_obj->rx_advanced_params_set) == 0) {
545 			al_err("rx_advanced_params_set is not supported for this serdes group\n");
546 			return;
547 		}
548 
549 		lm_context->serdes_obj->rx_advanced_params_set(
550 					lm_context->serdes_obj,
551 					lm_context->lane,
552 					&lm_context->rx_params_override);
553 
554 	} else if (lm_context->static_values != 0) {
555 		lm_context->rx_param_dirty = 0;
556 
557 		if ((lm_context->serdes_obj->rx_advanced_params_set) == 0) {
558 			al_err("rx_advanced_params_set is not supported for this serdes group\n");
559 			return;
560 		}
561 
562 		if ((lm_context->retimer_exist == 0) &&
563 		    (lm_context->mode == AL_ETH_LM_MODE_10G_DA))
564 			lm_context->serdes_obj->rx_advanced_params_set(
565 						lm_context->serdes_obj,
566 						lm_context->lane,
567 						&da_rx_params);
568 		else
569 			lm_context->serdes_obj->rx_advanced_params_set(
570 						lm_context->serdes_obj,
571 						lm_context->lane,
572 						&optic_rx_params);
573 	}
574 }
575 
576 static int
577 al_eth_rx_equal_run(struct al_eth_lm_context *lm_context)
578 {
579 	struct al_serdes_adv_rx_params rx_params;
580 	int dcgain;
581 	int best_dcgain = -1;
582 	int i;
583 	int best_score  = -1;
584 	int test_score = -1;
585 
586 	rx_params.override = FALSE;
587 	lm_context->serdes_obj->rx_advanced_params_set(lm_context->serdes_obj,
588 							lm_context->lane, &rx_params);
589 
590 	lm_debug("score | dcgain | dfe3db | dfegain | tap1 | tap2 | tap3 | "
591 	    "tap4 | low freq | high freq\n");
592 
593 	for (dcgain = 0; dcgain < AL_ETH_LM_MAX_DCGAIN; dcgain++) {
594 		lm_context->serdes_obj->dcgain_set(
595 					lm_context->serdes_obj,
596 					dcgain);
597 
598 		test_score = lm_context->serdes_obj->rx_equalization(
599 					lm_context->serdes_obj,
600 					lm_context->lane);
601 
602 		if (test_score < 0) {
603 			al_warn("serdes rx equalization failed on error\n");
604 			return (test_score);
605 		}
606 
607 		if (test_score > best_score) {
608 			best_score = test_score;
609 			best_dcgain = dcgain;
610 		}
611 
612 		lm_context->serdes_obj->rx_advanced_params_get(
613 					lm_context->serdes_obj,
614 					lm_context->lane,
615 					&rx_params);
616 
617 		lm_debug("%6d|%8x|%8x|%9x|%6x|%6x|%6x|%6x|%10x|%10x|\n",
618 		    test_score, rx_params.dcgain, rx_params.dfe_3db_freq,
619 		    rx_params.dfe_gain, rx_params.dfe_first_tap_ctrl,
620 		    rx_params.dfe_secound_tap_ctrl, rx_params.dfe_third_tap_ctrl,
621 		    rx_params.dfe_fourth_tap_ctrl, rx_params.low_freq_agc_gain,
622 		    rx_params.high_freq_agc_boost);
623 	}
624 
625 	lm_context->serdes_obj->dcgain_set(
626 					lm_context->serdes_obj,
627 					best_dcgain);
628 
629 	best_score = -1;
630 	for(i = 0; i < AL_ETH_LM_EQ_ITERATIONS; i++) {
631 		test_score = lm_context->serdes_obj->rx_equalization(
632 						lm_context->serdes_obj,
633 						lm_context->lane);
634 
635 		if (test_score < 0) {
636 			al_warn("serdes rx equalization failed on error\n");
637 			return (test_score);
638 		}
639 
640 		if (test_score > best_score) {
641 			best_score = test_score;
642 			lm_context->serdes_obj->rx_advanced_params_get(
643 						lm_context->serdes_obj,
644 						lm_context->lane,
645 						&rx_params);
646 		}
647 	}
648 
649 	rx_params.precal_code_sel = 0;
650 	rx_params.override = TRUE;
651 	lm_context->serdes_obj->rx_advanced_params_set(
652 					lm_context->serdes_obj,
653 					lm_context->lane,
654 					&rx_params);
655 
656 	lm_debug("-------------------- best dcgain %d ------------------------------------\n", best_dcgain);
657 	lm_debug("%6d|%8x|%8x|%9x|%6x|%6x|%6x|%6x|%10x|%10x|\n",
658 	    best_score, rx_params.dcgain, rx_params.dfe_3db_freq,
659 	    rx_params.dfe_gain, rx_params.dfe_first_tap_ctrl,
660 	    rx_params.dfe_secound_tap_ctrl, rx_params.dfe_third_tap_ctrl,
661 	    rx_params.dfe_fourth_tap_ctrl, rx_params.low_freq_agc_gain,
662 	    rx_params.high_freq_agc_boost);
663 
664 	return (0);
665 }
666 
667 static int al_eth_lm_retimer_boost_config(struct al_eth_lm_context *lm_context)
668 {
669 	int i;
670 	int rc = 0;
671 	uint8_t boost = 0;
672 	uint32_t boost_addr =
673 	    al_eth_retimer_boost_addr[lm_context->retimer_channel][lm_context->retimer_type];
674 
675 	if (lm_context->mode != AL_ETH_LM_MODE_10G_DA) {
676 		boost = al_eth_retimer_boost_value[0][lm_context->retimer_type];
677 	} else {
678 		for (i = 0; i < RETIMER_LENS_MAX; i++) {
679 			if (lm_context->da_len <= al_eth_retimer_boost_lens[i]) {
680 				boost = al_eth_retimer_boost_value[i][lm_context->retimer_type];
681 				break;
682 			}
683 		}
684 
685 		if (i == RETIMER_LENS_MAX)
686 			boost = al_eth_retimer_boost_value[RETIMER_LENS_MAX][lm_context->retimer_type];
687 	}
688 
689 	lm_debug("config retimer boost in channel %d (addr %x) to 0x%x\n",
690 	    lm_context->retimer_channel, boost_addr, boost);
691 
692 	rc = lm_context->i2c_write(lm_context->i2c_context,
693 	    lm_context->retimer_bus_id, lm_context->retimer_i2c_addr,
694 	    boost_addr, boost);
695 
696 	if (rc != 0) {
697 		al_err("%s: Error occurred (%d) while writing retimer "
698 		    "configuration (bus-id %x i2c-addr %x)\n",
699 		    __func__, rc, lm_context->retimer_bus_id,
700 		    lm_context->retimer_i2c_addr);
701 		return (rc);
702 	}
703 
704 	return (0);
705 }
706 
707 /*******************************************************************************
708  ************************** retimer DS25 ***************************************
709  ******************************************************************************/
710 #define LM_DS25_CHANNEL_EN_REG		0xff
711 #define LM_DS25_CHANNEL_EN_MASK		0x03
712 #define LM_DS25_CHANNEL_EN_VAL		0x01
713 
714 #define LM_DS25_CHANNEL_SEL_REG		0xfc
715 #define LM_DS25_CHANNEL_SEL_MASK	0xff
716 
717 #define LM_DS25_CDR_RESET_REG		0x0a
718 #define LM_DS25_CDR_RESET_MASK		0x0c
719 #define LM_DS25_CDR_RESET_ASSERT	0x0c
720 #define LM_DS25_CDR_RESET_RELEASE	0x00
721 
722 #define LM_DS25_SIGNAL_DETECT_REG	0x78
723 #define LM_DS25_SIGNAL_DETECT_MASK	0x20
724 
725 #define LM_DS25_CDR_LOCK_REG		0x78
726 #define LM_DS25_CDR_LOCK_MASK		0x10
727 
728 #define LM_DS25_DRV_PD_REG		0x15
729 #define LM_DS25_DRV_PD_MASK		0x08
730 
731 static int al_eth_lm_retimer_ds25_write_reg(struct al_eth_lm_context	*lm_context,
732 					    uint8_t			reg_addr,
733 					    uint8_t			reg_mask,
734 					    uint8_t			reg_value)
735 {
736 	uint8_t reg;
737 	int rc;
738 
739 	rc = lm_context->i2c_read(lm_context->i2c_context,
740 				  lm_context->retimer_bus_id,
741 				  lm_context->retimer_i2c_addr,
742 				  reg_addr,
743 				  &reg);
744 
745 	if (rc != 0)
746 		return (EIO);
747 
748 	reg &= ~(reg_mask);
749 	reg |= reg_value;
750 
751 	rc = lm_context->i2c_write(lm_context->i2c_context,
752 				   lm_context->retimer_bus_id,
753 				   lm_context->retimer_i2c_addr,
754 				   reg_addr,
755 				   reg);
756 
757 	if (rc != 0)
758 		return (EIO);
759 
760 	return (0);
761 }
762 
763 static int al_eth_lm_retimer_ds25_channel_select(struct al_eth_lm_context	*lm_context,
764 						 uint8_t			channel)
765 {
766 	int rc = 0;
767 
768 	/* Write to specific channel */
769 	rc = al_eth_lm_retimer_ds25_write_reg(lm_context,
770 					      LM_DS25_CHANNEL_EN_REG,
771 					      LM_DS25_CHANNEL_EN_MASK,
772 					      LM_DS25_CHANNEL_EN_VAL);
773 
774 	if (rc != 0)
775 		return (rc);
776 
777 	rc = al_eth_lm_retimer_ds25_write_reg(lm_context,
778 					      LM_DS25_CHANNEL_SEL_REG,
779 					      LM_DS25_CHANNEL_SEL_MASK,
780 					      (1 << channel));
781 
782 	return (rc);
783 }
784 
785 static int al_eth_lm_retimer_ds25_channel_config(struct al_eth_lm_context	*lm_context,
786 						 uint8_t			channel,
787 						 struct retimer_config_reg	*config,
788 						 uint8_t			config_size)
789 {
790 	uint8_t i;
791 	int rc;
792 
793 	rc = al_eth_lm_retimer_ds25_channel_select(lm_context, channel);
794 	if (rc != 0)
795 		goto config_error;
796 
797 	for (i = 0; i < config_size; i++) {
798 		rc = al_eth_lm_retimer_ds25_write_reg(lm_context,
799 						      config[i].addr,
800 						      config[i].mask,
801 						      config[i].value);
802 
803 		if (rc != 0)
804 			goto config_error;
805 	}
806 
807 	lm_debug("%s: retimer channel config done for channel %d\n", __func__, channel);
808 
809 	return (0);
810 
811 config_error:
812 	al_err("%s: failed to access to the retimer\n", __func__);
813 
814 	return (rc);
815 }
816 
817 static int al_eth_lm_retimer_ds25_cdr_reset(struct al_eth_lm_context *lm_context, uint32_t channel)
818 {
819 	int rc;
820 
821 	lm_debug("Perform CDR reset to channel %d\n", channel);
822 
823 	rc = al_eth_lm_retimer_ds25_channel_select(lm_context, channel);
824 	if (rc)
825 		goto config_error;
826 
827 	rc = al_eth_lm_retimer_ds25_write_reg(lm_context,
828 					      LM_DS25_CDR_RESET_REG,
829 					      LM_DS25_CDR_RESET_MASK,
830 					      LM_DS25_CDR_RESET_ASSERT);
831 
832 	if (rc)
833 		goto config_error;
834 
835 	rc = al_eth_lm_retimer_ds25_write_reg(lm_context,
836 					      LM_DS25_CDR_RESET_REG,
837 					      LM_DS25_CDR_RESET_MASK,
838 					      LM_DS25_CDR_RESET_RELEASE);
839 
840 	if (rc)
841 		goto config_error;
842 
843 	return 0;
844 
845 config_error:
846 	al_err("%s: failed to access to the retimer\n", __func__);
847 
848 	return rc;
849 }
850 
851 static boolean_t al_eth_lm_retimer_ds25_signal_detect(struct al_eth_lm_context *lm_context,
852 						    uint32_t channel)
853 {
854 	int rc = 0;
855 	uint8_t reg;
856 
857 	rc = al_eth_lm_retimer_ds25_channel_select(lm_context, channel);
858 	if (rc)
859 		goto config_error;
860 
861 	rc = lm_context->i2c_read(lm_context->i2c_context,
862 				  lm_context->retimer_bus_id,
863 				  lm_context->retimer_i2c_addr,
864 				  LM_DS25_SIGNAL_DETECT_REG,
865 				  &reg);
866 
867 	if (rc)
868 		goto config_error;
869 
870 	if (reg & LM_DS25_SIGNAL_DETECT_MASK)
871 		return TRUE;
872 
873 	return FALSE;
874 
875 config_error:
876 	al_err("%s: failed to access to the retimer\n", __func__);
877 
878 	return FALSE;
879 }
880 
881 static boolean_t al_eth_lm_retimer_ds25_cdr_lock(struct al_eth_lm_context *lm_context,
882 					       uint32_t channel)
883 {
884 	int rc = 0;
885 	uint8_t reg;
886 
887 	rc = al_eth_lm_retimer_ds25_channel_select(lm_context, channel);
888 	if (rc)
889 		goto config_error;
890 
891 	rc = lm_context->i2c_read(lm_context->i2c_context,
892 				  lm_context->retimer_bus_id,
893 				  lm_context->retimer_i2c_addr,
894 				  LM_DS25_CDR_LOCK_REG,
895 				  &reg);
896 
897 	if (rc)
898 		goto config_error;
899 
900 	if (reg & LM_DS25_CDR_LOCK_MASK)
901 		return TRUE;
902 
903 	return FALSE;
904 
905 config_error:
906 	al_err("%s: failed to access to the retimer\n", __func__);
907 
908 	return FALSE;
909 }
910 
911 static boolean_t al_eth_lm_wait_for_lock(struct al_eth_lm_context	*lm_context,
912 				       uint32_t			channel)
913 {
914 	uint32_t timeout = AL_ETH_LM_RETIMER_WAIT_FOR_LOCK;
915 	al_bool lock = AL_FALSE;
916 
917 	while ((timeout > 0) && (lock == FALSE)) {
918 		al_msleep(10);
919 		timeout -= 10;
920 
921 		lock = retimer[lm_context->retimer_type].cdr_lock(lm_context, channel);
922 	}
923 
924 	lm_debug("%s: %s to achieve CDR lock in %d msec\n",
925 		 __func__, (lock) ? "succeed" : "FAILED",
926 		 (AL_ETH_LM_RETIMER_WAIT_FOR_LOCK - timeout));
927 
928 	return lock;
929 }
930 
931 static void al_eth_lm_retimer_signal_lock_check(struct al_eth_lm_context	*lm_context,
932 						uint32_t			channel,
933 						boolean_t			*ready)
934 {
935 	al_bool signal_detect = TRUE;
936 	al_bool cdr_lock = TRUE;
937 
938 	if (retimer[lm_context->retimer_type].signal_detect) {
939 		if (!retimer[lm_context->retimer_type].signal_detect(lm_context, channel)) {
940 			lm_debug("no signal detected on retimer channel %d\n", channel);
941 
942 			signal_detect = AL_FALSE;
943 		} else {
944 			if (retimer[lm_context->retimer_type].cdr_lock) {
945 				cdr_lock = retimer[lm_context->retimer_type].cdr_lock(
946 									lm_context,
947 									channel);
948 				if (!cdr_lock) {
949 					if (retimer[lm_context->retimer_type].reset) {
950 						retimer[lm_context->retimer_type].reset(lm_context,
951 											channel);
952 
953 						cdr_lock = al_eth_lm_wait_for_lock(lm_context,
954 										   channel);
955 					}
956 				}
957 			}
958 		}
959 	}
960 
961 	al_info("%s: (channel %d) signal %d cdr lock %d\n",
962 		 __func__, channel, signal_detect, (signal_detect) ? cdr_lock : 0);
963 
964 	*ready = ((cdr_lock == TRUE) && (signal_detect == TRUE));
965 }
966 
967 static int al_eth_lm_retimer_ds25_full_config(struct al_eth_lm_context *lm_context)
968 {
969 	int rc = 0;
970 	al_bool ready;
971 	struct retimer_config_reg *config_tx;
972 	uint32_t config_tx_size;
973 	struct retimer_config_reg *config_rx;
974 	uint32_t config_rx_size;
975 
976 	if (lm_context->mode == AL_ETH_LM_MODE_25G) {
977 		config_tx = retimer_ds25_25g_mode_tx_ch;
978 		config_tx_size = AL_ARR_SIZE(retimer_ds25_25g_mode_tx_ch);
979 
980 		config_rx = retimer_ds25_25g_mode_rx_ch;
981 		config_rx_size = AL_ARR_SIZE(retimer_ds25_25g_mode_rx_ch);
982 
983 	} else {
984 		config_tx = retimer_ds25_10g_mode;
985 		config_tx_size = AL_ARR_SIZE(retimer_ds25_10g_mode);
986 
987 		config_rx = retimer_ds25_10g_mode;
988 		config_rx_size = AL_ARR_SIZE(retimer_ds25_10g_mode);
989 	}
990 
991 	rc = al_eth_lm_retimer_ds25_channel_config(lm_context,
992 					lm_context->retimer_channel,
993 					config_rx,
994 					config_rx_size);
995 
996 	if (rc)
997 		return rc;
998 
999 	rc = al_eth_lm_retimer_ds25_channel_config(lm_context,
1000 					lm_context->retimer_tx_channel,
1001 					config_tx,
1002 					config_tx_size);
1003 
1004 	if (rc)
1005 		return rc;
1006 
1007 	if (lm_context->serdes_obj->type_get() == AL_SRDS_TYPE_25G) {
1008 		lm_debug("%s: serdes 25G - perform tx and rx gearbox reset\n", __func__);
1009 		al_eth_gearbox_reset(lm_context->adapter, TRUE, TRUE);
1010 		DELAY(AL_ETH_LM_GEARBOX_RESET_DELAY);
1011 	}
1012 
1013 	al_eth_lm_retimer_signal_lock_check(lm_context, lm_context->retimer_tx_channel, &ready);
1014 
1015 	if (!ready) {
1016 		lm_debug("%s: Failed to lock tx channel!\n", __func__);
1017 		return (1);
1018 	}
1019 
1020 	lm_debug("%s: retimer full configuration done\n", __func__);
1021 
1022 	return rc;
1023 }
1024 
1025 static int al_eth_lm_retimer_25g_rx_adaptation(struct al_eth_lm_context *lm_context)
1026 {
1027 	int rc = 0;
1028 	al_bool ready;
1029 
1030 	al_eth_lm_retimer_signal_lock_check(lm_context, lm_context->retimer_channel, &ready);
1031 
1032 	if (!ready) {
1033 		lm_debug("%s: no signal detected on retimer Rx channel (%d)\n",
1034 			 __func__,  lm_context->retimer_channel);
1035 
1036 		return rc;
1037 	}
1038 
1039 	al_msleep(AL_ETH_LM_SERDES_WAIT_FOR_LOCK);
1040 
1041 	return 0;
1042 }
1043 
1044 static int al_eth_lm_check_for_link(struct al_eth_lm_context *lm_context, boolean_t *link_up)
1045 {
1046 	struct al_eth_link_status status;
1047 	int ret = 0;
1048 
1049 	al_eth_link_status_clear(lm_context->adapter);
1050 	al_eth_link_status_get(lm_context->adapter, &status);
1051 
1052 	if (status.link_up == AL_TRUE) {
1053 		lm_debug("%s: >>>> Link state DOWN ==> UP\n", __func__);
1054 		al_eth_led_set(lm_context->adapter, AL_TRUE);
1055 		lm_context->link_state = AL_ETH_LM_LINK_UP;
1056 		*link_up = AL_TRUE;
1057 
1058 		return 0;
1059 	} else if (status.local_fault) {
1060 		lm_context->link_state = AL_ETH_LM_LINK_DOWN;
1061 		al_eth_led_set(lm_context->adapter, AL_FALSE);
1062 
1063 		al_err("%s: Failed to establish link\n", __func__);
1064 		ret = 1;
1065 	} else {
1066 		lm_debug("%s: >>>> Link state DOWN ==> DOWN_RF\n", __func__);
1067 		lm_context->link_state = AL_ETH_LM_LINK_DOWN_RF;
1068 		al_eth_led_set(lm_context->adapter, AL_FALSE);
1069 
1070 		ret = 0;
1071 	}
1072 
1073 	*link_up = AL_FALSE;
1074 	return ret;
1075 }
1076 
1077 /*****************************************************************************/
1078 /***************************** API functions *********************************/
1079 /*****************************************************************************/
1080 int
1081 al_eth_lm_init(struct al_eth_lm_context	*lm_context,
1082     struct al_eth_lm_init_params *params)
1083 {
1084 
1085 	lm_context->adapter = params->adapter;
1086 	lm_context->serdes_obj = params->serdes_obj;
1087 	lm_context->lane = params->lane;
1088 	lm_context->sfp_detection = params->sfp_detection;
1089 	lm_context->sfp_bus_id = params->sfp_bus_id;
1090 	lm_context->sfp_i2c_addr = params->sfp_i2c_addr;
1091 
1092 	lm_context->retimer_exist = params->retimer_exist;
1093 	lm_context->retimer_type = params->retimer_type;
1094 	lm_context->retimer_bus_id = params->retimer_bus_id;
1095 	lm_context->retimer_i2c_addr = params->retimer_i2c_addr;
1096 	lm_context->retimer_channel = params->retimer_channel;
1097 	lm_context->retimer_tx_channel = params->retimer_tx_channel;
1098 
1099 	lm_context->default_mode = params->default_mode;
1100 	lm_context->default_dac_len = params->default_dac_len;
1101 	lm_context->link_training = params->link_training;
1102 	lm_context->rx_equal = params->rx_equal;
1103 	lm_context->static_values = params->static_values;
1104 	lm_context->i2c_read = params->i2c_read;
1105 	lm_context->i2c_write = params->i2c_write;
1106 	lm_context->i2c_context = params->i2c_context;
1107 	lm_context->get_random_byte = params->get_random_byte;
1108 
1109 	/* eeprom_read must be provided if sfp_detection is true */
1110 	al_assert((lm_context->sfp_detection == FALSE) ||
1111 	    (lm_context->i2c_read != NULL));
1112 
1113 	al_assert((lm_context->retimer_exist == FALSE) ||
1114 	    (lm_context->i2c_write != NULL));
1115 
1116 	lm_context->local_adv.selector_field = 1;
1117 	lm_context->local_adv.capability = 0;
1118 	lm_context->local_adv.remote_fault = 0;
1119 	lm_context->local_adv.acknowledge = 0;
1120 	lm_context->local_adv.next_page = 0;
1121 	lm_context->local_adv.technology = AL_ETH_AN_TECH_10GBASE_KR;
1122 	lm_context->local_adv.fec_capability = params->kr_fec_enable;
1123 
1124 	lm_context->mode = AL_ETH_LM_MODE_DISCONNECTED;
1125 	lm_context->serdes_tx_params_valid = FALSE;
1126 	lm_context->serdes_rx_params_valid = FALSE;
1127 
1128 	lm_context->rx_param_dirty = 1;
1129 	lm_context->tx_param_dirty = 1;
1130 
1131 	lm_context->gpio_get = params->gpio_get;
1132 	lm_context->gpio_present = params->gpio_present;
1133 
1134 	lm_context->max_speed = params->max_speed;
1135 	lm_context->sfp_detect_force_mode = params->sfp_detect_force_mode;
1136 
1137 	lm_context->lm_pause = params->lm_pause;
1138 
1139 	lm_context->led_config = params->led_config;
1140 
1141 	lm_context->retimer_configured = FALSE;
1142 
1143 	lm_context->link_state = AL_ETH_LM_LINK_DOWN;
1144 
1145 	return (0);
1146 }
1147 
1148 int
1149 al_eth_lm_link_detection(struct al_eth_lm_context *lm_context,
1150     boolean_t *link_fault, enum al_eth_lm_link_mode *old_mode,
1151     enum al_eth_lm_link_mode *new_mode)
1152 {
1153 	int err;
1154 	struct al_eth_link_status status;
1155 
1156 	al_assert(lm_context != NULL);
1157 	al_assert(old_mode != NULL);
1158 	al_assert(new_mode != NULL);
1159 
1160 	/**
1161 	 * if Link management is disabled, report no link fault in case the link was up
1162 	 * before and set new mode to disconnected to avoid calling to link establish
1163 	 * if the link wasn't up.
1164 	 */
1165 	if (lm_context->lm_pause != NULL) {
1166 		boolean_t lm_pause = lm_context->lm_pause(lm_context->i2c_context);
1167 		if (lm_pause == TRUE) {
1168 			*new_mode = AL_ETH_LM_MODE_DISCONNECTED;
1169 			if (link_fault != NULL) {
1170 				if (lm_context->link_state == AL_ETH_LM_LINK_UP)
1171 					*link_fault = FALSE;
1172 				else
1173 					*link_fault = TRUE;
1174 			}
1175 
1176 			return 0;
1177 		}
1178 	}
1179 
1180 	*old_mode = lm_context->mode;
1181 	*new_mode = lm_context->mode;
1182 
1183 	if (link_fault != NULL)
1184 		*link_fault = TRUE;
1185 
1186 	switch (lm_context->link_state) {
1187 	case AL_ETH_LM_LINK_UP:
1188 		al_eth_link_status_get(lm_context->adapter, &status);
1189 
1190 		if (status.link_up) {
1191 			if (link_fault != NULL)
1192 				*link_fault = FALSE;
1193 
1194 			al_eth_led_set(lm_context->adapter, TRUE);
1195 
1196 			return (0);
1197 		} else if (status.local_fault) {
1198 			lm_debug("%s: >>>> Link state UP ==> DOWN\n", __func__);
1199 			lm_context->link_state = AL_ETH_LM_LINK_DOWN;
1200 		} else {
1201 			lm_debug("%s: >>>> Link state UP ==> DOWN_RF\n", __func__);
1202 			lm_context->link_state = AL_ETH_LM_LINK_DOWN_RF;
1203 		}
1204 
1205 		break;
1206 	case AL_ETH_LM_LINK_DOWN_RF:
1207 		al_eth_link_status_get(lm_context->adapter, &status);
1208 
1209 		if (status.local_fault) {
1210 			lm_debug("%s: >>>> Link state DOWN_RF ==> DOWN\n", __func__);
1211 			lm_context->link_state = AL_ETH_LM_LINK_DOWN;
1212 
1213 			break;
1214 		} else if (status.remote_fault == FALSE) {
1215 			lm_debug("%s: >>>> Link state DOWN_RF ==> UP\n", __func__);
1216 			lm_context->link_state = AL_ETH_LM_LINK_UP;
1217 		}
1218 		/* in case of remote fault only no need to check SFP again */
1219 		return (0);
1220 	case AL_ETH_LM_LINK_DOWN:
1221 		break;
1222 	};
1223 
1224 	al_eth_led_set(lm_context->adapter, FALSE);
1225 
1226 	if (lm_context->sfp_detection) {
1227 		err = al_eth_module_detect(lm_context, new_mode);
1228 		if (err != 0) {
1229 			al_err("module_detection failed!\n");
1230 			return (err);
1231 		}
1232 
1233 		lm_context->mode = *new_mode;
1234 	} else {
1235 		lm_context->mode = lm_context->default_mode;
1236 		*new_mode = lm_context->mode;
1237 	}
1238 
1239 	if (*old_mode != *new_mode) {
1240 		al_info("%s: New SFP mode detected %s -> %s\n",
1241 		    __func__, al_eth_lm_mode_convert_to_str(*old_mode),
1242 		    al_eth_lm_mode_convert_to_str(*new_mode));
1243 
1244 		lm_context->rx_param_dirty = 1;
1245 		lm_context->tx_param_dirty = 1;
1246 
1247 		lm_context->new_port = TRUE;
1248 
1249 		if ((*new_mode != AL_ETH_LM_MODE_DISCONNECTED) && (lm_context->led_config)) {
1250 			struct al_eth_lm_led_config_data data = {0};
1251 
1252 			switch (*new_mode) {
1253 			case AL_ETH_LM_MODE_10G_OPTIC:
1254 			case AL_ETH_LM_MODE_10G_DA:
1255 				data.speed = AL_ETH_LM_LED_CONFIG_10G;
1256 				break;
1257 			case AL_ETH_LM_MODE_1G:
1258 				data.speed = AL_ETH_LM_LED_CONFIG_1G;
1259 				break;
1260 			case AL_ETH_LM_MODE_25G:
1261 				data.speed = AL_ETH_LM_LED_CONFIG_25G;
1262 				break;
1263 			default:
1264 				al_err("%s: unknown LM mode!\n", __func__);
1265 			};
1266 
1267 			lm_context->led_config(lm_context->i2c_context, &data);
1268 		}
1269 	}
1270 
1271 	return (0);
1272 }
1273 
1274 int
1275 al_eth_lm_link_establish(struct al_eth_lm_context *lm_context, boolean_t *link_up)
1276 {
1277 	boolean_t signal_detected;
1278 	int ret = 0;
1279 
1280 	switch (lm_context->link_state) {
1281 	case AL_ETH_LM_LINK_UP:
1282 		*link_up = TRUE;
1283 		lm_debug("%s: return link up\n", __func__);
1284 
1285 		return (0);
1286 	case AL_ETH_LM_LINK_DOWN_RF:
1287 		*link_up = FALSE;
1288 		lm_debug("%s: return link down (DOWN_RF)\n", __func__);
1289 
1290 		return (0);
1291 	case AL_ETH_LM_LINK_DOWN:
1292 		break;
1293 	};
1294 
1295 	/**
1296 	 * At this point we will get LM disable only if changed to disable after link detection
1297 	 * finished. in this case link will not be established until LM will be enable again.
1298 	 */
1299 	if (lm_context->lm_pause) {
1300 		boolean_t lm_pause = lm_context->lm_pause(lm_context->i2c_context);
1301 		if (lm_pause == TRUE) {
1302 			*link_up = FALSE;
1303 
1304 			return (0);
1305 		}
1306 	}
1307 
1308 	if ((lm_context->new_port) && (lm_context->retimer_exist)) {
1309 		al_eth_serdes_static_rx_params_set(lm_context);
1310 		al_eth_serdes_static_tx_params_set(lm_context);
1311 #if 0
1312 		al_eth_lm_retimer_config(lm_context);
1313 		DELAY(AL_ETH_LM_RETIMER_LINK_STATUS_DELAY);
1314 #endif
1315 
1316 		if (retimer[lm_context->retimer_type].config(lm_context)) {
1317 			al_info("%s: failed to configure the retimer\n", __func__);
1318 
1319 			*link_up = FALSE;
1320 			return (1);
1321 		}
1322 
1323 		lm_context->new_port = FALSE;
1324 
1325 		DELAY(1000);
1326 	}
1327 
1328 	if (lm_context->retimer_exist) {
1329 		if (retimer[lm_context->retimer_type].rx_adaptation) {
1330 			ret = retimer[lm_context->retimer_type].rx_adaptation(lm_context);
1331 
1332 			if (ret != 0) {
1333 				lm_debug("retimer rx is not ready\n");
1334 				*link_up = FALSE;
1335 
1336 				return (0);
1337 			}
1338 		}
1339 	}
1340 
1341 	signal_detected = lm_context->serdes_obj->signal_is_detected(
1342 					lm_context->serdes_obj,
1343 					lm_context->lane);
1344 
1345 	if (signal_detected == FALSE) {
1346 		/* if no signal detected there is nothing to do */
1347 		lm_debug("serdes signal is down\n");
1348 		*link_up = AL_FALSE;
1349 		return 0;
1350 	}
1351 
1352 	if (lm_context->serdes_obj->type_get() == AL_SRDS_TYPE_25G) {
1353 		lm_debug("%s: serdes 25G - perform rx gearbox reset\n", __func__);
1354 		al_eth_gearbox_reset(lm_context->adapter, FALSE, TRUE);
1355 		DELAY(AL_ETH_LM_GEARBOX_RESET_DELAY);
1356 	}
1357 
1358 	if (lm_context->retimer_exist) {
1359 		DELAY(AL_ETH_LM_RETIMER_LINK_STATUS_DELAY);
1360 
1361 		ret = al_eth_lm_check_for_link(lm_context, link_up);
1362 
1363 		if (ret == 0) {
1364 			lm_debug("%s: link is up with retimer\n", __func__);
1365 			return 0;
1366 		}
1367 
1368 		return ret;
1369 	}
1370 
1371 	if ((lm_context->mode == AL_ETH_LM_MODE_10G_DA) && (lm_context->link_training)) {
1372 		lm_context->local_adv.transmitted_nonce = lm_context->get_random_byte();
1373 		lm_context->local_adv.transmitted_nonce &= 0x1f;
1374 
1375 		ret = al_eth_an_lt_execute(lm_context->adapter,
1376 					   lm_context->serdes_obj,
1377 					   lm_context->lane,
1378 					   &lm_context->local_adv,
1379 					   &lm_context->partner_adv);
1380 
1381 		lm_context->rx_param_dirty = 1;
1382 		lm_context->tx_param_dirty = 1;
1383 
1384 		if (ret == 0) {
1385 			al_info("%s: link training finished successfully\n", __func__);
1386 			lm_context->link_training_failures = 0;
1387 			ret = al_eth_lm_check_for_link(lm_context, link_up);
1388 
1389 			if (ret == 0) {
1390 				lm_debug("%s: link is up with LT\n", __func__);
1391 				return (0);
1392 			}
1393 		}
1394 
1395 		lm_context->link_training_failures++;
1396 		if (lm_context->link_training_failures > AL_ETH_LT_FAILURES_TO_RESET) {
1397 			lm_debug("%s: failed to establish LT %d times. reset serdes\n",
1398 				 __func__, AL_ETH_LT_FAILURES_TO_RESET);
1399 
1400 			lm_context->serdes_obj->pma_hard_reset_lane(
1401 						lm_context->serdes_obj,
1402 						lm_context->lane,
1403 						TRUE);
1404 			lm_context->serdes_obj->pma_hard_reset_lane(
1405 						lm_context->serdes_obj,
1406 						lm_context->lane,
1407 						FALSE);
1408 			lm_context->link_training_failures = 0;
1409 		}
1410 	}
1411 
1412 	al_eth_serdes_static_tx_params_set(lm_context);
1413 
1414 	if ((lm_context->mode == AL_ETH_LM_MODE_10G_DA) &&
1415 	    (lm_context->rx_equal)) {
1416 		ret = al_eth_rx_equal_run(lm_context);
1417 
1418 		if (ret == 0) {
1419 			DELAY(AL_ETH_LM_LINK_STATUS_DELAY);
1420 			ret = al_eth_lm_check_for_link(lm_context, link_up);
1421 
1422 			if (ret == 0) {
1423 				lm_debug("%s: link is up with Rx Equalization\n", __func__);
1424 				return (0);
1425 			}
1426 		}
1427 	}
1428 
1429 	al_eth_serdes_static_rx_params_set(lm_context);
1430 
1431 	DELAY(AL_ETH_LM_LINK_STATUS_DELAY);
1432 
1433 	ret = al_eth_lm_check_for_link(lm_context, link_up);
1434 
1435 	if (ret == 0) {
1436 		lm_debug("%s: link is up with static parameters\n", __func__);
1437 		return (0);
1438 	}
1439 
1440 	*link_up = FALSE;
1441 	return (1);
1442 }
1443 
1444 int
1445 al_eth_lm_static_parameters_override(struct al_eth_lm_context *lm_context,
1446     struct al_serdes_adv_tx_params *tx_params,
1447     struct al_serdes_adv_rx_params *rx_params)
1448 {
1449 
1450 	if (tx_params != NULL) {
1451 		lm_context->tx_params_override = *tx_params;
1452 		lm_context->tx_param_dirty = 1;
1453 		lm_context->serdes_tx_params_valid = TRUE;
1454 	}
1455 
1456 	if (rx_params != NULL) {
1457 		lm_context->rx_params_override = *rx_params;
1458 		lm_context->rx_param_dirty = 1;
1459 		lm_context->serdes_rx_params_valid = TRUE;
1460 	}
1461 
1462 	return (0);
1463 }
1464 
1465 int
1466 al_eth_lm_static_parameters_override_disable(struct al_eth_lm_context *lm_context,
1467     boolean_t tx_params, boolean_t rx_params)
1468 {
1469 
1470 	if (tx_params != 0)
1471 		lm_context->serdes_tx_params_valid = FALSE;
1472 	if (rx_params != 0)
1473 		lm_context->serdes_tx_params_valid = FALSE;
1474 
1475 	return (0);
1476 }
1477 
1478 int
1479 al_eth_lm_static_parameters_get(struct al_eth_lm_context *lm_context,
1480     struct al_serdes_adv_tx_params *tx_params,
1481     struct al_serdes_adv_rx_params *rx_params)
1482 {
1483 
1484 	if (tx_params != NULL) {
1485 		if (lm_context->serdes_tx_params_valid)
1486 			*tx_params = lm_context->tx_params_override;
1487 		else
1488 			lm_context->serdes_obj->tx_advanced_params_get(
1489 							lm_context->serdes_obj,
1490 							lm_context->lane,
1491 							tx_params);
1492 	}
1493 
1494 	if (rx_params != NULL) {
1495 		if (lm_context->serdes_rx_params_valid)
1496 			*rx_params = lm_context->rx_params_override;
1497 		else
1498 			lm_context->serdes_obj->rx_advanced_params_get(
1499 							lm_context->serdes_obj,
1500 							lm_context->lane,
1501 							rx_params);
1502 	}
1503 
1504 	return (0);
1505 }
1506 
1507 const char *
1508 al_eth_lm_mode_convert_to_str(enum al_eth_lm_link_mode val)
1509 {
1510 
1511 	switch (val) {
1512 	case AL_ETH_LM_MODE_DISCONNECTED:
1513 		return ("AL_ETH_LM_MODE_DISCONNECTED");
1514 	case AL_ETH_LM_MODE_10G_OPTIC:
1515 		return ("AL_ETH_LM_MODE_10G_OPTIC");
1516 	case AL_ETH_LM_MODE_10G_DA:
1517 		return ("AL_ETH_LM_MODE_10G_DA");
1518 	case AL_ETH_LM_MODE_1G:
1519 		return ("AL_ETH_LM_MODE_1G");
1520 	case AL_ETH_LM_MODE_25G:
1521 		return ("AL_ETH_LM_MODE_25G");
1522 	}
1523 
1524 	return ("N/A");
1525 }
1526 
1527 void
1528 al_eth_lm_debug_mode_set(struct al_eth_lm_context *lm_context,
1529     boolean_t enable)
1530 {
1531 
1532 	lm_context->debug = enable;
1533 }
1534