diff options
| author | Kishon Vijay Abraham I <kishon@ti.com> | 2018-10-17 03:41:04 -0400 |
|---|---|---|
| committer | Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> | 2018-10-17 04:46:15 -0400 |
| commit | 49229238ab47fa1852a89ee55d1e7fb251ee4eb0 (patch) | |
| tree | 70a341f0fc41fbe5402543535a96a2ded502e2a9 /drivers | |
| parent | b51a625b784aa9cdac4a177560e19f0a0041ce19 (diff) | |
PCI: keystone: Cleanup PHY handling
Cleanup PHY handling by using devm_phy_optional_get() to get PHYs if
the PHYs are optional, creating a device link between the PHY device
and the controller device and disable PHY on error cases here.
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/pci/controller/dwc/pci-keystone.c | 122 |
1 files changed, 106 insertions, 16 deletions
diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index e22328f89c84..5ae73c185c99 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c | |||
| @@ -105,6 +105,9 @@ struct keystone_pcie { | |||
| 105 | 105 | ||
| 106 | int num_msi_host_irqs; | 106 | int num_msi_host_irqs; |
| 107 | int msi_host_irqs[MAX_MSI_HOST_IRQS]; | 107 | int msi_host_irqs[MAX_MSI_HOST_IRQS]; |
| 108 | int num_lanes; | ||
| 109 | struct phy **phy; | ||
| 110 | struct device_link **link; | ||
| 108 | struct device_node *msi_intc_np; | 111 | struct device_node *msi_intc_np; |
| 109 | struct irq_domain *legacy_irq_domain; | 112 | struct irq_domain *legacy_irq_domain; |
| 110 | struct device_node *np; | 113 | struct device_node *np; |
| @@ -880,22 +883,57 @@ static const struct dw_pcie_ops ks_pcie_dw_pcie_ops = { | |||
| 880 | .link_up = ks_pcie_link_up, | 883 | .link_up = ks_pcie_link_up, |
| 881 | }; | 884 | }; |
| 882 | 885 | ||
| 883 | static int __exit ks_pcie_remove(struct platform_device *pdev) | 886 | static void ks_pcie_disable_phy(struct keystone_pcie *ks_pcie) |
| 884 | { | 887 | { |
| 885 | struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev); | 888 | int num_lanes = ks_pcie->num_lanes; |
| 886 | 889 | ||
| 887 | clk_disable_unprepare(ks_pcie->clk); | 890 | while (num_lanes--) { |
| 891 | phy_power_off(ks_pcie->phy[num_lanes]); | ||
| 892 | phy_exit(ks_pcie->phy[num_lanes]); | ||
| 893 | } | ||
| 894 | } | ||
| 895 | |||
| 896 | static int ks_pcie_enable_phy(struct keystone_pcie *ks_pcie) | ||
| 897 | { | ||
| 898 | int i; | ||
| 899 | int ret; | ||
| 900 | int num_lanes = ks_pcie->num_lanes; | ||
| 901 | |||
| 902 | for (i = 0; i < num_lanes; i++) { | ||
| 903 | ret = phy_init(ks_pcie->phy[i]); | ||
| 904 | if (ret < 0) | ||
| 905 | goto err_phy; | ||
| 906 | |||
| 907 | ret = phy_power_on(ks_pcie->phy[i]); | ||
| 908 | if (ret < 0) { | ||
| 909 | phy_exit(ks_pcie->phy[i]); | ||
| 910 | goto err_phy; | ||
| 911 | } | ||
| 912 | } | ||
| 888 | 913 | ||
| 889 | return 0; | 914 | return 0; |
| 915 | |||
| 916 | err_phy: | ||
| 917 | while (--i >= 0) { | ||
| 918 | phy_power_off(ks_pcie->phy[i]); | ||
| 919 | phy_exit(ks_pcie->phy[i]); | ||
| 920 | } | ||
| 921 | |||
| 922 | return ret; | ||
| 890 | } | 923 | } |
| 891 | 924 | ||
| 892 | static int __init ks_pcie_probe(struct platform_device *pdev) | 925 | static int __init ks_pcie_probe(struct platform_device *pdev) |
| 893 | { | 926 | { |
| 894 | struct device *dev = &pdev->dev; | 927 | struct device *dev = &pdev->dev; |
| 928 | struct device_node *np = dev->of_node; | ||
| 895 | struct dw_pcie *pci; | 929 | struct dw_pcie *pci; |
| 896 | struct keystone_pcie *ks_pcie; | 930 | struct keystone_pcie *ks_pcie; |
| 897 | struct phy *phy; | 931 | struct device_link **link; |
| 932 | struct phy **phy; | ||
| 933 | u32 num_lanes; | ||
| 934 | char name[10]; | ||
| 898 | int ret; | 935 | int ret; |
| 936 | int i; | ||
| 899 | 937 | ||
| 900 | ks_pcie = devm_kzalloc(dev, sizeof(*ks_pcie), GFP_KERNEL); | 938 | ks_pcie = devm_kzalloc(dev, sizeof(*ks_pcie), GFP_KERNEL); |
| 901 | if (!ks_pcie) | 939 | if (!ks_pcie) |
| @@ -908,29 +946,59 @@ static int __init ks_pcie_probe(struct platform_device *pdev) | |||
| 908 | pci->dev = dev; | 946 | pci->dev = dev; |
| 909 | pci->ops = &ks_pcie_dw_pcie_ops; | 947 | pci->ops = &ks_pcie_dw_pcie_ops; |
| 910 | 948 | ||
| 911 | ks_pcie->pci = pci; | 949 | ret = of_property_read_u32(np, "num-lanes", &num_lanes); |
| 950 | if (ret) | ||
| 951 | num_lanes = 1; | ||
| 912 | 952 | ||
| 913 | /* initialize SerDes Phy if present */ | 953 | phy = devm_kzalloc(dev, sizeof(*phy) * num_lanes, GFP_KERNEL); |
| 914 | phy = devm_phy_get(dev, "pcie-phy"); | 954 | if (!phy) |
| 915 | if (PTR_ERR_OR_ZERO(phy) == -EPROBE_DEFER) | 955 | return -ENOMEM; |
| 916 | return PTR_ERR(phy); | ||
| 917 | 956 | ||
| 918 | if (!IS_ERR_OR_NULL(phy)) { | 957 | link = devm_kzalloc(dev, sizeof(*link) * num_lanes, GFP_KERNEL); |
| 919 | ret = phy_init(phy); | 958 | if (!link) |
| 920 | if (ret < 0) | 959 | return -ENOMEM; |
| 921 | return ret; | 960 | |
| 961 | for (i = 0; i < num_lanes; i++) { | ||
| 962 | snprintf(name, sizeof(name), "pcie-phy%d", i); | ||
| 963 | phy[i] = devm_phy_optional_get(dev, name); | ||
| 964 | if (IS_ERR(phy[i])) { | ||
| 965 | ret = PTR_ERR(phy[i]); | ||
| 966 | goto err_link; | ||
| 967 | } | ||
| 968 | |||
| 969 | if (!phy[i]) | ||
| 970 | continue; | ||
| 971 | |||
| 972 | link[i] = device_link_add(dev, &phy[i]->dev, DL_FLAG_STATELESS); | ||
| 973 | if (!link[i]) { | ||
| 974 | ret = -EINVAL; | ||
| 975 | goto err_link; | ||
| 976 | } | ||
| 977 | } | ||
| 978 | |||
| 979 | ks_pcie->np = np; | ||
| 980 | ks_pcie->pci = pci; | ||
| 981 | ks_pcie->link = link; | ||
| 982 | ks_pcie->num_lanes = num_lanes; | ||
| 983 | ks_pcie->phy = phy; | ||
| 984 | |||
| 985 | ret = ks_pcie_enable_phy(ks_pcie); | ||
| 986 | if (ret) { | ||
| 987 | dev_err(dev, "failed to enable phy\n"); | ||
| 988 | goto err_link; | ||
| 922 | } | 989 | } |
| 923 | 990 | ||
| 924 | ks_pcie->np = dev->of_node; | ||
| 925 | platform_set_drvdata(pdev, ks_pcie); | 991 | platform_set_drvdata(pdev, ks_pcie); |
| 926 | ks_pcie->clk = devm_clk_get(dev, "pcie"); | 992 | ks_pcie->clk = devm_clk_get(dev, "pcie"); |
| 927 | if (IS_ERR(ks_pcie->clk)) { | 993 | if (IS_ERR(ks_pcie->clk)) { |
| 928 | dev_err(dev, "Failed to get pcie rc clock\n"); | 994 | dev_err(dev, "Failed to get pcie rc clock\n"); |
| 929 | return PTR_ERR(ks_pcie->clk); | 995 | ret = PTR_ERR(ks_pcie->clk); |
| 996 | goto err_phy; | ||
| 930 | } | 997 | } |
| 998 | |||
| 931 | ret = clk_prepare_enable(ks_pcie->clk); | 999 | ret = clk_prepare_enable(ks_pcie->clk); |
| 932 | if (ret) | 1000 | if (ret) |
| 933 | return ret; | 1001 | goto err_phy; |
| 934 | 1002 | ||
| 935 | ret = ks_pcie_add_pcie_port(ks_pcie, pdev); | 1003 | ret = ks_pcie_add_pcie_port(ks_pcie, pdev); |
| 936 | if (ret < 0) | 1004 | if (ret < 0) |
| @@ -940,9 +1008,31 @@ static int __init ks_pcie_probe(struct platform_device *pdev) | |||
| 940 | fail_clk: | 1008 | fail_clk: |
| 941 | clk_disable_unprepare(ks_pcie->clk); | 1009 | clk_disable_unprepare(ks_pcie->clk); |
| 942 | 1010 | ||
| 1011 | err_phy: | ||
| 1012 | ks_pcie_disable_phy(ks_pcie); | ||
| 1013 | |||
| 1014 | err_link: | ||
| 1015 | while (--i >= 0 && link[i]) | ||
| 1016 | device_link_del(link[i]); | ||
| 1017 | |||
| 943 | return ret; | 1018 | return ret; |
| 944 | } | 1019 | } |
| 945 | 1020 | ||
| 1021 | static int __exit ks_pcie_remove(struct platform_device *pdev) | ||
| 1022 | { | ||
| 1023 | struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev); | ||
| 1024 | struct device_link **link = ks_pcie->link; | ||
| 1025 | int num_lanes = ks_pcie->num_lanes; | ||
| 1026 | |||
| 1027 | clk_disable_unprepare(ks_pcie->clk); | ||
| 1028 | ks_pcie_disable_phy(ks_pcie); | ||
| 1029 | |||
| 1030 | while (num_lanes--) | ||
| 1031 | device_link_del(link[num_lanes]); | ||
| 1032 | |||
| 1033 | return 0; | ||
| 1034 | } | ||
| 1035 | |||
| 946 | static struct platform_driver ks_pcie_driver __refdata = { | 1036 | static struct platform_driver ks_pcie_driver __refdata = { |
| 947 | .probe = ks_pcie_probe, | 1037 | .probe = ks_pcie_probe, |
| 948 | .remove = __exit_p(ks_pcie_remove), | 1038 | .remove = __exit_p(ks_pcie_remove), |
