Merge branch 'stmmac-cleanup'
Joachim Eastwood says: ==================== stmmac clean up for 4.3 part1 This patch set continues the conversion of the dwmac glue layers to more proper platform drivers. The first part of the patch set cleans up stmmac_platform a bit. Refactors code from the common probe function and exports two functions that will be used in the dwmac-* drivers. Second part converts two simple dwmac-* drivers to have their own probe function and use the exported functions. This brings us closer to point where stmmac_platform is only a library of common functions for the dwmac-* drivers to use. The plan next is: * add probe functions to the rest of the dwmac-* drivers * move probe function in stmmac_platform to dwmac-generic * remove struct stmmac_of_data and let those drivers that actually need match data handle it themselves * clean up include/linux/stmmac.h Note that this patch set has only been tested on lpc18xx so testing on other platforms is greatly appreciated. Previous parts can be found here: http://www.spinics.net/lists/netdev/msg328997.html http://www.spinics.net/lists/netdev/msg329932.html ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
2c1bcaffe8
6 changed files with 142 additions and 130 deletions
|
@ -139,8 +139,6 @@ struct plat_stmmacenet_data {
|
|||
void (*free)(struct platform_device *pdev, void *priv);
|
||||
int (*init)(struct platform_device *pdev, void *priv);
|
||||
void (*exit)(struct platform_device *pdev, void *priv);
|
||||
void *custom_cfg;
|
||||
void *custom_data;
|
||||
void *bsp_priv;
|
||||
};
|
||||
|
||||
|
@ -186,8 +184,6 @@ Where:
|
|||
which will be stored in bsp_priv, and then passed to init and
|
||||
exit callbacks. init/exit callbacks should not use or modify
|
||||
platform data.
|
||||
o custom_cfg/custom_data: this is a custom configuration that can be passed
|
||||
while initializing the resources.
|
||||
o bsp_priv: another private pointer.
|
||||
|
||||
For MDIO bus The we have:
|
||||
|
|
|
@ -25,66 +25,53 @@
|
|||
# define LPC18XX_CREG_CREG6_ETHMODE_MII 0x0
|
||||
# define LPC18XX_CREG_CREG6_ETHMODE_RMII 0x4
|
||||
|
||||
struct lpc18xx_dwmac_priv_data {
|
||||
struct regmap *reg;
|
||||
int interface;
|
||||
};
|
||||
|
||||
static void *lpc18xx_dwmac_setup(struct platform_device *pdev)
|
||||
static int lpc18xx_dwmac_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct lpc18xx_dwmac_priv_data *dwmac;
|
||||
struct plat_stmmacenet_data *plat_dat;
|
||||
struct stmmac_resources stmmac_res;
|
||||
struct regmap *reg;
|
||||
u8 ethmode;
|
||||
int ret;
|
||||
|
||||
dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
|
||||
if (!dwmac)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ret = stmmac_get_platform_resources(pdev, &stmmac_res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dwmac->interface = of_get_phy_mode(pdev->dev.of_node);
|
||||
if (dwmac->interface < 0)
|
||||
return ERR_PTR(dwmac->interface);
|
||||
plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
|
||||
if (IS_ERR(plat_dat))
|
||||
return PTR_ERR(plat_dat);
|
||||
|
||||
dwmac->reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg");
|
||||
if (IS_ERR(dwmac->reg)) {
|
||||
dev_err(&pdev->dev, "Syscon lookup failed\n");
|
||||
return dwmac->reg;
|
||||
plat_dat->has_gmac = true;
|
||||
|
||||
reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg");
|
||||
if (IS_ERR(reg)) {
|
||||
dev_err(&pdev->dev, "syscon lookup failed\n");
|
||||
return PTR_ERR(reg);
|
||||
}
|
||||
|
||||
return dwmac;
|
||||
}
|
||||
|
||||
static int lpc18xx_dwmac_init(struct platform_device *pdev, void *priv)
|
||||
{
|
||||
struct lpc18xx_dwmac_priv_data *dwmac = priv;
|
||||
u8 ethmode;
|
||||
|
||||
if (dwmac->interface == PHY_INTERFACE_MODE_MII) {
|
||||
if (plat_dat->interface == PHY_INTERFACE_MODE_MII) {
|
||||
ethmode = LPC18XX_CREG_CREG6_ETHMODE_MII;
|
||||
} else if (dwmac->interface == PHY_INTERFACE_MODE_RMII) {
|
||||
} else if (plat_dat->interface == PHY_INTERFACE_MODE_RMII) {
|
||||
ethmode = LPC18XX_CREG_CREG6_ETHMODE_RMII;
|
||||
} else {
|
||||
dev_err(&pdev->dev, "Only MII and RMII mode supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(dwmac->reg, LPC18XX_CREG_CREG6,
|
||||
regmap_update_bits(reg, LPC18XX_CREG_CREG6,
|
||||
LPC18XX_CREG_CREG6_ETHMODE_MASK, ethmode);
|
||||
|
||||
return 0;
|
||||
return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
|
||||
}
|
||||
|
||||
static const struct stmmac_of_data lpc18xx_dwmac_data = {
|
||||
.has_gmac = 1,
|
||||
.setup = lpc18xx_dwmac_setup,
|
||||
.init = lpc18xx_dwmac_init,
|
||||
};
|
||||
|
||||
static const struct of_device_id lpc18xx_dwmac_match[] = {
|
||||
{ .compatible = "nxp,lpc1850-dwmac", .data = &lpc18xx_dwmac_data },
|
||||
{ .compatible = "nxp,lpc1850-dwmac" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lpc18xx_dwmac_match);
|
||||
|
||||
static struct platform_driver lpc18xx_dwmac_driver = {
|
||||
.probe = stmmac_pltfr_probe,
|
||||
.probe = lpc18xx_dwmac_probe,
|
||||
.remove = stmmac_pltfr_remove,
|
||||
.driver = {
|
||||
.name = "lpc18xx-dwmac",
|
||||
|
|
|
@ -47,36 +47,45 @@ static void meson6_dwmac_fix_mac_speed(void *priv, unsigned int speed)
|
|||
writel(val, dwmac->reg);
|
||||
}
|
||||
|
||||
static void *meson6_dwmac_setup(struct platform_device *pdev)
|
||||
static int meson6_dwmac_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct plat_stmmacenet_data *plat_dat;
|
||||
struct stmmac_resources stmmac_res;
|
||||
struct meson_dwmac *dwmac;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
ret = stmmac_get_platform_resources(pdev, &stmmac_res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
|
||||
if (IS_ERR(plat_dat))
|
||||
return PTR_ERR(plat_dat);
|
||||
|
||||
dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
|
||||
if (!dwmac)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
dwmac->reg = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(dwmac->reg))
|
||||
return ERR_CAST(dwmac->reg);
|
||||
return PTR_ERR(dwmac->reg);
|
||||
|
||||
return dwmac;
|
||||
plat_dat->bsp_priv = dwmac;
|
||||
plat_dat->fix_mac_speed = meson6_dwmac_fix_mac_speed;
|
||||
|
||||
return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
|
||||
}
|
||||
|
||||
static const struct stmmac_of_data meson6_dwmac_data = {
|
||||
.setup = meson6_dwmac_setup,
|
||||
.fix_mac_speed = meson6_dwmac_fix_mac_speed,
|
||||
};
|
||||
|
||||
static const struct of_device_id meson6_dwmac_match[] = {
|
||||
{ .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data},
|
||||
{ .compatible = "amlogic,meson6-dwmac" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, meson6_dwmac_match);
|
||||
|
||||
static struct platform_driver meson6_dwmac_driver = {
|
||||
.probe = stmmac_pltfr_probe,
|
||||
.probe = meson6_dwmac_probe,
|
||||
.remove = stmmac_pltfr_remove,
|
||||
.driver = {
|
||||
.name = "meson6-dwmac",
|
||||
|
|
|
@ -104,18 +104,20 @@ static int dwmac1000_validate_ucast_entries(int ucast_entries)
|
|||
* this function is to read the driver parameters from device-tree and
|
||||
* set some private fields that will be used by the main at runtime.
|
||||
*/
|
||||
static int stmmac_probe_config_dt(struct platform_device *pdev,
|
||||
struct plat_stmmacenet_data *plat,
|
||||
const char **mac)
|
||||
struct plat_stmmacenet_data *
|
||||
stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct plat_stmmacenet_data *plat;
|
||||
const struct stmmac_of_data *data;
|
||||
struct stmmac_dma_cfg *dma_cfg;
|
||||
const struct of_device_id *device;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
device = of_match_device(dev->driver->of_match_table, dev);
|
||||
if (device->data) {
|
||||
const struct stmmac_of_data *data = device->data;
|
||||
plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
|
||||
if (!plat)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
data = of_device_get_match_data(&pdev->dev);
|
||||
if (data) {
|
||||
plat->has_gmac = data->has_gmac;
|
||||
plat->enh_desc = data->enh_desc;
|
||||
plat->tx_coe = data->tx_coe;
|
||||
|
@ -151,7 +153,7 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
|
|||
/* If phy-handle is not specified, check if we have a fixed-phy */
|
||||
if (!plat->phy_node && of_phy_is_fixed_link(np)) {
|
||||
if ((of_phy_register_fixed_link(np) < 0))
|
||||
return -ENODEV;
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
plat->phy_node = of_node_get(np);
|
||||
}
|
||||
|
@ -182,6 +184,12 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
|
|||
*/
|
||||
plat->maxmtu = JUMBO_LEN;
|
||||
|
||||
/* Set default value for multicast hash bins */
|
||||
plat->multicast_filter_bins = HASH_TABLE_SIZE;
|
||||
|
||||
/* Set default value for unicast filter entries */
|
||||
plat->unicast_filter_entries = 1;
|
||||
|
||||
/*
|
||||
* Currently only the properties needed on SPEAr600
|
||||
* are provided. All other properties should be added
|
||||
|
@ -222,7 +230,7 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
|
|||
GFP_KERNEL);
|
||||
if (!dma_cfg) {
|
||||
of_node_put(np);
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
plat->dma_cfg = dma_cfg;
|
||||
of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
|
||||
|
@ -240,16 +248,62 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
|
|||
pr_warn("force_sf_dma_mode is ignored if force_thresh_dma_mode is set.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
return plat;
|
||||
}
|
||||
#else
|
||||
static int stmmac_probe_config_dt(struct platform_device *pdev,
|
||||
struct plat_stmmacenet_data *plat,
|
||||
const char **mac)
|
||||
struct plat_stmmacenet_data *
|
||||
stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
|
||||
{
|
||||
return -ENOSYS;
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
EXPORT_SYMBOL_GPL(stmmac_probe_config_dt);
|
||||
|
||||
int stmmac_get_platform_resources(struct platform_device *pdev,
|
||||
struct stmmac_resources *stmmac_res)
|
||||
{
|
||||
struct resource *res;
|
||||
|
||||
memset(stmmac_res, 0, sizeof(*stmmac_res));
|
||||
|
||||
/* Get IRQ information early to have an ability to ask for deferred
|
||||
* probe if needed before we went too far with resource allocation.
|
||||
*/
|
||||
stmmac_res->irq = platform_get_irq_byname(pdev, "macirq");
|
||||
if (stmmac_res->irq < 0) {
|
||||
if (stmmac_res->irq != -EPROBE_DEFER) {
|
||||
dev_err(&pdev->dev,
|
||||
"MAC IRQ configuration information not found\n");
|
||||
}
|
||||
return stmmac_res->irq;
|
||||
}
|
||||
|
||||
/* On some platforms e.g. SPEAr the wake up irq differs from the mac irq
|
||||
* The external wake up irq can be passed through the platform code
|
||||
* named as "eth_wake_irq"
|
||||
*
|
||||
* In case the wake up interrupt is not passed from the platform
|
||||
* so the driver will continue to use the mac irq (ndev->irq)
|
||||
*/
|
||||
stmmac_res->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
|
||||
if (stmmac_res->wol_irq < 0) {
|
||||
if (stmmac_res->wol_irq == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
stmmac_res->wol_irq = stmmac_res->irq;
|
||||
}
|
||||
|
||||
stmmac_res->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
|
||||
if (stmmac_res->lpi_irq == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
stmmac_res->addr = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(stmmac_res->addr))
|
||||
return PTR_ERR(stmmac_res->addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(stmmac_get_platform_resources);
|
||||
|
||||
/**
|
||||
* stmmac_pltfr_probe - platform driver probe.
|
||||
|
@ -260,72 +314,32 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
|
|||
*/
|
||||
int stmmac_pltfr_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct plat_stmmacenet_data *plat_dat;
|
||||
struct stmmac_resources stmmac_res;
|
||||
int ret = 0;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct plat_stmmacenet_data *plat_dat = NULL;
|
||||
int ret;
|
||||
|
||||
memset(&stmmac_res, 0, sizeof(stmmac_res));
|
||||
|
||||
/* Get IRQ information early to have an ability to ask for deferred
|
||||
* probe if needed before we went too far with resource allocation.
|
||||
*/
|
||||
stmmac_res.irq = platform_get_irq_byname(pdev, "macirq");
|
||||
if (stmmac_res.irq < 0) {
|
||||
if (stmmac_res.irq != -EPROBE_DEFER) {
|
||||
dev_err(dev,
|
||||
"MAC IRQ configuration information not found\n");
|
||||
}
|
||||
return stmmac_res.irq;
|
||||
}
|
||||
|
||||
/* On some platforms e.g. SPEAr the wake up irq differs from the mac irq
|
||||
* The external wake up irq can be passed through the platform code
|
||||
* named as "eth_wake_irq"
|
||||
*
|
||||
* In case the wake up interrupt is not passed from the platform
|
||||
* so the driver will continue to use the mac irq (ndev->irq)
|
||||
*/
|
||||
stmmac_res.wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
|
||||
if (stmmac_res.wol_irq < 0) {
|
||||
if (stmmac_res.wol_irq == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
stmmac_res.wol_irq = stmmac_res.irq;
|
||||
}
|
||||
|
||||
stmmac_res.lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
|
||||
if (stmmac_res.lpi_irq == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
stmmac_res.addr = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(stmmac_res.addr))
|
||||
return PTR_ERR(stmmac_res.addr);
|
||||
|
||||
plat_dat = dev_get_platdata(&pdev->dev);
|
||||
|
||||
if (!plat_dat)
|
||||
plat_dat = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct plat_stmmacenet_data),
|
||||
GFP_KERNEL);
|
||||
if (!plat_dat) {
|
||||
pr_err("%s: ERROR: no memory", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Set default value for multicast hash bins */
|
||||
plat_dat->multicast_filter_bins = HASH_TABLE_SIZE;
|
||||
|
||||
/* Set default value for unicast filter entries */
|
||||
plat_dat->unicast_filter_entries = 1;
|
||||
ret = stmmac_get_platform_resources(pdev, &stmmac_res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (pdev->dev.of_node) {
|
||||
ret = stmmac_probe_config_dt(pdev, plat_dat, &stmmac_res.mac);
|
||||
if (ret) {
|
||||
pr_err("%s: main dt probe failed", __func__);
|
||||
return ret;
|
||||
plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
|
||||
if (IS_ERR(plat_dat)) {
|
||||
dev_err(&pdev->dev, "dt configuration failed\n");
|
||||
return PTR_ERR(plat_dat);
|
||||
}
|
||||
} else {
|
||||
plat_dat = dev_get_platdata(&pdev->dev);
|
||||
if (!plat_dat) {
|
||||
dev_err(&pdev->dev, "no platform data provided\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Set default value for multicast hash bins */
|
||||
plat_dat->multicast_filter_bins = HASH_TABLE_SIZE;
|
||||
|
||||
/* Set default value for unicast filter entries */
|
||||
plat_dat->unicast_filter_entries = 1;
|
||||
}
|
||||
|
||||
/* Custom setup (if needed) */
|
||||
|
|
|
@ -19,6 +19,14 @@
|
|||
#ifndef __STMMAC_PLATFORM_H__
|
||||
#define __STMMAC_PLATFORM_H__
|
||||
|
||||
#include "stmmac.h"
|
||||
|
||||
struct plat_stmmacenet_data *
|
||||
stmmac_probe_config_dt(struct platform_device *pdev, const char **mac);
|
||||
|
||||
int stmmac_get_platform_resources(struct platform_device *pdev,
|
||||
struct stmmac_resources *stmmac_res);
|
||||
|
||||
int stmmac_pltfr_probe(struct platform_device *pdev);
|
||||
int stmmac_pltfr_remove(struct platform_device *pdev);
|
||||
extern const struct dev_pm_ops stmmac_pltfr_pm_ops;
|
||||
|
|
|
@ -123,8 +123,6 @@ struct plat_stmmacenet_data {
|
|||
void (*free)(struct platform_device *pdev, void *priv);
|
||||
int (*init)(struct platform_device *pdev, void *priv);
|
||||
void (*exit)(struct platform_device *pdev, void *priv);
|
||||
void *custom_cfg;
|
||||
void *custom_data;
|
||||
void *bsp_priv;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue