net: dwc_eth_qos: add dwc eqos for imx support

Add dwc eqos for imx support.

Reviewed-by: Ye Li <ye.li@nxp.com>
Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
index bdddbde..75c7066 100644
--- a/drivers/net/dwc_eth_qos.c
+++ b/drivers/net/dwc_eth_qos.c
@@ -81,6 +81,7 @@
 #define EQOS_MAC_CONFIGURATION_PS			BIT(15)
 #define EQOS_MAC_CONFIGURATION_FES			BIT(14)
 #define EQOS_MAC_CONFIGURATION_DM			BIT(13)
+#define EQOS_MAC_CONFIGURATION_LM			BIT(12)
 #define EQOS_MAC_CONFIGURATION_TE			BIT(1)
 #define EQOS_MAC_CONFIGURATION_RE			BIT(0)
 
@@ -102,11 +103,19 @@
 #define EQOS_MAC_RXQ_CTRL2_PSRQ0_SHIFT			0
 #define EQOS_MAC_RXQ_CTRL2_PSRQ0_MASK			0xff
 
+#define EQOS_MAC_HW_FEATURE0_MMCSEL_SHIFT		8
+#define EQOS_MAC_HW_FEATURE0_HDSEL_SHIFT		2
+#define EQOS_MAC_HW_FEATURE0_GMIISEL_SHIFT		1
+#define EQOS_MAC_HW_FEATURE0_MIISEL_SHIFT		0
+
 #define EQOS_MAC_HW_FEATURE1_TXFIFOSIZE_SHIFT		6
 #define EQOS_MAC_HW_FEATURE1_TXFIFOSIZE_MASK		0x1f
 #define EQOS_MAC_HW_FEATURE1_RXFIFOSIZE_SHIFT		0
 #define EQOS_MAC_HW_FEATURE1_RXFIFOSIZE_MASK		0x1f
 
+#define EQOS_MAC_HW_FEATURE3_ASP_SHIFT			28
+#define EQOS_MAC_HW_FEATURE3_ASP_MASK			0x3
+
 #define EQOS_MAC_MDIO_ADDRESS_PA_SHIFT			21
 #define EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT			16
 #define EQOS_MAC_MDIO_ADDRESS_CR_SHIFT			8
@@ -154,6 +163,8 @@
 #define EQOS_MTL_RXQ0_OPERATION_MODE_RFA_MASK		0x3f
 #define EQOS_MTL_RXQ0_OPERATION_MODE_EHFC		BIT(7)
 #define EQOS_MTL_RXQ0_OPERATION_MODE_RSF		BIT(5)
+#define EQOS_MTL_RXQ0_OPERATION_MODE_FEP		BIT(4)
+#define EQOS_MTL_RXQ0_OPERATION_MODE_FUP		BIT(3)
 
 #define EQOS_MTL_RXQ0_DEBUG_PRXQ_SHIFT			16
 #define EQOS_MTL_RXQ0_DEBUG_PRXQ_MASK			0x7fff
@@ -368,7 +379,7 @@
 #endif
 }
 
-static void eqos_inval_desc_stm32(void *desc)
+static void eqos_inval_desc_generic(void *desc)
 {
 #ifndef CONFIG_SYS_NONCACHED_MEMORY
 	unsigned long start = rounddown((unsigned long)desc, ARCH_DMA_MINALIGN);
@@ -386,7 +397,7 @@
 #endif
 }
 
-static void eqos_flush_desc_stm32(void *desc)
+static void eqos_flush_desc_generic(void *desc)
 {
 #ifndef CONFIG_SYS_NONCACHED_MEMORY
 	unsigned long start = rounddown((unsigned long)desc, ARCH_DMA_MINALIGN);
@@ -405,7 +416,7 @@
 	invalidate_dcache_range(start, end);
 }
 
-static void eqos_inval_buffer_stm32(void *buf, size_t size)
+static void eqos_inval_buffer_generic(void *buf, size_t size)
 {
 	unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN);
 	unsigned long end = roundup((unsigned long)buf + size,
@@ -419,7 +430,7 @@
 	flush_cache((unsigned long)buf, size);
 }
 
