All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 1/2] net: macb: Add MDIO driver for accessing multiple PHY devices
@ 2016-05-13  9:26 ` Harini Katakam
  0 siblings, 0 replies; 17+ messages in thread
From: Harini Katakam @ 2016-05-13  9:26 UTC (permalink / raw)
  To: nicolas.ferre, davem, robh+dt, pawel.moll, mark.rutland,
	ijc+devicetree, galak, harinikatakamlinux
  Cc: netdev, linux-kernel, devicetree, harinik, punnaia, michals

This patch is to add support for the hardware with multiple ethernet
MAC controllers and a single MDIO bus connected to multiple PHY devices.
MDIO lines are connected to any one of the ethernet MAC controllers and
all the PHY devices will be accessed using the PHY maintenance interface
in that MAC controller. This handling along with PHY functionality is
moved to macb_mdio.c

Signed-off-by: Punnaiah Choudary Kalluri <punnaia@xilinx.com>
Signed-off-by: Harini Katakam <harinik@xilinx.com>
---
 drivers/net/ethernet/cadence/Makefile    |    2 +-
 drivers/net/ethernet/cadence/macb.c      |  183 ++++----------------
 drivers/net/ethernet/cadence/macb.h      |    2 +
 drivers/net/ethernet/cadence/macb_mdio.c |  266 ++++++++++++++++++++++++++++++
 4 files changed, 302 insertions(+), 151 deletions(-)
 create mode 100644 drivers/net/ethernet/cadence/macb_mdio.c

diff --git a/drivers/net/ethernet/cadence/Makefile b/drivers/net/ethernet/cadence/Makefile
index 91f79b1..75c3d84 100644
--- a/drivers/net/ethernet/cadence/Makefile
+++ b/drivers/net/ethernet/cadence/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the Atmel network device drivers.
 #
 
-obj-$(CONFIG_MACB) += macb.o
+obj-$(CONFIG_MACB) += macb.o macb_mdio.o
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index cb07d95..6e8ff4e 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -218,45 +218,6 @@ static void macb_get_hwaddr(struct macb *bp)
 	eth_hw_addr_random(bp->dev);
 }
 
-static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
-{
-	struct macb *bp = bus->priv;
-	int value;
-
-	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
-			      | MACB_BF(RW, MACB_MAN_READ)
-			      | MACB_BF(PHYA, mii_id)
-			      | MACB_BF(REGA, regnum)
-			      | MACB_BF(CODE, MACB_MAN_CODE)));
-
-	/* wait for end of transfer */
-	while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
-		cpu_relax();
-
-	value = MACB_BFEXT(DATA, macb_readl(bp, MAN));
-
-	return value;
-}
-
-static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
-			   u16 value)
-{
-	struct macb *bp = bus->priv;
-
-	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
-			      | MACB_BF(RW, MACB_MAN_WRITE)
-			      | MACB_BF(PHYA, mii_id)
-			      | MACB_BF(REGA, regnum)
-			      | MACB_BF(CODE, MACB_MAN_CODE)
-			      | MACB_BF(DATA, value)));
-
-	/* wait for end of transfer */
-	while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
-		cpu_relax();
-
-	return 0;
-}
-
 /**
  * macb_set_tx_clk() - Set a clock to a new frequency
  * @clk		Pointer to the clock to change
@@ -371,27 +332,19 @@ static void macb_handle_link_change(struct net_device *dev)
 static int macb_mii_probe(struct net_device *dev)
 {
 	struct macb *bp = netdev_priv(dev);
-	struct macb_platform_data *pdata;
 	struct phy_device *phydev;
-	int phy_irq;
 	int ret;
 
-	phydev = phy_find_first(bp->mii_bus);
+	if (bp->phy_dev)
+		return 0;
+
+	phydev = of_phy_find_device(bp->phy_node);
 	if (!phydev) {
 		netdev_err(dev, "no PHY found\n");
 		return -ENXIO;
 	}
-
-	pdata = dev_get_platdata(&bp->pdev->dev);
-	if (pdata && gpio_is_valid(pdata->phy_irq_pin)) {
-		ret = devm_gpio_request(&bp->pdev->dev, pdata->phy_irq_pin,
-					"phy int");
-		if (!ret) {
-			phy_irq = gpio_to_irq(pdata->phy_irq_pin);
-			phydev->irq = (phy_irq < 0) ? PHY_POLL : phy_irq;
-		}
-	}
-
+	if (bp->phy_irq)
+		phydev->irq = bp->phy_irq;
 	/* attach the mac to the phy */
 	ret = phy_connect_direct(dev, phydev, &macb_handle_link_change,
 				 bp->phy_interface);
@@ -416,80 +369,9 @@ static int macb_mii_probe(struct net_device *dev)
 	bp->duplex = -1;
 	bp->phy_dev = phydev;
 
-	return 0;
-}
-
-static int macb_mii_init(struct macb *bp)
-{
-	struct macb_platform_data *pdata;
-	struct device_node *np;
-	int err = -ENXIO, i;
-
-	/* Enable management port */
-	macb_writel(bp, NCR, MACB_BIT(MPE));
-
-	bp->mii_bus = mdiobus_alloc();
-	if (!bp->mii_bus) {
-		err = -ENOMEM;
-		goto err_out;
-	}
-
-	bp->mii_bus->name = "MACB_mii_bus";
-	bp->mii_bus->read = &macb_mdio_read;
-	bp->mii_bus->write = &macb_mdio_write;
-	snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
-		 bp->pdev->name, bp->pdev->id);
-	bp->mii_bus->priv = bp;
-	bp->mii_bus->parent = &bp->pdev->dev;
-	pdata = dev_get_platdata(&bp->pdev->dev);
-
-	dev_set_drvdata(&bp->dev->dev, bp->mii_bus);
-
-	np = bp->pdev->dev.of_node;
-	if (np) {
-		/* try dt phy registration */
-		err = of_mdiobus_register(bp->mii_bus, np);
-
-		/* fallback to standard phy registration if no phy were
-		 * found during dt phy registration
-		 */
-		if (!err && !phy_find_first(bp->mii_bus)) {
-			for (i = 0; i < PHY_MAX_ADDR; i++) {
-				struct phy_device *phydev;
-
-				phydev = mdiobus_scan(bp->mii_bus, i);
-				if (IS_ERR(phydev) &&
-				    PTR_ERR(phydev) != -ENODEV) {
-					err = PTR_ERR(phydev);
-					break;
-				}
-			}
-
-			if (err)
-				goto err_out_unregister_bus;
-		}
-	} else {
-		if (pdata)
-			bp->mii_bus->phy_mask = pdata->phy_mask;
-
-		err = mdiobus_register(bp->mii_bus);
-	}
-
-	if (err)
-		goto err_out_free_mdiobus;
-
-	err = macb_mii_probe(bp->dev);
-	if (err)
-		goto err_out_unregister_bus;
+	phy_attached_info(phydev);
 
 	return 0;
-
-err_out_unregister_bus:
-	mdiobus_unregister(bp->mii_bus);
-err_out_free_mdiobus:
-	mdiobus_free(bp->mii_bus);
-err_out:
-	return err;
 }
 
 static void macb_update_stats(struct macb *bp)
@@ -1582,15 +1464,18 @@ static void macb_init_rings(struct macb *bp)
 static void macb_reset_hw(struct macb *bp)
 {
 	struct macb_queue *queue;
-	unsigned int q;
+	unsigned int q, ctrl;
 
 	/* Disable RX and TX (XXX: Should we halt the transmission
 	 * more gracefully?)
 	 */
-	macb_writel(bp, NCR, 0);
+	ctrl = macb_readl(bp, NCR);
+	ctrl &= ~(MACB_BIT(RE) | MACB_BIT(TE));
+	macb_writel(bp, NCR, ctrl);
 
 	/* Clear the stats registers (XXX: Update stats first?) */
-	macb_writel(bp, NCR, MACB_BIT(CLRSTAT));
+	ctrl |= MACB_BIT(CLRSTAT);
+	macb_writel(bp, NCR, ctrl);
 
 	/* Clear all status flags */
 	macb_writel(bp, TSR, -1);
@@ -1886,7 +1771,8 @@ static int macb_open(struct net_device *dev)
 	netif_carrier_off(dev);
 
 	/* if the phy is not yet register, retry later*/
-	if (!bp->phy_dev)
+	err = macb_mii_probe(dev);
+	if (err)
 		return -EAGAIN;
 
 	/* RX buffers initialization */
@@ -2891,16 +2777,16 @@ static int macb_probe(struct platform_device *pdev)
 	unsigned int queue_mask, num_queues;
 	struct macb_platform_data *pdata;
 	bool native_io;
-	struct phy_device *phydev;
 	struct net_device *dev;
 	struct resource *regs;
 	void __iomem *mem;
 	const char *mac;
 	struct macb *bp;
+	int phy_irq;
 	int err;
 
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	mem = devm_ioremap_resource(&pdev->dev, regs);
+	mem = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
 	if (IS_ERR(mem))
 		return PTR_ERR(mem);
 
@@ -3006,21 +2892,26 @@ static int macb_probe(struct platform_device *pdev)
 	if (err)
 		goto err_out_free_netdev;
 
-	err = macb_mii_init(bp);
-	if (err)
-		goto err_out_free_netdev;
-
-	phydev = bp->phy_dev;
-
-	netif_carrier_off(dev);
-
 	err = register_netdev(dev);
 	if (err) {
 		dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
-		goto err_out_unregister_mdio;
+		goto err_out_free_netdev;
 	}
 
-	phy_attached_info(phydev);
+	bp->phy_node = of_parse_phandle(bp->pdev->dev.of_node,
+					"phy-handle", 0);
+
+	pdata = dev_get_platdata(&bp->pdev->dev);
+	if (pdata && gpio_is_valid(pdata->phy_irq_pin)) {
+		err = devm_gpio_request(&bp->pdev->dev, pdata->phy_irq_pin,
+					"phy int");
+		if (!err) {
+			phy_irq = gpio_to_irq(pdata->phy_irq_pin);
+			bp->phy_irq = (phy_irq < 0) ? PHY_POLL : phy_irq;
+		}
+	}
+
+	netif_carrier_off(dev);
 
 	netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n",
 		    macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID),
@@ -3028,16 +2919,10 @@ static int macb_probe(struct platform_device *pdev)
 
 	return 0;
 
-err_out_unregister_mdio:
-	phy_disconnect(bp->phy_dev);
-	mdiobus_unregister(bp->mii_bus);
-	mdiobus_free(bp->mii_bus);
-
+err_out_free_netdev:
 	/* Shutdown the PHY if there is a GPIO reset */
 	if (bp->reset_gpio)
 		gpiod_set_value(bp->reset_gpio, 0);
-
-err_out_free_netdev:
 	free_netdev(dev);
 
 err_disable_clocks:
@@ -3059,8 +2944,6 @@ static int macb_remove(struct platform_device *pdev)
 		bp = netdev_priv(dev);
 		if (bp->phy_dev)
 			phy_disconnect(bp->phy_dev);
-		mdiobus_unregister(bp->mii_bus);
-		mdiobus_free(bp->mii_bus);
 
 		/* Shutdown the PHY if there is a GPIO reset */
 		if (bp->reset_gpio)
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 8a13824..a63b215 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -846,6 +846,8 @@ struct macb {
 	unsigned int		jumbo_max_len;
 
 	u32			wol;
+	struct device_node *phy_node;
+	int phy_irq;
 };
 
 static inline bool macb_is_gem(struct macb *bp)
diff --git a/drivers/net/ethernet/cadence/macb_mdio.c b/drivers/net/ethernet/cadence/macb_mdio.c
new file mode 100644
index 0000000..1277ca3
--- /dev/null
+++ b/drivers/net/ethernet/cadence/macb_mdio.c
@@ -0,0 +1,266 @@
+/*
+ * Cadence Macb mdio controller driver
+ *
+ * Copyright (C) 2014 - 2016 Xilinx, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/of_address.h>
+#include <linux/of_mdio.h>
+#include <linux/io.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/ptp_clock_kernel.h>
+#include "macb.h"
+
+struct macb_mdio_data {
+	void __iomem *regs;
+
+	struct clk *pclk;
+	struct clk *hclk;
+};
+
+#define macb_mdio_reg_writel(bp, offset, value)	\
+	writel_relaxed(value, bp->regs + offset)
+#define macb_mdio_writel(bp, reg, value)	\
+	macb_mdio_reg_writel(bp, MACB_##reg, value)
+
+#define macb_mdio_reg_readl(bp, offset)	readl_relaxed(bp->regs + offset)
+#define macb_mdio_readl(bp, reg)	macb_mdio_reg_readl(bp, MACB_##reg)
+
+#define MACB_MDIO_TIMEOUT	1000
+
+static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+	struct macb_mdio_data *bp = bus->priv;
+	unsigned int timeout = MACB_MDIO_TIMEOUT;
+	int value;
+
+	macb_mdio_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) |
+				   MACB_BF(RW, MACB_MAN_READ) |
+				   MACB_BF(PHYA, mii_id) |
+				   MACB_BF(REGA, regnum) |
+				   MACB_BF(CODE, MACB_MAN_CODE)));
+
+	/* wait for end of transfer */
+	while (!MACB_BFEXT(IDLE, macb_mdio_readl(bp, NSR)) && timeout) {
+		cpu_relax();
+		timeout--;
+	}
+
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	value = MACB_BFEXT(DATA, macb_mdio_readl(bp, MAN));
+
+	return value;
+}
+
+static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+			   u16 value)
+{
+	struct macb_mdio_data *bp = bus->priv;
+	unsigned int timeout = MACB_MDIO_TIMEOUT;
+
+	macb_mdio_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) |
+				   MACB_BF(RW, MACB_MAN_WRITE) |
+				   MACB_BF(PHYA, mii_id) |
+				   MACB_BF(REGA, regnum) |
+				   MACB_BF(CODE, MACB_MAN_CODE) |
+				   MACB_BF(DATA, value)));
+
+	/* wait for end of transfer */
+	while (!MACB_BFEXT(IDLE, macb_mdio_readl(bp, NSR)) && timeout) {
+		cpu_relax();
+		timeout--;
+	}
+
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static u32 gem_mdc_clk_div(struct macb_mdio_data *bp)
+{
+	u32 config;
+	unsigned long pclk_hz = clk_get_rate(bp->pclk);
+
+	if (pclk_hz <= 20000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV8);
+	else if (pclk_hz <= 40000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV16);
+	else if (pclk_hz <= 80000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV32);
+	else if (pclk_hz <= 120000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV48);
+	else if (pclk_hz <= 160000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV64);
+	else
+		config = GEM_BF(CLK, GEM_CLK_DIV96);
+
+	return config;
+}
+
+static int macb_mdio_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct mii_bus *bus;
+	struct macb_mdio_data *bp;
+	struct resource *res;
+	int ret;
+	u32 config, i;
+
+	bus = mdiobus_alloc_size(sizeof(*bp));
+	if (!bus)
+		return -ENOMEM;
+
+	bus->name = "macb_mii_bus";
+	bus->read = &macb_mdio_read;
+	bus->write = &macb_mdio_write;
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
+	bus->parent = &pdev->dev;
+	bus->irq = devm_kzalloc(&pdev->dev, sizeof(int) * PHY_MAX_ADDR,
+				GFP_KERNEL);
+	if (!bus->irq) {
+		ret = -ENOMEM;
+		goto err_out_free_mdiobus;
+	}
+
+	bp = bus->priv;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	bp->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (IS_ERR(bp->regs)) {
+		ret = PTR_ERR(bp->regs);
+		goto err_out_free_mdiobus;
+	}
+
+	bp->pclk = devm_clk_get(&pdev->dev, "pclk");
+	if (IS_ERR(bp->pclk)) {
+		ret = PTR_ERR(bp->pclk);
+		dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", ret);
+		goto err_out_free_mdiobus;
+	}
+
+	bp->hclk = devm_clk_get(&pdev->dev, "hclk");
+	if (IS_ERR(bp->hclk)) {
+		ret = PTR_ERR(bp->hclk);
+		dev_err(&pdev->dev, "failed to get hclk (%u)\n", ret);
+		goto err_out_free_mdiobus;
+	}
+
+	ret = clk_prepare_enable(bp->pclk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable pclk (%u)\n", ret);
+		goto err_out_free_mdiobus;
+	}
+
+	ret = clk_prepare_enable(bp->hclk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable hclk (%u)\n", ret);
+		goto err_disable_pclk;
+	}
+
+	platform_set_drvdata(pdev, bus);
+
+	/* Enable management port */
+	config = macb_mdio_readl(bp, NCR);
+	config |= MACB_BIT(MPE);
+	macb_mdio_writel(bp, NCR, config);
+	config = gem_mdc_clk_div(bp);
+	macb_mdio_writel(bp, NCFGR, config);
+
+	np = pdev->dev.of_node;
+	if (np) {
+		/* try dt phy registration */
+		ret = of_mdiobus_register(bus, np);
+
+		/* Fallback to standard phy registration if no phy were
+		 * found during dt phy registration
+		 */
+		if (!ret && !phy_find_first(bus)) {
+			for (i = 0; i < PHY_MAX_ADDR; i++) {
+				struct phy_device *phydev;
+
+				phydev = mdiobus_scan(bus, i);
+				if (IS_ERR(phydev) &&
+				    PTR_ERR(phydev) != -ENODEV) {
+					ret = PTR_ERR(phydev);
+					break;
+				}
+			}
+
+			if (ret)
+				goto err_out_unregister_bus;
+		}
+	} else {
+		for (i = 0; i < PHY_MAX_ADDR; i++)
+			bus->irq[i] = PHY_POLL;
+
+		ret = of_mdiobus_register(bus, np);
+	}
+
+	if (ret)
+		goto err_out_free_mdio_irq;
+
+	return 0;
+
+err_out_unregister_bus:
+	mdiobus_unregister(bus);
+err_out_free_mdio_irq:
+	kfree(bus->irq);
+err_disable_pclk:
+	clk_disable_unprepare(bp->pclk);
+	clk_disable_unprepare(bp->hclk);
+err_out_free_mdiobus:
+	mdiobus_free(bus);
+	return ret;
+}
+
+static int macb_mdio_remove(struct platform_device *pdev)
+{
+	struct mii_bus *bus = platform_get_drvdata(pdev);
+	struct macb_mdio_data *bp = bus->priv;
+	u32 config;
+
+	/* Disable management port */
+	config = macb_mdio_readl(bp, NCR);
+	config &= ~MACB_BIT(MPE);
+	macb_mdio_writel(bp, NCR, config);
+	mdiobus_unregister(bus);
+	clk_disable_unprepare(bp->hclk);
+	clk_disable_unprepare(bp->pclk);
+	mdiobus_free(bus);
+
+	return 0;
+}
+
+static const struct of_device_id macb_mdio_dt_ids[] = {
+	{ .compatible = "cdns,macb-mdio" },
+
+};
+MODULE_DEVICE_TABLE(of, macb_mdio_dt_ids);
+
+static struct platform_driver macb_mdio_driver = {
+	.probe = macb_mdio_probe,
+	.remove = macb_mdio_remove,
+	.driver = {
+		.name = "macb-mdio",
+		.of_match_table = macb_mdio_dt_ids,
+	},
+};
+
+module_platform_driver(macb_mdio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence MACB MDIO driver");
+MODULE_AUTHOR("Xilinx");
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 1/2] net: macb: Add MDIO driver for accessing multiple PHY devices
@ 2016-05-13  9:26 ` Harini Katakam
  0 siblings, 0 replies; 17+ messages in thread
