[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