-static void eqos_flush_buffer_stm32(void *buf, size_t size)
+static void eqos_flush_buffer_generic(void *buf, size_t size)
 {
 	unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN);
 	unsigned long end = roundup((unsigned long)buf + size,
@@ -522,6 +533,7 @@
 
 static int eqos_start_clks_tegra186(struct udevice *dev)
 {
+#ifdef CONFIG_CLK
 	struct eqos_priv *eqos = dev_get_priv(dev);
 	int ret;
 
@@ -562,10 +574,12 @@
 		pr_err("clk_enable(clk_tx) failed: %d", ret);
 		goto err_disable_clk_ptp_ref;
 	}
+#endif
 
 	debug("%s: OK\n", __func__);
 	return 0;
 
+#ifdef CONFIG_CLK
 err_disable_clk_ptp_ref:
 	clk_disable(&eqos->clk_ptp_ref);
 err_disable_clk_rx:
@@ -577,10 +591,12 @@
 err:
 	debug("%s: FAILED: %d\n", __func__, ret);
 	return ret;
+#endif
 }
 
 static int eqos_start_clks_stm32(struct udevice *dev)
 {
+#ifdef CONFIG_CLK
 	struct eqos_priv *eqos = dev_get_priv(dev);
 	int ret;
 
@@ -611,10 +627,12 @@
 			goto err_disable_clk_tx;
 		}
 	}
+#endif
 
 	debug("%s: OK\n", __func__);
 	return 0;
 
+#ifdef CONFIG_CLK
 err_disable_clk_tx:
 	clk_disable(&eqos->clk_tx);
 err_disable_clk_rx:
@@ -624,10 +642,17 @@
 err:
 	debug("%s: FAILED: %d\n", __func__, ret);
 	return ret;
+#endif
+}
+
+static int eqos_start_clks_imx(struct udevice *dev)
+{
+	return 0;
 }
 
 static void eqos_stop_clks_tegra186(struct udevice *dev)
 {
+#ifdef CONFIG_CLK
 	struct eqos_priv *eqos = dev_get_priv(dev);
 
 	debug("%s(dev=%p):\n", __func__, dev);
@@ -637,12 +662,14 @@
 	clk_disable(&eqos->clk_rx);
 	clk_disable(&eqos->clk_master_bus);
 	clk_disable(&eqos->clk_slave_bus);
+#endif
 
 	debug("%s: OK\n", __func__);
 }
 
 static void eqos_stop_clks_stm32(struct udevice *dev)
 {
+#ifdef CONFIG_CLK
 	struct eqos_priv *eqos = dev_get_priv(dev);
 
 	debug("%s(dev=%p):\n", __func__, dev);
@@ -652,10 +679,16 @@
 	clk_disable(&eqos->clk_master_bus);
 	if (clk_valid(&eqos->clk_ck))
 		clk_disable(&eqos->clk_ck);
+#endif
 
 	debug("%s: OK\n", __func__);
 }
 
+static void eqos_stop_clks_imx(struct udevice *dev)
+{
+	/* empty */
+}
+
 static int eqos_start_resets_tegra186(struct udevice *dev)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
@@ -723,6 +756,11 @@
 	return 0;
 }
 
+static int eqos_start_resets_imx(struct udevice *dev)
+{
+	return 0;
+}
+
 static int eqos_stop_resets_tegra186(struct udevice *dev)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
@@ -750,6 +788,11 @@
 	return 0;
 }
 
+static int eqos_stop_resets_imx(struct udevice *dev)
+{
+	return 0;
+}
+
 static int eqos_calibrate_pads_tegra186(struct udevice *dev)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
@@ -804,16 +847,30 @@
 
 static ulong eqos_get_tick_clk_rate_tegra186(struct udevice *dev)
 {
+#ifdef CONFIG_CLK
 	struct eqos_priv *eqos = dev_get_priv(dev);
 
 	return clk_get_rate(&eqos->clk_slave_bus);
+#else
+	return 0;
+#endif
 }
 
 static ulong eqos_get_tick_clk_rate_stm32(struct udevice *dev)
 {
+#ifdef CONFIG_CLK
 	struct eqos_priv *eqos = dev_get_priv(dev);
 
 	return clk_get_rate(&eqos->clk_master_bus);
+#else
+	return 0;
+#endif
+}
+
+static ulong eqos_get_tick_clk_rate_imx(struct udevice *dev)
+{
+	/* TODO: retrieve from CSR clock */
+	return 100 * 1000000;
 }
 
 static int eqos_calibrate_pads_stm32(struct udevice *dev)
@@ -821,11 +878,21 @@
 	return 0;
 }
 
+static int eqos_calibrate_pads_imx(struct udevice *dev)
+{
+	return 0;
+}
+
 static int eqos_disable_calibration_stm32(struct udevice *dev)
 {
 	return 0;
 }
 
+static int eqos_disable_calibration_imx(struct udevice *dev)
+{
+	return 0;
+}
+
 static int eqos_set_full_duplex(struct udevice *dev)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
