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: Stuart Menefy <stuart.menefy@st.com> Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
f3240e2811
commit
36bcfe7d74
@@ -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 {
|
|||||||
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 @@
|
|||||||
#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)
|
|||||||
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);
|
||||||
@@ -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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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",
|
|
||||||
|
/*
|
||||||
|
* If we're going to bind the MAC to this PHY bus,
|
||||||
|
* 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,
|
ndev->name, phydev->phy_id, addr,
|
||||||
phydev->irq, dev_name(&phydev->dev),
|
irq_str, dev_name(&phydev->dev),
|
||||||
(addr == priv->phy_addr) ? " active" : "");
|
act ? " active" : "");
|
||||||
found = 1;
|
found = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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)
|
|||||||
|
|
||||||
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 @@
|
|||||||
|
|
||||||
#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 {
|
|||||||
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
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user