config AMD_XGBE
        tristate "AMD 10GbE Ethernet driver"
-       depends on OF_NET && HAS_IOMEM
+       depends on (OF_NET || ACPI) && HAS_IOMEM
        select PHYLIB
        select AMD_XGBE_PHY
        select BITREVERSE
 
 
        DBGPR("-->xgbe_usec_to_riwt\n");
 
-       rate = clk_get_rate(pdata->sysclk);
+       rate = pdata->sysclk_rate;
 
        /*
         * Convert the input usec value to the watchdog timer value. Each
 
        DBGPR("-->xgbe_riwt_to_usec\n");
 
-       rate = clk_get_rate(pdata->sysclk);
+       rate = pdata->sysclk_rate;
 
        /*
         * Convert the input watchdog timer value to the usec value. Each
 
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_net.h>
+#include <linux/of_address.h>
 #include <linux/clk.h>
+#include <linux/property.h>
+#include <linux/acpi.h>
 
 #include "xgbe.h"
 #include "xgbe-common.h"
        xgbe_init_function_ptrs_desc(&pdata->desc_if);
 }
 
+#ifdef CONFIG_ACPI
+static int xgbe_acpi_support(struct xgbe_prv_data *pdata)
+{
+       struct acpi_device *adev = pdata->adev;
+       struct device *dev = pdata->dev;
+       u32 property;
+       acpi_handle handle;
+       acpi_status status;
+       unsigned long long data;
+       int cca;
+       int ret;
+
+       /* Obtain the system clock setting */
+       ret = device_property_read_u32(dev, XGBE_ACPI_DMA_FREQ, &property);
+       if (ret) {
+               dev_err(dev, "unable to obtain %s property\n",
+                       XGBE_ACPI_DMA_FREQ);
+               return ret;
+       }
+       pdata->sysclk_rate = property;
+
+       /* Obtain the PTP clock setting */
+       ret = device_property_read_u32(dev, XGBE_ACPI_PTP_FREQ, &property);
+       if (ret) {
+               dev_err(dev, "unable to obtain %s property\n",
+                       XGBE_ACPI_PTP_FREQ);
+               return ret;
+       }
+       pdata->ptpclk_rate = property;
+
+       /* Retrieve the device cache coherency value */
+       handle = adev->handle;
+       do {
+               status = acpi_evaluate_integer(handle, "_CCA", NULL, &data);
+               if (!ACPI_FAILURE(status)) {
+                       cca = data;
+                       break;
+               }
+
+               status = acpi_get_parent(handle, &handle);
+       } while (!ACPI_FAILURE(status));
+
+       if (ACPI_FAILURE(status)) {
+               dev_err(dev, "error obtaining acpi coherency value\n");
+               return -EINVAL;
+       }
+       pdata->coherent = !!cca;
+
+       return 0;
+}
+#else   /* CONFIG_ACPI */
+static int xgbe_acpi_support(struct xgbe_prv_data *pdata)
+{
+       return -EINVAL;
+}
+#endif  /* CONFIG_ACPI */
+
+#ifdef CONFIG_OF
+static int xgbe_of_support(struct xgbe_prv_data *pdata)
+{
+       struct device *dev = pdata->dev;
+
+       /* Obtain the system clock setting */
+       pdata->sysclk = devm_clk_get(dev, XGBE_DMA_CLOCK);
+       if (IS_ERR(pdata->sysclk)) {
+               dev_err(dev, "dma devm_clk_get failed\n");
+               return PTR_ERR(pdata->sysclk);
+       }
+       pdata->sysclk_rate = clk_get_rate(pdata->sysclk);
+
+       /* Obtain the PTP clock setting */
+       pdata->ptpclk = devm_clk_get(dev, XGBE_PTP_CLOCK);
+       if (IS_ERR(pdata->ptpclk)) {
+               dev_err(dev, "ptp devm_clk_get failed\n");
+               return PTR_ERR(pdata->ptpclk);
+       }
+       pdata->ptpclk_rate = clk_get_rate(pdata->ptpclk);
+
+       /* Retrieve the device cache coherency value */
+       pdata->coherent = of_dma_is_coherent(dev->of_node);
+
+       return 0;
+}
+#else   /* CONFIG_OF */
+static int xgbe_of_support(struct xgbe_prv_data *pdata)
+{
+       return -EINVAL;
+}
+#endif  /*CONFIG_OF */
+
 static int xgbe_probe(struct platform_device *pdev)
 {
        struct xgbe_prv_data *pdata;
        struct net_device *netdev;
        struct device *dev = &pdev->dev;
        struct resource *res;
-       const u8 *mac_addr;
+       const char *phy_mode;
        unsigned int i;
        int ret;
 
        pdata = netdev_priv(netdev);
        pdata->netdev = netdev;
        pdata->pdev = pdev;
+       pdata->adev = ACPI_COMPANION(dev);
        pdata->dev = dev;
        platform_set_drvdata(pdev, netdev);
 
        mutex_init(&pdata->rss_mutex);
        spin_lock_init(&pdata->tstamp_lock);
 
+       /* Check if we should use ACPI or DT */
+       pdata->use_acpi = (!pdata->adev || acpi_disabled) ? 0 : 1;
+
        /* Set and validate the number of descriptors for a ring */
        BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_TX_DESC_CNT);
        pdata->tx_desc_count = XGBE_TX_DESC_CNT;
                goto err_io;
        }
 
