U-Boot
Threads by month
- ----- 2025 -----
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2000 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
June 2020
- 213 participants
- 765 discussions
The previous version of the get_rate helper does not work if the mux
clock parent is changed after the probe. This error has not been
detected because this condition has not been tested. The error occurs
because the set_parent helper does not change the parent of the clock
device but only the clock selection register. Since changing the parent
of a probed device can be tricky, the new version of the get_rate helper
provides the rate of the selected clock and not that of the parent.
Signed-off-by: Dario Binacchi <dariobin(a)libero.it>
---
drivers/clk/clk-mux.c | 26 +++++++++++++++++++++++++-
test/dm/clk_ccf.c | 24 ++++++++++++++++++++++++
2 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 8f85e84ae9..1f2dab647f 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -152,8 +152,32 @@ static int clk_mux_set_parent(struct clk *clk, struct clk *parent)
return 0;
}
+static ulong clk_mux_get_rate(struct clk *clk)
+{
+ struct clk_mux *mux = to_clk_mux(clk_dev_binded(clk) ?
+ dev_get_clk_ptr(clk->dev) : clk);
+ struct udevice *parent;
+ struct clk *pclk;
+ int err, index;
+
+ index = clk_mux_get_parent(clk);
+ if (index >= mux->num_parents)
+ return -EFAULT;
+
+ err = uclass_get_device_by_name(UCLASS_CLK, mux->parent_names[index],
+ &parent);
+ if (err)
+ return err;
+
+ pclk = dev_get_clk_ptr(parent);
+ if (!pclk)
+ return -ENODEV;
+
+ return clk_get_rate(pclk);
+}
+
const struct clk_ops clk_mux_ops = {
- .get_rate = clk_generic_get_rate,
+ .get_rate = clk_mux_get_rate,
.set_parent = clk_mux_set_parent,
};
diff --git a/test/dm/clk_ccf.c b/test/dm/clk_ccf.c
index ae3a4d8a76..bf99776ac1 100644
--- a/test/dm/clk_ccf.c
+++ b/test/dm/clk_ccf.c
@@ -46,6 +46,18 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
rate = clk_get_parent_rate(clk);
ut_asserteq(rate, 60000000);
+ rate = clk_get_rate(clk);
+ ut_asserteq(rate, 60000000);
+
+ ret = clk_get_by_id(SANDBOX_CLK_PLL3_80M, &pclk);
+ ut_assertok(ret);
+
+ ret = clk_set_parent(clk, pclk);
+ ut_assertok(ret);
+
+ rate = clk_get_rate(clk);
+ ut_asserteq(rate, 80000000);
+
ret = clk_get_by_id(SANDBOX_CLK_USDHC2_SEL, &clk);
ut_assertok(ret);
ut_asserteq_str("usdhc2_sel", clk->dev->name);
@@ -56,6 +68,18 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
pclk = clk_get_parent(clk);
ut_asserteq_str("pll3_80m", pclk->dev->name);
+ rate = clk_get_rate(clk);
+ ut_asserteq(rate, 80000000);
+
+ ret = clk_get_by_id(SANDBOX_CLK_PLL3_60M, &pclk);
+ ut_assertok(ret);
+
+ ret = clk_set_parent(clk, pclk);
+ ut_assertok(ret);
+
+ rate = clk_get_rate(clk);
+ ut_asserteq(rate, 60000000);
+
/* Test the composite of CCF */
ret = clk_get_by_id(SANDBOX_CLK_I2C, &clk);
ut_assertok(ret);
--
2.17.1
1
0

03 Jun '20
Hello Simon,
We are adding support for Xen [1] para-virtualized block device as a u-boot driver and have some questions with respect to driver model and instantiation of new devices.
Because of the nature of the device driver we cannot use device tree or define statically the device instances beforehand and those get known during some device enumeration.
So, this makes us bind the new devices to the driver at run-time. For that we use:
(init)
device_bind_by_name(gd->dm_root, false, &info, &udev);
...
ret = uclass_get(UCLASS_BLK, &uc);
if (ret) {
printk("UCLASS_BLK class has no registered entities\n");
return;
}
uclass_foreach_dev(udev, uc) {
ret = device_probe(udev);
if (ret < 0)
printk("Failed to probe " DRV_NAME " device\n");
}
...
(probe)
struct blkfront_platdata *platdata = dev_get_platdata(udev);
struct blkfront_dev *blk_dev = dev_get_priv(udev);
struct blk_desc *desc = dev_get_uclass_platdata(udev);
We create a device with [IF_TYPE_PVBLOCK] = "pvblock" (UCLASS_BLK) typename and UCLASS. Everything goes smooth, driver's probe is called, but the problem we are seeing is that when we call "part list pvblock 0" command with the device description and udev's parent not set or set to gd->dm_root then we see <** Bad device pvblock 0 **> from blk_get_device_by_str function.
Digging into the code shows that there is a check (equality of block device's interface type and the uclass of the block device's parent) in blk_get_devnum_by_typename function in drivers/blk-uclass.c file, which makes us think that we should somehow set our parent to UCLASS_BLK or something. At the same time setting udev to udev->parent makes things work, but it doesn't seem to be correct. (For example, "pvblock part 0" command works properly, because it doesn't use blk_get_devnum_by_typename.)
1. What is the right procedure to bind a device to a driver in such cases as ours? Can we still use what we have? (Is it okay to use device_bind_by_name function in init stage?)
2. How can we become a child of UCLASS_BLK or any other entity, so we are recognized by the framework properly? (Do we need to create child from our udev device in probe stage by using blk_create_devicef function?)
3. Why parent's and device's U_CLASS must be the same? For what cases this check has been implemented?
4. According to blk uclass implementation is it okay to have parent with UCLASS_ROOT for block device? If no, then what parent should we assign?
[1] - https://xenproject.org/
Regards,
ANASTASIIA LUKIANENKO
Software Engineer
Office: +380 44 390 5457xx39470<tel:+380%2044%20390%205457;ext=x39470> Cell: +380 93 080 6457<tel:+380%2093%20080%206457> Email: anastasiia_lukianenko(a)epam.com<mailto:Anastasiia_Lukianenko@epam.com>
Kyiv, Ukraine epam.com<http://www.epam.com>
CONFIDENTIALITY CAUTION AND DISCLAIMER
This message is intended only for the use of the individual(s) or entity(ies) to which it is addressed and contains information that is legally privileged and confidential. If you are not the intended recipient, or the person responsible for delivering the message to the intended recipient, you are hereby notified that any dissemination, distribution or copying of this communication is strictly prohibited. All unintended recipients are obliged to delete this message and destroy any printed copies.
1
0

