Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 150014
b: refs/heads/master
c: ca816d9
h: refs/heads/master
v: v3
  • Loading branch information
Grant Likely authored and David S. Miller committed Apr 27, 2009
1 parent 9231ae7 commit 5aea539
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 148 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 8bc487d150b939e69830c39322df4ee486efe381
refs/heads/master: ca816d98170942371535b3e862813b0aba9b7d90
180 changes: 53 additions & 127 deletions trunk/drivers/net/fec_mpc52xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <linux/hardirq.h>
#include <linux/delay.h>
#include <linux/of_device.h>
#include <linux/of_mdio.h>
#include <linux/of_platform.h>

#include <linux/netdevice.h>
Expand All @@ -43,11 +44,9 @@

#define DRIVER_NAME "mpc52xx-fec"

#define FEC5200_PHYADDR_NONE (-1)
#define FEC5200_PHYADDR_7WIRE (-2)

/* Private driver data structure */
struct mpc52xx_fec_priv {
struct net_device *ndev;
int duplex;
int speed;
int r_irq;
Expand All @@ -59,10 +58,11 @@ struct mpc52xx_fec_priv {
int msg_enable;

/* MDIO link details */
int phy_addr;
unsigned int phy_speed;
unsigned int mdio_speed;
struct device_node *phy_node;
struct phy_device *phydev;
enum phy_state link;
int seven_wire_mode;
};


Expand Down Expand Up @@ -211,85 +211,25 @@ static void mpc52xx_fec_adjust_link(struct net_device *dev)
phy_print_status(phydev);
}

static int mpc52xx_fec_init_phy(struct net_device *dev)
{
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
struct phy_device *phydev;
char phy_id[BUS_ID_SIZE];

snprintf(phy_id, sizeof(phy_id), "%x:%02x",
(unsigned int)dev->base_addr, priv->phy_addr);

priv->link = PHY_DOWN;
priv->speed = 0;
priv->duplex = -1;

phydev = phy_connect(dev, phy_id, &mpc52xx_fec_adjust_link, 0, PHY_INTERFACE_MODE_MII);
if (IS_ERR(phydev)) {
dev_err(&dev->dev, "phy_connect failed\n");
return PTR_ERR(phydev);
}
dev_info(&dev->dev, "attached phy %i to driver %s\n",
phydev->addr, phydev->drv->name);

priv->phydev = phydev;

return 0;
}

static int mpc52xx_fec_phy_start(struct net_device *dev)
{
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
int err;

if (priv->phy_addr < 0)
return 0;

err = mpc52xx_fec_init_phy(dev);
if (err) {
dev_err(&dev->dev, "mpc52xx_fec_init_phy failed\n");
return err;
}

/* reset phy - this also wakes it from PDOWN */
phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
phy_start(priv->phydev);

return 0;
}

static void mpc52xx_fec_phy_stop(struct net_device *dev)
{
struct mpc52xx_fec_priv *priv = netdev_priv(dev);

if (!priv->phydev)
return;

phy_disconnect(priv->phydev);
/* power down phy */
phy_stop(priv->phydev);
phy_write(priv->phydev, MII_BMCR, BMCR_PDOWN);
}

static void mpc52xx_fec_phy_hw_init(struct mpc52xx_fec_priv *priv)
{
struct mpc52xx_fec __iomem *fec = priv->fec;

if (priv->phydev)
return;

out_be32(&fec->mii_speed, priv->phy_speed);
}

static int mpc52xx_fec_open(struct net_device *dev)
{
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
int err = -EBUSY;

if (priv->phy_node) {
priv->phydev = of_phy_connect(priv->ndev, priv->phy_node,
mpc52xx_fec_adjust_link, 0, 0);
if (!priv->phydev) {
dev_err(&dev->dev, "of_phy_connect failed\n");
return -ENODEV;
}
phy_start(priv->phydev);
}

if (request_irq(dev->irq, &mpc52xx_fec_interrupt, IRQF_SHARED,
DRIVER_NAME "_ctrl", dev)) {
dev_err(&dev->dev, "ctrl interrupt request failed\n");
goto out;
goto free_phy;
}
if (request_irq(priv->r_irq, &mpc52xx_fec_rx_interrupt, 0,
DRIVER_NAME "_rx", dev)) {
Expand All @@ -311,10 +251,6 @@ static int mpc52xx_fec_open(struct net_device *dev)
goto free_irqs;
}

err = mpc52xx_fec_phy_start(dev);
if (err)
goto free_skbs;

bcom_enable(priv->rx_dmatsk);
bcom_enable(priv->tx_dmatsk);

Expand All @@ -324,16 +260,18 @@ static int mpc52xx_fec_open(struct net_device *dev)

return 0;

free_skbs:
mpc52xx_fec_free_rx_buffers(dev, priv->rx_dmatsk);

free_irqs:
free_irq(priv->t_irq, dev);
free_2irqs:
free_irq(priv->r_irq, dev);
free_ctrl_irq:
free_irq(dev->irq, dev);
out:
free_phy:
if (priv->phydev) {
phy_stop(priv->phydev);
phy_disconnect(priv->phydev);
priv->phydev = NULL;
}

return err;
}
Expand All @@ -352,7 +290,12 @@ static int mpc52xx_fec_close(struct net_device *dev)
free_irq(priv->r_irq, dev);
free_irq(priv->t_irq, dev);

mpc52xx_fec_phy_stop(dev);
if (priv->phydev) {
/* power down phy */
phy_stop(priv->phydev);
phy_disconnect(priv->phydev);
priv->phydev = NULL;
}

