17ac6653aSJeff Kirsher /*******************************************************************************
27ac6653aSJeff Kirsher   STMMAC Ethernet Driver -- MDIO bus implementation
37ac6653aSJeff Kirsher   Provides Bus interface for MII registers
47ac6653aSJeff Kirsher 
57ac6653aSJeff Kirsher   Copyright (C) 2007-2009  STMicroelectronics Ltd
67ac6653aSJeff Kirsher 
77ac6653aSJeff Kirsher   This program is free software; you can redistribute it and/or modify it
87ac6653aSJeff Kirsher   under the terms and conditions of the GNU General Public License,
97ac6653aSJeff Kirsher   version 2, as published by the Free Software Foundation.
107ac6653aSJeff Kirsher 
117ac6653aSJeff Kirsher   This program is distributed in the hope it will be useful, but WITHOUT
127ac6653aSJeff Kirsher   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
137ac6653aSJeff Kirsher   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
147ac6653aSJeff Kirsher   more details.
157ac6653aSJeff Kirsher 
167ac6653aSJeff Kirsher   You should have received a copy of the GNU General Public License along with
177ac6653aSJeff Kirsher   this program; if not, write to the Free Software Foundation, Inc.,
187ac6653aSJeff Kirsher   51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
197ac6653aSJeff Kirsher 
207ac6653aSJeff Kirsher   The full GNU General Public License is included in this distribution in
217ac6653aSJeff Kirsher   the file called "COPYING".
227ac6653aSJeff Kirsher 
237ac6653aSJeff Kirsher   Author: Carl Shaw <carl.shaw@st.com>
247ac6653aSJeff Kirsher   Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>
257ac6653aSJeff Kirsher *******************************************************************************/
267ac6653aSJeff Kirsher 
277ac6653aSJeff Kirsher #include <linux/mii.h>
287ac6653aSJeff Kirsher #include <linux/phy.h>
297ac6653aSJeff Kirsher #include <linux/slab.h>
300e076471SSrinivas Kandagatla #include <linux/of.h>
310e076471SSrinivas Kandagatla #include <linux/of_gpio.h>
320e076471SSrinivas Kandagatla 
337ac6653aSJeff Kirsher #include <asm/io.h>
347ac6653aSJeff Kirsher 
357ac6653aSJeff Kirsher #include "stmmac.h"
367ac6653aSJeff Kirsher 
377ac6653aSJeff Kirsher #define MII_BUSY 0x00000001
387ac6653aSJeff Kirsher #define MII_WRITE 0x00000002
397ac6653aSJeff Kirsher 
4039b401dbSDeepak SIKRI static int stmmac_mdio_busy_wait(void __iomem *ioaddr, unsigned int mii_addr)
4139b401dbSDeepak SIKRI {
4239b401dbSDeepak SIKRI 	unsigned long curr;
4339b401dbSDeepak SIKRI 	unsigned long finish = jiffies + 3 * HZ;
4439b401dbSDeepak SIKRI 
4539b401dbSDeepak SIKRI 	do {
4639b401dbSDeepak SIKRI 		curr = jiffies;
4739b401dbSDeepak SIKRI 		if (readl(ioaddr + mii_addr) & MII_BUSY)
4839b401dbSDeepak SIKRI 			cpu_relax();
4939b401dbSDeepak SIKRI 		else
5039b401dbSDeepak SIKRI 			return 0;
5139b401dbSDeepak SIKRI 	} while (!time_after_eq(curr, finish));
5239b401dbSDeepak SIKRI 
5339b401dbSDeepak SIKRI 	return -EBUSY;
5439b401dbSDeepak SIKRI }
5539b401dbSDeepak SIKRI 
567ac6653aSJeff Kirsher /**
577ac6653aSJeff Kirsher  * stmmac_mdio_read
587ac6653aSJeff Kirsher  * @bus: points to the mii_bus structure
597ac6653aSJeff Kirsher  * @phyaddr: MII addr reg bits 15-11
607ac6653aSJeff Kirsher  * @phyreg: MII addr reg bits 10-6
617ac6653aSJeff Kirsher  * Description: it reads data from the MII register from within the phy device.
627ac6653aSJeff Kirsher  * For the 7111 GMAC, we must set the bit 0 in the MII address register while
637ac6653aSJeff Kirsher  * accessing the PHY registers.
647ac6653aSJeff Kirsher  * Fortunately, it seems this has no drawback for the 7109 MAC.
657ac6653aSJeff Kirsher  */
667ac6653aSJeff Kirsher static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
677ac6653aSJeff Kirsher {
687ac6653aSJeff Kirsher 	struct net_device *ndev = bus->priv;
697ac6653aSJeff Kirsher 	struct stmmac_priv *priv = netdev_priv(ndev);
707ac6653aSJeff Kirsher 	unsigned int mii_address = priv->hw->mii.addr;
717ac6653aSJeff Kirsher 	unsigned int mii_data = priv->hw->mii.data;
727ac6653aSJeff Kirsher 
737ac6653aSJeff Kirsher 	int data;
747ac6653aSJeff Kirsher 	u16 regValue = (((phyaddr << 11) & (0x0000F800)) |
757ac6653aSJeff Kirsher 			((phyreg << 6) & (0x000007C0)));
76cd7201f4SGiuseppe CAVALLARO 	regValue |= MII_BUSY | ((priv->clk_csr & 0xF) << 2);
777ac6653aSJeff Kirsher 
7839b401dbSDeepak SIKRI 	if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
7939b401dbSDeepak SIKRI 		return -EBUSY;
8039b401dbSDeepak SIKRI 
817ac6653aSJeff Kirsher 	writel(regValue, priv->ioaddr + mii_address);
8239b401dbSDeepak SIKRI 
8339b401dbSDeepak SIKRI 	if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
8439b401dbSDeepak SIKRI 		return -EBUSY;
857ac6653aSJeff Kirsher 
867ac6653aSJeff Kirsher 	/* Read the data from the MII data register */
877ac6653aSJeff Kirsher 	data = (int)readl(priv->ioaddr + mii_data);
887ac6653aSJeff Kirsher 
897ac6653aSJeff Kirsher 	return data;
907ac6653aSJeff Kirsher }
917ac6653aSJeff Kirsher 
927ac6653aSJeff Kirsher /**
937ac6653aSJeff Kirsher  * stmmac_mdio_write
947ac6653aSJeff Kirsher  * @bus: points to the mii_bus structure
957ac6653aSJeff Kirsher  * @phyaddr: MII addr reg bits 15-11
967ac6653aSJeff Kirsher  * @phyreg: MII addr reg bits 10-6
977ac6653aSJeff Kirsher  * @phydata: phy data
987ac6653aSJeff Kirsher  * Description: it writes the data into the MII register from within the device.
997ac6653aSJeff Kirsher  */
1007ac6653aSJeff Kirsher static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
1017ac6653aSJeff Kirsher 			     u16 phydata)
1027ac6653aSJeff Kirsher {
1037ac6653aSJeff Kirsher 	struct net_device *ndev = bus->priv;
1047ac6653aSJeff Kirsher 	struct stmmac_priv *priv = netdev_priv(ndev);
1057ac6653aSJeff Kirsher 	unsigned int mii_address = priv->hw->mii.addr;
1067ac6653aSJeff Kirsher 	unsigned int mii_data = priv->hw->mii.data;
1077ac6653aSJeff Kirsher 
1087ac6653aSJeff Kirsher 	u16 value =
1097ac6653aSJeff Kirsher 	    (((phyaddr << 11) & (0x0000F800)) | ((phyreg << 6) & (0x000007C0)))
1107ac6653aSJeff Kirsher 	    | MII_WRITE;
1117ac6653aSJeff Kirsher 
112cd7201f4SGiuseppe CAVALLARO 	value |= MII_BUSY | ((priv->clk_csr & 0xF) << 2);
1137ac6653aSJeff Kirsher 
1147ac6653aSJeff Kirsher 	/* Wait until any existing MII operation is complete */
11539b401dbSDeepak SIKRI 	if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
11639b401dbSDeepak SIKRI 		return -EBUSY;
1177ac6653aSJeff Kirsher 
1187ac6653aSJeff Kirsher 	/* Set the MII address register to write */
1197ac6653aSJeff Kirsher 	writel(phydata, priv->ioaddr + mii_data);
1207ac6653aSJeff Kirsher 	writel(value, priv->ioaddr + mii_address);
1217ac6653aSJeff Kirsher 
1227ac6653aSJeff Kirsher 	/* Wait until any existing MII operation is complete */
12339b401dbSDeepak SIKRI 	return stmmac_mdio_busy_wait(priv->ioaddr, mii_address);
1247ac6653aSJeff Kirsher }
1257ac6653aSJeff Kirsher 
1267ac6653aSJeff Kirsher /**
1277ac6653aSJeff Kirsher  * stmmac_mdio_reset
1287ac6653aSJeff Kirsher  * @bus: points to the mii_bus structure
1297ac6653aSJeff Kirsher  * Description: reset the MII bus
1307ac6653aSJeff Kirsher  */
131073752aaSSrinivas Kandagatla int stmmac_mdio_reset(struct mii_bus *bus)
1327ac6653aSJeff Kirsher {
133bfab27a1SGiuseppe CAVALLARO #if defined(CONFIG_STMMAC_PLATFORM)
1347ac6653aSJeff Kirsher 	struct net_device *ndev = bus->priv;
1357ac6653aSJeff Kirsher 	struct stmmac_priv *priv = netdev_priv(ndev);
1367ac6653aSJeff Kirsher 	unsigned int mii_address = priv->hw->mii.addr;
1370e076471SSrinivas Kandagatla 	struct stmmac_mdio_bus_data *data = priv->plat->mdio_bus_data;
1387ac6653aSJeff Kirsher 
1390e076471SSrinivas Kandagatla #ifdef CONFIG_OF
1400e076471SSrinivas Kandagatla 	if (priv->device->of_node) {
1410e076471SSrinivas Kandagatla 		int reset_gpio, active_low;
1420e076471SSrinivas Kandagatla 
1430e076471SSrinivas Kandagatla 		if (data->reset_gpio < 0) {
1440e076471SSrinivas Kandagatla 			struct device_node *np = priv->device->of_node;
1450e076471SSrinivas Kandagatla 			if (!np)
1460e076471SSrinivas Kandagatla 				return 0;
1470e076471SSrinivas Kandagatla 
1480e076471SSrinivas Kandagatla 			data->reset_gpio = of_get_named_gpio(np,
1490e076471SSrinivas Kandagatla 						"snps,reset-gpio", 0);
1500e076471SSrinivas Kandagatla 			if (data->reset_gpio < 0)
1510e076471SSrinivas Kandagatla 				return 0;
1520e076471SSrinivas Kandagatla 
1530e076471SSrinivas Kandagatla 			data->active_low = of_property_read_bool(np,
1540e076471SSrinivas Kandagatla 						"snps,reset-active-low");
1550e076471SSrinivas Kandagatla 			of_property_read_u32_array(np,
1560e076471SSrinivas Kandagatla 				"snps,reset-delays-us", data->delays, 3);
1570e076471SSrinivas Kandagatla 		}
1580e076471SSrinivas Kandagatla 
1590e076471SSrinivas Kandagatla 		reset_gpio = data->reset_gpio;
1600e076471SSrinivas Kandagatla 		active_low = data->active_low;
1610e076471SSrinivas Kandagatla 
1620e076471SSrinivas Kandagatla 		if (!gpio_request(reset_gpio, "mdio-reset")) {
1630e076471SSrinivas Kandagatla 			gpio_direction_output(reset_gpio, active_low ? 1 : 0);
1640e076471SSrinivas Kandagatla 			udelay(data->delays[0]);
1650e076471SSrinivas Kandagatla 			gpio_set_value(reset_gpio, active_low ? 0 : 1);
1660e076471SSrinivas Kandagatla 			udelay(data->delays[1]);
1670e076471SSrinivas Kandagatla 			gpio_set_value(reset_gpio, active_low ? 1 : 0);
1680e076471SSrinivas Kandagatla 			udelay(data->delays[2]);
1690e076471SSrinivas Kandagatla 		}
1700e076471SSrinivas Kandagatla 	}
1710e076471SSrinivas Kandagatla #endif
1720e076471SSrinivas Kandagatla 
1730e076471SSrinivas Kandagatla 	if (data->phy_reset) {
1747ac6653aSJeff Kirsher 		pr_debug("stmmac_mdio_reset: calling phy_reset\n");
1750e076471SSrinivas Kandagatla 		data->phy_reset(priv->plat->bsp_priv);
1767ac6653aSJeff Kirsher 	}
1777ac6653aSJeff Kirsher 
1787ac6653aSJeff Kirsher 	/* This is a workaround for problems with the STE101P PHY.
1797ac6653aSJeff Kirsher 	 * It doesn't complete its reset until at least one clock cycle
1807ac6653aSJeff Kirsher 	 * on MDC, so perform a dummy mdio read.
1817ac6653aSJeff Kirsher 	 */
1827ac6653aSJeff Kirsher 	writel(0, priv->ioaddr + mii_address);
183bfab27a1SGiuseppe CAVALLARO #endif
1847ac6653aSJeff Kirsher 	return 0;
1857ac6653aSJeff Kirsher }
1867ac6653aSJeff Kirsher 
1877ac6653aSJeff Kirsher /**
1887ac6653aSJeff Kirsher  * stmmac_mdio_register
1897ac6653aSJeff Kirsher  * @ndev: net device structure
1907ac6653aSJeff Kirsher  * Description: it registers the MII bus
1917ac6653aSJeff Kirsher  */
1927ac6653aSJeff Kirsher int stmmac_mdio_register(struct net_device *ndev)
1937ac6653aSJeff Kirsher {
1947ac6653aSJeff Kirsher 	int err = 0;
1957ac6653aSJeff Kirsher 	struct mii_bus *new_bus;
1967ac6653aSJeff Kirsher 	int *irqlist;
1977ac6653aSJeff Kirsher 	struct stmmac_priv *priv = netdev_priv(ndev);
1987ac6653aSJeff Kirsher 	struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
1997ac6653aSJeff Kirsher 	int addr, found;
2007ac6653aSJeff Kirsher 
2017ac6653aSJeff Kirsher 	if (!mdio_bus_data)
2027ac6653aSJeff Kirsher 		return 0;
2037ac6653aSJeff Kirsher 
2047ac6653aSJeff Kirsher 	new_bus = mdiobus_alloc();
2057ac6653aSJeff Kirsher 	if (new_bus == NULL)
2067ac6653aSJeff Kirsher 		return -ENOMEM;
2077ac6653aSJeff Kirsher 
2087ac6653aSJeff Kirsher 	if (mdio_bus_data->irqs)
2097ac6653aSJeff Kirsher 		irqlist = mdio_bus_data->irqs;
2107ac6653aSJeff Kirsher 	else
2117ac6653aSJeff Kirsher 		irqlist = priv->mii_irq;
2127ac6653aSJeff Kirsher 
2130e076471SSrinivas Kandagatla #ifdef CONFIG_OF
2140e076471SSrinivas Kandagatla 	if (priv->device->of_node)
2150e076471SSrinivas Kandagatla 		mdio_bus_data->reset_gpio = -1;
2160e076471SSrinivas Kandagatla #endif
2170e076471SSrinivas Kandagatla 
21890b9a545SAlessandro Rubini 	new_bus->name = "stmmac";
2197ac6653aSJeff Kirsher 	new_bus->read = &stmmac_mdio_read;
2207ac6653aSJeff Kirsher 	new_bus->write = &stmmac_mdio_write;
2217ac6653aSJeff Kirsher 	new_bus->reset = &stmmac_mdio_reset;
222db8857bfSFlorian Fainelli 	snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x",
223d56631a6SSrinivas Kandagatla 		 new_bus->name, priv->plat->bus_id);
2247ac6653aSJeff Kirsher 	new_bus->priv = ndev;
2257ac6653aSJeff Kirsher 	new_bus->irq = irqlist;
2267ac6653aSJeff Kirsher 	new_bus->phy_mask = mdio_bus_data->phy_mask;
2277ac6653aSJeff Kirsher 	new_bus->parent = priv->device;
2287ac6653aSJeff Kirsher 	err = mdiobus_register(new_bus);
2297ac6653aSJeff Kirsher 	if (err != 0) {
2307ac6653aSJeff Kirsher 		pr_err("%s: Cannot register as MDIO bus\n", new_bus->name);
2317ac6653aSJeff Kirsher 		goto bus_register_fail;
2327ac6653aSJeff Kirsher 	}
2337ac6653aSJeff Kirsher 
2347ac6653aSJeff Kirsher 	found = 0;
2357ac6653aSJeff Kirsher 	for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
2367ac6653aSJeff Kirsher 		struct phy_device *phydev = new_bus->phy_map[addr];
2377ac6653aSJeff Kirsher 		if (phydev) {
2387ac6653aSJeff Kirsher 			int act = 0;
2397ac6653aSJeff Kirsher 			char irq_num[4];
2407ac6653aSJeff Kirsher 			char *irq_str;
2417ac6653aSJeff Kirsher 
2427ac6653aSJeff Kirsher 			/*
2437ac6653aSJeff Kirsher 			 * If an IRQ was provided to be assigned after
2447ac6653aSJeff Kirsher 			 * the bus probe, do it here.
2457ac6653aSJeff Kirsher 			 */
2467ac6653aSJeff Kirsher 			if ((mdio_bus_data->irqs == NULL) &&
2477ac6653aSJeff Kirsher 			    (mdio_bus_data->probed_phy_irq > 0)) {
2487ac6653aSJeff Kirsher 				irqlist[addr] = mdio_bus_data->probed_phy_irq;
2497ac6653aSJeff Kirsher 				phydev->irq = mdio_bus_data->probed_phy_irq;
2507ac6653aSJeff Kirsher 			}
2517ac6653aSJeff Kirsher 
2527ac6653aSJeff Kirsher 			/*
2537ac6653aSJeff Kirsher 			 * If we're  going to bind the MAC to this PHY bus,
2547ac6653aSJeff Kirsher 			 * and no PHY number was provided to the MAC,
2557ac6653aSJeff Kirsher 			 * use the one probed here.
2567ac6653aSJeff Kirsher 			 */
257d56631a6SSrinivas Kandagatla 			if (priv->plat->phy_addr == -1)
2587ac6653aSJeff Kirsher 				priv->plat->phy_addr = addr;
2597ac6653aSJeff Kirsher 
260d56631a6SSrinivas Kandagatla 			act = (priv->plat->phy_addr == addr);
2617ac6653aSJeff Kirsher 			switch (phydev->irq) {
2627ac6653aSJeff Kirsher 			case PHY_POLL:
2637ac6653aSJeff Kirsher 				irq_str = "POLL";
2647ac6653aSJeff Kirsher 				break;
2657ac6653aSJeff Kirsher 			case PHY_IGNORE_INTERRUPT:
2667ac6653aSJeff Kirsher 				irq_str = "IGNORE";
2677ac6653aSJeff Kirsher 				break;
2687ac6653aSJeff Kirsher 			default:
2697ac6653aSJeff Kirsher 				sprintf(irq_num, "%d", phydev->irq);
2707ac6653aSJeff Kirsher 				irq_str = irq_num;
2717ac6653aSJeff Kirsher 				break;
2727ac6653aSJeff Kirsher 			}
2737ac6653aSJeff Kirsher 			pr_info("%s: PHY ID %08x at %d IRQ %s (%s)%s\n",
2747ac6653aSJeff Kirsher 				ndev->name, phydev->phy_id, addr,
2757ac6653aSJeff Kirsher 				irq_str, dev_name(&phydev->dev),
2767ac6653aSJeff Kirsher 				act ? " active" : "");
2777ac6653aSJeff Kirsher 			found = 1;
2787ac6653aSJeff Kirsher 		}
2797ac6653aSJeff Kirsher 	}
2807ac6653aSJeff Kirsher 
2813955b22bSGiuseppe CAVALLARO 	if (!found) {
2827ac6653aSJeff Kirsher 		pr_warning("%s: No PHY found\n", ndev->name);
2833955b22bSGiuseppe CAVALLARO 		mdiobus_unregister(new_bus);
2843955b22bSGiuseppe CAVALLARO 		mdiobus_free(new_bus);
2853955b22bSGiuseppe CAVALLARO 		return -ENODEV;
2863955b22bSGiuseppe CAVALLARO 	}
2873955b22bSGiuseppe CAVALLARO 
2883955b22bSGiuseppe CAVALLARO 	priv->mii = new_bus;
2897ac6653aSJeff Kirsher 
2907ac6653aSJeff Kirsher 	return 0;
2917ac6653aSJeff Kirsher 
2927ac6653aSJeff Kirsher bus_register_fail:
2937ac6653aSJeff Kirsher 	mdiobus_free(new_bus);
2947ac6653aSJeff Kirsher 	return err;
2957ac6653aSJeff Kirsher }
2967ac6653aSJeff Kirsher 
2977ac6653aSJeff Kirsher /**
2987ac6653aSJeff Kirsher  * stmmac_mdio_unregister
2997ac6653aSJeff Kirsher  * @ndev: net device structure
3007ac6653aSJeff Kirsher  * Description: it unregisters the MII bus
3017ac6653aSJeff Kirsher  */
3027ac6653aSJeff Kirsher int stmmac_mdio_unregister(struct net_device *ndev)
3037ac6653aSJeff Kirsher {
3047ac6653aSJeff Kirsher 	struct stmmac_priv *priv = netdev_priv(ndev);
3057ac6653aSJeff Kirsher 
306a5cf5ce9SSrinivas Kandagatla 	if (!priv->mii)
307a5cf5ce9SSrinivas Kandagatla 		return 0;
308a5cf5ce9SSrinivas Kandagatla 
3097ac6653aSJeff Kirsher 	mdiobus_unregister(priv->mii);
3107ac6653aSJeff Kirsher 	priv->mii->priv = NULL;
3117ac6653aSJeff Kirsher 	mdiobus_free(priv->mii);
3127ac6653aSJeff Kirsher 	priv->mii = NULL;
3137ac6653aSJeff Kirsher 
3147ac6653aSJeff Kirsher 	return 0;
3157ac6653aSJeff Kirsher }
316