From: Harini Katakam @ 2016-05-13  9:26 UTC (permalink / raw)
  To: nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ,
	harinikatakamlinux-Re5JQEeQqe8AvxtiuMwx3w
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	harinik-gjFFaj9aHVfQT0dZR+AlfA, punnaia-gjFFaj9aHVfQT0dZR+AlfA,
	michals-gjFFaj9aHVfQT0dZR+AlfA

This patch is to add support for the hardware with multiple ethernet
MAC controllers and a single MDIO bus connected to multiple PHY devices.
MDIO lines are connected to any one of the ethernet MAC controllers and
all the PHY devices will be accessed using the PHY maintenance interface
in that MAC controller. This handling along with PHY functionality is
moved to macb_mdio.c

Signed-off-by: Punnaiah Choudary Kalluri <punnaia-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Harini Katakam <harinik-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
---
 drivers/net/ethernet/cadence/Makefile    |    2 +-
 drivers/net/ethernet/cadence/macb.c      |  183 ++++----------------
 drivers/net/ethernet/cadence/macb.h      |    2 +
 drivers/net/ethernet/cadence/macb_mdio.c |  266 ++++++++++++++++++++++++++++++
 4 files changed, 302 insertions(+), 151 deletions(-)
 create mode 100644 drivers/net/ethernet/cadence/macb_mdio.c

diff --git a/drivers/net/ethernet/cadence/Makefile b/drivers/net/ethernet/cadence/Makefile
index 91f79b1..75c3d84 100644
--- a/drivers/net/ethernet/cadence/Makefile
+++ b/drivers/net/ethernet/cadence/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the Atmel network device drivers.
 #
 
-obj-$(CONFIG_MACB) += macb.o
+obj-$(CONFIG_MACB) += macb.o macb_mdio.o
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index cb07d95..6e8ff4e 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -218,45 +218,6 @@ static void macb_get_hwaddr(struct macb *bp)
 	eth_hw_addr_random(bp->dev);
 }
 
-static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
-{
-	struct macb *bp = bus->priv;
-	int value;
-
-	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
-			      | MACB_BF(RW, MACB_MAN_READ)
-			      | MACB_BF(PHYA, mii_id)
-			      | MACB_BF(REGA, regnum)
-			      | MACB_BF(CODE, MACB_MAN_CODE)));
-
-	/* wait for end of transfer */
-	while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
-		cpu_relax();
-
-	value = MACB_BFEXT(DATA, macb_readl(bp, MAN));
-
-	return value;
-}
-
-static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
-			   u16 value)
-{
-	struct macb *bp = bus->priv;
-
-	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
-			      | MACB_BF(RW, MACB_MAN_WRITE)
-			      | MACB_BF(PHYA, mii_id)
-			      | MACB_BF(REGA, regnum)
-			      | MACB_BF(CODE, MACB_MAN_CODE)
-			      | MACB_BF(DATA, value)));
-
-	/* wait for end of transfer */
-	while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
-		cpu_relax();
-
-	return 0;
-}
-
 /**
  * macb_set_tx_clk() - Set a clock to a new frequency
  * @clk		Pointer to the clock to change
@@ -371,27 +332,19 @@ static void macb_handle_link_change(struct net_device *dev)
 static int macb_mii_probe(struct net_device *dev)
 {
 	struct macb *bp = netdev_priv(dev);
-	struct macb_platform_data *pdata;
 	struct phy_device *phydev;
-	int phy_irq;
 	int ret;
 
-	phydev = phy_find_first(bp->mii_bus);
+	if (bp->phy_dev)
+		return 0;
+
+	phydev = of_phy_find_device(bp->phy_node);
 	if (!phydev) {
 		netdev_err(dev, "no PHY found\n");
 		return -ENXIO;
 	}
-
-	pdata = dev_get_platdata(&bp->pdev->dev);
-	if (pdata && gpio_is_valid(pdata->phy_irq_pin)) {
-		ret = devm_gpio_request(&bp->pdev->dev, pdata->phy_irq_pin,
-					"phy int");
-		if (!ret) {
-			phy_irq = gpio_to_irq(pdata->phy_irq_pin);
-			phydev->irq = (phy_irq < 0) ? PHY_POLL : phy_irq;
-		}
-	}
-
+	if (bp->phy_irq)
+		phydev->irq = bp->phy_irq;
 	/* attach the mac to the phy */
 	ret = phy_connect_direct(dev, phydev, &macb_handle_link_change,
 				 bp->phy_interface);
@@ -416,80 +369,9 @@ static int macb_mii_probe(struct net_device *dev)
 	bp->duplex = -1;
 	bp->phy_dev = phydev;
 
-	return 0;
-}
-
-static int macb_mii_init(struct macb *bp)
-{
-	struct macb_platform_data *pdata;
-	struct device_node *np;
-	int err = -ENXIO, i;
-
-	/* Enable management port */
-	macb_writel(bp, NCR, MACB_BIT(MPE));
-
-	bp->mii_bus = mdiobus_alloc();
-	if (!bp->mii_bus) {
-		err = -ENOMEM;
-		goto err_out;
-	}
-
-	bp->mii_bus->name = "MACB_mii_bus";
-	bp->mii_bus->read = &macb_mdio_read;
-	bp->mii_bus->write = &macb_mdio_write;
-	snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
-		 bp->pdev->name, bp->pdev->id);
-	bp->mii_bus->priv = bp;
-	bp->mii_bus->parent = &bp->pdev->dev;
-	pdata = dev_get_platdata(&bp->pdev->dev);
-
-	dev_set_drvdata(&bp->dev->dev, bp->mii_bus);
-
-	np = bp->pdev->dev.of_node;
-	if (np) {
-		/* try dt phy registration */
-		err = of_mdiobus_register(bp->mii_bus, np);
-
-		/* fallback to standard phy registration if no phy were
-		 * found during dt phy registration
-		 */
-		if (!err && !phy_find_first(bp->mii_bus)) {
-			for (i = 0; i < PHY_MAX_ADDR; i++) {
-				struct phy_device *phydev;
-
-				phydev = mdiobus_scan(bp->mii_bus, i);
-				if (IS_ERR(phydev) &&
-				    PTR_ERR(phydev) != -ENODEV) {
-					err = PTR_ERR(phydev);
-					break;
-				}
-			}
-
-			if (err)
-				goto err_out_unregister_bus;
-		}
-	} else {
-		if (pdata)
-			bp->mii_bus->phy_mask = pdata->phy_mask;
-
-		err = mdiobus_register(bp->mii_bus);
-	}
-
-	if (err)
-		goto err_out_free_mdiobus;
-
-	err = macb_mii_probe(bp->dev);
-	if (err)
-		goto err_out_unregister_bus;
+	phy_attached_info(phydev);
 
 	return 0;
-
-err_out_unregister_bus:
-	mdiobus_unregister(bp->mii_bus);
-err_out_free_mdiobus:
-	mdiobus_free(bp->mii_bus);
-err_out:
-	return err;
 }
 
 static void macb_update_stats(struct macb *bp)
@@ -1582,15 +1464,18 @@ static void macb_init_rings(struct macb *bp)
 static void macb_reset_hw(struct macb *bp)
 {
 	struct macb_queue *queue;
-	unsigned int q;
+	unsigned int q, ctrl;
 
 	/* Disable RX and TX (XXX: Should we halt the transmission
 	 * more gracefully?)
 	 */
-	macb_writel(bp, NCR, 0);
+	ctrl = macb_readl(bp, NCR);
+	ctrl &= ~(MACB_BIT(RE) | MACB_BIT(TE));
+	macb_writel(bp, NCR, ctrl);
 
 	/* Clear the stats registers (XXX: Update stats first?) */
-	macb_writel(bp, NCR, MACB_BIT(CLRSTAT));
+	ctrl |= MACB_BIT(CLRSTAT);
+	macb_writel(bp, NCR, ctrl);
 
 	/* Clear all status flags */
 	macb_writel(bp, TSR, -1);
@@ -1886,7 +1771,8 @@ static int macb_open(struct net_device *dev)
 	netif_carrier_off(dev);
 
 	/* if the phy is not yet register, retry later*/
-	if (!bp->phy_dev)
+	err = macb_mii_probe(dev);
+	if (err)
 		return -EAGAIN;
 
 	/* RX buffers initialization */
@@ -2891,16 +2777,16 @@ static int macb_probe(struct platform_device *pdev)
 	unsigned int queue_mask, num_queues;
 	struct macb_platform_data *pdata;
 	bool native_io;
-	struct phy_device *phydev;
 	struct net_device *dev;
 	struct resource *regs;
 	void __iomem *mem;
 	const char *mac;
 	struct macb *bp;
+	int phy_irq;
 	int err;
 
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	mem = devm_ioremap_resource(&pdev->dev, regs);
+	mem = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
 	if (IS_ERR(mem))
 		return PTR_ERR(mem);
 
@@ -3006,21 +2892,26 @@ static int macb_probe(struct platform_device *pdev)
 	if (err)
 		goto err_out_free_netdev;
 
-	err = macb_mii_init(bp);
-	if (err)
-		goto err_out_free_netdev;
-
-	phydev = bp->phy_dev;
-
-	netif_carrier_off(dev);
-
 	err = register_netdev(dev);
 	if (err) {
 		dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
-		goto err_out_unregister_mdio;
+		goto err_out_free_netdev;
 	}
 
-	phy_attached_info(phydev);
+	bp->phy_node = of_parse_phandle(bp->pdev->dev.of_node,
+					"phy-handle", 0);
+
+	pdata = dev_get_platdata(&bp->pdev->dev);
+	if (pdata && gpio_is_valid(pdata->phy_irq_pin)) {
+		err = devm_gpio_request(&bp->pdev->dev, pdata->phy_irq_pin,
+					"phy int");
+		if (!err) {
+			phy_irq = gpio_to_irq(pdata->phy_irq_pin);
+			bp->phy_irq = (phy_irq < 0) ? PHY_POLL : phy_irq;
+		}
+	}
+
+	netif_carrier_off(dev);
 
 	netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n",
 		    macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID),
@@ -3028,16 +2919,10 @@ static int macb_probe(struct platform_device *pdev)
 
 	return 0;
 
-err_out_unregister_mdio:
-	phy_disconnect(bp->phy_dev);
-	mdiobus_unregister(bp->mii_bus);
-	mdiobus_free(bp->mii_bus);
-
+err_out_free_netdev:
 	/* Shutdown the PHY if there is a GPIO reset */
 	if (bp->reset_gpio)
 		gpiod_set_value(bp->reset_gpio, 0);
-
-err_out_free_netdev:
 	free_netdev(dev);
 
 err_disable_clocks:
@@ -3059,8 +2944,6 @@ static int macb_remove(struct platform_device *pdev)
 		bp = netdev_priv(dev);
 		if (bp->phy_dev)
 			phy_disconnect(bp->phy_dev);
-		mdiobus_unregister(bp->mii_bus);
-		mdiobus_free(bp->mii_bus);
 
 		/* Shutdown the PHY if there is a GPIO reset */
 		if (bp->reset_gpio)
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 8a13824..a63b215 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -846,6 +846,8 @@ struct macb {
 	unsigned int		jumbo_max_len;
 
 	u32			wol;
+	struct device_node *phy_node;
+	int phy_irq;
 };
 
 static inline bool macb_is_gem(struct macb *bp)
