From 83d2dbc59924c90dd865de113a55d60826ac0c04 Mon Sep 17 00:00:00 2001
From: Chuanhong Guo <gch981213@gmail.com>
Date: Tue, 17 Jul 2018 17:09:13 +0800
Subject: [PATCH] ath79: ag71xx: Split mdio driver into an independent platform
 device.

We need to have mdio1 belonging to gmac1 initialized before gmac0.
Split it into a separated mdio device to get both mdios ready before probing gmac.

Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
---
 .../net/ethernet/atheros/ag71xx/Makefile      |   2 +-
 .../net/ethernet/atheros/ag71xx/ag71xx.h      |  14 +-
 .../net/ethernet/atheros/ag71xx/ag71xx_main.c |   6 +-
 .../net/ethernet/atheros/ag71xx/ag71xx_mdio.c | 140 +++++++++---------
 4 files changed, 78 insertions(+), 84 deletions(-)

diff --git a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/Makefile b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/Makefile
index ed74e3b5e6..3636077166 100644
--- a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/Makefile
+++ b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/Makefile
@@ -6,10 +6,10 @@ ag71xx-y	+= ag71xx_main.o
 ag71xx-y	+= ag71xx_gmac.o
 ag71xx-y	+= ag71xx_ethtool.o
 ag71xx-y	+= ag71xx_phy.o
-ag71xx-y	+= ag71xx_mdio.o
 ag71xx-y	+= ag71xx_ar7240.o
 
 ag71xx-$(CONFIG_AG71XX_DEBUG_FS)	+= ag71xx_debugfs.o
 
+obj-$(CONFIG_AG71XX)	+= ag71xx_mdio.o
 obj-$(CONFIG_AG71XX)	+= ag71xx.o
 
