diff options
Diffstat (limited to 'drivers/net/ethernet/freescale/fec_main.c')
| -rw-r--r-- | drivers/net/ethernet/freescale/fec_main.c | 30 | 
1 files changed, 27 insertions, 3 deletions
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 78e1ce09b1ab..f6a3a7abd468 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1954,6 +1954,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)  	struct fec_enet_private *fep = netdev_priv(ndev);  	struct device_node *node;  	int err = -ENXIO, i; +	u32 mii_speed, holdtime;  	/*  	 * The i.MX28 dual fec interfaces are not equal. @@ -1991,10 +1992,33 @@ static int fec_enet_mii_init(struct platform_device *pdev)  	 * Reference Manual has an error on this, and gets fixed on i.MX6Q  	 * document.  	 */ -	fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000); +	mii_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000);  	if (fep->quirks & FEC_QUIRK_ENET_MAC) -		fep->phy_speed--; -	fep->phy_speed <<= 1; +		mii_speed--; +	if (mii_speed > 63) { +		dev_err(&pdev->dev, +			"fec clock (%lu) to fast to get right mii speed\n", +			clk_get_rate(fep->clk_ipg)); +		err = -EINVAL; +		goto err_out; +	} + +	/* +	 * The i.MX28 and i.MX6 types have another filed in the MSCR (aka +	 * MII_SPEED) register that defines the MDIO output hold time. Earlier +	 * versions are RAZ there, so just ignore the difference and write the +	 * register always. +	 * The minimal hold time according to IEE802.3 (clause 22) is 10 ns. +	 * HOLDTIME + 1 is the number of clk cycles the fec is holding the +	 * output. +	 * The HOLDTIME bitfield takes values between 0 and 7 (inclusive). +	 * Given that ceil(clkrate / 5000000) <= 64, the calculation for +	 * holdtime cannot result in a value greater than 3. +	 */ +	holdtime = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 100000000) - 1; + +	fep->phy_speed = mii_speed << 1 | holdtime << 8; +  	writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);  	fep->mii_bus = mdiobus_alloc();  |