diff --git a/drivers/net/ethernet/cadence/macb_mdio.c b/drivers/net/ethernet/cadence/macb_mdio.c
new file mode 100644
index 0000000..1277ca3
--- /dev/null
+++ b/drivers/net/ethernet/cadence/macb_mdio.c
@@ -0,0 +1,266 @@
+/*
+ * Cadence Macb mdio controller driver
+ *
+ * Copyright (C) 2014 - 2016 Xilinx, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/of_address.h>
+#include <linux/of_mdio.h>
+#include <linux/io.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/ptp_clock_kernel.h>
+#include "macb.h"
+
+struct macb_mdio_data {
+	void __iomem *regs;
+
+	struct clk *pclk;
+	struct clk *hclk;
+};
+
+#define macb_mdio_reg_writel(bp, offset, value)	\
+	writel_relaxed(value, bp->regs + offset)
+#define macb_mdio_writel(bp, reg, value)	\
+	macb_mdio_reg_writel(bp, MACB_##reg, value)
+
+#define macb_mdio_reg_readl(bp, offset)	readl_relaxed(bp->regs + offset)
+#define macb_mdio_readl(bp, reg)	macb_mdio_reg_readl(bp, MACB_##reg)
+
+#define MACB_MDIO_TIMEOUT	1000
+
+static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+	struct macb_mdio_data *bp = bus->priv;
+	unsigned int timeout = MACB_MDIO_TIMEOUT;
+	int value;
+
+	macb_mdio_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) |
+				   MACB_BF(RW, MACB_MAN_READ) |
+				   MACB_BF(PHYA, mii_id) |
+				   MACB_BF(REGA, regnum) |
+				   MACB_BF(CODE, MACB_MAN_CODE)));
+
+	/* wait for end of transfer */
+	while (!MACB_BFEXT(IDLE, macb_mdio_readl(bp, NSR)) && timeout) {
+		cpu_relax();
+		timeout--;
+	}
+
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	value = MACB_BFEXT(DATA, macb_mdio_readl(bp, MAN));
+
+	return value;
+}
+
+static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+			   u16 value)
+{
+	struct macb_mdio_data *bp = bus->priv;
+	unsigned int timeout = MACB_MDIO_TIMEOUT;
+
+	macb_mdio_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) |
+				   MACB_BF(RW, MACB_MAN_WRITE) |
+				   MACB_BF(PHYA, mii_id) |
+				   MACB_BF(REGA, regnum) |
+				   MACB_BF(CODE, MACB_MAN_CODE) |
+				   MACB_BF(DATA, value)));
+
+	/* wait for end of transfer */
+	while (!MACB_BFEXT(IDLE, macb_mdio_readl(bp, NSR)) && timeout) {
+		cpu_relax();
+		timeout--;
+	}
+
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static u32 gem_mdc_clk_div(struct macb_mdio_data *bp)
+{
+	u32 config;
+	unsigned long pclk_hz = clk_get_rate(bp->pclk);
+
+	if (pclk_hz <= 20000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV8);
+	else if (pclk_hz <= 40000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV16);
+	else if (pclk_hz <= 80000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV32);
+	else if (pclk_hz <= 120000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV48);
+	else if (pclk_hz <= 160000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV64);
+	else
+		config = GEM_BF(CLK, GEM_CLK_DIV96);
+
+	return config;
+}
+
+static int macb_mdio_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct mii_bus *bus;
+	struct macb_mdio_data *bp;
+	struct resource *res;
+	int ret;
+	u32 config, i;
+
+	bus = mdiobus_alloc_size(sizeof(*bp));
+	if (!bus)
+		return -ENOMEM;
+
+	bus->name = "macb_mii_bus";
+	bus->read = &macb_mdio_read;
+	bus->write = &macb_mdio_write;
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
+	bus->parent = &pdev->dev;
+	bus->irq = devm_kzalloc(&pdev->dev, sizeof(int) * PHY_MAX_ADDR,
+				GFP_KERNEL);
+	if (!bus->irq) {
+		ret = -ENOMEM;
+		goto err_out_free_mdiobus;
+	}
+
+	bp = bus->priv;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	bp->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (IS_ERR(bp->regs)) {
+		ret = PTR_ERR(bp->regs);
+		goto err_out_free_mdiobus;
+	}
+
+	bp->pclk = devm_clk_get(&pdev->dev, "pclk");
+	if (IS_ERR(bp->pclk)) {
+		ret = PTR_ERR(bp->pclk);
+		dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", ret);
+		goto err_out_free_mdiobus;
+	}
+
+	bp->hclk = devm_clk_get(&pdev->dev, "hclk");
+	if (IS_ERR(bp->hclk)) {
+		ret = PTR_ERR(bp->hclk);
+		dev_err(&pdev->dev, "failed to get hclk (%u)\n", ret);
+		goto err_out_free_mdiobus;
+	}
+
+	ret = clk_prepare_enable(bp->pclk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable pclk (%u)\n", ret);
+		goto err_out_free_mdiobus;
+	}
+
+	ret = clk_prepare_enable(bp->hclk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable hclk (%u)\n", ret);
+		goto err_disable_pclk;
+	}
+
+	platform_set_drvdata(pdev, bus);
+
+	/* Enable management port */
+	config = macb_mdio_readl(bp, NCR);
+	config |= MACB_BIT(MPE);
+	macb_mdio_writel(bp, NCR, config);
+	config = gem_mdc_clk_div(bp);
+	macb_mdio_writel(bp, NCFGR, config);
+
+	np = pdev->dev.of_node;
+	if (np) {
+		/* try dt phy registration */
+		ret = of_mdiobus_register(bus, np);
+
+		/* Fallback to standard phy registration if no phy were
+		 * found during dt phy registration
+		 */
+		if (!ret && !phy_find_first(bus)) {
+			for (i = 0; i < PHY_MAX_ADDR; i++) {
+				struct phy_device *phydev;
+
+				phydev = mdiobus_scan(bus, i);
+				if (IS_ERR(phydev) &&
+				    PTR_ERR(phydev) != -ENODEV) {
+					ret = PTR_ERR(phydev);
+					break;
+				}
+			}
+
+			if (ret)
+				goto err_out_unregister_bus;
+		}
+	} else {
+		for (i = 0; i < PHY_MAX_ADDR; i++)
+			bus->irq[i] = PHY_POLL;
+
+		ret = of_mdiobus_register(bus, np);
+	}
+
+	if (ret)
+		goto err_out_free_mdio_irq;
+
+	return 0;
+
+err_out_unregister_bus:
+	mdiobus_unregister(bus);
+err_out_free_mdio_irq:
+	kfree(bus->irq);
+err_disable_pclk:
+	clk_disable_unprepare(bp->pclk);
+	clk_disable_unprepare(bp->hclk);
+err_out_free_mdiobus:
+	mdiobus_free(bus);
+	return ret;
+}
+
+static int macb_mdio_remove(struct platform_device *pdev)
+{
+	struct mii_bus *bus = platform_get_drvdata(pdev);
+	struct macb_mdio_data *bp = bus->priv;
+	u32 config;
+
+	/* Disable management port */
+	config = macb_mdio_readl(bp, NCR);
+	config &= ~MACB_BIT(MPE);
+	macb_mdio_writel(bp, NCR, config);
+	mdiobus_unregister(bus);
+	clk_disable_unprepare(bp->hclk);
+	clk_disable_unprepare(bp->pclk);
+	mdiobus_free(bus);
+
+	return 0;
+}
+
+static const struct of_device_id macb_mdio_dt_ids[] = {
+	{ .compatible = "cdns,macb-mdio" },
+
+};
+MODULE_DEVICE_TABLE(of, macb_mdio_dt_ids);
+
+static struct platform_driver macb_mdio_driver = {
+	.probe = macb_mdio_probe,
+	.remove = macb_mdio_remove,
+	.driver = {
+		.name = "macb-mdio",
+		.of_match_table = macb_mdio_dt_ids,
+	},
+};
+
+module_platform_driver(macb_mdio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence MACB MDIO driver");
+MODULE_AUTHOR("Xilinx");
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 1/2] net: macb: Add MDIO driver for accessing multiple PHY devices
@ 2016-05-13  9:26 ` Harini Katakam
  0 siblings, 0 replies; 17+ messages in thread
From: Harini Katakam @ 2016-05-13  9:26 UTC (permalink / raw)
  To: nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ,
	harinikatakamlinux-Re5JQEeQqe8AvxtiuMwx3w
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	harinik-gjFFaj9aHVfQT0dZR+AlfA, punnaia-gjFFaj9aHVfQT0dZR+AlfA,
	michals-gjFFaj9aHVfQT0dZR+AlfA

This patch is to add support for the hardware with multiple ethernet
MAC controllers and a single MDIO bus connected to multiple PHY devices.
MDIO lines are connected to any one of the ethernet MAC controllers and
all the PHY devices will be accessed using the PHY maintenance interface
in that MAC controller. This handling along with PHY functionality is
moved to macb_mdio.c

Signed-off-by: Punnaiah Choudary Kalluri <punnaia-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Harini Katakam <harinik-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
---
 drivers/net/ethernet/cadence/Makefile    |    2 +-
 drivers/net/ethernet/cadence/macb.c      |  183 ++++----------------
 drivers/net/ethernet/cadence/macb.h      |    2 +
 drivers/net/ethernet/cadence/macb_mdio.c |  266 ++++++++++++++++++++++++++++++
 4 files changed, 302 insertions(+), 151 deletions(-)
 create mode 100644 drivers/net/ethernet/cadence/macb_mdio.c

diff --git a/drivers/net/ethernet/cadence/Makefile b/drivers/net/ethernet/cadence/Makefile
index 91f79b1..75c3d84 100644
--- a/drivers/net/ethernet/cadence/Makefile
+++ b/drivers/net/ethernet/cadence/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the Atmel network device drivers.
 #
 
-obj-$(CONFIG_MACB) += macb.o
+obj-$(CONFIG_MACB) += macb.o macb_mdio.o
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index cb07d95..6e8ff4e 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -218,45 +218,6 @@ static void macb_get_hwaddr(struct macb *bp)
 	eth_hw_addr_random(bp->dev);
 }
 
-static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
-{
-	struct macb *bp = bus->priv;
-	int value;
-
-	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
-			      | MACB_BF(RW, MACB_MAN_READ)
-			      | MACB_BF(PHYA, mii_id)
-			      | MACB_BF(REGA, regnum)
-			      | MACB_BF(CODE, MACB_MAN_CODE)));
-
-	/* wait for end of transfer */
-	while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
-		cpu_relax();
-
-	value = MACB_BFEXT(DATA, macb_readl(bp, MAN));
-
-	return value;
-}
-
-static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
-			   u16 value)
-{
-	struct macb *bp = bus->priv;
-
-	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
-			      | MACB_BF(RW, MACB_MAN_WRITE)
-			      | MACB_BF(PHYA, mii_id)
-			      | MACB_BF(REGA, regnum)
-			      | MACB_BF(CODE, MACB_MAN_CODE)
-			      | MACB_BF(DATA, value)));
-
-	/* wait for end of transfer */
-	while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
-		cpu_relax();
-
-	return 0;
-}
-
 /**
  * macb_set_tx_clk() - Set a clock to a new frequency
  * @clk		Pointer to the clock to change
@@ -371,27 +332,19 @@ static void macb_handle_link_change(struct net_device *dev)
 static int macb_mii_probe(struct net_device *dev)
 {
 	struct macb *bp = netdev_priv(dev);
-	struct macb_platform_data *pdata;
 	struct phy_device *phydev;
-	int phy_irq;
 	int ret;
 
-	phydev = phy_find_first(bp->mii_bus);
+	if (bp->phy_dev)
+		return 0;
+
+	phydev = of_phy_find_device(bp->phy_node);
 	if (!phydev) {
 		netdev_err(dev, "no PHY found\n");
 		return -ENXIO;
 	}
-
-	pdata = dev_get_platdata(&bp->pdev->dev);
-	if (pdata && gpio_is_valid(pdata->phy_irq_pin)) {
-		ret = devm_gpio_request(&bp->pdev->dev, pdata->phy_irq_pin,
-					"phy int");
-		if (!ret) {
-			phy_irq = gpio_to_irq(pdata->phy_irq_pin);
-			phydev->irq = (phy_irq < 0) ? PHY_POLL : phy_irq;
-		}
-	}
-
+	if (bp->phy_irq)
+		phydev->irq = bp->phy_irq;
 	/* attach the mac to the phy */
 	ret = phy_connect_direct(dev, phydev, &macb_handle_link_change,
 				 bp->phy_interface);
@@ -416,80 +369,9 @@ static int macb_mii_probe(struct net_device *dev)
 	bp->duplex = -1;
 	bp->phy_dev = phydev;
 
-	return 0;
-}
-
-static int macb_mii_init(struct macb *bp)
-{
-	struct macb_platform_data *pdata;
-	struct device_node *np;
-	int err = -ENXIO, i;
-
-	/* Enable management port */
-	macb_writel(bp, NCR, MACB_BIT(MPE));
-
-	bp->mii_bus = mdiobus_alloc();
-	if (!bp->mii_bus) {
-		err = -ENOMEM;
-		goto err_out;
-	}
-
-	bp->mii_bus->name = "MACB_mii_bus";
-	bp->mii_bus->read = &macb_mdio_read;
-	bp->mii_bus->write = &macb_mdio_write;
-	snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
-		 bp->pdev->name, bp->pdev->id);
-	bp->mii_bus->priv = bp;
-	bp->mii_bus->parent = &bp->pdev->dev;
-	pdata = dev_get_platdata(&bp->pdev->dev);
-
-	dev_set_drvdata(&bp->dev->dev, bp->mii_bus);
-
-	np = bp->pdev->dev.of_node;
-	if (np) {
-		/* try dt phy registration */
-		err = of_mdiobus_register(bp->mii_bus, np);
-
-		/* fallback to standard phy registration if no phy were
-		 * found during dt phy registration
-		 */
-		if (!err && !phy_find_first(bp->mii_bus)) {
-			for (i = 0; i < PHY_MAX_ADDR; i++) {
-				struct phy_device *phydev;
-
-				phydev = mdiobus_scan(bp->mii_bus, i);
-				if (IS_ERR(phydev) &&
-				    PTR_ERR(phydev) != -ENODEV) {
-					err = PTR_ERR(phydev);
-					break;
-				}
-			}
-
-			if (err)
-				goto err_out_unregister_bus;
-		}
-	} else {
-		if (pdata)
-			bp->mii_bus->phy_mask = pdata->phy_mask;
-
-		err = mdiobus_register(bp->mii_bus);
-	}
-
-	if (err)
-		goto err_out_free_mdiobus;
-
-	err = macb_mii_probe(bp->dev);
-	if (err)
-		goto err_out_unregister_bus;
+	phy_attached_info(phydev);
 
 	return 0;
-
-err_out_unregister_bus:
-	mdiobus_unregister(bp->mii_bus);
-err_out_free_mdiobus:
-	mdiobus_free(bp->mii_bus);
-err_out:
-	return err;
 }
 
 static void macb_update_stats(struct macb *bp)
@@ -1582,15 +1464,18 @@ static void macb_init_rings(struct macb *bp)
 static void macb_reset_hw(struct macb *bp)
 {
 	struct macb_queue *queue;
-	unsigned int q;
+	unsigned int q, ctrl;
 
 	/* Disable RX and TX (XXX: Should we halt the transmission
 	 * more gracefully?)
 	 */
-	macb_writel(bp, NCR, 0);
+	ctrl = macb_readl(bp, NCR);
+	ctrl &= ~(MACB_BIT(RE) | MACB_BIT(TE));
+	macb_writel(bp, NCR, ctrl);
 
 	/* Clear the stats registers (XXX: Update stats first?) */
-	macb_writel(bp, NCR, MACB_BIT(CLRSTAT));
+	ctrl |= MACB_BIT(CLRSTAT);
+	macb_writel(bp, NCR, ctrl);
 
 	/* Clear all status flags */
 	macb_writel(bp, TSR, -1);
@@ -1886,7 +1771,8 @@ static int macb_open(struct net_device *dev)
 	netif_carrier_off(dev);
 
 	/* if the phy is not yet register, retry later*/
-	if (!bp->phy_dev)
+	err = macb_mii_probe(dev);
+	if (err)
 		return -EAGAIN;
 
 	/* RX buffers initialization */
@@ -2891,16 +2777,16 @@ static int macb_probe(struct platform_device *pdev)
 	unsigned int queue_mask, num_queues;
 	struct macb_platform_data *pdata;
 	bool native_io;
-	struct phy_device *phydev;
 	struct net_device *dev;
 	struct resource *regs;
 	void __iomem *mem;
 	const char *mac;
 	struct macb *bp;
+	int phy_irq;
 	int err;
 
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	mem = devm_ioremap_resource(&pdev->dev, regs);
+	mem = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
 	if (IS_ERR(mem))
 		return PTR_ERR(mem);
 
@@ -3006,21 +2892,26 @@ static int macb_probe(struct platform_device *pdev)
 	if (err)
 		goto err_out_free_netdev;
 
-	err = macb_mii_init(bp);
-	if (err)
-		goto err_out_free_netdev;
-
-	phydev = bp->phy_dev;
-
-	netif_carrier_off(dev);
-
 	err = register_netdev(dev);
 	if (err) {
 		dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
-		goto err_out_unregister_mdio;
+		goto err_out_free_netdev;
 	}
 
-	phy_attached_info(phydev);
+	bp->phy_node = of_parse_phandle(bp->pdev->dev.of_node,
+					"phy-handle", 0);
+
+	pdata = dev_get_platdata(&bp->pdev->dev);
+	if (pdata && gpio_is_valid(pdata->phy_irq_pin)) {
+		err = devm_gpio_request(&bp->pdev->dev, pdata->phy_irq_pin,
+					"phy int");
+		if (!err) {
+			phy_irq = gpio_to_irq(pdata->phy_irq_pin);
+			bp->phy_irq = (phy_irq < 0) ? PHY_POLL : phy_irq;
+		}
+	}
+
+	netif_carrier_off(dev);
 
 	netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n",
 		    macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID),
@@ -3028,16 +2919,10 @@ static int macb_probe(struct platform_device *pdev)
 
 	return 0;
 
-err_out_unregister_mdio:
-	phy_disconnect(bp->phy_dev);
-	mdiobus_unregister(bp->mii_bus);
-	mdiobus_free(bp->mii_bus);
-
+err_out_free_netdev:
 	/* Shutdown the PHY if there is a GPIO reset */
 	if (bp->reset_gpio)
 		gpiod_set_value(bp->reset_gpio, 0);
-
-err_out_free_netdev:
 	free_netdev(dev);
 
 err_disable_clocks:
@@ -3059,8 +2944,6 @@ static int macb_remove(struct platform_device *pdev)
 		bp = netdev_priv(dev);
 		if (bp->phy_dev)
 			phy_disconnect(bp->phy_dev);
-		mdiobus_unregister(bp->mii_bus);
-		mdiobus_free(bp->mii_bus);
 
 		/* Shutdown the PHY if there is a GPIO reset */
 		if (bp->reset_gpio)
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 8a13824..a63b215 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -846,6 +846,8 @@ struct macb {
 	unsigned int		jumbo_max_len;
 
 	u32			wol;
+	struct device_node *phy_node;
+	int phy_irq;
 };
 
 static inline bool macb_is_gem(struct macb *bp)
diff --git a/drivers/net/ethernet/cadence/macb_mdio.c b/drivers/net/ethernet/cadence/macb_mdio.c
new file mode 100644
index 0000000..1277ca3
--- /dev/null
+++ b/drivers/net/ethernet/cadence/macb_mdio.c
@@ -0,0 +1,266 @@
+/*
+ * Cadence Macb mdio controller driver
+ *
+ * Copyright (C) 2014 - 2016 Xilinx, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/of_address.h>
+#include <linux/of_mdio.h>
+#include <linux/io.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/ptp_clock_kernel.h>
+#include "macb.h"
+
+struct macb_mdio_data {
+	void __iomem *regs;
+
+	struct clk *pclk;
+	struct clk *hclk;
+};
+
+#define macb_mdio_reg_writel(bp, offset, value)	\
+	writel_relaxed(value, bp->regs + offset)
+#define macb_mdio_writel(bp, reg, value)	\
+	macb_mdio_reg_writel(bp, MACB_##reg, value)
+
+#define macb_mdio_reg_readl(bp, offset)	readl_relaxed(bp->regs + offset)
+#define macb_mdio_readl(bp, reg)	macb_mdio_reg_readl(bp, MACB_##reg)
+
+#define MACB_MDIO_TIMEOUT	1000
+
+static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+	struct macb_mdio_data *bp = bus->priv;
+	unsigned int timeout = MACB_MDIO_TIMEOUT;
+	int value;
+
+	macb_mdio_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) |
+				   MACB_BF(RW, MACB_MAN_READ) |
+				   MACB_BF(PHYA, mii_id) |
+				   MACB_BF(REGA, regnum) |
+				   MACB_BF(CODE, MACB_MAN_CODE)));
+
+	/* wait for end of transfer */
+	while (!MACB_BFEXT(IDLE, macb_mdio_readl(bp, NSR)) && timeout) {
+		cpu_relax();
+		timeout--;
+	}
+
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	value = MACB_BFEXT(DATA, macb_mdio_readl(bp, MAN));
+
+	return value;
+}
+
+static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+			   u16 value)
+{
+	struct macb_mdio_data *bp = bus->priv;
+	unsigned int timeout = MACB_MDIO_TIMEOUT;
+
+	macb_mdio_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) |
+				   MACB_BF(RW, MACB_MAN_WRITE) |
+				   MACB_BF(PHYA, mii_id) |
+				   MACB_BF(REGA, regnum) |
+				   MACB_BF(CODE, MACB_MAN_CODE) |
+				   MACB_BF(DATA, value)));
+
+	/* wait for end of transfer */
+	while (!MACB_BFEXT(IDLE, macb_mdio_readl(bp, NSR)) && timeout) {
+		cpu_relax();
+		timeout--;
+	}
+
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static u32 gem_mdc_clk_div(struct macb_mdio_data *bp)
+{
+	u32 config;
+	unsigned long pclk_hz = clk_get_rate(bp->pclk);
+
+	if (pclk_hz <= 20000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV8);
+	else if (pclk_hz <= 40000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV16);
+	else if (pclk_hz <= 80000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV32);
+	else if (pclk_hz <= 120000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV48);
+	else if (pclk_hz <= 160000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV64);
+	else
+		config = GEM_BF(CLK, GEM_CLK_DIV96);
+
+	return config;
+}
+
+static int macb_mdio_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct mii_bus *bus;
+	struct macb_mdio_data *bp;
+	struct resource *res;
+	int ret;
+	u32 config, i;
+
+	bus = mdiobus_alloc_size(sizeof(*bp));
+	if (!bus)
+		return -ENOMEM;
+
+	bus->name = "macb_mii_bus";
+	bus->read = &macb_mdio_read;
+	bus->write = &macb_mdio_write;
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
+	bus->parent = &pdev->dev;
+	bus->irq = devm_kzalloc(&pdev->dev, sizeof(int) * PHY_MAX_ADDR,
+				GFP_KERNEL);
+	if (!bus->irq) {
+		ret = -ENOMEM;
+		goto err_out_free_mdiobus;
+	}
+
+	bp = bus->priv;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	bp->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (IS_ERR(bp->regs)) {
+		ret = PTR_ERR(bp->regs);
+		goto err_out_free_mdiobus;
+	}
+
+	bp->pclk = devm_clk_get(&pdev->dev, "pclk");
+	if (IS_ERR(bp->pclk)) {
+		ret = PTR_ERR(bp->pclk);
+		dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", ret);
+		goto err_out_free_mdiobus;
+	}
+
+	bp->hclk = devm_clk_get(&pdev->dev, "hclk");
+	if (IS_ERR(bp->hclk)) {
+		ret = PTR_ERR(bp->hclk);
+		dev_err(&pdev->dev, "failed to get hclk (%u)\n", ret);
+		goto err_out_free_mdiobus;
+	}
+
+	ret = clk_prepare_enable(bp->pclk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable pclk (%u)\n", ret);
+		goto err_out_free_mdiobus;
+	}
+
+	ret = clk_prepare_enable(bp->hclk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable hclk (%u)\n", ret);
+		goto err_disable_pclk;
+	}
+
+	platform_set_drvdata(pdev, bus);
+
+	/* Enable management port */
+	config = macb_mdio_readl(bp, NCR);
+	config |= MACB_BIT(MPE);
+	macb_mdio_writel(bp, NCR, config);
+	config = gem_mdc_clk_div(bp);
+	macb_mdio_writel(bp, NCFGR, config);
+
+	np = pdev->dev.of_node;
+	if (np) {
+		/* try dt phy registration */
+		ret = of_mdiobus_register(bus, np);
+
+		/* Fallback to standard phy registration if no phy were
+		 * found during dt phy registration
+		 */
+		if (!ret && !phy_find_first(bus)) {
+			for (i = 0; i < PHY_MAX_ADDR; i++) {
+				struct phy_device *phydev;
+
+				phydev = mdiobus_scan(bus, i);
+				if (IS_ERR(phydev) &&
+				    PTR_ERR(phydev) != -ENODEV) {
+					ret = PTR_ERR(phydev);
+					break;
+				}
+			}
+
+			if (ret)
+				goto err_out_unregister_bus;
+		}
+	} else {
+		for (i = 0; i < PHY_MAX_ADDR; i++)
+			bus->irq[i] = PHY_POLL;
+
+		ret = of_mdiobus_register(bus, np);
+	}
+
+	if (ret)
+		goto err_out_free_mdio_irq;
+
+	return 0;
+
+err_out_unregister_bus:
+	mdiobus_unregister(bus);
+err_out_free_mdio_irq:
+	kfree(bus->irq);
+err_disable_pclk:
+	clk_disable_unprepare(bp->pclk);
+	clk_disable_unprepare(bp->hclk);
+err_out_free_mdiobus:
+	mdiobus_free(bus);
+	return ret;
+}
+
+static int macb_mdio_remove(struct platform_device *pdev)
+{
+	struct mii_bus *bus = platform_get_drvdata(pdev);
+	struct macb_mdio_data *bp = bus->priv;
+	u32 config;
+
+	/* Disable management port */
+	config = macb_mdio_readl(bp, NCR);
+	config &= ~MACB_BIT(MPE);
+	macb_mdio_writel(bp, NCR, config);
+	mdiobus_unregister(bus);
+	clk_disable_unprepare(bp->hclk);
+	clk_disable_unprepare(bp->pclk);
+	mdiobus_free(bus);
+
+	return 0;
+}
+
+static const struct of_device_id macb_mdio_dt_ids[] = {
+	{ .compatible = "cdns,macb-mdio" },
+
+};
+MODULE_DEVICE_TABLE(of, macb_mdio_dt_ids);
+
+static struct platform_driver macb_mdio_driver = {
+	.probe = macb_mdio_probe,
+	.remove = macb_mdio_remove,
+	.driver = {
+		.name = "macb-mdio",
+		.of_match_table = macb_mdio_dt_ids,
+	},
+};
+
+module_platform_driver(macb_mdio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence MACB MDIO driver");
+MODULE_AUTHOR("Xilinx");
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 2/2] Documentation: devictree: Add macb mdio bindings
@ 2016-05-13  9:26   ` Harini Katakam
  0 siblings, 0 replies; 17+ messages in thread
From: Harini Katakam @ 2016-05-13  9:26 UTC (permalink / raw)
  To: nicolas.ferre, davem, robh+dt, pawel.moll, mark.rutland,
	ijc+devicetree, galak, harinikatakamlinux
  Cc: netdev, linux-kernel, devicetree, harinik, punnaia, michals

Add documentations for macb mdio driver.

Signed-off-by: Harini Katakam <harinik@xilinx.com>
---
 .../devicetree/bindings/net/macb-mdio.txt          |   31 ++++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/macb-mdio.txt

