net: ethoc: set up MII management bus clock
MII management bus clock is derived from the MAC clock by dividing it by MIIMODER register CLKDIV field value. This value may need to be set up in case it is undefined or its default value is too high (and communication with PHY is too slow) or too low (and communication with PHY is impossible). The value of CLKDIV is not specified directly, but is derived from the MAC clock for the default MII management bus frequency of 2.5MHz. The MAC clock may be specified in the platform data, or in the 'clocks' device tree attribute. Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
445a48cc9d
commit
a13aff0641
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/etherdevice.h>
|
#include <linux/etherdevice.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
#include <linux/crc32.h>
|
#include <linux/crc32.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
@ -219,6 +220,7 @@ struct ethoc {
|
|||||||
|
|
||||||
struct phy_device *phy;
|
struct phy_device *phy;
|
||||||
struct mii_bus *mdio;
|
struct mii_bus *mdio;
|
||||||
|
struct clk *clk;
|
||||||
s8 phy_id;
|
s8 phy_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1021,6 +1023,8 @@ static int ethoc_probe(struct platform_device *pdev)
|
|||||||
int num_bd;
|
int num_bd;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
bool random_mac = false;
|
bool random_mac = false;
|
||||||
|
struct ethoc_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||||
|
u32 eth_clkfreq = pdata ? pdata->eth_clkfreq : 0;
|
||||||
|
|
||||||
/* allocate networking device */
|
/* allocate networking device */
|
||||||
netdev = alloc_etherdev(sizeof(struct ethoc));
|
netdev = alloc_etherdev(sizeof(struct ethoc));
|
||||||
@ -1135,8 +1139,7 @@ static int ethoc_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Allow the platform setup code to pass in a MAC address. */
|
/* Allow the platform setup code to pass in a MAC address. */
|
||||||
if (dev_get_platdata(&pdev->dev)) {
|
if (pdata) {
|
||||||
struct ethoc_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
|
||||||
memcpy(netdev->dev_addr, pdata->hwaddr, IFHWADDRLEN);
|
memcpy(netdev->dev_addr, pdata->hwaddr, IFHWADDRLEN);
|
||||||
priv->phy_id = pdata->phy_id;
|
priv->phy_id = pdata->phy_id;
|
||||||
} else {
|
} else {
|
||||||
@ -1174,6 +1177,27 @@ static int ethoc_probe(struct platform_device *pdev)
|
|||||||
if (random_mac)
|
if (random_mac)
|
||||||
netdev->addr_assign_type = NET_ADDR_RANDOM;
|
netdev->addr_assign_type = NET_ADDR_RANDOM;
|
||||||
|
|
||||||
|
/* Allow the platform setup code to adjust MII management bus clock. */
|
||||||
|
if (!eth_clkfreq) {
|
||||||
|
struct clk *clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
|
|
||||||
|
if (!IS_ERR(clk)) {
|
||||||
|
priv->clk = clk;
|
||||||
|
clk_prepare_enable(clk);
|
||||||
|
eth_clkfreq = clk_get_rate(clk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (eth_clkfreq) {
|
||||||
|
u32 clkdiv = MIIMODER_CLKDIV(eth_clkfreq / 2500000 + 1);
|
||||||
|
|
||||||
|
if (!clkdiv)
|
||||||
|
clkdiv = 2;
|
||||||
|
dev_dbg(&pdev->dev, "setting MII clkdiv to %u\n", clkdiv);
|
||||||
|
ethoc_write(priv, MIIMODER,
|
||||||
|
(ethoc_read(priv, MIIMODER) & MIIMODER_NOPRE) |
|
||||||
|
clkdiv);
|
||||||
|
}
|
||||||
|
|
||||||
/* register MII bus */
|
/* register MII bus */
|
||||||
priv->mdio = mdiobus_alloc();
|
priv->mdio = mdiobus_alloc();
|
||||||
if (!priv->mdio) {
|
if (!priv->mdio) {
|
||||||
@ -1239,6 +1263,8 @@ free_mdio:
|
|||||||
kfree(priv->mdio->irq);
|
kfree(priv->mdio->irq);
|
||||||
mdiobus_free(priv->mdio);
|
mdiobus_free(priv->mdio);
|
||||||
free:
|
free:
|
||||||
|
if (priv->clk)
|
||||||
|
clk_disable_unprepare(priv->clk);
|
||||||
free_netdev(netdev);
|
free_netdev(netdev);
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
@ -1263,6 +1289,8 @@ static int ethoc_remove(struct platform_device *pdev)
|
|||||||
kfree(priv->mdio->irq);
|
kfree(priv->mdio->irq);
|
||||||
mdiobus_free(priv->mdio);
|
mdiobus_free(priv->mdio);
|
||||||
}
|
}
|
||||||
|
if (priv->clk)
|
||||||
|
clk_disable_unprepare(priv->clk);
|
||||||
unregister_netdev(netdev);
|
unregister_netdev(netdev);
|
||||||
free_netdev(netdev);
|
free_netdev(netdev);
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
struct ethoc_platform_data {
|
struct ethoc_platform_data {
|
||||||
u8 hwaddr[IFHWADDRLEN];
|
u8 hwaddr[IFHWADDRLEN];
|
||||||
s8 phy_id;
|
s8 phy_id;
|
||||||
|
u32 eth_clkfreq;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* !LINUX_NET_ETHOC_H */
|
#endif /* !LINUX_NET_ETHOC_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user