From patchwork Wed Apr 29 23:58:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Nemirovsky X-Patchwork-Id: 238916 List-Id: U-Boot discussion From: alex.nemirovsky at cortina-access.com (Alex Nemirovsky) Date: Wed, 29 Apr 2020 16:58:25 -0700 Subject: [PATCH 1/2] net: cortina_ni: Addd eth support for Cortina Access CAxxxx SoCs Message-ID: <1588204706-20237-1-git-send-email-alex.nemirovsky@cortina-access.com> From: Aaron Tseng Add Cortina Access Ethernet device driver for CAxxxx SoCs. This driver supports both legacy and DM_ETH network models. Signed-off-by: Aaron Tseng Signed-off-by: Alex Nemirovsky Signed-off-by: Abbie Chang Cc: Joe Hershberger --- MAINTAINERS | 6 + drivers/net/Kconfig | 7 + drivers/net/Makefile | 1 + drivers/net/cortina_ni.c | 2096 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/cortina_ni.h | 626 ++++++++++++++ 5 files changed, 2736 insertions(+) create mode 100644 drivers/net/cortina_ni.c create mode 100644 drivers/net/cortina_ni.h diff --git a/MAINTAINERS b/MAINTAINERS index dd92af5..8a7b094 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 @@ -722,6 +724,10 @@ 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/i2c/i2c-cortina.c +F: drivers/i2c/i2c-cortina.h +F: drivers/led/led_cortina.c +F: drivers/spi/ca_sflash.c MIPS MSCC M: Gregory CLEMENT diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 4d1013c..edeb132 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -143,6 +143,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 6e0a688..85e60f3 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..de9f2e1 --- /dev/null +++ b/drivers/net/cortina_ni.c @@ -0,0 +1,2096 @@ +// 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 "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 + +struct eth_device *dbg_dev; + +#endif /* CORTINA_NI_DBG */ + +#ifdef CONFIG_DM_ETH +static struct udevice *curr_dev; +#else +static struct eth_device *curr_dev; +#endif +#define RDWRPTR_ADVANCE_ONE(x, base, max) \ + ((((x) + 1) >= (u32 *)(ca_uint)(max)) ? (u32 *)(ca_uint)base : (x) + 1) + +#if defined(CONFIG_TARGET_SATURN_ASIC) +#define CA_REG_READ(off) readl((u64)KSEG1_ATU_XLAT(off)) +#define CA_REG_WRITE(data, off) writel(data, (u64)KSEG1_ATU_XLAT(off)) +#else +#define CA_REG_READ(off) readl((u64)off) +#define CA_REG_WRITE(data, off) writel(data, (u64)off) +#endif + +#ifdef CONFIG_DM_ETH +int cortina_ni_recv(struct udevice *netdev); +static int ca_ni_ofdata_to_platdata(struct udevice *dev); +#else +int cortina_ni_recv(struct eth_device *netdev); +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) +#define GLB_BASE_ADDR 0xf4320000 +#define PER_MDIO_BASE_ADDR 0xf43290d8 +#define NI_HV_BASE_ADDR 0xf4304000 +#elif defined(CONFIG_TARGET_SATURN_ASIC) +#define GLB_BASE_ADDR 0x44100000 +#define PER_MDIO_BASE_ADDR 0x522240d8 +#define NI_HV_BASE_ADDR 0xd0004000 +#elif defined(CONFIG_TARGET_VENUS) +#define GLB_BASE_ADDR 0xf4320028 +#define PER_MDIO_BASE_ADDR 0xf4329118 +#define NI_HV_BASE_ADDR 0xf4304000 +#endif +#endif + +static void ni_setup_mac_addr(void) +{ + unsigned char mac[6]; + NI_HV_GLB_MAC_ADDR_CFG0_t mac_addr_cfg0; + NI_HV_GLB_MAC_ADDR_CFG1_t mac_addr_cfg1; + NI_HV_PT_PORT_STATIC_CFG_t port_static_cfg; + NI_HV_XRAM_CPUXRAM_CFG_t cpuxram_cfg; + +#ifdef CONFIG_DM_ETH + struct cortina_ni_priv *priv = dev_get_priv(curr_dev); +#else + struct cortina_ni_priv *priv = + (struct cortina_ni_priv *)(curr_dev->priv); +#endif + /* parsing ethaddr and set to NI registers. */ + if (eth_env_get_enetaddr("ethaddr", mac)) { + /* The complete MAC address consists of + * {MAC_ADDR0_mac_addr0[0-3], MAC_ADDR1_mac_addr1[4], + * PT_PORT_STATIC_CFG_mac_addr6[5]}. + */ + mac_addr_cfg0.bf.mac_addr0 = (mac[0] << 24) + + (mac[1] << 16) + + (mac[2] << 8) + + mac[3]; + CA_REG_WRITE(mac_addr_cfg0.wrd, priv->ni_hv_base_addr + + NI_HV_GLB_MAC_ADDR_CFG0_OFFSET); + + mac_addr_cfg1.wrd = 0; + mac_addr_cfg1.bf.mac_addr1 = mac[4]; + CA_REG_WRITE(mac_addr_cfg1.wrd, (priv->ni_hv_base_addr + + NI_HV_GLB_MAC_ADDR_CFG1_OFFSET)); + + port_static_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr + + NI_HV_PT_PORT_STATIC_CFG_OFFSET + + APB0_NI_HV_PT_STRIDE * active_port)); + + port_static_cfg.bf.mac_addr6 = mac[5]; + CA_REG_WRITE(port_static_cfg.wrd, (priv->ni_hv_base_addr + + NI_HV_PT_PORT_STATIC_CFG_OFFSET + + APB0_NI_HV_PT_STRIDE * active_port)); + + /* received only Broadcast and Address matched packets */ + cpuxram_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr + + NI_HV_XRAM_CPUXRAM_CFG_OFFSET)); + cpuxram_cfg.bf.xram_mgmt_promisc_mode = 0; + cpuxram_cfg.bf.rx_0_cpu_pkt_dis = 0; + cpuxram_cfg.bf.tx_0_cpu_pkt_dis = 0; + CA_REG_WRITE(cpuxram_cfg.wrd, (priv->ni_hv_base_addr + + NI_HV_XRAM_CPUXRAM_CFG_OFFSET)); + } else { + /* received all packets(promiscuous mode) */ + cpuxram_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr + + NI_HV_XRAM_CPUXRAM_CFG_OFFSET)); + cpuxram_cfg.bf.xram_mgmt_promisc_mode = 3; + cpuxram_cfg.bf.rx_0_cpu_pkt_dis = 0; + cpuxram_cfg.bf.tx_0_cpu_pkt_dis = 0; + CA_REG_WRITE(cpuxram_cfg.wrd, (priv->ni_hv_base_addr + + NI_HV_XRAM_CPUXRAM_CFG_OFFSET)); + } +} + +static void ni_enable_tx_rx(void) +{ + NI_HV_PT_RXMAC_CFG_t rxmac_cfg; + NI_HV_PT_TXMAC_CFG_t txmac_cfg; + //NI_HV_GLB_RXMUX_WEIGHT_RATIO_CFG0_t weight_ratio_cfg0; + //NI_HV_GLB_RXMUX_WEIGHT_RATIO_CFG1_t weight_ratio_cfg1; + +#ifdef CONFIG_DM_ETH + struct cortina_ni_priv *priv = dev_get_priv(curr_dev); +#else + struct cortina_ni_priv *priv = + (struct cortina_ni_priv *)(curr_dev->priv); +#endif + /* Enable TX and RX functions */ + rxmac_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr + + NI_HV_PT_RXMAC_CFG_OFFSET + + APB0_NI_HV_PT_STRIDE * active_port)); + rxmac_cfg.bf.rx_en = 1; + CA_REG_WRITE(rxmac_cfg.wrd, (priv->ni_hv_base_addr + + NI_HV_PT_RXMAC_CFG_OFFSET + + APB0_NI_HV_PT_STRIDE * active_port)); + + txmac_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr + + NI_HV_PT_TXMAC_CFG_OFFSET + + APB0_NI_HV_PT_STRIDE * active_port)); + txmac_cfg.bf.tx_en = 1; + CA_REG_WRITE(txmac_cfg.wrd, (priv->ni_hv_base_addr + + NI_HV_PT_TXMAC_CFG_OFFSET + + APB0_NI_HV_PT_STRIDE * active_port)); + +#if 0 + /* Configure RXMUX weight ratio */ + if (active_port >= NI_PORT_0 && active_port <= NI_PORT_3) { + weight_ratio_cfg0.wrd = + CA_REG_READ(NI_HV_GLB_RXMUX_WEIGHT_RATIO_CFG0); + switch (active_port) { + case NI_PORT_0: + weight_ratio_cfg0.bf.port0 = 0x10; + break; + case NI_PORT_1: + weight_ratio_cfg0.bf.port1 = 0x10; + break; + case NI_PORT_2: + weight_ratio_cfg0.bf.port2 = 0x10; + break; + case NI_PORT_3: + weight_ratio_cfg0.bf.port3 = 0x10; + break; + } + CA_REG_WRITE(weight_ratio_cfg0.wrd, + NI_HV_GLB_RXMUX_WEIGHT_RATIO_CFG0); + } + + if (active_port >= NI_PORT_4 && active_port <= NI_PORT_7) { + weight_ratio_cfg1.wrd = + CA_REG_READ(NI_HV_GLB_RXMUX_WEIGHT_RATIO_CFG1); + switch (active_port) { + case NI_PORT_4: + weight_ratio_cfg1.bf.port4 = 0x10; + break; + case NI_PORT_5: + weight_ratio_cfg1.bf.port5 = 0x10; + break; + case NI_PORT_6: + weight_ratio_cfg1.bf.port6 = 0x10; + break; + case NI_PORT_7: + weight_ratio_cfg1.bf.port7 = 0x10; + break; + } + CA_REG_WRITE(weight_ratio_cfg1.wrd, + NI_HV_GLB_RXMUX_WEIGHT_RATIO_CFG1); + } +#endif +} + +void cortina_ni_reset(void) +{ + int i; + NI_HV_GLB_INIT_DONE_t init_done; + NI_HV_GLB_INTF_RST_CONFIG_t intf_rst_config; + NI_HV_GLB_STATIC_CFG_t static_cfg; + GLOBAL_BLOCK_RESET_t glb_blk_reset; + +#ifdef CONFIG_DM_ETH + struct cortina_ni_priv *priv = dev_get_priv(curr_dev); +#else + struct cortina_ni_priv *priv = + (struct cortina_ni_priv *)(curr_dev->priv); +#endif + /* NI global resets */ + glb_blk_reset.wrd = CA_REG_READ((priv->glb_base_addr + + GLOBAL_BLOCK_RESET_OFFSET)); + glb_blk_reset.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); + } + + switch (active_port) { +#ifdef CONFIG_CA77XX + 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 ca_status_t ca_mdio_write_rgmii(ca_uint32_t addr, + ca_uint32_t offset, + ca_uint16_t data) +{ + PER_MDIO_ADDR_t mdio_addr; + PER_MDIO_CTRL_t mdio_ctrl; + /* up to 10000 cycles*/ + ca_uint32_t loop_wait = __MDIO_ACCESS_TIMEOUT; + +#ifdef CONFIG_DM_ETH + struct cortina_ni_priv *priv = dev_get_priv(curr_dev); +#else + struct cortina_ni_priv *priv = + (struct cortina_ni_priv *)(curr_dev->priv); +#endif + mdio_addr.wrd = 0; + mdio_addr.bf.mdio_addr = addr; + mdio_addr.bf.mdio_offset = offset; + mdio_addr.bf.mdio_rd_wr = __MDIO_WR_FLAG; + CA_REG_WRITE(mdio_addr.wrd, + priv->per_mdio_base_addr + PER_MDIO_ADDR_OFFSET); + CA_REG_WRITE(data, + priv->per_mdio_base_addr + PER_MDIO_WRDATA_OFFSET); + +#if CORTINA_NI_DBG + printf("%s: mdio_addr.wrd=0x%x\n", __func__, mdio_addr.wrd); +#endif + + mdio_ctrl.wrd = 0; + mdio_ctrl.bf.mdiostart = 1; + CA_REG_WRITE(mdio_ctrl.wrd, + priv->per_mdio_base_addr + PER_MDIO_CTRL_OFFSET); + +#if CORTINA_NI_DBG + printf("%s: phy_addr=%d, offset=%d, data=0x%x\n", + __func__, addr, offset, data); +#endif + + do { + mdio_ctrl.wrd = CA_REG_READ((priv->per_mdio_base_addr + + PER_MDIO_CTRL_OFFSET)); + if (mdio_ctrl.bf.mdiodone) { + CA_REG_WRITE(mdio_ctrl.wrd, (priv->per_mdio_base_addr + + PER_MDIO_CTRL_OFFSET)); + return CA_E_OK; + } + } while (--loop_wait); + + printf("%s: PHY rite timeout!!!\n", __func__); + return CA_E_TIMEOUT; +} + +ca_status_t ca_mdio_write(CA_IN ca_uint32_t addr, + CA_IN ca_uint32_t offset, + CA_IN ca_uint16_t data) +{ +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || \ + defined(CONFIG_TARGET_SATURN_ASIC) || defined(CONFIG_TARGET_VENUS) + NI_MDIO_OPER_T mdio_oper; + + __MDIO_ADDR_CHK(addr); + + /* 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 + __MDIO_ADDR_CHK(addr); + + return ca_mdio_write_rgmii(addr, offset, data); +#endif +} + +static ca_status_t ca_mdio_read_rgmii(ca_uint32_t addr, + ca_uint32_t offset, + ca_uint16_t *data) +{ + PER_MDIO_ADDR_t mdio_addr; + PER_MDIO_CTRL_t mdio_ctrl; + PER_MDIO_RDDATA_t read_data; + ca_uint32_t loop_wait = __MDIO_ACCESS_TIMEOUT; + +#ifdef CONFIG_DM_ETH + struct cortina_ni_priv *priv = dev_get_priv(curr_dev); +#else + struct cortina_ni_priv *priv = + (struct cortina_ni_priv *)(curr_dev->priv); +#endif + mdio_addr.wrd = 0; + mdio_addr.bf.mdio_addr = addr; + mdio_addr.bf.mdio_offset = offset; + mdio_addr.bf.mdio_rd_wr = __MDIO_RD_FLAG; + CA_REG_WRITE(mdio_addr.wrd, + priv->per_mdio_base_addr + PER_MDIO_ADDR_OFFSET); + + mdio_ctrl.wrd = 0; + mdio_ctrl.bf.mdiostart = 1; + CA_REG_WRITE(mdio_ctrl.wrd, + priv->per_mdio_base_addr + PER_MDIO_CTRL_OFFSET); + + do { + mdio_ctrl.wrd = CA_REG_READ((priv->per_mdio_base_addr + + PER_MDIO_CTRL_OFFSET)); + if (mdio_ctrl.bf.mdiodone) { + CA_REG_WRITE(mdio_ctrl.wrd, (priv->per_mdio_base_addr + + PER_MDIO_CTRL_OFFSET)); + read_data.wrd = CA_REG_READ((priv->per_mdio_base_addr + + PER_MDIO_RDDATA_OFFSET)); + *data = read_data.bf.mdio_rddata; + return CA_E_OK; + } + } while (--loop_wait); + + printf("%s: CA_E_TIMEOUT!!\n", __func__); + return CA_E_TIMEOUT; +} + +ca_status_t ca_mdio_read(CA_IN ca_uint32_t addr, + CA_IN ca_uint32_t offset, + CA_OUT ca_uint16_t *data) +{ +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || \ + defined(CONFIG_TARGET_SATURN_ASIC) || defined(CONFIG_TARGET_VENUS) + NI_MDIO_OPER_T mdio_oper; + + CA_ASSERT(data); + __MDIO_ADDR_CHK(addr); /* support range: 1~31*/ + + /* 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 + CA_ASSERT(data); + __MDIO_ADDR_CHK(addr); /* support range: 1~31*/ + + 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 0 +int g2_phy_disable(int port) +{ + unsigned int addr, val; + + switch (port) { + case 0: + addr = GE_PORT0_PHY_ADDR; + break; + case 1: + addr = GE_PORT1_PHY_ADDR; + break; + case 2: + addr = GE_PORT2_PHY_ADDR; + break; + default: + printf("%s: invalid port %d\n", __func__, port); + return -1; + } + + if (addr == 0) /* ignore PHY address 0 */ + return 0; + + val = ca_mdio_read(addr, 0); + val = val | (1 << 11); /* set power down */ + ca_mdio_write(addr, 0, val); + return 0; +} +#endif + +#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=%d, read register 19, " + "val=0x%x\n", __func__, phy_addr, data); + } +#ifdef CORTINA_NI_DBG + printf("%s: phy_addr=%d, read register 19, value=0x%x\n", + __func__, phy_addr, data); +#endif + } +} +#endif + +#ifdef CONFIG_DM_ETH +int cortina_ni_init(struct udevice *dev) +#else +int cortina_ni_init(struct eth_device *dev, bd_t *bd) +#endif +{ + u16 vendor_id, chip_id; + u32 phy_id; + u16 phy_reg_value, lpagb, lpa, phy_speed, phy_duplex, speed, duplex; + char *spd, *dup; + NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t cpuxram_adrcfg_rx; + NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t cpuxram_adrcfg_tx; + NI_HV_XRAM_CPUXRAM_CFG_t cpuxram_cfg; + NI_HV_PT_PORT_STATIC_CFG_t port_static_cfg; + NI_HV_PT_PORT_GLB_CFG_t port_glb_cfg; + +#ifdef CONFIG_DM_ETH + struct cortina_ni_priv *priv = dev_get_priv(dev); +#else + struct cortina_ni_priv *priv = (struct cortina_ni_priv *)(dev->priv); +#endif + /* read "ethaddr" and setup to NI regsiters */ + ni_setup_mac_addr(); + + /* RX XRAM ADDRESS CONFIG (start and end address) */ + cpuxram_adrcfg_rx.wrd = 0; + cpuxram_adrcfg_rx.bf.rx_top_addr = RX_TOP_ADDR; + cpuxram_adrcfg_rx.bf.rx_base_addr = RX_BASE_ADDR; + CA_REG_WRITE(cpuxram_adrcfg_rx.wrd, (priv->ni_hv_base_addr + + NI_HV_XRAM_CPUXRAM_ADRCFG_RX_OFFSET)); + + /* TX XRAM ADDRESS CONFIG (start and end address) */ + cpuxram_adrcfg_tx.wrd = 0; + cpuxram_adrcfg_tx.bf.tx_top_addr = TX_TOP_ADDR; + cpuxram_adrcfg_tx.bf.tx_base_addr = TX_BASE_ADDR; + CA_REG_WRITE(cpuxram_adrcfg_tx.wrd, (priv->ni_hv_base_addr + + NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_OFFSET)); + + ca_mdio_read(ge_port_phy_addr, 0x02, &vendor_id); + ca_mdio_read(ge_port_phy_addr, 0x03, &chip_id); + phy_id = (vendor_id << 16) | chip_id; + +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS) + /* workaround to fix GPHY fail */ + if ((phy_id & PHY_ID_MASK) == PHY_ID_RTL8211_G3_ASIC) + cortina_ni_fix_gphy(); +#endif + + /* PHY GB status */ + ca_mdio_read(ge_port_phy_addr, 0x0a, &lpagb); + /* PHY GB control */ + ca_mdio_read(ge_port_phy_addr, 0x09, &phy_reg_value); + lpagb &= phy_reg_value << 2; + + /* Link Partner Ability */ + ca_mdio_read(ge_port_phy_addr, 0x05, &lpa); + /* PHY Advertisement */ + ca_mdio_read(ge_port_phy_addr, 0x04, &phy_reg_value); + lpa &= phy_reg_value; + + /* phy_speed 0: 10Mbps, 1: 100Mbps, 2: 1000Mbps */ + /* duplex 0: half duplex, 1: full duplex */ + phy_speed = 0; + phy_duplex = 0; + if (lpagb & (3 << 10)) { + /* 1000Mbps */ + phy_speed = 2; + if (lpagb & (1 << 11)) { + /* 1000Mbps full */ + duplex = 1; + } + } else if (lpa & (3 << 7)) { + /* 100Mbps */ + phy_speed = 1; + if (lpa & (1 << 8)) { + /* 100Mbps full */ + phy_duplex = 1; + } + } else if (lpa & (1 << 6)) { + /* 10Mbps full */ + phy_duplex = 1; + } + + switch (phy_speed) { + default: + case 0: + spd = "10Mbps"; + break; + case 1: + spd = "100Mbps"; + break; + case 2: + spd = "1000Mbps"; + break; + } + + if (duplex == 1) + dup = "full duplex"; + else + dup = "half duplex"; + + printf("PHY ID 0x%08X %s %s\n", phy_id, spd, dup); + + switch (phy_id & PHY_ID_MASK) { + case PHY_ID_RTL8214: + port_static_cfg.wrd = + CA_REG_READ((priv->ni_hv_base_addr + + NI_HV_PT_PORT_STATIC_CFG_OFFSET + + APB0_NI_HV_PT_STRIDE * active_port)); + /* QSGMII_GE */ + port_static_cfg.bf.int_cfg = GE_MAC_INTF_QSGMII_1000; + CA_REG_WRITE(port_static_cfg.wrd, + (priv->ni_hv_base_addr + + NI_HV_PT_PORT_STATIC_CFG_OFFSET + + APB0_NI_HV_PT_STRIDE * active_port)); + break; + case PHY_ID_RTL8211: +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS) + case PHY_ID_RTL8211_G3_ASIC: +#endif +#ifdef CONFIG_TARGET_SATURN_ASIC + case PHY_ID_RTL8211_SATURN_ASIC: +#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.xram_mgmt_promisc_mode = 3; + 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; + NI_HV_XRAM_CPUXRAM_CFG_t cpuxram_cfg; + +#ifdef CONFIG_DM_ETH + struct cortina_ni_priv *priv = dev_get_priv(curr_dev); +#else + struct cortina_ni_priv *priv = + (struct cortina_ni_priv *)(curr_dev->priv); +#endif + + if (first_time) { + /* received all kind of packets */ + cpuxram_cfg.wrd = CA_REG_READ((priv->ni_hv_base_addr + + NI_HV_XRAM_CPUXRAM_CFG_OFFSET)); + cpuxram_cfg.bf.xram_mgmt_promisc_mode = 3; + cpuxram_cfg.bf.rx_0_cpu_pkt_dis = 0; + cpuxram_cfg.bf.tx_0_cpu_pkt_dis = 0; + CA_REG_WRITE(cpuxram_cfg.wrd, (priv->ni_hv_base_addr + + NI_HV_XRAM_CPUXRAM_CFG_OFFSET)); + first_time = 0; + } + + cortina_ni_recv(curr_dev); + return 0; +} + +/********************************************* + * Packet receive routine from Management FE + * Expects a previously allocated buffer and + * fills the length + * Retruns 0 on success -1 on failure + *******************************************/ +#ifdef CONFIG_DM_ETH +int cortina_ni_recv(struct udevice *netdev) +#else +int cortina_ni_recv(struct eth_device *netdev) +#endif +{ +#ifdef CONFIG_DM_ETH + struct cortina_ni_priv *priv = dev_get_priv(netdev); +#else + struct cortina_ni_priv *priv = + (struct cortina_ni_priv *)(netdev->priv); +#endif + NI_HEADER_X_T header_x; + u32 pktlen = 0; + u32 sw_rx_rd_ptr; + u32 hw_rx_wr_ptr; + volatile u32 *rx_xram_ptr; +#ifdef CORTINA_NI_DBG + int blk_num; +#endif + int loop; + //static unsigned char pkt_buf[2048]; + u32 *data_ptr; +#ifdef CORTINA_NI_DBG + u8 *ptr; +#endif + NI_PACKET_STATUS_T packet_status; + NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t cpuxram_cpu_sta_rx; + NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t cpuxram_cpu_cfg_rx; + int index = 0; + + /* 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%x, " + "NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0=0x%x\n", + __func__, NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0, + NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0); + + 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 *)((ca_uint)NI_XRAM_BASE + sw_rx_rd_ptr * 8); + + /* Wrap around if required */ + if (rx_xram_ptr >= (u32 *)(ca_uint)(priv->rx_xram_end_adr)) + rx_xram_ptr = (u32 *)(ca_uint)(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 = (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 = (NI_PACKET_STATUS_T)(*rx_xram_ptr); + +#if CORTINA_NI_DBG + printf("%s: packet_status=0x%x\n", + __func__, packet_status); +#endif + if (packet_status.bf.valid == 0) { +#if CORTINA_NI_DBG + printf("%s: Invalid Packet !!, " + "Packet status=0x%x, " + "header_x.bf.next_link=%d\n", + __func__, packet_status.wrd, + 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," + " header_x.bf.next_link=%d\n", + __func__, packet_status.wrd, + 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, " + "larger than 1518, " + "Packet status=0x%x, " + "header_x.bf.next_link=%d\n", + __func__, + packet_status.bf.packet_size, + packet_status.wrd, + 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 0 + /* Wrap around if required */ + if (rx_xram_ptr >= + (u32 *)(ca_uint)(priv->rx_xram_end_adr)) + rx_xram_ptr = + (u32 *)(ca_uint)(priv->rx_xram_base_adr); + + rx_xram_ptr++; /* skip Packet status [31:0] */ + + /* Wrap around if required */ + if (rx_xram_ptr >= + (u32 *)(ca_uint)(priv->rx_xram_end_adr)) + rx_xram_ptr = + (u32 *)(ca_uint)(priv->rx_xram_base_adr); +#endif + 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 = rx_xram_ptr; + printf("[0x%x]-[0x%x]-[0x%x]-[0x%x]", + ptr[0], ptr[1], ptr[2], ptr[3]); +#endif + *data_ptr++ = *rx_xram_ptr++; + /* Wrap around if required */ + if (rx_xram_ptr >= + (u32 *)(ca_uint)(priv->rx_xram_end_adr)) + rx_xram_ptr = (u32 *)(ca_uint) + (priv->rx_xram_base_adr); + } +#if CORTINA_NI_DBG + printf("\n"); +#endif + net_process_received_packet(net_rx_packets[index], + pktlen); + if (++index >= PKTBUFSRX) + index = 0; +#if CORTINA_NI_DBG + blk_num = net_rx_packets[index][0x2c] * 255 + + net_rx_packets[index][0x2d]; + printf("%s: tftp block number=%d\n", __func__, blk_num); +#endif + + /* Update the software read pointer */ + CA_REG_WRITE(header_x.bf.next_link, + (priv->ni_hv_base_addr + + NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET)); + } + + /* get the hw write pointer */ + cpuxram_cpu_sta_rx.wrd = + CA_REG_READ((priv->ni_hv_base_addr + + NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET)); + hw_rx_wr_ptr = cpuxram_cpu_sta_rx.bf.pkt_wr_ptr; + + /* get the sw read pointer */ + sw_rx_rd_ptr = + CA_REG_READ((priv->ni_hv_base_addr + + NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET)); + } + return 0; +} + +/* LITTLE_ENDIAN */ +static u32 calc_crc(u32 crc, u8 const *p, u32 len) +{ + int i; + + while (len--) { + crc ^= *p++; + for (i = 0; i < 8; i++) + crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0); + } + return crc; +} + +#ifdef CONFIG_DM_ETH +static int cortina_ni_send(struct udevice *dev, void *packet, int length) +#else +static int cortina_ni_send(struct eth_device *dev, void *packet, int length) +#endif +{ +#ifdef CONFIG_DM_ETH + struct cortina_ni_priv *priv = dev_get_priv(dev); +#else + struct cortina_ni_priv *priv = (struct cortina_ni_priv *)(dev->priv); +#endif + u32 hw_tx_rd_ptr; + u32 sw_tx_wr_ptr; + unsigned int new_pkt_len; + unsigned char valid_bytes = 0; + u32 *tx_xram_ptr; + u16 next_link = 0; + unsigned char *pkt_buf_ptr; + unsigned int loop; + u32 crc32; + //unsigned int hdr_xt = 0; + NI_HEADER_X_T hdr_xt; + int pad = 0; + static unsigned char pkt_buf[2048]; + u32 *data_ptr; + //NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_t cpuxram_cpu_stat_tx; + NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t cpuxram_cpu_cfg_tx; +#if CORTINA_NI_DBG + u8 *ptr; +#endif + + if (NULL == packet || length > 2032) + return -1; + + /* Get the hardware read pointer */ + //cpuxram_cpu_stat_tx.wrd = + // CA_REG_READ(NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0); + //hw_tx_rd_ptr = cpuxram_cpu_stat_tx.bf.pkt_rd_ptr; + 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 */ + //cpuxram_cpu_cfg_tx.wrd = CA_REG_READ(NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0); + //sw_tx_wr_ptr = cpuxram_cpu_cfg_tx.bf.pkt_wr_ptr; + 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%x, " + "NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0=0x%x\n", + __func__, + KSEG1_ATU_XLAT(NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0), + KSEG1_ATU_XLAT(NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0)); +#else + printf("%s: NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0=0x%x, " + "NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0=0x%x\n", + __func__, + NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0, + NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0); +#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 *)((ca_uint)NI_XRAM_BASE + sw_tx_wr_ptr * 8); + + /* Wrap around if required */ + if (tx_xram_ptr >= (u32 *)(ca_uint)(priv->tx_xram_end_adr)) + tx_xram_ptr = (u32 *)(ca_uint)(priv->tx_xram_base_adr); + +#if 0 + /* skip first 4 bytes before copying the headerXT */ + tx_xram_ptr++; + + /* Wrap around if required */ + if (tx_xram_ptr >= (u32 *)(ca_uint)(priv->tx_xram_end_adr)) + tx_xram_ptr = (u32 *)(ca_uint)(priv->tx_xram_base_adr); +#endif + 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; + +#if 0 + tx_xram_ptr++; + + /* Wrap around if required */ + if (tx_xram_ptr >= (u32 *)(ca_uint)(priv->tx_xram_end_adr)) + tx_xram_ptr = (u32 *)(ca_uint)(priv->tx_xram_base_adr); +#endif + 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 = 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 + +#if 0 + *tx_xram_ptr++ = *data_ptr++; + /* Wrap around if required */ + if (tx_xram_ptr >= (u32 *)(ca_uint)(priv->tx_xram_end_adr)) + tx_xram_ptr = (u32 *)(ca_uint)(priv->tx_xram_base_adr); +#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 write pointer */ + cpuxram_cpu_cfg_tx.bf.pkt_wr_ptr = next_link; + CA_REG_WRITE(cpuxram_cpu_cfg_tx.wrd, + (priv->ni_hv_base_addr + + NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET)); + + return 0; +} + +#ifdef CONFIG_DM_ETH +void cortina_ni_halt(struct udevice *netdev) +#else +void cortina_ni_halt(struct eth_device *netdev) +#endif +{ +#if FOR_DEBUG + /* MFE MAC configuration Disable tx and rx */ + reg_value = CA_REG_READ((priv->ni_hv_base_addr + + NI_TOP_NI_ETH_MAC_CONFIG0_0_MFE_OFFSET)); + reg_value = reg_value & ~(NI_RX_ENB); + reg_value = reg_value & ~(NI_TX_ENB); + CA_REG_WRITE(reg_value, (priv->ni_hv_base_addr + + NI_TOP_NI_ETH_MAC_CONFIG0_0_MFE_OFFSET)); + + /* Disable MFE ethernet interface */ + reg_value = CA_REG_READ(TOP_NI_INTF_RST_CONFIG); + reg_value = reg_value | (INTF_RST_GE1); + CA_REG_WRITE(reg_value, TOP_NI_INTF_RST_CONFIG); +#endif +} + +#define RTL8214_INIT_REG_COUNT 58 +static u32 rtl8214_init_reg_val[RTL8214_INIT_REG_COUNT] = { + 0x6602, 0x84D7, 0x6601, 0x0540, 0x6600, 0x00C0, + 0x6602, 0xF994, 0x6601, 0x0541, 0x6600, 0x00C0, + 0x6602, 0x2DA3, 0x6601, 0x0542, 0x6600, 0x00C0, + 0x6602, 0x3960, 0x6601, 0x0543, 0x6600, 0x00C0, + 0x6602, 0x9728, 0x6601, 0x0544, 0x6600, 0x00C0, + 0x6602, 0xF83F, 0x6601, 0x0545, 0x6600, 0x00C0, + 0x6602, 0x9D85, 0x6601, 0x0423, 0x6600, 0x00C0, + 0x6602, 0xD810, 0x6601, 0x0424, 0x6600, 0x00C0, + 0x1D11, 0x1506, + 0x1D12, 0x0800, + 0x6602, 0xC3FA, 0x6601, 0x002E, 0x6600, 0x00C0 +}; + +#ifdef CONFIG_TARGET_PRESIDIO_ASIC +/* move to LED driver */ +#if 0 +/* initialize LEDs for ethernet link and traffic lights */ +static void ca77xx_init_led(void) +{ + int i; + GLOBAL_PIN_MUX_t pin_mux; + GLOBAL_LED_CONTROL_t led_control; + GLOBAL_LED_CONFIG_0_t led_config0; + + pin_mux.wrd = CA_REG_READ(GLOBAL_PIN_MUX); + pin_mux.bf.iomux_led_enable = 1; + CA_REG_WRITE(pin_mux.wrd, GLOBAL_PIN_MUX); + + /* LED control & config - led 0 ~ 7 for rx of port 0 ~ 7, + * led 8 ~ 15 for tx of port 0 ~ 7 with 256ms blinking + */ + led_control.wrd = CA_REG_READ(GLOBAL_LED_CONTROL); + led_control.bf.blink_rate_1 = 0x0f; + led_control.bf.blink_rate_2 = 0x1f; + CA_REG_WRITE(led_control.wrd, GLOBAL_LED_CONTROL); + + for (i = 0; i < 8; i++) { + led_config0.wrd = CA_REG_READ(GLOBAL_LED_CONFIG_0 + i * 4); + led_config0.bf.led_event_blink = 1; + led_config0.bf.led_off_val = 1; + led_config0.bf.led_port = i; + CA_REG_WRITE(led_config0.wrd, GLOBAL_LED_CONFIG_0 + i * 4); + } + + for (i = 0; i < 8; i++) { + led_config0.wrd = CA_REG_READ(GLOBAL_LED_CONFIG_8 + i * 4); + led_config0.bf.led_event_blink = 2; + led_config0.bf.led_off_val = 1; + led_config0.bf.led_port = i; + CA_REG_WRITE(led_config0.wrd, GLOBAL_LED_CONFIG_8 + i * 4); + } +} +#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; + ca_uint16_t 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 to 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; + ca_uint16_t data; + + /* if etherent not initialized do nothing */ + if (NULL == 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; + ca_uint16_t data; + + /* should initialize 4 GPHYs at once */ + for (phy_addr = 4; phy_addr > 0; phy_addr--) { + ca_mdio_write(phy_addr, 31, 0x0BC6); + ca_mdio_write(phy_addr, 16, 0x0053); + ca_mdio_write(phy_addr, 18, 0x4003); + ca_mdio_write(phy_addr, 22, 0x7e01); + ca_mdio_write(phy_addr, 31, 0x0A42); + ca_mdio_write(phy_addr, 31, 0x0A40); + ca_mdio_write(phy_addr, 0, 0x1140); + } + /* workaround to fix GPHY fail */ + cortina_ni_fix_gphy(); + + start_time = get_timer(0); + while (get_timer(start_time) < AUTO_SCAN_TIMEOUT) { + for (phy_addr = 1; phy_addr < 5; phy_addr++) { + ca_mdio_read(phy_addr, 1, &data); + if (data & 0x04) { + active_port = phy_addr - 1; + printf("%s: active_port=%d\n", + __func__, active_port); + + ca77xx_ni_led(active_port, 1); + return; + } + } + } + printf("%s: auto scan active_port timeout, set active_port to 1.\n", + __func__); + active_port = NI_PORT_1; + + ca77xx_ni_led(active_port, 0); +} + +#elif defined(CONFIG_TARGET_SATURN_ASIC) + +/* auto scan the first link up port as active_port */ +#define AUTO_SCAN_TIMEOUT 3000 /* 3 seconds */ +static void ca77xx_ni_auto_scan_active_port(void) +{ + u8 phy_addr; + u32 start_time; + ca_uint16_t 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, read register 19, " + "value=0x%x\n", __func__, phy_addr, 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 +typedef struct gphy_cal_s { + u32 reg_off; + u32 value; +} gphy_cal_t; + +static gphy_cal_t gphy_cal_vlaues[GPHY_CAL_LEN] = { + {0xf43380fc, 0xbcd}, + {0xf43380dc, 0xeeee}, + {0xf43380d8, 0xeeee}, + {0xf43380fc, 0xbce}, + {0xf43380c0, 0x7777}, + {0xf43380c4, 0x7777} +}; + +static void do_internal_gphy_cal(void) +{ + int i, port; + u32 reg_off, value; + + for (port = 0; port < 4; port++) { + for (i = 0; i < GPHY_CAL_LEN; i++) { + reg_off = gphy_cal_vlaues[i].reg_off + (port * 0x80); + value = gphy_cal_vlaues[i].value; + CA_REG_WRITE(value, reg_off); + mdelay(50); + } + } +} +#endif + +#ifdef CONFIG_DM_ETH +int ca77xx_eth_initialize(struct udevice *dev) +#else +int ca77xx_eth_initialize(bd_t *bis) +#endif +{ + struct cortina_ni_priv *priv; + char *buf; + u16 val; + int i; + u16 vendor_id, chip_id; + u32 phy_id; + +#ifndef CONFIG_DM_ETH + struct eth_device *dev; + + dev = (struct eth_device *)malloc(sizeof(*dev)); + if (NULL == dev) + return 1; + memset(dev, 0, sizeof(*dev)); + priv = (struct cortina_ni_priv *)malloc(sizeof(*priv)); + if (NULL == priv) { + free(dev); + return 1; + } + memset(priv, 0, sizeof(*priv)); + + dev->priv = priv; + priv->glb_base_addr = GLB_BASE_ADDR; + priv->per_mdio_base_addr = PER_MDIO_BASE_ADDR; + priv->ni_hv_base_addr = NI_HV_BASE_ADDR; + printf("%s: priv->glb_base_addr is 0x%x\n", + __func__, priv->glb_base_addr); + printf("%s: priv->per_mdio_base_addr is 0x%x\n", + __func__, priv->per_mdio_base_addr); + printf("%s: priv->ni_hv_base_addr is 0x%x\n", + __func__, priv->ni_hv_base_addr); +#else + priv = dev_get_priv(dev); +#endif + + priv->rx_xram_base_adr = NI_XRAM_BASE + (RX_BASE_ADDR * 8); + priv->rx_xram_end_adr = NI_XRAM_BASE + ((RX_TOP_ADDR + 1) * 8); + priv->rx_xram_start = RX_BASE_ADDR; + priv->rx_xram_end = RX_TOP_ADDR; + priv->tx_xram_base_adr = NI_XRAM_BASE + (TX_BASE_ADDR * 8); + priv->tx_xram_end_adr = NI_XRAM_BASE + ((TX_TOP_ADDR + 1) * 8); + priv->tx_xram_start = TX_BASE_ADDR; + priv->tx_xram_end = TX_TOP_ADDR; + + curr_dev = dev; +#if CORTINA_NI_DBG + printf("%s: rx_base_addr:%x\t rx_top_addr %x\n", + __func__, priv->rx_xram_start, priv->rx_xram_end); + printf("%s: tx_base_addr:%x\t tx_top_addr %x\n", + __func__, priv->tx_xram_start, priv->tx_xram_end); + printf("%s: rx physical start address = %x end address = %x\n", + __func__, priv->rx_xram_base_adr, priv->rx_xram_end_adr); + printf("%s: tx physical start address = %x end address = %x\n", + __func__, priv->tx_xram_base_adr, priv->tx_xram_end_adr); +#endif + + //ni_enable_tx_rx(); + + /* set MDIO pre-scale value */ + reg_value = CA_REG_READ(priv->per_mdio_base_addr + PER_MDIO_CFG_OFFSET); + reg_value = reg_value | 0x00280000; + CA_REG_WRITE(reg_value, priv->per_mdio_base_addr + PER_MDIO_CFG_OFFSET); + + /* In Saturn active_port are 3 or 4, + * because the register offset has been shifted forward + * LAN ports (port 4-7) connect to RTL8214 + */ +#if defined(CONFIG_TARGET_SATURN_ASIC) + buf = env_get("auto_scan_active_port"); + if (buf != 0) { + auto_scan_active_port = simple_strtoul(buf, NULL, 0); + printf("%s: auto_scan_active_port=%d\n", + __func__, auto_scan_active_port); + } + + if (auto_scan_active_port) { + ca77xx_ni_auto_scan_active_port(); + } else { + buf = env_get("active_port"); + if (buf != 0) { + active_port = simple_strtoul(buf, NULL, 0); + printf("%s: active_port=%d\n", __func__, active_port); + if (active_port != NI_PORT_3 && + active_port != NI_PORT_4) { + printf("ERROR: does not support " + "active_port %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 " + "%d\n", active_port); + printf("Please change active_port to 0-3.\n"); + free(dev); + free(priv); + return 1; + } + } else { + active_port = NI_PORT_1; + } + } +#endif + + cortina_ni_reset(); + +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS) + /* port0: phy address 1 - GMAC0: port 0 + port1: phy address 2 - GMAC1: port 1 + port2: phy address 3 - GMAC2: port 2 + port3: phy address 4 - GMAC3: port 3 + port4: phy address 5 - RGMII: port 4 + */ + ge_port_phy_addr = active_port + 1; +#else + /* port0: phy address 1 - GMAC0: port 0 + port1: phy address 2 - GMAC1: port 1 + port2: phy address 3 - GMAC2: port 2 + port3: phy address 4 - GMAC3: port 3 + port4: phy address 16 - QSGMII: port 0 + port5: phy address 17 - QSGMII: port 1 + port6: phy address 18 - QSGMII: port 2 + port7: phy address 19 - QSGMII: port 3 + */ + if (active_port >= NI_PORT_0 && active_port <= NI_PORT_3) + ge_port_phy_addr = active_port + 1; + else + ge_port_phy_addr = active_port - 2; +#endif + +#if defined(CONFIG_TARGET_SATURN_ASIC) + /* internal GPHY addr=1 */ + if (active_port == NI_PORT_3) + ge_port_phy_addr = 1; + else + ge_port_phy_addr = active_port + 1; + + printf("%s: active_port=%d, ge_port_phy_addr=%d\n", + __func__, active_port, ge_port_phy_addr); +#endif + + ca_mdio_read(ge_port_phy_addr, 2, &vendor_id); + ca_mdio_read(ge_port_phy_addr, 3, &chip_id); + phy_id = ((u32)vendor_id << 16) | chip_id; + + printf("%s: vendor_id=0x%x\n", __func__, vendor_id); + printf("%s: chip_id=0x%x\n", __func__, chip_id); + printf("%s: phy_id=0x%x\n", __func__, phy_id); + printf("%s: phy_id & PHY_ID_MASK=0x%x\n", + __func__, (phy_id & PHY_ID_MASK)); + printf("%s: PHY_ID_RTL8214=0x%x\n", __func__, PHY_ID_RTL8214); + + if ((phy_id & PHY_ID_MASK) == PHY_ID_RTL8211) { + printf("%s: do initial patch for PHY_ID_RTL8211\n", __func__); + /* + * Disable response PHYAD=0 function of + * RTL8211 series PHY + */ + + /* REG31 write 0x0007, set to extension page */ + ca_mdio_write(ge_port_phy_addr, 31, 0x0007); + + /* REG30 write 0x002C, set to extension page 44 */ + ca_mdio_write(ge_port_phy_addr, 30, 0x002C); + + /* + * REG27 write bit[2] =0 + * disable response PHYAD=0 function. + * we should read REG27 and clear bit[2], and write back + */ + ca_mdio_read(ge_port_phy_addr, 27, &val); + val &= ~(1 << 2); + ca_mdio_write(ge_port_phy_addr, 27, val); + + /* REG31 write 0X0000, back to page0 */ + ca_mdio_write(ge_port_phy_addr, 31, 0x0000); + } + + /* the init sequency provided by RTK */ + if ((phy_id & PHY_ID_MASK) == PHY_ID_RTL8214) { + printf("%s: write initial sequency for PHY_ID_RTL8214!!\n", + __func__); + for (i = 0; i < RTL8214_INIT_REG_COUNT; i++) { + if (!(i & 1)) { + ca_mdio_write(ge_port_phy_addr, 29, + rtl8214_init_reg_val[i]); + } else { + ca_mdio_write(ge_port_phy_addr, 30, + rtl8214_init_reg_val[i]); + } + } + } + +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS) + if ((phy_id & PHY_ID_MASK) == PHY_ID_RTL8211_G3_ASIC) { + u8 phy_addr; + + if (!auto_scan_active_port) { + printf("%s: write initial sequency for " + "PHY_ID_RTL8211_G3_ASIC!!\n", __func__); + + /* should initialize 4 GPHYs at once */ + for (phy_addr = 4; phy_addr > 0; phy_addr--) { + ca_mdio_write(phy_addr, 31, 0x0BC6); + ca_mdio_write(phy_addr, 16, 0x0053); + ca_mdio_write(phy_addr, 18, 0x4003); + ca_mdio_write(phy_addr, 22, 0x7e01); + ca_mdio_write(phy_addr, 31, 0x0A42); + ca_mdio_write(phy_addr, 31, 0x0A40); + ca_mdio_write(phy_addr, 0, 0x1140); + } + + /* workaround to fix GPHY fail */ + cortina_ni_fix_gphy(); + } + } + + ca77xx_ni_scan_phy_link(); +#endif + +#ifdef CONFIG_TARGET_VENUS + /* REG9 write 0x0200->0x0000, disable adv. 1000BASE capability */ + ca_mdio_write(ge_port_phy_addr, 0x09, 0x0000); + /* REG0 write 0x1040->0x9040, reset and associate the PHY link + * REG0 and REG1 will return to default values after reset + */ + ca_mdio_read(ge_port_phy_addr, 0x00, &val); + val |= 0x8000; + ca_mdio_write(ge_port_phy_addr, 0x00, val); + mdelay(1); +#endif + + /* parsing ethaddr and set to NI registers. */ + ni_setup_mac_addr(); + +#ifndef CONFIG_DM_ETH + sprintf(dev->name, CONFIG_IDENT_STRING); + dev->init = cortina_ni_init; + dev->halt = cortina_ni_halt; + dev->send = cortina_ni_send; + dev->recv = cortina_ni_recv; + + eth_register(dev); +#endif + /* the phy_read and phy_write + * should meet the proto type of miiphy_register + */ +#ifdef MIIPHY_REGISTER + miiphy_register(dev->name, ca_miiphy_read, ca_miiphy_write); +#endif + +#if CORTINA_NI_DBG + dbg_dev = dev; +#endif + +#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || defined(CONFIG_TARGET_VENUS) + /* hardware settings for RGMII port */ + { + GLOBAL_GLOBAL_CONFIG_t glb_config; + GLOBAL_IO_DRIVE_CONTROL_t io_drive_control; + + /* Generating 25Mhz reference clock for switch */ + glb_config.wrd = CA_REG_READ((priv->glb_base_addr + + GLOBAL_GLOBAL_CONFIG_OFFSET)); + glb_config.bf.refclk_sel = 0x01; + glb_config.bf.ext_reset = 0x01; + CA_REG_WRITE(glb_config.wrd, (priv->glb_base_addr + + GLOBAL_GLOBAL_CONFIG_OFFSET)); + + mdelay(20); + + /* should do a external reset */ + glb_config.wrd = CA_REG_READ((priv->glb_base_addr + + GLOBAL_GLOBAL_CONFIG_OFFSET)); + glb_config.bf.ext_reset = 0x0; + CA_REG_WRITE(glb_config.wrd, (priv->glb_base_addr + + GLOBAL_GLOBAL_CONFIG_OFFSET)); + + io_drive_control.wrd = + CA_REG_READ((priv->glb_base_addr + + GLOBAL_IO_DRIVE_CONTROL_OFFSET)); + io_drive_control.bf.gmac_mode = 2; + io_drive_control.bf.gmac_dn = 1; + io_drive_control.bf.gmac_dp = 1; + CA_REG_WRITE(io_drive_control.wrd, (priv->glb_base_addr + + GLOBAL_IO_DRIVE_CONTROL_OFFSET)); + } + + /* initialize LEDs for ethernet link and traffic lights */ + //ca77xx_init_led(); + + /* do internal gphy calibration */ + do_internal_gphy_cal(); +#endif + return 0; +} + +#if CORTINA_NI_DBG +DECLARE_GLOBAL_DATA_PTR; +int do_eth_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + bd_t *bd = gd->bd; + + cortina_ni_init(0x00, bd); + 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(cmd_tbl_t *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(cmd_tbl_t *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(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + unsigned int phy_adr; + unsigned int reg_off; + ca_uint16_t 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(cmd_tbl_t *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(cmd_tbl_t *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, " + "ret = %d\n", phy_addr, reg, val, ret); + } + } + return 0; +} + +U_BOOT_CMD(phy_reg, 4, 1, do_phy_reg, + "read/write PHY register", + "[PHY addr] [reg_valueaddr] ([value])\n" + "PHY addr : 0-31\n"); + +#ifdef CONFIG_MK_CUSTOMB +/* code custom switch register access function here */ +#endif + +#ifdef CONFIG_DM_ETH +static int cortina_eth_start(struct udevice *dev) +{ + return cortina_ni_init(dev); +} + +int cortina_eth_send(struct udevice *dev, void *packet, int length) +{ + return cortina_ni_send(dev, packet, length); +} + +int cortina_eth_recv(struct udevice *dev, int flags, uchar **packetp) +{ + return cortina_ni_recv(dev); +} + +void cortina_eth_stop(struct udevice *dev) +{ + cortina_ni_halt(dev); +} + +static int cortina_eth_probe(struct udevice *dev) +{ + return ca77xx_eth_initialize(dev); +} + +static int ca_ni_ofdata_to_platdata(struct udevice *dev) +{ + struct cortina_ni_priv *priv = dev_get_priv(dev); + + priv->glb_base_addr = dev_remap_addr_index(dev, 0); + if (!priv->glb_base_addr) + return -ENOENT; + printf("%s: priv->glb_base_addr for index 0 is 0x%p\n", + __func__, priv->glb_base_addr); + + priv->per_mdio_base_addr = dev_remap_addr_index(dev, 1); + if (!priv->per_mdio_base_addr) + return -ENOENT; + printf("%s: priv->per_mdio_base_addr for index 1 is 0x%p\n", + __func__, priv->per_mdio_base_addr); + + priv->ni_hv_base_addr = dev_remap_addr_index(dev, 2); + if (!priv->ni_hv_base_addr) + return -ENOENT; + printf("%s: priv->ni_hv_base_addr for index 2 is 0x%p\n", + __func__, priv->ni_hv_base_addr); + + return 0; +} + +static const struct eth_ops cortina_eth_ops = { + .start = cortina_eth_start, + .send = cortina_eth_send, + .recv = cortina_eth_recv, + .stop = cortina_eth_stop, +}; + +static const struct udevice_id cortina_eth_ids[] = { + { .compatible = "eth_cortina" }, + { } +}; + +U_BOOT_DRIVER(eth_cortina) = { + .name = "eth_cortina", + .id = UCLASS_ETH, + .of_match = cortina_eth_ids, + .probe = cortina_eth_probe, + .ops = &cortina_eth_ops, + .priv_auto_alloc_size = sizeof(struct cortina_ni_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), + .ofdata_to_platdata = ca_ni_ofdata_to_platdata, +}; + +#endif diff --git a/drivers/net/cortina_ni.h b/drivers/net/cortina_ni.h new file mode 100644 index 0000000..ae04063 --- /dev/null +++ b/drivers/net/cortina_ni.h @@ -0,0 +1,626 @@ +/* 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 CS_SWAP32(x) ((((x) & 0xFF000000) >> 24) \ + | (((x) & 0xFF0000) >> 8) \ + | (((x) & 0xFF00) << 8) \ + | (((x) & 0xFF) << 24)) + +#ifdef CONFIG_MK_REFERENCEQ +#define CONFIG_CS75XX_PHY_ADDR_GMAC0 4 +#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 + +typedef unsigned long ca_uint; +typedef unsigned int ca_uint32_t; +typedef unsigned short ca_uint16_t; +typedef ca_uint32_t ca_uint32; + +typedef enum { + 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, +} ca_status_t; + +#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 +}; + +typedef volatile union { + struct { + ca_uint32 next_link : 10; /* bits 9: 0 */ + ca_uint32 bytes_valid : 4; /* bits 13:10 */ + ca_uint32 reserved : 16; /* bits 29:14 */ + ca_uint32 hdr_a : 1; /* bits 30:30 */ + ca_uint32 ownership : 1; /* bits 31:31 */ + } bf; + ca_uint32 wrd; +} NI_HEADER_X_T; + +typedef volatile union { + struct { + ca_uint32 packet_size : 14; /* bits 13:0 */ + ca_uint32 byte_valid : 4; /* bits 17:14 */ + ca_uint32 pfc : 1; /* bits 18:18 */ + ca_uint32 valid : 1; /* bits 19:19 */ + ca_uint32 drop : 1; /* bits 20:20 */ + ca_uint32 runt : 1; /* bits 21:21 */ + ca_uint32 oversize : 1; /* bits 22:22 */ + ca_uint32 jumbo : 1; /* bits 23:23 */ + ca_uint32 link_status : 1; /* bits 24:24 */ + ca_uint32 jabber : 1; /* bits 25:25 */ + ca_uint32 crc_error : 1; /* bits 26:26 */ + ca_uint32 pause : 1; /* bits 27:27 */ + ca_uint32 oam : 1; /* bits 28:28 */ + ca_uint32 unknown_opcode : 1; /* bits 29:29 */ + ca_uint32 multicast : 1; /* bits 30:30 */ + ca_uint32 broadcast : 1; /* bits 31:31 */ + } bf; + ca_uint32 wrd; +} NI_PACKET_STATUS_T; + +#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 + +typedef volatile union { + struct { + ca_uint32 reserved : 2; /* bits 1:0 */ + ca_uint32 reg_off : 5; /* bits 6:2 */ + ca_uint32 phy_addr : 5; /* bits 11:7 */ + ca_uint32 reg_base : 20; /* bits 31:12 */ + } bf; + ca_uint32 wrd; +} NI_MDIO_OPER_T; + +#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) + +#define __MDIO_ADDR_CHK(addr) do { \ + if ((addr) < CA_MDIO_ADDR_MIN || \ + (addr) > CA_MDIO_ADDR_MAX) { \ + return CA_E_PARAM; \ + } \ +} while (0) + +#define CA_ASSERT(x) do { \ + if (!(x)) \ + return CA_E_PARAM; \ +} while (0) + +#endif /* !__ASSEMBLER__ */ + +/* Copy from registers.h */ +typedef volatile union { + struct { + ca_uint32_t mac_addr0 : 32; /* bits 31:0 */ + } bf; + ca_uint32_t wrd; +} NI_HV_GLB_MAC_ADDR_CFG0_t; + +typedef volatile union { + struct { + ca_uint32_t mac_addr1 : 8; /* bits 7:0 */ + ca_uint32_t rsrvd1 : 24; + } bf; + ca_uint32_t wrd; +} NI_HV_GLB_MAC_ADDR_CFG1_t; + +typedef volatile union { + struct { + ca_uint32_t int_cfg : 4; /* bits 3:0 */ + ca_uint32_t phy_mode : 1; /* bits 4:4 */ + ca_uint32_t rmii_clksrc : 1; /* bits 5:5 */ + ca_uint32_t inv_clk_in : 1; /* bits 6:6 */ + ca_uint32_t inv_clk_out : 1; /* bits 7:7 */ + ca_uint32_t inv_rxclk_out : 1; /* bits 8:8 */ + ca_uint32_t tx_use_gefifo : 1; /* bits 9:9 */ + ca_uint32_t smii_tx_stat : 1; /* bits 10:10 */ + ca_uint32_t crs_polarity : 1; /* bits 11:11 */ + ca_uint32_t lpbk_mode : 2; /* bits 13:12 */ + ca_uint32_t gmii_like_half_duplex_en : 1; /* bits 14:14 */ + ca_uint32_t sup_tx_to_rx_lpbk_data : 1; /* bits 15:15 */ + ca_uint32_t rsrvd1 : 8; + ca_uint32_t mac_addr6 : 8; /* bits 31:24 */ + } bf; + ca_uint32_t wrd; +} NI_HV_PT_PORT_STATIC_CFG_t; + +typedef volatile union { + struct { + ca_uint32_t rx_0_cpu_pkt_dis : 1; /* bits 0:0 */ + ca_uint32_t rsrvd1 : 8; + ca_uint32_t tx_0_cpu_pkt_dis : 1; /* bits 9:9 */ + ca_uint32_t rsrvd2 : 1; + ca_uint32_t rx_x_drop_err_pkt : 1; /* bits 11:11 */ + ca_uint32_t xram_mgmt_dis_drop_ovsz_pkt : 1; /* bits 12:12 */ + ca_uint32_t xram_mgmt_term_large_pkt : 1; /* bits 13:13 */ + ca_uint32_t xram_mgmt_promisc_mode : 2; /* bits 15:14 */ + ca_uint32_t xram_cntr_debug_mode : 1; /* bits 16:16 */ + ca_uint32_t xram_cntr_op_code : 2; /* bits 18:17 */ + ca_uint32_t rsrvd3 : 2; + ca_uint32_t xram_rx_mgmtfifo_srst : 1; /* bits 21:21 */ + ca_uint32_t xram_dma_fifo_srst : 1; /* bits 22:22 */ + ca_uint32_t rsrvd4 : 9; + } bf; + ca_uint32_t wrd; +} NI_HV_XRAM_CPUXRAM_CFG_t; + +typedef volatile union { + struct { + ca_uint32_t rx_en : 1; /* bits 0:0 */ + ca_uint32_t rsrvd1 : 7; + ca_uint32_t rx_flow_disable : 1; /* bits 8:8 */ + ca_uint32_t rsrvd2 : 3; + ca_uint32_t rx_flow_to_tx_en : 1; /* bits 12:12 */ + ca_uint32_t rx_pfc_disable : 1; /* bits 13:13 */ + ca_uint32_t rsrvd3 : 15; + ca_uint32_t send_pg_data : 1; /* bits 29:29 */ + ca_uint32_t rsrvd4 : 2; + } bf; + ca_uint32_t wrd; +} NI_HV_PT_RXMAC_CFG_t; + +typedef volatile union { + struct { + ca_uint32_t tx_en : 1; /* bits 0:0 */ + ca_uint32_t rsrvd1 : 7; + ca_uint32_t mac_crc_calc_en : 1; /* bits 8:8 */ + ca_uint32_t tx_ipg_sel : 3; /* bits 11:9 */ + ca_uint32_t tx_flow_disable : 1; /* bits 12:12 */ + ca_uint32_t tx_drain : 1; /* bits 13:13 */ + ca_uint32_t tx_pfc_disable : 1; /* bits 14:14 */ + ca_uint32_t tx_pau_sel : 2; /* bits 16:15 */ + ca_uint32_t rsrvd2 : 9; + ca_uint32_t tx_auto_xon : 1; /* bits 26:26 */ + ca_uint32_t rsrvd3 : 1; + ca_uint32_t pass_thru_hdr : 1; /* bits 28:28 */ + ca_uint32_t rsrvd4 : 3; + } bf; + ca_uint32_t wrd; +} NI_HV_PT_TXMAC_CFG_t; + +typedef volatile union { + struct { + ca_uint32_t intf_rst_p0 : 1; /* bits 0:0 */ + ca_uint32_t intf_rst_p1 : 1; /* bits 1:1 */ + ca_uint32_t intf_rst_p2 : 1; /* bits 2:2 */ + ca_uint32_t intf_rst_p3 : 1; /* bits 3:3 */ + ca_uint32_t intf_rst_p4 : 1; /* bits 4:4 */ + ca_uint32_t mac_rx_rst_p0 : 1; /* bits 5:5 */ + ca_uint32_t mac_rx_rst_p1 : 1; /* bits 6:6 */ + ca_uint32_t mac_rx_rst_p2 : 1; /* bits 7:7 */ + ca_uint32_t mac_rx_rst_p3 : 1; /* bits 8:8 */ + ca_uint32_t mac_rx_rst_p4 : 1; /* bits 9:9 */ + ca_uint32_t mac_tx_rst_p0 : 1; /* bits 10:10 */ + ca_uint32_t mac_tx_rst_p1 : 1; /* bits 11:11 */ + ca_uint32_t mac_tx_rst_p2 : 1; /* bits 12:12 */ + ca_uint32_t mac_tx_rst_p3 : 1; /* bits 13:13 */ + ca_uint32_t mac_tx_rst_p4 : 1; /* bits 14:14 */ + ca_uint32_t port_rst_p5 : 1; /* bits 15:15 */ + ca_uint32_t pcs_rst_p6 : 1; /* bits 16:16 */ + ca_uint32_t pcs_rst_p7 : 1; /* bits 17:17 */ + ca_uint32_t mac_rst_p6 : 1; /* bits 18:18 */ + ca_uint32_t mac_rst_p7 : 1; /* bits 19:19 */ + ca_uint32_t rsrvd1 : 12; + } bf; + ca_uint32_t wrd; +} NI_HV_GLB_INTF_RST_CONFIG_t; + +typedef volatile union { + struct { + ca_uint32_t port_to_cpu : 4; /* bits 3:0 */ + ca_uint32_t mgmt_pt_to_fe_also : 1; /* bits 4:4 */ + ca_uint32_t txcrc_chk_en : 1; /* bits 5:5 */ + ca_uint32_t p4_rgmii_tx_clk_phase : 2; /* bits 7:6 */ + ca_uint32_t p4_rgmii_tx_data_order : 1; /* bits 8:8 */ + ca_uint32_t rsrvd1 : 7; + ca_uint32_t rxmib_mode : 1; /* bits 16:16 */ + ca_uint32_t txmib_mode : 1; /* bits 17:17 */ + ca_uint32_t eth_sch_rdy_pkt : 1; /* bits 18:18 */ + ca_uint32_t rsrvd2 : 1; + ca_uint32_t rxaui_mode : 2; /* bits 21:20 */ + ca_uint32_t rxaui_sigdet : 2; /* bits 23:22 */ + ca_uint32_t cnt_op_mode : 3; /* bits 26:24 */ + ca_uint32_t rsrvd3 : 5; + } bf; + ca_uint32_t wrd; +} NI_HV_GLB_STATIC_CFG_t; + +typedef volatile union { + struct { + ca_uint32_t reset_ni : 1; /* bits 0:0 */ + ca_uint32_t reset_l2fe : 1; /* bits 1:1 */ + ca_uint32_t reset_l2tm : 1; /* bits 2:2 */ + ca_uint32_t reset_l3fe : 1; /* bits 3:3 */ + ca_uint32_t reset_sdram : 1; /* bits 4:4 */ + ca_uint32_t reset_tqm : 1; /* bits 5:5 */ + ca_uint32_t reset_pcie0 : 1; /* bits 6:6 */ + ca_uint32_t reset_pcie1 : 1; /* bits 7:7 */ + ca_uint32_t reset_pcie2 : 1; /* bits 8:8 */ + ca_uint32_t reset_sata : 1; /* bits 9:9 */ + ca_uint32_t reset_gic400 : 1; /* bits 10:10 */ + ca_uint32_t rsrvd1 : 2; + ca_uint32_t reset_usb : 1; /* bits 13:13 */ + ca_uint32_t reset_flash : 1; /* bits 14:14 */ + ca_uint32_t reset_per : 1; /* bits 15:15 */ + ca_uint32_t reset_dma : 1; /* bits 16:16 */ + ca_uint32_t reset_rtc : 1; /* bits 17:17 */ + ca_uint32_t reset_pe0 : 1; /* bits 18:18 */ + ca_uint32_t reset_pe1 : 1; /* bits 19:19 */ + ca_uint32_t reset_rcpu0 : 1; /* bits 20:20 */ + ca_uint32_t reset_rcpu1 : 1; /* bits 21:21 */ + ca_uint32_t reset_sadb : 1; /* bits 22:22 */ + ca_uint32_t rsrvd2 : 1; + ca_uint32_t reset_rcrypto : 1; /* bits 24:24 */ + ca_uint32_t reset_ldma : 1; /* bits 25:25 */ + ca_uint32_t reset_fbm : 1; /* bits 26:26 */ + ca_uint32_t reset_eaxi : 1; /* bits 27:27 */ + ca_uint32_t reset_sd : 1; /* bits 28:28 */ + ca_uint32_t reset_otprom : 1; /* bits 29:29 */ + ca_uint32_t rsrvd3 : 2; + } bf; + ca_uint32_t wrd; +} GLOBAL_BLOCK_RESET_t; + +typedef volatile union { + struct { + ca_uint32_t mdio_addr : 5; /* bits 4:0 */ + ca_uint32_t rsrvd1 : 3; + ca_uint32_t mdio_offset : 5; /* bits 12:8 */ + ca_uint32_t rsrvd2 : 2; + ca_uint32_t mdio_rd_wr : 1; /* bits 15:15 */ + ca_uint32_t mdio_st : 1; /* bits 16:16 */ + ca_uint32_t rsrvd3 : 1; + ca_uint32_t mdio_op : 2; /* bits 19:18 */ + ca_uint32_t rsrvd4 : 12; + } bf; + ca_uint32_t wrd; +} PER_MDIO_ADDR_t; + +typedef volatile union { + struct { + ca_uint32_t mdiodone : 1; /* bits 0:0 */ + ca_uint32_t rsrvd1 : 6; + ca_uint32_t mdiostart : 1; /* bits 7:7 */ + ca_uint32_t rsrvd2 : 24; + } bf; + ca_uint32_t wrd; +} PER_MDIO_CTRL_t; + +typedef volatile union { + struct { + ca_uint32_t mdio_rddata : 16; /* bits 15:0 */ + ca_uint32_t rsrvd1 : 16; + } bf; + ca_uint32_t wrd; +} PER_MDIO_RDDATA_t; + +/* + * XRAM + */ + +typedef volatile union { + struct { + ca_uint32_t rx_base_addr : 10; /* bits 9:0 */ + ca_uint32_t rsrvd1 : 6; + ca_uint32_t rx_top_addr : 10; /* bits 25:16 */ + ca_uint32_t rsrvd2 : 6; + } bf; + ca_uint32_t wrd; +} NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t; + +typedef volatile union { + struct { + ca_uint32_t tx_base_addr : 10; /* bits 9:0 */ + ca_uint32_t rsrvd1 : 6; + ca_uint32_t tx_top_addr : 10; /* bits 25:16 */ + ca_uint32_t rsrvd2 : 6; + } bf; + ca_uint32_t wrd; +} NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t; + +typedef volatile union { + struct { + ca_uint32_t pkt_wr_ptr : 10; /* bits 9:0 */ + ca_uint32_t rsrvd1 : 5; + ca_uint32_t int_colsc_thresh_reached : 1; /* bits 15:15 */ + ca_uint32_t rsrvd2 : 16; + } bf; + ca_uint32_t wrd; +} NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t; + +typedef volatile union { + struct { + ca_uint32_t pkt_rd_ptr : 10; /* bits 9:0 */ + ca_uint32_t rsrvd1 : 22; + } bf; + ca_uint32_t wrd; +} NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t; + +typedef volatile union { + struct { + ca_uint32_t pkt_wr_ptr : 10; /* bits 9:0 */ + ca_uint32_t rsrvd1 : 22; + } bf; + ca_uint32_t wrd; +} NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t; + +typedef volatile union { + struct { + ca_uint32_t rsrvd1 : 4; + ca_uint32_t wd_reset_subsys_enable : 1; /* bits 4:4 */ + ca_uint32_t rsrvd2 : 1; + ca_uint32_t wd_reset_all_blocks : 1; /* bits 6:6 */ + ca_uint32_t wd_reset_remap : 1; /* bits 7:7 */ + ca_uint32_t wd_reset_ext_reset : 1; /* bits 8:8 */ + ca_uint32_t ext_reset : 1; /* bits 9:9 */ + ca_uint32_t cfg_pcie_0_clken : 1; /* bits 10:10 */ + ca_uint32_t cfg_sata_clken : 1; /* bits 11:11 */ + ca_uint32_t cfg_pcie_1_clken : 1; /* bits 12:12 */ + ca_uint32_t rsrvd3 : 1; + ca_uint32_t cfg_pcie_2_clken : 1; /* bits 14:14 */ + ca_uint32_t rsrvd4 : 2; + ca_uint32_t ext_eth_refclk : 1; /* bits 17:17 */ + ca_uint32_t refclk_sel : 2; /* bits 19:18 */ + ca_uint32_t rsrvd5 : 7; + ca_uint32_t l3fe_pd : 1; /* bits 27:27 */ + ca_uint32_t offload0_pd : 1; /* bits 28:28 */ + ca_uint32_t offload1_pd : 1; /* bits 29:29 */ + ca_uint32_t crypto_pd : 1; /* bits 30:30 */ + ca_uint32_t core_pd : 1; /* bits 31:31 */ + } bf; + ca_uint32_t wrd; +} GLOBAL_GLOBAL_CONFIG_t; + +typedef volatile union { + struct { + ca_uint32_t gmac_dp : 3; /* bits 2:0 */ + ca_uint32_t gmac_dn : 3; /* bits 5:3 */ + ca_uint32_t gmac_mode : 2; /* bits 7:6 */ + ca_uint32_t gmac_ds : 1; /* bits 8:8 */ + ca_uint32_t flash_ds : 1; /* bits 9:9 */ + ca_uint32_t nu_ds : 1; /* bits 10:10 */ + ca_uint32_t ssp_ds : 1; /* bits 11:11 */ + ca_uint32_t spi_ds : 1; /* bits 12:12 */ + ca_uint32_t gpio_ds : 1; /* bits 13:13 */ + ca_uint32_t misc_ds : 1; /* bits 14:14 */ + ca_uint32_t eaxi_ds : 1; /* bits 15:15 */ + ca_uint32_t sd_ds : 8; /* bits 23:16 */ + ca_uint32_t rsrvd1 : 8; + } bf; + ca_uint32_t wrd; +} GLOBAL_IO_DRIVE_CONTROL_t; + +typedef volatile union { + struct { + ca_uint32_t rsrvd1 : 1; + ca_uint32_t ni_init_done : 1; /* bits 1:1 */ + ca_uint32_t rsrvd2 : 30; + } bf; + ca_uint32_t wrd; +} NI_HV_GLB_INIT_DONE_t; + +typedef volatile union { + struct { + ca_uint32_t mdio_wrdata : 16; /* bits 15:0 */ + ca_uint32_t rsrvd1 : 16; + } bf; + ca_uint32_t wrd; +} PER_MDIO_WRDATA_t; + +typedef volatile union { + struct { + ca_uint32_t speed : 1; /* bits 0:0 */ + ca_uint32_t duplex : 1; /* bits 1:1 */ + ca_uint32_t link_status : 1; /* bits 2:2 */ + ca_uint32_t link_stat_mask : 1; /* bits 3:3 */ + ca_uint32_t rsrvd1 : 7; + ca_uint32_t power_dwn_rx : 1; /* bits 11:11 */ + ca_uint32_t power_dwn_tx : 1; /* bits 12:12 */ + ca_uint32_t tx_intf_lp_time : 1; /* bits 13:13 */ + ca_uint32_t rsrvd2 : 18; + } bf; + ca_uint32_t wrd; +} NI_HV_PT_PORT_GLB_CFG_t; + +#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 */ From patchwork Wed Apr 29 23:58:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Nemirovsky X-Patchwork-Id: 238915 List-Id: U-Boot discussion From: alex.nemirovsky at cortina-access.com (Alex Nemirovsky) Date: Wed, 29 Apr 2020 16:58:26 -0700 Subject: [PATCH 2/2] board: presidio-asic: Add CAxxxx Ethernet support In-Reply-To: <1588204706-20237-1-git-send-email-alex.nemirovsky@cortina-access.com> References: <1588204706-20237-1-git-send-email-alex.nemirovsky@cortina-access.com> Message-ID: <1588204706-20237-2-git-send-email-alex.nemirovsky@cortina-access.com> Add CAxxxx Ethernet support for the Cortina Access Presidio Engineering Board Signed-off-by: Alex Nemirovsky Cc: Joe Hershberger Cc: Tom Rini --- arch/arm/dts/ca-presidio-engboard.dts | 7 +++++++ board/cortina/presidio-asic/presidio.c | 21 +++++++++++++++++++++ configs/cortina_presidio-asic-emmc_defconfig | 4 +++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/arch/arm/dts/ca-presidio-engboard.dts b/arch/arm/dts/ca-presidio-engboard.dts index c03dacc..78eb542 100644 --- a/arch/arm/dts/ca-presidio-engboard.dts +++ b/arch/arm/dts/ca-presidio-engboard.dts @@ -19,6 +19,13 @@ io_drv_ctrl = <0xf432004c>; }; + eth: ethnet at 0xf4300000 { + compatible = "eth_cortina"; + reg = <0x0 0xf4320000 0x34>, + <0x0 0xf43290d8 0x04>, + <0x0 0xf4304000 0x04>; + }; + gpio0: gpio-controller at 0xf4329280 { compatible = "cortina,ca-gpio"; reg = <0x0 0xf4329280 0x24>; diff --git a/board/cortina/presidio-asic/presidio.c b/board/cortina/presidio-asic/presidio.c index b4fa01f..881845d 100644 --- a/board/cortina/presidio-asic/presidio.c +++ b/board/cortina/presidio-asic/presidio.c @@ -103,6 +103,27 @@ int board_init(void) return 0; } +#ifndef CONFIG_DM_ETH +/* + * Board specific ethernet initialization routine. + */ +int ca77xx_eth_initialize(bd_t *bis); +int board_eth_init(bd_t *bis) +{ + int rc = 0; + unsigned int reg_data; + + ca77xx_eth_initialize(bis); + + // Power down GMAC4 TX/RX clock for EMI issue + reg_data = readl(0xf4304684); + reg_data |= (3 << 11); + writel(reg_data, 0xf4304684); + + return rc; +} +#endif + int dram_init(void) { unsigned int ddr_size; diff --git a/configs/cortina_presidio-asic-emmc_defconfig b/configs/cortina_presidio-asic-emmc_defconfig index e10008a..360ebeb 100644 --- a/configs/cortina_presidio-asic-emmc_defconfig +++ b/configs/cortina_presidio-asic-emmc_defconfig @@ -21,12 +21,14 @@ CONFIG_CMD_EXT4=y CONFIG_OF_CONTROL=y CONFIG_OF_LIVE=y CONFIG_DEFAULT_DEVICE_TREE="ca-presidio-engboard" -# CONFIG_NET is not set CONFIG_DM=y CONFIG_CORTINA_GPIO=y CONFIG_DM_MMC=y CONFIG_MMC_DW=y CONFIG_MMC_DW_CORTINA=y +CONFIG_PHYLIB=y +CONFIG_DM_ETH=y +CONFIG_CORTINA_NI_ENET=y CONFIG_DM_SERIAL=y CONFIG_CORTINA_UART=y CONFIG_WDT=y