diff --git a/Documentation/devicetree/bindings/net/macb-mdio.txt b/Documentation/devicetree/bindings/net/macb-mdio.txt
new file mode 100644
index 0000000..11c70a3
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/macb-mdio.txt
@@ -0,0 +1,31 @@
+* Cadence MACB MDIO controller
+
+Required properties:
+- compatible: Should be "cdns,macb-mdio"
+- reg: Address and length of the register set of MAC to be used
+- clock-names: Tuple listing input clock names.
+	Required elements: 'pclk', 'hclk'
+	Optional elements: 'tx_clk'
+- clocks: Phandles to input clocks.
+
+Examples:
+
+	mdio {
+		compatible = "cdns,macb-mdio";
+		reg = <0x0 0xff0b0000 0x0 0x1000>;
+		clocks = <&clk125>, <&clk125>, <&clk125>;
+		clock-names = "pclk", "hclk", "tx_clk";
+		ethernet_phyC: ethernet-phy@C {
+			reg = <C>;
+		};
+		ethernet_phy7: ethernet-phy@7 {
+			reg = <7>;
+		};
+		ethernet_phy3: ethernet-phy@3 {
+			reg = <3>;
+		};
+		ethernet_phy8: ethernet-phy@8 {
+			reg = <8>;
+		};
+	};
+
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 2/2] Documentation: devictree: Add macb mdio bindings
@ 2016-05-13  9:26   ` Harini Katakam
  0 siblings, 0 replies; 17+ messages in thread
From: Harini Katakam @ 2016-05-13  9:26 UTC (permalink / raw)
  To: nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ,
	harinikatakamlinux-Re5JQEeQqe8AvxtiuMwx3w
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	harinik-gjFFaj9aHVfQT0dZR+AlfA, punnaia-gjFFaj9aHVfQT0dZR+AlfA,
	michals-gjFFaj9aHVfQT0dZR+AlfA

Add documentations for macb mdio driver.

Signed-off-by: Harini Katakam <harinik-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
---
 .../devicetree/bindings/net/macb-mdio.txt          |   31 ++++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/macb-mdio.txt

diff --git a/Documentation/devicetree/bindings/net/macb-mdio.txt b/Documentation/devicetree/bindings/net/macb-mdio.txt
new file mode 100644
index 0000000..11c70a3
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/macb-mdio.txt
@@ -0,0 +1,31 @@
+* Cadence MACB MDIO controller
+
+Required properties:
+- compatible: Should be "cdns,macb-mdio"
+- reg: Address and length of the register set of MAC to be used
+- clock-names: Tuple listing input clock names.
+	Required elements: 'pclk', 'hclk'
+	Optional elements: 'tx_clk'
+- clocks: Phandles to input clocks.
+
+Examples:
+
+	mdio {
+		compatible = "cdns,macb-mdio";
+		reg = <0x0 0xff0b0000 0x0 0x1000>;
+		clocks = <&clk125>, <&clk125>, <&clk125>;
+		clock-names = "pclk", "hclk", "tx_clk";
+		ethernet_phyC: ethernet-phy@C {
+			reg = <C>;
+		};
+		ethernet_phy7: ethernet-phy@7 {
+			reg = <7>;
+		};
+		ethernet_phy3: ethernet-phy@3 {
+			reg = <3>;
+		};
+		ethernet_phy8: ethernet-phy@8 {
+			reg = <8>;
+		};
+	};
+
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 2/2] Documentation: devictree: Add macb mdio bindings
@ 2016-05-13  9:26   ` Harini Katakam
  0 siblings, 0 replies; 17+ messages in thread
From: Harini Katakam @ 2016-05-13  9:26 UTC (permalink / raw)
  To: nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ,
	harinikatakamlinux-Re5JQEeQqe8AvxtiuMwx3w
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	harinik-gjFFaj9aHVfQT0dZR+AlfA, punnaia-gjFFaj9aHVfQT0dZR+AlfA,
	michals-gjFFaj9aHVfQT0dZR+AlfA

Add documentations for macb mdio driver.

Signed-off-by: Harini Katakam <harinik-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
---
 .../devicetree/bindings/net/macb-mdio.txt          |   31 ++++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/macb-mdio.txt

diff --git a/Documentation/devicetree/bindings/net/macb-mdio.txt b/Documentation/devicetree/bindings/net/macb-mdio.txt
new file mode 100644
index 0000000..11c70a3
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/macb-mdio.txt
@@ -0,0 +1,31 @@
+* Cadence MACB MDIO controller
+
+Required properties:
+- compatible: Should be "cdns,macb-mdio"
+- reg: Address and length of the register set of MAC to be used
+- clock-names: Tuple listing input clock names.
+	Required elements: 'pclk', 'hclk'
+	Optional elements: 'tx_clk'
+- clocks: Phandles to input clocks.
+
+Examples:
+
+	mdio {
+		compatible = "cdns,macb-mdio";
+		reg = <0x0 0xff0b0000 0x0 0x1000>;
+		clocks = <&clk125>, <&clk125>, <&clk125>;
+		clock-names = "pclk", "hclk", "tx_clk";
+		ethernet_phyC: ethernet-phy@C {
+			reg = <C>;
+		};
+		ethernet_phy7: ethernet-phy@7 {
+			reg = <7>;
+		};
+		ethernet_phy3: ethernet-phy@3 {
+			reg = <3>;
+		};
+		ethernet_phy8: ethernet-phy@8 {
+			reg = <8>;
+		};
+	};
+
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 2/2] Documentation: devictree: Add macb mdio bindings
@ 2016-05-13 17:36     ` Andrew Lunn
  0 siblings, 0 replies; 17+ messages in thread
From: Andrew Lunn @ 2016-05-13 17:36 UTC (permalink / raw)
  To: Harini Katakam
  Cc: nicolas.ferre, davem, robh+dt, pawel.moll, mark.rutland,
	ijc+devicetree, galak, harinikatakamlinux, netdev, linux-kernel,
	devicetree, harinik, punnaia, michals

> +	mdio {
> +		compatible = "cdns,macb-mdio";
> +		reg = <0x0 0xff0b0000 0x0 0x1000>;
> +		clocks = <&clk125>, <&clk125>, <&clk125>;
> +		clock-names = "pclk", "hclk", "tx_clk";
> +		ethernet_phyC: ethernet-phy@C {
> +			reg = <C>;

I think that needs an 0x prefix.

  Andrew

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 2/2] Documentation: devictree: Add macb mdio bindings
@ 2016-05-13 17:36     ` Andrew Lunn
  0 siblings, 0 replies; 17+ messages in thread
From: Andrew Lunn @ 2016-05-13 17:36 UTC (permalink / raw)
  To: Harini Katakam
  Cc: nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ,
	harinikatakamlinux-Re5JQEeQqe8AvxtiuMwx3w,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	harinik-gjFFaj9aHVfQT0dZR+AlfA, punnaia-gjFFaj9aHVfQT0dZR+AlfA,
	michals-gjFFaj9aHVfQT0dZR+AlfA

> +	mdio {
> +		compatible = "cdns,macb-mdio";
> +		reg = <0x0 0xff0b0000 0x0 0x1000>;
> +		clocks = <&clk125>, <&clk125>, <&clk125>;
> +		clock-names = "pclk", "hclk", "tx_clk";
> +		ethernet_phyC: ethernet-phy@C {
> +			reg = <C>;

I think that needs an 0x prefix.

  Andrew
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 2/2] Documentation: devictree: Add macb mdio bindings
@ 2016-05-13 17:43     ` Andrew Lunn
  0 siblings, 0 replies; 17+ messages in thread
From: Andrew Lunn @ 2016-05-13 17:43 UTC (permalink / raw)
  To: Harini Katakam
  Cc: nicolas.ferre, davem, robh+dt, pawel.moll, mark.rutland,
	ijc+devicetree, galak, harinikatakamlinux, netdev, linux-kernel,
	devicetree, harinik, punnaia, michals

Hi Harini

Is this backward compatible? Will devices using the old binding still
work?

  /* Disable RX and TX (XXX: Should we halt the transmission
   * more gracefully?)
    */
-   macb_writel(bp, NCR, 0);
+   ctrl = macb_readl(bp, NCR);
+   ctrl &= ~(MACB_BIT(RE) | MACB_BIT(TE));
+   macb_writel(bp, NCR, ctrl);
 
	/* Clear the stats registers (XXX: Update stats first?) */
-	macb_writel(bp, NCR, MACB_BIT(CLRSTAT));
+	ctrl |= MACB_BIT(CLRSTAT);
+	macb_writel(bp, NCR, ctrl);
 
	/* Clear all status flags */
 	macb_writel(bp, TSR, -1);

It is not clear to me what this part has to do with MDIO.

   Andrew

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 2/2] Documentation: devictree: Add macb mdio bindings
@ 2016-05-13 17:43     ` Andrew Lunn
  0 siblings, 0 replies; 17+ messages in thread
From: Andrew Lunn @ 2016-05-13 17:43 UTC (permalink / raw)
  To: Harini Katakam
  Cc: nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ,
	harinikatakamlinux-Re5JQEeQqe8AvxtiuMwx3w,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	harinik-gjFFaj9aHVfQT0dZR+AlfA, punnaia-gjFFaj9aHVfQT0dZR+AlfA,
	michals-gjFFaj9aHVfQT0dZR+AlfA

Hi Harini

Is this backward compatible? Will devices using the old binding still
work?

  /* Disable RX and TX (XXX: Should we halt the transmission
   * more gracefully?)
    */
-   macb_writel(bp, NCR, 0);
+   ctrl = macb_readl(bp, NCR);
+   ctrl &= ~(MACB_BIT(RE) | MACB_BIT(TE));
+   macb_writel(bp, NCR, ctrl);
 
	/* Clear the stats registers (XXX: Update stats first?) */
-	macb_writel(bp, NCR, MACB_BIT(CLRSTAT));
+	ctrl |= MACB_BIT(CLRSTAT);
+	macb_writel(bp, NCR, ctrl);
 
	/* Clear all status flags */
 	macb_writel(bp, TSR, -1);

It is not clear to me what this part has to do with MDIO.

   Andrew
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 2/2] Documentation: devictree: Add macb mdio bindings
  2016-05-13 17:43     ` Andrew Lunn
  (?)
@ 2016-05-14  2:50     ` Harini Katakam
  -1 siblings, 0 replies; 17+ messages in thread
From: Harini Katakam @ 2016-05-14  2:50 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Harini Katakam, Nicolas Ferre, davem, Rob Herring, Pawel Moll,
	Mark Rutland, ijc+devicetree, Kumar Gala, netdev, linux-kernel,
	devicetree, Punnaiah Choudary Kalluri, michals

HI Andrew,

On Fri, May 13, 2016 at 11:13 PM, Andrew Lunn <andrew@lunn.ch> wrote:
> Hi Harini
>
> Is this backward compatible? Will devices using the old binding still
> work?

It isn't right now.
I will have to assign the bus read/write functions conditionally in order to
do that - I'll see if I can make it clean.

>
>   /* Disable RX and TX (XXX: Should we halt the transmission
>    * more gracefully?)
>     */
> -   macb_writel(bp, NCR, 0);
> +   ctrl = macb_readl(bp, NCR);
> +   ctrl &= ~(MACB_BIT(RE) | MACB_BIT(TE));
> +   macb_writel(bp, NCR, ctrl);
>
>         /* Clear the stats registers (XXX: Update stats first?) */
> -       macb_writel(bp, NCR, MACB_BIT(CLRSTAT));
> +       ctrl |= MACB_BIT(CLRSTAT);
> +       macb_writel(bp, NCR, ctrl);
>
>         /* Clear all status flags */
>         macb_writel(bp, TSR, -1);
>
> It is not clear to me what this part has to do with MDIO.
>

Sorry, I'll move this to a separate patch in my next version.
It is intended to write those registers without disturbing reserved bits.

Regards,
Harini

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 1/2] net: macb: Add MDIO driver for accessing multiple PHY devices
  2016-11-28 16:33   ` Andrew Lunn
  (?)
@ 2016-11-29  4:11   ` Harini Katakam
  -1 siblings, 0 replies; 17+ messages in thread
From: Harini Katakam @ 2016-11-29  4:11 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Harini Katakam, Nicolas Ferre, davem, Rob Herring, Pawel Moll,
	Mark Rutland, ijc+devicetree, Kumar Gala, Boris Brezillon,
	alexandre.belloni, netdev, linux-kernel, devicetree, michals,
	Punnaiah Choudary Kalluri

Hi Andrew,

On Mon, Nov 28, 2016 at 10:03 PM, Andrew Lunn <andrew@lunn.ch> wrote:
> On Mon, Nov 28, 2016 at 03:19:14PM +0530, Harini Katakam wrote:
>> This patch is to add support for the hardware with multiple ethernet
>> MAC controllers and a single MDIO bus connected to multiple PHY devices.
>> MDIO lines are connected to any one of the ethernet MAC controllers and
>> all the PHY devices will be accessed using the PHY maintenance interface
>> in that MAC controller. This handling along with PHY functionality is
>> moved to macb_mdio.c
>>
>> Signed-off-by: Punnaiah Choudary Kalluri <punnaia@xilinx.com>
>> Signed-off-by: Harini Katakam <harinik@xilinx.com>
>> ---
>>  drivers/net/ethernet/cadence/Makefile    |   2 +-
>>  drivers/net/ethernet/cadence/macb.c      | 169 +++-----------------
>>  drivers/net/ethernet/cadence/macb.h      |   2 +
>>  drivers/net/ethernet/cadence/macb_mdio.c | 266 +++++++++++++++++++++++++++++++
>>  4 files changed, 294 insertions(+), 145 deletions(-)
>>  create mode 100644 drivers/net/ethernet/cadence/macb_mdio.c
>>
<snip>
>> +     bus->irq = devm_kzalloc(&pdev->dev, sizeof(int) * PHY_MAX_ADDR,
>> +                             GFP_KERNEL);
>
> This looks wrong, or at least old. It used to be a pointer to an array,
> but it is now an actual array.

Sorry, this was a mistake.
I changed this after rebase, will update in next version.

>
>> +static const struct of_device_id macb_mdio_dt_ids[] = {
>> +     { .compatible = "cdns,macb-mdio" },
>> +
>> +};
>
>
> I've not looked hard enough to know, but can you keep backwards
> compatibility? Won't old device tree's assume the mdio bus is always
> present? Now you need an explicit node otherwise there will not be an
> mdio bus?

Yes, an explicit MDIO bus is required. But I'm not sure
how to maintain backward compatibility (without using this separate
macb_mdio) and have different MACs use the same MDIO bus
with separate PHYs.

