aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/xscale
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/xscale')
-rw-r--r--drivers/net/ethernet/xscale/Kconfig1
-rw-r--r--drivers/net/ethernet/xscale/ixp4xx_eth.c210
2 files changed, 148 insertions, 63 deletions
diff --git a/drivers/net/ethernet/xscale/Kconfig b/drivers/net/ethernet/xscale/Kconfig
index 7b83a6e5d894..468ffe3d1707 100644
--- a/drivers/net/ethernet/xscale/Kconfig
+++ b/drivers/net/ethernet/xscale/Kconfig
@@ -22,6 +22,7 @@ config IXP4XX_ETH
tristate "Intel IXP4xx Ethernet support"
depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
select PHYLIB
+ select OF_MDIO if OF
select NET_PTP_CLASSIFY
help
Say Y here if you want to use built-in Ethernet ports
diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c
index 9d323e8595e2..1149e88e6454 100644
--- a/drivers/net/ethernet/xscale/ixp4xx_eth.c
+++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c
@@ -28,6 +28,7 @@
#include <linux/kernel.h>
#include <linux/net_tstamp.h>
#include <linux/of.h>
+#include <linux/of_mdio.h>
#include <linux/phy.h>
#include <linux/platform_data/eth_ixp4xx.h>
#include <linux/platform_device.h>
@@ -165,7 +166,6 @@ struct eth_regs {
};
struct port {
- struct resource *mem_res;
struct eth_regs __iomem *regs;
struct npe *npe;
struct net_device *netdev;
@@ -250,6 +250,7 @@ static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt)
static DEFINE_SPINLOCK(mdio_lock);
static struct eth_regs __iomem *mdio_regs; /* mdio command and status only */
static struct mii_bus *mdio_bus;
+static struct device_node *mdio_bus_np;
static int ports_open;
static struct port *npe_port_tab[MAX_NPES];
static struct dma_pool *dma_pool;
@@ -533,7 +534,8 @@ static int ixp4xx_mdio_register(struct eth_regs __iomem *regs)
mdio_bus->write = &ixp4xx_mdio_write;
snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "ixp4xx-eth-0");
- if ((err = mdiobus_register(mdio_bus)))
+ err = of_mdiobus_register(mdio_bus, mdio_bus_np);
+ if (err)
mdiobus_free(mdio_bus);
return err;
}
@@ -1358,18 +1360,118 @@ static const struct net_device_ops ixp4xx_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
};
+#ifdef CONFIG_OF
+static struct eth_plat_info *ixp4xx_of_get_platdata(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ struct of_phandle_args queue_spec;
+ struct of_phandle_args npe_spec;
+ struct device_node *mdio_np;
+ struct eth_plat_info *plat;
+ int ret;
+
+ plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL);
+ if (!plat)
+ return NULL;
+
+ ret = of_parse_phandle_with_fixed_args(np, "intel,npe-handle", 1, 0,
+ &npe_spec);
+ if (ret) {
+ dev_err(dev, "no NPE engine specified\n");
+ return NULL;
+ }
+ /* NPE ID 0x00, 0x10, 0x20... */
+ plat->npe = (npe_spec.args[0] << 4);
+
+ /* Check if this device has an MDIO bus */
+ mdio_np = of_get_child_by_name(np, "mdio");
+ if (mdio_np) {
+ plat->has_mdio = true;
+ mdio_bus_np = mdio_np;
+ /* DO NOT put the mdio_np, it will be used */
+ }
+
+ /* Get the rx queue as a resource from queue manager */
+ ret = of_parse_phandle_with_fixed_args(np, "queue-rx", 1, 0,
+ &queue_spec);
+ if (ret) {
+ dev_err(dev, "no rx queue phandle\n");
+ return NULL;
+ }
+ plat->rxq = queue_spec.args[0];
+
+ /* Get the txready queue as resource from queue manager */
+ ret = of_parse_phandle_with_fixed_args(np, "queue-txready", 1, 0,
+ &queue_spec);
+ if (ret) {
+ dev_err(dev, "no txready queue phandle\n");
+ return NULL;
+ }
+ plat->txreadyq = queue_spec.args[0];
+
+ return plat;
+}
+#else
+static struct eth_plat_info *ixp4xx_of_get_platdata(struct device *dev)
+{
+ return NULL;
+}
+#endif
+
static int ixp4xx_eth_probe(struct platform_device *pdev)
{
struct phy_device *phydev = NULL;
struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
struct eth_plat_info *plat;
- resource_size_t regs_phys;
struct net_device *ndev;
struct resource *res;
struct port *port;
int err;
- plat = dev_get_platdata(dev);
+ if (np) {
+ plat = ixp4xx_of_get_platdata(dev);
+ if (!plat)
+ return -ENODEV;
+ } else {
+ plat = dev_get_platdata(dev);
+ if (!plat)
+ return -ENODEV;
+ plat->npe = pdev->id;
+ switch (plat->npe) {
+ case IXP4XX_ETH_NPEA:
+ /* If the MDIO bus is not up yet, defer probe */
+ break;
+ case IXP4XX_ETH_NPEB:
+ /* On all except IXP43x, NPE-B is used for the MDIO bus.
+ * If there is no NPE-B in the feature set, bail out,
+ * else we have the MDIO bus here.
+ */
+ if (!cpu_is_ixp43x()) {
+ if (!(ixp4xx_read_feature_bits() &
+ IXP4XX_FEATURE_NPEB_ETH0))
+ return -ENODEV;
+ /* Else register the MDIO bus on NPE-B */
+ plat->has_mdio = true;
+ }
+ break;
+ case IXP4XX_ETH_NPEC:
+ /* IXP43x lacks NPE-B and uses NPE-C for the MDIO bus
+ * access, if there is no NPE-C, no bus, nothing works,
+ * so bail out.
+ */
+ if (cpu_is_ixp43x()) {
+ if (!(ixp4xx_read_feature_bits() &
+ IXP4XX_FEATURE_NPEC_ETH))
+ return -ENODEV;
+ /* Else register the MDIO bus on NPE-B */
+ plat->has_mdio = true;
+ }
+ break;
+ default:
+ return -ENODEV;
+ }
+ }
if (!(ndev = devm_alloc_etherdev(dev, sizeof(struct port))))
return -ENOMEM;
@@ -1377,59 +1479,29 @@ static int ixp4xx_eth_probe(struct platform_device *pdev)
SET_NETDEV_DEV(ndev, dev);
port = netdev_priv(ndev);
port->netdev = ndev;
- port->id = pdev->id;
+ port->id = plat->npe;
/* Get the port resource and remap */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
- regs_phys = res->start;
port->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(port->regs))
return PTR_ERR(port->regs);
- switch (port->id) {
- case IXP4XX_ETH_NPEA:
- /* If the MDIO bus is not up yet, defer probe */
- if (!mdio_bus)
- return -EPROBE_DEFER;
- break;
- case IXP4XX_ETH_NPEB:
- /*
- * On all except IXP43x, NPE-B is used for the MDIO bus.
- * If there is no NPE-B in the feature set, bail out, else
- * register the MDIO bus.
- */
- if (!cpu_is_ixp43x()) {
- if (!(ixp4xx_read_feature_bits() &
- IXP4XX_FEATURE_NPEB_ETH0))
- return -ENODEV;
- /* Else register the MDIO bus on NPE-B */
- if ((err = ixp4xx_mdio_register(port->regs)))
- return err;
- }
- if (!mdio_bus)
- return -EPROBE_DEFER;
- break;
- case IXP4XX_ETH_NPEC:
- /*
- * IXP43x lacks NPE-B and uses NPE-C for the MDIO bus access,
- * of there is no NPE-C, no bus, nothing works, so bail out.
- */
- if (cpu_is_ixp43x()) {
- if (!(ixp4xx_read_feature_bits() &
- IXP4XX_FEATURE_NPEC_ETH))
- return -ENODEV;
- /* Else register the MDIO bus on NPE-C */
- if ((err = ixp4xx_mdio_register(port->regs)))
- return err;
+ /* Register the MDIO bus if we have it */
+ if (plat->has_mdio) {
+ err = ixp4xx_mdio_register(port->regs);
+ if (err) {
+ dev_err(dev, "failed to register MDIO bus\n");
+ return err;
}
- if (!mdio_bus)
- return -EPROBE_DEFER;
- break;
- default:
- return -ENODEV;
}
+ /* If the instance with the MDIO bus has not yet appeared,
+ * defer probing until it gets probed.
+ */
+ if (!mdio_bus)
+ return -EPROBE_DEFER;
ndev->netdev_ops = &ixp4xx_netdev_ops;
ndev->ethtool_ops = &ixp4xx_ethtool_ops;
@@ -1440,12 +1512,6 @@ static int ixp4xx_eth_probe(struct platform_device *pdev)
if (!(port->npe = npe_request(NPE_ID(port->id))))
return -EIO;
- port->mem_res = request_mem_region(regs_phys, REGS_SIZE, ndev->name);
- if (!port->mem_res) {
- err = -EBUSY;
- goto err_npe_rel;
- }
-
port->plat = plat;
npe_port_tab[NPE_ID(port->id)] = port;
memcpy(ndev->dev_addr, plat->hwaddr, ETH_ALEN);
@@ -1458,15 +1524,26 @@ static int ixp4xx_eth_probe(struct platform_device *pdev)
__raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
udelay(50);
- phydev = mdiobus_get_phy(mdio_bus, plat->phy);
- if (IS_ERR(phydev)) {
- err = PTR_ERR(phydev);
- goto err_free_mem;
+ if (np) {
+ phydev = of_phy_get_and_connect(ndev, np, ixp4xx_adjust_link);
+ } else {
+ phydev = mdiobus_get_phy(mdio_bus, plat->phy);
+ if (IS_ERR(phydev)) {
+ err = PTR_ERR(phydev);
+ dev_err(dev, "could not connect phydev (%d)\n", err);
+ goto err_free_mem;
+ }
+ err = phy_connect_direct(ndev, phydev, ixp4xx_adjust_link,
+ PHY_INTERFACE_MODE_MII);
+ if (err)
+ goto err_free_mem;
+
}
- err = phy_connect_direct(ndev, phydev, ixp4xx_adjust_link,
- PHY_INTERFACE_MODE_MII);
- if (err)
+ if (!phydev) {
+ err = -ENODEV;
+ dev_err(dev, "no phydev\n");
goto err_free_mem;
+ }
phydev->irq = PHY_POLL;
@@ -1482,8 +1559,6 @@ err_phy_dis:
phy_disconnect(phydev);
err_free_mem:
npe_port_tab[NPE_ID(port->id)] = NULL;
- release_resource(port->mem_res);
-err_npe_rel:
npe_release(port->npe);
return err;
}
@@ -1499,12 +1574,21 @@ static int ixp4xx_eth_remove(struct platform_device *pdev)
ixp4xx_mdio_remove();
npe_port_tab[NPE_ID(port->id)] = NULL;
npe_release(port->npe);
- release_resource(port->mem_res);
return 0;
}
+static const struct of_device_id ixp4xx_eth_of_match[] = {
+ {
+ .compatible = "intel,ixp4xx-ethernet",
+ },
+ { },
+};
+
static struct platform_driver ixp4xx_eth_driver = {
- .driver.name = DRV_NAME,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = of_match_ptr(ixp4xx_eth_of_match),
+ },
.probe = ixp4xx_eth_probe,
.remove = ixp4xx_eth_remove,
};