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

Ramon Fried rfried.dev at gmail.com
Thu Jun 4 18:28:39 CEST 2020


On Wed, Jun 3, 2020 at 11:05 AM Alex Nemirovsky
<alex.nemirovsky at cortina-access.com> wrote:
>
> From: Aaron Tseng <aaron.tseng at cortina-access.com>
>
> Add Cortina Access Ethernet device driver for CAxxxx SoCs.
> This driver supports only the DM_ETH network model.
>
> Signed-off-by: Aaron Tseng <aaron.tseng at cortina-access.com>
> Signed-off-by: Alex Nemirovsky <alex.nemirovsky at cortina-access.com>
>
> CC: Joe Hershberger <joe.hershberger at ni.com>
> CC: Abbie Chang <abbie.chang at Cortina-Access.com>
> CC: Tom Rini <trini at konsulko.com>
>
> ---
>
> Changes in v4: None
> Changes in v3:
> - Changed commit comment to state that only DM model is supported
> - Removed blank line at end of C file
>
> Changes in v2:
> - Remove legacy mode support
> - Add support for additional SoC variants
> - Remove unused variables
>
>  MAINTAINERS              |    4 +
>  drivers/net/Kconfig      |    7 +
>  drivers/net/Makefile     |    1 +
>  drivers/net/cortina_ni.c | 1909 ++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/net/cortina_ni.h |  592 ++++++++++++++
>  5 files changed, 2513 insertions(+)
>  create mode 100644 drivers/net/cortina_ni.c
>  create mode 100644 drivers/net/cortina_ni.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 8add9d4..1b166d2 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -181,6 +181,8 @@ F:  drivers/gpio/cortina_gpio.c
>  F:     drivers/watchdog/cortina_wdt.c
>  F:     drivers/serial/serial_cortina.c
>  F:     drivers/mmc/ca_dw_mmc.c
> +F:     drivers/net/cortina_ni.c
> +F:     drivers/net/cortina_ni.h
>
>  ARM/CZ.NIC TURRIS MOX SUPPORT
>  M:     Marek Behun <marek.behun at nic.cz>
> @@ -732,6 +734,8 @@ F:  drivers/gpio/cortina_gpio.c
>  F:     drivers/watchdog/cortina_wdt.c
>  F:     drivers/serial/serial_cortina.c
>  F:     drivers/mmc/ca_dw_mmc.c
> +F:     drivers/net/cortina_ni.c
> +F:     drivers/net/cortina_ni.h
>
>  MIPS MSCC
>  M:     Gregory CLEMENT <gregory.clement at bootlin.com>
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index f7855c9..45e0480 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -149,6 +149,13 @@ config BCMGENET
>         help
>           This driver supports the BCMGENET Ethernet MAC.
>
> +config CORTINA_NI_ENET
> +       bool "Cortina-Access Ethernet driver"
> +       depends on DM_ETH && CORTINA_PLATFORM
> +       help
> +         The driver supports the Cortina-Access Ethernet MAC for
> +         all supported CAxxxx SoCs
> +
>  config DWC_ETH_QOS
>         bool "Synopsys DWC Ethernet QOS device support"
>         depends on DM_ETH
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index 383ed1c..1d6ec4f 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
>  obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
>  obj-$(CONFIG_BCM_SF2_ETH_GMAC) += bcm-sf2-eth-gmac.o
>  obj-$(CONFIG_CALXEDA_XGMAC) += calxedaxgmac.o
> +obj-$(CONFIG_CORTINA_NI_ENET) += cortina_ni.o
>  obj-$(CONFIG_CS8900) += cs8900.o
>  obj-$(CONFIG_TULIP) += dc2114x.o
>  obj-$(CONFIG_ETH_DESIGNWARE) += designware.o
> diff --git a/drivers/net/cortina_ni.c b/drivers/net/cortina_ni.c
> new file mode 100644
> index 0000000..d5bbf3e
> --- /dev/null
> +++ b/drivers/net/cortina_ni.c
> @@ -0,0 +1,1909 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +/*
> + * Copyright (C) 2020 Cortina Access Inc.
> + * Author: Aaron Tseng <aaron.tseng at cortina-access.com>
> + *
> + * Ethernet MAC Driver for all supported CAxxxx SoCs
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <malloc.h>
> +#include <net.h>
> +#include <miiphy.h>
> +#include <env.h>
> +#include <linux/delay.h>
> +
> +#include "cortina_ni.h"
> +
> +static u32 reg_value;
> +
> +/* port 0-3 are individual port connect to PHY directly */
> +/* port 4-7 are LAN ports connected to QSGMII PHY */
> +int active_port = NI_PORT_5;  /* Physical port 5 */
> +u32 ge_port_phy_addr;  /* PHY address connected to active port */
> +int auto_scan_active_port;
> +
> +#define HEADER_A_SIZE  8
> +
> +/*define CORTINA_NI_DBG if individual rx,tx,init needs to be called */
> +#if CORTINA_NI_DBG
> +static struct udevice  *dbg_dev;
> +#endif
> +static struct udevice   *curr_dev;
> +
> +#if defined(CONFIG_TARGET_SATURN_ASIC)
> +#define CA_REG_READ(off)        readl((u64)KSEG1_ATU_XLAT(off))
> +#define CA_REG_WRITE(data, off) writel(data, (u64)KSEG1_ATU_XLAT(off))
> +#else
> +#define CA_REG_READ(off)        readl((u64)off)
> +#define CA_REG_WRITE(data, off) writel(data, (u64)off)
> +#endif
> +
> +int cortina_ni_recv(struct udevice *netdev);
> +static int ca_ni_ofdata_to_platdata(struct udevice *dev);
> +
> +static u32 *RDWRPTR_ADVANCE_ONE(u32 *x, unsigned long base, unsigned long max)
Please don't use upper case function names.
> +{
> +       if (x + 1 >= (u32 *)max)
> +               return (u32 *)base;
> +       else
> +               return (x + 1);
> +}
> +
> +static void ni_setup_mac_addr(void)
> +{
> +       unsigned char mac[6];
> +
> +       union NI_HV_GLB_MAC_ADDR_CFG0_t         mac_addr_cfg0;
> +       union NI_HV_GLB_MAC_ADDR_CFG1_t         mac_addr_cfg1;
> +       union NI_HV_PT_PORT_STATIC_CFG_t        port_static_cfg;
> +       union NI_HV_XRAM_CPUXRAM_CFG_t          cpuxram_cfg;
> +       struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
> +
> +       /* parsing ethaddr and set to NI registers. */
> +       if (eth_env_get_enetaddr("ethaddr", mac)) {
> +               /* The complete MAC address consists of
> +                * {MAC_ADDR0_mac_addr0[0-3], MAC_ADDR1_mac_addr1[4],
> +                * PT_PORT_STATIC_CFG_mac_addr6[5]}.
> +                */
> +               mac_addr_cfg0.bf.mac_addr0 = (mac[0] << 24) +
> +                                            (mac[1] << 16) +
> +                                            (mac[2] << 8) +
> +                                            mac[3];
> +               CA_REG_WRITE(mac_addr_cfg0.wrd, priv->ni_hv_base_addr
> +                               + NI_HV_GLB_MAC_ADDR_CFG0_OFFSET);
> +
> +               mac_addr_cfg1.wrd = 0;
> +               mac_addr_cfg1.bf.mac_addr1 = mac[4];
> +               CA_REG_WRITE(mac_addr_cfg1.wrd, (priv->ni_hv_base_addr +
> +                               NI_HV_GLB_MAC_ADDR_CFG1_OFFSET));
> +
> +               port_static_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
> +                                       NI_HV_PT_PORT_STATIC_CFG_OFFSET +
> +                                       APB0_NI_HV_PT_STRIDE * active_port));
> +
> +               port_static_cfg.bf.mac_addr6 = mac[5];
> +               CA_REG_WRITE(port_static_cfg.wrd, (priv->ni_hv_base_addr +
> +                                       NI_HV_PT_PORT_STATIC_CFG_OFFSET +
> +                                       APB0_NI_HV_PT_STRIDE * active_port));
> +
> +               /* received only Broadcast and Address matched packets */
> +               cpuxram_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
> +                               NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
> +               cpuxram_cfg.bf.xram_mgmt_promisc_mode = 0;
> +               cpuxram_cfg.bf.rx_0_cpu_pkt_dis = 0;
> +               cpuxram_cfg.bf.tx_0_cpu_pkt_dis = 0;
> +               CA_REG_WRITE(cpuxram_cfg.wrd, (priv->ni_hv_base_addr +
> +                                       NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
> +       } else {
> +               /* received all packets(promiscuous mode) */
> +               cpuxram_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
> +                                       NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
> +               cpuxram_cfg.bf.xram_mgmt_promisc_mode = 3;
> +               cpuxram_cfg.bf.rx_0_cpu_pkt_dis = 0;
> +               cpuxram_cfg.bf.tx_0_cpu_pkt_dis = 0;
> +               CA_REG_WRITE(cpuxram_cfg.wrd, (priv->ni_hv_base_addr +
> +                                       NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
> +       }
> +}
> +
> +static void ni_enable_tx_rx(void)
> +{
> +       union NI_HV_PT_RXMAC_CFG_t rxmac_cfg;
> +       union NI_HV_PT_TXMAC_CFG_t txmac_cfg;
> +
> +       struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
> +
> +       /* Enable TX and RX functions */
> +       rxmac_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
> +                               NI_HV_PT_RXMAC_CFG_OFFSET +
> +                               APB0_NI_HV_PT_STRIDE * active_port));
> +       rxmac_cfg.bf.rx_en = 1;
> +       CA_REG_WRITE(rxmac_cfg.wrd, (priv->ni_hv_base_addr +
> +                               NI_HV_PT_RXMAC_CFG_OFFSET +
> +                               APB0_NI_HV_PT_STRIDE * active_port));
> +
> +       txmac_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
> +                               NI_HV_PT_TXMAC_CFG_OFFSET +
> +                               APB0_NI_HV_PT_STRIDE * active_port));
> +       txmac_cfg.bf.tx_en = 1;
> +       CA_REG_WRITE(txmac_cfg.wrd, (priv->ni_hv_base_addr +
> +                               NI_HV_PT_TXMAC_CFG_OFFSET +
> +                               APB0_NI_HV_PT_STRIDE * active_port));
> +}
> +
> +void cortina_ni_reset(void)
> +{
> +       int i;
> +       union NI_HV_GLB_INIT_DONE_t             init_done;
> +       union NI_HV_GLB_INTF_RST_CONFIG_t       intf_rst_config;
> +       union NI_HV_GLB_STATIC_CFG_t            static_cfg;
> +       union GLOBAL_BLOCK_RESET_t              glb_blk_reset;
> +
> +       struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
> +
> +       /* NI global resets */
> +       glb_blk_reset.wrd = CA_REG_READ((priv->glb_base_addr +
> +                               GLOBAL_BLOCK_RESET_OFFSET));
> +       glb_blk_reset.bf.reset_ni = 1;
> +       CA_REG_WRITE(glb_blk_reset.wrd, (priv->glb_base_addr +
> +                               GLOBAL_BLOCK_RESET_OFFSET));
> +       /* Remove resets */
> +       glb_blk_reset.bf.reset_ni = 0;
> +       CA_REG_WRITE(glb_blk_reset.wrd, (priv->glb_base_addr +
> +                               GLOBAL_BLOCK_RESET_OFFSET));
> +
> +       /* check the ready bit of NI module */
> +       for (i = 0; i < NI_READ_POLL_COUNT; i++) {
> +               init_done.wrd = CA_REG_READ((priv->ni_hv_base_addr +
> +                                       NI_HV_GLB_INIT_DONE_OFFSET));
> +               if (init_done.bf.ni_init_done)
> +                       break;
> +       }
> +       if (i == NI_READ_POLL_COUNT) {
> +               printf("%s: NI init done not ready, init_done.wrd=0x%x!!!\n",
> +                      __func__, init_done.wrd);
> +       }
> +
> +       intf_rst_config.wrd = CA_REG_READ(priv->ni_hv_base_addr +
> +                                         NI_HV_GLB_INTF_RST_CONFIG_OFFSET);
> +       switch (active_port) {
> +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
> +       case NI_PORT_0:
> +               intf_rst_config.bf.intf_rst_p0 = 0;
> +               intf_rst_config.bf.mac_rx_rst_p0 = 0;
> +               intf_rst_config.bf.mac_tx_rst_p0 = 0;
> +               break;
> +       case NI_PORT_1:
> +               intf_rst_config.bf.intf_rst_p1 = 0;
> +               intf_rst_config.bf.mac_rx_rst_p1 = 0;
> +               intf_rst_config.bf.mac_tx_rst_p1 = 0;
> +               break;
> +       case NI_PORT_2:
> +               intf_rst_config.bf.intf_rst_p2 = 0;
> +               intf_rst_config.bf.mac_rx_rst_p2 = 0;
> +               intf_rst_config.bf.mac_tx_rst_p2 = 0;
> +               break;
> +#endif
> +       case NI_PORT_3:
> +               intf_rst_config.bf.intf_rst_p3 = 0;
> +               intf_rst_config.bf.mac_tx_rst_p3 = 0;
> +               intf_rst_config.bf.mac_rx_rst_p3 = 0;
> +               break;
> +       case NI_PORT_4:
> +               intf_rst_config.bf.intf_rst_p4 = 0;
> +               intf_rst_config.bf.mac_tx_rst_p4 = 0;
> +               intf_rst_config.bf.mac_rx_rst_p4 = 0;
> +               break;
> +       }
> +
> +       CA_REG_WRITE(intf_rst_config.wrd, (priv->ni_hv_base_addr +
> +                               NI_HV_GLB_INTF_RST_CONFIG_OFFSET));
> +
> +       /* Only one GMAC can connect to CPU */
> +       static_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
> +                               NI_HV_GLB_STATIC_CFG_OFFSET));
> +
> +       static_cfg.bf.port_to_cpu = active_port;
> +       static_cfg.bf.txmib_mode = 1;
> +       static_cfg.bf.rxmib_mode = 1;
> +
> +       CA_REG_WRITE(static_cfg.wrd, (priv->ni_hv_base_addr +
> +                               NI_HV_GLB_STATIC_CFG_OFFSET));
> +
> +       //printf("%s: Connect port %d to CPU\n", __func__, active_port);
> +
> +#if defined(CONFIG_TARGET_SATURN_ASIC)
> +       /* set IO driver control */
> +       io_driver_control.wrd = CA_REG_READ((priv->glb_base_addr +
> +                               GLOBAL_IO_DRIVE_CONTROL_OFFSET));
> +       io_driver_control.bf.gmac_dp = 1;
> +       io_driver_control.bf.gmac_dn = 1;
> +       io_driver_control.bf.gmac_ds = 0;
> +       io_driver_control.bf.gmac_mode = 2;
> +       CA_REG_WRITE(io_driver_control.wrd, (priv->glb_base_addr +
> +                               GLOBAL_IO_DRIVE_CONTROL_OFFSET));
> +
> +       /* initialize internal GPHY */
> +       gige_phy.wrd = 0;
> +       gige_phy.bf.gphy_phyrst_cen_b = 1;
> +       CA_REG_WRITE(gige_phy.wrd, (priv->glb_base_addr +
> +                               GLOBAL_GIGE_PHY_OFFSET));
> +       mdelay(50);
> +
> +       CA_REG_WRITE(0xa46, 0xd000b0fc);
> +       mdelay(50);
> +       CA_REG_WRITE(0x1, 0xd000b0d0);
> +       mdelay(100);
> +#endif
> +}
> +
> +#define NI_ETH_SPEED_100 0xFFFFFFFE
> +#define NI_ETH_DUPLEX_FULL 0xFFFFFFD
> +#define PHY_MODE_MFE_MAC       BIT(12)
> +
> +#define NI_RX_ENB              BIT(2)
> +#define NI_TX_ENB              BIT(3)
> +#define FLOW_CNTL_RX_DSBL      BIT(8)
> +#define FLOW_CNTL_TX_DSBL      BIT(12)
> +
> +static enum ca_status_t ca_mdio_write_rgmii(unsigned int addr,
> +                                           unsigned int offset,
> +                                           unsigned short data)
> +{
> +       union PER_MDIO_ADDR_t  mdio_addr;
> +       union PER_MDIO_CTRL_t  mdio_ctrl;
> +       /* up to 10000 cycles*/
> +       unsigned int      loop_wait = __MDIO_ACCESS_TIMEOUT;
> +
> +       struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
> +
> +       mdio_addr.wrd            = 0;
> +       mdio_addr.bf.mdio_addr   = addr;
> +       mdio_addr.bf.mdio_offset = offset;
> +       mdio_addr.bf.mdio_rd_wr  = __MDIO_WR_FLAG;
> +       CA_REG_WRITE(mdio_addr.wrd,
> +                    priv->per_mdio_base_addr + PER_MDIO_ADDR_OFFSET);
> +       CA_REG_WRITE(data,
> +                    priv->per_mdio_base_addr + PER_MDIO_WRDATA_OFFSET);
> +
> +#if CORTINA_NI_DBG
> +       printf("%s: mdio_addr.wrd=0x%x\n", __func__, mdio_addr.wrd);
> +#endif
> +
> +       mdio_ctrl.wrd          = 0;
> +       mdio_ctrl.bf.mdiostart = 1;
> +       CA_REG_WRITE(mdio_ctrl.wrd,
> +                    priv->per_mdio_base_addr + PER_MDIO_CTRL_OFFSET);
> +
> +#if CORTINA_NI_DBG
> +       printf("%s: phy_addr=%d, offset=%d, data=0x%x\n",
> +              __func__, addr, offset, data);
> +#endif
> +
> +       do {
> +               mdio_ctrl.wrd = CA_REG_READ((priv->per_mdio_base_addr +
> +                                       PER_MDIO_CTRL_OFFSET));
> +               if (mdio_ctrl.bf.mdiodone) {
> +                       CA_REG_WRITE(mdio_ctrl.wrd, (priv->per_mdio_base_addr +
> +                                               PER_MDIO_CTRL_OFFSET));
> +                       return CA_E_OK;
> +               }
> +       } while (--loop_wait);
> +
> +       printf("%s: PHY rite timeout!!!\n", __func__);
typo
> +       return CA_E_TIMEOUT;
> +}
> +
> +enum ca_status_t ca_mdio_write(CA_IN       unsigned int             addr,
> +                              CA_IN       unsigned int             offset,
> +                              CA_IN       unsigned short             data)
> +{
> +       /* support range: 1~31*/
> +       if (addr < CA_MDIO_ADDR_MIN || addr > CA_MDIO_ADDR_MAX)
> +               return CA_E_PARAM;
> +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || \
> +       defined(CONFIG_TARGET_SATURN_ASIC) || defined(CONFIG_TARGET_VENUS)
> +       union NI_MDIO_OPER_T mdio_oper;
> +
> +       /* the phy addr 5 is connect to RGMII */
> +       if (addr >= 5)
> +               return ca_mdio_write_rgmii(addr, offset, data);
> +
> +       mdio_oper.wrd = 0;
> +       mdio_oper.bf.reg_off = offset;
> +       mdio_oper.bf.phy_addr = addr;
> +       mdio_oper.bf.reg_base = CA_NI_MDIO_REG_BASE;
> +       CA_REG_WRITE(data, mdio_oper.wrd);
> +
> +#if CORTINA_NI_DBG
> +       printf("%s: mdio_oper.wrd=0x%x, data=0x%x\n",
> +              __func__, mdio_oper.wrd, data);
> +#endif
> +       return CA_E_OK;
> +#else
> +       return ca_mdio_write_rgmii(addr, offset, data);
> +#endif
> +}
> +
> +static enum ca_status_t ca_mdio_read_rgmii(unsigned int addr,
> +                                          unsigned int offset,
> +                                          unsigned short *data)
> +{
> +       union PER_MDIO_ADDR_t  mdio_addr;
> +       union PER_MDIO_CTRL_t  mdio_ctrl;
> +       union PER_MDIO_RDDATA_t  read_data;
> +       unsigned int loop_wait = __MDIO_ACCESS_TIMEOUT;
> +
> +       struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
> +
> +       mdio_addr.wrd            = 0;
> +       mdio_addr.bf.mdio_addr   = addr;
> +       mdio_addr.bf.mdio_offset = offset;
> +       mdio_addr.bf.mdio_rd_wr  = __MDIO_RD_FLAG;
> +       CA_REG_WRITE(mdio_addr.wrd,
> +                    priv->per_mdio_base_addr + PER_MDIO_ADDR_OFFSET);
> +
> +       mdio_ctrl.wrd          = 0;
> +       mdio_ctrl.bf.mdiostart = 1;
> +       CA_REG_WRITE(mdio_ctrl.wrd,
> +                    priv->per_mdio_base_addr + PER_MDIO_CTRL_OFFSET);
> +
> +       do {
> +               mdio_ctrl.wrd = CA_REG_READ((priv->per_mdio_base_addr +
> +                                       PER_MDIO_CTRL_OFFSET));
> +               if (mdio_ctrl.bf.mdiodone) {
> +                       CA_REG_WRITE(mdio_ctrl.wrd, (priv->per_mdio_base_addr +
> +                                               PER_MDIO_CTRL_OFFSET));
> +                       read_data.wrd = CA_REG_READ((priv->per_mdio_base_addr +
> +                                               PER_MDIO_RDDATA_OFFSET));
> +                       *data = read_data.bf.mdio_rddata;
> +                       return CA_E_OK;
> +               }
> +       } while (--loop_wait);
> +
> +       printf("%s: CA_E_TIMEOUT!!\n", __func__);
> +       return CA_E_TIMEOUT;
> +}
> +
> +enum ca_status_t ca_mdio_read(CA_IN       unsigned int          addr,
> +                             CA_IN       unsigned int          offset,
> +                             CA_OUT      unsigned short        *data)
> +{
> +       if (!data)
> +               return CA_E_PARAM;
> +
> +       /* support range: 1~31*/
> +       if (addr < CA_MDIO_ADDR_MIN || addr > CA_MDIO_ADDR_MAX)
> +               return CA_E_PARAM;
> +
> +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || \
> +       defined(CONFIG_TARGET_SATURN_ASIC) || defined(CONFIG_TARGET_VENUS)
> +       union NI_MDIO_OPER_T  mdio_oper;
> +
> +       /* the phy addr 5 is connect to RGMII */
> +       if (addr >= 5)
> +               return  ca_mdio_read_rgmii(addr, offset, data);
> +
> +       mdio_oper.wrd = 0;
> +       mdio_oper.bf.reg_off = offset;
> +       mdio_oper.bf.phy_addr = addr;
> +       mdio_oper.bf.reg_base = CA_NI_MDIO_REG_BASE;
> +       *data = CA_REG_READ(mdio_oper.wrd);
> +
> +       return CA_E_OK;
> +#else
> +       return ca_mdio_read_rgmii(addr, offset, data);
> +#endif
> +}
> +
> +int ca_miiphy_read(const char *devname,
> +                  unsigned char addr,
> +                  unsigned char reg,
> +                  unsigned short *value)
> +{
> +       return ca_mdio_read(addr, reg, value);
> +}
> +
> +int ca_miiphy_write(const char *devname,
> +                   unsigned char addr,
> +                   unsigned char reg,
> +                   unsigned short value)
> +{
> +       return ca_mdio_write(addr, reg, value);
> +}
> +
> +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
> +static void cortina_ni_fix_gphy(void)
> +{
> +       u16     data;
> +       u8      phy_addr;
> +
> +       for (phy_addr = 1; phy_addr < 5; phy_addr++) {
> +               /* Clear clock fail interrupt */
> +               ca_mdio_write(phy_addr, 31, 0xB90);
> +               ca_mdio_read(phy_addr, 19, &data);
> +               if (data == 0x10) {
> +                       ca_mdio_write(phy_addr, 31, 0xB90);
> +                       ca_mdio_read(phy_addr, 19, &data);
> +                       printf("%s: read again phy_addr=", __func__);
> +                       printf("%d, read register 19, ", phy_addr);
> +                       printf("val=0x%x\n", data);
> +               }
> +#ifdef CORTINA_NI_DBG
> +               printf("%s: phy_addr=%d, read register 19, value=0x%x\n",
> +                      __func__, phy_addr, data);
> +#endif
> +       }
> +}
> +#endif
> +
> +int cortina_ni_init(struct udevice *dev)
> +{
> +       u16  vendor_id, chip_id;
> +       u32  phy_id;
> +       u16  phy_reg_value, lpagb, lpa, phy_speed, phy_duplex, speed, duplex;
> +       char *spd, *dup;
> +       union NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t    cpuxram_adrcfg_rx;
> +       union NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t  cpuxram_adrcfg_tx;
> +       union NI_HV_XRAM_CPUXRAM_CFG_t          cpuxram_cfg;
> +       union NI_HV_PT_PORT_STATIC_CFG_t        port_static_cfg;
> +       union NI_HV_PT_PORT_GLB_CFG_t           port_glb_cfg;
> +
> +       struct cortina_ni_priv *priv = dev_get_priv(dev);
> +
> +       /* read "ethaddr" and setup to NI regsiters */
> +       ni_setup_mac_addr();
> +
> +       /* RX XRAM ADDRESS CONFIG (start and end address) */
> +       cpuxram_adrcfg_rx.wrd = 0;
> +       cpuxram_adrcfg_rx.bf.rx_top_addr = RX_TOP_ADDR;
> +       cpuxram_adrcfg_rx.bf.rx_base_addr = RX_BASE_ADDR;
> +       CA_REG_WRITE(cpuxram_adrcfg_rx.wrd, (priv->ni_hv_base_addr +
> +                               NI_HV_XRAM_CPUXRAM_ADRCFG_RX_OFFSET));
> +
> +       /* TX XRAM ADDRESS CONFIG (start and end address) */
> +       cpuxram_adrcfg_tx.wrd = 0;
> +       cpuxram_adrcfg_tx.bf.tx_top_addr = TX_TOP_ADDR;
> +       cpuxram_adrcfg_tx.bf.tx_base_addr = TX_BASE_ADDR;
> +       CA_REG_WRITE(cpuxram_adrcfg_tx.wrd, (priv->ni_hv_base_addr +
> +                               NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_OFFSET));
> +
> +       ca_mdio_read(ge_port_phy_addr, 0x02, &vendor_id);
> +       ca_mdio_read(ge_port_phy_addr, 0x03, &chip_id);
> +       phy_id = (vendor_id << 16) | chip_id;
> +
> +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
> +       /* workaround to fix GPHY fail */
> +       if ((phy_id & PHY_ID_MASK) == PHY_ID_RTL8211_G3_ASIC)
> +               cortina_ni_fix_gphy();
> +#endif
> +
> +       /* PHY GB status */
> +       ca_mdio_read(ge_port_phy_addr, 0x0a, &lpagb);
> +       /* PHY GB control */
> +       ca_mdio_read(ge_port_phy_addr, 0x09, &phy_reg_value);
> +       lpagb &= phy_reg_value << 2;
> +
> +       /* Link Partner Ability */
> +       ca_mdio_read(ge_port_phy_addr, 0x05, &lpa);
> +       /* PHY Advertisement */
> +       ca_mdio_read(ge_port_phy_addr, 0x04, &phy_reg_value);
> +       lpa &= phy_reg_value;
> +
> +       /* phy_speed 0: 10Mbps, 1: 100Mbps, 2: 1000Mbps */
> +       /* duplex 0: half duplex, 1: full duplex */
> +       phy_speed = 0;
> +       phy_duplex = 0;
> +       if (lpagb & (3 << 10)) {
> +               /* 1000Mbps */
> +               phy_speed = 2;
> +               if (lpagb & (1 << 11)) {
> +                       /* 1000Mbps full */
> +                       duplex = 1;
> +               }
> +       } else if (lpa & (3 << 7)) {
> +               /* 100Mbps */
> +               phy_speed = 1;
> +               if (lpa & (1 << 8)) {
> +                       /* 100Mbps full */
> +                       phy_duplex = 1;
> +               }
> +       } else if (lpa & (1 << 6)) {
> +               /* 10Mbps full */
> +               phy_duplex = 1;
> +       }
> +
> +       switch (phy_speed) {
> +       default:
> +       case 0:
> +               spd = "10Mbps";
> +               break;
> +       case 1:
> +               spd = "100Mbps";
> +               break;
> +       case 2:
> +               spd = "1000Mbps";
> +               break;
> +       }
> +
> +       if (duplex == 1)
> +               dup = "full duplex";
> +       else
> +               dup = "half duplex";
> +
> +       printf("PHY ID 0x%08X %s %s\n", phy_id, spd, dup);
> +
> +       switch (phy_id & PHY_ID_MASK) {
> +       case PHY_ID_RTL8214:
> +               port_static_cfg.wrd =
> +                       CA_REG_READ((priv->ni_hv_base_addr +
> +                                  NI_HV_PT_PORT_STATIC_CFG_OFFSET +
> +                                  APB0_NI_HV_PT_STRIDE * active_port));
> +               /* QSGMII_GE */
> +               port_static_cfg.bf.int_cfg = GE_MAC_INTF_QSGMII_1000;
> +               CA_REG_WRITE(port_static_cfg.wrd,
> +                            (priv->ni_hv_base_addr +
> +                             NI_HV_PT_PORT_STATIC_CFG_OFFSET +
> +                             APB0_NI_HV_PT_STRIDE * active_port));
> +               break;
> +       case PHY_ID_RTL8211:
> +               /* fallthrough */
> +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
> +       case PHY_ID_RTL8211_G3_ASIC:
> +               /* fallthrough */
> +#endif
> +#ifdef CONFIG_TARGET_SATURN_ASIC
> +       case PHY_ID_RTL8211_SATURN_ASIC:
> +               /* fallthrough */
> +#endif
> +       default:
> +               /*
> +                * Configuration for Management Ethernet
> +                * Interface:
> +                * - RGMII 1000 mode or RGMII 100 mode
> +                * - MAC mode
> +                */
> +               port_static_cfg.wrd =
> +                       CA_REG_READ((priv->ni_hv_base_addr +
> +                                   NI_HV_PT_PORT_STATIC_CFG_OFFSET +
> +                                   APB0_NI_HV_PT_STRIDE * active_port));
> +               if (phy_speed == 2 /* 1000Mbps */) {
> +                       /* port 4 connects to RGMII PHY */
> +                       if (ge_port_phy_addr == 5)
> +                               port_static_cfg.bf.int_cfg =
> +                                       GE_MAC_INTF_RGMII_1000;
> +                       else
> +                               port_static_cfg.bf.int_cfg = GE_MAC_INTF_GMII;
> +               } else {
> +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || \
> +       defined(CONFIG_TARGET_SATURN_ASIC) || defined(CONFIG_TARGET_VENUS)
> +                       /* port 4 connects to RGMII PHY */
> +                       if (ge_port_phy_addr == 5) {
> +                               port_static_cfg.bf.int_cfg =
> +                                       GE_MAC_INTF_RGMII_100;
> +                       } else {
> +                               port_static_cfg.bf.int_cfg = GE_MAC_INTF_MII;
> +                       }
> +#else
> +                       port_static_cfg.bf.int_cfg = GE_MAC_INTF_RGMII_100;
> +#endif
> +               }
> +               CA_REG_WRITE(port_static_cfg.wrd,
> +                            (priv->ni_hv_base_addr +
> +                            NI_HV_PT_PORT_STATIC_CFG_OFFSET +
> +                            APB0_NI_HV_PT_STRIDE * active_port));
> +               break;
> +       }
> +
> +       port_glb_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
> +                                      NI_HV_PT_PORT_GLB_CFG_OFFSET +
> +                                      APB0_NI_HV_PT_STRIDE * active_port));
> +       if (phy_speed == 0)  /* 10Mbps */
> +               speed = 1;
> +       else
> +               speed = 0;
> +       if (phy_duplex == 0)  /* half duplex */
> +               duplex = 1;
> +       else
> +               duplex = 0;
> +       port_glb_cfg.bf.speed = speed;
> +       port_glb_cfg.bf.duplex = duplex;
> +       CA_REG_WRITE(port_glb_cfg.wrd, (priv->ni_hv_base_addr +
> +                                       NI_HV_PT_PORT_GLB_CFG_OFFSET +
> +                                       APB0_NI_HV_PT_STRIDE * active_port));
> +
> +#if FOR_DEBUG
> +       /* Enable MFE ethernet interface */
> +       reg_value = CA_REG_READ(NI_TOP_NI_INTF_RST_CONFIG);
> +       reg_value = reg_value & ~(INTF_RST_GE);
> +       CA_REG_WRITE(reg_value, NI_TOP_NI_INTF_RST_CONFIG);
> +#endif
> +
> +       /* Need to toggle the tx and rx cpu_pkt_dis bit */
> +       /* after changing Address config register.      */
> +       cpuxram_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
> +                               NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
> +       cpuxram_cfg.bf.rx_0_cpu_pkt_dis = 1;
> +       cpuxram_cfg.bf.tx_0_cpu_pkt_dis = 1;
> +       CA_REG_WRITE(cpuxram_cfg.wrd, (priv->ni_hv_base_addr +
> +                               NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
> +
> +       cpuxram_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
> +                               NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
> +       cpuxram_cfg.bf.rx_0_cpu_pkt_dis = 0;
> +       cpuxram_cfg.bf.tx_0_cpu_pkt_dis = 0;
> +       CA_REG_WRITE(cpuxram_cfg.wrd, (priv->ni_hv_base_addr +
> +                               NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
> +
> +       ni_enable_tx_rx();
> +
> +       return 0;
> +}
> +
> +int cortina_ni_check_rx_packet(void)
> +{
> +       static int first_time = 1;
> +       union NI_HV_XRAM_CPUXRAM_CFG_t        cpuxram_cfg;
> +
> +       struct cortina_ni_priv *priv = dev_get_priv(curr_dev);
> +
> +       if (first_time) {
> +               /* received all kind of packets */
> +               cpuxram_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr +
> +                                       NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
> +               cpuxram_cfg.bf.xram_mgmt_promisc_mode = 3;
> +               cpuxram_cfg.bf.rx_0_cpu_pkt_dis = 0;
> +               cpuxram_cfg.bf.tx_0_cpu_pkt_dis = 0;
> +               CA_REG_WRITE(cpuxram_cfg.wrd, (priv->ni_hv_base_addr +
> +                                       NI_HV_XRAM_CPUXRAM_CFG_OFFSET));
> +               first_time = 0;
> +       }
> +
> +       cortina_ni_recv(curr_dev);
> +       return 0;
> +}
> +
> +/*********************************************
> + * Packet receive routine from Management FE
> + * Expects a previously allocated buffer and
> + * fills the length
> + * Retruns 0 on success -1 on failure
> + *******************************************/
> +int cortina_ni_recv(struct udevice *netdev)
> +{
> +       struct cortina_ni_priv *priv = dev_get_priv(netdev);
> +       union NI_HEADER_X_T             header_x;
> +       u32                     pktlen = 0;
> +       u32                     sw_rx_rd_ptr;
> +       u32                     hw_rx_wr_ptr;
> +       u32                     *rx_xram_ptr;
> +       int                     loop;
> +       u32                     *data_ptr;
> +       union NI_PACKET_STATUS packet_status;
> +       union NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t cpuxram_cpu_sta_rx;
> +       union NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t cpuxram_cpu_cfg_rx;
> +       int index = 0;
> +#ifdef CORTINA_NI_DBG
> +       int                     blk_num;
> +       u8                      *ptr;
> +#endif
> +
> +       /* get the hw write pointer */
> +       cpuxram_cpu_sta_rx.wrd = CA_REG_READ((priv->ni_hv_base_addr +
> +                               NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET));
> +       hw_rx_wr_ptr = cpuxram_cpu_sta_rx.bf.pkt_wr_ptr;
> +
> +       /* get the sw read pointer */
> +       cpuxram_cpu_cfg_rx.wrd = CA_REG_READ((priv->ni_hv_base_addr +
> +                               NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET));
> +       sw_rx_rd_ptr = cpuxram_cpu_cfg_rx.bf.pkt_rd_ptr;
> +
> +#if CORTINA_NI_DBG
> +       printf("%s: NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0 = 0x%p, ",
> +              __func__,
> +              priv->ni_hv_base_addr + NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET);
> +       printf("NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0 = 0x%p\n",
> +              priv->ni_hv_base_addr + NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
> +       printf("%s : RX hw_wr_ptr = %d, sw_rd_ptr = %d\n",
> +              __func__, hw_rx_wr_ptr, sw_rx_rd_ptr);
> +#endif
> +
> +       while (sw_rx_rd_ptr != hw_rx_wr_ptr) {
> +               /* Point to the absolute memory address of XRAM
> +                * where read pointer is
> +                */
> +               rx_xram_ptr = (u32 *)
> +                             ((unsigned long)NI_XRAM_BASE + sw_rx_rd_ptr * 8);
> +
> +               /* Wrap around if required */
> +               if (rx_xram_ptr >= (u32 *)(unsigned long)priv->rx_xram_end_adr)
> +                       rx_xram_ptr = (u32 *)
> +                                     (unsigned long)priv->rx_xram_base_adr;
> +
> +               /* Checking header XR. Do not update the read pointer yet */
> +               //rx_xram_ptr++;
> +               /* skip unused 32-bit in Header XR */
> +               rx_xram_ptr = RDWRPTR_ADVANCE_ONE(rx_xram_ptr,
> +                                                 priv->rx_xram_base_adr,
> +                                                 priv->rx_xram_end_adr);
> +
> +               header_x = (union NI_HEADER_X_T)(*rx_xram_ptr);
> +               /* Header XR [31:0] */
> +
> +               if (*rx_xram_ptr == 0xffffffff)
> +                       printf("%s: XRAM Error !\n", __func__);
> +#if CORTINA_NI_DBG
> +               printf("%s : RX next link %x(%d)\n", __func__,
> +                      header_x.bf.next_link, header_x.bf.next_link);
> +               printf("%s : bytes_valid %x\n", __func__,
> +                      header_x.bf.bytes_valid);
> +#endif
> +
> +               if (header_x.bf.ownership == 0) {
> +                       /* point to Packet status [31:0] */
> +                       //rx_xram_ptr++;
> +                       rx_xram_ptr =
> +                               RDWRPTR_ADVANCE_ONE(rx_xram_ptr,
> +                                                   priv->rx_xram_base_adr,
> +                                                   priv->rx_xram_end_adr);
> +
> +                       packet_status = (union NI_PACKET_STATUS)(*rx_xram_ptr);
> +
> +#if CORTINA_NI_DBG
> +                       printf("%s: packet_status=0x%x\n",
> +                              __func__, packet_status.wrd);
> +#endif
> +                       if (packet_status.bf.valid == 0) {
> +#if CORTINA_NI_DBG
> +                               printf("%s: Invalid Packet !!, ", __func__);
> +                               printf("Packet status=0x%x, ",
> +                                      packet_status.wrd);
> +                               printf("header_x.bf.next_link=%d\n",
> +                                      header_x.bf.next_link);
> +#endif
> +
> +                               /* Update the software read pointer */
> +                               CA_REG_WRITE(header_x.bf.next_link,
> +                                            priv->ni_hv_base_addr +
> +                                       NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
> +                               return 0;
> +                       }
> +
> +                       if (packet_status.bf.drop ||
> +                           packet_status.bf.runt ||
> +                           packet_status.bf.oversize ||
> +                           packet_status.bf.jabber ||
> +                           packet_status.bf.crc_error ||
> +                           packet_status.bf.jumbo) {
> +#if CORTINA_NI_DBG
> +                               printf("%s: Error Packet!! Packet status=0x%x,",
> +                                      __func__, packet_status.wrd);
> +                               printf(" header_x.bf.next_link=%d\n",
> +                                      header_x.bf.next_link);
> +#endif
> +
> +                               /* Update the software read pointer */
> +                               CA_REG_WRITE(header_x.bf.next_link,
> +                                            priv->ni_hv_base_addr +
> +                                       NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
> +                               return 0;
> +                       }
> +
> +                       /* check whether packet size is larger than 1514 */
> +                       if (packet_status.bf.packet_size > 1518) {
> +#if CORTINA_NI_DBG
> +                               printf("%s: Error Packet !! Packet size=%d, ",
> +                                      __func__, packet_status.bf.packet_size);
> +                               printf("larger than 1518, Packet status=0x%x, ",
> +                                      packet_status.wrd);
> +                               printf("header_x.bf.next_link=%d\n",
> +                                      header_x.bf.next_link);
> +#endif
> +
> +                               /* Update the software read pointer */
> +                               CA_REG_WRITE(header_x.bf.next_link,
> +                                            priv->ni_hv_base_addr +
> +                                       NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET);
> +                               return 0;
> +                       }
> +
> +                       rx_xram_ptr =
> +                               RDWRPTR_ADVANCE_ONE(rx_xram_ptr,
> +                                                   priv->rx_xram_base_adr,
> +                                                   priv->rx_xram_end_adr);
> +
> +                       pktlen = packet_status.bf.packet_size;
> +
> +#if CORTINA_NI_DBG
> +                       printf("%s : rx packet length = %d\n",
> +                              __func__, packet_status.bf.packet_size);
> +#endif
> +
> +                       rx_xram_ptr =
> +                               RDWRPTR_ADVANCE_ONE(rx_xram_ptr,
> +                                                   priv->rx_xram_base_adr,
> +                                                   priv->rx_xram_end_adr);
> +
> +                       data_ptr = (u32 *)net_rx_packets[index];
> +
> +                       /* Read out the packet */
> +                       /* Data is in little endian form in the XRAM */
> +
> +                       /* Send the packet to upper layer */
> +
> +#if CORTINA_NI_DBG
> +                       printf("%s: packet data[]=", __func__);
> +#endif
> +
> +                       for (loop = 0; loop <= pktlen / 4; loop++) {
> +#if CORTINA_NI_DBG
> +                               ptr = (u8 *)rx_xram_ptr;
> +                               if (loop < 10)
> +                                       printf("[0x%x]-[0x%x]-[0x%x]-[0x%x]",
> +                                              ptr[0], ptr[1], ptr[2], ptr[3]);
> +#endif
> +                               *data_ptr++ = *rx_xram_ptr++;
> +                               /* Wrap around if required */
> +                               if (rx_xram_ptr >= (u32 *)
> +                                   (unsigned long)priv->rx_xram_end_adr) {
> +                                       rx_xram_ptr = (u32 *)(unsigned long)
> +                                                      (priv->rx_xram_base_adr);
> +                               }
> +                       }
> +#if CORTINA_NI_DBG
> +                               printf("\n");
> +#endif
> +                       net_process_received_packet(net_rx_packets[index],
> +                                                   pktlen);
> +                       if (++index >= PKTBUFSRX)
> +                               index = 0;
> +#if CORTINA_NI_DBG
> +                       blk_num = net_rx_packets[index][0x2c] * 255 +
> +                               net_rx_packets[index][0x2d];
> +                       printf("%s: tftp block number=%d\n", __func__, blk_num);
> +#endif
> +
> +                       /* Update the software read pointer */
> +                       CA_REG_WRITE(header_x.bf.next_link,
> +                                    (priv->ni_hv_base_addr +
> +                                    NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET));
> +               }
> +
> +               /* get the hw write pointer */
> +               cpuxram_cpu_sta_rx.wrd =
> +                       CA_REG_READ((priv->ni_hv_base_addr +
> +                                  NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET));
> +               hw_rx_wr_ptr = cpuxram_cpu_sta_rx.bf.pkt_wr_ptr;
> +
> +               /* get the sw read pointer */
> +               sw_rx_rd_ptr =
> +                       CA_REG_READ((priv->ni_hv_base_addr +
> +                                  NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET));
> +       }
> +       return 0;
> +}
> +
> +/* LITTLE_ENDIAN */
> +static u32 calc_crc(u32 crc, u8 const *p, u32 len)
> +{
> +       int i;
> +
> +       while (len--) {
> +               crc ^= *p++;
> +               for (i = 0; i < 8; i++)
> +                       crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
> +       }
> +       return crc;
> +}
> +
> +static int cortina_ni_send(struct udevice *dev, void *packet, int length)
> +{
> +       struct cortina_ni_priv *priv = dev_get_priv(dev);
> +       u32     hw_tx_rd_ptr;
> +       u32     sw_tx_wr_ptr;
> +       unsigned int    new_pkt_len;
> +       unsigned char   valid_bytes = 0;
> +       u32     *tx_xram_ptr;
> +       u16  next_link = 0;
> +       unsigned char   *pkt_buf_ptr;
> +       unsigned int    loop;
> +       u32     crc32;
> +       union NI_HEADER_X_T     hdr_xt;
> +       int             pad = 0;
> +       static unsigned char   pkt_buf[2048];
> +       u32     *data_ptr;
> +       union NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t cpuxram_cpu_cfg_tx;
> +#if CORTINA_NI_DBG
> +       u8 *ptr;
> +#endif
> +
> +       if (!packet || length > 2032)
> +               return -1;
> +
> +       /* Get the hardware read pointer */
> +       hw_tx_rd_ptr = CA_REG_READ((priv->ni_hv_base_addr +
> +                                 NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET));
> +
> +       /* Get the software write pointer */
> +       sw_tx_wr_ptr = CA_REG_READ((priv->ni_hv_base_addr +
> +                                 NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET));
> +
> +#if CORTINA_NI_DBG
> +#if defined(CONFIG_TARGET_SATURN_ASIC)
> +       printf("%s: NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0=0x%p, ",
> +              __func__,
> +              KSEG1_ATU_XLAT(priv->ni_hv_base_addr +
> +                             NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET));
> +       printf("NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0=0x%p\n",
> +              KSEG1_ATU_XLAT(priv->ni_hv_base_addr +
> +                             NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET));
> +#else
> +       printf("%s: NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0=0x%p, ",
> +              __func__,
> +              priv->ni_hv_base_addr + NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET);
> +       printf("NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0=0x%p\n",
> +              priv->ni_hv_base_addr + NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET);
> +#endif
> +       printf("%s : hw_tx_rd_ptr = %d\n", __func__, hw_tx_rd_ptr);
> +       printf("%s : sw_tx_wr_ptr = %d\n", __func__, sw_tx_wr_ptr);
> +#endif
> +
> +       if (hw_tx_rd_ptr != sw_tx_wr_ptr) {
> +               printf("%s: Tx FIFO is not available!\n", __func__);
> +               return 1;
> +       }
> +
> +       /* a workaround on 2015/10/01
> +        * the packet size+CRC should be 8-byte alignment
> +        */
> +       if (((length + 4) % 8) != 0)
> +               length += (8 - ((length + 4) % 8));
> +
> +       memset(pkt_buf, 0x00, sizeof(pkt_buf));
> +
> +       /* add 8-byte header_A at the beginning of packet */
> +       //memcpy(&(pkt_buf[0]), (const void *)packet, 8);
> +       memcpy(&pkt_buf[HEADER_A_SIZE], (const void *)packet, length);
> +
> +       pad = 64 - (length + 4);        /* if packet length < 60 */
> +       pad = (pad < 0) ? 0 : pad;
> +
> +#if CORTINA_NI_DBG
> +       printf("%s: length=%d, pad=%d\n", __func__, length, pad);
> +#endif
> +
> +       new_pkt_len = length + pad;     /* new packet length */
> +
> +       pkt_buf_ptr = (unsigned char *)pkt_buf;
> +
> +       /* Calculate the CRC32 */
> +       /* skip 8-byte header_A */
> +       crc32 = ~(calc_crc(~0,
> +                       (u8 *)(pkt_buf_ptr + HEADER_A_SIZE), new_pkt_len));
> +
> +#if CORTINA_NI_DBG
> +       printf("%s: crc32 is 0x%x\n", __func__, crc32);
> +       printf("%s: ~crc32 is 0x%x\n", __func__, ~crc32);
> +       printf("%s: pkt len %d\n", __func__, new_pkt_len);
> +#endif
> +       /* should add 8-byte header_! */
> +       /* CRC will re-calculated by hardware */
> +       memcpy((pkt_buf_ptr + new_pkt_len + HEADER_A_SIZE),
> +              (u8 *)(&crc32), sizeof(crc32));
> +       new_pkt_len = new_pkt_len + 4;  /* add CRC */
> +
> +       valid_bytes = new_pkt_len % 8;
> +       valid_bytes = valid_bytes ? valid_bytes : 0;
> +
> +#if CORTINA_NI_DBG
> +       printf("%s: valid_bytes %d\n", __func__, valid_bytes);
> +#endif
> +
> +       /* should add 8-byte headerA */
> +       next_link = sw_tx_wr_ptr +
> +               (new_pkt_len + 7 + HEADER_A_SIZE) / 8; /* for headr XT */
> +       next_link = next_link + 1; /* add header */
> +       /* Wrap around if required */
> +       if (next_link > priv->tx_xram_end) {
> +               next_link = priv->tx_xram_start +
> +                       (next_link - (priv->tx_xram_end + 1));
> +       }
> +
> +#if CORTINA_NI_DBG
> +       printf("%s: TX next_link %x\n", __func__, next_link);
> +#endif
> +
> +       hdr_xt.wrd = 0;
> +       hdr_xt.bf.ownership = 1;
> +       hdr_xt.bf.bytes_valid = valid_bytes;
> +       hdr_xt.bf.next_link = next_link;
> +
> +       tx_xram_ptr = (u32 *)((unsigned long)NI_XRAM_BASE + sw_tx_wr_ptr * 8);
> +
> +       /* Wrap around if required */
> +       if (tx_xram_ptr >= (u32 *)(unsigned long)priv->tx_xram_end_adr)
> +               tx_xram_ptr = (u32 *)(unsigned long)priv->tx_xram_base_adr;
> +
> +       tx_xram_ptr = RDWRPTR_ADVANCE_ONE(tx_xram_ptr,
> +                                         priv->tx_xram_base_adr,
> +                                         priv->tx_xram_end_adr);
> +
> +       *tx_xram_ptr = hdr_xt.wrd;
> +
> +       tx_xram_ptr = RDWRPTR_ADVANCE_ONE(tx_xram_ptr,
> +                                         priv->tx_xram_base_adr,
> +                                         priv->tx_xram_end_adr);
> +
> +       /* Now to copy the data . The first byte on the line goes first */
> +       data_ptr = (u32 *)pkt_buf_ptr;
> +
> +#if CORTINA_NI_DBG
> +       printf("%s: packet data[]=", __func__);
> +#endif
> +
> +       /* copy header_A to XRAM */
> +       for (loop = 0; loop <= (new_pkt_len + HEADER_A_SIZE) / 4; loop++) {
> +#if CORTINA_NI_DBG
> +               ptr = (u8 *)data_ptr;
> +               if ((loop % 4) == 0)
> +                       printf("\n");
> +               printf("[0x%x]-[0x%x]-[0x%x]-[0x%x]-",
> +                      ptr[0], ptr[1], ptr[2], ptr[3]);
> +#endif
> +
> +               *tx_xram_ptr = *data_ptr++;
> +               tx_xram_ptr = RDWRPTR_ADVANCE_ONE(tx_xram_ptr,
> +                                                 priv->tx_xram_base_adr,
> +                                                 priv->tx_xram_end_adr);
> +       }
> +#if CORTINA_NI_DBG
> +       printf("\n");
> +#endif
> +
> +       /* Publish the software write pointer */
> +       cpuxram_cpu_cfg_tx.bf.pkt_wr_ptr = next_link;
> +       CA_REG_WRITE(cpuxram_cpu_cfg_tx.wrd,
> +                    (priv->ni_hv_base_addr +
> +                    NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET));
> +
> +       return 0;
> +}
> +
> +void cortina_ni_halt(struct udevice *netdev)
> +{
> +#if FOR_DEBUG
> +       /* MFE MAC configuration Disable tx and rx */
> +       reg_value = CA_REG_READ((priv->ni_hv_base_addr +
> +                              NI_TOP_NI_ETH_MAC_CONFIG0_0_MFE_OFFSET));
> +       reg_value = reg_value & ~(NI_RX_ENB);
> +       reg_value = reg_value & ~(NI_TX_ENB);
> +       CA_REG_WRITE(reg_value, (priv->ni_hv_base_addr +
> +                   NI_TOP_NI_ETH_MAC_CONFIG0_0_MFE_OFFSET));
> +
> +       /* Disable MFE ethernet interface */
> +       reg_value = CA_REG_READ(TOP_NI_INTF_RST_CONFIG);
> +       reg_value = reg_value | (INTF_RST_GE1);
> +       CA_REG_WRITE(reg_value, TOP_NI_INTF_RST_CONFIG);
> +#endif
> +}
> +
> +#define RTL8214_INIT_REG_COUNT         58
> +static u32 rtl8214_init_reg_val[RTL8214_INIT_REG_COUNT] = {
> +       0x6602, 0x84D7, 0x6601, 0x0540, 0x6600, 0x00C0,
> +       0x6602, 0xF994, 0x6601, 0x0541, 0x6600, 0x00C0,
> +       0x6602, 0x2DA3, 0x6601, 0x0542, 0x6600, 0x00C0,
> +       0x6602, 0x3960, 0x6601, 0x0543, 0x6600, 0x00C0,
> +       0x6602, 0x9728, 0x6601, 0x0544, 0x6600, 0x00C0,
> +       0x6602, 0xF83F, 0x6601, 0x0545, 0x6600, 0x00C0,
> +       0x6602, 0x9D85, 0x6601, 0x0423, 0x6600, 0x00C0,
> +       0x6602, 0xD810, 0x6601, 0x0424, 0x6600, 0x00C0,
> +       0x1D11, 0x1506,
> +       0x1D12, 0x0800,
> +       0x6602, 0xC3FA, 0x6601, 0x002E, 0x6600, 0x00C0
> +};
> +
> +#if defined(CONFIG_TARGET_VENUS)
> +static void __internal_phy_init(int reset_phy)
> +{
> +       u16 phy_addr;
> +       u16 data;
> +       u32 start_time;
> +
> +       /* GPHY clock rg_clr_clk_die_sys=0/rg_auto_clr_clk_die[10]=1 */
> +       for (phy_addr = 4; phy_addr > 0; phy_addr--) {
> +               ca_mdio_write(phy_addr, 31, 0x0C40);
> +               ca_mdio_write(phy_addr, 17, 0x0480);
> +       }
> +
> +       /* port 2 PLL port AIF correction */
> +       phy_addr = 3;
> +       ca_mdio_write(phy_addr, 31, 0x0BC6);
> +       ca_mdio_write(phy_addr, 16, 0x0053);
> +       ca_mdio_write(phy_addr, 18, 0x4003);
> +       ca_mdio_write(phy_addr, 22, 0x7E01);
> +       ca_mdio_write(phy_addr, 23, 0);
> +
> +       /* GIGA port AIF correction */
> +       for (phy_addr = 4; phy_addr > 0; phy_addr--) {
> +               ca_mdio_write(phy_addr, 31, 0x0BC0);
> +               ca_mdio_write(phy_addr, 19, 0x01C0);
> +               ca_mdio_write(phy_addr, 20, 0x3C61);
> +               ca_mdio_write(phy_addr, 21, 0x8022);
> +               ca_mdio_write(phy_addr, 23, 0x0441);
> +               ca_mdio_write(phy_addr, 31, 0x0BC1);
> +               ca_mdio_write(phy_addr, 16, 0x1328);
> +               ca_mdio_write(phy_addr, 17, 0xF0B0);
> +               ca_mdio_write(phy_addr, 18, 0x0E00);
> +       }
> +       mdelay(1);
> +
> +       /* check clk_fail = 0
> +        * read phy_fatal_err_int_flag & rg_auto_clr_clk_die[10]=0
> +        * power-on & reset GPHY
> +        */
> +       for (phy_addr = 4; phy_addr > 0; phy_addr--) {
> +               ca_mdio_write(phy_addr, 31, 0x0C40);
> +               ca_mdio_read(phy_addr,  18, &data);
> +               if (data & 1)
> +                       printf("%s: GPHY clock failed!!\n", __func__);
> +               ca_mdio_write(phy_addr, 31, 0x0B90);
> +               ca_mdio_read(phy_addr,  19, &data);
> +               ca_mdio_write(phy_addr, 31, 0x0B90);
> +               ca_mdio_read(phy_addr,  19, &data);
> +               mdelay(1);
> +               ca_mdio_write(phy_addr, 31, 0x0C40);
> +               ca_mdio_write(phy_addr, 17, 0x0080);
> +               mdelay(1);
> +               ca_mdio_write(phy_addr, 31, 0x0A42);
> +
> +               if (reset_phy) {
> +                       ca_mdio_write(phy_addr,  0, 0x9140);
> +
> +                       start_time = get_timer(0);
> +                       while (get_timer(start_time) < 3000) {
> +                               ca_mdio_read(phy_addr,   0, &data);
> +                               if (!(data & 0x8000)) {
> +                                       printf("%s: GPHY addr=%d, ",
> +                                              __func__, phy_addr);
> +                                       printf("reset completed!!\n");
> +                                       break;
> +                               }
> +                       }
> +                       if (data & 0x8000)
> +                               printf("%s: GPHY addr=%d, reset timeout!!\n",
> +                                      __func__, phy_addr);
> +               } else {
> +                       ca_mdio_write(phy_addr,  0, 0x1140);
> +               }
> +
> +               mdelay(100);
> +       }
> +}
> +#endif
> +
> +#if  defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
> +static void ca_ni_internal_phy_init(void)
> +{
> +#if defined(CONFIG_TARGET_PRESIDIO_ASIC)
> +       u8 phy_addr;
> +
> +       /* should initialize 4 GPHYs at once */
> +       for (phy_addr = 4; phy_addr > 0; phy_addr--) {
> +               ca_mdio_write(phy_addr, 31, 0x0BC6);
> +               ca_mdio_write(phy_addr, 16, 0x0053);
> +               ca_mdio_write(phy_addr, 18, 0x4003);
> +               ca_mdio_write(phy_addr, 22, 0x7e01);
> +               ca_mdio_write(phy_addr, 31, 0x0A42);
> +               ca_mdio_write(phy_addr, 31, 0x0A40);
> +               ca_mdio_write(phy_addr,  0, 0x1140);
> +       }
> +
> +       /* workaround to fix GPHY fail */
> +       cortina_ni_fix_gphy();
> +
> +#else
> +       /* should initialize 4 GPHYs at once */
> +       __internal_phy_init(0);
> +#endif
> +}
> +#endif
> +
> +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
> +extern u8 port2led[8][2];
> +
> +static void ca77xx_ni_led(int port, int sw_on)
> +{
> +#ifdef CORTINA_LED_READY
> +       if (sw_on) {
> +               /* turn on led light */
> +               __led_set(1 << port2led[port][0], STATUS_LED_ON);
> +               __led_set(1 << port2led[port][1], STATUS_LED_ON);
> +       } else {
> +               /* turn off led light */
> +               __led_set(1 << port2led[port][0], STATUS_LED_OFF);
> +               __led_set(1 << port2led[port][1], STATUS_LED_OFF);
> +       }
> +#endif
> +}
> +
> +#define AUTO_SCAN_PHY_TIMEOUT  1000            /* 1s */
> +
> +static void ca77xx_ni_scan_active_port(void)
> +{
> +       u8      phy_addr;
> +       int     port;
> +       int     found_active_port = 0;
> +       unsigned short data;
> +
> +       for (phy_addr = 1; phy_addr < 5; phy_addr++) {
> +               port = phy_addr - 1;
> +               ca_mdio_read(phy_addr, 1, &data);
> +               if (data & 0x04) {
> +                       if (found_active_port == 0) {
> +                               /* apply new active_port when port changed */
> +                               if (phy_addr != ge_port_phy_addr) {
> +                                       ge_port_phy_addr = phy_addr;
> +                                       active_port = port;
> +                                       cortina_ni_reset();
> +                                       ca77xx_ni_led(port, 1);
> +                                       printf("active port has been changed ");
> +                                       printf("port %d\n", active_port);
> +                               } else {
> +                                       ca77xx_ni_led(port, 1);
> +                               }
> +                               found_active_port = 1;
> +                       } else {
> +                               ca77xx_ni_led(port, 1);
> +                       }
> +               } else {
> +                       ca77xx_ni_led(port, 0);
> +               }
> +       }
> +}
> +
> +void ca77xx_ni_scan_phy_link(void)
> +{
> +       static u32     start_time;
> +       unsigned short data;
> +
> +       /* if etherent not initialized do nothing */
> +       if (!curr_dev)
> +               return;
> +
> +       if (start_time == 0) {
> +               start_time = get_timer(0);
> +       } else {
> +               /* scan GPHY link status per second */
> +               if (get_timer(start_time) > AUTO_SCAN_PHY_TIMEOUT) {
> +                       if (auto_scan_active_port) {
> +                               /* search for the first link PHY act
> +                                * as active port
> +                                */
> +                               ca77xx_ni_scan_active_port();
> +                       } else {
> +                               ca_mdio_read(ge_port_phy_addr, 1, &data);
> +                               if (data & 0x04)
> +                                       ca77xx_ni_led(active_port, 1);
> +                               else
> +                                       ca77xx_ni_led(active_port, 0);
> +                       }
> +                       start_time = 0;
> +               }
> +       }
> +}
> +
> +/* auto scan the first link up port as active_port */
> +#define AUTO_SCAN_TIMEOUT      3000            /* 3 seconds */
> +static void ca77xx_ni_auto_scan_active_port(void)
> +{
> +       u8      phy_addr;
> +       u32     start_time;
> +       unsigned short data;
> +
> +       ca_ni_internal_phy_init();
> +
> +       start_time = get_timer(0);
> +       while (get_timer(start_time) < AUTO_SCAN_TIMEOUT) {
> +               for (phy_addr = 1; phy_addr < 5; phy_addr++) {
> +                       ca_mdio_read(phy_addr, 1, &data);
> +                       if (data & 0x04) {
> +                               active_port = phy_addr - 1;
> +                               printf("%s: active_port=%d\n",
> +                                      __func__, active_port);
> +
> +                               ca77xx_ni_led(active_port, 1);
> +                               return;
> +                       }
> +               }
> +       }
> +       printf("%s: auto scan active_port timeout, set active_port to 1.\n",
> +              __func__);
> +       active_port = NI_PORT_1;
> +
> +       ca77xx_ni_led(active_port, 0);
> +}
> +
> +#elif defined(CONFIG_TARGET_SATURN_ASIC)
> +
> +/* auto scan the first link up port as active_port */
> +#define AUTO_SCAN_TIMEOUT       3000            /* 3 seconds */
> +static void ca77xx_ni_auto_scan_active_port(void)
> +{
> +       u8      phy_addr;
> +       u32     start_time;
> +       unsigned short data;
> +
> +       /* do internal GHPY reset */
> +       active_port = 3;
> +       cortina_ni_reset();
> +
> +       /* should initialize internal GPHY, NI port 3 */
> +       phy_addr = 1;
> +       ca_mdio_write(phy_addr, 31, 0x0BC6);
> +       ca_mdio_write(phy_addr, 16, 0x0053);
> +       ca_mdio_write(phy_addr, 18, 0x4003);
> +       ca_mdio_write(phy_addr, 22, 0x7e01);
> +       ca_mdio_write(phy_addr, 31, 0x0A42);
> +       ca_mdio_write(phy_addr, 31, 0x0A40);
> +       ca_mdio_write(phy_addr,  0, 0x1140);
> +
> +       /* workaround to fix GPHY fail */
> +       /* Clear clock fail interrupt */
> +       ca_mdio_write(phy_addr, 31, 0xB90);
> +       ca_mdio_read(phy_addr, 19, &data);
> +       //printf("%s: phy_addr=%d, read register 19, value=0x%x\n",
> +       //__func__, phy_addr, data);
Please don't push commented out lines.
> +       if (data == 0x10) {
> +               ca_mdio_write(phy_addr, 31, 0xB90);
> +               ca_mdio_read(phy_addr, 19, &data);
> +               printf("%s: read again phy_addr=%d, ", __func__, phy_addr);
> +               printf("read register 19, value=0x%x\n", data);
> +       }
> +#ifdef CORTINA_NI_DBG
> +       printf("%s: phy_addr=%d, read register 19, value=0x%x\n",
> +              __func__, phy_addr, data);
> +#endif
> +
> +       start_time = get_timer(0);
> +       while (get_timer(start_time) < AUTO_SCAN_TIMEOUT) {
> +               phy_addr = 5;  /* NI port 4 */
> +               ca_mdio_read(phy_addr, 1, &data);
> +               if (data & 0x04) {
> +                       active_port = NI_PORT_4;
> +                       printf("%s: active_port=%d\n", __func__, active_port);
> +                       return;
> +               }
> +               phy_addr = 1;  /* NI port 3 */
> +               ca_mdio_read(phy_addr, 1, &data);
> +               if (data & 0x04) {
> +                       active_port = NI_PORT_3;
> +                       printf("%s: active_port=%d\n", __func__, active_port);
> +                       return;
> +               }
> +       }
> +       printf("%s: auto scan active_port timeout, set active_port to 3.\n",
> +              __func__);
> +       active_port = NI_PORT_3;
> +}
> +
> +#endif
> +
> +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
> +#define GPHY_CAL_LEN   6
> +struct gphy_cal {
> +       u32 reg_off;
> +       u32 value;
> +};
> +
> +static struct gphy_cal gphy_cal_vlaues[GPHY_CAL_LEN] = {
> +       {0xf43380fc, 0xbcd},
> +       {0xf43380dc, 0xeeee},
> +       {0xf43380d8, 0xeeee},
> +       {0xf43380fc, 0xbce},
> +       {0xf43380c0, 0x7777},
> +       {0xf43380c4, 0x7777}
> +};
> +
> +static void do_internal_gphy_cal(void)
> +{
> +       int i, port;
> +       u32 reg_off, value;
> +
> +       for (port = 0; port < 4; port++) {
> +               for (i = 0; i < GPHY_CAL_LEN; i++) {
> +                       reg_off = gphy_cal_vlaues[i].reg_off + (port * 0x80);
> +                       value = gphy_cal_vlaues[i].value;
> +                       CA_REG_WRITE(value, reg_off);
> +                       mdelay(50);
> +               }
> +       }
> +}
> +#endif
> +
> +int ca77xx_eth_initialize(struct udevice *dev)
> +{
> +       struct cortina_ni_priv  *priv;
> +       char            *buf;
> +#if !defined(CONFIG_TARGET_VENUS)
> +       u16             val;
> +#endif
> +       int             i;
> +       u16             vendor_id, chip_id;
> +       u32             phy_id;
> +
> +       env_set_hex("active_port", 1);
> +       env_set_hex("auto_scan_active_port", 1);
> +
> +       priv = dev_get_priv(dev);
> +       priv->rx_xram_base_adr  = NI_XRAM_BASE + (RX_BASE_ADDR * 8);
> +       priv->rx_xram_end_adr   = NI_XRAM_BASE + ((RX_TOP_ADDR + 1) * 8);
> +       priv->rx_xram_start     = RX_BASE_ADDR;
> +       priv->rx_xram_end       = RX_TOP_ADDR;
> +       priv->tx_xram_base_adr  = NI_XRAM_BASE + (TX_BASE_ADDR * 8);
> +       priv->tx_xram_end_adr   = NI_XRAM_BASE + ((TX_TOP_ADDR + 1) * 8);
> +       priv->tx_xram_start     = TX_BASE_ADDR;
> +       priv->tx_xram_end       = TX_TOP_ADDR;
> +
> +       curr_dev = dev;
> +#if CORTINA_NI_DBG
> +       printf("%s: rx_base_addr:%x\t rx_top_addr %x\n",
> +              __func__, priv->rx_xram_start, priv->rx_xram_end);
> +       printf("%s: tx_base_addr:%x\t tx_top_addr %x\n",
> +              __func__, priv->tx_xram_start, priv->tx_xram_end);
> +       printf("%s: rx physical start address = %x end address = %x\n",
> +              __func__, priv->rx_xram_base_adr, priv->rx_xram_end_adr);
> +       printf("%s: tx physical start address = %x end address = %x\n",
> +              __func__, priv->tx_xram_base_adr, priv->tx_xram_end_adr);
> +#endif
> +
> +       //ni_enable_tx_rx();
> +
> +       /* set MDIO pre-scale value */
> +       reg_value = CA_REG_READ(priv->per_mdio_base_addr + PER_MDIO_CFG_OFFSET);
> +       reg_value = reg_value | 0x00280000;
> +       CA_REG_WRITE(reg_value, priv->per_mdio_base_addr + PER_MDIO_CFG_OFFSET);
> +
> +       /* In Saturn active_port are 3 or 4,
> +        * because the register offset has been shifted forward
> +        * LAN ports (port 4-7) connect to RTL8214
> +        */
> +#if defined(CONFIG_TARGET_SATURN_ASIC)
> +       buf = env_get("auto_scan_active_port");
> +       if (buf != 0) {
> +               auto_scan_active_port = simple_strtoul(buf, NULL, 0);
> +               printf("%s: auto_scan_active_port=%d\n",
> +                      __func__, auto_scan_active_port);
> +       }
> +
> +       if (auto_scan_active_port) {
> +               ca77xx_ni_auto_scan_active_port();
> +       } else {
> +               buf = env_get("active_port");
> +               if (buf != 0) {
> +                       active_port = simple_strtoul(buf, NULL, 0);
> +                       printf("%s: active_port=%d\n", __func__, active_port);
> +                       if (active_port != NI_PORT_3 &&
> +                           active_port != NI_PORT_4) {
> +                               printf("ERROR: does not support active_port ");
> +                               printf("%d!!\n", active_port);
> +                               printf("Please change active_port to 3 or 4\n");
> +                               free(dev);
> +                               free(priv);
> +                               return 1;
> +                       }
> +               } else {
> +                       active_port = NI_PORT_4;
> +               }
> +       }
> +#else
> +       buf = env_get("auto_scan_active_port");
> +       if (buf != 0) {
> +               auto_scan_active_port = simple_strtoul(buf, NULL, 0);
> +               printf("%s: auto_scan_active_port=%d\n", __func__,
> +                      auto_scan_active_port);
> +       }
> +       if (auto_scan_active_port) {
> +               ca77xx_ni_auto_scan_active_port();
> +       } else {
> +               buf = env_get("active_port");
> +               if (buf != 0) {
> +                       active_port = simple_strtoul(buf, NULL, 0);
> +                       printf("%s: active_port=%d\n", __func__, active_port);
> +                       if (active_port < NI_PORT_0 ||
> +                           active_port > NI_PORT_4) {
> +                               printf("ERROR: does not support active_port ");
> +                               printf("%d\n", active_port);
> +                               printf("Please change active_port to 0-3.\n");
> +                               free(dev);
> +                               free(priv);
> +                               return 1;
> +                       }
> +               } else {
> +                       active_port = NI_PORT_1;
> +               }
> +       }
> +#endif
> +
> +       cortina_ni_reset();
> +
> +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
> +       /* port0: phy address 1 - GMAC0: port 0
> +        * port1: phy address 2 - GMAC1: port 1
> +        * port2: phy address 3 - GMAC2: port 2
> +        * port3: phy address 4 - GMAC3: port 3
> +        * port4: phy address 5 - RGMII: port 4
> +        */
> +       ge_port_phy_addr = active_port + 1;
> +#else
> +       /* port0: phy address 1 - GMAC0: port 0
> +        * port1: phy address 2 - GMAC1: port 1
> +        * port2: phy address 3 - GMAC2: port 2
> +        * port3: phy address 4 - GMAC3: port 3
> +        * port4: phy address 16 - QSGMII: port 0
> +        * port5: phy address 17 - QSGMII: port 1
> +        * port6: phy address 18 - QSGMII: port 2
> +        * port7: phy address 19 - QSGMII: port 3
> +        */
> +       if (active_port >= NI_PORT_0 && active_port <= NI_PORT_3)
> +               ge_port_phy_addr = active_port + 1;
> +       else
> +               ge_port_phy_addr = active_port - 2;
> +#endif
> +
> +#if defined(CONFIG_TARGET_SATURN_ASIC)
> +       /* internal GPHY addr=1 */
> +       if (active_port == NI_PORT_3)
> +               ge_port_phy_addr = 1;
> +       else
> +               ge_port_phy_addr = active_port + 1;
> +
> +       printf("%s: active_port=%d, ge_port_phy_addr=%d\n",
> +              __func__, active_port, ge_port_phy_addr);
> +#endif
> +
> +       ca_mdio_read(ge_port_phy_addr, 2, &vendor_id);
> +       ca_mdio_read(ge_port_phy_addr, 3, &chip_id);
> +       phy_id = ((u32)vendor_id << 16) | chip_id;
> +
> +       printf("%s: vendor_id=0x%x\n", __func__, vendor_id);
> +       printf("%s: chip_id=0x%x\n", __func__, chip_id);
> +       printf("%s: phy_id=0x%x\n", __func__, phy_id);
> +       printf("%s: phy_id & PHY_ID_MASK=0x%x\n",
> +              __func__, (phy_id & PHY_ID_MASK));
> +       printf("%s: PHY_ID_RTL8214=0x%x\n", __func__, PHY_ID_RTL8214);
> +
> +       if ((phy_id & PHY_ID_MASK) == PHY_ID_RTL8211) {
> +#if !defined(CONFIG_TARGET_VENUS)
> +               printf("%s: do initial patch for PHY_ID_RTL8211\n", __func__);
> +               /*
> +                * Disable response PHYAD=0 function of
> +                * RTL8211 series PHY
> +                */
> +
> +               /* REG31 write 0x0007, set to extension page */
> +               ca_mdio_write(ge_port_phy_addr, 31, 0x0007);
> +
> +               /* REG30 write 0x002C, set to extension page 44 */
> +               ca_mdio_write(ge_port_phy_addr, 30, 0x002C);
> +
> +               /*
> +                * REG27 write bit[2] =0
> +                * disable response PHYAD=0  function.
> +                * we should read REG27 and clear bit[2], and write back
> +                */
> +               ca_mdio_read(ge_port_phy_addr, 27, &val);
> +               val &= ~(1 << 2);
> +               ca_mdio_write(ge_port_phy_addr, 27, val);
> +
> +               /* REG31 write 0X0000, back to page0 */
> +               ca_mdio_write(ge_port_phy_addr, 31, 0x0000);
> +#endif
> +       }
> +
> +       /* the init sequency provided by RTK */
> +       if ((phy_id & PHY_ID_MASK) == PHY_ID_RTL8214) {
> +               printf("%s: write initial sequency for PHY_ID_RTL8214!!\n",
> +                      __func__);
> +               for (i = 0; i < RTL8214_INIT_REG_COUNT; i++) {
> +                       if (!(i & 1)) {
> +                               ca_mdio_write(ge_port_phy_addr, 29,
> +                                             rtl8214_init_reg_val[i]);
> +                       } else {
> +                               ca_mdio_write(ge_port_phy_addr, 30,
> +                                             rtl8214_init_reg_val[i]);
> +                       }
> +               }
> +       }
> +
> +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
> +       if ((phy_id & PHY_ID_MASK) == PHY_ID_RTL8211_G3_ASIC) {
> +               if (!auto_scan_active_port) {
> +                       printf("%s: write initial sequency for ", __func__);
> +                       printf("PHY_ID_RTL8211_G3_ASIC!!\n");
> +
> +                       ca_ni_internal_phy_init();
> +               }
> +#if defined(CONFIG_TARGET_VENUS)
> +               else
> +                       ca77xx_ni_auto_scan_active_port();
> +#endif
> +       }
> +
> +       ca77xx_ni_scan_phy_link();
> +#endif
> +
> +       /* parsing ethaddr and set to NI registers. */
> +       ni_setup_mac_addr();
> +
> +       /* the phy_read and phy_write
> +        * should meet the proto type of miiphy_register
> +        */
> +#ifdef MIIPHY_REGISTER
> +       miiphy_register(dev->name, ca_miiphy_read, ca_miiphy_write);
> +#endif
> +
> +#if CORTINA_NI_DBG
> +       dbg_dev = dev;
> +#endif
> +
> +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS)
> +       /* hardware settings for RGMII port */
> +       {
> +               union GLOBAL_GLOBAL_CONFIG_t    glb_config;
> +               union GLOBAL_IO_DRIVE_CONTROL_t io_drive_control;
> +
> +               /* Generating 25Mhz reference clock for switch */
> +               glb_config.wrd = CA_REG_READ((priv->glb_base_addr +
> +                                           GLOBAL_GLOBAL_CONFIG_OFFSET));
> +               glb_config.bf.refclk_sel = 0x01;
> +               glb_config.bf.ext_reset = 0x01;
> +               CA_REG_WRITE(glb_config.wrd, (priv->glb_base_addr +
> +                           GLOBAL_GLOBAL_CONFIG_OFFSET));
> +
> +               mdelay(20);
> +
> +               /* should do a external reset */
> +               glb_config.wrd = CA_REG_READ((priv->glb_base_addr +
> +                                           GLOBAL_GLOBAL_CONFIG_OFFSET));
> +               glb_config.bf.ext_reset = 0x0;
> +               CA_REG_WRITE(glb_config.wrd, (priv->glb_base_addr +
> +                           GLOBAL_GLOBAL_CONFIG_OFFSET));
> +
> +               io_drive_control.wrd =
> +                       CA_REG_READ((priv->glb_base_addr +
> +                                  GLOBAL_IO_DRIVE_CONTROL_OFFSET));
> +               io_drive_control.bf.gmac_mode = 2;
> +               io_drive_control.bf.gmac_dn = 1;
> +               io_drive_control.bf.gmac_dp = 1;
> +               CA_REG_WRITE(io_drive_control.wrd, (priv->glb_base_addr +
> +                           GLOBAL_IO_DRIVE_CONTROL_OFFSET));
> +       }
> +
> +       /* initialize LEDs for ethernet link and traffic lights */
> +       //ca77xx_init_led();
> +
> +#if defined(CONFIG_TARGET_PRESIDIO_ASIC)
> +       /* do internal gphy calibration */
> +       do_internal_gphy_cal();
> +#endif
> +       return 0;
> +#endif
> +}
> +
> +#if CORTINA_NI_DBG
> +DECLARE_GLOBAL_DATA_PTR;
> +int do_eth_init(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
> +{
> +       cortina_ni_init(0x00);
> +       return 0;
> +}
> +
> +U_BOOT_CMD(do_eth_init, 2, 1, do_eth_init,
> +          "do_eth_init\t- to test eth_init\n",
> +          "None\n");
> +#endif
> +
> +#if CORTINA_NI_DBG
> +int do_eth_send(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
....<snip>
> +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");
> +
This entire debug chunk. why do we need it upstream ?


More information about the U-Boot mailing list