diff options
author | Feng Kan <fkan@apm.com> | 2015-01-06 17:41:33 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-01-06 17:43:13 -0500 |
commit | de7b5b3d790a2524c3f992d357983600635c441b (patch) | |
tree | b5928d566a4f526d535fbf0983b987e56840b2f7 | |
parent | 1fcf77c87ad659a92e1dcfb883388cb43baeaab6 (diff) |
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>
-rw-r--r-- | drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 94 | ||||
-rw-r--r-- | drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 97 | ||||
-rw-r--r-- | drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 3 |
3 files changed, 150 insertions, 44 deletions
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 7ba83ffb08ac..869d97fcf781 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | |||
@@ -593,10 +593,12 @@ static int xgene_enet_reset(struct xgene_enet_pdata *pdata) | |||
593 | if (!xgene_ring_mgr_init(pdata)) | 593 | if (!xgene_ring_mgr_init(pdata)) |
594 | return -ENODEV; | 594 | return -ENODEV; |
595 | 595 | ||
596 | clk_prepare_enable(pdata->clk); | 596 | if (!efi_enabled(EFI_BOOT)) { |
597 | clk_disable_unprepare(pdata->clk); | 597 | clk_prepare_enable(pdata->clk); |
598 | clk_prepare_enable(pdata->clk); | 598 | clk_disable_unprepare(pdata->clk); |
599 | xgene_enet_ecc_init(pdata); | 599 | clk_prepare_enable(pdata->clk); |
600 | xgene_enet_ecc_init(pdata); | ||
601 | } | ||
600 | xgene_enet_config_ring_if_assoc(pdata); | 602 | xgene_enet_config_ring_if_assoc(pdata); |
601 | 603 | ||
602 | /* Enable auto-incr for scanning */ | 604 | /* Enable auto-incr for scanning */ |
@@ -663,15 +665,20 @@ static int xgene_enet_phy_connect(struct net_device *ndev) | |||
663 | struct phy_device *phy_dev; | 665 | struct phy_device *phy_dev; |
664 | struct device *dev = &pdata->pdev->dev; | 666 | struct device *dev = &pdata->pdev->dev; |
665 | 667 | ||
666 | phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0); | 668 | if (dev->of_node) { |
667 | if (!phy_np) { | 669 | phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0); |
668 | netdev_dbg(ndev, "No phy-handle found\n"); | 670 | if (!phy_np) { |
669 | return -ENODEV; | 671 | netdev_dbg(ndev, "No phy-handle found in DT\n"); |
672 | return -ENODEV; | ||
673 | } | ||
674 | pdata->phy_dev = of_phy_find_device(phy_np); | ||
670 | } | 675 | } |
671 | 676 | ||
672 | phy_dev = of_phy_connect(ndev, phy_np, &xgene_enet_adjust_link, | 677 | phy_dev = pdata->phy_dev; |
673 | 0, pdata->phy_mode); | 678 | |
674 | if (!phy_dev) { | 679 | if (!phy_dev || |
680 | phy_connect_direct(ndev, phy_dev, &xgene_enet_adjust_link, | ||
681 | pdata->phy_mode)) { | ||
675 | netdev_err(ndev, "Could not connect to PHY\n"); | 682 | netdev_err(ndev, "Could not connect to PHY\n"); |
676 | return -ENODEV; | 683 | return -ENODEV; |
677 | } | 684 | } |
@@ -681,32 +688,71 @@ static int xgene_enet_phy_connect(struct net_device *ndev) | |||
681 | ~SUPPORTED_100baseT_Half & | 688 | ~SUPPORTED_100baseT_Half & |
682 | ~SUPPORTED_1000baseT_Half; | 689 | ~SUPPORTED_1000baseT_Half; |
683 | phy_dev->advertising = phy_dev->supported; | 690 | phy_dev->advertising = phy_dev->supported; |
684 | pdata->phy_dev = phy_dev; | ||
685 | 691 | ||
686 | return 0; | 692 | return 0; |
687 | } | 693 | } |
688 | 694 | ||
689 | int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) | 695 | static int xgene_mdiobus_register(struct xgene_enet_pdata *pdata, |
696 | struct mii_bus *mdio) | ||
690 | { | 697 | { |
691 | struct net_device *ndev = pdata->ndev; | ||
692 | struct device *dev = &pdata->pdev->dev; | 698 | struct device *dev = &pdata->pdev->dev; |
699 | struct net_device *ndev = pdata->ndev; | ||
700 | struct phy_device *phy; | ||
693 | struct device_node *child_np; | 701 | struct device_node *child_np; |
694 | struct device_node *mdio_np = NULL; | 702 | struct device_node *mdio_np = NULL; |
695 | struct mii_bus *mdio_bus; | ||
696 | int ret; | 703 | int ret; |
704 | u32 phy_id; | ||
705 | |||
706 | if (dev->of_node) { | ||
707 | for_each_child_of_node(dev->of_node, child_np) { | ||
708 | if (of_device_is_compatible(child_np, | ||
709 | "apm,xgene-mdio")) { | ||
710 | mdio_np = child_np; | ||
711 | break; | ||
712 | } | ||
713 | } | ||
697 | 714 | ||
698 | for_each_child_of_node(dev->of_node, child_np) { | 715 | if (!mdio_np) { |
699 | if (of_device_is_compatible(child_np, "apm,xgene-mdio")) { | 716 | netdev_dbg(ndev, "No mdio node in the dts\n"); |
700 | mdio_np = child_np; | 717 | return -ENXIO; |
701 | break; | ||
702 | } | 718 | } |
703 | } | ||
704 | 719 | ||
705 | if (!mdio_np) { | 720 | return of_mdiobus_register(mdio, mdio_np); |
706 | netdev_dbg(ndev, "No mdio node in the dts\n"); | ||
707 | return -ENXIO; | ||
708 | } | 721 | } |
709 | 722 | ||
723 | /* Mask out all PHYs from auto probing. */ | ||
724 | mdio->phy_mask = ~0; | ||
725 | |||
726 | /* Register the MDIO bus */ | ||
727 | ret = mdiobus_register(mdio); | ||
728 | if (ret) | ||
729 | return ret; | ||
730 | |||
731 | ret = device_property_read_u32(dev, "phy-channel", &phy_id); | ||
732 | if (ret) | ||
733 | ret = device_property_read_u32(dev, "phy-addr", &phy_id); | ||
734 | if (ret) | ||
735 | return -EINVAL; | ||
736 | |||
737 | phy = get_phy_device(mdio, phy_id, true); | ||
738 | if (!phy || IS_ERR(phy)) | ||
739 | return -EIO; | ||
740 | |||
741 | ret = phy_device_register(phy); | ||
742 | if (ret) | ||
743 | phy_device_free(phy); | ||
744 | else | ||
745 | pdata->phy_dev = phy; | ||
746 | |||
747 | return ret; | ||
748 | } | ||
749 | |||
750 | int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) | ||
751 | { | ||
752 | struct net_device *ndev = pdata->ndev; | ||
753 | struct mii_bus *mdio_bus; | ||
754 | int ret; | ||
755 | |||
710 | mdio_bus = mdiobus_alloc(); | 756 | mdio_bus = mdiobus_alloc(); |
711 | if (!mdio_bus) | 757 | if (!mdio_bus) |
712 | return -ENOMEM; | 758 | return -ENOMEM; |
@@ -720,7 +766,7 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) | |||
720 | mdio_bus->priv = pdata; | 766 | mdio_bus->priv = pdata; |
721 | mdio_bus->parent = &ndev->dev; | 767 | mdio_bus->parent = &ndev->dev; |
722 | 768 | ||
723 | ret = of_mdiobus_register(mdio_bus, mdio_np); | 769 | ret = xgene_mdiobus_register(pdata, mdio_bus); |
724 | if (ret) { | 770 | if (ret) { |
725 | netdev_err(ndev, "Failed to register MDIO bus\n"); | 771 | netdev_err(ndev, "Failed to register MDIO bus\n"); |
726 | mdiobus_free(mdio_bus); | 772 | mdiobus_free(mdio_bus); |
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 83a50280bb70..1e56bf30366f 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c | |||
@@ -24,6 +24,10 @@ | |||
24 | #include "xgene_enet_sgmac.h" | 24 | #include "xgene_enet_sgmac.h" |
25 | #include "xgene_enet_xgmac.h" | 25 | #include "xgene_enet_xgmac.h" |
26 | 26 | ||
27 | #define RES_ENET_CSR 0 | ||
28 | #define RES_RING_CSR 1 | ||
29 | #define RES_RING_CMD 2 | ||
30 | |||
27 | static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool) | 31 | static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool) |
28 | { | 32 | { |
29 | struct xgene_enet_raw_desc16 *raw_desc; | 33 | struct xgene_enet_raw_desc16 *raw_desc; |
@@ -746,6 +750,41 @@ static const struct net_device_ops xgene_ndev_ops = { | |||
746 | .ndo_set_mac_address = xgene_enet_set_mac_address, | 750 | .ndo_set_mac_address = xgene_enet_set_mac_address, |
747 | }; | 751 | }; |
748 | 752 | ||
753 | static int xgene_get_mac_address(struct device *dev, | ||
754 | unsigned char *addr) | ||
755 | { | ||
756 | int ret; | ||
757 | |||
758 | ret = device_property_read_u8_array(dev, "local-mac-address", addr, 6); | ||
759 | if (ret) | ||
760 | ret = device_property_read_u8_array(dev, "mac-address", | ||
761 | addr, 6); | ||
762 | if (ret) | ||
763 | return -ENODEV; | ||
764 | |||
765 | return ETH_ALEN; | ||
766 | } | ||
767 | |||
768 | static int xgene_get_phy_mode(struct device *dev) | ||
769 | { | ||
770 | int i, ret; | ||
771 | char *modestr; | ||
772 | |||
773 | ret = device_property_read_string(dev, "phy-connection-type", | ||
774 | (const char **)&modestr); | ||
775 | if (ret) | ||
776 | ret = device_property_read_string(dev, "phy-mode", | ||
777 | (const char **)&modestr); | ||
778 | if (ret) | ||
779 | return -ENODEV; | ||
780 | |||
781 | for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) { | ||
782 | if (!strcasecmp(modestr, phy_modes(i))) | ||
783 | return i; | ||
784 | } | ||
785 | return -ENODEV; | ||
786 | } | ||
787 | |||
749 | static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) | 788 | static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) |
750 | { | 789 | { |
751 | struct platform_device *pdev; | 790 | struct platform_device *pdev; |
@@ -753,29 +792,42 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) | |||
753 | struct device *dev; | 792 | struct device *dev; |
754 | struct resource *res; | 793 | struct resource *res; |
755 | void __iomem *base_addr; | 794 | void __iomem *base_addr; |
756 | const char *mac; | ||
757 | int ret; | 795 | int ret; |
758 | 796 | ||
759 | pdev = pdata->pdev; | 797 | pdev = pdata->pdev; |
760 | dev = &pdev->dev; | 798 | dev = &pdev->dev; |
761 | ndev = pdata->ndev; | 799 | ndev = pdata->ndev; |
762 | 800 | ||
763 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "enet_csr"); | 801 | res = platform_get_resource(pdev, IORESOURCE_MEM, RES_ENET_CSR); |
764 | pdata->base_addr = devm_ioremap_resource(dev, res); | 802 | if (!res) { |
803 | dev_err(dev, "Resource enet_csr not defined\n"); | ||
804 | return -ENODEV; | ||
805 | } | ||
806 | pdata->base_addr = devm_ioremap(dev, res->start, resource_size(res)); | ||
765 | if (IS_ERR(pdata->base_addr)) { | 807 | if (IS_ERR(pdata->base_addr)) { |
766 | dev_err(dev, "Unable to retrieve ENET Port CSR region\n"); | 808 | dev_err(dev, "Unable to retrieve ENET Port CSR region\n"); |
767 | return PTR_ERR(pdata->base_addr); | 809 | return PTR_ERR(pdata->base_addr); |
768 | } | 810 | } |
769 | 811 | ||
770 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_csr"); | 812 | res = platform_get_resource(pdev, IORESOURCE_MEM, RES_RING_CSR); |
771 | pdata->ring_csr_addr = devm_ioremap_resource(dev, res); | 813 | if (!res) { |
814 | dev_err(dev, "Resource ring_csr not defined\n"); | ||
815 | return -ENODEV; | ||
816 | } | ||
817 | pdata->ring_csr_addr = devm_ioremap(dev, res->start, | ||
818 | resource_size(res)); | ||
772 | if (IS_ERR(pdata->ring_csr_addr)) { | 819 | if (IS_ERR(pdata->ring_csr_addr)) { |
773 | dev_err(dev, "Unable to retrieve ENET Ring CSR region\n"); | 820 | dev_err(dev, "Unable to retrieve ENET Ring CSR region\n"); |
774 | return PTR_ERR(pdata->ring_csr_addr); | 821 | return PTR_ERR(pdata->ring_csr_addr); |
775 | } | 822 | } |
776 | 823 | ||
777 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_cmd"); | 824 | res = platform_get_resource(pdev, IORESOURCE_MEM, RES_RING_CMD); |
778 | pdata->ring_cmd_addr = devm_ioremap_resource(dev, res); | 825 | if (!res) { |
826 | dev_err(dev, "Resource ring_cmd not defined\n"); | ||
827 | return -ENODEV; | ||
828 | } | ||
829 | pdata->ring_cmd_addr = devm_ioremap(dev, res->start, | ||
830 | resource_size(res)); | ||
779 | if (IS_ERR(pdata->ring_cmd_addr)) { | 831 | if (IS_ERR(pdata->ring_cmd_addr)) { |
780 | dev_err(dev, "Unable to retrieve ENET Ring command region\n"); | 832 | dev_err(dev, "Unable to retrieve ENET Ring command region\n"); |
781 | return PTR_ERR(pdata->ring_cmd_addr); | 833 | return PTR_ERR(pdata->ring_cmd_addr); |
@@ -789,14 +841,12 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) | |||
789 | } | 841 | } |
790 | pdata->rx_irq = ret; | 842 | pdata->rx_irq = ret; |
791 | 843 | ||
792 | mac = of_get_mac_address(dev->of_node); | 844 | if (xgene_get_mac_address(dev, ndev->dev_addr) != ETH_ALEN) |
793 | if (mac) | ||
794 | memcpy(ndev->dev_addr, mac, ndev->addr_len); | ||
795 | else | ||
796 | eth_hw_addr_random(ndev); | 845 | eth_hw_addr_random(ndev); |
846 | |||
797 | memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len); | 847 | memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len); |
798 | 848 | ||
799 | pdata->phy_mode = of_get_phy_mode(pdev->dev.of_node); | 849 | pdata->phy_mode = xgene_get_phy_mode(dev); |
800 | if (pdata->phy_mode < 0) { | 850 | if (pdata->phy_mode < 0) { |
801 | dev_err(dev, "Unable to get phy-connection-type\n"); | 851 | dev_err(dev, "Unable to get phy-connection-type\n"); |
802 | return pdata->phy_mode; | 852 | return pdata->phy_mode; |
@@ -809,11 +859,9 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) | |||
809 | } | 859 | } |
810 | 860 | ||
811 | pdata->clk = devm_clk_get(&pdev->dev, NULL); | 861 | pdata->clk = devm_clk_get(&pdev->dev, NULL); |
812 | ret = IS_ERR(pdata->clk); | ||
813 | if (IS_ERR(pdata->clk)) { | 862 | if (IS_ERR(pdata->clk)) { |
814 | dev_err(&pdev->dev, "can't get clock\n"); | 863 | /* Firmware may have set up the clock already. */ |
815 | ret = PTR_ERR(pdata->clk); | 864 | pdata->clk = NULL; |
816 | return ret; | ||
817 | } | 865 | } |
818 | 866 | ||
819 | base_addr = pdata->base_addr; | 867 | base_addr = pdata->base_addr; |
@@ -924,7 +972,7 @@ static int xgene_enet_probe(struct platform_device *pdev) | |||
924 | goto err; | 972 | goto err; |
925 | } | 973 | } |
926 | 974 | ||
927 | ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); | 975 | ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64)); |
928 | if (ret) { | 976 | if (ret) { |
929 | netdev_err(ndev, "No usable DMA configuration\n"); | 977 | netdev_err(ndev, "No usable DMA configuration\n"); |
930 | goto err; | 978 | goto err; |
@@ -972,17 +1020,26 @@ static int xgene_enet_remove(struct platform_device *pdev) | |||
972 | return 0; | 1020 | return 0; |
973 | } | 1021 | } |
974 | 1022 | ||
975 | static struct of_device_id xgene_enet_match[] = { | 1023 | #ifdef CONFIG_ACPI |
1024 | static const struct acpi_device_id xgene_enet_acpi_match[] = { | ||
1025 | { "APMC0D05", }, | ||
1026 | { } | ||
1027 | }; | ||
1028 | MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match); | ||
1029 | #endif | ||
1030 | |||
1031 | static struct of_device_id xgene_enet_of_match[] = { | ||
976 | {.compatible = "apm,xgene-enet",}, | 1032 | {.compatible = "apm,xgene-enet",}, |
977 | {}, | 1033 | {}, |
978 | }; | 1034 | }; |
979 | 1035 | ||
980 | MODULE_DEVICE_TABLE(of, xgene_enet_match); | 1036 | MODULE_DEVICE_TABLE(of, xgene_enet_of_match); |
981 | 1037 | ||
982 | static struct platform_driver xgene_enet_driver = { | 1038 | static struct platform_driver xgene_enet_driver = { |
983 | .driver = { | 1039 | .driver = { |
984 | .name = "xgene-enet", | 1040 | .name = "xgene-enet", |
985 | .of_match_table = xgene_enet_match, | 1041 | .of_match_table = of_match_ptr(xgene_enet_of_match), |
1042 | .acpi_match_table = ACPI_PTR(xgene_enet_acpi_match), | ||
986 | }, | 1043 | }, |
987 | .probe = xgene_enet_probe, | 1044 | .probe = xgene_enet_probe, |
988 | .remove = xgene_enet_remove, | 1045 | .remove = xgene_enet_remove, |
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index f9958fae6ffd..c2d465c3db66 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h | |||
@@ -22,7 +22,10 @@ | |||
22 | #ifndef __XGENE_ENET_MAIN_H__ | 22 | #ifndef __XGENE_ENET_MAIN_H__ |
23 | #define __XGENE_ENET_MAIN_H__ | 23 | #define __XGENE_ENET_MAIN_H__ |
24 | 24 | ||
25 | #include <linux/acpi.h> | ||
25 | #include <linux/clk.h> | 26 | #include <linux/clk.h> |
27 | #include <linux/efi.h> | ||
28 | #include <linux/io.h> | ||
26 | #include <linux/of_platform.h> | 29 | #include <linux/of_platform.h> |
27 | #include <linux/of_net.h> | 30 | #include <linux/of_net.h> |
28 | #include <linux/of_mdio.h> | 31 | #include <linux/of_mdio.h> |