[PATCH v4 1/2] net: cortina_ni: Add eth support for Cortina Access CAxxxx SoCs

Alex Nemirovsky alex.nemirovsky at cortina-access.com
Wed Jun 3 10:05:18 CEST 2020


From: Aaron Tseng <aaron.tseng at cortina-access.com>

Add Cortina Access Ethernet device driver for CAxxxx SoCs.
This driver supports only the DM_ETH network model.

Signed-off-by: Aaron Tseng <aaron.tseng at cortina-access.com>
Signed-off-by: Alex Nemirovsky <alex.nemirovsky at cortina-access.com>

CC: Joe Hershberger <joe.hershberger at ni.com>
CC: Abbie Chang <abbie.chang at Cortina-Access.com>
CC: Tom Rini <trini at konsulko.com>

---

Changes in v4: None
Changes in v3:
- Changed commit comment to state that only DM model is supported
- Removed blank line at end of C file

Changes in v2:
- Remove legacy mode support
- Add support for additional SoC variants
- Remove unused variables

 MAINTAINERS              |    4 +
 drivers/net/Kconfig      |    7 +
 drivers/net/Makefile     |    1 +
 drivers/net/cortina_ni.c | 1909 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/cortina_ni.h |  592 ++++++++++++++
 5 files changed, 2513 insertions(+)
 create mode 100644 drivers/net/cortina_ni.c
 create mode 100644 drivers/net/cortina_ni.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 8add9d4..1b166d2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -181,6 +181,8 @@ F:	drivers/gpio/cortina_gpio.c
 F:	drivers/watchdog/cortina_wdt.c
 F:	drivers/serial/serial_cortina.c
 F:	drivers/mmc/ca_dw_mmc.c
+F:	drivers/net/cortina_ni.c
+F:	drivers/net/cortina_ni.h
 
 ARM/CZ.NIC TURRIS MOX SUPPORT
 M:	Marek Behun <marek.behun at nic.cz>
@@ -732,6 +734,8 @@ F:	drivers/gpio/cortina_gpio.c
 F:	drivers/watchdog/cortina_wdt.c
 F:	drivers/serial/serial_cortina.c
 F:	drivers/mmc/ca_dw_mmc.c
+F:	drivers/net/cortina_ni.c
+F:	drivers/net/cortina_ni.h
 
 MIPS MSCC
 M:	Gregory CLEMENT <gregory.clement at bootlin.com>
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index f7855c9..45e0480 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -149,6 +149,13 @@ config BCMGENET
 	help
 	  This driver supports the BCMGENET Ethernet MAC.
 
+config CORTINA_NI_ENET
+    	bool "Cortina-Access Ethernet driver"
+    	depends on DM_ETH && CORTINA_PLATFORM
+    	help
+      	  The driver supports the Cortina-Access Ethernet MAC for
+	  all supported CAxxxx SoCs
+
 config DWC_ETH_QOS
 	bool "Synopsys DWC Ethernet QOS device support"
 	depends on DM_ETH
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 383ed1c..1d6ec4f 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
 obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
 obj-$(CONFIG_BCM_SF2_ETH_GMAC) += bcm-sf2-eth-gmac.o
 obj-$(CONFIG_CALXEDA_XGMAC) += calxedaxgmac.o
+obj-$(CONFIG_CORTINA_NI_ENET) += cortina_ni.o
 obj-$(CONFIG_CS8900) += cs8900.o
 obj-$(CONFIG_TULIP) += dc2114x.o
 obj-$(CONFIG_ETH_DESIGNWARE) += designware.o