-       /* Obtain the system clock setting */
-       pdata->sysclk = devm_clk_get(dev, XGBE_DMA_CLOCK);
-       if (IS_ERR(pdata->sysclk)) {
-               dev_err(dev, "dma devm_clk_get failed\n");
-               ret = PTR_ERR(pdata->sysclk);
-               goto err_io;
-       }
-
-       /* Obtain the PTP clock setting */
-       pdata->ptpclk = devm_clk_get(dev, XGBE_PTP_CLOCK);
-       if (IS_ERR(pdata->ptpclk)) {
-               dev_err(dev, "ptp devm_clk_get failed\n");
-               ret = PTR_ERR(pdata->ptpclk);
-               goto err_io;
-       }
-
        /* Obtain the mmio areas for the device */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        pdata->xgmac_regs = devm_ioremap_resource(dev, res);
        }
        DBGPR("  xpcs_regs  = %p\n", pdata->xpcs_regs);
 
-       /* Set the DMA mask */
-       if (!dev->dma_mask)
-               dev->dma_mask = &dev->coherent_dma_mask;
-       ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
-       if (ret) {
-               dev_err(dev, "dma_set_mask_and_coherent failed\n");
+       /* Retrieve the MAC address */
+       ret = device_property_read_u8_array(dev, XGBE_MAC_ADDR_PROPERTY,
+                                           pdata->mac_addr,
+                                           sizeof(pdata->mac_addr));
+       if (ret || !is_valid_ether_addr(pdata->mac_addr)) {
+               dev_err(dev, "invalid %s property\n", XGBE_MAC_ADDR_PROPERTY);
+               if (!ret)
+                       ret = -EINVAL;
                goto err_io;
        }
 
-       if (of_property_read_bool(dev->of_node, "dma-coherent")) {
+       /* Retrieve the PHY mode - it must be "xgmii" */
+       ret = device_property_read_string(dev, XGBE_PHY_MODE_PROPERTY,
+                                         &phy_mode);
+       if (ret || strcmp(phy_mode, phy_modes(PHY_INTERFACE_MODE_XGMII))) {
+               dev_err(dev, "invalid %s property\n", XGBE_PHY_MODE_PROPERTY);
+               if (!ret)
+                       ret = -EINVAL;
+               goto err_io;
+       }
+       pdata->phy_mode = PHY_INTERFACE_MODE_XGMII;
+
+       /* Check for per channel interrupt support */
+       if (device_property_present(dev, XGBE_DMA_IRQS_PROPERTY))
+               pdata->per_channel_irq = 1;
+
+       /* Obtain device settings unique to ACPI/OF */
+       if (pdata->use_acpi)
+               ret = xgbe_acpi_support(pdata);
+       else
+               ret = xgbe_of_support(pdata);
+       if (ret)
+               goto err_io;
+
+       /* Set the DMA coherency values */
+       if (pdata->coherent) {
                pdata->axdomain = XGBE_DMA_OS_AXDOMAIN;
                pdata->arcache = XGBE_DMA_OS_ARCACHE;
                pdata->awcache = XGBE_DMA_OS_AWCACHE;
                pdata->awcache = XGBE_DMA_SYS_AWCACHE;
        }
 
-       /* Check for per channel interrupt support */
-       if (of_property_read_bool(dev->of_node, XGBE_DMA_IRQS))
-               pdata->per_channel_irq = 1;
+       /* Set the DMA mask */
+       if (!dev->dma_mask)
+               dev->dma_mask = &dev->coherent_dma_mask;
+       ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
+       if (ret) {
+               dev_err(dev, "dma_set_mask_and_coherent failed\n");
+               goto err_io;
+       }
 
+       /* Get the device interrupt */
        ret = platform_get_irq(pdev, 0);
        if (ret < 0) {
                dev_err(dev, "platform_get_irq 0 failed\n");
 
        netdev->irq = pdata->dev_irq;
        netdev->base_addr = (unsigned long)pdata->xgmac_regs;
+       memcpy(netdev->dev_addr, pdata->mac_addr, netdev->addr_len);
 
        /* Set all the function pointers */
        xgbe_init_all_fptrs(pdata);
        /* Populate the hardware features */
        xgbe_get_all_hw_features(pdata);
 
-       /* Retrieve the MAC address */
-       mac_addr = of_get_mac_address(dev->of_node);
-       if (!mac_addr) {
-               dev_err(dev, "invalid mac address for this device\n");
-               ret = -EINVAL;
-               goto err_io;
-       }
-       memcpy(netdev->dev_addr, mac_addr, netdev->addr_len);
-
-       /* Retrieve the PHY mode - it must be "xgmii" */
-       pdata->phy_mode = of_get_phy_mode(dev->of_node);
-       if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) {
-               dev_err(dev, "invalid phy-mode specified for this device\n");
-               ret = -EINVAL;
-               goto err_io;
-       }
-
        /* Set default configuration data */
        xgbe_default_config(pdata);
 
 }
 #endif /* CONFIG_PM */
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id xgbe_acpi_match[] = {
+       { "AMDI8001", 0 },
+       {},
+};
+
+MODULE_DEVICE_TABLE(acpi, xgbe_acpi_match);
+#endif
+
+#ifdef CONFIG_OF
 static const struct of_device_id xgbe_of_match[] = {
        { .compatible = "amd,xgbe-seattle-v1a", },
        {},
 };
 
 MODULE_DEVICE_TABLE(of, xgbe_of_match);
+#endif
+
 static SIMPLE_DEV_PM_OPS(xgbe_pm_ops, xgbe_suspend, xgbe_resume);
 
 static struct platform_driver xgbe_driver = {
        .driver = {
                .name = "amd-xgbe",
+#ifdef CONFIG_ACPI
+               .acpi_match_table = xgbe_acpi_match,
+#endif
+#ifdef CONFIG_OF
                .of_match_table = xgbe_of_match,
+#endif
                .pm = &xgbe_pm_ops,
        },
        .probe = xgbe_probe,
 
 
 int xgbe_mdio_register(struct xgbe_prv_data *pdata)
 {
-       struct device_node *phy_node;
        struct mii_bus *mii;
        struct phy_device *phydev;
        int ret = 0;
 
        DBGPR("-->xgbe_mdio_register\n");
 
-       /* Retrieve the phy-handle */
-       phy_node = of_parse_phandle(pdata->dev->of_node, "phy-handle", 0);
-       if (!phy_node) {
-               dev_err(pdata->dev, "unable to parse phy-handle\n");
-               return -EINVAL;
-       }
-
        mii = mdiobus_alloc();
        if (!mii) {
                dev_err(pdata->dev, "mdiobus_alloc failed\n");
-               ret = -ENOMEM;
-               goto err_node_get;
+               return -ENOMEM;
        }
 
        /* Register on the MDIO bus (don't probe any PHYs) */
        request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT,
                       MDIO_ID_ARGS(phydev->c45_ids.device_ids[MDIO_MMD_PCS]));
 
-       of_node_get(phy_node);
-       phydev->dev.of_node = phy_node;
        ret = phy_device_register(phydev);
        if (ret) {
                dev_err(pdata->dev, "phy_device_register failed\n");
-               of_node_put(phy_node);
                goto err_phy_device;
        }
        if (!phydev->dev.driver) {
 
        pdata->phydev = phydev;
 
-       of_node_put(phy_node);
-
        DBGPHY_REGS(pdata);
 
        DBGPR("<--xgbe_mdio_register\n");
 err_mdiobus_alloc:
        mdiobus_free(mii);
 
-err_node_get:
-       of_node_put(phy_node);
-
        return ret;
 }
 
 
        snprintf(info->name, sizeof(info->name), "%s",
                 netdev_name(pdata->netdev));
        info->owner = THIS_MODULE;
-       info->max_adj = clk_get_rate(pdata->ptpclk);
+       info->max_adj = pdata->ptpclk_rate;
        info->adjfreq = xgbe_adjfreq;
        info->adjtime = xgbe_adjtime;
        info->gettime = xgbe_gettime;
         */
        dividend = 50000000;
        dividend <<= 32;
-       pdata->tstamp_addend = div_u64(dividend, clk_get_rate(pdata->ptpclk));
+       pdata->tstamp_addend = div_u64(dividend, pdata->ptpclk_rate);
 
        /* Setup the timecounter */
        cc->read = xgbe_cc_read;
 
 #define XGBE_PHY_NAME          "amd_xgbe_phy"
 #define XGBE_PRTAD             0
 
+/* Common property names */
+#define XGBE_MAC_ADDR_PROPERTY "mac-address"
+#define XGBE_PHY_MODE_PROPERTY "phy-mode"
+#define XGBE_DMA_IRQS_PROPERTY "amd,per-channel-interrupt"
+
 /* Device-tree clock names */
 #define XGBE_DMA_CLOCK         "dma_clk"
 #define XGBE_PTP_CLOCK         "ptp_clk"
-#define XGBE_DMA_IRQS          "amd,per-channel-interrupt"
+
+/* ACPI property names */
+#define XGBE_ACPI_DMA_FREQ     "amd,dma-freq"
+#define XGBE_ACPI_PTP_FREQ     "amd,ptp-freq"
 
 /* Timestamp support - values based on 50MHz PTP clock
  *   50MHz => 20 nsec
 struct xgbe_prv_data {
        struct net_device *netdev;
        struct platform_device *pdev;
+       struct acpi_device *adev;
        struct device *dev;
 
+       /* ACPI or DT flag */
+       unsigned int use_acpi;
+
        /* XGMAC/XPCS related mmio registers */
        void __iomem *xgmac_regs;       /* XGMAC CSRs */
        void __iomem *xpcs_regs;        /* XPCS MMD registers */
        struct xgbe_desc_if desc_if;
 
        /* AXI DMA settings */
+       unsigned int coherent;
        unsigned int axdomain;
        unsigned int arcache;
        unsigned int awcache;
        unsigned int phy_rx_pause;
 
        /* Netdev related settings */
+       unsigned char mac_addr[ETH_ALEN];
        netdev_features_t netdev_features;
        struct napi_struct napi;
        struct xgbe_mmc_stats mmc_stats;
 
        /* Device clocks */
        struct clk *sysclk;
+       unsigned long sysclk_rate;
        struct clk *ptpclk;
+       unsigned long ptpclk_rate;
 
        /* Timestamp support */
        spinlock_t tstamp_lock;
 
 
 config AMD_XGBE_PHY
        tristate "Driver for the AMD 10GbE (amd-xgbe) PHYs"
-       depends on OF && HAS_IOMEM
+       depends on (OF || ACPI) && HAS_IOMEM
        ---help---
          Currently supports the AMD 10GbE PHY
 
 
 #include <linux/of_device.h>
 #include <linux/uaccess.h>
 #include <linux/bitops.h>
+#include <linux/property.h>
+#include <linux/acpi.h>
 
 MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>");
 MODULE_LICENSE("Dual BSD/GPL");
 };
 
 enum amd_xgbe_phy_speedset {
-       AMD_XGBE_PHY_SPEEDSET_1000_10000,
+       AMD_XGBE_PHY_SPEEDSET_1000_10000 = 0,
        AMD_XGBE_PHY_SPEEDSET_2500_10000,
 };
 
 struct amd_xgbe_phy_priv {
        struct platform_device *pdev;
+       struct acpi_device *adev;
        struct device *dev;
 
        struct phy_device *phydev;
        return 0;
 }
 
+static unsigned int amd_xgbe_phy_resource_count(struct platform_device *pdev,
+                                               unsigned int type)
+{
+       unsigned int count;
+       int i;
+
+       for (i = 0, count = 0; i < pdev->num_resources; i++) {
+               struct resource *r = &pdev->resource[i];
+
+               if (type == resource_type(r))
+                       count++;
+       }
+
+       return count;
+}
+
 static int amd_xgbe_phy_probe(struct phy_device *phydev)
 {
        struct amd_xgbe_phy_priv *priv;
-       struct platform_device *pdev;
-       struct device *dev;
-       const __be32 *property;
-       unsigned int speed_set;
+       struct platform_device *phy_pdev;
+       struct device *dev, *phy_dev;
+       unsigned int phy_resnum, phy_irqnum;
        int ret;
 
-       if (!phydev->dev.of_node)
+       if (!phydev->bus || !phydev->bus->parent)
                return -EINVAL;
 
-       pdev = of_find_device_by_node(phydev->dev.of_node);
-       if (!pdev)
-               return -EINVAL;
-       dev = &pdev->dev;
+       dev = phydev->bus->parent;
 
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv) {
-               ret = -ENOMEM;
-               goto err_pdev;
-       }
+       if (!priv)
+               return -ENOMEM;
 
-       priv->pdev = pdev;
+       priv->pdev = to_platform_device(dev);
+       priv->adev = ACPI_COMPANION(dev);
        priv->dev = dev;
        priv->phydev = phydev;
        mutex_init(&priv->an_mutex);
        INIT_WORK(&priv->an_irq_work, amd_xgbe_an_irq_work);
        INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine);
 