Regards,
Harini

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 1/2] net: macb: Add MDIO driver for accessing multiple PHY devices
@ 2016-11-28 16:33   ` Andrew Lunn
  0 siblings, 0 replies; 17+ messages in thread
From: Andrew Lunn @ 2016-11-28 16:33 UTC (permalink / raw)
  To: Harini Katakam
  Cc: nicolas.ferre, davem, robh+dt, pawel.moll, mark.rutland,
	ijc+devicetree, galak, boris.brezillon, alexandre.belloni,
	harinikatakamlinux, netdev, linux-kernel, devicetree, harinik,
	michals, Punnaiah Choudary Kalluri

On Mon, Nov 28, 2016 at 03:19:14PM +0530, Harini Katakam wrote:
> This patch is to add support for the hardware with multiple ethernet
> MAC controllers and a single MDIO bus connected to multiple PHY devices.
> MDIO lines are connected to any one of the ethernet MAC controllers and
> all the PHY devices will be accessed using the PHY maintenance interface
> in that MAC controller. This handling along with PHY functionality is
> moved to macb_mdio.c
> 
> Signed-off-by: Punnaiah Choudary Kalluri <punnaia@xilinx.com>
> Signed-off-by: Harini Katakam <harinik@xilinx.com>
> ---
>  drivers/net/ethernet/cadence/Makefile    |   2 +-
>  drivers/net/ethernet/cadence/macb.c      | 169 +++-----------------
>  drivers/net/ethernet/cadence/macb.h      |   2 +
>  drivers/net/ethernet/cadence/macb_mdio.c | 266 +++++++++++++++++++++++++++++++
>  4 files changed, 294 insertions(+), 145 deletions(-)
>  create mode 100644 drivers/net/ethernet/cadence/macb_mdio.c
> 
> diff --git a/drivers/net/ethernet/cadence/Makefile b/drivers/net/ethernet/cadence/Makefile
> index 91f79b1..75c3d84 100644
> --- a/drivers/net/ethernet/cadence/Makefile
> +++ b/drivers/net/ethernet/cadence/Makefile
> @@ -2,4 +2,4 @@
>  # Makefile for the Atmel network device drivers.
>  #
>  
> -obj-$(CONFIG_MACB) += macb.o
> +obj-$(CONFIG_MACB) += macb.o macb_mdio.o
> diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
> index 80ccfc4..ae2a797 100644
> --- a/drivers/net/ethernet/cadence/macb.c
> +++ b/drivers/net/ethernet/cadence/macb.c
> @@ -232,45 +232,6 @@ static void macb_get_hwaddr(struct macb *bp)
>  	eth_hw_addr_random(bp->dev);
>  }
>  
> -static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
> -{
> -	struct macb *bp = bus->priv;
> -	int value;
> -
> -	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
> -			      | MACB_BF(RW, MACB_MAN_READ)
> -			      | MACB_BF(PHYA, mii_id)
> -			      | MACB_BF(REGA, regnum)
> -			      | MACB_BF(CODE, MACB_MAN_CODE)));
> -
> -	/* wait for end of transfer */
> -	while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
> -		cpu_relax();
> -
> -	value = MACB_BFEXT(DATA, macb_readl(bp, MAN));
> -
> -	return value;
> -}
> -
> -static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
> -			   u16 value)
> -{
> -	struct macb *bp = bus->priv;
> -
> -	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
> -			      | MACB_BF(RW, MACB_MAN_WRITE)
> -			      | MACB_BF(PHYA, mii_id)
> -			      | MACB_BF(REGA, regnum)
> -			      | MACB_BF(CODE, MACB_MAN_CODE)
> -			      | MACB_BF(DATA, value)));
> -
> -	/* wait for end of transfer */
> -	while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
> -		cpu_relax();
> -
> -	return 0;
> -}
> -
>  /**
>   * macb_set_tx_clk() - Set a clock to a new frequency
>   * @clk		Pointer to the clock to change
> @@ -385,27 +346,19 @@ static void macb_handle_link_change(struct net_device *dev)
>  static int macb_mii_probe(struct net_device *dev)
>  {
>  	struct macb *bp = netdev_priv(dev);
> -	struct macb_platform_data *pdata;
>  	struct phy_device *phydev;
> -	int phy_irq;
>  	int ret;
>  
> -	phydev = phy_find_first(bp->mii_bus);
> +	if (dev->phydev)
> +		return 0;
> +
> +	phydev = of_phy_find_device(bp->phy_node);
>  	if (!phydev) {
>  		netdev_err(dev, "no PHY found\n");
>  		return -ENXIO;
>  	}
> -
> -	pdata = dev_get_platdata(&bp->pdev->dev);
> -	if (pdata && gpio_is_valid(pdata->phy_irq_pin)) {
> -		ret = devm_gpio_request(&bp->pdev->dev, pdata->phy_irq_pin,
> -					"phy int");
> -		if (!ret) {
> -			phy_irq = gpio_to_irq(pdata->phy_irq_pin);
> -			phydev->irq = (phy_irq < 0) ? PHY_POLL : phy_irq;
> -		}
> -	}
> -
> +	if (bp->phy_irq)
> +		phydev->irq = bp->phy_irq;
>  	/* attach the mac to the phy */
>  	ret = phy_connect_direct(dev, phydev, &macb_handle_link_change,
>  				 bp->phy_interface);
> @@ -429,80 +382,9 @@ static int macb_mii_probe(struct net_device *dev)
>  	bp->speed = 0;
>  	bp->duplex = -1;
>  
> -	return 0;
> -}
> -
> -static int macb_mii_init(struct macb *bp)
> -{
> -	struct macb_platform_data *pdata;
> -	struct device_node *np;
> -	int err = -ENXIO, i;
> -
> -	/* Enable management port */
> -	macb_writel(bp, NCR, MACB_BIT(MPE));
> -
> -	bp->mii_bus = mdiobus_alloc();
> -	if (!bp->mii_bus) {
> -		err = -ENOMEM;
> -		goto err_out;
> -	}
> -
> -	bp->mii_bus->name = "MACB_mii_bus";
> -	bp->mii_bus->read = &macb_mdio_read;
> -	bp->mii_bus->write = &macb_mdio_write;
> -	snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
> -		 bp->pdev->name, bp->pdev->id);
> -	bp->mii_bus->priv = bp;
> -	bp->mii_bus->parent = &bp->pdev->dev;
> -	pdata = dev_get_platdata(&bp->pdev->dev);
> -
> -	dev_set_drvdata(&bp->dev->dev, bp->mii_bus);
> -
> -	np = bp->pdev->dev.of_node;
> -	if (np) {
> -		/* try dt phy registration */
> -		err = of_mdiobus_register(bp->mii_bus, np);
> -
> -		/* fallback to standard phy registration if no phy were
> -		 * found during dt phy registration
> -		 */
> -		if (!err && !phy_find_first(bp->mii_bus)) {
> -			for (i = 0; i < PHY_MAX_ADDR; i++) {
> -				struct phy_device *phydev;
> -
> -				phydev = mdiobus_scan(bp->mii_bus, i);
> -				if (IS_ERR(phydev) &&
> -				    PTR_ERR(phydev) != -ENODEV) {
> -					err = PTR_ERR(phydev);
> -					break;
> -				}
> -			}
> -
> -			if (err)
> -				goto err_out_unregister_bus;
> -		}
> -	} else {
> -		if (pdata)
> -			bp->mii_bus->phy_mask = pdata->phy_mask;
> -
> -		err = mdiobus_register(bp->mii_bus);
> -	}
> -
> -	if (err)
> -		goto err_out_free_mdiobus;
> -
> -	err = macb_mii_probe(bp->dev);
> -	if (err)
> -		goto err_out_unregister_bus;
> +	phy_attached_info(phydev);
>  
>  	return 0;
> -
> -err_out_unregister_bus:
> -	mdiobus_unregister(bp->mii_bus);
> -err_out_free_mdiobus:
> -	mdiobus_free(bp->mii_bus);
> -err_out:
> -	return err;
>  }
>  
>  static void macb_update_stats(struct macb *bp)
> @@ -2060,7 +1942,8 @@ static int macb_open(struct net_device *dev)
>  	netif_carrier_off(dev);
>  
>  	/* if the phy is not yet register, retry later*/
> -	if (!dev->phydev)
> +	err = macb_mii_probe(dev);
> +	if (err)
>  		return -EAGAIN;
>  
>  	/* RX buffers initialization */
> @@ -3122,16 +3005,16 @@ static int macb_probe(struct platform_device *pdev)
>  	unsigned int queue_mask, num_queues;
>  	struct macb_platform_data *pdata;
>  	bool native_io;
> -	struct phy_device *phydev;
>  	struct net_device *dev;
>  	struct resource *regs;
>  	void __iomem *mem;
>  	const char *mac;
>  	struct macb *bp;
> +	int phy_irq;
>  	int err;
>  
>  	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	mem = devm_ioremap_resource(&pdev->dev, regs);
> +	mem = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
>  	if (IS_ERR(mem))
>  		return PTR_ERR(mem);
>  
> @@ -3250,21 +3133,26 @@ static int macb_probe(struct platform_device *pdev)
>  	if (err)
>  		goto err_out_free_netdev;
>  
> -	err = macb_mii_init(bp);
> -	if (err)
> -		goto err_out_free_netdev;
> -
> -	phydev = dev->phydev;
> -
> -	netif_carrier_off(dev);
> -
>  	err = register_netdev(dev);
>  	if (err) {
>  		dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
>  		goto err_out_unregister_mdio;
>  	}
>  
> -	phy_attached_info(phydev);
> +	bp->phy_node = of_parse_phandle(bp->pdev->dev.of_node,
> +					"phy-handle", 0);
> +
> +	pdata = dev_get_platdata(&bp->pdev->dev);
> +	if (pdata && gpio_is_valid(pdata->phy_irq_pin)) {
> +		err = devm_gpio_request(&bp->pdev->dev, pdata->phy_irq_pin,
> +					"phy int");
> +		if (!err) {
> +			phy_irq = gpio_to_irq(pdata->phy_irq_pin);
> +			bp->phy_irq = (phy_irq < 0) ? PHY_POLL : phy_irq;
> +		}
> +	}
> +
> +	netif_carrier_off(dev);
>  
>  	netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n",
>  		    macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID),
> @@ -3273,10 +3161,6 @@ static int macb_probe(struct platform_device *pdev)
>  	return 0;
>  
>  err_out_unregister_mdio:
> -	phy_disconnect(dev->phydev);
> -	mdiobus_unregister(bp->mii_bus);
> -	mdiobus_free(bp->mii_bus);
> -
>  	/* Shutdown the PHY if there is a GPIO reset */
>  	if (bp->reset_gpio)
>  		gpiod_set_value(bp->reset_gpio, 0);
> @@ -3304,9 +3188,6 @@ static int macb_remove(struct platform_device *pdev)
>  		bp = netdev_priv(dev);
>  		if (dev->phydev)
>  			phy_disconnect(dev->phydev);
> -		mdiobus_unregister(bp->mii_bus);
> -		dev->phydev = NULL;
> -		mdiobus_free(bp->mii_bus);
>  
>  		/* Shutdown the PHY if there is a GPIO reset */
>  		if (bp->reset_gpio)
> diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
> index d67adad..15e5c0f 100644
> --- a/drivers/net/ethernet/cadence/macb.h
> +++ b/drivers/net/ethernet/cadence/macb.h
> @@ -874,6 +874,8 @@ struct macb {
>  	unsigned int		jumbo_max_len;
>  
>  	u32			wol;
> +	struct device_node *phy_node;
> +	int phy_irq;
>  };
>  
>  static inline bool macb_is_gem(struct macb *bp)
> diff --git a/drivers/net/ethernet/cadence/macb_mdio.c b/drivers/net/ethernet/cadence/macb_mdio.c
> new file mode 100644
> index 0000000..1277ca3
> --- /dev/null
> +++ b/drivers/net/ethernet/cadence/macb_mdio.c
> @@ -0,0 +1,266 @@
> +/*
> + * Cadence Macb mdio controller driver
> + *
> + * Copyright (C) 2014 - 2016 Xilinx, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation; either version 2 of the License, or (at your
> + * option) any later version.
> + */
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/netdevice.h>
> +#include <linux/of_address.h>
> +#include <linux/of_mdio.h>
> +#include <linux/io.h>
> +#include <linux/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/ptp_clock_kernel.h>
> +#include "macb.h"
> +
> +struct macb_mdio_data {
> +	void __iomem *regs;
> +
> +	struct clk *pclk;
> +	struct clk *hclk;
> +};
> +
> +#define macb_mdio_reg_writel(bp, offset, value)	\
> +	writel_relaxed(value, bp->regs + offset)
> +#define macb_mdio_writel(bp, reg, value)	\
> +	macb_mdio_reg_writel(bp, MACB_##reg, value)
> +
> +#define macb_mdio_reg_readl(bp, offset)	readl_relaxed(bp->regs + offset)
> +#define macb_mdio_readl(bp, reg)	macb_mdio_reg_readl(bp, MACB_##reg)
> +
> +#define MACB_MDIO_TIMEOUT	1000
> +
> +static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
> +{
> +	struct macb_mdio_data *bp = bus->priv;
> +	unsigned int timeout = MACB_MDIO_TIMEOUT;
> +	int value;
> +
> +	macb_mdio_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) |
> +				   MACB_BF(RW, MACB_MAN_READ) |
> +				   MACB_BF(PHYA, mii_id) |
> +				   MACB_BF(REGA, regnum) |
> +				   MACB_BF(CODE, MACB_MAN_CODE)));
> +
> +	/* wait for end of transfer */
> +	while (!MACB_BFEXT(IDLE, macb_mdio_readl(bp, NSR)) && timeout) {
> +		cpu_relax();
> +		timeout--;
> +	}
> +
> +	if (!timeout)
> +		return -ETIMEDOUT;
> +
> +	value = MACB_BFEXT(DATA, macb_mdio_readl(bp, MAN));
> +
> +	return value;
> +}
> +
> +static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
> +			   u16 value)
> +{
> +	struct macb_mdio_data *bp = bus->priv;
> +	unsigned int timeout = MACB_MDIO_TIMEOUT;
> +
> +	macb_mdio_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) |
> +				   MACB_BF(RW, MACB_MAN_WRITE) |
> +				   MACB_BF(PHYA, mii_id) |
> +				   MACB_BF(REGA, regnum) |
> +				   MACB_BF(CODE, MACB_MAN_CODE) |
> +				   MACB_BF(DATA, value)));
> +
> +	/* wait for end of transfer */
> +	while (!MACB_BFEXT(IDLE, macb_mdio_readl(bp, NSR)) && timeout) {
> +		cpu_relax();
> +		timeout--;
> +	}
> +
> +	if (!timeout)
> +		return -ETIMEDOUT;
> +
> +	return 0;
> +}
> +
> +static u32 gem_mdc_clk_div(struct macb_mdio_data *bp)
> +{
> +	u32 config;
> +	unsigned long pclk_hz = clk_get_rate(bp->pclk);
> +
> +	if (pclk_hz <= 20000000)
> +		config = GEM_BF(CLK, GEM_CLK_DIV8);
> +	else if (pclk_hz <= 40000000)
> +		config = GEM_BF(CLK, GEM_CLK_DIV16);
> +	else if (pclk_hz <= 80000000)
> +		config = GEM_BF(CLK, GEM_CLK_DIV32);
> +	else if (pclk_hz <= 120000000)
> +		config = GEM_BF(CLK, GEM_CLK_DIV48);
> +	else if (pclk_hz <= 160000000)
> +		config = GEM_BF(CLK, GEM_CLK_DIV64);
> +	else
> +		config = GEM_BF(CLK, GEM_CLK_DIV96);
> +
> +	return config;
> +}
> +
> +static int macb_mdio_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct mii_bus *bus;
> +	struct macb_mdio_data *bp;
> +	struct resource *res;
> +	int ret;
> +	u32 config, i;
> +
> +	bus = mdiobus_alloc_size(sizeof(*bp));
> +	if (!bus)
> +		return -ENOMEM;
> +
> +	bus->name = "macb_mii_bus";
> +	bus->read = &macb_mdio_read;
> +	bus->write = &macb_mdio_write;
> +	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
> +	bus->parent = &pdev->dev;
> +	bus->irq = devm_kzalloc(&pdev->dev, sizeof(int) * PHY_MAX_ADDR,
> +				GFP_KERNEL);

This looks wrong, or at least old. It used to be a pointer to an array,
but it is now an actual array.

> +static const struct of_device_id macb_mdio_dt_ids[] = {
> +	{ .compatible = "cdns,macb-mdio" },
> +
> +};


I've not looked hard enough to know, but can you keep backwards
compatibility? Won't old device tree's assume the mdio bus is always
present? Now you need an explicit node otherwise there will not be an
mdio bus?

     Andrew

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 1/2] net: macb: Add MDIO driver for accessing multiple PHY devices
@ 2016-11-28 16:33   ` Andrew Lunn
  0 siblings, 0 replies; 17+ messages in thread
From: Andrew Lunn @ 2016-11-28 16:33 UTC (permalink / raw)
  To: Harini Katakam
  Cc: nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ,
	boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	harinikatakamlinux-Re5JQEeQqe8AvxtiuMwx3w,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	harinik-gjFFaj9aHVfQT0dZR+AlfA, michals-gjFFaj9aHVfQT0dZR+AlfA,
	Punnaiah Choudary Kalluri

