Commit 36bcfe7d authored by Giuseppe CAVALLARO's avatar Giuseppe CAVALLARO Committed by David S. Miller

stmmac: unify MAC and PHY configuration parameters (V2)

Prior to this change, most PHY configuration parameters were passed
into the STMMAC device as a separate PHY device. As well as being
unusual, this made it difficult to make changes to the MAC/PHY
relationship.

This patch moves all the PHY parameters into the MAC configuration
structure, mainly as a separate structure. This allows us to completely
ignore the MDIO bus attached to a stmmac if desired, and not create
the PHY bus. It also allows the stmmac driver to use a different PHY
from the one it is connected to, for example a fixed PHY or bit banging
PHY.

Also derive the stmmac/PHY connection type (MII/RMII etc) from the
mode can be passed into <platf>_configure_ethernet.
STLinux kernel at git://git.stlinux.com/stm/linux-sh4-2.6.32.y.git
provides several examples how to use this new infrastructure (that
actually is easier to maintain and clearer).
Signed-off-by: default avatarStuart Menefy <stuart.menefy@st.com>
Signed-off-by: default avatarGiuseppe Cavallaro <peppe.cavallaro@st.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f3240e28
...@@ -56,14 +56,9 @@ struct stmmac_priv { ...@@ -56,14 +56,9 @@ struct stmmac_priv {
struct stmmac_extra_stats xstats; struct stmmac_extra_stats xstats;
struct napi_struct napi; struct napi_struct napi;
phy_interface_t phy_interface;
int phy_addr;
int phy_mask;
int (*phy_reset) (void *priv);
int rx_coe; int rx_coe;
int no_csum_insertion; int no_csum_insertion;
int phy_irq;
struct phy_device *phydev; struct phy_device *phydev;
int oldlink; int oldlink;
int speed; int speed;
...@@ -71,6 +66,7 @@ struct stmmac_priv { ...@@ -71,6 +66,7 @@ struct stmmac_priv {
unsigned int flow_ctrl; unsigned int flow_ctrl;
unsigned int pause; unsigned int pause;
struct mii_bus *mii; struct mii_bus *mii;
int mii_irq[PHY_MAX_ADDR];
u32 msg_enable; u32 msg_enable;
spinlock_t lock; spinlock_t lock;
......
...@@ -49,7 +49,6 @@ ...@@ -49,7 +49,6 @@
#include "stmmac.h" #include "stmmac.h"
#define STMMAC_RESOURCE_NAME "stmmaceth" #define STMMAC_RESOURCE_NAME "stmmaceth"
#define PHY_RESOURCE_NAME "stmmacphy"
#undef STMMAC_DEBUG #undef STMMAC_DEBUG
/*#define STMMAC_DEBUG*/ /*#define STMMAC_DEBUG*/
...@@ -305,18 +304,13 @@ static int stmmac_init_phy(struct net_device *dev) ...@@ -305,18 +304,13 @@ static int stmmac_init_phy(struct net_device *dev)
priv->speed = 0; priv->speed = 0;
priv->oldduplex = -1; priv->oldduplex = -1;
if (priv->phy_addr == -1) {
/* We don't have a PHY, so do nothing */
return 0;
}
snprintf(bus_id, MII_BUS_ID_SIZE, "%x", priv->plat->bus_id); snprintf(bus_id, MII_BUS_ID_SIZE, "%x", priv->plat->bus_id);
snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
priv->phy_addr); priv->plat->phy_addr);
pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id); pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id);
phydev = phy_connect(dev, phy_id, &stmmac_adjust_link, 0, phydev = phy_connect(dev, phy_id, &stmmac_adjust_link, 0,
priv->phy_interface); priv->plat->interface);
if (IS_ERR(phydev)) { if (IS_ERR(phydev)) {
pr_err("%s: Could not attach to PHY\n", dev->name); pr_err("%s: Could not attach to PHY\n", dev->name);
...@@ -335,7 +329,7 @@ static int stmmac_init_phy(struct net_device *dev) ...@@ -335,7 +329,7 @@ static int stmmac_init_phy(struct net_device *dev)
return -ENODEV; return -ENODEV;
} }
pr_debug("stmmac_init_phy: %s: attached to PHY (UID 0x%x)" pr_debug("stmmac_init_phy: %s: attached to PHY (UID 0x%x)"
" Link = %d\n", dev->name, phydev->phy_id, phydev->link); " Link = %d\n", dev->name, phydev->phy_id, phydev->link);
priv->phydev = phydev; priv->phydev = phydev;
...@@ -1528,71 +1522,6 @@ static int stmmac_mac_device_setup(struct net_device *dev) ...@@ -1528,71 +1522,6 @@ static int stmmac_mac_device_setup(struct net_device *dev)
return 0; return 0;
} }
static int stmmacphy_dvr_probe(struct platform_device *pdev)
{
struct plat_stmmacphy_data *plat_dat = pdev->dev.platform_data;
pr_debug("stmmacphy_dvr_probe: added phy for bus %d\n",
plat_dat->bus_id);
return 0;
}
static int stmmacphy_dvr_remove(struct platform_device *pdev)
{
return 0;
}
static struct platform_driver stmmacphy_driver = {
.driver = {
.name = PHY_RESOURCE_NAME,
},
.probe = stmmacphy_dvr_probe,
.remove = stmmacphy_dvr_remove,
};
/**
* stmmac_associate_phy
* @dev: pointer to device structure
* @data: points to the private structure.
* Description: Scans through all the PHYs we have registered and checks if
* any are associated with our MAC. If so, then just fill in
* the blanks in our local context structure
*/
static int stmmac_associate_phy(struct device *dev, void *data)
{
struct stmmac_priv *priv = (struct stmmac_priv *)data;
struct plat_stmmacphy_data *plat_dat = dev->platform_data;
DBG(probe, DEBUG, "%s: checking phy for bus %d\n", __func__,
plat_dat->bus_id);
/* Check that this phy is for the MAC being initialised */
if (priv->plat->bus_id != plat_dat->bus_id)
return 0;
/* OK, this PHY is connected to the MAC.
Go ahead and get the parameters */
DBG(probe, DEBUG, "%s: OK. Found PHY config\n", __func__);
priv->phy_irq =
platform_get_irq_byname(to_platform_device(dev), "phyirq");
DBG(probe, DEBUG, "%s: PHY irq on bus %d is %d\n", __func__,
plat_dat->bus_id, priv->phy_irq);
/* Override with kernel parameters if supplied XXX CRS XXX
* this needs to have multiple instances */
if ((phyaddr >= 0) && (phyaddr <= 31))
plat_dat->phy_addr = phyaddr;
priv->phy_addr = plat_dat->phy_addr;
priv->phy_mask = plat_dat->phy_mask;
priv->phy_interface = plat_dat->interface;
priv->phy_reset = plat_dat->phy_reset;
DBG(probe, DEBUG, "%s: exiting\n", __func__);
return 1; /* forces exit of driver_for_each_device() */
}
/** /**
* stmmac_dvr_probe * stmmac_dvr_probe
* @pdev: platform device pointer * @pdev: platform device pointer
...@@ -1683,14 +1612,10 @@ static int stmmac_dvr_probe(struct platform_device *pdev) ...@@ -1683,14 +1612,10 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
if (ret < 0) if (ret < 0)
goto out_plat_exit; goto out_plat_exit;
/* associate a PHY - it is provided by another platform bus */ /* Override with kernel parameters if supplied XXX CRS XXX
if (!driver_for_each_device * this needs to have multiple instances */
(&(stmmacphy_driver.driver), NULL, (void *)priv, if ((phyaddr >= 0) && (phyaddr <= 31))
stmmac_associate_phy)) { priv->plat->phy_addr = phyaddr;
pr_err("No PHY device is associated with this MAC!\n");
ret = -ENODEV;
goto out_unregister;
}
pr_info("\t%s - (dev. name: %s - id: %d, IRQ #%d\n" pr_info("\t%s - (dev. name: %s - id: %d, IRQ #%d\n"
"\tIO base addr: 0x%p)\n", ndev->name, pdev->name, "\tIO base addr: 0x%p)\n", ndev->name, pdev->name,
...@@ -1890,11 +1815,6 @@ static int __init stmmac_init_module(void) ...@@ -1890,11 +1815,6 @@ static int __init stmmac_init_module(void)
{ {
int ret; int ret;
if (platform_driver_register(&stmmacphy_driver)) {
pr_err("No PHY devices registered!\n");
return -ENODEV;
}
ret = platform_driver_register(&stmmac_driver); ret = platform_driver_register(&stmmac_driver);
return ret; return ret;
} }
...@@ -1905,7 +1825,6 @@ static int __init stmmac_init_module(void) ...@@ -1905,7 +1825,6 @@ static int __init stmmac_init_module(void)
*/ */
static void __exit stmmac_cleanup_module(void) static void __exit stmmac_cleanup_module(void)
{ {
platform_driver_unregister(&stmmacphy_driver);
platform_driver_unregister(&stmmac_driver); platform_driver_unregister(&stmmac_driver);
} }
......
...@@ -113,9 +113,9 @@ static int stmmac_mdio_reset(struct mii_bus *bus) ...@@ -113,9 +113,9 @@ static int stmmac_mdio_reset(struct mii_bus *bus)
struct stmmac_priv *priv = netdev_priv(ndev); struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr; unsigned int mii_address = priv->hw->mii.addr;
if (priv->phy_reset) { if (priv->plat->mdio_bus_data->phy_reset) {
pr_debug("stmmac_mdio_reset: calling phy_reset\n"); pr_debug("stmmac_mdio_reset: calling phy_reset\n");
priv->phy_reset(priv->plat->bsp_priv); priv->plat->mdio_bus_data->phy_reset(priv->plat->bsp_priv);
} }
/* This is a workaround for problems with the STE101P PHY. /* This is a workaround for problems with the STE101P PHY.
...@@ -138,30 +138,29 @@ int stmmac_mdio_register(struct net_device *ndev) ...@@ -138,30 +138,29 @@ int stmmac_mdio_register(struct net_device *ndev)
struct mii_bus *new_bus; struct mii_bus *new_bus;
int *irqlist; int *irqlist;
struct stmmac_priv *priv = netdev_priv(ndev); struct stmmac_priv *priv = netdev_priv(ndev);
struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
int addr, found; int addr, found;
if (!mdio_bus_data)
return 0;
new_bus = mdiobus_alloc(); new_bus = mdiobus_alloc();
if (new_bus == NULL) if (new_bus == NULL)
return -ENOMEM; return -ENOMEM;
irqlist = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); if (mdio_bus_data->irqs)
if (irqlist == NULL) { irqlist = mdio_bus_data->irqs;
err = -ENOMEM; else
goto irqlist_alloc_fail; irqlist = priv->mii_irq;
}
/* Assign IRQ to phy at address phy_addr */
if (priv->phy_addr != -1)
irqlist[priv->phy_addr] = priv->phy_irq;
new_bus->name = "STMMAC MII Bus"; new_bus->name = "STMMAC MII Bus";
new_bus->read = &stmmac_mdio_read; new_bus->read = &stmmac_mdio_read;
new_bus->write = &stmmac_mdio_write; new_bus->write = &stmmac_mdio_write;
new_bus->reset = &stmmac_mdio_reset; new_bus->reset = &stmmac_mdio_reset;
snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", priv->plat->bus_id); snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", mdio_bus_data->bus_id);
new_bus->priv = ndev; new_bus->priv = ndev;
new_bus->irq = irqlist; new_bus->irq = irqlist;
new_bus->phy_mask = priv->phy_mask; new_bus->phy_mask = mdio_bus_data->phy_mask;
new_bus->parent = priv->device; new_bus->parent = priv->device;
err = mdiobus_register(new_bus); err = mdiobus_register(new_bus);
if (err != 0) { if (err != 0) {
...@@ -172,18 +171,50 @@ int stmmac_mdio_register(struct net_device *ndev) ...@@ -172,18 +171,50 @@ int stmmac_mdio_register(struct net_device *ndev)
priv->mii = new_bus; priv->mii = new_bus;
found = 0; found = 0;
for (addr = 0; addr < 32; addr++) { for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
struct phy_device *phydev = new_bus->phy_map[addr]; struct phy_device *phydev = new_bus->phy_map[addr];
if (phydev) { if (phydev) {
if (priv->phy_addr == -1) { int act = 0;
priv->phy_addr = addr; char irq_num[4];
phydev->irq = priv->phy_irq; char *irq_str;
irqlist[addr] = priv->phy_irq;
/*
* If an IRQ was provided to be assigned after
* the bus probe, do it here.
*/
if ((mdio_bus_data->irqs == NULL) &&
(mdio_bus_data->probed_phy_irq > 0)) {
irqlist[addr] = mdio_bus_data->probed_phy_irq;
phydev->irq = mdio_bus_data->probed_phy_irq;
} }
pr_info("%s: PHY ID %08x at %d IRQ %d (%s)%s\n",
ndev->name, phydev->phy_id, addr, /*
phydev->irq, dev_name(&phydev->dev), * If we're going to bind the MAC to this PHY bus,
(addr == priv->phy_addr) ? " active" : ""); * and no PHY number was provided to the MAC,
* use the one probed here.
*/
if ((priv->plat->bus_id == mdio_bus_data->bus_id) &&
(priv->plat->phy_addr == -1))
priv->plat->phy_addr = addr;
act = (priv->plat->bus_id == mdio_bus_data->bus_id) &&
(priv->plat->phy_addr == addr);
switch (phydev->irq) {
case PHY_POLL:
irq_str = "POLL";
break;
case PHY_IGNORE_INTERRUPT:
irq_str = "IGNORE";
break;
default:
sprintf(irq_num, "%d", phydev->irq);
irq_str = irq_num;
break;
}
pr_info("%s: PHY ID %08x at %d IRQ %s (%s)%s\n",
ndev->name, phydev->phy_id, addr,
irq_str, dev_name(&phydev->dev),
act ? " active" : "");
found = 1; found = 1;
} }
} }
...@@ -192,10 +223,9 @@ int stmmac_mdio_register(struct net_device *ndev) ...@@ -192,10 +223,9 @@ int stmmac_mdio_register(struct net_device *ndev)
pr_warning("%s: No PHY found\n", ndev->name); pr_warning("%s: No PHY found\n", ndev->name);
return 0; return 0;
bus_register_fail: bus_register_fail:
kfree(irqlist); mdiobus_free(new_bus);
irqlist_alloc_fail:
kfree(new_bus);
return err; return err;
} }
...@@ -210,7 +240,8 @@ int stmmac_mdio_unregister(struct net_device *ndev) ...@@ -210,7 +240,8 @@ int stmmac_mdio_unregister(struct net_device *ndev)
mdiobus_unregister(priv->mii); mdiobus_unregister(priv->mii);
priv->mii->priv = NULL; priv->mii->priv = NULL;
kfree(priv->mii); mdiobus_free(priv->mii);
priv->mii = NULL;
return 0; return 0;
} }
...@@ -28,11 +28,21 @@ ...@@ -28,11 +28,21 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
/* platform data for platform device structure's platform_data field */ /* Platfrom data for platform device structure's platform_data field */
struct stmmac_mdio_bus_data {
int bus_id;
int (*phy_reset)(void *priv);
unsigned int phy_mask;
int *irqs;
int probed_phy_irq;
};
/* Private data for the STM on-board ethernet driver */
struct plat_stmmacenet_data { struct plat_stmmacenet_data {
int bus_id; int bus_id;
int phy_addr;
int interface;
struct stmmac_mdio_bus_data *mdio_bus_data;
int pbl; int pbl;
int clk_csr; int clk_csr;
int has_gmac; int has_gmac;
...@@ -48,14 +58,4 @@ struct plat_stmmacenet_data { ...@@ -48,14 +58,4 @@ struct plat_stmmacenet_data {
void *custom_cfg; void *custom_cfg;
void *bsp_priv; void *bsp_priv;
}; };
struct plat_stmmacphy_data {
int bus_id;
int phy_addr;
unsigned int phy_mask;
int interface;
int (*phy_reset)(void *priv);
void *priv;
};
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment