123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715 |
- // 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;
- }
|