diff --git a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx.h b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx.h
index d154bbec9e..70c8582294 100644
--- a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx.h
+++ b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx.h
@@ -170,12 +170,10 @@ struct ag71xx {
 	 */
 	void __iomem		*mac_base;
 	void __iomem		*mii_base;
-	struct regmap		*mii_regmap;
 
 	struct ag71xx_desc	*stop_desc;
 	dma_addr_t		stop_desc_dma;
 
-	struct mii_bus		*mii_bus;
 	struct phy_device	*phy_dev;
 	void			*phy_priv;
 	int			phy_if_mode;
@@ -189,7 +187,6 @@ struct ag71xx {
 
 	struct reset_control *mac_reset;
 	struct reset_control *phy_reset;
-	struct reset_control *mdio_reset;
 
 	u32			fifodata[3];
 	u32			plldata[3];
@@ -201,6 +198,12 @@ struct ag71xx {
 #endif
 };
 
+struct ag71xx_mdio {
+	struct reset_control *mdio_reset;
+	struct mii_bus		*mii_bus;
+	struct regmap		*mii_regmap;
+};
+
 extern struct ethtool_ops ag71xx_ethtool_ops;
 void ag71xx_link_adjust(struct ag71xx *ag);
 
@@ -441,11 +444,6 @@ static inline void ag71xx_debugfs_update_napi_stats(struct ag71xx *ag,
 int ag71xx_ar7240_init(struct ag71xx *ag, struct device_node *np);
 void ag71xx_ar7240_cleanup(struct ag71xx *ag);
 
-int ag71xx_mdio_init(struct ag71xx *ag);
-void ag71xx_mdio_cleanup(struct ag71xx *ag);
-int ag71xx_mdio_mii_read(struct mii_bus *bus, int addr, int reg);
-int ag71xx_mdio_mii_write(struct mii_bus *bus, int addr, int reg, u16 val);
-
 int ag71xx_setup_gmac(struct device_node *np);
 
 int ar7240sw_phy_read(struct mii_bus *mii, int addr, int reg);
diff --git a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
index 72cfd6cf15..e741bdfa7b 100644
--- a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
+++ b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
@@ -1438,11 +1438,10 @@ static int ag71xx_probe(struct platform_device *pdev)
 
 	ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, 0);
 	ag71xx_hw_init(ag);
-	ag71xx_mdio_init(ag);
 
 	err = ag71xx_phy_connect(ag);
 	if (err)
-		goto err_mdio_free;
+		goto err_free;
 
 	err = ag71xx_debugfs_init(ag);
 	if (err)
@@ -1466,8 +1465,6 @@ static int ag71xx_probe(struct platform_device *pdev)
 
 err_phy_disconnect:
 	ag71xx_phy_disconnect(ag);
-err_mdio_free:
-	ag71xx_mdio_cleanup(ag);
 err_free:
 	free_netdev(dev);
 	return err;
@@ -1484,7 +1481,6 @@ static int ag71xx_remove(struct platform_device *pdev)
 	ag = netdev_priv(dev);
 	ag71xx_debugfs_exit(ag);
 	ag71xx_phy_disconnect(ag);
-	ag71xx_mdio_cleanup(ag);
 	unregister_netdev(dev);
 	free_irq(dev->irq, dev);
 	iounmap(ag->mac_base);
diff --git a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c
index 8c1572b181..baaa33e10b 100644
--- a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c
+++ b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c
@@ -20,7 +20,7 @@
 
 static int bus_count;
 
-static int ag71xx_mdio_wait_busy(struct ag71xx *ag)
+static int ag71xx_mdio_wait_busy(struct ag71xx_mdio *am)
 {
 	int i;
 
@@ -29,57 +29,57 @@ static int ag71xx_mdio_wait_busy(struct ag71xx *ag)
 
 		udelay(AG71XX_MDIO_DELAY);
 
-		regmap_read(ag->mii_regmap, AG71XX_REG_MII_IND, &busy);
+		regmap_read(am->mii_regmap, AG71XX_REG_MII_IND, &busy);
 		if (!busy)
 			return 0;
 
 		udelay(AG71XX_MDIO_DELAY);
 	}
 
-	pr_err("%s: MDIO operation timed out\n", ag->mii_bus->name);
+	pr_err("%s: MDIO operation timed out\n", am->mii_bus->name);
 
 	return -ETIMEDOUT;
 }
 
-int ag71xx_mdio_mii_read(struct mii_bus *bus, int addr, int reg)
+static int ag71xx_mdio_mii_read(struct mii_bus *bus, int addr, int reg)
 {
-	struct ag71xx *ag = bus->priv;
+	struct ag71xx_mdio *am = bus->priv;
 	int err;
 	int ret;
 
-	err = ag71xx_mdio_wait_busy(ag);
+	err = ag71xx_mdio_wait_busy(am);
 	if (err)
 		return 0xffff;
 
-	regmap_write(ag->mii_regmap, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
-	regmap_write(ag->mii_regmap, AG71XX_REG_MII_ADDR,
+	regmap_write(am->mii_regmap, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
+	regmap_write(am->mii_regmap, AG71XX_REG_MII_ADDR,
 			((addr & 0xff) << MII_ADDR_SHIFT) | (reg & 0xff));
-	regmap_write(ag->mii_regmap, AG71XX_REG_MII_CMD, MII_CMD_READ);
+	regmap_write(am->mii_regmap, AG71XX_REG_MII_CMD, MII_CMD_READ);
 
-	err = ag71xx_mdio_wait_busy(ag);
+	err = ag71xx_mdio_wait_busy(am);
 	if (err)
 		return 0xffff;
 
-	regmap_read(ag->mii_regmap, AG71XX_REG_MII_STATUS, &ret);
+	regmap_read(am->mii_regmap, AG71XX_REG_MII_STATUS, &ret);
 	ret &= 0xffff;
-	regmap_write(ag->mii_regmap, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
+	regmap_write(am->mii_regmap, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
 
 	DBG("mii_read: addr=%04x, reg=%04x, value=%04x\n", addr, reg, ret);
 
 	return ret;
 }
 
-int ag71xx_mdio_mii_write(struct mii_bus *bus, int addr, int reg, u16 val)
+static int ag71xx_mdio_mii_write(struct mii_bus *bus, int addr, int reg, u16 val)
 {
-	struct ag71xx *ag = bus->priv;
+	struct ag71xx_mdio *am = bus->priv;
 
 	DBG("mii_write: addr=%04x, reg=%04x, value=%04x\n", addr, reg, val);
 
-	regmap_write(ag->mii_regmap, AG71XX_REG_MII_ADDR,
+	regmap_write(am->mii_regmap, AG71XX_REG_MII_ADDR,
 			((addr & 0xff) << MII_ADDR_SHIFT) | (reg & 0xff));
-	regmap_write(ag->mii_regmap, AG71XX_REG_MII_CTRL, val);
+	regmap_write(am->mii_regmap, AG71XX_REG_MII_CTRL, val);
 
-	ag71xx_mdio_wait_busy(ag);
+	ag71xx_mdio_wait_busy(am);
 
 	return 0;
 }
@@ -97,23 +97,22 @@ static int ar934x_mdio_clock_div(unsigned int rate)
 static int ag71xx_mdio_reset(struct mii_bus *bus)
 {
 	struct device_node *np = bus->dev.of_node;
-	struct ag71xx *ag = bus->priv;
-	struct device_node *np_ag = ag->pdev->dev.of_node;
+	struct ag71xx_mdio *am = bus->priv;
 	bool builtin_switch;
 	u32 t;
 
 	builtin_switch = of_property_read_bool(np, "builtin-switch");
 
-	if (of_device_is_compatible(np_ag, "qca,ar7240-eth"))
+	if (of_device_is_compatible(np, "qca,ar7240-mdio"))
 		t = MII_CFG_CLK_DIV_6;
-	else if (of_device_is_compatible(np_ag, "qca,ar9340-eth"))
+	else if (of_device_is_compatible(np, "qca,ar9340-mdio"))
 		t = MII_CFG_CLK_DIV_58;
 	else if (builtin_switch)
 		t = MII_CFG_CLK_DIV_10;
 	else
 		t = MII_CFG_CLK_DIV_28;
 
-	if (builtin_switch && of_device_is_compatible(np_ag, "qca,ar9340-eth")) {
+	if (builtin_switch && of_device_is_compatible(np, "qca,ar9340-mdio")) {
 		struct clk *ref_clk = of_clk_get(np, 0);
 		int clock_rate;
 
@@ -126,56 +125,45 @@ static int ag71xx_mdio_reset(struct mii_bus *bus)
 		clk_put(ref_clk);
 	}
 
-	regmap_write(ag->mii_regmap, AG71XX_REG_MII_CFG, t | MII_CFG_RESET);
+	regmap_write(am->mii_regmap, AG71XX_REG_MII_CFG, t | MII_CFG_RESET);
 	udelay(100);
 
-	regmap_write(ag->mii_regmap, AG71XX_REG_MII_CFG, t);
+	regmap_write(am->mii_regmap, AG71XX_REG_MII_CFG, t);
 	udelay(100);
 
 	return 0;
 }
 
-int ag71xx_mdio_init(struct ag71xx *ag)
+static int ag71xx_mdio_probe(struct platform_device *pdev)
 {
-	struct device *parent = &ag->pdev->dev;
-	struct device_node *np;
+	struct device *amdev = &pdev->dev;
+	struct device_node *np = pdev->dev.of_node;
+	struct ag71xx_mdio *am;
 	struct mii_bus *mii_bus;
 	bool builtin_switch;
 	int i, err;
 
-	np = of_get_child_by_name(parent->of_node, "mdio-bus");
-	if (!np)
-		return -ENODEV;
+	am = devm_kzalloc(amdev, sizeof(*am), GFP_KERNEL);
+	if (!am)
+		return -ENOMEM;
 
-	if (!of_device_is_available(np)) {
-		err = 0;
-		goto err_out;
-	}
-
-	ag->mii_regmap = syscon_regmap_lookup_by_phandle(np, "regmap");
-	if (!ag->mii_regmap)
+	am->mii_regmap = syscon_regmap_lookup_by_phandle(np, "regmap");
+	if (!am->mii_regmap)
 		return -ENOENT;
 
-	mii_bus = devm_mdiobus_alloc(parent);
-	if (!mii_bus) {
-		err = -ENOMEM;
-		goto err_out;
-	}
+	mii_bus = devm_mdiobus_alloc(amdev);
+	if (!mii_bus)
+		return -ENOMEM;
 
-	ag->mdio_reset = of_reset_control_get_exclusive(np, "mdio");
+	am->mdio_reset = of_reset_control_get_exclusive(np, "mdio");
 	builtin_switch = of_property_read_bool(np, "builtin-switch");
 
-	mii_bus->name = "mdio";
-	if (builtin_switch) {
-		mii_bus->read = ar7240sw_phy_read;
-		mii_bus->write = ar7240sw_phy_write;
-	} else {
-		mii_bus->read = ag71xx_mdio_mii_read;
-		mii_bus->write = ag71xx_mdio_mii_write;
-	}
+	mii_bus->name = "ag71xx_mdio";
+	mii_bus->read = ag71xx_mdio_mii_read;
+	mii_bus->write = ag71xx_mdio_mii_write;
 	mii_bus->reset = ag71xx_mdio_reset;
-	mii_bus->priv = ag;
-	mii_bus->parent = parent;
+	mii_bus->priv = am;
+	mii_bus->parent = amdev;
 	snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%s.%d", np->name, bus_count++);
 
 	if (!builtin_switch &&
@@ -185,34 +173,46 @@ int ag71xx_mdio_init(struct ag71xx *ag)
 	for (i = 0; i < PHY_MAX_ADDR; i++)
 		mii_bus->irq[i] = PHY_POLL;
 
-	if (!IS_ERR(ag->mdio_reset)) {
-		reset_control_assert(ag->mdio_reset);
+	if (!IS_ERR(am->mdio_reset)) {
+		reset_control_assert(am->mdio_reset);
 		msleep(100);
-		reset_control_deassert(ag->mdio_reset);
+		reset_control_deassert(am->mdio_reset);
 		msleep(200);
 	}
 
 	err = of_mdiobus_register(mii_bus, np);
 	if (err)
-		goto err_out;
-
-	ag->mii_bus = mii_bus;
+		return err;
 
-	if (builtin_switch)
-		ag71xx_ar7240_init(ag, np);
+	am->mii_bus = mii_bus;
+	platform_set_drvdata(pdev, am);
 
 	return 0;
-
-err_out:
-	of_node_put(np);
-	return err;
 }
 
-void ag71xx_mdio_cleanup(struct ag71xx *ag)
+static int ag71xx_mdio_remove(struct platform_device *pdev)
 {
-	if (!ag->mii_bus)
-		return;
+	struct ag71xx_mdio *am = platform_get_drvdata(pdev);
 
-	ag71xx_ar7240_cleanup(ag);
-	mdiobus_unregister(ag->mii_bus);
+	mdiobus_unregister(am->mii_bus);
+	return 0;
 }
+
+static const struct of_device_id ag71xx_mdio_match[] = {
+	{ .compatible = "qca,ar7240-mdio" },
+	{ .compatible = "qca,ar9340-mdio" },
+	{ .compatible = "qca,ath79-mdio" },
+	{}
+};
+
+static struct platform_driver ag71xx_mdio_driver = {
+	.probe		= ag71xx_mdio_probe,
+	.remove		= ag71xx_mdio_remove,
+	.driver = {
+		.name	 = "ag71xx-mdio",
+		.of_match_table = ag71xx_mdio_match,
+	}
+};
+
+module_platform_driver(ag71xx_mdio_driver);
+MODULE_LICENSE("GPL");
-- 
2.30.2