03 Jun '20
From: Hou Zhiqiang <Zhiqiang.Hou(a)nxp.com>
Rebased the patch set below, and fixed build warning on ls1046a by
removing SPL_DM_SPI from target ls1046 boards.
https://patchwork.ozlabs.org/project/uboot/list/?series=129069&archive=both…
Lukasz Majewski (3):
spi: Move DM_SPI_FLASH to Kconfig (for NXP's ls1043a)
spi: Move DM_SPI_FLASH and SPI_FLASH_DATAFLASH to Kconfig (for
ls1021aXXX)
spi: Convert CONFIG_DM_SPI* to CONFIG_$(SPL_TPL_)DM_SPI*
arch/arm/Kconfig | 21 +++++++++++++++++++--
board/l+g/vinco/vinco.c | 4 ++--
cmd/sf.c | 4 ++--
cmd/spi.c | 6 +++---
common/spl/Kconfig | 20 ++++++++++++++++++++
configs/am57xx_evm_defconfig | 2 ++
configs/am57xx_hs_evm_defconfig | 2 ++
configs/am57xx_hs_evm_usb_defconfig | 2 ++
configs/axm_defconfig | 2 ++
configs/chromebook_link64_defconfig | 2 ++
configs/chromebook_samus_tpl_defconfig | 4 ++++
configs/dra7xx_evm_defconfig | 2 ++
configs/dra7xx_hs_evm_defconfig | 2 ++
configs/dra7xx_hs_evm_usb_defconfig | 2 ++
configs/j721e_evm_a72_defconfig | 2 ++
configs/j721e_evm_r5_defconfig | 2 ++
configs/ls1021aiot_qspi_defconfig | 2 ++
configs/ls1021aiot_sdcard_defconfig | 2 ++
configs/ls1021aqds_qspi_defconfig | 1 +
configs/ls1021aqds_sdcard_qspi_defconfig | 1 +
configs/ls1021atwr_qspi_defconfig | 1 +
configs/sama5d2_xplained_spiflash_defconfig | 2 ++
configs/sama5d3xek_spiflash_defconfig | 7 ++++---
configs/sama5d4_xplained_spiflash_defconfig | 2 ++
configs/sama5d4ek_spiflash_defconfig | 2 ++
configs/stm32mp15_basic_defconfig | 2 ++
configs/taurus_defconfig | 2 ++
drivers/mtd/spi/Makefile | 4 ++--
drivers/mtd/spi/sf_probe.c | 2 +-
drivers/net/fm/fm.c | 4 ++--
drivers/spi/Makefile | 2 +-
drivers/spi/atmel_spi.c | 4 ++--
drivers/spi/davinci_spi.c | 6 +++---
drivers/spi/fsl_dspi.c | 5 +++--
drivers/spi/kirkwood_spi.c | 2 +-
drivers/spi/mxc_spi.c | 6 +++---
drivers/spi/omap3_spi.c | 4 ++--
drivers/spi/sh_qspi.c | 4 ++--
env/sf.c | 2 +-
include/configs/ls1021aiot.h | 6 ------
include/configs/ls1021aqds.h | 5 -----
include/configs/ls1021atwr.h | 5 -----
include/configs/ls1043a_common.h | 2 --
include/spi.h | 8 ++++----
include/spi_flash.h | 2 +-
test/dm/spi.c | 2 +-
46 files changed, 120 insertions(+), 58 deletions(-)
--
2.17.1
6
14
Hello, I am using 1042rdb to have graphical output from E9171.
For ATI GPU's, these steps are setting a gpu environment for U-boot
include/configs/T104xRDB.h
+/* Video */
+#define CONFIG_VIDEO
+#define VIDEO_IO_OFFSET
+#if defined(CONFIG_VIDEO)
+#define CONFIG_BIOSEMU
+#define CONFIG_CFB_CONSOLE
+#define CONFIG_VIDEO_SW_CURSOR
+#define CONFIG_VGA_AS_SINGLE_DEVICE
+#define CONFIG_ATI_RADEON_FB
+#define CONFIG_VIDEO_LOGO
+#endif
Does adding CONFIG_ATI_RADEON_FB also supports AMD E9171 GPU ? If not, is
there any other way to have amg gpu support for U-boot ? Thanks.
1
0

[PATCH v3 1/2] net: cortina_ni: Add eth support for Cortina Access CAxxxx SoCs
by Alex Nemirovsky 03 Jun '20
by Alex Nemirovsky 03 Jun '20
03 Jun '20
From: Aaron Tseng <aaron.tseng(a)cortina-access.com>
Add Cortina Access Ethernet device driver for CAxxxx SoCs.
This driver supports only the DM_ETH network model.
Signed-off-by: Aaron Tseng <aaron.tseng(a)cortina-access.com>
Signed-off-by: Alex Nemirovsky <alex.nemirovsky(a)cortina-access.com>
CC: Joe Hershberger <joe.hershberger(a)ni.com>
CC: Abbie Chang <abbie.chang(a)Cortina-Access.com>
CC: Tom Rini <trini(a)konsulko.com>
---
Changes in v3:
- Changed commit comment to state that only DM model is supported
- Removed blank line at end of C file
Changes in v2:
- Remove legacy mode support
- Add support for additional SoC variants
- Remove unused variables
MAINTAINERS | 4 +
drivers/net/Kconfig | 7 +
drivers/net/Makefile | 1 +
drivers/net/cortina_ni.c | 1909 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/cortina_ni.h | 592 ++++++++++++++
5 files changed, 2513 insertions(+)
create mode 100644 drivers/net/cortina_ni.c
create mode 100644 drivers/net/cortina_ni.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 8add9d4..1b166d2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -181,6 +181,8 @@ F: drivers/gpio/cortina_gpio.c
F: drivers/watchdog/cortina_wdt.c
F: drivers/serial/serial_cortina.c
F: drivers/mmc/ca_dw_mmc.c
+F: drivers/net/cortina_ni.c
+F: drivers/net/cortina_ni.h
ARM/CZ.NIC TURRIS MOX SUPPORT
M: Marek Behun <marek.behun(a)nic.cz>
@@ -732,6 +734,8 @@ F: drivers/gpio/cortina_gpio.c
F: drivers/watchdog/cortina_wdt.c
F: drivers/serial/serial_cortina.c
F: drivers/mmc/ca_dw_mmc.c
+F: drivers/net/cortina_ni.c
+F: drivers/net/cortina_ni.h
MIPS MSCC
M: Gregory CLEMENT <gregory.clement(a)bootlin.com>
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index f7855c9..45e0480 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -149,6 +149,13 @@ config BCMGENET
help
This driver supports the BCMGENET Ethernet MAC.
+config CORTINA_NI_ENET
+ bool "Cortina-Access Ethernet driver"
+ depends on DM_ETH && CORTINA_PLATFORM
+ help
+ The driver supports the Cortina-Access Ethernet MAC for
+ all supported CAxxxx SoCs
+
config DWC_ETH_QOS
bool "Synopsys DWC Ethernet QOS device support"
depends on DM_ETH
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 383ed1c..1d6ec4f 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
obj-$(CONFIG_BCM_SF2_ETH_GMAC) += bcm-sf2-eth-gmac.o
obj-$(CONFIG_CALXEDA_XGMAC) += calxedaxgmac.o
+obj-$(CONFIG_CORTINA_NI_ENET) += cortina_ni.o
obj-$(CONFIG_CS8900) += cs8900.o
obj-$(CONFIG_TULIP) += dc2114x.o
obj-$(CONFIG_ETH_DESIGNWARE) += designware.o
diff --git a/drivers/net/cortina_ni.c b/drivers/net/cortina_ni.c
new file mode 100644
index 0000000..d5bbf3e
--- /dev/null
+++ b/drivers/net/cortina_ni.c
@@ -0,0 +1,1909 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * Copyright (C) 2020 Cortina Access Inc.
+ * Author: Aaron Tseng <aaron.tseng(a)cortina-access.com>
+ *
+ * Ethernet MAC Driver for all supported CAxxxx SoCs
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+#include <env.h>
+#include <linux/delay.h>
+
+#include "cortina_ni.h"
+
+static u32 reg_value;
+
+/* port 0-3 are individual port connect to PHY directly */
+/* port 4-7 are LAN ports connected to QSGMII PHY */
+int active_port = NI_PORT_5; /* Physical port 5 */
+u32 ge_port_phy_addr; /* PHY address connected to active port */
+int auto_scan_active_port;
+
+#define HEADER_A_SIZE 8
+
+/*define CORTINA_NI_DBG if individual rx,tx,init needs to be called */
+#if CORTINA_NI_DBG
+static struct udevice *dbg_dev;
+#endif
+static struct udevice *curr_dev;
+
+#if defined(CONFIG_TARGET_SATURN_ASIC)
+#define CA_REG_READ(off) readl((u64)KSEG1_ATU_XLAT(off))
+#define CA_REG_WRITE(data, off) writel(data, (u64)KSEG1_ATU_XLAT(off))
+#else
+#define CA_REG_READ(off) readl((u64)off)
+#define CA_REG_WRITE(data, off) writel(data, (u64)off)
+#endif
+
+int cortina_ni_recv(struct udevice *netdev);
+static int ca_ni_ofdata_to_platdata(struct udevice *dev);
+
+static u32 *RDWRPTR_ADVANCE_ONE(u32 *x, unsigned long base, unsigned long max)
+{
+ 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 <aaron.tseng(a)cortina-access.com>
+ *
+ * Ethernet MAC Driver for all supported CAxxxx SoCs
+ */
+
+#ifndef __CORTINA_NI_H
+#define __CORTINA_NI_H
+
+#include <asm/types.h>
+#include <asm/io.h>
+#include <config.h>
+
+//#define CORTINA_NI_DBG 1
+
+#ifdef CS_BIG_ENDIAN
+#define CRCPOLY_BE 0x04c11db7
+#else /* CS_LITTLE_ENDIAN */
+#define CRCPOLY_LE 0xedb88320
+#endif
+
+#define GE_PORT0_PHY_ADDR CONFIG_NI_PHY_ADDR_GMAC0
+#define GE_PORT1_PHY_ADDR CONFIG_NI_PHY_ADDR_GMAC1
+#define GE_PORT2_PHY_ADDR CONFIG_NI_PHY_ADDR_GMAC2
+
+#define PHY_ID_RTL8201 0x001cc810
+#define PHY_ID_RTL8211 0x001cc910
+#define PHY_ID_RTL8214 0x001cc940
+#define PHY_ID_RTL8211_G3_ASIC 0x001cc980
+#define PHY_ID_RTL8211_SATURN_ASIC 0x001cc900
+#define PHY_ID_QCA8337 0x004dd035
+#define PHY_ID_MASK 0xFFFFFFF0
+
+#define GE_MAC_INTF_GMII 0x0
+#define GE_MAC_INTF_MII 0x1
+#define GE_MAC_INTF_RGMII_1000 0x2
+#define GE_MAC_INTF_RGMII_100 0x3
+#define GE_MAC_INTF_QSGMII_1000 0x4
+#define GE_MAC_INTF_RMII 0x5
+
+#define NI_TOP_NI_RTH_MAC_10M 1
+#define NI_TOP_NI_RTH_MAC_100M 0
+#define NI_TOP_NI_RTH_MAC_HALF 1
+#define NI_TOP_NI_RTH_MAC_FULL 0
+
+/* Defines the base and top address in CPU XRA
+ * for packets to cpu instance 0
+ * 0x300 * 8-byte = 6K-byte
+ */
+#define RX_TOP_ADDR 0x02FF
+#define RX_BASE_ADDR 0x0000
+
+/* Defines the base and top address in CPU XRAM
+ * for packets from cpu instance 0.
+ * 0x100 * 8-byte = 2K-byte
+ */
+#define TX_TOP_ADDR 0x03FF
+#define TX_BASE_ADDR 0x0300
+
+#define RX_0_CPU_PKT_DIS BIT(0)
+#define TX_0_CPU_PKT_DIS BIT(9)
+
+#define PHY_POLL_TIMES 0x200
+
+#define NI_XRAM_BASE 0xF4500000
+
+enum ca_status_t {
+ CA_E_ERROR = -1,
+ CA_E_OK = 0x0,
+ CA_E_RESOURCE = 0x1,
+ CA_E_PARAM = 0x2,
+ CA_E_NOT_FOUND = 0x3,
+ CA_E_CONFLICT = 0x4,
+ CA_E_TIMEOUT = 0x5,
+ CA_E_INTERNAL = 0x6,
+ CA_E_NOT_SUPPORT = 0x7,
+ CA_E_CONFIG = 0x8,
+ CA_E_UNAVAIL = 0x9,
+ CA_E_MEMORY = 0xa,
+ CA_E_BUSY = 0xb,
+ CA_E_FULL = 0xc,
+ CA_E_EMPTY = 0xd,
+ CA_E_EXISTS = 0xe,
+ CA_E_DEV = 0xf,
+ CA_E_PORT = 0x10,
+ CA_E_LLID = 0x11,
+ CA_E_VLAN = 0x12,
+ CA_E_INIT = 0x13,
+ CA_E_INTF = 0x14,
+ CA_E_NEXTHOP = 0x15,
+ CA_E_ROUTE = 0x16,
+ CA_E_DB_CHANGED = 0x17,
+ CA_E_INACTIVE = 0x18,
+ CA_E_ALREADY_SET = 0x19,
+};
+
+#ifndef CA_IN
+#define CA_IN
+#endif
+
+#ifndef CA_OUT
+#define CA_OUT
+#endif
+
+#if !defined(__ASSEMBLER__) && !defined(__ASSEMBLY__)
+struct cortina_ni_priv {
+ unsigned int rx_xram_base_adr;
+ unsigned int rx_xram_end_adr;
+ unsigned short rx_xram_start;
+ unsigned short rx_xram_end;
+ unsigned int tx_xram_base_adr;
+ unsigned int tx_xram_end_adr;
+ unsigned short tx_xram_start;
+ unsigned short tx_xram_end;
+#ifdef CONFIG_DM_ETH
+ void __iomem *glb_base_addr;
+ void __iomem *per_mdio_base_addr;
+ void __iomem *ni_hv_base_addr;
+#else
+ unsigned int glb_base_addr;
+ unsigned int per_mdio_base_addr;
+ unsigned int ni_hv_base_addr;
+#endif
+};
+
+union NI_HEADER_X_T {
+ struct {
+ unsigned int next_link : 10; /* bits 9: 0 */
+ unsigned int bytes_valid : 4; /* bits 13:10 */
+ unsigned int reserved : 16; /* bits 29:14 */
+ unsigned int hdr_a : 1; /* bits 30:30 */
+ unsigned int ownership : 1; /* bits 31:31 */
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_PACKET_STATUS {
+ struct {
+ unsigned int packet_size : 14; /* bits 13:0 */
+ unsigned int byte_valid : 4; /* bits 17:14 */
+ unsigned int pfc : 1; /* bits 18:18 */
+ unsigned int valid : 1; /* bits 19:19 */
+ unsigned int drop : 1; /* bits 20:20 */
+ unsigned int runt : 1; /* bits 21:21 */
+ unsigned int oversize : 1; /* bits 22:22 */
+ unsigned int jumbo : 1; /* bits 23:23 */
+ unsigned int link_status : 1; /* bits 24:24 */
+ unsigned int jabber : 1; /* bits 25:25 */
+ unsigned int crc_error : 1; /* bits 26:26 */
+ unsigned int pause : 1; /* bits 27:27 */
+ unsigned int oam : 1; /* bits 28:28 */
+ unsigned int unknown_opcode : 1; /* bits 29:29 */
+ unsigned int multicast : 1; /* bits 30:30 */
+ unsigned int broadcast : 1; /* bits 31:31 */
+ } bf;
+ unsigned int wrd;
+};
+
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || \
+ defined(CONFIG_TARGET_SATURN_ASIC) || defined(CONFIG_TARGET_VENUS)
+
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC)
+#define CA_NI_MDIO_REG_BASE 0xF4338
+#else
+
+#if defined(CONFIG_TARGET_VENUS)
+#define CA_NI_MDIO_REG_BASE 0xF4339
+#else
+#define CA_NI_MDIO_REG_BASE 0xD000B
+#endif
+
+#endif
+
+union NI_MDIO_OPER_T {
+ struct {
+ unsigned int reserved : 2; /* bits 1:0 */
+ unsigned int reg_off : 5; /* bits 6:2 */
+ unsigned int phy_addr : 5; /* bits 11:7 */
+ unsigned int reg_base : 20; /* bits 31:12 */
+ } bf;
+ unsigned int wrd;
+};
+
+#endif
+
+#define NI_PORT_0 0
+#define NI_PORT_1 1
+#define NI_PORT_2 2
+#define NI_PORT_3 3
+#define NI_PORT_4 4
+#define NI_PORT_5 5
+#define NI_PORT_6 6
+#define NI_PORT_7 7
+
+#if defined(CONFIG_TARGET_SATURN_ASIC)
+#define NI_READ_POLL_COUNT 1000000
+#else
+#define NI_READ_POLL_COUNT 1000
+#endif
+
+#define __MDIO_WR_FLAG (0)
+#define __MDIO_RD_FLAG (1)
+#define __MDIO_ACCESS_TIMEOUT (1000000)
+#define __MDIO_PER_CLK (62500)
+#define CA_MDIO_ADDR_MIN (1)
+#define CA_MDIO_ADDR_MAX (31)
+#define CA_MDIO_CLOCK_MIN (1)
+#define CA_MDIO_CLOCK_MAX (20000)
+
+#endif /* !__ASSEMBLER__ */
+
+/* Copy from registers.h */
+union NI_HV_GLB_MAC_ADDR_CFG0_t {
+ struct {
+ unsigned int mac_addr0 : 32; /* bits 31:0 */
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_GLB_MAC_ADDR_CFG1_t {
+ struct {
+ unsigned int mac_addr1 : 8; /* bits 7:0 */
+ unsigned int rsrvd1 : 24;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_PT_PORT_STATIC_CFG_t {
+ struct {
+ unsigned int int_cfg : 4; /* bits 3:0 */
+ unsigned int phy_mode : 1; /* bits 4:4 */
+ unsigned int rmii_clksrc : 1; /* bits 5:5 */
+ unsigned int inv_clk_in : 1; /* bits 6:6 */
+ unsigned int inv_clk_out : 1; /* bits 7:7 */
+ unsigned int inv_rxclk_out : 1; /* bits 8:8 */
+ unsigned int tx_use_gefifo : 1; /* bits 9:9 */
+ unsigned int smii_tx_stat : 1; /* bits 10:10 */
+ unsigned int crs_polarity : 1; /* bits 11:11 */
+ unsigned int lpbk_mode : 2; /* bits 13:12 */
+ unsigned int gmii_like_half_duplex_en : 1; /* bits 14:14 */
+ unsigned int sup_tx_to_rx_lpbk_data : 1; /* bits 15:15 */
+ unsigned int rsrvd1 : 8;
+ unsigned int mac_addr6 : 8; /* bits 31:24 */
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_XRAM_CPUXRAM_CFG_t {
+ struct {
+ unsigned int rx_0_cpu_pkt_dis : 1; /* bits 0:0 */
+ unsigned int rsrvd1 : 8;
+ unsigned int tx_0_cpu_pkt_dis : 1; /* bits 9:9 */
+ unsigned int rsrvd2 : 1;
+ unsigned int rx_x_drop_err_pkt : 1; /* bits 11:11 */
+ unsigned int xram_mgmt_dis_drop_ovsz_pkt : 1; /* bits 12:12 */
+ unsigned int xram_mgmt_term_large_pkt : 1; /* bits 13:13 */
+ unsigned int xram_mgmt_promisc_mode : 2; /* bits 15:14 */
+ unsigned int xram_cntr_debug_mode : 1; /* bits 16:16 */
+ unsigned int xram_cntr_op_code : 2; /* bits 18:17 */
+ unsigned int rsrvd3 : 2;
+ unsigned int xram_rx_mgmtfifo_srst : 1; /* bits 21:21 */
+ unsigned int xram_dma_fifo_srst : 1; /* bits 22:22 */
+ unsigned int rsrvd4 : 9;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_PT_RXMAC_CFG_t {
+ struct {
+ unsigned int rx_en : 1; /* bits 0:0 */
+ unsigned int rsrvd1 : 7;
+ unsigned int rx_flow_disable : 1; /* bits 8:8 */
+ unsigned int rsrvd2 : 3;
+ unsigned int rx_flow_to_tx_en : 1; /* bits 12:12 */
+ unsigned int rx_pfc_disable : 1; /* bits 13:13 */
+ unsigned int rsrvd3 : 15;
+ unsigned int send_pg_data : 1; /* bits 29:29 */
+ unsigned int rsrvd4 : 2;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_PT_TXMAC_CFG_t {
+ struct {
+ unsigned int tx_en : 1; /* bits 0:0 */
+ unsigned int rsrvd1 : 7;
+ unsigned int mac_crc_calc_en : 1; /* bits 8:8 */
+ unsigned int tx_ipg_sel : 3; /* bits 11:9 */
+ unsigned int tx_flow_disable : 1; /* bits 12:12 */
+ unsigned int tx_drain : 1; /* bits 13:13 */
+ unsigned int tx_pfc_disable : 1; /* bits 14:14 */
+ unsigned int tx_pau_sel : 2; /* bits 16:15 */
+ unsigned int rsrvd2 : 9;
+ unsigned int tx_auto_xon : 1; /* bits 26:26 */
+ unsigned int rsrvd3 : 1;
+ unsigned int pass_thru_hdr : 1; /* bits 28:28 */
+ unsigned int rsrvd4 : 3;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_GLB_INTF_RST_CONFIG_t {
+ struct {
+ unsigned int intf_rst_p0 : 1; /* bits 0:0 */
+ unsigned int intf_rst_p1 : 1; /* bits 1:1 */
+ unsigned int intf_rst_p2 : 1; /* bits 2:2 */
+ unsigned int intf_rst_p3 : 1; /* bits 3:3 */
+ unsigned int intf_rst_p4 : 1; /* bits 4:4 */
+ unsigned int mac_rx_rst_p0 : 1; /* bits 5:5 */
+ unsigned int mac_rx_rst_p1 : 1; /* bits 6:6 */
+ unsigned int mac_rx_rst_p2 : 1; /* bits 7:7 */
+ unsigned int mac_rx_rst_p3 : 1; /* bits 8:8 */
+ unsigned int mac_rx_rst_p4 : 1; /* bits 9:9 */
+ unsigned int mac_tx_rst_p0 : 1; /* bits 10:10 */
+ unsigned int mac_tx_rst_p1 : 1; /* bits 11:11 */
+ unsigned int mac_tx_rst_p2 : 1; /* bits 12:12 */
+ unsigned int mac_tx_rst_p3 : 1; /* bits 13:13 */
+ unsigned int mac_tx_rst_p4 : 1; /* bits 14:14 */
+ unsigned int port_rst_p5 : 1; /* bits 15:15 */
+ unsigned int pcs_rst_p6 : 1; /* bits 16:16 */
+ unsigned int pcs_rst_p7 : 1; /* bits 17:17 */
+ unsigned int mac_rst_p6 : 1; /* bits 18:18 */
+ unsigned int mac_rst_p7 : 1; /* bits 19:19 */
+ unsigned int rsrvd1 : 12;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_GLB_STATIC_CFG_t {
+ struct {
+ unsigned int port_to_cpu : 4; /* bits 3:0 */
+ unsigned int mgmt_pt_to_fe_also : 1; /* bits 4:4 */
+ unsigned int txcrc_chk_en : 1; /* bits 5:5 */
+ unsigned int p4_rgmii_tx_clk_phase : 2; /* bits 7:6 */
+ unsigned int p4_rgmii_tx_data_order : 1; /* bits 8:8 */
+ unsigned int rsrvd1 : 7;
+ unsigned int rxmib_mode : 1; /* bits 16:16 */
+ unsigned int txmib_mode : 1; /* bits 17:17 */
+ unsigned int eth_sch_rdy_pkt : 1; /* bits 18:18 */
+ unsigned int rsrvd2 : 1;
+ unsigned int rxaui_mode : 2; /* bits 21:20 */
+ unsigned int rxaui_sigdet : 2; /* bits 23:22 */
+ unsigned int cnt_op_mode : 3; /* bits 26:24 */
+ unsigned int rsrvd3 : 5;
+ } bf;
+ unsigned int wrd;
+};
+
+union GLOBAL_BLOCK_RESET_t {
+ struct {
+ unsigned int reset_ni : 1; /* bits 0:0 */
+ unsigned int reset_l2fe : 1; /* bits 1:1 */
+ unsigned int reset_l2tm : 1; /* bits 2:2 */
+ unsigned int reset_l3fe : 1; /* bits 3:3 */
+ unsigned int reset_sdram : 1; /* bits 4:4 */
+ unsigned int reset_tqm : 1; /* bits 5:5 */
+ unsigned int reset_pcie0 : 1; /* bits 6:6 */
+ unsigned int reset_pcie1 : 1; /* bits 7:7 */
+ unsigned int reset_pcie2 : 1; /* bits 8:8 */
+ unsigned int reset_sata : 1; /* bits 9:9 */
+ unsigned int reset_gic400 : 1; /* bits 10:10 */
+ unsigned int rsrvd1 : 2;
+ unsigned int reset_usb : 1; /* bits 13:13 */
+ unsigned int reset_flash : 1; /* bits 14:14 */
+ unsigned int reset_per : 1; /* bits 15:15 */
+ unsigned int reset_dma : 1; /* bits 16:16 */
+ unsigned int reset_rtc : 1; /* bits 17:17 */
+ unsigned int reset_pe0 : 1; /* bits 18:18 */
+ unsigned int reset_pe1 : 1; /* bits 19:19 */
+ unsigned int reset_rcpu0 : 1; /* bits 20:20 */
+ unsigned int reset_rcpu1 : 1; /* bits 21:21 */
+ unsigned int reset_sadb : 1; /* bits 22:22 */
+ unsigned int rsrvd2 : 1;
+ unsigned int reset_rcrypto : 1; /* bits 24:24 */
+ unsigned int reset_ldma : 1; /* bits 25:25 */
+ unsigned int reset_fbm : 1; /* bits 26:26 */
+ unsigned int reset_eaxi : 1; /* bits 27:27 */
+ unsigned int reset_sd : 1; /* bits 28:28 */
+ unsigned int reset_otprom : 1; /* bits 29:29 */
+ unsigned int rsrvd3 : 2;
+ } bf;
+ unsigned int wrd;
+};
+
+union PER_MDIO_ADDR_t {
+ struct {
+ unsigned int mdio_addr : 5; /* bits 4:0 */
+ unsigned int rsrvd1 : 3;
+ unsigned int mdio_offset : 5; /* bits 12:8 */
+ unsigned int rsrvd2 : 2;
+ unsigned int mdio_rd_wr : 1; /* bits 15:15 */
+ unsigned int mdio_st : 1; /* bits 16:16 */
+ unsigned int rsrvd3 : 1;
+ unsigned int mdio_op : 2; /* bits 19:18 */
+ unsigned int rsrvd4 : 12;
+ } bf;
+ unsigned int wrd;
+};
+
+union PER_MDIO_CTRL_t {
+ struct {
+ unsigned int mdiodone : 1; /* bits 0:0 */
+ unsigned int rsrvd1 : 6;
+ unsigned int mdiostart : 1; /* bits 7:7 */
+ unsigned int rsrvd2 : 24;
+ } bf;
+ unsigned int wrd;
+};
+
+union PER_MDIO_RDDATA_t {
+ struct {
+ unsigned int mdio_rddata : 16; /* bits 15:0 */
+ unsigned int rsrvd1 : 16;
+ } bf;
+ unsigned int wrd;
+};
+
+/*
+ * XRAM
+ */
+
+union NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t {
+ struct {
+ unsigned int rx_base_addr : 10; /* bits 9:0 */
+ unsigned int rsrvd1 : 6;
+ unsigned int rx_top_addr : 10; /* bits 25:16 */
+ unsigned int rsrvd2 : 6;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t {
+ struct {
+ unsigned int tx_base_addr : 10; /* bits 9:0 */
+ unsigned int rsrvd1 : 6;
+ unsigned int tx_top_addr : 10; /* bits 25:16 */
+ unsigned int rsrvd2 : 6;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t {
+ struct {
+ unsigned int pkt_wr_ptr : 10; /* bits 9:0 */
+ unsigned int rsrvd1 : 5;
+ unsigned int int_colsc_thresh_reached : 1; /* bits 15:15 */
+ unsigned int rsrvd2 : 16;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t {
+ struct {
+ unsigned int pkt_rd_ptr : 10; /* bits 9:0 */
+ unsigned int rsrvd1 : 22;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t {
+ struct {
+ unsigned int pkt_wr_ptr : 10; /* bits 9:0 */
+ unsigned int rsrvd1 : 22;
+ } bf;
+ unsigned int wrd;
+};
+
+union GLOBAL_GLOBAL_CONFIG_t {
+ struct {
+ unsigned int rsrvd1 : 4;
+ unsigned int wd_reset_subsys_enable : 1; /* bits 4:4 */
+ unsigned int rsrvd2 : 1;
+ unsigned int wd_reset_all_blocks : 1; /* bits 6:6 */
+ unsigned int wd_reset_remap : 1; /* bits 7:7 */
+ unsigned int wd_reset_ext_reset : 1; /* bits 8:8 */
+ unsigned int ext_reset : 1; /* bits 9:9 */
+ unsigned int cfg_pcie_0_clken : 1; /* bits 10:10 */
+ unsigned int cfg_sata_clken : 1; /* bits 11:11 */
+ unsigned int cfg_pcie_1_clken : 1; /* bits 12:12 */
+ unsigned int rsrvd3 : 1;
+ unsigned int cfg_pcie_2_clken : 1; /* bits 14:14 */
+ unsigned int rsrvd4 : 2;
+ unsigned int ext_eth_refclk : 1; /* bits 17:17 */
+ unsigned int refclk_sel : 2; /* bits 19:18 */
+ unsigned int rsrvd5 : 7;
+ unsigned int l3fe_pd : 1; /* bits 27:27 */
+ unsigned int offload0_pd : 1; /* bits 28:28 */
+ unsigned int offload1_pd : 1; /* bits 29:29 */
+ unsigned int crypto_pd : 1; /* bits 30:30 */
+ unsigned int core_pd : 1; /* bits 31:31 */
+ } bf;
+ unsigned int wrd;
+};
+
+union GLOBAL_IO_DRIVE_CONTROL_t {
+ struct {
+ unsigned int gmac_dp : 3; /* bits 2:0 */
+ unsigned int gmac_dn : 3; /* bits 5:3 */
+ unsigned int gmac_mode : 2; /* bits 7:6 */
+ unsigned int gmac_ds : 1; /* bits 8:8 */
+ unsigned int flash_ds : 1; /* bits 9:9 */
+ unsigned int nu_ds : 1; /* bits 10:10 */
+ unsigned int ssp_ds : 1; /* bits 11:11 */
+ unsigned int spi_ds : 1; /* bits 12:12 */
+ unsigned int gpio_ds : 1; /* bits 13:13 */
+ unsigned int misc_ds : 1; /* bits 14:14 */
+ unsigned int eaxi_ds : 1; /* bits 15:15 */
+ unsigned int sd_ds : 8; /* bits 23:16 */
+ unsigned int rsrvd1 : 8;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_GLB_INIT_DONE_t {
+ struct {
+ unsigned int rsrvd1 : 1;
+ unsigned int ni_init_done : 1; /* bits 1:1 */
+ unsigned int rsrvd2 : 30;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_PT_PORT_GLB_CFG_t {
+ struct {
+ unsigned int speed : 1; /* bits 0:0 */
+ unsigned int duplex : 1; /* bits 1:1 */
+ unsigned int link_status : 1; /* bits 2:2 */
+ unsigned int link_stat_mask : 1; /* bits 3:3 */
+ unsigned int rsrvd1 : 7;
+ unsigned int power_dwn_rx : 1; /* bits 11:11 */
+ unsigned int power_dwn_tx : 1; /* bits 12:12 */
+ unsigned int tx_intf_lp_time : 1; /* bits 13:13 */
+ unsigned int rsrvd2 : 18;
+ } bf;
+ unsigned int wrd;
+};
+
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC)
+#define NI_HV_GLB_MAC_ADDR_CFG0_OFFSET 0x010
+#define NI_HV_GLB_MAC_ADDR_CFG1_OFFSET 0x014
+#define NI_HV_PT_BASE 0x400
+#define NI_HV_XRAM_BASE 0x820
+#define GLOBAL_BLOCK_RESET_OFFSET 0x04
+#define GLOBAL_GLOBAL_CONFIG_OFFSET 0x20
+#define GLOBAL_IO_DRIVE_CONTROL_OFFSET 0x4c
+#elif defined(CONFIG_TARGET_SATURN_ASIC)
+#define NI_HV_GLB_MAC_ADDR_CFG0_OFFSET 0x010
+#define NI_HV_GLB_MAC_ADDR_CFG1_OFFSET 0x014
+#define NI_HV_PT_BASE 0x580
+#define NI_HV_XRAM_BASE 0xA80
+#define GLOBAL_BLOCK_RESET_OFFSET 0x28
+#define GLOBAL_GLOBAL_CONFIG_OFFSET 0x48
+#define GLOBAL_IO_DRIVE_CONTROL_OFFSET 0x54
+#elif defined(CONFIG_TARGET_VENUS)
+#define NI_HV_GLB_MAC_ADDR_CFG0_OFFSET 0x014
+#define NI_HV_GLB_MAC_ADDR_CFG1_OFFSET 0x018
+#define NI_HV_PT_BASE 0x600
+#define NI_HV_XRAM_BASE 0xA20
+#define GLOBAL_BLOCK_RESET_OFFSET 0x28
+#define GLOBAL_GLOBAL_CONFIG_OFFSET 0x48
+#define GLOBAL_IO_DRIVE_CONTROL_OFFSET 0x7c
+#endif
+
+#define NI_HV_GLB_INIT_DONE_OFFSET 0x004
+#define NI_HV_GLB_INTF_RST_CONFIG_OFFSET 0x008
+#define NI_HV_GLB_STATIC_CFG_OFFSET 0x00c
+
+#define NI_HV_PT_PORT_STATIC_CFG_OFFSET NI_HV_PT_BASE
+#define NI_HV_PT_PORT_GLB_CFG_OFFSET (0x4 + NI_HV_PT_BASE)
+#define NI_HV_PT_RXMAC_CFG_OFFSET (0x8 + NI_HV_PT_BASE)
+#define NI_HV_PT_TXMAC_CFG_OFFSET (0x14 + NI_HV_PT_BASE)
+
+#define NI_HV_XRAM_CPUXRAM_ADRCFG_RX_OFFSET NI_HV_XRAM_BASE
+#define NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_OFFSET (0x4 + NI_HV_XRAM_BASE)
+#define NI_HV_XRAM_CPUXRAM_CFG_OFFSET (0x8 + NI_HV_XRAM_BASE)
+#define NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET (0xc + NI_HV_XRAM_BASE)
+#define NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET (0x10 + NI_HV_XRAM_BASE)
+#define NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET (0x24 + NI_HV_XRAM_BASE)
+#define NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET (0x28 + NI_HV_XRAM_BASE)
+
+#define PER_MDIO_CFG_OFFSET 0x00
+#define PER_MDIO_ADDR_OFFSET 0x04
+#define PER_MDIO_WRDATA_OFFSET 0x08
+#define PER_MDIO_RDDATA_OFFSET 0x0C
+#define PER_MDIO_CTRL_OFFSET 0x10
+
+#define APB0_NI_HV_PT_STRIDE 160
+
+#endif /* __CORTINA_NI_H */
--
2.7.4
1
1

[PATCH v2 1/2] net: cortina_ni: Add eth support for Cortina Access CAxxxx SoCs
by Alex Nemirovsky 03 Jun '20
by Alex Nemirovsky 03 Jun '20
03 Jun '20
From: Aaron Tseng <aaron.tseng(a)cortina-access.com>
Add Cortina Access Ethernet device driver for CAxxxx SoCs.
This driver supports both legacy and DM_ETH network models.
Signed-off-by: Aaron Tseng <aaron.tseng(a)cortina-access.com>
Signed-off-by: Alex Nemirovsky <alex.nemirovsky(a)cortina-access.com>
CC: Joe Hershberger <joe.hershberger(a)ni.com>
CC: Abbie Chang <abbie.chang(a)Cortina-Access.com>
CC: Tom Rini <trini(a)konsulko.com>
---
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 | 1910 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/cortina_ni.h | 592 ++++++++++++++
5 files changed, 2514 insertions(+)
create mode 100644 drivers/net/cortina_ni.c
create mode 100644 drivers/net/cortina_ni.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 8add9d4..1b166d2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -181,6 +181,8 @@ F: drivers/gpio/cortina_gpio.c
F: drivers/watchdog/cortina_wdt.c
F: drivers/serial/serial_cortina.c
F: drivers/mmc/ca_dw_mmc.c
+F: drivers/net/cortina_ni.c
+F: drivers/net/cortina_ni.h
ARM/CZ.NIC TURRIS MOX SUPPORT
M: Marek Behun <marek.behun(a)nic.cz>
@@ -732,6 +734,8 @@ F: drivers/gpio/cortina_gpio.c
F: drivers/watchdog/cortina_wdt.c
F: drivers/serial/serial_cortina.c
F: drivers/mmc/ca_dw_mmc.c
+F: drivers/net/cortina_ni.c
+F: drivers/net/cortina_ni.h
MIPS MSCC
M: Gregory CLEMENT <gregory.clement(a)bootlin.com>
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index f7855c9..45e0480 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -149,6 +149,13 @@ config BCMGENET
help
This driver supports the BCMGENET Ethernet MAC.
+config CORTINA_NI_ENET
+ bool "Cortina-Access Ethernet driver"
+ depends on DM_ETH && CORTINA_PLATFORM
+ help
+ The driver supports the Cortina-Access Ethernet MAC for
+ all supported CAxxxx SoCs
+
config DWC_ETH_QOS
bool "Synopsys DWC Ethernet QOS device support"
depends on DM_ETH
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 383ed1c..1d6ec4f 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
obj-$(CONFIG_BCM_SF2_ETH_GMAC) += bcm-sf2-eth-gmac.o
obj-$(CONFIG_CALXEDA_XGMAC) += calxedaxgmac.o
+obj-$(CONFIG_CORTINA_NI_ENET) += cortina_ni.o
obj-$(CONFIG_CS8900) += cs8900.o
obj-$(CONFIG_TULIP) += dc2114x.o
obj-$(CONFIG_ETH_DESIGNWARE) += designware.o
diff --git a/drivers/net/cortina_ni.c b/drivers/net/cortina_ni.c
new file mode 100644
index 0000000..9851f6e
--- /dev/null
+++ b/drivers/net/cortina_ni.c
@@ -0,0 +1,1910 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * Copyright (C) 2020 Cortina Access Inc.
+ * Author: Aaron Tseng <aaron.tseng(a)cortina-access.com>
+ *
+ * Ethernet MAC Driver for all supported CAxxxx SoCs
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+#include <env.h>
+#include <linux/delay.h>
+
+#include "cortina_ni.h"
+
+static u32 reg_value;
+
+/* port 0-3 are individual port connect to PHY directly */
+/* port 4-7 are LAN ports connected to QSGMII PHY */
+int active_port = NI_PORT_5; /* Physical port 5 */
+u32 ge_port_phy_addr; /* PHY address connected to active port */
+int auto_scan_active_port;
+
+#define HEADER_A_SIZE 8
+
+/*define CORTINA_NI_DBG if individual rx,tx,init needs to be called */
+#if CORTINA_NI_DBG
+static struct udevice *dbg_dev;
+#endif
+static struct udevice *curr_dev;
+
+#if defined(CONFIG_TARGET_SATURN_ASIC)
+#define CA_REG_READ(off) readl((u64)KSEG1_ATU_XLAT(off))
+#define CA_REG_WRITE(data, off) writel(data, (u64)KSEG1_ATU_XLAT(off))
+#else
+#define CA_REG_READ(off) readl((u64)off)
+#define CA_REG_WRITE(data, off) writel(data, (u64)off)
+#endif
+
+int cortina_ni_recv(struct udevice *netdev);
+static int ca_ni_ofdata_to_platdata(struct udevice *dev);
+
+static u32 *RDWRPTR_ADVANCE_ONE(u32 *x, unsigned long base, unsigned long max)
+{
+ 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 <aaron.tseng(a)cortina-access.com>
+ *
+ * Ethernet MAC Driver for all supported CAxxxx SoCs
+ */
+
+#ifndef __CORTINA_NI_H
+#define __CORTINA_NI_H
+
+#include <asm/types.h>
+#include <asm/io.h>
+#include <config.h>
+
+//#define CORTINA_NI_DBG 1
+
+#ifdef CS_BIG_ENDIAN
+#define CRCPOLY_BE 0x04c11db7
+#else /* CS_LITTLE_ENDIAN */
+#define CRCPOLY_LE 0xedb88320
+#endif
+
+#define GE_PORT0_PHY_ADDR CONFIG_NI_PHY_ADDR_GMAC0
+#define GE_PORT1_PHY_ADDR CONFIG_NI_PHY_ADDR_GMAC1
+#define GE_PORT2_PHY_ADDR CONFIG_NI_PHY_ADDR_GMAC2
+
+#define PHY_ID_RTL8201 0x001cc810
+#define PHY_ID_RTL8211 0x001cc910
+#define PHY_ID_RTL8214 0x001cc940
+#define PHY_ID_RTL8211_G3_ASIC 0x001cc980
+#define PHY_ID_RTL8211_SATURN_ASIC 0x001cc900
+#define PHY_ID_QCA8337 0x004dd035
+#define PHY_ID_MASK 0xFFFFFFF0
+
+#define GE_MAC_INTF_GMII 0x0
+#define GE_MAC_INTF_MII 0x1
+#define GE_MAC_INTF_RGMII_1000 0x2
+#define GE_MAC_INTF_RGMII_100 0x3
+#define GE_MAC_INTF_QSGMII_1000 0x4
+#define GE_MAC_INTF_RMII 0x5
+
+#define NI_TOP_NI_RTH_MAC_10M 1
+#define NI_TOP_NI_RTH_MAC_100M 0
+#define NI_TOP_NI_RTH_MAC_HALF 1
+#define NI_TOP_NI_RTH_MAC_FULL 0
+
+/* Defines the base and top address in CPU XRA
+ * for packets to cpu instance 0
+ * 0x300 * 8-byte = 6K-byte
+ */
+#define RX_TOP_ADDR 0x02FF
+#define RX_BASE_ADDR 0x0000
+
+/* Defines the base and top address in CPU XRAM
+ * for packets from cpu instance 0.
+ * 0x100 * 8-byte = 2K-byte
+ */
+#define TX_TOP_ADDR 0x03FF
+#define TX_BASE_ADDR 0x0300
+
+#define RX_0_CPU_PKT_DIS BIT(0)
+#define TX_0_CPU_PKT_DIS BIT(9)
+
+#define PHY_POLL_TIMES 0x200
+
+#define NI_XRAM_BASE 0xF4500000
+
+enum ca_status_t {
+ CA_E_ERROR = -1,
+ CA_E_OK = 0x0,
+ CA_E_RESOURCE = 0x1,
+ CA_E_PARAM = 0x2,
+ CA_E_NOT_FOUND = 0x3,
+ CA_E_CONFLICT = 0x4,
+ CA_E_TIMEOUT = 0x5,
+ CA_E_INTERNAL = 0x6,
+ CA_E_NOT_SUPPORT = 0x7,
+ CA_E_CONFIG = 0x8,
+ CA_E_UNAVAIL = 0x9,
+ CA_E_MEMORY = 0xa,
+ CA_E_BUSY = 0xb,
+ CA_E_FULL = 0xc,
+ CA_E_EMPTY = 0xd,
+ CA_E_EXISTS = 0xe,
+ CA_E_DEV = 0xf,
+ CA_E_PORT = 0x10,
+ CA_E_LLID = 0x11,
+ CA_E_VLAN = 0x12,
+ CA_E_INIT = 0x13,
+ CA_E_INTF = 0x14,
+ CA_E_NEXTHOP = 0x15,
+ CA_E_ROUTE = 0x16,
+ CA_E_DB_CHANGED = 0x17,
+ CA_E_INACTIVE = 0x18,
+ CA_E_ALREADY_SET = 0x19,
+};
+
+#ifndef CA_IN
+#define CA_IN
+#endif
+
+#ifndef CA_OUT
+#define CA_OUT
+#endif
+
+#if !defined(__ASSEMBLER__) && !defined(__ASSEMBLY__)
+struct cortina_ni_priv {
+ unsigned int rx_xram_base_adr;
+ unsigned int rx_xram_end_adr;
+ unsigned short rx_xram_start;
+ unsigned short rx_xram_end;
+ unsigned int tx_xram_base_adr;
+ unsigned int tx_xram_end_adr;
+ unsigned short tx_xram_start;
+ unsigned short tx_xram_end;
+#ifdef CONFIG_DM_ETH
+ void __iomem *glb_base_addr;
+ void __iomem *per_mdio_base_addr;
+ void __iomem *ni_hv_base_addr;
+#else
+ unsigned int glb_base_addr;
+ unsigned int per_mdio_base_addr;
+ unsigned int ni_hv_base_addr;
+#endif
+};
+
+union NI_HEADER_X_T {
+ struct {
+ unsigned int next_link : 10; /* bits 9: 0 */
+ unsigned int bytes_valid : 4; /* bits 13:10 */
+ unsigned int reserved : 16; /* bits 29:14 */
+ unsigned int hdr_a : 1; /* bits 30:30 */
+ unsigned int ownership : 1; /* bits 31:31 */
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_PACKET_STATUS {
+ struct {
+ unsigned int packet_size : 14; /* bits 13:0 */
+ unsigned int byte_valid : 4; /* bits 17:14 */
+ unsigned int pfc : 1; /* bits 18:18 */
+ unsigned int valid : 1; /* bits 19:19 */
+ unsigned int drop : 1; /* bits 20:20 */
+ unsigned int runt : 1; /* bits 21:21 */
+ unsigned int oversize : 1; /* bits 22:22 */
+ unsigned int jumbo : 1; /* bits 23:23 */
+ unsigned int link_status : 1; /* bits 24:24 */
+ unsigned int jabber : 1; /* bits 25:25 */
+ unsigned int crc_error : 1; /* bits 26:26 */
+ unsigned int pause : 1; /* bits 27:27 */
+ unsigned int oam : 1; /* bits 28:28 */
+ unsigned int unknown_opcode : 1; /* bits 29:29 */
+ unsigned int multicast : 1; /* bits 30:30 */
+ unsigned int broadcast : 1; /* bits 31:31 */
+ } bf;
+ unsigned int wrd;
+};
+
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC) || \
+ defined(CONFIG_TARGET_SATURN_ASIC) || defined(CONFIG_TARGET_VENUS)
+
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC)
+#define CA_NI_MDIO_REG_BASE 0xF4338
+#else
+
+#if defined(CONFIG_TARGET_VENUS)
+#define CA_NI_MDIO_REG_BASE 0xF4339
+#else
+#define CA_NI_MDIO_REG_BASE 0xD000B
+#endif
+
+#endif
+
+union NI_MDIO_OPER_T {
+ struct {
+ unsigned int reserved : 2; /* bits 1:0 */
+ unsigned int reg_off : 5; /* bits 6:2 */
+ unsigned int phy_addr : 5; /* bits 11:7 */
+ unsigned int reg_base : 20; /* bits 31:12 */
+ } bf;
+ unsigned int wrd;
+};
+
+#endif
+
+#define NI_PORT_0 0
+#define NI_PORT_1 1
+#define NI_PORT_2 2
+#define NI_PORT_3 3
+#define NI_PORT_4 4
+#define NI_PORT_5 5
+#define NI_PORT_6 6
+#define NI_PORT_7 7
+
+#if defined(CONFIG_TARGET_SATURN_ASIC)
+#define NI_READ_POLL_COUNT 1000000
+#else
+#define NI_READ_POLL_COUNT 1000
+#endif
+
+#define __MDIO_WR_FLAG (0)
+#define __MDIO_RD_FLAG (1)
+#define __MDIO_ACCESS_TIMEOUT (1000000)
+#define __MDIO_PER_CLK (62500)
+#define CA_MDIO_ADDR_MIN (1)
+#define CA_MDIO_ADDR_MAX (31)
+#define CA_MDIO_CLOCK_MIN (1)
+#define CA_MDIO_CLOCK_MAX (20000)
+
+#endif /* !__ASSEMBLER__ */
+
+/* Copy from registers.h */
+union NI_HV_GLB_MAC_ADDR_CFG0_t {
+ struct {
+ unsigned int mac_addr0 : 32; /* bits 31:0 */
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_GLB_MAC_ADDR_CFG1_t {
+ struct {
+ unsigned int mac_addr1 : 8; /* bits 7:0 */
+ unsigned int rsrvd1 : 24;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_PT_PORT_STATIC_CFG_t {
+ struct {
+ unsigned int int_cfg : 4; /* bits 3:0 */
+ unsigned int phy_mode : 1; /* bits 4:4 */
+ unsigned int rmii_clksrc : 1; /* bits 5:5 */
+ unsigned int inv_clk_in : 1; /* bits 6:6 */
+ unsigned int inv_clk_out : 1; /* bits 7:7 */
+ unsigned int inv_rxclk_out : 1; /* bits 8:8 */
+ unsigned int tx_use_gefifo : 1; /* bits 9:9 */
+ unsigned int smii_tx_stat : 1; /* bits 10:10 */
+ unsigned int crs_polarity : 1; /* bits 11:11 */
+ unsigned int lpbk_mode : 2; /* bits 13:12 */
+ unsigned int gmii_like_half_duplex_en : 1; /* bits 14:14 */
+ unsigned int sup_tx_to_rx_lpbk_data : 1; /* bits 15:15 */
+ unsigned int rsrvd1 : 8;
+ unsigned int mac_addr6 : 8; /* bits 31:24 */
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_XRAM_CPUXRAM_CFG_t {
+ struct {
+ unsigned int rx_0_cpu_pkt_dis : 1; /* bits 0:0 */
+ unsigned int rsrvd1 : 8;
+ unsigned int tx_0_cpu_pkt_dis : 1; /* bits 9:9 */
+ unsigned int rsrvd2 : 1;
+ unsigned int rx_x_drop_err_pkt : 1; /* bits 11:11 */
+ unsigned int xram_mgmt_dis_drop_ovsz_pkt : 1; /* bits 12:12 */
+ unsigned int xram_mgmt_term_large_pkt : 1; /* bits 13:13 */
+ unsigned int xram_mgmt_promisc_mode : 2; /* bits 15:14 */
+ unsigned int xram_cntr_debug_mode : 1; /* bits 16:16 */
+ unsigned int xram_cntr_op_code : 2; /* bits 18:17 */
+ unsigned int rsrvd3 : 2;
+ unsigned int xram_rx_mgmtfifo_srst : 1; /* bits 21:21 */
+ unsigned int xram_dma_fifo_srst : 1; /* bits 22:22 */
+ unsigned int rsrvd4 : 9;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_PT_RXMAC_CFG_t {
+ struct {
+ unsigned int rx_en : 1; /* bits 0:0 */
+ unsigned int rsrvd1 : 7;
+ unsigned int rx_flow_disable : 1; /* bits 8:8 */
+ unsigned int rsrvd2 : 3;
+ unsigned int rx_flow_to_tx_en : 1; /* bits 12:12 */
+ unsigned int rx_pfc_disable : 1; /* bits 13:13 */
+ unsigned int rsrvd3 : 15;
+ unsigned int send_pg_data : 1; /* bits 29:29 */
+ unsigned int rsrvd4 : 2;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_PT_TXMAC_CFG_t {
+ struct {
+ unsigned int tx_en : 1; /* bits 0:0 */
+ unsigned int rsrvd1 : 7;
+ unsigned int mac_crc_calc_en : 1; /* bits 8:8 */
+ unsigned int tx_ipg_sel : 3; /* bits 11:9 */
+ unsigned int tx_flow_disable : 1; /* bits 12:12 */
+ unsigned int tx_drain : 1; /* bits 13:13 */
+ unsigned int tx_pfc_disable : 1; /* bits 14:14 */
+ unsigned int tx_pau_sel : 2; /* bits 16:15 */
+ unsigned int rsrvd2 : 9;
+ unsigned int tx_auto_xon : 1; /* bits 26:26 */
+ unsigned int rsrvd3 : 1;
+ unsigned int pass_thru_hdr : 1; /* bits 28:28 */
+ unsigned int rsrvd4 : 3;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_GLB_INTF_RST_CONFIG_t {
+ struct {
+ unsigned int intf_rst_p0 : 1; /* bits 0:0 */
+ unsigned int intf_rst_p1 : 1; /* bits 1:1 */
+ unsigned int intf_rst_p2 : 1; /* bits 2:2 */
+ unsigned int intf_rst_p3 : 1; /* bits 3:3 */
+ unsigned int intf_rst_p4 : 1; /* bits 4:4 */
+ unsigned int mac_rx_rst_p0 : 1; /* bits 5:5 */
+ unsigned int mac_rx_rst_p1 : 1; /* bits 6:6 */
+ unsigned int mac_rx_rst_p2 : 1; /* bits 7:7 */
+ unsigned int mac_rx_rst_p3 : 1; /* bits 8:8 */
+ unsigned int mac_rx_rst_p4 : 1; /* bits 9:9 */
+ unsigned int mac_tx_rst_p0 : 1; /* bits 10:10 */
+ unsigned int mac_tx_rst_p1 : 1; /* bits 11:11 */
+ unsigned int mac_tx_rst_p2 : 1; /* bits 12:12 */
+ unsigned int mac_tx_rst_p3 : 1; /* bits 13:13 */
+ unsigned int mac_tx_rst_p4 : 1; /* bits 14:14 */
+ unsigned int port_rst_p5 : 1; /* bits 15:15 */
+ unsigned int pcs_rst_p6 : 1; /* bits 16:16 */
+ unsigned int pcs_rst_p7 : 1; /* bits 17:17 */
+ unsigned int mac_rst_p6 : 1; /* bits 18:18 */
+ unsigned int mac_rst_p7 : 1; /* bits 19:19 */
+ unsigned int rsrvd1 : 12;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_GLB_STATIC_CFG_t {
+ struct {
+ unsigned int port_to_cpu : 4; /* bits 3:0 */
+ unsigned int mgmt_pt_to_fe_also : 1; /* bits 4:4 */
+ unsigned int txcrc_chk_en : 1; /* bits 5:5 */
+ unsigned int p4_rgmii_tx_clk_phase : 2; /* bits 7:6 */
+ unsigned int p4_rgmii_tx_data_order : 1; /* bits 8:8 */
+ unsigned int rsrvd1 : 7;
+ unsigned int rxmib_mode : 1; /* bits 16:16 */
+ unsigned int txmib_mode : 1; /* bits 17:17 */
+ unsigned int eth_sch_rdy_pkt : 1; /* bits 18:18 */
+ unsigned int rsrvd2 : 1;
+ unsigned int rxaui_mode : 2; /* bits 21:20 */
+ unsigned int rxaui_sigdet : 2; /* bits 23:22 */
+ unsigned int cnt_op_mode : 3; /* bits 26:24 */
+ unsigned int rsrvd3 : 5;
+ } bf;
+ unsigned int wrd;
+};
+
+union GLOBAL_BLOCK_RESET_t {
+ struct {
+ unsigned int reset_ni : 1; /* bits 0:0 */
+ unsigned int reset_l2fe : 1; /* bits 1:1 */
+ unsigned int reset_l2tm : 1; /* bits 2:2 */
+ unsigned int reset_l3fe : 1; /* bits 3:3 */
+ unsigned int reset_sdram : 1; /* bits 4:4 */
+ unsigned int reset_tqm : 1; /* bits 5:5 */
+ unsigned int reset_pcie0 : 1; /* bits 6:6 */
+ unsigned int reset_pcie1 : 1; /* bits 7:7 */
+ unsigned int reset_pcie2 : 1; /* bits 8:8 */
+ unsigned int reset_sata : 1; /* bits 9:9 */
+ unsigned int reset_gic400 : 1; /* bits 10:10 */
+ unsigned int rsrvd1 : 2;
+ unsigned int reset_usb : 1; /* bits 13:13 */
+ unsigned int reset_flash : 1; /* bits 14:14 */
+ unsigned int reset_per : 1; /* bits 15:15 */
+ unsigned int reset_dma : 1; /* bits 16:16 */
+ unsigned int reset_rtc : 1; /* bits 17:17 */
+ unsigned int reset_pe0 : 1; /* bits 18:18 */
+ unsigned int reset_pe1 : 1; /* bits 19:19 */
+ unsigned int reset_rcpu0 : 1; /* bits 20:20 */
+ unsigned int reset_rcpu1 : 1; /* bits 21:21 */
+ unsigned int reset_sadb : 1; /* bits 22:22 */
+ unsigned int rsrvd2 : 1;
+ unsigned int reset_rcrypto : 1; /* bits 24:24 */
+ unsigned int reset_ldma : 1; /* bits 25:25 */
+ unsigned int reset_fbm : 1; /* bits 26:26 */
+ unsigned int reset_eaxi : 1; /* bits 27:27 */
+ unsigned int reset_sd : 1; /* bits 28:28 */
+ unsigned int reset_otprom : 1; /* bits 29:29 */
+ unsigned int rsrvd3 : 2;
+ } bf;
+ unsigned int wrd;
+};
+
+union PER_MDIO_ADDR_t {
+ struct {
+ unsigned int mdio_addr : 5; /* bits 4:0 */
+ unsigned int rsrvd1 : 3;
+ unsigned int mdio_offset : 5; /* bits 12:8 */
+ unsigned int rsrvd2 : 2;
+ unsigned int mdio_rd_wr : 1; /* bits 15:15 */
+ unsigned int mdio_st : 1; /* bits 16:16 */
+ unsigned int rsrvd3 : 1;
+ unsigned int mdio_op : 2; /* bits 19:18 */
+ unsigned int rsrvd4 : 12;
+ } bf;
+ unsigned int wrd;
+};
+
+union PER_MDIO_CTRL_t {
+ struct {
+ unsigned int mdiodone : 1; /* bits 0:0 */
+ unsigned int rsrvd1 : 6;
+ unsigned int mdiostart : 1; /* bits 7:7 */
+ unsigned int rsrvd2 : 24;
+ } bf;
+ unsigned int wrd;
+};
+
+union PER_MDIO_RDDATA_t {
+ struct {
+ unsigned int mdio_rddata : 16; /* bits 15:0 */
+ unsigned int rsrvd1 : 16;
+ } bf;
+ unsigned int wrd;
+};
+
+/*
+ * XRAM
+ */
+
+union NI_HV_XRAM_CPUXRAM_ADRCFG_RX_t {
+ struct {
+ unsigned int rx_base_addr : 10; /* bits 9:0 */
+ unsigned int rsrvd1 : 6;
+ unsigned int rx_top_addr : 10; /* bits 25:16 */
+ unsigned int rsrvd2 : 6;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_t {
+ struct {
+ unsigned int tx_base_addr : 10; /* bits 9:0 */
+ unsigned int rsrvd1 : 6;
+ unsigned int tx_top_addr : 10; /* bits 25:16 */
+ unsigned int rsrvd2 : 6;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_t {
+ struct {
+ unsigned int pkt_wr_ptr : 10; /* bits 9:0 */
+ unsigned int rsrvd1 : 5;
+ unsigned int int_colsc_thresh_reached : 1; /* bits 15:15 */
+ unsigned int rsrvd2 : 16;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_t {
+ struct {
+ unsigned int pkt_rd_ptr : 10; /* bits 9:0 */
+ unsigned int rsrvd1 : 22;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_t {
+ struct {
+ unsigned int pkt_wr_ptr : 10; /* bits 9:0 */
+ unsigned int rsrvd1 : 22;
+ } bf;
+ unsigned int wrd;
+};
+
+union GLOBAL_GLOBAL_CONFIG_t {
+ struct {
+ unsigned int rsrvd1 : 4;
+ unsigned int wd_reset_subsys_enable : 1; /* bits 4:4 */
+ unsigned int rsrvd2 : 1;
+ unsigned int wd_reset_all_blocks : 1; /* bits 6:6 */
+ unsigned int wd_reset_remap : 1; /* bits 7:7 */
+ unsigned int wd_reset_ext_reset : 1; /* bits 8:8 */
+ unsigned int ext_reset : 1; /* bits 9:9 */
+ unsigned int cfg_pcie_0_clken : 1; /* bits 10:10 */
+ unsigned int cfg_sata_clken : 1; /* bits 11:11 */
+ unsigned int cfg_pcie_1_clken : 1; /* bits 12:12 */
+ unsigned int rsrvd3 : 1;
+ unsigned int cfg_pcie_2_clken : 1; /* bits 14:14 */
+ unsigned int rsrvd4 : 2;
+ unsigned int ext_eth_refclk : 1; /* bits 17:17 */
+ unsigned int refclk_sel : 2; /* bits 19:18 */
+ unsigned int rsrvd5 : 7;
+ unsigned int l3fe_pd : 1; /* bits 27:27 */
+ unsigned int offload0_pd : 1; /* bits 28:28 */
+ unsigned int offload1_pd : 1; /* bits 29:29 */
+ unsigned int crypto_pd : 1; /* bits 30:30 */
+ unsigned int core_pd : 1; /* bits 31:31 */
+ } bf;
+ unsigned int wrd;
+};
+
+union GLOBAL_IO_DRIVE_CONTROL_t {
+ struct {
+ unsigned int gmac_dp : 3; /* bits 2:0 */
+ unsigned int gmac_dn : 3; /* bits 5:3 */
+ unsigned int gmac_mode : 2; /* bits 7:6 */
+ unsigned int gmac_ds : 1; /* bits 8:8 */
+ unsigned int flash_ds : 1; /* bits 9:9 */
+ unsigned int nu_ds : 1; /* bits 10:10 */
+ unsigned int ssp_ds : 1; /* bits 11:11 */
+ unsigned int spi_ds : 1; /* bits 12:12 */
+ unsigned int gpio_ds : 1; /* bits 13:13 */
+ unsigned int misc_ds : 1; /* bits 14:14 */
+ unsigned int eaxi_ds : 1; /* bits 15:15 */
+ unsigned int sd_ds : 8; /* bits 23:16 */
+ unsigned int rsrvd1 : 8;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_GLB_INIT_DONE_t {
+ struct {
+ unsigned int rsrvd1 : 1;
+ unsigned int ni_init_done : 1; /* bits 1:1 */
+ unsigned int rsrvd2 : 30;
+ } bf;
+ unsigned int wrd;
+};
+
+union NI_HV_PT_PORT_GLB_CFG_t {
+ struct {
+ unsigned int speed : 1; /* bits 0:0 */
+ unsigned int duplex : 1; /* bits 1:1 */
+ unsigned int link_status : 1; /* bits 2:2 */
+ unsigned int link_stat_mask : 1; /* bits 3:3 */
+ unsigned int rsrvd1 : 7;
+ unsigned int power_dwn_rx : 1; /* bits 11:11 */
+ unsigned int power_dwn_tx : 1; /* bits 12:12 */
+ unsigned int tx_intf_lp_time : 1; /* bits 13:13 */
+ unsigned int rsrvd2 : 18;
+ } bf;
+ unsigned int wrd;
+};
+
+#if defined(CONFIG_TARGET_PRESIDIO_ASIC)
+#define NI_HV_GLB_MAC_ADDR_CFG0_OFFSET 0x010
+#define NI_HV_GLB_MAC_ADDR_CFG1_OFFSET 0x014
+#define NI_HV_PT_BASE 0x400
+#define NI_HV_XRAM_BASE 0x820
+#define GLOBAL_BLOCK_RESET_OFFSET 0x04
+#define GLOBAL_GLOBAL_CONFIG_OFFSET 0x20
+#define GLOBAL_IO_DRIVE_CONTROL_OFFSET 0x4c
+#elif defined(CONFIG_TARGET_SATURN_ASIC)
+#define NI_HV_GLB_MAC_ADDR_CFG0_OFFSET 0x010
+#define NI_HV_GLB_MAC_ADDR_CFG1_OFFSET 0x014
+#define NI_HV_PT_BASE 0x580
+#define NI_HV_XRAM_BASE 0xA80
+#define GLOBAL_BLOCK_RESET_OFFSET 0x28
+#define GLOBAL_GLOBAL_CONFIG_OFFSET 0x48
+#define GLOBAL_IO_DRIVE_CONTROL_OFFSET 0x54
+#elif defined(CONFIG_TARGET_VENUS)
+#define NI_HV_GLB_MAC_ADDR_CFG0_OFFSET 0x014
+#define NI_HV_GLB_MAC_ADDR_CFG1_OFFSET 0x018
+#define NI_HV_PT_BASE 0x600
+#define NI_HV_XRAM_BASE 0xA20
+#define GLOBAL_BLOCK_RESET_OFFSET 0x28
+#define GLOBAL_GLOBAL_CONFIG_OFFSET 0x48
+#define GLOBAL_IO_DRIVE_CONTROL_OFFSET 0x7c
+#endif
+
+#define NI_HV_GLB_INIT_DONE_OFFSET 0x004
+#define NI_HV_GLB_INTF_RST_CONFIG_OFFSET 0x008
+#define NI_HV_GLB_STATIC_CFG_OFFSET 0x00c
+
+#define NI_HV_PT_PORT_STATIC_CFG_OFFSET NI_HV_PT_BASE
+#define NI_HV_PT_PORT_GLB_CFG_OFFSET (0x4 + NI_HV_PT_BASE)
+#define NI_HV_PT_RXMAC_CFG_OFFSET (0x8 + NI_HV_PT_BASE)
+#define NI_HV_PT_TXMAC_CFG_OFFSET (0x14 + NI_HV_PT_BASE)
+
+#define NI_HV_XRAM_CPUXRAM_ADRCFG_RX_OFFSET NI_HV_XRAM_BASE
+#define NI_HV_XRAM_CPUXRAM_ADRCFG_TX_0_OFFSET (0x4 + NI_HV_XRAM_BASE)
+#define NI_HV_XRAM_CPUXRAM_CFG_OFFSET (0x8 + NI_HV_XRAM_BASE)
+#define NI_HV_XRAM_CPUXRAM_CPU_CFG_RX_0_OFFSET (0xc + NI_HV_XRAM_BASE)
+#define NI_HV_XRAM_CPUXRAM_CPU_STA_RX_0_OFFSET (0x10 + NI_HV_XRAM_BASE)
+#define NI_HV_XRAM_CPUXRAM_CPU_CFG_TX_0_OFFSET (0x24 + NI_HV_XRAM_BASE)
+#define NI_HV_XRAM_CPUXRAM_CPU_STAT_TX_0_OFFSET (0x28 + NI_HV_XRAM_BASE)
+
+#define PER_MDIO_CFG_OFFSET 0x00
+#define PER_MDIO_ADDR_OFFSET 0x04
+#define PER_MDIO_WRDATA_OFFSET 0x08
+#define PER_MDIO_RDDATA_OFFSET 0x0C
+#define PER_MDIO_CTRL_OFFSET 0x10
+
+#define APB0_NI_HV_PT_STRIDE 160
+
+#endif /* __CORTINA_NI_H */
--
2.7.4
1
1

03 Jun '20
From: Hou Zhiqiang <Zhiqiang.Hou(a)nxp.com>
This patch set depends on:
https://patchwork.ozlabs.org/project/uboot/list/?series=174343
Hou Zhiqiang (13):
net: fsl_pq_mdio: Add the compatible "fsl,gianfar-mdio" support
net: tsec: Add the compatible string "gianfar" support
powerpc: mpc8xxx: Don't compile cpu_eth_init() when DM_ETH enabled
fsl: p1_p2_rdb: Move vsc7835 firmware uploading to
board_early_init_r()
configs: p1_p2_rdb: Add the default address of vsc7385 firmware
dts: powerpc: p1020rdb: Add eTSEC DT nodes
powerpc: p1_p2_rdb: Don't compile board_eth_init() when DM_ETH enabled
configs: P1020RDB: Enable DM_ETH config
dts: powerpc: p1010rdb: Add eTSEC DT nodes
powerpc: p1010rdb: Compile legacy ethernet init function when no
DM_ETH
configs: P1010RDB: Enable DM_ETH config
dts: powerpc: p2020rdb: Add eTSEC DT nodes
configs: P2020RDB: Enable DM_ETH config
arch/powerpc/cpu/mpc8xxx/cpu.c | 2 +
arch/powerpc/dts/p1010rdb-pa.dts | 1 +
arch/powerpc/dts/p1010rdb-pa_36b.dts | 1 +
arch/powerpc/dts/p1010rdb-pb.dts | 1 +
arch/powerpc/dts/p1010rdb-pb_36b.dts | 1 +
arch/powerpc/dts/p1010rdb.dtsi | 71 +++++++++++++++++++
arch/powerpc/dts/p1010si-post.dtsi | 25 +++++++
arch/powerpc/dts/p1020-post.dtsi | 15 ++++
arch/powerpc/dts/p1020rdb-pc.dts | 1 +
arch/powerpc/dts/p1020rdb-pc.dtsi | 55 ++++++++++++++
arch/powerpc/dts/p1020rdb-pc_36b.dts | 1 +
arch/powerpc/dts/p1020rdb-pd.dts | 57 +++++++++++++++
arch/powerpc/dts/p2020-post.dtsi | 10 +++
arch/powerpc/dts/p2020rdb-pc.dts | 1 +
arch/powerpc/dts/p2020rdb-pc.dtsi | 59 +++++++++++++++
arch/powerpc/dts/p2020rdb-pc_36b.dts | 1 +
arch/powerpc/dts/pq3-etsec1-0.dtsi | 28 ++++++++
arch/powerpc/dts/pq3-etsec1-1.dtsi | 28 ++++++++
arch/powerpc/dts/pq3-etsec1-2.dtsi | 28 ++++++++
arch/powerpc/dts/pq3-etsec1-3.dtsi | 28 ++++++++
arch/powerpc/dts/pq3-etsec1-timer-0.dtsi | 13 ++++
arch/powerpc/dts/pq3-etsec2-0.dtsi | 35 +++++++++
arch/powerpc/dts/pq3-etsec2-1.dtsi | 35 +++++++++
arch/powerpc/dts/pq3-etsec2-2.dtsi | 35 +++++++++
arch/powerpc/dts/pq3-etsec2-grp2-0.dtsi | 16 +++++
arch/powerpc/dts/pq3-etsec2-grp2-1.dtsi | 16 +++++
arch/powerpc/dts/pq3-etsec2-grp2-2.dtsi | 16 +++++
board/freescale/p1010rdb/p1010rdb.c | 2 +
board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c | 37 +++++-----
configs/P1010RDB-PA_36BIT_NAND_defconfig | 2 +
configs/P1010RDB-PA_36BIT_NOR_defconfig | 2 +
configs/P1010RDB-PA_36BIT_SDCARD_defconfig | 2 +
configs/P1010RDB-PA_36BIT_SPIFLASH_defconfig | 2 +
configs/P1010RDB-PA_NAND_defconfig | 2 +
configs/P1010RDB-PA_NOR_defconfig | 2 +
configs/P1010RDB-PA_SDCARD_defconfig | 2 +
configs/P1010RDB-PA_SPIFLASH_defconfig | 2 +
configs/P1010RDB-PB_36BIT_NAND_defconfig | 2 +
configs/P1010RDB-PB_36BIT_NOR_defconfig | 2 +
configs/P1010RDB-PB_36BIT_SDCARD_defconfig | 2 +
configs/P1010RDB-PB_36BIT_SPIFLASH_defconfig | 2 +
configs/P1010RDB-PB_NAND_defconfig | 2 +
configs/P1010RDB-PB_NOR_defconfig | 2 +
configs/P1010RDB-PB_SDCARD_defconfig | 2 +
configs/P1010RDB-PB_SPIFLASH_defconfig | 2 +
configs/P1020RDB-PC_36BIT_NAND_defconfig | 3 +
configs/P1020RDB-PC_36BIT_SDCARD_defconfig | 3 +
configs/P1020RDB-PC_36BIT_SPIFLASH_defconfig | 3 +
configs/P1020RDB-PC_36BIT_defconfig | 3 +
configs/P1020RDB-PC_NAND_defconfig | 3 +
configs/P1020RDB-PC_SDCARD_defconfig | 3 +
configs/P1020RDB-PC_SPIFLASH_defconfig | 3 +
configs/P1020RDB-PC_defconfig | 3 +
configs/P1020RDB-PD_NAND_defconfig | 3 +
configs/P1020RDB-PD_SDCARD_defconfig | 3 +
configs/P1020RDB-PD_SPIFLASH_defconfig | 3 +
configs/P1020RDB-PD_defconfig | 3 +
configs/P2020RDB-PC_36BIT_NAND_defconfig | 3 +
configs/P2020RDB-PC_36BIT_SDCARD_defconfig | 3 +
configs/P2020RDB-PC_36BIT_SPIFLASH_defconfig | 3 +
configs/P2020RDB-PC_36BIT_defconfig | 3 +
configs/P2020RDB-PC_NAND_defconfig | 3 +
configs/P2020RDB-PC_SDCARD_defconfig | 3 +
configs/P2020RDB-PC_SPIFLASH_defconfig | 3 +
configs/P2020RDB-PC_defconfig | 3 +
doc/device-tree-bindings/net/fsl-tsec-phy.txt | 5 +-
drivers/net/fsl_mdio.c | 15 +++-
drivers/net/tsec.c | 16 ++++-
include/configs/p1_p2_rdb_pc.h | 2 +
include/fsl_mdio.h | 4 ++
include/tsec.h | 4 ++
71 files changed, 734 insertions(+), 23 deletions(-)
create mode 100644 arch/powerpc/dts/p1010rdb.dtsi
create mode 100644 arch/powerpc/dts/p1020rdb-pc.dtsi
create mode 100644 arch/powerpc/dts/p2020rdb-pc.dtsi
create mode 100644 arch/powerpc/dts/pq3-etsec1-0.dtsi
create mode 100644 arch/powerpc/dts/pq3-etsec1-1.dtsi
create mode 100644 arch/powerpc/dts/pq3-etsec1-2.dtsi
create mode 100644 arch/powerpc/dts/pq3-etsec1-3.dtsi
create mode 100644 arch/powerpc/dts/pq3-etsec1-timer-0.dtsi
create mode 100644 arch/powerpc/dts/pq3-etsec2-0.dtsi
create mode 100644 arch/powerpc/dts/pq3-etsec2-1.dtsi
create mode 100644 arch/powerpc/dts/pq3-etsec2-2.dtsi
create mode 100644 arch/powerpc/dts/pq3-etsec2-grp2-0.dtsi
create mode 100644 arch/powerpc/dts/pq3-etsec2-grp2-1.dtsi
create mode 100644 arch/powerpc/dts/pq3-etsec2-grp2-2.dtsi
--
2.17.1
3
15

03 Jun '20
From: Suneel Garapati <sgarapati(a)marvell.com>
Add support for I2C controllers found on Octeon II/III and Octeon TX
TX2 SoC platforms.
Signed-off-by: Aaron Williams <awilliams(a)marvell.com>
Signed-off-by: Suneel Garapati <sgarapati(a)marvell.com>
Signed-off-by: Stefan Roese <sr(a)denx.de>
Cc: Heiko Schocher <hs(a)denx.de>
Cc: Simon Glass <sjg(a)chromium.org>
Cc: Daniel Schwierzeck <daniel.schwierzeck(a)gmail.com>
Cc: Aaron Williams <awilliams(a)marvell.com>
Cc: Chandrakala Chavva <cchavva(a)marvell.com>
---
RFC -> v1 (Stefan):
- Separated this patch from the OcteonTX/TX2 RFC patch series into a
single patch. This is useful, as the upcoming MIPS Octeon support will
use this I2C driver.
- Added MIPS Octeon II/III support (big endian). Rename driver and its
function names from "octeontx" to "octeon" to better match all Octeon
platforms.
- Moved from union to defines / bitmasks as suggested by Simon. This makes
the driver usage on little- and big-endian platforms much easier.
- Enhanced Kconfig text
- Removed all clock macros (use values from DT)
- Removed long driver debug strings. This is only available when a debug
version of this driver is built. The user / developer can lookup the
descriptive error messages in the driver in this case anyway.
- Removed static "last_id"
- Dropped misc blank lines. Misc reformatting.
- Dropped "!= 0"
- Added missing function comments
- Added missing strut comments
- Changed comment style
- Renames "result" to "ret"
- Hex numbers uppercase
- Minor other changes
- Reword commit text and subject
drivers/i2c/Kconfig | 10 +
drivers/i2c/Makefile | 1 +
drivers/i2c/octeon_i2c.c | 803 +++++++++++++++++++++++++++++++++++++++
3 files changed, 814 insertions(+)
create mode 100644 drivers/i2c/octeon_i2c.c
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index e42b6516bf..1330b36698 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -374,6 +374,16 @@ config SYS_I2C_SANDBOX
bus. Devices can be attached to the bus using the device tree
which specifies the driver to use. See sandbox.dts as an example.
+config SYS_I2C_OCTEON
+ bool "Octeon II/III/TX/TX2 I2C driver"
+ depends on (ARCH_OCTEON || ARCH_OCTEONTX || ARCH_OCTEONTX2) && DM_I2C
+ default y
+ help
+ Add support for the Marvell Octeon I2C driver. This is used with
+ various Octeon parts such as Octeon II/III and OcteonTX/TX2. All
+ chips have several I2C ports and all are provided, controlled by
+ the device tree.
+
config SYS_I2C_S3C24X0
bool "Samsung I2C driver"
depends on ARCH_EXYNOS4 && DM_I2C
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 62935b7ebc..2b58aae892 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_SYS_I2C_LPC32XX) += lpc32xx_i2c.o
obj-$(CONFIG_SYS_I2C_MESON) += meson_i2c.o
obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o
obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o
+obj-$(CONFIG_SYS_I2C_OCTEON) += octeon_i2c.o
obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o
obj-$(CONFIG_SYS_I2C_RCAR_I2C) += rcar_i2c.o
obj-$(CONFIG_SYS_I2C_RCAR_IIC) += rcar_iic.o
diff --git a/drivers/i2c/octeon_i2c.c b/drivers/i2c/octeon_i2c.c
new file mode 100644
index 0000000000..210f98655e
--- /dev/null
+++ b/drivers/i2c/octeon_i2c.c
@@ -0,0 +1,803 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <dm.h>
+#include <pci_ids.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <linux/bitfield.h>
+
+/*
+ * Octeon II/III (MIPS) have different register offsets than the ARM based
+ * Octeon TX/TX2 SoCs
+ */
+#if defined(CONFIG_ARCH_OCTEON)
+#define REG_OFFS 0x0000
+#else
+#define REG_OFFS 0x1000
+#endif
+
+#define TWSI_SW_TWSI (REG_OFFS + 0x00)
+#define TWSI_TWSI_SW (REG_OFFS + 0x08)
+#define TWSI_INT (REG_OFFS + 0x10)
+#define TWSI_SW_TWSI_EXT (REG_OFFS + 0x18)
+
+#define TWSI_SW_DATA_MASK GENMASK_ULL(31, 0)
+#define TWSI_SW_EOP_IA_MASK GENMASK_ULL(34, 32)
+#define TWSI_SW_IA_MASK GENMASK_ULL(39, 35)
+#define TWSI_SW_ADDR_MASK GENMASK_ULL(49, 40)
+#define TWSI_SW_SCR_MASK GENMASK_ULL(51, 50)
+#define TWSI_SW_SIZE_MASK GENMASK_ULL(54, 52)
+#define TWSI_SW_SOVR BIT_ULL(55)
+#define TWSI_SW_R BIT_ULL(56)
+#define TWSI_SW_OP_MASK GENMASK_ULL(60, 57)
+#define TWSI_SW_EIA GENMASK_ULL(61)
+#define TWSI_SW_SLONLY BIT_ULL(62)
+#define TWSI_SW_V BIT_ULL(63)
+
+#define TWSI_INT_SDA_OVR BIT_ULL(8)
+#define TWSI_INT_SCL_OVR BIT_ULL(9)
+#define TWSI_INT_SDA BIT_ULL(10)
+#define TWSI_INT_SCL BIT_ULL(11)
+
+enum {
+ TWSI_OP_WRITE = 0,
+ TWSI_OP_READ = 1,
+};
+
+enum {
+ TWSI_EOP_SLAVE_ADDR = 0,
+ TWSI_EOP_CLK_CTL = 3,
+ TWSI_SW_EOP_IA = 6,
+};
+
+enum {
+ TWSI_SLAVEADD = 0,
+ TWSI_DATA = 1,
+ TWSI_CTL = 2,
+ TWSI_CLKCTL = 3,
+ TWSI_STAT = 3,
+ TWSI_SLAVEADD_EXT = 4,
+ TWSI_RST = 7,
+};
+
+enum {
+ TWSI_CTL_AAK = BIT(2),
+ TWSI_CTL_IFLG = BIT(3),
+ TWSI_CTL_STP = BIT(4),
+ TWSI_CTL_STA = BIT(5),
+ TWSI_CTL_ENAB = BIT(6),
+ TWSI_CTL_CE = BIT(7),
+};
+
+/*
+ * Internal errors. When debugging is enabled, the driver will report the
+ * error number and the user / developer can check the table below for the
+ * detailed error description.
+ */
+enum {
+ /** Bus error */
+ TWSI_STAT_BUS_ERROR = 0x00,
+ /** Start condition transmitted */
+ TWSI_STAT_START = 0x08,
+ /** Repeat start condition transmitted */
+ TWSI_STAT_RSTART = 0x10,
+ /** Address + write bit transmitted, ACK received */
+ TWSI_STAT_TXADDR_ACK = 0x18,
+ /** Address + write bit transmitted, /ACK received */
+ TWSI_STAT_TXADDR_NAK = 0x20,
+ /** Data byte transmitted in master mode, ACK received */
+ TWSI_STAT_TXDATA_ACK = 0x28,
+ /** Data byte transmitted in master mode, ACK received */
+ TWSI_STAT_TXDATA_NAK = 0x30,
+ /** Arbitration lost in address or data byte */
+ TWSI_STAT_TX_ARB_LOST = 0x38,
+ /** Address + read bit transmitted, ACK received */
+ TWSI_STAT_RXADDR_ACK = 0x40,
+ /** Address + read bit transmitted, /ACK received */
+ TWSI_STAT_RXADDR_NAK = 0x48,
+ /** Data byte received in master mode, ACK transmitted */
+ TWSI_STAT_RXDATA_ACK_SENT = 0x50,
+ /** Data byte received, NACK transmitted */
+ TWSI_STAT_RXDATA_NAK_SENT = 0x58,
+ /** Slave address received, sent ACK */
+ TWSI_STAT_SLAVE_RXADDR_ACK = 0x60,
+ /**
+ * Arbitration lost in address as master, slave address + write bit
+ * received, ACK transmitted
+ */
+ TWSI_STAT_TX_ACK_ARB_LOST = 0x68,
+ /** General call address received, ACK transmitted */
+ TWSI_STAT_RX_GEN_ADDR_ACK = 0x70,
+ /**
+ * Arbitration lost in address as master, general call address
+ * received, ACK transmitted
+ */
+ TWSI_STAT_RX_GEN_ADDR_ARB_LOST = 0x78,
+ /** Data byte received after slave address received, ACK transmitted */
+ TWSI_STAT_SLAVE_RXDATA_ACK = 0x80,
+ /** Data byte received after slave address received, /ACK transmitted */
+ TWSI_STAT_SLAVE_RXDATA_NAK = 0x88,
+ /**
+ * Data byte received after general call address received, ACK
+ * transmitted
+ */
+ TWSI_STAT_GEN_RXADDR_ACK = 0x90,
+ /**
+ * Data byte received after general call address received, /ACK
+ * transmitted
+ */
+ TWSI_STAT_GEN_RXADDR_NAK = 0x98,
+ /** STOP or repeated START condition received in slave mode */
+ TWSI_STAT_STOP_MULTI_START = 0xa0,
+ /** Slave address + read bit received, ACK transmitted */
+ TWSI_STAT_SLAVE_RXADDR2_ACK = 0xa8,
+ /**
+ * Arbitration lost in address as master, slave address + read bit
+ * received, ACK transmitted
+ */
+ TWSI_STAT_RXDATA_ACK_ARB_LOST = 0xb0,
+ /** Data byte transmitted in slave mode, ACK received */
+ TWSI_STAT_SLAVE_TXDATA_ACK = 0xb8,
+ /** Data byte transmitted in slave mode, /ACK received */
+ TWSI_STAT_SLAVE_TXDATA_NAK = 0xc0,
+ /** Last byte transmitted in slave mode, ACK received */
+ TWSI_STAT_SLAVE_TXDATA_END_ACK = 0xc8,
+ /** Second address byte + write bit transmitted, ACK received */
+ TWSI_STAT_TXADDR2DATA_ACK = 0xd0,
+ /** Second address byte + write bit transmitted, /ACK received */
+ TWSI_STAT_TXADDR2DATA_NAK = 0xd8,
+ /** No relevant status information */
+ TWSI_STAT_IDLE = 0xf8
+};
+
+#ifndef CONFIG_SYS_I2C_OCTEON_SLAVE_ADDR
+# define CONFIG_SYS_I2C_OCTEON_SLAVE_ADDR 0x77
+#endif
+
+/**
+ * struct octeon_twsi - Private data of this driver
+ *
+ * @base: Base address of i2c registers
+ */
+struct octeon_twsi {
+ void __iomem *base;
+};
+
+static void twsi_unblock(void *base);
+static int twsi_stop(void *base);
+
+#if defined(CONFIG_ARCH_OCTEON)
+static int get_io_clock(void)
+{
+ return octeon_get_io_clock();
+}
+#else
+static int get_io_clock(void)
+{
+ return octeontx_get_io_clock();
+}
+#endif
+
+static int twsi_thp(void)
+{
+ if (IS_ENABLED(CONFIG_ARCH_OCTEON) || IS_ENABLED(CONFIG_ARCH_OCTEONTX))
+ return 24;
+ else
+ return 3;
+}
+
+/**
+ * Returns true if we lost arbitration
+ *
+ * @code status code
+ * @final_read true if this is the final read operation
+ * @return true if arbitration has been lost, false if it hasn't been lost.
+ */
+static int twsi_i2c_lost_arb(u8 code, int final_read)
+{
+ switch (code) {
+ case TWSI_STAT_TX_ARB_LOST:
+ case TWSI_STAT_TX_ACK_ARB_LOST:
+ case TWSI_STAT_RX_GEN_ADDR_ARB_LOST:
+ case TWSI_STAT_RXDATA_ACK_ARB_LOST:
+ /* Arbitration lost */
+ return -EAGAIN;
+
+ case TWSI_STAT_SLAVE_RXADDR_ACK:
+ case TWSI_STAT_RX_GEN_ADDR_ACK:
+ case TWSI_STAT_GEN_RXADDR_ACK:
+ case TWSI_STAT_GEN_RXADDR_NAK:
+ /* Being addressed as slave, should back off and listen */
+ return -EIO;
+
+ case TWSI_STAT_SLAVE_RXDATA_ACK:
+ case TWSI_STAT_SLAVE_RXDATA_NAK:
+ case TWSI_STAT_STOP_MULTI_START:
+ case TWSI_STAT_SLAVE_RXADDR2_ACK:
+ case TWSI_STAT_SLAVE_TXDATA_ACK:
+ case TWSI_STAT_SLAVE_TXDATA_NAK:
+ case TWSI_STAT_SLAVE_TXDATA_END_ACK:
+ /* Core busy as slave */
+ return -EIO;
+
+ case TWSI_STAT_RXDATA_ACK_SENT:
+ /* Ack allowed on pre-terminal bytes only */
+ if (!final_read)
+ return 0;
+ return -EAGAIN;
+
+ case TWSI_STAT_RXDATA_NAK_SENT:
+ /* NAK allowed on terminal byte only */
+ if (!final_read)
+ return 0;
+ return -EAGAIN;
+
+ case TWSI_STAT_TXDATA_NAK:
+ case TWSI_STAT_TXADDR_NAK:
+ case TWSI_STAT_RXADDR_NAK:
+ case TWSI_STAT_TXADDR2DATA_NAK:
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+#define RST_BOOT_PNR_MUL(val) (((val) >> 33) & 0x1F)
+
+/**
+ * Writes to the MIO_TWS(0..5)_SW_TWSI register
+ *
+ * @base Base address of i2c registers
+ * @val value to write
+ * @return 0 for success, otherwise error
+ */
+static u64 twsi_write_sw(void __iomem *base, u64 val)
+{
+ unsigned long start = get_timer(0);
+
+ val &= ~TWSI_SW_R;
+ val |= TWSI_SW_V;
+
+ debug("%s(%p, 0x%llx)\n", __func__, base, val);
+ writeq(val, base + TWSI_SW_TWSI);
+ do {
+ val = readq(base + TWSI_SW_TWSI);
+ } while ((val & TWSI_SW_V) && (get_timer(start) < 50));
+
+ if (val & TWSI_SW_V)
+ debug("%s: timed out\n", __func__);
+ return val;
+}
+
+/**
+ * Reads the MIO_TWS(0..5)_SW_TWSI register
+ *
+ * @base Base address of i2c registers
+ * @val value for eia and op, etc. to read
+ * @return value of the register
+ */
+static u64 twsi_read_sw(void __iomem *base, u64 val)
+{
+ unsigned long start = get_timer(0);
+
+ val |= TWSI_SW_R | TWSI_SW_V;
+
+ debug("%s(%p, 0x%llx)\n", __func__, base, val);
+ writeq(val, base + TWSI_SW_TWSI);
+
+ do {
+ val = readq(base + TWSI_SW_TWSI);
+ } while ((val & TWSI_SW_V) && (get_timer(start) < 50));
+
+ if (val & TWSI_SW_V)
+ debug("%s: Error writing 0x%llx\n", __func__, val);
+
+ debug("%s: Returning 0x%llx\n", __func__, val);
+ return val;
+}
+
+/**
+ * Write control register
+ *
+ * @base Base address for i2c registers
+ * @data data to write
+ */
+static void twsi_write_ctl(void __iomem *base, u8 data)
+{
+ u64 val;
+
+ debug("%s(%p, 0x%x)\n", __func__, base, data);
+ val = data | FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_CTL) |
+ FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA);
+ twsi_write_sw(base, val);
+}
+
+/**
+ * Reads the TWSI Control Register
+ *
+ * @base Base address for i2c
+ * @return 8-bit TWSI control register
+ */
+static u8 twsi_read_ctl(void __iomem *base)
+{
+ u64 val;
+
+ val = FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_CTL) |
+ FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA);
+ val = twsi_read_sw(base, val);
+
+ debug("%s(%p): 0x%x\n", __func__, base, (u8)val);
+ return (u8)val;
+}
+
+/**
+ * Read i2c status register
+ *
+ * @base Base address of i2c registers
+ * @return value of status register
+ */
+static u8 twsi_read_status(void __iomem *base)
+{
+ u64 val;
+
+ val = FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_STAT) |
+ FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA);
+
+ return twsi_read_sw(base, val);
+}
+
+/**
+ * Waits for an i2c operation to complete
+ *
+ * @param base Base address of registers
+ * @return 0 for success, 1 if timeout
+ */
+static int twsi_wait(void __iomem *base)
+{
+ unsigned long start = get_timer(0);
+ u8 twsi_ctl;
+
+ debug("%s(%p)\n", __func__, base);
+ do {
+ twsi_ctl = twsi_read_ctl(base);
+ twsi_ctl &= TWSI_CTL_IFLG;
+ } while (!twsi_ctl && get_timer(start) < 50);
+
+ debug(" return: %u\n", !twsi_ctl);
+ return !twsi_ctl;
+}
+
+/**
+ * Unsticks the i2c bus
+ *
+ * @base base address of registers
+ */
+static int twsi_start_unstick(void __iomem *base)
+{
+ twsi_stop(base);
+ twsi_unblock(base);
+
+ return 0;
+}
+
+/**
+ * Sends an i2c start condition
+ *
+ * @base base address of registers
+ * @return 0 for success, otherwise error
+ */
+static int twsi_start(void __iomem *base)
+{
+ int ret;
+ u8 stat;
+
+ debug("%s(%p)\n", __func__, base);
+ twsi_write_ctl(base, TWSI_CTL_STA | TWSI_CTL_ENAB);
+ ret = twsi_wait(base);
+ if (ret) {
+ stat = twsi_read_status(base);
+ debug("%s: ret: 0x%x, status: 0x%x\n", __func__, ret, stat);
+ switch (stat) {
+ case TWSI_STAT_START:
+ case TWSI_STAT_RSTART:
+ return 0;
+ case TWSI_STAT_RXADDR_ACK:
+ default:
+ return twsi_start_unstick(base);
+ }
+ }
+
+ debug("%s: success\n", __func__);
+ return 0;
+}
+
+/**
+ * Sends an i2c stop condition
+ *
+ * @base register base address
+ * @return 0 for success, -1 if error
+ */
+static int twsi_stop(void __iomem *base)
+{
+ u8 stat;
+
+ twsi_write_ctl(base, TWSI_CTL_STP | TWSI_CTL_ENAB);
+
+ stat = twsi_read_status(base);
+ if (stat != TWSI_STAT_IDLE) {
+ debug("%s: Bad status on bus@%p\n", __func__, base);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Writes data to the i2c bus
+ *
+ * @base register base address
+ * @slave_addr address of slave to write to
+ * @buffer Pointer to buffer to write
+ * @length Number of bytes in buffer to write
+ * @return 0 for success, otherwise error
+ */
+static int twsi_write_data(void __iomem *base, u8 slave_addr,
+ u8 *buffer, unsigned int length)
+{
+ unsigned int curr = 0;
+ u64 val;
+ int ret;
+
+ debug("%s(%p, 0x%x, %p, 0x%x)\n", __func__, base, slave_addr,
+ buffer, length);
+ ret = twsi_start(base);
+ if (ret) {
+ debug("%s: Could not start BUS transaction\n", __func__);
+ return -1;
+ }
+
+ ret = twsi_wait(base);
+ if (ret) {
+ debug("%s: wait failed\n", __func__);
+ return ret;
+ }
+
+ val = (u32)(slave_addr << 1) | TWSI_OP_WRITE |
+ FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_DATA) |
+ FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA);
+ twsi_write_sw(base, val);
+ twsi_write_ctl(base, TWSI_CTL_ENAB);
+
+ debug("%s: Waiting\n", __func__);
+ ret = twsi_wait(base);
+ if (ret) {
+ debug("%s: Timed out writing slave address 0x%x to target\n",
+ __func__, slave_addr);
+ return ret;
+ }
+
+ ret = twsi_read_status(base);
+ debug("%s: status: 0x%x\n", __func__, ret);
+ if (ret != TWSI_STAT_TXADDR_ACK) {
+ debug("%s: status: 0x%x\n", __func__, ret);
+ twsi_stop(base);
+ return twsi_i2c_lost_arb(ret, 0);
+ }
+
+ while (curr < length) {
+ val = buffer[curr++] |
+ FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_DATA) |
+ FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA);
+ twsi_write_sw(base, val);
+ twsi_write_ctl(base, TWSI_CTL_ENAB);
+
+ debug("%s: Writing 0x%llx\n", __func__, val);
+
+ ret = twsi_wait(base);
+ if (ret) {
+ debug("%s: Timed out writing data to 0x%x\n",
+ __func__, slave_addr);
+ return ret;
+ }
+ ret = twsi_read_status(base);
+ debug("%s: status: 0x%x\n", __func__, ret);
+ }
+
+ debug("%s: Stopping\n", __func__);
+ return twsi_stop(base);
+}
+
+/**
+ * Manually clear the I2C bus and send a stop
+ *
+ * @base register base address
+ */
+static void twsi_unblock(void __iomem *base)
+{
+ int i;
+
+ for (i = 0; i < 9; i++) {
+ writeq(0, base + TWSI_INT);
+ udelay(5);
+ writeq(TWSI_INT_SCL_OVR, base + TWSI_INT);
+ udelay(5);
+ }
+ writeq(TWSI_INT_SCL_OVR | TWSI_INT_SDA_OVR, base + TWSI_INT);
+ udelay(5);
+ writeq(TWSI_INT_SDA_OVR, base + TWSI_INT);
+ udelay(5);
+ writeq(0, base + TWSI_INT);
+ udelay(5);
+}
+
+/**
+ * Performs a read transaction on the i2c bus
+ *
+ * @base Base address of twsi registers
+ * @slave_addr i2c bus address to read from
+ * @buffer buffer to read into
+ * @length number of bytes to read
+ * @return 0 for success, otherwise error
+ */
+static int twsi_read_data(void __iomem *base, u8 slave_addr,
+ u8 *buffer, unsigned int length)
+{
+ unsigned int curr = 0;
+ u64 val;
+ int ret;
+
+ debug("%s(%p, 0x%x, %p, %u)\n", __func__, base, slave_addr,
+ buffer, length);
+ ret = twsi_start(base);
+ if (ret) {
+ debug("%s: start failed\n", __func__);
+ return ret;
+ }
+
+ ret = twsi_wait(base);
+ if (ret) {
+ debug("%s: wait failed\n", __func__);
+ return ret;
+ }
+
+ val = (u32)(slave_addr << 1) | TWSI_OP_READ |
+ FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_DATA) |
+ FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA);
+ twsi_write_sw(base, val);
+ twsi_write_ctl(base, TWSI_CTL_ENAB);
+
+ ret = twsi_wait(base);
+ if (ret) {
+ debug("%s: waiting for sending addr failed\n", __func__);
+ return ret;
+ }
+
+ ret = twsi_read_status(base);
+ debug("%s: status: 0x%x\n", __func__, ret);
+ if (ret != TWSI_STAT_RXADDR_ACK) {
+ debug("%s: status: 0x%x\n", __func__, ret);
+ twsi_stop(base);
+ return twsi_i2c_lost_arb(ret, 0);
+ }
+
+ while (curr < length) {
+ twsi_write_ctl(base, TWSI_CTL_ENAB |
+ ((curr < length - 1) ? TWSI_CTL_AAK : 0));
+
+ ret = twsi_wait(base);
+ if (ret) {
+ debug("%s: waiting for data failed\n", __func__);
+ return ret;
+ }
+
+ val = twsi_read_sw(base, val);
+ buffer[curr++] = (u8)val;
+ }
+
+ twsi_stop(base);
+
+ return 0;
+}
+
+/**
+ * Calculate the divisor values
+ *
+ * @speed Speed to set
+ * @m_div Pointer to M divisor
+ * @n_div Pointer to N divisor
+ * @return 0 for success, otherwise error
+ */
+static void twsi_calc_div(unsigned int speed, int *m_div, int *n_div)
+{
+ int io_clock_hz;
+ int tclk, fsamp;
+ int ndiv, mdiv;
+
+#if defined(CONFIG_ARCH_OCTEON) || defined(CONFIG_ARCH_OCTEONTX)
+ io_clock_hz = get_io_clock();
+ tclk = io_clock_hz / (2 * (twsi_thp() + 1));
+#elif defined(CONFIG_ARCH_OCTEONTX2)
+ /* Refclk src in mode register defaults to 100MHz clock */
+ io_clock_hz = 100000000; /* 100 Mhz */
+ tclk = io_clock_hz / (twsi_thp() + 2);
+#endif
+ debug("%s( io_clock %u tclk %u)\n", __func__, io_clock_hz, tclk);
+
+ /*
+ * Compute the clocks M divider:
+ *
+ * TWSI freq = (core freq) / (10 x (M+1) x 2 * (thp+1) x 2^N)
+ * M = ((core freq) / (10 x (TWSI freq) x 2 * (thp+1) x 2^N)) - 1
+ *
+ * For OcteonTX2 -
+ * TWSI freq = (core freq) / (10 x (M+1) x (thp+2) x 2^N)
+ * M = ((core freq) / (10 x (TWSI freq) x (thp+2) x 2^N)) - 1
+ */
+ for (ndiv = 0; ndiv < 8; ndiv++) {
+ fsamp = tclk / (1 << ndiv);
+ mdiv = fsamp / speed / 10;
+ mdiv -= 1;
+ if (mdiv < 16)
+ break;
+ }
+
+ *m_div = mdiv;
+ *n_div = ndiv;
+}
+
+/**
+ * Init I2C controller
+ *
+ * @base Base address of twsi registers
+ * @slave_addr I2C slave address to configure this controller to
+ * @return 0 for success, otherwise error
+ */
+static int twsi_init(void __iomem *base, int slaveaddr)
+{
+ u64 val;
+
+ debug("%s (%p, 0x%x)\n", __func__, base, slaveaddr);
+
+ val = slaveaddr << 1 |
+ FIELD_PREP(TWSI_SW_EOP_IA_MASK, 0) |
+ FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA) |
+ TWSI_SW_V;
+ twsi_write_sw(base, val);
+
+ /* Set slave address */
+ val = slaveaddr |
+ FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_EOP_SLAVE_ADDR) |
+ FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA) |
+ TWSI_SW_V;
+ twsi_write_sw(base, val);
+
+ return 0;
+}
+
+/**
+ * Transfers data over the i2c bus
+ *
+ * @bus i2c bus to transfer data over
+ * @msg Array of i2c messages
+ * @nmsgs Number of messages to send/receive
+ * @return 0 for success, otherwise error
+ */
+static int octeon_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct octeon_twsi *twsi = dev_get_priv(bus);
+ int ret;
+ int i;
+
+ debug("%s: %d messages\n", __func__, nmsgs);
+ for (i = 0; i < nmsgs; i++, msg++) {
+ debug("%s: chip=0x%x, len=0x%x\n", __func__, msg->addr,
+ msg->len);
+
+ if (msg->flags & I2C_M_RD) {
+ debug("%s: Reading data\n", __func__);
+ ret = twsi_read_data(twsi->base, msg->addr,
+ msg->buf, msg->len);
+ } else {
+ debug("%s: Writing data\n", __func__);
+ ret = twsi_write_data(twsi->base, msg->addr,
+ msg->buf, msg->len);
+ }
+ if (ret) {
+ debug("%s: error sending\n", __func__);
+ return -EREMOTEIO;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Set I2C bus speed
+ *
+ * @bus i2c bus to transfer data over
+ * @speed Speed in Hz to set
+ * @return 0 for success, otherwise error
+ */
+static int octeon_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ struct octeon_twsi *twsi = dev_get_priv(bus);
+ int m_div, n_div;
+ u64 val;
+
+ debug("%s(%p, %u)\n", __func__, bus, speed);
+
+ twsi_calc_div(speed, &m_div, &n_div);
+ if (m_div >= 16)
+ return -1;
+
+ val = (u32)(((m_div & 0xf) << 3) | ((n_div & 0x7) << 0)) |
+ FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_CLKCTL) |
+ FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA) |
+ TWSI_SW_V;
+ /* Only init non-slave ports */
+ writeq(val, twsi->base + TWSI_SW_TWSI);
+
+ debug("%s: Wrote 0x%llx to sw_twsi\n", __func__, val);
+ return 0;
+}
+
+/**
+ * Driver probe function
+ *
+ * @dev I2C device to probe
+ * @return 0 for success, otherwise error
+ */
+static int octeon_pci_i2c_probe(struct udevice *dev)
+{
+ struct octeon_twsi *twsi = dev_get_priv(dev);
+#if !defined(CONFIG_ARCH_OCTEON)
+ pci_dev_t bdf = dm_pci_get_bdf(dev);
+
+ debug("TWSI PCI device: %x\n", bdf);
+ dev->req_seq = PCI_FUNC(bdf);
+
+ twsi->base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
+ PCI_REGION_MEM);
+#else
+ twsi->base = dev_remap_addr(dev);
+#endif
+ debug("TWSI bus %d at %p\n", dev->seq, twsi->base);
+
+ /* Start with standard speed, real speed set via DT or cmd */
+ return twsi_init(twsi->base, CONFIG_SYS_I2C_OCTEON_SLAVE_ADDR);
+}
+
+static const struct dm_i2c_ops octeon_i2c_ops = {
+ .xfer = octeon_i2c_xfer,
+ .set_bus_speed = octeon_i2c_set_bus_speed,
+};
+
+static const struct udevice_id octeon_i2c_ids[] = {
+ { .compatible = "cavium,thunder-8890-twsi" },
+ { .compatible = "cavium,octeon-7890-twsi" },
+ { }
+};
+
+U_BOOT_DRIVER(octeon_pci_twsi) = {
+ .name = "i2c_octeon",
+ .id = UCLASS_I2C,
+ .of_match = octeon_i2c_ids,
+ .probe = octeon_pci_i2c_probe,
+ .priv_auto_alloc_size = sizeof(struct octeon_twsi),
+ .ops = &octeon_i2c_ops,
+};
+
+#if !defined(CONFIG_ARCH_OCTEON)
+static struct pci_device_id octeon_twsi_supported[] = {
+ { PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_TWSI) },
+ { },
+};
+
+U_BOOT_PCI_DEVICE(octeon_pci_twsi, octeon_twsi_supported);
+#endif
--
2.26.2
4
8
Hi Jagan
> From: Jagan Teki [mailto:jagan@amarulasolutions.com]
> Sent: Wednesday, June 03, 2020 2:57 AM
> To: Rick Jian-Zhi Chen(陳建志)
> Cc: U-Boot-Denx; Atish Patra; Palmer Dabbelt; Bin Meng; Paul Walmsley; Anup Patel; Sagar Kadam; Pragnesh Patel
> Subject: Re: [PATCH v13 00/19] RISC-V SiFive FU540 support SPL
>
> Hi Rick,
>
> On Fri, May 29, 2020 at 11:34 AM Pragnesh Patel <pragnesh.patel(a)sifive.com> wrote:
> >
> > This series add support for SPL to FU540. U-Boot SPL can boot from
> > L2 LIM (0x0800_0000) and jump to OpenSBI(FW_DYNAMIC firmware) and
> > U-Boot proper from MMC devices.
> >
> > This series is also available here [1] for testing [1]
> > https://github.com/pragnesh26992/u-boot/tree/spl
> >
> > How to test this patch:
> > 1) Go to OpenSBI-dir : make PLATFORM=generic FW_DYNAMIC=y
> > 2) export OPENSBI=<path to
> > opensbi/build/platform/generic/firmware/fw_dynamic.bin>
> > 3) Change to u-boot-dir
> > 4) make sifive_fu540_defconfig
> > 5) make all
> > 6) Format the SD card (make sure the disk has GPT, otherwise use gdisk
> > to switch)
> >
> > # sudo sgdisk --clear \
> > > --set-alignment=2 \
> > > --new=1:34:2081 --change-name=1:loader1 --typecode=1:5B193300-FC78-40CD-8002-E86C45580B47 \
> > > --new=2:2082:10273 --change-name=2:loader2 --typecode=2:2E54B353-1271-4842-806F-E436D6AF6985 \
> > > --new=3:10274: --change-name=3:rootfs --typecode=3:0FC63DAF-8483-4772-8E79-3D69D8477DE4 \
> > > /dev/sda
> >
> > 7) sudo dd if=spl/u-boot-spl.bin of=/dev/sda seek=34
> > 8) sudo dd if=u-boot.itb of=/dev/sda seek=2082
> >
> > Changes in v13:
> > - Add a new patch to set the ethernet clock rate
> > (riscv: sifive: dts: fu540: set ethernet clock rate)
> >
> > Changes in v12:
> > - Rebase on mainline U-Boot
> > Added necessary include files which are not part of common header now
> > Remove unnecessary include files
> >
> > drivers/misc/sifive-otp.c
> > +#include <linux/bitops.h>
> > +#include <linux/delay.h>
> >
> > board/sifive/fu540/fu540.c
> > -#include <common.h>
> > +#include <log.h>
> >
> > board/sifive/fu540/spl.c
> > +#include <init.h>
> > +#include <log.h>
> > +#include <linux/delay.h>
> >
> > drivers/ram/sifive/fu540_ddr.c
> > +#include <linux/bitops.h>
> >
> > arch/riscv/cpu/fu540/cpu.c
> > -#include <common.h>
> > +#include <asm/cache.h>
> >
> > arch/riscv/cpu/fu540/spl.c
> > -#include <common.h>
> > +#include <log.h>
> >
> > board/sifive/fu540/spl.c
> > -#include <common.h>
> > +#include <init.h>
> > +#include <log.h>
> > +#include <linux/delay.h>
> >
> > - Update commit description for Release ethernet clock reset
> > - Update OpenSBI building section in "doc/board/sifive/fu540.rst"
> >
> > Changes in v11:
> > - Remove TPL related code and OF_PLATDATA from FU540
> > DDR driver (drivers/ram/sifive/fu540_ddr.c)
> > - Update FU540 doc (doc/board/sifive/fu540.rst)
> > Remove unnecessary print
> >
> > Changes in v10:
> > - Update commit description for ethernet clock reset
> > (https://patchwork.ozlabs.org/patch/1289003)
> > - Update commit description for ddr clock initialization
> > (https://patchwork.ozlabs.org/patch/1289000)
> >
> > Changes in v9:
> > - Remove cache related patches from this series
> > sifive: dts: fu540: Enable L2 Cache in U-Boot
> > (https://patchwork.ozlabs.org/patch/1286705)
> > riscv: sifive: fu540: enable all cache ways from U-Boot proper
> > (https://patchwork.ozlabs.org/patch/1286706)
> > - Rename SiFive DDR driver from sdram_fu540.c to fu540_ddr.c
> > and also do some typo correction in driver
> > - Remove CONFIG_SPL_BUILD for __prci_ddr_release_reset()
> > - Release ethernet clock reset instead of ethernet clock
> > initialization
> > (https://patchwork.ozlabs.org/patch/1286697)
> > - Squash fu540 cpu patches
> > (https://patchwork.ozlabs.org/patch/1286699)
> > (https://patchwork.ozlabs.org/patch/1286700)
> > - Use spl_boot_device() instead of board_boot_order()
> >
> > Changes in v8:
> > - Remove SPL_CRC7_SUPPORT Kconfig option and compile
> > crc7.o when CONFIG_MMC_SPI selected
> > - Add "TODO" in drivers/ram/sifive/sdram_fu540.c
> > - Remove unnecessary TODO from drivers/clk/sifive/fu540-prci.c
> > - Make fu540-hifive-unleashed-a00-sdram-ddr4.dtsi file dual-licensed
> > - Add 2 new patches
> > sifive: fu540: Add sample SD gpt partition layout
> > (https://patchwork.ozlabs.org/patch/1092)
> > sifive: fu540: Add U-Boot proper sector start
> > (https://patchwork.ozlabs.org/patch/1093)
> > - Remove patch
> > riscv: Enable cpu clock if it is present
> > (https://patchwork.ozlabs.org/patch/1281573)
> > - Update doc/board/sifive/fu540.rst for PLATFORM=generic
> >
> > Changes in v7:
> > - Standardize SD gpt partition layout
> > - Add delay for SiFive OTP driver
> > - Use DM way for corepll and ddrpll
> > - Add new cpu fu540 (arch/riscv/cpu/fu540)
> > - Update document for FU540 (doc/board/sifive/fu540.rst)
> >
> > Changes in v6:
> > - Typo Correction
> > - Make fu540-c000-u-boot.dtsi and hifive-unleashed-a00-u-boot.dtsi
> > Dual Licensed
> > - Sync Hifive unleashed dts from Linux
> > - Add arch/riscv/fu540 for FU540 specific code
> >
> > Changes in v5:
> > - Return read/write bytes for sifive_otp_read and sifive_otp_write
> > - Correct Palmer's email address
> >
> > Changes in v4:
> > - Split misc DM driver patch into multiple patches
> > - Added new SPL_CRC7_SUPPORT Kconfig option
> > - Added DM driver for DDR
> > - Added clk_enable and clk_disable ops in SiFive PRCI driver
> > - Added early clock initialization for SPL in SiFive PRCI driver
> > - Added early clock initialization for SPL in SiFive PRCI driver
> > - Added SPL config options in sifive_fu540_defconfig instead of
> > creatiing a new config file for SPL
> > - Update fu540.rst on how to build and flash U-boot SPL
> >
> > Changes in v3:
> > - Remove arch-fu540 and arch-sifive from arch/riscv/include/asm/
> > - Split SPL patches into DDR and SPL and spl defconfig
> > - Update fu540/MAINTAINERS file
> > - Update fu540.rst on how to build and flash U-boot SPL
> >
> > Changes in v2:
> > - Add DM driver Sifive OTP
> > - Split SPL patches into multiple patches
> > - Add a seprate patch for _image_binary_end and crc7.c
> > - Add a seprate patch to add board -u-boot.dtsi files
> > - Update FU540 RISC-V documentation
> >
> >
> > Jagan Teki (2):
> > sifive: fu540: Add sample SD gpt partition layout
> > sifive: fu540: Add U-Boot proper sector start
> >
> > Pragnesh Patel (17):
> > misc: add driver for the SiFive otp controller
> > riscv: sifive: fu540: Use OTP DM driver for serial environment
> > variable
> > riscv: Add _image_binary_end for SPL
> > lib: Makefile: build crc7.c when CONFIG_MMC_SPI
> > riscv: sifive: dts: fu540: Add board -u-boot.dtsi files
> > sifive: fu540: add ddr driver
> > sifive: dts: fu540: Add DDR controller and phy register settings
> > riscv: sifive: dts: fu540: add U-Boot dmc node
> > clk: sifive: fu540-prci: Add clock enable and disable ops
> > clk: sifive: fu540-prci: Add ddr clock initialization
> > clk: sifive: fu540-prci: Release ethernet clock reset
> > riscv: sifive: dts: fu540: set ethernet clock rate
> > riscv: dts: sifive: Sync hifive-unleashed-a00 dts from linux
> > riscv: cpu: fu540: Add support for cpu fu540
> > riscv: sifive: fu540: add SPL configuration
> > configs: fu540: Add config options for U-Boot SPL
> > doc: sifive: fu540: Add description for OpenSBI generic platform
>
> Any plan to pull this for the release?
Applied to u-boot-riscv/master!
CI is running ..., will send a PR later.
Thanks,
Rick
>
> Jagan.
1
0
Hi Bin
> From: Bin Meng [mailto:bmeng.cn@gmail.com]
> Sent: Wednesday, May 27, 2020 5:05 PM
> To: Rick Jian-Zhi Chen(陳建志); U-Boot Mailing List
> Cc: Atish Patra; Bin Meng
> Subject: [PATCH 1/2] riscv: sbi: Remove sbi_spec_version
>
> From: Bin Meng <bin.meng(a)windriver.com>
>
> U-Boot defaults to use SBI v0.2. Howerver there is a global variable sbi_spec_version that stills refers to v0.1. Since it is not used anywhere, let's remove it.
>
> Signed-off-by: Bin Meng <bin.meng(a)windriver.com>
> ---
>
> arch/riscv/include/asm/sbi.h | 2 --
> arch/riscv/lib/sbi.c | 3 ---
> 2 files changed, 5 deletions(-)
>
> diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 453cb5c..08e1ac0 100644
> --- a/arch/riscv/include/asm/sbi.h
> +++ b/arch/riscv/include/asm/sbi.h
> @@ -77,7 +77,6 @@ enum sbi_ext_rfence_fid {
> #define SBI_FID_REMOTE_SFENCE_VMA_ASID SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID
> #endif
>
> -#define SBI_SPEC_VERSION_DEFAULT 0x1
> #define SBI_SPEC_VERSION_MAJOR_SHIFT 24
> #define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
> #define SBI_SPEC_VERSION_MINOR_MASK 0xffffff
> @@ -90,7 +89,6 @@ enum sbi_ext_rfence_fid {
> #define SBI_ERR_DENIED -4
> #define SBI_ERR_INVALID_ADDRESS -5
>
> -extern unsigned long sbi_spec_version;
> struct sbiret {
> long error;
> long value;
> diff --git a/arch/riscv/lib/sbi.c b/arch/riscv/lib/sbi.c index 993597e..f298846 100644
> --- a/arch/riscv/lib/sbi.c
> +++ b/arch/riscv/lib/sbi.c
> @@ -11,9 +11,6 @@
> #include <asm/encoding.h>
> #include <asm/sbi.h>
>
> -/* default SBI version is 0.1 */
> -unsigned long sbi_spec_version = SBI_SPEC_VERSION_DEFAULT;
Why not keep this variable and get version of openSbi automatically,
then register v01 or v02 callback function just like sbi_init() of
Atish' patch.
Thanks,
Rick
> -
> struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
> unsigned long arg1, unsigned long arg2,
> unsigned long arg3, unsigned long arg4,
> --
> 2.7.4
>
2
4