On Mon, Nov 28, 2016 at 03:19:14PM +0530, Harini Katakam wrote:
> This patch is to add support for the hardware with multiple ethernet
> MAC controllers and a single MDIO bus connected to multiple PHY devices.
> MDIO lines are connected to any one of the ethernet MAC controllers and
> all the PHY devices will be accessed using the PHY maintenance interface
> in that MAC controller. This handling along with PHY functionality is
> moved to macb_mdio.c
> 
> Signed-off-by: Punnaiah Choudary Kalluri <punnaia-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Harini Katakam <harinik-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
> ---
>  drivers/net/ethernet/cadence/Makefile    |   2 +-
>  drivers/net/ethernet/cadence/macb.c      | 169 +++-----------------
>  drivers/net/ethernet/cadence/macb.h      |   2 +
>  drivers/net/ethernet/cadence/macb_mdio.c | 266 +++++++++++++++++++++++++++++++
>  4 files changed, 294 insertions(+), 145 deletions(-)
>  create mode 100644 drivers/net/ethernet/cadence/macb_mdio.c
> 
> diff --git a/drivers/net/ethernet/cadence/Makefile b/drivers/net/ethernet/cadence/Makefile
> index 91f79b1..75c3d84 100644
> --- a/drivers/net/ethernet/cadence/Makefile
> +++ b/drivers/net/ethernet/cadence/Makefile
> @@ -2,4 +2,4 @@
>  # Makefile for the Atmel network device drivers.
>  #
>  
> -obj-$(CONFIG_MACB) += macb.o
> +obj-$(CONFIG_MACB) += macb.o macb_mdio.o
> diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
> index 80ccfc4..ae2a797 100644
> --- a/drivers/net/ethernet/cadence/macb.c
> +++ b/drivers/net/ethernet/cadence/macb.c
> @@ -232,45 +232,6 @@ static void macb_get_hwaddr(struct macb *bp)
>  	eth_hw_addr_random(bp->dev);
>  }
>  
> -static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
> -{
> -	struct macb *bp = bus->priv;
> -	int value;
> -
> -	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
> -			      | MACB_BF(RW, MACB_MAN_READ)
> -			      | MACB_BF(PHYA, mii_id)
> -			      | MACB_BF(REGA, regnum)
> -			      | MACB_BF(CODE, MACB_MAN_CODE)));
> -
> -	/* wait for end of transfer */
> -	while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
> -		cpu_relax();
> -
> -	value = MACB_BFEXT(DATA, macb_readl(bp, MAN));
> -
> -	return value;
> -}
> -
> -static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
> -			   u16 value)
> -{
> -	struct macb *bp = bus->priv;
> -
> -	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
> -			      | MACB_BF(RW, MACB_MAN_WRITE)
> -			      | MACB_BF(PHYA, mii_id)
> -			      | MACB_BF(REGA, regnum)
> -			      | MACB_BF(CODE, MACB_MAN_CODE)
> -			      | MACB_BF(DATA, value)));
> -
> -	/* wait for end of transfer */
> -	while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
> -		cpu_relax();
> -
> -	return 0;
> -}
> -
>  /**
>   * macb_set_tx_clk() - Set a clock to a new frequency
>   * @clk		Pointer to the clock to change
> @@ -385,27 +346,19 @@ static void macb_handle_link_change(struct net_device *dev)
>  static int macb_mii_probe(struct net_device *dev)
>  {
>  	struct macb *bp = netdev_priv(dev);
> -	struct macb_platform_data *pdata;
>  	struct phy_device *phydev;
> -	int phy_irq;
>  	int ret;
>  
> -	phydev = phy_find_first(bp->mii_bus);
> +	if (dev->phydev)
> +		return 0;
> +
> +	phydev = of_phy_find_device(bp->phy_node);
>  	if (!phydev) {
>  		netdev_err(dev, "no PHY found\n");
>  		return -ENXIO;
>  	}
> -
> -	pdata = dev_get_platdata(&bp->pdev->dev);
> -	if (pdata && gpio_is_valid(pdata->phy_irq_pin)) {
> -		ret = devm_gpio_request(&bp->pdev->dev, pdata->phy_irq_pin,
> -					"phy int");
> -		if (!ret) {
> -			phy_irq = gpio_to_irq(pdata->phy_irq_pin);
> -			phydev->irq = (phy_irq < 0) ? PHY_POLL : phy_irq;
> -		}
> -	}
> -
> +	if (bp->phy_irq)
> +		phydev->irq = bp->phy_irq;
>  	/* attach the mac to the phy */
>  	ret = phy_connect_direct(dev, phydev, &macb_handle_link_change,
>  				 bp->phy_interface);
> @@ -429,80 +382,9 @@ static int macb_mii_probe(struct net_device *dev)
>  	bp->speed = 0;
>  	bp->duplex = -1;
>  
> -	return 0;
> -}
> -
> -static int macb_mii_init(struct macb *bp)
> -{
> -	struct macb_platform_data *pdata;
> -	struct device_node *np;
> -	int err = -ENXIO, i;
> -
> -	/* Enable management port */
> -	macb_writel(bp, NCR, MACB_BIT(MPE));
> -
> -	bp->mii_bus = mdiobus_alloc();
> -	if (!bp->mii_bus) {
> -		err = -ENOMEM;
> -		goto err_out;
> -	}
> -
> -	bp->mii_bus->name = "MACB_mii_bus";
> -	bp->mii_bus->read = &macb_mdio_read;
> -	bp->mii_bus->write = &macb_mdio_write;
> -	snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
> -		 bp->pdev->name, bp->pdev->id);
> -	bp->mii_bus->priv = bp;
> -	bp->mii_bus->parent = &bp->pdev->dev;
> -	pdata = dev_get_platdata(&bp->pdev->dev);
> -
> -	dev_set_drvdata(&bp->dev->dev, bp->mii_bus);
> -
> -	np = bp->pdev->dev.of_node;
> -	if (np) {
> -		/* try dt phy registration */
> -		err = of_mdiobus_register(bp->mii_bus, np);
> -
> -		/* fallback to standard phy registration if no phy were
> -		 * found during dt phy registration
> -		 */
> -		if (!err && !phy_find_first(bp->mii_bus)) {
> -			for (i = 0; i < PHY_MAX_ADDR; i++) {
> -				struct phy_device *phydev;
> -
> -				phydev = mdiobus_scan(bp->mii_bus, i);
> -				if (IS_ERR(phydev) &&
> -				    PTR_ERR(phydev) != -ENODEV) {
> -					err = PTR_ERR(phydev);
> -					break;
> -				}
> -			}
> -
> -			if (err)
> -				goto err_out_unregister_bus;
> -		}
> -	} else {
> -		if (pdata)
> -			bp->mii_bus->phy_mask = pdata->phy_mask;
> -
> -		err = mdiobus_register(bp->mii_bus);
> -	}
> -
> -	if (err)
> -		goto err_out_free_mdiobus;
> -
> -	err = macb_mii_probe(bp->dev);
> -	if (err)
> -		goto err_out_unregister_bus;
> +	phy_attached_info(phydev);
>  
>  	return 0;
> -
> -err_out_unregister_bus:
> -	mdiobus_unregister(bp->mii_bus);
> -err_out_free_mdiobus:
> -	mdiobus_free(bp->mii_bus);
> -err_out:
> -	return err;
>  }
>  
>  static void macb_update_stats(struct macb *bp)
> @@ -2060,7 +1942,8 @@ static int macb_open(struct net_device *dev)
>  	netif_carrier_off(dev);
>  
>  	/* if the phy is not yet register, retry later*/
> -	if (!dev->phydev)
> +	err = macb_mii_probe(dev);
> +	if (err)
>  		return -EAGAIN;
>  
>  	/* RX buffers initialization */
> @@ -3122,16 +3005,16 @@ static int macb_probe(struct platform_device *pdev)
>  	unsigned int queue_mask, num_queues;
>  	struct macb_platform_data *pdata;
>  	bool native_io;
> -	struct phy_device *phydev;
>  	struct net_device *dev;
>  	struct resource *regs;
>  	void __iomem *mem;
>  	const char *mac;
>  	struct macb *bp;
> +	int phy_irq;
>  	int err;
>  
>  	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	mem = devm_ioremap_resource(&pdev->dev, regs);
> +	mem = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
>  	if (IS_ERR(mem))
>  		return PTR_ERR(mem);
>  
> @@ -3250,21 +3133,26 @@ static int macb_probe(struct platform_device *pdev)
>  	if (err)
>  		goto err_out_free_netdev;
>  
> -	err = macb_mii_init(bp);
> -	if (err)
> -		goto err_out_free_netdev;
> -
> -	phydev = dev->phydev;
> -
> -	netif_carrier_off(dev);
> -
>  	err = register_netdev(dev);
>  	if (err) {
>  		dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
>  		goto err_out_unregister_mdio;
>  	}
>  
> -	phy_attached_info(phydev);
> +	bp->phy_node = of_parse_phandle(bp->pdev->dev.of_node,
> +					"phy-handle", 0);
> +
> +	pdata = dev_get_platdata(&bp->pdev->dev);
> +	if (pdata && gpio_is_valid(pdata->phy_irq_pin)) {
> +		err = devm_gpio_request(&bp->pdev->dev, pdata->phy_irq_pin,
> +					"phy int");
> +		if (!err) {
> +			phy_irq = gpio_to_irq(pdata->phy_irq_pin);
> +			bp->phy_irq = (phy_irq < 0) ? PHY_POLL : phy_irq;
> +		}
> +	}
> +
> +	netif_carrier_off(dev);
>  
>  	netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n",
>  		    macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID),
> @@ -3273,10 +3161,6 @@ static int macb_probe(struct platform_device *pdev)
>  	return 0;
>  
>  err_out_unregister_mdio:
> -	phy_disconnect(dev->phydev);
> -	mdiobus_unregister(bp->mii_bus);
> -	mdiobus_free(bp->mii_bus);
> -
>  	/* Shutdown the PHY if there is a GPIO reset */
>  	if (bp->reset_gpio)
>  		gpiod_set_value(bp->reset_gpio, 0);
> @@ -3304,9 +3188,6 @@ static int macb_remove(struct platform_device *pdev)
>  		bp = netdev_priv(dev);
>  		if (dev->phydev)
>  			phy_disconnect(dev->phydev);
> -		mdiobus_unregister(bp->mii_bus);
> -		dev->phydev = NULL;
> -		mdiobus_free(bp->mii_bus);
>  
>  		/* Shutdown the PHY if there is a GPIO reset */
>  		if (bp->reset_gpio)
> diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
> index d67adad..15e5c0f 100644
> --- a/drivers/net/ethernet/cadence/macb.h
> +++ b/drivers/net/ethernet/cadence/macb.h
> @@ -874,6 +874,8 @@ struct macb {
>  	unsigned int		jumbo_max_len;
>  
>  	u32			wol;
> +	struct device_node *phy_node;
> +	int phy_irq;
>  };
>  
>  static inline bool macb_is_gem(struct macb *bp)
> diff --git a/drivers/net/ethernet/cadence/macb_mdio.c b/drivers/net/ethernet/cadence/macb_mdio.c
> new file mode 100644
> index 0000000..1277ca3
> --- /dev/null
> +++ b/drivers/net/ethernet/cadence/macb_mdio.c
> @@ -0,0 +1,266 @@
> +/*
> + * Cadence Macb mdio controller driver
> + *
> + * Copyright (C) 2014 - 2016 Xilinx, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation; either version 2 of the License, or (at your
> + * option) any later version.
> + */
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/netdevice.h>
> +#include <linux/of_address.h>
> +#include <linux/of_mdio.h>
> +#include <linux/io.h>
> +#include <linux/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/ptp_clock_kernel.h>
> +#include "macb.h"
> +
> +struct macb_mdio_data {
> +	void __iomem *regs;
> +
> +	struct clk *pclk;
> +	struct clk *hclk;
> +};
> +
> +#define macb_mdio_reg_writel(bp, offset, value)	\
> +	writel_relaxed(value, bp->regs + offset)
> +#define macb_mdio_writel(bp, reg, value)	\
> +	macb_mdio_reg_writel(bp, MACB_##reg, value)
> +
> +#define macb_mdio_reg_readl(bp, offset)	readl_relaxed(bp->regs + offset)
> +#define macb_mdio_readl(bp, reg)	macb_mdio_reg_readl(bp, MACB_##reg)
> +
> +#define MACB_MDIO_TIMEOUT	1000
> +
> +static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
> +{
> +	struct macb_mdio_data *bp = bus->priv;
> +	unsigned int timeout = MACB_MDIO_TIMEOUT;
> +	int value;
> +
> +	macb_mdio_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) |
> +				   MACB_BF(RW, MACB_MAN_READ) |
> +				   MACB_BF(PHYA, mii_id) |
> +				   MACB_BF(REGA, regnum) |
> +				   MACB_BF(CODE, MACB_MAN_CODE)));
> +
> +	/* wait for end of transfer */
> +	while (!MACB_BFEXT(IDLE, macb_mdio_readl(bp, NSR)) && timeout) {
> +		cpu_relax();
> +		timeout--;
> +	}
> +
> +	if (!timeout)
> +		return -ETIMEDOUT;
> +
> +	value = MACB_BFEXT(DATA, macb_mdio_readl(bp, MAN));
> +
> +	return value;
> +}
> +
> +static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
> +			   u16 value)
> +{
> +	struct macb_mdio_data *bp = bus->priv;
> +	unsigned int timeout = MACB_MDIO_TIMEOUT;
> +
> +	macb_mdio_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) |
> +				   MACB_BF(RW, MACB_MAN_WRITE) |
> +				   MACB_BF(PHYA, mii_id) |
> +				   MACB_BF(REGA, regnum) |
> +				   MACB_BF(CODE, MACB_MAN_CODE) |
> +				   MACB_BF(DATA, value)));
> +
> +	/* wait for end of transfer */
> +	while (!MACB_BFEXT(IDLE, macb_mdio_readl(bp, NSR)) && timeout) {
> +		cpu_relax();
> +		timeout--;
> +	}
> +
> +	if (!timeout)
> +		return -ETIMEDOUT;
> +
> +	return 0;
> +}
> +
> +static u32 gem_mdc_clk_div(struct macb_mdio_data *bp)
> +{
> +	u32 config;
> +	unsigned long pclk_hz = clk_get_rate(bp->pclk);
> +
> +	if (pclk_hz <= 20000000)
> +		config = GEM_BF(CLK, GEM_CLK_DIV8);
> +	else if (pclk_hz <= 40000000)
> +		config = GEM_BF(CLK, GEM_CLK_DIV16);
> +	else if (pclk_hz <= 80000000)
> +		config = GEM_BF(CLK, GEM_CLK_DIV32);
> +	else if (pclk_hz <= 120000000)
> +		config = GEM_BF(CLK, GEM_CLK_DIV48);
> +	else if (pclk_hz <= 160000000)
> +		config = GEM_BF(CLK, GEM_CLK_DIV64);
> +	else
> +		config = GEM_BF(CLK, GEM_CLK_DIV96);
> +
> +	return config;
> +}
> +
> +static int macb_mdio_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct mii_bus *bus;
> +	struct macb_mdio_data *bp;
> +	struct resource *res;
> +	int ret;
> +	u32 config, i;
> +
> +	bus = mdiobus_alloc_size(sizeof(*bp));
> +	if (!bus)
> +		return -ENOMEM;
> +
> +	bus->name = "macb_mii_bus";
> +	bus->read = &macb_mdio_read;
> +	bus->write = &macb_mdio_write;
> +	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
> +	bus->parent = &pdev->dev;
> +	bus->irq = devm_kzalloc(&pdev->dev, sizeof(int) * PHY_MAX_ADDR,
> +				GFP_KERNEL);

This looks wrong, or at least old. It used to be a pointer to an array,
but it is now an actual array.

> +static const struct of_device_id macb_mdio_dt_ids[] = {
> +	{ .compatible = "cdns,macb-mdio" },
> +
> +};


I've not looked hard enough to know, but can you keep backwards
compatibility? Won't old device tree's assume the mdio bus is always
present? Now you need an explicit node otherwise there will not be an
mdio bus?

     Andrew
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC PATCH 1/2] net: macb: Add MDIO driver for accessing multiple PHY devices
@ 2016-11-28  9:49 ` Harini Katakam
  0 siblings, 0 replies; 17+ messages in thread
From: Harini Katakam @ 2016-11-28  9:49 UTC (permalink / raw)
  To: nicolas.ferre, davem, robh+dt, pawel.moll, mark.rutland,
	ijc+devicetree, galak, boris.brezillon, alexandre.belloni,
	harinikatakamlinux
  Cc: netdev, linux-kernel, devicetree, harinik, michals,
	Punnaiah Choudary Kalluri

This patch is to add support for the hardware with multiple ethernet
MAC controllers and a single MDIO bus connected to multiple PHY devices.
MDIO lines are connected to any one of the ethernet MAC controllers and
all the PHY devices will be accessed using the PHY maintenance interface
in that MAC controller. This handling along with PHY functionality is
moved to macb_mdio.c

Signed-off-by: Punnaiah Choudary Kalluri <punnaia@xilinx.com>
Signed-off-by: Harini Katakam <harinik@xilinx.com>
---
 drivers/net/ethernet/cadence/Makefile    |   2 +-
 drivers/net/ethernet/cadence/macb.c      | 169 +++-----------------
 drivers/net/ethernet/cadence/macb.h      |   2 +
 drivers/net/ethernet/cadence/macb_mdio.c | 266 +++++++++++++++++++++++++++++++
 4 files changed, 294 insertions(+), 145 deletions(-)
 create mode 100644 drivers/net/ethernet/cadence/macb_mdio.c

diff --git a/drivers/net/ethernet/cadence/Makefile b/drivers/net/ethernet/cadence/Makefile
index 91f79b1..75c3d84 100644
--- a/drivers/net/ethernet/cadence/Makefile
+++ b/drivers/net/ethernet/cadence/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the Atmel network device drivers.
 #
 
-obj-$(CONFIG_MACB) += macb.o
+obj-$(CONFIG_MACB) += macb.o macb_mdio.o
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index 80ccfc4..ae2a797 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -232,45 +232,6 @@ static void macb_get_hwaddr(struct macb *bp)
 	eth_hw_addr_random(bp->dev);
 }
 
-static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
-{
-	struct macb *bp = bus->priv;
-	int value;
-
-	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
-			      | MACB_BF(RW, MACB_MAN_READ)
-			      | MACB_BF(PHYA, mii_id)
-			      | MACB_BF(REGA, regnum)
-			      | MACB_BF(CODE, MACB_MAN_CODE)));
-
-	/* wait for end of transfer */
-	while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
-		cpu_relax();
-
-	value = MACB_BFEXT(DATA, macb_readl(bp, MAN));
-
-	return value;
-}
-
-static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
-			   u16 value)
-{
-	struct macb *bp = bus->priv;
-
-	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
-			      | MACB_BF(RW, MACB_MAN_WRITE)
-			      | MACB_BF(PHYA, mii_id)
-			      | MACB_BF(REGA, regnum)
-			      | MACB_BF(CODE, MACB_MAN_CODE)
-			      | MACB_BF(DATA, value)));
-
-	/* wait for end of transfer */
-	while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
-		cpu_relax();
-
-	return 0;
-}
-
 /**
  * macb_set_tx_clk() - Set a clock to a new frequency
  * @clk		Pointer to the clock to change
@@ -385,27 +346,19 @@ static void macb_handle_link_change(struct net_device *dev)
 static int macb_mii_probe(struct net_device *dev)
 {
 	struct macb *bp = netdev_priv(dev);
-	struct macb_platform_data *pdata;
 	struct phy_device *phydev;
-	int phy_irq;
 	int ret;
 
-	phydev = phy_find_first(bp->mii_bus);
+	if (dev->phydev)
+		return 0;
+
+	phydev = of_phy_find_device(bp->phy_node);
 	if (!phydev) {
 		netdev_err(dev, "no PHY found\n");
 		return -ENXIO;
 	}
-
-	pdata = dev_get_platdata(&bp->pdev->dev);
-	if (pdata && gpio_is_valid(pdata->phy_irq_pin)) {
-		ret = devm_gpio_request(&bp->pdev->dev, pdata->phy_irq_pin,
-					"phy int");
-		if (!ret) {
-			phy_irq = gpio_to_irq(pdata->phy_irq_pin);
-			phydev->irq = (phy_irq < 0) ? PHY_POLL : phy_irq;
-		}
-	}
-
+	if (bp->phy_irq)
+		phydev->irq = bp->phy_irq;
 	/* attach the mac to the phy */
 	ret = phy_connect_direct(dev, phydev, &macb_handle_link_change,
 				 bp->phy_interface);
@@ -429,80 +382,9 @@ static int macb_mii_probe(struct net_device *dev)
 	bp->speed = 0;
 	bp->duplex = -1;
 
-	return 0;
-}
-
-static int macb_mii_init(struct macb *bp)
-{
-	struct macb_platform_data *pdata;
-	struct device_node *np;
-	int err = -ENXIO, i;
-
-	/* Enable management port */
-	macb_writel(bp, NCR, MACB_BIT(MPE));
-
-	bp->mii_bus = mdiobus_alloc();
-	if (!bp->mii_bus) {
-		err = -ENOMEM;
-		goto err_out;
-	}
-
-	bp->mii_bus->name = "MACB_mii_bus";
-	bp->mii_bus->read = &macb_mdio_read;
-	bp->mii_bus->write = &macb_mdio_write;
-	snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
-		 bp->pdev->name, bp->pdev->id);
-	bp->mii_bus->priv = bp;
-	bp->mii_bus->parent = &bp->pdev->dev;
-	pdata = dev_get_platdata(&bp->pdev->dev);
-
-	dev_set_drvdata(&bp->dev->dev, bp->mii_bus);
-
-	np = bp->pdev->dev.of_node;
-	if (np) {
-		/* try dt phy registration */
-		err = of_mdiobus_register(bp->mii_bus, np);
-
-		/* fallback to standard phy registration if no phy were
-		 * found during dt phy registration
-		 */
-		if (!err && !phy_find_first(bp->mii_bus)) {
-			for (i = 0; i < PHY_MAX_ADDR; i++) {
-				struct phy_device *phydev;
-
-				phydev = mdiobus_scan(bp->mii_bus, i);
-				if (IS_ERR(phydev) &&
-				    PTR_ERR(phydev) != -ENODEV) {
-					err = PTR_ERR(phydev);
-					break;
-				}
-			}
-
-			if (err)
-				goto err_out_unregister_bus;
-		}
-	} else {
-		if (pdata)
-			bp->mii_bus->phy_mask = pdata->phy_mask;
-
-		err = mdiobus_register(bp->mii_bus);
-	}
-
-	if (err)
-		goto err_out_free_mdiobus;
-
-	err = macb_mii_probe(bp->dev);
-	if (err)
-		goto err_out_unregister_bus;
+	phy_attached_info(phydev);
 
 	return 0;
-
-err_out_unregister_bus:
-	mdiobus_unregister(bp->mii_bus);
-err_out_free_mdiobus:
-	mdiobus_free(bp->mii_bus);
-err_out:
-	return err;
 }
 
 static void macb_update_stats(struct macb *bp)
@@ -2060,7 +1942,8 @@ static int macb_open(struct net_device *dev)
 	netif_carrier_off(dev);
 
 	/* if the phy is not yet register, retry later*/
-	if (!dev->phydev)
+	err = macb_mii_probe(dev);
+	if (err)
 		return -EAGAIN;
 
 	/* RX buffers initialization */
@@ -3122,16 +3005,16 @@ static int macb_probe(struct platform_device *pdev)
 	unsigned int queue_mask, num_queues;
 	struct macb_platform_data *pdata;
 	bool native_io;
-	struct phy_device *phydev;
 	struct net_device *dev;
 	struct resource *regs;
 	void __iomem *mem;
 	const char *mac;
 	struct macb *bp;
+	int phy_irq;
 	int err;
 
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	mem = devm_ioremap_resource(&pdev->dev, regs);
+	mem = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
 	if (IS_ERR(mem))
 		return PTR_ERR(mem);
 
@@ -3250,21 +3133,26 @@ static int macb_probe(struct platform_device *pdev)
 	if (err)
 		goto err_out_free_netdev;
 
-	err = macb_mii_init(bp);
-	if (err)
-		goto err_out_free_netdev;
-
-	phydev = dev->phydev;
-
-	netif_carrier_off(dev);
-
 	err = register_netdev(dev);
 	if (err) {
 		dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
 		goto err_out_unregister_mdio;
 	}
 
-	phy_attached_info(phydev);
+	bp->phy_node = of_parse_phandle(bp->pdev->dev.of_node,
+					"phy-handle", 0);
+
+	pdata = dev_get_platdata(&bp->pdev->dev);
+	if (pdata && gpio_is_valid(pdata->phy_irq_pin)) {
+		err = devm_gpio_request(&bp->pdev->dev, pdata->phy_irq_pin,
+					"phy int");
+		if (!err) {
+			phy_irq = gpio_to_irq(pdata->phy_irq_pin);
+			bp->phy_irq = (phy_irq < 0) ? PHY_POLL : phy_irq;
+		}
+	}
+
+	netif_carrier_off(dev);
 
 	netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n",
 		    macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID),
@@ -3273,10 +3161,6 @@ static int macb_probe(struct platform_device *pdev)
 	return 0;
 
 err_out_unregister_mdio:
-	phy_disconnect(dev->phydev);
-	mdiobus_unregister(bp->mii_bus);
-	mdiobus_free(bp->mii_bus);
-
 	/* Shutdown the PHY if there is a GPIO reset */
 	if (bp->reset_gpio)
 		gpiod_set_value(bp->reset_gpio, 0);
@@ -3304,9 +3188,6 @@ static int macb_remove(struct platform_device *pdev)
 		bp = netdev_priv(dev);
 		if (dev->phydev)
 			phy_disconnect(dev->phydev);
-		mdiobus_unregister(bp->mii_bus);
-		dev->phydev = NULL;
-		mdiobus_free(bp->mii_bus);
 
 		/* Shutdown the PHY if there is a GPIO reset */
 		if (bp->reset_gpio)
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index d67adad..15e5c0f 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -874,6 +874,8 @@ struct macb {
 	unsigned int		jumbo_max_len;
 
 	u32			wol;
+	struct device_node *phy_node;
+	int phy_irq;
 };
 
 static inline bool macb_is_gem(struct macb *bp)
diff --git a/drivers/net/ethernet/cadence/macb_mdio.c b/drivers/net/ethernet/cadence/macb_mdio.c
new file mode 100644
index 0000000..1277ca3
--- /dev/null
+++ b/drivers/net/ethernet/cadence/macb_mdio.c
@@ -0,0 +1,266 @@
+/*
+ * Cadence Macb mdio controller driver
+ *
+ * Copyright (C) 2014 - 2016 Xilinx, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/of_address.h>
+#include <linux/of_mdio.h>
+#include <linux/io.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/ptp_clock_kernel.h>
+#include "macb.h"
+
+struct macb_mdio_data {
+	void __iomem *regs;
+
+	struct clk *pclk;
+	struct clk *hclk;
+};
+
+#define macb_mdio_reg_writel(bp, offset, value)	\
+	writel_relaxed(value, bp->regs + offset)
+#define macb_mdio_writel(bp, reg, value)	\
+	macb_mdio_reg_writel(bp, MACB_##reg, value)
+
+#define macb_mdio_reg_readl(bp, offset)	readl_relaxed(bp->regs + offset)
+#define macb_mdio_readl(bp, reg)	macb_mdio_reg_readl(bp, MACB_##reg)
+
+#define MACB_MDIO_TIMEOUT	1000
+
+static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+	struct macb_mdio_data *bp = bus->priv;
+	unsigned int timeout = MACB_MDIO_TIMEOUT;
+	int value;
+
+	macb_mdio_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) |
+				   MACB_BF(RW, MACB_MAN_READ) |
+				   MACB_BF(PHYA, mii_id) |
+				   MACB_BF(REGA, regnum) |
+				   MACB_BF(CODE, MACB_MAN_CODE)));
+
+	/* wait for end of transfer */
+	while (!MACB_BFEXT(IDLE, macb_mdio_readl(bp, NSR)) && timeout) {
+		cpu_relax();
+		timeout--;
+	}
+
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	value = MACB_BFEXT(DATA, macb_mdio_readl(bp, MAN));
+
+	return value;
+}
+
+static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+			   u16 value)
+{
+	struct macb_mdio_data *bp = bus->priv;
+	unsigned int timeout = MACB_MDIO_TIMEOUT;
+
+	macb_mdio_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) |
+				   MACB_BF(RW, MACB_MAN_WRITE) |
+				   MACB_BF(PHYA, mii_id) |
+				   MACB_BF(REGA, regnum) |
+				   MACB_BF(CODE, MACB_MAN_CODE) |
+				   MACB_BF(DATA, value)));
+
+	/* wait for end of transfer */
+	while (!MACB_BFEXT(IDLE, macb_mdio_readl(bp, NSR)) && timeout) {
+		cpu_relax();
+		timeout--;
+	}
+
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static u32 gem_mdc_clk_div(struct macb_mdio_data *bp)
+{
+	u32 config;
+	unsigned long pclk_hz = clk_get_rate(bp->pclk);
+
+	if (pclk_hz <= 20000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV8);
+	else if (pclk_hz <= 40000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV16);
+	else if (pclk_hz <= 80000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV32);
+	else if (pclk_hz <= 120000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV48);
+	else if (pclk_hz <= 160000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV64);
+	else
+		config = GEM_BF(CLK, GEM_CLK_DIV96);
+
+	return config;
+}
+
+static int macb_mdio_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct mii_bus *bus;
+	struct macb_mdio_data *bp;
+	struct resource *res;
+	int ret;
+	u32 config, i;
+
+	bus = mdiobus_alloc_size(sizeof(*bp));
+	if (!bus)
+		return -ENOMEM;
+
+	bus->name = "macb_mii_bus";
+	bus->read = &macb_mdio_read;
+	bus->write = &macb_mdio_write;
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
+	bus->parent = &pdev->dev;
+	bus->irq = devm_kzalloc(&pdev->dev, sizeof(int) * PHY_MAX_ADDR,
+				GFP_KERNEL);
+	if (!bus->irq) {
+		ret = -ENOMEM;
+		goto err_out_free_mdiobus;
+	}
+
+	bp = bus->priv;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	bp->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (IS_ERR(bp->regs)) {
+		ret = PTR_ERR(bp->regs);
+		goto err_out_free_mdiobus;
+	}
+
+	bp->pclk = devm_clk_get(&pdev->dev, "pclk");
+	if (IS_ERR(bp->pclk)) {
+		ret = PTR_ERR(bp->pclk);
+		dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", ret);
+		goto err_out_free_mdiobus;
+	}
+
+	bp->hclk = devm_clk_get(&pdev->dev, "hclk");
+	if (IS_ERR(bp->hclk)) {
+		ret = PTR_ERR(bp->hclk);
+		dev_err(&pdev->dev, "failed to get hclk (%u)\n", ret);
+		goto err_out_free_mdiobus;
+	}
+
+	ret = clk_prepare_enable(bp->pclk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable pclk (%u)\n", ret);
+		goto err_out_free_mdiobus;
+	}
+
+	ret = clk_prepare_enable(bp->hclk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable hclk (%u)\n", ret);
+		goto err_disable_pclk;
+	}
+
+	platform_set_drvdata(pdev, bus);
+
+	/* Enable management port */
+	config = macb_mdio_readl(bp, NCR);
+	config |= MACB_BIT(MPE);
+	macb_mdio_writel(bp, NCR, config);
+	config = gem_mdc_clk_div(bp);
+	macb_mdio_writel(bp, NCFGR, config);
+
+	np = pdev->dev.of_node;
+	if (np) {
+		/* try dt phy registration */
+		ret = of_mdiobus_register(bus, np);
+
+		/* Fallback to standard phy registration if no phy were
+		 * found during dt phy registration
+		 */
+		if (!ret && !phy_find_first(bus)) {
+			for (i = 0; i < PHY_MAX_ADDR; i++) {
+				struct phy_device *phydev;
+
+				phydev = mdiobus_scan(bus, i);
+				if (IS_ERR(phydev) &&
+				    PTR_ERR(phydev) != -ENODEV) {
+					ret = PTR_ERR(phydev);
+					break;
+				}
+			}
+
+			if (ret)
+				goto err_out_unregister_bus;
+		}
+	} else {
+		for (i = 0; i < PHY_MAX_ADDR; i++)
+			bus->irq[i] = PHY_POLL;
+
+		ret = of_mdiobus_register(bus, np);
+	}
+
+	if (ret)
+		goto err_out_free_mdio_irq;
+
+	return 0;
+
+err_out_unregister_bus:
+	mdiobus_unregister(bus);
+err_out_free_mdio_irq:
+	kfree(bus->irq);
+err_disable_pclk:
+	clk_disable_unprepare(bp->pclk);
+	clk_disable_unprepare(bp->hclk);
+err_out_free_mdiobus:
+	mdiobus_free(bus);
+	return ret;
+}
+
+static int macb_mdio_remove(struct platform_device *pdev)
+{
+	struct mii_bus *bus = platform_get_drvdata(pdev);
+	struct macb_mdio_data *bp = bus->priv;
+	u32 config;
+
+	/* Disable management port */
+	config = macb_mdio_readl(bp, NCR);
+	config &= ~MACB_BIT(MPE);
+	macb_mdio_writel(bp, NCR, config);
+	mdiobus_unregister(bus);
+	clk_disable_unprepare(bp->hclk);
+	clk_disable_unprepare(bp->pclk);
+	mdiobus_free(bus);
+
+	return 0;
+}
+
+static const struct of_device_id macb_mdio_dt_ids[] = {
+	{ .compatible = "cdns,macb-mdio" },
+
+};
+MODULE_DEVICE_TABLE(of, macb_mdio_dt_ids);
+
+static struct platform_driver macb_mdio_driver = {
+	.probe = macb_mdio_probe,
+	.remove = macb_mdio_remove,
+	.driver = {
+		.name = "macb-mdio",
+		.of_match_table = macb_mdio_dt_ids,
+	},
+};
+
+module_platform_driver(macb_mdio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence MACB MDIO driver");
+MODULE_AUTHOR("Xilinx");
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 1/2] net: macb: Add MDIO driver for accessing multiple PHY devices
@ 2016-11-28  9:49 ` Harini Katakam
  0 siblings, 0 replies; 17+ messages in thread
