Commit 2c1bcaff authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 7781e5d1 f4c190eb
......@@ -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 {
static int lpc18xx_dwmac_probe(struct platform_device *pdev)
{
struct plat_stmmacenet_data *plat_dat;
struct stmmac_resources stmmac_res;
struct regmap *reg;
int interface;
};
u8 ethmode;
int ret;
static void *lpc18xx_dwmac_setup(struct platform_device *pdev)
{
struct lpc18xx_dwmac_priv_data *dwmac;
ret = stmmac_get_platform_resources(pdev, &stmmac_res);
if (ret)
return ret;
dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
if (!dwmac)
return ERR_PTR(-ENOMEM);
plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
if (IS_ERR(plat_dat))
return PTR_ERR(plat_dat);
dwmac->interface = of_get_phy_mode(pdev->dev.of_node);
if (dwmac->interface < 0)
return ERR_PTR(dwmac->interface);
plat_dat->has_gmac = true;
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;
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;
static const struct stmmac_of_data meson6_dwmac_data = {
.setup = meson6_dwmac_setup,
.fix_mac_speed = meson6_dwmac_fix_mac_speed,
};
return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
}
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,44 +248,34 @@ 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);
/**
* stmmac_pltfr_probe - platform driver probe.
* @pdev: platform device pointer
* Description: platform_device probe function. It is to allocate
* the necessary platform resources, invoke custom helper (if required) and
* invoke the main probe function.
*/
int stmmac_pltfr_probe(struct platform_device *pdev)
int stmmac_get_platform_resources(struct platform_device *pdev,
struct stmmac_resources *stmmac_res)
{
struct stmmac_resources stmmac_res;
int ret = 0;
struct resource *res;
struct device *dev = &pdev->dev;
struct plat_stmmacenet_data *plat_dat = NULL;
memset(&stmmac_res, 0, sizeof(stmmac_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(dev,
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;
return stmmac_res->irq;
}
/* On some platforms e.g. SPEAr the wake up irq differs from the mac irq
......@@ -287,45 +285,61 @@ int stmmac_pltfr_probe(struct platform_device *pdev)
* 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)
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->wol_irq = stmmac_res->irq;
}
stmmac_res.lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
if (stmmac_res.lpi_irq == -EPROBE_DEFER)
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;
}
stmmac_res->addr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(stmmac_res->addr))
return PTR_ERR(stmmac_res->addr);
/* Set default value for multicast hash bins */
plat_dat->multicast_filter_bins = HASH_TABLE_SIZE;
return 0;
}
EXPORT_SYMBOL_GPL(stmmac_get_platform_resources);
/* Set default value for unicast filter entries */
plat_dat->unicast_filter_entries = 1;
/**
* stmmac_pltfr_probe - platform driver probe.
* @pdev: platform device pointer
* Description: platform_device probe function. It is to allocate
* the necessary platform resources, invoke custom helper (if required) and
* invoke the main probe function.
*/
int stmmac_pltfr_probe(struct platform_device *pdev)
{
struct plat_stmmacenet_data *plat_dat;
struct stmmac_resources stmmac_res;
int ret;
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;
};
......
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