mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 22:51:42 +00:00
net: eth: xgene: change APM X-Gene SoC platform ethernet to support ACPI
This adds support for APM X-Gene ethernet driver to use ACPI table to derive ethernet driver parameter. Signed-off-by: Feng Kan <fkan@apm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
1fcf77c87a
commit
de7b5b3d79
@ -593,10 +593,12 @@ static int xgene_enet_reset(struct xgene_enet_pdata *pdata)
|
|||||||
if (!xgene_ring_mgr_init(pdata))
|
if (!xgene_ring_mgr_init(pdata))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
clk_prepare_enable(pdata->clk);
|
if (!efi_enabled(EFI_BOOT)) {
|
||||||
clk_disable_unprepare(pdata->clk);
|
clk_prepare_enable(pdata->clk);
|
||||||
clk_prepare_enable(pdata->clk);
|
clk_disable_unprepare(pdata->clk);
|
||||||
xgene_enet_ecc_init(pdata);
|
clk_prepare_enable(pdata->clk);
|
||||||
|
xgene_enet_ecc_init(pdata);
|
||||||
|
}
|
||||||
xgene_enet_config_ring_if_assoc(pdata);
|
xgene_enet_config_ring_if_assoc(pdata);
|
||||||
|
|
||||||
/* Enable auto-incr for scanning */
|
/* Enable auto-incr for scanning */
|
||||||
@ -663,15 +665,20 @@ static int xgene_enet_phy_connect(struct net_device *ndev)
|
|||||||
struct phy_device *phy_dev;
|
struct phy_device *phy_dev;
|
||||||
struct device *dev = &pdata->pdev->dev;
|
struct device *dev = &pdata->pdev->dev;
|
||||||
|
|
||||||
phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0);
|
if (dev->of_node) {
|
||||||
if (!phy_np) {
|
phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0);
|
||||||
netdev_dbg(ndev, "No phy-handle found\n");
|
if (!phy_np) {
|
||||||
return -ENODEV;
|
netdev_dbg(ndev, "No phy-handle found in DT\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
pdata->phy_dev = of_phy_find_device(phy_np);
|
||||||
}
|
}
|
||||||
|
|
||||||
phy_dev = of_phy_connect(ndev, phy_np, &xgene_enet_adjust_link,
|
phy_dev = pdata->phy_dev;
|
||||||
0, pdata->phy_mode);
|
|
||||||
if (!phy_dev) {
|
if (!phy_dev ||
|
||||||
|
phy_connect_direct(ndev, phy_dev, &xgene_enet_adjust_link,
|
||||||
|
pdata->phy_mode)) {
|
||||||
netdev_err(ndev, "Could not connect to PHY\n");
|
netdev_err(ndev, "Could not connect to PHY\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
@ -681,32 +688,71 @@ static int xgene_enet_phy_connect(struct net_device *ndev)
|
|||||||
~SUPPORTED_100baseT_Half &
|
~SUPPORTED_100baseT_Half &
|
||||||
~SUPPORTED_1000baseT_Half;
|
~SUPPORTED_1000baseT_Half;
|
||||||
phy_dev->advertising = phy_dev->supported;
|
phy_dev->advertising = phy_dev->supported;
|
||||||
pdata->phy_dev = phy_dev;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int xgene_mdiobus_register(struct xgene_enet_pdata *pdata,
|
||||||
|
struct mii_bus *mdio)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdata->pdev->dev;
|
||||||
|
struct net_device *ndev = pdata->ndev;
|
||||||
|
struct phy_device *phy;
|
||||||
|
struct device_node *child_np;
|
||||||
|
struct device_node *mdio_np = NULL;
|
||||||
|
int ret;
|
||||||
|
u32 phy_id;
|
||||||
|
|
||||||
|
if (dev->of_node) {
|
||||||
|
for_each_child_of_node(dev->of_node, child_np) {
|
||||||
|
if (of_device_is_compatible(child_np,
|
||||||
|
"apm,xgene-mdio")) {
|
||||||
|
mdio_np = child_np;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mdio_np) {
|
||||||
|
netdev_dbg(ndev, "No mdio node in the dts\n");
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return of_mdiobus_register(mdio, mdio_np);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mask out all PHYs from auto probing. */
|
||||||
|
mdio->phy_mask = ~0;
|
||||||
|
|
||||||
|
/* Register the MDIO bus */
|
||||||
|
ret = mdiobus_register(mdio);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = device_property_read_u32(dev, "phy-channel", &phy_id);
|
||||||
|
if (ret)
|
||||||
|
ret = device_property_read_u32(dev, "phy-addr", &phy_id);
|
||||||
|
if (ret)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
phy = get_phy_device(mdio, phy_id, true);
|
||||||
|
if (!phy || IS_ERR(phy))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
ret = phy_device_register(phy);
|
||||||
|
if (ret)
|
||||||
|
phy_device_free(phy);
|
||||||
|
else
|
||||||
|
pdata->phy_dev = phy;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata)
|
int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata)
|
||||||
{
|
{
|
||||||
struct net_device *ndev = pdata->ndev;
|
struct net_device *ndev = pdata->ndev;
|
||||||
struct device *dev = &pdata->pdev->dev;
|
|
||||||
struct device_node *child_np;
|
|
||||||
struct device_node *mdio_np = NULL;
|
|
||||||
struct mii_bus *mdio_bus;
|
struct mii_bus *mdio_bus;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
for_each_child_of_node(dev->of_node, child_np) {
|
|
||||||
if (of_device_is_compatible(child_np, "apm,xgene-mdio")) {
|
|
||||||
mdio_np = child_np;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mdio_np) {
|
|
||||||
netdev_dbg(ndev, "No mdio node in the dts\n");
|
|
||||||
return -ENXIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
mdio_bus = mdiobus_alloc();
|
mdio_bus = mdiobus_alloc();
|
||||||
if (!mdio_bus)
|
if (!mdio_bus)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -720,7 +766,7 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata)
|
|||||||
mdio_bus->priv = pdata;
|
mdio_bus->priv = pdata;
|
||||||
mdio_bus->parent = &ndev->dev;
|
mdio_bus->parent = &ndev->dev;
|
||||||
|
|
||||||
ret = of_mdiobus_register(mdio_bus, mdio_np);
|
ret = xgene_mdiobus_register(pdata, mdio_bus);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
netdev_err(ndev, "Failed to register MDIO bus\n");
|
netdev_err(ndev, "Failed to register MDIO bus\n");
|
||||||
mdiobus_free(mdio_bus);
|
mdiobus_free(mdio_bus);
|
||||||
|
@ -24,6 +24,10 @@
|
|||||||
#include "xgene_enet_sgmac.h"
|
#include "xgene_enet_sgmac.h"
|
||||||
#include "xgene_enet_xgmac.h"
|
#include "xgene_enet_xgmac.h"
|
||||||
|
|
||||||
|
#define RES_ENET_CSR 0
|
||||||
|
#define RES_RING_CSR 1
|
||||||
|
#define RES_RING_CMD 2
|
||||||
|
|
||||||
static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool)
|
static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool)
|
||||||
{
|
{
|
||||||
struct xgene_enet_raw_desc16 *raw_desc;
|
struct xgene_enet_raw_desc16 *raw_desc;
|
||||||
@ -746,6 +750,41 @@ static const struct net_device_ops xgene_ndev_ops = {
|
|||||||
.ndo_set_mac_address = xgene_enet_set_mac_address,
|
.ndo_set_mac_address = xgene_enet_set_mac_address,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int xgene_get_mac_address(struct device *dev,
|
||||||
|
unsigned char *addr)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = device_property_read_u8_array(dev, "local-mac-address", addr, 6);
|
||||||
|
if (ret)
|
||||||
|
ret = device_property_read_u8_array(dev, "mac-address",
|
||||||
|
addr, 6);
|
||||||
|
if (ret)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
return ETH_ALEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xgene_get_phy_mode(struct device *dev)
|
||||||
|
{
|
||||||
|
int i, ret;
|
||||||
|
char *modestr;
|
||||||
|
|
||||||
|
ret = device_property_read_string(dev, "phy-connection-type",
|
||||||
|
(const char **)&modestr);
|
||||||
|
if (ret)
|
||||||
|
ret = device_property_read_string(dev, "phy-mode",
|
||||||
|
(const char **)&modestr);
|
||||||
|
if (ret)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) {
|
||||||
|
if (!strcasecmp(modestr, phy_modes(i)))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
|
static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
|
||||||
{
|
{
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
@ -753,29 +792,42 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
|
|||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
void __iomem *base_addr;
|
void __iomem *base_addr;
|
||||||
const char *mac;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
pdev = pdata->pdev;
|
pdev = pdata->pdev;
|
||||||
dev = &pdev->dev;
|
dev = &pdev->dev;
|
||||||
ndev = pdata->ndev;
|
ndev = pdata->ndev;
|
||||||
|
|
||||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "enet_csr");
|
res = platform_get_resource(pdev, IORESOURCE_MEM, RES_ENET_CSR);
|
||||||
pdata->base_addr = devm_ioremap_resource(dev, res);
|
if (!res) {
|
||||||
|
dev_err(dev, "Resource enet_csr not defined\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
pdata->base_addr = devm_ioremap(dev, res->start, resource_size(res));
|
||||||
if (IS_ERR(pdata->base_addr)) {
|
if (IS_ERR(pdata->base_addr)) {
|
||||||
dev_err(dev, "Unable to retrieve ENET Port CSR region\n");
|
dev_err(dev, "Unable to retrieve ENET Port CSR region\n");
|
||||||
return PTR_ERR(pdata->base_addr);
|
return PTR_ERR(pdata->base_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_csr");
|
res = platform_get_resource(pdev, IORESOURCE_MEM, RES_RING_CSR);
|
||||||
pdata->ring_csr_addr = devm_ioremap_resource(dev, res);
|
if (!res) {
|
||||||
|
dev_err(dev, "Resource ring_csr not defined\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
pdata->ring_csr_addr = devm_ioremap(dev, res->start,
|
||||||
|
resource_size(res));
|
||||||
if (IS_ERR(pdata->ring_csr_addr)) {
|
if (IS_ERR(pdata->ring_csr_addr)) {
|
||||||
dev_err(dev, "Unable to retrieve ENET Ring CSR region\n");
|
dev_err(dev, "Unable to retrieve ENET Ring CSR region\n");
|
||||||
return PTR_ERR(pdata->ring_csr_addr);
|
return PTR_ERR(pdata->ring_csr_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_cmd");
|
res = platform_get_resource(pdev, IORESOURCE_MEM, RES_RING_CMD);
|
||||||
pdata->ring_cmd_addr = devm_ioremap_resource(dev, res);
|
if (!res) {
|
||||||
|
dev_err(dev, "Resource ring_cmd not defined\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
pdata->ring_cmd_addr = devm_ioremap(dev, res->start,
|
||||||
|
resource_size(res));
|
||||||
if (IS_ERR(pdata->ring_cmd_addr)) {
|
if (IS_ERR(pdata->ring_cmd_addr)) {
|
||||||
dev_err(dev, "Unable to retrieve ENET Ring command region\n");
|
dev_err(dev, "Unable to retrieve ENET Ring command region\n");
|
||||||
return PTR_ERR(pdata->ring_cmd_addr);
|
return PTR_ERR(pdata->ring_cmd_addr);
|
||||||
@ -789,14 +841,12 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
|
|||||||
}
|
}
|
||||||
pdata->rx_irq = ret;
|
pdata->rx_irq = ret;
|
||||||
|
|
||||||
mac = of_get_mac_address(dev->of_node);
|
if (xgene_get_mac_address(dev, ndev->dev_addr) != ETH_ALEN)
|
||||||
if (mac)
|
|
||||||
memcpy(ndev->dev_addr, mac, ndev->addr_len);
|
|
||||||
else
|
|
||||||
eth_hw_addr_random(ndev);
|
eth_hw_addr_random(ndev);
|
||||||
|
|
||||||
memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
|
memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
|
||||||
|
|
||||||
pdata->phy_mode = of_get_phy_mode(pdev->dev.of_node);
|
pdata->phy_mode = xgene_get_phy_mode(dev);
|
||||||
if (pdata->phy_mode < 0) {
|
if (pdata->phy_mode < 0) {
|
||||||
dev_err(dev, "Unable to get phy-connection-type\n");
|
dev_err(dev, "Unable to get phy-connection-type\n");
|
||||||
return pdata->phy_mode;
|
return pdata->phy_mode;
|
||||||
@ -809,11 +859,9 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pdata->clk = devm_clk_get(&pdev->dev, NULL);
|
pdata->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
ret = IS_ERR(pdata->clk);
|
|
||||||
if (IS_ERR(pdata->clk)) {
|
if (IS_ERR(pdata->clk)) {
|
||||||
dev_err(&pdev->dev, "can't get clock\n");
|
/* Firmware may have set up the clock already. */
|
||||||
ret = PTR_ERR(pdata->clk);
|
pdata->clk = NULL;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
base_addr = pdata->base_addr;
|
base_addr = pdata->base_addr;
|
||||||
@ -924,7 +972,7 @@ static int xgene_enet_probe(struct platform_device *pdev)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
|
ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
|
||||||
if (ret) {
|
if (ret) {
|
||||||
netdev_err(ndev, "No usable DMA configuration\n");
|
netdev_err(ndev, "No usable DMA configuration\n");
|
||||||
goto err;
|
goto err;
|
||||||
@ -972,17 +1020,26 @@ static int xgene_enet_remove(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct of_device_id xgene_enet_match[] = {
|
#ifdef CONFIG_ACPI
|
||||||
|
static const struct acpi_device_id xgene_enet_acpi_match[] = {
|
||||||
|
{ "APMC0D05", },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct of_device_id xgene_enet_of_match[] = {
|
||||||
{.compatible = "apm,xgene-enet",},
|
{.compatible = "apm,xgene-enet",},
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
MODULE_DEVICE_TABLE(of, xgene_enet_match);
|
MODULE_DEVICE_TABLE(of, xgene_enet_of_match);
|
||||||
|
|
||||||
static struct platform_driver xgene_enet_driver = {
|
static struct platform_driver xgene_enet_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "xgene-enet",
|
.name = "xgene-enet",
|
||||||
.of_match_table = xgene_enet_match,
|
.of_match_table = of_match_ptr(xgene_enet_of_match),
|
||||||
|
.acpi_match_table = ACPI_PTR(xgene_enet_acpi_match),
|
||||||
},
|
},
|
||||||
.probe = xgene_enet_probe,
|
.probe = xgene_enet_probe,
|
||||||
.remove = xgene_enet_remove,
|
.remove = xgene_enet_remove,
|
||||||
|
@ -22,7 +22,10 @@
|
|||||||
#ifndef __XGENE_ENET_MAIN_H__
|
#ifndef __XGENE_ENET_MAIN_H__
|
||||||
#define __XGENE_ENET_MAIN_H__
|
#define __XGENE_ENET_MAIN_H__
|
||||||
|
|
||||||
|
#include <linux/acpi.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#include <linux/efi.h>
|
||||||
|
#include <linux/io.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <linux/of_net.h>
|
#include <linux/of_net.h>
|
||||||
#include <linux/of_mdio.h>
|
#include <linux/of_mdio.h>
|
||||||
|
Loading…
Reference in New Issue
Block a user