return 0;
}
Expand Down Expand Up @@ -696,7 +639,7 @@ static void mpc52xx_fec_hw_init(struct net_device *dev)
/* set phy speed.
* this can't be done in phy driver, since it needs to be called
* before fec stuff (even on resume) */
mpc52xx_fec_phy_hw_init(priv);
out_be32(&fec->mii_speed, priv->mdio_speed);
}

/**
Expand Down Expand Up @@ -732,7 +675,7 @@ static void mpc52xx_fec_start(struct net_device *dev)
rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */
rcntrl |= FEC_RCNTRL_FCE;

if (priv->phy_addr != FEC5200_PHYADDR_7WIRE)
if (!priv->seven_wire_mode)
rcntrl |= FEC_RCNTRL_MII_MODE;

if (priv->duplex == DUPLEX_FULL)
Expand Down Expand Up @@ -798,8 +741,6 @@ static void mpc52xx_fec_stop(struct net_device *dev)

/* Stop FEC */
out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~FEC_ECNTRL_ETHER_EN);

return;
}

/* reset fec and bestcomm tasks */
Expand All @@ -817,9 +758,11 @@ static void mpc52xx_fec_reset(struct net_device *dev)

mpc52xx_fec_hw_init(dev);

phy_stop(priv->phydev);
phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
phy_start(priv->phydev);
if (priv->phydev) {
phy_stop(priv->phydev);
phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
phy_start(priv->phydev);
}

bcom_fec_rx_reset(priv->rx_dmatsk);
bcom_fec_tx_reset(priv->tx_dmatsk);
Expand Down Expand Up @@ -919,8 +862,6 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
struct net_device *ndev;
struct mpc52xx_fec_priv *priv = NULL;
struct resource mem;
struct device_node *phy_node;
const phandle *phy_handle;
const u32 *prop;
int prop_size;

Expand All @@ -933,6 +874,7 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
return -ENOMEM;

priv = netdev_priv(ndev);
priv->ndev = ndev;

/* Reserve FEC control zone */
rv = of_address_to_resource(op->node, 0, &mem);
Expand All @@ -956,6 +898,7 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
ndev->ethtool_ops = &mpc52xx_fec_ethtool_ops;
ndev->watchdog_timeo = FEC_WATCHDOG_TIMEOUT;
ndev->base_addr = mem.start;
SET_NETDEV_DEV(ndev, &op->dev);

spin_lock_init(&priv->lock);

Expand Down Expand Up @@ -1003,14 +946,9 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
*/

/* Start with safe defaults for link connection */
priv->phy_addr = FEC5200_PHYADDR_NONE;
priv->speed = 100;
priv->duplex = DUPLEX_HALF;
priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;

/* the 7-wire property means don't use MII mode */
if (of_find_property(op->node, "fsl,7-wire-mode", NULL))
priv->phy_addr = FEC5200_PHYADDR_7WIRE;
priv->mdio_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;

/* The current speed preconfigures the speed of the MII link */
prop = of_get_property(op->node, "current-speed", &prop_size);
Expand All @@ -1019,43 +957,23 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
priv->duplex = prop[1] ? DUPLEX_FULL : DUPLEX_HALF;
}

/* If there is a phy handle, setup link to that phy */
phy_handle = of_get_property(op->node, "phy-handle", &prop_size);
if (phy_handle && (prop_size >= sizeof(phandle))) {
phy_node = of_find_node_by_phandle(*phy_handle);
prop = of_get_property(phy_node, "reg", &prop_size);
if (prop && (prop_size >= sizeof(u32)))
if ((*prop >= 0) && (*prop < PHY_MAX_ADDR))
priv->phy_addr = *prop;
of_node_put(phy_node);
/* If there is a phy handle, then get the PHY node */
priv->phy_node = of_parse_phandle(op->node, "phy-handle", 0);

/* the 7-wire property means don't use MII mode */
if (of_find_property(op->node, "fsl,7-wire-mode", NULL)) {
priv->seven_wire_mode = 1;
dev_info(&ndev->dev, "using 7-wire PHY mode\n");
}

/* Hardware init */
mpc52xx_fec_hw_init(ndev);

mpc52xx_fec_reset_stats(ndev);

SET_NETDEV_DEV(ndev, &op->dev);

/* Register the new network device */
rv = register_netdev(ndev);
if (rv < 0)
goto probe_error;

/* Now report the link setup */
switch (priv->phy_addr) {
case FEC5200_PHYADDR_NONE:
dev_info(&ndev->dev, "Fixed speed MII link: %i%cD\n",
priv->speed, priv->duplex ? 'F' : 'H');
break;
case FEC5200_PHYADDR_7WIRE:
dev_info(&ndev->dev, "using 7-wire PHY mode\n");
break;
default:
dev_info(&ndev->dev, "Using PHY at MDIO address %i\n",
priv->phy_addr);
}

/* We're done ! */
dev_set_drvdata(&op->dev, ndev);

Expand All @@ -1065,6 +983,10 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
/* Error handling - free everything that might be allocated */
probe_error:

if (priv->phy_node)
of_node_put(priv->phy_node);
priv->phy_node = NULL;

irq_dispose_mapping(ndev->irq);

if (priv->rx_dmatsk)
Expand Down Expand Up @@ -1093,6 +1015,10 @@ mpc52xx_fec_remove(struct of_device *op)

unregister_netdev(ndev);

if (priv->phy_node)
of_node_put(priv->phy_node);
priv->phy_node = NULL;

irq_dispose_mapping(ndev->irq);

bcom_fec_rx_release(priv->rx_dmatsk);
Expand Down
Loading

0 comments on commit 5aea539

Please sign in to comment.