@@ -890,6 +957,7 @@
 
 static int eqos_set_tx_clk_speed_tegra186(struct udevice *dev)
 {
+#ifdef CONFIG_CLK
 	struct eqos_priv *eqos = dev_get_priv(dev);
 	ulong rate;
 	int ret;
@@ -916,6 +984,7 @@
 		pr_err("clk_set_rate(tx_clk, %lu) failed: %d", rate, ret);
 		return ret;
 	}
+#endif
 
 	return 0;
 }
@@ -925,6 +994,11 @@
 	return 0;
 }
 
+static int eqos_set_tx_clk_speed_imx(struct udevice *dev)
+{
+	return 0;
+}
+
 static int eqos_adjust_link(struct udevice *dev)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
@@ -1131,6 +1205,7 @@
 	}
 
 	/* Configure MTL */
+	writel(0x60, &eqos->mtl_regs->txq0_quantum_weight - 0x100);
 
 	/* Enable Store and Forward mode for TX */
 	/* Program Tx operating mode */
@@ -1144,7 +1219,9 @@
 
 	/* Enable Store and Forward mode for RX, since no jumbo frame */
 	setbits_le32(&eqos->mtl_regs->rxq0_operation_mode,
-		     EQOS_MTL_RXQ0_OPERATION_MODE_RSF);
+		     EQOS_MTL_RXQ0_OPERATION_MODE_RSF |
+		     EQOS_MTL_RXQ0_OPERATION_MODE_FEP |
+		     EQOS_MTL_RXQ0_OPERATION_MODE_FUP);
 
 	/* Transmit/Receive queue fifo size; use all RAM for 1 queue */
 	val = readl(&eqos->mac_regs->hw_feature1);
@@ -1220,6 +1297,19 @@
 			eqos->config->config_mac <<
 			EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT);
 
+	clrsetbits_le32(&eqos->mac_regs->rxq_ctrl0,
+			EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK <<
+			EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT,
+			0x2 <<
+			EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT);
+
+	/* Multicast and Broadcast Queue Enable */
+	setbits_le32(&eqos->mac_regs->unused_0a4,
+		     0x00100000);
+	/* enable promise mode */
+	setbits_le32(&eqos->mac_regs->unused_004[1],
+		     0x1);
+
 	/* Set TX flow control parameters */
 	/* Set Pause Time */
 	setbits_le32(&eqos->mac_regs->q0_tx_flow_ctrl,
@@ -1297,7 +1387,11 @@
 		rx_desc->des0 = (u32)(ulong)(eqos->rx_dma_buf +
 					     (i * EQOS_MAX_PACKET_SIZE));
 		rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V;
+		mb();
 		eqos->config->ops->eqos_flush_desc(rx_desc);
+		eqos->config->ops->eqos_inval_buffer(eqos->rx_dma_buf +
+						(i * EQOS_MAX_PACKET_SIZE),
+						EQOS_MAX_PACKET_SIZE);
 	}
 
 	writel(0, &eqos->dma_regs->ch0_txdesc_list_haddress);
@@ -1311,14 +1405,12 @@
 	       &eqos->dma_regs->ch0_rxdesc_ring_length);
 
 	/* Enable everything */
-
-	setbits_le32(&eqos->mac_regs->configuration,
-		     EQOS_MAC_CONFIGURATION_TE | EQOS_MAC_CONFIGURATION_RE);
-
 	setbits_le32(&eqos->dma_regs->ch0_tx_control,
 		     EQOS_DMA_CH0_TX_CONTROL_ST);
 	setbits_le32(&eqos->dma_regs->ch0_rx_control,
 		     EQOS_DMA_CH0_RX_CONTROL_SR);
