From: Aaron Tseng <aaron.ts...@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.ts...@cortina-access.com>
Signed-off-by: Alex Nemirovsky <alex.nemirov...@cortina-access.com>

CC: Joe Hershberger <joe.hershber...@ni.com>
CC: Abbie Chang <abbie.ch...@cortina-access.com>
CC: Tom Rini <tr...@konsulko.com>

---

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.be...@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.clem...@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.ts...@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.ts...@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

Reply via email to