From patchwork Wed Jun 3 08:05:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Nemirovsky X-Patchwork-Id: 241601 List-Id: U-Boot discussion From: alex.nemirovsky at cortina-access.com (Alex Nemirovsky) Date: Wed, 3 Jun 2020 01:05:18 -0700 Subject: [PATCH v4 1/2] net: cortina_ni: Add eth support for Cortina Access CAxxxx SoCs Message-ID: <1591171519-10406-1-git-send-email-alex.nemirovsky@cortina-access.com> From: Aaron Tseng Add Cortina Access Ethernet device driver for CAxxxx SoCs. This driver supports only the DM_ETH network model. Signed-off-by: Aaron Tseng Signed-off-by: Alex Nemirovsky CC: Joe Hershberger CC: Abbie Chang CC: Tom Rini --- 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 @@ -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 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 + * + * Ethernet MAC Driver for all supported CAxxxx SoCs + */ + +#include +#include +#include +#include +#include +#include +#include + +#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) +{ + 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__); + 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); + 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[]) +{ + unsigned char pkt[1536]; + unsigned int i; + + for (i = 0; i < 1500; i++) + pkt[i] = i % 256; + + for (i = 60; i < 360; i++) + cortina_ni_send(dbg_dev, pkt, i); + + return 0; +} + +U_BOOT_CMD(do_eth_send, 3, 2, do_eth_send, + "do_eth_send\t- to test eth_send\n", + "None\n"); + +int do_eth_rx(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + cortina_ni_recv(dbg_dev); + return 0; +} + +U_BOOT_CMD(do_eth_rx, 2, 1, do_eth_rx, + "do_eth_rx\t- to test eth_rx\n", + "None\n"); + +int do_read_phy(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + unsigned int phy_adr; + unsigned int reg_off; + unsigned short reg_val; + + phy_adr = simple_strtoul(argv[1], NULL, 0); + reg_off = simple_strtoul(argv[2], NULL, 0); + ca_mdio_read(phy_adr, reg_off, ®_val); + printf("PHY_ADR = %d offset=%d reg_val=%x\n", + phy_adr, reg_off, reg_val); + return 0; +} + +U_BOOT_CMD(ca_phy_read, 3, 1, do_read_phy, + "do_read_phy\t- to read PHY register\n", + "None\n"); + +int do_write_phy(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + unsigned int phy_adr; + unsigned int reg_off; + unsigned int reg_val; + + phy_adr = simple_strtoul(argv[1], NULL, 0); + reg_off = simple_strtoul(argv[2], NULL, 0); + reg_val = simple_strtoul(argv[3], NULL, 0); + ca_mdio_write(phy_adr, reg_off, reg_val); + printf("PHY_ADR = %d offset=%d reg_val=%x\n", + phy_adr, reg_off, reg_val); + return 0; +} + +U_BOOT_CMD(ca_phy_write, 4, 1, do_write_phy, + "do_write_phy\t- to write PHY register\n", + "None\n"); + +#endif + +static int do_phy_reg(struct cmd_tbl *cmdtp, + int flag, + int argc, + char * const argv[]) +{ + int ret, i; + u16 phy_addr, reg, val; + + if (argc < 2) { + printf("Usage:\nphy_reg_value%s\n", cmdtp->help); + return -1; + } + + phy_addr = simple_strtoul(argv[1], NULL, 10); + + if (phy_addr > 31) { + printf("Usage:\nphy_reg_value%s\n", cmdtp->help); + return -1; + } + if (argc == 2) { + /* read the first 15 registers of the PHY */ + printf("PHY addr %d:\n", phy_addr); + for (i = 0; i < 15; i++) { + ca_mdio_read(phy_addr, i, &val); + printf("Reg 0x%04X = 0x%04X\n", i, val); + } + return 0; + } + + reg = simple_strtoul(argv[2], NULL, 10); + + if (argc == 3) { + /* read cmd */ + ca_mdio_read(phy_addr, reg, &val); + printf("PHY addr %d Reg 0x%04X = 0x%04X\n", phy_addr, reg, val); + } else { + /* argc > 3*/ + /* write cmd */ + val = simple_strtoul(argv[3], NULL, 10); + ret = ca_mdio_write(phy_addr, reg, val); + if (!ret) { + printf("PHY addr %d Reg 0x%04X = 0x%04X\n", + phy_addr, reg, val); + } else { + printf("Can't write PHY addr %d Reg 0x%04X as 0x%04X, ", + phy_addr, reg, val); + printf("ret = %d\n", ret); + } + } + return 0; +} + +U_BOOT_CMD(phy_reg, 4, 1, do_phy_reg, + "read/write PHY register", + "[PHY addr] [reg_valueaddr] ([value])\n" + "PHY addr : 0-31\n"); + +#ifdef CONFIG_MK_CUSTOMB +/* code custom switch register access function here */ +#endif + +static int cortina_eth_start(struct udevice *dev) +{ + return cortina_ni_init(dev); +} + +int cortina_eth_send(struct udevice *dev, void *packet, int length) +{ + return cortina_ni_send(dev, packet, length); +} + +int cortina_eth_recv(struct udevice *dev, int flags, uchar **packetp) +{ + return cortina_ni_recv(dev); +} + +void cortina_eth_stop(struct udevice *dev) +{ + cortina_ni_halt(dev); +} + +static int cortina_eth_probe(struct udevice *dev) +{ + return ca77xx_eth_initialize(dev); +} + +static int ca_ni_ofdata_to_platdata(struct udevice *dev) +{ + struct cortina_ni_priv *priv = dev_get_priv(dev); + + priv->glb_base_addr = dev_remap_addr_index(dev, 0); + if (!priv->glb_base_addr) + return -ENOENT; + printf("%s: priv->glb_base_addr for index 0 is 0x%p\n", + __func__, priv->glb_base_addr); + + priv->per_mdio_base_addr = dev_remap_addr_index(dev, 1); + if (!priv->per_mdio_base_addr) + return -ENOENT; + printf("%s: priv->per_mdio_base_addr for index 1 is 0x%p\n", + __func__, priv->per_mdio_base_addr); + + priv->ni_hv_base_addr = dev_remap_addr_index(dev, 2); + if (!priv->ni_hv_base_addr) + return -ENOENT; + printf("%s: priv->ni_hv_base_addr for index 2 is 0x%p\n", + __func__, priv->ni_hv_base_addr); + + return 0; +} + +static const struct eth_ops cortina_eth_ops = { + .start = cortina_eth_start, + .send = cortina_eth_send, + .recv = cortina_eth_recv, + .stop = cortina_eth_stop, +}; + +static const struct udevice_id cortina_eth_ids[] = { + { .compatible = "eth_cortina" }, + { } +}; + +U_BOOT_DRIVER(eth_cortina) = { + .name = "eth_cortina", + .id = UCLASS_ETH, + .of_match = cortina_eth_ids, + .probe = cortina_eth_probe, + .ops = &cortina_eth_ops, + .priv_auto_alloc_size = sizeof(struct cortina_ni_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), + .ofdata_to_platdata = ca_ni_ofdata_to_platdata, +}; diff --git a/drivers/net/cortina_ni.h b/drivers/net/cortina_ni.h new file mode 100644 index 0000000..0fea6a1 --- /dev/null +++ b/drivers/net/cortina_ni.h @@ -0,0 +1,592 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +/* + * Copyright (C) 2020 Cortina Access Inc. + * Author: Aaron Tseng + * + * Ethernet MAC Driver for all supported CAxxxx SoCs + */ + +#ifndef __CORTINA_NI_H +#define __CORTINA_NI_H + +#include +#include +#include + +//#define CORTINA_NI_DBG 1 + +#ifdef CS_BIG_ENDIAN +#define CRCPOLY_BE 0x04c11db7 +#else /* CS_LITTLE_ENDIAN */ +#define CRCPOLY_LE 0xedb88320 +#endif + +#define GE_PORT0_PHY_ADDR CONFIG_NI_PHY_ADDR_GMAC0 +#define GE_PORT1_PHY_ADDR CONFIG_NI_PHY_ADDR_GMAC1 +#define GE_PORT2_PHY_ADDR CONFIG_NI_PHY_ADDR_GMAC2 + +#define PHY_ID_RTL8201 0x001cc810 +#define PHY_ID_RTL8211 0x001cc910 +#define PHY_ID_RTL8214 0x001cc940 +#define PHY_ID_RTL8211_G3_ASIC 0x001cc980 +#define PHY_ID_RTL8211_SATURN_ASIC 0x001cc900 +#define PHY_ID_QCA8337 0x004dd035 +#define PHY_ID_MASK 0xFFFFFFF0 + +#define GE_MAC_INTF_GMII 0x0 +#define GE_MAC_INTF_MII 0x1 +#define GE_MAC_INTF_RGMII_1000 0x2 +#define GE_MAC_INTF_RGMII_100 0x3 +#define GE_MAC_INTF_QSGMII_1000 0x4 +#define GE_MAC_INTF_RMII 0x5 + +#define NI_TOP_NI_RTH_MAC_10M 1 +#define NI_TOP_NI_RTH_MAC_100M 0 +#define NI_TOP_NI_RTH_MAC_HALF 1 +#define NI_TOP_NI_RTH_MAC_FULL 0 + +/* Defines the base and top address in CPU XRA + * for packets to cpu instance 0 + * 0x300 * 8-byte = 6K-byte + */ +#define RX_TOP_ADDR 0x02FF +#define RX_BASE_ADDR 0x0000 + +/* Defines the base and top address in CPU XRAM + * for packets from cpu instance 0. + * 0x100 * 8-byte = 2K-byte + */ +#define TX_TOP_ADDR 0x03FF +#define TX_BASE_ADDR 0x0300 + +#define RX_0_CPU_PKT_DIS BIT(0) +#define TX_0_CPU_PKT_DIS BIT(9) + +#define PHY_POLL_TIMES 0x200 + +#define NI_XRAM_BASE 0xF4500000 + +enum ca_status_t { + CA_E_ERROR = -1, + CA_E_OK = 0x0, + CA_E_RESOURCE = 0x1, + CA_E_PARAM = 0x2, + CA_E_NOT_FOUND = 0x3, + CA_E_CONFLICT = 0x4, + CA_E_TIMEOUT = 0x5, + CA_E_INTERNAL = 0x6, + CA_E_NOT_SUPPORT = 0x7, + CA_E_CONFIG = 0x8, + CA_E_UNAVAIL = 0x9, + CA_E_MEMORY = 0xa, + CA_E_BUSY = 0xb, + CA_E_FULL = 0xc, + CA_E_EMPTY = 0xd, + CA_E_EXISTS = 0xe, + CA_E_DEV = 0xf, + CA_E_PORT = 0x10, + CA_E_LLID = 0x11, + CA_E_VLAN = 0x12, + CA_E_INIT = 0x13, + CA_E_INTF = 0x14, + CA_E_NEXTHOP = 0x15, + CA_E_ROUTE = 0x16, + CA_E_DB_CHANGED = 0x17, + CA_E_INACTIVE = 0x18, + CA_E_ALREADY_SET = 0x19, +}; + +#ifndef CA_IN +#define CA_IN +#endif + +#ifndef CA_OUT +#define CA_OUT +#endif + +#if !defined(__ASSEMBLER__) && !defined(__ASSEMBLY__) +struct cortina_ni_priv { + unsigned int rx_xram_base_adr; + unsigned int rx_xram_end_adr; + unsigned short rx_xram_start; + unsigned short rx_xram_end; + unsigned int tx_xram_base_adr; + unsigned int tx_xram_end_adr; + unsigned short tx_xram_start; + unsigned short tx_xram_end; +#ifdef CONFIG_DM_ETH + void __iomem *glb_base_addr; + void __iomem *per_mdio_base_addr; + void __iomem *ni_hv_base_addr; +#else + unsigned int glb_base_addr; + unsigned int per_mdio_base_addr; + unsigned int ni_hv_base_addr; +#endif +}; + +union NI_HEADER_X_T { + struct { + unsigned int next_link : 10; /* bits 9: 0 */ + unsigned int bytes_valid : 4; /* bits 13:10 */ + unsigned int reserved : 16; /* bits 29:14 */ + unsigned int hdr_a : 1; /* bits 30:30 */ + unsigned int ownership : 1; /* bits 31:31 */ + } bf; + unsigned int wrd; +}; + +union NI_PACKET_STATUS { + struct { + unsigned int packet_size : 14; /* bits 13:0 */ + unsigned int byte_valid : 4; /* bits 17:14 */ + unsigned int pfc : 1; /* bits 18:18 */ + unsigned int valid : 1; /* bits 19:19 */ + unsigned int drop : 1; /* bits 20:20 */ + unsigned int runt : 1; /* bits 21:21 */ + unsigned int oversize : 1; /* bits 22:22 */ + unsigned int jumbo : 1; /* bits 23:23 */ + unsigned int link_status : 1; /* bits 24:24 */ + unsigned int jabber : 1; /* bits 25:25 */ + unsigned int crc_error : 1; /* bits 26:26 */ + unsigned int pause : 1; /* bits 27:27 */ + unsigned int oam : 1; /* bits 28:28 */ + unsigned int unknown_opcode : 1; /* bits 29:29 */ + unsigned int multicast : 1; /* bits 30:30 */ + unsigned int broadcast : 1; /* bits 31:31 */ + } bf; + unsigned int wrd; +}; + +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || \ + defined(CONFIG_TARGET_SATURN_ASIC) || defined(CONFIG_TARGET_VENUS) + +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) +#define CA_NI_MDIO_REG_BASE 0xF4338 +#else + +#if defined(CONFIG_TARGET_VENUS) +#define CA_NI_MDIO_REG_BASE 0xF4339 +#else +#define CA_NI_MDIO_REG_BASE 0xD000B +#endif + +#endif + +union NI_MDIO_OPER_T { + struct { + unsigned int reserved : 2; /* bits 1:0 */ + unsigned int reg_off : 5; /* bits 6:2 */ + unsigned int phy_addr : 5; /* bits 11:7 */ + unsigned int reg_base : 20; /* bits 31:12 */ + } bf; + unsigned int wrd; +}; + +#endif + +#define NI_PORT_0 0 +#define NI_PORT_1 1 +#define NI_PORT_2 2 +#define NI_PORT_3 3 +#define NI_PORT_4 4 +#define NI_PORT_5 5 +#define NI_PORT_6 6 +#define NI_PORT_7 7 + +#if defined(CONFIG_TARGET_SATURN_ASIC) +#define NI_READ_POLL_COUNT 1000000 +#else +#define NI_READ_POLL_COUNT 1000 +#endif + +#define __MDIO_WR_FLAG (0) +#define __MDIO_RD_FLAG (1) +#define __MDIO_ACCESS_TIMEOUT (1000000) +#define __MDIO_PER_CLK (62500) +#define CA_MDIO_ADDR_MIN (1) +#define CA_MDIO_ADDR_MAX (31) +#define CA_MDIO_CLOCK_MIN (1) +#define CA_MDIO_CLOCK_MAX (20000) + +#endif /* !__ASSEMBLER__ */ + +/* Copy from registers.h */ +union NI_HV_GLB_MAC_ADDR_CFG0_t { + struct { + unsigned int mac_addr0 : 32; /* bits 31:0 */ + } bf; + unsigned int wrd; +}; + +union NI_HV_GLB_MAC_ADDR_CFG1_t { + struct { + unsigned int mac_addr1 : 8; /* bits 7:0 */ + unsigned int rsrvd1 : 24; + } bf; + unsigned int wrd; +}; + +union NI_HV_PT_PORT_STATIC_CFG_t { + struct { + unsigned int int_cfg : 4; /* bits 3:0 */ + unsigned int phy_mode : 1; /* bits 4:4 */ + unsigned int rmii_clksrc : 1; /* bits 5:5 */ + unsigned int inv_clk_in : 1; /* bits 6:6 */ + unsigned int inv_clk_out : 1; /* bits 7:7 */ + unsigned int inv_rxclk_out : 1; /* bits 8:8 */ + unsigned int tx_use_gefifo : 1; /* bits 9:9 */ + unsigned int smii_tx_stat : 1; /* bits 10:10 */ + unsigned int crs_polarity : 1; /* bits 11:11 */ + unsigned int lpbk_mode : 2; /* bits 13:12 */ + unsigned int gmii_like_half_duplex_en : 1; /* bits 14:14 */ + unsigned int sup_tx_to_rx_lpbk_data : 1; /* bits 15:15 */ + unsigned int rsrvd1 : 8; + unsigned int mac_addr6 : 8; /* bits 31:24 */ + } bf; + unsigned int wrd; +}; + +union NI_HV_XRAM_CPUXRAM_CFG_t { + struct { + unsigned int rx_0_cpu_pkt_dis : 1; /* bits 0:0 */ + unsigned int rsrvd1 : 8; + unsigned int tx_0_cpu_pkt_dis : 1; /* bits 9:9 */ + unsigned int rsrvd2 : 1; + unsigned int rx_x_drop_err_pkt : 1; /* bits 11:11 */ + unsigned int xram_mgmt_dis_drop_ovsz_pkt : 1; /* bits 12:12 */ + unsigned int xram_mgmt_term_large_pkt : 1; /* bits 13:13 */ + unsigned int xram_mgmt_promisc_mode : 2; /* bits 15:14 */ + unsigned int xram_cntr_debug_mode : 1; /* bits 16:16 */ + unsigned int xram_cntr_op_code : 2; /* bits 18:17 */ + unsigned int rsrvd3 : 2; + unsigned int xram_rx_mgmtfifo_srst : 1; /* bits 21:21 */ + unsigned int xram_dma_fifo_srst : 1; /* bits 22:22 */ + unsigned int rsrvd4 : 9; + } bf; + unsigned int wrd; +}; + +union NI_HV_PT_RXMAC_CFG_t { + struct { + unsigned int rx_en : 1; /* bits 0:0 */ + unsigned int rsrvd1 : 7; + unsigned int rx_flow_disable : 1; /* bits 8:8 */ + unsigned int rsrvd2 : 3; + unsigned int rx_flow_to_tx_en : 1; /* bits 12:12 */ + unsigned int rx_pfc_disable : 1; /* bits 13:13 */ + unsigned int rsrvd3 : 15; + unsigned int send_pg_data : 1; /* bits 29:29 */ + unsigned int rsrvd4 : 2; + } bf; + unsigned int wrd; +}; + +union NI_HV_PT_TXMAC_CFG_t { + struct { + unsigned int tx_en : 1; /* bits 0:0 */ + unsigned int rsrvd1 : 7; + unsigned int mac_crc_calc_en : 1; /* bits 8:8 */ + unsigned int tx_ipg_sel : 3; /* bits 11:9 */ + unsigned int tx_flow_disable : 1; /* bits 12:12 */ + unsigned int tx_drain : 1; /* bits 13:13 */ + unsigned int tx_pfc_disable : 1; /* bits 14:14 */ + unsigned int tx_pau_sel : 2; /* bits 16:15 */ + unsigned int rsrvd2 : 9; + unsigned int tx_auto_xon : 1; /* bits 26:26 */ + unsigned int rsrvd3 : 1; + unsigned int pass_thru_hdr : 1; /* bits 28:28 */ + unsigned int rsrvd4 : 3; + } bf; + unsigned int wrd; +}; + +union NI_HV_GLB_INTF_RST_CONFIG_t { + struct { + unsigned int intf_rst_p0 : 1; /* bits 0:0 */ + unsigned int intf_rst_p1 : 1; /* bits 1:1 */ + unsigned int intf_rst_p2 : 1; /* bits 2:2 */ + unsigned int intf_rst_p3 : 1; /* bits 3:3 */ + unsigned int intf_rst_p4 : 1; /* bits 4:4 */ + unsigned int mac_rx_rst_p0 : 1; /* bits 5:5 */ + unsigned int mac_rx_rst_p1 : 1; /* bits 6:6 */ + unsigned int mac_rx_rst_p2 : 1; /* bits 7:7 */ + unsigned int mac_rx_rst_p3 : 1; /* bits 8:8 */ + unsigned int mac_rx_rst_p4 : 1; /* bits 9:9 */ + unsigned int mac_tx_rst_p0 : 1; /* bits 10:10 */ + unsigned int mac_tx_rst_p1 : 1; /* bits 11:11 */ + unsigned int mac_tx_rst_p2 : 1; /* bits 12:12 */ + unsigned int mac_tx_rst_p3 : 1; /* bits 13:13 */ + unsigned int mac_tx_rst_p4 : 1; /* bits 14:14 */ + unsigned int port_rst_p5 : 1; /* bits 15:15 */ + unsigned int pcs_rst_p6 : 1; /* bits 16:16 */ + unsigned int pcs_rst_p7 : 1; /* bits 17:17 */ + unsigned int mac_rst_p6 : 1; /* bits 18:18 */ + unsigned int mac_rst_p7 : 1; /* bits 19:19 */ + unsigned int rsrvd1 : 12; + } bf; + unsigned int wrd; +}; + +union NI_HV_GLB_STATIC_CFG_t { + struct { + unsigned int port_to_cpu : 4; /* bits 3:0 */ + unsigned int mgmt_pt_to_fe_also : 1; /* bits 4:4 */ + unsigned int txcrc_chk_en : 1; /* bits 5:5 */ + unsigned int p4_rgmii_tx_clk_phase : 2; /* bits 7:6 */ + unsigned int p4_rgmii_tx_data_order : 1; /* bits 8:8 */ + unsigned int rsrvd1 : 7; + unsigned int rxmib_mode : 1; /* bits 16:16 */ + unsigned int txmib_mode : 1; /* bits 17:17 */ + unsigned int eth_sch_rdy_pkt : 1; /* bits 18:18 */ + unsigned int rsrvd2 : 1; + unsigned int rxaui_mode : 2; /* bits 21:20 */ + unsigned int rxaui_sigdet : 2; /* bits 23:22 */ + unsigned int cnt_op_mode : 3; /* bits 26:24 */ + unsigned int rsrvd3 : 5; + } bf; + unsigned int wrd; +}; + +union GLOBAL_BLOCK_RESET_t { + struct { + unsigned int reset_ni : 1; /* bits 0:0 */ + unsigned int reset_l2fe : 1; /* bits 1:1 */ + unsigned int reset_l2tm : 1; /* bits 2:2 */ + unsigned int reset_l3fe : 1; /* bits 3:3 */ + unsigned int reset_sdram : 1; /* bits 4:4 */ + unsigned int reset_tqm : 1; /* bits 5:5 */ + unsigned int reset_pcie0 : 1; /* bits 6:6 */ + unsigned int reset_pcie1 : 1; /* bits 7:7 */ + unsigned int reset_pcie2 : 1; /* bits 8:8 */ + unsigned int reset_sata : 1; /* bits 9:9 */ + unsigned int reset_gic400 : 1; /* bits 10:10 */ + unsigned int rsrvd1 : 2; + unsigned int reset_usb : 1; /* bits 13:13 */ + unsigned int reset_flash : 1; /* bits 14:14 */ + unsigned int reset_per : 1; /* bits 15:15 */ + unsigned int reset_dma : 1; /* bits 16:16 */ + unsigned int reset_rtc : 1; /* bits 17:17 */ + unsigned int reset_pe0 : 1; /* bits 18:18 */ + unsigned int reset_pe1 : 1; /* bits 19:19 */ + unsigned int reset_rcpu0 : 1; /* bits 20:20 */ + unsigned int reset_rcpu1 : 1; /* bits 21:21 */ + unsigned int reset_sadb : 1; /* bits 22:22 */ + unsigned int rsrvd2 : 1; + unsigned int reset_rcrypto : 1; /* bits 24:24 */ + unsigned int reset_ldma : 1; /* bits 25:25 */ + unsigned int reset_fbm : 1; /* bits 26:26 */ + unsigned int reset_eaxi : 1; /* bits 27:27 */ + unsigned int reset_sd : 1; /* bits 28:28 */ + unsigned int reset_otprom : 1; /* bits 29:29 */ + unsigned int rsrvd3 : 2; + } bf; + unsigned int wrd; +}; + +union PER_MDIO_ADDR_t { + struct { + unsigned int mdio_addr : 5; /* bits 4:0 */ + unsigned int rsrvd1 : 3; + unsigned int mdio_offset : 5; /* bits 12:8 */ + unsigned int rsrvd2 : 2; + unsigned int mdio_rd_wr : 1; /* bits 15:15 */ + unsigned int mdio_st : 1; /* bits 16:16 */ + unsigned int rsrvd3 : 1; + unsigned int mdio_op : 2; /* bits 19:18 */ + unsigned int rsrvd4 : 12; + } bf; + unsigned int wrd; +}; + +union PER_MDIO_CTRL_t { + struct { + unsigned int mdiodone : 1; /* bits 0:0 */ + unsigned int rsrvd1 : 6; + unsigned int mdiostart : 1; /* bits 7:7 */ + unsigned int rsrvd2 : 24; + } bf; + unsigned int wrd; +}; + +union PER_MDIO_RDDATA_t { + struct { + unsigned int mdio_rddata : 16; /* bits 15:0 */ + unsigned int rsrvd1 : 16; + } bf; + unsigned int wrd; +}; + +/* + * XRAM + */ + +union NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t { + struct { + unsigned int rx_base_addr : 10; /* bits 9:0 */ + unsigned int rsrvd1 : 6; + unsigned int rx_top_addr : 10; /* bits 25:16 */ + unsigned int rsrvd2 : 6; + } bf; + unsigned int wrd; +}; + +union NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t { + struct { + unsigned int tx_base_addr : 10; /* bits 9:0 */ + unsigned int rsrvd1 : 6; + unsigned int tx_top_addr : 10; /* bits 25:16 */ + unsigned int rsrvd2 : 6; + } bf; + unsigned int wrd; +}; + +union NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t { + struct { + unsigned int pkt_wr_ptr : 10; /* bits 9:0 */ + unsigned int rsrvd1 : 5; + unsigned int int_colsc_thresh_reached : 1; /* bits 15:15 */ + unsigned int rsrvd2 : 16; + } bf; + unsigned int wrd; +}; + +union NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t { + struct { + unsigned int pkt_rd_ptr : 10; /* bits 9:0 */ + unsigned int rsrvd1 : 22; + } bf; + unsigned int wrd; +}; + +union NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t { + struct { + unsigned int pkt_wr_ptr : 10; /* bits 9:0 */ + unsigned int rsrvd1 : 22; + } bf; + unsigned int wrd; +}; + +union GLOBAL_GLOBAL_CONFIG_t { + struct { + unsigned int rsrvd1 : 4; + unsigned int wd_reset_subsys_enable : 1; /* bits 4:4 */ + unsigned int rsrvd2 : 1; + unsigned int wd_reset_all_blocks : 1; /* bits 6:6 */ + unsigned int wd_reset_remap : 1; /* bits 7:7 */ + unsigned int wd_reset_ext_reset : 1; /* bits 8:8 */ + unsigned int ext_reset : 1; /* bits 9:9 */ + unsigned int cfg_pcie_0_clken : 1; /* bits 10:10 */ + unsigned int cfg_sata_clken : 1; /* bits 11:11 */ + unsigned int cfg_pcie_1_clken : 1; /* bits 12:12 */ + unsigned int rsrvd3 : 1; + unsigned int cfg_pcie_2_clken : 1; /* bits 14:14 */ + unsigned int rsrvd4 : 2; + unsigned int ext_eth_refclk : 1; /* bits 17:17 */ + unsigned int refclk_sel : 2; /* bits 19:18 */ + unsigned int rsrvd5 : 7; + unsigned int l3fe_pd : 1; /* bits 27:27 */ + unsigned int offload0_pd : 1; /* bits 28:28 */ + unsigned int offload1_pd : 1; /* bits 29:29 */ + unsigned int crypto_pd : 1; /* bits 30:30 */ + unsigned int core_pd : 1; /* bits 31:31 */ + } bf; + unsigned int wrd; +}; + +union GLOBAL_IO_DRIVE_CONTROL_t { + struct { + unsigned int gmac_dp : 3; /* bits 2:0 */ + unsigned int gmac_dn : 3; /* bits 5:3 */ + unsigned int gmac_mode : 2; /* bits 7:6 */ + unsigned int gmac_ds : 1; /* bits 8:8 */ + unsigned int flash_ds : 1; /* bits 9:9 */ + unsigned int nu_ds : 1; /* bits 10:10 */ + unsigned int ssp_ds : 1; /* bits 11:11 */ + unsigned int spi_ds : 1; /* bits 12:12 */ + unsigned int gpio_ds : 1; /* bits 13:13 */ + unsigned int misc_ds : 1; /* bits 14:14 */ + unsigned int eaxi_ds : 1; /* bits 15:15 */ + unsigned int sd_ds : 8; /* bits 23:16 */ + unsigned int rsrvd1 : 8; + } bf; + unsigned int wrd; +}; + +union NI_HV_GLB_INIT_DONE_t { + struct { + unsigned int rsrvd1 : 1; + unsigned int ni_init_done : 1; /* bits 1:1 */ + unsigned int rsrvd2 : 30; + } bf; + unsigned int wrd; +}; + +union NI_HV_PT_PORT_GLB_CFG_t { + struct { + unsigned int speed : 1; /* bits 0:0 */ + unsigned int duplex : 1; /* bits 1:1 */ + unsigned int link_status : 1; /* bits 2:2 */ + unsigned int link_stat_mask : 1; /* bits 3:3 */ + unsigned int rsrvd1 : 7; + unsigned int power_dwn_rx : 1; /* bits 11:11 */ + unsigned int power_dwn_tx : 1; /* bits 12:12 */ + unsigned int tx_intf_lp_time : 1; /* bits 13:13 */ + unsigned int rsrvd2 : 18; + } bf; + unsigned int wrd; +}; + +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) +#define NI_HV_GLB_MAC_ADDR_CFG0_OFFSET 0x010 +#define NI_HV_GLB_MAC_ADDR_CFG1_OFFSET 0x014 +#define NI_HV_PT_BASE 0x400 +#define NI_HV_XRAM_BASE 0x820 +#define GLOBAL_BLOCK_RESET_OFFSET 0x04 +#define GLOBAL_GLOBAL_CONFIG_OFFSET 0x20 +#define GLOBAL_IO_DRIVE_CONTROL_OFFSET 0x4c +#elif defined(CONFIG_TARGET_SATURN_ASIC) +#define NI_HV_GLB_MAC_ADDR_CFG0_OFFSET 0x010 +#define NI_HV_GLB_MAC_ADDR_CFG1_OFFSET 0x014 +#define NI_HV_PT_BASE 0x580 +#define NI_HV_XRAM_BASE 0xA80 +#define GLOBAL_BLOCK_RESET_OFFSET 0x28 +#define GLOBAL_GLOBAL_CONFIG_OFFSET 0x48 +#define GLOBAL_IO_DRIVE_CONTROL_OFFSET 0x54 +#elif defined(CONFIG_TARGET_VENUS) +#define NI_HV_GLB_MAC_ADDR_CFG0_OFFSET 0x014 +#define NI_HV_GLB_MAC_ADDR_CFG1_OFFSET 0x018 +#define NI_HV_PT_BASE 0x600 +#define NI_HV_XRAM_BASE 0xA20 +#define GLOBAL_BLOCK_RESET_OFFSET 0x28 +#define GLOBAL_GLOBAL_CONFIG_OFFSET 0x48 +#define GLOBAL_IO_DRIVE_CONTROL_OFFSET 0x7c +#endif + +#define NI_HV_GLB_INIT_DONE_OFFSET 0x004 +#define NI_HV_GLB_INTF_RST_CONFIG_OFFSET 0x008 +#define NI_HV_GLB_STATIC_CFG_OFFSET 0x00c + +#define NI_HV_PT_PORT_STATIC_CFG_OFFSET NI_HV_PT_BASE +#define NI_HV_PT_PORT_GLB_CFG_OFFSET (0x4 + NI_HV_PT_BASE) +#define NI_HV_PT_RXMAC_CFG_OFFSET (0x8 + NI_HV_PT_BASE) +#define NI_HV_PT_TXMAC_CFG_OFFSET (0x14 + NI_HV_PT_BASE) + +#define NI_HV_XRAM_CPUXRAM_ADRCFG_RX_OFFSET NI_HV_XRAM_BASE +#define NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_OFFSET (0x4 + NI_HV_XRAM_BASE) +#define NI_HV_XRAM_CPUXRAM_CFG_OFFSET (0x8 + NI_HV_XRAM_BASE) +#define NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET (0xc + NI_HV_XRAM_BASE) +#define NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET (0x10 + NI_HV_XRAM_BASE) +#define NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET (0x24 + NI_HV_XRAM_BASE) +#define NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET (0x28 + NI_HV_XRAM_BASE) + +#define PER_MDIO_CFG_OFFSET 0x00 +#define PER_MDIO_ADDR_OFFSET 0x04 +#define PER_MDIO_WRDATA_OFFSET 0x08 +#define PER_MDIO_RDDATA_OFFSET 0x0C +#define PER_MDIO_CTRL_OFFSET 0x10 + +#define APB0_NI_HV_PT_STRIDE 160 + +#endif /* __CORTINA_NI_H */