[U-Boot] [RFC PATCH] net: gem: Add support for more PHYs on MDIO bus

Michal Simek michal.simek at xilinx.com
Thu Feb 1 12:42:15 UTC 2018


Find out MDIO bus and enable MDIO access to it if this is done via
different controller.

Signed-off-by: Michal Simek <michal.simek at xilinx.com>
---

Hi Joe,

this is the code I have hacked a year ago for ZynqMP where we can have
configuration that 4 gems are enabled but they share the same MDIO bus
which can be assigned to only gem. Normally recommendation is that you
should assign it to IP which is required for boot and this is suitable I
would say for almost everybody.
But for testing purpose it will be good to support sharing mdio bus
between others IPs. This hack is "enabling" this for others gem but not
across different ethernet drivers.
And my question is if there is any solution which can be used now for
handling it. Or even this should work even now but we do something
wrong.

I am refreshing this topic based on communication with Tomasz
Gorochowik when he wanted to separate mdio part but it is not compatible
with solution used in Linux which is pattern we should follow.

Note: I tested it only on zcu102 with the standard configuration but
Tomasz confirmed that this is still working with shared mdio bus.

Thanks,
Michal

---
 drivers/net/zynq_gem.c | 37 ++++++++++++++++++++++++++++++-------
 1 file changed, 30 insertions(+), 7 deletions(-)

diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c
index 2cc49bca922a..33245ec36e67 100644
--- a/drivers/net/zynq_gem.c
+++ b/drivers/net/zynq_gem.c
@@ -177,6 +177,7 @@ struct zynq_gem_priv {
 	int phyaddr;
 	int init;
 	struct zynq_gem_regs *iobase;
+	struct zynq_gem_regs *mdiobase;
 	phy_interface_t interface;
 	struct phy_device *phydev;
 	int phy_of_handle;
@@ -189,7 +190,7 @@ static u32 phy_setup_op(struct zynq_gem_priv *priv, u32 phy_addr, u32 regnum,
 			u32 op, u16 *data)
 {
 	u32 mgtcr;
-	struct zynq_gem_regs *regs = priv->iobase;
+	struct zynq_gem_regs *regs = priv->mdiobase;
 	int err;
 
 	err = wait_for_bit_le32(&regs->nwsr, ZYNQ_GEM_NWSR_MDIOIDLE_MASK,
@@ -314,7 +315,7 @@ static int zynq_phy_init(struct udevice *dev)
 {
 	int ret;
 	struct zynq_gem_priv *priv = dev_get_priv(dev);
-	struct zynq_gem_regs *regs = priv->iobase;
+	struct zynq_gem_regs *regs_mdio = priv->mdiobase;
 	const u32 supported = SUPPORTED_10baseT_Half |
 			SUPPORTED_10baseT_Full |
 			SUPPORTED_100baseT_Half |
@@ -323,7 +324,7 @@ static int zynq_phy_init(struct udevice *dev)
 			SUPPORTED_1000baseT_Full;
 
 	/* Enable only MDIO bus */
-	writel(ZYNQ_GEM_NWCTRL_MDEN_MASK, &regs->nwctrl);
+	writel(ZYNQ_GEM_NWCTRL_MDEN_MASK, &regs_mdio->nwctrl);
 
 	if (priv->interface != PHY_INTERFACE_MODE_SGMII) {
 		ret = phy_detection(dev);
@@ -355,6 +356,7 @@ static int zynq_gem_init(struct udevice *dev)
 	unsigned long clk_rate = 0;
 	struct zynq_gem_priv *priv = dev_get_priv(dev);
 	struct zynq_gem_regs *regs = priv->iobase;
+	struct zynq_gem_regs *regs_mdio = priv->mdiobase;
 	struct emac_bd *dummy_tx_bd = &priv->tx_bd[TX_FREE_DESC];
 	struct emac_bd *dummy_rx_bd = &priv->tx_bd[TX_FREE_DESC + 2];
 
@@ -397,7 +399,7 @@ static int zynq_gem_init(struct udevice *dev)
 		writel(ZYNQ_GEM_DMACR_INIT, &regs->dmacr);
 
 		/* Setup for Network Control register, MDIO, Rx and Tx enable */
-		setbits_le32(&regs->nwctrl, ZYNQ_GEM_NWCTRL_MDEN_MASK);
+		setbits_le32(&regs_mdio->nwctrl, ZYNQ_GEM_NWCTRL_MDEN_MASK);
 
 		/* Disable the second priority queue */
 		dummy_tx_bd->addr = 0;
@@ -623,6 +625,7 @@ static int zynq_gem_probe(struct udevice *dev)
 	void *bd_space;
 	struct zynq_gem_priv *priv = dev_get_priv(dev);
 	int ret;
+	char name[MDIO_NAME_LEN];
 
 	/* Align rxbuffers to ARCH_DMA_MINALIGN */
 	priv->rxbuffers = memalign(ARCH_DMA_MINALIGN, RX_BUF * PKTSIZE_ALIGN);
@@ -648,6 +651,9 @@ static int zynq_gem_probe(struct udevice *dev)
 	priv->bus->write = zynq_gem_miiphy_write;
 	priv->bus->priv = priv;
 
+	snprintf(name, MDIO_NAME_LEN, "gem%lx", (ulong)priv->iobase);
+	strncpy(priv->bus->name, name, MDIO_NAME_LEN);
+
 	ret = mdio_register_seq(priv->bus, dev->seq);
 	if (ret)
 		return ret;
@@ -682,6 +688,8 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev)
 	struct zynq_gem_priv *priv = dev_get_priv(dev);
 	int node = dev_of_offset(dev);
 	const char *phy_mode;
+	fdt_addr_t addr;
+	int parent;
 
 	pdata->iobase = (phys_addr_t)devfdt_get_addr(dev);
 	priv->iobase = (struct zynq_gem_regs *)pdata->iobase;
@@ -690,10 +698,24 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev)
 
 	priv->phy_of_handle = fdtdec_lookup_phandle(gd->fdt_blob, node,
 						    "phy-handle");
-	if (priv->phy_of_handle > 0)
+	if (priv->phy_of_handle > 0) {
 		priv->phyaddr = fdtdec_get_int(gd->fdt_blob,
 					priv->phy_of_handle, "reg", -1);
 
+		parent = fdt_parent_offset(gd->fdt_blob, priv->phy_of_handle);
+		addr = fdtdec_get_addr(gd->fdt_blob, parent, "reg");
+
+		if (addr == FDT_ADDR_T_NONE) {
+			printf("MDIO bus not found %x %x, %x\n",
+			       node, priv->phy_of_handle, parent);
+			return -ENODEV;
+		}
+
+		priv->mdiobase = (struct zynq_gem_regs *)addr;
+	} else {
+		priv->mdiobase = priv->iobase;
+	}
+
 	phy_mode = fdt_getprop(gd->fdt_blob, node, "phy-mode", NULL);
 	if (phy_mode)
 		pdata->phy_interface = phy_get_interface_by_name(phy_mode);
@@ -706,8 +728,9 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev)
 	priv->int_pcs = fdtdec_get_bool(gd->fdt_blob, node,
 					"is-internal-pcspma");
 
-	printf("ZYNQ GEM: %lx, phyaddr %x, interface %s\n", (ulong)priv->iobase,
-	       priv->phyaddr, phy_string_for_interface(priv->interface));
+	printf("ZYNQ GEM: %lx, mdio bus %lx, phyaddr %d, interface %s\n",
+	       (ulong)priv->iobase, (ulong)priv->mdiobase, priv->phyaddr,
+	       phy_string_for_interface(priv->interface));
 
 	return 0;
 }
-- 
1.9.1



More information about the U-Boot mailing list