All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 1/3] net: cortina_ni: Add eth support for Cortina Access CAxxxx SoCs
@ 2020-07-30 19:05 Alex Nemirovsky
  2020-07-30 19:05 ` [PATCH v2 2/3] net: phy: ca_phy: Add driver for " Alex Nemirovsky
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Alex Nemirovsky @ 2020-07-30 19:05 UTC (permalink / raw)
  To: u-boot

From: Aaron Tseng <aaron.tseng@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.tseng@cortina-access.com>
Signed-off-by: Alex Nemirovsky <alex.nemirovsky@cortina-access.com>
Signed-off-by: Abbie Chang <abbie.chang@cortina-access.com>

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

---

Changes in v2:
- clean up old debug code
- reference CRC functions already provided in u-boot core
- remove unused code, ex: CA_IN/CA_OUT
- refactor the design of register read/write, union -> struct
- remove platform dependent code

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

diff --git a/MAINTAINERS b/MAINTAINERS
index db8cecd..272caca 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -182,6 +182,8 @@ F:	drivers/gpio/cortina_gpio.c
 F:	drivers/watchdog/cortina_wdt.c
 F:	drivers/serial/serial_cortina.c
 F:	drivers/mmc/ca_dw_mmc.c
+F:	drivers/net/cortina_ni.c
+F:	drivers/net/cortina_ni.h
 
 ARM/CZ.NIC TURRIS MOX SUPPORT
 M:	Marek Behun <marek.behun@nic.cz>
@@ -738,6 +740,8 @@ F:	drivers/gpio/cortina_gpio.c
 F:	drivers/watchdog/cortina_wdt.c
 F:	drivers/serial/serial_cortina.c
 F:	drivers/mmc/ca_dw_mmc.c
+F:	drivers/net/cortina_ni.c
+F:	drivers/net/cortina_ni.h
 
 MIPS MSCC
 M:	Gregory CLEMENT <gregory.clement@bootlin.com>
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index bb23f73..616d238 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -149,6 +149,13 @@ config BCMGENET
 	help
 	  This driver supports the BCMGENET Ethernet MAC.
 
+config CORTINA_NI_ENET
+	bool "Cortina-Access Ethernet driver"
+	depends on DM_ETH && CORTINA_PLATFORM
+	help
+	  This driver supports the Cortina-Access Ethernet MAC for
+	  all supported CAxxxx SoCs.
+
 config DWC_ETH_QOS
 	bool "Synopsys DWC Ethernet QOS device support"
 	depends on DM_ETH
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 383ed1c..1d6ec4f 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
 obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
 obj-$(CONFIG_BCM_SF2_ETH_GMAC) += bcm-sf2-eth-gmac.o
 obj-$(CONFIG_CALXEDA_XGMAC) += calxedaxgmac.o
+obj-$(CONFIG_CORTINA_NI_ENET) += cortina_ni.o
 obj-$(CONFIG_CS8900) += cs8900.o
 obj-$(CONFIG_TULIP) += dc2114x.o
 obj-$(CONFIG_ETH_DESIGNWARE) += designware.o
diff --git a/drivers/net/cortina_ni.c b/drivers/net/cortina_ni.c
new file mode 100644
index 0000000..7acfa6a
--- /dev/null
+++ b/drivers/net/cortina_ni.c
@@ -0,0 +1,1168 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * Copyright (C) 2020 Cortina Access Inc.
+ * Author: Aaron Tseng <aaron.tseng@cortina-access.com>
+ *
+ * Ethernet MAC Driver for all supported CAxxxx SoCs
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+#include <env.h>
+#include <linux/delay.h>
+#include <u-boot/crc.h>
+#include <led.h>
+
+#include "cortina_ni.h"
+
+#define HEADER_A_SIZE	8
+
+enum ca_led_state_t {
+	CA_LED_OFF = 0,
+	CA_LED_ON = 1,
+};
+
+static struct udevice   *curr_dev;
+static int ca_ni_ofdata_to_platdata(struct udevice *dev);
+
+static u32 *rdwrptr_adv_one(u32 *x, unsigned long base, unsigned long max)
+{
+	if (x + 1 >= (u32 *)max)
+		return (u32 *)base;
+	else
+		return (x + 1);
+}
+
+static int phyaddr_to_port(int phy_addr)
+{
+	int idx;
+
+	for (idx = 0; idx < NI_PORT_MAX; idx++)
+		if (phy_addr == port_map[idx].phy_addr)
+			return port_map[idx].active_port;
+	return 0;
+}
+
+static int port_to_phyaddr(int active_port)
+{
+	int idx;
+
+	for (idx = 0; idx < NI_PORT_MAX; idx++)
+		if (active_port == port_map[idx].active_port)
+			return port_map[idx].phy_addr;
+	return 0;
+}
+
+static u32 REG_TO_U32(void *reg)
+{
+	return *(u32 *)reg;
+}
+
+static void ca_reg_read(void *reg, u64 base, u64 offset)
+{
+	u32 *val = (u32 *)reg;
+
+	*val = readl(KSEG1_ATU_XLAT(base + offset));
+}
+
+static void ca_reg_write(void *reg, u64 base, u64 offset)
+{
+	u32 val = *(u32 *)reg;
+
+	writel(val, KSEG1_ATU_XLAT(base + offset));
+}
+
+static enum ca_status_t ca_mdio_write_rgmii(unsigned int addr,
+					    unsigned int offset,
+					    unsigned short data)
+{
+	struct PER_MDIO_ADDR_t  mdio_addr;
+	struct PER_MDIO_CTRL_t  mdio_ctrl;
+	/* up to 10000 cycles*/
+	unsigned int      loop_wait = __MDIO_ACCESS_TIMEOUT;
+	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
+
+	memset(&mdio_addr, 0, sizeof(mdio_addr));
+	mdio_addr.mdio_addr   = addr;
+	mdio_addr.mdio_offset = offset;
+	mdio_addr.mdio_rd_wr  = __MDIO_WR_FLAG;
+	ca_reg_write(&mdio_addr, (u64)priv->per_mdio_base_addr,
+		     PER_MDIO_ADDR_OFFSET);
+	ca_reg_write(&data, (u64)priv->per_mdio_base_addr,
+		     PER_MDIO_WRDATA_OFFSET);
+
+	debug("%s: mdio_addr=0x%x\n", __func__, REG_TO_U32(&mdio_addr));
+
+	memset(&mdio_ctrl, 0, sizeof(mdio_ctrl));
+	mdio_ctrl.mdiostart = 1;
+	ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
+		     PER_MDIO_CTRL_OFFSET);
+
+	debug("%s: phy_addr=%d, offset=%d, data=0x%x\n",
+	      __func__, addr, offset, data);
+
+	do {
+		ca_reg_read(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
+			    PER_MDIO_CTRL_OFFSET);
+		if (mdio_ctrl.mdiodone) {
+			ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
+				     PER_MDIO_CTRL_OFFSET);
+			return CA_E_OK;
+		}
+	} while (--loop_wait);
+
+	printf("%s: PHY write timeout!!!\n", __func__);
+	return CA_E_TIMEOUT;
+}
+
+enum ca_status_t ca_mdio_write(unsigned int     addr,
+			       unsigned int     offset,
+			       unsigned short   data)
+{
+	u32 reg_addr, reg_val;
+	struct NI_MDIO_OPER_T mdio_oper;
+
+	/* support range: 1~31*/
+	if (addr < CA_MDIO_ADDR_MIN || addr > CA_MDIO_ADDR_MAX)
+		return CA_E_PARAM;
+
+	/* the phy addr 5 is connect to RGMII */
+	if (addr >= 5)
+		return ca_mdio_write_rgmii(addr, offset, data);
+
+	memset(&mdio_oper, 0, sizeof(mdio_oper));
+	mdio_oper.reg_off = offset;
+	mdio_oper.phy_addr = addr;
+	mdio_oper.reg_base = CA_NI_MDIO_REG_BASE;
+	reg_val = data;
+	memcpy(&reg_addr, &mdio_oper, sizeof(reg_addr));
+	ca_reg_write(&reg_val, (u64)reg_addr, 0);
+
+	debug("%s: mdio_oper=0x%x, data=0x%x\n",
+	      __func__, REG_TO_U32(&mdio_oper), data);
+	return CA_E_OK;
+}
+
+static enum ca_status_t ca_mdio_read_rgmii(unsigned int addr,
+					   unsigned int offset,
+					   unsigned short *data)
+{
+	struct PER_MDIO_ADDR_t  mdio_addr;
+	struct PER_MDIO_CTRL_t  mdio_ctrl;
+	struct PER_MDIO_RDDATA_t  read_data;
+	unsigned int loop_wait = __MDIO_ACCESS_TIMEOUT;
+	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
+
+	memset(&mdio_addr, 0, sizeof(mdio_addr));
+	mdio_addr.mdio_addr   = addr;
+	mdio_addr.mdio_offset = offset;
+	mdio_addr.mdio_rd_wr  = __MDIO_RD_FLAG;
+	ca_reg_write(&mdio_addr, (u64)priv->per_mdio_base_addr,
+		     PER_MDIO_ADDR_OFFSET);
+
+	memset(&mdio_ctrl, 0, sizeof(mdio_ctrl));
+	mdio_ctrl.mdiostart = 1;
+	ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
+		     PER_MDIO_CTRL_OFFSET);
+
+	do {
+		ca_reg_read(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
+			    PER_MDIO_CTRL_OFFSET);
+		if (mdio_ctrl.mdiodone) {
+			ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
+				     PER_MDIO_CTRL_OFFSET);
+			ca_reg_read(&read_data, (u64)priv->per_mdio_base_addr,
+				    PER_MDIO_RDDATA_OFFSET);
+			*data = read_data.mdio_rddata;
+			return CA_E_OK;
+		}
+	} while (--loop_wait);
+
+	printf("%s: CA_E_TIMEOUT!!\n", __func__);
+	return CA_E_TIMEOUT;
+}
+
+enum ca_status_t ca_mdio_read(unsigned int      addr,
+			      unsigned int	offset,
+			      unsigned short	*data)
+{
+	u32 reg_addr, reg_val;
+	struct NI_MDIO_OPER_T  mdio_oper;
+
+	if (!data)
+		return CA_E_PARAM;
+
+	/* support range: 1~31*/
+	if (addr < CA_MDIO_ADDR_MIN || addr > CA_MDIO_ADDR_MAX)
+		return CA_E_PARAM;
+
+	/* the phy addr 5 is connect to RGMII */
+	if (addr >= 5)
+		return  ca_mdio_read_rgmii(addr, offset, data);
+
+	memset(&mdio_oper, 0, sizeof(mdio_oper));
+	mdio_oper.reg_off = offset;
+	mdio_oper.phy_addr = addr;
+	mdio_oper.reg_base = CA_NI_MDIO_REG_BASE;
+	reg_val = *data;
+	memcpy(&reg_addr, &mdio_oper, sizeof(reg_addr));
+	ca_reg_read(&reg_val, (u64)reg_addr, 0);
+	*data = reg_val;
+	return CA_E_OK;
+}
+
+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);
+}
+
+static int cortina_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+	unsigned short data;
+
+	ca_mdio_read(addr, reg, &data);
+	return data;
+}
+
+static int cortina_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
+			      u16 val)
+{
+	ca_mdio_write(addr, reg, val);
+	return 0;
+}
+
+static void ca_ni_setup_mac_addr(void)
+{
+	unsigned char mac[6];
+
+	struct NI_HV_GLB_MAC_ADDR_CFG0_t	mac_addr_cfg0;
+	struct NI_HV_GLB_MAC_ADDR_CFG1_t	mac_addr_cfg1;
+	struct NI_HV_PT_PORT_STATIC_CFG_t	port_static_cfg;
+	struct NI_HV_XRAM_CPUXRAM_CFG_t		cpuxram_cfg;
+	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
+
+	/* parsing ethaddr and set to NI registers. */
+	if (eth_env_get_enetaddr("ethaddr", mac)) {
+		/* The complete MAC address consists of
+		 * {MAC_ADDR0_mac_addr0[0-3], MAC_ADDR1_mac_addr1[4],
+		 * PT_PORT_STATIC_CFG_mac_addr6[5]}.
+		 */
+		mac_addr_cfg0.mac_addr0 = (mac[0] << 24) + (mac[1] << 16) +
+					  (mac[2] << 8) + mac[3];
+		ca_reg_write(&mac_addr_cfg0, (u64)priv->ni_hv_base_addr,
+			     NI_HV_GLB_MAC_ADDR_CFG0_OFFSET);
+
+		memset(&mac_addr_cfg1, 0, sizeof(mac_addr_cfg1));
+		mac_addr_cfg1.mac_addr1 = mac[4];
+		ca_reg_write(&mac_addr_cfg1, (u64)priv->ni_hv_base_addr,
+			     NI_HV_GLB_MAC_ADDR_CFG1_OFFSET);
+
+		ca_reg_read(&port_static_cfg, (u64)priv->ni_hv_base_addr,
+			    NI_HV_PT_PORT_STATIC_CFG_OFFSET +
+			    (APB0_NI_HV_PT_STRIDE * active_port));
+
+		port_static_cfg.mac_addr6 = mac[5];
+		ca_reg_write(&port_static_cfg, (u64)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 */
+		ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
+			    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
+		cpuxram_cfg.xram_mgmt_promisc_mode = 0;
+		cpuxram_cfg.rx_0_cpu_pkt_dis = 0;
+		cpuxram_cfg.tx_0_cpu_pkt_dis = 0;
+		ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
+			     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
+	} else {
+		/* received all packets(promiscuous mode) */
+		ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
+			    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
+		cpuxram_cfg.xram_mgmt_promisc_mode = 3;
+		cpuxram_cfg.rx_0_cpu_pkt_dis = 0;
+		cpuxram_cfg.tx_0_cpu_pkt_dis = 0;
+		ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
+			     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
+	}
+}
+
+static void ca_ni_enable_tx_rx(void)
+{
+	struct NI_HV_PT_RXMAC_CFG_t rxmac_cfg;
+	struct NI_HV_PT_TXMAC_CFG_t txmac_cfg;
+
+	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
+
+	/* Enable TX and RX functions */
+	ca_reg_read(&rxmac_cfg, (u64)priv->ni_hv_base_addr,
+		    NI_HV_PT_RXMAC_CFG_OFFSET +
+		    (APB0_NI_HV_PT_STRIDE * active_port));
+	rxmac_cfg.rx_en = 1;
+	ca_reg_write(&rxmac_cfg, (u64)priv->ni_hv_base_addr,
+		     NI_HV_PT_RXMAC_CFG_OFFSET +
+		     (APB0_NI_HV_PT_STRIDE * active_port));
+
+	ca_reg_read(&txmac_cfg, (u64)priv->ni_hv_base_addr,
+		    NI_HV_PT_TXMAC_CFG_OFFSET +
+		    (APB0_NI_HV_PT_STRIDE * active_port));
+	txmac_cfg.tx_en = 1;
+	ca_reg_write(&txmac_cfg, (u64)priv->ni_hv_base_addr,
+		     NI_HV_PT_TXMAC_CFG_OFFSET +
+		     (APB0_NI_HV_PT_STRIDE * active_port));
+}
+
+#define AUTO_SCAN_TIMEOUT	3000		/* 3 seconds */
+__weak int ca_ni_auto_scan_active_port(void)
+{
+	u8	phy_addr;
+	u32	start_time;
+	unsigned short data;
+
+	start_time = get_timer(0);
+	while (get_timer(start_time) < AUTO_SCAN_TIMEOUT) {
+		phy_addr = 1;
+		for (; phy_addr < 6; phy_addr++) {
+			ca_mdio_read(phy_addr, 1, &data);
+			if (data & 0x04) {
+				active_port = phyaddr_to_port(phy_addr);
+				return 0;
+			}
+		}
+	}
+
+	printf("%s: auto scan active_port timeout.\n", __func__);
+	return -1;
+}
+
+__weak int invalid_active_port(int port)
+{
+	if (active_port < NI_PORT_0 || active_port > NI_PORT_4)
+		return -1;
+	else
+		return 0;
+}
+
+static int ca_phy_probe(struct udevice *dev)
+{
+	struct cortina_ni_priv *priv = dev_get_priv(dev);
+	struct phy_device *int_phydev, *ext_phydev;
+	int auto_scan_active_port = 0, tmp_port;
+	char *buf;
+
+	/* Initialize internal phy device */
+	int_phydev = phy_connect(priv->mdio_bus, port_to_phyaddr(NI_PORT_3),
+				 dev, priv->phy_interface);
+	if (int_phydev) {
+		int_phydev->supported &= PHY_GBIT_FEATURES;
+		int_phydev->advertising = int_phydev->supported;
+		phy_config(int_phydev);
+	} else {
+		printf("%s: There is no internal phy device\n", __func__);
+	}
+
+	/* Initialize external phy device */
+	ext_phydev = phy_connect(priv->mdio_bus, port_to_phyaddr(NI_PORT_4),
+				 dev, priv->phy_interface);
+	if (ext_phydev) {
+		ext_phydev->supported &= PHY_GBIT_FEATURES;
+		ext_phydev->advertising = int_phydev->supported;
+		phy_config(ext_phydev);
+	} else {
+		printf("%s: There is no external phy device\n", __func__);
+	}
+
+	/* auto scan the first link up port as active_port */
+	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) {
+		ca_ni_auto_scan_active_port();
+	} else {
+		buf = env_get("active_port");
+		if (buf != 0) {
+			tmp_port = simple_strtoul(buf, NULL, 0);
+			if (invalid_active_port(active_port)) {
+				printf("ERROR: doesn't support this port.");
+				free(dev);
+				free(priv);
+				return 1;
+			}
+
+			active_port = tmp_port;
+		}
+	}
+
+	printf("%s: active_port=%d\n", __func__, active_port);
+	if (active_port == NI_PORT_4)
+		priv->phydev = ext_phydev;
+	else
+		priv->phydev = int_phydev;
+
+	return 0;
+}
+
+static void ca_ni_led(int port, int status)
+{
+	struct udevice *led_dev;
+	char label[10];
+
+	if (IS_ENABLED(CONFIG_LED_CORTINA)) {
+		snprintf(label, sizeof(label), "led%d", port);
+		debug("%s: set port %d led %s.\n",
+		      __func__, port, status ? "on" : "off");
+		led_get_by_label(label, &led_dev);
+		led_set_state(led_dev, status);
+	}
+}
+
+static void cortina_ni_reset(void)
+{
+	int i;
+	struct NI_HV_GLB_INIT_DONE_t		init_done;
+	struct NI_HV_GLB_INTF_RST_CONFIG_t	intf_rst_config;
+	struct NI_HV_GLB_STATIC_CFG_t		static_cfg;
+	struct GLOBAL_BLOCK_RESET_t		glb_blk_reset;
+
+	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
+
+	/* NI global resets */
+	ca_reg_read(&glb_blk_reset, (u64)priv->glb_base_addr,
+		    GLOBAL_BLOCK_RESET_OFFSET);
+	glb_blk_reset.reset_ni = 1;
+	ca_reg_write(&glb_blk_reset, (u64)priv->glb_base_addr,
+		     GLOBAL_BLOCK_RESET_OFFSET);
+	/* Remove resets */
+	glb_blk_reset.reset_ni = 0;
+	ca_reg_write(&glb_blk_reset, (u64)priv->glb_base_addr,
+		     GLOBAL_BLOCK_RESET_OFFSET);
+
+	/* check the ready bit of NI module */
+	for (i = 0; i < NI_READ_POLL_COUNT; i++) {
+		ca_reg_read(&init_done, (u64)priv->ni_hv_base_addr,
+			    NI_HV_GLB_INIT_DONE_OFFSET);
+		if (init_done.ni_init_done)
+			break;
+	}
+	if (i == NI_READ_POLL_COUNT) {
+		printf("%s: NI init done not ready, init_done=0x%x!!!\n",
+		       __func__, init_done.ni_init_done);
+	}
+
+	ca_reg_read(&intf_rst_config, (u64)priv->ni_hv_base_addr,
+		    NI_HV_GLB_INTF_RST_CONFIG_OFFSET);
+	switch (active_port) {
+	case NI_PORT_0:
+		intf_rst_config.intf_rst_p0 = 0;
+		intf_rst_config.mac_rx_rst_p0 = 0;
+		intf_rst_config.mac_tx_rst_p0 = 0;
+		break;
+	case NI_PORT_1:
+		intf_rst_config.intf_rst_p1 = 0;
+		intf_rst_config.mac_rx_rst_p1 = 0;
+		intf_rst_config.mac_tx_rst_p1 = 0;
+		break;
+	case NI_PORT_2:
+		intf_rst_config.intf_rst_p2 = 0;
+		intf_rst_config.mac_rx_rst_p2 = 0;
+		intf_rst_config.mac_tx_rst_p2 = 0;
+		break;
+	case NI_PORT_3:
+		intf_rst_config.intf_rst_p3 = 0;
+		intf_rst_config.mac_tx_rst_p3 = 0;
+		intf_rst_config.mac_rx_rst_p3 = 0;
+		break;
+	case NI_PORT_4:
+		intf_rst_config.intf_rst_p4 = 0;
+		intf_rst_config.mac_tx_rst_p4 = 0;
+		intf_rst_config.mac_rx_rst_p4 = 0;
+		break;
+	}
+
+	ca_reg_write(&intf_rst_config, (u64)priv->ni_hv_base_addr,
+		     NI_HV_GLB_INTF_RST_CONFIG_OFFSET);
+
+	/* Only one GMAC can connect to CPU */
+	ca_reg_read(&static_cfg, (u64)priv->ni_hv_base_addr,
+		    NI_HV_GLB_STATIC_CFG_OFFSET);
+	static_cfg.port_to_cpu = active_port;
+	static_cfg.txmib_mode = 1;
+	static_cfg.rxmib_mode = 1;
+
+	ca_reg_write(&static_cfg, (u64)priv->ni_hv_base_addr,
+		     NI_HV_GLB_STATIC_CFG_OFFSET);
+}
+
+static int cortina_ni_init(struct udevice *dev)
+{
+	int ret;
+	struct NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t	cpuxram_adrcfg_rx;
+	struct NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t  cpuxram_adrcfg_tx;
+	struct NI_HV_XRAM_CPUXRAM_CFG_t		cpuxram_cfg;
+	struct NI_HV_PT_PORT_STATIC_CFG_t	port_static_cfg;
+	struct NI_HV_PT_PORT_GLB_CFG_t		port_glb_cfg;
+
+	struct cortina_ni_priv *priv = dev_get_priv(dev);
+	struct phy_device *phydev = priv->phydev;
+
+	ret = phy_startup(priv->phydev);
+	if (ret) {
+		ca_ni_led(active_port, CA_LED_OFF);
+		printf("Could not initialize PHY %s, active_port=%d\n",
+		       priv->phydev->dev->name, active_port);
+		return ret;
+	}
+
+	if (!priv->phydev->link) {
+		printf("%s: link down.\n", priv->phydev->dev->name);
+		return 0;
+	}
+
+	ca_ni_led(active_port, CA_LED_ON);
+	printf("PHY ID 0x%08X %dMbps %s duplex\n",
+	       phydev->phy_id, phydev->speed,
+	       phydev->duplex == DUPLEX_HALF ? "half" : "full");
+
+	/* RX XRAM ADDRESS CONFIG (start and end address) */
+	memset(&cpuxram_adrcfg_rx, 0, sizeof(cpuxram_adrcfg_rx));
+	cpuxram_adrcfg_rx.rx_top_addr = RX_TOP_ADDR;
+	cpuxram_adrcfg_rx.rx_base_addr = RX_BASE_ADDR;
+	ca_reg_write(&cpuxram_adrcfg_rx, (u64)priv->ni_hv_base_addr,
+		     NI_HV_XRAM_CPUXRAM_ADRCFG_RX_OFFSET);
+
+	/* TX XRAM ADDRESS CONFIG (start and end address) */
+	memset(&cpuxram_adrcfg_tx, 0, sizeof(cpuxram_adrcfg_tx));
+	cpuxram_adrcfg_tx.tx_top_addr = TX_TOP_ADDR;
+	cpuxram_adrcfg_tx.tx_base_addr = TX_BASE_ADDR;
+	ca_reg_write(&cpuxram_adrcfg_tx, (u64)priv->ni_hv_base_addr,
+		     NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_OFFSET);
+
+	/*
+	 * Configuration for Management Ethernet Interface:
+	 * - RGMII 1000 mode or RGMII 100 mode
+	 * - MAC mode
+	 */
+	ca_reg_read(&port_static_cfg, (u64)priv->ni_hv_base_addr,
+		    NI_HV_PT_PORT_STATIC_CFG_OFFSET +
+		    (APB0_NI_HV_PT_STRIDE * active_port));
+	if (phydev->speed == SPEED_1000) {
+		/* port 4 connects to RGMII PHY */
+		if (phydev->addr == 5)
+			port_static_cfg.int_cfg = GE_MAC_INTF_RGMII_1000;
+		else
+			port_static_cfg.int_cfg = GE_MAC_INTF_GMII;
+	} else {
+		/* port 4 connects to RGMII PHY */
+		if (phydev->addr == 5)
+			port_static_cfg.int_cfg = GE_MAC_INTF_RGMII_100;
+		else
+			port_static_cfg.int_cfg = GE_MAC_INTF_MII;
+	}
+
+	ca_reg_write(&port_static_cfg, (u64)priv->ni_hv_base_addr,
+		     NI_HV_PT_PORT_STATIC_CFG_OFFSET +
+		     (APB0_NI_HV_PT_STRIDE * active_port));
+
+	ca_reg_read(&port_glb_cfg, (u64)priv->ni_hv_base_addr,
+		    NI_HV_PT_PORT_GLB_CFG_OFFSET +
+		    (APB0_NI_HV_PT_STRIDE * active_port));
+	port_glb_cfg.speed = phydev->speed == SPEED_10 ? 1 : 0;
+	port_glb_cfg.duplex = phydev->duplex == DUPLEX_HALF ? 1 : 0;
+	ca_reg_write(&port_glb_cfg, (u64)priv->ni_hv_base_addr,
+		     NI_HV_PT_PORT_GLB_CFG_OFFSET +
+		     (APB0_NI_HV_PT_STRIDE * active_port));
+
+	/* Need to toggle the tx and rx cpu_pkt_dis bit */
+	/* after changing Address config register.      */
+	ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
+		    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
+	cpuxram_cfg.rx_0_cpu_pkt_dis = 1;
+	cpuxram_cfg.tx_0_cpu_pkt_dis = 1;
+	ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
+		     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
+
+	ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
+		    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
+	cpuxram_cfg.rx_0_cpu_pkt_dis = 0;
+	cpuxram_cfg.tx_0_cpu_pkt_dis = 0;
+	ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
+		     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
+
+	ca_ni_enable_tx_rx();
+
+	return 0;
+}
+
+/*********************************************
+ * Packet receive routine from Management FE
+ * Expects a previously allocated buffer and
+ * fills the length
+ * Retruns 0 on success -1 on failure
+ *******************************************/
+int cortina_ni_recv(struct udevice *netdev)
+{
+	struct cortina_ni_priv *priv = dev_get_priv(netdev);
+	struct NI_HEADER_X_T	header_x;
+	u32			next_link;
+	u32			pktlen = 0;
+	u32			sw_rx_rd_ptr;
+	u32			hw_rx_wr_ptr;
+	u32			*rx_xram_ptr;
+	int			loop;
+	u32			*data_ptr;
+	struct NI_PACKET_STATUS packet_status;
+	struct NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t cpuxram_cpu_sta_rx;
+	struct NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t cpuxram_cpu_cfg_rx;
+	int index = 0;
+	int			blk_num;
+	u8			*ptr;
+
+	/* get the hw write pointer */
+	memset(&cpuxram_cpu_sta_rx, 0, sizeof(cpuxram_cpu_sta_rx));
+	ca_reg_read(&cpuxram_cpu_sta_rx, (u64)priv->ni_hv_base_addr,
+		    NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET);
+	hw_rx_wr_ptr = cpuxram_cpu_sta_rx.pkt_wr_ptr;
+
+	/* get the sw read pointer */
+	memset(&cpuxram_cpu_cfg_rx, 0, sizeof(cpuxram_cpu_cfg_rx));
+	ca_reg_read(&cpuxram_cpu_cfg_rx, (u64)priv->ni_hv_base_addr,
+		    NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
+	sw_rx_rd_ptr = cpuxram_cpu_cfg_rx.pkt_rd_ptr;
+
+	debug("%s: NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0 = 0x%p, ", __func__,
+	      priv->ni_hv_base_addr + NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET);
+	debug("NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0 = 0x%p\n",
+	      priv->ni_hv_base_addr + NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
+	debug("%s : RX hw_wr_ptr = %d, sw_rd_ptr = %d\n",
+	      __func__, hw_rx_wr_ptr, sw_rx_rd_ptr);
+
+	while (sw_rx_rd_ptr != hw_rx_wr_ptr) {
+		/* Point to the absolute memory address of XRAM
+		 * where read pointer is
+		 */
+		rx_xram_ptr = (u32 *)
+			      ((unsigned long)NI_XRAM_BASE + sw_rx_rd_ptr * 8);
+
+		/* Wrap around if required */
+		if (rx_xram_ptr >= (u32 *)(unsigned long)priv->rx_xram_end_adr)
+			rx_xram_ptr = (u32 *)
+				      (unsigned long)priv->rx_xram_base_adr;
+
+		/* Checking header XR. Do not update the read pointer yet */
+		/* skip unused 32-bit in Header XR */
+		rx_xram_ptr = rdwrptr_adv_one(rx_xram_ptr,
+					      priv->rx_xram_base_adr,
+					      priv->rx_xram_end_adr);
+
+		memcpy(&header_x, rx_xram_ptr, sizeof(header_x));
+		next_link = header_x.next_link;
+		/* Header XR [31:0] */
+
+		if (*rx_xram_ptr == 0xffffffff)
+			printf("%s: XRAM Error !\n", __func__);
+
+		debug("%s : RX next link 0x%x\n", __func__, next_link);
+		debug("%s : bytes_valid %x\n", __func__, header_x.bytes_valid);
+
+		if (header_x.ownership == 0) {
+			/* point to Packet status [31:0] */
+			rx_xram_ptr = rdwrptr_adv_one(rx_xram_ptr,
+						      priv->rx_xram_base_adr,
+						      priv->rx_xram_end_adr);
+
+			memcpy(&packet_status, rx_xram_ptr,
+			       sizeof(rx_xram_ptr));
+			debug("%s: packet status=0x%x\n",
+			      __func__, REG_TO_U32(&packet_status));
+			if (packet_status.valid == 0) {
+				debug("%s: Invalid Packet !!, ", __func__);
+				debug("next_link=%d\n", next_link);
+
+				/* Update the software read pointer */
+				ca_reg_write(&next_link,
+					     (u64)priv->ni_hv_base_addr,
+					NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
+				return 0;
+			}
+
+			if (packet_status.drop ||
+			    packet_status.runt ||
+			    packet_status.oversize ||
+			    packet_status.jabber ||
+			    packet_status.crc_error ||
+			    packet_status.jumbo) {
+				debug("%s: Error Packet!!, ", __func__);
+				debug("next_link=%d\n", next_link);
+
+				/* Update the software read pointer */
+				ca_reg_write(&next_link,
+					     (u64)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.packet_size > 1518) {
+				debug("%s: Error Packet !! Packet size=%d, ",
+				      __func__, packet_status.packet_size);
+				debug("larger than 1518, next_link=%d\n",
+				      next_link);
+
+				/* Update the software read pointer */
+				ca_reg_write(&next_link,
+					     (u64)priv->ni_hv_base_addr,
+					NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
+				return 0;
+			}
+
+			rx_xram_ptr = rdwrptr_adv_one(rx_xram_ptr,
+						      priv->rx_xram_base_adr,
+						      priv->rx_xram_end_adr);
+
+			pktlen = packet_status.packet_size;
+
+			debug("%s : rx packet length = %d\n",
+			      __func__, packet_status.packet_size);
+
+			rx_xram_ptr = rdwrptr_adv_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 */
+
+			debug("%s: packet data[]=", __func__);
+
+			for (loop = 0; loop <= pktlen / 4; loop++) {
+				ptr = (u8 *)rx_xram_ptr;
+				if (loop < 10)
+					debug("[0x%x]-[0x%x]-[0x%x]-[0x%x]",
+					      ptr[0], ptr[1], ptr[2], ptr[3]);
+				*data_ptr++ = *rx_xram_ptr++;
+				/* Wrap around if required */
+				if (rx_xram_ptr >= (u32 *)
+				    (unsigned long)priv->rx_xram_end_adr) {
+					rx_xram_ptr = (u32 *)(unsigned long)
+						       (priv->rx_xram_base_adr);
+				}
+			}
+
+			debug("\n");
+			net_process_received_packet(net_rx_packets[index],
+						    pktlen);
+			if (++index >= PKTBUFSRX)
+				index = 0;
+			blk_num = net_rx_packets[index][0x2c] * 255 +
+				net_rx_packets[index][0x2d];
+			debug("%s: tftp block number=%d\n", __func__, blk_num);
+
+			/* Update the software read pointer */
+			ca_reg_write(&next_link,
+				     (u64)priv->ni_hv_base_addr,
+				     NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
+		}
+
+		/* get the hw write pointer */
+		ca_reg_read(&cpuxram_cpu_sta_rx, (u64)priv->ni_hv_base_addr,
+			    NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET);
+		hw_rx_wr_ptr = cpuxram_cpu_sta_rx.pkt_wr_ptr;
+
+		/* get the sw read pointer */
+		ca_reg_read(&sw_rx_rd_ptr, (u64)priv->ni_hv_base_addr,
+			    NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
+	}
+	return 0;
+}
+
+static int cortina_ni_send(struct udevice *dev, void *packet, int length)
+{
+	struct cortina_ni_priv *priv = dev_get_priv(dev);
+	u32	hw_tx_rd_ptr = 0;
+	u32	sw_tx_wr_ptr = 0;
+	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	ca_crc32;
+	struct NI_HEADER_X_T	hdr_xt;
+	int		pad = 0;
+	static unsigned char   pkt_buf[2048];
+	u32	*data_ptr;
+	struct NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t cpuxram_cpu_cfg_tx;
+	u8 *ptr;
+
+	if (!packet || length > 2032)
+		return -1;
+
+	/* Get the hardware read pointer */
+	ca_reg_read(&hw_tx_rd_ptr, (u64)priv->ni_hv_base_addr,
+		    NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET);
+
+	/* Get the software write pointer */
+	ca_reg_read(&sw_tx_wr_ptr, (u64)priv->ni_hv_base_addr,
+		    NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET);
+
+	debug("%s: NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0=0x%p, ",
+	      __func__,
+	      KSEG1_ATU_XLAT(priv->ni_hv_base_addr +
+			     NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET));
+	debug("NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0=0x%p\n",
+	      KSEG1_ATU_XLAT(priv->ni_hv_base_addr +
+			     NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET));
+	debug("%s : hw_tx_rd_ptr = %d\n", __func__, hw_tx_rd_ptr);
+	debug("%s : sw_tx_wr_ptr = %d\n", __func__, sw_tx_wr_ptr);
+
+	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[HEADER_A_SIZE], (const void *)packet, length);
+
+	pad = 64 - (length + 4);	/* if packet length < 60 */
+	pad = (pad < 0) ? 0 : pad;
+
+	debug("%s: length=%d, pad=%d\n", __func__, length, pad);
+
+	new_pkt_len = length + pad;	/* new packet length */
+
+	pkt_buf_ptr = (unsigned char *)pkt_buf;
+
+	/* Calculate the CRC32, skip 8-byte header_A */
+	ca_crc32 = crc32(0, (u8 *)(pkt_buf_ptr + HEADER_A_SIZE), new_pkt_len);
+
+	debug("%s: crc32 is 0x%x\n", __func__, ca_crc32);
+	debug("%s: ~crc32 is 0x%x\n", __func__, ~ca_crc32);
+	debug("%s: pkt len %d\n", __func__, new_pkt_len);
+	/* should add 8-byte header_! */
+	/* CRC will re-calculated by hardware */
+	memcpy((pkt_buf_ptr + new_pkt_len + HEADER_A_SIZE),
+	       (u8 *)(&ca_crc32), sizeof(ca_crc32));
+	new_pkt_len = new_pkt_len + 4;	/* add CRC */
+
+	valid_bytes = new_pkt_len % 8;
+	valid_bytes = valid_bytes ? valid_bytes : 0;
+	debug("%s: valid_bytes %d\n", __func__, valid_bytes);
+
+	/* should add 8-byte headerA */
+	next_link = sw_tx_wr_ptr +
+		(new_pkt_len + 7 + HEADER_A_SIZE) / 8; /* for headr XT */
+	/* add header */
+	next_link = next_link + 1;
+	/* Wrap around if required */
+	if (next_link > priv->tx_xram_end) {
+		next_link = priv->tx_xram_start +
+			(next_link - (priv->tx_xram_end + 1));
+	}
+
+	debug("%s: TX next_link %x\n", __func__, next_link);
+	memset(&hdr_xt, 0, sizeof(hdr_xt));
+	hdr_xt.ownership = 1;
+	hdr_xt.bytes_valid = valid_bytes;
+	hdr_xt.next_link = next_link;
+
+	tx_xram_ptr = (u32 *)((unsigned long)NI_XRAM_BASE + sw_tx_wr_ptr * 8);
+
+	/* Wrap around if required */
+	if (tx_xram_ptr >= (u32 *)(unsigned long)priv->tx_xram_end_adr)
+		tx_xram_ptr = (u32 *)(unsigned long)priv->tx_xram_base_adr;
+
+	tx_xram_ptr = rdwrptr_adv_one(tx_xram_ptr,
+				      priv->tx_xram_base_adr,
+				      priv->tx_xram_end_adr);
+
+	memcpy(tx_xram_ptr, &hdr_xt, sizeof(*tx_xram_ptr));
+
+	tx_xram_ptr = rdwrptr_adv_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;
+	debug("%s: packet data[]=", __func__);
+
+	/* copy header_A to XRAM */
+	for (loop = 0; loop <= (new_pkt_len + HEADER_A_SIZE) / 4; loop++) {
+		ptr = (u8 *)data_ptr;
+		if ((loop % 4) == 0)
+			debug("\n");
+		debug("[0x%x]-[0x%x]-[0x%x]-[0x%x]-",
+		      ptr[0], ptr[1], ptr[2], ptr[3]);
+
+		*tx_xram_ptr = *data_ptr++;
+		tx_xram_ptr = rdwrptr_adv_one(tx_xram_ptr,
+					      priv->tx_xram_base_adr,
+					      priv->tx_xram_end_adr);
+	}
+	debug("\n");
+
+	/* Publish the software write pointer */
+	cpuxram_cpu_cfg_tx.pkt_wr_ptr = next_link;
+	ca_reg_write(&cpuxram_cpu_cfg_tx,
+		     (u64)priv->ni_hv_base_addr,
+		     NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET);
+
+	return 0;
+}
+
+static void cortina_ni_halt(struct udevice *netdev)
+{
+	/* Nothing to do for now. */
+}
+
+#define GPHY_CAL_LEN	6
+struct gphy_cal {
+	u32 reg_off;
+	u32 value;
+};
+
+static struct gphy_cal gphy_cal_vlaues[GPHY_CAL_LEN] = {
+	{0xf43380fc, 0xbcd},
+	{0xf43380dc, 0xeeee},
+	{0xf43380d8, 0xeeee},
+	{0xf43380fc, 0xbce},
+	{0xf43380c0, 0x7777},
+	{0xf43380c4, 0x7777}
+};
+
+__weak 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, 0);
+			mdelay(50);
+		}
+	}
+}
+
+static int ca_mdio_register(struct udevice *dev)
+{
+	struct cortina_ni_priv *priv = dev_get_priv(dev);
+	struct mii_dev *mdio_bus = mdio_alloc();
+	int ret;
+
+	if (!mdio_bus)
+		return -ENOMEM;
+
+	mdio_bus->read = cortina_mdio_read;
+	mdio_bus->write = cortina_mdio_write;
+	snprintf(mdio_bus->name, sizeof(mdio_bus->name), dev->name);
+
+	mdio_bus->priv = (void *)priv;
+
+	ret = mdio_register(mdio_bus);
+	if (ret)
+		return ret;
+
+	priv->mdio_bus = mdio_bus;
+	return 0;
+}
+
+__weak void ca_rgmii_init(struct cortina_ni_priv *priv)
+{
+	/* hardware settings for RGMII port */
+	struct GLOBAL_GLOBAL_CONFIG_t	glb_config;
+	struct GLOBAL_IO_DRIVE_CONTROL_t io_drive_control;
+
+	/* Generating 25Mhz reference clock for switch */
+	ca_reg_read(&glb_config, (u64)priv->glb_base_addr,
+		    GLOBAL_GLOBAL_CONFIG_OFFSET);
+	glb_config.refclk_sel = 0x01;
+	glb_config.ext_reset = 0x01;
+	ca_reg_write(&glb_config, (u64)priv->glb_base_addr,
+		     GLOBAL_GLOBAL_CONFIG_OFFSET);
+
+	mdelay(20);
+
+	/* should do a external reset */
+	ca_reg_read(&glb_config, (u64)priv->glb_base_addr,
+		    GLOBAL_GLOBAL_CONFIG_OFFSET);
+	glb_config.ext_reset = 0x0;
+	ca_reg_write(&glb_config, (u64)priv->glb_base_addr,
+		     GLOBAL_GLOBAL_CONFIG_OFFSET);
+
+	ca_reg_read(&io_drive_control, (u64)priv->glb_base_addr,
+		    GLOBAL_IO_DRIVE_CONTROL_OFFSET);
+	io_drive_control.gmac_mode = 2;
+	io_drive_control.gmac_dn = 1;
+	io_drive_control.gmac_dp = 1;
+	ca_reg_write(&io_drive_control, (u64)priv->glb_base_addr,
+		     GLOBAL_IO_DRIVE_CONTROL_OFFSET);
+}
+
+int ca_eth_initialize(struct udevice *dev)
+{
+	struct cortina_ni_priv *priv;
+	int ret, reg_value;
+
+	priv = dev_get_priv(dev);
+	priv->rx_xram_base_adr	= NI_XRAM_BASE + (RX_BASE_ADDR * 8);
+	priv->rx_xram_end_adr	= NI_XRAM_BASE + ((RX_TOP_ADDR + 1) * 8);
+	priv->rx_xram_start	= RX_BASE_ADDR;
+	priv->rx_xram_end	= RX_TOP_ADDR;
+	priv->tx_xram_base_adr	= NI_XRAM_BASE + (TX_BASE_ADDR * 8);
+	priv->tx_xram_end_adr	= NI_XRAM_BASE + ((TX_TOP_ADDR + 1) * 8);
+	priv->tx_xram_start	= TX_BASE_ADDR;
+	priv->tx_xram_end	= TX_TOP_ADDR;
+
+	curr_dev = dev;
+	debug("%s: rx_base_addr:%x\t rx_top_addr %x\n",
+	      __func__, priv->rx_xram_start, priv->rx_xram_end);
+	debug("%s: tx_base_addr:%x\t tx_top_addr %x\n",
+	      __func__, priv->tx_xram_start, priv->tx_xram_end);
+	debug("%s: rx physical start address = %x end address = %x\n",
+	      __func__, priv->rx_xram_base_adr, priv->rx_xram_end_adr);
+	debug("%s: tx physical start address = %x end address = %x\n",
+	      __func__, priv->tx_xram_base_adr, priv->tx_xram_end_adr);
+
+	/* MDIO register */
+	ret = ca_mdio_register(dev);
+	if (ret)
+		return ret;
+
+	/* set MDIO pre-scale value */
+	ca_reg_read(&reg_value, (u64)priv->per_mdio_base_addr,
+		    PER_MDIO_CFG_OFFSET);
+	reg_value = reg_value | 0x00280000;
+	ca_reg_write(&reg_value, (u64)priv->per_mdio_base_addr,
+		     PER_MDIO_CFG_OFFSET);
+
+	ca_phy_probe(dev);
+	priv->phydev->addr = port_to_phyaddr(active_port);
+
+	ca_ni_led(active_port, CA_LED_ON);
+
+	cortina_ni_reset();
+
+	printf("%s: active_port=%d, phy_addr=%d\n",
+	       __func__, active_port, priv->phydev->addr);
+	printf("%s: phy_id=0x%x, phy_id & PHY_ID_MASK=0x%x\n", __func__,
+	       priv->phydev->phy_id, priv->phydev->phy_id & 0xFFFFFFF0);
+
+	/* parsing ethaddr and set to NI registers. */
+	ca_ni_setup_mac_addr();
+
+#ifdef MIIPHY_REGISTER
+	/* the phy_read and phy_write
+	 * should meet the proto type of miiphy_register
+	 */
+	miiphy_register(dev->name, ca_miiphy_read, ca_miiphy_write);
+#endif
+
+	ca_rgmii_init(priv);
+
+	/* do internal gphy calibration */
+	do_internal_gphy_cal();
+	return 0;
+}
+
+static int cortina_eth_start(struct udevice *dev)
+{
+	return cortina_ni_init(dev);
+}
+
+static int cortina_eth_send(struct udevice *dev, void *packet, int length)
+{
+	return cortina_ni_send(dev, packet, length);
+}
+
+static int cortina_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	return cortina_ni_recv(dev);
+}
+
+static void cortina_eth_stop(struct udevice *dev)
+{
+	cortina_ni_halt(dev);
+}
+
+static int cortina_eth_probe(struct udevice *dev)
+{
+	return ca_eth_initialize(dev);
+}
+
+static int ca_ni_ofdata_to_platdata(struct udevice *dev)
+{
+	struct cortina_ni_priv *priv = dev_get_priv(dev);
+
+	priv->glb_base_addr = dev_remap_addr_index(dev, 0);
+	if (!priv->glb_base_addr)
+		return -ENOENT;
+	printf("%s: priv->glb_base_addr for index 0 is 0x%p\n",
+	       __func__, priv->glb_base_addr);
+
+	priv->per_mdio_base_addr = dev_remap_addr_index(dev, 1);
+	if (!priv->per_mdio_base_addr)
+		return -ENOENT;
+	printf("%s: priv->per_mdio_base_addr for index 1 is 0x%p\n",
+	       __func__, priv->per_mdio_base_addr);
+
+	priv->ni_hv_base_addr = dev_remap_addr_index(dev, 2);
+	if (!priv->ni_hv_base_addr)
+		return -ENOENT;
+	printf("%s: priv->ni_hv_base_addr for index 2 is 0x%p\n",
+	       __func__, priv->ni_hv_base_addr);
+
+	return 0;
+}
+
+static const struct eth_ops cortina_eth_ops = {
+	.start  = cortina_eth_start,
+	.send   = cortina_eth_send,
+	.recv   = cortina_eth_recv,
+	.stop   = cortina_eth_stop,
+};
+
+static const struct udevice_id cortina_eth_ids[] = {
+	{ .compatible = "eth_cortina" },
+	{ }
+};
+
+U_BOOT_DRIVER(eth_cortina) = {
+	.name   = "eth_cortina",
+	.id     = UCLASS_ETH,
+	.of_match = cortina_eth_ids,
+	.probe  = cortina_eth_probe,
+	.ops    = &cortina_eth_ops,
+	.priv_auto_alloc_size = sizeof(struct cortina_ni_priv),
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+	.ofdata_to_platdata = ca_ni_ofdata_to_platdata,
+};
diff --git a/drivers/net/cortina_ni.h b/drivers/net/cortina_ni.h
new file mode 100644
index 0000000..ff9a396
--- /dev/null
+++ b/drivers/net/cortina_ni.h
@@ -0,0 +1,435 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+/*
+ * Copyright (C) 2020 Cortina Access Inc.
+ * Author: Aaron Tseng <aaron.tseng@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 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
+
+/* 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 NI_XRAM_BASE                    0xF4500000
+
+enum ca_status_t {
+	CA_E_ERROR          = -1,
+	CA_E_OK             = 0x0,
+	CA_E_RESOURCE       = 0x1,
+	CA_E_PARAM          = 0x2,
+	CA_E_NOT_FOUND      = 0x3,
+	CA_E_CONFLICT       = 0x4,
+	CA_E_TIMEOUT        = 0x5,
+	CA_E_INTERNAL       = 0x6,
+	CA_E_NOT_SUPPORT    = 0x7,
+	CA_E_CONFIG         = 0x8,
+	CA_E_UNAVAIL        = 0x9,
+	CA_E_MEMORY         = 0xa,
+	CA_E_BUSY           = 0xb,
+	CA_E_FULL           = 0xc,
+	CA_E_EMPTY          = 0xd,
+	CA_E_EXISTS         = 0xe,
+	CA_E_DEV            = 0xf,
+	CA_E_PORT           = 0x10,
+	CA_E_LLID           = 0x11,
+	CA_E_VLAN           = 0x12,
+	CA_E_INIT           = 0x13,
+	CA_E_INTF           = 0x14,
+	CA_E_NEXTHOP        = 0x15,
+	CA_E_ROUTE          = 0x16,
+	CA_E_DB_CHANGED     = 0x17,
+	CA_E_INACTIVE       = 0x18,
+	CA_E_ALREADY_SET    = 0x19,
+};
+
+#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;
+	void __iomem    *glb_base_addr;
+	void __iomem    *per_mdio_base_addr;
+	void __iomem    *ni_hv_base_addr;
+
+	struct mii_dev *mdio_bus;
+	struct phy_device *phydev;
+	int phy_interface;
+};
+
+struct NI_HEADER_X_T {
+	unsigned int next_link		: 10; /* bits  9: 0 */
+	unsigned int bytes_valid	:  4; /* bits 13:10 */
+	unsigned int reserved		: 16; /* bits 29:14 */
+	unsigned int hdr_a		:  1; /* bits 30:30 */
+	unsigned int ownership		:  1; /* bits 31:31 */
+};
+
+struct NI_PACKET_STATUS {
+	unsigned int packet_size       : 14; /* bits 13:0 */
+	unsigned int byte_valid        :  4; /* bits 17:14 */
+	unsigned int pfc               :  1; /* bits 18:18 */
+	unsigned int valid             :  1; /* bits 19:19 */
+	unsigned int drop              :  1; /* bits 20:20 */
+	unsigned int runt              :  1; /* bits 21:21 */
+	unsigned int oversize          :  1; /* bits 22:22 */
+	unsigned int jumbo             :  1; /* bits 23:23 */
+	unsigned int link_status       :  1; /* bits 24:24 */
+	unsigned int jabber            :  1; /* bits 25:25 */
+	unsigned int crc_error         :  1; /* bits 26:26 */
+	unsigned int pause             :  1; /* bits 27:27 */
+	unsigned int oam               :  1; /* bits 28:28 */
+	unsigned int unknown_opcode    :  1; /* bits 29:29 */
+	unsigned int multicast         :  1; /* bits 30:30 */
+	unsigned int broadcast         :  1; /* bits 31:31 */
+};
+
+struct NI_MDIO_OPER_T {
+	unsigned int reserved       : 2; /* bits  1:0 */
+	unsigned int reg_off        : 5; /* bits  6:2 */
+	unsigned int phy_addr       : 5; /* bits 11:7 */
+	unsigned int reg_base       : 20; /* bits 31:12 */
+};
+
+enum ca_port_t {
+	NI_PORT_0 = 0,
+	NI_PORT_1,
+	NI_PORT_2,
+	NI_PORT_3,
+	NI_PORT_4,
+	NI_PORT_5,
+	NI_PORT_MAX,
+};
+
+struct port_map_s {
+	int active_port;
+	int phy_addr;
+};
+
+extern struct port_map_s port_map[NI_PORT_MAX];
+extern int active_port;
+
+#define __MDIO_WR_FLAG				(0)
+#define __MDIO_RD_FLAG				(1)
+#define __MDIO_ACCESS_TIMEOUT			(1000000)
+#define CA_MDIO_ADDR_MIN			(1)
+#define CA_MDIO_ADDR_MAX			(31)
+
+#endif /* !__ASSEMBLER__ */
+
+/* Copy from registers.h */
+struct NI_HV_GLB_MAC_ADDR_CFG0_t {
+	unsigned int mac_addr0            : 32; /* bits 31:0 */
+};
+
+struct NI_HV_GLB_MAC_ADDR_CFG1_t {
+	unsigned int mac_addr1            :  8; /* bits 7:0 */
+	unsigned int rsrvd1               : 24;
+};
+
+struct NI_HV_PT_PORT_STATIC_CFG_t {
+	unsigned int int_cfg              :  4; /* bits 3:0 */
+	unsigned int phy_mode             :  1; /* bits 4:4 */
+	unsigned int rmii_clksrc          :  1; /* bits 5:5 */
+	unsigned int inv_clk_in           :  1; /* bits 6:6 */
+	unsigned int inv_clk_out          :  1; /* bits 7:7 */
+	unsigned int inv_rxclk_out        :  1; /* bits 8:8 */
+	unsigned int tx_use_gefifo        :  1; /* bits 9:9 */
+	unsigned int smii_tx_stat         :  1; /* bits 10:10 */
+	unsigned int crs_polarity         :  1; /* bits 11:11 */
+	unsigned int lpbk_mode            :  2; /* bits 13:12 */
+	unsigned int gmii_like_half_duplex_en :  1; /* bits 14:14 */
+	unsigned int sup_tx_to_rx_lpbk_data :  1; /* bits 15:15 */
+	unsigned int rsrvd1               :  8;
+	unsigned int mac_addr6            :  8; /* bits 31:24 */
+};
+
+struct NI_HV_XRAM_CPUXRAM_CFG_t {
+	unsigned int rx_0_cpu_pkt_dis     :  1; /* bits 0:0 */
+	unsigned int rsrvd1               :  8;
+	unsigned int tx_0_cpu_pkt_dis     :  1; /* bits 9:9 */
+	unsigned int rsrvd2               :  1;
+	unsigned int rx_x_drop_err_pkt    :  1; /* bits 11:11 */
+	unsigned int xram_mgmt_dis_drop_ovsz_pkt :  1; /* bits 12:12 */
+	unsigned int xram_mgmt_term_large_pkt :  1; /* bits 13:13 */
+	unsigned int xram_mgmt_promisc_mode :  2; /* bits 15:14 */
+	unsigned int xram_cntr_debug_mode :  1; /* bits 16:16 */
+	unsigned int xram_cntr_op_code    :  2; /* bits 18:17 */
+	unsigned int rsrvd3               :  2;
+	unsigned int xram_rx_mgmtfifo_srst :  1; /* bits 21:21 */
+	unsigned int xram_dma_fifo_srst   :  1; /* bits 22:22 */
+	unsigned int rsrvd4               :  9;
+};
+
+struct NI_HV_PT_RXMAC_CFG_t {
+	unsigned int rx_en                :  1; /* bits 0:0 */
+	unsigned int rsrvd1               :  7;
+	unsigned int rx_flow_disable      :  1; /* bits 8:8 */
+	unsigned int rsrvd2               :  3;
+	unsigned int rx_flow_to_tx_en     :  1; /* bits 12:12 */
+	unsigned int rx_pfc_disable       :  1; /* bits 13:13 */
+	unsigned int rsrvd3               : 15;
+	unsigned int send_pg_data         :  1; /* bits 29:29 */
+	unsigned int rsrvd4               :  2;
+};
+
+struct NI_HV_PT_TXMAC_CFG_t {
+	unsigned int tx_en                :  1; /* bits 0:0 */
+	unsigned int rsrvd1               :  7;
+	unsigned int mac_crc_calc_en      :  1; /* bits 8:8 */
+	unsigned int tx_ipg_sel           :  3; /* bits 11:9 */
+	unsigned int tx_flow_disable      :  1; /* bits 12:12 */
+	unsigned int tx_drain             :  1; /* bits 13:13 */
+	unsigned int tx_pfc_disable       :  1; /* bits 14:14 */
+	unsigned int tx_pau_sel           :  2; /* bits 16:15 */
+	unsigned int rsrvd2               :  9;
+	unsigned int tx_auto_xon          :  1; /* bits 26:26 */
+	unsigned int rsrvd3               :  1;
+	unsigned int pass_thru_hdr        :  1; /* bits 28:28 */
+	unsigned int rsrvd4               :  3;
+};
+
+struct NI_HV_GLB_INTF_RST_CONFIG_t {
+	unsigned int intf_rst_p0          :  1; /* bits 0:0 */
+	unsigned int intf_rst_p1          :  1; /* bits 1:1 */
+	unsigned int intf_rst_p2          :  1; /* bits 2:2 */
+	unsigned int intf_rst_p3          :  1; /* bits 3:3 */
+	unsigned int intf_rst_p4          :  1; /* bits 4:4 */
+	unsigned int mac_rx_rst_p0        :  1; /* bits 5:5 */
+	unsigned int mac_rx_rst_p1        :  1; /* bits 6:6 */
+	unsigned int mac_rx_rst_p2        :  1; /* bits 7:7 */
+	unsigned int mac_rx_rst_p3        :  1; /* bits 8:8 */
+	unsigned int mac_rx_rst_p4        :  1; /* bits 9:9 */
+	unsigned int mac_tx_rst_p0        :  1; /* bits 10:10 */
+	unsigned int mac_tx_rst_p1        :  1; /* bits 11:11 */
+	unsigned int mac_tx_rst_p2        :  1; /* bits 12:12 */
+	unsigned int mac_tx_rst_p3        :  1; /* bits 13:13 */
+	unsigned int mac_tx_rst_p4        :  1; /* bits 14:14 */
+	unsigned int port_rst_p5          :  1; /* bits 15:15 */
+	unsigned int pcs_rst_p6           :  1; /* bits 16:16 */
+	unsigned int pcs_rst_p7           :  1; /* bits 17:17 */
+	unsigned int mac_rst_p6           :  1; /* bits 18:18 */
+	unsigned int mac_rst_p7           :  1; /* bits 19:19 */
+	unsigned int rsrvd1               : 12;
+};
+
+struct NI_HV_GLB_STATIC_CFG_t {
+	unsigned int port_to_cpu          :  4; /* bits 3:0 */
+	unsigned int mgmt_pt_to_fe_also   :  1; /* bits 4:4 */
+	unsigned int txcrc_chk_en         :  1; /* bits 5:5 */
+	unsigned int p4_rgmii_tx_clk_phase :  2; /* bits 7:6 */
+	unsigned int p4_rgmii_tx_data_order :  1; /* bits 8:8 */
+	unsigned int rsrvd1               :  7;
+	unsigned int rxmib_mode           :  1; /* bits 16:16 */
+	unsigned int txmib_mode           :  1; /* bits 17:17 */
+	unsigned int eth_sch_rdy_pkt      :  1; /* bits 18:18 */
+	unsigned int rsrvd2               :  1;
+	unsigned int rxaui_mode           :  2; /* bits 21:20 */
+	unsigned int rxaui_sigdet         :  2; /* bits 23:22 */
+	unsigned int cnt_op_mode          :  3; /* bits 26:24 */
+	unsigned int rsrvd3               :  5;
+};
+
+struct GLOBAL_BLOCK_RESET_t {
+	unsigned int reset_ni             :  1; /* bits 0:0 */
+	unsigned int reset_l2fe           :  1; /* bits 1:1 */
+	unsigned int reset_l2tm           :  1; /* bits 2:2 */
+	unsigned int reset_l3fe           :  1; /* bits 3:3 */
+	unsigned int reset_sdram          :  1; /* bits 4:4 */
+	unsigned int reset_tqm            :  1; /* bits 5:5 */
+	unsigned int reset_pcie0          :  1; /* bits 6:6 */
+	unsigned int reset_pcie1          :  1; /* bits 7:7 */
+	unsigned int reset_pcie2          :  1; /* bits 8:8 */
+	unsigned int reset_sata           :  1; /* bits 9:9 */
+	unsigned int reset_gic400         :  1; /* bits 10:10 */
+	unsigned int rsrvd1               :  2;
+	unsigned int reset_usb            :  1; /* bits 13:13 */
+	unsigned int reset_flash          :  1; /* bits 14:14 */
+	unsigned int reset_per            :  1; /* bits 15:15 */
+	unsigned int reset_dma            :  1; /* bits 16:16 */
+	unsigned int reset_rtc            :  1; /* bits 17:17 */
+	unsigned int reset_pe0            :  1; /* bits 18:18 */
+	unsigned int reset_pe1            :  1; /* bits 19:19 */
+	unsigned int reset_rcpu0          :  1; /* bits 20:20 */
+	unsigned int reset_rcpu1          :  1; /* bits 21:21 */
+	unsigned int reset_sadb           :  1; /* bits 22:22 */
+	unsigned int rsrvd2               :  1;
+	unsigned int reset_rcrypto        :  1; /* bits 24:24 */
+	unsigned int reset_ldma           :  1; /* bits 25:25 */
+	unsigned int reset_fbm            :  1; /* bits 26:26 */
+	unsigned int reset_eaxi           :  1; /* bits 27:27 */
+	unsigned int reset_sd             :  1; /* bits 28:28 */
+	unsigned int reset_otprom         :  1; /* bits 29:29 */
+	unsigned int rsrvd3               :  2;
+};
+
+struct PER_MDIO_ADDR_t {
+	unsigned int mdio_addr            :  5; /* bits 4:0 */
+	unsigned int rsrvd1               :  3;
+	unsigned int mdio_offset          :  5; /* bits 12:8 */
+	unsigned int rsrvd2               :  2;
+	unsigned int mdio_rd_wr           :  1; /* bits 15:15 */
+	unsigned int mdio_st              :  1; /* bits 16:16 */
+	unsigned int rsrvd3               :  1;
+	unsigned int mdio_op              :  2; /* bits 19:18 */
+	unsigned int rsrvd4               : 12;
+};
+
+struct PER_MDIO_CTRL_t {
+	unsigned int mdiodone             :  1; /* bits 0:0 */
+	unsigned int rsrvd1               :  6;
+	unsigned int mdiostart            :  1; /* bits 7:7 */
+	unsigned int rsrvd2               : 24;
+};
+
+struct PER_MDIO_RDDATA_t {
+	unsigned int mdio_rddata          : 16; /* bits 15:0 */
+	unsigned int rsrvd1               : 16;
+};
+
+/*
+ * XRAM
+ */
+
+struct NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t {
+	unsigned int rx_base_addr         : 10; /* bits 9:0 */
+	unsigned int rsrvd1               :  6;
+	unsigned int rx_top_addr          : 10; /* bits 25:16 */
+	unsigned int rsrvd2               :  6;
+};
+
+struct NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t {
+	unsigned int tx_base_addr         : 10; /* bits 9:0 */
+	unsigned int rsrvd1               :  6;
+	unsigned int tx_top_addr          : 10; /* bits 25:16 */
+	unsigned int rsrvd2               :  6;
+};
+
+struct NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t {
+	unsigned int pkt_wr_ptr           : 10; /* bits 9:0 */
+	unsigned int rsrvd1               :  5;
+	unsigned int int_colsc_thresh_reached :  1; /* bits 15:15 */
+	unsigned int rsrvd2               : 16;
+};
+
+struct NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t {
+	unsigned int pkt_rd_ptr           : 10; /* bits 9:0 */
+	unsigned int rsrvd1               : 22;
+};
+
+struct NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t {
+	unsigned int pkt_wr_ptr           : 10; /* bits 9:0 */
+	unsigned int rsrvd1               : 22;
+};
+
+struct GLOBAL_GLOBAL_CONFIG_t {
+	unsigned int rsrvd1               :  4;
+	unsigned int wd_reset_subsys_enable :  1; /* bits 4:4 */
+	unsigned int rsrvd2               :  1;
+	unsigned int wd_reset_all_blocks  :  1; /* bits 6:6 */
+	unsigned int wd_reset_remap       :  1; /* bits 7:7 */
+	unsigned int wd_reset_ext_reset   :  1; /* bits 8:8 */
+	unsigned int ext_reset            :  1; /* bits 9:9 */
+	unsigned int cfg_pcie_0_clken     :  1; /* bits 10:10 */
+	unsigned int cfg_sata_clken       :  1; /* bits 11:11 */
+	unsigned int cfg_pcie_1_clken     :  1; /* bits 12:12 */
+	unsigned int rsrvd3               :  1;
+	unsigned int cfg_pcie_2_clken     :  1; /* bits 14:14 */
+	unsigned int rsrvd4               :  2;
+	unsigned int ext_eth_refclk       :  1; /* bits 17:17 */
+	unsigned int refclk_sel           :  2; /* bits 19:18 */
+	unsigned int rsrvd5               :  7;
+	unsigned int l3fe_pd              :  1; /* bits 27:27 */
+	unsigned int offload0_pd          :  1; /* bits 28:28 */
+	unsigned int offload1_pd          :  1; /* bits 29:29 */
+	unsigned int crypto_pd            :  1; /* bits 30:30 */
+	unsigned int core_pd              :  1; /* bits 31:31 */
+};
+
+struct GLOBAL_IO_DRIVE_CONTROL_t {
+	unsigned int gmac_dp              :  3; /* bits 2:0 */
+	unsigned int gmac_dn              :  3; /* bits 5:3 */
+	unsigned int gmac_mode            :  2; /* bits 7:6 */
+	unsigned int gmac_ds              :  1; /* bits 8:8 */
+	unsigned int flash_ds             :  1; /* bits 9:9 */
+	unsigned int nu_ds                :  1; /* bits 10:10 */
+	unsigned int ssp_ds               :  1; /* bits 11:11 */
+	unsigned int spi_ds               :  1; /* bits 12:12 */
+	unsigned int gpio_ds              :  1; /* bits 13:13 */
+	unsigned int misc_ds              :  1; /* bits 14:14 */
+	unsigned int eaxi_ds              :  1; /* bits 15:15 */
+	unsigned int sd_ds                :  8; /* bits 23:16 */
+	unsigned int rsrvd1               :  8;
+};
+
+struct NI_HV_GLB_INIT_DONE_t {
+	unsigned int rsrvd1               :  1;
+	unsigned int ni_init_done         :  1; /* bits 1:1 */
+	unsigned int rsrvd2               : 30;
+};
+
+struct NI_HV_PT_PORT_GLB_CFG_t {
+	unsigned int speed                :  1; /* bits 0:0 */
+	unsigned int duplex               :  1; /* bits 1:1 */
+	unsigned int link_status          :  1; /* bits 2:2 */
+	unsigned int link_stat_mask       :  1; /* bits 3:3 */
+	unsigned int rsrvd1               :  7;
+	unsigned int power_dwn_rx         :  1; /* bits 11:11 */
+	unsigned int power_dwn_tx         :  1; /* bits 12:12 */
+	unsigned int tx_intf_lp_time      :  1; /* bits 13:13 */
+	unsigned int rsrvd2               : 18;
+};
+
+#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

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 2/3] net: phy: ca_phy: Add driver for CAxxxx SoCs
  2020-07-30 19:05 [PATCH v2 1/3] net: cortina_ni: Add eth support for Cortina Access CAxxxx SoCs Alex Nemirovsky
@ 2020-07-30 19:05 ` Alex Nemirovsky
  2020-07-30 19:05 ` [PATCH v2 3/3] board: presidio-asic: Add CAxxxx Ethernet support Alex Nemirovsky
  2020-09-10 23:18 ` [PATCH v2 1/3] net: cortina_ni: Add eth support for Cortina Access CAxxxx SoCs Alex Nemirovsky
  2 siblings, 0 replies; 9+ messages in thread
From: Alex Nemirovsky @ 2020-07-30 19:05 UTC (permalink / raw)
  To: u-boot

From: Abbie Chang <abbie.chang@cortina-access.com>

Add phy driver support for MACs embedded inside Cortina Access SoCs

Signed-off-by: Abbie Chang <abbie.chang@cortina-access.com>
Signed-off-by: Alex Nemirovsky <alex.nemirovsky@cortina-access.com>

CC: Joe Hershberger <joe.hershberger@ni.com>
CC: Tom Rini <trini@konsulko.com>
CC: Aaron Tseng <aaron.tseng@cortina-access.com>

Moved out PHY specific code out of Cortina NI Ethernet driver
and into a Cortina Access PHY interface driver

---

(no changes since v1)

 MAINTAINERS              |   2 +
 drivers/net/phy/Kconfig  |   9 ++++
 drivers/net/phy/Makefile |   1 +
 drivers/net/phy/ca_phy.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/phy/phy.c    |   2 +
 include/phy.h            |   1 +
 6 files changed, 148 insertions(+)
 create mode 100644 drivers/net/phy/ca_phy.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 272caca..cf50592 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -184,6 +184,7 @@ 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
+F:	drivers/net/phy/ca_phy.c
 
 ARM/CZ.NIC TURRIS MOX SUPPORT
 M:	Marek Behun <marek.behun@nic.cz>
@@ -742,6 +743,7 @@ 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
+F:	drivers/net/phy/ca_phy.c
 
 MIPS MSCC
 M:	Gregory CLEMENT <gregory.clement@bootlin.com>
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index d1f049e..b8e8943 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -122,6 +122,15 @@ config SYS_CORTINA_FW_IN_SPIFLASH
 
 endchoice
 
+config PHY_CORTINA_ACCESS
+	bool "Cortina Access Ethernet PHYs support"
+	default y
+	depends on CORTINA_NI_ENET
+	help
+		Cortina Access Ethernet PHYs support
+
+		Cortina Access Ethernet PHYs init process
+
 config PHY_DAVICOM
 	bool "Davicom Ethernet PHYs support"
 
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 1d81516..baf4238 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_PHY_AQUANTIA) += aquantia.o
 obj-$(CONFIG_PHY_ATHEROS) += atheros.o
 obj-$(CONFIG_PHY_BROADCOM) += broadcom.o
 obj-$(CONFIG_PHY_CORTINA) += cortina.o
+obj-$(CONFIG_PHY_CORTINA_ACCESS) += ca_phy.o
 obj-$(CONFIG_PHY_DAVICOM) += davicom.o
 obj-$(CONFIG_PHY_ET1011C) += et1011c.o
 obj-$(CONFIG_PHY_LXT) += lxt.o
diff --git a/drivers/net/phy/ca_phy.c b/drivers/net/phy/ca_phy.c
new file mode 100644
index 0000000..d3a49f9
--- /dev/null
+++ b/drivers/net/phy/ca_phy.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Cortina CS4315/CS4340 10G PHY drivers
+ *
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ * Copyright 2018 NXP
+ *
+ */
+
+#include <config.h>
+#include <common.h>
+#include <log.h>
+#include <malloc.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/err.h>
+#include <phy.h>
+
+#define PHY_ID_RTL8211_EXT      0x001cc910
+#define PHY_ID_RTL8211_INT	0x001cc980
+#define PHY_ID_MASK             0xFFFFFFF0
+
+__weak void __internal_phy_init(struct phy_device *phydev, int reset_phy)
+{
+	u8 phy_addr;
+	u16     data;
+
+	/* should initialize 4 GPHYs at once */
+	for (phy_addr = 4; phy_addr > 0; phy_addr--) {
+		phydev->addr = phy_addr;
+		phy_write(phydev, MDIO_DEVAD_NONE, 31, 0x0BC6);
+		phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x0053);
+		phy_write(phydev, MDIO_DEVAD_NONE, 18, 0x4003);
+		phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x7e01);
+		phy_write(phydev, MDIO_DEVAD_NONE, 31, 0x0A42);
+		phy_write(phydev, MDIO_DEVAD_NONE, 31, 0x0A40);
+		phy_write(phydev, MDIO_DEVAD_NONE,  0, 0x1140);
+	}
+
+	/* workaround to fix GPHY fail */
+	for (phy_addr = 1; phy_addr < 5; phy_addr++) {
+		/* Clear clock fail interrupt */
+		phydev->addr = phy_addr;
+		phy_write(phydev, MDIO_DEVAD_NONE, 31, 0xB90);
+		data = phy_read(phydev, MDIO_DEVAD_NONE, 19);
+		if (data == 0x10) {
+			phy_write(phydev, MDIO_DEVAD_NONE, 31, 0xB90);
+			data = phy_read(phydev, MDIO_DEVAD_NONE, 19);
+			printf("%s: read again.\n", __func__);
+		}
+
+		printf("%s: phy_addr=%d, read register 19, value=0x%x\n",
+		       __func__, phy_addr, data);
+	}
+}
+
+__weak void __external_phy_init(struct phy_device *phydev, int reset_phy)
+{
+	u16 val;
+
+	/* Disable response PHYAD=0 function of RTL8211 series PHY */
+	/* REG31 write 0x0007, set to extension page */
+	phy_write(phydev, MDIO_DEVAD_NONE, 31, 0x0007);
+
+	/* REG30 write 0x002C, set to extension page 44 */
+	phy_write(phydev, MDIO_DEVAD_NONE, 30, 0x002C);
+
+	/*
+	 * REG27 write bit[2] = 0 disable response PHYAD = 0 function.
+	 * we should read REG27 and clear bit[2], and write back
+	 */
+	val = phy_read(phydev, MDIO_DEVAD_NONE, 27);
+	val &= ~(1 << 2);
+	phy_write(phydev, MDIO_DEVAD_NONE, 27, val);
+
+	/* REG31 write 0X0000, back to page0 */
+	phy_write(phydev, MDIO_DEVAD_NONE, 31, 0x0000);
+}
+
+static int rtl8211_external_config(struct phy_device *phydev)
+{
+	__external_phy_init(phydev, 0);
+	printf("%s: initialize RTL8211 external done.\n", __func__);
+	return 0;
+}
+
+static int rtl8211_internal_config(struct phy_device *phydev)
+{
+	struct phy_device phydev_init;
+
+	memcpy(&phydev_init, phydev, sizeof(struct phy_device));
+	/* should initialize 4 GPHYs@once */
+	__internal_phy_init(&phydev_init, 0);
+	printf("%s: initialize RTL8211 internal done.\n", __func__);
+	return 0;
+}
+
+static int rtl8211_probe(struct phy_device *phydev)
+{
+	/* disable reset behavior */
+	phydev->flags = PHY_FLAG_BROKEN_RESET;
+	return 0;
+}
+
+/* Support for RTL8211 External PHY */
+struct phy_driver rtl8211_external_driver = {
+	.name = "Cortina RTL8211 External",
+	.uid = PHY_ID_RTL8211_EXT,
+	.mask = PHY_ID_MASK,
+	.features = PHY_GBIT_FEATURES,
+	.config = &rtl8211_external_config,
+	.probe = &rtl8211_probe,
+	.startup = &genphy_startup,
+};
+
+/* Support for RTL8211 Internal PHY */
+struct phy_driver rtl8211_internal_driver = {
+	.name = "Cortina RTL8211 Inrernal",
+	.uid = PHY_ID_RTL8211_INT,
+	.mask = PHY_ID_MASK,
+	.features = PHY_GBIT_FEATURES,
+	.config = &rtl8211_internal_config,
+	.probe = &rtl8211_probe,
+	.startup = &genphy_startup,
+};
+
+int phy_cortina_access_init(void)
+{
+	phy_register(&rtl8211_external_driver);
+	phy_register(&rtl8211_internal_driver);
+	return 0;
+}
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index cce09c4..67325f2 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -500,6 +500,8 @@ int phy_init(void)
 #ifdef CONFIG_PHY_CORTINA
 	phy_cortina_init();
 #endif
+	if (IS_ENABLED(CONFIG_PHY_CORTINA_ACCESS))
+		phy_cortina_access_init();
 #ifdef CONFIG_PHY_DAVICOM
 	phy_davicom_init();
 #endif
diff --git a/include/phy.h b/include/phy.h
index b5de14c..83e984d 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -402,6 +402,7 @@ int phy_aquantia_init(void);
 int phy_atheros_init(void);
 int phy_broadcom_init(void);
 int phy_cortina_init(void);
+int phy_cortina_access_init(void);
 int phy_davicom_init(void);
 int phy_et1011c_init(void);
 int phy_lxt_init(void);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 3/3] board: presidio-asic: Add CAxxxx Ethernet support
  2020-07-30 19:05 [PATCH v2 1/3] net: cortina_ni: Add eth support for Cortina Access CAxxxx SoCs Alex Nemirovsky
  2020-07-30 19:05 ` [PATCH v2 2/3] net: phy: ca_phy: Add driver for " Alex Nemirovsky
@ 2020-07-30 19:05 ` Alex Nemirovsky
  2020-09-10 23:18 ` [PATCH v2 1/3] net: cortina_ni: Add eth support for Cortina Access CAxxxx SoCs Alex Nemirovsky
  2 siblings, 0 replies; 9+ messages in thread
From: Alex Nemirovsky @ 2020-07-30 19:05 UTC (permalink / raw)
  To: u-boot

Add CAxxxx Ethernet support for the Cortina Access
Presidio Engineering Board

Signed-off-by: Alex Nemirovsky <alex.nemirovsky@cortina-access.com>
CC: Tom Rini <trini@konsulko.com>

---

Changes in v2:
- only support DM_ETH network models by removing
code for legacy mode support

 arch/arm/dts/ca-presidio-engboard.dts        |  7 +++++++
 board/cortina/presidio-asic/presidio.c       | 31 ++++++++++++++++++++++++++++
 configs/cortina_presidio-asic-emmc_defconfig |  4 +++-
 include/configs/presidio_asic.h              | 15 +++++++++++++-
 4 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/arch/arm/dts/ca-presidio-engboard.dts b/arch/arm/dts/ca-presidio-engboard.dts
index 40c93d7..4e5681a 100644
--- a/arch/arm/dts/ca-presidio-engboard.dts
+++ b/arch/arm/dts/ca-presidio-engboard.dts
@@ -64,4 +64,11 @@
 			spi-max-frequency = <108000000>;
 		};
 	};
+
+	eth: ethnet at 0xf4300000 {
+		compatible = "eth_cortina";
+		reg = <0x0 0xf4320000 0x34>,
+		      <0x0 0xf43290d8 0x04>,
+		      <0x0 0xf4304000 0x04>;
+	};
 };
diff --git a/board/cortina/presidio-asic/presidio.c b/board/cortina/presidio-asic/presidio.c
index 3c132f1..74e0ba6 100644
--- a/board/cortina/presidio-asic/presidio.c
+++ b/board/cortina/presidio-asic/presidio.c
@@ -134,3 +134,34 @@ int last_stage_init(void)
 	return 0;
 }
 #endif
+
+enum ca_port_t {
+	NI_PORT_0 = 0,
+	NI_PORT_1,
+	NI_PORT_2,
+	NI_PORT_3,
+	NI_PORT_4,
+	NI_PORT_5,
+	NI_PORT_MAX,
+};
+
+struct port_map_s {
+	int active_port;
+	int phy_addr;
+};
+
+/* 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
+ */
+struct port_map_s port_map[NI_PORT_MAX] = {
+	{NI_PORT_0, 1},
+	{NI_PORT_1, 2},
+	{NI_PORT_2, 3},
+	{NI_PORT_3, 4},
+	{NI_PORT_4, 5}
+};
+
+int active_port = NI_PORT_3;  /* Physical port 3 */
diff --git a/configs/cortina_presidio-asic-emmc_defconfig b/configs/cortina_presidio-asic-emmc_defconfig
index e10008a..360ebeb 100644
--- a/configs/cortina_presidio-asic-emmc_defconfig
+++ b/configs/cortina_presidio-asic-emmc_defconfig
@@ -21,12 +21,14 @@ CONFIG_CMD_EXT4=y
 CONFIG_OF_CONTROL=y
 CONFIG_OF_LIVE=y
 CONFIG_DEFAULT_DEVICE_TREE="ca-presidio-engboard"
-# CONFIG_NET is not set
 CONFIG_DM=y
 CONFIG_CORTINA_GPIO=y
 CONFIG_DM_MMC=y
 CONFIG_MMC_DW=y
 CONFIG_MMC_DW_CORTINA=y
+CONFIG_PHYLIB=y
+CONFIG_DM_ETH=y
+CONFIG_CORTINA_NI_ENET=y
 CONFIG_DM_SERIAL=y
 CONFIG_CORTINA_UART=y
 CONFIG_WDT=y
diff --git a/include/configs/presidio_asic.h b/include/configs/presidio_asic.h
index 51177f4..8cbb1df 100644
--- a/include/configs/presidio_asic.h
+++ b/include/configs/presidio_asic.h
@@ -2,7 +2,7 @@
 /*
  * Copyright (C) 2020 Cortina Access Inc.
  *
- * Configuration for Cortina-Access Presidio board.
+ * Configuration for Cortina-Access Presidio board
  */
 
 #ifndef __PRESIDIO_ASIC_H
@@ -64,6 +64,19 @@
 					sizeof(CONFIG_SYS_PROMPT) + 16)
 #define CONFIG_SYS_BARGSIZE		CONFIG_SYS_CBSIZE
 
+#define KSEG1_ATU_XLAT(x) (x)
+
+/* HW REG ADDR */
+#define NI_READ_POLL_COUNT                      1000
+#define CA_NI_MDIO_REG_BASE                     0xF4338
+#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
+
 /* max command args */
 #define CONFIG_SYS_MAXARGS		64
 #define CONFIG_EXTRA_ENV_SETTINGS	"silent=y\0"
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 1/3] net: cortina_ni: Add eth support for Cortina Access CAxxxx SoCs
  2020-07-30 19:05 [PATCH v2 1/3] net: cortina_ni: Add eth support for Cortina Access CAxxxx SoCs Alex Nemirovsky
  2020-07-30 19:05 ` [PATCH v2 2/3] net: phy: ca_phy: Add driver for " Alex Nemirovsky
  2020-07-30 19:05 ` [PATCH v2 3/3] board: presidio-asic: Add CAxxxx Ethernet support Alex Nemirovsky
@ 2020-09-10 23:18 ` Alex Nemirovsky
  2020-09-10 23:54   ` Tom Rini
  2 siblings, 1 reply; 9+ messages in thread
From: Alex Nemirovsky @ 2020-09-10 23:18 UTC (permalink / raw)
  To: u-boot

bump.

> On Jul 30, 2020, at 12:05 PM, Alex Nemirovsky <alex.nemirovsky@cortina-access.com> wrote:
> 
> From: Aaron Tseng <aaron.tseng@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.tseng@cortina-access.com>
> Signed-off-by: Alex Nemirovsky <alex.nemirovsky@cortina-access.com>
> Signed-off-by: Abbie Chang <abbie.chang@cortina-access.com>
> 
> CC: Joe Hershberger <joe.hershberger@ni.com>
> CC: Abbie Chang <abbie.chang@Cortina-Access.com>
> CC: Tom Rini <trini@konsulko.com>
> 
> ---
> 
> Changes in v2:
> - clean up old debug code
> - reference CRC functions already provided in u-boot core
> - remove unused code, ex: CA_IN/CA_OUT
> - refactor the design of register read/write, union -> struct
> - remove platform dependent code
> 
> MAINTAINERS              |    4 +
> drivers/net/Kconfig      |    7 +
> drivers/net/Makefile     |    1 +
> drivers/net/cortina_ni.c | 1168 ++++++++++++++++++++++++++++++++++++++++++++++
> drivers/net/cortina_ni.h |  435 +++++++++++++++++
> 5 files changed, 1615 insertions(+)
> create mode 100644 drivers/net/cortina_ni.c
> create mode 100644 drivers/net/cortina_ni.h
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index db8cecd..272caca 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -182,6 +182,8 @@ F:	drivers/gpio/cortina_gpio.c
> F:	drivers/watchdog/cortina_wdt.c
> F:	drivers/serial/serial_cortina.c
> F:	drivers/mmc/ca_dw_mmc.c
> +F:	drivers/net/cortina_ni.c
> +F:	drivers/net/cortina_ni.h
> 
> ARM/CZ.NIC TURRIS MOX SUPPORT
> M:	Marek Behun <marek.behun@nic.cz>
> @@ -738,6 +740,8 @@ F:	drivers/gpio/cortina_gpio.c
> F:	drivers/watchdog/cortina_wdt.c
> F:	drivers/serial/serial_cortina.c
> F:	drivers/mmc/ca_dw_mmc.c
> +F:	drivers/net/cortina_ni.c
> +F:	drivers/net/cortina_ni.h
> 
> MIPS MSCC
> M:	Gregory CLEMENT <gregory.clement@bootlin.com>
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index bb23f73..616d238 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -149,6 +149,13 @@ config BCMGENET
> 	help
> 	  This driver supports the BCMGENET Ethernet MAC.
> 
> +config CORTINA_NI_ENET
> +	bool "Cortina-Access Ethernet driver"
> +	depends on DM_ETH && CORTINA_PLATFORM
> +	help
> +	  This driver supports the Cortina-Access Ethernet MAC for
> +	  all supported CAxxxx SoCs.
> +
> config DWC_ETH_QOS
> 	bool "Synopsys DWC Ethernet QOS device support"
> 	depends on DM_ETH
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index 383ed1c..1d6ec4f 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
> obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
> obj-$(CONFIG_BCM_SF2_ETH_GMAC) += bcm-sf2-eth-gmac.o
> obj-$(CONFIG_CALXEDA_XGMAC) += calxedaxgmac.o
> +obj-$(CONFIG_CORTINA_NI_ENET) += cortina_ni.o
> obj-$(CONFIG_CS8900) += cs8900.o
> obj-$(CONFIG_TULIP) += dc2114x.o
> obj-$(CONFIG_ETH_DESIGNWARE) += designware.o
> diff --git a/drivers/net/cortina_ni.c b/drivers/net/cortina_ni.c
> new file mode 100644
> index 0000000..7acfa6a
> --- /dev/null
> +++ b/drivers/net/cortina_ni.c
> @@ -0,0 +1,1168 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +/*
> + * Copyright (C) 2020 Cortina Access Inc.
> + * Author: Aaron Tseng <aaron.tseng@cortina-access.com>
> + *
> + * Ethernet MAC Driver for all supported CAxxxx SoCs
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <malloc.h>
> +#include <net.h>
> +#include <miiphy.h>
> +#include <env.h>
> +#include <linux/delay.h>
> +#include <u-boot/crc.h>
> +#include <led.h>
> +
> +#include "cortina_ni.h"
> +
> +#define HEADER_A_SIZE	8
> +
> +enum ca_led_state_t {
> +	CA_LED_OFF = 0,
> +	CA_LED_ON = 1,
> +};
> +
> +static struct udevice   *curr_dev;
> +static int ca_ni_ofdata_to_platdata(struct udevice *dev);
> +
> +static u32 *rdwrptr_adv_one(u32 *x, unsigned long base, unsigned long max)
> +{
> +	if (x + 1 >= (u32 *)max)
> +		return (u32 *)base;
> +	else
> +		return (x + 1);
> +}
> +
> +static int phyaddr_to_port(int phy_addr)
> +{
> +	int idx;
> +
> +	for (idx = 0; idx < NI_PORT_MAX; idx++)
> +		if (phy_addr == port_map[idx].phy_addr)
> +			return port_map[idx].active_port;
> +	return 0;
> +}
> +
> +static int port_to_phyaddr(int active_port)
> +{
> +	int idx;
> +
> +	for (idx = 0; idx < NI_PORT_MAX; idx++)
> +		if (active_port == port_map[idx].active_port)
> +			return port_map[idx].phy_addr;
> +	return 0;
> +}
> +
> +static u32 REG_TO_U32(void *reg)
> +{
> +	return *(u32 *)reg;
> +}
> +
> +static void ca_reg_read(void *reg, u64 base, u64 offset)
> +{
> +	u32 *val = (u32 *)reg;
> +
> +	*val = readl(KSEG1_ATU_XLAT(base + offset));
> +}
> +
> +static void ca_reg_write(void *reg, u64 base, u64 offset)
> +{
> +	u32 val = *(u32 *)reg;
> +
> +	writel(val, KSEG1_ATU_XLAT(base + offset));
> +}
> +
> +static enum ca_status_t ca_mdio_write_rgmii(unsigned int addr,
> +					    unsigned int offset,
> +					    unsigned short data)
> +{
> +	struct PER_MDIO_ADDR_t  mdio_addr;
> +	struct PER_MDIO_CTRL_t  mdio_ctrl;
> +	/* up to 10000 cycles*/
> +	unsigned int      loop_wait = __MDIO_ACCESS_TIMEOUT;
> +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
> +
> +	memset(&mdio_addr, 0, sizeof(mdio_addr));
> +	mdio_addr.mdio_addr   = addr;
> +	mdio_addr.mdio_offset = offset;
> +	mdio_addr.mdio_rd_wr  = __MDIO_WR_FLAG;
> +	ca_reg_write(&mdio_addr, (u64)priv->per_mdio_base_addr,
> +		     PER_MDIO_ADDR_OFFSET);
> +	ca_reg_write(&data, (u64)priv->per_mdio_base_addr,
> +		     PER_MDIO_WRDATA_OFFSET);
> +
> +	debug("%s: mdio_addr=0x%x\n", __func__, REG_TO_U32(&mdio_addr));
> +
> +	memset(&mdio_ctrl, 0, sizeof(mdio_ctrl));
> +	mdio_ctrl.mdiostart = 1;
> +	ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
> +		     PER_MDIO_CTRL_OFFSET);
> +
> +	debug("%s: phy_addr=%d, offset=%d, data=0x%x\n",
> +	      __func__, addr, offset, data);
> +
> +	do {
> +		ca_reg_read(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
> +			    PER_MDIO_CTRL_OFFSET);
> +		if (mdio_ctrl.mdiodone) {
> +			ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
> +				     PER_MDIO_CTRL_OFFSET);
> +			return CA_E_OK;
> +		}
> +	} while (--loop_wait);
> +
> +	printf("%s: PHY write timeout!!!\n", __func__);
> +	return CA_E_TIMEOUT;
> +}
> +
> +enum ca_status_t ca_mdio_write(unsigned int     addr,
> +			       unsigned int     offset,
> +			       unsigned short   data)
> +{
> +	u32 reg_addr, reg_val;
> +	struct NI_MDIO_OPER_T mdio_oper;
> +
> +	/* support range: 1~31*/
> +	if (addr < CA_MDIO_ADDR_MIN || addr > CA_MDIO_ADDR_MAX)
> +		return CA_E_PARAM;
> +
> +	/* the phy addr 5 is connect to RGMII */
> +	if (addr >= 5)
> +		return ca_mdio_write_rgmii(addr, offset, data);
> +
> +	memset(&mdio_oper, 0, sizeof(mdio_oper));
> +	mdio_oper.reg_off = offset;
> +	mdio_oper.phy_addr = addr;
> +	mdio_oper.reg_base = CA_NI_MDIO_REG_BASE;
> +	reg_val = data;
> +	memcpy(&reg_addr, &mdio_oper, sizeof(reg_addr));
> +	ca_reg_write(&reg_val, (u64)reg_addr, 0);
> +
> +	debug("%s: mdio_oper=0x%x, data=0x%x\n",
> +	      __func__, REG_TO_U32(&mdio_oper), data);
> +	return CA_E_OK;
> +}
> +
> +static enum ca_status_t ca_mdio_read_rgmii(unsigned int addr,
> +					   unsigned int offset,
> +					   unsigned short *data)
> +{
> +	struct PER_MDIO_ADDR_t  mdio_addr;
> +	struct PER_MDIO_CTRL_t  mdio_ctrl;
> +	struct PER_MDIO_RDDATA_t  read_data;
> +	unsigned int loop_wait = __MDIO_ACCESS_TIMEOUT;
> +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
> +
> +	memset(&mdio_addr, 0, sizeof(mdio_addr));
> +	mdio_addr.mdio_addr   = addr;
> +	mdio_addr.mdio_offset = offset;
> +	mdio_addr.mdio_rd_wr  = __MDIO_RD_FLAG;
> +	ca_reg_write(&mdio_addr, (u64)priv->per_mdio_base_addr,
> +		     PER_MDIO_ADDR_OFFSET);
> +
> +	memset(&mdio_ctrl, 0, sizeof(mdio_ctrl));
> +	mdio_ctrl.mdiostart = 1;
> +	ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
> +		     PER_MDIO_CTRL_OFFSET);
> +
> +	do {
> +		ca_reg_read(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
> +			    PER_MDIO_CTRL_OFFSET);
> +		if (mdio_ctrl.mdiodone) {
> +			ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
> +				     PER_MDIO_CTRL_OFFSET);
> +			ca_reg_read(&read_data, (u64)priv->per_mdio_base_addr,
> +				    PER_MDIO_RDDATA_OFFSET);
> +			*data = read_data.mdio_rddata;
> +			return CA_E_OK;
> +		}
> +	} while (--loop_wait);
> +
> +	printf("%s: CA_E_TIMEOUT!!\n", __func__);
> +	return CA_E_TIMEOUT;
> +}
> +
> +enum ca_status_t ca_mdio_read(unsigned int      addr,
> +			      unsigned int	offset,
> +			      unsigned short	*data)
> +{
> +	u32 reg_addr, reg_val;
> +	struct NI_MDIO_OPER_T  mdio_oper;
> +
> +	if (!data)
> +		return CA_E_PARAM;
> +
> +	/* support range: 1~31*/
> +	if (addr < CA_MDIO_ADDR_MIN || addr > CA_MDIO_ADDR_MAX)
> +		return CA_E_PARAM;
> +
> +	/* the phy addr 5 is connect to RGMII */
> +	if (addr >= 5)
> +		return  ca_mdio_read_rgmii(addr, offset, data);
> +
> +	memset(&mdio_oper, 0, sizeof(mdio_oper));
> +	mdio_oper.reg_off = offset;
> +	mdio_oper.phy_addr = addr;
> +	mdio_oper.reg_base = CA_NI_MDIO_REG_BASE;
> +	reg_val = *data;
> +	memcpy(&reg_addr, &mdio_oper, sizeof(reg_addr));
> +	ca_reg_read(&reg_val, (u64)reg_addr, 0);
> +	*data = reg_val;
> +	return CA_E_OK;
> +}
> +
> +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);
> +}
> +
> +static int cortina_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
> +{
> +	unsigned short data;
> +
> +	ca_mdio_read(addr, reg, &data);
> +	return data;
> +}
> +
> +static int cortina_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
> +			      u16 val)
> +{
> +	ca_mdio_write(addr, reg, val);
> +	return 0;
> +}
> +
> +static void ca_ni_setup_mac_addr(void)
> +{
> +	unsigned char mac[6];
> +
> +	struct NI_HV_GLB_MAC_ADDR_CFG0_t	mac_addr_cfg0;
> +	struct NI_HV_GLB_MAC_ADDR_CFG1_t	mac_addr_cfg1;
> +	struct NI_HV_PT_PORT_STATIC_CFG_t	port_static_cfg;
> +	struct NI_HV_XRAM_CPUXRAM_CFG_t		cpuxram_cfg;
> +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
> +
> +	/* parsing ethaddr and set to NI registers. */
> +	if (eth_env_get_enetaddr("ethaddr", mac)) {
> +		/* The complete MAC address consists of
> +		 * {MAC_ADDR0_mac_addr0[0-3], MAC_ADDR1_mac_addr1[4],
> +		 * PT_PORT_STATIC_CFG_mac_addr6[5]}.
> +		 */
> +		mac_addr_cfg0.mac_addr0 = (mac[0] << 24) + (mac[1] << 16) +
> +					  (mac[2] << 8) + mac[3];
> +		ca_reg_write(&mac_addr_cfg0, (u64)priv->ni_hv_base_addr,
> +			     NI_HV_GLB_MAC_ADDR_CFG0_OFFSET);
> +
> +		memset(&mac_addr_cfg1, 0, sizeof(mac_addr_cfg1));
> +		mac_addr_cfg1.mac_addr1 = mac[4];
> +		ca_reg_write(&mac_addr_cfg1, (u64)priv->ni_hv_base_addr,
> +			     NI_HV_GLB_MAC_ADDR_CFG1_OFFSET);
> +
> +		ca_reg_read(&port_static_cfg, (u64)priv->ni_hv_base_addr,
> +			    NI_HV_PT_PORT_STATIC_CFG_OFFSET +
> +			    (APB0_NI_HV_PT_STRIDE * active_port));
> +
> +		port_static_cfg.mac_addr6 = mac[5];
> +		ca_reg_write(&port_static_cfg, (u64)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 */
> +		ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
> +			    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
> +		cpuxram_cfg.xram_mgmt_promisc_mode = 0;
> +		cpuxram_cfg.rx_0_cpu_pkt_dis = 0;
> +		cpuxram_cfg.tx_0_cpu_pkt_dis = 0;
> +		ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
> +			     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
> +	} else {
> +		/* received all packets(promiscuous mode) */
> +		ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
> +			    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
> +		cpuxram_cfg.xram_mgmt_promisc_mode = 3;
> +		cpuxram_cfg.rx_0_cpu_pkt_dis = 0;
> +		cpuxram_cfg.tx_0_cpu_pkt_dis = 0;
> +		ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
> +			     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
> +	}
> +}
> +
> +static void ca_ni_enable_tx_rx(void)
> +{
> +	struct NI_HV_PT_RXMAC_CFG_t rxmac_cfg;
> +	struct NI_HV_PT_TXMAC_CFG_t txmac_cfg;
> +
> +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
> +
> +	/* Enable TX and RX functions */
> +	ca_reg_read(&rxmac_cfg, (u64)priv->ni_hv_base_addr,
> +		    NI_HV_PT_RXMAC_CFG_OFFSET +
> +		    (APB0_NI_HV_PT_STRIDE * active_port));
> +	rxmac_cfg.rx_en = 1;
> +	ca_reg_write(&rxmac_cfg, (u64)priv->ni_hv_base_addr,
> +		     NI_HV_PT_RXMAC_CFG_OFFSET +
> +		     (APB0_NI_HV_PT_STRIDE * active_port));
> +
> +	ca_reg_read(&txmac_cfg, (u64)priv->ni_hv_base_addr,
> +		    NI_HV_PT_TXMAC_CFG_OFFSET +
> +		    (APB0_NI_HV_PT_STRIDE * active_port));
> +	txmac_cfg.tx_en = 1;
> +	ca_reg_write(&txmac_cfg, (u64)priv->ni_hv_base_addr,
> +		     NI_HV_PT_TXMAC_CFG_OFFSET +
> +		     (APB0_NI_HV_PT_STRIDE * active_port));
> +}
> +
> +#define AUTO_SCAN_TIMEOUT	3000		/* 3 seconds */
> +__weak int ca_ni_auto_scan_active_port(void)
> +{
> +	u8	phy_addr;
> +	u32	start_time;
> +	unsigned short data;
> +
> +	start_time = get_timer(0);
> +	while (get_timer(start_time) < AUTO_SCAN_TIMEOUT) {
> +		phy_addr = 1;
> +		for (; phy_addr < 6; phy_addr++) {
> +			ca_mdio_read(phy_addr, 1, &data);
> +			if (data & 0x04) {
> +				active_port = phyaddr_to_port(phy_addr);
> +				return 0;
> +			}
> +		}
> +	}
> +
> +	printf("%s: auto scan active_port timeout.\n", __func__);
> +	return -1;
> +}
> +
> +__weak int invalid_active_port(int port)
> +{
> +	if (active_port < NI_PORT_0 || active_port > NI_PORT_4)
> +		return -1;
> +	else
> +		return 0;
> +}
> +
> +static int ca_phy_probe(struct udevice *dev)
> +{
> +	struct cortina_ni_priv *priv = dev_get_priv(dev);
> +	struct phy_device *int_phydev, *ext_phydev;
> +	int auto_scan_active_port = 0, tmp_port;
> +	char *buf;
> +
> +	/* Initialize internal phy device */
> +	int_phydev = phy_connect(priv->mdio_bus, port_to_phyaddr(NI_PORT_3),
> +				 dev, priv->phy_interface);
> +	if (int_phydev) {
> +		int_phydev->supported &= PHY_GBIT_FEATURES;
> +		int_phydev->advertising = int_phydev->supported;
> +		phy_config(int_phydev);
> +	} else {
> +		printf("%s: There is no internal phy device\n", __func__);
> +	}
> +
> +	/* Initialize external phy device */
> +	ext_phydev = phy_connect(priv->mdio_bus, port_to_phyaddr(NI_PORT_4),
> +				 dev, priv->phy_interface);
> +	if (ext_phydev) {
> +		ext_phydev->supported &= PHY_GBIT_FEATURES;
> +		ext_phydev->advertising = int_phydev->supported;
> +		phy_config(ext_phydev);
> +	} else {
> +		printf("%s: There is no external phy device\n", __func__);
> +	}
> +
> +	/* auto scan the first link up port as active_port */
> +	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) {
> +		ca_ni_auto_scan_active_port();
> +	} else {
> +		buf = env_get("active_port");
> +		if (buf != 0) {
> +			tmp_port = simple_strtoul(buf, NULL, 0);
> +			if (invalid_active_port(active_port)) {
> +				printf("ERROR: doesn't support this port.");
> +				free(dev);
> +				free(priv);
> +				return 1;
> +			}
> +
> +			active_port = tmp_port;
> +		}
> +	}
> +
> +	printf("%s: active_port=%d\n", __func__, active_port);
> +	if (active_port == NI_PORT_4)
> +		priv->phydev = ext_phydev;
> +	else
> +		priv->phydev = int_phydev;
> +
> +	return 0;
> +}
> +
> +static void ca_ni_led(int port, int status)
> +{
> +	struct udevice *led_dev;
> +	char label[10];
> +
> +	if (IS_ENABLED(CONFIG_LED_CORTINA)) {
> +		snprintf(label, sizeof(label), "led%d", port);
> +		debug("%s: set port %d led %s.\n",
> +		      __func__, port, status ? "on" : "off");
> +		led_get_by_label(label, &led_dev);
> +		led_set_state(led_dev, status);
> +	}
> +}
> +
> +static void cortina_ni_reset(void)
> +{
> +	int i;
> +	struct NI_HV_GLB_INIT_DONE_t		init_done;
> +	struct NI_HV_GLB_INTF_RST_CONFIG_t	intf_rst_config;
> +	struct NI_HV_GLB_STATIC_CFG_t		static_cfg;
> +	struct GLOBAL_BLOCK_RESET_t		glb_blk_reset;
> +
> +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
> +
> +	/* NI global resets */
> +	ca_reg_read(&glb_blk_reset, (u64)priv->glb_base_addr,
> +		    GLOBAL_BLOCK_RESET_OFFSET);
> +	glb_blk_reset.reset_ni = 1;
> +	ca_reg_write(&glb_blk_reset, (u64)priv->glb_base_addr,
> +		     GLOBAL_BLOCK_RESET_OFFSET);
> +	/* Remove resets */
> +	glb_blk_reset.reset_ni = 0;
> +	ca_reg_write(&glb_blk_reset, (u64)priv->glb_base_addr,
> +		     GLOBAL_BLOCK_RESET_OFFSET);
> +
> +	/* check the ready bit of NI module */
> +	for (i = 0; i < NI_READ_POLL_COUNT; i++) {
> +		ca_reg_read(&init_done, (u64)priv->ni_hv_base_addr,
> +			    NI_HV_GLB_INIT_DONE_OFFSET);
> +		if (init_done.ni_init_done)
> +			break;
> +	}
> +	if (i == NI_READ_POLL_COUNT) {
> +		printf("%s: NI init done not ready, init_done=0x%x!!!\n",
> +		       __func__, init_done.ni_init_done);
> +	}
> +
> +	ca_reg_read(&intf_rst_config, (u64)priv->ni_hv_base_addr,
> +		    NI_HV_GLB_INTF_RST_CONFIG_OFFSET);
> +	switch (active_port) {
> +	case NI_PORT_0:
> +		intf_rst_config.intf_rst_p0 = 0;
> +		intf_rst_config.mac_rx_rst_p0 = 0;
> +		intf_rst_config.mac_tx_rst_p0 = 0;
> +		break;
> +	case NI_PORT_1:
> +		intf_rst_config.intf_rst_p1 = 0;
> +		intf_rst_config.mac_rx_rst_p1 = 0;
> +		intf_rst_config.mac_tx_rst_p1 = 0;
> +		break;
> +	case NI_PORT_2:
> +		intf_rst_config.intf_rst_p2 = 0;
> +		intf_rst_config.mac_rx_rst_p2 = 0;
> +		intf_rst_config.mac_tx_rst_p2 = 0;
> +		break;
> +	case NI_PORT_3:
> +		intf_rst_config.intf_rst_p3 = 0;
> +		intf_rst_config.mac_tx_rst_p3 = 0;
> +		intf_rst_config.mac_rx_rst_p3 = 0;
> +		break;
> +	case NI_PORT_4:
> +		intf_rst_config.intf_rst_p4 = 0;
> +		intf_rst_config.mac_tx_rst_p4 = 0;
> +		intf_rst_config.mac_rx_rst_p4 = 0;
> +		break;
> +	}
> +
> +	ca_reg_write(&intf_rst_config, (u64)priv->ni_hv_base_addr,
> +		     NI_HV_GLB_INTF_RST_CONFIG_OFFSET);
> +
> +	/* Only one GMAC can connect to CPU */
> +	ca_reg_read(&static_cfg, (u64)priv->ni_hv_base_addr,
> +		    NI_HV_GLB_STATIC_CFG_OFFSET);
> +	static_cfg.port_to_cpu = active_port;
> +	static_cfg.txmib_mode = 1;
> +	static_cfg.rxmib_mode = 1;
> +
> +	ca_reg_write(&static_cfg, (u64)priv->ni_hv_base_addr,
> +		     NI_HV_GLB_STATIC_CFG_OFFSET);
> +}
> +
> +static int cortina_ni_init(struct udevice *dev)
> +{
> +	int ret;
> +	struct NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t	cpuxram_adrcfg_rx;
> +	struct NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t  cpuxram_adrcfg_tx;
> +	struct NI_HV_XRAM_CPUXRAM_CFG_t		cpuxram_cfg;
> +	struct NI_HV_PT_PORT_STATIC_CFG_t	port_static_cfg;
> +	struct NI_HV_PT_PORT_GLB_CFG_t		port_glb_cfg;
> +
> +	struct cortina_ni_priv *priv = dev_get_priv(dev);
> +	struct phy_device *phydev = priv->phydev;
> +
> +	ret = phy_startup(priv->phydev);
> +	if (ret) {
> +		ca_ni_led(active_port, CA_LED_OFF);
> +		printf("Could not initialize PHY %s, active_port=%d\n",
> +		       priv->phydev->dev->name, active_port);
> +		return ret;
> +	}
> +
> +	if (!priv->phydev->link) {
> +		printf("%s: link down.\n", priv->phydev->dev->name);
> +		return 0;
> +	}
> +
> +	ca_ni_led(active_port, CA_LED_ON);
> +	printf("PHY ID 0x%08X %dMbps %s duplex\n",
> +	       phydev->phy_id, phydev->speed,
> +	       phydev->duplex == DUPLEX_HALF ? "half" : "full");
> +
> +	/* RX XRAM ADDRESS CONFIG (start and end address) */
> +	memset(&cpuxram_adrcfg_rx, 0, sizeof(cpuxram_adrcfg_rx));
> +	cpuxram_adrcfg_rx.rx_top_addr = RX_TOP_ADDR;
> +	cpuxram_adrcfg_rx.rx_base_addr = RX_BASE_ADDR;
> +	ca_reg_write(&cpuxram_adrcfg_rx, (u64)priv->ni_hv_base_addr,
> +		     NI_HV_XRAM_CPUXRAM_ADRCFG_RX_OFFSET);
> +
> +	/* TX XRAM ADDRESS CONFIG (start and end address) */
> +	memset(&cpuxram_adrcfg_tx, 0, sizeof(cpuxram_adrcfg_tx));
> +	cpuxram_adrcfg_tx.tx_top_addr = TX_TOP_ADDR;
> +	cpuxram_adrcfg_tx.tx_base_addr = TX_BASE_ADDR;
> +	ca_reg_write(&cpuxram_adrcfg_tx, (u64)priv->ni_hv_base_addr,
> +		     NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_OFFSET);
> +
> +	/*
> +	 * Configuration for Management Ethernet Interface:
> +	 * - RGMII 1000 mode or RGMII 100 mode
> +	 * - MAC mode
> +	 */
> +	ca_reg_read(&port_static_cfg, (u64)priv->ni_hv_base_addr,
> +		    NI_HV_PT_PORT_STATIC_CFG_OFFSET +
> +		    (APB0_NI_HV_PT_STRIDE * active_port));
> +	if (phydev->speed == SPEED_1000) {
> +		/* port 4 connects to RGMII PHY */
> +		if (phydev->addr == 5)
> +			port_static_cfg.int_cfg = GE_MAC_INTF_RGMII_1000;
> +		else
> +			port_static_cfg.int_cfg = GE_MAC_INTF_GMII;
> +	} else {
> +		/* port 4 connects to RGMII PHY */
> +		if (phydev->addr == 5)
> +			port_static_cfg.int_cfg = GE_MAC_INTF_RGMII_100;
> +		else
> +			port_static_cfg.int_cfg = GE_MAC_INTF_MII;
> +	}
> +
> +	ca_reg_write(&port_static_cfg, (u64)priv->ni_hv_base_addr,
> +		     NI_HV_PT_PORT_STATIC_CFG_OFFSET +
> +		     (APB0_NI_HV_PT_STRIDE * active_port));
> +
> +	ca_reg_read(&port_glb_cfg, (u64)priv->ni_hv_base_addr,
> +		    NI_HV_PT_PORT_GLB_CFG_OFFSET +
> +		    (APB0_NI_HV_PT_STRIDE * active_port));
> +	port_glb_cfg.speed = phydev->speed == SPEED_10 ? 1 : 0;
> +	port_glb_cfg.duplex = phydev->duplex == DUPLEX_HALF ? 1 : 0;
> +	ca_reg_write(&port_glb_cfg, (u64)priv->ni_hv_base_addr,
> +		     NI_HV_PT_PORT_GLB_CFG_OFFSET +
> +		     (APB0_NI_HV_PT_STRIDE * active_port));
> +
> +	/* Need to toggle the tx and rx cpu_pkt_dis bit */
> +	/* after changing Address config register.      */
> +	ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
> +		    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
> +	cpuxram_cfg.rx_0_cpu_pkt_dis = 1;
> +	cpuxram_cfg.tx_0_cpu_pkt_dis = 1;
> +	ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
> +		     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
> +
> +	ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
> +		    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
> +	cpuxram_cfg.rx_0_cpu_pkt_dis = 0;
> +	cpuxram_cfg.tx_0_cpu_pkt_dis = 0;
> +	ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
> +		     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
> +
> +	ca_ni_enable_tx_rx();
> +
> +	return 0;
> +}
> +
> +/*********************************************
> + * Packet receive routine from Management FE
> + * Expects a previously allocated buffer and
> + * fills the length
> + * Retruns 0 on success -1 on failure
> + *******************************************/
> +int cortina_ni_recv(struct udevice *netdev)
> +{
> +	struct cortina_ni_priv *priv = dev_get_priv(netdev);
> +	struct NI_HEADER_X_T	header_x;
> +	u32			next_link;
> +	u32			pktlen = 0;
> +	u32			sw_rx_rd_ptr;
> +	u32			hw_rx_wr_ptr;
> +	u32			*rx_xram_ptr;
> +	int			loop;
> +	u32			*data_ptr;
> +	struct NI_PACKET_STATUS packet_status;
> +	struct NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t cpuxram_cpu_sta_rx;
> +	struct NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t cpuxram_cpu_cfg_rx;
> +	int index = 0;
> +	int			blk_num;
> +	u8			*ptr;
> +
> +	/* get the hw write pointer */
> +	memset(&cpuxram_cpu_sta_rx, 0, sizeof(cpuxram_cpu_sta_rx));
> +	ca_reg_read(&cpuxram_cpu_sta_rx, (u64)priv->ni_hv_base_addr,
> +		    NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET);
> +	hw_rx_wr_ptr = cpuxram_cpu_sta_rx.pkt_wr_ptr;
> +
> +	/* get the sw read pointer */
> +	memset(&cpuxram_cpu_cfg_rx, 0, sizeof(cpuxram_cpu_cfg_rx));
> +	ca_reg_read(&cpuxram_cpu_cfg_rx, (u64)priv->ni_hv_base_addr,
> +		    NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
> +	sw_rx_rd_ptr = cpuxram_cpu_cfg_rx.pkt_rd_ptr;
> +
> +	debug("%s: NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0 = 0x%p, ", __func__,
> +	      priv->ni_hv_base_addr + NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET);
> +	debug("NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0 = 0x%p\n",
> +	      priv->ni_hv_base_addr + NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
> +	debug("%s : RX hw_wr_ptr = %d, sw_rd_ptr = %d\n",
> +	      __func__, hw_rx_wr_ptr, sw_rx_rd_ptr);
> +
> +	while (sw_rx_rd_ptr != hw_rx_wr_ptr) {
> +		/* Point to the absolute memory address of XRAM
> +		 * where read pointer is
> +		 */
> +		rx_xram_ptr = (u32 *)
> +			      ((unsigned long)NI_XRAM_BASE + sw_rx_rd_ptr * 8);
> +
> +		/* Wrap around if required */
> +		if (rx_xram_ptr >= (u32 *)(unsigned long)priv->rx_xram_end_adr)
> +			rx_xram_ptr = (u32 *)
> +				      (unsigned long)priv->rx_xram_base_adr;
> +
> +		/* Checking header XR. Do not update the read pointer yet */
> +		/* skip unused 32-bit in Header XR */
> +		rx_xram_ptr = rdwrptr_adv_one(rx_xram_ptr,
> +					      priv->rx_xram_base_adr,
> +					      priv->rx_xram_end_adr);
> +
> +		memcpy(&header_x, rx_xram_ptr, sizeof(header_x));
> +		next_link = header_x.next_link;
> +		/* Header XR [31:0] */
> +
> +		if (*rx_xram_ptr == 0xffffffff)
> +			printf("%s: XRAM Error !\n", __func__);
> +
> +		debug("%s : RX next link 0x%x\n", __func__, next_link);
> +		debug("%s : bytes_valid %x\n", __func__, header_x.bytes_valid);
> +
> +		if (header_x.ownership == 0) {
> +			/* point to Packet status [31:0] */
> +			rx_xram_ptr = rdwrptr_adv_one(rx_xram_ptr,
> +						      priv->rx_xram_base_adr,
> +						      priv->rx_xram_end_adr);
> +
> +			memcpy(&packet_status, rx_xram_ptr,
> +			       sizeof(rx_xram_ptr));
> +			debug("%s: packet status=0x%x\n",
> +			      __func__, REG_TO_U32(&packet_status));
> +			if (packet_status.valid == 0) {
> +				debug("%s: Invalid Packet !!, ", __func__);
> +				debug("next_link=%d\n", next_link);
> +
> +				/* Update the software read pointer */
> +				ca_reg_write(&next_link,
> +					     (u64)priv->ni_hv_base_addr,
> +					NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
> +				return 0;
> +			}
> +
> +			if (packet_status.drop ||
> +			    packet_status.runt ||
> +			    packet_status.oversize ||
> +			    packet_status.jabber ||
> +			    packet_status.crc_error ||
> +			    packet_status.jumbo) {
> +				debug("%s: Error Packet!!, ", __func__);
> +				debug("next_link=%d\n", next_link);
> +
> +				/* Update the software read pointer */
> +				ca_reg_write(&next_link,
> +					     (u64)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.packet_size > 1518) {
> +				debug("%s: Error Packet !! Packet size=%d, ",
> +				      __func__, packet_status.packet_size);
> +				debug("larger than 1518, next_link=%d\n",
> +				      next_link);
> +
> +				/* Update the software read pointer */
> +				ca_reg_write(&next_link,
> +					     (u64)priv->ni_hv_base_addr,
> +					NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
> +				return 0;
> +			}
> +
> +			rx_xram_ptr = rdwrptr_adv_one(rx_xram_ptr,
> +						      priv->rx_xram_base_adr,
> +						      priv->rx_xram_end_adr);
> +
> +			pktlen = packet_status.packet_size;
> +
> +			debug("%s : rx packet length = %d\n",
> +			      __func__, packet_status.packet_size);
> +
> +			rx_xram_ptr = rdwrptr_adv_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 */
> +
> +			debug("%s: packet data[]=", __func__);
> +
> +			for (loop = 0; loop <= pktlen / 4; loop++) {
> +				ptr = (u8 *)rx_xram_ptr;
> +				if (loop < 10)
> +					debug("[0x%x]-[0x%x]-[0x%x]-[0x%x]",
> +					      ptr[0], ptr[1], ptr[2], ptr[3]);
> +				*data_ptr++ = *rx_xram_ptr++;
> +				/* Wrap around if required */
> +				if (rx_xram_ptr >= (u32 *)
> +				    (unsigned long)priv->rx_xram_end_adr) {
> +					rx_xram_ptr = (u32 *)(unsigned long)
> +						       (priv->rx_xram_base_adr);
> +				}
> +			}
> +
> +			debug("\n");
> +			net_process_received_packet(net_rx_packets[index],
> +						    pktlen);
> +			if (++index >= PKTBUFSRX)
> +				index = 0;
> +			blk_num = net_rx_packets[index][0x2c] * 255 +
> +				net_rx_packets[index][0x2d];
> +			debug("%s: tftp block number=%d\n", __func__, blk_num);
> +
> +			/* Update the software read pointer */
> +			ca_reg_write(&next_link,
> +				     (u64)priv->ni_hv_base_addr,
> +				     NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
> +		}
> +
> +		/* get the hw write pointer */
> +		ca_reg_read(&cpuxram_cpu_sta_rx, (u64)priv->ni_hv_base_addr,
> +			    NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET);
> +		hw_rx_wr_ptr = cpuxram_cpu_sta_rx.pkt_wr_ptr;
> +
> +		/* get the sw read pointer */
> +		ca_reg_read(&sw_rx_rd_ptr, (u64)priv->ni_hv_base_addr,
> +			    NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
> +	}
> +	return 0;
> +}
> +
> +static int cortina_ni_send(struct udevice *dev, void *packet, int length)
> +{
> +	struct cortina_ni_priv *priv = dev_get_priv(dev);
> +	u32	hw_tx_rd_ptr = 0;
> +	u32	sw_tx_wr_ptr = 0;
> +	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	ca_crc32;
> +	struct NI_HEADER_X_T	hdr_xt;
> +	int		pad = 0;
> +	static unsigned char   pkt_buf[2048];
> +	u32	*data_ptr;
> +	struct NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t cpuxram_cpu_cfg_tx;
> +	u8 *ptr;
> +
> +	if (!packet || length > 2032)
> +		return -1;
> +
> +	/* Get the hardware read pointer */
> +	ca_reg_read(&hw_tx_rd_ptr, (u64)priv->ni_hv_base_addr,
> +		    NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET);
> +
> +	/* Get the software write pointer */
> +	ca_reg_read(&sw_tx_wr_ptr, (u64)priv->ni_hv_base_addr,
> +		    NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET);
> +
> +	debug("%s: NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0=0x%p, ",
> +	      __func__,
> +	      KSEG1_ATU_XLAT(priv->ni_hv_base_addr +
> +			     NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET));
> +	debug("NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0=0x%p\n",
> +	      KSEG1_ATU_XLAT(priv->ni_hv_base_addr +
> +			     NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET));
> +	debug("%s : hw_tx_rd_ptr = %d\n", __func__, hw_tx_rd_ptr);
> +	debug("%s : sw_tx_wr_ptr = %d\n", __func__, sw_tx_wr_ptr);
> +
> +	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[HEADER_A_SIZE], (const void *)packet, length);
> +
> +	pad = 64 - (length + 4);	/* if packet length < 60 */
> +	pad = (pad < 0) ? 0 : pad;
> +
> +	debug("%s: length=%d, pad=%d\n", __func__, length, pad);
> +
> +	new_pkt_len = length + pad;	/* new packet length */
> +
> +	pkt_buf_ptr = (unsigned char *)pkt_buf;
> +
> +	/* Calculate the CRC32, skip 8-byte header_A */
> +	ca_crc32 = crc32(0, (u8 *)(pkt_buf_ptr + HEADER_A_SIZE), new_pkt_len);
> +
> +	debug("%s: crc32 is 0x%x\n", __func__, ca_crc32);
> +	debug("%s: ~crc32 is 0x%x\n", __func__, ~ca_crc32);
> +	debug("%s: pkt len %d\n", __func__, new_pkt_len);
> +	/* should add 8-byte header_! */
> +	/* CRC will re-calculated by hardware */
> +	memcpy((pkt_buf_ptr + new_pkt_len + HEADER_A_SIZE),
> +	       (u8 *)(&ca_crc32), sizeof(ca_crc32));
> +	new_pkt_len = new_pkt_len + 4;	/* add CRC */
> +
> +	valid_bytes = new_pkt_len % 8;
> +	valid_bytes = valid_bytes ? valid_bytes : 0;
> +	debug("%s: valid_bytes %d\n", __func__, valid_bytes);
> +
> +	/* should add 8-byte headerA */
> +	next_link = sw_tx_wr_ptr +
> +		(new_pkt_len + 7 + HEADER_A_SIZE) / 8; /* for headr XT */
> +	/* add header */
> +	next_link = next_link + 1;
> +	/* Wrap around if required */
> +	if (next_link > priv->tx_xram_end) {
> +		next_link = priv->tx_xram_start +
> +			(next_link - (priv->tx_xram_end + 1));
> +	}
> +
> +	debug("%s: TX next_link %x\n", __func__, next_link);
> +	memset(&hdr_xt, 0, sizeof(hdr_xt));
> +	hdr_xt.ownership = 1;
> +	hdr_xt.bytes_valid = valid_bytes;
> +	hdr_xt.next_link = next_link;
> +
> +	tx_xram_ptr = (u32 *)((unsigned long)NI_XRAM_BASE + sw_tx_wr_ptr * 8);
> +
> +	/* Wrap around if required */
> +	if (tx_xram_ptr >= (u32 *)(unsigned long)priv->tx_xram_end_adr)
> +		tx_xram_ptr = (u32 *)(unsigned long)priv->tx_xram_base_adr;
> +
> +	tx_xram_ptr = rdwrptr_adv_one(tx_xram_ptr,
> +				      priv->tx_xram_base_adr,
> +				      priv->tx_xram_end_adr);
> +
> +	memcpy(tx_xram_ptr, &hdr_xt, sizeof(*tx_xram_ptr));
> +
> +	tx_xram_ptr = rdwrptr_adv_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;
> +	debug("%s: packet data[]=", __func__);
> +
> +	/* copy header_A to XRAM */
> +	for (loop = 0; loop <= (new_pkt_len + HEADER_A_SIZE) / 4; loop++) {
> +		ptr = (u8 *)data_ptr;
> +		if ((loop % 4) == 0)
> +			debug("\n");
> +		debug("[0x%x]-[0x%x]-[0x%x]-[0x%x]-",
> +		      ptr[0], ptr[1], ptr[2], ptr[3]);
> +
> +		*tx_xram_ptr = *data_ptr++;
> +		tx_xram_ptr = rdwrptr_adv_one(tx_xram_ptr,
> +					      priv->tx_xram_base_adr,
> +					      priv->tx_xram_end_adr);
> +	}
> +	debug("\n");
> +
> +	/* Publish the software write pointer */
> +	cpuxram_cpu_cfg_tx.pkt_wr_ptr = next_link;
> +	ca_reg_write(&cpuxram_cpu_cfg_tx,
> +		     (u64)priv->ni_hv_base_addr,
> +		     NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET);
> +
> +	return 0;
> +}
> +
> +static void cortina_ni_halt(struct udevice *netdev)
> +{
> +	/* Nothing to do for now. */
> +}
> +
> +#define GPHY_CAL_LEN	6
> +struct gphy_cal {
> +	u32 reg_off;
> +	u32 value;
> +};
> +
> +static struct gphy_cal gphy_cal_vlaues[GPHY_CAL_LEN] = {
> +	{0xf43380fc, 0xbcd},
> +	{0xf43380dc, 0xeeee},
> +	{0xf43380d8, 0xeeee},
> +	{0xf43380fc, 0xbce},
> +	{0xf43380c0, 0x7777},
> +	{0xf43380c4, 0x7777}
> +};
> +
> +__weak 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, 0);
> +			mdelay(50);
> +		}
> +	}
> +}
> +
> +static int ca_mdio_register(struct udevice *dev)
> +{
> +	struct cortina_ni_priv *priv = dev_get_priv(dev);
> +	struct mii_dev *mdio_bus = mdio_alloc();
> +	int ret;
> +
> +	if (!mdio_bus)
> +		return -ENOMEM;
> +
> +	mdio_bus->read = cortina_mdio_read;
> +	mdio_bus->write = cortina_mdio_write;
> +	snprintf(mdio_bus->name, sizeof(mdio_bus->name), dev->name);
> +
> +	mdio_bus->priv = (void *)priv;
> +
> +	ret = mdio_register(mdio_bus);
> +	if (ret)
> +		return ret;
> +
> +	priv->mdio_bus = mdio_bus;
> +	return 0;
> +}
> +
> +__weak void ca_rgmii_init(struct cortina_ni_priv *priv)
> +{
> +	/* hardware settings for RGMII port */
> +	struct GLOBAL_GLOBAL_CONFIG_t	glb_config;
> +	struct GLOBAL_IO_DRIVE_CONTROL_t io_drive_control;
> +
> +	/* Generating 25Mhz reference clock for switch */
> +	ca_reg_read(&glb_config, (u64)priv->glb_base_addr,
> +		    GLOBAL_GLOBAL_CONFIG_OFFSET);
> +	glb_config.refclk_sel = 0x01;
> +	glb_config.ext_reset = 0x01;
> +	ca_reg_write(&glb_config, (u64)priv->glb_base_addr,
> +		     GLOBAL_GLOBAL_CONFIG_OFFSET);
> +
> +	mdelay(20);
> +
> +	/* should do a external reset */
> +	ca_reg_read(&glb_config, (u64)priv->glb_base_addr,
> +		    GLOBAL_GLOBAL_CONFIG_OFFSET);
> +	glb_config.ext_reset = 0x0;
> +	ca_reg_write(&glb_config, (u64)priv->glb_base_addr,
> +		     GLOBAL_GLOBAL_CONFIG_OFFSET);
> +
> +	ca_reg_read(&io_drive_control, (u64)priv->glb_base_addr,
> +		    GLOBAL_IO_DRIVE_CONTROL_OFFSET);
> +	io_drive_control.gmac_mode = 2;
> +	io_drive_control.gmac_dn = 1;
> +	io_drive_control.gmac_dp = 1;
> +	ca_reg_write(&io_drive_control, (u64)priv->glb_base_addr,
> +		     GLOBAL_IO_DRIVE_CONTROL_OFFSET);
> +}
> +
> +int ca_eth_initialize(struct udevice *dev)
> +{
> +	struct cortina_ni_priv *priv;
> +	int ret, reg_value;
> +
> +	priv = dev_get_priv(dev);
> +	priv->rx_xram_base_adr	= NI_XRAM_BASE + (RX_BASE_ADDR * 8);
> +	priv->rx_xram_end_adr	= NI_XRAM_BASE + ((RX_TOP_ADDR + 1) * 8);
> +	priv->rx_xram_start	= RX_BASE_ADDR;
> +	priv->rx_xram_end	= RX_TOP_ADDR;
> +	priv->tx_xram_base_adr	= NI_XRAM_BASE + (TX_BASE_ADDR * 8);
> +	priv->tx_xram_end_adr	= NI_XRAM_BASE + ((TX_TOP_ADDR + 1) * 8);
> +	priv->tx_xram_start	= TX_BASE_ADDR;
> +	priv->tx_xram_end	= TX_TOP_ADDR;
> +
> +	curr_dev = dev;
> +	debug("%s: rx_base_addr:%x\t rx_top_addr %x\n",
> +	      __func__, priv->rx_xram_start, priv->rx_xram_end);
> +	debug("%s: tx_base_addr:%x\t tx_top_addr %x\n",
> +	      __func__, priv->tx_xram_start, priv->tx_xram_end);
> +	debug("%s: rx physical start address = %x end address = %x\n",
> +	      __func__, priv->rx_xram_base_adr, priv->rx_xram_end_adr);
> +	debug("%s: tx physical start address = %x end address = %x\n",
> +	      __func__, priv->tx_xram_base_adr, priv->tx_xram_end_adr);
> +
> +	/* MDIO register */
> +	ret = ca_mdio_register(dev);
> +	if (ret)
> +		return ret;
> +
> +	/* set MDIO pre-scale value */
> +	ca_reg_read(&reg_value, (u64)priv->per_mdio_base_addr,
> +		    PER_MDIO_CFG_OFFSET);
> +	reg_value = reg_value | 0x00280000;
> +	ca_reg_write(&reg_value, (u64)priv->per_mdio_base_addr,
> +		     PER_MDIO_CFG_OFFSET);
> +
> +	ca_phy_probe(dev);
> +	priv->phydev->addr = port_to_phyaddr(active_port);
> +
> +	ca_ni_led(active_port, CA_LED_ON);
> +
> +	cortina_ni_reset();
> +
> +	printf("%s: active_port=%d, phy_addr=%d\n",
> +	       __func__, active_port, priv->phydev->addr);
> +	printf("%s: phy_id=0x%x, phy_id & PHY_ID_MASK=0x%x\n", __func__,
> +	       priv->phydev->phy_id, priv->phydev->phy_id & 0xFFFFFFF0);
> +
> +	/* parsing ethaddr and set to NI registers. */
> +	ca_ni_setup_mac_addr();
> +
> +#ifdef MIIPHY_REGISTER
> +	/* the phy_read and phy_write
> +	 * should meet the proto type of miiphy_register
> +	 */
> +	miiphy_register(dev->name, ca_miiphy_read, ca_miiphy_write);
> +#endif
> +
> +	ca_rgmii_init(priv);
> +
> +	/* do internal gphy calibration */
> +	do_internal_gphy_cal();
> +	return 0;
> +}
> +
> +static int cortina_eth_start(struct udevice *dev)
> +{
> +	return cortina_ni_init(dev);
> +}
> +
> +static int cortina_eth_send(struct udevice *dev, void *packet, int length)
> +{
> +	return cortina_ni_send(dev, packet, length);
> +}
> +
> +static int cortina_eth_recv(struct udevice *dev, int flags, uchar **packetp)
> +{
> +	return cortina_ni_recv(dev);
> +}
> +
> +static void cortina_eth_stop(struct udevice *dev)
> +{
> +	cortina_ni_halt(dev);
> +}
> +
> +static int cortina_eth_probe(struct udevice *dev)
> +{
> +	return ca_eth_initialize(dev);
> +}
> +
> +static int ca_ni_ofdata_to_platdata(struct udevice *dev)
> +{
> +	struct cortina_ni_priv *priv = dev_get_priv(dev);
> +
> +	priv->glb_base_addr = dev_remap_addr_index(dev, 0);
> +	if (!priv->glb_base_addr)
> +		return -ENOENT;
> +	printf("%s: priv->glb_base_addr for index 0 is 0x%p\n",
> +	       __func__, priv->glb_base_addr);
> +
> +	priv->per_mdio_base_addr = dev_remap_addr_index(dev, 1);
> +	if (!priv->per_mdio_base_addr)
> +		return -ENOENT;
> +	printf("%s: priv->per_mdio_base_addr for index 1 is 0x%p\n",
> +	       __func__, priv->per_mdio_base_addr);
> +
> +	priv->ni_hv_base_addr = dev_remap_addr_index(dev, 2);
> +	if (!priv->ni_hv_base_addr)
> +		return -ENOENT;
> +	printf("%s: priv->ni_hv_base_addr for index 2 is 0x%p\n",
> +	       __func__, priv->ni_hv_base_addr);
> +
> +	return 0;
> +}
> +
> +static const struct eth_ops cortina_eth_ops = {
> +	.start  = cortina_eth_start,
> +	.send   = cortina_eth_send,
> +	.recv   = cortina_eth_recv,
> +	.stop   = cortina_eth_stop,
> +};
> +
> +static const struct udevice_id cortina_eth_ids[] = {
> +	{ .compatible = "eth_cortina" },
> +	{ }
> +};
> +
> +U_BOOT_DRIVER(eth_cortina) = {
> +	.name   = "eth_cortina",
> +	.id     = UCLASS_ETH,
> +	.of_match = cortina_eth_ids,
> +	.probe  = cortina_eth_probe,
> +	.ops    = &cortina_eth_ops,
> +	.priv_auto_alloc_size = sizeof(struct cortina_ni_priv),
> +	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
> +	.ofdata_to_platdata = ca_ni_ofdata_to_platdata,
> +};
> diff --git a/drivers/net/cortina_ni.h b/drivers/net/cortina_ni.h
> new file mode 100644
> index 0000000..ff9a396
> --- /dev/null
> +++ b/drivers/net/cortina_ni.h
> @@ -0,0 +1,435 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +
> +/*
> + * Copyright (C) 2020 Cortina Access Inc.
> + * Author: Aaron Tseng <aaron.tseng@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 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
> +
> +/* 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 NI_XRAM_BASE                    0xF4500000
> +
> +enum ca_status_t {
> +	CA_E_ERROR          = -1,
> +	CA_E_OK             = 0x0,
> +	CA_E_RESOURCE       = 0x1,
> +	CA_E_PARAM          = 0x2,
> +	CA_E_NOT_FOUND      = 0x3,
> +	CA_E_CONFLICT       = 0x4,
> +	CA_E_TIMEOUT        = 0x5,
> +	CA_E_INTERNAL       = 0x6,
> +	CA_E_NOT_SUPPORT    = 0x7,
> +	CA_E_CONFIG         = 0x8,
> +	CA_E_UNAVAIL        = 0x9,
> +	CA_E_MEMORY         = 0xa,
> +	CA_E_BUSY           = 0xb,
> +	CA_E_FULL           = 0xc,
> +	CA_E_EMPTY          = 0xd,
> +	CA_E_EXISTS         = 0xe,
> +	CA_E_DEV            = 0xf,
> +	CA_E_PORT           = 0x10,
> +	CA_E_LLID           = 0x11,
> +	CA_E_VLAN           = 0x12,
> +	CA_E_INIT           = 0x13,
> +	CA_E_INTF           = 0x14,
> +	CA_E_NEXTHOP        = 0x15,
> +	CA_E_ROUTE          = 0x16,
> +	CA_E_DB_CHANGED     = 0x17,
> +	CA_E_INACTIVE       = 0x18,
> +	CA_E_ALREADY_SET    = 0x19,
> +};
> +
> +#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;
> +	void __iomem    *glb_base_addr;
> +	void __iomem    *per_mdio_base_addr;
> +	void __iomem    *ni_hv_base_addr;
> +
> +	struct mii_dev *mdio_bus;
> +	struct phy_device *phydev;
> +	int phy_interface;
> +};
> +
> +struct NI_HEADER_X_T {
> +	unsigned int next_link		: 10; /* bits  9: 0 */
> +	unsigned int bytes_valid	:  4; /* bits 13:10 */
> +	unsigned int reserved		: 16; /* bits 29:14 */
> +	unsigned int hdr_a		:  1; /* bits 30:30 */
> +	unsigned int ownership		:  1; /* bits 31:31 */
> +};
> +
> +struct NI_PACKET_STATUS {
> +	unsigned int packet_size       : 14; /* bits 13:0 */
> +	unsigned int byte_valid        :  4; /* bits 17:14 */
> +	unsigned int pfc               :  1; /* bits 18:18 */
> +	unsigned int valid             :  1; /* bits 19:19 */
> +	unsigned int drop              :  1; /* bits 20:20 */
> +	unsigned int runt              :  1; /* bits 21:21 */
> +	unsigned int oversize          :  1; /* bits 22:22 */
> +	unsigned int jumbo             :  1; /* bits 23:23 */
> +	unsigned int link_status       :  1; /* bits 24:24 */
> +	unsigned int jabber            :  1; /* bits 25:25 */
> +	unsigned int crc_error         :  1; /* bits 26:26 */
> +	unsigned int pause             :  1; /* bits 27:27 */
> +	unsigned int oam               :  1; /* bits 28:28 */
> +	unsigned int unknown_opcode    :  1; /* bits 29:29 */
> +	unsigned int multicast         :  1; /* bits 30:30 */
> +	unsigned int broadcast         :  1; /* bits 31:31 */
> +};
> +
> +struct NI_MDIO_OPER_T {
> +	unsigned int reserved       : 2; /* bits  1:0 */
> +	unsigned int reg_off        : 5; /* bits  6:2 */
> +	unsigned int phy_addr       : 5; /* bits 11:7 */
> +	unsigned int reg_base       : 20; /* bits 31:12 */
> +};
> +
> +enum ca_port_t {
> +	NI_PORT_0 = 0,
> +	NI_PORT_1,
> +	NI_PORT_2,
> +	NI_PORT_3,
> +	NI_PORT_4,
> +	NI_PORT_5,
> +	NI_PORT_MAX,
> +};
> +
> +struct port_map_s {
> +	int active_port;
> +	int phy_addr;
> +};
> +
> +extern struct port_map_s port_map[NI_PORT_MAX];
> +extern int active_port;
> +
> +#define __MDIO_WR_FLAG				(0)
> +#define __MDIO_RD_FLAG				(1)
> +#define __MDIO_ACCESS_TIMEOUT			(1000000)
> +#define CA_MDIO_ADDR_MIN			(1)
> +#define CA_MDIO_ADDR_MAX			(31)
> +
> +#endif /* !__ASSEMBLER__ */
> +
> +/* Copy from registers.h */
> +struct NI_HV_GLB_MAC_ADDR_CFG0_t {
> +	unsigned int mac_addr0            : 32; /* bits 31:0 */
> +};
> +
> +struct NI_HV_GLB_MAC_ADDR_CFG1_t {
> +	unsigned int mac_addr1            :  8; /* bits 7:0 */
> +	unsigned int rsrvd1               : 24;
> +};
> +
> +struct NI_HV_PT_PORT_STATIC_CFG_t {
> +	unsigned int int_cfg              :  4; /* bits 3:0 */
> +	unsigned int phy_mode             :  1; /* bits 4:4 */
> +	unsigned int rmii_clksrc          :  1; /* bits 5:5 */
> +	unsigned int inv_clk_in           :  1; /* bits 6:6 */
> +	unsigned int inv_clk_out          :  1; /* bits 7:7 */
> +	unsigned int inv_rxclk_out        :  1; /* bits 8:8 */
> +	unsigned int tx_use_gefifo        :  1; /* bits 9:9 */
> +	unsigned int smii_tx_stat         :  1; /* bits 10:10 */
> +	unsigned int crs_polarity         :  1; /* bits 11:11 */
> +	unsigned int lpbk_mode            :  2; /* bits 13:12 */
> +	unsigned int gmii_like_half_duplex_en :  1; /* bits 14:14 */
> +	unsigned int sup_tx_to_rx_lpbk_data :  1; /* bits 15:15 */
> +	unsigned int rsrvd1               :  8;
> +	unsigned int mac_addr6            :  8; /* bits 31:24 */
> +};
> +
> +struct NI_HV_XRAM_CPUXRAM_CFG_t {
> +	unsigned int rx_0_cpu_pkt_dis     :  1; /* bits 0:0 */
> +	unsigned int rsrvd1               :  8;
> +	unsigned int tx_0_cpu_pkt_dis     :  1; /* bits 9:9 */
> +	unsigned int rsrvd2               :  1;
> +	unsigned int rx_x_drop_err_pkt    :  1; /* bits 11:11 */
> +	unsigned int xram_mgmt_dis_drop_ovsz_pkt :  1; /* bits 12:12 */
> +	unsigned int xram_mgmt_term_large_pkt :  1; /* bits 13:13 */
> +	unsigned int xram_mgmt_promisc_mode :  2; /* bits 15:14 */
> +	unsigned int xram_cntr_debug_mode :  1; /* bits 16:16 */
> +	unsigned int xram_cntr_op_code    :  2; /* bits 18:17 */
> +	unsigned int rsrvd3               :  2;
> +	unsigned int xram_rx_mgmtfifo_srst :  1; /* bits 21:21 */
> +	unsigned int xram_dma_fifo_srst   :  1; /* bits 22:22 */
> +	unsigned int rsrvd4               :  9;
> +};
> +
> +struct NI_HV_PT_RXMAC_CFG_t {
> +	unsigned int rx_en                :  1; /* bits 0:0 */
> +	unsigned int rsrvd1               :  7;
> +	unsigned int rx_flow_disable      :  1; /* bits 8:8 */
> +	unsigned int rsrvd2               :  3;
> +	unsigned int rx_flow_to_tx_en     :  1; /* bits 12:12 */
> +	unsigned int rx_pfc_disable       :  1; /* bits 13:13 */
> +	unsigned int rsrvd3               : 15;
> +	unsigned int send_pg_data         :  1; /* bits 29:29 */
> +	unsigned int rsrvd4               :  2;
> +};
> +
> +struct NI_HV_PT_TXMAC_CFG_t {
> +	unsigned int tx_en                :  1; /* bits 0:0 */
> +	unsigned int rsrvd1               :  7;
> +	unsigned int mac_crc_calc_en      :  1; /* bits 8:8 */
> +	unsigned int tx_ipg_sel           :  3; /* bits 11:9 */
> +	unsigned int tx_flow_disable      :  1; /* bits 12:12 */
> +	unsigned int tx_drain             :  1; /* bits 13:13 */
> +	unsigned int tx_pfc_disable       :  1; /* bits 14:14 */
> +	unsigned int tx_pau_sel           :  2; /* bits 16:15 */
> +	unsigned int rsrvd2               :  9;
> +	unsigned int tx_auto_xon          :  1; /* bits 26:26 */
> +	unsigned int rsrvd3               :  1;
> +	unsigned int pass_thru_hdr        :  1; /* bits 28:28 */
> +	unsigned int rsrvd4               :  3;
> +};
> +
> +struct NI_HV_GLB_INTF_RST_CONFIG_t {
> +	unsigned int intf_rst_p0          :  1; /* bits 0:0 */
> +	unsigned int intf_rst_p1          :  1; /* bits 1:1 */
> +	unsigned int intf_rst_p2          :  1; /* bits 2:2 */
> +	unsigned int intf_rst_p3          :  1; /* bits 3:3 */
> +	unsigned int intf_rst_p4          :  1; /* bits 4:4 */
> +	unsigned int mac_rx_rst_p0        :  1; /* bits 5:5 */
> +	unsigned int mac_rx_rst_p1        :  1; /* bits 6:6 */
> +	unsigned int mac_rx_rst_p2        :  1; /* bits 7:7 */
> +	unsigned int mac_rx_rst_p3        :  1; /* bits 8:8 */
> +	unsigned int mac_rx_rst_p4        :  1; /* bits 9:9 */
> +	unsigned int mac_tx_rst_p0        :  1; /* bits 10:10 */
> +	unsigned int mac_tx_rst_p1        :  1; /* bits 11:11 */
> +	unsigned int mac_tx_rst_p2        :  1; /* bits 12:12 */
> +	unsigned int mac_tx_rst_p3        :  1; /* bits 13:13 */
> +	unsigned int mac_tx_rst_p4        :  1; /* bits 14:14 */
> +	unsigned int port_rst_p5          :  1; /* bits 15:15 */
> +	unsigned int pcs_rst_p6           :  1; /* bits 16:16 */
> +	unsigned int pcs_rst_p7           :  1; /* bits 17:17 */
> +	unsigned int mac_rst_p6           :  1; /* bits 18:18 */
> +	unsigned int mac_rst_p7           :  1; /* bits 19:19 */
> +	unsigned int rsrvd1               : 12;
> +};
> +
> +struct NI_HV_GLB_STATIC_CFG_t {
> +	unsigned int port_to_cpu          :  4; /* bits 3:0 */
> +	unsigned int mgmt_pt_to_fe_also   :  1; /* bits 4:4 */
> +	unsigned int txcrc_chk_en         :  1; /* bits 5:5 */
> +	unsigned int p4_rgmii_tx_clk_phase :  2; /* bits 7:6 */
> +	unsigned int p4_rgmii_tx_data_order :  1; /* bits 8:8 */
> +	unsigned int rsrvd1               :  7;
> +	unsigned int rxmib_mode           :  1; /* bits 16:16 */
> +	unsigned int txmib_mode           :  1; /* bits 17:17 */
> +	unsigned int eth_sch_rdy_pkt      :  1; /* bits 18:18 */
> +	unsigned int rsrvd2               :  1;
> +	unsigned int rxaui_mode           :  2; /* bits 21:20 */
> +	unsigned int rxaui_sigdet         :  2; /* bits 23:22 */
> +	unsigned int cnt_op_mode          :  3; /* bits 26:24 */
> +	unsigned int rsrvd3               :  5;
> +};
> +
> +struct GLOBAL_BLOCK_RESET_t {
> +	unsigned int reset_ni             :  1; /* bits 0:0 */
> +	unsigned int reset_l2fe           :  1; /* bits 1:1 */
> +	unsigned int reset_l2tm           :  1; /* bits 2:2 */
> +	unsigned int reset_l3fe           :  1; /* bits 3:3 */
> +	unsigned int reset_sdram          :  1; /* bits 4:4 */
> +	unsigned int reset_tqm            :  1; /* bits 5:5 */
> +	unsigned int reset_pcie0          :  1; /* bits 6:6 */
> +	unsigned int reset_pcie1          :  1; /* bits 7:7 */
> +	unsigned int reset_pcie2          :  1; /* bits 8:8 */
> +	unsigned int reset_sata           :  1; /* bits 9:9 */
> +	unsigned int reset_gic400         :  1; /* bits 10:10 */
> +	unsigned int rsrvd1               :  2;
> +	unsigned int reset_usb            :  1; /* bits 13:13 */
> +	unsigned int reset_flash          :  1; /* bits 14:14 */
> +	unsigned int reset_per            :  1; /* bits 15:15 */
> +	unsigned int reset_dma            :  1; /* bits 16:16 */
> +	unsigned int reset_rtc            :  1; /* bits 17:17 */
> +	unsigned int reset_pe0            :  1; /* bits 18:18 */
> +	unsigned int reset_pe1            :  1; /* bits 19:19 */
> +	unsigned int reset_rcpu0          :  1; /* bits 20:20 */
> +	unsigned int reset_rcpu1          :  1; /* bits 21:21 */
> +	unsigned int reset_sadb           :  1; /* bits 22:22 */
> +	unsigned int rsrvd2               :  1;
> +	unsigned int reset_rcrypto        :  1; /* bits 24:24 */
> +	unsigned int reset_ldma           :  1; /* bits 25:25 */
> +	unsigned int reset_fbm            :  1; /* bits 26:26 */
> +	unsigned int reset_eaxi           :  1; /* bits 27:27 */
> +	unsigned int reset_sd             :  1; /* bits 28:28 */
> +	unsigned int reset_otprom         :  1; /* bits 29:29 */
> +	unsigned int rsrvd3               :  2;
> +};
> +
> +struct PER_MDIO_ADDR_t {
> +	unsigned int mdio_addr            :  5; /* bits 4:0 */
> +	unsigned int rsrvd1               :  3;
> +	unsigned int mdio_offset          :  5; /* bits 12:8 */
> +	unsigned int rsrvd2               :  2;
> +	unsigned int mdio_rd_wr           :  1; /* bits 15:15 */
> +	unsigned int mdio_st              :  1; /* bits 16:16 */
> +	unsigned int rsrvd3               :  1;
> +	unsigned int mdio_op              :  2; /* bits 19:18 */
> +	unsigned int rsrvd4               : 12;
> +};
> +
> +struct PER_MDIO_CTRL_t {
> +	unsigned int mdiodone             :  1; /* bits 0:0 */
> +	unsigned int rsrvd1               :  6;
> +	unsigned int mdiostart            :  1; /* bits 7:7 */
> +	unsigned int rsrvd2               : 24;
> +};
> +
> +struct PER_MDIO_RDDATA_t {
> +	unsigned int mdio_rddata          : 16; /* bits 15:0 */
> +	unsigned int rsrvd1               : 16;
> +};
> +
> +/*
> + * XRAM
> + */
> +
> +struct NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t {
> +	unsigned int rx_base_addr         : 10; /* bits 9:0 */
> +	unsigned int rsrvd1               :  6;
> +	unsigned int rx_top_addr          : 10; /* bits 25:16 */
> +	unsigned int rsrvd2               :  6;
> +};
> +
> +struct NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t {
> +	unsigned int tx_base_addr         : 10; /* bits 9:0 */
> +	unsigned int rsrvd1               :  6;
> +	unsigned int tx_top_addr          : 10; /* bits 25:16 */
> +	unsigned int rsrvd2               :  6;
> +};
> +
> +struct NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t {
> +	unsigned int pkt_wr_ptr           : 10; /* bits 9:0 */
> +	unsigned int rsrvd1               :  5;
> +	unsigned int int_colsc_thresh_reached :  1; /* bits 15:15 */
> +	unsigned int rsrvd2               : 16;
> +};
> +
> +struct NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t {
> +	unsigned int pkt_rd_ptr           : 10; /* bits 9:0 */
> +	unsigned int rsrvd1               : 22;
> +};
> +
> +struct NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t {
> +	unsigned int pkt_wr_ptr           : 10; /* bits 9:0 */
> +	unsigned int rsrvd1               : 22;
> +};
> +
> +struct GLOBAL_GLOBAL_CONFIG_t {
> +	unsigned int rsrvd1               :  4;
> +	unsigned int wd_reset_subsys_enable :  1; /* bits 4:4 */
> +	unsigned int rsrvd2               :  1;
> +	unsigned int wd_reset_all_blocks  :  1; /* bits 6:6 */
> +	unsigned int wd_reset_remap       :  1; /* bits 7:7 */
> +	unsigned int wd_reset_ext_reset   :  1; /* bits 8:8 */
> +	unsigned int ext_reset            :  1; /* bits 9:9 */
> +	unsigned int cfg_pcie_0_clken     :  1; /* bits 10:10 */
> +	unsigned int cfg_sata_clken       :  1; /* bits 11:11 */
> +	unsigned int cfg_pcie_1_clken     :  1; /* bits 12:12 */
> +	unsigned int rsrvd3               :  1;
> +	unsigned int cfg_pcie_2_clken     :  1; /* bits 14:14 */
> +	unsigned int rsrvd4               :  2;
> +	unsigned int ext_eth_refclk       :  1; /* bits 17:17 */
> +	unsigned int refclk_sel           :  2; /* bits 19:18 */
> +	unsigned int rsrvd5               :  7;
> +	unsigned int l3fe_pd              :  1; /* bits 27:27 */
> +	unsigned int offload0_pd          :  1; /* bits 28:28 */
> +	unsigned int offload1_pd          :  1; /* bits 29:29 */
> +	unsigned int crypto_pd            :  1; /* bits 30:30 */
> +	unsigned int core_pd              :  1; /* bits 31:31 */
> +};
> +
> +struct GLOBAL_IO_DRIVE_CONTROL_t {
> +	unsigned int gmac_dp              :  3; /* bits 2:0 */
> +	unsigned int gmac_dn              :  3; /* bits 5:3 */
> +	unsigned int gmac_mode            :  2; /* bits 7:6 */
> +	unsigned int gmac_ds              :  1; /* bits 8:8 */
> +	unsigned int flash_ds             :  1; /* bits 9:9 */
> +	unsigned int nu_ds                :  1; /* bits 10:10 */
> +	unsigned int ssp_ds               :  1; /* bits 11:11 */
> +	unsigned int spi_ds               :  1; /* bits 12:12 */
> +	unsigned int gpio_ds              :  1; /* bits 13:13 */
> +	unsigned int misc_ds              :  1; /* bits 14:14 */
> +	unsigned int eaxi_ds              :  1; /* bits 15:15 */
> +	unsigned int sd_ds                :  8; /* bits 23:16 */
> +	unsigned int rsrvd1               :  8;
> +};
> +
> +struct NI_HV_GLB_INIT_DONE_t {
> +	unsigned int rsrvd1               :  1;
> +	unsigned int ni_init_done         :  1; /* bits 1:1 */
> +	unsigned int rsrvd2               : 30;
> +};
> +
> +struct NI_HV_PT_PORT_GLB_CFG_t {
> +	unsigned int speed                :  1; /* bits 0:0 */
> +	unsigned int duplex               :  1; /* bits 1:1 */
> +	unsigned int link_status          :  1; /* bits 2:2 */
> +	unsigned int link_stat_mask       :  1; /* bits 3:3 */
> +	unsigned int rsrvd1               :  7;
> +	unsigned int power_dwn_rx         :  1; /* bits 11:11 */
> +	unsigned int power_dwn_tx         :  1; /* bits 12:12 */
> +	unsigned int tx_intf_lp_time      :  1; /* bits 13:13 */
> +	unsigned int rsrvd2               : 18;
> +};
> +
> +#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
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v2 1/3] net: cortina_ni: Add eth support for Cortina Access CAxxxx SoCs
  2020-09-10 23:18 ` [PATCH v2 1/3] net: cortina_ni: Add eth support for Cortina Access CAxxxx SoCs Alex Nemirovsky
@ 2020-09-10 23:54   ` Tom Rini
  2020-09-10 23:56     ` Alex Nemirovsky
  2020-09-24  1:00     ` Alex Nemirovsky
  0 siblings, 2 replies; 9+ messages in thread
From: Tom Rini @ 2020-09-10 23:54 UTC (permalink / raw)
  To: u-boot

On Thu, Sep 10, 2020 at 11:18:46PM +0000, Alex Nemirovsky wrote:

> bump.

Sorry, I've meant to reply on some of this.  Please fix the usage of
ca_status_t and use the normal errno values.  Make sure that
checkpatch.pl is happy about formatting, etc.  Please also check for
existing standard structs, etc, that can be used rather than creating
new ones.

> 
> > On Jul 30, 2020, at 12:05 PM, Alex Nemirovsky <alex.nemirovsky@cortina-access.com> wrote:
> > 
> > From: Aaron Tseng <aaron.tseng@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.tseng@cortina-access.com>
> > Signed-off-by: Alex Nemirovsky <alex.nemirovsky@cortina-access.com>
> > Signed-off-by: Abbie Chang <abbie.chang@cortina-access.com>
> > 
> > CC: Joe Hershberger <joe.hershberger@ni.com>
> > CC: Abbie Chang <abbie.chang@Cortina-Access.com>
> > CC: Tom Rini <trini@konsulko.com>
> > 
> > ---
> > 
> > Changes in v2:
> > - clean up old debug code
> > - reference CRC functions already provided in u-boot core
> > - remove unused code, ex: CA_IN/CA_OUT
> > - refactor the design of register read/write, union -> struct
> > - remove platform dependent code
> > 
> > MAINTAINERS              |    4 +
> > drivers/net/Kconfig      |    7 +
> > drivers/net/Makefile     |    1 +
> > drivers/net/cortina_ni.c | 1168 ++++++++++++++++++++++++++++++++++++++++++++++
> > drivers/net/cortina_ni.h |  435 +++++++++++++++++
> > 5 files changed, 1615 insertions(+)
> > create mode 100644 drivers/net/cortina_ni.c
> > create mode 100644 drivers/net/cortina_ni.h
> > 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index db8cecd..272caca 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -182,6 +182,8 @@ F:	drivers/gpio/cortina_gpio.c
> > F:	drivers/watchdog/cortina_wdt.c
> > F:	drivers/serial/serial_cortina.c
> > F:	drivers/mmc/ca_dw_mmc.c
> > +F:	drivers/net/cortina_ni.c
> > +F:	drivers/net/cortina_ni.h
> > 
> > ARM/CZ.NIC TURRIS MOX SUPPORT
> > M:	Marek Behun <marek.behun@nic.cz>
> > @@ -738,6 +740,8 @@ F:	drivers/gpio/cortina_gpio.c
> > F:	drivers/watchdog/cortina_wdt.c
> > F:	drivers/serial/serial_cortina.c
> > F:	drivers/mmc/ca_dw_mmc.c
> > +F:	drivers/net/cortina_ni.c
> > +F:	drivers/net/cortina_ni.h
> > 
> > MIPS MSCC
> > M:	Gregory CLEMENT <gregory.clement@bootlin.com>
> > diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> > index bb23f73..616d238 100644
> > --- a/drivers/net/Kconfig
> > +++ b/drivers/net/Kconfig
> > @@ -149,6 +149,13 @@ config BCMGENET
> > 	help
> > 	  This driver supports the BCMGENET Ethernet MAC.
> > 
> > +config CORTINA_NI_ENET
> > +	bool "Cortina-Access Ethernet driver"
> > +	depends on DM_ETH && CORTINA_PLATFORM
> > +	help
> > +	  This driver supports the Cortina-Access Ethernet MAC for
> > +	  all supported CAxxxx SoCs.
> > +
> > config DWC_ETH_QOS
> > 	bool "Synopsys DWC Ethernet QOS device support"
> > 	depends on DM_ETH
> > diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> > index 383ed1c..1d6ec4f 100644
> > --- a/drivers/net/Makefile
> > +++ b/drivers/net/Makefile
> > @@ -14,6 +14,7 @@ obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
> > obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
> > obj-$(CONFIG_BCM_SF2_ETH_GMAC) += bcm-sf2-eth-gmac.o
> > obj-$(CONFIG_CALXEDA_XGMAC) += calxedaxgmac.o
> > +obj-$(CONFIG_CORTINA_NI_ENET) += cortina_ni.o
> > obj-$(CONFIG_CS8900) += cs8900.o
> > obj-$(CONFIG_TULIP) += dc2114x.o
> > obj-$(CONFIG_ETH_DESIGNWARE) += designware.o
> > diff --git a/drivers/net/cortina_ni.c b/drivers/net/cortina_ni.c
> > new file mode 100644
> > index 0000000..7acfa6a
> > --- /dev/null
> > +++ b/drivers/net/cortina_ni.c
> > @@ -0,0 +1,1168 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +
> > +/*
> > + * Copyright (C) 2020 Cortina Access Inc.
> > + * Author: Aaron Tseng <aaron.tseng@cortina-access.com>
> > + *
> > + * Ethernet MAC Driver for all supported CAxxxx SoCs
> > + */
> > +
> > +#include <common.h>
> > +#include <command.h>
> > +#include <malloc.h>
> > +#include <net.h>
> > +#include <miiphy.h>
> > +#include <env.h>
> > +#include <linux/delay.h>
> > +#include <u-boot/crc.h>
> > +#include <led.h>
> > +
> > +#include "cortina_ni.h"
> > +
> > +#define HEADER_A_SIZE	8
> > +
> > +enum ca_led_state_t {
> > +	CA_LED_OFF = 0,
> > +	CA_LED_ON = 1,
> > +};
> > +
> > +static struct udevice   *curr_dev;
> > +static int ca_ni_ofdata_to_platdata(struct udevice *dev);
> > +
> > +static u32 *rdwrptr_adv_one(u32 *x, unsigned long base, unsigned long max)
> > +{
> > +	if (x + 1 >= (u32 *)max)
> > +		return (u32 *)base;
> > +	else
> > +		return (x + 1);
> > +}
> > +
> > +static int phyaddr_to_port(int phy_addr)
> > +{
> > +	int idx;
> > +
> > +	for (idx = 0; idx < NI_PORT_MAX; idx++)
> > +		if (phy_addr == port_map[idx].phy_addr)
> > +			return port_map[idx].active_port;
> > +	return 0;
> > +}
> > +
> > +static int port_to_phyaddr(int active_port)
> > +{
> > +	int idx;
> > +
> > +	for (idx = 0; idx < NI_PORT_MAX; idx++)
> > +		if (active_port == port_map[idx].active_port)
> > +			return port_map[idx].phy_addr;
> > +	return 0;
> > +}
> > +
> > +static u32 REG_TO_U32(void *reg)
> > +{
> > +	return *(u32 *)reg;
> > +}
> > +
> > +static void ca_reg_read(void *reg, u64 base, u64 offset)
> > +{
> > +	u32 *val = (u32 *)reg;
> > +
> > +	*val = readl(KSEG1_ATU_XLAT(base + offset));
> > +}
> > +
> > +static void ca_reg_write(void *reg, u64 base, u64 offset)
> > +{
> > +	u32 val = *(u32 *)reg;
> > +
> > +	writel(val, KSEG1_ATU_XLAT(base + offset));
> > +}
> > +
> > +static enum ca_status_t ca_mdio_write_rgmii(unsigned int addr,
> > +					    unsigned int offset,
> > +					    unsigned short data)
> > +{
> > +	struct PER_MDIO_ADDR_t  mdio_addr;
> > +	struct PER_MDIO_CTRL_t  mdio_ctrl;
> > +	/* up to 10000 cycles*/
> > +	unsigned int      loop_wait = __MDIO_ACCESS_TIMEOUT;
> > +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
> > +
> > +	memset(&mdio_addr, 0, sizeof(mdio_addr));
> > +	mdio_addr.mdio_addr   = addr;
> > +	mdio_addr.mdio_offset = offset;
> > +	mdio_addr.mdio_rd_wr  = __MDIO_WR_FLAG;
> > +	ca_reg_write(&mdio_addr, (u64)priv->per_mdio_base_addr,
> > +		     PER_MDIO_ADDR_OFFSET);
> > +	ca_reg_write(&data, (u64)priv->per_mdio_base_addr,
> > +		     PER_MDIO_WRDATA_OFFSET);
> > +
> > +	debug("%s: mdio_addr=0x%x\n", __func__, REG_TO_U32(&mdio_addr));
> > +
> > +	memset(&mdio_ctrl, 0, sizeof(mdio_ctrl));
> > +	mdio_ctrl.mdiostart = 1;
> > +	ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
> > +		     PER_MDIO_CTRL_OFFSET);
> > +
> > +	debug("%s: phy_addr=%d, offset=%d, data=0x%x\n",
> > +	      __func__, addr, offset, data);
> > +
> > +	do {
> > +		ca_reg_read(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
> > +			    PER_MDIO_CTRL_OFFSET);
> > +		if (mdio_ctrl.mdiodone) {
> > +			ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
> > +				     PER_MDIO_CTRL_OFFSET);
> > +			return CA_E_OK;
> > +		}
> > +	} while (--loop_wait);
> > +
> > +	printf("%s: PHY write timeout!!!\n", __func__);
> > +	return CA_E_TIMEOUT;
> > +}
> > +
> > +enum ca_status_t ca_mdio_write(unsigned int     addr,
> > +			       unsigned int     offset,
> > +			       unsigned short   data)
> > +{
> > +	u32 reg_addr, reg_val;
> > +	struct NI_MDIO_OPER_T mdio_oper;
> > +
> > +	/* support range: 1~31*/
> > +	if (addr < CA_MDIO_ADDR_MIN || addr > CA_MDIO_ADDR_MAX)
> > +		return CA_E_PARAM;
> > +
> > +	/* the phy addr 5 is connect to RGMII */
> > +	if (addr >= 5)
> > +		return ca_mdio_write_rgmii(addr, offset, data);
> > +
> > +	memset(&mdio_oper, 0, sizeof(mdio_oper));
> > +	mdio_oper.reg_off = offset;
> > +	mdio_oper.phy_addr = addr;
> > +	mdio_oper.reg_base = CA_NI_MDIO_REG_BASE;
> > +	reg_val = data;
> > +	memcpy(&reg_addr, &mdio_oper, sizeof(reg_addr));
> > +	ca_reg_write(&reg_val, (u64)reg_addr, 0);
> > +
> > +	debug("%s: mdio_oper=0x%x, data=0x%x\n",
> > +	      __func__, REG_TO_U32(&mdio_oper), data);
> > +	return CA_E_OK;
> > +}
> > +
> > +static enum ca_status_t ca_mdio_read_rgmii(unsigned int addr,
> > +					   unsigned int offset,
> > +					   unsigned short *data)
> > +{
> > +	struct PER_MDIO_ADDR_t  mdio_addr;
> > +	struct PER_MDIO_CTRL_t  mdio_ctrl;
> > +	struct PER_MDIO_RDDATA_t  read_data;
> > +	unsigned int loop_wait = __MDIO_ACCESS_TIMEOUT;
> > +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
> > +
> > +	memset(&mdio_addr, 0, sizeof(mdio_addr));
> > +	mdio_addr.mdio_addr   = addr;
> > +	mdio_addr.mdio_offset = offset;
> > +	mdio_addr.mdio_rd_wr  = __MDIO_RD_FLAG;
> > +	ca_reg_write(&mdio_addr, (u64)priv->per_mdio_base_addr,
> > +		     PER_MDIO_ADDR_OFFSET);
> > +
> > +	memset(&mdio_ctrl, 0, sizeof(mdio_ctrl));
> > +	mdio_ctrl.mdiostart = 1;
> > +	ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
> > +		     PER_MDIO_CTRL_OFFSET);
> > +
> > +	do {
> > +		ca_reg_read(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
> > +			    PER_MDIO_CTRL_OFFSET);
> > +		if (mdio_ctrl.mdiodone) {
> > +			ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
> > +				     PER_MDIO_CTRL_OFFSET);
> > +			ca_reg_read(&read_data, (u64)priv->per_mdio_base_addr,
> > +				    PER_MDIO_RDDATA_OFFSET);
> > +			*data = read_data.mdio_rddata;
> > +			return CA_E_OK;
> > +		}
> > +	} while (--loop_wait);
> > +
> > +	printf("%s: CA_E_TIMEOUT!!\n", __func__);
> > +	return CA_E_TIMEOUT;
> > +}
> > +
> > +enum ca_status_t ca_mdio_read(unsigned int      addr,
> > +			      unsigned int	offset,
> > +			      unsigned short	*data)
> > +{
> > +	u32 reg_addr, reg_val;
> > +	struct NI_MDIO_OPER_T  mdio_oper;
> > +
> > +	if (!data)
> > +		return CA_E_PARAM;
> > +
> > +	/* support range: 1~31*/
> > +	if (addr < CA_MDIO_ADDR_MIN || addr > CA_MDIO_ADDR_MAX)
> > +		return CA_E_PARAM;
> > +
> > +	/* the phy addr 5 is connect to RGMII */
> > +	if (addr >= 5)
> > +		return  ca_mdio_read_rgmii(addr, offset, data);
> > +
> > +	memset(&mdio_oper, 0, sizeof(mdio_oper));
> > +	mdio_oper.reg_off = offset;
> > +	mdio_oper.phy_addr = addr;
> > +	mdio_oper.reg_base = CA_NI_MDIO_REG_BASE;
> > +	reg_val = *data;
> > +	memcpy(&reg_addr, &mdio_oper, sizeof(reg_addr));
> > +	ca_reg_read(&reg_val, (u64)reg_addr, 0);
> > +	*data = reg_val;
> > +	return CA_E_OK;
> > +}
> > +
> > +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);
> > +}
> > +
> > +static int cortina_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
> > +{
> > +	unsigned short data;
> > +
> > +	ca_mdio_read(addr, reg, &data);
> > +	return data;
> > +}
> > +
> > +static int cortina_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
> > +			      u16 val)
> > +{
> > +	ca_mdio_write(addr, reg, val);
> > +	return 0;
> > +}
> > +
> > +static void ca_ni_setup_mac_addr(void)
> > +{
> > +	unsigned char mac[6];
> > +
> > +	struct NI_HV_GLB_MAC_ADDR_CFG0_t	mac_addr_cfg0;
> > +	struct NI_HV_GLB_MAC_ADDR_CFG1_t	mac_addr_cfg1;
> > +	struct NI_HV_PT_PORT_STATIC_CFG_t	port_static_cfg;
> > +	struct NI_HV_XRAM_CPUXRAM_CFG_t		cpuxram_cfg;
> > +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
> > +
> > +	/* parsing ethaddr and set to NI registers. */
> > +	if (eth_env_get_enetaddr("ethaddr", mac)) {
> > +		/* The complete MAC address consists of
> > +		 * {MAC_ADDR0_mac_addr0[0-3], MAC_ADDR1_mac_addr1[4],
> > +		 * PT_PORT_STATIC_CFG_mac_addr6[5]}.
> > +		 */
> > +		mac_addr_cfg0.mac_addr0 = (mac[0] << 24) + (mac[1] << 16) +
> > +					  (mac[2] << 8) + mac[3];
> > +		ca_reg_write(&mac_addr_cfg0, (u64)priv->ni_hv_base_addr,
> > +			     NI_HV_GLB_MAC_ADDR_CFG0_OFFSET);
> > +
> > +		memset(&mac_addr_cfg1, 0, sizeof(mac_addr_cfg1));
> > +		mac_addr_cfg1.mac_addr1 = mac[4];
> > +		ca_reg_write(&mac_addr_cfg1, (u64)priv->ni_hv_base_addr,
> > +			     NI_HV_GLB_MAC_ADDR_CFG1_OFFSET);
> > +
> > +		ca_reg_read(&port_static_cfg, (u64)priv->ni_hv_base_addr,
> > +			    NI_HV_PT_PORT_STATIC_CFG_OFFSET +
> > +			    (APB0_NI_HV_PT_STRIDE * active_port));
> > +
> > +		port_static_cfg.mac_addr6 = mac[5];
> > +		ca_reg_write(&port_static_cfg, (u64)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 */
> > +		ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
> > +			    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
> > +		cpuxram_cfg.xram_mgmt_promisc_mode = 0;
> > +		cpuxram_cfg.rx_0_cpu_pkt_dis = 0;
> > +		cpuxram_cfg.tx_0_cpu_pkt_dis = 0;
> > +		ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
> > +			     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
> > +	} else {
> > +		/* received all packets(promiscuous mode) */
> > +		ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
> > +			    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
> > +		cpuxram_cfg.xram_mgmt_promisc_mode = 3;
> > +		cpuxram_cfg.rx_0_cpu_pkt_dis = 0;
> > +		cpuxram_cfg.tx_0_cpu_pkt_dis = 0;
> > +		ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
> > +			     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
> > +	}
> > +}
> > +
> > +static void ca_ni_enable_tx_rx(void)
> > +{
> > +	struct NI_HV_PT_RXMAC_CFG_t rxmac_cfg;
> > +	struct NI_HV_PT_TXMAC_CFG_t txmac_cfg;
> > +
> > +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
> > +
> > +	/* Enable TX and RX functions */
> > +	ca_reg_read(&rxmac_cfg, (u64)priv->ni_hv_base_addr,
> > +		    NI_HV_PT_RXMAC_CFG_OFFSET +
> > +		    (APB0_NI_HV_PT_STRIDE * active_port));
> > +	rxmac_cfg.rx_en = 1;
> > +	ca_reg_write(&rxmac_cfg, (u64)priv->ni_hv_base_addr,
> > +		     NI_HV_PT_RXMAC_CFG_OFFSET +
> > +		     (APB0_NI_HV_PT_STRIDE * active_port));
> > +
> > +	ca_reg_read(&txmac_cfg, (u64)priv->ni_hv_base_addr,
> > +		    NI_HV_PT_TXMAC_CFG_OFFSET +
> > +		    (APB0_NI_HV_PT_STRIDE * active_port));
> > +	txmac_cfg.tx_en = 1;
> > +	ca_reg_write(&txmac_cfg, (u64)priv->ni_hv_base_addr,
> > +		     NI_HV_PT_TXMAC_CFG_OFFSET +
> > +		     (APB0_NI_HV_PT_STRIDE * active_port));
> > +}
> > +
> > +#define AUTO_SCAN_TIMEOUT	3000		/* 3 seconds */
> > +__weak int ca_ni_auto_scan_active_port(void)
> > +{
> > +	u8	phy_addr;
> > +	u32	start_time;
> > +	unsigned short data;
> > +
> > +	start_time = get_timer(0);
> > +	while (get_timer(start_time) < AUTO_SCAN_TIMEOUT) {
> > +		phy_addr = 1;
> > +		for (; phy_addr < 6; phy_addr++) {
> > +			ca_mdio_read(phy_addr, 1, &data);
> > +			if (data & 0x04) {
> > +				active_port = phyaddr_to_port(phy_addr);
> > +				return 0;
> > +			}
> > +		}
> > +	}
> > +
> > +	printf("%s: auto scan active_port timeout.\n", __func__);
> > +	return -1;
> > +}
> > +
> > +__weak int invalid_active_port(int port)
> > +{
> > +	if (active_port < NI_PORT_0 || active_port > NI_PORT_4)
> > +		return -1;
> > +	else
> > +		return 0;
> > +}
> > +
> > +static int ca_phy_probe(struct udevice *dev)
> > +{
> > +	struct cortina_ni_priv *priv = dev_get_priv(dev);
> > +	struct phy_device *int_phydev, *ext_phydev;
> > +	int auto_scan_active_port = 0, tmp_port;
> > +	char *buf;
> > +
> > +	/* Initialize internal phy device */
> > +	int_phydev = phy_connect(priv->mdio_bus, port_to_phyaddr(NI_PORT_3),
> > +				 dev, priv->phy_interface);
> > +	if (int_phydev) {
> > +		int_phydev->supported &= PHY_GBIT_FEATURES;
> > +		int_phydev->advertising = int_phydev->supported;
> > +		phy_config(int_phydev);
> > +	} else {
> > +		printf("%s: There is no internal phy device\n", __func__);
> > +	}
> > +
> > +	/* Initialize external phy device */
> > +	ext_phydev = phy_connect(priv->mdio_bus, port_to_phyaddr(NI_PORT_4),
> > +				 dev, priv->phy_interface);
> > +	if (ext_phydev) {
> > +		ext_phydev->supported &= PHY_GBIT_FEATURES;
> > +		ext_phydev->advertising = int_phydev->supported;
> > +		phy_config(ext_phydev);
> > +	} else {
> > +		printf("%s: There is no external phy device\n", __func__);
> > +	}
> > +
> > +	/* auto scan the first link up port as active_port */
> > +	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) {
> > +		ca_ni_auto_scan_active_port();
> > +	} else {
> > +		buf = env_get("active_port");
> > +		if (buf != 0) {
> > +			tmp_port = simple_strtoul(buf, NULL, 0);
> > +			if (invalid_active_port(active_port)) {
> > +				printf("ERROR: doesn't support this port.");
> > +				free(dev);
> > +				free(priv);
> > +				return 1;
> > +			}
> > +
> > +			active_port = tmp_port;
> > +		}
> > +	}
> > +
> > +	printf("%s: active_port=%d\n", __func__, active_port);
> > +	if (active_port == NI_PORT_4)
> > +		priv->phydev = ext_phydev;
> > +	else
> > +		priv->phydev = int_phydev;
> > +
> > +	return 0;
> > +}
> > +
> > +static void ca_ni_led(int port, int status)
> > +{
> > +	struct udevice *led_dev;
> > +	char label[10];
> > +
> > +	if (IS_ENABLED(CONFIG_LED_CORTINA)) {
> > +		snprintf(label, sizeof(label), "led%d", port);
> > +		debug("%s: set port %d led %s.\n",
> > +		      __func__, port, status ? "on" : "off");
> > +		led_get_by_label(label, &led_dev);
> > +		led_set_state(led_dev, status);
> > +	}
> > +}
> > +
> > +static void cortina_ni_reset(void)
> > +{
> > +	int i;
> > +	struct NI_HV_GLB_INIT_DONE_t		init_done;
> > +	struct NI_HV_GLB_INTF_RST_CONFIG_t	intf_rst_config;
> > +	struct NI_HV_GLB_STATIC_CFG_t		static_cfg;
> > +	struct GLOBAL_BLOCK_RESET_t		glb_blk_reset;
> > +
> > +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
> > +
> > +	/* NI global resets */
> > +	ca_reg_read(&glb_blk_reset, (u64)priv->glb_base_addr,
> > +		    GLOBAL_BLOCK_RESET_OFFSET);
> > +	glb_blk_reset.reset_ni = 1;
> > +	ca_reg_write(&glb_blk_reset, (u64)priv->glb_base_addr,
> > +		     GLOBAL_BLOCK_RESET_OFFSET);
> > +	/* Remove resets */
> > +	glb_blk_reset.reset_ni = 0;
> > +	ca_reg_write(&glb_blk_reset, (u64)priv->glb_base_addr,
> > +		     GLOBAL_BLOCK_RESET_OFFSET);
> > +
> > +	/* check the ready bit of NI module */
> > +	for (i = 0; i < NI_READ_POLL_COUNT; i++) {
> > +		ca_reg_read(&init_done, (u64)priv->ni_hv_base_addr,
> > +			    NI_HV_GLB_INIT_DONE_OFFSET);
> > +		if (init_done.ni_init_done)
> > +			break;
> > +	}
> > +	if (i == NI_READ_POLL_COUNT) {
> > +		printf("%s: NI init done not ready, init_done=0x%x!!!\n",
> > +		       __func__, init_done.ni_init_done);
> > +	}
> > +
> > +	ca_reg_read(&intf_rst_config, (u64)priv->ni_hv_base_addr,
> > +		    NI_HV_GLB_INTF_RST_CONFIG_OFFSET);
> > +	switch (active_port) {
> > +	case NI_PORT_0:
> > +		intf_rst_config.intf_rst_p0 = 0;
> > +		intf_rst_config.mac_rx_rst_p0 = 0;
> > +		intf_rst_config.mac_tx_rst_p0 = 0;
> > +		break;
> > +	case NI_PORT_1:
> > +		intf_rst_config.intf_rst_p1 = 0;
> > +		intf_rst_config.mac_rx_rst_p1 = 0;
> > +		intf_rst_config.mac_tx_rst_p1 = 0;
> > +		break;
> > +	case NI_PORT_2:
> > +		intf_rst_config.intf_rst_p2 = 0;
> > +		intf_rst_config.mac_rx_rst_p2 = 0;
> > +		intf_rst_config.mac_tx_rst_p2 = 0;
> > +		break;
> > +	case NI_PORT_3:
> > +		intf_rst_config.intf_rst_p3 = 0;
> > +		intf_rst_config.mac_tx_rst_p3 = 0;
> > +		intf_rst_config.mac_rx_rst_p3 = 0;
> > +		break;
> > +	case NI_PORT_4:
> > +		intf_rst_config.intf_rst_p4 = 0;
> > +		intf_rst_config.mac_tx_rst_p4 = 0;
> > +		intf_rst_config.mac_rx_rst_p4 = 0;
> > +		break;
> > +	}
> > +
> > +	ca_reg_write(&intf_rst_config, (u64)priv->ni_hv_base_addr,
> > +		     NI_HV_GLB_INTF_RST_CONFIG_OFFSET);
> > +
> > +	/* Only one GMAC can connect to CPU */
> > +	ca_reg_read(&static_cfg, (u64)priv->ni_hv_base_addr,
> > +		    NI_HV_GLB_STATIC_CFG_OFFSET);
> > +	static_cfg.port_to_cpu = active_port;
> > +	static_cfg.txmib_mode = 1;
> > +	static_cfg.rxmib_mode = 1;
> > +
> > +	ca_reg_write(&static_cfg, (u64)priv->ni_hv_base_addr,
> > +		     NI_HV_GLB_STATIC_CFG_OFFSET);
> > +}
> > +
> > +static int cortina_ni_init(struct udevice *dev)
> > +{
> > +	int ret;
> > +	struct NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t	cpuxram_adrcfg_rx;
> > +	struct NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t  cpuxram_adrcfg_tx;
> > +	struct NI_HV_XRAM_CPUXRAM_CFG_t		cpuxram_cfg;
> > +	struct NI_HV_PT_PORT_STATIC_CFG_t	port_static_cfg;
> > +	struct NI_HV_PT_PORT_GLB_CFG_t		port_glb_cfg;
> > +
> > +	struct cortina_ni_priv *priv = dev_get_priv(dev);
> > +	struct phy_device *phydev = priv->phydev;
> > +
> > +	ret = phy_startup(priv->phydev);
> > +	if (ret) {
> > +		ca_ni_led(active_port, CA_LED_OFF);
> > +		printf("Could not initialize PHY %s, active_port=%d\n",
> > +		       priv->phydev->dev->name, active_port);
> > +		return ret;
> > +	}
> > +
> > +	if (!priv->phydev->link) {
> > +		printf("%s: link down.\n", priv->phydev->dev->name);
> > +		return 0;
> > +	}
> > +
> > +	ca_ni_led(active_port, CA_LED_ON);
> > +	printf("PHY ID 0x%08X %dMbps %s duplex\n",
> > +	       phydev->phy_id, phydev->speed,
> > +	       phydev->duplex == DUPLEX_HALF ? "half" : "full");
> > +
> > +	/* RX XRAM ADDRESS CONFIG (start and end address) */
> > +	memset(&cpuxram_adrcfg_rx, 0, sizeof(cpuxram_adrcfg_rx));
> > +	cpuxram_adrcfg_rx.rx_top_addr = RX_TOP_ADDR;
> > +	cpuxram_adrcfg_rx.rx_base_addr = RX_BASE_ADDR;
> > +	ca_reg_write(&cpuxram_adrcfg_rx, (u64)priv->ni_hv_base_addr,
> > +		     NI_HV_XRAM_CPUXRAM_ADRCFG_RX_OFFSET);
> > +
> > +	/* TX XRAM ADDRESS CONFIG (start and end address) */
> > +	memset(&cpuxram_adrcfg_tx, 0, sizeof(cpuxram_adrcfg_tx));
> > +	cpuxram_adrcfg_tx.tx_top_addr = TX_TOP_ADDR;
> > +	cpuxram_adrcfg_tx.tx_base_addr = TX_BASE_ADDR;
> > +	ca_reg_write(&cpuxram_adrcfg_tx, (u64)priv->ni_hv_base_addr,
> > +		     NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_OFFSET);
> > +
> > +	/*
> > +	 * Configuration for Management Ethernet Interface:
> > +	 * - RGMII 1000 mode or RGMII 100 mode
> > +	 * - MAC mode
> > +	 */
> > +	ca_reg_read(&port_static_cfg, (u64)priv->ni_hv_base_addr,
> > +		    NI_HV_PT_PORT_STATIC_CFG_OFFSET +
> > +		    (APB0_NI_HV_PT_STRIDE * active_port));
> > +	if (phydev->speed == SPEED_1000) {
> > +		/* port 4 connects to RGMII PHY */
> > +		if (phydev->addr == 5)
> > +			port_static_cfg.int_cfg = GE_MAC_INTF_RGMII_1000;
> > +		else
> > +			port_static_cfg.int_cfg = GE_MAC_INTF_GMII;
> > +	} else {
> > +		/* port 4 connects to RGMII PHY */
> > +		if (phydev->addr == 5)
> > +			port_static_cfg.int_cfg = GE_MAC_INTF_RGMII_100;
> > +		else
> > +			port_static_cfg.int_cfg = GE_MAC_INTF_MII;
> > +	}
> > +
> > +	ca_reg_write(&port_static_cfg, (u64)priv->ni_hv_base_addr,
> > +		     NI_HV_PT_PORT_STATIC_CFG_OFFSET +
> > +		     (APB0_NI_HV_PT_STRIDE * active_port));
> > +
> > +	ca_reg_read(&port_glb_cfg, (u64)priv->ni_hv_base_addr,
> > +		    NI_HV_PT_PORT_GLB_CFG_OFFSET +
> > +		    (APB0_NI_HV_PT_STRIDE * active_port));
> > +	port_glb_cfg.speed = phydev->speed == SPEED_10 ? 1 : 0;
> > +	port_glb_cfg.duplex = phydev->duplex == DUPLEX_HALF ? 1 : 0;
> > +	ca_reg_write(&port_glb_cfg, (u64)priv->ni_hv_base_addr,
> > +		     NI_HV_PT_PORT_GLB_CFG_OFFSET +
> > +		     (APB0_NI_HV_PT_STRIDE * active_port));
> > +
> > +	/* Need to toggle the tx and rx cpu_pkt_dis bit */
> > +	/* after changing Address config register.      */
> > +	ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
> > +		    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
> > +	cpuxram_cfg.rx_0_cpu_pkt_dis = 1;
> > +	cpuxram_cfg.tx_0_cpu_pkt_dis = 1;
> > +	ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
> > +		     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
> > +
> > +	ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
> > +		    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
> > +	cpuxram_cfg.rx_0_cpu_pkt_dis = 0;
> > +	cpuxram_cfg.tx_0_cpu_pkt_dis = 0;
> > +	ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
> > +		     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
> > +
> > +	ca_ni_enable_tx_rx();
> > +
> > +	return 0;
> > +}
> > +
> > +/*********************************************
> > + * Packet receive routine from Management FE
> > + * Expects a previously allocated buffer and
> > + * fills the length
> > + * Retruns 0 on success -1 on failure
> > + *******************************************/
> > +int cortina_ni_recv(struct udevice *netdev)
> > +{
> > +	struct cortina_ni_priv *priv = dev_get_priv(netdev);
> > +	struct NI_HEADER_X_T	header_x;
> > +	u32			next_link;
> > +	u32			pktlen = 0;
> > +	u32			sw_rx_rd_ptr;
> > +	u32			hw_rx_wr_ptr;
> > +	u32			*rx_xram_ptr;
> > +	int			loop;
> > +	u32			*data_ptr;
> > +	struct NI_PACKET_STATUS packet_status;
> > +	struct NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t cpuxram_cpu_sta_rx;
> > +	struct NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t cpuxram_cpu_cfg_rx;
> > +	int index = 0;
> > +	int			blk_num;
> > +	u8			*ptr;
> > +
> > +	/* get the hw write pointer */
> > +	memset(&cpuxram_cpu_sta_rx, 0, sizeof(cpuxram_cpu_sta_rx));
> > +	ca_reg_read(&cpuxram_cpu_sta_rx, (u64)priv->ni_hv_base_addr,
> > +		    NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET);
> > +	hw_rx_wr_ptr = cpuxram_cpu_sta_rx.pkt_wr_ptr;
> > +
> > +	/* get the sw read pointer */
> > +	memset(&cpuxram_cpu_cfg_rx, 0, sizeof(cpuxram_cpu_cfg_rx));
> > +	ca_reg_read(&cpuxram_cpu_cfg_rx, (u64)priv->ni_hv_base_addr,
> > +		    NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
> > +	sw_rx_rd_ptr = cpuxram_cpu_cfg_rx.pkt_rd_ptr;
> > +
> > +	debug("%s: NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0 = 0x%p, ", __func__,
> > +	      priv->ni_hv_base_addr + NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET);
> > +	debug("NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0 = 0x%p\n",
> > +	      priv->ni_hv_base_addr + NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
> > +	debug("%s : RX hw_wr_ptr = %d, sw_rd_ptr = %d\n",
> > +	      __func__, hw_rx_wr_ptr, sw_rx_rd_ptr);
> > +
> > +	while (sw_rx_rd_ptr != hw_rx_wr_ptr) {
> > +		/* Point to the absolute memory address of XRAM
> > +		 * where read pointer is
> > +		 */
> > +		rx_xram_ptr = (u32 *)
> > +			      ((unsigned long)NI_XRAM_BASE + sw_rx_rd_ptr * 8);
> > +
> > +		/* Wrap around if required */
> > +		if (rx_xram_ptr >= (u32 *)(unsigned long)priv->rx_xram_end_adr)
> > +			rx_xram_ptr = (u32 *)
> > +				      (unsigned long)priv->rx_xram_base_adr;
> > +
> > +		/* Checking header XR. Do not update the read pointer yet */
> > +		/* skip unused 32-bit in Header XR */
> > +		rx_xram_ptr = rdwrptr_adv_one(rx_xram_ptr,
> > +					      priv->rx_xram_base_adr,
> > +					      priv->rx_xram_end_adr);
> > +
> > +		memcpy(&header_x, rx_xram_ptr, sizeof(header_x));
> > +		next_link = header_x.next_link;
> > +		/* Header XR [31:0] */
> > +
> > +		if (*rx_xram_ptr == 0xffffffff)
> > +			printf("%s: XRAM Error !\n", __func__);
> > +
> > +		debug("%s : RX next link 0x%x\n", __func__, next_link);
> > +		debug("%s : bytes_valid %x\n", __func__, header_x.bytes_valid);
> > +
> > +		if (header_x.ownership == 0) {
> > +			/* point to Packet status [31:0] */
> > +			rx_xram_ptr = rdwrptr_adv_one(rx_xram_ptr,
> > +						      priv->rx_xram_base_adr,
> > +						      priv->rx_xram_end_adr);
> > +
> > +			memcpy(&packet_status, rx_xram_ptr,
> > +			       sizeof(rx_xram_ptr));
> > +			debug("%s: packet status=0x%x\n",
> > +			      __func__, REG_TO_U32(&packet_status));
> > +			if (packet_status.valid == 0) {
> > +				debug("%s: Invalid Packet !!, ", __func__);
> > +				debug("next_link=%d\n", next_link);
> > +
> > +				/* Update the software read pointer */
> > +				ca_reg_write(&next_link,
> > +					     (u64)priv->ni_hv_base_addr,
> > +					NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
> > +				return 0;
> > +			}
> > +
> > +			if (packet_status.drop ||
> > +			    packet_status.runt ||
> > +			    packet_status.oversize ||
> > +			    packet_status.jabber ||
> > +			    packet_status.crc_error ||
> > +			    packet_status.jumbo) {
> > +				debug("%s: Error Packet!!, ", __func__);
> > +				debug("next_link=%d\n", next_link);
> > +
> > +				/* Update the software read pointer */
> > +				ca_reg_write(&next_link,
> > +					     (u64)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.packet_size > 1518) {
> > +				debug("%s: Error Packet !! Packet size=%d, ",
> > +				      __func__, packet_status.packet_size);
> > +				debug("larger than 1518, next_link=%d\n",
> > +				      next_link);
> > +
> > +				/* Update the software read pointer */
> > +				ca_reg_write(&next_link,
> > +					     (u64)priv->ni_hv_base_addr,
> > +					NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
> > +				return 0;
> > +			}
> > +
> > +			rx_xram_ptr = rdwrptr_adv_one(rx_xram_ptr,
> > +						      priv->rx_xram_base_adr,
> > +						      priv->rx_xram_end_adr);
> > +
> > +			pktlen = packet_status.packet_size;
> > +
> > +			debug("%s : rx packet length = %d\n",
> > +			      __func__, packet_status.packet_size);
> > +
> > +			rx_xram_ptr = rdwrptr_adv_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 */
> > +
> > +			debug("%s: packet data[]=", __func__);
> > +
> > +			for (loop = 0; loop <= pktlen / 4; loop++) {
> > +				ptr = (u8 *)rx_xram_ptr;
> > +				if (loop < 10)
> > +					debug("[0x%x]-[0x%x]-[0x%x]-[0x%x]",
> > +					      ptr[0], ptr[1], ptr[2], ptr[3]);
> > +				*data_ptr++ = *rx_xram_ptr++;
> > +				/* Wrap around if required */
> > +				if (rx_xram_ptr >= (u32 *)
> > +				    (unsigned long)priv->rx_xram_end_adr) {
> > +					rx_xram_ptr = (u32 *)(unsigned long)
> > +						       (priv->rx_xram_base_adr);
> > +				}
> > +			}
> > +
> > +			debug("\n");
> > +			net_process_received_packet(net_rx_packets[index],
> > +						    pktlen);
> > +			if (++index >= PKTBUFSRX)
> > +				index = 0;
> > +			blk_num = net_rx_packets[index][0x2c] * 255 +
> > +				net_rx_packets[index][0x2d];
> > +			debug("%s: tftp block number=%d\n", __func__, blk_num);
> > +
> > +			/* Update the software read pointer */
> > +			ca_reg_write(&next_link,
> > +				     (u64)priv->ni_hv_base_addr,
> > +				     NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
> > +		}
> > +
> > +		/* get the hw write pointer */
> > +		ca_reg_read(&cpuxram_cpu_sta_rx, (u64)priv->ni_hv_base_addr,
> > +			    NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET);
> > +		hw_rx_wr_ptr = cpuxram_cpu_sta_rx.pkt_wr_ptr;
> > +
> > +		/* get the sw read pointer */
> > +		ca_reg_read(&sw_rx_rd_ptr, (u64)priv->ni_hv_base_addr,
> > +			    NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
> > +	}
> > +	return 0;
> > +}
> > +
> > +static int cortina_ni_send(struct udevice *dev, void *packet, int length)
> > +{
> > +	struct cortina_ni_priv *priv = dev_get_priv(dev);
> > +	u32	hw_tx_rd_ptr = 0;
> > +	u32	sw_tx_wr_ptr = 0;
> > +	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	ca_crc32;
> > +	struct NI_HEADER_X_T	hdr_xt;
> > +	int		pad = 0;
> > +	static unsigned char   pkt_buf[2048];
> > +	u32	*data_ptr;
> > +	struct NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t cpuxram_cpu_cfg_tx;
> > +	u8 *ptr;
> > +
> > +	if (!packet || length > 2032)
> > +		return -1;
> > +
> > +	/* Get the hardware read pointer */
> > +	ca_reg_read(&hw_tx_rd_ptr, (u64)priv->ni_hv_base_addr,
> > +		    NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET);
> > +
> > +	/* Get the software write pointer */
> > +	ca_reg_read(&sw_tx_wr_ptr, (u64)priv->ni_hv_base_addr,
> > +		    NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET);
> > +
> > +	debug("%s: NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0=0x%p, ",
> > +	      __func__,
> > +	      KSEG1_ATU_XLAT(priv->ni_hv_base_addr +
> > +			     NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET));
> > +	debug("NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0=0x%p\n",
> > +	      KSEG1_ATU_XLAT(priv->ni_hv_base_addr +
> > +			     NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET));
> > +	debug("%s : hw_tx_rd_ptr = %d\n", __func__, hw_tx_rd_ptr);
> > +	debug("%s : sw_tx_wr_ptr = %d\n", __func__, sw_tx_wr_ptr);
> > +
> > +	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[HEADER_A_SIZE], (const void *)packet, length);
> > +
> > +	pad = 64 - (length + 4);	/* if packet length < 60 */
> > +	pad = (pad < 0) ? 0 : pad;
> > +
> > +	debug("%s: length=%d, pad=%d\n", __func__, length, pad);
> > +
> > +	new_pkt_len = length + pad;	/* new packet length */
> > +
> > +	pkt_buf_ptr = (unsigned char *)pkt_buf;
> > +
> > +	/* Calculate the CRC32, skip 8-byte header_A */
> > +	ca_crc32 = crc32(0, (u8 *)(pkt_buf_ptr + HEADER_A_SIZE), new_pkt_len);
> > +
> > +	debug("%s: crc32 is 0x%x\n", __func__, ca_crc32);
> > +	debug("%s: ~crc32 is 0x%x\n", __func__, ~ca_crc32);
> > +	debug("%s: pkt len %d\n", __func__, new_pkt_len);
> > +	/* should add 8-byte header_! */
> > +	/* CRC will re-calculated by hardware */
> > +	memcpy((pkt_buf_ptr + new_pkt_len + HEADER_A_SIZE),
> > +	       (u8 *)(&ca_crc32), sizeof(ca_crc32));
> > +	new_pkt_len = new_pkt_len + 4;	/* add CRC */
> > +
> > +	valid_bytes = new_pkt_len % 8;
> > +	valid_bytes = valid_bytes ? valid_bytes : 0;
> > +	debug("%s: valid_bytes %d\n", __func__, valid_bytes);
> > +
> > +	/* should add 8-byte headerA */
> > +	next_link = sw_tx_wr_ptr +
> > +		(new_pkt_len + 7 + HEADER_A_SIZE) / 8; /* for headr XT */
> > +	/* add header */
> > +	next_link = next_link + 1;
> > +	/* Wrap around if required */
> > +	if (next_link > priv->tx_xram_end) {
> > +		next_link = priv->tx_xram_start +
> > +			(next_link - (priv->tx_xram_end + 1));
> > +	}
> > +
> > +	debug("%s: TX next_link %x\n", __func__, next_link);
> > +	memset(&hdr_xt, 0, sizeof(hdr_xt));
> > +	hdr_xt.ownership = 1;
> > +	hdr_xt.bytes_valid = valid_bytes;
> > +	hdr_xt.next_link = next_link;
> > +
> > +	tx_xram_ptr = (u32 *)((unsigned long)NI_XRAM_BASE + sw_tx_wr_ptr * 8);
> > +
> > +	/* Wrap around if required */
> > +	if (tx_xram_ptr >= (u32 *)(unsigned long)priv->tx_xram_end_adr)
> > +		tx_xram_ptr = (u32 *)(unsigned long)priv->tx_xram_base_adr;
> > +
> > +	tx_xram_ptr = rdwrptr_adv_one(tx_xram_ptr,
> > +				      priv->tx_xram_base_adr,
> > +				      priv->tx_xram_end_adr);
> > +
> > +	memcpy(tx_xram_ptr, &hdr_xt, sizeof(*tx_xram_ptr));
> > +
> > +	tx_xram_ptr = rdwrptr_adv_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;
> > +	debug("%s: packet data[]=", __func__);
> > +
> > +	/* copy header_A to XRAM */
> > +	for (loop = 0; loop <= (new_pkt_len + HEADER_A_SIZE) / 4; loop++) {
> > +		ptr = (u8 *)data_ptr;
> > +		if ((loop % 4) == 0)
> > +			debug("\n");
> > +		debug("[0x%x]-[0x%x]-[0x%x]-[0x%x]-",
> > +		      ptr[0], ptr[1], ptr[2], ptr[3]);
> > +
> > +		*tx_xram_ptr = *data_ptr++;
> > +		tx_xram_ptr = rdwrptr_adv_one(tx_xram_ptr,
> > +					      priv->tx_xram_base_adr,
> > +					      priv->tx_xram_end_adr);
> > +	}
> > +	debug("\n");
> > +
> > +	/* Publish the software write pointer */
> > +	cpuxram_cpu_cfg_tx.pkt_wr_ptr = next_link;
> > +	ca_reg_write(&cpuxram_cpu_cfg_tx,
> > +		     (u64)priv->ni_hv_base_addr,
> > +		     NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET);
> > +
> > +	return 0;
> > +}
> > +
> > +static void cortina_ni_halt(struct udevice *netdev)
> > +{
> > +	/* Nothing to do for now. */
> > +}
> > +
> > +#define GPHY_CAL_LEN	6
> > +struct gphy_cal {
> > +	u32 reg_off;
> > +	u32 value;
> > +};
> > +
> > +static struct gphy_cal gphy_cal_vlaues[GPHY_CAL_LEN] = {
> > +	{0xf43380fc, 0xbcd},
> > +	{0xf43380dc, 0xeeee},
> > +	{0xf43380d8, 0xeeee},
> > +	{0xf43380fc, 0xbce},
> > +	{0xf43380c0, 0x7777},
> > +	{0xf43380c4, 0x7777}
> > +};
> > +
> > +__weak 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, 0);
> > +			mdelay(50);
> > +		}
> > +	}
> > +}
> > +
> > +static int ca_mdio_register(struct udevice *dev)
> > +{
> > +	struct cortina_ni_priv *priv = dev_get_priv(dev);
> > +	struct mii_dev *mdio_bus = mdio_alloc();
> > +	int ret;
> > +
> > +	if (!mdio_bus)
> > +		return -ENOMEM;
> > +
> > +	mdio_bus->read = cortina_mdio_read;
> > +	mdio_bus->write = cortina_mdio_write;
> > +	snprintf(mdio_bus->name, sizeof(mdio_bus->name), dev->name);
> > +
> > +	mdio_bus->priv = (void *)priv;
> > +
> > +	ret = mdio_register(mdio_bus);
> > +	if (ret)
> > +		return ret;
> > +
> > +	priv->mdio_bus = mdio_bus;
> > +	return 0;
> > +}
> > +
> > +__weak void ca_rgmii_init(struct cortina_ni_priv *priv)
> > +{
> > +	/* hardware settings for RGMII port */
> > +	struct GLOBAL_GLOBAL_CONFIG_t	glb_config;
> > +	struct GLOBAL_IO_DRIVE_CONTROL_t io_drive_control;
> > +
> > +	/* Generating 25Mhz reference clock for switch */
> > +	ca_reg_read(&glb_config, (u64)priv->glb_base_addr,
> > +		    GLOBAL_GLOBAL_CONFIG_OFFSET);
> > +	glb_config.refclk_sel = 0x01;
> > +	glb_config.ext_reset = 0x01;
> > +	ca_reg_write(&glb_config, (u64)priv->glb_base_addr,
> > +		     GLOBAL_GLOBAL_CONFIG_OFFSET);
> > +
> > +	mdelay(20);
> > +
> > +	/* should do a external reset */
> > +	ca_reg_read(&glb_config, (u64)priv->glb_base_addr,
> > +		    GLOBAL_GLOBAL_CONFIG_OFFSET);
> > +	glb_config.ext_reset = 0x0;
> > +	ca_reg_write(&glb_config, (u64)priv->glb_base_addr,
> > +		     GLOBAL_GLOBAL_CONFIG_OFFSET);
> > +
> > +	ca_reg_read(&io_drive_control, (u64)priv->glb_base_addr,
> > +		    GLOBAL_IO_DRIVE_CONTROL_OFFSET);
> > +	io_drive_control.gmac_mode = 2;
> > +	io_drive_control.gmac_dn = 1;
> > +	io_drive_control.gmac_dp = 1;
> > +	ca_reg_write(&io_drive_control, (u64)priv->glb_base_addr,
> > +		     GLOBAL_IO_DRIVE_CONTROL_OFFSET);
> > +}
> > +
> > +int ca_eth_initialize(struct udevice *dev)
> > +{
> > +	struct cortina_ni_priv *priv;
> > +	int ret, reg_value;
> > +
> > +	priv = dev_get_priv(dev);
> > +	priv->rx_xram_base_adr	= NI_XRAM_BASE + (RX_BASE_ADDR * 8);
> > +	priv->rx_xram_end_adr	= NI_XRAM_BASE + ((RX_TOP_ADDR + 1) * 8);
> > +	priv->rx_xram_start	= RX_BASE_ADDR;
> > +	priv->rx_xram_end	= RX_TOP_ADDR;
> > +	priv->tx_xram_base_adr	= NI_XRAM_BASE + (TX_BASE_ADDR * 8);
> > +	priv->tx_xram_end_adr	= NI_XRAM_BASE + ((TX_TOP_ADDR + 1) * 8);
> > +	priv->tx_xram_start	= TX_BASE_ADDR;
> > +	priv->tx_xram_end	= TX_TOP_ADDR;
> > +
> > +	curr_dev = dev;
> > +	debug("%s: rx_base_addr:%x\t rx_top_addr %x\n",
> > +	      __func__, priv->rx_xram_start, priv->rx_xram_end);
> > +	debug("%s: tx_base_addr:%x\t tx_top_addr %x\n",
> > +	      __func__, priv->tx_xram_start, priv->tx_xram_end);
> > +	debug("%s: rx physical start address = %x end address = %x\n",
> > +	      __func__, priv->rx_xram_base_adr, priv->rx_xram_end_adr);
> > +	debug("%s: tx physical start address = %x end address = %x\n",
> > +	      __func__, priv->tx_xram_base_adr, priv->tx_xram_end_adr);
> > +
> > +	/* MDIO register */
> > +	ret = ca_mdio_register(dev);
> > +	if (ret)
> > +		return ret;
> > +
> > +	/* set MDIO pre-scale value */
> > +	ca_reg_read(&reg_value, (u64)priv->per_mdio_base_addr,
> > +		    PER_MDIO_CFG_OFFSET);
> > +	reg_value = reg_value | 0x00280000;
> > +	ca_reg_write(&reg_value, (u64)priv->per_mdio_base_addr,
> > +		     PER_MDIO_CFG_OFFSET);
> > +
> > +	ca_phy_probe(dev);
> > +	priv->phydev->addr = port_to_phyaddr(active_port);
> > +
> > +	ca_ni_led(active_port, CA_LED_ON);
> > +
> > +	cortina_ni_reset();
> > +
> > +	printf("%s: active_port=%d, phy_addr=%d\n",
> > +	       __func__, active_port, priv->phydev->addr);
> > +	printf("%s: phy_id=0x%x, phy_id & PHY_ID_MASK=0x%x\n", __func__,
> > +	       priv->phydev->phy_id, priv->phydev->phy_id & 0xFFFFFFF0);
> > +
> > +	/* parsing ethaddr and set to NI registers. */
> > +	ca_ni_setup_mac_addr();
> > +
> > +#ifdef MIIPHY_REGISTER
> > +	/* the phy_read and phy_write
> > +	 * should meet the proto type of miiphy_register
> > +	 */
> > +	miiphy_register(dev->name, ca_miiphy_read, ca_miiphy_write);
> > +#endif
> > +
> > +	ca_rgmii_init(priv);
> > +
> > +	/* do internal gphy calibration */
> > +	do_internal_gphy_cal();
> > +	return 0;
> > +}
> > +
> > +static int cortina_eth_start(struct udevice *dev)
> > +{
> > +	return cortina_ni_init(dev);
> > +}
> > +
> > +static int cortina_eth_send(struct udevice *dev, void *packet, int length)
> > +{
> > +	return cortina_ni_send(dev, packet, length);
> > +}
> > +
> > +static int cortina_eth_recv(struct udevice *dev, int flags, uchar **packetp)
> > +{
> > +	return cortina_ni_recv(dev);
> > +}
> > +
> > +static void cortina_eth_stop(struct udevice *dev)
> > +{
> > +	cortina_ni_halt(dev);
> > +}
> > +
> > +static int cortina_eth_probe(struct udevice *dev)
> > +{
> > +	return ca_eth_initialize(dev);
> > +}
> > +
> > +static int ca_ni_ofdata_to_platdata(struct udevice *dev)
> > +{
> > +	struct cortina_ni_priv *priv = dev_get_priv(dev);
> > +
> > +	priv->glb_base_addr = dev_remap_addr_index(dev, 0);
> > +	if (!priv->glb_base_addr)
> > +		return -ENOENT;
> > +	printf("%s: priv->glb_base_addr for index 0 is 0x%p\n",
> > +	       __func__, priv->glb_base_addr);
> > +
> > +	priv->per_mdio_base_addr = dev_remap_addr_index(dev, 1);
> > +	if (!priv->per_mdio_base_addr)
> > +		return -ENOENT;
> > +	printf("%s: priv->per_mdio_base_addr for index 1 is 0x%p\n",
> > +	       __func__, priv->per_mdio_base_addr);
> > +
> > +	priv->ni_hv_base_addr = dev_remap_addr_index(dev, 2);
> > +	if (!priv->ni_hv_base_addr)
> > +		return -ENOENT;
> > +	printf("%s: priv->ni_hv_base_addr for index 2 is 0x%p\n",
> > +	       __func__, priv->ni_hv_base_addr);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct eth_ops cortina_eth_ops = {
> > +	.start  = cortina_eth_start,
> > +	.send   = cortina_eth_send,
> > +	.recv   = cortina_eth_recv,
> > +	.stop   = cortina_eth_stop,
> > +};
> > +
> > +static const struct udevice_id cortina_eth_ids[] = {
> > +	{ .compatible = "eth_cortina" },
> > +	{ }
> > +};
> > +
> > +U_BOOT_DRIVER(eth_cortina) = {
> > +	.name   = "eth_cortina",
> > +	.id     = UCLASS_ETH,
> > +	.of_match = cortina_eth_ids,
> > +	.probe  = cortina_eth_probe,
> > +	.ops    = &cortina_eth_ops,
> > +	.priv_auto_alloc_size = sizeof(struct cortina_ni_priv),
> > +	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
> > +	.ofdata_to_platdata = ca_ni_ofdata_to_platdata,
> > +};
> > diff --git a/drivers/net/cortina_ni.h b/drivers/net/cortina_ni.h
> > new file mode 100644
> > index 0000000..ff9a396
> > --- /dev/null
> > +++ b/drivers/net/cortina_ni.h
> > @@ -0,0 +1,435 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +
> > +/*
> > + * Copyright (C) 2020 Cortina Access Inc.
> > + * Author: Aaron Tseng <aaron.tseng@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 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
> > +
> > +/* 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 NI_XRAM_BASE                    0xF4500000
> > +
> > +enum ca_status_t {
> > +	CA_E_ERROR          = -1,
> > +	CA_E_OK             = 0x0,
> > +	CA_E_RESOURCE       = 0x1,
> > +	CA_E_PARAM          = 0x2,
> > +	CA_E_NOT_FOUND      = 0x3,
> > +	CA_E_CONFLICT       = 0x4,
> > +	CA_E_TIMEOUT        = 0x5,
> > +	CA_E_INTERNAL       = 0x6,
> > +	CA_E_NOT_SUPPORT    = 0x7,
> > +	CA_E_CONFIG         = 0x8,
> > +	CA_E_UNAVAIL        = 0x9,
> > +	CA_E_MEMORY         = 0xa,
> > +	CA_E_BUSY           = 0xb,
> > +	CA_E_FULL           = 0xc,
> > +	CA_E_EMPTY          = 0xd,
> > +	CA_E_EXISTS         = 0xe,
> > +	CA_E_DEV            = 0xf,
> > +	CA_E_PORT           = 0x10,
> > +	CA_E_LLID           = 0x11,
> > +	CA_E_VLAN           = 0x12,
> > +	CA_E_INIT           = 0x13,
> > +	CA_E_INTF           = 0x14,
> > +	CA_E_NEXTHOP        = 0x15,
> > +	CA_E_ROUTE          = 0x16,
> > +	CA_E_DB_CHANGED     = 0x17,
> > +	CA_E_INACTIVE       = 0x18,
> > +	CA_E_ALREADY_SET    = 0x19,
> > +};
> > +
> > +#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;
> > +	void __iomem    *glb_base_addr;
> > +	void __iomem    *per_mdio_base_addr;
> > +	void __iomem    *ni_hv_base_addr;
> > +
> > +	struct mii_dev *mdio_bus;
> > +	struct phy_device *phydev;
> > +	int phy_interface;
> > +};
> > +
> > +struct NI_HEADER_X_T {
> > +	unsigned int next_link		: 10; /* bits  9: 0 */
> > +	unsigned int bytes_valid	:  4; /* bits 13:10 */
> > +	unsigned int reserved		: 16; /* bits 29:14 */
> > +	unsigned int hdr_a		:  1; /* bits 30:30 */
> > +	unsigned int ownership		:  1; /* bits 31:31 */
> > +};
> > +
> > +struct NI_PACKET_STATUS {
> > +	unsigned int packet_size       : 14; /* bits 13:0 */
> > +	unsigned int byte_valid        :  4; /* bits 17:14 */
> > +	unsigned int pfc               :  1; /* bits 18:18 */
> > +	unsigned int valid             :  1; /* bits 19:19 */
> > +	unsigned int drop              :  1; /* bits 20:20 */
> > +	unsigned int runt              :  1; /* bits 21:21 */
> > +	unsigned int oversize          :  1; /* bits 22:22 */
> > +	unsigned int jumbo             :  1; /* bits 23:23 */
> > +	unsigned int link_status       :  1; /* bits 24:24 */
> > +	unsigned int jabber            :  1; /* bits 25:25 */
> > +	unsigned int crc_error         :  1; /* bits 26:26 */
> > +	unsigned int pause             :  1; /* bits 27:27 */
> > +	unsigned int oam               :  1; /* bits 28:28 */
> > +	unsigned int unknown_opcode    :  1; /* bits 29:29 */
> > +	unsigned int multicast         :  1; /* bits 30:30 */
> > +	unsigned int broadcast         :  1; /* bits 31:31 */
> > +};
> > +
> > +struct NI_MDIO_OPER_T {
> > +	unsigned int reserved       : 2; /* bits  1:0 */
> > +	unsigned int reg_off        : 5; /* bits  6:2 */
> > +	unsigned int phy_addr       : 5; /* bits 11:7 */
> > +	unsigned int reg_base       : 20; /* bits 31:12 */
> > +};
> > +
> > +enum ca_port_t {
> > +	NI_PORT_0 = 0,
> > +	NI_PORT_1,
> > +	NI_PORT_2,
> > +	NI_PORT_3,
> > +	NI_PORT_4,
> > +	NI_PORT_5,
> > +	NI_PORT_MAX,
> > +};
> > +
> > +struct port_map_s {
> > +	int active_port;
> > +	int phy_addr;
> > +};
> > +
> > +extern struct port_map_s port_map[NI_PORT_MAX];
> > +extern int active_port;
> > +
> > +#define __MDIO_WR_FLAG				(0)
> > +#define __MDIO_RD_FLAG				(1)
> > +#define __MDIO_ACCESS_TIMEOUT			(1000000)
> > +#define CA_MDIO_ADDR_MIN			(1)
> > +#define CA_MDIO_ADDR_MAX			(31)
> > +
> > +#endif /* !__ASSEMBLER__ */
> > +
> > +/* Copy from registers.h */
> > +struct NI_HV_GLB_MAC_ADDR_CFG0_t {
> > +	unsigned int mac_addr0            : 32; /* bits 31:0 */
> > +};
> > +
> > +struct NI_HV_GLB_MAC_ADDR_CFG1_t {
> > +	unsigned int mac_addr1            :  8; /* bits 7:0 */
> > +	unsigned int rsrvd1               : 24;
> > +};
> > +
> > +struct NI_HV_PT_PORT_STATIC_CFG_t {
> > +	unsigned int int_cfg              :  4; /* bits 3:0 */
> > +	unsigned int phy_mode             :  1; /* bits 4:4 */
> > +	unsigned int rmii_clksrc          :  1; /* bits 5:5 */
> > +	unsigned int inv_clk_in           :  1; /* bits 6:6 */
> > +	unsigned int inv_clk_out          :  1; /* bits 7:7 */
> > +	unsigned int inv_rxclk_out        :  1; /* bits 8:8 */
> > +	unsigned int tx_use_gefifo        :  1; /* bits 9:9 */
> > +	unsigned int smii_tx_stat         :  1; /* bits 10:10 */
> > +	unsigned int crs_polarity         :  1; /* bits 11:11 */
> > +	unsigned int lpbk_mode            :  2; /* bits 13:12 */
> > +	unsigned int gmii_like_half_duplex_en :  1; /* bits 14:14 */
> > +	unsigned int sup_tx_to_rx_lpbk_data :  1; /* bits 15:15 */
> > +	unsigned int rsrvd1               :  8;
> > +	unsigned int mac_addr6            :  8; /* bits 31:24 */
> > +};
> > +
> > +struct NI_HV_XRAM_CPUXRAM_CFG_t {
> > +	unsigned int rx_0_cpu_pkt_dis     :  1; /* bits 0:0 */
> > +	unsigned int rsrvd1               :  8;
> > +	unsigned int tx_0_cpu_pkt_dis     :  1; /* bits 9:9 */
> > +	unsigned int rsrvd2               :  1;
> > +	unsigned int rx_x_drop_err_pkt    :  1; /* bits 11:11 */
> > +	unsigned int xram_mgmt_dis_drop_ovsz_pkt :  1; /* bits 12:12 */
> > +	unsigned int xram_mgmt_term_large_pkt :  1; /* bits 13:13 */
> > +	unsigned int xram_mgmt_promisc_mode :  2; /* bits 15:14 */
> > +	unsigned int xram_cntr_debug_mode :  1; /* bits 16:16 */
> > +	unsigned int xram_cntr_op_code    :  2; /* bits 18:17 */
> > +	unsigned int rsrvd3               :  2;
> > +	unsigned int xram_rx_mgmtfifo_srst :  1; /* bits 21:21 */
> > +	unsigned int xram_dma_fifo_srst   :  1; /* bits 22:22 */
> > +	unsigned int rsrvd4               :  9;
> > +};
> > +
> > +struct NI_HV_PT_RXMAC_CFG_t {
> > +	unsigned int rx_en                :  1; /* bits 0:0 */
> > +	unsigned int rsrvd1               :  7;
> > +	unsigned int rx_flow_disable      :  1; /* bits 8:8 */
> > +	unsigned int rsrvd2               :  3;
> > +	unsigned int rx_flow_to_tx_en     :  1; /* bits 12:12 */
> > +	unsigned int rx_pfc_disable       :  1; /* bits 13:13 */
> > +	unsigned int rsrvd3               : 15;
> > +	unsigned int send_pg_data         :  1; /* bits 29:29 */
> > +	unsigned int rsrvd4               :  2;
> > +};
> > +
> > +struct NI_HV_PT_TXMAC_CFG_t {
> > +	unsigned int tx_en                :  1; /* bits 0:0 */
> > +	unsigned int rsrvd1               :  7;
> > +	unsigned int mac_crc_calc_en      :  1; /* bits 8:8 */
> > +	unsigned int tx_ipg_sel           :  3; /* bits 11:9 */
> > +	unsigned int tx_flow_disable      :  1; /* bits 12:12 */
> > +	unsigned int tx_drain             :  1; /* bits 13:13 */
> > +	unsigned int tx_pfc_disable       :  1; /* bits 14:14 */
> > +	unsigned int tx_pau_sel           :  2; /* bits 16:15 */
> > +	unsigned int rsrvd2               :  9;
> > +	unsigned int tx_auto_xon          :  1; /* bits 26:26 */
> > +	unsigned int rsrvd3               :  1;
> > +	unsigned int pass_thru_hdr        :  1; /* bits 28:28 */
> > +	unsigned int rsrvd4               :  3;
> > +};
> > +
> > +struct NI_HV_GLB_INTF_RST_CONFIG_t {
> > +	unsigned int intf_rst_p0          :  1; /* bits 0:0 */
> > +	unsigned int intf_rst_p1          :  1; /* bits 1:1 */
> > +	unsigned int intf_rst_p2          :  1; /* bits 2:2 */
> > +	unsigned int intf_rst_p3          :  1; /* bits 3:3 */
> > +	unsigned int intf_rst_p4          :  1; /* bits 4:4 */
> > +	unsigned int mac_rx_rst_p0        :  1; /* bits 5:5 */
> > +	unsigned int mac_rx_rst_p1        :  1; /* bits 6:6 */
> > +	unsigned int mac_rx_rst_p2        :  1; /* bits 7:7 */
> > +	unsigned int mac_rx_rst_p3        :  1; /* bits 8:8 */
> > +	unsigned int mac_rx_rst_p4        :  1; /* bits 9:9 */
> > +	unsigned int mac_tx_rst_p0        :  1; /* bits 10:10 */
> > +	unsigned int mac_tx_rst_p1        :  1; /* bits 11:11 */
> > +	unsigned int mac_tx_rst_p2        :  1; /* bits 12:12 */
> > +	unsigned int mac_tx_rst_p3        :  1; /* bits 13:13 */
> > +	unsigned int mac_tx_rst_p4        :  1; /* bits 14:14 */
> > +	unsigned int port_rst_p5          :  1; /* bits 15:15 */
> > +	unsigned int pcs_rst_p6           :  1; /* bits 16:16 */
> > +	unsigned int pcs_rst_p7           :  1; /* bits 17:17 */
> > +	unsigned int mac_rst_p6           :  1; /* bits 18:18 */
> > +	unsigned int mac_rst_p7           :  1; /* bits 19:19 */
> > +	unsigned int rsrvd1               : 12;
> > +};
> > +
> > +struct NI_HV_GLB_STATIC_CFG_t {
> > +	unsigned int port_to_cpu          :  4; /* bits 3:0 */
> > +	unsigned int mgmt_pt_to_fe_also   :  1; /* bits 4:4 */
> > +	unsigned int txcrc_chk_en         :  1; /* bits 5:5 */
> > +	unsigned int p4_rgmii_tx_clk_phase :  2; /* bits 7:6 */
> > +	unsigned int p4_rgmii_tx_data_order :  1; /* bits 8:8 */
> > +	unsigned int rsrvd1               :  7;
> > +	unsigned int rxmib_mode           :  1; /* bits 16:16 */
> > +	unsigned int txmib_mode           :  1; /* bits 17:17 */
> > +	unsigned int eth_sch_rdy_pkt      :  1; /* bits 18:18 */
> > +	unsigned int rsrvd2               :  1;
> > +	unsigned int rxaui_mode           :  2; /* bits 21:20 */
> > +	unsigned int rxaui_sigdet         :  2; /* bits 23:22 */
> > +	unsigned int cnt_op_mode          :  3; /* bits 26:24 */
> > +	unsigned int rsrvd3               :  5;
> > +};
> > +
> > +struct GLOBAL_BLOCK_RESET_t {
> > +	unsigned int reset_ni             :  1; /* bits 0:0 */
> > +	unsigned int reset_l2fe           :  1; /* bits 1:1 */
> > +	unsigned int reset_l2tm           :  1; /* bits 2:2 */
> > +	unsigned int reset_l3fe           :  1; /* bits 3:3 */
> > +	unsigned int reset_sdram          :  1; /* bits 4:4 */
> > +	unsigned int reset_tqm            :  1; /* bits 5:5 */
> > +	unsigned int reset_pcie0          :  1; /* bits 6:6 */
> > +	unsigned int reset_pcie1          :  1; /* bits 7:7 */
> > +	unsigned int reset_pcie2          :  1; /* bits 8:8 */
> > +	unsigned int reset_sata           :  1; /* bits 9:9 */
> > +	unsigned int reset_gic400         :  1; /* bits 10:10 */
> > +	unsigned int rsrvd1               :  2;
> > +	unsigned int reset_usb            :  1; /* bits 13:13 */
> > +	unsigned int reset_flash          :  1; /* bits 14:14 */
> > +	unsigned int reset_per            :  1; /* bits 15:15 */
> > +	unsigned int reset_dma            :  1; /* bits 16:16 */
> > +	unsigned int reset_rtc            :  1; /* bits 17:17 */
> > +	unsigned int reset_pe0            :  1; /* bits 18:18 */
> > +	unsigned int reset_pe1            :  1; /* bits 19:19 */
> > +	unsigned int reset_rcpu0          :  1; /* bits 20:20 */
> > +	unsigned int reset_rcpu1          :  1; /* bits 21:21 */
> > +	unsigned int reset_sadb           :  1; /* bits 22:22 */
> > +	unsigned int rsrvd2               :  1;
> > +	unsigned int reset_rcrypto        :  1; /* bits 24:24 */
> > +	unsigned int reset_ldma           :  1; /* bits 25:25 */
> > +	unsigned int reset_fbm            :  1; /* bits 26:26 */
> > +	unsigned int reset_eaxi           :  1; /* bits 27:27 */
> > +	unsigned int reset_sd             :  1; /* bits 28:28 */
> > +	unsigned int reset_otprom         :  1; /* bits 29:29 */
> > +	unsigned int rsrvd3               :  2;
> > +};
> > +
> > +struct PER_MDIO_ADDR_t {
> > +	unsigned int mdio_addr            :  5; /* bits 4:0 */
> > +	unsigned int rsrvd1               :  3;
> > +	unsigned int mdio_offset          :  5; /* bits 12:8 */
> > +	unsigned int rsrvd2               :  2;
> > +	unsigned int mdio_rd_wr           :  1; /* bits 15:15 */
> > +	unsigned int mdio_st              :  1; /* bits 16:16 */
> > +	unsigned int rsrvd3               :  1;
> > +	unsigned int mdio_op              :  2; /* bits 19:18 */
> > +	unsigned int rsrvd4               : 12;
> > +};
> > +
> > +struct PER_MDIO_CTRL_t {
> > +	unsigned int mdiodone             :  1; /* bits 0:0 */
> > +	unsigned int rsrvd1               :  6;
> > +	unsigned int mdiostart            :  1; /* bits 7:7 */
> > +	unsigned int rsrvd2               : 24;
> > +};
> > +
> > +struct PER_MDIO_RDDATA_t {
> > +	unsigned int mdio_rddata          : 16; /* bits 15:0 */
> > +	unsigned int rsrvd1               : 16;
> > +};
> > +
> > +/*
> > + * XRAM
> > + */
> > +
> > +struct NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t {
> > +	unsigned int rx_base_addr         : 10; /* bits 9:0 */
> > +	unsigned int rsrvd1               :  6;
> > +	unsigned int rx_top_addr          : 10; /* bits 25:16 */
> > +	unsigned int rsrvd2               :  6;
> > +};
> > +
> > +struct NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t {
> > +	unsigned int tx_base_addr         : 10; /* bits 9:0 */
> > +	unsigned int rsrvd1               :  6;
> > +	unsigned int tx_top_addr          : 10; /* bits 25:16 */
> > +	unsigned int rsrvd2               :  6;
> > +};
> > +
> > +struct NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t {
> > +	unsigned int pkt_wr_ptr           : 10; /* bits 9:0 */
> > +	unsigned int rsrvd1               :  5;
> > +	unsigned int int_colsc_thresh_reached :  1; /* bits 15:15 */
> > +	unsigned int rsrvd2               : 16;
> > +};
> > +
> > +struct NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t {
> > +	unsigned int pkt_rd_ptr           : 10; /* bits 9:0 */
> > +	unsigned int rsrvd1               : 22;
> > +};
> > +
> > +struct NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t {
> > +	unsigned int pkt_wr_ptr           : 10; /* bits 9:0 */
> > +	unsigned int rsrvd1               : 22;
> > +};
> > +
> > +struct GLOBAL_GLOBAL_CONFIG_t {
> > +	unsigned int rsrvd1               :  4;
> > +	unsigned int wd_reset_subsys_enable :  1; /* bits 4:4 */
> > +	unsigned int rsrvd2               :  1;
> > +	unsigned int wd_reset_all_blocks  :  1; /* bits 6:6 */
> > +	unsigned int wd_reset_remap       :  1; /* bits 7:7 */
> > +	unsigned int wd_reset_ext_reset   :  1; /* bits 8:8 */
> > +	unsigned int ext_reset            :  1; /* bits 9:9 */
> > +	unsigned int cfg_pcie_0_clken     :  1; /* bits 10:10 */
> > +	unsigned int cfg_sata_clken       :  1; /* bits 11:11 */
> > +	unsigned int cfg_pcie_1_clken     :  1; /* bits 12:12 */
> > +	unsigned int rsrvd3               :  1;
> > +	unsigned int cfg_pcie_2_clken     :  1; /* bits 14:14 */
> > +	unsigned int rsrvd4               :  2;
> > +	unsigned int ext_eth_refclk       :  1; /* bits 17:17 */
> > +	unsigned int refclk_sel           :  2; /* bits 19:18 */
> > +	unsigned int rsrvd5               :  7;
> > +	unsigned int l3fe_pd              :  1; /* bits 27:27 */
> > +	unsigned int offload0_pd          :  1; /* bits 28:28 */
> > +	unsigned int offload1_pd          :  1; /* bits 29:29 */
> > +	unsigned int crypto_pd            :  1; /* bits 30:30 */
> > +	unsigned int core_pd              :  1; /* bits 31:31 */
> > +};
> > +
> > +struct GLOBAL_IO_DRIVE_CONTROL_t {
> > +	unsigned int gmac_dp              :  3; /* bits 2:0 */
> > +	unsigned int gmac_dn              :  3; /* bits 5:3 */
> > +	unsigned int gmac_mode            :  2; /* bits 7:6 */
> > +	unsigned int gmac_ds              :  1; /* bits 8:8 */
> > +	unsigned int flash_ds             :  1; /* bits 9:9 */
> > +	unsigned int nu_ds                :  1; /* bits 10:10 */
> > +	unsigned int ssp_ds               :  1; /* bits 11:11 */
> > +	unsigned int spi_ds               :  1; /* bits 12:12 */
> > +	unsigned int gpio_ds              :  1; /* bits 13:13 */
> > +	unsigned int misc_ds              :  1; /* bits 14:14 */
> > +	unsigned int eaxi_ds              :  1; /* bits 15:15 */
> > +	unsigned int sd_ds                :  8; /* bits 23:16 */
> > +	unsigned int rsrvd1               :  8;
> > +};
> > +
> > +struct NI_HV_GLB_INIT_DONE_t {
> > +	unsigned int rsrvd1               :  1;
> > +	unsigned int ni_init_done         :  1; /* bits 1:1 */
> > +	unsigned int rsrvd2               : 30;
> > +};
> > +
> > +struct NI_HV_PT_PORT_GLB_CFG_t {
> > +	unsigned int speed                :  1; /* bits 0:0 */
> > +	unsigned int duplex               :  1; /* bits 1:1 */
> > +	unsigned int link_status          :  1; /* bits 2:2 */
> > +	unsigned int link_stat_mask       :  1; /* bits 3:3 */
> > +	unsigned int rsrvd1               :  7;
> > +	unsigned int power_dwn_rx         :  1; /* bits 11:11 */
> > +	unsigned int power_dwn_tx         :  1; /* bits 12:12 */
> > +	unsigned int tx_intf_lp_time      :  1; /* bits 13:13 */
> > +	unsigned int rsrvd2               : 18;
> > +};
> > +
> > +#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
> > 
> 

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 659 bytes
Desc: not available
URL: <https://lists.denx.de/pipermail/u-boot/attachments/20200910/d414a535/attachment.sig>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v2 1/3] net: cortina_ni: Add eth support for Cortina Access CAxxxx SoCs
  2020-09-10 23:54   ` Tom Rini
@ 2020-09-10 23:56     ` Alex Nemirovsky
  2020-09-24  1:00     ` Alex Nemirovsky
  1 sibling, 0 replies; 9+ messages in thread
From: Alex Nemirovsky @ 2020-09-10 23:56 UTC (permalink / raw)
  To: u-boot

Will do. Thanks Tom.

Abbie, please review.

> On Sep 10, 2020, at 4:54 PM, Tom Rini <trini@konsulko.com> wrote:
> 
> On Thu, Sep 10, 2020 at 11:18:46PM +0000, Alex Nemirovsky wrote:
> 
>> bump.
> 
> Sorry, I've meant to reply on some of this.  Please fix the usage of
> ca_status_t and use the normal errno values.  Make sure that
> checkpatch.pl is happy about formatting, etc.  Please also check for
> existing standard structs, etc, that can be used rather than creating
> new ones.
> 
>> 
>>> On Jul 30, 2020, at 12:05 PM, Alex Nemirovsky <alex.nemirovsky@cortina-access.com> wrote:
>>> 
>>> From: Aaron Tseng <aaron.tseng@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.tseng@cortina-access.com>
>>> Signed-off-by: Alex Nemirovsky <alex.nemirovsky@cortina-access.com>
>>> Signed-off-by: Abbie Chang <abbie.chang@cortina-access.com>
>>> 
>>> CC: Joe Hershberger <joe.hershberger@ni.com>
>>> CC: Abbie Chang <abbie.chang@Cortina-Access.com>
>>> CC: Tom Rini <trini@konsulko.com>
>>> 
>>> ---
>>> 
>>> Changes in v2:
>>> - clean up old debug code
>>> - reference CRC functions already provided in u-boot core
>>> - remove unused code, ex: CA_IN/CA_OUT
>>> - refactor the design of register read/write, union -> struct
>>> - remove platform dependent code
>>> 
>>> MAINTAINERS              |    4 +
>>> drivers/net/Kconfig      |    7 +
>>> drivers/net/Makefile     |    1 +
>>> drivers/net/cortina_ni.c | 1168 ++++++++++++++++++++++++++++++++++++++++++++++
>>> drivers/net/cortina_ni.h |  435 +++++++++++++++++
>>> 5 files changed, 1615 insertions(+)
>>> create mode 100644 drivers/net/cortina_ni.c
>>> create mode 100644 drivers/net/cortina_ni.h
>>> 
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index db8cecd..272caca 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -182,6 +182,8 @@ F:	drivers/gpio/cortina_gpio.c
>>> F:	drivers/watchdog/cortina_wdt.c
>>> F:	drivers/serial/serial_cortina.c
>>> F:	drivers/mmc/ca_dw_mmc.c
>>> +F:	drivers/net/cortina_ni.c
>>> +F:	drivers/net/cortina_ni.h
>>> 
>>> ARM/CZ.NIC TURRIS MOX SUPPORT
>>> M:	Marek Behun <marek.behun@nic.cz>
>>> @@ -738,6 +740,8 @@ F:	drivers/gpio/cortina_gpio.c
>>> F:	drivers/watchdog/cortina_wdt.c
>>> F:	drivers/serial/serial_cortina.c
>>> F:	drivers/mmc/ca_dw_mmc.c
>>> +F:	drivers/net/cortina_ni.c
>>> +F:	drivers/net/cortina_ni.h
>>> 
>>> MIPS MSCC
>>> M:	Gregory CLEMENT <gregory.clement@bootlin.com>
>>> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
>>> index bb23f73..616d238 100644
>>> --- a/drivers/net/Kconfig
>>> +++ b/drivers/net/Kconfig
>>> @@ -149,6 +149,13 @@ config BCMGENET
>>> 	help
>>> 	  This driver supports the BCMGENET Ethernet MAC.
>>> 
>>> +config CORTINA_NI_ENET
>>> +	bool "Cortina-Access Ethernet driver"
>>> +	depends on DM_ETH && CORTINA_PLATFORM
>>> +	help
>>> +	  This driver supports the Cortina-Access Ethernet MAC for
>>> +	  all supported CAxxxx SoCs.
>>> +
>>> config DWC_ETH_QOS
>>> 	bool "Synopsys DWC Ethernet QOS device support"
>>> 	depends on DM_ETH
>>> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
>>> index 383ed1c..1d6ec4f 100644
>>> --- a/drivers/net/Makefile
>>> +++ b/drivers/net/Makefile
>>> @@ -14,6 +14,7 @@ obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
>>> obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
>>> obj-$(CONFIG_BCM_SF2_ETH_GMAC) += bcm-sf2-eth-gmac.o
>>> obj-$(CONFIG_CALXEDA_XGMAC) += calxedaxgmac.o
>>> +obj-$(CONFIG_CORTINA_NI_ENET) += cortina_ni.o
>>> obj-$(CONFIG_CS8900) += cs8900.o
>>> obj-$(CONFIG_TULIP) += dc2114x.o
>>> obj-$(CONFIG_ETH_DESIGNWARE) += designware.o
>>> diff --git a/drivers/net/cortina_ni.c b/drivers/net/cortina_ni.c
>>> new file mode 100644
>>> index 0000000..7acfa6a
>>> --- /dev/null
>>> +++ b/drivers/net/cortina_ni.c
>>> @@ -0,0 +1,1168 @@
>>> +// SPDX-License-Identifier: GPL-2.0+
>>> +
>>> +/*
>>> + * Copyright (C) 2020 Cortina Access Inc.
>>> + * Author: Aaron Tseng <aaron.tseng@cortina-access.com>
>>> + *
>>> + * Ethernet MAC Driver for all supported CAxxxx SoCs
>>> + */
>>> +
>>> +#include <common.h>
>>> +#include <command.h>
>>> +#include <malloc.h>
>>> +#include <net.h>
>>> +#include <miiphy.h>
>>> +#include <env.h>
>>> +#include <linux/delay.h>
>>> +#include <u-boot/crc.h>
>>> +#include <led.h>
>>> +
>>> +#include "cortina_ni.h"
>>> +
>>> +#define HEADER_A_SIZE	8
>>> +
>>> +enum ca_led_state_t {
>>> +	CA_LED_OFF = 0,
>>> +	CA_LED_ON = 1,
>>> +};
>>> +
>>> +static struct udevice   *curr_dev;
>>> +static int ca_ni_ofdata_to_platdata(struct udevice *dev);
>>> +
>>> +static u32 *rdwrptr_adv_one(u32 *x, unsigned long base, unsigned long max)
>>> +{
>>> +	if (x + 1 >= (u32 *)max)
>>> +		return (u32 *)base;
>>> +	else
>>> +		return (x + 1);
>>> +}
>>> +
>>> +static int phyaddr_to_port(int phy_addr)
>>> +{
>>> +	int idx;
>>> +
>>> +	for (idx = 0; idx < NI_PORT_MAX; idx++)
>>> +		if (phy_addr == port_map[idx].phy_addr)
>>> +			return port_map[idx].active_port;
>>> +	return 0;
>>> +}
>>> +
>>> +static int port_to_phyaddr(int active_port)
>>> +{
>>> +	int idx;
>>> +
>>> +	for (idx = 0; idx < NI_PORT_MAX; idx++)
>>> +		if (active_port == port_map[idx].active_port)
>>> +			return port_map[idx].phy_addr;
>>> +	return 0;
>>> +}
>>> +
>>> +static u32 REG_TO_U32(void *reg)
>>> +{
>>> +	return *(u32 *)reg;
>>> +}
>>> +
>>> +static void ca_reg_read(void *reg, u64 base, u64 offset)
>>> +{
>>> +	u32 *val = (u32 *)reg;
>>> +
>>> +	*val = readl(KSEG1_ATU_XLAT(base + offset));
>>> +}
>>> +
>>> +static void ca_reg_write(void *reg, u64 base, u64 offset)
>>> +{
>>> +	u32 val = *(u32 *)reg;
>>> +
>>> +	writel(val, KSEG1_ATU_XLAT(base + offset));
>>> +}
>>> +
>>> +static enum ca_status_t ca_mdio_write_rgmii(unsigned int addr,
>>> +					    unsigned int offset,
>>> +					    unsigned short data)
>>> +{
>>> +	struct PER_MDIO_ADDR_t  mdio_addr;
>>> +	struct PER_MDIO_CTRL_t  mdio_ctrl;
>>> +	/* up to 10000 cycles*/
>>> +	unsigned int      loop_wait = __MDIO_ACCESS_TIMEOUT;
>>> +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
>>> +
>>> +	memset(&mdio_addr, 0, sizeof(mdio_addr));
>>> +	mdio_addr.mdio_addr   = addr;
>>> +	mdio_addr.mdio_offset = offset;
>>> +	mdio_addr.mdio_rd_wr  = __MDIO_WR_FLAG;
>>> +	ca_reg_write(&mdio_addr, (u64)priv->per_mdio_base_addr,
>>> +		     PER_MDIO_ADDR_OFFSET);
>>> +	ca_reg_write(&data, (u64)priv->per_mdio_base_addr,
>>> +		     PER_MDIO_WRDATA_OFFSET);
>>> +
>>> +	debug("%s: mdio_addr=0x%x\n", __func__, REG_TO_U32(&mdio_addr));
>>> +
>>> +	memset(&mdio_ctrl, 0, sizeof(mdio_ctrl));
>>> +	mdio_ctrl.mdiostart = 1;
>>> +	ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
>>> +		     PER_MDIO_CTRL_OFFSET);
>>> +
>>> +	debug("%s: phy_addr=%d, offset=%d, data=0x%x\n",
>>> +	      __func__, addr, offset, data);
>>> +
>>> +	do {
>>> +		ca_reg_read(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
>>> +			    PER_MDIO_CTRL_OFFSET);
>>> +		if (mdio_ctrl.mdiodone) {
>>> +			ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
>>> +				     PER_MDIO_CTRL_OFFSET);
>>> +			return CA_E_OK;
>>> +		}
>>> +	} while (--loop_wait);
>>> +
>>> +	printf("%s: PHY write timeout!!!\n", __func__);
>>> +	return CA_E_TIMEOUT;
>>> +}
>>> +
>>> +enum ca_status_t ca_mdio_write(unsigned int     addr,
>>> +			       unsigned int     offset,
>>> +			       unsigned short   data)
>>> +{
>>> +	u32 reg_addr, reg_val;
>>> +	struct NI_MDIO_OPER_T mdio_oper;
>>> +
>>> +	/* support range: 1~31*/
>>> +	if (addr < CA_MDIO_ADDR_MIN || addr > CA_MDIO_ADDR_MAX)
>>> +		return CA_E_PARAM;
>>> +
>>> +	/* the phy addr 5 is connect to RGMII */
>>> +	if (addr >= 5)
>>> +		return ca_mdio_write_rgmii(addr, offset, data);
>>> +
>>> +	memset(&mdio_oper, 0, sizeof(mdio_oper));
>>> +	mdio_oper.reg_off = offset;
>>> +	mdio_oper.phy_addr = addr;
>>> +	mdio_oper.reg_base = CA_NI_MDIO_REG_BASE;
>>> +	reg_val = data;
>>> +	memcpy(&reg_addr, &mdio_oper, sizeof(reg_addr));
>>> +	ca_reg_write(&reg_val, (u64)reg_addr, 0);
>>> +
>>> +	debug("%s: mdio_oper=0x%x, data=0x%x\n",
>>> +	      __func__, REG_TO_U32(&mdio_oper), data);
>>> +	return CA_E_OK;
>>> +}
>>> +
>>> +static enum ca_status_t ca_mdio_read_rgmii(unsigned int addr,
>>> +					   unsigned int offset,
>>> +					   unsigned short *data)
>>> +{
>>> +	struct PER_MDIO_ADDR_t  mdio_addr;
>>> +	struct PER_MDIO_CTRL_t  mdio_ctrl;
>>> +	struct PER_MDIO_RDDATA_t  read_data;
>>> +	unsigned int loop_wait = __MDIO_ACCESS_TIMEOUT;
>>> +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
>>> +
>>> +	memset(&mdio_addr, 0, sizeof(mdio_addr));
>>> +	mdio_addr.mdio_addr   = addr;
>>> +	mdio_addr.mdio_offset = offset;
>>> +	mdio_addr.mdio_rd_wr  = __MDIO_RD_FLAG;
>>> +	ca_reg_write(&mdio_addr, (u64)priv->per_mdio_base_addr,
>>> +		     PER_MDIO_ADDR_OFFSET);
>>> +
>>> +	memset(&mdio_ctrl, 0, sizeof(mdio_ctrl));
>>> +	mdio_ctrl.mdiostart = 1;
>>> +	ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
>>> +		     PER_MDIO_CTRL_OFFSET);
>>> +
>>> +	do {
>>> +		ca_reg_read(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
>>> +			    PER_MDIO_CTRL_OFFSET);
>>> +		if (mdio_ctrl.mdiodone) {
>>> +			ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
>>> +				     PER_MDIO_CTRL_OFFSET);
>>> +			ca_reg_read(&read_data, (u64)priv->per_mdio_base_addr,
>>> +				    PER_MDIO_RDDATA_OFFSET);
>>> +			*data = read_data.mdio_rddata;
>>> +			return CA_E_OK;
>>> +		}
>>> +	} while (--loop_wait);
>>> +
>>> +	printf("%s: CA_E_TIMEOUT!!\n", __func__);
>>> +	return CA_E_TIMEOUT;
>>> +}
>>> +
>>> +enum ca_status_t ca_mdio_read(unsigned int      addr,
>>> +			      unsigned int	offset,
>>> +			      unsigned short	*data)
>>> +{
>>> +	u32 reg_addr, reg_val;
>>> +	struct NI_MDIO_OPER_T  mdio_oper;
>>> +
>>> +	if (!data)
>>> +		return CA_E_PARAM;
>>> +
>>> +	/* support range: 1~31*/
>>> +	if (addr < CA_MDIO_ADDR_MIN || addr > CA_MDIO_ADDR_MAX)
>>> +		return CA_E_PARAM;
>>> +
>>> +	/* the phy addr 5 is connect to RGMII */
>>> +	if (addr >= 5)
>>> +		return  ca_mdio_read_rgmii(addr, offset, data);
>>> +
>>> +	memset(&mdio_oper, 0, sizeof(mdio_oper));
>>> +	mdio_oper.reg_off = offset;
>>> +	mdio_oper.phy_addr = addr;
>>> +	mdio_oper.reg_base = CA_NI_MDIO_REG_BASE;
>>> +	reg_val = *data;
>>> +	memcpy(&reg_addr, &mdio_oper, sizeof(reg_addr));
>>> +	ca_reg_read(&reg_val, (u64)reg_addr, 0);
>>> +	*data = reg_val;
>>> +	return CA_E_OK;
>>> +}
>>> +
>>> +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);
>>> +}
>>> +
>>> +static int cortina_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
>>> +{
>>> +	unsigned short data;
>>> +
>>> +	ca_mdio_read(addr, reg, &data);
>>> +	return data;
>>> +}
>>> +
>>> +static int cortina_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
>>> +			      u16 val)
>>> +{
>>> +	ca_mdio_write(addr, reg, val);
>>> +	return 0;
>>> +}
>>> +
>>> +static void ca_ni_setup_mac_addr(void)
>>> +{
>>> +	unsigned char mac[6];
>>> +
>>> +	struct NI_HV_GLB_MAC_ADDR_CFG0_t	mac_addr_cfg0;
>>> +	struct NI_HV_GLB_MAC_ADDR_CFG1_t	mac_addr_cfg1;
>>> +	struct NI_HV_PT_PORT_STATIC_CFG_t	port_static_cfg;
>>> +	struct NI_HV_XRAM_CPUXRAM_CFG_t		cpuxram_cfg;
>>> +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
>>> +
>>> +	/* parsing ethaddr and set to NI registers. */
>>> +	if (eth_env_get_enetaddr("ethaddr", mac)) {
>>> +		/* The complete MAC address consists of
>>> +		 * {MAC_ADDR0_mac_addr0[0-3], MAC_ADDR1_mac_addr1[4],
>>> +		 * PT_PORT_STATIC_CFG_mac_addr6[5]}.
>>> +		 */
>>> +		mac_addr_cfg0.mac_addr0 = (mac[0] << 24) + (mac[1] << 16) +
>>> +					  (mac[2] << 8) + mac[3];
>>> +		ca_reg_write(&mac_addr_cfg0, (u64)priv->ni_hv_base_addr,
>>> +			     NI_HV_GLB_MAC_ADDR_CFG0_OFFSET);
>>> +
>>> +		memset(&mac_addr_cfg1, 0, sizeof(mac_addr_cfg1));
>>> +		mac_addr_cfg1.mac_addr1 = mac[4];
>>> +		ca_reg_write(&mac_addr_cfg1, (u64)priv->ni_hv_base_addr,
>>> +			     NI_HV_GLB_MAC_ADDR_CFG1_OFFSET);
>>> +
>>> +		ca_reg_read(&port_static_cfg, (u64)priv->ni_hv_base_addr,
>>> +			    NI_HV_PT_PORT_STATIC_CFG_OFFSET +
>>> +			    (APB0_NI_HV_PT_STRIDE * active_port));
>>> +
>>> +		port_static_cfg.mac_addr6 = mac[5];
>>> +		ca_reg_write(&port_static_cfg, (u64)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 */
>>> +		ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
>>> +			    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
>>> +		cpuxram_cfg.xram_mgmt_promisc_mode = 0;
>>> +		cpuxram_cfg.rx_0_cpu_pkt_dis = 0;
>>> +		cpuxram_cfg.tx_0_cpu_pkt_dis = 0;
>>> +		ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
>>> +			     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
>>> +	} else {
>>> +		/* received all packets(promiscuous mode) */
>>> +		ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
>>> +			    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
>>> +		cpuxram_cfg.xram_mgmt_promisc_mode = 3;
>>> +		cpuxram_cfg.rx_0_cpu_pkt_dis = 0;
>>> +		cpuxram_cfg.tx_0_cpu_pkt_dis = 0;
>>> +		ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
>>> +			     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
>>> +	}
>>> +}
>>> +
>>> +static void ca_ni_enable_tx_rx(void)
>>> +{
>>> +	struct NI_HV_PT_RXMAC_CFG_t rxmac_cfg;
>>> +	struct NI_HV_PT_TXMAC_CFG_t txmac_cfg;
>>> +
>>> +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
>>> +
>>> +	/* Enable TX and RX functions */
>>> +	ca_reg_read(&rxmac_cfg, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_PT_RXMAC_CFG_OFFSET +
>>> +		    (APB0_NI_HV_PT_STRIDE * active_port));
>>> +	rxmac_cfg.rx_en = 1;
>>> +	ca_reg_write(&rxmac_cfg, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_PT_RXMAC_CFG_OFFSET +
>>> +		     (APB0_NI_HV_PT_STRIDE * active_port));
>>> +
>>> +	ca_reg_read(&txmac_cfg, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_PT_TXMAC_CFG_OFFSET +
>>> +		    (APB0_NI_HV_PT_STRIDE * active_port));
>>> +	txmac_cfg.tx_en = 1;
>>> +	ca_reg_write(&txmac_cfg, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_PT_TXMAC_CFG_OFFSET +
>>> +		     (APB0_NI_HV_PT_STRIDE * active_port));
>>> +}
>>> +
>>> +#define AUTO_SCAN_TIMEOUT	3000		/* 3 seconds */
>>> +__weak int ca_ni_auto_scan_active_port(void)
>>> +{
>>> +	u8	phy_addr;
>>> +	u32	start_time;
>>> +	unsigned short data;
>>> +
>>> +	start_time = get_timer(0);
>>> +	while (get_timer(start_time) < AUTO_SCAN_TIMEOUT) {
>>> +		phy_addr = 1;
>>> +		for (; phy_addr < 6; phy_addr++) {
>>> +			ca_mdio_read(phy_addr, 1, &data);
>>> +			if (data & 0x04) {
>>> +				active_port = phyaddr_to_port(phy_addr);
>>> +				return 0;
>>> +			}
>>> +		}
>>> +	}
>>> +
>>> +	printf("%s: auto scan active_port timeout.\n", __func__);
>>> +	return -1;
>>> +}
>>> +
>>> +__weak int invalid_active_port(int port)
>>> +{
>>> +	if (active_port < NI_PORT_0 || active_port > NI_PORT_4)
>>> +		return -1;
>>> +	else
>>> +		return 0;
>>> +}
>>> +
>>> +static int ca_phy_probe(struct udevice *dev)
>>> +{
>>> +	struct cortina_ni_priv *priv = dev_get_priv(dev);
>>> +	struct phy_device *int_phydev, *ext_phydev;
>>> +	int auto_scan_active_port = 0, tmp_port;
>>> +	char *buf;
>>> +
>>> +	/* Initialize internal phy device */
>>> +	int_phydev = phy_connect(priv->mdio_bus, port_to_phyaddr(NI_PORT_3),
>>> +				 dev, priv->phy_interface);
>>> +	if (int_phydev) {
>>> +		int_phydev->supported &= PHY_GBIT_FEATURES;
>>> +		int_phydev->advertising = int_phydev->supported;
>>> +		phy_config(int_phydev);
>>> +	} else {
>>> +		printf("%s: There is no internal phy device\n", __func__);
>>> +	}
>>> +
>>> +	/* Initialize external phy device */
>>> +	ext_phydev = phy_connect(priv->mdio_bus, port_to_phyaddr(NI_PORT_4),
>>> +				 dev, priv->phy_interface);
>>> +	if (ext_phydev) {
>>> +		ext_phydev->supported &= PHY_GBIT_FEATURES;
>>> +		ext_phydev->advertising = int_phydev->supported;
>>> +		phy_config(ext_phydev);
>>> +	} else {
>>> +		printf("%s: There is no external phy device\n", __func__);
>>> +	}
>>> +
>>> +	/* auto scan the first link up port as active_port */
>>> +	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) {
>>> +		ca_ni_auto_scan_active_port();
>>> +	} else {
>>> +		buf = env_get("active_port");
>>> +		if (buf != 0) {
>>> +			tmp_port = simple_strtoul(buf, NULL, 0);
>>> +			if (invalid_active_port(active_port)) {
>>> +				printf("ERROR: doesn't support this port.");
>>> +				free(dev);
>>> +				free(priv);
>>> +				return 1;
>>> +			}
>>> +
>>> +			active_port = tmp_port;
>>> +		}
>>> +	}
>>> +
>>> +	printf("%s: active_port=%d\n", __func__, active_port);
>>> +	if (active_port == NI_PORT_4)
>>> +		priv->phydev = ext_phydev;
>>> +	else
>>> +		priv->phydev = int_phydev;
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static void ca_ni_led(int port, int status)
>>> +{
>>> +	struct udevice *led_dev;
>>> +	char label[10];
>>> +
>>> +	if (IS_ENABLED(CONFIG_LED_CORTINA)) {
>>> +		snprintf(label, sizeof(label), "led%d", port);
>>> +		debug("%s: set port %d led %s.\n",
>>> +		      __func__, port, status ? "on" : "off");
>>> +		led_get_by_label(label, &led_dev);
>>> +		led_set_state(led_dev, status);
>>> +	}
>>> +}
>>> +
>>> +static void cortina_ni_reset(void)
>>> +{
>>> +	int i;
>>> +	struct NI_HV_GLB_INIT_DONE_t		init_done;
>>> +	struct NI_HV_GLB_INTF_RST_CONFIG_t	intf_rst_config;
>>> +	struct NI_HV_GLB_STATIC_CFG_t		static_cfg;
>>> +	struct GLOBAL_BLOCK_RESET_t		glb_blk_reset;
>>> +
>>> +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
>>> +
>>> +	/* NI global resets */
>>> +	ca_reg_read(&glb_blk_reset, (u64)priv->glb_base_addr,
>>> +		    GLOBAL_BLOCK_RESET_OFFSET);
>>> +	glb_blk_reset.reset_ni = 1;
>>> +	ca_reg_write(&glb_blk_reset, (u64)priv->glb_base_addr,
>>> +		     GLOBAL_BLOCK_RESET_OFFSET);
>>> +	/* Remove resets */
>>> +	glb_blk_reset.reset_ni = 0;
>>> +	ca_reg_write(&glb_blk_reset, (u64)priv->glb_base_addr,
>>> +		     GLOBAL_BLOCK_RESET_OFFSET);
>>> +
>>> +	/* check the ready bit of NI module */
>>> +	for (i = 0; i < NI_READ_POLL_COUNT; i++) {
>>> +		ca_reg_read(&init_done, (u64)priv->ni_hv_base_addr,
>>> +			    NI_HV_GLB_INIT_DONE_OFFSET);
>>> +		if (init_done.ni_init_done)
>>> +			break;
>>> +	}
>>> +	if (i == NI_READ_POLL_COUNT) {
>>> +		printf("%s: NI init done not ready, init_done=0x%x!!!\n",
>>> +		       __func__, init_done.ni_init_done);
>>> +	}
>>> +
>>> +	ca_reg_read(&intf_rst_config, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_GLB_INTF_RST_CONFIG_OFFSET);
>>> +	switch (active_port) {
>>> +	case NI_PORT_0:
>>> +		intf_rst_config.intf_rst_p0 = 0;
>>> +		intf_rst_config.mac_rx_rst_p0 = 0;
>>> +		intf_rst_config.mac_tx_rst_p0 = 0;
>>> +		break;
>>> +	case NI_PORT_1:
>>> +		intf_rst_config.intf_rst_p1 = 0;
>>> +		intf_rst_config.mac_rx_rst_p1 = 0;
>>> +		intf_rst_config.mac_tx_rst_p1 = 0;
>>> +		break;
>>> +	case NI_PORT_2:
>>> +		intf_rst_config.intf_rst_p2 = 0;
>>> +		intf_rst_config.mac_rx_rst_p2 = 0;
>>> +		intf_rst_config.mac_tx_rst_p2 = 0;
>>> +		break;
>>> +	case NI_PORT_3:
>>> +		intf_rst_config.intf_rst_p3 = 0;
>>> +		intf_rst_config.mac_tx_rst_p3 = 0;
>>> +		intf_rst_config.mac_rx_rst_p3 = 0;
>>> +		break;
>>> +	case NI_PORT_4:
>>> +		intf_rst_config.intf_rst_p4 = 0;
>>> +		intf_rst_config.mac_tx_rst_p4 = 0;
>>> +		intf_rst_config.mac_rx_rst_p4 = 0;
>>> +		break;
>>> +	}
>>> +
>>> +	ca_reg_write(&intf_rst_config, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_GLB_INTF_RST_CONFIG_OFFSET);
>>> +
>>> +	/* Only one GMAC can connect to CPU */
>>> +	ca_reg_read(&static_cfg, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_GLB_STATIC_CFG_OFFSET);
>>> +	static_cfg.port_to_cpu = active_port;
>>> +	static_cfg.txmib_mode = 1;
>>> +	static_cfg.rxmib_mode = 1;
>>> +
>>> +	ca_reg_write(&static_cfg, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_GLB_STATIC_CFG_OFFSET);
>>> +}
>>> +
>>> +static int cortina_ni_init(struct udevice *dev)
>>> +{
>>> +	int ret;
>>> +	struct NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t	cpuxram_adrcfg_rx;
>>> +	struct NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t  cpuxram_adrcfg_tx;
>>> +	struct NI_HV_XRAM_CPUXRAM_CFG_t		cpuxram_cfg;
>>> +	struct NI_HV_PT_PORT_STATIC_CFG_t	port_static_cfg;
>>> +	struct NI_HV_PT_PORT_GLB_CFG_t		port_glb_cfg;
>>> +
>>> +	struct cortina_ni_priv *priv = dev_get_priv(dev);
>>> +	struct phy_device *phydev = priv->phydev;
>>> +
>>> +	ret = phy_startup(priv->phydev);
>>> +	if (ret) {
>>> +		ca_ni_led(active_port, CA_LED_OFF);
>>> +		printf("Could not initialize PHY %s, active_port=%d\n",
>>> +		       priv->phydev->dev->name, active_port);
>>> +		return ret;
>>> +	}
>>> +
>>> +	if (!priv->phydev->link) {
>>> +		printf("%s: link down.\n", priv->phydev->dev->name);
>>> +		return 0;
>>> +	}
>>> +
>>> +	ca_ni_led(active_port, CA_LED_ON);
>>> +	printf("PHY ID 0x%08X %dMbps %s duplex\n",
>>> +	       phydev->phy_id, phydev->speed,
>>> +	       phydev->duplex == DUPLEX_HALF ? "half" : "full");
>>> +
>>> +	/* RX XRAM ADDRESS CONFIG (start and end address) */
>>> +	memset(&cpuxram_adrcfg_rx, 0, sizeof(cpuxram_adrcfg_rx));
>>> +	cpuxram_adrcfg_rx.rx_top_addr = RX_TOP_ADDR;
>>> +	cpuxram_adrcfg_rx.rx_base_addr = RX_BASE_ADDR;
>>> +	ca_reg_write(&cpuxram_adrcfg_rx, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_XRAM_CPUXRAM_ADRCFG_RX_OFFSET);
>>> +
>>> +	/* TX XRAM ADDRESS CONFIG (start and end address) */
>>> +	memset(&cpuxram_adrcfg_tx, 0, sizeof(cpuxram_adrcfg_tx));
>>> +	cpuxram_adrcfg_tx.tx_top_addr = TX_TOP_ADDR;
>>> +	cpuxram_adrcfg_tx.tx_base_addr = TX_BASE_ADDR;
>>> +	ca_reg_write(&cpuxram_adrcfg_tx, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_OFFSET);
>>> +
>>> +	/*
>>> +	 * Configuration for Management Ethernet Interface:
>>> +	 * - RGMII 1000 mode or RGMII 100 mode
>>> +	 * - MAC mode
>>> +	 */
>>> +	ca_reg_read(&port_static_cfg, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_PT_PORT_STATIC_CFG_OFFSET +
>>> +		    (APB0_NI_HV_PT_STRIDE * active_port));
>>> +	if (phydev->speed == SPEED_1000) {
>>> +		/* port 4 connects to RGMII PHY */
>>> +		if (phydev->addr == 5)
>>> +			port_static_cfg.int_cfg = GE_MAC_INTF_RGMII_1000;
>>> +		else
>>> +			port_static_cfg.int_cfg = GE_MAC_INTF_GMII;
>>> +	} else {
>>> +		/* port 4 connects to RGMII PHY */
>>> +		if (phydev->addr == 5)
>>> +			port_static_cfg.int_cfg = GE_MAC_INTF_RGMII_100;
>>> +		else
>>> +			port_static_cfg.int_cfg = GE_MAC_INTF_MII;
>>> +	}
>>> +
>>> +	ca_reg_write(&port_static_cfg, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_PT_PORT_STATIC_CFG_OFFSET +
>>> +		     (APB0_NI_HV_PT_STRIDE * active_port));
>>> +
>>> +	ca_reg_read(&port_glb_cfg, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_PT_PORT_GLB_CFG_OFFSET +
>>> +		    (APB0_NI_HV_PT_STRIDE * active_port));
>>> +	port_glb_cfg.speed = phydev->speed == SPEED_10 ? 1 : 0;
>>> +	port_glb_cfg.duplex = phydev->duplex == DUPLEX_HALF ? 1 : 0;
>>> +	ca_reg_write(&port_glb_cfg, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_PT_PORT_GLB_CFG_OFFSET +
>>> +		     (APB0_NI_HV_PT_STRIDE * active_port));
>>> +
>>> +	/* Need to toggle the tx and rx cpu_pkt_dis bit */
>>> +	/* after changing Address config register.      */
>>> +	ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
>>> +	cpuxram_cfg.rx_0_cpu_pkt_dis = 1;
>>> +	cpuxram_cfg.tx_0_cpu_pkt_dis = 1;
>>> +	ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
>>> +
>>> +	ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
>>> +	cpuxram_cfg.rx_0_cpu_pkt_dis = 0;
>>> +	cpuxram_cfg.tx_0_cpu_pkt_dis = 0;
>>> +	ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
>>> +
>>> +	ca_ni_enable_tx_rx();
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +/*********************************************
>>> + * Packet receive routine from Management FE
>>> + * Expects a previously allocated buffer and
>>> + * fills the length
>>> + * Retruns 0 on success -1 on failure
>>> + *******************************************/
>>> +int cortina_ni_recv(struct udevice *netdev)
>>> +{
>>> +	struct cortina_ni_priv *priv = dev_get_priv(netdev);
>>> +	struct NI_HEADER_X_T	header_x;
>>> +	u32			next_link;
>>> +	u32			pktlen = 0;
>>> +	u32			sw_rx_rd_ptr;
>>> +	u32			hw_rx_wr_ptr;
>>> +	u32			*rx_xram_ptr;
>>> +	int			loop;
>>> +	u32			*data_ptr;
>>> +	struct NI_PACKET_STATUS packet_status;
>>> +	struct NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t cpuxram_cpu_sta_rx;
>>> +	struct NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t cpuxram_cpu_cfg_rx;
>>> +	int index = 0;
>>> +	int			blk_num;
>>> +	u8			*ptr;
>>> +
>>> +	/* get the hw write pointer */
>>> +	memset(&cpuxram_cpu_sta_rx, 0, sizeof(cpuxram_cpu_sta_rx));
>>> +	ca_reg_read(&cpuxram_cpu_sta_rx, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET);
>>> +	hw_rx_wr_ptr = cpuxram_cpu_sta_rx.pkt_wr_ptr;
>>> +
>>> +	/* get the sw read pointer */
>>> +	memset(&cpuxram_cpu_cfg_rx, 0, sizeof(cpuxram_cpu_cfg_rx));
>>> +	ca_reg_read(&cpuxram_cpu_cfg_rx, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
>>> +	sw_rx_rd_ptr = cpuxram_cpu_cfg_rx.pkt_rd_ptr;
>>> +
>>> +	debug("%s: NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0 = 0x%p, ", __func__,
>>> +	      priv->ni_hv_base_addr + NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET);
>>> +	debug("NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0 = 0x%p\n",
>>> +	      priv->ni_hv_base_addr + NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
>>> +	debug("%s : RX hw_wr_ptr = %d, sw_rd_ptr = %d\n",
>>> +	      __func__, hw_rx_wr_ptr, sw_rx_rd_ptr);
>>> +
>>> +	while (sw_rx_rd_ptr != hw_rx_wr_ptr) {
>>> +		/* Point to the absolute memory address of XRAM
>>> +		 * where read pointer is
>>> +		 */
>>> +		rx_xram_ptr = (u32 *)
>>> +			      ((unsigned long)NI_XRAM_BASE + sw_rx_rd_ptr * 8);
>>> +
>>> +		/* Wrap around if required */
>>> +		if (rx_xram_ptr >= (u32 *)(unsigned long)priv->rx_xram_end_adr)
>>> +			rx_xram_ptr = (u32 *)
>>> +				      (unsigned long)priv->rx_xram_base_adr;
>>> +
>>> +		/* Checking header XR. Do not update the read pointer yet */
>>> +		/* skip unused 32-bit in Header XR */
>>> +		rx_xram_ptr = rdwrptr_adv_one(rx_xram_ptr,
>>> +					      priv->rx_xram_base_adr,
>>> +					      priv->rx_xram_end_adr);
>>> +
>>> +		memcpy(&header_x, rx_xram_ptr, sizeof(header_x));
>>> +		next_link = header_x.next_link;
>>> +		/* Header XR [31:0] */
>>> +
>>> +		if (*rx_xram_ptr == 0xffffffff)
>>> +			printf("%s: XRAM Error !\n", __func__);
>>> +
>>> +		debug("%s : RX next link 0x%x\n", __func__, next_link);
>>> +		debug("%s : bytes_valid %x\n", __func__, header_x.bytes_valid);
>>> +
>>> +		if (header_x.ownership == 0) {
>>> +			/* point to Packet status [31:0] */
>>> +			rx_xram_ptr = rdwrptr_adv_one(rx_xram_ptr,
>>> +						      priv->rx_xram_base_adr,
>>> +						      priv->rx_xram_end_adr);
>>> +
>>> +			memcpy(&packet_status, rx_xram_ptr,
>>> +			       sizeof(rx_xram_ptr));
>>> +			debug("%s: packet status=0x%x\n",
>>> +			      __func__, REG_TO_U32(&packet_status));
>>> +			if (packet_status.valid == 0) {
>>> +				debug("%s: Invalid Packet !!, ", __func__);
>>> +				debug("next_link=%d\n", next_link);
>>> +
>>> +				/* Update the software read pointer */
>>> +				ca_reg_write(&next_link,
>>> +					     (u64)priv->ni_hv_base_addr,
>>> +					NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
>>> +				return 0;
>>> +			}
>>> +
>>> +			if (packet_status.drop ||
>>> +			    packet_status.runt ||
>>> +			    packet_status.oversize ||
>>> +			    packet_status.jabber ||
>>> +			    packet_status.crc_error ||
>>> +			    packet_status.jumbo) {
>>> +				debug("%s: Error Packet!!, ", __func__);
>>> +				debug("next_link=%d\n", next_link);
>>> +
>>> +				/* Update the software read pointer */
>>> +				ca_reg_write(&next_link,
>>> +					     (u64)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.packet_size > 1518) {
>>> +				debug("%s: Error Packet !! Packet size=%d, ",
>>> +				      __func__, packet_status.packet_size);
>>> +				debug("larger than 1518, next_link=%d\n",
>>> +				      next_link);
>>> +
>>> +				/* Update the software read pointer */
>>> +				ca_reg_write(&next_link,
>>> +					     (u64)priv->ni_hv_base_addr,
>>> +					NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
>>> +				return 0;
>>> +			}
>>> +
>>> +			rx_xram_ptr = rdwrptr_adv_one(rx_xram_ptr,
>>> +						      priv->rx_xram_base_adr,
>>> +						      priv->rx_xram_end_adr);
>>> +
>>> +			pktlen = packet_status.packet_size;
>>> +
>>> +			debug("%s : rx packet length = %d\n",
>>> +			      __func__, packet_status.packet_size);
>>> +
>>> +			rx_xram_ptr = rdwrptr_adv_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 */
>>> +
>>> +			debug("%s: packet data[]=", __func__);
>>> +
>>> +			for (loop = 0; loop <= pktlen / 4; loop++) {
>>> +				ptr = (u8 *)rx_xram_ptr;
>>> +				if (loop < 10)
>>> +					debug("[0x%x]-[0x%x]-[0x%x]-[0x%x]",
>>> +					      ptr[0], ptr[1], ptr[2], ptr[3]);
>>> +				*data_ptr++ = *rx_xram_ptr++;
>>> +				/* Wrap around if required */
>>> +				if (rx_xram_ptr >= (u32 *)
>>> +				    (unsigned long)priv->rx_xram_end_adr) {
>>> +					rx_xram_ptr = (u32 *)(unsigned long)
>>> +						       (priv->rx_xram_base_adr);
>>> +				}
>>> +			}
>>> +
>>> +			debug("\n");
>>> +			net_process_received_packet(net_rx_packets[index],
>>> +						    pktlen);
>>> +			if (++index >= PKTBUFSRX)
>>> +				index = 0;
>>> +			blk_num = net_rx_packets[index][0x2c] * 255 +
>>> +				net_rx_packets[index][0x2d];
>>> +			debug("%s: tftp block number=%d\n", __func__, blk_num);
>>> +
>>> +			/* Update the software read pointer */
>>> +			ca_reg_write(&next_link,
>>> +				     (u64)priv->ni_hv_base_addr,
>>> +				     NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
>>> +		}
>>> +
>>> +		/* get the hw write pointer */
>>> +		ca_reg_read(&cpuxram_cpu_sta_rx, (u64)priv->ni_hv_base_addr,
>>> +			    NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET);
>>> +		hw_rx_wr_ptr = cpuxram_cpu_sta_rx.pkt_wr_ptr;
>>> +
>>> +		/* get the sw read pointer */
>>> +		ca_reg_read(&sw_rx_rd_ptr, (u64)priv->ni_hv_base_addr,
>>> +			    NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
>>> +	}
>>> +	return 0;
>>> +}
>>> +
>>> +static int cortina_ni_send(struct udevice *dev, void *packet, int length)
>>> +{
>>> +	struct cortina_ni_priv *priv = dev_get_priv(dev);
>>> +	u32	hw_tx_rd_ptr = 0;
>>> +	u32	sw_tx_wr_ptr = 0;
>>> +	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	ca_crc32;
>>> +	struct NI_HEADER_X_T	hdr_xt;
>>> +	int		pad = 0;
>>> +	static unsigned char   pkt_buf[2048];
>>> +	u32	*data_ptr;
>>> +	struct NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t cpuxram_cpu_cfg_tx;
>>> +	u8 *ptr;
>>> +
>>> +	if (!packet || length > 2032)
>>> +		return -1;
>>> +
>>> +	/* Get the hardware read pointer */
>>> +	ca_reg_read(&hw_tx_rd_ptr, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET);
>>> +
>>> +	/* Get the software write pointer */
>>> +	ca_reg_read(&sw_tx_wr_ptr, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET);
>>> +
>>> +	debug("%s: NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0=0x%p, ",
>>> +	      __func__,
>>> +	      KSEG1_ATU_XLAT(priv->ni_hv_base_addr +
>>> +			     NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET));
>>> +	debug("NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0=0x%p\n",
>>> +	      KSEG1_ATU_XLAT(priv->ni_hv_base_addr +
>>> +			     NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET));
>>> +	debug("%s : hw_tx_rd_ptr = %d\n", __func__, hw_tx_rd_ptr);
>>> +	debug("%s : sw_tx_wr_ptr = %d\n", __func__, sw_tx_wr_ptr);
>>> +
>>> +	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[HEADER_A_SIZE], (const void *)packet, length);
>>> +
>>> +	pad = 64 - (length + 4);	/* if packet length < 60 */
>>> +	pad = (pad < 0) ? 0 : pad;
>>> +
>>> +	debug("%s: length=%d, pad=%d\n", __func__, length, pad);
>>> +
>>> +	new_pkt_len = length + pad;	/* new packet length */
>>> +
>>> +	pkt_buf_ptr = (unsigned char *)pkt_buf;
>>> +
>>> +	/* Calculate the CRC32, skip 8-byte header_A */
>>> +	ca_crc32 = crc32(0, (u8 *)(pkt_buf_ptr + HEADER_A_SIZE), new_pkt_len);
>>> +
>>> +	debug("%s: crc32 is 0x%x\n", __func__, ca_crc32);
>>> +	debug("%s: ~crc32 is 0x%x\n", __func__, ~ca_crc32);
>>> +	debug("%s: pkt len %d\n", __func__, new_pkt_len);
>>> +	/* should add 8-byte header_! */
>>> +	/* CRC will re-calculated by hardware */
>>> +	memcpy((pkt_buf_ptr + new_pkt_len + HEADER_A_SIZE),
>>> +	       (u8 *)(&ca_crc32), sizeof(ca_crc32));
>>> +	new_pkt_len = new_pkt_len + 4;	/* add CRC */
>>> +
>>> +	valid_bytes = new_pkt_len % 8;
>>> +	valid_bytes = valid_bytes ? valid_bytes : 0;
>>> +	debug("%s: valid_bytes %d\n", __func__, valid_bytes);
>>> +
>>> +	/* should add 8-byte headerA */
>>> +	next_link = sw_tx_wr_ptr +
>>> +		(new_pkt_len + 7 + HEADER_A_SIZE) / 8; /* for headr XT */
>>> +	/* add header */
>>> +	next_link = next_link + 1;
>>> +	/* Wrap around if required */
>>> +	if (next_link > priv->tx_xram_end) {
>>> +		next_link = priv->tx_xram_start +
>>> +			(next_link - (priv->tx_xram_end + 1));
>>> +	}
>>> +
>>> +	debug("%s: TX next_link %x\n", __func__, next_link);
>>> +	memset(&hdr_xt, 0, sizeof(hdr_xt));
>>> +	hdr_xt.ownership = 1;
>>> +	hdr_xt.bytes_valid = valid_bytes;
>>> +	hdr_xt.next_link = next_link;
>>> +
>>> +	tx_xram_ptr = (u32 *)((unsigned long)NI_XRAM_BASE + sw_tx_wr_ptr * 8);
>>> +
>>> +	/* Wrap around if required */
>>> +	if (tx_xram_ptr >= (u32 *)(unsigned long)priv->tx_xram_end_adr)
>>> +		tx_xram_ptr = (u32 *)(unsigned long)priv->tx_xram_base_adr;
>>> +
>>> +	tx_xram_ptr = rdwrptr_adv_one(tx_xram_ptr,
>>> +				      priv->tx_xram_base_adr,
>>> +				      priv->tx_xram_end_adr);
>>> +
>>> +	memcpy(tx_xram_ptr, &hdr_xt, sizeof(*tx_xram_ptr));
>>> +
>>> +	tx_xram_ptr = rdwrptr_adv_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;
>>> +	debug("%s: packet data[]=", __func__);
>>> +
>>> +	/* copy header_A to XRAM */
>>> +	for (loop = 0; loop <= (new_pkt_len + HEADER_A_SIZE) / 4; loop++) {
>>> +		ptr = (u8 *)data_ptr;
>>> +		if ((loop % 4) == 0)
>>> +			debug("\n");
>>> +		debug("[0x%x]-[0x%x]-[0x%x]-[0x%x]-",
>>> +		      ptr[0], ptr[1], ptr[2], ptr[3]);
>>> +
>>> +		*tx_xram_ptr = *data_ptr++;
>>> +		tx_xram_ptr = rdwrptr_adv_one(tx_xram_ptr,
>>> +					      priv->tx_xram_base_adr,
>>> +					      priv->tx_xram_end_adr);
>>> +	}
>>> +	debug("\n");
>>> +
>>> +	/* Publish the software write pointer */
>>> +	cpuxram_cpu_cfg_tx.pkt_wr_ptr = next_link;
>>> +	ca_reg_write(&cpuxram_cpu_cfg_tx,
>>> +		     (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static void cortina_ni_halt(struct udevice *netdev)
>>> +{
>>> +	/* Nothing to do for now. */
>>> +}
>>> +
>>> +#define GPHY_CAL_LEN	6
>>> +struct gphy_cal {
>>> +	u32 reg_off;
>>> +	u32 value;
>>> +};
>>> +
>>> +static struct gphy_cal gphy_cal_vlaues[GPHY_CAL_LEN] = {
>>> +	{0xf43380fc, 0xbcd},
>>> +	{0xf43380dc, 0xeeee},
>>> +	{0xf43380d8, 0xeeee},
>>> +	{0xf43380fc, 0xbce},
>>> +	{0xf43380c0, 0x7777},
>>> +	{0xf43380c4, 0x7777}
>>> +};
>>> +
>>> +__weak 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, 0);
>>> +			mdelay(50);
>>> +		}
>>> +	}
>>> +}
>>> +
>>> +static int ca_mdio_register(struct udevice *dev)
>>> +{
>>> +	struct cortina_ni_priv *priv = dev_get_priv(dev);
>>> +	struct mii_dev *mdio_bus = mdio_alloc();
>>> +	int ret;
>>> +
>>> +	if (!mdio_bus)
>>> +		return -ENOMEM;
>>> +
>>> +	mdio_bus->read = cortina_mdio_read;
>>> +	mdio_bus->write = cortina_mdio_write;
>>> +	snprintf(mdio_bus->name, sizeof(mdio_bus->name), dev->name);
>>> +
>>> +	mdio_bus->priv = (void *)priv;
>>> +
>>> +	ret = mdio_register(mdio_bus);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	priv->mdio_bus = mdio_bus;
>>> +	return 0;
>>> +}
>>> +
>>> +__weak void ca_rgmii_init(struct cortina_ni_priv *priv)
>>> +{
>>> +	/* hardware settings for RGMII port */
>>> +	struct GLOBAL_GLOBAL_CONFIG_t	glb_config;
>>> +	struct GLOBAL_IO_DRIVE_CONTROL_t io_drive_control;
>>> +
>>> +	/* Generating 25Mhz reference clock for switch */
>>> +	ca_reg_read(&glb_config, (u64)priv->glb_base_addr,
>>> +		    GLOBAL_GLOBAL_CONFIG_OFFSET);
>>> +	glb_config.refclk_sel = 0x01;
>>> +	glb_config.ext_reset = 0x01;
>>> +	ca_reg_write(&glb_config, (u64)priv->glb_base_addr,
>>> +		     GLOBAL_GLOBAL_CONFIG_OFFSET);
>>> +
>>> +	mdelay(20);
>>> +
>>> +	/* should do a external reset */
>>> +	ca_reg_read(&glb_config, (u64)priv->glb_base_addr,
>>> +		    GLOBAL_GLOBAL_CONFIG_OFFSET);
>>> +	glb_config.ext_reset = 0x0;
>>> +	ca_reg_write(&glb_config, (u64)priv->glb_base_addr,
>>> +		     GLOBAL_GLOBAL_CONFIG_OFFSET);
>>> +
>>> +	ca_reg_read(&io_drive_control, (u64)priv->glb_base_addr,
>>> +		    GLOBAL_IO_DRIVE_CONTROL_OFFSET);
>>> +	io_drive_control.gmac_mode = 2;
>>> +	io_drive_control.gmac_dn = 1;
>>> +	io_drive_control.gmac_dp = 1;
>>> +	ca_reg_write(&io_drive_control, (u64)priv->glb_base_addr,
>>> +		     GLOBAL_IO_DRIVE_CONTROL_OFFSET);
>>> +}
>>> +
>>> +int ca_eth_initialize(struct udevice *dev)
>>> +{
>>> +	struct cortina_ni_priv *priv;
>>> +	int ret, reg_value;
>>> +
>>> +	priv = dev_get_priv(dev);
>>> +	priv->rx_xram_base_adr	= NI_XRAM_BASE + (RX_BASE_ADDR * 8);
>>> +	priv->rx_xram_end_adr	= NI_XRAM_BASE + ((RX_TOP_ADDR + 1) * 8);
>>> +	priv->rx_xram_start	= RX_BASE_ADDR;
>>> +	priv->rx_xram_end	= RX_TOP_ADDR;
>>> +	priv->tx_xram_base_adr	= NI_XRAM_BASE + (TX_BASE_ADDR * 8);
>>> +	priv->tx_xram_end_adr	= NI_XRAM_BASE + ((TX_TOP_ADDR + 1) * 8);
>>> +	priv->tx_xram_start	= TX_BASE_ADDR;
>>> +	priv->tx_xram_end	= TX_TOP_ADDR;
>>> +
>>> +	curr_dev = dev;
>>> +	debug("%s: rx_base_addr:%x\t rx_top_addr %x\n",
>>> +	      __func__, priv->rx_xram_start, priv->rx_xram_end);
>>> +	debug("%s: tx_base_addr:%x\t tx_top_addr %x\n",
>>> +	      __func__, priv->tx_xram_start, priv->tx_xram_end);
>>> +	debug("%s: rx physical start address = %x end address = %x\n",
>>> +	      __func__, priv->rx_xram_base_adr, priv->rx_xram_end_adr);
>>> +	debug("%s: tx physical start address = %x end address = %x\n",
>>> +	      __func__, priv->tx_xram_base_adr, priv->tx_xram_end_adr);
>>> +
>>> +	/* MDIO register */
>>> +	ret = ca_mdio_register(dev);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	/* set MDIO pre-scale value */
>>> +	ca_reg_read(&reg_value, (u64)priv->per_mdio_base_addr,
>>> +		    PER_MDIO_CFG_OFFSET);
>>> +	reg_value = reg_value | 0x00280000;
>>> +	ca_reg_write(&reg_value, (u64)priv->per_mdio_base_addr,
>>> +		     PER_MDIO_CFG_OFFSET);
>>> +
>>> +	ca_phy_probe(dev);
>>> +	priv->phydev->addr = port_to_phyaddr(active_port);
>>> +
>>> +	ca_ni_led(active_port, CA_LED_ON);
>>> +
>>> +	cortina_ni_reset();
>>> +
>>> +	printf("%s: active_port=%d, phy_addr=%d\n",
>>> +	       __func__, active_port, priv->phydev->addr);
>>> +	printf("%s: phy_id=0x%x, phy_id & PHY_ID_MASK=0x%x\n", __func__,
>>> +	       priv->phydev->phy_id, priv->phydev->phy_id & 0xFFFFFFF0);
>>> +
>>> +	/* parsing ethaddr and set to NI registers. */
>>> +	ca_ni_setup_mac_addr();
>>> +
>>> +#ifdef MIIPHY_REGISTER
>>> +	/* the phy_read and phy_write
>>> +	 * should meet the proto type of miiphy_register
>>> +	 */
>>> +	miiphy_register(dev->name, ca_miiphy_read, ca_miiphy_write);
>>> +#endif
>>> +
>>> +	ca_rgmii_init(priv);
>>> +
>>> +	/* do internal gphy calibration */
>>> +	do_internal_gphy_cal();
>>> +	return 0;
>>> +}
>>> +
>>> +static int cortina_eth_start(struct udevice *dev)
>>> +{
>>> +	return cortina_ni_init(dev);
>>> +}
>>> +
>>> +static int cortina_eth_send(struct udevice *dev, void *packet, int length)
>>> +{
>>> +	return cortina_ni_send(dev, packet, length);
>>> +}
>>> +
>>> +static int cortina_eth_recv(struct udevice *dev, int flags, uchar **packetp)
>>> +{
>>> +	return cortina_ni_recv(dev);
>>> +}
>>> +
>>> +static void cortina_eth_stop(struct udevice *dev)
>>> +{
>>> +	cortina_ni_halt(dev);
>>> +}
>>> +
>>> +static int cortina_eth_probe(struct udevice *dev)
>>> +{
>>> +	return ca_eth_initialize(dev);
>>> +}
>>> +
>>> +static int ca_ni_ofdata_to_platdata(struct udevice *dev)
>>> +{
>>> +	struct cortina_ni_priv *priv = dev_get_priv(dev);
>>> +
>>> +	priv->glb_base_addr = dev_remap_addr_index(dev, 0);
>>> +	if (!priv->glb_base_addr)
>>> +		return -ENOENT;
>>> +	printf("%s: priv->glb_base_addr for index 0 is 0x%p\n",
>>> +	       __func__, priv->glb_base_addr);
>>> +
>>> +	priv->per_mdio_base_addr = dev_remap_addr_index(dev, 1);
>>> +	if (!priv->per_mdio_base_addr)
>>> +		return -ENOENT;
>>> +	printf("%s: priv->per_mdio_base_addr for index 1 is 0x%p\n",
>>> +	       __func__, priv->per_mdio_base_addr);
>>> +
>>> +	priv->ni_hv_base_addr = dev_remap_addr_index(dev, 2);
>>> +	if (!priv->ni_hv_base_addr)
>>> +		return -ENOENT;
>>> +	printf("%s: priv->ni_hv_base_addr for index 2 is 0x%p\n",
>>> +	       __func__, priv->ni_hv_base_addr);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static const struct eth_ops cortina_eth_ops = {
>>> +	.start  = cortina_eth_start,
>>> +	.send   = cortina_eth_send,
>>> +	.recv   = cortina_eth_recv,
>>> +	.stop   = cortina_eth_stop,
>>> +};
>>> +
>>> +static const struct udevice_id cortina_eth_ids[] = {
>>> +	{ .compatible = "eth_cortina" },
>>> +	{ }
>>> +};
>>> +
>>> +U_BOOT_DRIVER(eth_cortina) = {
>>> +	.name   = "eth_cortina",
>>> +	.id     = UCLASS_ETH,
>>> +	.of_match = cortina_eth_ids,
>>> +	.probe  = cortina_eth_probe,
>>> +	.ops    = &cortina_eth_ops,
>>> +	.priv_auto_alloc_size = sizeof(struct cortina_ni_priv),
>>> +	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
>>> +	.ofdata_to_platdata = ca_ni_ofdata_to_platdata,
>>> +};
>>> diff --git a/drivers/net/cortina_ni.h b/drivers/net/cortina_ni.h
>>> new file mode 100644
>>> index 0000000..ff9a396
>>> --- /dev/null
>>> +++ b/drivers/net/cortina_ni.h
>>> @@ -0,0 +1,435 @@
>>> +/* SPDX-License-Identifier: GPL-2.0+ */
>>> +
>>> +/*
>>> + * Copyright (C) 2020 Cortina Access Inc.
>>> + * Author: Aaron Tseng <aaron.tseng@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 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
>>> +
>>> +/* 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 NI_XRAM_BASE                    0xF4500000
>>> +
>>> +enum ca_status_t {
>>> +	CA_E_ERROR          = -1,
>>> +	CA_E_OK             = 0x0,
>>> +	CA_E_RESOURCE       = 0x1,
>>> +	CA_E_PARAM          = 0x2,
>>> +	CA_E_NOT_FOUND      = 0x3,
>>> +	CA_E_CONFLICT       = 0x4,
>>> +	CA_E_TIMEOUT        = 0x5,
>>> +	CA_E_INTERNAL       = 0x6,
>>> +	CA_E_NOT_SUPPORT    = 0x7,
>>> +	CA_E_CONFIG         = 0x8,
>>> +	CA_E_UNAVAIL        = 0x9,
>>> +	CA_E_MEMORY         = 0xa,
>>> +	CA_E_BUSY           = 0xb,
>>> +	CA_E_FULL           = 0xc,
>>> +	CA_E_EMPTY          = 0xd,
>>> +	CA_E_EXISTS         = 0xe,
>>> +	CA_E_DEV            = 0xf,
>>> +	CA_E_PORT           = 0x10,
>>> +	CA_E_LLID           = 0x11,
>>> +	CA_E_VLAN           = 0x12,
>>> +	CA_E_INIT           = 0x13,
>>> +	CA_E_INTF           = 0x14,
>>> +	CA_E_NEXTHOP        = 0x15,
>>> +	CA_E_ROUTE          = 0x16,
>>> +	CA_E_DB_CHANGED     = 0x17,
>>> +	CA_E_INACTIVE       = 0x18,
>>> +	CA_E_ALREADY_SET    = 0x19,
>>> +};
>>> +
>>> +#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;
>>> +	void __iomem    *glb_base_addr;
>>> +	void __iomem    *per_mdio_base_addr;
>>> +	void __iomem    *ni_hv_base_addr;
>>> +
>>> +	struct mii_dev *mdio_bus;
>>> +	struct phy_device *phydev;
>>> +	int phy_interface;
>>> +};
>>> +
>>> +struct NI_HEADER_X_T {
>>> +	unsigned int next_link		: 10; /* bits  9: 0 */
>>> +	unsigned int bytes_valid	:  4; /* bits 13:10 */
>>> +	unsigned int reserved		: 16; /* bits 29:14 */
>>> +	unsigned int hdr_a		:  1; /* bits 30:30 */
>>> +	unsigned int ownership		:  1; /* bits 31:31 */
>>> +};
>>> +
>>> +struct NI_PACKET_STATUS {
>>> +	unsigned int packet_size       : 14; /* bits 13:0 */
>>> +	unsigned int byte_valid        :  4; /* bits 17:14 */
>>> +	unsigned int pfc               :  1; /* bits 18:18 */
>>> +	unsigned int valid             :  1; /* bits 19:19 */
>>> +	unsigned int drop              :  1; /* bits 20:20 */
>>> +	unsigned int runt              :  1; /* bits 21:21 */
>>> +	unsigned int oversize          :  1; /* bits 22:22 */
>>> +	unsigned int jumbo             :  1; /* bits 23:23 */
>>> +	unsigned int link_status       :  1; /* bits 24:24 */
>>> +	unsigned int jabber            :  1; /* bits 25:25 */
>>> +	unsigned int crc_error         :  1; /* bits 26:26 */
>>> +	unsigned int pause             :  1; /* bits 27:27 */
>>> +	unsigned int oam               :  1; /* bits 28:28 */
>>> +	unsigned int unknown_opcode    :  1; /* bits 29:29 */
>>> +	unsigned int multicast         :  1; /* bits 30:30 */
>>> +	unsigned int broadcast         :  1; /* bits 31:31 */
>>> +};
>>> +
>>> +struct NI_MDIO_OPER_T {
>>> +	unsigned int reserved       : 2; /* bits  1:0 */
>>> +	unsigned int reg_off        : 5; /* bits  6:2 */
>>> +	unsigned int phy_addr       : 5; /* bits 11:7 */
>>> +	unsigned int reg_base       : 20; /* bits 31:12 */
>>> +};
>>> +
>>> +enum ca_port_t {
>>> +	NI_PORT_0 = 0,
>>> +	NI_PORT_1,
>>> +	NI_PORT_2,
>>> +	NI_PORT_3,
>>> +	NI_PORT_4,
>>> +	NI_PORT_5,
>>> +	NI_PORT_MAX,
>>> +};
>>> +
>>> +struct port_map_s {
>>> +	int active_port;
>>> +	int phy_addr;
>>> +};
>>> +
>>> +extern struct port_map_s port_map[NI_PORT_MAX];
>>> +extern int active_port;
>>> +
>>> +#define __MDIO_WR_FLAG				(0)
>>> +#define __MDIO_RD_FLAG				(1)
>>> +#define __MDIO_ACCESS_TIMEOUT			(1000000)
>>> +#define CA_MDIO_ADDR_MIN			(1)
>>> +#define CA_MDIO_ADDR_MAX			(31)
>>> +
>>> +#endif /* !__ASSEMBLER__ */
>>> +
>>> +/* Copy from registers.h */
>>> +struct NI_HV_GLB_MAC_ADDR_CFG0_t {
>>> +	unsigned int mac_addr0            : 32; /* bits 31:0 */
>>> +};
>>> +
>>> +struct NI_HV_GLB_MAC_ADDR_CFG1_t {
>>> +	unsigned int mac_addr1            :  8; /* bits 7:0 */
>>> +	unsigned int rsrvd1               : 24;
>>> +};
>>> +
>>> +struct NI_HV_PT_PORT_STATIC_CFG_t {
>>> +	unsigned int int_cfg              :  4; /* bits 3:0 */
>>> +	unsigned int phy_mode             :  1; /* bits 4:4 */
>>> +	unsigned int rmii_clksrc          :  1; /* bits 5:5 */
>>> +	unsigned int inv_clk_in           :  1; /* bits 6:6 */
>>> +	unsigned int inv_clk_out          :  1; /* bits 7:7 */
>>> +	unsigned int inv_rxclk_out        :  1; /* bits 8:8 */
>>> +	unsigned int tx_use_gefifo        :  1; /* bits 9:9 */
>>> +	unsigned int smii_tx_stat         :  1; /* bits 10:10 */
>>> +	unsigned int crs_polarity         :  1; /* bits 11:11 */
>>> +	unsigned int lpbk_mode            :  2; /* bits 13:12 */
>>> +	unsigned int gmii_like_half_duplex_en :  1; /* bits 14:14 */
>>> +	unsigned int sup_tx_to_rx_lpbk_data :  1; /* bits 15:15 */
>>> +	unsigned int rsrvd1               :  8;
>>> +	unsigned int mac_addr6            :  8; /* bits 31:24 */
>>> +};
>>> +
>>> +struct NI_HV_XRAM_CPUXRAM_CFG_t {
>>> +	unsigned int rx_0_cpu_pkt_dis     :  1; /* bits 0:0 */
>>> +	unsigned int rsrvd1               :  8;
>>> +	unsigned int tx_0_cpu_pkt_dis     :  1; /* bits 9:9 */
>>> +	unsigned int rsrvd2               :  1;
>>> +	unsigned int rx_x_drop_err_pkt    :  1; /* bits 11:11 */
>>> +	unsigned int xram_mgmt_dis_drop_ovsz_pkt :  1; /* bits 12:12 */
>>> +	unsigned int xram_mgmt_term_large_pkt :  1; /* bits 13:13 */
>>> +	unsigned int xram_mgmt_promisc_mode :  2; /* bits 15:14 */
>>> +	unsigned int xram_cntr_debug_mode :  1; /* bits 16:16 */
>>> +	unsigned int xram_cntr_op_code    :  2; /* bits 18:17 */
>>> +	unsigned int rsrvd3               :  2;
>>> +	unsigned int xram_rx_mgmtfifo_srst :  1; /* bits 21:21 */
>>> +	unsigned int xram_dma_fifo_srst   :  1; /* bits 22:22 */
>>> +	unsigned int rsrvd4               :  9;
>>> +};
>>> +
>>> +struct NI_HV_PT_RXMAC_CFG_t {
>>> +	unsigned int rx_en                :  1; /* bits 0:0 */
>>> +	unsigned int rsrvd1               :  7;
>>> +	unsigned int rx_flow_disable      :  1; /* bits 8:8 */
>>> +	unsigned int rsrvd2               :  3;
>>> +	unsigned int rx_flow_to_tx_en     :  1; /* bits 12:12 */
>>> +	unsigned int rx_pfc_disable       :  1; /* bits 13:13 */
>>> +	unsigned int rsrvd3               : 15;
>>> +	unsigned int send_pg_data         :  1; /* bits 29:29 */
>>> +	unsigned int rsrvd4               :  2;
>>> +};
>>> +
>>> +struct NI_HV_PT_TXMAC_CFG_t {
>>> +	unsigned int tx_en                :  1; /* bits 0:0 */
>>> +	unsigned int rsrvd1               :  7;
>>> +	unsigned int mac_crc_calc_en      :  1; /* bits 8:8 */
>>> +	unsigned int tx_ipg_sel           :  3; /* bits 11:9 */
>>> +	unsigned int tx_flow_disable      :  1; /* bits 12:12 */
>>> +	unsigned int tx_drain             :  1; /* bits 13:13 */
>>> +	unsigned int tx_pfc_disable       :  1; /* bits 14:14 */
>>> +	unsigned int tx_pau_sel           :  2; /* bits 16:15 */
>>> +	unsigned int rsrvd2               :  9;
>>> +	unsigned int tx_auto_xon          :  1; /* bits 26:26 */
>>> +	unsigned int rsrvd3               :  1;
>>> +	unsigned int pass_thru_hdr        :  1; /* bits 28:28 */
>>> +	unsigned int rsrvd4               :  3;
>>> +};
>>> +
>>> +struct NI_HV_GLB_INTF_RST_CONFIG_t {
>>> +	unsigned int intf_rst_p0          :  1; /* bits 0:0 */
>>> +	unsigned int intf_rst_p1          :  1; /* bits 1:1 */
>>> +	unsigned int intf_rst_p2          :  1; /* bits 2:2 */
>>> +	unsigned int intf_rst_p3          :  1; /* bits 3:3 */
>>> +	unsigned int intf_rst_p4          :  1; /* bits 4:4 */
>>> +	unsigned int mac_rx_rst_p0        :  1; /* bits 5:5 */
>>> +	unsigned int mac_rx_rst_p1        :  1; /* bits 6:6 */
>>> +	unsigned int mac_rx_rst_p2        :  1; /* bits 7:7 */
>>> +	unsigned int mac_rx_rst_p3        :  1; /* bits 8:8 */
>>> +	unsigned int mac_rx_rst_p4        :  1; /* bits 9:9 */
>>> +	unsigned int mac_tx_rst_p0        :  1; /* bits 10:10 */
>>> +	unsigned int mac_tx_rst_p1        :  1; /* bits 11:11 */
>>> +	unsigned int mac_tx_rst_p2        :  1; /* bits 12:12 */
>>> +	unsigned int mac_tx_rst_p3        :  1; /* bits 13:13 */
>>> +	unsigned int mac_tx_rst_p4        :  1; /* bits 14:14 */
>>> +	unsigned int port_rst_p5          :  1; /* bits 15:15 */
>>> +	unsigned int pcs_rst_p6           :  1; /* bits 16:16 */
>>> +	unsigned int pcs_rst_p7           :  1; /* bits 17:17 */
>>> +	unsigned int mac_rst_p6           :  1; /* bits 18:18 */
>>> +	unsigned int mac_rst_p7           :  1; /* bits 19:19 */
>>> +	unsigned int rsrvd1               : 12;
>>> +};
>>> +
>>> +struct NI_HV_GLB_STATIC_CFG_t {
>>> +	unsigned int port_to_cpu          :  4; /* bits 3:0 */
>>> +	unsigned int mgmt_pt_to_fe_also   :  1; /* bits 4:4 */
>>> +	unsigned int txcrc_chk_en         :  1; /* bits 5:5 */
>>> +	unsigned int p4_rgmii_tx_clk_phase :  2; /* bits 7:6 */
>>> +	unsigned int p4_rgmii_tx_data_order :  1; /* bits 8:8 */
>>> +	unsigned int rsrvd1               :  7;
>>> +	unsigned int rxmib_mode           :  1; /* bits 16:16 */
>>> +	unsigned int txmib_mode           :  1; /* bits 17:17 */
>>> +	unsigned int eth_sch_rdy_pkt      :  1; /* bits 18:18 */
>>> +	unsigned int rsrvd2               :  1;
>>> +	unsigned int rxaui_mode           :  2; /* bits 21:20 */
>>> +	unsigned int rxaui_sigdet         :  2; /* bits 23:22 */
>>> +	unsigned int cnt_op_mode          :  3; /* bits 26:24 */
>>> +	unsigned int rsrvd3               :  5;
>>> +};
>>> +
>>> +struct GLOBAL_BLOCK_RESET_t {
>>> +	unsigned int reset_ni             :  1; /* bits 0:0 */
>>> +	unsigned int reset_l2fe           :  1; /* bits 1:1 */
>>> +	unsigned int reset_l2tm           :  1; /* bits 2:2 */
>>> +	unsigned int reset_l3fe           :  1; /* bits 3:3 */
>>> +	unsigned int reset_sdram          :  1; /* bits 4:4 */
>>> +	unsigned int reset_tqm            :  1; /* bits 5:5 */
>>> +	unsigned int reset_pcie0          :  1; /* bits 6:6 */
>>> +	unsigned int reset_pcie1          :  1; /* bits 7:7 */
>>> +	unsigned int reset_pcie2          :  1; /* bits 8:8 */
>>> +	unsigned int reset_sata           :  1; /* bits 9:9 */
>>> +	unsigned int reset_gic400         :  1; /* bits 10:10 */
>>> +	unsigned int rsrvd1               :  2;
>>> +	unsigned int reset_usb            :  1; /* bits 13:13 */
>>> +	unsigned int reset_flash          :  1; /* bits 14:14 */
>>> +	unsigned int reset_per            :  1; /* bits 15:15 */
>>> +	unsigned int reset_dma            :  1; /* bits 16:16 */
>>> +	unsigned int reset_rtc            :  1; /* bits 17:17 */
>>> +	unsigned int reset_pe0            :  1; /* bits 18:18 */
>>> +	unsigned int reset_pe1            :  1; /* bits 19:19 */
>>> +	unsigned int reset_rcpu0          :  1; /* bits 20:20 */
>>> +	unsigned int reset_rcpu1          :  1; /* bits 21:21 */
>>> +	unsigned int reset_sadb           :  1; /* bits 22:22 */
>>> +	unsigned int rsrvd2               :  1;
>>> +	unsigned int reset_rcrypto        :  1; /* bits 24:24 */
>>> +	unsigned int reset_ldma           :  1; /* bits 25:25 */
>>> +	unsigned int reset_fbm            :  1; /* bits 26:26 */
>>> +	unsigned int reset_eaxi           :  1; /* bits 27:27 */
>>> +	unsigned int reset_sd             :  1; /* bits 28:28 */
>>> +	unsigned int reset_otprom         :  1; /* bits 29:29 */
>>> +	unsigned int rsrvd3               :  2;
>>> +};
>>> +
>>> +struct PER_MDIO_ADDR_t {
>>> +	unsigned int mdio_addr            :  5; /* bits 4:0 */
>>> +	unsigned int rsrvd1               :  3;
>>> +	unsigned int mdio_offset          :  5; /* bits 12:8 */
>>> +	unsigned int rsrvd2               :  2;
>>> +	unsigned int mdio_rd_wr           :  1; /* bits 15:15 */
>>> +	unsigned int mdio_st              :  1; /* bits 16:16 */
>>> +	unsigned int rsrvd3               :  1;
>>> +	unsigned int mdio_op              :  2; /* bits 19:18 */
>>> +	unsigned int rsrvd4               : 12;
>>> +};
>>> +
>>> +struct PER_MDIO_CTRL_t {
>>> +	unsigned int mdiodone             :  1; /* bits 0:0 */
>>> +	unsigned int rsrvd1               :  6;
>>> +	unsigned int mdiostart            :  1; /* bits 7:7 */
>>> +	unsigned int rsrvd2               : 24;
>>> +};
>>> +
>>> +struct PER_MDIO_RDDATA_t {
>>> +	unsigned int mdio_rddata          : 16; /* bits 15:0 */
>>> +	unsigned int rsrvd1               : 16;
>>> +};
>>> +
>>> +/*
>>> + * XRAM
>>> + */
>>> +
>>> +struct NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t {
>>> +	unsigned int rx_base_addr         : 10; /* bits 9:0 */
>>> +	unsigned int rsrvd1               :  6;
>>> +	unsigned int rx_top_addr          : 10; /* bits 25:16 */
>>> +	unsigned int rsrvd2               :  6;
>>> +};
>>> +
>>> +struct NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t {
>>> +	unsigned int tx_base_addr         : 10; /* bits 9:0 */
>>> +	unsigned int rsrvd1               :  6;
>>> +	unsigned int tx_top_addr          : 10; /* bits 25:16 */
>>> +	unsigned int rsrvd2               :  6;
>>> +};
>>> +
>>> +struct NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t {
>>> +	unsigned int pkt_wr_ptr           : 10; /* bits 9:0 */
>>> +	unsigned int rsrvd1               :  5;
>>> +	unsigned int int_colsc_thresh_reached :  1; /* bits 15:15 */
>>> +	unsigned int rsrvd2               : 16;
>>> +};
>>> +
>>> +struct NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t {
>>> +	unsigned int pkt_rd_ptr           : 10; /* bits 9:0 */
>>> +	unsigned int rsrvd1               : 22;
>>> +};
>>> +
>>> +struct NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t {
>>> +	unsigned int pkt_wr_ptr           : 10; /* bits 9:0 */
>>> +	unsigned int rsrvd1               : 22;
>>> +};
>>> +
>>> +struct GLOBAL_GLOBAL_CONFIG_t {
>>> +	unsigned int rsrvd1               :  4;
>>> +	unsigned int wd_reset_subsys_enable :  1; /* bits 4:4 */
>>> +	unsigned int rsrvd2               :  1;
>>> +	unsigned int wd_reset_all_blocks  :  1; /* bits 6:6 */
>>> +	unsigned int wd_reset_remap       :  1; /* bits 7:7 */
>>> +	unsigned int wd_reset_ext_reset   :  1; /* bits 8:8 */
>>> +	unsigned int ext_reset            :  1; /* bits 9:9 */
>>> +	unsigned int cfg_pcie_0_clken     :  1; /* bits 10:10 */
>>> +	unsigned int cfg_sata_clken       :  1; /* bits 11:11 */
>>> +	unsigned int cfg_pcie_1_clken     :  1; /* bits 12:12 */
>>> +	unsigned int rsrvd3               :  1;
>>> +	unsigned int cfg_pcie_2_clken     :  1; /* bits 14:14 */
>>> +	unsigned int rsrvd4               :  2;
>>> +	unsigned int ext_eth_refclk       :  1; /* bits 17:17 */
>>> +	unsigned int refclk_sel           :  2; /* bits 19:18 */
>>> +	unsigned int rsrvd5               :  7;
>>> +	unsigned int l3fe_pd              :  1; /* bits 27:27 */
>>> +	unsigned int offload0_pd          :  1; /* bits 28:28 */
>>> +	unsigned int offload1_pd          :  1; /* bits 29:29 */
>>> +	unsigned int crypto_pd            :  1; /* bits 30:30 */
>>> +	unsigned int core_pd              :  1; /* bits 31:31 */
>>> +};
>>> +
>>> +struct GLOBAL_IO_DRIVE_CONTROL_t {
>>> +	unsigned int gmac_dp              :  3; /* bits 2:0 */
>>> +	unsigned int gmac_dn              :  3; /* bits 5:3 */
>>> +	unsigned int gmac_mode            :  2; /* bits 7:6 */
>>> +	unsigned int gmac_ds              :  1; /* bits 8:8 */
>>> +	unsigned int flash_ds             :  1; /* bits 9:9 */
>>> +	unsigned int nu_ds                :  1; /* bits 10:10 */
>>> +	unsigned int ssp_ds               :  1; /* bits 11:11 */
>>> +	unsigned int spi_ds               :  1; /* bits 12:12 */
>>> +	unsigned int gpio_ds              :  1; /* bits 13:13 */
>>> +	unsigned int misc_ds              :  1; /* bits 14:14 */
>>> +	unsigned int eaxi_ds              :  1; /* bits 15:15 */
>>> +	unsigned int sd_ds                :  8; /* bits 23:16 */
>>> +	unsigned int rsrvd1               :  8;
>>> +};
>>> +
>>> +struct NI_HV_GLB_INIT_DONE_t {
>>> +	unsigned int rsrvd1               :  1;
>>> +	unsigned int ni_init_done         :  1; /* bits 1:1 */
>>> +	unsigned int rsrvd2               : 30;
>>> +};
>>> +
>>> +struct NI_HV_PT_PORT_GLB_CFG_t {
>>> +	unsigned int speed                :  1; /* bits 0:0 */
>>> +	unsigned int duplex               :  1; /* bits 1:1 */
>>> +	unsigned int link_status          :  1; /* bits 2:2 */
>>> +	unsigned int link_stat_mask       :  1; /* bits 3:3 */
>>> +	unsigned int rsrvd1               :  7;
>>> +	unsigned int power_dwn_rx         :  1; /* bits 11:11 */
>>> +	unsigned int power_dwn_tx         :  1; /* bits 12:12 */
>>> +	unsigned int tx_intf_lp_time      :  1; /* bits 13:13 */
>>> +	unsigned int rsrvd2               : 18;
>>> +};
>>> +
>>> +#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
>>> 
>> 
> 
> -- 
> Tom

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v2 1/3] net: cortina_ni: Add eth support for Cortina Access CAxxxx SoCs
  2020-09-10 23:54   ` Tom Rini
  2020-09-10 23:56     ` Alex Nemirovsky
@ 2020-09-24  1:00     ` Alex Nemirovsky
  1 sibling, 0 replies; 9+ messages in thread
From: Alex Nemirovsky @ 2020-09-24  1:00 UTC (permalink / raw)
  To: u-boot

Tom,

v3 submitted after Abbie reviewed and updated per your request. 


> On Sep 10, 2020, at 4:54 PM, Tom Rini <trini@konsulko.com> wrote:
> 
> On Thu, Sep 10, 2020 at 11:18:46PM +0000, Alex Nemirovsky wrote:
> 
>> bump.
> 
> Sorry, I've meant to reply on some of this.  Please fix the usage of
> ca_status_t and use the normal errno values.  Make sure that
> checkpatch.pl is happy about formatting, etc.  Please also check for
> existing standard structs, etc, that can be used rather than creating
> new ones.
> 
>> 
>>> On Jul 30, 2020, at 12:05 PM, Alex Nemirovsky <alex.nemirovsky@cortina-access.com> wrote:
>>> 
>>> From: Aaron Tseng <aaron.tseng@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.tseng@cortina-access.com>
>>> Signed-off-by: Alex Nemirovsky <alex.nemirovsky@cortina-access.com>
>>> Signed-off-by: Abbie Chang <abbie.chang@cortina-access.com>
>>> 
>>> CC: Joe Hershberger <joe.hershberger@ni.com>
>>> CC: Abbie Chang <abbie.chang@Cortina-Access.com>
>>> CC: Tom Rini <trini@konsulko.com>
>>> 
>>> ---
>>> 
>>> Changes in v2:
>>> - clean up old debug code
>>> - reference CRC functions already provided in u-boot core
>>> - remove unused code, ex: CA_IN/CA_OUT
>>> - refactor the design of register read/write, union -> struct
>>> - remove platform dependent code
>>> 
>>> MAINTAINERS              |    4 +
>>> drivers/net/Kconfig      |    7 +
>>> drivers/net/Makefile     |    1 +
>>> drivers/net/cortina_ni.c | 1168 ++++++++++++++++++++++++++++++++++++++++++++++
>>> drivers/net/cortina_ni.h |  435 +++++++++++++++++
>>> 5 files changed, 1615 insertions(+)
>>> create mode 100644 drivers/net/cortina_ni.c
>>> create mode 100644 drivers/net/cortina_ni.h
>>> 
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index db8cecd..272caca 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -182,6 +182,8 @@ F:	drivers/gpio/cortina_gpio.c
>>> F:	drivers/watchdog/cortina_wdt.c
>>> F:	drivers/serial/serial_cortina.c
>>> F:	drivers/mmc/ca_dw_mmc.c
>>> +F:	drivers/net/cortina_ni.c
>>> +F:	drivers/net/cortina_ni.h
>>> 
>>> ARM/CZ.NIC TURRIS MOX SUPPORT
>>> M:	Marek Behun <marek.behun@nic.cz>
>>> @@ -738,6 +740,8 @@ F:	drivers/gpio/cortina_gpio.c
>>> F:	drivers/watchdog/cortina_wdt.c
>>> F:	drivers/serial/serial_cortina.c
>>> F:	drivers/mmc/ca_dw_mmc.c
>>> +F:	drivers/net/cortina_ni.c
>>> +F:	drivers/net/cortina_ni.h
>>> 
>>> MIPS MSCC
>>> M:	Gregory CLEMENT <gregory.clement@bootlin.com>
>>> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
>>> index bb23f73..616d238 100644
>>> --- a/drivers/net/Kconfig
>>> +++ b/drivers/net/Kconfig
>>> @@ -149,6 +149,13 @@ config BCMGENET
>>> 	help
>>> 	  This driver supports the BCMGENET Ethernet MAC.
>>> 
>>> +config CORTINA_NI_ENET
>>> +	bool "Cortina-Access Ethernet driver"
>>> +	depends on DM_ETH && CORTINA_PLATFORM
>>> +	help
>>> +	  This driver supports the Cortina-Access Ethernet MAC for
>>> +	  all supported CAxxxx SoCs.
>>> +
>>> config DWC_ETH_QOS
>>> 	bool "Synopsys DWC Ethernet QOS device support"
>>> 	depends on DM_ETH
>>> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
>>> index 383ed1c..1d6ec4f 100644
>>> --- a/drivers/net/Makefile
>>> +++ b/drivers/net/Makefile
>>> @@ -14,6 +14,7 @@ obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
>>> obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
>>> obj-$(CONFIG_BCM_SF2_ETH_GMAC) += bcm-sf2-eth-gmac.o
>>> obj-$(CONFIG_CALXEDA_XGMAC) += calxedaxgmac.o
>>> +obj-$(CONFIG_CORTINA_NI_ENET) += cortina_ni.o
>>> obj-$(CONFIG_CS8900) += cs8900.o
>>> obj-$(CONFIG_TULIP) += dc2114x.o
>>> obj-$(CONFIG_ETH_DESIGNWARE) += designware.o
>>> diff --git a/drivers/net/cortina_ni.c b/drivers/net/cortina_ni.c
>>> new file mode 100644
>>> index 0000000..7acfa6a
>>> --- /dev/null
>>> +++ b/drivers/net/cortina_ni.c
>>> @@ -0,0 +1,1168 @@
>>> +// SPDX-License-Identifier: GPL-2.0+
>>> +
>>> +/*
>>> + * Copyright (C) 2020 Cortina Access Inc.
>>> + * Author: Aaron Tseng <aaron.tseng@cortina-access.com>
>>> + *
>>> + * Ethernet MAC Driver for all supported CAxxxx SoCs
>>> + */
>>> +
>>> +#include <common.h>
>>> +#include <command.h>
>>> +#include <malloc.h>
>>> +#include <net.h>
>>> +#include <miiphy.h>
>>> +#include <env.h>
>>> +#include <linux/delay.h>
>>> +#include <u-boot/crc.h>
>>> +#include <led.h>
>>> +
>>> +#include "cortina_ni.h"
>>> +
>>> +#define HEADER_A_SIZE	8
>>> +
>>> +enum ca_led_state_t {
>>> +	CA_LED_OFF = 0,
>>> +	CA_LED_ON = 1,
>>> +};
>>> +
>>> +static struct udevice   *curr_dev;
>>> +static int ca_ni_ofdata_to_platdata(struct udevice *dev);
>>> +
>>> +static u32 *rdwrptr_adv_one(u32 *x, unsigned long base, unsigned long max)
>>> +{
>>> +	if (x + 1 >= (u32 *)max)
>>> +		return (u32 *)base;
>>> +	else
>>> +		return (x + 1);
>>> +}
>>> +
>>> +static int phyaddr_to_port(int phy_addr)
>>> +{
>>> +	int idx;
>>> +
>>> +	for (idx = 0; idx < NI_PORT_MAX; idx++)
>>> +		if (phy_addr == port_map[idx].phy_addr)
>>> +			return port_map[idx].active_port;
>>> +	return 0;
>>> +}
>>> +
>>> +static int port_to_phyaddr(int active_port)
>>> +{
>>> +	int idx;
>>> +
>>> +	for (idx = 0; idx < NI_PORT_MAX; idx++)
>>> +		if (active_port == port_map[idx].active_port)
>>> +			return port_map[idx].phy_addr;
>>> +	return 0;
>>> +}
>>> +
>>> +static u32 REG_TO_U32(void *reg)
>>> +{
>>> +	return *(u32 *)reg;
>>> +}
>>> +
>>> +static void ca_reg_read(void *reg, u64 base, u64 offset)
>>> +{
>>> +	u32 *val = (u32 *)reg;
>>> +
>>> +	*val = readl(KSEG1_ATU_XLAT(base + offset));
>>> +}
>>> +
>>> +static void ca_reg_write(void *reg, u64 base, u64 offset)
>>> +{
>>> +	u32 val = *(u32 *)reg;
>>> +
>>> +	writel(val, KSEG1_ATU_XLAT(base + offset));
>>> +}
>>> +
>>> +static enum ca_status_t ca_mdio_write_rgmii(unsigned int addr,
>>> +					    unsigned int offset,
>>> +					    unsigned short data)
>>> +{
>>> +	struct PER_MDIO_ADDR_t  mdio_addr;
>>> +	struct PER_MDIO_CTRL_t  mdio_ctrl;
>>> +	/* up to 10000 cycles*/
>>> +	unsigned int      loop_wait = __MDIO_ACCESS_TIMEOUT;
>>> +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
>>> +
>>> +	memset(&mdio_addr, 0, sizeof(mdio_addr));
>>> +	mdio_addr.mdio_addr   = addr;
>>> +	mdio_addr.mdio_offset = offset;
>>> +	mdio_addr.mdio_rd_wr  = __MDIO_WR_FLAG;
>>> +	ca_reg_write(&mdio_addr, (u64)priv->per_mdio_base_addr,
>>> +		     PER_MDIO_ADDR_OFFSET);
>>> +	ca_reg_write(&data, (u64)priv->per_mdio_base_addr,
>>> +		     PER_MDIO_WRDATA_OFFSET);
>>> +
>>> +	debug("%s: mdio_addr=0x%x\n", __func__, REG_TO_U32(&mdio_addr));
>>> +
>>> +	memset(&mdio_ctrl, 0, sizeof(mdio_ctrl));
>>> +	mdio_ctrl.mdiostart = 1;
>>> +	ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
>>> +		     PER_MDIO_CTRL_OFFSET);
>>> +
>>> +	debug("%s: phy_addr=%d, offset=%d, data=0x%x\n",
>>> +	      __func__, addr, offset, data);
>>> +
>>> +	do {
>>> +		ca_reg_read(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
>>> +			    PER_MDIO_CTRL_OFFSET);
>>> +		if (mdio_ctrl.mdiodone) {
>>> +			ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
>>> +				     PER_MDIO_CTRL_OFFSET);
>>> +			return CA_E_OK;
>>> +		}
>>> +	} while (--loop_wait);
>>> +
>>> +	printf("%s: PHY write timeout!!!\n", __func__);
>>> +	return CA_E_TIMEOUT;
>>> +}
>>> +
>>> +enum ca_status_t ca_mdio_write(unsigned int     addr,
>>> +			       unsigned int     offset,
>>> +			       unsigned short   data)
>>> +{
>>> +	u32 reg_addr, reg_val;
>>> +	struct NI_MDIO_OPER_T mdio_oper;
>>> +
>>> +	/* support range: 1~31*/
>>> +	if (addr < CA_MDIO_ADDR_MIN || addr > CA_MDIO_ADDR_MAX)
>>> +		return CA_E_PARAM;
>>> +
>>> +	/* the phy addr 5 is connect to RGMII */
>>> +	if (addr >= 5)
>>> +		return ca_mdio_write_rgmii(addr, offset, data);
>>> +
>>> +	memset(&mdio_oper, 0, sizeof(mdio_oper));
>>> +	mdio_oper.reg_off = offset;
>>> +	mdio_oper.phy_addr = addr;
>>> +	mdio_oper.reg_base = CA_NI_MDIO_REG_BASE;
>>> +	reg_val = data;
>>> +	memcpy(&reg_addr, &mdio_oper, sizeof(reg_addr));
>>> +	ca_reg_write(&reg_val, (u64)reg_addr, 0);
>>> +
>>> +	debug("%s: mdio_oper=0x%x, data=0x%x\n",
>>> +	      __func__, REG_TO_U32(&mdio_oper), data);
>>> +	return CA_E_OK;
>>> +}
>>> +
>>> +static enum ca_status_t ca_mdio_read_rgmii(unsigned int addr,
>>> +					   unsigned int offset,
>>> +					   unsigned short *data)
>>> +{
>>> +	struct PER_MDIO_ADDR_t  mdio_addr;
>>> +	struct PER_MDIO_CTRL_t  mdio_ctrl;
>>> +	struct PER_MDIO_RDDATA_t  read_data;
>>> +	unsigned int loop_wait = __MDIO_ACCESS_TIMEOUT;
>>> +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
>>> +
>>> +	memset(&mdio_addr, 0, sizeof(mdio_addr));
>>> +	mdio_addr.mdio_addr   = addr;
>>> +	mdio_addr.mdio_offset = offset;
>>> +	mdio_addr.mdio_rd_wr  = __MDIO_RD_FLAG;
>>> +	ca_reg_write(&mdio_addr, (u64)priv->per_mdio_base_addr,
>>> +		     PER_MDIO_ADDR_OFFSET);
>>> +
>>> +	memset(&mdio_ctrl, 0, sizeof(mdio_ctrl));
>>> +	mdio_ctrl.mdiostart = 1;
>>> +	ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
>>> +		     PER_MDIO_CTRL_OFFSET);
>>> +
>>> +	do {
>>> +		ca_reg_read(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
>>> +			    PER_MDIO_CTRL_OFFSET);
>>> +		if (mdio_ctrl.mdiodone) {
>>> +			ca_reg_write(&mdio_ctrl, (u64)priv->per_mdio_base_addr,
>>> +				     PER_MDIO_CTRL_OFFSET);
>>> +			ca_reg_read(&read_data, (u64)priv->per_mdio_base_addr,
>>> +				    PER_MDIO_RDDATA_OFFSET);
>>> +			*data = read_data.mdio_rddata;
>>> +			return CA_E_OK;
>>> +		}
>>> +	} while (--loop_wait);
>>> +
>>> +	printf("%s: CA_E_TIMEOUT!!\n", __func__);
>>> +	return CA_E_TIMEOUT;
>>> +}
>>> +
>>> +enum ca_status_t ca_mdio_read(unsigned int      addr,
>>> +			      unsigned int	offset,
>>> +			      unsigned short	*data)
>>> +{
>>> +	u32 reg_addr, reg_val;
>>> +	struct NI_MDIO_OPER_T  mdio_oper;
>>> +
>>> +	if (!data)
>>> +		return CA_E_PARAM;
>>> +
>>> +	/* support range: 1~31*/
>>> +	if (addr < CA_MDIO_ADDR_MIN || addr > CA_MDIO_ADDR_MAX)
>>> +		return CA_E_PARAM;
>>> +
>>> +	/* the phy addr 5 is connect to RGMII */
>>> +	if (addr >= 5)
>>> +		return  ca_mdio_read_rgmii(addr, offset, data);
>>> +
>>> +	memset(&mdio_oper, 0, sizeof(mdio_oper));
>>> +	mdio_oper.reg_off = offset;
>>> +	mdio_oper.phy_addr = addr;
>>> +	mdio_oper.reg_base = CA_NI_MDIO_REG_BASE;
>>> +	reg_val = *data;
>>> +	memcpy(&reg_addr, &mdio_oper, sizeof(reg_addr));
>>> +	ca_reg_read(&reg_val, (u64)reg_addr, 0);
>>> +	*data = reg_val;
>>> +	return CA_E_OK;
>>> +}
>>> +
>>> +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);
>>> +}
>>> +
>>> +static int cortina_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
>>> +{
>>> +	unsigned short data;
>>> +
>>> +	ca_mdio_read(addr, reg, &data);
>>> +	return data;
>>> +}
>>> +
>>> +static int cortina_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
>>> +			      u16 val)
>>> +{
>>> +	ca_mdio_write(addr, reg, val);
>>> +	return 0;
>>> +}
>>> +
>>> +static void ca_ni_setup_mac_addr(void)
>>> +{
>>> +	unsigned char mac[6];
>>> +
>>> +	struct NI_HV_GLB_MAC_ADDR_CFG0_t	mac_addr_cfg0;
>>> +	struct NI_HV_GLB_MAC_ADDR_CFG1_t	mac_addr_cfg1;
>>> +	struct NI_HV_PT_PORT_STATIC_CFG_t	port_static_cfg;
>>> +	struct NI_HV_XRAM_CPUXRAM_CFG_t		cpuxram_cfg;
>>> +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
>>> +
>>> +	/* parsing ethaddr and set to NI registers. */
>>> +	if (eth_env_get_enetaddr("ethaddr", mac)) {
>>> +		/* The complete MAC address consists of
>>> +		 * {MAC_ADDR0_mac_addr0[0-3], MAC_ADDR1_mac_addr1[4],
>>> +		 * PT_PORT_STATIC_CFG_mac_addr6[5]}.
>>> +		 */
>>> +		mac_addr_cfg0.mac_addr0 = (mac[0] << 24) + (mac[1] << 16) +
>>> +					  (mac[2] << 8) + mac[3];
>>> +		ca_reg_write(&mac_addr_cfg0, (u64)priv->ni_hv_base_addr,
>>> +			     NI_HV_GLB_MAC_ADDR_CFG0_OFFSET);
>>> +
>>> +		memset(&mac_addr_cfg1, 0, sizeof(mac_addr_cfg1));
>>> +		mac_addr_cfg1.mac_addr1 = mac[4];
>>> +		ca_reg_write(&mac_addr_cfg1, (u64)priv->ni_hv_base_addr,
>>> +			     NI_HV_GLB_MAC_ADDR_CFG1_OFFSET);
>>> +
>>> +		ca_reg_read(&port_static_cfg, (u64)priv->ni_hv_base_addr,
>>> +			    NI_HV_PT_PORT_STATIC_CFG_OFFSET +
>>> +			    (APB0_NI_HV_PT_STRIDE * active_port));
>>> +
>>> +		port_static_cfg.mac_addr6 = mac[5];
>>> +		ca_reg_write(&port_static_cfg, (u64)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 */
>>> +		ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
>>> +			    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
>>> +		cpuxram_cfg.xram_mgmt_promisc_mode = 0;
>>> +		cpuxram_cfg.rx_0_cpu_pkt_dis = 0;
>>> +		cpuxram_cfg.tx_0_cpu_pkt_dis = 0;
>>> +		ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
>>> +			     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
>>> +	} else {
>>> +		/* received all packets(promiscuous mode) */
>>> +		ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
>>> +			    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
>>> +		cpuxram_cfg.xram_mgmt_promisc_mode = 3;
>>> +		cpuxram_cfg.rx_0_cpu_pkt_dis = 0;
>>> +		cpuxram_cfg.tx_0_cpu_pkt_dis = 0;
>>> +		ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
>>> +			     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
>>> +	}
>>> +}
>>> +
>>> +static void ca_ni_enable_tx_rx(void)
>>> +{
>>> +	struct NI_HV_PT_RXMAC_CFG_t rxmac_cfg;
>>> +	struct NI_HV_PT_TXMAC_CFG_t txmac_cfg;
>>> +
>>> +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
>>> +
>>> +	/* Enable TX and RX functions */
>>> +	ca_reg_read(&rxmac_cfg, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_PT_RXMAC_CFG_OFFSET +
>>> +		    (APB0_NI_HV_PT_STRIDE * active_port));
>>> +	rxmac_cfg.rx_en = 1;
>>> +	ca_reg_write(&rxmac_cfg, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_PT_RXMAC_CFG_OFFSET +
>>> +		     (APB0_NI_HV_PT_STRIDE * active_port));
>>> +
>>> +	ca_reg_read(&txmac_cfg, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_PT_TXMAC_CFG_OFFSET +
>>> +		    (APB0_NI_HV_PT_STRIDE * active_port));
>>> +	txmac_cfg.tx_en = 1;
>>> +	ca_reg_write(&txmac_cfg, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_PT_TXMAC_CFG_OFFSET +
>>> +		     (APB0_NI_HV_PT_STRIDE * active_port));
>>> +}
>>> +
>>> +#define AUTO_SCAN_TIMEOUT	3000		/* 3 seconds */
>>> +__weak int ca_ni_auto_scan_active_port(void)
>>> +{
>>> +	u8	phy_addr;
>>> +	u32	start_time;
>>> +	unsigned short data;
>>> +
>>> +	start_time = get_timer(0);
>>> +	while (get_timer(start_time) < AUTO_SCAN_TIMEOUT) {
>>> +		phy_addr = 1;
>>> +		for (; phy_addr < 6; phy_addr++) {
>>> +			ca_mdio_read(phy_addr, 1, &data);
>>> +			if (data & 0x04) {
>>> +				active_port = phyaddr_to_port(phy_addr);
>>> +				return 0;
>>> +			}
>>> +		}
>>> +	}
>>> +
>>> +	printf("%s: auto scan active_port timeout.\n", __func__);
>>> +	return -1;
>>> +}
>>> +
>>> +__weak int invalid_active_port(int port)
>>> +{
>>> +	if (active_port < NI_PORT_0 || active_port > NI_PORT_4)
>>> +		return -1;
>>> +	else
>>> +		return 0;
>>> +}
>>> +
>>> +static int ca_phy_probe(struct udevice *dev)
>>> +{
>>> +	struct cortina_ni_priv *priv = dev_get_priv(dev);
>>> +	struct phy_device *int_phydev, *ext_phydev;
>>> +	int auto_scan_active_port = 0, tmp_port;
>>> +	char *buf;
>>> +
>>> +	/* Initialize internal phy device */
>>> +	int_phydev = phy_connect(priv->mdio_bus, port_to_phyaddr(NI_PORT_3),
>>> +				 dev, priv->phy_interface);
>>> +	if (int_phydev) {
>>> +		int_phydev->supported &= PHY_GBIT_FEATURES;
>>> +		int_phydev->advertising = int_phydev->supported;
>>> +		phy_config(int_phydev);
>>> +	} else {
>>> +		printf("%s: There is no internal phy device\n", __func__);
>>> +	}
>>> +
>>> +	/* Initialize external phy device */
>>> +	ext_phydev = phy_connect(priv->mdio_bus, port_to_phyaddr(NI_PORT_4),
>>> +				 dev, priv->phy_interface);
>>> +	if (ext_phydev) {
>>> +		ext_phydev->supported &= PHY_GBIT_FEATURES;
>>> +		ext_phydev->advertising = int_phydev->supported;
>>> +		phy_config(ext_phydev);
>>> +	} else {
>>> +		printf("%s: There is no external phy device\n", __func__);
>>> +	}
>>> +
>>> +	/* auto scan the first link up port as active_port */
>>> +	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) {
>>> +		ca_ni_auto_scan_active_port();
>>> +	} else {
>>> +		buf = env_get("active_port");
>>> +		if (buf != 0) {
>>> +			tmp_port = simple_strtoul(buf, NULL, 0);
>>> +			if (invalid_active_port(active_port)) {
>>> +				printf("ERROR: doesn't support this port.");
>>> +				free(dev);
>>> +				free(priv);
>>> +				return 1;
>>> +			}
>>> +
>>> +			active_port = tmp_port;
>>> +		}
>>> +	}
>>> +
>>> +	printf("%s: active_port=%d\n", __func__, active_port);
>>> +	if (active_port == NI_PORT_4)
>>> +		priv->phydev = ext_phydev;
>>> +	else
>>> +		priv->phydev = int_phydev;
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static void ca_ni_led(int port, int status)
>>> +{
>>> +	struct udevice *led_dev;
>>> +	char label[10];
>>> +
>>> +	if (IS_ENABLED(CONFIG_LED_CORTINA)) {
>>> +		snprintf(label, sizeof(label), "led%d", port);
>>> +		debug("%s: set port %d led %s.\n",
>>> +		      __func__, port, status ? "on" : "off");
>>> +		led_get_by_label(label, &led_dev);
>>> +		led_set_state(led_dev, status);
>>> +	}
>>> +}
>>> +
>>> +static void cortina_ni_reset(void)
>>> +{
>>> +	int i;
>>> +	struct NI_HV_GLB_INIT_DONE_t		init_done;
>>> +	struct NI_HV_GLB_INTF_RST_CONFIG_t	intf_rst_config;
>>> +	struct NI_HV_GLB_STATIC_CFG_t		static_cfg;
>>> +	struct GLOBAL_BLOCK_RESET_t		glb_blk_reset;
>>> +
>>> +	struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
>>> +
>>> +	/* NI global resets */
>>> +	ca_reg_read(&glb_blk_reset, (u64)priv->glb_base_addr,
>>> +		    GLOBAL_BLOCK_RESET_OFFSET);
>>> +	glb_blk_reset.reset_ni = 1;
>>> +	ca_reg_write(&glb_blk_reset, (u64)priv->glb_base_addr,
>>> +		     GLOBAL_BLOCK_RESET_OFFSET);
>>> +	/* Remove resets */
>>> +	glb_blk_reset.reset_ni = 0;
>>> +	ca_reg_write(&glb_blk_reset, (u64)priv->glb_base_addr,
>>> +		     GLOBAL_BLOCK_RESET_OFFSET);
>>> +
>>> +	/* check the ready bit of NI module */
>>> +	for (i = 0; i < NI_READ_POLL_COUNT; i++) {
>>> +		ca_reg_read(&init_done, (u64)priv->ni_hv_base_addr,
>>> +			    NI_HV_GLB_INIT_DONE_OFFSET);
>>> +		if (init_done.ni_init_done)
>>> +			break;
>>> +	}
>>> +	if (i == NI_READ_POLL_COUNT) {
>>> +		printf("%s: NI init done not ready, init_done=0x%x!!!\n",
>>> +		       __func__, init_done.ni_init_done);
>>> +	}
>>> +
>>> +	ca_reg_read(&intf_rst_config, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_GLB_INTF_RST_CONFIG_OFFSET);
>>> +	switch (active_port) {
>>> +	case NI_PORT_0:
>>> +		intf_rst_config.intf_rst_p0 = 0;
>>> +		intf_rst_config.mac_rx_rst_p0 = 0;
>>> +		intf_rst_config.mac_tx_rst_p0 = 0;
>>> +		break;
>>> +	case NI_PORT_1:
>>> +		intf_rst_config.intf_rst_p1 = 0;
>>> +		intf_rst_config.mac_rx_rst_p1 = 0;
>>> +		intf_rst_config.mac_tx_rst_p1 = 0;
>>> +		break;
>>> +	case NI_PORT_2:
>>> +		intf_rst_config.intf_rst_p2 = 0;
>>> +		intf_rst_config.mac_rx_rst_p2 = 0;
>>> +		intf_rst_config.mac_tx_rst_p2 = 0;
>>> +		break;
>>> +	case NI_PORT_3:
>>> +		intf_rst_config.intf_rst_p3 = 0;
>>> +		intf_rst_config.mac_tx_rst_p3 = 0;
>>> +		intf_rst_config.mac_rx_rst_p3 = 0;
>>> +		break;
>>> +	case NI_PORT_4:
>>> +		intf_rst_config.intf_rst_p4 = 0;
>>> +		intf_rst_config.mac_tx_rst_p4 = 0;
>>> +		intf_rst_config.mac_rx_rst_p4 = 0;
>>> +		break;
>>> +	}
>>> +
>>> +	ca_reg_write(&intf_rst_config, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_GLB_INTF_RST_CONFIG_OFFSET);
>>> +
>>> +	/* Only one GMAC can connect to CPU */
>>> +	ca_reg_read(&static_cfg, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_GLB_STATIC_CFG_OFFSET);
>>> +	static_cfg.port_to_cpu = active_port;
>>> +	static_cfg.txmib_mode = 1;
>>> +	static_cfg.rxmib_mode = 1;
>>> +
>>> +	ca_reg_write(&static_cfg, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_GLB_STATIC_CFG_OFFSET);
>>> +}
>>> +
>>> +static int cortina_ni_init(struct udevice *dev)
>>> +{
>>> +	int ret;
>>> +	struct NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t	cpuxram_adrcfg_rx;
>>> +	struct NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t  cpuxram_adrcfg_tx;
>>> +	struct NI_HV_XRAM_CPUXRAM_CFG_t		cpuxram_cfg;
>>> +	struct NI_HV_PT_PORT_STATIC_CFG_t	port_static_cfg;
>>> +	struct NI_HV_PT_PORT_GLB_CFG_t		port_glb_cfg;
>>> +
>>> +	struct cortina_ni_priv *priv = dev_get_priv(dev);
>>> +	struct phy_device *phydev = priv->phydev;
>>> +
>>> +	ret = phy_startup(priv->phydev);
>>> +	if (ret) {
>>> +		ca_ni_led(active_port, CA_LED_OFF);
>>> +		printf("Could not initialize PHY %s, active_port=%d\n",
>>> +		       priv->phydev->dev->name, active_port);
>>> +		return ret;
>>> +	}
>>> +
>>> +	if (!priv->phydev->link) {
>>> +		printf("%s: link down.\n", priv->phydev->dev->name);
>>> +		return 0;
>>> +	}
>>> +
>>> +	ca_ni_led(active_port, CA_LED_ON);
>>> +	printf("PHY ID 0x%08X %dMbps %s duplex\n",
>>> +	       phydev->phy_id, phydev->speed,
>>> +	       phydev->duplex == DUPLEX_HALF ? "half" : "full");
>>> +
>>> +	/* RX XRAM ADDRESS CONFIG (start and end address) */
>>> +	memset(&cpuxram_adrcfg_rx, 0, sizeof(cpuxram_adrcfg_rx));
>>> +	cpuxram_adrcfg_rx.rx_top_addr = RX_TOP_ADDR;
>>> +	cpuxram_adrcfg_rx.rx_base_addr = RX_BASE_ADDR;
>>> +	ca_reg_write(&cpuxram_adrcfg_rx, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_XRAM_CPUXRAM_ADRCFG_RX_OFFSET);
>>> +
>>> +	/* TX XRAM ADDRESS CONFIG (start and end address) */
>>> +	memset(&cpuxram_adrcfg_tx, 0, sizeof(cpuxram_adrcfg_tx));
>>> +	cpuxram_adrcfg_tx.tx_top_addr = TX_TOP_ADDR;
>>> +	cpuxram_adrcfg_tx.tx_base_addr = TX_BASE_ADDR;
>>> +	ca_reg_write(&cpuxram_adrcfg_tx, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_OFFSET);
>>> +
>>> +	/*
>>> +	 * Configuration for Management Ethernet Interface:
>>> +	 * - RGMII 1000 mode or RGMII 100 mode
>>> +	 * - MAC mode
>>> +	 */
>>> +	ca_reg_read(&port_static_cfg, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_PT_PORT_STATIC_CFG_OFFSET +
>>> +		    (APB0_NI_HV_PT_STRIDE * active_port));
>>> +	if (phydev->speed == SPEED_1000) {
>>> +		/* port 4 connects to RGMII PHY */
>>> +		if (phydev->addr == 5)
>>> +			port_static_cfg.int_cfg = GE_MAC_INTF_RGMII_1000;
>>> +		else
>>> +			port_static_cfg.int_cfg = GE_MAC_INTF_GMII;
>>> +	} else {
>>> +		/* port 4 connects to RGMII PHY */
>>> +		if (phydev->addr == 5)
>>> +			port_static_cfg.int_cfg = GE_MAC_INTF_RGMII_100;
>>> +		else
>>> +			port_static_cfg.int_cfg = GE_MAC_INTF_MII;
>>> +	}
>>> +
>>> +	ca_reg_write(&port_static_cfg, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_PT_PORT_STATIC_CFG_OFFSET +
>>> +		     (APB0_NI_HV_PT_STRIDE * active_port));
>>> +
>>> +	ca_reg_read(&port_glb_cfg, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_PT_PORT_GLB_CFG_OFFSET +
>>> +		    (APB0_NI_HV_PT_STRIDE * active_port));
>>> +	port_glb_cfg.speed = phydev->speed == SPEED_10 ? 1 : 0;
>>> +	port_glb_cfg.duplex = phydev->duplex == DUPLEX_HALF ? 1 : 0;
>>> +	ca_reg_write(&port_glb_cfg, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_PT_PORT_GLB_CFG_OFFSET +
>>> +		     (APB0_NI_HV_PT_STRIDE * active_port));
>>> +
>>> +	/* Need to toggle the tx and rx cpu_pkt_dis bit */
>>> +	/* after changing Address config register.      */
>>> +	ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
>>> +	cpuxram_cfg.rx_0_cpu_pkt_dis = 1;
>>> +	cpuxram_cfg.tx_0_cpu_pkt_dis = 1;
>>> +	ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
>>> +
>>> +	ca_reg_read(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
>>> +	cpuxram_cfg.rx_0_cpu_pkt_dis = 0;
>>> +	cpuxram_cfg.tx_0_cpu_pkt_dis = 0;
>>> +	ca_reg_write(&cpuxram_cfg, (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_XRAM_CPUXRAM_CFG_OFFSET);
>>> +
>>> +	ca_ni_enable_tx_rx();
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +/*********************************************
>>> + * Packet receive routine from Management FE
>>> + * Expects a previously allocated buffer and
>>> + * fills the length
>>> + * Retruns 0 on success -1 on failure
>>> + *******************************************/
>>> +int cortina_ni_recv(struct udevice *netdev)
>>> +{
>>> +	struct cortina_ni_priv *priv = dev_get_priv(netdev);
>>> +	struct NI_HEADER_X_T	header_x;
>>> +	u32			next_link;
>>> +	u32			pktlen = 0;
>>> +	u32			sw_rx_rd_ptr;
>>> +	u32			hw_rx_wr_ptr;
>>> +	u32			*rx_xram_ptr;
>>> +	int			loop;
>>> +	u32			*data_ptr;
>>> +	struct NI_PACKET_STATUS packet_status;
>>> +	struct NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t cpuxram_cpu_sta_rx;
>>> +	struct NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t cpuxram_cpu_cfg_rx;
>>> +	int index = 0;
>>> +	int			blk_num;
>>> +	u8			*ptr;
>>> +
>>> +	/* get the hw write pointer */
>>> +	memset(&cpuxram_cpu_sta_rx, 0, sizeof(cpuxram_cpu_sta_rx));
>>> +	ca_reg_read(&cpuxram_cpu_sta_rx, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET);
>>> +	hw_rx_wr_ptr = cpuxram_cpu_sta_rx.pkt_wr_ptr;
>>> +
>>> +	/* get the sw read pointer */
>>> +	memset(&cpuxram_cpu_cfg_rx, 0, sizeof(cpuxram_cpu_cfg_rx));
>>> +	ca_reg_read(&cpuxram_cpu_cfg_rx, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
>>> +	sw_rx_rd_ptr = cpuxram_cpu_cfg_rx.pkt_rd_ptr;
>>> +
>>> +	debug("%s: NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0 = 0x%p, ", __func__,
>>> +	      priv->ni_hv_base_addr + NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET);
>>> +	debug("NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0 = 0x%p\n",
>>> +	      priv->ni_hv_base_addr + NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
>>> +	debug("%s : RX hw_wr_ptr = %d, sw_rd_ptr = %d\n",
>>> +	      __func__, hw_rx_wr_ptr, sw_rx_rd_ptr);
>>> +
>>> +	while (sw_rx_rd_ptr != hw_rx_wr_ptr) {
>>> +		/* Point to the absolute memory address of XRAM
>>> +		 * where read pointer is
>>> +		 */
>>> +		rx_xram_ptr = (u32 *)
>>> +			      ((unsigned long)NI_XRAM_BASE + sw_rx_rd_ptr * 8);
>>> +
>>> +		/* Wrap around if required */
>>> +		if (rx_xram_ptr >= (u32 *)(unsigned long)priv->rx_xram_end_adr)
>>> +			rx_xram_ptr = (u32 *)
>>> +				      (unsigned long)priv->rx_xram_base_adr;
>>> +
>>> +		/* Checking header XR. Do not update the read pointer yet */
>>> +		/* skip unused 32-bit in Header XR */
>>> +		rx_xram_ptr = rdwrptr_adv_one(rx_xram_ptr,
>>> +					      priv->rx_xram_base_adr,
>>> +					      priv->rx_xram_end_adr);
>>> +
>>> +		memcpy(&header_x, rx_xram_ptr, sizeof(header_x));
>>> +		next_link = header_x.next_link;
>>> +		/* Header XR [31:0] */
>>> +
>>> +		if (*rx_xram_ptr == 0xffffffff)
>>> +			printf("%s: XRAM Error !\n", __func__);
>>> +
>>> +		debug("%s : RX next link 0x%x\n", __func__, next_link);
>>> +		debug("%s : bytes_valid %x\n", __func__, header_x.bytes_valid);
>>> +
>>> +		if (header_x.ownership == 0) {
>>> +			/* point to Packet status [31:0] */
>>> +			rx_xram_ptr = rdwrptr_adv_one(rx_xram_ptr,
>>> +						      priv->rx_xram_base_adr,
>>> +						      priv->rx_xram_end_adr);
>>> +
>>> +			memcpy(&packet_status, rx_xram_ptr,
>>> +			       sizeof(rx_xram_ptr));
>>> +			debug("%s: packet status=0x%x\n",
>>> +			      __func__, REG_TO_U32(&packet_status));
>>> +			if (packet_status.valid == 0) {
>>> +				debug("%s: Invalid Packet !!, ", __func__);
>>> +				debug("next_link=%d\n", next_link);
>>> +
>>> +				/* Update the software read pointer */
>>> +				ca_reg_write(&next_link,
>>> +					     (u64)priv->ni_hv_base_addr,
>>> +					NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
>>> +				return 0;
>>> +			}
>>> +
>>> +			if (packet_status.drop ||
>>> +			    packet_status.runt ||
>>> +			    packet_status.oversize ||
>>> +			    packet_status.jabber ||
>>> +			    packet_status.crc_error ||
>>> +			    packet_status.jumbo) {
>>> +				debug("%s: Error Packet!!, ", __func__);
>>> +				debug("next_link=%d\n", next_link);
>>> +
>>> +				/* Update the software read pointer */
>>> +				ca_reg_write(&next_link,
>>> +					     (u64)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.packet_size > 1518) {
>>> +				debug("%s: Error Packet !! Packet size=%d, ",
>>> +				      __func__, packet_status.packet_size);
>>> +				debug("larger than 1518, next_link=%d\n",
>>> +				      next_link);
>>> +
>>> +				/* Update the software read pointer */
>>> +				ca_reg_write(&next_link,
>>> +					     (u64)priv->ni_hv_base_addr,
>>> +					NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
>>> +				return 0;
>>> +			}
>>> +
>>> +			rx_xram_ptr = rdwrptr_adv_one(rx_xram_ptr,
>>> +						      priv->rx_xram_base_adr,
>>> +						      priv->rx_xram_end_adr);
>>> +
>>> +			pktlen = packet_status.packet_size;
>>> +
>>> +			debug("%s : rx packet length = %d\n",
>>> +			      __func__, packet_status.packet_size);
>>> +
>>> +			rx_xram_ptr = rdwrptr_adv_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 */
>>> +
>>> +			debug("%s: packet data[]=", __func__);
>>> +
>>> +			for (loop = 0; loop <= pktlen / 4; loop++) {
>>> +				ptr = (u8 *)rx_xram_ptr;
>>> +				if (loop < 10)
>>> +					debug("[0x%x]-[0x%x]-[0x%x]-[0x%x]",
>>> +					      ptr[0], ptr[1], ptr[2], ptr[3]);
>>> +				*data_ptr++ = *rx_xram_ptr++;
>>> +				/* Wrap around if required */
>>> +				if (rx_xram_ptr >= (u32 *)
>>> +				    (unsigned long)priv->rx_xram_end_adr) {
>>> +					rx_xram_ptr = (u32 *)(unsigned long)
>>> +						       (priv->rx_xram_base_adr);
>>> +				}
>>> +			}
>>> +
>>> +			debug("\n");
>>> +			net_process_received_packet(net_rx_packets[index],
>>> +						    pktlen);
>>> +			if (++index >= PKTBUFSRX)
>>> +				index = 0;
>>> +			blk_num = net_rx_packets[index][0x2c] * 255 +
>>> +				net_rx_packets[index][0x2d];
>>> +			debug("%s: tftp block number=%d\n", __func__, blk_num);
>>> +
>>> +			/* Update the software read pointer */
>>> +			ca_reg_write(&next_link,
>>> +				     (u64)priv->ni_hv_base_addr,
>>> +				     NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
>>> +		}
>>> +
>>> +		/* get the hw write pointer */
>>> +		ca_reg_read(&cpuxram_cpu_sta_rx, (u64)priv->ni_hv_base_addr,
>>> +			    NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET);
>>> +		hw_rx_wr_ptr = cpuxram_cpu_sta_rx.pkt_wr_ptr;
>>> +
>>> +		/* get the sw read pointer */
>>> +		ca_reg_read(&sw_rx_rd_ptr, (u64)priv->ni_hv_base_addr,
>>> +			    NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
>>> +	}
>>> +	return 0;
>>> +}
>>> +
>>> +static int cortina_ni_send(struct udevice *dev, void *packet, int length)
>>> +{
>>> +	struct cortina_ni_priv *priv = dev_get_priv(dev);
>>> +	u32	hw_tx_rd_ptr = 0;
>>> +	u32	sw_tx_wr_ptr = 0;
>>> +	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	ca_crc32;
>>> +	struct NI_HEADER_X_T	hdr_xt;
>>> +	int		pad = 0;
>>> +	static unsigned char   pkt_buf[2048];
>>> +	u32	*data_ptr;
>>> +	struct NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t cpuxram_cpu_cfg_tx;
>>> +	u8 *ptr;
>>> +
>>> +	if (!packet || length > 2032)
>>> +		return -1;
>>> +
>>> +	/* Get the hardware read pointer */
>>> +	ca_reg_read(&hw_tx_rd_ptr, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET);
>>> +
>>> +	/* Get the software write pointer */
>>> +	ca_reg_read(&sw_tx_wr_ptr, (u64)priv->ni_hv_base_addr,
>>> +		    NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET);
>>> +
>>> +	debug("%s: NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0=0x%p, ",
>>> +	      __func__,
>>> +	      KSEG1_ATU_XLAT(priv->ni_hv_base_addr +
>>> +			     NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET));
>>> +	debug("NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0=0x%p\n",
>>> +	      KSEG1_ATU_XLAT(priv->ni_hv_base_addr +
>>> +			     NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET));
>>> +	debug("%s : hw_tx_rd_ptr = %d\n", __func__, hw_tx_rd_ptr);
>>> +	debug("%s : sw_tx_wr_ptr = %d\n", __func__, sw_tx_wr_ptr);
>>> +
>>> +	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[HEADER_A_SIZE], (const void *)packet, length);
>>> +
>>> +	pad = 64 - (length + 4);	/* if packet length < 60 */
>>> +	pad = (pad < 0) ? 0 : pad;
>>> +
>>> +	debug("%s: length=%d, pad=%d\n", __func__, length, pad);
>>> +
>>> +	new_pkt_len = length + pad;	/* new packet length */
>>> +
>>> +	pkt_buf_ptr = (unsigned char *)pkt_buf;
>>> +
>>> +	/* Calculate the CRC32, skip 8-byte header_A */
>>> +	ca_crc32 = crc32(0, (u8 *)(pkt_buf_ptr + HEADER_A_SIZE), new_pkt_len);
>>> +
>>> +	debug("%s: crc32 is 0x%x\n", __func__, ca_crc32);
>>> +	debug("%s: ~crc32 is 0x%x\n", __func__, ~ca_crc32);
>>> +	debug("%s: pkt len %d\n", __func__, new_pkt_len);
>>> +	/* should add 8-byte header_! */
>>> +	/* CRC will re-calculated by hardware */
>>> +	memcpy((pkt_buf_ptr + new_pkt_len + HEADER_A_SIZE),
>>> +	       (u8 *)(&ca_crc32), sizeof(ca_crc32));
>>> +	new_pkt_len = new_pkt_len + 4;	/* add CRC */
>>> +
>>> +	valid_bytes = new_pkt_len % 8;
>>> +	valid_bytes = valid_bytes ? valid_bytes : 0;
>>> +	debug("%s: valid_bytes %d\n", __func__, valid_bytes);
>>> +
>>> +	/* should add 8-byte headerA */
>>> +	next_link = sw_tx_wr_ptr +
>>> +		(new_pkt_len + 7 + HEADER_A_SIZE) / 8; /* for headr XT */
>>> +	/* add header */
>>> +	next_link = next_link + 1;
>>> +	/* Wrap around if required */
>>> +	if (next_link > priv->tx_xram_end) {
>>> +		next_link = priv->tx_xram_start +
>>> +			(next_link - (priv->tx_xram_end + 1));
>>> +	}
>>> +
>>> +	debug("%s: TX next_link %x\n", __func__, next_link);
>>> +	memset(&hdr_xt, 0, sizeof(hdr_xt));
>>> +	hdr_xt.ownership = 1;
>>> +	hdr_xt.bytes_valid = valid_bytes;
>>> +	hdr_xt.next_link = next_link;
>>> +
>>> +	tx_xram_ptr = (u32 *)((unsigned long)NI_XRAM_BASE + sw_tx_wr_ptr * 8);
>>> +
>>> +	/* Wrap around if required */
>>> +	if (tx_xram_ptr >= (u32 *)(unsigned long)priv->tx_xram_end_adr)
>>> +		tx_xram_ptr = (u32 *)(unsigned long)priv->tx_xram_base_adr;
>>> +
>>> +	tx_xram_ptr = rdwrptr_adv_one(tx_xram_ptr,
>>> +				      priv->tx_xram_base_adr,
>>> +				      priv->tx_xram_end_adr);
>>> +
>>> +	memcpy(tx_xram_ptr, &hdr_xt, sizeof(*tx_xram_ptr));
>>> +
>>> +	tx_xram_ptr = rdwrptr_adv_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;
>>> +	debug("%s: packet data[]=", __func__);
>>> +
>>> +	/* copy header_A to XRAM */
>>> +	for (loop = 0; loop <= (new_pkt_len + HEADER_A_SIZE) / 4; loop++) {
>>> +		ptr = (u8 *)data_ptr;
>>> +		if ((loop % 4) == 0)
>>> +			debug("\n");
>>> +		debug("[0x%x]-[0x%x]-[0x%x]-[0x%x]-",
>>> +		      ptr[0], ptr[1], ptr[2], ptr[3]);
>>> +
>>> +		*tx_xram_ptr = *data_ptr++;
>>> +		tx_xram_ptr = rdwrptr_adv_one(tx_xram_ptr,
>>> +					      priv->tx_xram_base_adr,
>>> +					      priv->tx_xram_end_adr);
>>> +	}
>>> +	debug("\n");
>>> +
>>> +	/* Publish the software write pointer */
>>> +	cpuxram_cpu_cfg_tx.pkt_wr_ptr = next_link;
>>> +	ca_reg_write(&cpuxram_cpu_cfg_tx,
>>> +		     (u64)priv->ni_hv_base_addr,
>>> +		     NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static void cortina_ni_halt(struct udevice *netdev)
>>> +{
>>> +	/* Nothing to do for now. */
>>> +}
>>> +
>>> +#define GPHY_CAL_LEN	6
>>> +struct gphy_cal {
>>> +	u32 reg_off;
>>> +	u32 value;
>>> +};
>>> +
>>> +static struct gphy_cal gphy_cal_vlaues[GPHY_CAL_LEN] = {
>>> +	{0xf43380fc, 0xbcd},
>>> +	{0xf43380dc, 0xeeee},
>>> +	{0xf43380d8, 0xeeee},
>>> +	{0xf43380fc, 0xbce},
>>> +	{0xf43380c0, 0x7777},
>>> +	{0xf43380c4, 0x7777}
>>> +};
>>> +
>>> +__weak 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, 0);
>>> +			mdelay(50);
>>> +		}
>>> +	}
>>> +}
>>> +
>>> +static int ca_mdio_register(struct udevice *dev)
>>> +{
>>> +	struct cortina_ni_priv *priv = dev_get_priv(dev);
>>> +	struct mii_dev *mdio_bus = mdio_alloc();
>>> +	int ret;
>>> +
>>> +	if (!mdio_bus)
>>> +		return -ENOMEM;
>>> +
>>> +	mdio_bus->read = cortina_mdio_read;
>>> +	mdio_bus->write = cortina_mdio_write;
>>> +	snprintf(mdio_bus->name, sizeof(mdio_bus->name), dev->name);
>>> +
>>> +	mdio_bus->priv = (void *)priv;
>>> +
>>> +	ret = mdio_register(mdio_bus);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	priv->mdio_bus = mdio_bus;
>>> +	return 0;
>>> +}
>>> +
>>> +__weak void ca_rgmii_init(struct cortina_ni_priv *priv)
>>> +{
>>> +	/* hardware settings for RGMII port */
>>> +	struct GLOBAL_GLOBAL_CONFIG_t	glb_config;
>>> +	struct GLOBAL_IO_DRIVE_CONTROL_t io_drive_control;
>>> +
>>> +	/* Generating 25Mhz reference clock for switch */
>>> +	ca_reg_read(&glb_config, (u64)priv->glb_base_addr,
>>> +		    GLOBAL_GLOBAL_CONFIG_OFFSET);
>>> +	glb_config.refclk_sel = 0x01;
>>> +	glb_config.ext_reset = 0x01;
>>> +	ca_reg_write(&glb_config, (u64)priv->glb_base_addr,
>>> +		     GLOBAL_GLOBAL_CONFIG_OFFSET);
>>> +
>>> +	mdelay(20);
>>> +
>>> +	/* should do a external reset */
>>> +	ca_reg_read(&glb_config, (u64)priv->glb_base_addr,
>>> +		    GLOBAL_GLOBAL_CONFIG_OFFSET);
>>> +	glb_config.ext_reset = 0x0;
>>> +	ca_reg_write(&glb_config, (u64)priv->glb_base_addr,
>>> +		     GLOBAL_GLOBAL_CONFIG_OFFSET);
>>> +
>>> +	ca_reg_read(&io_drive_control, (u64)priv->glb_base_addr,
>>> +		    GLOBAL_IO_DRIVE_CONTROL_OFFSET);
>>> +	io_drive_control.gmac_mode = 2;
>>> +	io_drive_control.gmac_dn = 1;
>>> +	io_drive_control.gmac_dp = 1;
>>> +	ca_reg_write(&io_drive_control, (u64)priv->glb_base_addr,
>>> +		     GLOBAL_IO_DRIVE_CONTROL_OFFSET);
>>> +}
>>> +
>>> +int ca_eth_initialize(struct udevice *dev)
>>> +{
>>> +	struct cortina_ni_priv *priv;
>>> +	int ret, reg_value;
>>> +
>>> +	priv = dev_get_priv(dev);
>>> +	priv->rx_xram_base_adr	= NI_XRAM_BASE + (RX_BASE_ADDR * 8);
>>> +	priv->rx_xram_end_adr	= NI_XRAM_BASE + ((RX_TOP_ADDR + 1) * 8);
>>> +	priv->rx_xram_start	= RX_BASE_ADDR;
>>> +	priv->rx_xram_end	= RX_TOP_ADDR;
>>> +	priv->tx_xram_base_adr	= NI_XRAM_BASE + (TX_BASE_ADDR * 8);
>>> +	priv->tx_xram_end_adr	= NI_XRAM_BASE + ((TX_TOP_ADDR + 1) * 8);
>>> +	priv->tx_xram_start	= TX_BASE_ADDR;
>>> +	priv->tx_xram_end	= TX_TOP_ADDR;
>>> +
>>> +	curr_dev = dev;
>>> +	debug("%s: rx_base_addr:%x\t rx_top_addr %x\n",
>>> +	      __func__, priv->rx_xram_start, priv->rx_xram_end);
>>> +	debug("%s: tx_base_addr:%x\t tx_top_addr %x\n",
>>> +	      __func__, priv->tx_xram_start, priv->tx_xram_end);
>>> +	debug("%s: rx physical start address = %x end address = %x\n",
>>> +	      __func__, priv->rx_xram_base_adr, priv->rx_xram_end_adr);
>>> +	debug("%s: tx physical start address = %x end address = %x\n",
>>> +	      __func__, priv->tx_xram_base_adr, priv->tx_xram_end_adr);
>>> +
>>> +	/* MDIO register */
>>> +	ret = ca_mdio_register(dev);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	/* set MDIO pre-scale value */
>>> +	ca_reg_read(&reg_value, (u64)priv->per_mdio_base_addr,
>>> +		    PER_MDIO_CFG_OFFSET);
>>> +	reg_value = reg_value | 0x00280000;
>>> +	ca_reg_write(&reg_value, (u64)priv->per_mdio_base_addr,
>>> +		     PER_MDIO_CFG_OFFSET);
>>> +
>>> +	ca_phy_probe(dev);
>>> +	priv->phydev->addr = port_to_phyaddr(active_port);
>>> +
>>> +	ca_ni_led(active_port, CA_LED_ON);
>>> +
>>> +	cortina_ni_reset();
>>> +
>>> +	printf("%s: active_port=%d, phy_addr=%d\n",
>>> +	       __func__, active_port, priv->phydev->addr);
>>> +	printf("%s: phy_id=0x%x, phy_id & PHY_ID_MASK=0x%x\n", __func__,
>>> +	       priv->phydev->phy_id, priv->phydev->phy_id & 0xFFFFFFF0);
>>> +
>>> +	/* parsing ethaddr and set to NI registers. */
>>> +	ca_ni_setup_mac_addr();
>>> +
>>> +#ifdef MIIPHY_REGISTER
>>> +	/* the phy_read and phy_write
>>> +	 * should meet the proto type of miiphy_register
>>> +	 */
>>> +	miiphy_register(dev->name, ca_miiphy_read, ca_miiphy_write);
>>> +#endif
>>> +
>>> +	ca_rgmii_init(priv);
>>> +
>>> +	/* do internal gphy calibration */
>>> +	do_internal_gphy_cal();
>>> +	return 0;
>>> +}
>>> +
>>> +static int cortina_eth_start(struct udevice *dev)
>>> +{
>>> +	return cortina_ni_init(dev);
>>> +}
>>> +
>>> +static int cortina_eth_send(struct udevice *dev, void *packet, int length)
>>> +{
>>> +	return cortina_ni_send(dev, packet, length);
>>> +}
>>> +
>>> +static int cortina_eth_recv(struct udevice *dev, int flags, uchar **packetp)
>>> +{
>>> +	return cortina_ni_recv(dev);
>>> +}
>>> +
>>> +static void cortina_eth_stop(struct udevice *dev)
>>> +{
>>> +	cortina_ni_halt(dev);
>>> +}
>>> +
>>> +static int cortina_eth_probe(struct udevice *dev)
>>> +{
>>> +	return ca_eth_initialize(dev);
>>> +}
>>> +
>>> +static int ca_ni_ofdata_to_platdata(struct udevice *dev)
>>> +{
>>> +	struct cortina_ni_priv *priv = dev_get_priv(dev);
>>> +
>>> +	priv->glb_base_addr = dev_remap_addr_index(dev, 0);
>>> +	if (!priv->glb_base_addr)
>>> +		return -ENOENT;
>>> +	printf("%s: priv->glb_base_addr for index 0 is 0x%p\n",
>>> +	       __func__, priv->glb_base_addr);
>>> +
>>> +	priv->per_mdio_base_addr = dev_remap_addr_index(dev, 1);
>>> +	if (!priv->per_mdio_base_addr)
>>> +		return -ENOENT;
>>> +	printf("%s: priv->per_mdio_base_addr for index 1 is 0x%p\n",
>>> +	       __func__, priv->per_mdio_base_addr);
>>> +
>>> +	priv->ni_hv_base_addr = dev_remap_addr_index(dev, 2);
>>> +	if (!priv->ni_hv_base_addr)
>>> +		return -ENOENT;
>>> +	printf("%s: priv->ni_hv_base_addr for index 2 is 0x%p\n",
>>> +	       __func__, priv->ni_hv_base_addr);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static const struct eth_ops cortina_eth_ops = {
>>> +	.start  = cortina_eth_start,
>>> +	.send   = cortina_eth_send,
>>> +	.recv   = cortina_eth_recv,
>>> +	.stop   = cortina_eth_stop,
>>> +};
>>> +
>>> +static const struct udevice_id cortina_eth_ids[] = {
>>> +	{ .compatible = "eth_cortina" },
>>> +	{ }
>>> +};
>>> +
>>> +U_BOOT_DRIVER(eth_cortina) = {
>>> +	.name   = "eth_cortina",
>>> +	.id     = UCLASS_ETH,
>>> +	.of_match = cortina_eth_ids,
>>> +	.probe  = cortina_eth_probe,
>>> +	.ops    = &cortina_eth_ops,
>>> +	.priv_auto_alloc_size = sizeof(struct cortina_ni_priv),
>>> +	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
>>> +	.ofdata_to_platdata = ca_ni_ofdata_to_platdata,
>>> +};
>>> diff --git a/drivers/net/cortina_ni.h b/drivers/net/cortina_ni.h
>>> new file mode 100644
>>> index 0000000..ff9a396
>>> --- /dev/null
>>> +++ b/drivers/net/cortina_ni.h
>>> @@ -0,0 +1,435 @@
>>> +/* SPDX-License-Identifier: GPL-2.0+ */
>>> +
>>> +/*
>>> + * Copyright (C) 2020 Cortina Access Inc.
>>> + * Author: Aaron Tseng <aaron.tseng@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 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
>>> +
>>> +/* 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 NI_XRAM_BASE                    0xF4500000
>>> +
>>> +enum ca_status_t {
>>> +	CA_E_ERROR          = -1,
>>> +	CA_E_OK             = 0x0,
>>> +	CA_E_RESOURCE       = 0x1,
>>> +	CA_E_PARAM          = 0x2,
>>> +	CA_E_NOT_FOUND      = 0x3,
>>> +	CA_E_CONFLICT       = 0x4,
>>> +	CA_E_TIMEOUT        = 0x5,
>>> +	CA_E_INTERNAL       = 0x6,
>>> +	CA_E_NOT_SUPPORT    = 0x7,
>>> +	CA_E_CONFIG         = 0x8,
>>> +	CA_E_UNAVAIL        = 0x9,
>>> +	CA_E_MEMORY         = 0xa,
>>> +	CA_E_BUSY           = 0xb,
>>> +	CA_E_FULL           = 0xc,
>>> +	CA_E_EMPTY          = 0xd,
>>> +	CA_E_EXISTS         = 0xe,
>>> +	CA_E_DEV            = 0xf,
>>> +	CA_E_PORT           = 0x10,
>>> +	CA_E_LLID           = 0x11,
>>> +	CA_E_VLAN           = 0x12,
>>> +	CA_E_INIT           = 0x13,
>>> +	CA_E_INTF           = 0x14,
>>> +	CA_E_NEXTHOP        = 0x15,
>>> +	CA_E_ROUTE          = 0x16,
>>> +	CA_E_DB_CHANGED     = 0x17,
>>> +	CA_E_INACTIVE       = 0x18,
>>> +	CA_E_ALREADY_SET    = 0x19,
>>> +};
>>> +
>>> +#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;
>>> +	void __iomem    *glb_base_addr;
>>> +	void __iomem    *per_mdio_base_addr;
>>> +	void __iomem    *ni_hv_base_addr;
>>> +
>>> +	struct mii_dev *mdio_bus;
>>> +	struct phy_device *phydev;
>>> +	int phy_interface;
>>> +};
>>> +
>>> +struct NI_HEADER_X_T {
>>> +	unsigned int next_link		: 10; /* bits  9: 0 */
>>> +	unsigned int bytes_valid	:  4; /* bits 13:10 */
>>> +	unsigned int reserved		: 16; /* bits 29:14 */
>>> +	unsigned int hdr_a		:  1; /* bits 30:30 */
>>> +	unsigned int ownership		:  1; /* bits 31:31 */
>>> +};
>>> +
>>> +struct NI_PACKET_STATUS {
>>> +	unsigned int packet_size       : 14; /* bits 13:0 */
>>> +	unsigned int byte_valid        :  4; /* bits 17:14 */
>>> +	unsigned int pfc               :  1; /* bits 18:18 */
>>> +	unsigned int valid             :  1; /* bits 19:19 */
>>> +	unsigned int drop              :  1; /* bits 20:20 */
>>> +	unsigned int runt              :  1; /* bits 21:21 */
>>> +	unsigned int oversize          :  1; /* bits 22:22 */
>>> +	unsigned int jumbo             :  1; /* bits 23:23 */
>>> +	unsigned int link_status       :  1; /* bits 24:24 */
>>> +	unsigned int jabber            :  1; /* bits 25:25 */
>>> +	unsigned int crc_error         :  1; /* bits 26:26 */
>>> +	unsigned int pause             :  1; /* bits 27:27 */
>>> +	unsigned int oam               :  1; /* bits 28:28 */
>>> +	unsigned int unknown_opcode    :  1; /* bits 29:29 */
>>> +	unsigned int multicast         :  1; /* bits 30:30 */
>>> +	unsigned int broadcast         :  1; /* bits 31:31 */
>>> +};
>>> +
>>> +struct NI_MDIO_OPER_T {
>>> +	unsigned int reserved       : 2; /* bits  1:0 */
>>> +	unsigned int reg_off        : 5; /* bits  6:2 */
>>> +	unsigned int phy_addr       : 5; /* bits 11:7 */
>>> +	unsigned int reg_base       : 20; /* bits 31:12 */
>>> +};
>>> +
>>> +enum ca_port_t {
>>> +	NI_PORT_0 = 0,
>>> +	NI_PORT_1,
>>> +	NI_PORT_2,
>>> +	NI_PORT_3,
>>> +	NI_PORT_4,
>>> +	NI_PORT_5,
>>> +	NI_PORT_MAX,
>>> +};
>>> +
>>> +struct port_map_s {
>>> +	int active_port;
>>> +	int phy_addr;
>>> +};
>>> +
>>> +extern struct port_map_s port_map[NI_PORT_MAX];
>>> +extern int active_port;
>>> +
>>> +#define __MDIO_WR_FLAG				(0)
>>> +#define __MDIO_RD_FLAG				(1)
>>> +#define __MDIO_ACCESS_TIMEOUT			(1000000)
>>> +#define CA_MDIO_ADDR_MIN			(1)
>>> +#define CA_MDIO_ADDR_MAX			(31)
>>> +
>>> +#endif /* !__ASSEMBLER__ */
>>> +
>>> +/* Copy from registers.h */
>>> +struct NI_HV_GLB_MAC_ADDR_CFG0_t {
>>> +	unsigned int mac_addr0            : 32; /* bits 31:0 */
>>> +};
>>> +
>>> +struct NI_HV_GLB_MAC_ADDR_CFG1_t {
>>> +	unsigned int mac_addr1            :  8; /* bits 7:0 */
>>> +	unsigned int rsrvd1               : 24;
>>> +};
>>> +
>>> +struct NI_HV_PT_PORT_STATIC_CFG_t {
>>> +	unsigned int int_cfg              :  4; /* bits 3:0 */
>>> +	unsigned int phy_mode             :  1; /* bits 4:4 */
>>> +	unsigned int rmii_clksrc          :  1; /* bits 5:5 */
>>> +	unsigned int inv_clk_in           :  1; /* bits 6:6 */
>>> +	unsigned int inv_clk_out          :  1; /* bits 7:7 */
>>> +	unsigned int inv_rxclk_out        :  1; /* bits 8:8 */
>>> +	unsigned int tx_use_gefifo        :  1; /* bits 9:9 */
>>> +	unsigned int smii_tx_stat         :  1; /* bits 10:10 */
>>> +	unsigned int crs_polarity         :  1; /* bits 11:11 */
>>> +	unsigned int lpbk_mode            :  2; /* bits 13:12 */
>>> +	unsigned int gmii_like_half_duplex_en :  1; /* bits 14:14 */
>>> +	unsigned int sup_tx_to_rx_lpbk_data :  1; /* bits 15:15 */
>>> +	unsigned int rsrvd1               :  8;
>>> +	unsigned int mac_addr6            :  8; /* bits 31:24 */
>>> +};
>>> +
>>> +struct NI_HV_XRAM_CPUXRAM_CFG_t {
>>> +	unsigned int rx_0_cpu_pkt_dis     :  1; /* bits 0:0 */
>>> +	unsigned int rsrvd1               :  8;
>>> +	unsigned int tx_0_cpu_pkt_dis     :  1; /* bits 9:9 */
>>> +	unsigned int rsrvd2               :  1;
>>> +	unsigned int rx_x_drop_err_pkt    :  1; /* bits 11:11 */
>>> +	unsigned int xram_mgmt_dis_drop_ovsz_pkt :  1; /* bits 12:12 */
>>> +	unsigned int xram_mgmt_term_large_pkt :  1; /* bits 13:13 */
>>> +	unsigned int xram_mgmt_promisc_mode :  2; /* bits 15:14 */
>>> +	unsigned int xram_cntr_debug_mode :  1; /* bits 16:16 */
>>> +	unsigned int xram_cntr_op_code    :  2; /* bits 18:17 */
>>> +	unsigned int rsrvd3               :  2;
>>> +	unsigned int xram_rx_mgmtfifo_srst :  1; /* bits 21:21 */
>>> +	unsigned int xram_dma_fifo_srst   :  1; /* bits 22:22 */
>>> +	unsigned int rsrvd4               :  9;
>>> +};
>>> +
>>> +struct NI_HV_PT_RXMAC_CFG_t {
>>> +	unsigned int rx_en                :  1; /* bits 0:0 */
>>> +	unsigned int rsrvd1               :  7;
>>> +	unsigned int rx_flow_disable      :  1; /* bits 8:8 */
>>> +	unsigned int rsrvd2               :  3;
>>> +	unsigned int rx_flow_to_tx_en     :  1; /* bits 12:12 */
>>> +	unsigned int rx_pfc_disable       :  1; /* bits 13:13 */
>>> +	unsigned int rsrvd3               : 15;
>>> +	unsigned int send_pg_data         :  1; /* bits 29:29 */
>>> +	unsigned int rsrvd4               :  2;
>>> +};
>>> +
>>> +struct NI_HV_PT_TXMAC_CFG_t {
>>> +	unsigned int tx_en                :  1; /* bits 0:0 */
>>> +	unsigned int rsrvd1               :  7;
>>> +	unsigned int mac_crc_calc_en      :  1; /* bits 8:8 */
>>> +	unsigned int tx_ipg_sel           :  3; /* bits 11:9 */
>>> +	unsigned int tx_flow_disable      :  1; /* bits 12:12 */
>>> +	unsigned int tx_drain             :  1; /* bits 13:13 */
>>> +	unsigned int tx_pfc_disable       :  1; /* bits 14:14 */
>>> +	unsigned int tx_pau_sel           :  2; /* bits 16:15 */
>>> +	unsigned int rsrvd2               :  9;
>>> +	unsigned int tx_auto_xon          :  1; /* bits 26:26 */
>>> +	unsigned int rsrvd3               :  1;
>>> +	unsigned int pass_thru_hdr        :  1; /* bits 28:28 */
>>> +	unsigned int rsrvd4               :  3;
>>> +};
>>> +
>>> +struct NI_HV_GLB_INTF_RST_CONFIG_t {
>>> +	unsigned int intf_rst_p0          :  1; /* bits 0:0 */
>>> +	unsigned int intf_rst_p1          :  1; /* bits 1:1 */
>>> +	unsigned int intf_rst_p2          :  1; /* bits 2:2 */
>>> +	unsigned int intf_rst_p3          :  1; /* bits 3:3 */
>>> +	unsigned int intf_rst_p4          :  1; /* bits 4:4 */
>>> +	unsigned int mac_rx_rst_p0        :  1; /* bits 5:5 */
>>> +	unsigned int mac_rx_rst_p1        :  1; /* bits 6:6 */
>>> +	unsigned int mac_rx_rst_p2        :  1; /* bits 7:7 */
>>> +	unsigned int mac_rx_rst_p3        :  1; /* bits 8:8 */
>>> +	unsigned int mac_rx_rst_p4        :  1; /* bits 9:9 */
>>> +	unsigned int mac_tx_rst_p0        :  1; /* bits 10:10 */
>>> +	unsigned int mac_tx_rst_p1        :  1; /* bits 11:11 */
>>> +	unsigned int mac_tx_rst_p2        :  1; /* bits 12:12 */
>>> +	unsigned int mac_tx_rst_p3        :  1; /* bits 13:13 */
>>> +	unsigned int mac_tx_rst_p4        :  1; /* bits 14:14 */
>>> +	unsigned int port_rst_p5          :  1; /* bits 15:15 */
>>> +	unsigned int pcs_rst_p6           :  1; /* bits 16:16 */
>>> +	unsigned int pcs_rst_p7           :  1; /* bits 17:17 */
>>> +	unsigned int mac_rst_p6           :  1; /* bits 18:18 */
>>> +	unsigned int mac_rst_p7           :  1; /* bits 19:19 */
>>> +	unsigned int rsrvd1               : 12;
>>> +};
>>> +
>>> +struct NI_HV_GLB_STATIC_CFG_t {
>>> +	unsigned int port_to_cpu          :  4; /* bits 3:0 */
>>> +	unsigned int mgmt_pt_to_fe_also   :  1; /* bits 4:4 */
>>> +	unsigned int txcrc_chk_en         :  1; /* bits 5:5 */
>>> +	unsigned int p4_rgmii_tx_clk_phase :  2; /* bits 7:6 */
>>> +	unsigned int p4_rgmii_tx_data_order :  1; /* bits 8:8 */
>>> +	unsigned int rsrvd1               :  7;
>>> +	unsigned int rxmib_mode           :  1; /* bits 16:16 */
>>> +	unsigned int txmib_mode           :  1; /* bits 17:17 */
>>> +	unsigned int eth_sch_rdy_pkt      :  1; /* bits 18:18 */
>>> +	unsigned int rsrvd2               :  1;
>>> +	unsigned int rxaui_mode           :  2; /* bits 21:20 */
>>> +	unsigned int rxaui_sigdet         :  2; /* bits 23:22 */
>>> +	unsigned int cnt_op_mode          :  3; /* bits 26:24 */
>>> +	unsigned int rsrvd3               :  5;
>>> +};
>>> +
>>> +struct GLOBAL_BLOCK_RESET_t {
>>> +	unsigned int reset_ni             :  1; /* bits 0:0 */
>>> +	unsigned int reset_l2fe           :  1; /* bits 1:1 */
>>> +	unsigned int reset_l2tm           :  1; /* bits 2:2 */
>>> +	unsigned int reset_l3fe           :  1; /* bits 3:3 */
>>> +	unsigned int reset_sdram          :  1; /* bits 4:4 */
>>> +	unsigned int reset_tqm            :  1; /* bits 5:5 */
>>> +	unsigned int reset_pcie0          :  1; /* bits 6:6 */
>>> +	unsigned int reset_pcie1          :  1; /* bits 7:7 */
>>> +	unsigned int reset_pcie2          :  1; /* bits 8:8 */
>>> +	unsigned int reset_sata           :  1; /* bits 9:9 */
>>> +	unsigned int reset_gic400         :  1; /* bits 10:10 */
>>> +	unsigned int rsrvd1               :  2;
>>> +	unsigned int reset_usb            :  1; /* bits 13:13 */
>>> +	unsigned int reset_flash          :  1; /* bits 14:14 */
>>> +	unsigned int reset_per            :  1; /* bits 15:15 */
>>> +	unsigned int reset_dma            :  1; /* bits 16:16 */
>>> +	unsigned int reset_rtc            :  1; /* bits 17:17 */
>>> +	unsigned int reset_pe0            :  1; /* bits 18:18 */
>>> +	unsigned int reset_pe1            :  1; /* bits 19:19 */
>>> +	unsigned int reset_rcpu0          :  1; /* bits 20:20 */
>>> +	unsigned int reset_rcpu1          :  1; /* bits 21:21 */
>>> +	unsigned int reset_sadb           :  1; /* bits 22:22 */
>>> +	unsigned int rsrvd2               :  1;
>>> +	unsigned int reset_rcrypto        :  1; /* bits 24:24 */
>>> +	unsigned int reset_ldma           :  1; /* bits 25:25 */
>>> +	unsigned int reset_fbm            :  1; /* bits 26:26 */
>>> +	unsigned int reset_eaxi           :  1; /* bits 27:27 */
>>> +	unsigned int reset_sd             :  1; /* bits 28:28 */
>>> +	unsigned int reset_otprom         :  1; /* bits 29:29 */
>>> +	unsigned int rsrvd3               :  2;
>>> +};
>>> +
>>> +struct PER_MDIO_ADDR_t {
>>> +	unsigned int mdio_addr            :  5; /* bits 4:0 */
>>> +	unsigned int rsrvd1               :  3;
>>> +	unsigned int mdio_offset          :  5; /* bits 12:8 */
>>> +	unsigned int rsrvd2               :  2;
>>> +	unsigned int mdio_rd_wr           :  1; /* bits 15:15 */
>>> +	unsigned int mdio_st              :  1; /* bits 16:16 */
>>> +	unsigned int rsrvd3               :  1;
>>> +	unsigned int mdio_op              :  2; /* bits 19:18 */
>>> +	unsigned int rsrvd4               : 12;
>>> +};
>>> +
>>> +struct PER_MDIO_CTRL_t {
>>> +	unsigned int mdiodone             :  1; /* bits 0:0 */
>>> +	unsigned int rsrvd1               :  6;
>>> +	unsigned int mdiostart            :  1; /* bits 7:7 */
>>> +	unsigned int rsrvd2               : 24;
>>> +};
>>> +
>>> +struct PER_MDIO_RDDATA_t {
>>> +	unsigned int mdio_rddata          : 16; /* bits 15:0 */
>>> +	unsigned int rsrvd1               : 16;
>>> +};
>>> +
>>> +/*
>>> + * XRAM
>>> + */
>>> +
>>> +struct NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t {
>>> +	unsigned int rx_base_addr         : 10; /* bits 9:0 */
>>> +	unsigned int rsrvd1               :  6;
>>> +	unsigned int rx_top_addr          : 10; /* bits 25:16 */
>>> +	unsigned int rsrvd2               :  6;
>>> +};
>>> +
>>> +struct NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t {
>>> +	unsigned int tx_base_addr         : 10; /* bits 9:0 */
>>> +	unsigned int rsrvd1               :  6;
>>> +	unsigned int tx_top_addr          : 10; /* bits 25:16 */
>>> +	unsigned int rsrvd2               :  6;
>>> +};
>>> +
>>> +struct NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t {
>>> +	unsigned int pkt_wr_ptr           : 10; /* bits 9:0 */
>>> +	unsigned int rsrvd1               :  5;
>>> +	unsigned int int_colsc_thresh_reached :  1; /* bits 15:15 */
>>> +	unsigned int rsrvd2               : 16;
>>> +};
>>> +
>>> +struct NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t {
>>> +	unsigned int pkt_rd_ptr           : 10; /* bits 9:0 */
>>> +	unsigned int rsrvd1               : 22;
>>> +};
>>> +
>>> +struct NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t {
>>> +	unsigned int pkt_wr_ptr           : 10; /* bits 9:0 */
>>> +	unsigned int rsrvd1               : 22;
>>> +};
>>> +
>>> +struct GLOBAL_GLOBAL_CONFIG_t {
>>> +	unsigned int rsrvd1               :  4;
>>> +	unsigned int wd_reset_subsys_enable :  1; /* bits 4:4 */
>>> +	unsigned int rsrvd2               :  1;
>>> +	unsigned int wd_reset_all_blocks  :  1; /* bits 6:6 */
>>> +	unsigned int wd_reset_remap       :  1; /* bits 7:7 */
>>> +	unsigned int wd_reset_ext_reset   :  1; /* bits 8:8 */
>>> +	unsigned int ext_reset            :  1; /* bits 9:9 */
>>> +	unsigned int cfg_pcie_0_clken     :  1; /* bits 10:10 */
>>> +	unsigned int cfg_sata_clken       :  1; /* bits 11:11 */
>>> +	unsigned int cfg_pcie_1_clken     :  1; /* bits 12:12 */
>>> +	unsigned int rsrvd3               :  1;
>>> +	unsigned int cfg_pcie_2_clken     :  1; /* bits 14:14 */
>>> +	unsigned int rsrvd4               :  2;
>>> +	unsigned int ext_eth_refclk       :  1; /* bits 17:17 */
>>> +	unsigned int refclk_sel           :  2; /* bits 19:18 */
>>> +	unsigned int rsrvd5               :  7;
>>> +	unsigned int l3fe_pd              :  1; /* bits 27:27 */
>>> +	unsigned int offload0_pd          :  1; /* bits 28:28 */
>>> +	unsigned int offload1_pd          :  1; /* bits 29:29 */
>>> +	unsigned int crypto_pd            :  1; /* bits 30:30 */
>>> +	unsigned int core_pd              :  1; /* bits 31:31 */
>>> +};
>>> +
>>> +struct GLOBAL_IO_DRIVE_CONTROL_t {
>>> +	unsigned int gmac_dp              :  3; /* bits 2:0 */
>>> +	unsigned int gmac_dn              :  3; /* bits 5:3 */
>>> +	unsigned int gmac_mode            :  2; /* bits 7:6 */
>>> +	unsigned int gmac_ds              :  1; /* bits 8:8 */
>>> +	unsigned int flash_ds             :  1; /* bits 9:9 */
>>> +	unsigned int nu_ds                :  1; /* bits 10:10 */
>>> +	unsigned int ssp_ds               :  1; /* bits 11:11 */
>>> +	unsigned int spi_ds               :  1; /* bits 12:12 */
>>> +	unsigned int gpio_ds              :  1; /* bits 13:13 */
>>> +	unsigned int misc_ds              :  1; /* bits 14:14 */
>>> +	unsigned int eaxi_ds              :  1; /* bits 15:15 */
>>> +	unsigned int sd_ds                :  8; /* bits 23:16 */
>>> +	unsigned int rsrvd1               :  8;
>>> +};
>>> +
>>> +struct NI_HV_GLB_INIT_DONE_t {
>>> +	unsigned int rsrvd1               :  1;
>>> +	unsigned int ni_init_done         :  1; /* bits 1:1 */
>>> +	unsigned int rsrvd2               : 30;
>>> +};
>>> +
>>> +struct NI_HV_PT_PORT_GLB_CFG_t {
>>> +	unsigned int speed                :  1; /* bits 0:0 */
>>> +	unsigned int duplex               :  1; /* bits 1:1 */
>>> +	unsigned int link_status          :  1; /* bits 2:2 */
>>> +	unsigned int link_stat_mask       :  1; /* bits 3:3 */
>>> +	unsigned int rsrvd1               :  7;
>>> +	unsigned int power_dwn_rx         :  1; /* bits 11:11 */
>>> +	unsigned int power_dwn_tx         :  1; /* bits 12:12 */
>>> +	unsigned int tx_intf_lp_time      :  1; /* bits 13:13 */
>>> +	unsigned int rsrvd2               : 18;
>>> +};
>>> +
>>> +#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
>>> 
>> 
> 
> -- 
> Tom

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v2 3/3] board: presidio-asic: Add CAxxxx Ethernet support
  2021-01-14 21:34 ` [PATCH v2 3/3] board: presidio-asic: Add CAxxxx Ethernet support Alex Nemirovsky
@ 2021-01-27 19:22   ` Tom Rini
  0 siblings, 0 replies; 9+ messages in thread
From: Tom Rini @ 2021-01-27 19:22 UTC (permalink / raw)
  To: u-boot

On Thu, Jan 14, 2021 at 01:34:13PM -0800, Alex Nemirovsky wrote:

> Add CAxxxx Ethernet support for the Cortina Access
> Presidio Engineering Board
> 
> Signed-off-by: Alex Nemirovsky <alex.nemirovsky@cortina-access.com>
> CC: Tom Rini <trini@konsulko.com>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 659 bytes
Desc: not available
URL: <https://lists.denx.de/pipermail/u-boot/attachments/20210127/bb7f9bb5/attachment.sig>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v2 3/3] board: presidio-asic: Add CAxxxx Ethernet support
  2021-01-14 21:34 Alex Nemirovsky
@ 2021-01-14 21:34 ` Alex Nemirovsky
  2021-01-27 19:22   ` Tom Rini
  0 siblings, 1 reply; 9+ messages in thread
From: Alex Nemirovsky @ 2021-01-14 21:34 UTC (permalink / raw)
  To: u-boot

Add CAxxxx Ethernet support for the Cortina Access
Presidio Engineering Board

Signed-off-by: Alex Nemirovsky <alex.nemirovsky@cortina-access.com>
CC: Tom Rini <trini@konsulko.com>

---

Changes in v2:
- only support DM_ETH network models by removing
code for legacy mode support

 arch/arm/dts/ca-presidio-engboard.dts        | 31 ++++++++++++++++++++++++++++
 configs/cortina_presidio-asic-emmc_defconfig |  4 +++-
 include/configs/presidio_asic.h              | 15 +++++++++++++-
 3 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/arch/arm/dts/ca-presidio-engboard.dts b/arch/arm/dts/ca-presidio-engboard.dts
index eef433e..7919866 100644
--- a/arch/arm/dts/ca-presidio-engboard.dts
+++ b/arch/arm/dts/ca-presidio-engboard.dts
@@ -95,4 +95,35 @@
 		};
 
 	};
+
+	eth: ethnet at 0xf4300000 {
+		compatible = "eth_cortina";
+		reg = <0x0 0xf4320000 0x34>,
+		      <0x0 0xf43290d8 0x04>,
+		      <0x0 0xf4304000 0x04>;
+
+		/* 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
+		 */
+		valid-port-map = <0x1f>;
+		valid-port-num = <5>;
+		valid-ports = <0x1 0x0>,
+			      <0x2 0x1>,
+			      <0x3 0x2>,
+			      <0x4 0x3>,
+			      <0x5 0x4>;
+		def-active-port = <0x3>;
+		inter-gphy-num = <6>;
+		inter-gphy-val = <0xf43380fc 0xbcd>,
+				 <0xf43380dc 0xeeee>,
+				 <0xf43380d8 0xeeee>,
+				 <0xf43380fc 0xbce>,
+				 <0xf43380c0 0x7777>,
+				 <0xf43380c4 0x7777>;
+		init-rgmii = <1>;
+		ni-xram-base = <0xF4500000>;
+	};
 };
diff --git a/configs/cortina_presidio-asic-emmc_defconfig b/configs/cortina_presidio-asic-emmc_defconfig
index faffdd4..eec9584 100644
--- a/configs/cortina_presidio-asic-emmc_defconfig
+++ b/configs/cortina_presidio-asic-emmc_defconfig
@@ -22,7 +22,6 @@ CONFIG_CMD_EXT2=y
 CONFIG_CMD_EXT4=y
 CONFIG_OF_CONTROL=y
 CONFIG_OF_LIVE=y
-# CONFIG_NET is not set
 CONFIG_DM=y
 CONFIG_CORTINA_GPIO=y
 CONFIG_DM_I2C=y
@@ -30,6 +29,9 @@ CONFIG_SYS_I2C_CA=y
 CONFIG_DM_MMC=y
 CONFIG_MMC_DW=y
 CONFIG_MMC_DW_CORTINA=y
+CONFIG_PHYLIB=y
+CONFIG_DM_ETH=y
+CONFIG_CORTINA_NI_ENET=y
 CONFIG_DM_SERIAL=y
 CONFIG_CORTINA_UART=y
 CONFIG_WDT=y
diff --git a/include/configs/presidio_asic.h b/include/configs/presidio_asic.h
index 34235b5..c2082b4 100644
--- a/include/configs/presidio_asic.h
+++ b/include/configs/presidio_asic.h
@@ -2,7 +2,7 @@
 /*
  * Copyright (C) 2020 Cortina Access Inc.
  *
- * Configuration for Cortina-Access Presidio board.
+ * Configuration for Cortina-Access Presidio board
  */
 
 #ifndef __PRESIDIO_ASIC_H
@@ -63,6 +63,19 @@
 					sizeof(CONFIG_SYS_PROMPT) + 16)
 #define CONFIG_SYS_BARGSIZE		CONFIG_SYS_CBSIZE
 
+#define KSEG1_ATU_XLAT(x) (x)
+
+/* HW REG ADDR */
+#define NI_READ_POLL_COUNT                      1000
+#define CA_NI_MDIO_REG_BASE                     0xF4338
+#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
+
 /* max command args */
 #define CONFIG_SYS_MAXARGS		64
 #define CONFIG_EXTRA_ENV_SETTINGS	"silent=y\0"
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2021-01-27 19:22 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-30 19:05 [PATCH v2 1/3] net: cortina_ni: Add eth support for Cortina Access CAxxxx SoCs Alex Nemirovsky
2020-07-30 19:05 ` [PATCH v2 2/3] net: phy: ca_phy: Add driver for " Alex Nemirovsky
2020-07-30 19:05 ` [PATCH v2 3/3] board: presidio-asic: Add CAxxxx Ethernet support Alex Nemirovsky
2020-09-10 23:18 ` [PATCH v2 1/3] net: cortina_ni: Add eth support for Cortina Access CAxxxx SoCs Alex Nemirovsky
2020-09-10 23:54   ` Tom Rini
2020-09-10 23:56     ` Alex Nemirovsky
2020-09-24  1:00     ` Alex Nemirovsky
2021-01-14 21:34 Alex Nemirovsky
2021-01-14 21:34 ` [PATCH v2 3/3] board: presidio-asic: Add CAxxxx Ethernet support Alex Nemirovsky
2021-01-27 19:22   ` Tom Rini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.