mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 10:26:10 +01:00 
			
		
		
		
	Adds support for Network Interface controllers found on OcteonTX2 SoC platforms. Signed-off-by: Suneel Garapati <sgarapati@marvell.com> Signed-off-by: Stefan Roese <sr@denx.de> Cc: Joe Hershberger <joe.hershberger@ni.com>
		
			
				
	
	
		
			716 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			716 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier:    GPL-2.0
 | |
| /*
 | |
|  * Copyright (C) 2018 Marvell International Ltd.
 | |
|  */
 | |
| 
 | |
| #include <dm.h>
 | |
| #include <errno.h>
 | |
| #include <malloc.h>
 | |
| #include <misc.h>
 | |
| #include <net.h>
 | |
| 
 | |
| #include <linux/bitops.h>
 | |
| #include <linux/delay.h>
 | |
| #include <linux/list.h>
 | |
| 
 | |
| #include <asm/arch/board.h>
 | |
| #include <asm/io.h>
 | |
| 
 | |
| #include "cgx_intf.h"
 | |
| #include "cgx.h"
 | |
| #include "nix.h"
 | |
| 
 | |
| static u64 cgx_rd_scrx(u8 cgx, u8 lmac, u8 index)
 | |
| {
 | |
| 	u64 addr;
 | |
| 
 | |
| 	addr = (index == 1) ? CGX_CMR_SCRATCH1 : CGX_CMR_SCRATCH0;
 | |
| 	addr += CGX_SHIFT(cgx) + CMR_SHIFT(lmac);
 | |
| 	return readq(addr);
 | |
| }
 | |
| 
 | |
| static void cgx_wr_scrx(u8 cgx, u8 lmac, u8 index, u64 val)
 | |
| {
 | |
| 	u64 addr;
 | |
| 
 | |
| 	addr = (index == 1) ? CGX_CMR_SCRATCH1 : CGX_CMR_SCRATCH0;
 | |
| 	addr += CGX_SHIFT(cgx) + CMR_SHIFT(lmac);
 | |
| 	writeq(val, addr);
 | |
| }
 | |
| 
 | |
| static u64 cgx_rd_scr0(u8 cgx, u8 lmac)
 | |
| {
 | |
| 	return cgx_rd_scrx(cgx, lmac, 0);
 | |
| }
 | |
| 
 | |
| static u64 cgx_rd_scr1(u8 cgx, u8 lmac)
 | |
| {
 | |
| 	return cgx_rd_scrx(cgx, lmac, 1);
 | |
| }
 | |
| 
 | |
| static void cgx_wr_scr0(u8 cgx, u8 lmac, u64 val)
 | |
| {
 | |
| 	return cgx_wr_scrx(cgx, lmac, 0, val);
 | |
| }
 | |
| 
 | |
| static void cgx_wr_scr1(u8 cgx, u8 lmac, u64 val)
 | |
| {
 | |
| 	return cgx_wr_scrx(cgx, lmac, 1, val);
 | |
| }
 | |
| 
 | |
| static inline void set_ownership(u8 cgx, u8 lmac, u8 val)
 | |
| {
 | |
| 	union cgx_scratchx1 scr1;
 | |
| 
 | |
| 	scr1.u = cgx_rd_scr1(cgx, lmac);
 | |
| 	scr1.s.own_status = val;
 | |
| 	cgx_wr_scr1(cgx, lmac, scr1.u);
 | |
| }
 | |
| 
 | |
| static int wait_for_ownership(u8 cgx, u8 lmac)
 | |
