net: phy: Add gmiitorgmii converter support

This patch adds support for gmiitorgmii converter.
This converter sits between the MAC and the external phy
MAC <==> GMII2RGMII <==> RGMII_PHY.
The ethernet driver probes this bridge and this bridge driver
probes real phy driver and invokes the real phy functionalities
as requested. This bridge just needs to be configured based on
real phy negotiated speed and duplex.

Signed-off-by: Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 8c40434..f2d17aa 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -545,6 +545,9 @@
 #ifdef CONFIG_PHY_FIXED
 	phy_fixed_init();
 #endif
+#ifdef CONFIG_PHY_XILINX_GMII2RGMII
+	phy_xilinx_gmii2rgmii_init();
+#endif
 	genphy_init();
 
 	return 0;
@@ -917,6 +920,41 @@
 	phydev->dev = dev;
 	debug("%s connected to %s\n", dev->name, phydev->drv->name);
 }
+
+#ifdef CONFIG_PHY_XILINX_GMII2RGMII
+#ifdef CONFIG_DM_ETH
+static struct phy_device *phy_connect_gmii2rgmii(struct mii_dev *bus,
+						 struct udevice *dev,
+						 phy_interface_t interface)
+#else
+static struct phy_device *phy_connect_gmii2rgmii(struct mii_dev *bus,
+						 struct eth_device *dev,
+						 phy_interface_t interface)
+#endif
+{
+	struct phy_device *phydev = NULL;
+	int sn = dev_of_offset(dev);
+	int off;
+
+	while (sn > 0) {
+		off = fdt_node_offset_by_compatible(gd->fdt_blob, sn,
+						    "xlnx,gmii-to-rgmii-1.0");
+		if (off > 0) {
+			phydev = phy_device_create(bus, off,
+						   PHY_GMII2RGMII_ID, false,
+						   interface);
+			break;
+		}
+		if (off == -FDT_ERR_NOTFOUND)
+			sn = fdt_first_subnode(gd->fdt_blob, sn);
+		else
+			printf("%s: Error finding compat string:%d\n",
+			       __func__, off);
+	}
+
+	return phydev;
+}
+#endif
 
 #ifdef CONFIG_PHY_FIXED
 #ifdef CONFIG_DM_ETH
@@ -964,6 +1002,10 @@
 #ifdef CONFIG_PHY_FIXED
 	phydev = phy_connect_fixed(bus, dev, interface);
 #endif
+#ifdef CONFIG_PHY_XILINX_GMII2RGMII
+	if (!phydev)
+		phydev = phy_connect_gmii2rgmii(bus, dev, interface);
+#endif
 
 	if (!phydev)
 		phydev = phy_find_by_mask(bus, mask, interface);