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