diff options
Diffstat (limited to 'drivers/pci/controller/dwc')
-rw-r--r-- | drivers/pci/controller/dwc/Kconfig | 24 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/Makefile | 2 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pci-imx6.c | 102 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pci-layerscape.c | 10 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pci-meson.c | 592 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-armada8k.c | 16 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-designware-ep.c | 4 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-designware-host.c | 40 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-designware.c | 8 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-designware.h | 28 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-histb.c | 2 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-uniphier.c | 471 |
12 files changed, 1265 insertions, 34 deletions
diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index 91b0194240a5..548c58223868 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig | |||
@@ -89,8 +89,8 @@ config PCI_EXYNOS | |||
89 | select PCIE_DW_HOST | 89 | select PCIE_DW_HOST |
90 | 90 | ||
91 | config PCI_IMX6 | 91 | config PCI_IMX6 |
92 | bool "Freescale i.MX6 PCIe controller" | 92 | bool "Freescale i.MX6/7 PCIe controller" |
93 | depends on SOC_IMX6Q || (ARM && COMPILE_TEST) | 93 | depends on SOC_IMX6Q || SOC_IMX7D || (ARM && COMPILE_TEST) |
94 | depends on PCI_MSI_IRQ_DOMAIN | 94 | depends on PCI_MSI_IRQ_DOMAIN |
95 | select PCIE_DW_HOST | 95 | select PCIE_DW_HOST |
96 | 96 | ||
@@ -193,4 +193,24 @@ config PCIE_HISI_STB | |||
193 | help | 193 | help |
194 | Say Y here if you want PCIe controller support on HiSilicon STB SoCs | 194 | Say Y here if you want PCIe controller support on HiSilicon STB SoCs |
195 | 195 | ||
196 | config PCI_MESON | ||
197 | bool "MESON PCIe controller" | ||
198 | depends on PCI_MSI_IRQ_DOMAIN | ||
199 | select PCIE_DW_HOST | ||
200 | help | ||
201 | Say Y here if you want to enable PCI controller support on Amlogic | ||
202 | SoCs. The PCI controller on Amlogic is based on DesignWare hardware | ||
203 | and therefore the driver re-uses the DesignWare core functions to | ||
204 | implement the driver. | ||
205 | |||
206 | config PCIE_UNIPHIER | ||
207 | bool "Socionext UniPhier PCIe controllers" | ||
208 | depends on ARCH_UNIPHIER || COMPILE_TEST | ||
209 | depends on OF && HAS_IOMEM | ||
210 | depends on PCI_MSI_IRQ_DOMAIN | ||
211 | select PCIE_DW_HOST | ||
212 | help | ||
213 | Say Y here if you want PCIe controller support on UniPhier SoCs. | ||
214 | This driver supports LD20 and PXs3 SoCs. | ||
215 | |||
196 | endmenu | 216 | endmenu |
diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile index fcf91eacfc63..7bcdcdf5024e 100644 --- a/drivers/pci/controller/dwc/Makefile +++ b/drivers/pci/controller/dwc/Makefile | |||
@@ -14,6 +14,8 @@ obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o | |||
14 | obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o | 14 | obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o |
15 | obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o | 15 | obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o |
16 | obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o | 16 | obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o |
17 | obj-$(CONFIG_PCI_MESON) += pci-meson.o | ||
18 | obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o | ||
17 | 19 | ||
18 | # The following drivers are for devices that use the generic ACPI | 20 | # The following drivers are for devices that use the generic ACPI |
19 | # pci_root.c driver but don't support standard ECAM config access. | 21 | # pci_root.c driver but don't support standard ECAM config access. |
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 88af6bff945f..52e47dac028f 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c | |||
@@ -27,6 +27,8 @@ | |||
27 | #include <linux/types.h> | 27 | #include <linux/types.h> |
28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
29 | #include <linux/reset.h> | 29 | #include <linux/reset.h> |
30 | #include <linux/pm_domain.h> | ||
31 | #include <linux/pm_runtime.h> | ||
30 | 32 | ||
31 | #include "pcie-designware.h" | 33 | #include "pcie-designware.h" |
32 | 34 | ||
@@ -59,6 +61,11 @@ struct imx6_pcie { | |||
59 | u32 tx_swing_low; | 61 | u32 tx_swing_low; |
60 | int link_gen; | 62 | int link_gen; |
61 | struct regulator *vpcie; | 63 | struct regulator *vpcie; |
64 | |||
65 | /* power domain for pcie */ | ||
66 | struct device *pd_pcie; | ||
67 | /* power domain for pcie phy */ | ||
68 | struct device *pd_pcie_phy; | ||
62 | }; | 69 | }; |
63 | 70 | ||
64 | /* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */ | 71 | /* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */ |
@@ -67,6 +74,7 @@ struct imx6_pcie { | |||
67 | #define PHY_PLL_LOCK_WAIT_USLEEP_MAX 200 | 74 | #define PHY_PLL_LOCK_WAIT_USLEEP_MAX 200 |
68 | 75 | ||
69 | /* PCIe Root Complex registers (memory-mapped) */ | 76 | /* PCIe Root Complex registers (memory-mapped) */ |
77 | #define PCIE_RC_IMX6_MSI_CAP 0x50 | ||
70 | #define PCIE_RC_LCR 0x7c | 78 | #define PCIE_RC_LCR 0x7c |
71 | #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 0x1 | 79 | #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 0x1 |
72 | #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 0x2 | 80 | #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 0x2 |
@@ -290,6 +298,43 @@ static int imx6q_pcie_abort_handler(unsigned long addr, | |||
290 | return 1; | 298 | return 1; |
291 | } | 299 | } |
292 | 300 | ||
301 | static int imx6_pcie_attach_pd(struct device *dev) | ||
302 | { | ||
303 | struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); | ||
304 | struct device_link *link; | ||
305 | |||
306 | /* Do nothing when in a single power domain */ | ||
307 | if (dev->pm_domain) | ||
308 | return 0; | ||
309 | |||
310 | imx6_pcie->pd_pcie = dev_pm_domain_attach_by_name(dev, "pcie"); | ||
311 | if (IS_ERR(imx6_pcie->pd_pcie)) | ||
312 | return PTR_ERR(imx6_pcie->pd_pcie); | ||
313 | link = device_link_add(dev, imx6_pcie->pd_pcie, | ||
314 | DL_FLAG_STATELESS | | ||
315 | DL_FLAG_PM_RUNTIME | | ||
316 | DL_FLAG_RPM_ACTIVE); | ||
317 | if (!link) { | ||
318 | dev_err(dev, "Failed to add device_link to pcie pd.\n"); | ||
319 | return -EINVAL; | ||
320 | } | ||
321 | |||
322 | imx6_pcie->pd_pcie_phy = dev_pm_domain_attach_by_name(dev, "pcie_phy"); | ||
323 | if (IS_ERR(imx6_pcie->pd_pcie_phy)) | ||
324 | return PTR_ERR(imx6_pcie->pd_pcie_phy); | ||
325 | |||
326 | device_link_add(dev, imx6_pcie->pd_pcie_phy, | ||
327 | DL_FLAG_STATELESS | | ||
328 | DL_FLAG_PM_RUNTIME | | ||
329 | DL_FLAG_RPM_ACTIVE); | ||
330 | if (IS_ERR(link)) { | ||
331 | dev_err(dev, "Failed to add device_link to pcie_phy pd: %ld\n", PTR_ERR(link)); | ||
332 | return PTR_ERR(link); | ||
333 | } | ||
334 | |||
335 | return 0; | ||
336 | } | ||
337 | |||
293 | static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) | 338 | static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) |
294 | { | 339 | { |
295 | struct device *dev = imx6_pcie->pci->dev; | 340 | struct device *dev = imx6_pcie->pci->dev; |
@@ -765,8 +810,28 @@ static void imx6_pcie_ltssm_disable(struct device *dev) | |||
765 | 810 | ||
766 | static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie) | 811 | static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie) |
767 | { | 812 | { |
768 | reset_control_assert(imx6_pcie->turnoff_reset); | 813 | struct device *dev = imx6_pcie->pci->dev; |
769 | reset_control_deassert(imx6_pcie->turnoff_reset); | 814 | |
815 | /* Some variants have a turnoff reset in DT */ | ||
816 | if (imx6_pcie->turnoff_reset) { | ||
817 | reset_control_assert(imx6_pcie->turnoff_reset); | ||
818 | reset_control_deassert(imx6_pcie->turnoff_reset); | ||
819 | goto pm_turnoff_sleep; | ||
820 | } | ||
821 | |||
822 | /* Others poke directly at IOMUXC registers */ | ||
823 | switch (imx6_pcie->variant) { | ||
824 | case IMX6SX: | ||
825 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, | ||
826 | IMX6SX_GPR12_PCIE_PM_TURN_OFF, | ||
827 | IMX6SX_GPR12_PCIE_PM_TURN_OFF); | ||
828 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, | ||
829 | IMX6SX_GPR12_PCIE_PM_TURN_OFF, 0); | ||
830 | break; | ||
831 | default: | ||
832 | dev_err(dev, "PME_Turn_Off not implemented\n"); | ||
833 | return; | ||
834 | } | ||
770 | 835 | ||
771 | /* | 836 | /* |
772 | * Components with an upstream port must respond to | 837 | * Components with an upstream port must respond to |
@@ -775,6 +840,7 @@ static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie) | |||
775 | * The standard recommends a 1-10ms timeout after which to | 840 | * The standard recommends a 1-10ms timeout after which to |
776 | * proceed anyway as if acks were received. | 841 | * proceed anyway as if acks were received. |
777 | */ | 842 | */ |
843 | pm_turnoff_sleep: | ||
778 | usleep_range(1000, 10000); | 844 | usleep_range(1000, 10000); |
779 | } | 845 | } |
780 | 846 | ||
@@ -784,18 +850,31 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) | |||
784 | clk_disable_unprepare(imx6_pcie->pcie_phy); | 850 | clk_disable_unprepare(imx6_pcie->pcie_phy); |
785 | clk_disable_unprepare(imx6_pcie->pcie_bus); | 851 | clk_disable_unprepare(imx6_pcie->pcie_bus); |
786 | 852 | ||
787 | if (imx6_pcie->variant == IMX7D) { | 853 | switch (imx6_pcie->variant) { |
854 | case IMX6SX: | ||
855 | clk_disable_unprepare(imx6_pcie->pcie_inbound_axi); | ||
856 | break; | ||
857 | case IMX7D: | ||
788 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, | 858 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, |
789 | IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, | 859 | IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, |
790 | IMX7D_GPR12_PCIE_PHY_REFCLK_SEL); | 860 | IMX7D_GPR12_PCIE_PHY_REFCLK_SEL); |
861 | break; | ||
862 | default: | ||
863 | break; | ||
791 | } | 864 | } |
792 | } | 865 | } |
793 | 866 | ||
867 | static inline bool imx6_pcie_supports_suspend(struct imx6_pcie *imx6_pcie) | ||
868 | { | ||
869 | return (imx6_pcie->variant == IMX7D || | ||
870 | imx6_pcie->variant == IMX6SX); | ||
871 | } | ||
872 | |||
794 | static int imx6_pcie_suspend_noirq(struct device *dev) | 873 | static int imx6_pcie_suspend_noirq(struct device *dev) |
795 | { | 874 | { |
796 | struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); | 875 | struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); |
797 | 876 | ||
798 | if (imx6_pcie->variant != IMX7D) | 877 | if (!imx6_pcie_supports_suspend(imx6_pcie)) |
799 | return 0; | 878 | return 0; |
800 | 879 | ||
801 | imx6_pcie_pm_turnoff(imx6_pcie); | 880 | imx6_pcie_pm_turnoff(imx6_pcie); |
@@ -811,7 +890,7 @@ static int imx6_pcie_resume_noirq(struct device *dev) | |||
811 | struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); | 890 | struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); |
812 | struct pcie_port *pp = &imx6_pcie->pci->pp; | 891 | struct pcie_port *pp = &imx6_pcie->pci->pp; |
813 | 892 | ||
814 | if (imx6_pcie->variant != IMX7D) | 893 | if (!imx6_pcie_supports_suspend(imx6_pcie)) |
815 | return 0; | 894 | return 0; |
816 | 895 | ||
817 | imx6_pcie_assert_core_reset(imx6_pcie); | 896 | imx6_pcie_assert_core_reset(imx6_pcie); |
@@ -840,6 +919,7 @@ static int imx6_pcie_probe(struct platform_device *pdev) | |||
840 | struct resource *dbi_base; | 919 | struct resource *dbi_base; |
841 | struct device_node *node = dev->of_node; | 920 | struct device_node *node = dev->of_node; |
842 | int ret; | 921 | int ret; |
922 | u16 val; | ||
843 | 923 | ||
844 | imx6_pcie = devm_kzalloc(dev, sizeof(*imx6_pcie), GFP_KERNEL); | 924 | imx6_pcie = devm_kzalloc(dev, sizeof(*imx6_pcie), GFP_KERNEL); |
845 | if (!imx6_pcie) | 925 | if (!imx6_pcie) |
@@ -977,10 +1057,22 @@ static int imx6_pcie_probe(struct platform_device *pdev) | |||
977 | 1057 | ||
978 | platform_set_drvdata(pdev, imx6_pcie); | 1058 | platform_set_drvdata(pdev, imx6_pcie); |
979 | 1059 | ||
1060 | ret = imx6_pcie_attach_pd(dev); | ||
1061 | if (ret) | ||
1062 | return ret; | ||
1063 | |||
980 | ret = imx6_add_pcie_port(imx6_pcie, pdev); | 1064 | ret = imx6_add_pcie_port(imx6_pcie, pdev); |
981 | if (ret < 0) | 1065 | if (ret < 0) |
982 | return ret; | 1066 | return ret; |
983 | 1067 | ||
1068 | if (pci_msi_enabled()) { | ||
1069 | val = dw_pcie_readw_dbi(pci, PCIE_RC_IMX6_MSI_CAP + | ||
1070 | PCI_MSI_FLAGS); | ||
1071 | val |= PCI_MSI_FLAGS_ENABLE; | ||
1072 | dw_pcie_writew_dbi(pci, PCIE_RC_IMX6_MSI_CAP + PCI_MSI_FLAGS, | ||
1073 | val); | ||
1074 | } | ||
1075 | |||
984 | return 0; | 1076 | return 0; |
985 | } | 1077 | } |
986 | 1078 | ||
diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index 7aa9a82b7ebd..ce45bde29bf8 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c | |||
@@ -222,12 +222,12 @@ static const struct dw_pcie_ops dw_ls_pcie_ops = { | |||
222 | .link_up = ls_pcie_link_up, | 222 | .link_up = ls_pcie_link_up, |
223 | }; | 223 | }; |
224 | 224 | ||
225 | static struct ls_pcie_drvdata ls1021_drvdata = { | 225 | static const struct ls_pcie_drvdata ls1021_drvdata = { |
226 | .ops = &ls1021_pcie_host_ops, | 226 | .ops = &ls1021_pcie_host_ops, |
227 | .dw_pcie_ops = &dw_ls1021_pcie_ops, | 227 | .dw_pcie_ops = &dw_ls1021_pcie_ops, |
228 | }; | 228 | }; |
229 | 229 | ||
230 | static struct ls_pcie_drvdata ls1043_drvdata = { | 230 | static const struct ls_pcie_drvdata ls1043_drvdata = { |
231 | .lut_offset = 0x10000, | 231 | .lut_offset = 0x10000, |
232 | .ltssm_shift = 24, | 232 | .ltssm_shift = 24, |
233 | .lut_dbg = 0x7fc, | 233 | .lut_dbg = 0x7fc, |
@@ -235,7 +235,7 @@ static struct ls_pcie_drvdata ls1043_drvdata = { | |||
235 | .dw_pcie_ops = &dw_ls_pcie_ops, | 235 | .dw_pcie_ops = &dw_ls_pcie_ops, |
236 | }; | 236 | }; |
237 | 237 | ||
238 | static struct ls_pcie_drvdata ls1046_drvdata = { | 238 | static const struct ls_pcie_drvdata ls1046_drvdata = { |
239 | .lut_offset = 0x80000, | 239 | .lut_offset = 0x80000, |
240 | .ltssm_shift = 24, | 240 | .ltssm_shift = 24, |
241 | .lut_dbg = 0x407fc, | 241 | .lut_dbg = 0x407fc, |
@@ -243,7 +243,7 @@ static struct ls_pcie_drvdata ls1046_drvdata = { | |||
243 | .dw_pcie_ops = &dw_ls_pcie_ops, | 243 | .dw_pcie_ops = &dw_ls_pcie_ops, |
244 | }; | 244 | }; |
245 | 245 | ||
246 | static struct ls_pcie_drvdata ls2080_drvdata = { | 246 | static const struct ls_pcie_drvdata ls2080_drvdata = { |
247 | .lut_offset = 0x80000, | 247 | .lut_offset = 0x80000, |
248 | .ltssm_shift = 0, | 248 | .ltssm_shift = 0, |
249 | .lut_dbg = 0x7fc, | 249 | .lut_dbg = 0x7fc, |
@@ -251,7 +251,7 @@ static struct ls_pcie_drvdata ls2080_drvdata = { | |||
251 | .dw_pcie_ops = &dw_ls_pcie_ops, | 251 | .dw_pcie_ops = &dw_ls_pcie_ops, |
252 | }; | 252 | }; |
253 | 253 | ||
254 | static struct ls_pcie_drvdata ls2088_drvdata = { | 254 | static const struct ls_pcie_drvdata ls2088_drvdata = { |
255 | .lut_offset = 0x80000, | 255 | .lut_offset = 0x80000, |
256 | .ltssm_shift = 0, | 256 | .ltssm_shift = 0, |
257 | .lut_dbg = 0x407fc, | 257 | .lut_dbg = 0x407fc, |
diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c new file mode 100644 index 000000000000..241ebe0c4505 --- /dev/null +++ b/drivers/pci/controller/dwc/pci-meson.c | |||
@@ -0,0 +1,592 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * PCIe host controller driver for Amlogic MESON SoCs | ||
4 | * | ||
5 | * Copyright (c) 2018 Amlogic, inc. | ||
6 | * Author: Yue Wang <yue.wang@amlogic.com> | ||
7 | */ | ||
8 | |||
9 | #include <linux/clk.h> | ||
10 | #include <linux/delay.h> | ||
11 | #include <linux/of_device.h> | ||
12 | #include <linux/of_gpio.h> | ||
13 | #include <linux/pci.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/reset.h> | ||
16 | #include <linux/resource.h> | ||
17 | #include <linux/types.h> | ||
18 | |||
19 | #include "pcie-designware.h" | ||
20 | |||
21 | #define to_meson_pcie(x) dev_get_drvdata((x)->dev) | ||
22 | |||
23 | /* External local bus interface registers */ | ||
24 | #define PLR_OFFSET 0x700 | ||
25 | #define PCIE_PORT_LINK_CTRL_OFF (PLR_OFFSET + 0x10) | ||
26 | #define FAST_LINK_MODE BIT(7) | ||
27 | #define LINK_CAPABLE_MASK GENMASK(21, 16) | ||
28 | #define LINK_CAPABLE_X1 BIT(16) | ||
29 | |||
30 | #define PCIE_GEN2_CTRL_OFF (PLR_OFFSET + 0x10c) | ||
31 | #define NUM_OF_LANES_MASK GENMASK(12, 8) | ||
32 | #define NUM_OF_LANES_X1 BIT(8) | ||
33 | #define DIRECT_SPEED_CHANGE BIT(17) | ||
34 | |||
35 | #define TYPE1_HDR_OFFSET 0x0 | ||
36 | #define PCIE_STATUS_COMMAND (TYPE1_HDR_OFFSET + 0x04) | ||
37 | #define PCI_IO_EN BIT(0) | ||
38 | #define PCI_MEM_SPACE_EN BIT(1) | ||
39 | #define PCI_BUS_MASTER_EN BIT(2) | ||
40 | |||
41 | #define PCIE_BASE_ADDR0 (TYPE1_HDR_OFFSET + 0x10) | ||
42 | #define PCIE_BASE_ADDR1 (TYPE1_HDR_OFFSET + 0x14) | ||
43 | |||
44 | #define PCIE_CAP_OFFSET 0x70 | ||
45 | #define PCIE_DEV_CTRL_DEV_STUS (PCIE_CAP_OFFSET + 0x08) | ||
46 | #define PCIE_CAP_MAX_PAYLOAD_MASK GENMASK(7, 5) | ||
47 | #define PCIE_CAP_MAX_PAYLOAD_SIZE(x) ((x) << 5) | ||
48 | #define PCIE_CAP_MAX_READ_REQ_MASK GENMASK(14, 12) | ||
49 | #define PCIE_CAP_MAX_READ_REQ_SIZE(x) ((x) << 12) | ||
50 | |||
51 | /* PCIe specific config registers */ | ||
52 | #define PCIE_CFG0 0x0 | ||
53 | #define APP_LTSSM_ENABLE BIT(7) | ||
54 | |||
55 | #define PCIE_CFG_STATUS12 0x30 | ||
56 | #define IS_SMLH_LINK_UP(x) ((x) & (1 << 6)) | ||
57 | #define IS_RDLH_LINK_UP(x) ((x) & (1 << 16)) | ||
58 | #define IS_LTSSM_UP(x) ((((x) >> 10) & 0x1f) == 0x11) | ||
59 | |||
60 | #define PCIE_CFG_STATUS17 0x44 | ||
61 | #define PM_CURRENT_STATE(x) (((x) >> 7) & 0x1) | ||
62 | |||
63 | #define WAIT_LINKUP_TIMEOUT 4000 | ||
64 | #define PORT_CLK_RATE 100000000UL | ||
65 | #define MAX_PAYLOAD_SIZE 256 | ||
66 | #define MAX_READ_REQ_SIZE 256 | ||
67 | #define MESON_PCIE_PHY_POWERUP 0x1c | ||
68 | #define PCIE_RESET_DELAY 500 | ||
69 | #define PCIE_SHARED_RESET 1 | ||
70 | #define PCIE_NORMAL_RESET 0 | ||
71 | |||
72 | enum pcie_data_rate { | ||
73 | PCIE_GEN1, | ||
74 | PCIE_GEN2, | ||
75 | PCIE_GEN3, | ||
76 | PCIE_GEN4 | ||
77 | }; | ||
78 | |||
79 | struct meson_pcie_mem_res { | ||
80 | void __iomem *elbi_base; | ||
81 | void __iomem *cfg_base; | ||
82 | void __iomem *phy_base; | ||
83 | }; | ||
84 | |||
85 | struct meson_pcie_clk_res { | ||
86 | struct clk *clk; | ||
87 | struct clk *mipi_gate; | ||
88 | struct clk *port_clk; | ||
89 | struct clk *general_clk; | ||
90 | }; | ||
91 | |||
92 | struct meson_pcie_rc_reset { | ||
93 | struct reset_control *phy; | ||
94 | struct reset_control *port; | ||
95 | struct reset_control *apb; | ||
96 | }; | ||
97 | |||
98 | struct meson_pcie { | ||
99 | struct dw_pcie pci; | ||
100 | struct meson_pcie_mem_res mem_res; | ||
101 | struct meson_pcie_clk_res clk_res; | ||
102 | struct meson_pcie_rc_reset mrst; | ||
103 | struct gpio_desc *reset_gpio; | ||
104 | }; | ||
105 | |||
106 | static struct reset_control *meson_pcie_get_reset(struct meson_pcie *mp, | ||
107 | const char *id, | ||
108 | u32 reset_type) | ||
109 | { | ||
110 | struct device *dev = mp->pci.dev; | ||
111 | struct reset_control *reset; | ||
112 | |||
113 | if (reset_type == PCIE_SHARED_RESET) | ||
114 | reset = devm_reset_control_get_shared(dev, id); | ||
115 | else | ||
116 | reset = devm_reset_control_get(dev, id); | ||
117 | |||
118 | return reset; | ||
119 | } | ||
120 | |||
121 | static int meson_pcie_get_resets(struct meson_pcie *mp) | ||
122 | { | ||
123 | struct meson_pcie_rc_reset *mrst = &mp->mrst; | ||
124 | |||
125 | mrst->phy = meson_pcie_get_reset(mp, "phy", PCIE_SHARED_RESET); | ||
126 | if (IS_ERR(mrst->phy)) | ||
127 | return PTR_ERR(mrst->phy); | ||
128 | reset_control_deassert(mrst->phy); | ||
129 | |||
130 | mrst->port = meson_pcie_get_reset(mp, "port", PCIE_NORMAL_RESET); | ||
131 | if (IS_ERR(mrst->port)) | ||
132 | return PTR_ERR(mrst->port); | ||
133 | reset_control_deassert(mrst->port); | ||
134 | |||
135 | mrst->apb = meson_pcie_get_reset(mp, "apb", PCIE_SHARED_RESET); | ||
136 | if (IS_ERR(mrst->apb)) | ||
137 | return PTR_ERR(mrst->apb); | ||
138 | reset_control_deassert(mrst->apb); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static void __iomem *meson_pcie_get_mem(struct platform_device *pdev, | ||
144 | struct meson_pcie *mp, | ||
145 | const char *id) | ||
146 | { | ||
147 | struct device *dev = mp->pci.dev; | ||
148 | struct resource *res; | ||
149 | |||
150 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, id); | ||
151 | |||
152 | return devm_ioremap_resource(dev, res); | ||
153 | } | ||
154 | |||
155 | static void __iomem *meson_pcie_get_mem_shared(struct platform_device *pdev, | ||
156 | struct meson_pcie *mp, | ||
157 | const char *id) | ||
158 | { | ||
159 | struct device *dev = mp->pci.dev; | ||
160 | struct resource *res; | ||
161 | |||
162 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, id); | ||
163 | if (!res) { | ||
164 | dev_err(dev, "No REG resource %s\n", id); | ||
165 | return ERR_PTR(-ENXIO); | ||
166 | } | ||
167 | |||
168 | return devm_ioremap(dev, res->start, resource_size(res)); | ||
169 | } | ||
170 | |||
171 | static int meson_pcie_get_mems(struct platform_device *pdev, | ||
172 | struct meson_pcie *mp) | ||
173 | { | ||
174 | mp->mem_res.elbi_base = meson_pcie_get_mem(pdev, mp, "elbi"); | ||
175 | if (IS_ERR(mp->mem_res.elbi_base)) | ||
176 | return PTR_ERR(mp->mem_res.elbi_base); | ||
177 | |||
178 | mp->mem_res.cfg_base = meson_pcie_get_mem(pdev, mp, "cfg"); | ||
179 | if (IS_ERR(mp->mem_res.cfg_base)) | ||
180 | return PTR_ERR(mp->mem_res.cfg_base); | ||
181 | |||
182 | /* Meson SoC has two PCI controllers use same phy register*/ | ||
183 | mp->mem_res.phy_base = meson_pcie_get_mem_shared(pdev, mp, "phy"); | ||
184 | if (IS_ERR(mp->mem_res.phy_base)) | ||
185 | return PTR_ERR(mp->mem_res.phy_base); | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static void meson_pcie_power_on(struct meson_pcie *mp) | ||
191 | { | ||
192 | writel(MESON_PCIE_PHY_POWERUP, mp->mem_res.phy_base); | ||
193 | } | ||
194 | |||
195 | static void meson_pcie_reset(struct meson_pcie *mp) | ||
196 | { | ||
197 | struct meson_pcie_rc_reset *mrst = &mp->mrst; | ||
198 | |||
199 | reset_control_assert(mrst->phy); | ||
200 | udelay(PCIE_RESET_DELAY); | ||
201 | reset_control_deassert(mrst->phy); | ||
202 | udelay(PCIE_RESET_DELAY); | ||
203 | |||
204 | reset_control_assert(mrst->port); | ||
205 | reset_control_assert(mrst->apb); | ||
206 | udelay(PCIE_RESET_DELAY); | ||
207 | reset_control_deassert(mrst->port); | ||
208 | reset_control_deassert(mrst->apb); | ||
209 | udelay(PCIE_RESET_DELAY); | ||
210 | } | ||
211 | |||
212 | static inline struct clk *meson_pcie_probe_clock(struct device *dev, | ||
213 | const char *id, u64 rate) | ||
214 | { | ||
215 | struct clk *clk; | ||
216 | int ret; | ||
217 | |||
218 | clk = devm_clk_get(dev, id); | ||
219 | if (IS_ERR(clk)) | ||
220 | return clk; | ||
221 | |||
222 | if (rate) { | ||
223 | ret = clk_set_rate(clk, rate); | ||
224 | if (ret) { | ||
225 | dev_err(dev, "set clk rate failed, ret = %d\n", ret); | ||
226 | return ERR_PTR(ret); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | ret = clk_prepare_enable(clk); | ||
231 | if (ret) { | ||
232 | dev_err(dev, "couldn't enable clk\n"); | ||
233 | return ERR_PTR(ret); | ||
234 | } | ||
235 | |||
236 | devm_add_action_or_reset(dev, | ||
237 | (void (*) (void *))clk_disable_unprepare, | ||
238 | clk); | ||
239 | |||
240 | return clk; | ||
241 | } | ||
242 | |||
243 | static int meson_pcie_probe_clocks(struct meson_pcie *mp) | ||
244 | { | ||
245 | struct device *dev = mp->pci.dev; | ||
246 | struct meson_pcie_clk_res *res = &mp->clk_res; | ||
247 | |||
248 | res->port_clk = meson_pcie_probe_clock(dev, "port", PORT_CLK_RATE); | ||
249 | if (IS_ERR(res->port_clk)) | ||
250 | return PTR_ERR(res->port_clk); | ||
251 | |||
252 | res->mipi_gate = meson_pcie_probe_clock(dev, "pcie_mipi_en", 0); | ||
253 | if (IS_ERR(res->mipi_gate)) | ||
254 | return PTR_ERR(res->mipi_gate); | ||
255 | |||
256 | res->general_clk = meson_pcie_probe_clock(dev, "pcie_general", 0); | ||
257 | if (IS_ERR(res->general_clk)) | ||
258 | return PTR_ERR(res->general_clk); | ||
259 | |||
260 | res->clk = meson_pcie_probe_clock(dev, "pcie", 0); | ||
261 | if (IS_ERR(res->clk)) | ||
262 | return PTR_ERR(res->clk); | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static inline void meson_elb_writel(struct meson_pcie *mp, u32 val, u32 reg) | ||
268 | { | ||
269 | writel(val, mp->mem_res.elbi_base + reg); | ||
270 | } | ||
271 | |||
272 | static inline u32 meson_elb_readl(struct meson_pcie *mp, u32 reg) | ||
273 | { | ||
274 | return readl(mp->mem_res.elbi_base + reg); | ||
275 | } | ||
276 | |||
277 | static inline u32 meson_cfg_readl(struct meson_pcie *mp, u32 reg) | ||
278 | { | ||
279 | return readl(mp->mem_res.cfg_base + reg); | ||
280 | } | ||
281 | |||
282 | static inline void meson_cfg_writel(struct meson_pcie *mp, u32 val, u32 reg) | ||
283 | { | ||
284 | writel(val, mp->mem_res.cfg_base + reg); | ||
285 | } | ||
286 | |||
287 | static void meson_pcie_assert_reset(struct meson_pcie *mp) | ||
288 | { | ||
289 | gpiod_set_value_cansleep(mp->reset_gpio, 0); | ||
290 | udelay(500); | ||
291 | gpiod_set_value_cansleep(mp->reset_gpio, 1); | ||
292 | } | ||
293 | |||
294 | static void meson_pcie_init_dw(struct meson_pcie *mp) | ||
295 | { | ||
296 | u32 val; | ||
297 | |||
298 | val = meson_cfg_readl(mp, PCIE_CFG0); | ||
299 | val |= APP_LTSSM_ENABLE; | ||
300 | meson_cfg_writel(mp, val, PCIE_CFG0); | ||
301 | |||
302 | val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF); | ||
303 | val &= ~LINK_CAPABLE_MASK; | ||
304 | meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF); | ||
305 | |||
306 | val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF); | ||
307 | val |= LINK_CAPABLE_X1 | FAST_LINK_MODE; | ||
308 | meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF); | ||
309 | |||
310 | val = meson_elb_readl(mp, PCIE_GEN2_CTRL_OFF); | ||
311 | val &= ~NUM_OF_LANES_MASK; | ||
312 | meson_elb_writel(mp, val, PCIE_GEN2_CTRL_OFF); | ||
313 | |||
314 | val = meson_elb_readl(mp, PCIE_GEN2_CTRL_OFF); | ||
315 | val |= NUM_OF_LANES_X1 | DIRECT_SPEED_CHANGE; | ||
316 | meson_elb_writel(mp, val, PCIE_GEN2_CTRL_OFF); | ||
317 | |||
318 | meson_elb_writel(mp, 0x0, PCIE_BASE_ADDR0); | ||
319 | meson_elb_writel(mp, 0x0, PCIE_BASE_ADDR1); | ||
320 | } | ||
321 | |||
322 | static int meson_size_to_payload(struct meson_pcie *mp, int size) | ||
323 | { | ||
324 | struct device *dev = mp->pci.dev; | ||
325 | |||
326 | /* | ||
327 | * dwc supports 2^(val+7) payload size, which val is 0~5 default to 1. | ||
328 | * So if input size is not 2^order alignment or less than 2^7 or bigger | ||
329 | * than 2^12, just set to default size 2^(1+7). | ||
330 | */ | ||
331 | if (!is_power_of_2(size) || size < 128 || size > 4096) { | ||
332 | dev_warn(dev, "payload size %d, set to default 256\n", size); | ||
333 | return 1; | ||
334 | } | ||
335 | |||
336 | return fls(size) - 8; | ||
337 | } | ||
338 | |||
339 | static void meson_set_max_payload(struct meson_pcie *mp, int size) | ||
340 | { | ||
341 | u32 val; | ||
342 | int max_payload_size = meson_size_to_payload(mp, size); | ||
343 | |||
344 | val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS); | ||
345 | val &= ~PCIE_CAP_MAX_PAYLOAD_MASK; | ||
346 | meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS); | ||
347 | |||
348 | val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS); | ||
349 | val |= PCIE_CAP_MAX_PAYLOAD_SIZE(max_payload_size); | ||
350 | meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS); | ||
351 | } | ||
352 | |||
353 | static void meson_set_max_rd_req_size(struct meson_pcie *mp, int size) | ||
354 | { | ||
355 | u32 val; | ||
356 | int max_rd_req_size = meson_size_to_payload(mp, size); | ||
357 | |||
358 | val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS); | ||
359 | val &= ~PCIE_CAP_MAX_READ_REQ_MASK; | ||
360 | meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS); | ||
361 | |||
362 | val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS); | ||
363 | val |= PCIE_CAP_MAX_READ_REQ_SIZE(max_rd_req_size); | ||
364 | meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS); | ||
365 | } | ||
366 | |||
367 | static inline void meson_enable_memory_space(struct meson_pcie *mp) | ||
368 | { | ||
369 | /* Set the RC Bus Master, Memory Space and I/O Space enables */ | ||
370 | meson_elb_writel(mp, PCI_IO_EN | PCI_MEM_SPACE_EN | PCI_BUS_MASTER_EN, | ||
371 | PCIE_STATUS_COMMAND); | ||
372 | } | ||
373 | |||
374 | static int meson_pcie_establish_link(struct meson_pcie *mp) | ||
375 | { | ||
376 | struct dw_pcie *pci = &mp->pci; | ||
377 | struct pcie_port *pp = &pci->pp; | ||
378 | |||
379 | meson_pcie_init_dw(mp); | ||
380 | meson_set_max_payload(mp, MAX_PAYLOAD_SIZE); | ||
381 | meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE); | ||
382 | |||
383 | dw_pcie_setup_rc(pp); | ||
384 | meson_enable_memory_space(mp); | ||
385 | |||
386 | meson_pcie_assert_reset(mp); | ||
387 | |||
388 | return dw_pcie_wait_for_link(pci); | ||
389 | } | ||
390 | |||
391 | static void meson_pcie_enable_interrupts(struct meson_pcie *mp) | ||
392 | { | ||
393 | if (IS_ENABLED(CONFIG_PCI_MSI)) | ||
394 | dw_pcie_msi_init(&mp->pci.pp); | ||
395 | } | ||
396 | |||
397 | static int meson_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, | ||
398 | u32 *val) | ||
399 | { | ||
400 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | ||
401 | int ret; | ||
402 | |||
403 | ret = dw_pcie_read(pci->dbi_base + where, size, val); | ||
404 | if (ret != PCIBIOS_SUCCESSFUL) | ||
405 | return ret; | ||
406 | |||
407 | /* | ||
408 | * There is a bug in the MESON AXG PCIe controller whereby software | ||
409 | * cannot program the PCI_CLASS_DEVICE register, so we must fabricate | ||
410 | * the return value in the config accessors. | ||
411 | */ | ||
412 | if (where == PCI_CLASS_REVISION && size == 4) | ||
413 | *val = (PCI_CLASS_BRIDGE_PCI << 16) | (*val & 0xffff); | ||
414 | else if (where == PCI_CLASS_DEVICE && size == 2) | ||
415 | *val = PCI_CLASS_BRIDGE_PCI; | ||
416 | else if (where == PCI_CLASS_DEVICE && size == 1) | ||
417 | *val = PCI_CLASS_BRIDGE_PCI & 0xff; | ||
418 | else if (where == PCI_CLASS_DEVICE + 1 && size == 1) | ||
419 | *val = (PCI_CLASS_BRIDGE_PCI >> 8) & 0xff; | ||
420 | |||
421 | return PCIBIOS_SUCCESSFUL; | ||
422 | } | ||
423 | |||
424 | static int meson_pcie_wr_own_conf(struct pcie_port *pp, int where, | ||
425 | int size, u32 val) | ||
426 | { | ||
427 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | ||
428 | |||
429 | return dw_pcie_write(pci->dbi_base + where, size, val); | ||
430 | } | ||
431 | |||
432 | static int meson_pcie_link_up(struct dw_pcie *pci) | ||
433 | { | ||
434 | struct meson_pcie *mp = to_meson_pcie(pci); | ||
435 | struct device *dev = pci->dev; | ||
436 | u32 speed_okay = 0; | ||
437 | u32 cnt = 0; | ||
438 | u32 state12, state17, smlh_up, ltssm_up, rdlh_up; | ||
439 | |||
440 | do { | ||
441 | state12 = meson_cfg_readl(mp, PCIE_CFG_STATUS12); | ||
442 | state17 = meson_cfg_readl(mp, PCIE_CFG_STATUS17); | ||
443 | smlh_up = IS_SMLH_LINK_UP(state12); | ||
444 | rdlh_up = IS_RDLH_LINK_UP(state12); | ||
445 | ltssm_up = IS_LTSSM_UP(state12); | ||
446 | |||
447 | if (PM_CURRENT_STATE(state17) < PCIE_GEN3) | ||
448 | speed_okay = 1; | ||
449 | |||
450 | if (smlh_up) | ||
451 | dev_dbg(dev, "smlh_link_up is on\n"); | ||
452 | if (rdlh_up) | ||
453 | dev_dbg(dev, "rdlh_link_up is on\n"); | ||
454 | if (ltssm_up) | ||
455 | dev_dbg(dev, "ltssm_up is on\n"); | ||
456 | if (speed_okay) | ||
457 | dev_dbg(dev, "speed_okay\n"); | ||
458 | |||
459 | if (smlh_up && rdlh_up && ltssm_up && speed_okay) | ||
460 | return 1; | ||
461 | |||
462 | cnt++; | ||
463 | |||
464 | udelay(10); | ||
465 | } while (cnt < WAIT_LINKUP_TIMEOUT); | ||
466 | |||
467 | dev_err(dev, "error: wait linkup timeout\n"); | ||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | static int meson_pcie_host_init(struct pcie_port *pp) | ||
472 | { | ||
473 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | ||
474 | struct meson_pcie *mp = to_meson_pcie(pci); | ||
475 | int ret; | ||
476 | |||
477 | ret = meson_pcie_establish_link(mp); | ||
478 | if (ret) | ||
479 | return ret; | ||
480 | |||
481 | meson_pcie_enable_interrupts(mp); | ||
482 | |||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | static const struct dw_pcie_host_ops meson_pcie_host_ops = { | ||
487 | .rd_own_conf = meson_pcie_rd_own_conf, | ||
488 | .wr_own_conf = meson_pcie_wr_own_conf, | ||
489 | .host_init = meson_pcie_host_init, | ||
490 | }; | ||
491 | |||
492 | static int meson_add_pcie_port(struct meson_pcie *mp, | ||
493 | struct platform_device *pdev) | ||
494 | { | ||
495 | struct dw_pcie *pci = &mp->pci; | ||
496 | struct pcie_port *pp = &pci->pp; | ||
497 | struct device *dev = &pdev->dev; | ||
498 | int ret; | ||
499 | |||
500 | if (IS_ENABLED(CONFIG_PCI_MSI)) { | ||
501 | pp->msi_irq = platform_get_irq(pdev, 0); | ||
502 | if (pp->msi_irq < 0) { | ||
503 | dev_err(dev, "failed to get MSI IRQ\n"); | ||
504 | return pp->msi_irq; | ||
505 | } | ||
506 | } | ||
507 | |||
508 | pp->ops = &meson_pcie_host_ops; | ||
509 | pci->dbi_base = mp->mem_res.elbi_base; | ||
510 | |||
511 | ret = dw_pcie_host_init(pp); | ||
512 | if (ret) { | ||
513 | dev_err(dev, "failed to initialize host\n"); | ||
514 | return ret; | ||
515 | } | ||
516 | |||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static const struct dw_pcie_ops dw_pcie_ops = { | ||
521 | .link_up = meson_pcie_link_up, | ||
522 | }; | ||
523 | |||
524 | static int meson_pcie_probe(struct platform_device *pdev) | ||
525 | { | ||
526 | struct device *dev = &pdev->dev; | ||
527 | struct dw_pcie *pci; | ||
528 | struct meson_pcie *mp; | ||
529 | int ret; | ||
530 | |||
531 | mp = devm_kzalloc(dev, sizeof(*mp), GFP_KERNEL); | ||
532 | if (!mp) | ||
533 | return -ENOMEM; | ||
534 | |||
535 | pci = &mp->pci; | ||
536 | pci->dev = dev; | ||
537 | pci->ops = &dw_pcie_ops; | ||
538 | |||
539 | mp->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); | ||
540 | if (IS_ERR(mp->reset_gpio)) { | ||
541 | dev_err(dev, "get reset gpio failed\n"); | ||
542 | return PTR_ERR(mp->reset_gpio); | ||
543 | } | ||
544 | |||
545 | ret = meson_pcie_get_resets(mp); | ||
546 | if (ret) { | ||
547 | dev_err(dev, "get reset resource failed, %d\n", ret); | ||
548 | return ret; | ||
549 | } | ||
550 | |||
551 | ret = meson_pcie_get_mems(pdev, mp); | ||
552 | if (ret) { | ||
553 | dev_err(dev, "get memory resource failed, %d\n", ret); | ||
554 | return ret; | ||
555 | } | ||
556 | |||
557 | meson_pcie_power_on(mp); | ||
558 | meson_pcie_reset(mp); | ||
559 | |||
560 | ret = meson_pcie_probe_clocks(mp); | ||
561 | if (ret) { | ||
562 | dev_err(dev, "init clock resources failed, %d\n", ret); | ||
563 | return ret; | ||
564 | } | ||
565 | |||
566 | platform_set_drvdata(pdev, mp); | ||
567 | |||
568 | ret = meson_add_pcie_port(mp, pdev); | ||
569 | if (ret < 0) { | ||
570 | dev_err(dev, "Add PCIe port failed, %d\n", ret); | ||
571 | return ret; | ||
572 | } | ||
573 | |||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | static const struct of_device_id meson_pcie_of_match[] = { | ||
578 | { | ||
579 | .compatible = "amlogic,axg-pcie", | ||
580 | }, | ||
581 | {}, | ||
582 | }; | ||
583 | |||
584 | static struct platform_driver meson_pcie_driver = { | ||
585 | .probe = meson_pcie_probe, | ||
586 | .driver = { | ||
587 | .name = "meson-pcie", | ||
588 | .of_match_table = meson_pcie_of_match, | ||
589 | }, | ||
590 | }; | ||
591 | |||
592 | builtin_platform_driver(meson_pcie_driver); | ||
diff --git a/drivers/pci/controller/dwc/pcie-armada8k.c b/drivers/pci/controller/dwc/pcie-armada8k.c index 0c389a30ef5d..b171b6bc15c8 100644 --- a/drivers/pci/controller/dwc/pcie-armada8k.c +++ b/drivers/pci/controller/dwc/pcie-armada8k.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/resource.h> | 22 | #include <linux/resource.h> |
23 | #include <linux/of_pci.h> | 23 | #include <linux/of_pci.h> |
24 | #include <linux/of_irq.h> | 24 | #include <linux/of_irq.h> |
25 | #include <linux/gpio/consumer.h> | ||
25 | 26 | ||
26 | #include "pcie-designware.h" | 27 | #include "pcie-designware.h" |
27 | 28 | ||
@@ -29,6 +30,7 @@ struct armada8k_pcie { | |||
29 | struct dw_pcie *pci; | 30 | struct dw_pcie *pci; |
30 | struct clk *clk; | 31 | struct clk *clk; |
31 | struct clk *clk_reg; | 32 | struct clk *clk_reg; |
33 | struct gpio_desc *reset_gpio; | ||
32 | }; | 34 | }; |
33 | 35 | ||
34 | #define PCIE_VENDOR_REGS_OFFSET 0x8000 | 36 | #define PCIE_VENDOR_REGS_OFFSET 0x8000 |
@@ -137,6 +139,12 @@ static int armada8k_pcie_host_init(struct pcie_port *pp) | |||
137 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | 139 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); |
138 | struct armada8k_pcie *pcie = to_armada8k_pcie(pci); | 140 | struct armada8k_pcie *pcie = to_armada8k_pcie(pci); |
139 | 141 | ||
142 | if (pcie->reset_gpio) { | ||
143 | /* assert and then deassert the reset signal */ | ||
144 | gpiod_set_value_cansleep(pcie->reset_gpio, 1); | ||
145 | msleep(100); | ||
146 | gpiod_set_value_cansleep(pcie->reset_gpio, 0); | ||
147 | } | ||
140 | dw_pcie_setup_rc(pp); | 148 | dw_pcie_setup_rc(pp); |
141 | armada8k_pcie_establish_link(pcie); | 149 | armada8k_pcie_establish_link(pcie); |
142 | 150 | ||
@@ -249,6 +257,14 @@ static int armada8k_pcie_probe(struct platform_device *pdev) | |||
249 | goto fail_clkreg; | 257 | goto fail_clkreg; |
250 | } | 258 | } |
251 | 259 | ||
260 | /* Get reset gpio signal and hold asserted (logically high) */ | ||
261 | pcie->reset_gpio = devm_gpiod_get_optional(dev, "reset", | ||
262 | GPIOD_OUT_HIGH); | ||
263 | if (IS_ERR(pcie->reset_gpio)) { | ||
264 | ret = PTR_ERR(pcie->reset_gpio); | ||
265 | goto fail_clkreg; | ||
266 | } | ||
267 | |||
252 | platform_set_drvdata(pdev, pcie); | 268 | platform_set_drvdata(pdev, pcie); |
253 | 269 | ||
254 | ret = armada8k_add_pcie_port(pcie, pdev); | 270 | ret = armada8k_add_pcie_port(pcie, pdev); |
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index de8635af4cde..a543c45c7224 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c | |||
@@ -503,6 +503,10 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) | |||
503 | dev_err(dev, "dbi_base/dbi_base2 is not populated\n"); | 503 | dev_err(dev, "dbi_base/dbi_base2 is not populated\n"); |
504 | return -EINVAL; | 504 | return -EINVAL; |
505 | } | 505 | } |
506 | if (pci->iatu_unroll_enabled && !pci->atu_base) { | ||
507 | dev_err(dev, "atu_base is not populated\n"); | ||
508 | return -EINVAL; | ||
509 | } | ||
506 | 510 | ||
507 | ret = of_property_read_u32(np, "num-ib-windows", &ep->num_ib_windows); | 511 | ret = of_property_read_u32(np, "num-ib-windows", &ep->num_ib_windows); |
508 | if (ret < 0) { | 512 | if (ret < 0) { |
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 29a05759a294..721d60a5d9e4 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c | |||
@@ -99,9 +99,6 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) | |||
99 | (i * MAX_MSI_IRQS_PER_CTRL) + | 99 | (i * MAX_MSI_IRQS_PER_CTRL) + |
100 | pos); | 100 | pos); |
101 | generic_handle_irq(irq); | 101 | generic_handle_irq(irq); |
102 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + | ||
103 | (i * MSI_REG_CTRL_BLOCK_SIZE), | ||
104 | 4, 1 << pos); | ||
105 | pos++; | 102 | pos++; |
106 | } | 103 | } |
107 | } | 104 | } |
@@ -168,8 +165,8 @@ static void dw_pci_bottom_mask(struct irq_data *data) | |||
168 | bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL; | 165 | bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL; |
169 | 166 | ||
170 | pp->irq_status[ctrl] &= ~(1 << bit); | 167 | pp->irq_status[ctrl] &= ~(1 << bit); |
171 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, | 168 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4, |
172 | pp->irq_status[ctrl]); | 169 | ~pp->irq_status[ctrl]); |
173 | } | 170 | } |
174 | 171 | ||
175 | raw_spin_unlock_irqrestore(&pp->lock, flags); | 172 | raw_spin_unlock_irqrestore(&pp->lock, flags); |
@@ -191,8 +188,8 @@ static void dw_pci_bottom_unmask(struct irq_data *data) | |||
191 | bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL; | 188 | bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL; |
192 | 189 | ||
193 | pp->irq_status[ctrl] |= 1 << bit; | 190 | pp->irq_status[ctrl] |= 1 << bit; |
194 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, | 191 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4, |
195 | pp->irq_status[ctrl]); | 192 | ~pp->irq_status[ctrl]); |
196 | } | 193 | } |
197 | 194 | ||
198 | raw_spin_unlock_irqrestore(&pp->lock, flags); | 195 | raw_spin_unlock_irqrestore(&pp->lock, flags); |
@@ -200,13 +197,22 @@ static void dw_pci_bottom_unmask(struct irq_data *data) | |||
200 | 197 | ||
201 | static void dw_pci_bottom_ack(struct irq_data *d) | 198 | static void dw_pci_bottom_ack(struct irq_data *d) |
202 | { | 199 | { |
203 | struct msi_desc *msi = irq_data_get_msi_desc(d); | 200 | struct pcie_port *pp = irq_data_get_irq_chip_data(d); |
204 | struct pcie_port *pp; | 201 | unsigned int res, bit, ctrl; |
202 | unsigned long flags; | ||
203 | |||
204 | ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL; | ||
205 | res = ctrl * MSI_REG_CTRL_BLOCK_SIZE; | ||
206 | bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL; | ||
207 | |||
208 | raw_spin_lock_irqsave(&pp->lock, flags); | ||
205 | 209 | ||
206 | pp = msi_desc_to_pci_sysdata(msi); | 210 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + res, 4, 1 << bit); |
207 | 211 | ||
208 | if (pp->ops->msi_irq_ack) | 212 | if (pp->ops->msi_irq_ack) |
209 | pp->ops->msi_irq_ack(d->hwirq, pp); | 213 | pp->ops->msi_irq_ack(d->hwirq, pp); |
214 | |||
215 | raw_spin_unlock_irqrestore(&pp->lock, flags); | ||
210 | } | 216 | } |
211 | 217 | ||
212 | static struct irq_chip dw_pci_msi_bottom_irq_chip = { | 218 | static struct irq_chip dw_pci_msi_bottom_irq_chip = { |
@@ -658,10 +664,15 @@ void dw_pcie_setup_rc(struct pcie_port *pp) | |||
658 | num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL; | 664 | num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL; |
659 | 665 | ||
660 | /* Initialize IRQ Status array */ | 666 | /* Initialize IRQ Status array */ |
661 | for (ctrl = 0; ctrl < num_ctrls; ctrl++) | 667 | for (ctrl = 0; ctrl < num_ctrls; ctrl++) { |
662 | dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + | 668 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + |
669 | (ctrl * MSI_REG_CTRL_BLOCK_SIZE), | ||
670 | 4, ~0); | ||
671 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + | ||
663 | (ctrl * MSI_REG_CTRL_BLOCK_SIZE), | 672 | (ctrl * MSI_REG_CTRL_BLOCK_SIZE), |
664 | 4, &pp->irq_status[ctrl]); | 673 | 4, ~0); |
674 | pp->irq_status[ctrl] = 0; | ||
675 | } | ||
665 | 676 | ||
666 | /* Setup RC BARs */ | 677 | /* Setup RC BARs */ |
667 | dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0x00000004); | 678 | dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0x00000004); |
@@ -699,6 +710,9 @@ void dw_pcie_setup_rc(struct pcie_port *pp) | |||
699 | dev_dbg(pci->dev, "iATU unroll: %s\n", | 710 | dev_dbg(pci->dev, "iATU unroll: %s\n", |
700 | pci->iatu_unroll_enabled ? "enabled" : "disabled"); | 711 | pci->iatu_unroll_enabled ? "enabled" : "disabled"); |
701 | 712 | ||
713 | if (pci->iatu_unroll_enabled && !pci->atu_base) | ||
714 | pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; | ||
715 | |||
702 | dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0, | 716 | dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0, |
703 | PCIE_ATU_TYPE_MEM, pp->mem_base, | 717 | PCIE_ATU_TYPE_MEM, pp->mem_base, |
704 | pp->mem_bus_addr, pp->mem_size); | 718 | pp->mem_bus_addr, pp->mem_size); |
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 2153956a0b20..93ef8c31fb39 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c | |||
@@ -93,7 +93,7 @@ static u32 dw_pcie_readl_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg) | |||
93 | { | 93 | { |
94 | u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); | 94 | u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); |
95 | 95 | ||
96 | return dw_pcie_readl_dbi(pci, offset + reg); | 96 | return dw_pcie_readl_atu(pci, offset + reg); |
97 | } | 97 | } |
98 | 98 | ||
99 | static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg, | 99 | static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg, |
@@ -101,7 +101,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg, | |||
101 | { | 101 | { |
102 | u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); | 102 | u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); |
103 | 103 | ||
104 | dw_pcie_writel_dbi(pci, offset + reg, val); | 104 | dw_pcie_writel_atu(pci, offset + reg, val); |
105 | } | 105 | } |
106 | 106 | ||
107 | static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index, | 107 | static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index, |
@@ -187,7 +187,7 @@ static u32 dw_pcie_readl_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg) | |||
187 | { | 187 | { |
188 | u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index); | 188 | u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index); |
189 | 189 | ||
190 | return dw_pcie_readl_dbi(pci, offset + reg); | 190 | return dw_pcie_readl_atu(pci, offset + reg); |
191 | } | 191 | } |
192 | 192 | ||
193 | static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg, | 193 | static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg, |
@@ -195,7 +195,7 @@ static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg, | |||
195 | { | 195 | { |
196 | u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index); | 196 | u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index); |
197 | 197 | ||
198 | dw_pcie_writel_dbi(pci, offset + reg, val); | 198 | dw_pcie_writel_atu(pci, offset + reg, val); |
199 | } | 199 | } |
200 | 200 | ||
201 | static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index, | 201 | static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index, |
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 0989d880ac46..9943d8c68335 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h | |||
@@ -92,12 +92,20 @@ | |||
92 | #define PCIE_ATU_UNR_LOWER_TARGET 0x14 | 92 | #define PCIE_ATU_UNR_LOWER_TARGET 0x14 |
93 | #define PCIE_ATU_UNR_UPPER_TARGET 0x18 | 93 | #define PCIE_ATU_UNR_UPPER_TARGET 0x18 |
94 | 94 | ||
95 | /* | ||
96 | * The default address offset between dbi_base and atu_base. Root controller | ||
97 | * drivers are not required to initialize atu_base if the offset matches this | ||
98 | * default; the driver core automatically derives atu_base from dbi_base using | ||
99 | * this offset, if atu_base not set. | ||
100 | */ | ||
101 | #define DEFAULT_DBI_ATU_OFFSET (0x3 << 20) | ||
102 | |||
95 | /* Register address builder */ | 103 | /* Register address builder */ |
96 | #define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) \ | 104 | #define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) \ |
97 | ((0x3 << 20) | ((region) << 9)) | 105 | ((region) << 9) |
98 | 106 | ||
99 | #define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \ | 107 | #define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \ |
100 | ((0x3 << 20) | ((region) << 9) | (0x1 << 8)) | 108 | (((region) << 9) | (0x1 << 8)) |
101 | 109 | ||
102 | #define MAX_MSI_IRQS 256 | 110 | #define MAX_MSI_IRQS 256 |
103 | #define MAX_MSI_IRQS_PER_CTRL 32 | 111 | #define MAX_MSI_IRQS_PER_CTRL 32 |
@@ -219,6 +227,8 @@ struct dw_pcie { | |||
219 | struct device *dev; | 227 | struct device *dev; |
220 | void __iomem *dbi_base; | 228 | void __iomem *dbi_base; |
221 | void __iomem *dbi_base2; | 229 | void __iomem *dbi_base2; |
230 | /* Used when iatu_unroll_enabled is true */ | ||
231 | void __iomem *atu_base; | ||
222 | u32 num_viewport; | 232 | u32 num_viewport; |
223 | u8 iatu_unroll_enabled; | 233 | u8 iatu_unroll_enabled; |
224 | struct pcie_port pp; | 234 | struct pcie_port pp; |
@@ -289,6 +299,16 @@ static inline u32 dw_pcie_readl_dbi2(struct dw_pcie *pci, u32 reg) | |||
289 | return __dw_pcie_read_dbi(pci, pci->dbi_base2, reg, 0x4); | 299 | return __dw_pcie_read_dbi(pci, pci->dbi_base2, reg, 0x4); |
290 | } | 300 | } |
291 | 301 | ||
302 | static inline void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val) | ||
303 | { | ||
304 | __dw_pcie_write_dbi(pci, pci->atu_base, reg, 0x4, val); | ||
305 | } | ||
306 | |||
307 | static inline u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg) | ||
308 | { | ||
309 | return __dw_pcie_read_dbi(pci, pci->atu_base, reg, 0x4); | ||
310 | } | ||
311 | |||
292 | static inline void dw_pcie_dbi_ro_wr_en(struct dw_pcie *pci) | 312 | static inline void dw_pcie_dbi_ro_wr_en(struct dw_pcie *pci) |
293 | { | 313 | { |
294 | u32 reg; | 314 | u32 reg; |
diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c index 7b32e619b959..954bc2b74bbc 100644 --- a/drivers/pci/controller/dwc/pcie-histb.c +++ b/drivers/pci/controller/dwc/pcie-histb.c | |||
@@ -202,7 +202,7 @@ static int histb_pcie_host_init(struct pcie_port *pp) | |||
202 | return 0; | 202 | return 0; |
203 | } | 203 | } |
204 | 204 | ||
205 | static struct dw_pcie_host_ops histb_pcie_host_ops = { | 205 | static const struct dw_pcie_host_ops histb_pcie_host_ops = { |
206 | .rd_own_conf = histb_pcie_rd_own_conf, | 206 | .rd_own_conf = histb_pcie_rd_own_conf, |
207 | .wr_own_conf = histb_pcie_wr_own_conf, | 207 | .wr_own_conf = histb_pcie_wr_own_conf, |
208 | .host_init = histb_pcie_host_init, | 208 | .host_init = histb_pcie_host_init, |
diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c new file mode 100644 index 000000000000..d5dc40289cce --- /dev/null +++ b/drivers/pci/controller/dwc/pcie-uniphier.c | |||
@@ -0,0 +1,471 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * PCIe host controller driver for UniPhier SoCs | ||
4 | * Copyright 2018 Socionext Inc. | ||
5 | * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> | ||
6 | */ | ||
7 | |||
8 | #include <linux/bitops.h> | ||
9 | #include <linux/bitfield.h> | ||
10 | #include <linux/clk.h> | ||
11 | #include <linux/delay.h> | ||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/iopoll.h> | ||
14 | #include <linux/irqchip/chained_irq.h> | ||
15 | #include <linux/irqdomain.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/of_irq.h> | ||
18 | #include <linux/pci.h> | ||
19 | #include <linux/phy/phy.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/reset.h> | ||
22 | |||
23 | #include "pcie-designware.h" | ||
24 | |||
25 | #define PCL_PINCTRL0 0x002c | ||
26 | #define PCL_PERST_PLDN_REGEN BIT(12) | ||
27 | #define PCL_PERST_NOE_REGEN BIT(11) | ||
28 | #define PCL_PERST_OUT_REGEN BIT(8) | ||
29 | #define PCL_PERST_PLDN_REGVAL BIT(4) | ||
30 | #define PCL_PERST_NOE_REGVAL BIT(3) | ||
31 | #define PCL_PERST_OUT_REGVAL BIT(0) | ||
32 | |||
33 | #define PCL_PIPEMON 0x0044 | ||
34 | #define PCL_PCLK_ALIVE BIT(15) | ||
35 | |||
36 | #define PCL_APP_READY_CTRL 0x8008 | ||
37 | #define PCL_APP_LTSSM_ENABLE BIT(0) | ||
38 | |||
39 | #define PCL_APP_PM0 0x8078 | ||
40 | #define PCL_SYS_AUX_PWR_DET BIT(8) | ||
41 | |||
42 | #define PCL_RCV_INT 0x8108 | ||
43 | #define PCL_RCV_INT_ALL_ENABLE GENMASK(20, 17) | ||
44 | #define PCL_CFG_BW_MGT_STATUS BIT(4) | ||
45 | #define PCL_CFG_LINK_AUTO_BW_STATUS BIT(3) | ||
46 | #define PCL_CFG_AER_RC_ERR_MSI_STATUS BIT(2) | ||
47 | #define PCL_CFG_PME_MSI_STATUS BIT(1) | ||
48 | |||
49 | #define PCL_RCV_INTX 0x810c | ||
50 | #define PCL_RCV_INTX_ALL_ENABLE GENMASK(19, 16) | ||
51 | #define PCL_RCV_INTX_ALL_MASK GENMASK(11, 8) | ||
52 | #define PCL_RCV_INTX_MASK_SHIFT 8 | ||
53 | #define PCL_RCV_INTX_ALL_STATUS GENMASK(3, 0) | ||
54 | #define PCL_RCV_INTX_STATUS_SHIFT 0 | ||
55 | |||
56 | #define PCL_STATUS_LINK 0x8140 | ||
57 | #define PCL_RDLH_LINK_UP BIT(1) | ||
58 | #define PCL_XMLH_LINK_UP BIT(0) | ||
59 | |||
60 | struct uniphier_pcie_priv { | ||
61 | void __iomem *base; | ||
62 | struct dw_pcie pci; | ||
63 | struct clk *clk; | ||
64 | struct reset_control *rst; | ||
65 | struct phy *phy; | ||
66 | struct irq_domain *legacy_irq_domain; | ||
67 | }; | ||
68 | |||
69 | #define to_uniphier_pcie(x) dev_get_drvdata((x)->dev) | ||
70 | |||
71 | static void uniphier_pcie_ltssm_enable(struct uniphier_pcie_priv *priv, | ||
72 | bool enable) | ||
73 | { | ||
74 | u32 val; | ||
75 | |||
76 | val = readl(priv->base + PCL_APP_READY_CTRL); | ||
77 | if (enable) | ||
78 | val |= PCL_APP_LTSSM_ENABLE; | ||
79 | else | ||
80 | val &= ~PCL_APP_LTSSM_ENABLE; | ||
81 | writel(val, priv->base + PCL_APP_READY_CTRL); | ||
82 | } | ||
83 | |||
84 | static void uniphier_pcie_init_rc(struct uniphier_pcie_priv *priv) | ||
85 | { | ||
86 | u32 val; | ||
87 | |||
88 | /* use auxiliary power detection */ | ||
89 | val = readl(priv->base + PCL_APP_PM0); | ||
90 | val |= PCL_SYS_AUX_PWR_DET; | ||
91 | writel(val, priv->base + PCL_APP_PM0); | ||
92 | |||
93 | /* assert PERST# */ | ||
94 | val = readl(priv->base + PCL_PINCTRL0); | ||
95 | val &= ~(PCL_PERST_NOE_REGVAL | PCL_PERST_OUT_REGVAL | ||
96 | | PCL_PERST_PLDN_REGVAL); | ||
97 | val |= PCL_PERST_NOE_REGEN | PCL_PERST_OUT_REGEN | ||
98 | | PCL_PERST_PLDN_REGEN; | ||
99 | writel(val, priv->base + PCL_PINCTRL0); | ||
100 | |||
101 | uniphier_pcie_ltssm_enable(priv, false); | ||
102 | |||
103 | usleep_range(100000, 200000); | ||
104 | |||
105 | /* deassert PERST# */ | ||
106 | val = readl(priv->base + PCL_PINCTRL0); | ||
107 | val |= PCL_PERST_OUT_REGVAL | PCL_PERST_OUT_REGEN; | ||
108 | writel(val, priv->base + PCL_PINCTRL0); | ||
109 | } | ||
110 | |||
111 | static int uniphier_pcie_wait_rc(struct uniphier_pcie_priv *priv) | ||
112 | { | ||
113 | u32 status; | ||
114 | int ret; | ||
115 | |||
116 | /* wait PIPE clock */ | ||
117 | ret = readl_poll_timeout(priv->base + PCL_PIPEMON, status, | ||
118 | status & PCL_PCLK_ALIVE, 100000, 1000000); | ||
119 | if (ret) { | ||
120 | dev_err(priv->pci.dev, | ||
121 | "Failed to initialize controller in RC mode\n"); | ||
122 | return ret; | ||
123 | } | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int uniphier_pcie_link_up(struct dw_pcie *pci) | ||
129 | { | ||
130 | struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci); | ||
131 | u32 val, mask; | ||
132 | |||
133 | val = readl(priv->base + PCL_STATUS_LINK); | ||
134 | mask = PCL_RDLH_LINK_UP | PCL_XMLH_LINK_UP; | ||
135 | |||
136 | return (val & mask) == mask; | ||
137 | } | ||
138 | |||
139 | static int uniphier_pcie_establish_link(struct dw_pcie *pci) | ||
140 | { | ||
141 | struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci); | ||
142 | |||
143 | if (dw_pcie_link_up(pci)) | ||
144 | return 0; | ||
145 | |||
146 | uniphier_pcie_ltssm_enable(priv, true); | ||
147 | |||
148 | return dw_pcie_wait_for_link(pci); | ||
149 | } | ||
150 | |||
151 | static void uniphier_pcie_stop_link(struct dw_pcie *pci) | ||
152 | { | ||
153 | struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci); | ||
154 | |||
155 | uniphier_pcie_ltssm_enable(priv, false); | ||
156 | } | ||
157 | |||
158 | static void uniphier_pcie_irq_enable(struct uniphier_pcie_priv *priv) | ||
159 | { | ||
160 | writel(PCL_RCV_INT_ALL_ENABLE, priv->base + PCL_RCV_INT); | ||
161 | writel(PCL_RCV_INTX_ALL_ENABLE, priv->base + PCL_RCV_INTX); | ||
162 | } | ||
163 | |||
164 | static void uniphier_pcie_irq_disable(struct uniphier_pcie_priv *priv) | ||
165 | { | ||
166 | writel(0, priv->base + PCL_RCV_INT); | ||
167 | writel(0, priv->base + PCL_RCV_INTX); | ||
168 | } | ||
169 | |||
170 | static void uniphier_pcie_irq_ack(struct irq_data *d) | ||
171 | { | ||
172 | struct pcie_port *pp = irq_data_get_irq_chip_data(d); | ||
173 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | ||
174 | struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci); | ||
175 | u32 val; | ||
176 | |||
177 | val = readl(priv->base + PCL_RCV_INTX); | ||
178 | val &= ~PCL_RCV_INTX_ALL_STATUS; | ||
179 | val |= BIT(irqd_to_hwirq(d) + PCL_RCV_INTX_STATUS_SHIFT); | ||
180 | writel(val, priv->base + PCL_RCV_INTX); | ||
181 | } | ||
182 | |||
183 | static void uniphier_pcie_irq_mask(struct irq_data *d) | ||
184 | { | ||
185 | struct pcie_port *pp = irq_data_get_irq_chip_data(d); | ||
186 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | ||
187 | struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci); | ||
188 | u32 val; | ||
189 | |||
190 | val = readl(priv->base + PCL_RCV_INTX); | ||
191 | val &= ~PCL_RCV_INTX_ALL_MASK; | ||
192 | val |= BIT(irqd_to_hwirq(d) + PCL_RCV_INTX_MASK_SHIFT); | ||
193 | writel(val, priv->base + PCL_RCV_INTX); | ||
194 | } | ||
195 | |||
196 | static void uniphier_pcie_irq_unmask(struct irq_data *d) | ||
197 | { | ||
198 | struct pcie_port *pp = irq_data_get_irq_chip_data(d); | ||
199 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | ||
200 | struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci); | ||
201 | u32 val; | ||
202 | |||
203 | val = readl(priv->base + PCL_RCV_INTX); | ||
204 | val &= ~PCL_RCV_INTX_ALL_MASK; | ||
205 | val &= ~BIT(irqd_to_hwirq(d) + PCL_RCV_INTX_MASK_SHIFT); | ||
206 | writel(val, priv->base + PCL_RCV_INTX); | ||
207 | } | ||
208 | |||
209 | static struct irq_chip uniphier_pcie_irq_chip = { | ||
210 | .name = "PCI", | ||
211 | .irq_ack = uniphier_pcie_irq_ack, | ||
212 | .irq_mask = uniphier_pcie_irq_mask, | ||
213 | .irq_unmask = uniphier_pcie_irq_unmask, | ||
214 | }; | ||
215 | |||
216 | static int uniphier_pcie_intx_map(struct irq_domain *domain, unsigned int irq, | ||
217 | irq_hw_number_t hwirq) | ||
218 | { | ||
219 | irq_set_chip_and_handler(irq, &uniphier_pcie_irq_chip, | ||
220 | handle_level_irq); | ||
221 | irq_set_chip_data(irq, domain->host_data); | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static const struct irq_domain_ops uniphier_intx_domain_ops = { | ||
227 | .map = uniphier_pcie_intx_map, | ||
228 | }; | ||
229 | |||
230 | static void uniphier_pcie_irq_handler(struct irq_desc *desc) | ||
231 | { | ||
232 | struct pcie_port *pp = irq_desc_get_handler_data(desc); | ||
233 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | ||
234 | struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci); | ||
235 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
236 | unsigned long reg; | ||
237 | u32 val, bit, virq; | ||
238 | |||
239 | /* INT for debug */ | ||
240 | val = readl(priv->base + PCL_RCV_INT); | ||
241 | |||
242 | if (val & PCL_CFG_BW_MGT_STATUS) | ||
243 | dev_dbg(pci->dev, "Link Bandwidth Management Event\n"); | ||
244 | if (val & PCL_CFG_LINK_AUTO_BW_STATUS) | ||
245 | dev_dbg(pci->dev, "Link Autonomous Bandwidth Event\n"); | ||
246 | if (val & PCL_CFG_AER_RC_ERR_MSI_STATUS) | ||
247 | dev_dbg(pci->dev, "Root Error\n"); | ||
248 | if (val & PCL_CFG_PME_MSI_STATUS) | ||
249 | dev_dbg(pci->dev, "PME Interrupt\n"); | ||
250 | |||
251 | writel(val, priv->base + PCL_RCV_INT); | ||
252 | |||
253 | /* INTx */ | ||
254 | chained_irq_enter(chip, desc); | ||
255 | |||
256 | val = readl(priv->base + PCL_RCV_INTX); | ||
257 | reg = FIELD_GET(PCL_RCV_INTX_ALL_STATUS, val); | ||
258 | |||
259 | for_each_set_bit(bit, ®, PCI_NUM_INTX) { | ||
260 | virq = irq_linear_revmap(priv->legacy_irq_domain, bit); | ||
261 | generic_handle_irq(virq); | ||
262 | } | ||
263 | |||
264 | chained_irq_exit(chip, desc); | ||
265 | } | ||
266 | |||
267 | static int uniphier_pcie_config_legacy_irq(struct pcie_port *pp) | ||
268 | { | ||
269 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | ||
270 | struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci); | ||
271 | struct device_node *np = pci->dev->of_node; | ||
272 | struct device_node *np_intc; | ||
273 | |||
274 | np_intc = of_get_child_by_name(np, "legacy-interrupt-controller"); | ||
275 | if (!np_intc) { | ||
276 | dev_err(pci->dev, "Failed to get legacy-interrupt-controller node\n"); | ||
277 | return -EINVAL; | ||
278 | } | ||
279 | |||
280 | pp->irq = irq_of_parse_and_map(np_intc, 0); | ||
281 | if (!pp->irq) { | ||
282 | dev_err(pci->dev, "Failed to get an IRQ entry in legacy-interrupt-controller\n"); | ||
283 | return -EINVAL; | ||
284 | } | ||
285 | |||
286 | priv->legacy_irq_domain = irq_domain_add_linear(np_intc, PCI_NUM_INTX, | ||
287 | &uniphier_intx_domain_ops, pp); | ||
288 | if (!priv->legacy_irq_domain) { | ||
289 | dev_err(pci->dev, "Failed to get INTx domain\n"); | ||
290 | return -ENODEV; | ||
291 | } | ||
292 | |||
293 | irq_set_chained_handler_and_data(pp->irq, uniphier_pcie_irq_handler, | ||
294 | pp); | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static int uniphier_pcie_host_init(struct pcie_port *pp) | ||
300 | { | ||
301 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | ||
302 | struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci); | ||
303 | int ret; | ||
304 | |||
305 | ret = uniphier_pcie_config_legacy_irq(pp); | ||
306 | if (ret) | ||
307 | return ret; | ||
308 | |||
309 | uniphier_pcie_irq_enable(priv); | ||
310 | |||
311 | dw_pcie_setup_rc(pp); | ||
312 | ret = uniphier_pcie_establish_link(pci); | ||
313 | if (ret) | ||
314 | return ret; | ||
315 | |||
316 | if (IS_ENABLED(CONFIG_PCI_MSI)) | ||
317 | dw_pcie_msi_init(pp); | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | static const struct dw_pcie_host_ops uniphier_pcie_host_ops = { | ||
323 | .host_init = uniphier_pcie_host_init, | ||
324 | }; | ||
325 | |||
326 | static int uniphier_add_pcie_port(struct uniphier_pcie_priv *priv, | ||
327 | struct platform_device *pdev) | ||
328 | { | ||
329 | struct dw_pcie *pci = &priv->pci; | ||
330 | struct pcie_port *pp = &pci->pp; | ||
331 | struct device *dev = &pdev->dev; | ||
332 | int ret; | ||
333 | |||
334 | pp->ops = &uniphier_pcie_host_ops; | ||
335 | |||
336 | if (IS_ENABLED(CONFIG_PCI_MSI)) { | ||
337 | pp->msi_irq = platform_get_irq_byname(pdev, "msi"); | ||
338 | if (pp->msi_irq < 0) | ||
339 | return pp->msi_irq; | ||
340 | } | ||
341 | |||
342 | ret = dw_pcie_host_init(pp); | ||
343 | if (ret) { | ||
344 | dev_err(dev, "Failed to initialize host (%d)\n", ret); | ||
345 | return ret; | ||
346 | } | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static int uniphier_pcie_host_enable(struct uniphier_pcie_priv *priv) | ||
352 | { | ||
353 | int ret; | ||
354 | |||
355 | ret = clk_prepare_enable(priv->clk); | ||
356 | if (ret) | ||
357 | return ret; | ||
358 | |||
359 | ret = reset_control_deassert(priv->rst); | ||
360 | if (ret) | ||
361 | goto out_clk_disable; | ||
362 | |||
363 | uniphier_pcie_init_rc(priv); | ||
364 | |||
365 | ret = phy_init(priv->phy); | ||
366 | if (ret) | ||
367 | goto out_rst_assert; | ||
368 | |||
369 | ret = uniphier_pcie_wait_rc(priv); | ||
370 | if (ret) | ||
371 | goto out_phy_exit; | ||
372 | |||
373 | return 0; | ||
374 | |||
375 | out_phy_exit: | ||
376 | phy_exit(priv->phy); | ||
377 | out_rst_assert: | ||
378 | reset_control_assert(priv->rst); | ||
379 | out_clk_disable: | ||
380 | clk_disable_unprepare(priv->clk); | ||
381 | |||
382 | return ret; | ||
383 | } | ||
384 | |||
385 | static void uniphier_pcie_host_disable(struct uniphier_pcie_priv *priv) | ||
386 | { | ||
387 | uniphier_pcie_irq_disable(priv); | ||
388 | phy_exit(priv->phy); | ||
389 | reset_control_assert(priv->rst); | ||
390 | clk_disable_unprepare(priv->clk); | ||
391 | } | ||
392 | |||
393 | static const struct dw_pcie_ops dw_pcie_ops = { | ||
394 | .start_link = uniphier_pcie_establish_link, | ||
395 | .stop_link = uniphier_pcie_stop_link, | ||
396 | .link_up = uniphier_pcie_link_up, | ||
397 | }; | ||
398 | |||
399 | static int uniphier_pcie_probe(struct platform_device *pdev) | ||
400 | { | ||
401 | struct device *dev = &pdev->dev; | ||
402 | struct uniphier_pcie_priv *priv; | ||
403 | struct resource *res; | ||
404 | int ret; | ||
405 | |||
406 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
407 | if (!priv) | ||
408 | return -ENOMEM; | ||
409 | |||
410 | priv->pci.dev = dev; | ||
411 | priv->pci.ops = &dw_pcie_ops; | ||
412 | |||
413 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); | ||
414 | priv->pci.dbi_base = devm_pci_remap_cfg_resource(dev, res); | ||
415 | if (IS_ERR(priv->pci.dbi_base)) | ||
416 | return PTR_ERR(priv->pci.dbi_base); | ||
417 | |||
418 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "link"); | ||
419 | priv->base = devm_ioremap_resource(dev, res); | ||
420 | if (IS_ERR(priv->base)) | ||
421 | return PTR_ERR(priv->base); | ||
422 | |||
423 | priv->clk = devm_clk_get(dev, NULL); | ||
424 | if (IS_ERR(priv->clk)) | ||
425 | return PTR_ERR(priv->clk); | ||
426 | |||
427 | priv->rst = devm_reset_control_get_shared(dev, NULL); | ||
428 | if (IS_ERR(priv->rst)) | ||
429 | return PTR_ERR(priv->rst); | ||
430 | |||
431 | priv->phy = devm_phy_optional_get(dev, "pcie-phy"); | ||
432 | if (IS_ERR(priv->phy)) | ||
433 | return PTR_ERR(priv->phy); | ||
434 | |||
435 | platform_set_drvdata(pdev, priv); | ||
436 | |||
437 | ret = uniphier_pcie_host_enable(priv); | ||
438 | if (ret) | ||
439 | return ret; | ||
440 | |||
441 | return uniphier_add_pcie_port(priv, pdev); | ||
442 | } | ||
443 | |||
444 | static int uniphier_pcie_remove(struct platform_device *pdev) | ||
445 | { | ||
446 | struct uniphier_pcie_priv *priv = platform_get_drvdata(pdev); | ||
447 | |||
448 | uniphier_pcie_host_disable(priv); | ||
449 | |||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | static const struct of_device_id uniphier_pcie_match[] = { | ||
454 | { .compatible = "socionext,uniphier-pcie", }, | ||
455 | { /* sentinel */ }, | ||
456 | }; | ||
457 | MODULE_DEVICE_TABLE(of, uniphier_pcie_match); | ||
458 | |||
459 | static struct platform_driver uniphier_pcie_driver = { | ||
460 | .probe = uniphier_pcie_probe, | ||
461 | .remove = uniphier_pcie_remove, | ||
462 | .driver = { | ||
463 | .name = "uniphier-pcie", | ||
464 | .of_match_table = uniphier_pcie_match, | ||
465 | }, | ||
466 | }; | ||
467 | builtin_platform_driver(uniphier_pcie_driver); | ||
468 | |||
469 | MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>"); | ||
470 | MODULE_DESCRIPTION("UniPhier PCIe host controller driver"); | ||
471 | MODULE_LICENSE("GPL v2"); | ||