From: Aaron Tseng <aaron.ts...@cortina-access.com>

Add Cortina Access Ethernet device driver for CAxxxx SoCs.
This driver supports both legacy and DM_ETH network models.

Signed-off-by: Aaron Tseng <aaron.ts...@cortina-access.com>
Signed-off-by: Alex Nemirovsky <alex.nemirov...@cortina-access.com>
Signed-off-by: Abbie Chang <abbie.ch...@cortina-access.com>
Cc: Joe Hershberger <joe.hershber...@ni.com>
---

 MAINTAINERS              |    6 +
 drivers/net/Kconfig      |    7 +
 drivers/net/Makefile     |    1 +
 drivers/net/cortina_ni.c | 2096 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/cortina_ni.h |  626 ++++++++++++++
 5 files changed, 2736 insertions(+)
 create mode 100644 drivers/net/cortina_ni.c
 create mode 100644 drivers/net/cortina_ni.h

diff --git a/MAINTAINERS b/MAINTAINERS
index dd92af5..8a7b094 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>
@@ -722,6 +724,10 @@ 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/i2c/i2c-cortina.c
+F:     drivers/i2c/i2c-cortina.h
+F:     drivers/led/led_cortina.c
+F:     drivers/spi/ca_sflash.c
 
 MIPS MSCC
 M:     Gregory CLEMENT <gregory.clem...@bootlin.com>
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 4d1013c..edeb132 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -143,6 +143,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 6e0a688..85e60f3 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..de9f2e1
--- /dev/null
+++ b/drivers/net/cortina_ni.c
@@ -0,0 +1,2096 @@
+// 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 "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
+
+struct eth_device      *dbg_dev;
+
+#endif /* CORTINA_NI_DBG */
+
+#ifdef CONFIG_DM_ETH
+static struct udevice       *curr_dev;
+#else
+static struct eth_device       *curr_dev;
+#endif
+#define RDWRPTR_ADVANCE_ONE(x, base, max) \
+       ((((x) + 1) >= (u32 *)(ca_uint)(max)) ? (u32 *)(ca_uint)base : (x) + 1)
+
+#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
+
+#ifdef CONFIG_DM_ETH
+int cortina_ni_recv(struct udevice *netdev);
+static int ca_ni_ofdata_to_platdata(struct udevice *dev);
+#else
+int cortina_ni_recv(struct eth_device *netdev);
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC)
+#define GLB_BASE_ADDR                          0xf4320000
+#define PER_MDIO_BASE_ADDR                     0xf43290d8
+#define NI_HV_BASE_ADDR                                0xf4304000
+#elif defined(CONFIG_TARGET_SATURN_ASIC)
+#define GLB_BASE_ADDR                          0x44100000
+#define PER_MDIO_BASE_ADDR                     0x522240d8
+#define NI_HV_BASE_ADDR                                0xd0004000
+#elif defined(CONFIG_TARGET_VENUS)
+#define GLB_BASE_ADDR                          0xf4320028
+#define PER_MDIO_BASE_ADDR                     0xf4329118
+#define NI_HV_BASE_ADDR                                0xf4304000
+#endif
+#endif
+
+static void ni_setup_mac_addr(void)
+{
+       unsigned char                   mac[6];
+       NI_HV_GLB_MAC_ADDR_CFG0_t       mac_addr_cfg0;
+       NI_HV_GLB_MAC_ADDR_CFG1_t       mac_addr_cfg1;
+       NI_HV_PT_PORT_STATIC_CFG_t      port_static_cfg;
+       NI_HV_XRAM_CPUXRAM_CFG_t        cpuxram_cfg;
+
+#ifdef CONFIG_DM_ETH
+       struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
+#else
+       struct cortina_ni_priv *priv =
+               (struct cortina_ni_priv *)(curr_dev->priv);
+#endif
+       /* 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)
+{
+       NI_HV_PT_RXMAC_CFG_t rxmac_cfg;
+       NI_HV_PT_TXMAC_CFG_t txmac_cfg;
+       //NI_HV_GLB_RXMUX_WEIGHT_RATIO_CFG0_t   weight_ratio_cfg0;
+       //NI_HV_GLB_RXMUX_WEIGHT_RATIO_CFG1_t   weight_ratio_cfg1;
+
+#ifdef CONFIG_DM_ETH
+       struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
+#else
+       struct cortina_ni_priv *priv =
+               (struct cortina_ni_priv *)(curr_dev->priv);
+#endif
+       /* 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));
+
+#if 0
+       /* Configure RXMUX weight ratio */
+       if (active_port >= NI_PORT_0 && active_port <= NI_PORT_3) {
+               weight_ratio_cfg0.wrd =
+                       CA_REG_READ(NI_HV_GLB_RXMUX_WEIGHT_RATIO_CFG0);
+               switch (active_port) {
+               case NI_PORT_0:
+                       weight_ratio_cfg0.bf.port0 = 0x10;
+                       break;
+               case NI_PORT_1:
+                       weight_ratio_cfg0.bf.port1 = 0x10;
+                       break;
+               case NI_PORT_2:
+                       weight_ratio_cfg0.bf.port2 = 0x10;
+                       break;
+               case NI_PORT_3:
+                       weight_ratio_cfg0.bf.port3 = 0x10;
+                       break;
+               }
+               CA_REG_WRITE(weight_ratio_cfg0.wrd,
+                            NI_HV_GLB_RXMUX_WEIGHT_RATIO_CFG0);
+       }
+
+       if (active_port >= NI_PORT_4 && active_port <= NI_PORT_7) {
+               weight_ratio_cfg1.wrd =
+                       CA_REG_READ(NI_HV_GLB_RXMUX_WEIGHT_RATIO_CFG1);
+               switch (active_port) {
+               case NI_PORT_4:
+                       weight_ratio_cfg1.bf.port4 = 0x10;
+                       break;
+               case NI_PORT_5:
+                       weight_ratio_cfg1.bf.port5 = 0x10;
+                       break;
+               case NI_PORT_6:
+                       weight_ratio_cfg1.bf.port6 = 0x10;
+                       break;
+               case NI_PORT_7:
+                       weight_ratio_cfg1.bf.port7 = 0x10;
+                       break;
+               }
+               CA_REG_WRITE(weight_ratio_cfg1.wrd,
+                            NI_HV_GLB_RXMUX_WEIGHT_RATIO_CFG1);
+       }
+#endif
+}
+
+void cortina_ni_reset(void)
+{
+       int i;
+       NI_HV_GLB_INIT_DONE_t init_done;
+       NI_HV_GLB_INTF_RST_CONFIG_t  intf_rst_config;
+       NI_HV_GLB_STATIC_CFG_t static_cfg;
+       GLOBAL_BLOCK_RESET_t    glb_blk_reset;
+
+#ifdef CONFIG_DM_ETH
+       struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
+#else
+       struct cortina_ni_priv *priv =
+               (struct cortina_ni_priv *)(curr_dev->priv);
+#endif
+       /* NI global resets */
+       glb_blk_reset.wrd = CA_REG_READ((priv->glb_base_addr +
+                               GLOBAL_BLOCK_RESET_OFFSET));
+       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);
+       }
+
+       switch (active_port) {
+#ifdef CONFIG_CA77XX
+       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 ca_status_t ca_mdio_write_rgmii(ca_uint32_t addr,
+                                      ca_uint32_t offset,
+                                      ca_uint16_t data)
+{
+       PER_MDIO_ADDR_t  mdio_addr;
+       PER_MDIO_CTRL_t  mdio_ctrl;
+       /* up to 10000 cycles*/
+       ca_uint32_t      loop_wait = __MDIO_ACCESS_TIMEOUT;
+
+#ifdef CONFIG_DM_ETH
+       struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
+#else
+       struct cortina_ni_priv *priv =
+               (struct cortina_ni_priv *)(curr_dev->priv);
+#endif
+       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;
+}
+
+ca_status_t ca_mdio_write(CA_IN       ca_uint32_t             addr,
+                         CA_IN       ca_uint32_t             offset,
+                         CA_IN       ca_uint16_t             data)
+{
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || \
+       defined(CONFIG_TARGET_SATURN_ASIC) || defined(CONFIG_TARGET_VENUS)
+       NI_MDIO_OPER_T  mdio_oper;
+
+       __MDIO_ADDR_CHK(addr);
+
+       /* 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
+       __MDIO_ADDR_CHK(addr);
+
+       return ca_mdio_write_rgmii(addr, offset, data);
+#endif
+}
+
+static ca_status_t ca_mdio_read_rgmii(ca_uint32_t addr,
+                                     ca_uint32_t offset,
+                                     ca_uint16_t *data)
+{
+       PER_MDIO_ADDR_t  mdio_addr;
+       PER_MDIO_CTRL_t  mdio_ctrl;
+       PER_MDIO_RDDATA_t  read_data;
+       ca_uint32_t      loop_wait = __MDIO_ACCESS_TIMEOUT;
+
+#ifdef CONFIG_DM_ETH
+       struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
+#else
+       struct cortina_ni_priv *priv =
+               (struct cortina_ni_priv *)(curr_dev->priv);
+#endif
+       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;
+}
+
+ca_status_t ca_mdio_read(CA_IN       ca_uint32_t             addr,
+                        CA_IN       ca_uint32_t             offset,
+                        CA_OUT      ca_uint16_t             *data)
+{
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || \
+       defined(CONFIG_TARGET_SATURN_ASIC) || defined(CONFIG_TARGET_VENUS)
+       NI_MDIO_OPER_T  mdio_oper;
+
+       CA_ASSERT(data);
+       __MDIO_ADDR_CHK(addr); /* support range: 1~31*/
+
+       /* 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
+       CA_ASSERT(data);
+       __MDIO_ADDR_CHK(addr); /* support range: 1~31*/
+
+       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 0
+int g2_phy_disable(int port)
+{
+       unsigned int addr, val;
+
+       switch (port) {
+       case 0:
+               addr = GE_PORT0_PHY_ADDR;
+               break;
+       case 1:
+               addr = GE_PORT1_PHY_ADDR;
+               break;
+       case 2:
+               addr = GE_PORT2_PHY_ADDR;
+               break;
+       default:
+               printf("%s: invalid port %d\n", __func__, port);
+               return -1;
+       }
+
+       if (addr == 0)  /* ignore PHY address 0 */
+               return 0;
+
+       val = ca_mdio_read(addr, 0);
+       val = val | (1 << 11); /* set power down */
+       ca_mdio_write(addr, 0, val);
+       return 0;
+}
+#endif
+
+#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=%d, read register 19, "
+                             "val=0x%x\n", __func__, phy_addr, data);
+               }
+#ifdef CORTINA_NI_DBG
+               printf("%s: phy_addr=%d, read register 19, value=0x%x\n",
+                      __func__, phy_addr, data);
+#endif
+       }
+}
+#endif
+
+#ifdef CONFIG_DM_ETH
+int cortina_ni_init(struct udevice *dev)
+#else
+int cortina_ni_init(struct eth_device *dev, bd_t *bd)
+#endif
+{
+       u16  vendor_id, chip_id;
+       u32  phy_id;
+       u16  phy_reg_value, lpagb, lpa, phy_speed, phy_duplex, speed, duplex;
+       char *spd, *dup;
+       NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t  cpuxram_adrcfg_rx;
+       NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t  cpuxram_adrcfg_tx;
+       NI_HV_XRAM_CPUXRAM_CFG_t        cpuxram_cfg;
+       NI_HV_PT_PORT_STATIC_CFG_t      port_static_cfg;
+       NI_HV_PT_PORT_GLB_CFG_t port_glb_cfg;
+
+#ifdef CONFIG_DM_ETH
+       struct cortina_ni_priv *priv = dev_get_priv(dev);
+#else
+       struct cortina_ni_priv *priv = (struct cortina_ni_priv *)(dev->priv);
+#endif
+       /* 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:
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
+       case PHY_ID_RTL8211_G3_ASIC:
+#endif
+#ifdef CONFIG_TARGET_SATURN_ASIC
+       case PHY_ID_RTL8211_SATURN_ASIC:
+#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.xram_mgmt_promisc_mode = 3;
+       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;
+       NI_HV_XRAM_CPUXRAM_CFG_t        cpuxram_cfg;
+
+#ifdef CONFIG_DM_ETH
+       struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
+#else
+       struct cortina_ni_priv *priv =
+               (struct cortina_ni_priv *)(curr_dev->priv);
+#endif
+
+       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
+ *******************************************/
+#ifdef CONFIG_DM_ETH
+int cortina_ni_recv(struct udevice *netdev)
+#else
+int cortina_ni_recv(struct eth_device *netdev)
+#endif
+{
+#ifdef CONFIG_DM_ETH
+       struct cortina_ni_priv *priv = dev_get_priv(netdev);
+#else
+       struct cortina_ni_priv *priv =
+               (struct cortina_ni_priv *)(netdev->priv);
+#endif
+       NI_HEADER_X_T           header_x;
+       u32                     pktlen = 0;
+       u32                     sw_rx_rd_ptr;
+       u32                     hw_rx_wr_ptr;
+       volatile u32            *rx_xram_ptr;
+#ifdef CORTINA_NI_DBG
+       int                     blk_num;
+#endif
+       int                     loop;
+       //static unsigned char  pkt_buf[2048];
+       u32                     *data_ptr;
+#ifdef CORTINA_NI_DBG
+       u8                      *ptr;
+#endif
+       NI_PACKET_STATUS_T      packet_status;
+       NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t cpuxram_cpu_sta_rx;
+       NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t cpuxram_cpu_cfg_rx;
+       int                     index = 0;
+
+       /* 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%x, "
+             "NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0=0x%x\n",
+             __func__, NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0,
+             NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0);
+
+       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 *)((ca_uint)NI_XRAM_BASE + sw_rx_rd_ptr * 8);
+
+               /* Wrap around if required */
+               if (rx_xram_ptr >= (u32 *)(ca_uint)(priv->rx_xram_end_adr))
+                       rx_xram_ptr = (u32 *)(ca_uint)(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 = (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 = (NI_PACKET_STATUS_T)(*rx_xram_ptr);
+
+#if CORTINA_NI_DBG
+                       printf("%s: packet_status=0x%x\n",
+                              __func__, packet_status);
+#endif
+                       if (packet_status.bf.valid == 0) {
+#if CORTINA_NI_DBG
+                               printf("%s: Invalid Packet !!, "
+                                      "Packet status=0x%x, "
+                                      "header_x.bf.next_link=%d\n",
+                                      __func__, packet_status.wrd,
+                                      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,"
+                                     " header_x.bf.next_link=%d\n",
+                                     __func__, packet_status.wrd,
+                                     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, "
+                                      "larger than 1518, "
+                                      "Packet status=0x%x, "
+                                      "header_x.bf.next_link=%d\n",
+                                      __func__,
+                                      packet_status.bf.packet_size,
+                                      packet_status.wrd,
+                                      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 0
+                       /* Wrap around if required */
+                       if (rx_xram_ptr >=
+                           (u32 *)(ca_uint)(priv->rx_xram_end_adr))
+                               rx_xram_ptr =
+                                      (u32 *)(ca_uint)(priv->rx_xram_base_adr);
+
+                       rx_xram_ptr++;  /* skip Packet status [31:0] */
+
+                       /* Wrap around if required */
+                       if (rx_xram_ptr >=
+                           (u32 *)(ca_uint)(priv->rx_xram_end_adr))
+                               rx_xram_ptr =
+                                      (u32 *)(ca_uint)(priv->rx_xram_base_adr);
+#endif
+                       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 = rx_xram_ptr;
+                               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 *)(ca_uint)(priv->rx_xram_end_adr))
+                                       rx_xram_ptr = (u32 *)(ca_uint)
+                                                      (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;
+}
+
+#ifdef CONFIG_DM_ETH
+static int cortina_ni_send(struct udevice *dev, void *packet, int length)
+#else
+static int cortina_ni_send(struct eth_device *dev, void *packet, int length)
+#endif
+{
+#ifdef CONFIG_DM_ETH
+       struct cortina_ni_priv *priv = dev_get_priv(dev);
+#else
+       struct cortina_ni_priv *priv = (struct cortina_ni_priv *)(dev->priv);
+#endif
+       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;
+       //unsigned int  hdr_xt = 0;
+       NI_HEADER_X_T   hdr_xt;
+       int             pad = 0;
+       static unsigned char   pkt_buf[2048];
+       u32     *data_ptr;
+       //NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_t    cpuxram_cpu_stat_tx;
+       NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t       cpuxram_cpu_cfg_tx;
+#if CORTINA_NI_DBG
+       u8 *ptr;
+#endif
+
+       if (NULL == packet || length > 2032)
+               return -1;
+
+       /* Get the hardware read pointer */
+       //cpuxram_cpu_stat_tx.wrd =
+       //                      CA_REG_READ(NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0);
+       //hw_tx_rd_ptr = cpuxram_cpu_stat_tx.bf.pkt_rd_ptr;
+       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 */
+       //cpuxram_cpu_cfg_tx.wrd = CA_REG_READ(NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0);
+       //sw_tx_wr_ptr = cpuxram_cpu_cfg_tx.bf.pkt_wr_ptr;
+       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%x, "
+             "NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0=0x%x\n",
+             __func__,
+             KSEG1_ATU_XLAT(NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0),
+             KSEG1_ATU_XLAT(NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0));
+#else
+       printf("%s: NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0=0x%x, "
+             "NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0=0x%x\n",
+             __func__,
+             NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0,
+             NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0);
+#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 *)((ca_uint)NI_XRAM_BASE + sw_tx_wr_ptr * 8);
+
+       /* Wrap around if required */
+       if (tx_xram_ptr >= (u32 *)(ca_uint)(priv->tx_xram_end_adr))
+               tx_xram_ptr = (u32 *)(ca_uint)(priv->tx_xram_base_adr);
+
+#if  0
+       /* skip first 4 bytes before copying the headerXT */
+       tx_xram_ptr++;
+
+       /* Wrap around if required */
+       if (tx_xram_ptr >= (u32 *)(ca_uint)(priv->tx_xram_end_adr))
+               tx_xram_ptr = (u32 *)(ca_uint)(priv->tx_xram_base_adr);
+#endif
+       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;
+
+#if  0
+       tx_xram_ptr++;
+
+       /* Wrap around if required */
+       if (tx_xram_ptr >= (u32 *)(ca_uint)(priv->tx_xram_end_adr))
+               tx_xram_ptr = (u32 *)(ca_uint)(priv->tx_xram_base_adr);
+#endif
+       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 = 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
+
+#if 0
+               *tx_xram_ptr++ = *data_ptr++;
+               /* Wrap around if required */
+               if (tx_xram_ptr >= (u32 *)(ca_uint)(priv->tx_xram_end_adr))
+                       tx_xram_ptr = (u32 *)(ca_uint)(priv->tx_xram_base_adr);
+#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 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;
+}
+
+#ifdef CONFIG_DM_ETH
+void cortina_ni_halt(struct udevice *netdev)
+#else
+void cortina_ni_halt(struct eth_device *netdev)
+#endif
+{
+#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
+};
+
+#ifdef CONFIG_TARGET_PRESIDIO_ASIC
+/* move to LED driver */
+#if 0
+/* initialize LEDs for ethernet link and traffic lights */
+static void ca77xx_init_led(void)
+{
+       int i;
+       GLOBAL_PIN_MUX_t        pin_mux;
+       GLOBAL_LED_CONTROL_t    led_control;
+       GLOBAL_LED_CONFIG_0_t   led_config0;
+
+       pin_mux.wrd = CA_REG_READ(GLOBAL_PIN_MUX);
+       pin_mux.bf.iomux_led_enable = 1;
+       CA_REG_WRITE(pin_mux.wrd, GLOBAL_PIN_MUX);
+
+       /* LED control & config - led 0 ~ 7 for rx of port 0 ~ 7,
+        * led 8 ~ 15 for tx of port 0 ~ 7 with 256ms blinking
+        */
+       led_control.wrd = CA_REG_READ(GLOBAL_LED_CONTROL);
+       led_control.bf.blink_rate_1 = 0x0f;
+       led_control.bf.blink_rate_2 = 0x1f;
+       CA_REG_WRITE(led_control.wrd, GLOBAL_LED_CONTROL);
+
+       for (i = 0; i < 8; i++) {
+               led_config0.wrd = CA_REG_READ(GLOBAL_LED_CONFIG_0 + i * 4);
+               led_config0.bf.led_event_blink = 1;
+               led_config0.bf.led_off_val = 1;
+               led_config0.bf.led_port = i;
+               CA_REG_WRITE(led_config0.wrd, GLOBAL_LED_CONFIG_0 + i * 4);
+       }
+
+       for (i = 0; i < 8; i++) {
+               led_config0.wrd = CA_REG_READ(GLOBAL_LED_CONFIG_8 + i * 4);
+               led_config0.bf.led_event_blink = 2;
+               led_config0.bf.led_off_val = 1;
+               led_config0.bf.led_port = i;
+               CA_REG_WRITE(led_config0.wrd, GLOBAL_LED_CONFIG_8 + i * 4);
+       }
+}
+#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;
+       ca_uint16_t 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 to 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;
+       ca_uint16_t data;
+
+       /* if etherent not initialized do nothing */
+       if (NULL == 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;
+       ca_uint16_t data;
+
+       /* 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();
+
+       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;
+       ca_uint16_t 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, read register 19, "
+                     "value=0x%x\n", __func__, phy_addr, 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
+typedef struct gphy_cal_s {
+       u32 reg_off;
+       u32 value;
+} gphy_cal_t;
+
+static gphy_cal_t 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
+
+#ifdef CONFIG_DM_ETH
+int ca77xx_eth_initialize(struct udevice *dev)
+#else
+int ca77xx_eth_initialize(bd_t *bis)
+#endif
+{
+       struct cortina_ni_priv  *priv;
+       char            *buf;
+       u16             val;
+       int             i;
+       u16             vendor_id, chip_id;
+       u32             phy_id;
+
+#ifndef CONFIG_DM_ETH
+       struct eth_device       *dev;
+
+       dev = (struct eth_device *)malloc(sizeof(*dev));
+       if (NULL == dev)
+               return 1;
+       memset(dev, 0, sizeof(*dev));
+       priv = (struct cortina_ni_priv *)malloc(sizeof(*priv));
+       if (NULL == priv) {
+               free(dev);
+               return 1;
+       }
+       memset(priv, 0, sizeof(*priv));
+
+       dev->priv = priv;
+       priv->glb_base_addr = GLB_BASE_ADDR;
+       priv->per_mdio_base_addr = PER_MDIO_BASE_ADDR;
+       priv->ni_hv_base_addr = NI_HV_BASE_ADDR;
+       printf("%s: priv->glb_base_addr is 0x%x\n",
+              __func__, priv->glb_base_addr);
+       printf("%s: priv->per_mdio_base_addr is 0x%x\n",
+              __func__, priv->per_mdio_base_addr);
+       printf("%s: priv->ni_hv_base_addr is 0x%x\n",
+              __func__, priv->ni_hv_base_addr);
+#else
+       priv = dev_get_priv(dev);
+#endif
+
+       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 %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 "
+                                      "%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) {
+               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);
+       }
+
+       /* 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) {
+               u8      phy_addr;
+
+               if (!auto_scan_active_port) {
+                       printf("%s: write initial sequency for "
+                             "PHY_ID_RTL8211_G3_ASIC!!\n", __func__);
+
+                       /* 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();
+               }
+       }
+
+       ca77xx_ni_scan_phy_link();
+#endif
+
+#ifdef CONFIG_TARGET_VENUS
+       /* REG9 write 0x0200->0x0000, disable adv. 1000BASE capability */
+       ca_mdio_write(ge_port_phy_addr, 0x09, 0x0000);
+       /* REG0 write 0x1040->0x9040, reset and associate the PHY link
+        * REG0 and REG1 will return to default values after reset
+        */
+       ca_mdio_read(ge_port_phy_addr, 0x00, &val);
+       val |= 0x8000;
+       ca_mdio_write(ge_port_phy_addr, 0x00, val);
+       mdelay(1);
+#endif
+
+       /* parsing ethaddr and set to NI registers. */
+       ni_setup_mac_addr();
+
+#ifndef CONFIG_DM_ETH
+       sprintf(dev->name, CONFIG_IDENT_STRING);
+       dev->init = cortina_ni_init;
+       dev->halt = cortina_ni_halt;
+       dev->send = cortina_ni_send;
+       dev->recv = cortina_ni_recv;
+
+       eth_register(dev);
+#endif
+       /* 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 */
+       {
+               GLOBAL_GLOBAL_CONFIG_t  glb_config;
+               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();
+
+       /* do internal gphy calibration */
+       do_internal_gphy_cal();
+#endif
+       return 0;
+}
+
+#if CORTINA_NI_DBG
+DECLARE_GLOBAL_DATA_PTR;
+int do_eth_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       bd_t *bd = gd->bd;
+
+       cortina_ni_init(0x00, bd);
+       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(cmd_tbl_t *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(cmd_tbl_t *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(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       unsigned int    phy_adr;
+       unsigned int    reg_off;
+       ca_uint16_t     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(cmd_tbl_t *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(cmd_tbl_t *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, "
+                              "ret = %d\n", phy_addr, reg, val, 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
+
+#ifdef CONFIG_DM_ETH
+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,
+};
+
+#endif
diff --git a/drivers/net/cortina_ni.h b/drivers/net/cortina_ni.h
new file mode 100644
index 0000000..ae04063
--- /dev/null
+++ b/drivers/net/cortina_ni.h
@@ -0,0 +1,626 @@
+/* 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 CS_SWAP32(x)   ((((x) & 0xFF000000) >> 24)  \
+                       | (((x)  & 0xFF0000) >> 8)   \
+                       | (((x)  & 0xFF00) << 8)     \
+                       | (((x)  & 0xFF) << 24))
+
+#ifdef CONFIG_MK_REFERENCEQ
+#define CONFIG_CS75XX_PHY_ADDR_GMAC0                   4
+#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
+
+typedef unsigned long           ca_uint;
+typedef unsigned int            ca_uint32_t;
+typedef unsigned short          ca_uint16_t;
+typedef ca_uint32_t             ca_uint32;
+
+typedef enum {
+       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,
+} ca_status_t;
+
+#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
+};
+
+typedef volatile union {
+       struct {
+               ca_uint32 next_link             : 10; /* bits  9: 0 */
+               ca_uint32 bytes_valid           :  4; /* bits 13:10 */
+               ca_uint32 reserved              : 16; /* bits 29:14 */
+               ca_uint32 hdr_a                 :  1; /* bits 30:30 */
+               ca_uint32 ownership             :  1; /* bits 31:31 */
+       } bf;
+       ca_uint32     wrd;
+} NI_HEADER_X_T;
+
+typedef volatile union {
+       struct {
+               ca_uint32 packet_size       : 14; /* bits 13:0 */
+               ca_uint32 byte_valid        :  4; /* bits 17:14 */
+               ca_uint32 pfc               :  1; /* bits 18:18 */
+               ca_uint32 valid             :  1; /* bits 19:19 */
+               ca_uint32 drop              :  1; /* bits 20:20 */
+               ca_uint32 runt              :  1; /* bits 21:21 */
+               ca_uint32 oversize          :  1; /* bits 22:22 */
+               ca_uint32 jumbo             :  1; /* bits 23:23 */
+               ca_uint32 link_status       :  1; /* bits 24:24 */
+               ca_uint32 jabber            :  1; /* bits 25:25 */
+               ca_uint32 crc_error         :  1; /* bits 26:26 */
+               ca_uint32 pause             :  1; /* bits 27:27 */
+               ca_uint32 oam               :  1; /* bits 28:28 */
+               ca_uint32 unknown_opcode    :  1; /* bits 29:29 */
+               ca_uint32 multicast         :  1; /* bits 30:30 */
+               ca_uint32 broadcast         :  1; /* bits 31:31 */
+       } bf;
+       ca_uint32     wrd;
+} NI_PACKET_STATUS_T;
+
+#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
+
+typedef volatile union {
+       struct {
+               ca_uint32 reserved       : 2; /* bits  1:0 */
+               ca_uint32 reg_off        : 5; /* bits  6:2 */
+               ca_uint32 phy_addr       : 5; /* bits 11:7 */
+               ca_uint32 reg_base       : 20; /* bits 31:12 */
+       } bf;
+       ca_uint32     wrd;
+} NI_MDIO_OPER_T;
+
+#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)
+
+#define __MDIO_ADDR_CHK(addr) do {                             \
+       if ((addr) < CA_MDIO_ADDR_MIN ||                        \
+                       (addr) > CA_MDIO_ADDR_MAX) {            \
+               return CA_E_PARAM;                              \
+       }                                                       \
+} while (0)
+
+#define CA_ASSERT(x)      do {                                 \
+       if (!(x))                                               \
+       return CA_E_PARAM;                                      \
+} while (0)
+
+#endif /* !__ASSEMBLER__ */
+
+/* Copy from registers.h */
+typedef volatile union {
+       struct {
+               ca_uint32_t mac_addr0            : 32; /* bits 31:0 */
+       } bf;
+       ca_uint32_t     wrd;
+} NI_HV_GLB_MAC_ADDR_CFG0_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t mac_addr1            :  8; /* bits 7:0 */
+               ca_uint32_t rsrvd1               : 24;
+       } bf;
+       ca_uint32_t     wrd;
+} NI_HV_GLB_MAC_ADDR_CFG1_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t int_cfg              :  4; /* bits 3:0 */
+               ca_uint32_t phy_mode             :  1; /* bits 4:4 */
+               ca_uint32_t rmii_clksrc          :  1; /* bits 5:5 */
+               ca_uint32_t inv_clk_in           :  1; /* bits 6:6 */
+               ca_uint32_t inv_clk_out          :  1; /* bits 7:7 */
+               ca_uint32_t inv_rxclk_out        :  1; /* bits 8:8 */
+               ca_uint32_t tx_use_gefifo        :  1; /* bits 9:9 */
+               ca_uint32_t smii_tx_stat         :  1; /* bits 10:10 */
+               ca_uint32_t crs_polarity         :  1; /* bits 11:11 */
+               ca_uint32_t lpbk_mode            :  2; /* bits 13:12 */
+               ca_uint32_t gmii_like_half_duplex_en :  1; /* bits 14:14 */
+               ca_uint32_t sup_tx_to_rx_lpbk_data :  1; /* bits 15:15 */
+               ca_uint32_t rsrvd1               :  8;
+               ca_uint32_t mac_addr6            :  8; /* bits 31:24 */
+       } bf;
+       ca_uint32_t     wrd;
+} NI_HV_PT_PORT_STATIC_CFG_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t rx_0_cpu_pkt_dis     :  1; /* bits 0:0 */
+               ca_uint32_t rsrvd1               :  8;
+               ca_uint32_t tx_0_cpu_pkt_dis     :  1; /* bits 9:9 */
+               ca_uint32_t rsrvd2               :  1;
+               ca_uint32_t rx_x_drop_err_pkt    :  1; /* bits 11:11 */
+               ca_uint32_t xram_mgmt_dis_drop_ovsz_pkt :  1; /* bits 12:12 */
+               ca_uint32_t xram_mgmt_term_large_pkt :  1; /* bits 13:13 */
+               ca_uint32_t xram_mgmt_promisc_mode :  2; /* bits 15:14 */
+               ca_uint32_t xram_cntr_debug_mode :  1; /* bits 16:16 */
+               ca_uint32_t xram_cntr_op_code    :  2; /* bits 18:17 */
+               ca_uint32_t rsrvd3               :  2;
+               ca_uint32_t xram_rx_mgmtfifo_srst :  1; /* bits 21:21 */
+               ca_uint32_t xram_dma_fifo_srst   :  1; /* bits 22:22 */
+               ca_uint32_t rsrvd4               :  9;
+       } bf;
+       ca_uint32_t     wrd;
+} NI_HV_XRAM_CPUXRAM_CFG_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t rx_en                :  1; /* bits 0:0 */
+               ca_uint32_t rsrvd1               :  7;
+               ca_uint32_t rx_flow_disable      :  1; /* bits 8:8 */
+               ca_uint32_t rsrvd2               :  3;
+               ca_uint32_t rx_flow_to_tx_en     :  1; /* bits 12:12 */
+               ca_uint32_t rx_pfc_disable       :  1; /* bits 13:13 */
+               ca_uint32_t rsrvd3               : 15;
+               ca_uint32_t send_pg_data         :  1; /* bits 29:29 */
+               ca_uint32_t rsrvd4               :  2;
+       } bf;
+       ca_uint32_t     wrd;
+} NI_HV_PT_RXMAC_CFG_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t tx_en                :  1; /* bits 0:0 */
+               ca_uint32_t rsrvd1               :  7;
+               ca_uint32_t mac_crc_calc_en      :  1; /* bits 8:8 */
+               ca_uint32_t tx_ipg_sel           :  3; /* bits 11:9 */
+               ca_uint32_t tx_flow_disable      :  1; /* bits 12:12 */
+               ca_uint32_t tx_drain             :  1; /* bits 13:13 */
+               ca_uint32_t tx_pfc_disable       :  1; /* bits 14:14 */
+               ca_uint32_t tx_pau_sel           :  2; /* bits 16:15 */
+               ca_uint32_t rsrvd2               :  9;
+               ca_uint32_t tx_auto_xon          :  1; /* bits 26:26 */
+               ca_uint32_t rsrvd3               :  1;
+               ca_uint32_t pass_thru_hdr        :  1; /* bits 28:28 */
+               ca_uint32_t rsrvd4               :  3;
+       } bf;
+       ca_uint32_t     wrd;
+} NI_HV_PT_TXMAC_CFG_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t intf_rst_p0          :  1; /* bits 0:0 */
+               ca_uint32_t intf_rst_p1          :  1; /* bits 1:1 */
+               ca_uint32_t intf_rst_p2          :  1; /* bits 2:2 */
+               ca_uint32_t intf_rst_p3          :  1; /* bits 3:3 */
+               ca_uint32_t intf_rst_p4          :  1; /* bits 4:4 */
+               ca_uint32_t mac_rx_rst_p0        :  1; /* bits 5:5 */
+               ca_uint32_t mac_rx_rst_p1        :  1; /* bits 6:6 */
+               ca_uint32_t mac_rx_rst_p2        :  1; /* bits 7:7 */
+               ca_uint32_t mac_rx_rst_p3        :  1; /* bits 8:8 */
+               ca_uint32_t mac_rx_rst_p4        :  1; /* bits 9:9 */
+               ca_uint32_t mac_tx_rst_p0        :  1; /* bits 10:10 */
+               ca_uint32_t mac_tx_rst_p1        :  1; /* bits 11:11 */
+               ca_uint32_t mac_tx_rst_p2        :  1; /* bits 12:12 */
+               ca_uint32_t mac_tx_rst_p3        :  1; /* bits 13:13 */
+               ca_uint32_t mac_tx_rst_p4        :  1; /* bits 14:14 */
+               ca_uint32_t port_rst_p5          :  1; /* bits 15:15 */
+               ca_uint32_t pcs_rst_p6           :  1; /* bits 16:16 */
+               ca_uint32_t pcs_rst_p7           :  1; /* bits 17:17 */
+               ca_uint32_t mac_rst_p6           :  1; /* bits 18:18 */
+               ca_uint32_t mac_rst_p7           :  1; /* bits 19:19 */
+               ca_uint32_t rsrvd1               : 12;
+       } bf;
+       ca_uint32_t     wrd;
+} NI_HV_GLB_INTF_RST_CONFIG_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t port_to_cpu          :  4; /* bits 3:0 */
+               ca_uint32_t mgmt_pt_to_fe_also   :  1; /* bits 4:4 */
+               ca_uint32_t txcrc_chk_en         :  1; /* bits 5:5 */
+               ca_uint32_t p4_rgmii_tx_clk_phase :  2; /* bits 7:6 */
+               ca_uint32_t p4_rgmii_tx_data_order :  1; /* bits 8:8 */
+               ca_uint32_t rsrvd1               :  7;
+               ca_uint32_t rxmib_mode           :  1; /* bits 16:16 */
+               ca_uint32_t txmib_mode           :  1; /* bits 17:17 */
+               ca_uint32_t eth_sch_rdy_pkt      :  1; /* bits 18:18 */
+               ca_uint32_t rsrvd2               :  1;
+               ca_uint32_t rxaui_mode           :  2; /* bits 21:20 */
+               ca_uint32_t rxaui_sigdet         :  2; /* bits 23:22 */
+               ca_uint32_t cnt_op_mode          :  3; /* bits 26:24 */
+               ca_uint32_t rsrvd3               :  5;
+       } bf;
+       ca_uint32_t     wrd;
+} NI_HV_GLB_STATIC_CFG_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t reset_ni             :  1; /* bits 0:0 */
+               ca_uint32_t reset_l2fe           :  1; /* bits 1:1 */
+               ca_uint32_t reset_l2tm           :  1; /* bits 2:2 */
+               ca_uint32_t reset_l3fe           :  1; /* bits 3:3 */
+               ca_uint32_t reset_sdram          :  1; /* bits 4:4 */
+               ca_uint32_t reset_tqm            :  1; /* bits 5:5 */
+               ca_uint32_t reset_pcie0          :  1; /* bits 6:6 */
+               ca_uint32_t reset_pcie1          :  1; /* bits 7:7 */
+               ca_uint32_t reset_pcie2          :  1; /* bits 8:8 */
+               ca_uint32_t reset_sata           :  1; /* bits 9:9 */
+               ca_uint32_t reset_gic400         :  1; /* bits 10:10 */
+               ca_uint32_t rsrvd1               :  2;
+               ca_uint32_t reset_usb            :  1; /* bits 13:13 */
+               ca_uint32_t reset_flash          :  1; /* bits 14:14 */
+               ca_uint32_t reset_per            :  1; /* bits 15:15 */
+               ca_uint32_t reset_dma            :  1; /* bits 16:16 */
+               ca_uint32_t reset_rtc            :  1; /* bits 17:17 */
+               ca_uint32_t reset_pe0            :  1; /* bits 18:18 */
+               ca_uint32_t reset_pe1            :  1; /* bits 19:19 */
+               ca_uint32_t reset_rcpu0          :  1; /* bits 20:20 */
+               ca_uint32_t reset_rcpu1          :  1; /* bits 21:21 */
+               ca_uint32_t reset_sadb           :  1; /* bits 22:22 */
+               ca_uint32_t rsrvd2               :  1;
+               ca_uint32_t reset_rcrypto        :  1; /* bits 24:24 */
+               ca_uint32_t reset_ldma           :  1; /* bits 25:25 */
+               ca_uint32_t reset_fbm            :  1; /* bits 26:26 */
+               ca_uint32_t reset_eaxi           :  1; /* bits 27:27 */
+               ca_uint32_t reset_sd             :  1; /* bits 28:28 */
+               ca_uint32_t reset_otprom         :  1; /* bits 29:29 */
+               ca_uint32_t rsrvd3               :  2;
+       } bf;
+       ca_uint32_t     wrd;
+} GLOBAL_BLOCK_RESET_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t mdio_addr            :  5; /* bits 4:0 */
+               ca_uint32_t rsrvd1               :  3;
+               ca_uint32_t mdio_offset          :  5; /* bits 12:8 */
+               ca_uint32_t rsrvd2               :  2;
+               ca_uint32_t mdio_rd_wr           :  1; /* bits 15:15 */
+               ca_uint32_t mdio_st              :  1; /* bits 16:16 */
+               ca_uint32_t rsrvd3               :  1;
+               ca_uint32_t mdio_op              :  2; /* bits 19:18 */
+               ca_uint32_t rsrvd4               : 12;
+       } bf;
+       ca_uint32_t     wrd;
+} PER_MDIO_ADDR_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t mdiodone             :  1; /* bits 0:0 */
+               ca_uint32_t rsrvd1               :  6;
+               ca_uint32_t mdiostart            :  1; /* bits 7:7 */
+               ca_uint32_t rsrvd2               : 24;
+       } bf;
+       ca_uint32_t     wrd;
+} PER_MDIO_CTRL_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t mdio_rddata          : 16; /* bits 15:0 */
+               ca_uint32_t rsrvd1               : 16;
+       } bf;
+       ca_uint32_t     wrd;
+} PER_MDIO_RDDATA_t;
+
+/*
+ * XRAM
+ */
+
+typedef volatile union {
+       struct {
+               ca_uint32_t rx_base_addr         : 10; /* bits 9:0 */
+               ca_uint32_t rsrvd1               :  6;
+               ca_uint32_t rx_top_addr          : 10; /* bits 25:16 */
+               ca_uint32_t rsrvd2               :  6;
+       } bf;
+       ca_uint32_t     wrd;
+} NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t tx_base_addr         : 10; /* bits 9:0 */
+               ca_uint32_t rsrvd1               :  6;
+               ca_uint32_t tx_top_addr          : 10; /* bits 25:16 */
+               ca_uint32_t rsrvd2               :  6;
+       } bf;
+       ca_uint32_t     wrd;
+} NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t pkt_wr_ptr           : 10; /* bits 9:0 */
+               ca_uint32_t rsrvd1               :  5;
+               ca_uint32_t int_colsc_thresh_reached :  1; /* bits 15:15 */
+               ca_uint32_t rsrvd2               : 16;
+       } bf;
+       ca_uint32_t     wrd;
+} NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t pkt_rd_ptr           : 10; /* bits 9:0 */
+               ca_uint32_t rsrvd1               : 22;
+       } bf;
+       ca_uint32_t     wrd;
+} NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t pkt_wr_ptr           : 10; /* bits 9:0 */
+               ca_uint32_t rsrvd1               : 22;
+       } bf;
+       ca_uint32_t     wrd;
+} NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t rsrvd1               :  4;
+               ca_uint32_t wd_reset_subsys_enable :  1; /* bits 4:4 */
+               ca_uint32_t rsrvd2               :  1;
+               ca_uint32_t wd_reset_all_blocks  :  1; /* bits 6:6 */
+               ca_uint32_t wd_reset_remap       :  1; /* bits 7:7 */
+               ca_uint32_t wd_reset_ext_reset   :  1; /* bits 8:8 */
+               ca_uint32_t ext_reset            :  1; /* bits 9:9 */
+               ca_uint32_t cfg_pcie_0_clken     :  1; /* bits 10:10 */
+               ca_uint32_t cfg_sata_clken       :  1; /* bits 11:11 */
+               ca_uint32_t cfg_pcie_1_clken     :  1; /* bits 12:12 */
+               ca_uint32_t rsrvd3               :  1;
+               ca_uint32_t cfg_pcie_2_clken     :  1; /* bits 14:14 */
+               ca_uint32_t rsrvd4               :  2;
+               ca_uint32_t ext_eth_refclk       :  1; /* bits 17:17 */
+               ca_uint32_t refclk_sel           :  2; /* bits 19:18 */
+               ca_uint32_t rsrvd5               :  7;
+               ca_uint32_t l3fe_pd              :  1; /* bits 27:27 */
+               ca_uint32_t offload0_pd          :  1; /* bits 28:28 */
+               ca_uint32_t offload1_pd          :  1; /* bits 29:29 */
+               ca_uint32_t crypto_pd            :  1; /* bits 30:30 */
+               ca_uint32_t core_pd              :  1; /* bits 31:31 */
+       } bf;
+       ca_uint32_t     wrd;
+} GLOBAL_GLOBAL_CONFIG_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t gmac_dp              :  3; /* bits 2:0 */
+               ca_uint32_t gmac_dn              :  3; /* bits 5:3 */
+               ca_uint32_t gmac_mode            :  2; /* bits 7:6 */
+               ca_uint32_t gmac_ds              :  1; /* bits 8:8 */
+               ca_uint32_t flash_ds             :  1; /* bits 9:9 */
+               ca_uint32_t nu_ds                :  1; /* bits 10:10 */
+               ca_uint32_t ssp_ds               :  1; /* bits 11:11 */
+               ca_uint32_t spi_ds               :  1; /* bits 12:12 */
+               ca_uint32_t gpio_ds              :  1; /* bits 13:13 */
+               ca_uint32_t misc_ds              :  1; /* bits 14:14 */
+               ca_uint32_t eaxi_ds              :  1; /* bits 15:15 */
+               ca_uint32_t sd_ds                :  8; /* bits 23:16 */
+               ca_uint32_t rsrvd1               :  8;
+       } bf;
+       ca_uint32_t     wrd;
+} GLOBAL_IO_DRIVE_CONTROL_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t rsrvd1               :  1;
+               ca_uint32_t ni_init_done         :  1; /* bits 1:1 */
+               ca_uint32_t rsrvd2               : 30;
+       } bf;
+       ca_uint32_t     wrd;
+} NI_HV_GLB_INIT_DONE_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t mdio_wrdata          : 16; /* bits 15:0 */
+               ca_uint32_t rsrvd1               : 16;
+       } bf;
+       ca_uint32_t     wrd;
+} PER_MDIO_WRDATA_t;
+
+typedef volatile union {
+       struct {
+               ca_uint32_t speed                :  1; /* bits 0:0 */
+               ca_uint32_t duplex               :  1; /* bits 1:1 */
+               ca_uint32_t link_status          :  1; /* bits 2:2 */
+               ca_uint32_t link_stat_mask       :  1; /* bits 3:3 */
+               ca_uint32_t rsrvd1               :  7;
+               ca_uint32_t power_dwn_rx         :  1; /* bits 11:11 */
+               ca_uint32_t power_dwn_tx         :  1; /* bits 12:12 */
+               ca_uint32_t tx_intf_lp_time      :  1; /* bits 13:13 */
+               ca_uint32_t rsrvd2               : 18;
+       } bf;
+       ca_uint32_t     wrd;
+} NI_HV_PT_PORT_GLB_CFG_t;
+
+#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