diff options
| author | Suneel Garapati <sgarapati@marvell.com> | 2020-08-26 14:37:33 +0200 |
|---|---|---|
| committer | Stefan Roese <sr@denx.de> | 2020-10-14 07:55:56 +0200 |
| commit | 0008e9a69da07a93d589b51922d80d9044233acb (patch) | |
| tree | 121126866f42b6bae4546bc48ccbf8c229fa3865 /drivers/net/octeontx/xcv.c | |
| parent | 05c7606ac928ae90451e0c0b2517d13e40452b59 (diff) | |
net: Add NIC controller driver for OcteonTX
Adds support for Network Interface controllers found on
OcteonTX 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>
Diffstat (limited to 'drivers/net/octeontx/xcv.c')
| -rw-r--r-- | drivers/net/octeontx/xcv.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/drivers/net/octeontx/xcv.c b/drivers/net/octeontx/xcv.c new file mode 100644 index 00000000000..8dd558b1bf2 --- /dev/null +++ b/drivers/net/octeontx/xcv.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Marvell International Ltd. + */ + +#include <config.h> +#include <dm.h> +#include <errno.h> +#include <fdt_support.h> +#include <pci.h> +#include <malloc.h> +#include <miiphy.h> +#include <misc.h> +#include <net.h> +#include <netdev.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <linux/libfdt.h> + +#include <asm/arch/csrs/csrs-xcv.h> + +#define XCVX_BASE 0x87E0DB000000ULL + +/* Initialize XCV block */ +void xcv_init_hw(void) +{ + union xcvx_reset reset; + union xcvx_dll_ctl xcv_dll_ctl; + + /* Take the DLL out of reset */ + reset.u = readq(XCVX_BASE + XCVX_RESET(0)); + reset.s.dllrst = 0; + writeq(reset.u, XCVX_BASE + XCVX_RESET(0)); + + /* Take the clock tree out of reset */ + reset.u = readq(XCVX_BASE + XCVX_RESET(0)); + reset.s.clkrst = 0; + writeq(reset.u, XCVX_BASE + XCVX_RESET(0)); + + /* Once the 125MHz ref clock is stable, wait 10us for DLL to lock */ + udelay(10); + + /* Optionally, bypass the DLL setting */ + xcv_dll_ctl.u = readq(XCVX_BASE + XCVX_DLL_CTL(0)); + xcv_dll_ctl.s.clkrx_set = 0; + xcv_dll_ctl.s.clkrx_byp = 1; + xcv_dll_ctl.s.clktx_byp = 0; + writeq(xcv_dll_ctl.u, XCVX_BASE + XCVX_DLL_CTL(0)); + + /* Enable the compensation controller */ + reset.u = readq(XCVX_BASE + XCVX_RESET(0)); + reset.s.comp = 1; + writeq(reset.u, XCVX_BASE + XCVX_RESET(0)); + reset.u = readq(XCVX_BASE + XCVX_RESET(0)); + + /* Wait for 1040 reference clock cycles for the compensation state + * machine lock. + */ + udelay(100); + + /* Enable the XCV block */ + reset.u = readq(XCVX_BASE + XCVX_RESET(0)); + reset.s.enable = 1; + writeq(reset.u, XCVX_BASE + XCVX_RESET(0)); + + /* set XCV(0)_RESET[CLKRST] to 1 */ + reset.u = readq(XCVX_BASE + XCVX_RESET(0)); + reset.s.clkrst = 1; + writeq(reset.u, XCVX_BASE + XCVX_RESET(0)); +} + +/* + * Configure XCV link based on the speed + * link_up : Set to 1 when link is up otherwise 0 + * link_speed: The speed of the link. + */ +void xcv_setup_link(bool link_up, int link_speed) +{ + union xcvx_ctl xcv_ctl; + union xcvx_reset reset; + union xcvx_batch_crd_ret xcv_crd_ret; + int speed = 2; + + /* Check RGMII link */ + if (link_speed == 100) + speed = 1; + else if (link_speed == 10) + speed = 0; + + if (link_up) { + /* Set operating speed */ + xcv_ctl.u = readq(XCVX_BASE + XCVX_CTL(0)); + xcv_ctl.s.speed = speed; + writeq(xcv_ctl.u, XCVX_BASE + XCVX_CTL(0)); + + /* Datapaths come out of reset + * - The datapath resets will disengage BGX from the + * RGMII interface + * - XCV will continue to return TX credits for each tick + * that is sent on the TX data path + */ + reset.u = readq(XCVX_BASE + XCVX_RESET(0)); + reset.s.tx_dat_rst_n = 1; + reset.s.rx_dat_rst_n = 1; + writeq(reset.u, XCVX_BASE + XCVX_RESET(0)); + + /* Enable packet flow */ + reset.u = readq(XCVX_BASE + XCVX_RESET(0)); + reset.s.tx_pkt_rst_n = 1; + reset.s.rx_pkt_rst_n = 1; + writeq(reset.u, XCVX_BASE + XCVX_RESET(0)); + + xcv_crd_ret.u = readq(XCVX_BASE + XCVX_BATCH_CRD_RET(0)); + xcv_crd_ret.s.crd_ret = 1; + writeq(xcv_crd_ret.u, XCVX_BASE + XCVX_BATCH_CRD_RET(0)); + } else { + /* Enable packet flow */ + reset.u = readq(XCVX_BASE + XCVX_RESET(0)); + reset.s.tx_pkt_rst_n = 0; + reset.s.rx_pkt_rst_n = 0; + writeq(reset.u, XCVX_BASE + XCVX_RESET(0)); + reset.u = readq(XCVX_BASE + XCVX_RESET(0)); + } +} |