+       if (!priv->adev || acpi_disabled) {
+               struct device_node *bus_node;
+               struct device_node *phy_node;
+
+               bus_node = priv->dev->of_node;
+               phy_node = of_parse_phandle(bus_node, "phy-handle", 0);
+               if (!phy_node) {
+                       dev_err(dev, "unable to parse phy-handle\n");
+                       ret = -EINVAL;
+                       goto err_priv;
+               }
+
+               phy_pdev = of_find_device_by_node(phy_node);
+               of_node_put(phy_node);
+
+               if (!phy_pdev) {
+                       dev_err(dev, "unable to obtain phy device\n");
+                       ret = -EINVAL;
+                       goto err_priv;
+               }
+
+               phy_resnum = 0;
+               phy_irqnum = 0;
+       } else {
+               /* In ACPI, the XGBE and PHY resources are the grouped
+                * together with the PHY resources at the end
+                */
+               phy_pdev = priv->pdev;
+               phy_resnum = amd_xgbe_phy_resource_count(phy_pdev,
+                                                        IORESOURCE_MEM) - 3;
+               phy_irqnum = amd_xgbe_phy_resource_count(phy_pdev,
+                                                        IORESOURCE_IRQ) - 1;
+       }
+       phy_dev = &phy_pdev->dev;
+
        /* Get the device mmio areas */
