net: lpc_eth: parse phy nodes from device tree
When connected to a micrel phy, phy_find_first doesn't work properly because the first phy found is on address 0, the broadcast address but, the first thing the phy driver is doing is disabling this broadcast address. The phy is then available only on address 1 but the mdio driver doesn't know about it. Instead, register the mdio bus using of_mdiobus_register and try to find the phy description in device tree before falling back to phy_find_first. This ultimately also allows to describe the interrupt the phy is connected to. Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
2c69dae840
commit
3503bf024b
@ -15,6 +15,7 @@
|
|||||||
#include <linux/etherdevice.h>
|
#include <linux/etherdevice.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_mdio.h>
|
||||||
#include <linux/of_net.h>
|
#include <linux/of_net.h>
|
||||||
#include <linux/phy.h>
|
#include <linux/phy.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
@ -391,6 +392,7 @@ struct rx_status_t {
|
|||||||
struct netdata_local {
|
struct netdata_local {
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
struct net_device *ndev;
|
struct net_device *ndev;
|
||||||
|
struct device_node *phy_node;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
void __iomem *net_base;
|
void __iomem *net_base;
|
||||||
u32 msg_enable;
|
u32 msg_enable;
|
||||||
@ -749,22 +751,26 @@ static void lpc_handle_link_change(struct net_device *ndev)
|
|||||||
static int lpc_mii_probe(struct net_device *ndev)
|
static int lpc_mii_probe(struct net_device *ndev)
|
||||||
{
|
{
|
||||||
struct netdata_local *pldat = netdev_priv(ndev);
|
struct netdata_local *pldat = netdev_priv(ndev);
|
||||||
struct phy_device *phydev = phy_find_first(pldat->mii_bus);
|
struct phy_device *phydev;
|
||||||
|
|
||||||
if (!phydev) {
|
|
||||||
netdev_err(ndev, "no PHY found\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Attach to the PHY */
|
/* Attach to the PHY */
|
||||||
if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII)
|
if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII)
|
||||||
netdev_info(ndev, "using MII interface\n");
|
netdev_info(ndev, "using MII interface\n");
|
||||||
else
|
else
|
||||||
netdev_info(ndev, "using RMII interface\n");
|
netdev_info(ndev, "using RMII interface\n");
|
||||||
|
|
||||||
|
if (pldat->phy_node)
|
||||||
|
phydev = of_phy_find_device(pldat->phy_node);
|
||||||
|
else
|
||||||
|
phydev = phy_find_first(pldat->mii_bus);
|
||||||
|
if (!phydev) {
|
||||||
|
netdev_err(ndev, "no PHY found\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
phydev = phy_connect(ndev, phydev_name(phydev),
|
phydev = phy_connect(ndev, phydev_name(phydev),
|
||||||
&lpc_handle_link_change,
|
&lpc_handle_link_change,
|
||||||
lpc_phy_interface_mode(&pldat->pdev->dev));
|
lpc_phy_interface_mode(&pldat->pdev->dev));
|
||||||
|
|
||||||
if (IS_ERR(phydev)) {
|
if (IS_ERR(phydev)) {
|
||||||
netdev_err(ndev, "Could not attach to PHY\n");
|
netdev_err(ndev, "Could not attach to PHY\n");
|
||||||
return PTR_ERR(phydev);
|
return PTR_ERR(phydev);
|
||||||
@ -783,6 +789,7 @@ static int lpc_mii_probe(struct net_device *ndev)
|
|||||||
|
|
||||||
static int lpc_mii_init(struct netdata_local *pldat)
|
static int lpc_mii_init(struct netdata_local *pldat)
|
||||||
{
|
{
|
||||||
|
struct device_node *node;
|
||||||
int err = -ENXIO;
|
int err = -ENXIO;
|
||||||
|
|
||||||
pldat->mii_bus = mdiobus_alloc();
|
pldat->mii_bus = mdiobus_alloc();
|
||||||
@ -812,7 +819,10 @@ static int lpc_mii_init(struct netdata_local *pldat)
|
|||||||
|
|
||||||
platform_set_drvdata(pldat->pdev, pldat->mii_bus);
|
platform_set_drvdata(pldat->pdev, pldat->mii_bus);
|
||||||
|
|
||||||
if (mdiobus_register(pldat->mii_bus))
|
node = of_get_child_by_name(pldat->pdev->dev.of_node, "mdio");
|
||||||
|
err = of_mdiobus_register(pldat->mii_bus, node);
|
||||||
|
of_node_put(node);
|
||||||
|
if (err)
|
||||||
goto err_out_unregister_bus;
|
goto err_out_unregister_bus;
|
||||||
|
|
||||||
if (lpc_mii_probe(pldat->ndev) != 0)
|
if (lpc_mii_probe(pldat->ndev) != 0)
|
||||||
@ -1345,6 +1355,8 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
|
|||||||
netdev_dbg(ndev, "DMA buffer V address :0x%p\n",
|
netdev_dbg(ndev, "DMA buffer V address :0x%p\n",
|
||||||
pldat->dma_buff_base_v);
|
pldat->dma_buff_base_v);
|
||||||
|
|
||||||
|
pldat->phy_node = of_parse_phandle(np, "phy-handle", 0);
|
||||||
|
|
||||||
/* Get MAC address from current HW setting (POR state is all zeros) */
|
/* Get MAC address from current HW setting (POR state is all zeros) */
|
||||||
__lpc_get_mac(pldat, ndev->dev_addr);
|
__lpc_get_mac(pldat, ndev->dev_addr);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user