Commit 31fbe81f authored by David S. Miller's avatar David S. Miller

Merge branch 'qcom-emac-acpi'

Timur Tabi says:

====================
Add basic ACPI support to the Qualcomm Technologies EMAC driver

This patch series adds support to the EMAC driver for extracting addresses,
interrupts, and some _DSDs (properties) from ACPI.  The first two patches
clean up the code, and the third patch adds ACPI-specific functionality.

The first patch fixes a bug with handling the platform_device for the
internal PHY.  This phy is treated as a separate device in both DT and
ACPI, but since the platform is not released automatically when the
driver unloads, managed functions like devm_ioremap_resource cannot be
used.

The second patch replaces of_get_mac_address with its platform-independent
equivalent device_get_mac_address.

The third patch parses the ACPI tables to obtain the platform_device for
the primary EMAC node ("QCOM8070") and the internal phy node ("QCOM8071").
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 48461135 5f3d3807
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/of_mdio.h> #include <linux/of_mdio.h>
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/acpi.h>
#include "emac.h" #include "emac.h"
#include "emac-mac.h" #include "emac-mac.h"
#include "emac-phy.h" #include "emac-phy.h"
...@@ -167,7 +168,6 @@ static int emac_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val) ...@@ -167,7 +168,6 @@ static int emac_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
int emac_phy_config(struct platform_device *pdev, struct emac_adapter *adpt) int emac_phy_config(struct platform_device *pdev, struct emac_adapter *adpt)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct device_node *phy_np;
struct mii_bus *mii_bus; struct mii_bus *mii_bus;
int ret; int ret;
...@@ -183,14 +183,37 @@ int emac_phy_config(struct platform_device *pdev, struct emac_adapter *adpt) ...@@ -183,14 +183,37 @@ int emac_phy_config(struct platform_device *pdev, struct emac_adapter *adpt)
mii_bus->parent = &pdev->dev; mii_bus->parent = &pdev->dev;
mii_bus->priv = adpt; mii_bus->priv = adpt;
ret = of_mdiobus_register(mii_bus, np); if (has_acpi_companion(&pdev->dev)) {
if (ret) { u32 phy_addr;
dev_err(&pdev->dev, "could not register mdio bus\n");
return ret; ret = mdiobus_register(mii_bus);
if (ret) {
dev_err(&pdev->dev, "could not register mdio bus\n");
return ret;
}
ret = device_property_read_u32(&pdev->dev, "phy-channel",
&phy_addr);
if (ret)
/* If we can't read a valid phy address, then assume
* that there is only one phy on this mdio bus.
*/
adpt->phydev = phy_find_first(mii_bus);
else
adpt->phydev = mdiobus_get_phy(mii_bus, phy_addr);
} else {
struct device_node *phy_np;
ret = of_mdiobus_register(mii_bus, np);
if (ret) {
dev_err(&pdev->dev, "could not register mdio bus\n");
return ret;
}
phy_np = of_parse_phandle(np, "phy-handle", 0);
adpt->phydev = of_phy_find_device(phy_np);
} }
phy_np = of_parse_phandle(np, "phy-handle", 0);
adpt->phydev = of_phy_find_device(phy_np);
if (!adpt->phydev) { if (!adpt->phydev) {
dev_err(&pdev->dev, "could not find external phy\n"); dev_err(&pdev->dev, "could not find external phy\n");
mdiobus_unregister(mii_bus); mdiobus_unregister(mii_bus);
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
*/ */
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/acpi.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include "emac.h" #include "emac.h"
#include "emac-mac.h" #include "emac-mac.h"
...@@ -662,6 +663,24 @@ void emac_sgmii_reset(struct emac_adapter *adpt) ...@@ -662,6 +663,24 @@ void emac_sgmii_reset(struct emac_adapter *adpt)
clk_set_rate(adpt->clk[EMAC_CLK_HIGH_SPEED], 125000000); clk_set_rate(adpt->clk[EMAC_CLK_HIGH_SPEED], 125000000);
} }
static int emac_sgmii_acpi_match(struct device *dev, void *data)
{
static const struct acpi_device_id match_table[] = {
{
.id = "QCOM8071",
.driver_data = (kernel_ulong_t)emac_sgmii_init_v2,
},
{}
};
const struct acpi_device_id *id = acpi_match_device(match_table, dev);
emac_sgmii_initialize *initialize = data;
if (id)
*initialize = (emac_sgmii_initialize)id->driver_data;
return !!id;
}
static const struct of_device_id emac_sgmii_dt_match[] = { static const struct of_device_id emac_sgmii_dt_match[] = {
{ {
.compatible = "qcom,fsm9900-emac-sgmii", .compatible = "qcom,fsm9900-emac-sgmii",
...@@ -679,43 +698,82 @@ int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt) ...@@ -679,43 +698,82 @@ int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt)
struct platform_device *sgmii_pdev = NULL; struct platform_device *sgmii_pdev = NULL;
struct emac_phy *phy = &adpt->phy; struct emac_phy *phy = &adpt->phy;
struct resource *res; struct resource *res;
const struct of_device_id *match; int ret;
struct device_node *np;
np = of_parse_phandle(pdev->dev.of_node, "internal-phy", 0); if (has_acpi_companion(&pdev->dev)) {
if (!np) { struct device *dev;
dev_err(&pdev->dev, "missing internal-phy property\n");
return -ENODEV;
}
sgmii_pdev = of_find_device_by_node(np); dev = device_find_child(&pdev->dev, &phy->initialize,
if (!sgmii_pdev) { emac_sgmii_acpi_match);
dev_err(&pdev->dev, "invalid internal-phy property\n");
return -ENODEV;
}
match = of_match_device(emac_sgmii_dt_match, &sgmii_pdev->dev); if (!dev) {
if (!match) { dev_err(&pdev->dev, "cannot find internal phy node\n");
dev_err(&pdev->dev, "unrecognized internal phy node\n"); return -ENODEV;
return -ENODEV; }
}
sgmii_pdev = to_platform_device(dev);
} else {
const struct of_device_id *match;
struct device_node *np;
phy->initialize = (emac_sgmii_initialize)match->data; np = of_parse_phandle(pdev->dev.of_node, "internal-phy", 0);
if (!np) {
dev_err(&pdev->dev, "missing internal-phy property\n");
return -ENODEV;
}
sgmii_pdev = of_find_device_by_node(np);
if (!sgmii_pdev) {
dev_err(&pdev->dev, "invalid internal-phy property\n");
return -ENODEV;
}
match = of_match_device(emac_sgmii_dt_match, &sgmii_pdev->dev);
if (!match) {
dev_err(&pdev->dev, "unrecognized internal phy node\n");
ret = -ENODEV;
goto error_put_device;
}
phy->initialize = (emac_sgmii_initialize)match->data;
}
/* Base address is the first address */ /* Base address is the first address */
res = platform_get_resource(sgmii_pdev, IORESOURCE_MEM, 0); res = platform_get_resource(sgmii_pdev, IORESOURCE_MEM, 0);
phy->base = devm_ioremap_resource(&sgmii_pdev->dev, res); phy->base = ioremap(res->start, resource_size(res));
if (IS_ERR(phy->base)) if (IS_ERR(phy->base)) {
return PTR_ERR(phy->base); ret = PTR_ERR(phy->base);
goto error_put_device;
}
/* v2 SGMII has a per-lane digital digital, so parse it if it exists */ /* v2 SGMII has a per-lane digital digital, so parse it if it exists */
res = platform_get_resource(sgmii_pdev, IORESOURCE_MEM, 1); res = platform_get_resource(sgmii_pdev, IORESOURCE_MEM, 1);
if (res) { if (res) {
phy->digital = devm_ioremap_resource(&sgmii_pdev->dev, res); phy->digital = ioremap(res->start, resource_size(res));
if (IS_ERR(phy->base)) if (IS_ERR(phy->digital)) {
return PTR_ERR(phy->base); ret = PTR_ERR(phy->digital);
goto error_unmap_base;
}
} }
return phy->initialize(adpt); ret = phy->initialize(adpt);
if (ret)
goto error;
/* We've remapped the addresses, so we don't need the device any
* more. of_find_device_by_node() says we should release it.
*/
put_device(&sgmii_pdev->dev);
return 0;
error:
if (phy->digital)
iounmap(phy->digital);
error_unmap_base:
iounmap(phy->base);
error_put_device:
put_device(&sgmii_pdev->dev);
return ret;
} }
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/acpi.h>
#include "emac.h" #include "emac.h"
#include "emac-mac.h" #include "emac-mac.h"
#include "emac-phy.h" #include "emac-phy.h"
...@@ -531,18 +532,16 @@ static void emac_clks_teardown(struct emac_adapter *adpt) ...@@ -531,18 +532,16 @@ static void emac_clks_teardown(struct emac_adapter *adpt)
static int emac_probe_resources(struct platform_device *pdev, static int emac_probe_resources(struct platform_device *pdev,
struct emac_adapter *adpt) struct emac_adapter *adpt)
{ {
struct device_node *node = pdev->dev.of_node;
struct net_device *netdev = adpt->netdev; struct net_device *netdev = adpt->netdev;
struct resource *res; struct resource *res;
const void *maddr; char maddr[ETH_ALEN];
int ret = 0; int ret = 0;
/* get mac address */ /* get mac address */
maddr = of_get_mac_address(node); if (device_get_mac_address(&pdev->dev, maddr, ETH_ALEN))
if (!maddr)
eth_hw_addr_random(netdev);
else
ether_addr_copy(netdev->dev_addr, maddr); ether_addr_copy(netdev->dev_addr, maddr);
else
eth_hw_addr_random(netdev);
/* Core 0 interrupt */ /* Core 0 interrupt */
ret = platform_get_irq(pdev, 0); ret = platform_get_irq(pdev, 0);
...@@ -577,6 +576,16 @@ static const struct of_device_id emac_dt_match[] = { ...@@ -577,6 +576,16 @@ static const struct of_device_id emac_dt_match[] = {
{} {}
}; };
#if IS_ENABLED(CONFIG_ACPI)
static const struct acpi_device_id emac_acpi_match[] = {
{
.id = "QCOM8070",
},
{}
};
MODULE_DEVICE_TABLE(acpi, emac_acpi_match);
#endif
static int emac_probe(struct platform_device *pdev) static int emac_probe(struct platform_device *pdev)
{ {
struct net_device *netdev; struct net_device *netdev;
...@@ -723,6 +732,10 @@ static int emac_remove(struct platform_device *pdev) ...@@ -723,6 +732,10 @@ static int emac_remove(struct platform_device *pdev)
mdiobus_unregister(adpt->mii_bus); mdiobus_unregister(adpt->mii_bus);
free_netdev(netdev); free_netdev(netdev);
if (adpt->phy.digital)
iounmap(adpt->phy.digital);
iounmap(adpt->phy.base);
return 0; return 0;
} }
...@@ -732,6 +745,7 @@ static struct platform_driver emac_platform_driver = { ...@@ -732,6 +745,7 @@ static struct platform_driver emac_platform_driver = {
.driver = { .driver = {
.name = "qcom-emac", .name = "qcom-emac",
.of_match_table = emac_dt_match, .of_match_table = emac_dt_match,
.acpi_match_table = ACPI_PTR(emac_acpi_match),
}, },
}; };
......
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