-       priv->rxtx_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       priv->rxtx_res = platform_get_resource(phy_pdev, IORESOURCE_MEM,
+                                              phy_resnum++);
        priv->rxtx_regs = devm_ioremap_resource(dev, priv->rxtx_res);
        if (IS_ERR(priv->rxtx_regs)) {
                dev_err(dev, "rxtx ioremap failed\n");
                ret = PTR_ERR(priv->rxtx_regs);
-               goto err_priv;
+               goto err_put;
        }
 
-       priv->sir0_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       priv->sir0_res = platform_get_resource(phy_pdev, IORESOURCE_MEM,
+                                              phy_resnum++);
        priv->sir0_regs = devm_ioremap_resource(dev, priv->sir0_res);
        if (IS_ERR(priv->sir0_regs)) {
                dev_err(dev, "sir0 ioremap failed\n");
                goto err_rxtx;
        }
 
-       priv->sir1_res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+       priv->sir1_res = platform_get_resource(phy_pdev, IORESOURCE_MEM,
+                                              phy_resnum++);
        priv->sir1_regs = devm_ioremap_resource(dev, priv->sir1_res);
        if (IS_ERR(priv->sir1_regs)) {
                dev_err(dev, "sir1 ioremap failed\n");
        }
 
        /* Get the auto-negotiation interrupt */