+	setbits_le32(&eqos->mac_regs->configuration,
+		     EQOS_MAC_CONFIGURATION_TE | EQOS_MAC_CONFIGURATION_RE);
 
 	/* TX tail pointer not written until we need to TX a packet */
 	/*
@@ -1483,6 +1575,8 @@
 		return -EINVAL;
 	}
 
+	eqos->config->ops->eqos_inval_buffer(packet, length);
+
 	rx_desc = &(eqos->rx_descs[eqos->rx_desc_idx]);
 
 	rx_desc->des0 = 0;
@@ -1759,17 +1853,42 @@
 	return PHY_INTERFACE_MODE_MII;
 }
 
+static int eqos_probe_resources_imx(struct udevice *dev)
+{
+	struct eqos_priv *eqos = dev_get_priv(dev);
+	phy_interface_t interface;
+
+	debug("%s(dev=%p):\n", __func__, dev);
+
+	interface = eqos->config->interface(dev);
+
+	if (interface == PHY_INTERFACE_MODE_NONE) {
+		pr_err("Invalid PHY interface\n");
+		return -EINVAL;
+	}
+
+	debug("%s: OK\n", __func__);
+	return 0;
+}
+
+static phy_interface_t eqos_get_interface_imx(struct udevice *dev)
+{
+	return PHY_INTERFACE_MODE_RGMII;
+}
+
 static int eqos_remove_resources_tegra186(struct udevice *dev)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
 
 	debug("%s(dev=%p):\n", __func__, dev);
 
+#ifdef CONFIG_CLK
 	clk_free(&eqos->clk_tx);
 	clk_free(&eqos->clk_ptp_ref);
 	clk_free(&eqos->clk_rx);
 	clk_free(&eqos->clk_slave_bus);
 	clk_free(&eqos->clk_master_bus);
+#endif
 	dm_gpio_free(dev, &eqos->phy_reset_gpio);
 	reset_free(&eqos->reset_ctl);
 
@@ -1779,6 +1898,7 @@
 
 static int eqos_remove_resources_stm32(struct udevice *dev)
 {
+#ifdef CONFIG_CLK
 	struct eqos_priv *eqos = dev_get_priv(dev);
 
 	debug("%s(dev=%p):\n", __func__, dev);
@@ -1788,6 +1908,7 @@
 	clk_free(&eqos->clk_master_bus);
 	if (clk_valid(&eqos->clk_ck))
 		clk_free(&eqos->clk_ck);
+#endif
 
 	if (dm_gpio_is_valid(&eqos->phy_reset_gpio))
 		dm_gpio_free(dev, &eqos->phy_reset_gpio);
@@ -1796,6 +1917,11 @@
 	return 0;
 }
 
+static int eqos_remove_resources_imx(struct udevice *dev)
+{
+	return 0;
+}
+
 static int eqos_probe(struct udevice *dev)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
@@ -1921,10 +2047,10 @@
 };
 
 static struct eqos_ops eqos_stm32_ops = {
-	.eqos_inval_desc = eqos_inval_desc_stm32,
-	.eqos_flush_desc = eqos_flush_desc_stm32,
-	.eqos_inval_buffer = eqos_inval_buffer_stm32,
-	.eqos_flush_buffer = eqos_flush_buffer_stm32,
+	.eqos_inval_desc = eqos_inval_desc_generic,
+	.eqos_flush_desc = eqos_flush_desc_generic,
+	.eqos_inval_buffer = eqos_inval_buffer_generic,
+	.eqos_flush_buffer = eqos_flush_buffer_generic,
 	.eqos_probe_resources = eqos_probe_resources_stm32,
 	.eqos_remove_resources = eqos_remove_resources_stm32,
 	.eqos_stop_resets = eqos_stop_resets_stm32,
@@ -1947,6 +2073,33 @@
 	.ops = &eqos_stm32_ops
 };
 
+static struct eqos_ops eqos_imx_ops = {
+	.eqos_inval_desc = eqos_inval_desc_generic,
+	.eqos_flush_desc = eqos_flush_desc_generic,
+	.eqos_inval_buffer = eqos_inval_buffer_generic,
+	.eqos_flush_buffer = eqos_flush_buffer_generic,
+	.eqos_probe_resources = eqos_probe_resources_imx,
+	.eqos_remove_resources = eqos_remove_resources_imx,
+	.eqos_stop_resets = eqos_stop_resets_imx,
+	.eqos_start_resets = eqos_start_resets_imx,
+	.eqos_stop_clks = eqos_stop_clks_imx,
+	.eqos_start_clks = eqos_start_clks_imx,
+	.eqos_calibrate_pads = eqos_calibrate_pads_imx,
+	.eqos_disable_calibration = eqos_disable_calibration_imx,
+	.eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_imx,
+	.eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_imx
+};
+
+struct eqos_config eqos_imx_config = {
+	.reg_access_always_ok = false,
+	.mdio_wait = 10000,
+	.swr_wait = 50,
+	.config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB,
+	.config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300,
+	.interface = eqos_get_interface_imx,
+	.ops = &eqos_imx_ops
+};
+
 static const struct udevice_id eqos_ids[] = {
 	{
 		.compatible = "nvidia,tegra186-eqos",
@@ -1956,6 +2109,10 @@
 		.compatible = "snps,dwmac-4.20a",
 		.data = (ulong)&eqos_stm32_config
 	},
+	{
+		.compatible = "fsl,imx-eqos",
+		.data = (ulong)&eqos_imx_config
+	},
 
 	{ }
 };
@@ -1963,7 +2120,7 @@
 U_BOOT_DRIVER(eth_eqos) = {
 	.name = "eth_eqos",
 	.id = UCLASS_ETH,
-	.of_match = eqos_ids,
+	.of_match = of_match_ptr(eqos_ids),
 	.probe = eqos_probe,
 	.remove = eqos_remove,
 	.ops = &eqos_ops,