net: macb: Add support for Xilinx Zynq SoC

Although Xilinx Zynq SoC was using MACB similar hardware. However,
U-boot MACB driver was not supporting Xilinx Zynq SoC. This patch is
to add support for the Xilinx Zynq SoC to the existing MACB network
driver.

This patch is to add Zynq GEM DMA Config, provide callback
function for different linkspeed for case of using Xilinx Zynq
Programmable Logic as GMII to RGMII converter.

This patch convert the return value to use error codes.

Signed-off-by: Wilson Lee <wilson.lee@ni.com>
Cc: Chen Yee Chew <chen.yee.chew@ni.com>
Cc: Keng Soon Cheah <keng.soon.cheah@ni.com>
Cc: Joe Hershberger <joe.hershberger@ni.com>
Cc: Wenyou Yang <wenyou.yang@atmel.com>
Acked-by: Joe Hershberger <joe.hershberger@ni.com>
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index f9373db..e62aefc 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -52,6 +52,22 @@
 #define MACB_TX_TIMEOUT		1000
 #define MACB_AUTONEG_TIMEOUT	5000000
 
+#ifdef CONFIG_MACB_ZYNQ
+/* INCR4 AHB bursts */
+#define MACB_ZYNQ_GEM_DMACR_BLENGTH		0x00000004
+/* Use full configured addressable space (8 Kb) */
+#define MACB_ZYNQ_GEM_DMACR_RXSIZE		0x00000300
+/* Use full configured addressable space (4 Kb) */
+#define MACB_ZYNQ_GEM_DMACR_TXSIZE		0x00000400
+/* Set RXBUF with use of 128 byte */
+#define MACB_ZYNQ_GEM_DMACR_RXBUF		0x00020000
+#define MACB_ZYNQ_GEM_DMACR_INIT \
+				(MACB_ZYNQ_GEM_DMACR_BLENGTH | \
+				MACB_ZYNQ_GEM_DMACR_RXSIZE | \
+				MACB_ZYNQ_GEM_DMACR_TXSIZE | \
+				MACB_ZYNQ_GEM_DMACR_RXBUF)
+#endif
+
 struct macb_dma_desc {
 	u32	addr;
 	u32	ctrl;
@@ -461,13 +477,25 @@
 		phy_id = macb_mdio_read(macb, MII_PHYSID1);
 		if (phy_id != 0xffff) {
 			printf("%s: PHY present at %d\n", name, i);
-			return 1;
+			return 0;
 		}
 	}
 
 	/* PHY isn't up to snuff */
 	printf("%s: PHY not found\n", name);
 
+	return -ENODEV;
+}
+
+/**
+ * macb_linkspd_cb - Linkspeed change callback function
+ * @regs:	Base Register of MACB devices
+ * @speed:	Linkspeed
+ * Returns 0 when operation success and negative errno number
+ * when operation failed.
+ */
+int __weak macb_linkspd_cb(void *regs, unsigned int speed)
+{
 	return 0;
 }
 
@@ -483,18 +511,20 @@
 	u32 ncfgr;
 	u16 phy_id, status, adv, lpa;
 	int media, speed, duplex;
+	int ret;
 	int i;
 
 	arch_get_mdio_control(name);
 	/* Auto-detect phy_addr */
-	if (!macb_phy_find(macb, name))
-		return 0;
+	ret = macb_phy_find(macb, name);
+	if (ret)
+		return ret;
 
 	/* Check if the PHY is up to snuff... */
 	phy_id = macb_mdio_read(macb, MII_PHYSID1);
 	if (phy_id == 0xffff) {
 		printf("%s: No PHY present\n", name);
-		return 0;
+		return -ENODEV;
 	}
 
 #ifdef CONFIG_PHYLIB
