1 /*******************************************************************************
2 Copyright (C) 2015 Annapurna Labs Ltd.
3 
4 This file may be licensed under the terms of the Annapurna Labs Commercial
5 License Agreement.
6 
7 Alternatively, this file can be distributed under the terms of the GNU General
8 Public License V2 as published by the Free Software Foundation and can be
9 found at http://www.gnu.org/licenses/gpl-2.0.html
10 
11 Alternatively, redistribution and use in source and binary forms, with or
12 without modification, are permitted provided that the following conditions are
13 met:
14 
15     *     Redistributions of source code must retain the above copyright notice,
16 this list of conditions and the following disclaimer.
17 
18     *     Redistributions in binary form must reproduce the above copyright
19 notice, this list of conditions and the following disclaimer in
20 the documentation and/or other materials provided with the
21 distribution.
22 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
27 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34 *******************************************************************************/
35 
36 #include "al_hal_serdes_25g.h"
37 #include "al_hal_serdes_25g_regs.h"
38 #include "al_hal_serdes_25g_internal_regs.h"
39 
40 #define AL_SERDES_MB_MAX_DATA_LEN		8
41 
42 #define AL_SERDES_25G_WAIT_FOR_READY_TO		200
43 #define AL_SERDES_25G_RESET_TO			100
44 #define AL_SERDES_25G_RESET_NUM_RETRIES		5
45 
46 #if (!defined(AL_SERDES_BASIC_SERVICES_ONLY)) || (AL_SERDES_BASIC_SERVICES_ONLY == 0)
47 #define AL_SRDS_ADV_SRVC(func)			func
48 #else
49 static void al_serdes_hssp_stub_func(void)
50 {
51 	al_err("%s: not implemented service called!\n", __func__);
52 }
53 
54 #define AL_SRDS_ADV_SRVC(func)			((typeof(func) *)al_serdes_hssp_stub_func)
55 #endif
56 
57 /******************************************************************************/
58 /******************************************************************************/
59 static enum al_serdes_type al_serdes_25g_type_get(void)
60 {
61 	return AL_SRDS_TYPE_25G;
62 }
63 
64 /******************************************************************************/
65 /******************************************************************************/
66 static int al_serdes_25g_reg_read(
67 	struct al_serdes_grp_obj	*obj,
68 	enum al_serdes_reg_page		page,
69 	enum al_serdes_reg_type		type,
70 	uint16_t			offset,
71 	uint8_t				*data)
72 {
73 	struct al_serdes_c_regs __iomem	*regs_base = obj->regs_base;
74 	uint32_t addr = 0;
75 
76 	al_dbg("%s(%p, %d, %d, %u)\n", __func__, obj, page, type, offset);
77 
78 	al_assert(obj);
79 	al_assert(data);
80 
81 	switch (page) {
82 	case AL_SRDS_REG_PAGE_TOP:
83 		addr = (SERDES_25G_TOP_BASE + offset);
84 		break;
85 	case AL_SRDS_REG_PAGE_4_COMMON:
86 		addr = (SERDES_25G_CM_BASE + offset);
87 		break;
88 	case AL_SRDS_REG_PAGE_0_LANE_0:
89 	case AL_SRDS_REG_PAGE_1_LANE_1:
90 		addr = (SERDES_25G_LANE_BASE + (page * SERDES_25G_LANE_SIZE) + offset);
91 		break;
92 	default:
93 		al_err("%s: wrong serdes type %d\n", __func__, type);
94 		return -1;
95 	}
96 
97 	al_reg_write32(&regs_base->gen.reg_addr, addr);
98 	*data = al_reg_read32(&regs_base->gen.reg_data);
99 
100 	al_dbg("%s: return(%u)\n", __func__, *data);
101 
102 	return 0;
103 }
104 
105 static int al_serdes_25g_reg_write(
106 	struct al_serdes_grp_obj	*obj,
107 	enum al_serdes_reg_page		page,
108 	enum al_serdes_reg_type		type,
109 	uint16_t			offset,
110 	uint8_t				data)
111 {
112 	struct al_serdes_c_regs __iomem	*regs_base = obj->regs_base;
113 	uint32_t addr = 0;
114 
115 	al_dbg("%s(%p, %d, %d, %u)\n", __func__, obj, page, type, offset);
116 
117 	al_assert(obj);
118 
119 	switch (page) {
120 	case AL_SRDS_REG_PAGE_TOP:
121 		addr = (SERDES_25G_TOP_BASE + offset);
122 		break;
123 	case AL_SRDS_REG_PAGE_4_COMMON:
124 		addr = (SERDES_25G_CM_BASE + offset);
125 		break;
126 	case AL_SRDS_REG_PAGE_0_LANE_0:
127 	case AL_SRDS_REG_PAGE_1_LANE_1:
128 		addr = (SERDES_25G_LANE_BASE + (page * SERDES_25G_LANE_SIZE) + offset);
129 		break;
130 	default:
131 		al_err("%s: wrong serdes type %d\n", __func__, type);
132 		return -1;
133 	}
134 
135 	al_reg_write32(&regs_base->gen.reg_addr, addr);
136 	al_reg_write32(&regs_base->gen.reg_data, (data | SERDES_C_GEN_REG_DATA_STRB_MASK));
137 
138 	al_dbg("%s: write(%u)\n", __func__, data);
139 
140 	return 0;
141 }
142 
143 /******************************************************************************/
144 /******************************************************************************/
145 static int al_serdes_25g_reg_masked_read(
146 	struct al_serdes_grp_obj	*obj,
147 	enum al_serdes_reg_page		page,
148 	uint16_t			offset,
149 	uint8_t				mask,
150 	uint8_t				shift,
151 	uint8_t				*data)
152 {
153 	uint8_t val;
154 	int status = 0;
155 
156 	status = al_serdes_25g_reg_read(obj, page, 0, offset, &val);
157 	if (status)
158 		return status;
159 
160 	*data = AL_REG_FIELD_GET(val, mask, shift);
161 
162 	return 0;
163 }
164 
165 static int al_serdes_25g_reg_masked_write(
166 	struct al_serdes_grp_obj	*obj,
167 	enum al_serdes_reg_page		page,
168 	uint16_t			offset,
169 	uint8_t				mask,
170 	uint8_t				shift,
171 	uint8_t				data)
172 {
173 	uint8_t val;
174 	int status = 0;
175 
176 	status = al_serdes_25g_reg_read(obj, page, 0, offset, &val);
177 	if (status)
178 		return status;
179 
180 	val &= (~mask);
181 	val |= (data << shift);
182 	return al_serdes_25g_reg_write(obj, page, 0, offset, val);
183 }
184 
185 /******************************************************************************/
186 /******************************************************************************/
187 #define SERDES_25G_MB_RESP_BYTES	16
188 #define SERDES_25G_MB_TIMEOUT		5000000 /* uSec */
189 
190 static int al_serdes_25g_mailbox_send_cmd(
191 	struct al_serdes_grp_obj	*obj,
192 	uint8_t				cmd,
193 	uint8_t				*data,
194 	uint8_t				data_len)
195 {
196 	uint8_t val;
197 	int i;
198 	uint32_t timeout = SERDES_25G_MB_TIMEOUT;
199 
200 	if (data_len > AL_SERDES_MB_MAX_DATA_LEN) {
201 		al_err("Cannot send command, data too long\n");
202 		return -1;
203 	}
204 
205 	/* Wait for CMD_FLAG to clear */
206 	while(1) {
207 		al_serdes_25g_reg_read(obj, AL_SRDS_REG_PAGE_TOP, 0,
208 				       SERDES_25G_TOP_CMD_FLAG_ADDR, &val);
209 		if (val == 0)
210 			break;
211 
212 		if (timeout == 0) {
213 			al_err("%s: timeout occurred waiting to CMD_FLAG\n", __func__);
214 			return -1;
215 		}
216 
217 		timeout--;
218 		al_udelay(1);
219 	}
220 
221 	for (i = 0; i < data_len; i++) {
222 		al_serdes_25g_reg_write(obj, AL_SRDS_REG_PAGE_TOP, 0,
223 					(SERDES_25G_TOP_CMD_DATA0_ADDR + i), data[i]);
224 	}
225 
226 	/* this write will set CMD_FLAG automatically */
227 	al_serdes_25g_reg_write(obj, AL_SRDS_REG_PAGE_TOP, 0, SERDES_25G_TOP_CMD_ADDR, cmd);
228 
229 	return 0;
230 }
231 
232 static int al_serdes_25g_mailbox_recv_rsp(
233 	struct al_serdes_grp_obj	*obj,
234 	uint8_t				*rsp_code,
235 	uint8_t				*data,
236 	uint8_t				*data_len)
237 {
238 	uint8_t val;
239 	int i;
240 	uint32_t timeout = SERDES_25G_MB_TIMEOUT;
241 
242 	/* wait for RSP_FLAG to set */
243 	while(1) {
244 		al_serdes_25g_reg_read(obj, AL_SRDS_REG_PAGE_TOP, 0,
245 				       SERDES_25G_TOP_RSP_FLAG_ADDR, &val);
246 		if (val == 0x1)
247 			break;
248 
249 		if (timeout == 0) {
250 			al_err("%s: timeout occurred waiting to RSP_FLAG\n", __func__);
251 			*data_len = 0;
252 			return -1;
253 		}
254 
255 		timeout--;
256 		al_udelay(1);
257 	}
258 
259 	/* Grab the response code and data */
260 	al_serdes_25g_reg_read(obj, AL_SRDS_REG_PAGE_TOP, 0,
261 				SERDES_25G_TOP_RSP_ADDR, rsp_code);
262 
263 	for (i = 0; i < SERDES_25G_MB_RESP_BYTES; i++) {
264 		al_serdes_25g_reg_read(obj, AL_SRDS_REG_PAGE_TOP, 0,
265 				(SERDES_25G_TOP_RSP_DATA0_ADDR + i), &data[i]);
266 	}
267 
268 	/* clear the RSP_FLAG (write 1 to clear) */
269 	al_serdes_25g_reg_write(obj, AL_SRDS_REG_PAGE_TOP, 0,
270 				SERDES_25G_TOP_RSP_FLAG_ADDR, 0x1);
271 
272 	*data_len = SERDES_25G_MB_RESP_BYTES;
273 
274 	return 0;
275 }
276 
277 /******************************************************************************/
278 /******************************************************************************/
279 static void al_serdes_25g_bist_rx_enable(
280 	struct al_serdes_grp_obj	*obj,
281 	enum al_serdes_lane		lane,
282 	al_bool				enable)
283 {
284 	if (enable) {
285 		switch (lane) {
286 		case 0:
287 			al_serdes_25g_reg_masked_write(
288 					obj,
289 					AL_SRDS_REG_PAGE_TOP,
290 					SERDES_25G_TOP_CLOCK_LN0_CLK_RX_ADDR,
291 					SERDES_25G_TOP_CLOCK_LN0_CLK_RX_CTRL_CG_EN_MASK,
292 					SERDES_25G_TOP_CLOCK_LN0_CLK_RX_CTRL_CG_EN_SHIFT,
293 					0x1);
294 			al_serdes_25g_reg_masked_write(
295 					obj,
296 					AL_SRDS_REG_PAGE_TOP,
297 					SERDES_25G_TOP_CLOCK_LN0_CLK_RX_ADDR,
298 					SERDES_25G_TOP_CLOCK_LN0_CLK_RX_CTRL_BIST_CG_EN_MASK,
299 					SERDES_25G_TOP_CLOCK_LN0_CLK_RX_CTRL_BIST_CG_EN_SHIFT,
300 					0x1);
301 			break;
302 		case 1:
303 			al_serdes_25g_reg_masked_write(
304 					obj,
305 					AL_SRDS_REG_PAGE_TOP,
306 					SERDES_25G_TOP_CLOCK_LN1_CLK_RX_ADDR,
307 					SERDES_25G_TOP_CLOCK_LN1_CLK_RX_CTRL_CG_EN_MASK,
308 					SERDES_25G_TOP_CLOCK_LN1_CLK_RX_CTRL_CG_EN_SHIFT,
309 					0x1);
310 
311 			al_serdes_25g_reg_masked_write(
312 					obj,
313 					AL_SRDS_REG_PAGE_TOP,
314 					SERDES_25G_TOP_CLOCK_LN1_CLK_RX_ADDR,
315 					SERDES_25G_TOP_CLOCK_LN1_CLK_RX_CTRL_BIST_CG_EN_MASK,
316 					SERDES_25G_TOP_CLOCK_LN1_CLK_RX_CTRL_BIST_CG_EN_SHIFT,
317 					0x1);
318 			break;
319 		default:
320 			al_err("%s: Wrong serdes lane %d\n", __func__, lane);
321 			return;
322 		}
323 
324 		al_serdes_25g_reg_masked_write(
325 				obj,
326 				(enum al_serdes_reg_page)lane,
327 				SERDES_25G_LANE_RX_BIST_LOSS_LOCK_CTRL4_ADDR,
328 				SERDES_25G_LANE_RX_BIST_LOSS_LOCK_CTRL4_STOP_ON_LOSS_LOCK_MASK,
329 				SERDES_25G_LANE_RX_BIST_LOSS_LOCK_CTRL4_STOP_ON_LOSS_LOCK_SHIFT,
330 				0);
331 		al_serdes_25g_reg_masked_write(
332 				obj,
333 				(enum al_serdes_reg_page)lane,
334 				SERDES_25G_LANE_RX_BIST_CTRL_ADDR,
335 				SERDES_25G_LANE_RX_BIST_CTRL_EN_MASK,
336 				SERDES_25G_LANE_RX_BIST_CTRL_EN_SHIFT,
337 				1);
338 		al_serdes_25g_reg_masked_write(
339 				obj,
340 				(enum al_serdes_reg_page)lane,
341 				SERDES_25G_LANE_RX_BIST_CTRL_ADDR,
342 				SERDES_25G_LANE_RX_BIST_CTRL_PATTERN_SEL_MASK,
343 				SERDES_25G_LANE_RX_BIST_CTRL_PATTERN_SEL_SHIFT,
344 				6);
345 	} else {
346 		/* clear counters */
347 		al_serdes_25g_reg_masked_write(
348 					obj,
349 					(enum al_serdes_reg_page)lane,
350 					SERDES_25G_LANE_RX_BIST_CTRL_ADDR,
351 					SERDES_25G_LANE_RX_BIST_CTRL_CLEAR_BER_MASK,
352 					SERDES_25G_LANE_RX_BIST_CTRL_CLEAR_BER_SHIFT,
353 					1);
354 
355 		al_serdes_25g_reg_masked_write(
356 					obj,
357 					(enum al_serdes_reg_page)lane,
358 					SERDES_25G_LANE_RX_BIST_CTRL_ADDR,
359 					SERDES_25G_LANE_RX_BIST_CTRL_CLEAR_BER_MASK,
360 					SERDES_25G_LANE_RX_BIST_CTRL_CLEAR_BER_SHIFT,
361 					0);
362 
363 		al_msleep(AL_SERDES_25G_WAIT_FOR_READY_TO);
364 
365 		/* disable */
366 		al_serdes_25g_reg_masked_write(
367 				obj,
368 				(enum al_serdes_reg_page)lane,
369 				SERDES_25G_LANE_RX_BIST_CTRL_ADDR,
370 				SERDES_25G_LANE_RX_BIST_CTRL_EN_MASK,
371 				SERDES_25G_LANE_RX_BIST_CTRL_EN_SHIFT,
372 				0);
373 	}
374 }
375 
376 // TODO: [Guy] change API to be per lane.
377 static void al_serdes_25g_bist_pattern_select(
378 	struct al_serdes_grp_obj	*obj,
379 	enum al_serdes_bist_pattern	pattern,
380 	uint8_t				*user_data)
381 {
382 	enum al_serdes_lane lane;
383 	uint8_t val = 0;
384 
385 	switch (pattern) {
386 	case AL_SRDS_BIST_PATTERN_USER:
387 		al_assert(user_data);
388 		val = SERDES_25G_LANE_TX_BIST_CTRL_PATTERN_PRBS_USER;
389 		break;
390 	case AL_SRDS_BIST_PATTERN_PRBS7:
391 		val = SERDES_25G_LANE_TX_BIST_CTRL_PATTERN_PRBS7;
392 		break;
393 	case AL_SRDS_BIST_PATTERN_PRBS23:
394 		val = SERDES_25G_LANE_TX_BIST_CTRL_PATTERN_PRBS23;
395 		break;
396 	case AL_SRDS_BIST_PATTERN_PRBS31:
397 		val = SERDES_25G_LANE_TX_BIST_CTRL_PATTERN_PRBS31;
398 		break;
399 	case AL_SRDS_BIST_PATTERN_CLK1010:
400 	default:
401 		al_err("%s: invalid pattern (%d)\n", __func__, pattern);
402 		al_assert(0);
403 	}
404 
405 	for (lane = AL_SRDS_LANE_0; lane <= AL_SRDS_LANE_1; lane++) {
406 		if (pattern == AL_SRDS_BIST_PATTERN_USER) {
407 			int i;
408 
409 			for (i = 0; i < SERDES_25G_LANE_TX_BIST_UDP_NUM_BYTES; i++)
410 				al_serdes_25g_reg_write(
411 						obj,
412 						(enum al_serdes_reg_page)lane,
413 						0,
414 						SERDES_25G_LANE_TX_BIST_UDP_ADDR(i),
415 						user_data[i]);
416 		}
417 
418 		al_serdes_25g_reg_masked_write(
419 					obj,
420 					(enum al_serdes_reg_page)lane,
421 					SERDES_25G_LANE_TX_BIST_CTRL_ADDR,
422 					SERDES_25G_LANE_TX_BIST_CTRL_PATTERN_SEL_MASK,
423 					SERDES_25G_LANE_TX_BIST_CTRL_PATTERN_SEL_SHIFT,
424 					val);
425 	}
426 }
427 
428 static void al_serdes_25g_bist_tx_enable(
429 	struct al_serdes_grp_obj	*obj,
430 	enum al_serdes_lane		lane,
431 	al_bool				enable)
432 {
433 	if (enable) {
434 		al_serdes_25g_reg_masked_write(
435 					obj,
436 					(enum al_serdes_reg_page)lane,
437 					SERDES_25G_LANE_TX_BIST_CTRL_ADDR,
438 					SERDES_25G_LANE_TX_BIST_CTRL_EN_MASK,
439 					SERDES_25G_LANE_TX_BIST_CTRL_EN_SHIFT,
440 					0x1);
441 		al_serdes_25g_reg_masked_write(
442 					obj,
443 					(enum al_serdes_reg_page)lane,
444 					SERDES_25G_LANE_TOP_DPL_TXDP_CTRL1_ADDR,
445 					SERDES_25G_LANE_TOP_DPL_TXDP_CTRL1_DMUX_TXA_SEL_MASK,
446 					SERDES_25G_LANE_TOP_DPL_TXDP_CTRL1_DMUX_TXA_SEL_SHIFT,
447 					0x2);
448 
449 		switch (lane) {
450 		case AL_SRDS_LANE_0:
451 			al_serdes_25g_reg_masked_write(
452 					obj,
453 					AL_SRDS_REG_PAGE_TOP,
454 					SERDES_25G_TOP_CLOCK_LN0_CLK_TX_ADDR,
455 					SERDES_25G_TOP_CLOCK_LN0_CLK_TX_CTRL_BIST_CG_EN_MASK,
456 					SERDES_25G_TOP_CLOCK_LN0_CLK_TX_CTRL_BIST_CG_EN_SHIFT,
457 					0x1);
458 			break;
459 		case AL_SRDS_LANE_1:
460 			al_serdes_25g_reg_masked_write(
461 					obj,
462 					AL_SRDS_REG_PAGE_TOP,
463 					SERDES_25G_TOP_CLOCK_LN1_CLK_TX_ADDR,
464 					SERDES_25G_TOP_CLOCK_LN1_CLK_TX_CTRL_BIST_CG_EN_MASK,
465 					SERDES_25G_TOP_CLOCK_LN1_CLK_TX_CTRL_BIST_CG_EN_SHIFT,
466 					0x1);
467 			break;
468 		default:
469 			al_err("%s: Wrong serdes lane %d\n", __func__, lane);
470 				return;
471 		}
472 	} else {
473 		al_serdes_25g_reg_masked_write(
474 					obj,
475 					(enum al_serdes_reg_page)lane,
476 					SERDES_25G_LANE_TX_BIST_CTRL_ADDR,
477 					SERDES_25G_LANE_TX_BIST_CTRL_EN_MASK,
478 					SERDES_25G_LANE_TX_BIST_CTRL_EN_SHIFT,
479 					0);
480 	}
481 
482 }
483 
484 static void al_serdes_25g_bist_rx_status(
485 	struct al_serdes_grp_obj	*obj,
486 	enum al_serdes_lane		lane,
487 	al_bool				*is_locked,
488 	al_bool				*err_cnt_overflow,
489 	uint32_t			*err_cnt)
490 {
491 	uint8_t status;
492 	uint8_t err1;
493 	uint8_t err2;
494 	uint8_t err3;
495 
496 	al_serdes_25g_reg_masked_read(
497 		obj,
498 		(enum al_serdes_reg_page)lane,
499 		SERDES_25G_LANE_RX_BIST_STATUS_ADDR,
500 		SERDES_25G_LANE_RX_BIST_STATUS_STATE_MASK,
501 		SERDES_25G_LANE_RX_BIST_STATUS_STATE_SHIFT,
502 		&status);
503 
504 	if (status != 3) {
505 		*is_locked = AL_FALSE;
506 		return;
507 	}
508 
509 	*is_locked = AL_TRUE;
510 	*err_cnt_overflow = AL_FALSE;
511 
512 	al_serdes_25g_reg_masked_read(
513 		obj,
514 		(enum al_serdes_reg_page)lane,
515 		SERDES_25G_LANE_RX_BIST_BER_STATUS0_ADDR,
516 		SERDES_25G_LANE_RX_BIST_BER_STATUS0_BIT_ERROR_COUNT_7_0_MASK,
517 		SERDES_25G_LANE_RX_BIST_BER_STATUS0_BIT_ERROR_COUNT_7_0_SHIFT,
518 		&err1);
519 
520 	al_serdes_25g_reg_masked_read(
521 		obj,
522 		(enum al_serdes_reg_page)lane,
523 		SERDES_25G_LANE_RX_BIST_BER_STATUS1_ADDR,
524 		SERDES_25G_LANE_RX_BIST_BER_STATUS1_BIT_ERROR_COUNT_15_8_MASK,
525 		SERDES_25G_LANE_RX_BIST_BER_STATUS1_BIT_ERROR_COUNT_15_8_SHIFT,
526 		&err2);
527 
528 	al_serdes_25g_reg_masked_read(
529 		obj,
530 		(enum al_serdes_reg_page)lane,
531 		SERDES_25G_LANE_RX_BIST_BER_STATUS2_ADDR,
532 		SERDES_25G_LANE_RX_BIST_BER_STATUS2_BIT_ERROR_COUNT_23_16_MASK,
533 		SERDES_25G_LANE_RX_BIST_BER_STATUS2_BIT_ERROR_COUNT_23_16_SHIFT,
534 		&err3);
535 
536 	*err_cnt = (err1 + (err2 << 8) + (err3 << 16));
537 }
538 
539 #define SERDES_MB_CMD_SWING_CFG		0x83
540 #define SERDES_MB_CMD_SAMPLES_COUNT	0x84
541 #define SERDES_MB_CMD_START_MEASURE	0x82
542 
543 #define SERDES_MB_RSP_CODE_0		0
544 #define SERDES_MB_RSP_CODE_1		1
545 #define SERDES_MB_RSP_CODE_2		2
546 
547 static int al_serdes_25g_eye_diag_run(
548 	struct al_serdes_grp_obj	*obj,
549 	enum al_serdes_lane		lane,
550 	int				x_start,
551 	int				x_stop,
552 	unsigned int			x_step,
553 	int				y_start,
554 	int				y_stop,
555 	unsigned int			y_step,
556 	uint64_t			ber_target,
557 	uint64_t			*buf,
558 	uint32_t			buf_size)
559 {
560 	int rc;
561 	uint8_t rsp_code;
562 	uint8_t data[16];
563 	uint8_t data_len;
564 	uint32_t total_bits;
565 	uint8_t bits_left_curr_sample;
566 	uint8_t bits_left_curr_byte;
567 	uint32_t byte = 0;
568 	uint32_t x = 0;
569 	uint32_t x_samples = (((x_stop - x_start) / x_step) + 1);
570 	uint32_t y = 0;
571 	uint32_t y_samples = (((y_stop - y_start) / y_step) + 1);
572 	uint8_t sample_width = (64 - __builtin_clzl(ber_target));
573 	uint8_t msb;
574 	uint8_t lsb;
575 	uint32_t samples_left = ((x_samples * y_samples));
576 	uint8_t sign = 0;
577 
578 	al_assert(buf_size == (samples_left * sizeof(uint64_t)));
579 
580 	al_memset(buf, 0, buf_size);
581 
582 	if (y_start < 0) {
583 		y_start *= -1;
584 		sign |= 0x1;
585 	}
586 
587 	if (y_stop < 0) {
588 		y_stop *= -1;
589 		sign |= 0x2;
590 	}
591 
592 	data[0] = lane;
593 	data[1] = x_start;
594 	data[2] = x_stop;
595 	data[3] = x_step;
596 	data[4] = y_start;
597 	data[5] = y_stop;
598 	data[6] = sign;
599 	data[7] = y_step;
600 
601 	rc = al_serdes_25g_mailbox_send_cmd(
602 				obj,
603 				SERDES_MB_CMD_SWING_CFG,
604 				data,
605 				8);
606 
607 	if (rc) {
608 		al_err("%s: Failed to send command %d to mailbox.\n",
609 			__func__, SERDES_MB_CMD_SWING_CFG);
610 		return rc;
611 	}
612 
613 	rc = al_serdes_25g_mailbox_recv_rsp(
614 				obj,
615 				&rsp_code,
616 				data,
617 				&data_len);
618 
619 	if ((rc) || (rsp_code != SERDES_MB_RSP_CODE_0)) {
620 		al_err("%s: Failed to send command %d to mailbox. rsp_code %d\n",
621 			__func__, SERDES_MB_CMD_SWING_CFG, rsp_code);
622 
623 		return (ETIMEDOUT);
624 	}
625 
626 	al_assert(sample_width <= 40);
627 
628 	data[0] = lane;
629 	data[1] = ((ber_target >> 32) & 0xFF);
630 	data[2] = ((ber_target >> 24) & 0xFF);
631 	data[3] = ((ber_target >> 16) & 0xFF);
632 	data[4] = ((ber_target >> 8) & 0xFF);
633 	data[5] = (ber_target & 0xFF);
634 
635 	rc = al_serdes_25g_mailbox_send_cmd(
636 				obj,
637 				SERDES_MB_CMD_SAMPLES_COUNT,
638 				data,
639 				6);
640 
641 	if (rc) {
642 		al_err("%s: Failed to send command %d to mailbox.\n",
643 			__func__, SERDES_MB_CMD_SAMPLES_COUNT);
644 		return rc;
645 	}
646 
647 	rc = al_serdes_25g_mailbox_recv_rsp(
648 				obj,
649 				&rsp_code,
650 				data,
651 				&data_len);
652 
653 	if ((rc) || (rsp_code != SERDES_MB_RSP_CODE_0)) {
654 		al_err("%s: Failed to send command %d to mailbox. rsp_code %d\n",
655 			__func__, SERDES_MB_CMD_SAMPLES_COUNT, rsp_code);
656 
657 		return (ETIMEDOUT);
658 	}
659 
660 	rc = al_serdes_25g_mailbox_send_cmd(
661 				obj,
662 				SERDES_MB_CMD_START_MEASURE,
663 				data,
664 				0);
665 
666 	bits_left_curr_sample = sample_width;
667 
668 	while (rsp_code != SERDES_MB_RSP_CODE_1) {
669 		uint8_t num_bits = 0;
670 
671 		rc = al_serdes_25g_mailbox_recv_rsp(
672 				obj,
673 				&rsp_code,
674 				data,
675 				&data_len);
676 
677 		if ((rc != 0) || (rsp_code > SERDES_MB_RSP_CODE_2)) {
678 			al_err("%s: command %d return failure. rsp_code %d\n",
679 			__func__, SERDES_MB_CMD_START_MEASURE, rsp_code);
680 
681 			return (ETIMEDOUT);
682 		}
683 		byte = 0;
684 		total_bits = data_len * 8;
685 		bits_left_curr_byte = 8;
686 		while (total_bits > 0) {
687 			num_bits = al_min_t(uint8_t, bits_left_curr_sample, bits_left_curr_byte);
688 
689 			buf[(y * x_samples) + x] <<= num_bits;
690 			msb = bits_left_curr_byte - 1;
691 			lsb = msb - num_bits + 1;
692 			buf[(y * x_samples) + x] |= (data[byte] & AL_FIELD_MASK(msb, lsb) >> lsb);
693 
694 			total_bits -= num_bits;
695 
696 			bits_left_curr_byte -= num_bits;
697 			if (!bits_left_curr_byte) {
698 				bits_left_curr_byte = 8;
699 				byte++;
700 			}
701 
702 			bits_left_curr_sample -= num_bits;
703 			if (!bits_left_curr_sample) {
704 				y++;
705 				if (y == y_samples) {
706 					y = 0;
707 					x++;
708 				}
709 
710 				samples_left--;
711 				bits_left_curr_sample = sample_width;
712 			}
713 
714 			if (samples_left == 0)
715 				break;
716 		}
717 
718 		if ((samples_left == 0) && (rsp_code != SERDES_MB_RSP_CODE_1)) {
719 			rc = al_serdes_25g_mailbox_recv_rsp(
720 						obj,
721 						&rsp_code,
722 						data,
723 						&data_len);
724 			if ((rc) || (rsp_code == SERDES_MB_RSP_CODE_0)) {
725 				al_err("%s: Parsed enough samples but f/w is still sending more\n",
726 					__func__);
727 
728 				return -EIO;
729 			}
730 			break;
731 		}
732 	}
733 
734 	if (samples_left > 0) {
735 		al_err("%s: Still need more samples but f/w has stopped sending them!?!?!?\n",
736 			__func__);
737 
738 		return -EIO;
739 	}
740 
741 	return 0;
742 }
743 
744 #define SERDES_25G_EYE_X_MIN		1
745 #define SERDES_25G_EYE_X_MAX		127
746 #define SERDES_25G_EYE_Y_MIN		-200
747 #define SERDES_25G_EYE_Y_MAX		200
748 #define SERDES_25G_EYE_SIZE_MAX_SAMPLES	401
749 #define SERDES_25G_EYE_SIZE_BER_TARGET	0xffff
750 #define SERDES_25G_EYE_SIZE_ERR_TH	10
751 
752 static int al_serdes_25g_calc_eye_size(
753 		struct al_serdes_grp_obj	*obj,
754 		enum al_serdes_lane		lane,
755 		int				*width,
756 		int				*height)
757 {
758 	uint64_t samples[SERDES_25G_EYE_SIZE_MAX_SAMPLES];
759 	int i;
760 	int _width = 0;
761 	int _height = 0;
762 	int rc;
763 	int mid_x = ((SERDES_25G_EYE_X_MIN + SERDES_25G_EYE_X_MAX) / 2);
764 	int mid_y = ((SERDES_25G_EYE_Y_MIN + SERDES_25G_EYE_Y_MAX) / 2);
765 
766 	*height = 0;
767 	*width = 0;
768 
769 	rc = al_serdes_25g_eye_diag_run(obj,
770 					lane,
771 					mid_x,
772 					mid_x,
773 					1,
774 					SERDES_25G_EYE_Y_MIN,
775 					SERDES_25G_EYE_Y_MAX,
776 					1,
777 					SERDES_25G_EYE_SIZE_BER_TARGET,
778 					samples,
779 					((SERDES_25G_EYE_Y_MAX - SERDES_25G_EYE_Y_MIN + 1) *
780 					  sizeof(uint64_t)));
781 
782 	if (rc) {
783 		al_err("%s: failed to run eye_diag\n", __func__);
784 		return rc;
785 	}
786 
787 	for (i = (mid_y - SERDES_25G_EYE_Y_MIN);
788 		((samples[i] < SERDES_25G_EYE_SIZE_ERR_TH) &&
789 			(i < (SERDES_25G_EYE_Y_MAX - SERDES_25G_EYE_Y_MIN + 1)));
790 		i++, (_height)++)
791 		;
792 	for (i = (mid_y - SERDES_25G_EYE_Y_MIN);
793 		((samples[i] < SERDES_25G_EYE_SIZE_ERR_TH) && (i >= 0));
794 		i--, (_height)++)
795 		;
796 
797 	rc = al_serdes_25g_eye_diag_run(obj,
798 					lane,
799 					SERDES_25G_EYE_X_MIN,
800 					SERDES_25G_EYE_X_MAX,
801 					1,
802 					mid_y,
803 					mid_y,
804 					1,
805 					SERDES_25G_EYE_SIZE_BER_TARGET,
806 					samples,
807 					((SERDES_25G_EYE_X_MAX - SERDES_25G_EYE_X_MIN + 1) *
808 					  sizeof(uint64_t)));
809 
810 	if (rc) {
811 		al_err("%s: failed to run eye_diag\n", __func__);
812 		return rc;
813 	}
814 
815 	for (i = (mid_x - SERDES_25G_EYE_X_MIN);
816 		((samples[i] < SERDES_25G_EYE_SIZE_ERR_TH) &&
817 			(i < (SERDES_25G_EYE_X_MAX - SERDES_25G_EYE_X_MIN + 1)));
818 		i++, (_width)++)
819 		;
820 	for (i = (mid_x - SERDES_25G_EYE_X_MIN);
821 		((samples[i] < SERDES_25G_EYE_SIZE_ERR_TH) && (i >= 0));
822 		i--, (_width)++)
823 		;
824 
825 	*height = _height;
826 	*width = _width;
827 
828 	return 0;
829 }
830 
831 
832 static void al_serdes_25g_tx_advanced_params_set(struct al_serdes_grp_obj	*obj,
833 					enum al_serdes_lane			lane,
834 					void					*tx_params)
835 {
836 	struct al_serdes_adv_tx_params	*params = tx_params;
837 	uint32_t timeout = 5000;
838 	uint8_t val = 0;
839 
840 	al_serdes_25g_reg_masked_write(obj,
841 					(enum al_serdes_reg_page)lane,
842 					SERDES_25G_LANE_DRV_TXEQ_CTRL3_ADDR,
843 					SERDES_25G_LANE_DRV_TXEQ_CTRL3_TXEQ_CM1_MASK,
844 					SERDES_25G_LANE_DRV_TXEQ_CTRL3_TXEQ_CM1_SHIFT,
845 					params->c_minus_1);
846 
847 	al_serdes_25g_reg_masked_write(obj,
848 					(enum al_serdes_reg_page)lane,
849 					SERDES_25G_LANE_DRV_TXEQ_CTRL1_ADDR,
850 					SERDES_25G_LANE_DRV_TXEQ_CTRL1_TXEQ_C1_MASK,
851 					SERDES_25G_LANE_DRV_TXEQ_CTRL1_TXEQ_C1_SHIFT,
852 					params->c_plus_1);
853 
854 	al_serdes_25g_reg_masked_write(obj,
855 					(enum al_serdes_reg_page)lane,
856 					SERDES_25G_LANE_DRV_TXEQ_CTRL5_ADDR,
857 					SERDES_25G_LANE_DRV_TXEQ_CTRL5_DRV_SWING_MASK,
858 					SERDES_25G_LANE_DRV_TXEQ_CTRL5_DRV_SWING_SHIFT,
859 					params->total_driver_units);
860 
861 	al_serdes_25g_reg_masked_write(obj,
862 					(enum al_serdes_reg_page)lane,
863 					SERDES_25G_LANE_DRV_TXEQ_CTRL0_ADDR,
864 					SERDES_25G_LANE_DRV_TXEQ_CTRL0_REQ_MASK,
865 					SERDES_25G_LANE_DRV_TXEQ_CTRL0_REQ_SHIFT,
866 					1);
867 
868 
869 	/* wait for acknowledge */
870 	while (1) {
871 		al_serdes_25g_reg_masked_read(obj,
872 					(enum al_serdes_reg_page)lane,
873 					SERDES_25G_LANE_DRV_TXEQ_STATUS0_ADDR,
874 					SERDES_25G_LANE_DRV_TXEQ_STATUS0_ACK_MASK,
875 					SERDES_25G_LANE_DRV_TXEQ_STATUS0_ACK_SHIFT,
876 					&val);
877 		if (val == 1)
878 			break;
879 
880 		if (timeout == 0) {
881 			al_err("%s: timeout occurred waiting to FW ack\n", __func__);
882 			break;
883 		}
884 
885 		timeout--;
886 		al_udelay(1);
887 	}
888 
889 	al_serdes_25g_reg_masked_write(obj,
890 					(enum al_serdes_reg_page)lane,
891 					SERDES_25G_LANE_DRV_TXEQ_CTRL0_ADDR,
892 					SERDES_25G_LANE_DRV_TXEQ_CTRL0_REQ_MASK,
893 					SERDES_25G_LANE_DRV_TXEQ_CTRL0_REQ_SHIFT,
894 					0);
895 }
896 
897 static void al_serdes_25g_tx_advanced_params_get(struct al_serdes_grp_obj	*obj,
898 		enum al_serdes_lane			lane,
899 		void					*tx_params)
900 {
901 	struct al_serdes_adv_tx_params	*params = tx_params;
902 
903 	al_serdes_25g_reg_masked_read(obj,
904 					(enum al_serdes_reg_page)lane,
905 					SERDES_25G_LANE_DRV_TXEQ_CTRL3_ADDR,
906 					SERDES_25G_LANE_DRV_TXEQ_CTRL3_TXEQ_CM1_MASK,
907 					SERDES_25G_LANE_DRV_TXEQ_CTRL3_TXEQ_CM1_SHIFT,
908 					&params->c_minus_1);
909 
910 	al_serdes_25g_reg_masked_read(obj,
911 					(enum al_serdes_reg_page)lane,
912 					SERDES_25G_LANE_DRV_TXEQ_CTRL1_ADDR,
913 					SERDES_25G_LANE_DRV_TXEQ_CTRL1_TXEQ_C1_MASK,
914 					SERDES_25G_LANE_DRV_TXEQ_CTRL1_TXEQ_C1_SHIFT,
915 					&params->c_plus_1);
916 
917 	al_serdes_25g_reg_masked_read(obj,
918 					(enum al_serdes_reg_page)lane,
919 					SERDES_25G_LANE_DRV_TXEQ_CTRL5_ADDR,
920 					SERDES_25G_LANE_DRV_TXEQ_CTRL5_DRV_SWING_MASK,
921 					SERDES_25G_LANE_DRV_TXEQ_CTRL5_DRV_SWING_SHIFT,
922 					&params->total_driver_units);
923 }
924 
925 static al_bool al_serdes_25g_cdr_is_locked(
926 		struct al_serdes_grp_obj	*obj,
927 		enum al_serdes_lane		lane)
928 {
929 	uint8_t reg;
930 
931 	al_serdes_25g_reg_masked_read(obj,
932 				(enum al_serdes_reg_page)lane,
933 				SERDES_25G_LANE_CDR_RXCLK_DLPF_STATUS5_ADDR,
934 				SERDES_25G_LANE_CDR_RXCLK_DLPF_STATUS5_LOCKED_MASK,
935 				SERDES_25G_LANE_CDR_RXCLK_DLPF_STATUS5_LOCKED_SHIFT,
936 				&reg);
937 
938 	return !!reg;
939 
940 }
941 
942 static al_bool al_serdes_25g_rx_valid(
943 		struct al_serdes_grp_obj	*obj,
944 		enum al_serdes_lane		lane)
945 {
946 	uint8_t reg;
947 
948 	al_serdes_25g_reg_masked_read(obj,
949 				(enum al_serdes_reg_page)lane,
950 				SERDES_25G_LANE_TOP_LN_STAT_CTRL0_ADDR,
951 				SERDES_25G_LANE_TOP_LN_STAT_CTRL0_RXVALID_MASK,
952 				SERDES_25G_LANE_TOP_LN_STAT_CTRL0_RXVALID_SHIFT,
953 				&reg);
954 
955 	return !!reg;
956 
957 }
958 
959 static al_bool al_serdes_25g_signal_is_detected(
960 		struct al_serdes_grp_obj	*obj,
961 		enum al_serdes_lane		lane)
962 {
963 	struct al_serdes_c_regs __iomem	*regs_base = obj->regs_base;
964 	uint32_t reg;
965 	al_bool signal_detect = AL_FALSE;
966 
967 	reg = al_reg_read32(&regs_base->lane[lane].stat);
968 
969 	signal_detect = ((reg & (SERDES_C_LANE_STAT_LN_STAT_LOS |
970 				 SERDES_C_LANE_STAT_LN_STAT_LOS_DEGLITCH)) ?
971 					AL_FALSE : AL_TRUE);
972 
973 	return signal_detect;
974 
975 }
976 
977 static int al_serdes_25g_rx_equalization(
978 		struct al_serdes_grp_obj	*obj,
979 		enum al_serdes_lane		lane)
980 {
981 	struct al_serdes_c_regs __iomem	*regs_base = obj->regs_base;
982 	uint32_t ready_mask = (SERDES_C_GEN_STATUS_CM0_RST_PD_READY | SERDES_C_GEN_STATUS_CM0_OK_O);
983 	uint32_t reset_mask;
984 	uint32_t timeout;
985 	uint32_t reg_val;
986 	uint32_t retries = AL_SERDES_25G_RESET_NUM_RETRIES;
987 	int status = 0;
988 
989 	if (lane == 0) {
990 		ready_mask |= SERDES_C_GEN_STATUS_LN0_RST_PD_READY;
991 		reset_mask = SERDES_C_GEN_RST_LN0_RST_N;
992 	} else {
993 		ready_mask |= SERDES_C_GEN_STATUS_LN1_RST_PD_READY;
994 		reset_mask = SERDES_C_GEN_RST_LN1_RST_N;
995 	}
996 
997 	while (retries > 0) {
998 		timeout = AL_SERDES_25G_WAIT_FOR_READY_TO;
999 		status = 0;
1000 
1001 		al_reg_write32_masked(&regs_base->gen.rst, reset_mask, 0);
1002 
1003 		al_msleep(AL_SERDES_25G_RESET_TO);
1004 
1005 		al_serdes_25g_reg_masked_write(obj,
1006 					(enum al_serdes_reg_page)lane,
1007 					SERDES_25G_LANE_FEATURE_CTLE_ADAPT_MBS_CFG_ADDR,
1008 					SERDES_25G_LANE_FEATURE_CTLE_ADAPT_MBS_CFG_INIT0_EN_MASK,
1009 					SERDES_25G_LANE_FEATURE_CTLE_ADAPT_MBS_CFG_INIT0_EN_SHIFT,
1010 					0);
1011 
1012 		al_serdes_25g_reg_masked_write(obj,
1013 					(enum al_serdes_reg_page)lane,
1014 					SERDES_25G_LANE_LEQ_REFCLK_EQ_MB_CTRL1_ADDR,
1015 					SERDES_25G_LANE_LEQ_REFCLK_EQ_MB_CTRL1_EQ_MBF_START_MASK,
1016 					SERDES_25G_LANE_LEQ_REFCLK_EQ_MB_CTRL1_EQ_MBF_START_SHIFT,
1017 					7);
1018 
1019 		al_serdes_25g_reg_masked_write(obj,
1020 					(enum al_serdes_reg_page)lane,
1021 					SERDES_25G_LANE_LEQ_REFCLK_EQ_MB_CTRL1_ADDR,
1022 					SERDES_25G_LANE_LEQ_REFCLK_EQ_MB_CTRL1_EQ_MBG_START_MASK,
1023 					SERDES_25G_LANE_LEQ_REFCLK_EQ_MB_CTRL1_EQ_MBG_START_SHIFT,
1024 					15);
1025 
1026 		al_msleep(AL_SERDES_25G_RESET_TO);
1027 
1028 		al_reg_write32_masked(&regs_base->gen.rst, reset_mask, reset_mask);
1029 
1030 		while (1) {
1031 			reg_val = al_reg_read32(&regs_base->gen.status);
1032 			if ((reg_val & ready_mask) == ready_mask)
1033 				break;
1034 
1035 			al_udelay(1);
1036 			timeout--;
1037 
1038 			if (timeout == 0) {
1039 				al_err("%s: Timeout waiting for serdes ready\n", __func__);
1040 				status = ETIMEDOUT;
1041 				retries--;
1042 				break;
1043 			}
1044 		}
1045 
1046 		if (status)
1047 			continue;
1048 
1049 		while (1) {
1050 			reg_val = al_reg_read32(&regs_base->lane[lane].stat);
1051 			reg_val &= (SERDES_C_LANE_STAT_LNX_STAT_OK |
1052 				    SERDES_C_LANE_STAT_LN_STAT_RXVALID);
1053 			if (reg_val == (SERDES_C_LANE_STAT_LNX_STAT_OK |
1054 					SERDES_C_LANE_STAT_LN_STAT_RXVALID))
1055 				break;
1056 
1057 			al_udelay(1);
1058 			timeout--;
1059 
1060 			if (timeout == 0) {
1061 				al_err("%s: TO waiting for lane ready (%x)\n", __func__, reg_val);
1062 				status = ETIMEDOUT;
1063 				retries--;
1064 				break;
1065 			}
1066 		}
1067 
1068 		if (status)
1069 			continue;
1070 
1071 		break;
1072 	}
1073 
1074 	if (retries == 0) {
1075 		al_err("%s: Failed to run equalization\n", __func__);
1076 		status = ETIMEDOUT;
1077 	}
1078 
1079 	return status;
1080 
1081 }
1082 
1083 #define AL_SERDES_25G_GCFSM2_READ_TIMEOUT		2000000 /* uSec */
1084 
1085 static int al_serdes_25g_gcfsm2_read(
1086 		struct al_serdes_grp_obj	*obj,
1087 		enum al_serdes_lane		lane,
1088 		uint8_t			offset,
1089 		uint16_t		*data)
1090 {
1091 	int status = 0;
1092 	uint32_t timeout = AL_SERDES_25G_GCFSM2_READ_TIMEOUT;
1093 	uint8_t ack = 0;
1094 	uint8_t data_low, data_high;
1095 
1096 	al_assert(data);
1097 
1098 	/* Make sure GCFSM2 REQuest is off */
1099 	al_serdes_25g_reg_masked_write(
1100 			obj,
1101 			(enum al_serdes_reg_page)lane,
1102 			SERDES_25G_LANE_GCFSM2_CMD_CTRL0_ADDR,
1103 			SERDES_25G_LANE_GCFSM2_CMD_CTRL0_REQ_MASK,
1104 			SERDES_25G_LANE_GCFSM2_CMD_CTRL0_REQ_SHIFT,
1105 			0);
1106 	/* Write GCFSM2 CMD; CMD=0 for Read Request */
1107 	al_serdes_25g_reg_masked_write(
1108 			obj,
1109 			(enum al_serdes_reg_page)lane,
1110 			SERDES_25G_LANE_GCFSM2_CMD_CTRL1_ADDR,
1111 			SERDES_25G_LANE_GCFSM2_CMD_CTRL1_CMD_MASK,
1112 			SERDES_25G_LANE_GCFSM2_CMD_CTRL1_CMD_SHIFT,
1113 			0);
1114 	/* Write GCFSM2 the Address we wish to read */
1115 	al_serdes_25g_reg_write(
1116 			obj,
1117 			(enum al_serdes_reg_page)lane,
1118 			0,
1119 			SERDES_25G_LANE_GCFSM2_CMD_CTRL2_ADDR,
1120 			offset);
1121 	/* Issue a command REQuest */
1122 	al_serdes_25g_reg_masked_write(
1123 			obj,
1124 			(enum al_serdes_reg_page)lane,
1125 			SERDES_25G_LANE_GCFSM2_CMD_CTRL0_ADDR,
1126 			SERDES_25G_LANE_GCFSM2_CMD_CTRL0_REQ_MASK,
1127 			SERDES_25G_LANE_GCFSM2_CMD_CTRL0_REQ_SHIFT,
1128 			1);
1129 	/* Poll on GCFSM2 ACK */
1130 	while (1) {
1131 		al_serdes_25g_reg_masked_read(
1132 				obj,
1133 				(enum al_serdes_reg_page)lane,
1134 				SERDES_25G_LANE_GCFSM2_CMD_STATUS_ADDR,
1135 				SERDES_25G_LANE_GCFSM2_CMD_STATUS_ACK_MASK,
1136 				SERDES_25G_LANE_GCFSM2_CMD_STATUS_ACK_SHIFT,
1137 				&ack);
1138 
1139 		if (ack || (timeout == 0))
1140 			break;
1141 
1142 		timeout--;
1143 		al_udelay(1);
1144 	}
1145 
1146 	if (ack) {
1147 		/* Read 12bit of register value */
1148 		al_serdes_25g_reg_read(
1149 				obj,
1150 				(enum al_serdes_reg_page)lane,
1151 				0,
1152 				SERDES_25G_LANE_GCFSM2_READ_SHADOW_DATA_STATUS0_ADDR,
1153 				&data_low);
1154 		al_serdes_25g_reg_masked_read(
1155 				obj,
1156 				(enum al_serdes_reg_page)lane,
1157 				SERDES_25G_LANE_GCFSM2_READ_SHADOW_DATA_STATUS1_ADDR,
1158 				SERDES_25G_LANE_GCFSM2_READ_SHADOW_DATA_STATUS1_11_8_MASK,
1159 				SERDES_25G_LANE_GCFSM2_READ_SHADOW_DATA_STATUS1_11_8_SHIFT,
1160 				&data_high);
1161 		*data = (data_high << 8) | data_low;
1162 	} else {
1163 		al_err("%s: TO waiting for GCFSM2 req to complete (%x)\n", __func__, offset);
1164 		status = ETIMEDOUT;
1165 	}
1166 
1167 	/* Deassert the GCFSM2 REQuest */
1168 	al_serdes_25g_reg_masked_write(
1169 			obj,
1170 			(enum al_serdes_reg_page)lane,
1171 			SERDES_25G_LANE_GCFSM2_CMD_CTRL0_ADDR,
1172 			SERDES_25G_LANE_GCFSM2_CMD_CTRL0_REQ_MASK,
1173 			SERDES_25G_LANE_GCFSM2_CMD_CTRL0_REQ_SHIFT,
1174 			0);
1175 
1176 	return status;
1177 }
1178 
1179 enum al_serdes_25g_rx_leq_fsm_opcode {
1180 	AL_SERDES_25G_RX_LEQ_FSM_OPCODE_READ		= 0x1,
1181 	AL_SERDES_25G_RX_LEQ_FSM_OPCODE_WRITE		= 0x2,
1182 };
1183 
1184 enum al_serdes_25g_rx_leq_fsm_target {
1185 	AL_SERDES_25G_RX_LEQ_FSM_TARGET_AGC_SOURCE		= 0x1,
1186 	AL_SERDES_25G_RX_LEQ_FSM_TARGET_PLE_ATT			= 0x2,
1187 	AL_SERDES_25G_RX_LEQ_FSM_TARGET_EQ_LFG			= 0x3,
1188 	AL_SERDES_25G_RX_LEQ_FSM_TARGET_GN_APG			= 0x4,
1189 	AL_SERDES_25G_RX_LEQ_FSM_TARGET_GNEQ_CCL_LFG	= 0x5,
1190 	AL_SERDES_25G_RX_LEQ_FSM_TARGET_HFG_SQL			= 0x6,
1191 	AL_SERDES_25G_RX_LEQ_FSM_TARGET_EQ_MBF			= 0x8,
1192 	AL_SERDES_25G_RX_LEQ_FSM_TARGET_EQ_MBG			= 0x9,
1193 	AL_SERDES_25G_RX_LEQ_FSM_TARGET_VSCAN			= 0xA,
1194 	AL_SERDES_25G_RX_LEQ_FSM_TARGET_HSCAN			= 0xB,
1195 	AL_SERDES_25G_RX_LEQ_FSM_TARGET_EYE_INTF		= 0xC,
1196 };
1197 
1198 #define AL_SERDES_25G_RX_LEQ_FSM_TIMEOUT		2000000 /* uSec */
1199 
1200 static int al_serdes_25g_rx_leq_fsm_op(
1201 		struct al_serdes_grp_obj	*obj,
1202 		enum al_serdes_lane	lane,
1203 		enum al_serdes_25g_rx_leq_fsm_opcode	opcode,
1204 		enum al_serdes_25g_rx_leq_fsm_target	target,
1205 		uint8_t	val,
1206 		uint8_t	*data,
1207 		uint8_t	*err)
1208 {
1209 	uint32_t reg;
1210 	uint32_t timeout = AL_SERDES_25G_RX_LEQ_FSM_TIMEOUT;
1211 	uint8_t ack = 0;
1212 	int status = 0;
1213 
1214 	al_assert(data);
1215 	al_assert(err);
1216 
1217 	/* Write the OpCode & Target to LEQ FSM */
1218 	reg = (target << 4) | opcode;
1219 	al_serdes_25g_reg_write(
1220 			obj,
1221 			(enum al_serdes_reg_page)lane,
1222 			0,
1223 			SERDES_25G_LANE_LEQ_REFCLK_LEQ_FSM_CMD0_ADDR,
1224 			reg);
1225 
1226 	/* Write 0 as MiscOption value to LEQ FSM */
1227 	al_serdes_25g_reg_write(
1228 			obj,
1229 			(enum al_serdes_reg_page)lane,
1230 			0,
1231 			SERDES_25G_LANE_LEQ_REFCLK_LEQ_FSM_CMD2_ADDR,
1232 			0);
1233 
1234 	/* Write the ArgumentValue to LEQ FSM if needed*/
1235 	if (opcode == AL_SERDES_25G_RX_LEQ_FSM_OPCODE_WRITE) {
1236 		al_serdes_25g_reg_write(
1237 				obj,
1238 				(enum al_serdes_reg_page)lane,
1239 				0,
1240 				SERDES_25G_LANE_LEQ_REFCLK_LEQ_FSM_CMD1_ADDR,
1241 				val);
1242 	}
1243 
1244 	/* Issue an LEQ FSM Command Request */
1245 	al_serdes_25g_reg_masked_write(
1246 			obj,
1247 			(enum al_serdes_reg_page)lane,
1248 			SERDES_25G_LANE_LEQ_REFCLK_LEQ_FSM_CTRL0_ADDR,
1249 			SERDES_25G_LANE_LEQ_REFCLK_LEQ_FSM_CTRL0_LEQ_FSM_CMD_REQ_MASK,
1250 			SERDES_25G_LANE_LEQ_REFCLK_LEQ_FSM_CTRL0_LEQ_FSM_CMD_REQ_SHIFT,
1251 			1);
1252 
1253 	/* Poll on LEQ FSM Command acknowledge */
1254 	while (1) {
1255 		al_serdes_25g_reg_masked_read(
1256 				obj,
1257 				(enum al_serdes_reg_page)lane,
1258 				SERDES_25G_LANE_LEQ_REFCLK_LEQ_FSM_STATUS5_ADDR,
1259 				SERDES_25G_LANE_LEQ_REFCLK_LEQ_FSM_STATUS5_LEQ_FSM_CMD_ACK_MASK,
1260 				SERDES_25G_LANE_LEQ_REFCLK_LEQ_FSM_STATUS5_LEQ_FSM_CMD_ACK_SHIFT,
1261 				&ack);
1262 
1263 		if (ack || (timeout == 0))
1264 			break;
1265 
1266 		timeout--;
1267 		al_udelay(1);
1268 	}
1269 
1270 	if (ack) {
1271 		uint8_t err1, err2;
1272 		al_serdes_25g_reg_read(
1273 				obj,
1274 				(enum al_serdes_reg_page)lane,
1275 				0,
1276 				SERDES_25G_LANE_LEQ_REFCLK_LEQ_FSM_STATUS0_ADDR,
1277 				err);
1278 
1279 		err1 = (*err &
1280 			SERDES_25G_LANE_LEQ_REFCLK_LEQ_FSM_STATUS0_LEQ_FSM_STATUS_ERROR1_MASK) >>
1281 			SERDES_25G_LANE_LEQ_REFCLK_LEQ_FSM_STATUS0_LEQ_FSM_STATUS_ERROR1_SHIFT;
1282 		err2 = (*err &
1283 			SERDES_25G_LANE_LEQ_REFCLK_LEQ_FSM_STATUS0_LEQ_FSM_STATUS_ERROR2_MASK) >>
1284 			SERDES_25G_LANE_LEQ_REFCLK_LEQ_FSM_STATUS0_LEQ_FSM_STATUS_ERROR2_SHIFT;
1285 
1286 		if (err1 || err2) {
1287 			al_err("%s: error in RX LEQ FSM req, err status 1=0x%x, err status 2=0x%x",
1288 					__func__, err1, err2);
1289 			status = -EIO;
1290 		}
1291 
1292 		/* Read LEQ FSM Command return Value */
1293 		al_serdes_25g_reg_read(
1294 				obj,
1295 				(enum al_serdes_reg_page)lane,
1296 				0,
1297 				SERDES_25G_LANE_LEQ_REFCLK_LEQ_FSM_STATUS3_ADDR,
1298 				data);
1299 
1300 		/* Clear an LEQ FSM Command Request */
1301 		al_serdes_25g_reg_masked_write(
1302 				obj,
1303 				(enum al_serdes_reg_page)lane,
1304 				SERDES_25G_LANE_LEQ_REFCLK_LEQ_FSM_CTRL0_ADDR,
1305 				SERDES_25G_LANE_LEQ_REFCLK_LEQ_FSM_CTRL0_LEQ_FSM_CMD_REQ_MASK,
1306 				SERDES_25G_LANE_LEQ_REFCLK_LEQ_FSM_CTRL0_LEQ_FSM_CMD_REQ_SHIFT,
1307 				0);
1308 	} else {
1309 		al_err("%s: TO waiting for RX LEQ FSM req to complete (opcode %x, target %x, val %x)\n",
1310 				__func__, opcode, target, val);
1311 		status = ETIMEDOUT;
1312 	}
1313 
1314 	return status;
1315 }
1316 
1317 /* enum values correspond to HW values, don't change! */
1318 enum al_serdes_25g_tbus_obj {
1319 	AL_SERDES_25G_TBUS_OBJ_TOP	= 0,
1320 	AL_SERDES_25G_TBUS_OBJ_CMU	= 1,
1321 	AL_SERDES_25G_TBUS_OBJ_LANE	= 2,
1322 };
1323 
1324 #define AL_SERDES_25G_TBUS_DELAY	1000 /* uSec */
1325 #define AL_SERDES_25G_TBUS_ADDR_HIGH_SHIFT	5
1326 
1327 static int al_serdes_25g_tbus_read(
1328 		struct al_serdes_grp_obj	*obj,
1329 		enum al_serdes_lane	lane,
1330 		enum al_serdes_25g_tbus_obj	tbus_obj,
1331 		uint8_t	offset,
1332 		uint16_t	*data)
1333 {
1334 	uint8_t addr_high, val_high, val_low;
1335 
1336 	al_assert(lane < AL_SRDS_NUM_LANES);
1337 
1338 	if (tbus_obj == AL_SERDES_25G_TBUS_OBJ_TOP)
1339 		addr_high = AL_SERDES_25G_TBUS_OBJ_TOP;
1340 	else if (tbus_obj == AL_SERDES_25G_TBUS_OBJ_CMU)
1341 		addr_high = AL_SERDES_25G_TBUS_OBJ_CMU;
1342 	else
1343 		addr_high = AL_SERDES_25G_TBUS_OBJ_LANE + lane;
1344 
1345 	addr_high <<= AL_SERDES_25G_TBUS_ADDR_HIGH_SHIFT;
1346 
1347 	al_serdes_25g_reg_write(
1348 			obj,
1349 			AL_SRDS_REG_PAGE_TOP,
1350 			0,
1351 			SERDES_25G_TOP_TBUS_ADDR_7_0_ADDR,
1352 			offset);
1353 
1354 	al_serdes_25g_reg_write(
1355 			obj,
1356 			AL_SRDS_REG_PAGE_TOP,
1357 			0,
1358 			SERDES_25G_TOP_TBUS_ADDR_15_8_ADDR,
1359 			addr_high);
1360 
1361 	al_udelay(AL_SERDES_25G_TBUS_DELAY);
1362 
1363 	al_serdes_25g_reg_read(
1364 			obj,
1365 			AL_SRDS_REG_PAGE_TOP,
1366 			0,
1367 			SERDES_25G_TOP_TBUS_DATA_7_0_ADDR,
1368 			&val_low);
1369 
1370 	al_serdes_25g_reg_masked_read(
1371 			obj,
1372 			AL_SRDS_REG_PAGE_TOP,
1373 			SERDES_25G_TOP_TBUS_DATA_11_8_ADDR,
1374 			SERDES_25G_TOP_TBUS_DATA_11_8_MASK,
1375 			SERDES_25G_TOP_TBUS_DATA_11_8_SHIFT,
1376 			&val_high);
1377 
1378 	*data = (val_high << 8) | val_low;
1379 
1380 	return 0;
1381 }
1382 
1383 #define AL_SERDES_25G_RX_ADV_PARAMS_ATT_MASK	0x07
1384 #define AL_SERDES_25G_RX_ADV_PARAMS_APG_MASK	0x03
1385 #define AL_SERDES_25G_RX_ADV_PARAMS_LFG_MASK	0x1F
1386 #define AL_SERDES_25G_RX_ADV_PARAMS_HFG_MASK	0x1F
1387 #define AL_SERDES_25G_RX_ADV_PARAMS_MBG_MASK	0x0F
1388 #define AL_SERDES_25G_RX_ADV_PARAMS_MBF_MASK	0x0F
1389 #define AL_SERDES_25G_RX_ADV_PARAMS_DFE_TAP_CNT			8
1390 #define AL_SERDES_25G_RX_ADV_PARAMS_DFE_TAP_MASK		0x1F
1391 #define AL_SERDES_25G_RX_ADV_PARAMS_DFE_TAP_SIGN_SHIFT	7
1392 
1393 static void al_serdes_25g_rx_advanced_params_get(
1394 		struct al_serdes_grp_obj	*obj,
1395 		enum al_serdes_lane			lane,
1396 		void					*rx_params)
1397 {
1398 	struct al_serdes_25g_adv_rx_params *params = rx_params;
1399 	uint8_t value, err;
1400 	int8_t tap_weight;
1401 	uint8_t tap_sign;
1402 	int8_t *tap_ptr_arr[AL_SERDES_25G_RX_ADV_PARAMS_DFE_TAP_CNT];
1403 	int rc;
1404 	int i;
1405 
1406 	rc = al_serdes_25g_rx_leq_fsm_op(obj, lane, AL_SERDES_25G_RX_LEQ_FSM_OPCODE_READ,
1407 			AL_SERDES_25G_RX_LEQ_FSM_TARGET_PLE_ATT, 0, &value, &err);
1408 	if (rc || err) {
1409 		al_err("%s: al_serdes_25g_rx_leq_fsm_op failed to read att, rc %d, err %d\n",
1410 				__func__, rc, err);
1411 		return;
1412 	}
1413 	params->att = value & AL_SERDES_25G_RX_ADV_PARAMS_ATT_MASK;
1414 
1415 	rc = al_serdes_25g_rx_leq_fsm_op(obj, lane, AL_SERDES_25G_RX_LEQ_FSM_OPCODE_READ,
1416 			AL_SERDES_25G_RX_LEQ_FSM_TARGET_GN_APG, 0, &value, &err);
1417 	if (rc || err) {
1418 		al_err("%s: al_serdes_25g_rx_leq_fsm_op failed to read apg, rc %d, err %d\n",
1419 				__func__, rc, err);
1420 		return;
1421 	}
1422 	params->apg = value & AL_SERDES_25G_RX_ADV_PARAMS_APG_MASK;
1423 
1424 	rc = al_serdes_25g_rx_leq_fsm_op(obj, lane, AL_SERDES_25G_RX_LEQ_FSM_OPCODE_READ,
1425 			AL_SERDES_25G_RX_LEQ_FSM_TARGET_EQ_LFG, 0, &value, &err);
1426 	if (rc || err) {
1427 		al_err("%s: al_serdes_25g_rx_leq_fsm_op failed to read lfg, rc %d, err %d\n",
1428 				__func__, rc, err);
1429 		return;
1430 	}
1431 	params->lfg = value & AL_SERDES_25G_RX_ADV_PARAMS_LFG_MASK;
1432 
1433 	rc = al_serdes_25g_rx_leq_fsm_op(obj, lane, AL_SERDES_25G_RX_LEQ_FSM_OPCODE_READ,
1434 			AL_SERDES_25G_RX_LEQ_FSM_TARGET_HFG_SQL, 0, &value, &err);
1435 	if (rc || err) {
1436 		al_err("%s: al_serdes_25g_rx_leq_fsm_op failed to read hfg, rc %d, err %d\n",
1437 				__func__, rc, err);
1438 		return;
1439 	}
1440 	params->hfg = value & AL_SERDES_25G_RX_ADV_PARAMS_HFG_MASK;
1441 
1442 	rc = al_serdes_25g_rx_leq_fsm_op(obj, lane, AL_SERDES_25G_RX_LEQ_FSM_OPCODE_READ,
1443 			AL_SERDES_25G_RX_LEQ_FSM_TARGET_EQ_MBG, 0, &value, &err);
1444 	if (rc || err) {
1445 		al_err("%s: al_serdes_25g_rx_leq_fsm_op failed to read mbg, rc %d, err %d\n",
1446 				__func__, rc, err);
1447 		return;
1448 	}
1449 	params->mbg = value & AL_SERDES_25G_RX_ADV_PARAMS_MBG_MASK;
1450 
1451 	rc = al_serdes_25g_rx_leq_fsm_op(obj, lane, AL_SERDES_25G_RX_LEQ_FSM_OPCODE_READ,
1452 			AL_SERDES_25G_RX_LEQ_FSM_TARGET_EQ_MBF, 0, &value, &err);
1453 	if (rc || err) {
1454 		al_err("%s: al_serdes_25g_rx_leq_fsm_op failed to read mbf, rc %d, err %d\n",
1455 				__func__, rc, err);
1456 		return;
1457 	}
1458 	params->mbf = value & AL_SERDES_25G_RX_ADV_PARAMS_MBF_MASK;
1459 
1460 	tap_ptr_arr[0] = &params->dfe_first_tap_even0_ctrl;
1461 	tap_ptr_arr[1] = &params->dfe_first_tap_even1_ctrl;
1462 	tap_ptr_arr[2] = &params->dfe_first_tap_odd0_ctrl;
1463 	tap_ptr_arr[3] = &params->dfe_first_tap_odd1_ctrl;
1464 	tap_ptr_arr[4] = &params->dfe_second_tap_ctrl;
1465 	tap_ptr_arr[5] = &params->dfe_third_tap_ctrl;
1466 	tap_ptr_arr[6] = &params->dfe_fourth_tap_ctrl;
1467 	tap_ptr_arr[7] = &params->dfe_fifth_tap_ctrl;
1468 
1469 	for (i = 0; i < AL_SERDES_25G_RX_ADV_PARAMS_DFE_TAP_CNT; i++) {
1470 		al_serdes_25g_reg_read(
1471 				obj,
1472 				(enum al_serdes_reg_page)lane,
1473 				0,
1474 				SERDES_25G_LANE_DFE_REFCLK_TAP_VAL_STATUS0_ADDR + i,
1475 				&value);
1476 
1477 		tap_weight = value & AL_SERDES_25G_RX_ADV_PARAMS_DFE_TAP_MASK;
1478 		tap_sign = (value & AL_BIT(AL_SERDES_25G_RX_ADV_PARAMS_DFE_TAP_SIGN_SHIFT)) >>
1479 				AL_SERDES_25G_RX_ADV_PARAMS_DFE_TAP_SIGN_SHIFT;
1480 		if (tap_sign == 0)
1481 			tap_weight = 0 - tap_weight;
1482 
1483 		*tap_ptr_arr[i] = tap_weight;
1484 	}
1485 }
1486 
1487 #define AL_SERDES_25G_TX_DIAG_GCFSM2_DCD_TRIM_ADDR		0x0B
1488 #define AL_SERDES_25G_TX_DIAG_GCFSM2_DCD_TRIM_MASK		0x3F
1489 #define AL_SERDES_25G_TX_DIAG_GCFSM2_DCD_TRIM_SIGN_SHIFT	7
1490 #define AL_SERDES_25G_TX_DIAG_GCFSM2_CLK_DELAY_ADDR		0x0C
1491 #define AL_SERDES_25G_TX_DIAG_GCFSM2_CLK_DELAY_MASK		0xFFF
1492 
1493 static void al_serdes_25g_tx_diag_info_get(
1494 		struct al_serdes_grp_obj	*obj,
1495 		enum al_serdes_lane		lane,
1496 		void *tx_info)
1497 {
1498 	struct al_serdes_25g_tx_diag_info *info = tx_info;
1499 	uint8_t cal_x1, cal_x1_fixed, cal_x2, cal_xp5_fixed;
1500 	uint16_t val16, sign;
1501 	uint8_t val8, abs;
1502 	int rc;
1503 
1504 	al_serdes_25g_reg_read(
1505 			obj,
1506 			(enum al_serdes_reg_page)lane,
1507 			0,
1508 			SERDES_25G_LANE_TOP_AFE_TXCP_CTRL0_ADDR,
1509 			&val8);
1510 	info->regulated_supply = val8 & SERDES_25G_LANE_TOP_AFE_TXCP_CTRL0_REG_TXCP_TRIM_MASK;
1511 
1512 	rc = al_serdes_25g_gcfsm2_read(
1513 			obj,
1514 			lane,
1515 			AL_SERDES_25G_TX_DIAG_GCFSM2_DCD_TRIM_ADDR,
1516 			&val16);
1517 	if (rc) {
1518 		al_err("%s: al_serdes_25g_gcfsm2_read failed to read dcd_trim, rc %d\n",
1519 				__func__, rc);
1520 		return;
1521 	}
1522 
1523 	abs = val16 & AL_SERDES_25G_TX_DIAG_GCFSM2_DCD_TRIM_MASK;
1524 	sign = (val16 & AL_BIT(AL_SERDES_25G_TX_DIAG_GCFSM2_DCD_TRIM_SIGN_SHIFT)) >>
1525 			AL_SERDES_25G_TX_DIAG_GCFSM2_DCD_TRIM_SIGN_SHIFT;
1526 	if (sign)
1527 		info->dcd_trim = abs;
1528 	else
1529 		info->dcd_trim = 0 - abs;
1530 
1531 	rc = al_serdes_25g_gcfsm2_read(
1532 			obj,
1533 			lane,
1534 			AL_SERDES_25G_TX_DIAG_GCFSM2_CLK_DELAY_ADDR,
1535 			&val16);
1536 	if (rc) {
1537 		al_err("%s: al_serdes_25g_gcfsm2_read failed to read clk_delay, rc %d\n",
1538 				__func__, rc);
1539 		return;
1540 	}
1541 	info->clk_delay = val16 & AL_SERDES_25G_TX_DIAG_GCFSM2_CLK_DELAY_MASK;
1542 
1543 	al_serdes_25g_reg_read(
1544 			obj,
1545 			(enum al_serdes_reg_page)lane,
1546 			0,
1547 			SERDES_25G_CM_TOP_AFE_TXTC_CTRL2_ADDR,
1548 			&val8);
1549 	cal_x1 = (val8 & SERDES_25G_CMU_TOP_AFE_TXTC_CTRL2_TXTC_CALP_X1_MASK) >>
1550 			SERDES_25G_CMU_TOP_AFE_TXTC_CTRL2_TXTC_CALP_X1_SHIFT;
1551 	cal_x1_fixed = (val8 & SERDES_25G_CMU_TOP_AFE_TXTC_CTRL2_TXTC_CALP_X1_FIXED_MASK) >>
1552 			SERDES_25G_CMU_TOP_AFE_TXTC_CTRL2_TXTC_CALP_X1_FIXED_SHIFT;
1553 	al_serdes_25g_reg_read(
1554 			obj,
1555 			(enum al_serdes_reg_page)lane,
1556 			0,
1557 			SERDES_25G_CM_TOP_AFE_TXTC_CTRL3_ADDR,
1558 			&val8);
1559 	cal_x2 = (val8 & SERDES_25G_CMU_TOP_AFE_TXTC_CTRL3_TXTC_CALP_X2_MASK) >>
1560 			SERDES_25G_CMU_TOP_AFE_TXTC_CTRL3_TXTC_CALP_X2_SHIFT;
1561 	cal_xp5_fixed = (val8 &
1562 			SERDES_25G_CMU_TOP_AFE_TXTC_CTRL3_TXTC_CALP_XP5_FIXED_MASK) >>
1563 					SERDES_25G_CMU_TOP_AFE_TXTC_CTRL3_TXTC_CALP_XP5_FIXED_SHIFT;
1564 	info->calp_multiplied_by_2 = 4 * cal_x2 + 2 * cal_x1 + 2 * cal_x1_fixed + cal_xp5_fixed;
1565 
1566 	al_serdes_25g_reg_read(
1567 			obj,
1568 			(enum al_serdes_reg_page)lane,
1569 			0,
1570 			SERDES_25G_CM_TOP_AFE_TXTC_CTRL0_ADDR,
1571 			&val8);
1572 	cal_x1 = (val8 & SERDES_25G_CMU_TOP_AFE_TXTC_CTRL0_TXTC_CALN_X1_MASK) >>
1573 			SERDES_25G_CMU_TOP_AFE_TXTC_CTRL0_TXTC_CALN_X1_SHIFT;
1574 	cal_x1_fixed = (val8 & SERDES_25G_CMU_TOP_AFE_TXTC_CTRL0_TXTC_CALN_X1_FIXED_MASK) >>
1575 			SERDES_25G_CMU_TOP_AFE_TXTC_CTRL0_TXTC_CALN_X1_FIXED_SHIFT;
1576 	al_serdes_25g_reg_read(
1577 			obj,
1578 			(enum al_serdes_reg_page)lane,
1579 			0,
1580 			SERDES_25G_CM_TOP_AFE_TXTC_CTRL1_ADDR,
1581 			&val8);
1582 	cal_x2 = (val8 & SERDES_25G_CMU_TOP_AFE_TXTC_CTRL1_TXTC_CALN_X2_MASK) >>
1583 			SERDES_25G_CMU_TOP_AFE_TXTC_CTRL1_TXTC_CALN_X2_SHIFT;
1584 	cal_xp5_fixed = (val8 &
1585 			SERDES_25G_CMU_TOP_AFE_TXTC_CTRL1_TXTC_CALN_XP5_FIXED_MASK) >>
1586 					SERDES_25G_CMU_TOP_AFE_TXTC_CTRL1_TXTC_CALN_XP5_FIXED_SHIFT;
1587 	info->caln_multiplied_by_2 = 4 * cal_x2 + 2 * cal_x1 + 2 * cal_x1_fixed + cal_xp5_fixed;
1588 }
1589 
1590 #define AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_ABS_MASK			0x1F
1591 #define AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_MASK				0x3F
1592 #define AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_SIGN_SHIFT		5
1593 #define AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_HIGH_MASK			0xFC0
1594 #define AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_HIGH_SHIFT		6
1595 #define AL_SERDES_25G_RX_DIAG_LEQ_EQ_COUNT					5
1596 #define AL_SERDES_25G_RX_DIAG_GCFSM2_LEQ_EQ_ADDR			0
1597 #define AL_SERDES_25G_RX_DIAG_GCFSM2_LEQ_GAINSTAGE_ADDR		0x5
1598 #define AL_SERDES_25G_RX_DIAG_GCFSM2_SUMMER_EVEN_ADDR		0x6
1599 #define AL_SERDES_25G_RX_DIAG_GCFSM2_SUMMER_ODD_ADDR		0x7
1600 #define AL_SERDES_25G_RX_DIAG_GCFSM2_VSCAN_EVEN_ADDR		0x8
1601 #define AL_SERDES_25G_RX_DIAG_GCFSM2_VSCAN_ODD_ADDR			0x9
1602 #define AL_SERDES_25G_RX_DIAG_GCFSM2_CDR_VCO_FR_ADDR		0xF
1603 #define AL_SERDES_25G_RX_DIAG_GCFSM2_CDR_VCO_FR_MASK		0xFFF
1604 #define AL_SERDES_25G_RX_DIAG_TBUS_DATA_SLICER_EVEN_ADDR	0x11
1605 #define AL_SERDES_25G_RX_DIAG_TBUS_DATA_SLICER_ODD_ADDR		0x12
1606 #define AL_SERDES_25G_RX_DIAG_TBUS_EDGE_SLICER_ADDR			0x13
1607 #define AL_SERDES_25G_RX_DIAG_TBUS_EYE_SLICER_ADDR			0x23
1608 #define AL_SERDES_25G_RX_DIAG_TBUS_CDR_CLK_Q_ADDR			0x2
1609 #define AL_SERDES_25G_RX_DIAG_TBUS_CDR_CLK_I_ADDR			0x1
1610 #define AL_SERDES_25G_RX_DIAG_CDR_RXCLK_DLPF_L_ADDR			0x26
1611 #define AL_SERDES_25G_RX_DIAG_CDR_RXCLK_DLPF_H_ADDR			0x27
1612 
1613 static inline void al_serdes_25g_rx_diag_5bit_signed_set(uint8_t packed_val, int8_t *ptr)
1614 {
1615 	uint8_t abs, sign;
1616 
1617 	abs = packed_val & AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_ABS_MASK;
1618 	sign = (packed_val & AL_BIT(AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_SIGN_SHIFT)) >>
1619 			AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_SIGN_SHIFT;
1620 	if (sign)
1621 		*ptr = abs;
1622 	else
1623 		*ptr = 0 - abs;
1624 }
1625 
1626 static void al_serdes_25g_rx_diag_info_get(
1627 		struct al_serdes_grp_obj	*obj,
1628 		enum al_serdes_lane		lane,
1629 		void *rx_info)
1630 {
1631 	struct al_serdes_25g_rx_diag_info *info = rx_info;
1632 	uint16_t val16;
1633 	uint8_t val8, val8_2;
1634 	int rc;
1635 	int i;
1636 
1637 	al_serdes_25g_reg_read(
1638 			obj,
1639 			(enum al_serdes_reg_page)lane,
1640 			0,
1641 			SERDES_25G_LANE_LOS_REFCLK_CALIBRATION_STATUS0_ADDR,
1642 			&val8);
1643 	al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->los_offset);
1644 
1645 	al_serdes_25g_reg_read(
1646 			obj,
1647 			(enum al_serdes_reg_page)lane,
1648 			0,
1649 			SERDES_25G_LANE_LOS_REFCLK_CALIBRATION_STATUS1_ADDR,
1650 			&val8);
1651 	al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->agc_offset);
1652 
1653 	rc = al_serdes_25g_gcfsm2_read(
1654 			obj,
1655 			lane,
1656 			AL_SERDES_25G_RX_DIAG_GCFSM2_LEQ_GAINSTAGE_ADDR,
1657 			&val16);
1658 	if (rc) {
1659 		al_err("%s: al_serdes_25g_gcfsm2_read failed to read leq_gainstage, rc %d\n",
1660 				__func__, rc);
1661 		return;
1662 	}
1663 	val8 = (uint8_t)val16;
1664 	al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->leq_gainstage_offset);
1665 
1666 	for (i = 0; i < AL_SERDES_25G_RX_DIAG_LEQ_EQ_COUNT; i++) {
1667 		rc = al_serdes_25g_gcfsm2_read(
1668 				obj,
1669 				lane,
1670 				AL_SERDES_25G_RX_DIAG_GCFSM2_LEQ_EQ_ADDR + i,
1671 				&val16);
1672 		if (rc) {
1673 			al_err("%s: al_serdes_25g_gcfsm2_read failed to read leq_eq %d, rc %d\n",
1674 					__func__, i, rc);
1675 			return;
1676 		}
1677 		val8 = (uint8_t)val16;
1678 
1679 		switch (i) {
1680 		case 0:
1681 			al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->leq_eq1_offset);
1682 			break;
1683 		case 1:
1684 			al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->leq_eq2_offset);
1685 			break;
1686 		case 2:
1687 			al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->leq_eq3_offset);
1688 			break;
1689 		case 3:
1690 			al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->leq_eq4_offset);
1691 			break;
1692 		case 4:
1693 			al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->leq_eq5_offset);
1694 			break;
1695 		default:
1696 			break;
1697 		}
1698 	}
1699 
1700 	rc = al_serdes_25g_gcfsm2_read(
1701 			obj,
1702 			lane,
1703 			AL_SERDES_25G_RX_DIAG_GCFSM2_SUMMER_EVEN_ADDR,
1704 			&val16);
1705 	if (rc) {
1706 		al_err("%s: al_serdes_25g_gcfsm2_read failed to read summer_even_offset, rc %d\n",
1707 				__func__, rc);
1708 		return;
1709 	}
1710 	val8 = (uint8_t)val16;
1711 	al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->summer_even_offset);
1712 
1713 	rc = al_serdes_25g_gcfsm2_read(
1714 			obj,
1715 			lane,
1716 			AL_SERDES_25G_RX_DIAG_GCFSM2_SUMMER_ODD_ADDR,
1717 			&val16);
1718 	if (rc) {
1719 		al_err("%s: al_serdes_25g_gcfsm2_read failed to read summer_odd_offset, rc %d\n",
1720 				__func__, rc);
1721 		return;
1722 	}
1723 	val8 = (uint8_t)val16;
1724 	al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->summer_odd_offset);
1725 
1726 	rc = al_serdes_25g_gcfsm2_read(
1727 			obj,
1728 			lane,
1729 			AL_SERDES_25G_RX_DIAG_GCFSM2_VSCAN_EVEN_ADDR,
1730 			&val16);
1731 	if (rc) {
1732 		al_err("%s: al_serdes_25g_gcfsm2_read failed to read vscan_even_offset, rc %d\n",
1733 				__func__, rc);
1734 		return;
1735 	}
1736 	val8 = (uint8_t)val16;
1737 	al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->vscan_even_offset);
1738 
1739 	rc = al_serdes_25g_gcfsm2_read(
1740 			obj,
1741 			lane,
1742 			AL_SERDES_25G_RX_DIAG_GCFSM2_VSCAN_ODD_ADDR,
1743 			&val16);
1744 	if (rc) {
1745 		al_err("%s: al_serdes_25g_gcfsm2_read failed to read vscan_odd_offset, rc %d\n",
1746 				__func__, rc);
1747 		return;
1748 	}
1749 	val8 = (uint8_t)val16;
1750 	al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->vscan_odd_offset);
1751 
1752 	al_serdes_25g_tbus_read(
1753 			obj,
1754 			lane,
1755 			AL_SERDES_25G_TBUS_OBJ_LANE,
1756 			AL_SERDES_25G_RX_DIAG_TBUS_DATA_SLICER_EVEN_ADDR,
1757 			&val16);
1758 	val8 = (uint8_t)(val16 & AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_MASK);
1759 	al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->data_slicer_even0_offset);
1760 	val8 = (uint8_t)((val16 & AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_HIGH_MASK) >>
1761 			AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_HIGH_SHIFT);
1762 	al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->data_slicer_even1_offset);
1763 
1764 	al_serdes_25g_tbus_read(
1765 			obj,
1766 			lane,
1767 			AL_SERDES_25G_TBUS_OBJ_LANE,
1768 			AL_SERDES_25G_RX_DIAG_TBUS_DATA_SLICER_ODD_ADDR,
1769 			&val16);
1770 	val8 = (uint8_t)(val16 & AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_MASK);
1771 	al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->data_slicer_odd0_offset);
1772 	val8 = (uint8_t)((val16 & AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_HIGH_MASK) >>
1773 			AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_HIGH_SHIFT);
1774 	al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->data_slicer_odd1_offset);
1775 
1776 	al_serdes_25g_tbus_read(
1777 			obj,
1778 			lane,
1779 			AL_SERDES_25G_TBUS_OBJ_LANE,
1780 			AL_SERDES_25G_RX_DIAG_TBUS_EDGE_SLICER_ADDR,
1781 			&val16);
1782 	val8 = (uint8_t)(val16 & AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_MASK);
1783 	al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->edge_slicer_even_offset);
1784 	val8 = (uint8_t)((val16 & AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_HIGH_MASK) >>
1785 			AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_HIGH_SHIFT);
1786 	al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->edge_slicer_odd_offset);
1787 
1788 	al_serdes_25g_tbus_read(
1789 			obj,
1790 			lane,
1791 			AL_SERDES_25G_TBUS_OBJ_LANE,
1792 			AL_SERDES_25G_RX_DIAG_TBUS_EYE_SLICER_ADDR,
1793 			&val16);
1794 	val8 = (uint8_t)(val16 & AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_MASK);
1795 	al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->eye_slicer_even_offset);
1796 	val8 = (uint8_t)((val16 & AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_HIGH_MASK) >>
1797 			AL_SERDES_25G_RX_DIAG_SIGNED_5BIT_HIGH_SHIFT);
1798 	al_serdes_25g_rx_diag_5bit_signed_set(val8, &info->eye_slicer_odd_offset);
1799 
1800 	al_serdes_25g_reg_masked_read(
1801 			obj,
1802 			(enum al_serdes_reg_page)lane,
1803 			SERDES_25G_LANE_CDR_REFCLK_AFE_PI_CTRL0_ADDR,
1804 			SERDES_25G_LANE_CDR_REFCLK_AFE_PI_CTRL0_RXCDR_HSCAN_CLKQ_MASK,
1805 			SERDES_25G_LANE_CDR_REFCLK_AFE_PI_CTRL0_RXCDR_HSCAN_CLKQ_SHIFT,
1806 			&info->cdr_clk_q);
1807 
1808 	al_serdes_25g_reg_masked_read(
1809 			obj,
1810 			(enum al_serdes_reg_page)lane,
1811 			SERDES_25G_LANE_CDR_REFCLK_AFE_PI_CTRL1_ADDR,
1812 			SERDES_25G_LANE_CDR_REFCLK_AFE_PI_CTRL1_RXCDR_HSCAN_CLKI_MASK,
1813 			SERDES_25G_LANE_CDR_REFCLK_AFE_PI_CTRL1_RXCDR_HSCAN_CLKI_SHIFT,
1814 			&info->cdr_clk_i);
1815 
1816 	al_serdes_25g_reg_masked_read(
1817 			obj,
1818 			(enum al_serdes_reg_page)lane,
1819 			SERDES_25G_LANE_CDR_REFCLK_AFE_PI_CTRL2_ADDR,
1820 			SERDES_25G_LANE_CDR_REFCLK_AFE_PI_CTRL2_RXCDR_HSCAN_EYE_MASK,
1821 			SERDES_25G_LANE_CDR_REFCLK_AFE_PI_CTRL2_RXCDR_HSCAN_EYE_SHIFT,
1822 			&info->cdr_dll);
1823 
1824 	al_serdes_25g_reg_masked_read(
1825 			obj,
1826 			(enum al_serdes_reg_page)lane,
1827 			SERDES_25G_LANE_CDR_REFCLK_AFE_VCO_CTRL2_ADDR,
1828 			SERDES_25G_LANE_CDR_REFCLK_AFE_VCO_CTRL2_RXCDR_DOSC_MASK,
1829 			SERDES_25G_LANE_CDR_REFCLK_AFE_VCO_CTRL2_RXCDR_DOSC_SHIFT,
1830 			&info->cdr_vco_dosc);
1831 
1832 	al_serdes_25g_reg_read(
1833 			obj,
1834 			(enum al_serdes_reg_page)lane,
1835 			0,
1836 			SERDES_25G_LANE_CDR_RXCLK_LOAD_MODE_CTRL1_ADDR,
1837 			&val8_2);
1838 	al_serdes_25g_reg_read(
1839 			obj,
1840 			(enum al_serdes_reg_page)lane,
1841 			0,
1842 			SERDES_25G_LANE_CDR_RXCLK_LOAD_MODE_CTRL0_ADDR,
1843 			&val8);
1844 	val8_2 &= SERDES_25G_LANE_CDR_RXCLK_LOAD_MODE_CTRL1_DLPF_VAL_8_MASK;
1845 	info->cdr_dlpf = (uint16_t)val8_2 << 8 | val8;
1846 
1847 	rc = al_serdes_25g_gcfsm2_read(
1848 			obj,
1849 			lane,
1850 			AL_SERDES_25G_RX_DIAG_GCFSM2_CDR_VCO_FR_ADDR,
1851 			&val16);
1852 	if (rc) {
1853 		al_err("%s: al_serdes_25g_gcfsm2_read failed to read cdr_vco_fr, rc %d\n",
1854 				__func__, rc);
1855 		return;
1856 	}
1857 	info->cdr_vco_fr = val16 & AL_SERDES_25G_RX_DIAG_GCFSM2_CDR_VCO_FR_MASK;
1858 
1859 	al_serdes_25g_reg_masked_read(
1860 			obj,
1861 			(enum al_serdes_reg_page)lane,
1862 			SERDES_25G_LANE_LEQ_REFCLK_AFE_PLE_CTRL0_ADDR,
1863 			SERDES_25G_LANE_LEQ_REFCLK_AFE_PLE_CTRL0_RXLEQ_PLE_BLW_ZERO_MASK,
1864 			SERDES_25G_LANE_LEQ_REFCLK_AFE_PLE_CTRL0_RXLEQ_PLE_BLW_ZERO_SHIFT,
1865 			&info->ple_resistance);
1866 
1867 	al_serdes_25g_reg_read(
1868 			obj,
1869 			(enum al_serdes_reg_page)lane,
1870 			0,
1871 			SERDES_25G_LANE_TOP_AFE_RXTERM_CTRL0_ADDR,
1872 			&val8);
1873 
1874 	info->rx_term_mode = (val8 & SERDES_25G_LANE_TOP_AFE_RXTERM_CTRL0_RXTERM_HIZ_MASK) >>
1875 			SERDES_25G_LANE_TOP_AFE_RXTERM_CTRL0_RXTERM_HIZ_SHIFT;
1876 
1877 	info->rx_coupling = (val8 & SERDES_25G_LANE_TOP_AFE_RXTERM_CTRL0_RXTERM_VCM_GND_MASK) >>
1878 			SERDES_25G_LANE_TOP_AFE_RXTERM_CTRL0_RXTERM_VCM_GND_SHIFT;
1879 
1880 	al_serdes_25g_reg_masked_read(
1881 			obj,
1882 			(enum al_serdes_reg_page)lane,
1883 			SERDES_25G_LANE_TOP_AFE_RXTERM_CTRL1_ADDR,
1884 			SERDES_25G_LANE_TOP_AFE_RXTERM_CTRL1_RXTERM_VAL_MASK,
1885 			SERDES_25G_LANE_TOP_AFE_RXTERM_CTRL1_RXTERM_VAL_SHIFT,
1886 			&info->rx_term_cal_code);
1887 
1888 	al_serdes_25g_reg_masked_read(
1889 			obj,
1890 			(enum al_serdes_reg_page)lane,
1891 			SERDES_25G_LANE_LEQ_REFCLK_AFE_BIAS_CTRL1_ADDR,
1892 			SERDES_25G_LANE_LEQ_REFCLK_AFE_BIAS_CTRL1_RXLEQ_BIASI_TRIM_MASK,
1893 			SERDES_25G_LANE_LEQ_REFCLK_AFE_BIAS_CTRL1_RXLEQ_BIASI_TRIM_SHIFT,
1894 			&info->rx_sheet_res_cal_code);
1895 }
1896 
1897 /******************************************************************************/
1898 /******************************************************************************/
1899 int al_serdes_25g_handle_init(
1900 	void __iomem			*serdes_regs_base,
1901 	struct al_serdes_grp_obj	*obj)
1902 {
1903 	al_dbg(
1904 		"%s(%p, %p)\n",
1905 		__func__,
1906 		serdes_regs_base,
1907 		obj);
1908 
1909 	al_memset(obj, 0, sizeof(struct al_serdes_grp_obj));
1910 
1911 	obj->regs_base = (struct al_serdes_regs *)serdes_regs_base;
1912 	obj->type_get = al_serdes_25g_type_get;
1913 	obj->reg_read = al_serdes_25g_reg_read;
1914 	obj->reg_write = al_serdes_25g_reg_write;
1915 	obj->bist_overrides_enable = NULL;
1916 	obj->bist_overrides_disable = NULL;
1917 	obj->rx_rate_change = NULL;
1918 	obj->group_pm_set = NULL;
1919 	obj->lane_pm_set = NULL;
1920 	obj->pma_hard_reset_group = NULL;
1921 	obj->pma_hard_reset_lane = NULL;
1922 	obj->loopback_control = NULL;
1923 	obj->bist_pattern_select = AL_SRDS_ADV_SRVC(al_serdes_25g_bist_pattern_select);
1924 	obj->bist_tx_enable = AL_SRDS_ADV_SRVC(al_serdes_25g_bist_tx_enable);
1925 	obj->bist_tx_err_inject = NULL;
1926 	obj->bist_rx_enable = AL_SRDS_ADV_SRVC(al_serdes_25g_bist_rx_enable);
1927 	obj->bist_rx_status = AL_SRDS_ADV_SRVC(al_serdes_25g_bist_rx_status);
1928 	obj->tx_deemph_preset = NULL;
1929 	obj->tx_deemph_inc = NULL;
1930 	obj->tx_deemph_dec = NULL;
1931 	obj->eye_measure_run = NULL;
1932 	obj->eye_diag_sample = NULL;
1933 	obj->eye_diag_run = AL_SRDS_ADV_SRVC(al_serdes_25g_eye_diag_run);
1934 	obj->cdr_is_locked = AL_SRDS_ADV_SRVC(al_serdes_25g_cdr_is_locked);
1935 	obj->rx_valid = AL_SRDS_ADV_SRVC(al_serdes_25g_rx_valid);
1936 	obj->signal_is_detected = AL_SRDS_ADV_SRVC(al_serdes_25g_signal_is_detected);
1937 	obj->tx_advanced_params_set = AL_SRDS_ADV_SRVC(al_serdes_25g_tx_advanced_params_set);
1938 	obj->tx_advanced_params_get = AL_SRDS_ADV_SRVC(al_serdes_25g_tx_advanced_params_get);
1939 	obj->rx_advanced_params_set = NULL;
1940 	obj->rx_advanced_params_get = AL_SRDS_ADV_SRVC(al_serdes_25g_rx_advanced_params_get);
1941 	obj->tx_diag_info_get = AL_SRDS_ADV_SRVC(al_serdes_25g_tx_diag_info_get);
1942 	obj->rx_diag_info_get = AL_SRDS_ADV_SRVC(al_serdes_25g_rx_diag_info_get);
1943 	obj->mode_set_sgmii = NULL;
1944 	obj->mode_set_kr = NULL;
1945 	obj->rx_equalization = AL_SRDS_ADV_SRVC(al_serdes_25g_rx_equalization);
1946 	obj->calc_eye_size = AL_SRDS_ADV_SRVC(al_serdes_25g_calc_eye_size);
1947 	obj->sris_config = NULL;
1948 
1949 	return 0;
1950 }
1951 
1952