From: Harini Katakam @ 2016-11-28  9:49 UTC (permalink / raw)
  To: nicolas.ferre, davem, robh+dt, pawel.moll, mark.rutland,
	ijc+devicetree, galak, boris.brezillon, alexandre.belloni,
	harinikatakamlinux
  Cc: netdev, linux-kernel, devicetree, harinik, michals,
	Punnaiah Choudary Kalluri

This patch is to add support for the hardware with multiple ethernet
MAC controllers and a single MDIO bus connected to multiple PHY devices.
MDIO lines are connected to any one of the ethernet MAC controllers and
all the PHY devices will be accessed using the PHY maintenance interface
in that MAC controller. This handling along with PHY functionality is
moved to macb_mdio.c

Signed-off-by: Punnaiah Choudary Kalluri <punnaia@xilinx.com>
Signed-off-by: Harini Katakam <harinik@xilinx.com>
---
 drivers/net/ethernet/cadence/Makefile    |   2 +-
 drivers/net/ethernet/cadence/macb.c      | 169 +++-----------------
 drivers/net/ethernet/cadence/macb.h      |   2 +
 drivers/net/ethernet/cadence/macb_mdio.c | 266 +++++++++++++++++++++++++++++++
 4 files changed, 294 insertions(+), 145 deletions(-)
 create mode 100644 drivers/net/ethernet/cadence/macb_mdio.c

diff --git a/drivers/net/ethernet/cadence/Makefile b/drivers/net/ethernet/cadence/Makefile
index 91f79b1..75c3d84 100644
--- a/drivers/net/ethernet/cadence/Makefile
+++ b/drivers/net/ethernet/cadence/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the Atmel network device drivers.
 #
 
-obj-$(CONFIG_MACB) += macb.o
+obj-$(CONFIG_MACB) += macb.o macb_mdio.o
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index 80ccfc4..ae2a797 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -232,45 +232,6 @@ static void macb_get_hwaddr(struct macb *bp)
 	eth_hw_addr_random(bp->dev);
 }
 
-static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
-{
-	struct macb *bp = bus->priv;
-	int value;
-
-	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
-			      | MACB_BF(RW, MACB_MAN_READ)
-			      | MACB_BF(PHYA, mii_id)
-			      | MACB_BF(REGA, regnum)
-			      | MACB_BF(CODE, MACB_MAN_CODE)));
-
-	/* wait for end of transfer */
-	while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
-		cpu_relax();
-
-	value = MACB_BFEXT(DATA, macb_readl(bp, MAN));
-
-	return value;
-}
-
-static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
-			   u16 value)
-{
-	struct macb *bp = bus->priv;
-
-	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
-			      | MACB_BF(RW, MACB_MAN_WRITE)
-			      | MACB_BF(PHYA, mii_id)
-			      | MACB_BF(REGA, regnum)
-			      | MACB_BF(CODE, MACB_MAN_CODE)
-			      | MACB_BF(DATA, value)));
-
-	/* wait for end of transfer */
-	while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
-		cpu_relax();
-
-	return 0;
-}
-
 /**
  * macb_set_tx_clk() - Set a clock to a new frequency
  * @clk		Pointer to the clock to change
@@ -385,27 +346,19 @@ static void macb_handle_link_change(struct net_device *dev)
 static int macb_mii_probe(struct net_device *dev)
 {
 	struct macb *bp = netdev_priv(dev);
-	struct macb_platform_data *pdata;
 	struct phy_device *phydev;
-	int phy_irq;
 	int ret;
 
-	phydev = phy_find_first(bp->mii_bus);
+	if (dev->phydev)
+		return 0;
+
+	phydev = of_phy_find_device(bp->phy_node);
 	if (!phydev) {
 		netdev_err(dev, "no PHY found\n");
 		return -ENXIO;
 	}
-
-	pdata = dev_get_platdata(&bp->pdev->dev);
-	if (pdata && gpio_is_valid(pdata->phy_irq_pin)) {
-		ret = devm_gpio_request(&bp->pdev->dev, pdata->phy_irq_pin,
-					"phy int");
-		if (!ret) {
-			phy_irq = gpio_to_irq(pdata->phy_irq_pin);
-			phydev->irq = (phy_irq < 0) ? PHY_POLL : phy_irq;
-		}
-	}
-
+	if (bp->phy_irq)
+		phydev->irq = bp->phy_irq;
 	/* attach the mac to the phy */
 	ret = phy_connect_direct(dev, phydev, &macb_handle_link_change,
 				 bp->phy_interface);
@@ -429,80 +382,9 @@ static int macb_mii_probe(struct net_device *dev)
 	bp->speed = 0;
 	bp->duplex = -1;
 
-	return 0;
-}
-
-static int macb_mii_init(struct macb *bp)
-{
-	struct macb_platform_data *pdata;
-	struct device_node *np;
-	int err = -ENXIO, i;
-
-	/* Enable management port */
-	macb_writel(bp, NCR, MACB_BIT(MPE));
-
-	bp->mii_bus = mdiobus_alloc();
-	if (!bp->mii_bus) {
-		err = -ENOMEM;
-		goto err_out;
-	}
-
-	bp->mii_bus->name = "MACB_mii_bus";
-	bp->mii_bus->read = &macb_mdio_read;
-	bp->mii_bus->write = &macb_mdio_write;
-	snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
-		 bp->pdev->name, bp->pdev->id);
-	bp->mii_bus->priv = bp;
-	bp->mii_bus->parent = &bp->pdev->dev;
-	pdata = dev_get_platdata(&bp->pdev->dev);
-
-	dev_set_drvdata(&bp->dev->dev, bp->mii_bus);
-
-	np = bp->pdev->dev.of_node;
-	if (np) {
-		/* try dt phy registration */
-		err = of_mdiobus_register(bp->mii_bus, np);
-
-		/* fallback to standard phy registration if no phy were
-		 * found during dt phy registration
-		 */
-		if (!err && !phy_find_first(bp->mii_bus)) {
-			for (i = 0; i < PHY_MAX_ADDR; i++) {
-				struct phy_device *phydev;
-
-				phydev = mdiobus_scan(bp->mii_bus, i);
-				if (IS_ERR(phydev) &&
-				    PTR_ERR(phydev) != -ENODEV) {
-					err = PTR_ERR(phydev);
-					break;
-				}
-			}
-
-			if (err)
-				goto err_out_unregister_bus;
-		}
-	} else {
-		if (pdata)
-			bp->mii_bus->phy_mask = pdata->phy_mask;
-
-		err = mdiobus_register(bp->mii_bus);
-	}
-
-	if (err)
-		goto err_out_free_mdiobus;
-
-	err = macb_mii_probe(bp->dev);
-	if (err)
-		goto err_out_unregister_bus;
+	phy_attached_info(phydev);
 
 	return 0;
-
-err_out_unregister_bus:
-	mdiobus_unregister(bp->mii_bus);
-err_out_free_mdiobus:
-	mdiobus_free(bp->mii_bus);
-err_out:
-	return err;
 }
 
 static void macb_update_stats(struct macb *bp)
@@ -2060,7 +1942,8 @@ static int macb_open(struct net_device *dev)
 	netif_carrier_off(dev);
 
 	/* if the phy is not yet register, retry later*/
-	if (!dev->phydev)
+	err = macb_mii_probe(dev);
+	if (err)
 		return -EAGAIN;
 
 	/* RX buffers initialization */
@@ -3122,16 +3005,16 @@ static int macb_probe(struct platform_device *pdev)
 	unsigned int queue_mask, num_queues;
 	struct macb_platform_data *pdata;
 	bool native_io;
-	struct phy_device *phydev;
 	struct net_device *dev;
 	struct resource *regs;
 	void __iomem *mem;
 	const char *mac;
 	struct macb *bp;
+	int phy_irq;
 	int err;
 
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	mem = devm_ioremap_resource(&pdev->dev, regs);
+	mem = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
 	if (IS_ERR(mem))
 		return PTR_ERR(mem);
 
@@ -3250,21 +3133,26 @@ static int macb_probe(struct platform_device *pdev)
 	if (err)
 		goto err_out_free_netdev;
 
-	err = macb_mii_init(bp);
-	if (err)
-		goto err_out_free_netdev;
-
-	phydev = dev->phydev;
-
-	netif_carrier_off(dev);
-
 	err = register_netdev(dev);
 	if (err) {
 		dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
 		goto err_out_unregister_mdio;
 	}
 
-	phy_attached_info(phydev);
+	bp->phy_node = of_parse_phandle(bp->pdev->dev.of_node,
+					"phy-handle", 0);
+
+	pdata = dev_get_platdata(&bp->pdev->dev);
+	if (pdata && gpio_is_valid(pdata->phy_irq_pin)) {
+		err = devm_gpio_request(&bp->pdev->dev, pdata->phy_irq_pin,
+					"phy int");
+		if (!err) {
+			phy_irq = gpio_to_irq(pdata->phy_irq_pin);
+			bp->phy_irq = (phy_irq < 0) ? PHY_POLL : phy_irq;
+		}
+	}
+
+	netif_carrier_off(dev);
 
 	netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n",
 		    macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID),
@@ -3273,10 +3161,6 @@ static int macb_probe(struct platform_device *pdev)
 	return 0;
 
 err_out_unregister_mdio:
-	phy_disconnect(dev->phydev);
-	mdiobus_unregister(bp->mii_bus);
-	mdiobus_free(bp->mii_bus);
-
 	/* Shutdown the PHY if there is a GPIO reset */
 	if (bp->reset_gpio)
 		gpiod_set_value(bp->reset_gpio, 0);
@@ -3304,9 +3188,6 @@ static int macb_remove(struct platform_device *pdev)
 		bp = netdev_priv(dev);
 		if (dev->phydev)
 			phy_disconnect(dev->phydev);
-		mdiobus_unregister(bp->mii_bus);
-		dev->phydev = NULL;
-		mdiobus_free(bp->mii_bus);
 
 		/* Shutdown the PHY if there is a GPIO reset */
 		if (bp->reset_gpio)
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index d67adad..15e5c0f 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -874,6 +874,8 @@ struct macb {
 	unsigned int		jumbo_max_len;
 
 	u32			wol;
+	struct device_node *phy_node;
+	int phy_irq;
 };
 
 static inline bool macb_is_gem(struct macb *bp)