@@ -530,7 +560,7 @@
 	if (!(status & BMSR_LSTATUS)) {
 		printf("%s: link down (status: 0x%04x)\n",
 		       name, status);
-		return 0;
+		return -ENETDOWN;
 	}
 
 	/* First check for GMAC and that it is GiB capable */
@@ -554,7 +584,11 @@
 
 			macb_writel(macb, NCFGR, ncfgr);
 
+			ret = macb_linkspd_cb(macb->regs, _1000BASET);
+			if (ret)
+				return ret;
+
-			return 1;
+			return 0;
 		}
 	}
 
@@ -573,13 +607,21 @@
 
 	ncfgr = macb_readl(macb, NCFGR);
 	ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD) | GEM_BIT(GBE));
-	if (speed)
+	if (speed) {
 		ncfgr |= MACB_BIT(SPD);
+		ret = macb_linkspd_cb(macb->regs, _100BASET);
+	} else {
+		ret = macb_linkspd_cb(macb->regs, _10BASET);
+	}
+
+	if (ret)
+		return ret;
+
 	if (duplex)
 		ncfgr |= MACB_BIT(FD);
 	macb_writel(macb, NCFGR, ncfgr);
 
-	return 1;
+	return 0;
 }
 
 static int gmac_init_multi_queues(struct macb_device *macb)
@@ -616,6 +658,7 @@
 	struct macb_device *macb = dev_get_priv(dev);
 #endif
 	unsigned long paddr;
+	int ret;
 	int i;
 
 	/*
@@ -649,6 +692,10 @@
 	macb->tx_tail = 0;
 	macb->next_rx_tail = 0;
 
+#ifdef CONFIG_MACB_ZYNQ
+	macb_writel(macb, DMACFG, MACB_ZYNQ_GEM_DMACR_INIT);
+#endif
+
 	macb_writel(macb, RBQP, macb->rx_ring_dma);
 	macb_writel(macb, TBQP, macb->tx_ring_dma);
 
@@ -709,11 +756,12 @@
 	}
 
 #ifdef CONFIG_DM_ETH
-	if (!macb_phy_init(dev, name))
+	ret = macb_phy_init(dev, name);
 #else
-	if (!macb_phy_init(macb, name))
+	ret = macb_phy_init(macb, name);
 #endif
-		return -1;
+	if (ret)
+		return ret;
 
 	/* Enable TX and RX */
 	macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE));
@@ -1013,9 +1061,15 @@
 	if (ret)
 		return -EINVAL;
 
+	/*
+	 * Zynq clock driver didn't support for enable or disable
+	 * clock. Hence, clk_enable() didn't apply for Zynq
+	 */
+#ifndef CONFIG_MACB_ZYNQ
 	ret = clk_enable(&clk);
 	if (ret)
 		return ret;
+#endif
 
 	clk_rate = clk_get_rate(&clk);
 	if (!clk_rate)
@@ -1080,6 +1134,17 @@
 	mdio_unregister(macb->bus);
 	mdio_free(macb->bus);
 
+	return 0;
+}
+
+/**
+ * macb_late_eth_ofdata_to_platdata
+ * @dev:	udevice struct
+ * Returns 0 when operation success and negative errno number
+ * when operation failed.
+ */
+int __weak macb_late_eth_ofdata_to_platdata(struct udevice *dev)
+{
 	return 0;
 }
 
@@ -1088,7 +1153,8 @@
 	struct eth_pdata *pdata = dev_get_platdata(dev);
 
 	pdata->iobase = devfdt_get_addr(dev);
-	return 0;
+
+	return macb_late_eth_ofdata_to_platdata(dev);
 }
 
 static const struct udevice_id macb_eth_ids[] = {
@@ -1097,6 +1163,7 @@
 	{ .compatible = "atmel,sama5d2-gem" },
 	{ .compatible = "atmel,sama5d3-gem" },
 	{ .compatible = "atmel,sama5d4-gem" },
+	{ .compatible = "cdns,zynq-gem" },
 	{ }
 };