| {
 | |
| 	union cgx_scratchx1 scr1;
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	u64 cmrx_int;
 | |
| 	int timeout = 5000;
 | |
| 
 | |
| 	do {
 | |
| 		scr1.u = cgx_rd_scr1(cgx, lmac);
 | |
| 		scr0.u = cgx_rd_scr0(cgx, lmac);
 | |
| 		/* clear async events if any */
 | |
| 		if (scr0.s.evt_sts.evt_type == CGX_EVT_ASYNC &&
 | |
| 		    scr0.s.evt_sts.ack) {
 | |
| 			/* clear interrupt */
 | |
| 			cmrx_int = readq(CGX_CMR_INT +
 | |
| 					 CGX_SHIFT(cgx) + CMR_SHIFT(lmac));
 | |
| 			cmrx_int |= 0x2; // Overflw bit
 | |
| 			writeq(cmrx_int, CGX_CMR_INT +
 | |
| 					 CGX_SHIFT(cgx) + CMR_SHIFT(lmac));
 | |
| 
 | |
| 			/* clear ack */
 | |
| 			scr0.s.evt_sts.ack = 0;
 | |
| 			cgx_wr_scr0(cgx, lmac, scr0.u);
 | |
| 		}
 | |
| 
 | |
| 		if (timeout-- < 0) {
 | |
| 			debug("timeout waiting for ownership\n");
 | |
| 			return -ETIMEDOUT;
 | |
| 		}
 | |
| 		mdelay(1);
 | |
| 	} while ((scr1.s.own_status == CGX_OWN_FIRMWARE) &&
 | |
| 		  scr0.s.evt_sts.ack);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int cgx_intf_req(u8 cgx, u8 lmac, union cgx_cmd_s cmd_args, u64 *rsp,
 | |
| 		 int use_cmd_id_only)
 | |
| {
 | |
| 	union cgx_scratchx1 scr1;
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	u64 cmrx_int;
 | |
| 	int timeout = 500;
 | |
| 	int err = 0;
 | |
| 	u8 cmd = cmd_args.cmd.id;
 | |
| 
 | |
| 	if (wait_for_ownership(cgx, lmac)) {
 | |
| 		err = -ETIMEDOUT;
 | |
| 		goto error;
 | |
| 	}
 | |
| 
 | |
| 	/* send command */
 | |
| 	scr1.u = cgx_rd_scr1(cgx, lmac);
 | |
| 
 | |
| 	if (use_cmd_id_only) {
 | |
| 		scr1.s.cmd.id = cmd;
 | |
| 	} else {
 | |
| 		cmd_args.own_status = scr1.s.own_status;
 | |
| 		scr1.s = cmd_args;
 | |
| 	}
 | |
| 	cgx_wr_scr1(cgx, lmac, scr1.u);
 | |
| 
 | |
| 	set_ownership(cgx, lmac, CGX_OWN_FIRMWARE);
 | |
| 
 | |
| 	/* wait for response and ownership */
 | |
| 	do {
 | |
| 		scr0.u = cgx_rd_scr0(cgx, lmac);
 | |
| 		scr1.u = cgx_rd_scr1(cgx, lmac);
 | |
| 		mdelay(10);
 | |
| 	} while (timeout-- && (!scr0.s.evt_sts.ack) &&
 | |
| 		 (scr1.s.own_status == CGX_OWN_FIRMWARE));
 | |
| 	if (timeout < 0) {
 | |
| 		debug("%s timeout waiting for ack\n", __func__);
 | |
| 		err = -ETIMEDOUT;
 | |
| 		goto error;
 | |
| 	}
 | |
| 
 | |
| 	if (cmd == CGX_CMD_INTF_SHUTDOWN)
 | |
| 		goto error;
 | |
| 
 | |
| 	if (scr0.s.evt_sts.evt_type != CGX_EVT_CMD_RESP) {
 | |
| 		debug("%s received async event instead of cmd resp event\n",
 | |
| 		      __func__);
 | |
| 		err = -1;
 | |
| 		goto error;
 | |
| 	}
 | |
| 	if (scr0.s.evt_sts.id != cmd) {
 | |
| 		debug("%s received resp for cmd %d expected cmd %d\n",
 | |
| 		      __func__, scr0.s.evt_sts.id, cmd);
 | |
| 		err = -1;
 | |
| 		goto error;
 | |
| 	}
 | |
| 	if (scr0.s.evt_sts.stat != CGX_STAT_SUCCESS) {
 | |
| 		debug("%s cmd%d failed on cgx%u lmac%u with errcode %d\n",
 | |
| 		      __func__, cmd, cgx, lmac, scr0.s.link_sts.err_type);
 | |
| 		err = -1;
 | |
| 	}
 | |
| 
 | |
| error:
 | |
| 	/* clear interrupt */
 | |
| 	cmrx_int = readq(CGX_CMR_INT + CGX_SHIFT(cgx) + CMR_SHIFT(lmac));
 | |
| 	cmrx_int |= 0x2; // Overflw bit
 | |
| 	writeq(cmrx_int, CGX_CMR_INT + CGX_SHIFT(cgx) + CMR_SHIFT(lmac));
 | |
| 
 | |
| 	/* clear ownership and ack */
 | |
| 	scr0.s.evt_sts.ack = 0;
 | |
| 	cgx_wr_scr0(cgx, lmac, scr0.u);
 | |
| 
 | |
| 	*rsp = err ? 0 : scr0.u;
 | |
| 
 | |
| 	return err;
 | |
| }
 | |
| 
 | |
| int cgx_intf_get_mac_addr(u8 cgx, u8 lmac, u8 *mac)
 | |
| {
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	int ret;
 | |
| 	union cgx_cmd_s cmd;
 | |
| 
 | |
| 	cmd.cmd.id = CGX_CMD_GET_MAC_ADDR;
 | |
| 
 | |
| 	ret = cgx_intf_req(cgx, lmac, cmd, &scr0.u, 1);
 | |
| 	if (ret)
 | |
| 		return -1;
 | |
| 
 | |
| 	scr0.u >>= 9;
 | |
| 	memcpy(mac, &scr0.u, 6);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int cgx_intf_get_ver(u8 cgx, u8 lmac, u8 *ver)
 | |
| {
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	int ret;
 | |
| 	union cgx_cmd_s cmd;
 | |
| 
 | |
| 	cmd.cmd.id = CGX_CMD_GET_FW_VER;
 | |
| 
 | |
| 	ret = cgx_intf_req(cgx, lmac, cmd, &scr0.u, 1);
 | |
| 	if (ret)
 | |
| 		return -1;
 | |
| 
 | |
| 	scr0.u >>= 9;
 | |
| 	*ver = scr0.u & 0xFFFF;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int cgx_intf_get_link_sts(u8 cgx, u8 lmac, u64 *lnk_sts)
 | |
| {
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	int ret;
 | |
| 	union cgx_cmd_s cmd;
 | |
| 
 | |
| 	cmd.cmd.id = CGX_CMD_GET_LINK_STS;
 | |
| 
 | |
| 	ret = cgx_intf_req(cgx, lmac, cmd, &scr0.u, 1);
 | |
| 	if (ret)
 | |
| 		return -1;
 | |
| 
 | |
| 	scr0.u >>= 9;
 | |
| 	/* pass the same format as cgx_lnk_sts_s
 | |
| 	 * err_type:10, speed:4, full_duplex:1, link_up:1
 | |
| 	 */
 | |
| 	*lnk_sts = scr0.u & 0xFFFF;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int cgx_intf_link_up_dwn(u8 cgx, u8 lmac, u8 up_dwn, u64 *lnk_sts)
 | |
| {
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	int ret;
 | |
| 	union cgx_cmd_s cmd;
 | |
| 
 | |
| 	cmd.cmd.id = up_dwn ? CGX_CMD_LINK_BRING_UP : CGX_CMD_LINK_BRING_DOWN;
 | |
| 
 | |
| 	ret = cgx_intf_req(cgx, lmac, cmd, &scr0.u, 1);
 | |
| 	if (ret)
 | |
| 		return -1;
 | |
| 
 | |
| 	scr0.u >>= 9;
 | |
| 	/* pass the same format as cgx_lnk_sts_s
 | |
| 	 * err_type:10, speed:4, full_duplex:1, link_up:1
 | |
| 	 */
 | |
| 	*lnk_sts = scr0.u & 0xFFFF;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void cgx_intf_shutdown(void)
 | |
| {
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	union cgx_cmd_s cmd;
 | |
| 
 | |
| 	cmd.cmd.id = CGX_CMD_INTF_SHUTDOWN;
 | |
| 
 | |
| 	cgx_intf_req(0, 0, cmd, &scr0.u, 1);
 | |
| }
 | |
| 
 | |
| int cgx_intf_prbs(u8 qlm, u8 mode, u32 time, u8 lane)
 | |
| {
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	int ret;
 | |
| 	union cgx_cmd_s cmd;
 | |
| 
 | |
| 	cmd.cmd.id = CGX_CMD_PRBS;
 | |
| 
 | |
| 	cmd.prbs_args.qlm = qlm;
 | |
| 	cmd.prbs_args.mode = mode;
 | |
| 	cmd.prbs_args.time = time;
 | |
| 	cmd.prbs_args.lane = lane;
 | |
| 
 | |
| 	ret = cgx_intf_req(0, 0, cmd, &scr0.u, 0);
 | |
| 	if (ret)
 | |
| 		return -1;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| enum cgx_mode {
 | |
| 	MODE_10G_C2C,
 | |
| 	MODE_10G_C2M,
 | |
| 	MODE_10G_KR,
 | |
| 	MODE_25G_C2C,
 | |
| 	MODE_25G_2_C2C,
 | |
| 	MODE_50G_C2C,
 | |
| 	MODE_50G_4_C2C
 | |
| };
 | |
| 
 | |
| static char intf_speed_to_str[][8] = {
 | |
| 	"10M",
 | |
| 	"100M",
 | |
| 	"1G",
 | |
| 	"2.5G",
 | |
| 	"5G",
 | |
| 	"10G",
 | |
| 	"20G",
 | |
| 	"25G",
 | |
| 	"40G",
 | |
| 	"50G",
 | |
| 	"80G",
 | |
| 	"100G",
 | |
| };
 | |
| 
 | |
| static void mode_to_args(int mode, struct cgx_mode_change_args *args)
 | |
| {
 | |
| 	args->an = 0;
 | |
| 	args->duplex = 0;
 | |
| 	args->port = 0;
 | |
| 
 | |
| 	switch (mode) {
 | |
| 	case MODE_10G_C2C:
 | |
| 		args->speed = CGX_LINK_10G;
 | |
| 		args->mode = BIT_ULL(CGX_MODE_10G_C2C_BIT);
 | |
| 		break;
 | |
| 	case MODE_10G_C2M:
 | |
| 		args->speed = CGX_LINK_10G;
 | |
| 		args->mode = BIT_ULL(CGX_MODE_10G_C2M_BIT);
 | |
| 		break;
 | |
| 	case MODE_10G_KR:
 | |
| 		args->speed = CGX_LINK_10G;
 | |
| 		args->mode = BIT_ULL(CGX_MODE_10G_KR_BIT);
 | |
| 		args->an = 1;
 | |
| 		break;
 | |
| 	case MODE_25G_C2C:
 | |
| 		args->speed = CGX_LINK_25G;
 | |
| 		args->mode = BIT_ULL(CGX_MODE_25G_C2C_BIT);
 | |
| 		break;
 | |
| 	case MODE_25G_2_C2C:
 | |
| 		args->speed = CGX_LINK_25G;
 | |
| 		args->mode = BIT_ULL(CGX_MODE_25G_2_C2C_BIT);
 | |
| 		break;
 | |
| 	case MODE_50G_C2C:
 | |
| 		args->speed = CGX_LINK_50G;
 | |
| 		args->mode = BIT_ULL(CGX_MODE_50G_C2C_BIT);
 | |
| 		break;
 | |
| 	case MODE_50G_4_C2C:
 | |
| 		args->speed = CGX_LINK_50G;
 | |
| 		args->mode = BIT_ULL(CGX_MODE_50G_4_C2C_BIT);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int cgx_intf_set_mode(struct udevice *ethdev, int mode)
 | |
| {
 | |
| 	struct rvu_pf *rvu = dev_get_priv(ethdev);
 | |
| 	struct nix *nix = rvu->nix;
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	int ret;
 | |
| 	union cgx_cmd_s cmd;
 | |
| 
 | |
| 	cmd.cmd.id = CGX_CMD_MODE_CHANGE;
 | |
| 
 | |
| 	mode_to_args(mode, &cmd.mode_change_args);
 | |
| 
 | |
| 	ret = cgx_intf_req(nix->lmac->cgx->cgx_id, nix->lmac->lmac_id,
 | |
| 			   cmd, &scr0.u, 0);
 | |
| 	if (ret) {
 | |
| 		printf("Mode change command failed for %s\n", ethdev->name);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	cmd.cmd.id = CGX_CMD_GET_LINK_STS;
 | |
| 	ret = cgx_intf_req(nix->lmac->cgx->cgx_id, nix->lmac->lmac_id,
 | |
| 			   cmd, &scr0.u, 1);
 | |
| 	if (ret) {
 | |
| 		printf("Get Link Status failed for %s\n", ethdev->name);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	printf("Current Link Status: ");
 | |
| 	if (scr0.s.link_sts.speed) {
 | |
| 		printf("%s\n", intf_speed_to_str[scr0.s.link_sts.speed]);
 | |
| 		switch (scr0.s.link_sts.fec) {
 | |
| 		case 0:
 | |
| 			printf("FEC_NONE\n");
 | |
| 			break;
 | |
| 		case 1:
 | |
| 			printf("FEC_BASE_R\n");
 | |
| 			break;
 | |
| 		case 2:
 | |
| 			printf("FEC_RS\n");
 | |
| 			break;
 | |
| 		}
 | |
| 		printf("Auto Negotiation %sabled\n",
 | |
| 		       scr0.s.link_sts.an ? "En" : "Dis");
 | |
| 		printf("%s Duplex\n",
 | |
| 		       scr0.s.link_sts.full_duplex ? "Full" : "Half");
 | |
| 	} else {
 | |
| 		printf("Down\n");
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int cgx_intf_get_mode(struct udevice *ethdev)
 | |
| {
 | |
| 	struct rvu_pf *rvu = dev_get_priv(ethdev);
 | |
| 	struct nix *nix = rvu->nix;
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	int ret;
 | |
| 	union cgx_cmd_s cmd;
 | |
| 
 | |
| 	cmd.cmd.id = CGX_CMD_GET_LINK_STS;
 | |
| 	ret = cgx_intf_req(nix->lmac->cgx->cgx_id, nix->lmac->lmac_id,
 | |
| 			   cmd, &scr0.u, 1);
 | |
| 	if (ret) {
 | |
| 		printf("Get link status failed for %s\n", ethdev->name);
 | |
| 		return -1;
 | |
| 	}
 | |
| 	printf("Current Interface Mode: ");
 | |
| 	switch (scr0.s.link_sts.mode) {
 | |
| 	case CGX_MODE_10G_C2C_BIT:
 | |
| 		printf("10G_C2C\n");
 | |
| 		break;
 | |
| 	case CGX_MODE_10G_C2M_BIT:
 | |
| 		printf("10G_C2M\n");
 | |
| 		break;
 | |
| 	case CGX_MODE_10G_KR_BIT:
 | |
| 		printf("10G_KR\n");
 | |
| 		break;
 | |
| 	case CGX_MODE_25G_C2C_BIT:
 | |
| 		printf("25G_C2C\n");
 | |
| 		break;
 | |
| 	case CGX_MODE_25G_2_C2C_BIT:
 | |
| 		printf("25G_2_C2C\n");
 | |
| 		break;
 | |
| 	case CGX_MODE_50G_C2C_BIT:
 | |
| 		printf("50G_C2C\n");
 | |
| 		break;
 | |
| 	case CGX_MODE_50G_4_C2C_BIT:
 | |
| 		printf("50G_4_C2C\n");
 | |
| 		break;
 | |
| 	default:
 | |
| 		printf("Unknown\n");
 | |
| 		break;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int cgx_intf_get_fec(struct udevice *ethdev)
 | |
| {
 | |
| 	struct rvu_pf *rvu = dev_get_priv(ethdev);
 | |
| 	struct nix *nix = rvu->nix;
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	int ret;
 | |
| 	union cgx_cmd_s cmd;
 | |
| 
 | |
| 	cmd.cmd.id = CGX_CMD_GET_SUPPORTED_FEC;
 | |
| 
 | |
| 	ret = cgx_intf_req(nix->lmac->cgx->cgx_id, nix->lmac->lmac_id,
 | |
| 			   cmd, &scr0.u, 1);
 | |
| 	if (ret) {
 | |
| 		printf("Get supported FEC failed for %s\n", ethdev->name);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	printf("Supported FEC type: ");
 | |
| 	switch (scr0.s.supported_fec.fec) {
 | |
| 	case 0:
 | |
| 		printf("FEC_NONE\n");
 | |
| 		break;
 | |
| 	case 1:
 | |
| 		printf("FEC_BASE_R\n");
 | |
| 		break;
 | |
| 	case 2:
 | |
| 		printf("FEC_RS\n");
 | |
| 		break;
 | |
| 	case 3:
 | |
| 		printf("FEC_BASE_R FEC_RS\n");
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	cmd.cmd.id = CGX_CMD_GET_LINK_STS;
 | |
| 	ret = cgx_intf_req(nix->lmac->cgx->cgx_id, nix->lmac->lmac_id,
 | |
| 			   cmd, &scr0.u, 1);
 | |
| 	if (ret) {
 | |
| 		printf("Get active fec failed for %s\n", ethdev->name);
 | |
| 		return -1;
 | |
| 	}
 | |
| 	printf("Active FEC type: ");
 | |
| 	switch (scr0.s.link_sts.fec) {
 | |
| 	case 0:
 | |
| 		printf("FEC_NONE\n");
 | |
| 		break;
 | |
| 	case 1:
 | |
| 		printf("FEC_BASE_R\n");
 | |
| 		break;
 | |
| 	case 2:
 | |
| 		printf("FEC_RS\n");
 | |
| 		break;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int cgx_intf_set_fec(struct udevice *ethdev, int type)
 | |
| {
 | |
| 	struct rvu_pf *rvu = dev_get_priv(ethdev);
 | |
| 	struct nix *nix = rvu->nix;
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	int ret;
 | |
| 	union cgx_cmd_s cmd;
 | |
| 
 | |
| 	cmd.cmd.id = CGX_CMD_SET_FEC;
 | |
| 	cmd.fec_args.fec = type;
 | |
| 
 | |
| 	ret = cgx_intf_req(nix->lmac->cgx->cgx_id, nix->lmac->lmac_id,
 | |
| 			   cmd, &scr0.u, 0);
 | |
| 	if (ret) {
 | |
| 		printf("Set FEC type %d failed for %s\n", type, ethdev->name);
 | |
| 		return -1;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int cgx_intf_get_phy_mod_type(struct udevice *ethdev)
 | |
| {
 | |
| 	struct rvu_pf *rvu = dev_get_priv(ethdev);
 | |
| 	struct nix *nix = rvu->nix;
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	int ret;
 | |
| 	union cgx_cmd_s cmd;
 | |
| 
 | |
| 	cmd.cmd.id = CGX_CMD_GET_PHY_MOD_TYPE;
 | |
| 
 | |
| 	ret = cgx_intf_req(nix->lmac->cgx->cgx_id, nix->lmac->lmac_id,
 | |
| 			   cmd, &scr0.u, 1);
 | |
| 	if (ret) {
 | |
| 		printf("Get PHYMOD type failed for %s\n", ethdev->name);
 | |
| 		return -1;
 | |
| 	}
 | |
| 	printf("Current phy mod type %s\n",
 | |
| 	       scr0.s.phy_mod_type.mod ? "PAM4" : "NRZ");
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int cgx_intf_set_phy_mod_type(struct udevice *ethdev, int type)
 | |
| {
 | |
| 	struct rvu_pf *rvu = dev_get_priv(ethdev);
 | |
| 	struct nix *nix = rvu->nix;
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	int ret;
 | |
| 	union cgx_cmd_s cmd;
 | |
| 
 | |
| 	cmd.cmd.id = CGX_CMD_SET_PHY_MOD_TYPE;
 | |
| 	cmd.phy_mod_args.mod = type;
 | |
| 
 | |
| 	ret = cgx_intf_req(nix->lmac->cgx->cgx_id, nix->lmac->lmac_id,
 | |
| 			   cmd, &scr0.u, 0);
 | |
| 	if (ret) {
 | |
| 		printf("Set PHYMOD type %d failed for %s\n", type,
 | |
| 		       ethdev->name);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int cgx_intf_set_an_lbk(struct udevice *ethdev, int enable)
 | |
| {
 | |
| 	struct rvu_pf *rvu = dev_get_priv(ethdev);
 | |
| 	struct nix *nix = rvu->nix;
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	int ret;
 | |
| 	union cgx_cmd_s cmd;
 | |
| 
 | |
| 	cmd.cmd.id = CGX_CMD_AN_LOOPBACK;
 | |
| 	cmd.cmd_args.enable = enable;
 | |
| 
 | |
| 	ret = cgx_intf_req(nix->lmac->cgx->cgx_id, nix->lmac->lmac_id,
 | |
| 			   cmd, &scr0.u, 0);
 | |
| 	if (ret) {
 | |
| 		printf("Set AN loopback command failed on %s\n", ethdev->name);
 | |
| 		return -1;
 | |
| 	}
 | |
| 	printf("AN loopback %s for %s\n", enable ? "set" : "clear",
 | |
| 	       ethdev->name);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int cgx_intf_get_ignore(struct udevice *ethdev, int cgx, int lmac)
 | |
| {
 | |
| 	struct rvu_pf *rvu;
 | |
| 	struct nix *nix;
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	int ret, cgx_id = cgx, lmac_id = lmac;
 | |
| 	union cgx_cmd_s cmd;
 | |
| 
 | |
| 	if (ethdev) {
 | |
| 		rvu = dev_get_priv(ethdev);
 | |
| 		nix = rvu->nix;
 | |
| 		cgx_id = nix->lmac->cgx->cgx_id;
 | |
| 		lmac_id = nix->lmac->lmac_id;
 | |
| 	}
 | |
| 	cmd.cmd.id = CGX_CMD_GET_PERSIST_IGNORE;
 | |
| 
 | |
| 	ret = cgx_intf_req(cgx_id, lmac_id, cmd, &scr0.u, 1);
 | |
| 	if (ret) {
 | |
| 		if (ethdev)
 | |
| 			printf("Get ignore command failed for %s\n",
 | |
| 			       ethdev->name);
 | |
| 		else
 | |
| 			printf("Get ignore command failed for CGX%d LMAC%d\n",
 | |
| 			       cgx_id, lmac_id);
 | |
| 		return -1;
 | |
| 	}
 | |
| 	if (ethdev)
 | |
| 		printf("Persist settings %signored for %s\n",
 | |
| 		       scr0.s.persist.ignore ? "" : "not ", ethdev->name);
 | |
| 	else
 | |
| 		printf("Persist settings %signored for CGX%d LMAC%d\n",
 | |
| 		       scr0.s.persist.ignore ? "" : "not ", cgx_id, lmac_id);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int cgx_intf_set_ignore(struct udevice *ethdev, int cgx, int lmac, int ignore)
 | |
| {
 | |
| 	struct rvu_pf *rvu;
 | |
| 	struct nix *nix;
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	int ret, cgx_id = cgx, lmac_id = lmac;
 | |
| 	union cgx_cmd_s cmd;
 | |
| 
 | |
| 	if (ethdev) {
 | |
| 		rvu = dev_get_priv(ethdev);
 | |
| 		nix = rvu->nix;
 | |
| 		cgx_id = nix->lmac->cgx->cgx_id;
 | |
| 		lmac_id = nix->lmac->lmac_id;
 | |
| 	}
 | |
| 	cmd.cmd.id = CGX_CMD_SET_PERSIST_IGNORE;
 | |
| 	cmd.persist_args.ignore = ignore;
 | |
| 
 | |
| 	ret = cgx_intf_req(cgx_id, lmac_id, cmd, &scr0.u, 0);
 | |
| 	if (ret) {
 | |
| 		if (ethdev)
 | |
| 			printf("Set ignore command failed for %s\n",
 | |
| 			       ethdev->name);
 | |
| 		else
 | |
| 			printf("Set ignore command failed for CGX%d LMAC%d\n",
 | |
| 			       cgx_id, lmac_id);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int cgx_intf_set_macaddr(struct udevice *ethdev)
 | |
| {
 | |
| 	struct rvu_pf *rvu = dev_get_priv(ethdev);
 | |
| 	struct nix *nix = rvu->nix;
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	int ret;
 | |
| 	union cgx_cmd_s cmd;
 | |
| 	u64 mac, tmp;
 | |
| 
 | |
| 	memcpy((void *)&tmp, nix->lmac->mac_addr, 6);
 | |
| 	mac = swab64(tmp) >> 16;
 | |
| 	cmd.cmd.id = CGX_CMD_SET_MAC_ADDR;
 | |
| 	cmd.mac_args.addr = mac;
 | |
| 	cmd.mac_args.pf_id = rvu->pfid;
 | |
| 
 | |
| 	ret = cgx_intf_req(nix->lmac->cgx->cgx_id, nix->lmac->lmac_id,
 | |
| 			   cmd, &scr0.u, 0);
 | |
| 	if (ret) {
 | |
| 		printf("Set user mac addr failed for %s\n", ethdev->name);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int cgx_intf_display_eye(u8 qlm, u8 lane)
 | |
| {
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	int ret;
 | |
| 	union cgx_cmd_s cmd;
 | |
| 
 | |
| 	cmd.cmd.id = CGX_CMD_DISPLAY_EYE;
 | |
| 
 | |
| 	cmd.dsp_eye_args.qlm = qlm;
 | |
| 	cmd.dsp_eye_args.lane = lane;
 | |
| 
 | |
| 	ret = cgx_intf_req(0, 0, cmd, &scr0.u, 0);
 | |
| 	if (ret)
 | |
| 		return -1;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int cgx_intf_display_serdes(u8 qlm, u8 lane)
 | |
| {
 | |
| 	union cgx_scratchx0 scr0;
 | |
| 	int ret;
 | |
| 	union cgx_cmd_s cmd;
 | |
| 
 | |
| 	cmd.cmd.id = CGX_CMD_DISPLAY_SERDES;
 | |
| 
 | |
| 	cmd.dsp_eye_args.qlm = qlm;
 | |
| 	cmd.dsp_eye_args.lane = lane;
 | |
| 
 | |
| 	ret = cgx_intf_req(0, 0, cmd, &scr0.u, 0);
 | |
| 	if (ret)
 | |
| 		return -1;
 | |
| 
 | |
| 	return 0;
 | |
| }
 |