diff --git a/drivers/net/ethernet/cadence/macb_mdio.c b/drivers/net/ethernet/cadence/macb_mdio.c
new file mode 100644
index 0000000..1277ca3
--- /dev/null
+++ b/drivers/net/ethernet/cadence/macb_mdio.c
@@ -0,0 +1,266 @@
+/*
+ * Cadence Macb mdio controller driver
+ *
+ * Copyright (C) 2014 - 2016 Xilinx, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/of_address.h>
+#include <linux/of_mdio.h>
+#include <linux/io.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/ptp_clock_kernel.h>
+#include "macb.h"
+
+struct macb_mdio_data {
+	void __iomem *regs;
+
+	struct clk *pclk;
+	struct clk *hclk;
+};
+
+#define macb_mdio_reg_writel(bp, offset, value)	\
+	writel_relaxed(value, bp->regs + offset)
+#define macb_mdio_writel(bp, reg, value)	\
+	macb_mdio_reg_writel(bp, MACB_##reg, value)
+
+#define macb_mdio_reg_readl(bp, offset)	readl_relaxed(bp->regs + offset)
+#define macb_mdio_readl(bp, reg)	macb_mdio_reg_readl(bp, MACB_##reg)
+
+#define MACB_MDIO_TIMEOUT	1000
+
+static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+	struct macb_mdio_data *bp = bus->priv;
+	unsigned int timeout = MACB_MDIO_TIMEOUT;
+	int value;
+
+	macb_mdio_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) |
+				   MACB_BF(RW, MACB_MAN_READ) |
+				   MACB_BF(PHYA, mii_id) |
+				   MACB_BF(REGA, regnum) |
+				   MACB_BF(CODE, MACB_MAN_CODE)));
+
+	/* wait for end of transfer */
+	while (!MACB_BFEXT(IDLE, macb_mdio_readl(bp, NSR)) && timeout) {
+		cpu_relax();
+		timeout--;
+	}
+
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	value = MACB_BFEXT(DATA, macb_mdio_readl(bp, MAN));
+
+	return value;
+}
+
+static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+			   u16 value)
+{
+	struct macb_mdio_data *bp = bus->priv;
+	unsigned int timeout = MACB_MDIO_TIMEOUT;
+
+	macb_mdio_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) |
+				   MACB_BF(RW, MACB_MAN_WRITE) |
+				   MACB_BF(PHYA, mii_id) |
+				   MACB_BF(REGA, regnum) |
+				   MACB_BF(CODE, MACB_MAN_CODE) |
+				   MACB_BF(DATA, value)));
+
+	/* wait for end of transfer */
+	while (!MACB_BFEXT(IDLE, macb_mdio_readl(bp, NSR)) && timeout) {
+		cpu_relax();
+		timeout--;
+	}
+
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static u32 gem_mdc_clk_div(struct macb_mdio_data *bp)
+{
+	u32 config;
+	unsigned long pclk_hz = clk_get_rate(bp->pclk);
+
+	if (pclk_hz <= 20000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV8);
+	else if (pclk_hz <= 40000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV16);
+	else if (pclk_hz <= 80000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV32);
+	else if (pclk_hz <= 120000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV48);
+	else if (pclk_hz <= 160000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV64);
+	else
+		config = GEM_BF(CLK, GEM_CLK_DIV96);
+
+	return config;
+}
+
+static int macb_mdio_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct mii_bus *bus;
+	struct macb_mdio_data *bp;
+	struct resource *res;
+	int ret;
+	u32 config, i;
+
+	bus = mdiobus_alloc_size(sizeof(*bp));
+	if (!bus)
+		return -ENOMEM;
+
+	bus->name = "macb_mii_bus";
+	bus->read = &macb_mdio_read;
+	bus->write = &macb_mdio_write;
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
+	bus->parent = &pdev->dev;
+	bus->irq = devm_kzalloc(&pdev->dev, sizeof(int) * PHY_MAX_ADDR,
+				GFP_KERNEL);
+	if (!bus->irq) {
+		ret = -ENOMEM;
+		goto err_out_free_mdiobus;
+	}
+
+	bp = bus->priv;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	bp->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (IS_ERR(bp->regs)) {
+		ret = PTR_ERR(bp->regs);
+		goto err_out_free_mdiobus;
+	}
+
+	bp->pclk = devm_clk_get(&pdev->dev, "pclk");
+	if (IS_ERR(bp->pclk)) {
+		ret = PTR_ERR(bp->pclk);
+		dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", ret);
+		goto err_out_free_mdiobus;
+	}
+
+	bp->hclk = devm_clk_get(&pdev->dev, "hclk");
+	if (IS_ERR(bp->hclk)) {
+		ret = PTR_ERR(bp->hclk);
+		dev_err(&pdev->dev, "failed to get hclk (%u)\n", ret);
+		goto err_out_free_mdiobus;
+	}
+
+	ret = clk_prepare_enable(bp->pclk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable pclk (%u)\n", ret);
+		goto err_out_free_mdiobus;
+	}
+
+	ret = clk_prepare_enable(bp->hclk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable hclk (%u)\n", ret);
+		goto err_disable_pclk;
+	}
+
+	platform_set_drvdata(pdev, bus);
+
+	/* Enable management port */
+	config = macb_mdio_readl(bp, NCR);
+	config |= MACB_BIT(MPE);
+	macb_mdio_writel(bp, NCR, config);
+	config = gem_mdc_clk_div(bp);
+	macb_mdio_writel(bp, NCFGR, config);
+
+	np = pdev->dev.of_node;
+	if (np) {
+		/* try dt phy registration */
+		ret = of_mdiobus_register(bus, np);
+
+		/* Fallback to standard phy registration if no phy were
+		 * found during dt phy registration
+		 */
+		if (!ret && !phy_find_first(bus)) {
+			for (i = 0; i < PHY_MAX_ADDR; i++) {
+				struct phy_device *phydev;
+
+				phydev = mdiobus_scan(bus, i);
+				if (IS_ERR(phydev) &&
+				    PTR_ERR(phydev) != -ENODEV) {
+					ret = PTR_ERR(phydev);
+					break;
+				}
+			}
+
+			if (ret)
+				goto err_out_unregister_bus;
+		}
+	} else {
+		for (i = 0; i < PHY_MAX_ADDR; i++)
+			bus->irq[i] = PHY_POLL;
+
+		ret = of_mdiobus_register(bus, np);
+	}
+
+	if (ret)
+		goto err_out_free_mdio_irq;
+
+	return 0;
+
+err_out_unregister_bus:
+	mdiobus_unregister(bus);
+err_out_free_mdio_irq:
+	kfree(bus->irq);
+err_disable_pclk:
+	clk_disable_unprepare(bp->pclk);
+	clk_disable_unprepare(bp->hclk);
+err_out_free_mdiobus:
+	mdiobus_free(bus);
+	return ret;
+}
+
+static int macb_mdio_remove(struct platform_device *pdev)
+{
+	struct mii_bus *bus = platform_get_drvdata(pdev);
+	struct macb_mdio_data *bp = bus->priv;
+	u32 config;
+
+	/* Disable management port */
+	config = macb_mdio_readl(bp, NCR);
+	config &= ~MACB_BIT(MPE);
+	macb_mdio_writel(bp, NCR, config);
+	mdiobus_unregister(bus);
+	clk_disable_unprepare(bp->hclk);
+	clk_disable_unprepare(bp->pclk);
+	mdiobus_free(bus);
+
+	return 0;
+}
+
+static const struct of_device_id macb_mdio_dt_ids[] = {
+	{ .compatible = "cdns,macb-mdio" },
+
+};
+MODULE_DEVICE_TABLE(of, macb_mdio_dt_ids);
+
+static struct platform_driver macb_mdio_driver = {
+	.probe = macb_mdio_probe,
+	.remove = macb_mdio_remove,
+	.driver = {
+		.name = "macb-mdio",
+		.of_match_table = macb_mdio_dt_ids,
+	},
+};
+
+module_platform_driver(macb_mdio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence MACB MDIO driver");
+MODULE_AUTHOR("Xilinx");
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 1/2] net: macb: Add mdio driver for accessing multiple phy devices
  2015-07-13  4:48 [RFC PATCH 0/2] net: macb: Add mdio driver for accessing multiple phy devices Punnaiah Choudary Kalluri
@ 2015-07-13  4:48 ` Punnaiah Choudary Kalluri
  0 siblings, 0 replies; 17+ messages in thread
From: Punnaiah Choudary Kalluri @ 2015-07-13  4:48 UTC (permalink / raw)
  To: nicolas.ferre, michals, anirudh, davem
  Cc: harinik, kpc528, kalluripunnaiahchoudary, netdev,
	Punnaiah Choudary Kalluri

This patch is to add spoort for the design that has multiple ethernet
mac controllers and single mdio bus connected to multiple phy devices.
i.e mdio lines are connected to any of the ethernet mac controller and
all the phy devices will be accessed using the phy maintainance interface
in that mac controller.

Signed-off-by: Punnaiah Choudary Kalluri <punnaia@xilinx.com>
---
 drivers/net/ethernet/cadence/Makefile    |    2 +-
 drivers/net/ethernet/cadence/macb.c      |   93 +-------------
 drivers/net/ethernet/cadence/macb.h      |    3 +-
 drivers/net/ethernet/cadence/macb_mdio.c |  204 ++++++++++++++++++++++++++++++
 4 files changed, 211 insertions(+), 91 deletions(-)
 create mode 100644 drivers/net/ethernet/cadence/macb_mdio.c

diff --git a/drivers/net/ethernet/cadence/Makefile b/drivers/net/ethernet/cadence/Makefile
index 9068b83..73504f4 100644
--- a/drivers/net/ethernet/cadence/Makefile
+++ b/drivers/net/ethernet/cadence/Makefile
@@ -3,4 +3,4 @@
 #
 
 obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o
-obj-$(CONFIG_MACB) += macb.o
+obj-$(CONFIG_MACB) += macb.o macb_mdio.o
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index 4833ba1..df1b928 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -320,7 +320,7 @@ static int macb_mii_probe(struct net_device *dev)
 	int phy_irq;
 	int ret;
 
-	phydev = phy_find_first(bp->mii_bus);
+	phydev = of_phy_find_device(bp->phy_node);
 	if (!phydev) {
 		netdev_err(dev, "no PHY found\n");
 		return -ENXIO;
@@ -359,89 +359,6 @@ static int macb_mii_probe(struct net_device *dev)
 	return 0;
 }
 
-int macb_mii_init(struct macb *bp)
-{
-	struct macb_platform_data *pdata;
-	struct device_node *np;
-	int err = -ENXIO, i;
-
-	/* Enable management port */
-	macb_writel(bp, NCR, MACB_BIT(MPE));
-
-	bp->mii_bus = mdiobus_alloc();
-	if (bp->mii_bus == NULL) {
-		err = -ENOMEM;
-		goto err_out;
-	}
-
-	bp->mii_bus->name = "MACB_mii_bus";
-	bp->mii_bus->read = &macb_mdio_read;
-	bp->mii_bus->write = &macb_mdio_write;
-	snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
-		bp->pdev->name, bp->pdev->id);
-	bp->mii_bus->priv = bp;
-	bp->mii_bus->parent = &bp->dev->dev;
-	pdata = dev_get_platdata(&bp->pdev->dev);
-
-	bp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
-	if (!bp->mii_bus->irq) {
-		err = -ENOMEM;
-		goto err_out_free_mdiobus;
-	}
-
-	dev_set_drvdata(&bp->dev->dev, bp->mii_bus);
-
-	np = bp->pdev->dev.of_node;
-	if (np) {
-		/* try dt phy registration */
-		err = of_mdiobus_register(bp->mii_bus, np);
-
-		/* fallback to standard phy registration if no phy were
-		   found during dt phy registration */
-		if (!err && !phy_find_first(bp->mii_bus)) {
-			for (i = 0; i < PHY_MAX_ADDR; i++) {
-				struct phy_device *phydev;
-
-				phydev = mdiobus_scan(bp->mii_bus, i);
-				if (IS_ERR(phydev)) {
-					err = PTR_ERR(phydev);
-					break;
-				}
-			}
-
-			if (err)
-				goto err_out_unregister_bus;
-		}
-	} else {
-		for (i = 0; i < PHY_MAX_ADDR; i++)
-			bp->mii_bus->irq[i] = PHY_POLL;
-
-		if (pdata)
-			bp->mii_bus->phy_mask = pdata->phy_mask;
-
-		err = mdiobus_register(bp->mii_bus);
-	}
-
-	if (err)
-		goto err_out_free_mdio_irq;
-
-	err = macb_mii_probe(bp->dev);
-	if (err)
-		goto err_out_unregister_bus;
-
-	return 0;
-
-err_out_unregister_bus:
-	mdiobus_unregister(bp->mii_bus);
-err_out_free_mdio_irq:
-	kfree(bp->mii_bus->irq);
-err_out_free_mdiobus:
-	mdiobus_free(bp->mii_bus);
-err_out:
-	return err;
-}
-EXPORT_SYMBOL_GPL(macb_mii_init);
-
 static void macb_update_stats(struct macb *bp)
 {
 	u32 __iomem *reg = bp->regs + MACB_PFR;
@@ -2480,7 +2397,10 @@ static int macb_probe(struct platform_device *pdev)
 		goto err_out_free_netdev;
 	}
 
-	err = macb_mii_init(bp);
+	bp->phy_node = of_parse_phandle(bp->pdev->dev.of_node,
+						"phy-handle", 0);
+
+	err = macb_mii_probe(bp->dev);
 	if (err)
 		goto err_out_unregister_netdev;
 
@@ -2524,9 +2444,6 @@ static int macb_remove(struct platform_device *pdev)
 		bp = netdev_priv(dev);
 		if (bp->phy_dev)
 			phy_disconnect(bp->phy_dev);
-		mdiobus_unregister(bp->mii_bus);
-		kfree(bp->mii_bus->irq);
-		mdiobus_free(bp->mii_bus);
 		unregister_netdev(dev);
 		if (!IS_ERR(bp->tx_clk))
 			clk_disable_unprepare(bp->tx_clk);
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index f0aa177..ba515ab 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -825,13 +825,12 @@ struct macb {
 	unsigned int		rx_frm_len_mask;
 	unsigned int		jumbo_max_len;
 	bool			isjumbo;
-
+	struct device_node *phy_node;
 	u64			ethtool_stats[GEM_STATS_LEN];
 };
 
 extern const struct ethtool_ops macb_ethtool_ops;
 
-int macb_mii_init(struct macb *bp);
 int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 struct net_device_stats *macb_get_stats(struct net_device *dev);
 void macb_set_rx_mode(struct net_device *dev);
diff --git a/drivers/net/ethernet/cadence/macb_mdio.c b/drivers/net/ethernet/cadence/macb_mdio.c
new file mode 100644
index 0000000..563ac52
--- /dev/null
+++ b/drivers/net/ethernet/cadence/macb_mdio.c
@@ -0,0 +1,204 @@
+/*
+ * Cadence Macb mdio controller driver
+ *
+ * Copyright (C) 2014 - 2015 Xilinx, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/of_address.h>
+#include <linux/of_mdio.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include "macb.h"
+
+struct macb_mdio_data {
+	void __iomem *regs;
+	struct clk *pclk;
+	struct clk *hclk;
+};
+
+static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+	struct macb_mdio_data *bp = bus->priv;
+	int value;
+
+	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
+			      | MACB_BF(RW, MACB_MAN_READ)
+			      | MACB_BF(PHYA, mii_id)
+			      | MACB_BF(REGA, regnum)
+			      | MACB_BF(CODE, MACB_MAN_CODE)));
+
+	/* wait for end of transfer */
+	while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
+		cpu_relax();
+
+	value = MACB_BFEXT(DATA, macb_readl(bp, MAN));
+
+	return value;
+}
+
+static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+			   u16 value)
+{
+	struct macb_mdio_data *bp = bus->priv;
+
+	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
+			      | MACB_BF(RW, MACB_MAN_WRITE)
+			      | MACB_BF(PHYA, mii_id)
+			      | MACB_BF(REGA, regnum)
+			      | MACB_BF(CODE, MACB_MAN_CODE)
+			      | MACB_BF(DATA, value)));
+
+	/* wait for end of transfer */
+	while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
+		cpu_relax();
+
+	return 0;
+}
+
+static u32 gem_mdc_clk_div(struct macb_mdio_data *bp)
+{
+	u32 config;
+	unsigned long pclk_hz = clk_get_rate(bp->pclk);
+
+	if (pclk_hz <= 20000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV8);
+	else if (pclk_hz <= 40000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV16);
+	else if (pclk_hz <= 80000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV32);
+	else if (pclk_hz <= 120000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV48);
+	else if (pclk_hz <= 160000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV64);
+	else
+		config = GEM_BF(CLK, GEM_CLK_DIV96);
+
+	return config;
+}
+
+static int macb_mdio_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct mii_bus *bus;
+	struct macb_mdio_data *bp;
+	struct resource *res;
+	int ret;
+	u32 config, i;
+
+	bus = mdiobus_alloc_size(sizeof(*bp));
+	if (!bus)
+		return -ENOMEM;
+
+	bus->name = "macb_mii_bus";
+	bus->read = &macb_mdio_read;
+	bus->write = &macb_mdio_write;
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
+	bus->parent = &pdev->dev;
+	bus->irq = devm_kzalloc(&pdev->dev, sizeof(int) * PHY_MAX_ADDR,
+				GFP_KERNEL);
+	if (!bus->irq) {
+		ret = -ENOMEM;
+		goto err_out_free_mdiobus;
+	}
+
+	for (i = 0; i < PHY_MAX_ADDR; i++)
+		bus->irq[i] = PHY_POLL;
+
+	bp = bus->priv;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	bp->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(bp->regs)) {
+		ret = PTR_ERR(bp->regs);
+		goto err_out_free_mdiobus;
+	}
+
+	bp->pclk = devm_clk_get(&pdev->dev, "pclk");
+	if (IS_ERR(bp->pclk)) {
+		ret = PTR_ERR(bp->pclk);
+		dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", ret);
+		goto err_out_free_mdiobus;
+	}
+
+	bp->hclk = devm_clk_get(&pdev->dev, "hclk");
+	if (IS_ERR(bp->hclk)) {
+		ret = PTR_ERR(bp->hclk);
+		dev_err(&pdev->dev, "failed to get hclk (%u)\n", ret);
+		goto err_out_free_mdiobus;
+	}
+
+	ret = clk_prepare_enable(bp->pclk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable pclk (%u)\n", ret);
+		goto err_out_free_mdiobus;
+	}
+
+	ret = clk_prepare_enable(bp->hclk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable hclk (%u)\n", ret);
+		goto err_disable_pclk;
+	}
+
+	/* Enable management port */
+	macb_writel(bp, NCR, MACB_BIT(MPE));
+	config = gem_mdc_clk_div(bp);
+	macb_writel(bp, NCFGR, config);
+
+	ret = of_mdiobus_register(bus, np);
+	if (ret < 0)
+		goto err_out_free_mdiobus;
+
+	platform_set_drvdata(pdev, bus);
+
+	return 0;
+
+err_disable_pclk:
+	clk_disable_unprepare(bp->pclk);
+
+err_out_free_mdiobus:
+	mdiobus_free(bus);
+	return ret;
+}
+
+static int macb_mdio_remove(struct platform_device *pdev)
+{
+	struct mii_bus *bus = platform_get_drvdata(pdev);
+	struct macb_mdio_data *bp = bus->priv;
+
+	mdiobus_unregister(bus);
+	clk_disable_unprepare(bp->hclk);
+	clk_disable_unprepare(bp->pclk);
+	mdiobus_free(bus);
+
+	return 0;
+}
+
+static const struct of_device_id macb_mdio_dt_ids[] = {
+	{ .compatible = "cdns,macb-mdio" },
+
+};
+MODULE_DEVICE_TABLE(of, macb_mdio_dt_ids);
+
+static struct platform_driver macb_mdio_driver = {
+	.probe = macb_mdio_probe,
+	.remove = macb_mdio_remove,
+	.driver = {
+		.name = "macb-mdio",
+		.of_match_table = macb_mdio_dt_ids,
+	},
+};
+
+module_platform_driver(macb_mdio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence MACB/GEM Ethernet driver");
+MODULE_AUTHOR("Xilinx");
-- 
1.7.4

^ permalink raw reply related	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2016-11-29  4:11 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-13  9:26 [RFC PATCH 1/2] net: macb: Add MDIO driver for accessing multiple PHY devices Harini Katakam
2016-05-13  9:26 ` Harini Katakam
2016-05-13  9:26 ` Harini Katakam
2016-05-13  9:26 ` [RFC PATCH 2/2] Documentation: devictree: Add macb mdio bindings Harini Katakam
2016-05-13  9:26   ` Harini Katakam
2016-05-13  9:26   ` Harini Katakam
2016-05-13 17:36   ` Andrew Lunn
2016-05-13 17:36     ` Andrew Lunn
2016-05-13 17:43   ` Andrew Lunn
2016-05-13 17:43     ` Andrew Lunn
2016-05-14  2:50     ` Harini Katakam
  -- strict thread matches above, loose matches on Subject: below --
2016-11-28  9:49 [RFC PATCH 1/2] net: macb: Add MDIO driver for accessing multiple PHY devices Harini Katakam
2016-11-28  9:49 ` Harini Katakam
2016-11-28 16:33 ` Andrew Lunn
2016-11-28 16:33   ` Andrew Lunn
2016-11-29  4:11   ` Harini Katakam
2015-07-13  4:48 [RFC PATCH 0/2] net: macb: Add mdio driver for accessing multiple phy devices Punnaiah Choudary Kalluri
2015-07-13  4:48 ` [RFC PATCH 1/2] " Punnaiah Choudary Kalluri

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.