diff --git a/drivers/net/cortina_ni.c b/drivers/net/cortina_ni.c
new file mode 100644
index 0000000..d5bbf3e
--- /dev/null
+++ b/drivers/net/cortina_ni.c
@@ -0,0 +1,1909 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * Copyright (C) 2020 Cortina Access Inc.
+ * Author: Aaron Tseng <aaron.tseng at cortina-access.com>
+ *
+ * Ethernet MAC Driver for all supported CAxxxx SoCs
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+#include <env.h>
+#include <linux/delay.h>
+
+#include "cortina_ni.h"
+
+static u32 reg_value;
+
+/* port 0-3 are individual port connect to PHY directly */
+/* port 4-7 are LAN ports connected to QSGMII PHY */
+int active_port = NI_PORT_5;  /* Physical port 5 */
+u32 ge_port_phy_addr;  /* PHY address connected to active port */
+int auto_scan_active_port;
+
+#define HEADER_A_SIZE	8
+
+/*define CORTINA_NI_DBG if individual rx,tx,init needs to be called */
+#if CORTINA_NI_DBG
+static struct udevice	*dbg_dev;
+#endif
+static struct udevice   *curr_dev;
+
+#if defined(CONFIG_TARGET_SATURN_ASIC)
+#define CA_REG_READ(off)        readl((u64)KSEG1_ATU_XLAT(off))
+#define CA_REG_WRITE(data, off) writel(data, (u64)KSEG1_ATU_XLAT(off))
+#else
+#define CA_REG_READ(off)        readl((u64)off)
+#define CA_REG_WRITE(data, off) writel(data, (u64)off)
+#endif
+
+int cortina_ni_recv(struct udevice *netdev);
+static int ca_ni_ofdata_to_platdata(struct udevice *dev);
+
+static u32 *RDWRPTR_ADVANCE_ONE(u32 *x, unsigned long base, unsigned long max)
+{
+	if (x + 1 >= (u32 *)max)
+		return (u32 *)base;
+	else
+		return (x + 1);
+}
+
+static void ni_setup_mac_addr(void)
+{
+	unsigned char mac[6];
+
+	union NI_HV_GLB_MAC_ADDR_CFG0_t		mac_addr_cfg0;
+	union NI_HV_GLB_MAC_ADDR_CFG1_t		mac_addr_cfg1;
+	union NI_HV_PT_PORT_STATIC_CFG_t	port_static_cfg;
+	union NI_HV_XRAM_CPUXRAM_CFG_t		cpuxram_cfg;
+	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
+
+	/* parsing ethaddr and set to NI registers. */
+	if (eth_env_get_enetaddr("ethaddr", mac)) {
+		/* The complete MAC address consists of
+		 * {MAC_ADDR0_mac_addr0[0-3], MAC_ADDR1_mac_addr1[4],
+		 * PT_PORT_STATIC_CFG_mac_addr6[5]}.
+		 */
+		mac_addr_cfg0.bf.mac_addr0 = (mac[0] << 24) +
+					     (mac[1] << 16) +
+					     (mac[2] << 8) +
+					     mac[3];
+		CA_REG_WRITE(mac_addr_cfg0.wrd, priv->ni_hv_base_addr
+				+ NI_HV_GLB_MAC_ADDR_CFG0_OFFSET);
+
+		mac_addr_cfg1.wrd = 0;
+		mac_addr_cfg1.bf.mac_addr1 = mac[4];
+		CA_REG_WRITE(mac_addr_cfg1.wrd, (priv->ni_hv_base_addr +
+				NI_HV_GLB_MAC_ADDR_CFG1_OFFSET));
+
+		port_static_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
+					NI_HV_PT_PORT_STATIC_CFG_OFFSET +
+					APB0_NI_HV_PT_STRIDE * active_port));
+
+		port_static_cfg.bf.mac_addr6 = mac[5];
+		CA_REG_WRITE(port_static_cfg.wrd, (priv->ni_hv_base_addr +
+					NI_HV_PT_PORT_STATIC_CFG_OFFSET +
+					APB0_NI_HV_PT_STRIDE * active_port));
+
+		/* received only Broadcast and Address matched packets */
+		cpuxram_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
+				NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
+		cpuxram_cfg.bf.xram_mgmt_promisc_mode = 0;
+		cpuxram_cfg.bf.rx_0_cpu_pkt_dis = 0;
+		cpuxram_cfg.bf.tx_0_cpu_pkt_dis = 0;
+		CA_REG_WRITE(cpuxram_cfg.wrd, (priv->ni_hv_base_addr +
+					NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
+	} else {
+		/* received all packets(promiscuous mode) */
+		cpuxram_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
+					NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
+		cpuxram_cfg.bf.xram_mgmt_promisc_mode = 3;
+		cpuxram_cfg.bf.rx_0_cpu_pkt_dis = 0;
+		cpuxram_cfg.bf.tx_0_cpu_pkt_dis = 0;
+		CA_REG_WRITE(cpuxram_cfg.wrd, (priv->ni_hv_base_addr +
+					NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
+	}
+}
+
+static void ni_enable_tx_rx(void)
+{
+	union NI_HV_PT_RXMAC_CFG_t rxmac_cfg;
+	union NI_HV_PT_TXMAC_CFG_t txmac_cfg;
+
+	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
+
+	/* Enable TX and RX functions */
+	rxmac_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
+				NI_HV_PT_RXMAC_CFG_OFFSET +
+				APB0_NI_HV_PT_STRIDE * active_port));
+	rxmac_cfg.bf.rx_en = 1;
+	CA_REG_WRITE(rxmac_cfg.wrd, (priv->ni_hv_base_addr +
+				NI_HV_PT_RXMAC_CFG_OFFSET +
+				APB0_NI_HV_PT_STRIDE * active_port));
+
+	txmac_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
+				NI_HV_PT_TXMAC_CFG_OFFSET +
+				APB0_NI_HV_PT_STRIDE * active_port));
+	txmac_cfg.bf.tx_en = 1;
+	CA_REG_WRITE(txmac_cfg.wrd, (priv->ni_hv_base_addr +
+				NI_HV_PT_TXMAC_CFG_OFFSET +
+				APB0_NI_HV_PT_STRIDE * active_port));
+}
+
+void cortina_ni_reset(void)
+{
+	int i;
+	union NI_HV_GLB_INIT_DONE_t		init_done;
+	union NI_HV_GLB_INTF_RST_CONFIG_t	intf_rst_config;
+	union NI_HV_GLB_STATIC_CFG_t		static_cfg;
+	union GLOBAL_BLOCK_RESET_t		glb_blk_reset;
+
+	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
+
+       /* NI global resets */
+	glb_blk_reset.wrd = CA_REG_READ((priv->glb_base_addr +
+				GLOBAL_BLOCK_RESET_OFFSET));
+	glb_blk_reset.bf.reset_ni = 1;
+	CA_REG_WRITE(glb_blk_reset.wrd, (priv->glb_base_addr +
+				GLOBAL_BLOCK_RESET_OFFSET));
+	/* Remove resets */
+	glb_blk_reset.bf.reset_ni = 0;
+	CA_REG_WRITE(glb_blk_reset.wrd, (priv->glb_base_addr +
+				GLOBAL_BLOCK_RESET_OFFSET));
+
+	/* check the ready bit of NI module */
+	for (i = 0; i < NI_READ_POLL_COUNT; i++) {
+		init_done.wrd = CA_REG_READ((priv->ni_hv_base_addr +
+					NI_HV_GLB_INIT_DONE_OFFSET));
+		if (init_done.bf.ni_init_done)
+			break;
+	}
+	if (i == NI_READ_POLL_COUNT) {
+		printf("%s: NI init done not ready, init_done.wrd=0x%x!!!\n",
+		       __func__, init_done.wrd);
+	}
+
+	intf_rst_config.wrd = CA_REG_READ(priv->ni_hv_base_addr +
+					  NI_HV_GLB_INTF_RST_CONFIG_OFFSET);
+	switch (active_port) {
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
+	case NI_PORT_0:
+		intf_rst_config.bf.intf_rst_p0 = 0;
+		intf_rst_config.bf.mac_rx_rst_p0 = 0;
+		intf_rst_config.bf.mac_tx_rst_p0 = 0;
+		break;
+	case NI_PORT_1:
+		intf_rst_config.bf.intf_rst_p1 = 0;
+		intf_rst_config.bf.mac_rx_rst_p1 = 0;
+		intf_rst_config.bf.mac_tx_rst_p1 = 0;
+		break;
+	case NI_PORT_2:
+		intf_rst_config.bf.intf_rst_p2 = 0;
+		intf_rst_config.bf.mac_rx_rst_p2 = 0;
+		intf_rst_config.bf.mac_tx_rst_p2 = 0;
+		break;
+#endif
+	case NI_PORT_3:
+		intf_rst_config.bf.intf_rst_p3 = 0;
+		intf_rst_config.bf.mac_tx_rst_p3 = 0;
+		intf_rst_config.bf.mac_rx_rst_p3 = 0;
+		break;
+	case NI_PORT_4:
+		intf_rst_config.bf.intf_rst_p4 = 0;
+		intf_rst_config.bf.mac_tx_rst_p4 = 0;
+		intf_rst_config.bf.mac_rx_rst_p4 = 0;
+		break;
+	}
+
+	CA_REG_WRITE(intf_rst_config.wrd, (priv->ni_hv_base_addr +
+				NI_HV_GLB_INTF_RST_CONFIG_OFFSET));
+
+	/* Only one GMAC can connect to CPU */
+	static_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
+				NI_HV_GLB_STATIC_CFG_OFFSET));
+
+	static_cfg.bf.port_to_cpu = active_port;
+	static_cfg.bf.txmib_mode = 1;
+	static_cfg.bf.rxmib_mode = 1;
+
+	CA_REG_WRITE(static_cfg.wrd, (priv->ni_hv_base_addr +
+				NI_HV_GLB_STATIC_CFG_OFFSET));
+
+	//printf("%s: Connect port %d to CPU\n", __func__, active_port);
+
+#if defined(CONFIG_TARGET_SATURN_ASIC)
+	/* set IO driver control */
+	io_driver_control.wrd = CA_REG_READ((priv->glb_base_addr +
+				GLOBAL_IO_DRIVE_CONTROL_OFFSET));
+	io_driver_control.bf.gmac_dp = 1;
+	io_driver_control.bf.gmac_dn = 1;
+	io_driver_control.bf.gmac_ds = 0;
+	io_driver_control.bf.gmac_mode = 2;
+	CA_REG_WRITE(io_driver_control.wrd, (priv->glb_base_addr +
+				GLOBAL_IO_DRIVE_CONTROL_OFFSET));
+
+	/* initialize internal GPHY */
+	gige_phy.wrd = 0;
+	gige_phy.bf.gphy_phyrst_cen_b = 1;
+	CA_REG_WRITE(gige_phy.wrd, (priv->glb_base_addr +
+				GLOBAL_GIGE_PHY_OFFSET));
+	mdelay(50);
+
+	CA_REG_WRITE(0xa46, 0xd000b0fc);
+	mdelay(50);
+	CA_REG_WRITE(0x1, 0xd000b0d0);
+	mdelay(100);
+#endif
+}
+
+#define NI_ETH_SPEED_100 0xFFFFFFFE
+#define NI_ETH_DUPLEX_FULL 0xFFFFFFD
+#define PHY_MODE_MFE_MAC	BIT(12)
+
+#define NI_RX_ENB		BIT(2)
+#define NI_TX_ENB		BIT(3)
+#define FLOW_CNTL_RX_DSBL	BIT(8)
+#define FLOW_CNTL_TX_DSBL	BIT(12)
+
+static enum ca_status_t ca_mdio_write_rgmii(unsigned int addr,
+					    unsigned int offset,
+					    unsigned short data)
+{
+	union PER_MDIO_ADDR_t  mdio_addr;
+	union PER_MDIO_CTRL_t  mdio_ctrl;
+	/* up to 10000 cycles*/
+	unsigned int      loop_wait = __MDIO_ACCESS_TIMEOUT;
+
+	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
+
+	mdio_addr.wrd            = 0;
+	mdio_addr.bf.mdio_addr   = addr;
+	mdio_addr.bf.mdio_offset = offset;
+	mdio_addr.bf.mdio_rd_wr  = __MDIO_WR_FLAG;
+	CA_REG_WRITE(mdio_addr.wrd,
+		     priv->per_mdio_base_addr + PER_MDIO_ADDR_OFFSET);
+	CA_REG_WRITE(data,
+		     priv->per_mdio_base_addr + PER_MDIO_WRDATA_OFFSET);
+
+#if CORTINA_NI_DBG
+	printf("%s: mdio_addr.wrd=0x%x\n", __func__, mdio_addr.wrd);
+#endif
+
+	mdio_ctrl.wrd          = 0;
+	mdio_ctrl.bf.mdiostart = 1;
+	CA_REG_WRITE(mdio_ctrl.wrd,
+		     priv->per_mdio_base_addr + PER_MDIO_CTRL_OFFSET);
+
+#if CORTINA_NI_DBG
+	printf("%s: phy_addr=%d, offset=%d, data=0x%x\n",
+	       __func__, addr, offset, data);
+#endif
+
+	do {
+		mdio_ctrl.wrd = CA_REG_READ((priv->per_mdio_base_addr +
+					PER_MDIO_CTRL_OFFSET));
+		if (mdio_ctrl.bf.mdiodone) {
+			CA_REG_WRITE(mdio_ctrl.wrd, (priv->per_mdio_base_addr +
+						PER_MDIO_CTRL_OFFSET));
+			return CA_E_OK;
+		}
+	} while (--loop_wait);
+
+	printf("%s: PHY rite timeout!!!\n", __func__);
+	return CA_E_TIMEOUT;
+}
+
+enum ca_status_t ca_mdio_write(CA_IN       unsigned int             addr,
+			       CA_IN       unsigned int             offset,
+			       CA_IN       unsigned short             data)
+{
+	/* support range: 1~31*/
+	if (addr < CA_MDIO_ADDR_MIN || addr > CA_MDIO_ADDR_MAX)
+		return CA_E_PARAM;
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || \
+	defined(CONFIG_TARGET_SATURN_ASIC) || defined(CONFIG_TARGET_VENUS)
+	union NI_MDIO_OPER_T mdio_oper;
+
+	/* the phy addr 5 is connect to RGMII */
+	if (addr >= 5)
+		return ca_mdio_write_rgmii(addr, offset, data);
+
+	mdio_oper.wrd = 0;
+	mdio_oper.bf.reg_off = offset;
+	mdio_oper.bf.phy_addr = addr;
+	mdio_oper.bf.reg_base = CA_NI_MDIO_REG_BASE;
+	CA_REG_WRITE(data, mdio_oper.wrd);
+
+#if CORTINA_NI_DBG
+	printf("%s: mdio_oper.wrd=0x%x, data=0x%x\n",
+	       __func__, mdio_oper.wrd, data);
+#endif
+	return CA_E_OK;
+#else
+	return ca_mdio_write_rgmii(addr, offset, data);
+#endif
+}
+
+static enum ca_status_t ca_mdio_read_rgmii(unsigned int addr,
+					   unsigned int offset,
+					   unsigned short *data)
+{
+	union PER_MDIO_ADDR_t  mdio_addr;
+	union PER_MDIO_CTRL_t  mdio_ctrl;
+	union PER_MDIO_RDDATA_t  read_data;
+	unsigned int loop_wait = __MDIO_ACCESS_TIMEOUT;
+
+	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
+
+	mdio_addr.wrd            = 0;
+	mdio_addr.bf.mdio_addr   = addr;
+	mdio_addr.bf.mdio_offset = offset;
+	mdio_addr.bf.mdio_rd_wr  = __MDIO_RD_FLAG;
+	CA_REG_WRITE(mdio_addr.wrd,
+		     priv->per_mdio_base_addr + PER_MDIO_ADDR_OFFSET);
+
+	mdio_ctrl.wrd          = 0;
+	mdio_ctrl.bf.mdiostart = 1;
+	CA_REG_WRITE(mdio_ctrl.wrd,
+		     priv->per_mdio_base_addr + PER_MDIO_CTRL_OFFSET);
+
+	do {
+		mdio_ctrl.wrd = CA_REG_READ((priv->per_mdio_base_addr +
+					PER_MDIO_CTRL_OFFSET));
+		if (mdio_ctrl.bf.mdiodone) {
+			CA_REG_WRITE(mdio_ctrl.wrd, (priv->per_mdio_base_addr +
+						PER_MDIO_CTRL_OFFSET));
+			read_data.wrd = CA_REG_READ((priv->per_mdio_base_addr +
+						PER_MDIO_RDDATA_OFFSET));
+			*data = read_data.bf.mdio_rddata;
+			return CA_E_OK;
+		}
+	} while (--loop_wait);
+
+	printf("%s: CA_E_TIMEOUT!!\n", __func__);
+	return CA_E_TIMEOUT;
+}
+
+enum ca_status_t ca_mdio_read(CA_IN       unsigned int          addr,
+			      CA_IN       unsigned int		offset,
+			      CA_OUT      unsigned short	*data)
+{
+	if (!data)
+		return CA_E_PARAM;
+
+	/* support range: 1~31*/
+	if (addr < CA_MDIO_ADDR_MIN || addr > CA_MDIO_ADDR_MAX)
+		return CA_E_PARAM;
+
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || \
+	defined(CONFIG_TARGET_SATURN_ASIC) || defined(CONFIG_TARGET_VENUS)
+	union NI_MDIO_OPER_T  mdio_oper;
+
+	/* the phy addr 5 is connect to RGMII */
+	if (addr >= 5)
+		return  ca_mdio_read_rgmii(addr, offset, data);
+
+	mdio_oper.wrd = 0;
+	mdio_oper.bf.reg_off = offset;
+	mdio_oper.bf.phy_addr = addr;
+	mdio_oper.bf.reg_base = CA_NI_MDIO_REG_BASE;
+	*data = CA_REG_READ(mdio_oper.wrd);
+
+	return CA_E_OK;
+#else
+	return ca_mdio_read_rgmii(addr, offset, data);
+#endif
+}
+
+int ca_miiphy_read(const char *devname,
+		   unsigned char addr,
+		   unsigned char reg,
+		   unsigned short *value)
+{
+	return ca_mdio_read(addr, reg, value);
+}
+
+int ca_miiphy_write(const char *devname,
+		    unsigned char addr,
+		    unsigned char reg,
+		    unsigned short value)
+{
+	return ca_mdio_write(addr, reg, value);
+}
+
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
+static void cortina_ni_fix_gphy(void)
+{
+	u16     data;
+	u8      phy_addr;
+
+	for (phy_addr = 1; phy_addr < 5; phy_addr++) {
+		/* Clear clock fail interrupt */
+		ca_mdio_write(phy_addr, 31, 0xB90);
+		ca_mdio_read(phy_addr, 19, &data);
+		if (data == 0x10) {
+			ca_mdio_write(phy_addr, 31, 0xB90);
+			ca_mdio_read(phy_addr, 19, &data);
+			printf("%s: read again phy_addr=", __func__);
+			printf("%d, read register 19, ", phy_addr);
+			printf("val=0x%x\n", data);
+		}
+#ifdef CORTINA_NI_DBG
+		printf("%s: phy_addr=%d, read register 19, value=0x%x\n",
+		       __func__, phy_addr, data);
+#endif
+	}
+}
+#endif
+
+int cortina_ni_init(struct udevice *dev)
+{
+	u16  vendor_id, chip_id;
+	u32  phy_id;
+	u16  phy_reg_value, lpagb, lpa, phy_speed, phy_duplex, speed, duplex;
+	char *spd, *dup;
+	union NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t	cpuxram_adrcfg_rx;
+	union NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t  cpuxram_adrcfg_tx;
+	union NI_HV_XRAM_CPUXRAM_CFG_t		cpuxram_cfg;
+	union NI_HV_PT_PORT_STATIC_CFG_t	port_static_cfg;
+	union NI_HV_PT_PORT_GLB_CFG_t		port_glb_cfg;
+
+	struct cortina_ni_priv *priv = dev_get_priv(dev);
+
+	/* read "ethaddr" and setup to NI regsiters */
+	ni_setup_mac_addr();
+
+	/* RX XRAM ADDRESS CONFIG (start and end address) */
+	cpuxram_adrcfg_rx.wrd = 0;
+	cpuxram_adrcfg_rx.bf.rx_top_addr = RX_TOP_ADDR;
+	cpuxram_adrcfg_rx.bf.rx_base_addr = RX_BASE_ADDR;
+	CA_REG_WRITE(cpuxram_adrcfg_rx.wrd, (priv->ni_hv_base_addr +
+				NI_HV_XRAM_CPUXRAM_ADRCFG_RX_OFFSET));
+
+	/* TX XRAM ADDRESS CONFIG (start and end address) */
+	cpuxram_adrcfg_tx.wrd = 0;
+	cpuxram_adrcfg_tx.bf.tx_top_addr = TX_TOP_ADDR;
+	cpuxram_adrcfg_tx.bf.tx_base_addr = TX_BASE_ADDR;
+	CA_REG_WRITE(cpuxram_adrcfg_tx.wrd, (priv->ni_hv_base_addr +
+				NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_OFFSET));
+
+	ca_mdio_read(ge_port_phy_addr, 0x02, &vendor_id);
+	ca_mdio_read(ge_port_phy_addr, 0x03, &chip_id);
+	phy_id = (vendor_id << 16) | chip_id;
+
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
+	/* workaround to fix GPHY fail */
+	if ((phy_id & PHY_ID_MASK) == PHY_ID_RTL8211_G3_ASIC)
+		cortina_ni_fix_gphy();
+#endif
+
+	/* PHY GB status */
+	ca_mdio_read(ge_port_phy_addr, 0x0a, &lpagb);
+	/* PHY GB control */
+	ca_mdio_read(ge_port_phy_addr, 0x09, &phy_reg_value);
+	lpagb &= phy_reg_value << 2;
+
+	/* Link Partner Ability */
+	ca_mdio_read(ge_port_phy_addr, 0x05, &lpa);
+	/* PHY Advertisement */
+	ca_mdio_read(ge_port_phy_addr, 0x04, &phy_reg_value);
+	lpa &= phy_reg_value;
+
+	/* phy_speed 0: 10Mbps, 1: 100Mbps, 2: 1000Mbps */
+	/* duplex 0: half duplex, 1: full duplex */
+	phy_speed = 0;
+	phy_duplex = 0;
+	if (lpagb & (3 << 10)) {
+		/* 1000Mbps */
+		phy_speed = 2;
+		if (lpagb & (1 << 11)) {
+			/* 1000Mbps full */
+			duplex = 1;
+		}
+	} else if (lpa & (3 << 7)) {
+		/* 100Mbps */
+		phy_speed = 1;
+		if (lpa & (1 << 8)) {
+			/* 100Mbps full */
+			phy_duplex = 1;
+		}
+	} else if (lpa & (1 << 6)) {
+		/* 10Mbps full */
+		phy_duplex = 1;
+	}
+
+	switch (phy_speed) {
+	default:
+	case 0:
+		spd = "10Mbps";
+		break;
+	case 1:
+		spd = "100Mbps";
+		break;
+	case 2:
+		spd = "1000Mbps";
+		break;
+	}
+
+	if (duplex == 1)
+		dup = "full duplex";
+	else
+		dup = "half duplex";
+
+	printf("PHY ID 0x%08X %s %s\n", phy_id, spd, dup);
+
+	switch (phy_id & PHY_ID_MASK) {
+	case PHY_ID_RTL8214:
+		port_static_cfg.wrd =
+			CA_REG_READ((priv->ni_hv_base_addr +
+				   NI_HV_PT_PORT_STATIC_CFG_OFFSET +
+				   APB0_NI_HV_PT_STRIDE * active_port));
+		/* QSGMII_GE */
+		port_static_cfg.bf.int_cfg = GE_MAC_INTF_QSGMII_1000;
+		CA_REG_WRITE(port_static_cfg.wrd,
+			     (priv->ni_hv_base_addr +
+			      NI_HV_PT_PORT_STATIC_CFG_OFFSET +
+			      APB0_NI_HV_PT_STRIDE * active_port));
+		break;
+	case PHY_ID_RTL8211:
+		/* fallthrough */
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
+	case PHY_ID_RTL8211_G3_ASIC:
+		/* fallthrough */
+#endif
+#ifdef CONFIG_TARGET_SATURN_ASIC
+	case PHY_ID_RTL8211_SATURN_ASIC:
+		/* fallthrough */
+#endif
+	default:
+		/*
+		 * Configuration for Management Ethernet
+		 * Interface:
+		 * - RGMII 1000 mode or RGMII 100 mode
+		 * - MAC mode
+		 */
+		port_static_cfg.wrd =
+			CA_REG_READ((priv->ni_hv_base_addr +
+				    NI_HV_PT_PORT_STATIC_CFG_OFFSET +
+				    APB0_NI_HV_PT_STRIDE * active_port));
+		if (phy_speed == 2 /* 1000Mbps */) {
+			/* port 4 connects to RGMII PHY */
+			if (ge_port_phy_addr == 5)
+				port_static_cfg.bf.int_cfg =
+					GE_MAC_INTF_RGMII_1000;
+			else
+				port_static_cfg.bf.int_cfg = GE_MAC_INTF_GMII;
+		} else {
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || \
+	defined(CONFIG_TARGET_SATURN_ASIC) || defined(CONFIG_TARGET_VENUS)
+			/* port 4 connects to RGMII PHY */
+			if (ge_port_phy_addr == 5) {
+				port_static_cfg.bf.int_cfg =
+					GE_MAC_INTF_RGMII_100;
+			} else {
+				port_static_cfg.bf.int_cfg = GE_MAC_INTF_MII;
+			}
+#else
+			port_static_cfg.bf.int_cfg = GE_MAC_INTF_RGMII_100;
+#endif
+		}
+		CA_REG_WRITE(port_static_cfg.wrd,
+			     (priv->ni_hv_base_addr +
+			     NI_HV_PT_PORT_STATIC_CFG_OFFSET +
+			     APB0_NI_HV_PT_STRIDE * active_port));
+		break;
+	}
+
+	port_glb_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
+				       NI_HV_PT_PORT_GLB_CFG_OFFSET +
+				       APB0_NI_HV_PT_STRIDE * active_port));
+	if (phy_speed == 0)  /* 10Mbps */
+		speed = 1;
+	else
+		speed = 0;
+	if (phy_duplex == 0)  /* half duplex */
+		duplex = 1;
+	else
+		duplex = 0;
+	port_glb_cfg.bf.speed = speed;
+	port_glb_cfg.bf.duplex = duplex;
+	CA_REG_WRITE(port_glb_cfg.wrd, (priv->ni_hv_base_addr +
+					NI_HV_PT_PORT_GLB_CFG_OFFSET +
+					APB0_NI_HV_PT_STRIDE * active_port));
+
+#if FOR_DEBUG
+	/* Enable MFE ethernet interface */
+	reg_value = CA_REG_READ(NI_TOP_NI_INTF_RST_CONFIG);
+	reg_value = reg_value & ~(INTF_RST_GE);
+	CA_REG_WRITE(reg_value, NI_TOP_NI_INTF_RST_CONFIG);
+#endif
+
+	/* Need to toggle the tx and rx cpu_pkt_dis bit */
+	/* after changing Address config register.      */
+	cpuxram_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
+				NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
+	cpuxram_cfg.bf.rx_0_cpu_pkt_dis = 1;
+	cpuxram_cfg.bf.tx_0_cpu_pkt_dis = 1;
+	CA_REG_WRITE(cpuxram_cfg.wrd, (priv->ni_hv_base_addr +
+				NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
+
+	cpuxram_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
+				NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
+	cpuxram_cfg.bf.rx_0_cpu_pkt_dis = 0;
+	cpuxram_cfg.bf.tx_0_cpu_pkt_dis = 0;
+	CA_REG_WRITE(cpuxram_cfg.wrd, (priv->ni_hv_base_addr +
+				NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
+
+	ni_enable_tx_rx();
+
+	return 0;
+}
+
+int cortina_ni_check_rx_packet(void)
+{
+	static int first_time = 1;
+	union NI_HV_XRAM_CPUXRAM_CFG_t        cpuxram_cfg;
+
+	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
+
+	if (first_time) {
+		/* received all kind of packets */
+		cpuxram_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
+					NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
+		cpuxram_cfg.bf.xram_mgmt_promisc_mode = 3;
+		cpuxram_cfg.bf.rx_0_cpu_pkt_dis = 0;
+		cpuxram_cfg.bf.tx_0_cpu_pkt_dis = 0;
+		CA_REG_WRITE(cpuxram_cfg.wrd, (priv->ni_hv_base_addr +
+					NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
+		first_time = 0;
+	}
+
+	cortina_ni_recv(curr_dev);
+	return 0;
+}
+
+/*********************************************
+ * Packet receive routine from Management FE
+ * Expects a previously allocated buffer and
+ * fills the length
+ * Retruns 0 on success -1 on failure
+ *******************************************/
+int cortina_ni_recv(struct udevice *netdev)
+{
+	struct cortina_ni_priv *priv = dev_get_priv(netdev);
+	union NI_HEADER_X_T		header_x;
+	u32			pktlen = 0;
+	u32			sw_rx_rd_ptr;
+	u32			hw_rx_wr_ptr;
+	u32			*rx_xram_ptr;
+	int			loop;
+	u32			*data_ptr;
+	union NI_PACKET_STATUS packet_status;
+	union NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t cpuxram_cpu_sta_rx;
+	union NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t cpuxram_cpu_cfg_rx;
+	int index = 0;
+#ifdef CORTINA_NI_DBG
+	int			blk_num;
+	u8			*ptr;
+#endif
+
+	/* get the hw write pointer */
+	cpuxram_cpu_sta_rx.wrd = CA_REG_READ((priv->ni_hv_base_addr +
+				NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET));
+	hw_rx_wr_ptr = cpuxram_cpu_sta_rx.bf.pkt_wr_ptr;
+
+	/* get the sw read pointer */
+	cpuxram_cpu_cfg_rx.wrd = CA_REG_READ((priv->ni_hv_base_addr +
+				NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET));
+	sw_rx_rd_ptr = cpuxram_cpu_cfg_rx.bf.pkt_rd_ptr;
+
+#if CORTINA_NI_DBG
+	printf("%s: NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0 = 0x%p, ",
+	       __func__,
+	       priv->ni_hv_base_addr + NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET);
+	printf("NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0 = 0x%p\n",
+	       priv->ni_hv_base_addr + NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
+	printf("%s : RX hw_wr_ptr = %d, sw_rd_ptr = %d\n",
+	       __func__, hw_rx_wr_ptr, sw_rx_rd_ptr);
+#endif
+
+	while (sw_rx_rd_ptr != hw_rx_wr_ptr) {
+		/* Point to the absolute memory address of XRAM
+		 * where read pointer is
+		 */
+		rx_xram_ptr = (u32 *)
+			      ((unsigned long)NI_XRAM_BASE + sw_rx_rd_ptr * 8);
+
+		/* Wrap around if required */
+		if (rx_xram_ptr >= (u32 *)(unsigned long)priv->rx_xram_end_adr)
+			rx_xram_ptr = (u32 *)
+				      (unsigned long)priv->rx_xram_base_adr;
+
+		/* Checking header XR. Do not update the read pointer yet */
+		//rx_xram_ptr++;
+		/* skip unused 32-bit in Header XR */
+		rx_xram_ptr = RDWRPTR_ADVANCE_ONE(rx_xram_ptr,
+						  priv->rx_xram_base_adr,
+						  priv->rx_xram_end_adr);
+
+		header_x = (union NI_HEADER_X_T)(*rx_xram_ptr);
+		/* Header XR [31:0] */
+
+		if (*rx_xram_ptr == 0xffffffff)
+			printf("%s: XRAM Error !\n", __func__);
+#if CORTINA_NI_DBG
+		printf("%s : RX next link %x(%d)\n", __func__,
+		       header_x.bf.next_link, header_x.bf.next_link);
+		printf("%s : bytes_valid %x\n", __func__,
+		       header_x.bf.bytes_valid);
+#endif
+
+		if (header_x.bf.ownership == 0) {
+			/* point to Packet status [31:0] */
+			//rx_xram_ptr++;
+			rx_xram_ptr =
+				RDWRPTR_ADVANCE_ONE(rx_xram_ptr,
+						    priv->rx_xram_base_adr,
+						    priv->rx_xram_end_adr);
+
+			packet_status = (union NI_PACKET_STATUS)(*rx_xram_ptr);
+
+#if CORTINA_NI_DBG
+			printf("%s: packet_status=0x%x\n",
+			       __func__, packet_status.wrd);
+#endif
+			if (packet_status.bf.valid == 0) {
+#if CORTINA_NI_DBG
+				printf("%s: Invalid Packet !!, ", __func__);
+				printf("Packet status=0x%x, ",
+				       packet_status.wrd);
+				printf("header_x.bf.next_link=%d\n",
+				       header_x.bf.next_link);
+#endif
+
+				/* Update the software read pointer */
+				CA_REG_WRITE(header_x.bf.next_link,
+					     priv->ni_hv_base_addr +
+					NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
+				return 0;
+			}
+
+			if (packet_status.bf.drop ||
+			    packet_status.bf.runt ||
+			    packet_status.bf.oversize ||
+			    packet_status.bf.jabber ||
+			    packet_status.bf.crc_error ||
+			    packet_status.bf.jumbo) {
+#if CORTINA_NI_DBG
+				printf("%s: Error Packet!! Packet status=0x%x,",
+				       __func__, packet_status.wrd);
+				printf(" header_x.bf.next_link=%d\n",
+				       header_x.bf.next_link);
+#endif
+
+				/* Update the software read pointer */
+				CA_REG_WRITE(header_x.bf.next_link,
+					     priv->ni_hv_base_addr +
+					NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
+				return 0;
+			}
+
+			/* check whether packet size is larger than 1514 */
+			if (packet_status.bf.packet_size > 1518) {
+#if CORTINA_NI_DBG
+				printf("%s: Error Packet !! Packet size=%d, ",
+				       __func__, packet_status.bf.packet_size);
+				printf("larger than 1518, Packet status=0x%x, ",
+				       packet_status.wrd);
+				printf("header_x.bf.next_link=%d\n",
+				       header_x.bf.next_link);
+#endif
+
+				/* Update the software read pointer */
+				CA_REG_WRITE(header_x.bf.next_link,
+					     priv->ni_hv_base_addr +
+					NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
+				return 0;
+			}
+
+			rx_xram_ptr =
+				RDWRPTR_ADVANCE_ONE(rx_xram_ptr,
+						    priv->rx_xram_base_adr,
+						    priv->rx_xram_end_adr);
+
+			pktlen = packet_status.bf.packet_size;
+
+#if CORTINA_NI_DBG
+			printf("%s : rx packet length = %d\n",
+			       __func__, packet_status.bf.packet_size);
+#endif
+
+			rx_xram_ptr =
+				RDWRPTR_ADVANCE_ONE(rx_xram_ptr,
+						    priv->rx_xram_base_adr,
+						    priv->rx_xram_end_adr);
+
+			data_ptr = (u32 *)net_rx_packets[index];
+
+			/* Read out the packet */
+			/* Data is in little endian form in the XRAM */
+
+			/* Send the packet to upper layer */
+
+#if CORTINA_NI_DBG
+			printf("%s: packet data[]=", __func__);
+#endif
+
+			for (loop = 0; loop <= pktlen / 4; loop++) {
+#if CORTINA_NI_DBG
+				ptr = (u8 *)rx_xram_ptr;
+				if (loop < 10)
+					printf("[0x%x]-[0x%x]-[0x%x]-[0x%x]",
+					       ptr[0], ptr[1], ptr[2], ptr[3]);
+#endif
+				*data_ptr++ = *rx_xram_ptr++;
+				/* Wrap around if required */
+				if (rx_xram_ptr >= (u32 *)
+				    (unsigned long)priv->rx_xram_end_adr) {
+					rx_xram_ptr = (u32 *)(unsigned long)
+						       (priv->rx_xram_base_adr);
+				}
+			}
+#if CORTINA_NI_DBG
+				printf("\n");
+#endif
+			net_process_received_packet(net_rx_packets[index],
+						    pktlen);
+			if (++index >= PKTBUFSRX)
+				index = 0;
+#if CORTINA_NI_DBG
+			blk_num = net_rx_packets[index][0x2c] * 255 +
+				net_rx_packets[index][0x2d];
+			printf("%s: tftp block number=%d\n", __func__, blk_num);
+#endif
+
+			/* Update the software read pointer */
+			CA_REG_WRITE(header_x.bf.next_link,
+				     (priv->ni_hv_base_addr +
+				     NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET));
+		}
+
+		/* get the hw write pointer */
+		cpuxram_cpu_sta_rx.wrd =
+			CA_REG_READ((priv->ni_hv_base_addr +
+				   NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET));
+		hw_rx_wr_ptr = cpuxram_cpu_sta_rx.bf.pkt_wr_ptr;
+
+		/* get the sw read pointer */
+		sw_rx_rd_ptr =
+			CA_REG_READ((priv->ni_hv_base_addr +
+				   NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET));
+	}
+	return 0;
+}
+
+/* LITTLE_ENDIAN */
+static u32 calc_crc(u32 crc, u8 const *p, u32 len)
+{
+	int i;
+
+	while (len--) {
+		crc ^= *p++;
+		for (i = 0; i < 8; i++)
+			crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+	}
+	return crc;
+}
+
+static int cortina_ni_send(struct udevice *dev, void *packet, int length)
+{
+	struct cortina_ni_priv *priv = dev_get_priv(dev);
+	u32	hw_tx_rd_ptr;
+	u32	sw_tx_wr_ptr;
+	unsigned int	new_pkt_len;
+	unsigned char	valid_bytes = 0;
+	u32	*tx_xram_ptr;
+	u16  next_link = 0;
+	unsigned char	*pkt_buf_ptr;
+	unsigned int	loop;
+	u32	crc32;
+	union NI_HEADER_X_T	hdr_xt;
+	int		pad = 0;
+	static unsigned char   pkt_buf[2048];
+	u32	*data_ptr;
+	union NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t cpuxram_cpu_cfg_tx;
+#if CORTINA_NI_DBG
+	u8 *ptr;
+#endif
+
+	if (!packet || length > 2032)
+		return -1;
+
+	/* Get the hardware read pointer */
+	hw_tx_rd_ptr = CA_REG_READ((priv->ni_hv_base_addr +
+				  NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET));
+
+	/* Get the software write pointer */
+	sw_tx_wr_ptr = CA_REG_READ((priv->ni_hv_base_addr +
+				  NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET));
+
+#if CORTINA_NI_DBG
+#if defined(CONFIG_TARGET_SATURN_ASIC)
+	printf("%s: NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0=0x%p, ",
+	       __func__,
+	       KSEG1_ATU_XLAT(priv->ni_hv_base_addr +
+			      NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET));
+	printf("NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0=0x%p\n",
+	       KSEG1_ATU_XLAT(priv->ni_hv_base_addr +
+			      NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET));
+#else
+	printf("%s: NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0=0x%p, ",
+	       __func__,
+	       priv->ni_hv_base_addr + NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET);
+	printf("NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0=0x%p\n",
+	       priv->ni_hv_base_addr + NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET);
+#endif
+	printf("%s : hw_tx_rd_ptr = %d\n", __func__, hw_tx_rd_ptr);
+	printf("%s : sw_tx_wr_ptr = %d\n", __func__, sw_tx_wr_ptr);
+#endif
+
+	if (hw_tx_rd_ptr != sw_tx_wr_ptr) {
+		printf("%s: Tx FIFO is not available!\n", __func__);
+		return 1;
+	}
+
+	/* a workaround on 2015/10/01
+	 * the packet size+CRC should be 8-byte alignment
+	 */
+	if (((length + 4) % 8) != 0)
+		length += (8 - ((length + 4) % 8));
+
+	memset(pkt_buf, 0x00, sizeof(pkt_buf));
+
+	/* add 8-byte header_A at the beginning of packet */
+	//memcpy(&(pkt_buf[0]), (const void *)packet, 8);
+	memcpy(&pkt_buf[HEADER_A_SIZE], (const void *)packet, length);
+
+	pad = 64 - (length + 4);	/* if packet length < 60 */
+	pad = (pad < 0) ? 0 : pad;
+
+#if CORTINA_NI_DBG
+	printf("%s: length=%d, pad=%d\n", __func__, length, pad);
+#endif
+
+	new_pkt_len = length + pad;	/* new packet length */
+
+	pkt_buf_ptr = (unsigned char *)pkt_buf;
+
+	/* Calculate the CRC32 */
+	/* skip 8-byte header_A */
+	crc32 = ~(calc_crc(~0,
+			(u8 *)(pkt_buf_ptr + HEADER_A_SIZE), new_pkt_len));
+
+#if CORTINA_NI_DBG
+	printf("%s: crc32 is 0x%x\n", __func__, crc32);
+	printf("%s: ~crc32 is 0x%x\n", __func__, ~crc32);
+	printf("%s: pkt len %d\n", __func__, new_pkt_len);
+#endif
+	/* should add 8-byte header_! */
+	/* CRC will re-calculated by hardware */
+	memcpy((pkt_buf_ptr + new_pkt_len + HEADER_A_SIZE),
+	       (u8 *)(&crc32), sizeof(crc32));
+	new_pkt_len = new_pkt_len + 4;	/* add CRC */
+
+	valid_bytes = new_pkt_len % 8;
+	valid_bytes = valid_bytes ? valid_bytes : 0;
+
+#if CORTINA_NI_DBG
+	printf("%s: valid_bytes %d\n", __func__, valid_bytes);
+#endif
+
+	/* should add 8-byte headerA */
+	next_link = sw_tx_wr_ptr +
+		(new_pkt_len + 7 + HEADER_A_SIZE) / 8; /* for headr XT */
+	next_link = next_link + 1; /* add header */
+	/* Wrap around if required */
+	if (next_link > priv->tx_xram_end) {
+		next_link = priv->tx_xram_start +
+			(next_link - (priv->tx_xram_end + 1));
+	}
+
+#if CORTINA_NI_DBG
+	printf("%s: TX next_link %x\n", __func__, next_link);
+#endif
+
+	hdr_xt.wrd = 0;
+	hdr_xt.bf.ownership = 1;
+	hdr_xt.bf.bytes_valid = valid_bytes;
+	hdr_xt.bf.next_link = next_link;
+
+	tx_xram_ptr = (u32 *)((unsigned long)NI_XRAM_BASE + sw_tx_wr_ptr * 8);
+
+	/* Wrap around if required */
+	if (tx_xram_ptr >= (u32 *)(unsigned long)priv->tx_xram_end_adr)
+		tx_xram_ptr = (u32 *)(unsigned long)priv->tx_xram_base_adr;
+
+	tx_xram_ptr = RDWRPTR_ADVANCE_ONE(tx_xram_ptr,
+					  priv->tx_xram_base_adr,
+					  priv->tx_xram_end_adr);
+
+	*tx_xram_ptr = hdr_xt.wrd;
+
+	tx_xram_ptr = RDWRPTR_ADVANCE_ONE(tx_xram_ptr,
+					  priv->tx_xram_base_adr,
+					  priv->tx_xram_end_adr);
+
+	/* Now to copy the data . The first byte on the line goes first */
+	data_ptr = (u32 *)pkt_buf_ptr;
+
+#if CORTINA_NI_DBG
+	printf("%s: packet data[]=", __func__);
+#endif
+
+	/* copy header_A to XRAM */
+	for (loop = 0; loop <= (new_pkt_len + HEADER_A_SIZE) / 4; loop++) {
+#if CORTINA_NI_DBG
+		ptr = (u8 *)data_ptr;
+		if ((loop % 4) == 0)
+			printf("\n");
+		printf("[0x%x]-[0x%x]-[0x%x]-[0x%x]-",
+		       ptr[0], ptr[1], ptr[2], ptr[3]);
+#endif
+
+		*tx_xram_ptr = *data_ptr++;
+		tx_xram_ptr = RDWRPTR_ADVANCE_ONE(tx_xram_ptr,
+						  priv->tx_xram_base_adr,
+						  priv->tx_xram_end_adr);
+	}
+#if CORTINA_NI_DBG
+	printf("\n");
+#endif
+
+	/* Publish the software write pointer */
+	cpuxram_cpu_cfg_tx.bf.pkt_wr_ptr = next_link;
+	CA_REG_WRITE(cpuxram_cpu_cfg_tx.wrd,
+		     (priv->ni_hv_base_addr +
+		     NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET));
+
+	return 0;
+}
+
+void cortina_ni_halt(struct udevice *netdev)
+{
+#if FOR_DEBUG
+	/* MFE MAC configuration Disable tx and rx */
+	reg_value = CA_REG_READ((priv->ni_hv_base_addr +
+			       NI_TOP_NI_ETH_MAC_CONFIG0_0_MFE_OFFSET));
+	reg_value = reg_value & ~(NI_RX_ENB);
+	reg_value = reg_value & ~(NI_TX_ENB);
+	CA_REG_WRITE(reg_value, (priv->ni_hv_base_addr +
+		    NI_TOP_NI_ETH_MAC_CONFIG0_0_MFE_OFFSET));
+
+	/* Disable MFE ethernet interface */
+	reg_value = CA_REG_READ(TOP_NI_INTF_RST_CONFIG);
+	reg_value = reg_value | (INTF_RST_GE1);
+	CA_REG_WRITE(reg_value, TOP_NI_INTF_RST_CONFIG);
+#endif
+}
+
+#define RTL8214_INIT_REG_COUNT		58
+static u32 rtl8214_init_reg_val[RTL8214_INIT_REG_COUNT] = {
+	0x6602, 0x84D7, 0x6601, 0x0540, 0x6600, 0x00C0,
+	0x6602, 0xF994, 0x6601, 0x0541, 0x6600, 0x00C0,
+	0x6602, 0x2DA3, 0x6601, 0x0542, 0x6600, 0x00C0,
+	0x6602, 0x3960, 0x6601, 0x0543, 0x6600, 0x00C0,
+	0x6602, 0x9728, 0x6601, 0x0544, 0x6600, 0x00C0,
+	0x6602, 0xF83F, 0x6601, 0x0545, 0x6600, 0x00C0,
+	0x6602, 0x9D85, 0x6601, 0x0423, 0x6600, 0x00C0,
+	0x6602, 0xD810, 0x6601, 0x0424, 0x6600, 0x00C0,
+	0x1D11, 0x1506,
+	0x1D12, 0x0800,
+	0x6602, 0xC3FA, 0x6601, 0x002E, 0x6600, 0x00C0
+};
+
+#if defined(CONFIG_TARGET_VENUS)
+static void __internal_phy_init(int reset_phy)
+{
+	u16 phy_addr;
+	u16 data;
+	u32 start_time;
+
+	/* GPHY clock rg_clr_clk_die_sys=0/rg_auto_clr_clk_die[10]=1 */
+	for (phy_addr = 4; phy_addr > 0; phy_addr--) {
+		ca_mdio_write(phy_addr, 31, 0x0C40);
+		ca_mdio_write(phy_addr, 17, 0x0480);
+	}
+
+	/* port 2 PLL port AIF correction */
+	phy_addr = 3;
+	ca_mdio_write(phy_addr, 31, 0x0BC6);
+	ca_mdio_write(phy_addr, 16, 0x0053);
+	ca_mdio_write(phy_addr, 18, 0x4003);
+	ca_mdio_write(phy_addr, 22, 0x7E01);
+	ca_mdio_write(phy_addr, 23, 0);
+
+	/* GIGA port AIF correction */
+	for (phy_addr = 4; phy_addr > 0; phy_addr--) {
+		ca_mdio_write(phy_addr, 31, 0x0BC0);
+		ca_mdio_write(phy_addr, 19, 0x01C0);
+		ca_mdio_write(phy_addr, 20, 0x3C61);
+		ca_mdio_write(phy_addr, 21, 0x8022);
+		ca_mdio_write(phy_addr, 23, 0x0441);
+		ca_mdio_write(phy_addr, 31, 0x0BC1);
+		ca_mdio_write(phy_addr, 16, 0x1328);
+		ca_mdio_write(phy_addr, 17, 0xF0B0);
+		ca_mdio_write(phy_addr, 18, 0x0E00);
+	}
+	mdelay(1);
+
+	/* check clk_fail = 0
+	 * read phy_fatal_err_int_flag & rg_auto_clr_clk_die[10]=0
+	 * power-on & reset GPHY
+	 */
+	for (phy_addr = 4; phy_addr > 0; phy_addr--) {
+		ca_mdio_write(phy_addr, 31, 0x0C40);
+		ca_mdio_read(phy_addr,  18, &data);
+		if (data & 1)
+			printf("%s: GPHY clock failed!!\n", __func__);
+		ca_mdio_write(phy_addr, 31, 0x0B90);
+		ca_mdio_read(phy_addr,  19, &data);
+		ca_mdio_write(phy_addr, 31, 0x0B90);
+		ca_mdio_read(phy_addr,  19, &data);
+		mdelay(1);
+		ca_mdio_write(phy_addr, 31, 0x0C40);
+		ca_mdio_write(phy_addr, 17, 0x0080);
+		mdelay(1);
+		ca_mdio_write(phy_addr, 31, 0x0A42);
+
+		if (reset_phy) {
+			ca_mdio_write(phy_addr,  0, 0x9140);
+
+			start_time = get_timer(0);
+			while (get_timer(start_time) < 3000) {
+				ca_mdio_read(phy_addr,   0, &data);
+				if (!(data & 0x8000)) {
+					printf("%s: GPHY addr=%d, ",
+					       __func__, phy_addr);
+					printf("reset completed!!\n");
+					break;
+				}
+			}
+			if (data & 0x8000)
+				printf("%s: GPHY addr=%d, reset timeout!!\n",
+				       __func__, phy_addr);
+		} else {
+			ca_mdio_write(phy_addr,  0, 0x1140);
+		}
+
+		mdelay(100);
+	}
+}
+#endif
+
+#if  defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
+static void ca_ni_internal_phy_init(void)
+{
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC)
+	u8 phy_addr;
+
+	/* should initialize 4 GPHYs at once */
+	for (phy_addr = 4; phy_addr > 0; phy_addr--) {
+		ca_mdio_write(phy_addr, 31, 0x0BC6);
+		ca_mdio_write(phy_addr, 16, 0x0053);
+		ca_mdio_write(phy_addr, 18, 0x4003);
+		ca_mdio_write(phy_addr, 22, 0x7e01);
+		ca_mdio_write(phy_addr, 31, 0x0A42);
+		ca_mdio_write(phy_addr, 31, 0x0A40);
+		ca_mdio_write(phy_addr,  0, 0x1140);
+	}
+
+	/* workaround to fix GPHY fail */
+	cortina_ni_fix_gphy();
+
+#else
+	/* should initialize 4 GPHYs at once */
+	__internal_phy_init(0);
+#endif
+}
+#endif
+
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
+extern u8 port2led[8][2];
+
+static void ca77xx_ni_led(int port, int sw_on)
+{
+#ifdef CORTINA_LED_READY
+	if (sw_on) {
+		/* turn on led light */
+		__led_set(1 << port2led[port][0], STATUS_LED_ON);
+		__led_set(1 << port2led[port][1], STATUS_LED_ON);
+	} else {
+		/* turn off led light */
+		__led_set(1 << port2led[port][0], STATUS_LED_OFF);
+		__led_set(1 << port2led[port][1], STATUS_LED_OFF);
+	}
+#endif
+}
+
+#define AUTO_SCAN_PHY_TIMEOUT	1000		/* 1s */
+
+static void ca77xx_ni_scan_active_port(void)
+{
+	u8	phy_addr;
+	int	port;
+	int	found_active_port = 0;
+	unsigned short data;
+
+	for (phy_addr = 1; phy_addr < 5; phy_addr++) {
+		port = phy_addr - 1;
+		ca_mdio_read(phy_addr, 1, &data);
+		if (data & 0x04) {
+			if (found_active_port == 0) {
+				/* apply new active_port when port changed */
+				if (phy_addr != ge_port_phy_addr) {
+					ge_port_phy_addr = phy_addr;
+					active_port = port;
+					cortina_ni_reset();
+					ca77xx_ni_led(port, 1);
+					printf("active port has been changed ");
+					printf("port %d\n", active_port);
+				} else {
+					ca77xx_ni_led(port, 1);
+				}
+				found_active_port = 1;
+			} else {
+				ca77xx_ni_led(port, 1);
+			}
+		} else {
+			ca77xx_ni_led(port, 0);
+		}
+	}
+}
+
+void ca77xx_ni_scan_phy_link(void)
+{
+	static u32     start_time;
+	unsigned short data;
+
+	/* if etherent not initialized do nothing */
+	if (!curr_dev)
+		return;
+
+	if (start_time == 0) {
+		start_time = get_timer(0);
+	} else {
+		/* scan GPHY link status per second */
+		if (get_timer(start_time) > AUTO_SCAN_PHY_TIMEOUT) {
+			if (auto_scan_active_port) {
+				/* search for the first link PHY act
+				 * as active port
+				 */
+				ca77xx_ni_scan_active_port();
+			} else {
+				ca_mdio_read(ge_port_phy_addr, 1, &data);
+				if (data & 0x04)
+					ca77xx_ni_led(active_port, 1);
+				else
+					ca77xx_ni_led(active_port, 0);
+			}
+			start_time = 0;
+		}
+	}
+}
+
+/* auto scan the first link up port as active_port */
+#define AUTO_SCAN_TIMEOUT	3000		/* 3 seconds */
+static void ca77xx_ni_auto_scan_active_port(void)
+{
+	u8	phy_addr;
+	u32	start_time;
+	unsigned short data;
+
+	ca_ni_internal_phy_init();
+
+	start_time = get_timer(0);
+	while (get_timer(start_time) < AUTO_SCAN_TIMEOUT) {
+		for (phy_addr = 1; phy_addr < 5; phy_addr++) {
+			ca_mdio_read(phy_addr, 1, &data);
+			if (data & 0x04) {
+				active_port = phy_addr - 1;
+				printf("%s: active_port=%d\n",
+				       __func__, active_port);
+
+				ca77xx_ni_led(active_port, 1);
+				return;
+			}
+		}
+	}
+	printf("%s: auto scan active_port timeout, set active_port to 1.\n",
+	       __func__);
+	active_port = NI_PORT_1;
+
+	ca77xx_ni_led(active_port, 0);
+}
+
+#elif defined(CONFIG_TARGET_SATURN_ASIC)
+
+/* auto scan the first link up port as active_port */
+#define AUTO_SCAN_TIMEOUT       3000            /* 3 seconds */
+static void ca77xx_ni_auto_scan_active_port(void)
+{
+	u8      phy_addr;
+	u32     start_time;
+	unsigned short data;
+
+	/* do internal GHPY reset */
+	active_port = 3;
+	cortina_ni_reset();
+
+	/* should initialize internal GPHY, NI port 3 */
+	phy_addr = 1;
+	ca_mdio_write(phy_addr, 31, 0x0BC6);
+	ca_mdio_write(phy_addr, 16, 0x0053);
+	ca_mdio_write(phy_addr, 18, 0x4003);
+	ca_mdio_write(phy_addr, 22, 0x7e01);
+	ca_mdio_write(phy_addr, 31, 0x0A42);
+	ca_mdio_write(phy_addr, 31, 0x0A40);
+	ca_mdio_write(phy_addr,  0, 0x1140);
+
+	/* workaround to fix GPHY fail */
+	/* Clear clock fail interrupt */
+	ca_mdio_write(phy_addr, 31, 0xB90);
+	ca_mdio_read(phy_addr, 19, &data);
+	//printf("%s: phy_addr=%d, read register 19, value=0x%x\n",
+	//__func__, phy_addr, data);
+	if (data == 0x10) {
+		ca_mdio_write(phy_addr, 31, 0xB90);
+		ca_mdio_read(phy_addr, 19, &data);
+		printf("%s: read again phy_addr=%d, ", __func__, phy_addr);
+		printf("read register 19, value=0x%x\n", data);
+	}
+#ifdef CORTINA_NI_DBG
+	printf("%s: phy_addr=%d, read register 19, value=0x%x\n",
+	       __func__, phy_addr, data);
+#endif
+
+	start_time = get_timer(0);
+	while (get_timer(start_time) < AUTO_SCAN_TIMEOUT) {
+		phy_addr = 5;  /* NI port 4 */
+		ca_mdio_read(phy_addr, 1, &data);
+		if (data & 0x04) {
+			active_port = NI_PORT_4;
+			printf("%s: active_port=%d\n", __func__, active_port);
+			return;
+		}
+		phy_addr = 1;  /* NI port 3 */
+		ca_mdio_read(phy_addr, 1, &data);
+		if (data & 0x04) {
+			active_port = NI_PORT_3;
+			printf("%s: active_port=%d\n", __func__, active_port);
+			return;
+		}
+	}
+	printf("%s: auto scan active_port timeout, set active_port to 3.\n",
+	       __func__);
+	active_port = NI_PORT_3;
+}
+
+#endif
+
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
+#define GPHY_CAL_LEN	6
+struct gphy_cal {
+	u32 reg_off;
+	u32 value;
+};
+
+static struct gphy_cal gphy_cal_vlaues[GPHY_CAL_LEN] = {
+	{0xf43380fc, 0xbcd},
+	{0xf43380dc, 0xeeee},
+	{0xf43380d8, 0xeeee},
+	{0xf43380fc, 0xbce},
+	{0xf43380c0, 0x7777},
+	{0xf43380c4, 0x7777}
+};
+
+static void do_internal_gphy_cal(void)
+{
+	int i, port;
+	u32 reg_off, value;
+
+	for (port = 0; port < 4; port++) {
+		for (i = 0; i < GPHY_CAL_LEN; i++) {
+			reg_off = gphy_cal_vlaues[i].reg_off + (port * 0x80);
+			value = gphy_cal_vlaues[i].value;
+			CA_REG_WRITE(value, reg_off);
+			mdelay(50);
+		}
+	}
+}
+#endif
+
+int ca77xx_eth_initialize(struct udevice *dev)
+{
+	struct cortina_ni_priv	*priv;
+	char		*buf;
+#if !defined(CONFIG_TARGET_VENUS)
+	u16		val;
+#endif
+	int		i;
+	u16		vendor_id, chip_id;
+	u32		phy_id;
+
+	env_set_hex("active_port", 1);
+	env_set_hex("auto_scan_active_port", 1);
+
+	priv = dev_get_priv(dev);
+	priv->rx_xram_base_adr	= NI_XRAM_BASE + (RX_BASE_ADDR * 8);
+	priv->rx_xram_end_adr	= NI_XRAM_BASE + ((RX_TOP_ADDR + 1) * 8);
+	priv->rx_xram_start	= RX_BASE_ADDR;
+	priv->rx_xram_end	= RX_TOP_ADDR;
+	priv->tx_xram_base_adr	= NI_XRAM_BASE + (TX_BASE_ADDR * 8);
+	priv->tx_xram_end_adr	= NI_XRAM_BASE + ((TX_TOP_ADDR + 1) * 8);
+	priv->tx_xram_start	= TX_BASE_ADDR;
+	priv->tx_xram_end	= TX_TOP_ADDR;
+
+	curr_dev = dev;
+#if CORTINA_NI_DBG
+	printf("%s: rx_base_addr:%x\t rx_top_addr %x\n",
+	       __func__, priv->rx_xram_start, priv->rx_xram_end);
+	printf("%s: tx_base_addr:%x\t tx_top_addr %x\n",
+	       __func__, priv->tx_xram_start, priv->tx_xram_end);
+	printf("%s: rx physical start address = %x end address = %x\n",
+	       __func__, priv->rx_xram_base_adr, priv->rx_xram_end_adr);
+	printf("%s: tx physical start address = %x end address = %x\n",
+	       __func__, priv->tx_xram_base_adr, priv->tx_xram_end_adr);
+#endif
+
+	//ni_enable_tx_rx();
+
+	/* set MDIO pre-scale value */
+	reg_value = CA_REG_READ(priv->per_mdio_base_addr + PER_MDIO_CFG_OFFSET);
+	reg_value = reg_value | 0x00280000;
+	CA_REG_WRITE(reg_value, priv->per_mdio_base_addr + PER_MDIO_CFG_OFFSET);
+
+	/* In Saturn active_port are 3 or 4,
+	 * because the register offset has been shifted forward
+	 * LAN ports (port 4-7) connect to RTL8214
+	 */
+#if defined(CONFIG_TARGET_SATURN_ASIC)
+	buf = env_get("auto_scan_active_port");
+	if (buf != 0) {
+		auto_scan_active_port = simple_strtoul(buf, NULL, 0);
+		printf("%s: auto_scan_active_port=%d\n",
+		       __func__, auto_scan_active_port);
+	}
+
+	if (auto_scan_active_port) {
+		ca77xx_ni_auto_scan_active_port();
+	} else {
+		buf = env_get("active_port");
+		if (buf != 0) {
+			active_port = simple_strtoul(buf, NULL, 0);
+			printf("%s: active_port=%d\n", __func__, active_port);
+			if (active_port != NI_PORT_3 &&
+			    active_port != NI_PORT_4) {
+				printf("ERROR: does not support active_port ");
+				printf("%d!!\n", active_port);
+				printf("Please change active_port to 3 or 4\n");
+				free(dev);
+				free(priv);
+				return 1;
+			}
+		} else {
+			active_port = NI_PORT_4;
+		}
+	}
+#else
+	buf = env_get("auto_scan_active_port");
+	if (buf != 0) {
+		auto_scan_active_port = simple_strtoul(buf, NULL, 0);
+		printf("%s: auto_scan_active_port=%d\n", __func__,
+		       auto_scan_active_port);
+	}
+	if (auto_scan_active_port) {
+		ca77xx_ni_auto_scan_active_port();
+	} else {
+		buf = env_get("active_port");
+		if (buf != 0) {
+			active_port = simple_strtoul(buf, NULL, 0);
+			printf("%s: active_port=%d\n", __func__, active_port);
+			if (active_port < NI_PORT_0 ||
+			    active_port > NI_PORT_4) {
+				printf("ERROR: does not support active_port ");
+				printf("%d\n", active_port);
+				printf("Please change active_port to 0-3.\n");
+				free(dev);
+				free(priv);
+				return 1;
+			}
+		} else {
+			active_port = NI_PORT_1;
+		}
+	}
+#endif
+
+	cortina_ni_reset();
+
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
+	/* port0: phy address 1 - GMAC0: port 0
+	 * port1: phy address 2 - GMAC1: port 1
+	 * port2: phy address 3 - GMAC2: port 2
+	 * port3: phy address 4 - GMAC3: port 3
+	 * port4: phy address 5 - RGMII: port 4
+	 */
+	ge_port_phy_addr = active_port + 1;
+#else
+	/* port0: phy address 1	- GMAC0: port 0
+	 * port1: phy address 2 - GMAC1: port 1
+	 * port2: phy address 3 - GMAC2: port 2
+	 * port3: phy address 4 - GMAC3: port 3
+	 * port4: phy address 16 - QSGMII: port 0
+	 * port5: phy address 17 - QSGMII: port 1
+	 * port6: phy address 18 - QSGMII: port 2
+	 * port7: phy address 19 - QSGMII: port 3
+	 */
+	if (active_port >= NI_PORT_0 && active_port <= NI_PORT_3)
+		ge_port_phy_addr = active_port + 1;
+	else
+		ge_port_phy_addr = active_port - 2;
+#endif
+
+#if defined(CONFIG_TARGET_SATURN_ASIC)
+	/* internal GPHY addr=1 */
+	if (active_port == NI_PORT_3)
+		ge_port_phy_addr = 1;
+	else
+		ge_port_phy_addr = active_port + 1;
+
+	printf("%s: active_port=%d, ge_port_phy_addr=%d\n",
+	       __func__, active_port, ge_port_phy_addr);
+#endif
+
+	ca_mdio_read(ge_port_phy_addr, 2, &vendor_id);
+	ca_mdio_read(ge_port_phy_addr, 3, &chip_id);
+	phy_id = ((u32)vendor_id << 16) | chip_id;
+
+	printf("%s: vendor_id=0x%x\n", __func__, vendor_id);
+	printf("%s: chip_id=0x%x\n", __func__, chip_id);
+	printf("%s: phy_id=0x%x\n", __func__, phy_id);
+	printf("%s: phy_id & PHY_ID_MASK=0x%x\n",
+	       __func__, (phy_id & PHY_ID_MASK));
+	printf("%s: PHY_ID_RTL8214=0x%x\n", __func__, PHY_ID_RTL8214);
+
+	if ((phy_id & PHY_ID_MASK) == PHY_ID_RTL8211) {
+#if !defined(CONFIG_TARGET_VENUS)
+		printf("%s: do initial patch for PHY_ID_RTL8211\n", __func__);
+		/*
+		 * Disable response PHYAD=0 function of
+		 * RTL8211 series PHY
+		 */
+
+		/* REG31 write 0x0007, set to extension page */
+		ca_mdio_write(ge_port_phy_addr, 31, 0x0007);
+
+		/* REG30 write 0x002C, set to extension page 44 */
+		ca_mdio_write(ge_port_phy_addr, 30, 0x002C);
+
+		/*
+		 * REG27 write bit[2] =0
+		 * disable response PHYAD=0  function.
+		 * we should read REG27 and clear bit[2], and write back
+		 */
+		ca_mdio_read(ge_port_phy_addr, 27, &val);
+		val &= ~(1 << 2);
+		ca_mdio_write(ge_port_phy_addr, 27, val);
+
+		/* REG31 write 0X0000, back to page0 */
+		ca_mdio_write(ge_port_phy_addr, 31, 0x0000);
+#endif
+	}
+
+	/* the init sequency provided by RTK */
+	if ((phy_id & PHY_ID_MASK) == PHY_ID_RTL8214) {
+		printf("%s: write initial sequency for PHY_ID_RTL8214!!\n",
+		       __func__);
+		for (i = 0; i < RTL8214_INIT_REG_COUNT; i++) {
+			if (!(i & 1)) {
+				ca_mdio_write(ge_port_phy_addr, 29,
+					      rtl8214_init_reg_val[i]);
+			} else {
+				ca_mdio_write(ge_port_phy_addr, 30,
+					      rtl8214_init_reg_val[i]);
+			}
+		}
+	}
+
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
+	if ((phy_id & PHY_ID_MASK) == PHY_ID_RTL8211_G3_ASIC) {
+		if (!auto_scan_active_port) {
+			printf("%s: write initial sequency for ", __func__);
+			printf("PHY_ID_RTL8211_G3_ASIC!!\n");
+
+			ca_ni_internal_phy_init();
+		}
+#if defined(CONFIG_TARGET_VENUS)
+		else
+			ca77xx_ni_auto_scan_active_port();
+#endif
+	}
+
+	ca77xx_ni_scan_phy_link();
+#endif
+
+	/* parsing ethaddr and set to NI registers. */
+	ni_setup_mac_addr();
+
+	/* the phy_read and phy_write
+	 * should meet the proto type of miiphy_register
+	 */
+#ifdef MIIPHY_REGISTER
+	miiphy_register(dev->name, ca_miiphy_read, ca_miiphy_write);
+#endif
+
+#if CORTINA_NI_DBG
+	dbg_dev = dev;
+#endif
+
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
+	/* hardware settings for RGMII port */
+	{
+		union GLOBAL_GLOBAL_CONFIG_t	glb_config;
+		union GLOBAL_IO_DRIVE_CONTROL_t io_drive_control;
+
+		/* Generating 25Mhz reference clock for switch */
+		glb_config.wrd = CA_REG_READ((priv->glb_base_addr +
+					    GLOBAL_GLOBAL_CONFIG_OFFSET));
+		glb_config.bf.refclk_sel = 0x01;
+		glb_config.bf.ext_reset = 0x01;
+		CA_REG_WRITE(glb_config.wrd, (priv->glb_base_addr +
+			    GLOBAL_GLOBAL_CONFIG_OFFSET));
+
+		mdelay(20);
+
+		/* should do a external reset */
+		glb_config.wrd = CA_REG_READ((priv->glb_base_addr +
+					    GLOBAL_GLOBAL_CONFIG_OFFSET));
+		glb_config.bf.ext_reset = 0x0;
+		CA_REG_WRITE(glb_config.wrd, (priv->glb_base_addr +
+			    GLOBAL_GLOBAL_CONFIG_OFFSET));
+
+		io_drive_control.wrd =
+			CA_REG_READ((priv->glb_base_addr +
+				   GLOBAL_IO_DRIVE_CONTROL_OFFSET));
+		io_drive_control.bf.gmac_mode = 2;
+		io_drive_control.bf.gmac_dn = 1;
+		io_drive_control.bf.gmac_dp = 1;
+		CA_REG_WRITE(io_drive_control.wrd, (priv->glb_base_addr +
+			    GLOBAL_IO_DRIVE_CONTROL_OFFSET));
+	}
+
+	/* initialize LEDs for ethernet link and traffic lights */
+	//ca77xx_init_led();
+
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC)
+	/* do internal gphy calibration */
+	do_internal_gphy_cal();
+#endif
+	return 0;
+#endif
+}
+
+#if CORTINA_NI_DBG
+DECLARE_GLOBAL_DATA_PTR;
+int do_eth_init(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
+{
+	cortina_ni_init(0x00);
+	return 0;
+}
+
+U_BOOT_CMD(do_eth_init, 2, 1, do_eth_init,
+	   "do_eth_init\t- to test eth_init\n",
+	   "None\n");
+#endif
+
+#if CORTINA_NI_DBG
+int do_eth_send(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
+{
+	unsigned char	pkt[1536];
+	unsigned int	i;
+
+	for (i = 0; i < 1500; i++)
+		pkt[i] = i % 256;
+
+	for (i = 60; i < 360; i++)
+		cortina_ni_send(dbg_dev, pkt, i);
+
+	return 0;
+}
+
+U_BOOT_CMD(do_eth_send, 3, 2, do_eth_send,
+	   "do_eth_send\t- to test eth_send\n",
+	   "None\n");
+
+int do_eth_rx(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
+{
+	cortina_ni_recv(dbg_dev);
+	return 0;
+}
+
+U_BOOT_CMD(do_eth_rx, 2, 1, do_eth_rx,
+	   "do_eth_rx\t- to test eth_rx\n",
+	   "None\n");
+
+int do_read_phy(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
+{
+	unsigned int	phy_adr;
+	unsigned int	reg_off;
+	unsigned short	reg_val;
+
+	phy_adr = simple_strtoul(argv[1], NULL, 0);
+	reg_off = simple_strtoul(argv[2], NULL, 0);
+	ca_mdio_read(phy_adr, reg_off, &reg_val);
+	printf("PHY_ADR = %d offset=%d reg_val=%x\n",
+	       phy_adr, reg_off, reg_val);
+	return 0;
+}
+
+U_BOOT_CMD(ca_phy_read, 3, 1, do_read_phy,
+	   "do_read_phy\t- to read PHY register\n",
+	   "None\n");
+
+int do_write_phy(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
+{
+	unsigned int	phy_adr;
+	unsigned int	reg_off;
+	unsigned int	reg_val;
+
+	phy_adr = simple_strtoul(argv[1], NULL, 0);
+	reg_off = simple_strtoul(argv[2], NULL, 0);
+	reg_val = simple_strtoul(argv[3], NULL, 0);
+	ca_mdio_write(phy_adr, reg_off, reg_val);
+	printf("PHY_ADR = %d offset=%d reg_val=%x\n",
+	       phy_adr, reg_off, reg_val);
+	return 0;
+}
+
+U_BOOT_CMD(ca_phy_write, 4, 1, do_write_phy,
+	   "do_write_phy\t- to write PHY register\n",
+	   "None\n");
+
+#endif
+
+static int do_phy_reg(struct cmd_tbl *cmdtp,
+		      int flag,
+		      int argc,
+		      char * const argv[])
+{
+	int ret, i;
+	u16 phy_addr, reg, val;
+
+	if (argc < 2) {
+		printf("Usage:\nphy_reg_value%s\n", cmdtp->help);
+		return -1;
+	}
+
+	phy_addr = simple_strtoul(argv[1], NULL, 10);
+
+	if (phy_addr > 31) {
+		printf("Usage:\nphy_reg_value%s\n", cmdtp->help);
+		return -1;
+	}
+	if (argc == 2) {
+		/* read the first 15 registers of the PHY */
+		printf("PHY addr %d:\n", phy_addr);
+		for (i = 0; i < 15; i++) {
+			ca_mdio_read(phy_addr, i, &val);
+			printf("Reg 0x%04X = 0x%04X\n", i, val);
+		}
+		return 0;
+	}
+
+	reg = simple_strtoul(argv[2], NULL, 10);
+
+	if (argc == 3) {
+		/* read cmd */
+		ca_mdio_read(phy_addr, reg, &val);
+		printf("PHY addr %d Reg 0x%04X = 0x%04X\n", phy_addr, reg, val);
+	} else {
+		/* argc > 3*/
+		/* write cmd */
+		val = simple_strtoul(argv[3], NULL, 10);
+		ret = ca_mdio_write(phy_addr, reg, val);
+		if (!ret) {
+			printf("PHY addr %d Reg 0x%04X = 0x%04X\n",
+			       phy_addr, reg, val);
+		} else {
+			printf("Can't write PHY addr %d Reg 0x%04X as 0x%04X, ",
+			       phy_addr, reg, val);
+			printf("ret = %d\n", ret);
+		}
+	}
+	return 0;
+}
+
+U_BOOT_CMD(phy_reg, 4, 1, do_phy_reg,
+	   "read/write PHY register",
+	   "[PHY addr] [reg_valueaddr] ([value])\n"
+	   "PHY addr : 0-31\n");
+
+#ifdef CONFIG_MK_CUSTOMB
+/* code custom switch register access function here */
+#endif
+
+static int cortina_eth_start(struct udevice *dev)
+{
+	return cortina_ni_init(dev);
+}
+
+int cortina_eth_send(struct udevice *dev, void *packet, int length)
+{
+	return cortina_ni_send(dev, packet, length);
+}
+
+int cortina_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	return cortina_ni_recv(dev);
+}
+
+void cortina_eth_stop(struct udevice *dev)
+{
+	cortina_ni_halt(dev);
+}
+
+static int cortina_eth_probe(struct udevice *dev)
+{
+	return ca77xx_eth_initialize(dev);
+}
+
+static int ca_ni_ofdata_to_platdata(struct udevice *dev)
+{
+	struct cortina_ni_priv *priv = dev_get_priv(dev);
+
+	priv->glb_base_addr = dev_remap_addr_index(dev, 0);
+	if (!priv->glb_base_addr)
+		return -ENOENT;
+	printf("%s: priv->glb_base_addr for index 0 is 0x%p\n",
+	       __func__, priv->glb_base_addr);
+
+	priv->per_mdio_base_addr = dev_remap_addr_index(dev, 1);
+	if (!priv->per_mdio_base_addr)
+		return -ENOENT;
+	printf("%s: priv->per_mdio_base_addr for index 1 is 0x%p\n",
+	       __func__, priv->per_mdio_base_addr);
+
+	priv->ni_hv_base_addr = dev_remap_addr_index(dev, 2);
+	if (!priv->ni_hv_base_addr)
+		return -ENOENT;
+	printf("%s: priv->ni_hv_base_addr for index 2 is 0x%p\n",
+	       __func__, priv->ni_hv_base_addr);
+
+	return 0;
+}
+
+static const struct eth_ops cortina_eth_ops = {
+	.start  = cortina_eth_start,
+	.send   = cortina_eth_send,
+	.recv   = cortina_eth_recv,
+	.stop   = cortina_eth_stop,
+};
+
+static const struct udevice_id cortina_eth_ids[] = {
+	{ .compatible = "eth_cortina" },
+	{ }
+};
+
+U_BOOT_DRIVER(eth_cortina) = {
+	.name   = "eth_cortina",
+	.id     = UCLASS_ETH,
+	.of_match = cortina_eth_ids,
+	.probe  = cortina_eth_probe,
+	.ops    = &cortina_eth_ops,
+	.priv_auto_alloc_size = sizeof(struct cortina_ni_priv),
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+	.ofdata_to_platdata = ca_ni_ofdata_to_platdata,
+};
diff --git a/drivers/net/cortina_ni.h b/drivers/net/cortina_ni.h
new file mode 100644
index 0000000..0fea6a1
--- /dev/null
+++ b/drivers/net/cortina_ni.h
@@ -0,0 +1,592 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+/*
+ * Copyright (C) 2020 Cortina Access Inc.
+ * Author: Aaron Tseng <aaron.tseng at cortina-access.com>
+ *
+ * Ethernet MAC Driver for all supported CAxxxx SoCs
+ */
+
+#ifndef __CORTINA_NI_H
+#define __CORTINA_NI_H
+
+#include <asm/types.h>
+#include <asm/io.h>
+#include <config.h>
+
+//#define CORTINA_NI_DBG				1
+
+#ifdef CS_BIG_ENDIAN
+#define CRCPOLY_BE					0x04c11db7
+#else /* CS_LITTLE_ENDIAN */
+#define CRCPOLY_LE					0xedb88320
+#endif
+
+#define GE_PORT0_PHY_ADDR				CONFIG_NI_PHY_ADDR_GMAC0
+#define GE_PORT1_PHY_ADDR				CONFIG_NI_PHY_ADDR_GMAC1
+#define GE_PORT2_PHY_ADDR				CONFIG_NI_PHY_ADDR_GMAC2
+
+#define PHY_ID_RTL8201					0x001cc810
+#define PHY_ID_RTL8211					0x001cc910
+#define PHY_ID_RTL8214					0x001cc940
+#define PHY_ID_RTL8211_G3_ASIC				0x001cc980
+#define PHY_ID_RTL8211_SATURN_ASIC			0x001cc900
+#define PHY_ID_QCA8337					0x004dd035
+#define PHY_ID_MASK					0xFFFFFFF0
+
+#define GE_MAC_INTF_GMII                                0x0
+#define GE_MAC_INTF_MII                                 0x1
+#define GE_MAC_INTF_RGMII_1000                          0x2
+#define GE_MAC_INTF_RGMII_100                           0x3
+#define GE_MAC_INTF_QSGMII_1000                         0x4
+#define GE_MAC_INTF_RMII                                0x5
+
+#define NI_TOP_NI_RTH_MAC_10M				1
+#define NI_TOP_NI_RTH_MAC_100M				0
+#define NI_TOP_NI_RTH_MAC_HALF				1
+#define NI_TOP_NI_RTH_MAC_FULL				0
+
+/* Defines the base and top address in CPU XRA
+ * for packets to cpu instance 0
+ * 0x300 * 8-byte = 6K-byte
+ */
+#define RX_TOP_ADDR					0x02FF
+#define RX_BASE_ADDR					0x0000
+
+/* Defines the base and top address in CPU XRAM
+ * for packets from cpu instance 0.
+ * 0x100 * 8-byte = 2K-byte
+ */
+#define TX_TOP_ADDR					0x03FF
+#define TX_BASE_ADDR					0x0300
+
+#define RX_0_CPU_PKT_DIS				BIT(0)
+#define TX_0_CPU_PKT_DIS				BIT(9)
+
+#define PHY_POLL_TIMES					0x200
+
+#define NI_XRAM_BASE                    0xF4500000
+
+enum ca_status_t {
+	CA_E_ERROR          = -1,
+	CA_E_OK             = 0x0,
+	CA_E_RESOURCE       = 0x1,
+	CA_E_PARAM          = 0x2,
+	CA_E_NOT_FOUND      = 0x3,
+	CA_E_CONFLICT       = 0x4,
+	CA_E_TIMEOUT        = 0x5,
+	CA_E_INTERNAL       = 0x6,
+	CA_E_NOT_SUPPORT    = 0x7,
+	CA_E_CONFIG         = 0x8,
+	CA_E_UNAVAIL        = 0x9,
+	CA_E_MEMORY         = 0xa,
+	CA_E_BUSY           = 0xb,
+	CA_E_FULL           = 0xc,
+	CA_E_EMPTY          = 0xd,
+	CA_E_EXISTS         = 0xe,
+	CA_E_DEV            = 0xf,
+	CA_E_PORT           = 0x10,
+	CA_E_LLID           = 0x11,
+	CA_E_VLAN           = 0x12,
+	CA_E_INIT           = 0x13,
+	CA_E_INTF           = 0x14,
+	CA_E_NEXTHOP        = 0x15,
+	CA_E_ROUTE          = 0x16,
+	CA_E_DB_CHANGED     = 0x17,
+	CA_E_INACTIVE       = 0x18,
+	CA_E_ALREADY_SET    = 0x19,
+};
+
+#ifndef CA_IN
+#define CA_IN
+#endif
+
+#ifndef CA_OUT
+#define CA_OUT
+#endif
+
+#if !defined(__ASSEMBLER__) && !defined(__ASSEMBLY__)
+struct cortina_ni_priv {
+	unsigned int	rx_xram_base_adr;
+	unsigned int	rx_xram_end_adr;
+	unsigned short  rx_xram_start;
+	unsigned short  rx_xram_end;
+	unsigned int	tx_xram_base_adr;
+	unsigned int	tx_xram_end_adr;
+	unsigned short  tx_xram_start;
+	unsigned short  tx_xram_end;
+#ifdef CONFIG_DM_ETH
+	void __iomem    *glb_base_addr;
+	void __iomem    *per_mdio_base_addr;
+	void __iomem    *ni_hv_base_addr;
+#else
+	unsigned int    glb_base_addr;
+	unsigned int    per_mdio_base_addr;
+	unsigned int    ni_hv_base_addr;
+#endif
+};
+
+union NI_HEADER_X_T {
+	struct {
+		unsigned int next_link		: 10; /* bits  9: 0 */
+		unsigned int bytes_valid		:  4; /* bits 13:10 */
+		unsigned int reserved		: 16; /* bits 29:14 */
+		unsigned int hdr_a			:  1; /* bits 30:30 */
+		unsigned int ownership		:  1; /* bits 31:31 */
+	} bf;
+	unsigned int     wrd;
+};
+
+union NI_PACKET_STATUS {
+	struct {
+		unsigned int packet_size       : 14; /* bits 13:0 */
+		unsigned int byte_valid        :  4; /* bits 17:14 */
+		unsigned int pfc               :  1; /* bits 18:18 */
+		unsigned int valid             :  1; /* bits 19:19 */
+		unsigned int drop              :  1; /* bits 20:20 */
+		unsigned int runt              :  1; /* bits 21:21 */
+		unsigned int oversize          :  1; /* bits 22:22 */
+		unsigned int jumbo             :  1; /* bits 23:23 */
+		unsigned int link_status       :  1; /* bits 24:24 */
+		unsigned int jabber            :  1; /* bits 25:25 */
+		unsigned int crc_error         :  1; /* bits 26:26 */
+		unsigned int pause             :  1; /* bits 27:27 */
+		unsigned int oam               :  1; /* bits 28:28 */
+		unsigned int unknown_opcode    :  1; /* bits 29:29 */
+		unsigned int multicast         :  1; /* bits 30:30 */
+		unsigned int broadcast         :  1; /* bits 31:31 */
+	} bf;
+	unsigned int     wrd;
+};
+
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || \
+	defined(CONFIG_TARGET_SATURN_ASIC) || defined(CONFIG_TARGET_VENUS)
+
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC)
+#define CA_NI_MDIO_REG_BASE				0xF4338
+#else
+
+#if defined(CONFIG_TARGET_VENUS)
+#define CA_NI_MDIO_REG_BASE				0xF4339
+#else
+#define CA_NI_MDIO_REG_BASE				0xD000B
+#endif
+
+#endif
+
+union NI_MDIO_OPER_T {
+	struct {
+		unsigned int reserved       : 2; /* bits  1:0 */
+		unsigned int reg_off        : 5; /* bits  6:2 */
+		unsigned int phy_addr       : 5; /* bits 11:7 */
+		unsigned int reg_base       : 20; /* bits 31:12 */
+	} bf;
+	unsigned int     wrd;
+};
+
+#endif
+
+#define NI_PORT_0					0
+#define NI_PORT_1					1
+#define NI_PORT_2					2
+#define NI_PORT_3					3
+#define NI_PORT_4					4
+#define NI_PORT_5					5
+#define NI_PORT_6					6
+#define NI_PORT_7					7
+
+#if defined(CONFIG_TARGET_SATURN_ASIC)
+#define NI_READ_POLL_COUNT				1000000
+#else
+#define NI_READ_POLL_COUNT				1000
+#endif
+
+#define __MDIO_WR_FLAG				(0)
+#define __MDIO_RD_FLAG				(1)
+#define __MDIO_ACCESS_TIMEOUT			(1000000)
+#define __MDIO_PER_CLK				(62500)
+#define CA_MDIO_ADDR_MIN			(1)
+#define CA_MDIO_ADDR_MAX			(31)
+#define CA_MDIO_CLOCK_MIN			(1)
+#define CA_MDIO_CLOCK_MAX			(20000)
+
+#endif /* !__ASSEMBLER__ */
+
+/* Copy from registers.h */
+union NI_HV_GLB_MAC_ADDR_CFG0_t {
+	struct {
+		unsigned int mac_addr0            : 32; /* bits 31:0 */
+	} bf;
+	unsigned int     wrd;
+};
+
+union NI_HV_GLB_MAC_ADDR_CFG1_t {
+	struct {
+		unsigned int mac_addr1            :  8; /* bits 7:0 */
+		unsigned int rsrvd1               : 24;
+	} bf;
+	unsigned int     wrd;
+};
+
+union NI_HV_PT_PORT_STATIC_CFG_t {
+	struct {
+		unsigned int int_cfg              :  4; /* bits 3:0 */
+		unsigned int phy_mode             :  1; /* bits 4:4 */
+		unsigned int rmii_clksrc          :  1; /* bits 5:5 */
+		unsigned int inv_clk_in           :  1; /* bits 6:6 */
+		unsigned int inv_clk_out          :  1; /* bits 7:7 */
+		unsigned int inv_rxclk_out        :  1; /* bits 8:8 */
+		unsigned int tx_use_gefifo        :  1; /* bits 9:9 */
+		unsigned int smii_tx_stat         :  1; /* bits 10:10 */
+		unsigned int crs_polarity         :  1; /* bits 11:11 */
+		unsigned int lpbk_mode            :  2; /* bits 13:12 */
+		unsigned int gmii_like_half_duplex_en :  1; /* bits 14:14 */
+		unsigned int sup_tx_to_rx_lpbk_data :  1; /* bits 15:15 */
+		unsigned int rsrvd1               :  8;
+		unsigned int mac_addr6            :  8; /* bits 31:24 */
+	} bf;
+	unsigned int     wrd;
+};
+
+union NI_HV_XRAM_CPUXRAM_CFG_t {
+	struct {
+		unsigned int rx_0_cpu_pkt_dis     :  1; /* bits 0:0 */
+		unsigned int rsrvd1               :  8;
+		unsigned int tx_0_cpu_pkt_dis     :  1; /* bits 9:9 */
+		unsigned int rsrvd2               :  1;
+		unsigned int rx_x_drop_err_pkt    :  1; /* bits 11:11 */
+		unsigned int xram_mgmt_dis_drop_ovsz_pkt :  1; /* bits 12:12 */
+		unsigned int xram_mgmt_term_large_pkt :  1; /* bits 13:13 */
+		unsigned int xram_mgmt_promisc_mode :  2; /* bits 15:14 */
+		unsigned int xram_cntr_debug_mode :  1; /* bits 16:16 */
+		unsigned int xram_cntr_op_code    :  2; /* bits 18:17 */
+		unsigned int rsrvd3               :  2;
+		unsigned int xram_rx_mgmtfifo_srst :  1; /* bits 21:21 */
+		unsigned int xram_dma_fifo_srst   :  1; /* bits 22:22 */
+		unsigned int rsrvd4               :  9;
+	} bf;
+	unsigned int     wrd;
+};
+
+union NI_HV_PT_RXMAC_CFG_t {
+	struct {
+		unsigned int rx_en                :  1; /* bits 0:0 */
+		unsigned int rsrvd1               :  7;
+		unsigned int rx_flow_disable      :  1; /* bits 8:8 */
+		unsigned int rsrvd2               :  3;
+		unsigned int rx_flow_to_tx_en     :  1; /* bits 12:12 */
+		unsigned int rx_pfc_disable       :  1; /* bits 13:13 */
+		unsigned int rsrvd3               : 15;
+		unsigned int send_pg_data         :  1; /* bits 29:29 */
+		unsigned int rsrvd4               :  2;
+	} bf;
+	unsigned int     wrd;
+};
+
+union NI_HV_PT_TXMAC_CFG_t {
+	struct {
+		unsigned int tx_en                :  1; /* bits 0:0 */
+		unsigned int rsrvd1               :  7;
+		unsigned int mac_crc_calc_en      :  1; /* bits 8:8 */
+		unsigned int tx_ipg_sel           :  3; /* bits 11:9 */
+		unsigned int tx_flow_disable      :  1; /* bits 12:12 */
+		unsigned int tx_drain             :  1; /* bits 13:13 */
+		unsigned int tx_pfc_disable       :  1; /* bits 14:14 */
+		unsigned int tx_pau_sel           :  2; /* bits 16:15 */
+		unsigned int rsrvd2               :  9;
+		unsigned int tx_auto_xon          :  1; /* bits 26:26 */
+		unsigned int rsrvd3               :  1;
+		unsigned int pass_thru_hdr        :  1; /* bits 28:28 */
+		unsigned int rsrvd4               :  3;
+	} bf;
+	unsigned int     wrd;
+};
+
+union NI_HV_GLB_INTF_RST_CONFIG_t {
+	struct {
+		unsigned int intf_rst_p0          :  1; /* bits 0:0 */
+		unsigned int intf_rst_p1          :  1; /* bits 1:1 */
+		unsigned int intf_rst_p2          :  1; /* bits 2:2 */
+		unsigned int intf_rst_p3          :  1; /* bits 3:3 */
+		unsigned int intf_rst_p4          :  1; /* bits 4:4 */
+		unsigned int mac_rx_rst_p0        :  1; /* bits 5:5 */
+		unsigned int mac_rx_rst_p1        :  1; /* bits 6:6 */
+		unsigned int mac_rx_rst_p2        :  1; /* bits 7:7 */
+		unsigned int mac_rx_rst_p3        :  1; /* bits 8:8 */
+		unsigned int mac_rx_rst_p4        :  1; /* bits 9:9 */
+		unsigned int mac_tx_rst_p0        :  1; /* bits 10:10 */
+		unsigned int mac_tx_rst_p1        :  1; /* bits 11:11 */
+		unsigned int mac_tx_rst_p2        :  1; /* bits 12:12 */
+		unsigned int mac_tx_rst_p3        :  1; /* bits 13:13 */
+		unsigned int mac_tx_rst_p4        :  1; /* bits 14:14 */
+		unsigned int port_rst_p5          :  1; /* bits 15:15 */
+		unsigned int pcs_rst_p6           :  1; /* bits 16:16 */
+		unsigned int pcs_rst_p7           :  1; /* bits 17:17 */
+		unsigned int mac_rst_p6           :  1; /* bits 18:18 */
+		unsigned int mac_rst_p7           :  1; /* bits 19:19 */
+		unsigned int rsrvd1               : 12;
+	} bf;
+	unsigned int     wrd;
+};
+
+union NI_HV_GLB_STATIC_CFG_t {
+	struct {
+		unsigned int port_to_cpu          :  4; /* bits 3:0 */
+		unsigned int mgmt_pt_to_fe_also   :  1; /* bits 4:4 */
+		unsigned int txcrc_chk_en         :  1; /* bits 5:5 */
+		unsigned int p4_rgmii_tx_clk_phase :  2; /* bits 7:6 */
+		unsigned int p4_rgmii_tx_data_order :  1; /* bits 8:8 */
+		unsigned int rsrvd1               :  7;
+		unsigned int rxmib_mode           :  1; /* bits 16:16 */
+		unsigned int txmib_mode           :  1; /* bits 17:17 */
+		unsigned int eth_sch_rdy_pkt      :  1; /* bits 18:18 */
+		unsigned int rsrvd2               :  1;
+		unsigned int rxaui_mode           :  2; /* bits 21:20 */
+		unsigned int rxaui_sigdet         :  2; /* bits 23:22 */
+		unsigned int cnt_op_mode          :  3; /* bits 26:24 */
+		unsigned int rsrvd3               :  5;
+	} bf;
+	unsigned int     wrd;
+};
+
+union GLOBAL_BLOCK_RESET_t {
+	struct {
+		unsigned int reset_ni             :  1; /* bits 0:0 */
+		unsigned int reset_l2fe           :  1; /* bits 1:1 */
+		unsigned int reset_l2tm           :  1; /* bits 2:2 */
+		unsigned int reset_l3fe           :  1; /* bits 3:3 */
+		unsigned int reset_sdram          :  1; /* bits 4:4 */
+		unsigned int reset_tqm            :  1; /* bits 5:5 */
+		unsigned int reset_pcie0          :  1; /* bits 6:6 */
+		unsigned int reset_pcie1          :  1; /* bits 7:7 */
+		unsigned int reset_pcie2          :  1; /* bits 8:8 */
+		unsigned int reset_sata           :  1; /* bits 9:9 */
+		unsigned int reset_gic400         :  1; /* bits 10:10 */
+		unsigned int rsrvd1               :  2;
+		unsigned int reset_usb            :  1; /* bits 13:13 */
+		unsigned int reset_flash          :  1; /* bits 14:14 */
+		unsigned int reset_per            :  1; /* bits 15:15 */
+		unsigned int reset_dma            :  1; /* bits 16:16 */
+		unsigned int reset_rtc            :  1; /* bits 17:17 */
+		unsigned int reset_pe0            :  1; /* bits 18:18 */
+		unsigned int reset_pe1            :  1; /* bits 19:19 */
+		unsigned int reset_rcpu0          :  1; /* bits 20:20 */
+		unsigned int reset_rcpu1          :  1; /* bits 21:21 */
+		unsigned int reset_sadb           :  1; /* bits 22:22 */
+		unsigned int rsrvd2               :  1;
+		unsigned int reset_rcrypto        :  1; /* bits 24:24 */
+		unsigned int reset_ldma           :  1; /* bits 25:25 */
+		unsigned int reset_fbm            :  1; /* bits 26:26 */
+		unsigned int reset_eaxi           :  1; /* bits 27:27 */
+		unsigned int reset_sd             :  1; /* bits 28:28 */
+		unsigned int reset_otprom         :  1; /* bits 29:29 */
+		unsigned int rsrvd3               :  2;
+	} bf;
+	unsigned int     wrd;
+};
+
+union PER_MDIO_ADDR_t {
+	struct {
+		unsigned int mdio_addr            :  5; /* bits 4:0 */
+		unsigned int rsrvd1               :  3;
+		unsigned int mdio_offset          :  5; /* bits 12:8 */
+		unsigned int rsrvd2               :  2;
+		unsigned int mdio_rd_wr           :  1; /* bits 15:15 */
+		unsigned int mdio_st              :  1; /* bits 16:16 */
+		unsigned int rsrvd3               :  1;
+		unsigned int mdio_op              :  2; /* bits 19:18 */
+		unsigned int rsrvd4               : 12;
+	} bf;
+	unsigned int     wrd;
+};
+
+union PER_MDIO_CTRL_t {
+	struct {
+		unsigned int mdiodone             :  1; /* bits 0:0 */
+		unsigned int rsrvd1               :  6;
+		unsigned int mdiostart            :  1; /* bits 7:7 */
+		unsigned int rsrvd2               : 24;
+	} bf;
+	unsigned int     wrd;
+};
+
+union PER_MDIO_RDDATA_t {
+	struct {
+		unsigned int mdio_rddata          : 16; /* bits 15:0 */
+		unsigned int rsrvd1               : 16;
+	} bf;
+	unsigned int     wrd;
+};
+
+/*
+ * XRAM
+ */
+
+union NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t {
+	struct {
+		unsigned int rx_base_addr         : 10; /* bits 9:0 */
+		unsigned int rsrvd1               :  6;
+		unsigned int rx_top_addr          : 10; /* bits 25:16 */
+		unsigned int rsrvd2               :  6;
+	} bf;
+	unsigned int     wrd;
+};
+
+union NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t {
+	struct {
+		unsigned int tx_base_addr         : 10; /* bits 9:0 */
+		unsigned int rsrvd1               :  6;
+		unsigned int tx_top_addr          : 10; /* bits 25:16 */
+		unsigned int rsrvd2               :  6;
+	} bf;
+	unsigned int     wrd;
+};
+
+union NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t {
+	struct {
+		unsigned int pkt_wr_ptr           : 10; /* bits 9:0 */
+		unsigned int rsrvd1               :  5;
+		unsigned int int_colsc_thresh_reached :  1; /* bits 15:15 */
+		unsigned int rsrvd2               : 16;
+	} bf;
+	unsigned int     wrd;
+};
+
+union NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t {
+	struct {
+		unsigned int pkt_rd_ptr           : 10; /* bits 9:0 */
+		unsigned int rsrvd1               : 22;
+	} bf;
+	unsigned int     wrd;
+};
+
+union NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t {
+	struct {
+		unsigned int pkt_wr_ptr           : 10; /* bits 9:0 */
+		unsigned int rsrvd1               : 22;
+	} bf;
+	unsigned int     wrd;
+};
+
+union GLOBAL_GLOBAL_CONFIG_t {
+	struct {
+		unsigned int rsrvd1               :  4;
+		unsigned int wd_reset_subsys_enable :  1; /* bits 4:4 */
+		unsigned int rsrvd2               :  1;
+		unsigned int wd_reset_all_blocks  :  1; /* bits 6:6 */
+		unsigned int wd_reset_remap       :  1; /* bits 7:7 */
+		unsigned int wd_reset_ext_reset   :  1; /* bits 8:8 */
+		unsigned int ext_reset            :  1; /* bits 9:9 */
+		unsigned int cfg_pcie_0_clken     :  1; /* bits 10:10 */
+		unsigned int cfg_sata_clken       :  1; /* bits 11:11 */
+		unsigned int cfg_pcie_1_clken     :  1; /* bits 12:12 */
+		unsigned int rsrvd3               :  1;
+		unsigned int cfg_pcie_2_clken     :  1; /* bits 14:14 */
+		unsigned int rsrvd4               :  2;
+		unsigned int ext_eth_refclk       :  1; /* bits 17:17 */
+		unsigned int refclk_sel           :  2; /* bits 19:18 */
+		unsigned int rsrvd5               :  7;
+		unsigned int l3fe_pd              :  1; /* bits 27:27 */
+		unsigned int offload0_pd          :  1; /* bits 28:28 */
+		unsigned int offload1_pd          :  1; /* bits 29:29 */
+		unsigned int crypto_pd            :  1; /* bits 30:30 */
+		unsigned int core_pd              :  1; /* bits 31:31 */
+	} bf;
+	unsigned int     wrd;
+};
+
+union GLOBAL_IO_DRIVE_CONTROL_t {
+	struct {
+		unsigned int gmac_dp              :  3; /* bits 2:0 */
+		unsigned int gmac_dn              :  3; /* bits 5:3 */
+		unsigned int gmac_mode            :  2; /* bits 7:6 */
+		unsigned int gmac_ds              :  1; /* bits 8:8 */
+		unsigned int flash_ds             :  1; /* bits 9:9 */
+		unsigned int nu_ds                :  1; /* bits 10:10 */
+		unsigned int ssp_ds               :  1; /* bits 11:11 */
+		unsigned int spi_ds               :  1; /* bits 12:12 */
+		unsigned int gpio_ds              :  1; /* bits 13:13 */
+		unsigned int misc_ds              :  1; /* bits 14:14 */
+		unsigned int eaxi_ds              :  1; /* bits 15:15 */
+		unsigned int sd_ds                :  8; /* bits 23:16 */
+		unsigned int rsrvd1               :  8;
+	} bf;
+	unsigned int     wrd;
+};
+
+union NI_HV_GLB_INIT_DONE_t {
+	struct {
+		unsigned int rsrvd1               :  1;
+		unsigned int ni_init_done         :  1; /* bits 1:1 */
+		unsigned int rsrvd2               : 30;
+	} bf;
+	unsigned int     wrd;
+};
+
+union NI_HV_PT_PORT_GLB_CFG_t {
+	struct {
+		unsigned int speed                :  1; /* bits 0:0 */
+		unsigned int duplex               :  1; /* bits 1:1 */
+		unsigned int link_status          :  1; /* bits 2:2 */
+		unsigned int link_stat_mask       :  1; /* bits 3:3 */
+		unsigned int rsrvd1               :  7;
+		unsigned int power_dwn_rx         :  1; /* bits 11:11 */
+		unsigned int power_dwn_tx         :  1; /* bits 12:12 */
+		unsigned int tx_intf_lp_time      :  1; /* bits 13:13 */
+		unsigned int rsrvd2               : 18;
+	} bf;
+	unsigned int     wrd;
+};
+
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC)
+#define NI_HV_GLB_MAC_ADDR_CFG0_OFFSET                  0x010
+#define NI_HV_GLB_MAC_ADDR_CFG1_OFFSET                  0x014
+#define NI_HV_PT_BASE					0x400
+#define NI_HV_XRAM_BASE					0x820
+#define GLOBAL_BLOCK_RESET_OFFSET                       0x04
+#define GLOBAL_GLOBAL_CONFIG_OFFSET                     0x20
+#define GLOBAL_IO_DRIVE_CONTROL_OFFSET                  0x4c
+#elif defined(CONFIG_TARGET_SATURN_ASIC)
+#define NI_HV_GLB_MAC_ADDR_CFG0_OFFSET                  0x010
+#define NI_HV_GLB_MAC_ADDR_CFG1_OFFSET                  0x014
+#define NI_HV_PT_BASE					0x580
+#define NI_HV_XRAM_BASE					0xA80
+#define GLOBAL_BLOCK_RESET_OFFSET                       0x28
+#define GLOBAL_GLOBAL_CONFIG_OFFSET                     0x48
+#define GLOBAL_IO_DRIVE_CONTROL_OFFSET                  0x54
+#elif defined(CONFIG_TARGET_VENUS)
+#define NI_HV_GLB_MAC_ADDR_CFG0_OFFSET                  0x014
+#define NI_HV_GLB_MAC_ADDR_CFG1_OFFSET                  0x018
+#define NI_HV_PT_BASE					0x600
+#define NI_HV_XRAM_BASE					0xA20
+#define GLOBAL_BLOCK_RESET_OFFSET                       0x28
+#define GLOBAL_GLOBAL_CONFIG_OFFSET                     0x48
+#define GLOBAL_IO_DRIVE_CONTROL_OFFSET                  0x7c
+#endif
+
+#define NI_HV_GLB_INIT_DONE_OFFSET                      0x004
+#define NI_HV_GLB_INTF_RST_CONFIG_OFFSET                0x008
+#define NI_HV_GLB_STATIC_CFG_OFFSET                     0x00c
+
+#define NI_HV_PT_PORT_STATIC_CFG_OFFSET                 NI_HV_PT_BASE
+#define NI_HV_PT_PORT_GLB_CFG_OFFSET                    (0x4 + NI_HV_PT_BASE)
+#define NI_HV_PT_RXMAC_CFG_OFFSET                       (0x8 + NI_HV_PT_BASE)
+#define NI_HV_PT_TXMAC_CFG_OFFSET                       (0x14 + NI_HV_PT_BASE)
+
+#define NI_HV_XRAM_CPUXRAM_ADRCFG_RX_OFFSET             NI_HV_XRAM_BASE
+#define NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_OFFSET           (0x4 + NI_HV_XRAM_BASE)
+#define NI_HV_XRAM_CPUXRAM_CFG_OFFSET                   (0x8 + NI_HV_XRAM_BASE)
+#define NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET          (0xc + NI_HV_XRAM_BASE)
+#define NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET          (0x10 + NI_HV_XRAM_BASE)
+#define NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET          (0x24 + NI_HV_XRAM_BASE)
+#define NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET         (0x28 + NI_HV_XRAM_BASE)
+
+#define PER_MDIO_CFG_OFFSET                             0x00
+#define PER_MDIO_ADDR_OFFSET                            0x04
+#define PER_MDIO_WRDATA_OFFSET                          0x08
+#define PER_MDIO_RDDATA_OFFSET                          0x0C
+#define PER_MDIO_CTRL_OFFSET                            0x10
+
+#define APB0_NI_HV_PT_STRIDE				160
+
+#endif /* __CORTINA_NI_H */
-- 
2.7.4



More information about the U-Boot mailing list