-       ret = platform_get_irq(pdev, 0);
+       ret = platform_get_irq(phy_pdev, phy_irqnum);
        if (ret < 0) {
                dev_err(dev, "platform_get_irq failed\n");
                goto err_sir1;
        priv->an_irq = ret;
 
        /* Get the device speed set property */
-       speed_set = 0;
-       property = of_get_property(dev->of_node, XGBE_PHY_SPEEDSET_PROPERTY,
-                                  NULL);
-       if (property)
-               speed_set = be32_to_cpu(*property);
-
-       switch (speed_set) {
-       case 0:
-               priv->speed_set = AMD_XGBE_PHY_SPEEDSET_1000_10000;
-               break;
-       case 1:
-               priv->speed_set = AMD_XGBE_PHY_SPEEDSET_2500_10000;
+       ret = device_property_read_u32(phy_dev, XGBE_PHY_SPEEDSET_PROPERTY,
+                                      &priv->speed_set);
+       if (ret) {
+               dev_err(dev, "invalid %s property\n",
+                       XGBE_PHY_SPEEDSET_PROPERTY);
+               goto err_sir1;
+       }
+
+       switch (priv->speed_set) {
+       case AMD_XGBE_PHY_SPEEDSET_1000_10000:
+       case AMD_XGBE_PHY_SPEEDSET_2500_10000:
                break;
        default:
-               dev_err(dev, "invalid amd,speed-set property\n");
+               dev_err(dev, "invalid %s property\n",
+                       XGBE_PHY_SPEEDSET_PROPERTY);
                ret = -EINVAL;
                goto err_sir1;
        }
 
        phydev->priv = priv;
 
-       of_dev_put(pdev);
+       if (!priv->adev || acpi_disabled)
+               platform_device_put(phy_pdev);
 
        return 0;
 
        devm_release_mem_region(dev, priv->rxtx_res->start,
                                resource_size(priv->rxtx_res));
 
+err_put:
+       if (!priv->adev || acpi_disabled)
+               platform_device_put(phy_pdev);
+
 err_priv:
        devm_kfree(dev, priv);
 
-err_pdev:
-       of_dev_put(pdev);
-
        return ret;
 }