aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2016-09-29 01:50:20 -0400
committerDavid S. Miller <davem@davemloft.net>2016-09-29 01:50:20 -0400
commit31fbe81fe3426dfb7f8056a7f5106c6b1841a9aa (patch)
tree45498ce13c16891134fde2b82b3d0eb93315e1f5
parent484611357c19f9e19ef742ebef4505a07d243cc9 (diff)
parent5f3d38078c84f7bc12739a3b79fc59797cf0262d (diff)
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: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac-phy.c37
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac-sgmii.c110
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac.c26
3 files changed, 134 insertions, 39 deletions
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-phy.c b/drivers/net/ethernet/qualcomm/emac/emac-phy.c
index c412ba9a27e7..da4e90db4d98 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac-phy.c
+++ b/drivers/net/ethernet/qualcomm/emac/emac-phy.c
@@ -19,6 +19,7 @@
19#include <linux/of_mdio.h> 19#include <linux/of_mdio.h>
20#include <linux/phy.h> 20#include <linux/phy.h>
21#include <linux/iopoll.h> 21#include <linux/iopoll.h>
22#include <linux/acpi.h>
22#include "emac.h" 23#include "emac.h"
23#include "emac-mac.h" 24#include "emac-mac.h"
24#include "emac-phy.h" 25#include "emac-phy.h"
@@ -167,7 +168,6 @@ static int emac_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
167int emac_phy_config(struct platform_device *pdev, struct emac_adapter *adpt) 168int emac_phy_config(struct platform_device *pdev, struct emac_adapter *adpt)
168{ 169{
169 struct device_node *np = pdev->dev.of_node; 170 struct device_node *np = pdev->dev.of_node;
170 struct device_node *phy_np;
171 struct mii_bus *mii_bus; 171 struct mii_bus *mii_bus;
172 int ret; 172 int ret;
173 173
@@ -183,14 +183,37 @@ int emac_phy_config(struct platform_device *pdev, struct emac_adapter *adpt)
183 mii_bus->parent = &pdev->dev; 183 mii_bus->parent = &pdev->dev;
184 mii_bus->priv = adpt; 184 mii_bus->priv = adpt;
185 185
186 ret = of_mdiobus_register(mii_bus, np); 186 if (has_acpi_companion(&pdev->dev)) {
187 if (ret) { 187 u32 phy_addr;
188 dev_err(&pdev->dev, "could not register mdio bus\n"); 188
189 return ret; 189 ret = mdiobus_register(mii_bus);
190 if (ret) {
191 dev_err(&pdev->dev, "could not register mdio bus\n");
192 return ret;
193 }
194 ret = device_property_read_u32(&pdev->dev, "phy-channel",
195 &phy_addr);
196 if (ret)
197 /* If we can't read a valid phy address, then assume
198 * that there is only one phy on this mdio bus.
199 */
200 adpt->phydev = phy_find_first(mii_bus);
201 else
202 adpt->phydev = mdiobus_get_phy(mii_bus, phy_addr);
203
204 } else {
205 struct device_node *phy_np;
206
207 ret = of_mdiobus_register(mii_bus, np);
208 if (ret) {
209 dev_err(&pdev->dev, "could not register mdio bus\n");
210 return ret;
211 }
212
213 phy_np = of_parse_phandle(np, "phy-handle", 0);
214 adpt->phydev = of_phy_find_device(phy_np);
190 } 215 }
191 216
192 phy_np = of_parse_phandle(np, "phy-handle", 0);
193 adpt->phydev = of_phy_find_device(phy_np);
194 if (!adpt->phydev) { 217 if (!adpt->phydev) {
195 dev_err(&pdev->dev, "could not find external phy\n"); 218 dev_err(&pdev->dev, "could not find external phy\n");
196 mdiobus_unregister(mii_bus); 219 mdiobus_unregister(mii_bus);
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
index 6ab0a3c96431..3d2c05a40d2c 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
+++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
@@ -14,6 +14,7 @@
14 */ 14 */
15 15
16#include <linux/iopoll.h> 16#include <linux/iopoll.h>
17#include <linux/acpi.h>
17#include <linux/of_device.h> 18#include <linux/of_device.h>
18#include "emac.h" 19#include "emac.h"
19#include "emac-mac.h" 20#include "emac-mac.h"
@@ -662,6 +663,24 @@ void emac_sgmii_reset(struct emac_adapter *adpt)
662 clk_set_rate(adpt->clk[EMAC_CLK_HIGH_SPEED], 125000000); 663 clk_set_rate(adpt->clk[EMAC_CLK_HIGH_SPEED], 125000000);
663} 664}
664 665
666static int emac_sgmii_acpi_match(struct device *dev, void *data)
667{
668 static const struct acpi_device_id match_table[] = {
669 {
670 .id = "QCOM8071",
671 .driver_data = (kernel_ulong_t)emac_sgmii_init_v2,
672 },
673 {}
674 };
675 const struct acpi_device_id *id = acpi_match_device(match_table, dev);
676 emac_sgmii_initialize *initialize = data;
677
678 if (id)
679 *initialize = (emac_sgmii_initialize)id->driver_data;
680
681 return !!id;
682}
683
665static const struct of_device_id emac_sgmii_dt_match[] = { 684static const struct of_device_id emac_sgmii_dt_match[] = {
666 { 685 {
667 .compatible = "qcom,fsm9900-emac-sgmii", 686 .compatible = "qcom,fsm9900-emac-sgmii",
@@ -679,43 +698,82 @@ int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt)
679 struct platform_device *sgmii_pdev = NULL; 698 struct platform_device *sgmii_pdev = NULL;
680 struct emac_phy *phy = &adpt->phy; 699 struct emac_phy *phy = &adpt->phy;
681 struct resource *res; 700 struct resource *res;
682 const struct of_device_id *match; 701 int ret;
683 struct device_node *np;
684 702
685 np = of_parse_phandle(pdev->dev.of_node, "internal-phy", 0); 703 if (has_acpi_companion(&pdev->dev)) {
686 if (!np) { 704 struct device *dev;
687 dev_err(&pdev->dev, "missing internal-phy property\n");
688 return -ENODEV;
689 }
690 705
691 sgmii_pdev = of_find_device_by_node(np); 706 dev = device_find_child(&pdev->dev, &phy->initialize,
692 if (!sgmii_pdev) { 707 emac_sgmii_acpi_match);
693 dev_err(&pdev->dev, "invalid internal-phy property\n");
694 return -ENODEV;
695 }
696 708
697 match = of_match_device(emac_sgmii_dt_match, &sgmii_pdev->dev); 709 if (!dev) {
698 if (!match) { 710 dev_err(&pdev->dev, "cannot find internal phy node\n");
699 dev_err(&pdev->dev, "unrecognized internal phy node\n"); 711 return -ENODEV;
700 return -ENODEV; 712 }
701 } 713
714 sgmii_pdev = to_platform_device(dev);
715 } else {
716 const struct of_device_id *match;
717 struct device_node *np;
702 718
703 phy->initialize = (emac_sgmii_initialize)match->data; 719 np = of_parse_phandle(pdev->dev.of_node, "internal-phy", 0);
720 if (!np) {
721 dev_err(&pdev->dev, "missing internal-phy property\n");
722 return -ENODEV;
723 }
724
725 sgmii_pdev = of_find_device_by_node(np);
726 if (!sgmii_pdev) {
727 dev_err(&pdev->dev, "invalid internal-phy property\n");
728 return -ENODEV;
729 }
730
731 match = of_match_device(emac_sgmii_dt_match, &sgmii_pdev->dev);
732 if (!match) {
733 dev_err(&pdev->dev, "unrecognized internal phy node\n");
734 ret = -ENODEV;
735 goto error_put_device;
736 }
737
738 phy->initialize = (emac_sgmii_initialize)match->data;
739 }
704 740
705 /* Base address is the first address */ 741 /* Base address is the first address */
706 res = platform_get_resource(sgmii_pdev, IORESOURCE_MEM, 0); 742 res = platform_get_resource(sgmii_pdev, IORESOURCE_MEM, 0);
707 phy->base = devm_ioremap_resource(&sgmii_pdev->dev, res); 743 phy->base = ioremap(res->start, resource_size(res));
708 if (IS_ERR(phy->base)) 744 if (IS_ERR(phy->base)) {
709 return PTR_ERR(phy->base); 745 ret = PTR_ERR(phy->base);
746 goto error_put_device;
747 }
710 748
711 /* v2 SGMII has a per-lane digital digital, so parse it if it exists */ 749 /* v2 SGMII has a per-lane digital digital, so parse it if it exists */
712 res = platform_get_resource(sgmii_pdev, IORESOURCE_MEM, 1); 750 res = platform_get_resource(sgmii_pdev, IORESOURCE_MEM, 1);
713 if (res) { 751 if (res) {
714 phy->digital = devm_ioremap_resource(&sgmii_pdev->dev, res); 752 phy->digital = ioremap(res->start, resource_size(res));
715 if (IS_ERR(phy->base)) 753 if (IS_ERR(phy->digital)) {
716 return PTR_ERR(phy->base); 754 ret = PTR_ERR(phy->digital);
717 755 goto error_unmap_base;
756 }
718 } 757 }
719 758
720 return phy->initialize(adpt); 759 ret = phy->initialize(adpt);
760 if (ret)
761 goto error;
762
763 /* We've remapped the addresses, so we don't need the device any
764 * more. of_find_device_by_node() says we should release it.
765 */
766 put_device(&sgmii_pdev->dev);
767
768 return 0;
769
770error:
771 if (phy->digital)
772 iounmap(phy->digital);
773error_unmap_base:
774 iounmap(phy->base);
775error_put_device:
776 put_device(&sgmii_pdev->dev);
777
778 return ret;
721} 779}
diff --git a/drivers/net/ethernet/qualcomm/emac/emac.c b/drivers/net/ethernet/qualcomm/emac/emac.c
index e47d38701d6c..9bf3b2b82e95 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac.c
+++ b/drivers/net/ethernet/qualcomm/emac/emac.c
@@ -22,6 +22,7 @@
22#include <linux/of_device.h> 22#include <linux/of_device.h>
23#include <linux/phy.h> 23#include <linux/phy.h>
24#include <linux/platform_device.h> 24#include <linux/platform_device.h>
25#include <linux/acpi.h>
25#include "emac.h" 26#include "emac.h"
26#include "emac-mac.h" 27#include "emac-mac.h"
27#include "emac-phy.h" 28#include "emac-phy.h"
@@ -531,18 +532,16 @@ static void emac_clks_teardown(struct emac_adapter *adpt)
531static int emac_probe_resources(struct platform_device *pdev, 532static int emac_probe_resources(struct platform_device *pdev,
532 struct emac_adapter *adpt) 533 struct emac_adapter *adpt)
533{ 534{
534 struct device_node *node = pdev->dev.of_node;
535 struct net_device *netdev = adpt->netdev; 535 struct net_device *netdev = adpt->netdev;
536 struct resource *res; 536 struct resource *res;
537 const void *maddr; 537 char maddr[ETH_ALEN];
538 int ret = 0; 538 int ret = 0;
539 539
540 /* get mac address */ 540 /* get mac address */
541 maddr = of_get_mac_address(node); 541 if (device_get_mac_address(&pdev->dev, maddr, ETH_ALEN))
542 if (!maddr)
543 eth_hw_addr_random(netdev);
544 else
545 ether_addr_copy(netdev->dev_addr, maddr); 542 ether_addr_copy(netdev->dev_addr, maddr);
543 else
544 eth_hw_addr_random(netdev);
546 545
547 /* Core 0 interrupt */ 546 /* Core 0 interrupt */
548 ret = platform_get_irq(pdev, 0); 547 ret = platform_get_irq(pdev, 0);
@@ -577,6 +576,16 @@ static const struct of_device_id emac_dt_match[] = {
577 {} 576 {}
578}; 577};
579 578
579#if IS_ENABLED(CONFIG_ACPI)
580static const struct acpi_device_id emac_acpi_match[] = {
581 {
582 .id = "QCOM8070",
583 },
584 {}
585};
586MODULE_DEVICE_TABLE(acpi, emac_acpi_match);
587#endif
588
580static int emac_probe(struct platform_device *pdev) 589static int emac_probe(struct platform_device *pdev)
581{ 590{
582 struct net_device *netdev; 591 struct net_device *netdev;
@@ -723,6 +732,10 @@ static int emac_remove(struct platform_device *pdev)
723 mdiobus_unregister(adpt->mii_bus); 732 mdiobus_unregister(adpt->mii_bus);
724 free_netdev(netdev); 733 free_netdev(netdev);
725 734
735 if (adpt->phy.digital)
736 iounmap(adpt->phy.digital);
737 iounmap(adpt->phy.base);
738
726 return 0; 739 return 0;
727} 740}
728 741
@@ -732,6 +745,7 @@ static struct platform_driver emac_platform_driver = {
732 .driver = { 745 .driver = {
733 .name = "qcom-emac", 746 .name = "qcom-emac",
734 .of_match_table = emac_dt_match, 747 .of_match_table = emac_dt_match,
748 .acpi_match_table = ACPI_PTR(emac_acpi_match),
735 }, 749 },
736}; 750};
737 751