xref: /dpdk/drivers/common/cnxk/roc_bphy_cgx.c (revision 6169517c111e5fefb9bb22458191e6c402d2ae9c)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4 
5 #include <pthread.h>
6 
7 #include "roc_api.h"
8 #include "roc_priv.h"
9 
10 #define CGX_CMRX_CONFIG		       0x00
11 #define CGX_CMRX_CONFIG_DATA_PKT_RX_EN BIT_ULL(54)
12 #define CGX_CMRX_CONFIG_DATA_PKT_TX_EN BIT_ULL(53)
13 #define CGX_CMRX_INT		       0x40
14 #define CGX_CMRX_INT_OVERFLW	       BIT_ULL(1)
15 /*
16  * CN10K stores number of lmacs in 4 bit filed
17  * in contrary to CN9K which uses only 3 bits.
18  *
19  * In theory masks should differ yet on CN9K
20  * bits beyond specified range contain zeros.
21  *
22  * Hence common longer mask may be used.
23  */
24 #define CGX_CMRX_RX_LMACS                     0x128
25 #define CGX_CMRX_RX_LMACS_LMACS               GENMASK_ULL(3, 0)
26 #define CGX_CMRX_SCRATCH0                     0x1050
27 #define CGX_CMRX_SCRATCH1                     0x1058
28 #define CGX_MTI_MAC100X_COMMAND_CONFIG        0x8010
29 #define CGX_MTI_MAC100X_COMMAND_CONFIG_RX_ENA BIT_ULL(1)
30 #define CGX_MTI_MAC100X_COMMAND_CONFIG_TX_ENA BIT_ULL(0)
31 
32 static uint64_t
33 roc_bphy_cgx_read(struct roc_bphy_cgx *roc_cgx, uint64_t lmac, uint64_t offset)
34 {
35 	int shift = roc_model_is_cn10k() ? 20 : 18;
36 	uint64_t base = (uint64_t)roc_cgx->bar0_va;
37 
38 	return plt_read64(base + (lmac << shift) + offset);
39 }
40 
41 static void
42 roc_bphy_cgx_write(struct roc_bphy_cgx *roc_cgx, uint64_t lmac, uint64_t offset,
43 		   uint64_t value)
44 {
45 	int shift = roc_model_is_cn10k() ? 20 : 18;
46 	uint64_t base = (uint64_t)roc_cgx->bar0_va;
47 
48 	plt_write64(value, base + (lmac << shift) + offset);
49 }
50 
51 static void
52 roc_bphy_cgx_ack(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
53 		 uint64_t *scr0)
54 {
55 	uint64_t val;
56 
57 	/* clear interrupt */
58 	val = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_INT);
59 	val |= FIELD_PREP(CGX_CMRX_INT_OVERFLW, 1);
60 	roc_bphy_cgx_write(roc_cgx, lmac, CGX_CMRX_INT, val);
61 
62 	/* ack fw response */
63 	*scr0 &= ~SCR0_ETH_EVT_STS_S_ACK;
64 	roc_bphy_cgx_write(roc_cgx, lmac, CGX_CMRX_SCRATCH0, *scr0);
65 }
66 
67 static int
68 roc_bphy_cgx_wait_for_ownership(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
69 				uint64_t *scr0)
70 {
71 	int tries = 5000;
72 	uint64_t scr1;
73 
74 	do {
75 		*scr0 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH0);
76 		scr1 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH1);
77 
78 		if (FIELD_GET(SCR1_OWN_STATUS, scr1) == ETH_OWN_NON_SECURE_SW &&
79 		    FIELD_GET(SCR0_ETH_EVT_STS_S_ACK, *scr0) == 0)
80 			break;
81 
82 		/* clear async events if any */
83 		if (FIELD_GET(SCR0_ETH_EVT_STS_S_EVT_TYPE, *scr0) ==
84 		    ETH_EVT_ASYNC &&
85 		    FIELD_GET(SCR0_ETH_EVT_STS_S_ACK, *scr0))
86 			roc_bphy_cgx_ack(roc_cgx, lmac, scr0);
87 
88 		plt_delay_ms(1);
89 	} while (--tries);
90 
91 	return tries ? 0 : -ETIMEDOUT;
92 }
93 
94 static int
95 roc_bphy_cgx_wait_for_ack(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
96 			  uint64_t *scr0)
97 {
98 	int tries = 5000;
99 	uint64_t scr1;
100 
101 	do {
102 		*scr0 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH0);
103 		scr1 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH1);
104 
105 		if (FIELD_GET(SCR1_OWN_STATUS, scr1) == ETH_OWN_NON_SECURE_SW &&
106 		    FIELD_GET(SCR0_ETH_EVT_STS_S_ACK, *scr0))
107 			break;
108 
109 		plt_delay_ms(1);
110 	} while (--tries);
111 
112 	return tries ? 0 : -ETIMEDOUT;
113 }
114 
115 static int
116 roc_bphy_cgx_intf_req(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
117 		      uint64_t scr1, uint64_t *scr0)
118 {
119 	uint8_t cmd_id = FIELD_GET(SCR1_ETH_CMD_ID, scr1);
120 	int ret;
121 
122 	pthread_mutex_lock(&roc_cgx->lock);
123 
124 	/* wait for ownership */
125 	ret = roc_bphy_cgx_wait_for_ownership(roc_cgx, lmac, scr0);
126 	if (ret) {
127 		plt_err("timed out waiting for ownership");
128 		goto out;
129 	}
130 
131 	/* write command */
132 	scr1 |= FIELD_PREP(SCR1_OWN_STATUS, ETH_OWN_FIRMWARE);
133 	roc_bphy_cgx_write(roc_cgx, lmac, CGX_CMRX_SCRATCH1, scr1);
134 
135 	/* wait for command ack */
136 	ret = roc_bphy_cgx_wait_for_ack(roc_cgx, lmac, scr0);
137 	if (ret) {
138 		plt_err("timed out waiting for response");
139 		goto out;
140 	}
141 
142 	if (cmd_id == ETH_CMD_INTF_SHUTDOWN)
143 		goto out;
144 
145 	if (FIELD_GET(SCR0_ETH_EVT_STS_S_EVT_TYPE, *scr0) != ETH_EVT_CMD_RESP) {
146 		plt_err("received async event instead of cmd resp event");
147 		ret = -EIO;
148 		goto out;
149 	}
150 
151 	if (FIELD_GET(SCR0_ETH_EVT_STS_S_ID, *scr0) != cmd_id) {
152 		plt_err("received resp for cmd %d expected for cmd %d",
153 			(int)FIELD_GET(SCR0_ETH_EVT_STS_S_ID, *scr0), cmd_id);
154 		ret = -EIO;
155 		goto out;
156 	}
157 
158 	if (FIELD_GET(SCR0_ETH_EVT_STS_S_STAT, *scr0) != ETH_STAT_SUCCESS) {
159 		plt_err("cmd %d failed on cgx%u lmac%u with errcode %d", cmd_id,
160 			roc_cgx->id, lmac,
161 			(int)FIELD_GET(SCR0_ETH_LNK_STS_S_ERR_TYPE, *scr0));
162 		ret = -EIO;
163 	}
164 
165 out:
166 	roc_bphy_cgx_ack(roc_cgx, lmac, scr0);
167 
168 	pthread_mutex_unlock(&roc_cgx->lock);
169 
170 	return ret;
171 }
172 
173 static unsigned int
174 roc_bphy_cgx_dev_id(struct roc_bphy_cgx *roc_cgx)
175 {
176 	uint64_t cgx_id;
177 
178 	if (roc_model_is_cnf10kb())
179 		cgx_id = GENMASK_ULL(27, 24);
180 	else if (roc_model_is_cn10k())
181 		cgx_id = GENMASK_ULL(26, 24);
182 	else
183 		cgx_id = GENMASK_ULL(25, 24);
184 
185 	return FIELD_GET(cgx_id, roc_cgx->bar0_pa);
186 }
187 
188 int
189 roc_bphy_cgx_dev_init(struct roc_bphy_cgx *roc_cgx)
190 {
191 	uint64_t val;
192 
193 	if (!roc_cgx || !roc_cgx->bar0_va || !roc_cgx->bar0_pa)
194 		return -EINVAL;
195 
196 	pthread_mutex_init(&roc_cgx->lock, NULL);
197 
198 	val = roc_bphy_cgx_read(roc_cgx, 0, CGX_CMRX_RX_LMACS);
199 	val = FIELD_GET(CGX_CMRX_RX_LMACS_LMACS, val);
200 	if (roc_model_is_cn9k())
201 		val = GENMASK_ULL(val - 1, 0);
202 	roc_cgx->lmac_bmap = val;
203 	roc_cgx->id = roc_bphy_cgx_dev_id(roc_cgx);
204 
205 	return 0;
206 }
207 
208 int
209 roc_bphy_cgx_dev_fini(struct roc_bphy_cgx *roc_cgx)
210 {
211 	if (!roc_cgx)
212 		return -EINVAL;
213 
214 	pthread_mutex_destroy(&roc_cgx->lock);
215 
216 	return 0;
217 }
218 
219 static bool
220 roc_bphy_cgx_lmac_exists(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
221 {
222 	return (lmac < MAX_LMACS_PER_CGX) &&
223 	       (roc_cgx->lmac_bmap & BIT_ULL(lmac));
224 }
225 
226 static int
227 roc_bphy_cgx_start_stop_rxtx(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
228 			     bool start)
229 {
230 	uint64_t val, reg, rx_field, tx_field;
231 
232 	if (!roc_cgx)
233 		return -EINVAL;
234 
235 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
236 		return -ENODEV;
237 
238 	if (roc_model_is_cnf10kb()) {
239 		reg = CGX_MTI_MAC100X_COMMAND_CONFIG;
240 		rx_field = CGX_MTI_MAC100X_COMMAND_CONFIG_RX_ENA;
241 		tx_field = CGX_MTI_MAC100X_COMMAND_CONFIG_TX_ENA;
242 	} else {
243 		reg = CGX_CMRX_CONFIG;
244 		rx_field = CGX_CMRX_CONFIG_DATA_PKT_RX_EN;
245 		tx_field = CGX_CMRX_CONFIG_DATA_PKT_TX_EN;
246 	}
247 
248 	pthread_mutex_lock(&roc_cgx->lock);
249 	val = roc_bphy_cgx_read(roc_cgx, lmac, reg);
250 	val &= ~(rx_field | tx_field);
251 
252 	if (start)
253 		val |= FIELD_PREP(rx_field, 1) | FIELD_PREP(tx_field, 1);
254 
255 	roc_bphy_cgx_write(roc_cgx, lmac, reg, val);
256 	pthread_mutex_unlock(&roc_cgx->lock);
257 
258 	return 0;
259 }
260 
261 static int
262 roc_bphy_cgx_intlbk_ena_dis(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
263 			    bool enable)
264 {
265 	uint64_t scr1, scr0;
266 
267 	if (!roc_cgx)
268 		return -EINVAL;
269 
270 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
271 		return -ENODEV;
272 
273 	scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_INTERNAL_LBK) |
274 	       FIELD_PREP(SCR1_ETH_CTL_ARGS_ENABLE, enable);
275 
276 	return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
277 }
278 
279 static int
280 roc_bphy_cgx_ptp_rx_ena_dis(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
281 			    bool enable)
282 {
283 	uint64_t scr1, scr0;
284 
285 	if (!roc_cgx)
286 		return -EINVAL;
287 
288 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
289 		return -ENODEV;
290 
291 	scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_SET_PTP_MODE) |
292 	       FIELD_PREP(SCR1_ETH_CTL_ARGS_ENABLE, enable);
293 
294 	return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
295 }
296 
297 int
298 roc_bphy_cgx_start_rxtx(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
299 {
300 	return roc_bphy_cgx_start_stop_rxtx(roc_cgx, lmac, true);
301 }
302 
303 int
304 roc_bphy_cgx_stop_rxtx(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
305 {
306 	return roc_bphy_cgx_start_stop_rxtx(roc_cgx, lmac, false);
307 }
308 
309 int
310 roc_bphy_cgx_set_link_state(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
311 			    struct roc_bphy_cgx_link_state *state)
312 {
313 	uint64_t scr1, scr0;
314 
315 	if (!roc_cgx)
316 		return -EINVAL;
317 
318 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
319 		return -ENODEV;
320 
321 	if (!state)
322 		return -EINVAL;
323 
324 	scr1 = (state->state ? FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_LINK_BRING_UP) :
325 			       FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_LINK_BRING_DOWN)) |
326 	       FIELD_PREP(SCR1_CGX_LINK_BRINGUP_ARGS_TIMEOUT, state->timeout) |
327 	       FIELD_PREP(SCR1_CGX_LINK_BRINGUP_ARGS_RX_TX_DIS, state->rx_tx_dis);
328 
329 	return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
330 }
331 
332 int
333 roc_bphy_cgx_get_linkinfo(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
334 			  struct roc_bphy_cgx_link_info *info)
335 {
336 	uint64_t scr1, scr0;
337 	int ret;
338 
339 	if (!roc_cgx)
340 		return -EINVAL;
341 
342 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
343 		return -ENODEV;
344 
345 	if (!info)
346 		return -EINVAL;
347 
348 	scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_GET_LINK_STS);
349 	ret = roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
350 	if (ret)
351 		return ret;
352 
353 	info->link_up = FIELD_GET(SCR0_ETH_LNK_STS_S_LINK_UP, scr0);
354 	info->full_duplex = FIELD_GET(SCR0_ETH_LNK_STS_S_FULL_DUPLEX, scr0);
355 	info->speed = FIELD_GET(SCR0_ETH_LNK_STS_S_SPEED, scr0);
356 	info->an = FIELD_GET(SCR0_ETH_LNK_STS_S_AN, scr0);
357 	info->fec = FIELD_GET(SCR0_ETH_LNK_STS_S_FEC, scr0);
358 	info->mode = FIELD_GET(SCR0_ETH_LNK_STS_S_MODE, scr0);
359 
360 	return 0;
361 }
362 
363 int
364 roc_bphy_cgx_set_link_mode(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
365 			   struct roc_bphy_cgx_link_mode *mode)
366 {
367 	uint64_t scr1, scr0;
368 
369 	if (roc_model_is_cn9k() &&
370 	    (mode->use_portm_idx || mode->portm_idx || mode->mode_group_idx)) {
371 		return -ENOTSUP;
372 	}
373 
374 	if (!roc_cgx)
375 		return -EINVAL;
376 
377 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
378 		return -ENODEV;
379 
380 	if (!mode)
381 		return -EINVAL;
382 
383 	scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_MODE_CHANGE) |
384 	       FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_SPEED, mode->speed) |
385 	       FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_DUPLEX, mode->full_duplex) |
386 	       FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_AN, mode->an) |
387 	       FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_USE_PORTM_IDX,
388 			  mode->use_portm_idx) |
389 	       FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_PORTM_IDX,
390 			  mode->portm_idx) |
391 	       FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_MODE_GROUP_IDX,
392 			  mode->mode_group_idx) |
393 	       FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_MODE, BIT_ULL(mode->mode));
394 
395 	return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
396 }
397 
398 int
399 roc_bphy_cgx_intlbk_enable(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
400 {
401 	return roc_bphy_cgx_intlbk_ena_dis(roc_cgx, lmac, true);
402 }
403 
404 int
405 roc_bphy_cgx_intlbk_disable(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
406 {
407 	return roc_bphy_cgx_intlbk_ena_dis(roc_cgx, lmac, false);
408 }
409 
410 int
411 roc_bphy_cgx_ptp_rx_enable(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
412 {
413 	return roc_bphy_cgx_ptp_rx_ena_dis(roc_cgx, lmac, true);
414 }
415 
416 int
417 roc_bphy_cgx_ptp_rx_disable(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
418 {
419 	return roc_bphy_cgx_ptp_rx_ena_dis(roc_cgx, lmac, false);
420 }
421 
422 int
423 roc_bphy_cgx_fec_set(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
424 		     enum roc_bphy_cgx_eth_link_fec fec)
425 {
426 	uint64_t scr1, scr0;
427 
428 	if (!roc_cgx)
429 		return -EINVAL;
430 
431 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
432 		return -ENODEV;
433 
434 	scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_SET_FEC) |
435 	       FIELD_PREP(SCR1_ETH_SET_FEC_ARGS, fec);
436 
437 	return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
438 }
439 
440 int
441 roc_bphy_cgx_fec_supported_get(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
442 			       enum roc_bphy_cgx_eth_link_fec *fec)
443 {
444 	uint64_t scr1, scr0;
445 	int ret;
446 
447 	if (!roc_cgx || !fec)
448 		return -EINVAL;
449 
450 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
451 		return -ENODEV;
452 
453 	scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_GET_SUPPORTED_FEC);
454 
455 	ret = roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
456 	if (ret)
457 		return ret;
458 
459 	scr0 = FIELD_GET(SCR0_ETH_FEC_TYPES_S_FEC, scr0);
460 	*fec = (enum roc_bphy_cgx_eth_link_fec)scr0;
461 
462 	return 0;
463 }
464 
465 int
466 roc_bphy_cgx_cpri_mode_change(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
467 			      struct roc_bphy_cgx_cpri_mode_change *mode)
468 {
469 	uint64_t scr1, scr0;
470 
471 	if (!(roc_model_is_cnf95xxn_a0() ||
472 	      roc_model_is_cnf95xxn_a1() ||
473 	      roc_model_is_cnf95xxn_b0()))
474 		return -ENOTSUP;
475 
476 	if (!roc_cgx)
477 		return -EINVAL;
478 
479 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
480 		return -ENODEV;
481 
482 	if (!mode)
483 		return -EINVAL;
484 
485 	scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_CPRI_MODE_CHANGE) |
486 	       FIELD_PREP(SCR1_CPRI_MODE_CHANGE_ARGS_GSERC_IDX,
487 			  mode->gserc_idx) |
488 	       FIELD_PREP(SCR1_CPRI_MODE_CHANGE_ARGS_LANE_IDX, mode->lane_idx) |
489 	       FIELD_PREP(SCR1_CPRI_MODE_CHANGE_ARGS_RATE, mode->rate) |
490 	       FIELD_PREP(SCR1_CPRI_MODE_CHANGE_ARGS_DISABLE_LEQ,
491 			  mode->disable_leq) |
492 	       FIELD_PREP(SCR1_CPRI_MODE_CHANGE_ARGS_DISABLE_DFE,
493 			  mode->disable_dfe);
494 
495 	return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
496 }
497 
498 int
499 roc_bphy_cgx_cpri_mode_tx_control(struct roc_bphy_cgx *roc_cgx,
500 				  unsigned int lmac,
501 				  struct roc_bphy_cgx_cpri_mode_tx_ctrl *mode)
502 {
503 	uint64_t scr1, scr0;
504 
505 	if (!(roc_model_is_cnf95xxn_a0() ||
506 	      roc_model_is_cnf95xxn_a1() ||
507 	      roc_model_is_cnf95xxn_b0()))
508 		return -ENOTSUP;
509 
510 	if (!roc_cgx)
511 		return -EINVAL;
512 
513 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
514 		return -ENODEV;
515 
516 	if (!mode)
517 		return -EINVAL;
518 
519 	scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_CPRI_TX_CONTROL) |
520 	       FIELD_PREP(SCR1_CPRI_MODE_TX_CTRL_ARGS_GSERC_IDX,
521 			  mode->gserc_idx) |
522 	       FIELD_PREP(SCR1_CPRI_MODE_TX_CTRL_ARGS_LANE_IDX,
523 			  mode->lane_idx) |
524 	       FIELD_PREP(SCR1_CPRI_MODE_TX_CTRL_ARGS_ENABLE, mode->enable);
525 
526 	return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
527 }
528 
529 int
530 roc_bphy_cgx_cpri_mode_misc(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
531 			    struct roc_bphy_cgx_cpri_mode_misc *mode)
532 {
533 	uint64_t scr1, scr0;
534 
535 	if (!(roc_model_is_cnf95xxn_a0() ||
536 	      roc_model_is_cnf95xxn_a1() ||
537 	      roc_model_is_cnf95xxn_b0()))
538 		return -ENOTSUP;
539 
540 	if (!roc_cgx)
541 		return -EINVAL;
542 
543 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
544 		return -ENODEV;
545 
546 	if (!mode)
547 		return -EINVAL;
548 
549 	scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_CPRI_MISC) |
550 	       FIELD_PREP(SCR1_CPRI_MODE_MISC_ARGS_GSERC_IDX,
551 			  mode->gserc_idx) |
552 	       FIELD_PREP(SCR1_CPRI_MODE_MISC_ARGS_LANE_IDX,
553 			  mode->lane_idx) |
554 	       FIELD_PREP(SCR1_CPRI_MODE_MISC_ARGS_FLAGS, mode->flags);
555 
556 	return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
557 }
558