diff options
author | Minghuan Lian <Minghuan.Lian@freescale.com> | 2014-11-05 03:45:11 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2014-11-13 11:31:52 -0500 |
commit | 62d0ff83c6e2221662fa0dccf2de096bdc7a2fc4 (patch) | |
tree | a28f30c8b8bb8585e1ede12217ac18efe2041f61 /drivers/pci | |
parent | f114040e3ea6e07372334ade75d1ee0775c355e1 (diff) |
PCI: layerscape: Add Freescale Layerscape PCIe driver
Add support for Freescale Layerscape PCIe controller. This driver re-uses
the Synopsis DesignWare core code.
[bhelgaas: add Kconfig dependency on CONFIG_ARM]
Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/host/Kconfig | 8 | ||||
-rw-r--r-- | drivers/pci/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/pci/host/pci-layerscape.c | 179 |
3 files changed, 188 insertions, 0 deletions
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 3dc25fad490c..67e2cc5a0bd4 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig | |||
@@ -91,4 +91,12 @@ config PCI_XGENE | |||
91 | There are 5 internal PCIe ports available. Each port is GEN3 capable | 91 | There are 5 internal PCIe ports available. Each port is GEN3 capable |
92 | and have varied lanes from x1 to x8. | 92 | and have varied lanes from x1 to x8. |
93 | 93 | ||
94 | config PCI_LAYERSCAPE | ||
95 | bool "Freescale Layerscape PCIe controller" | ||
96 | depends on OF && ARM | ||
97 | select PCIE_DW | ||
98 | select MFD_SYSCON | ||
99 | help | ||
100 | Say Y here if you want PCIe controller support on Layerscape SoCs. | ||
101 | |||
94 | endmenu | 102 | endmenu |
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 26b3461d68d7..44c26998027f 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile | |||
@@ -11,3 +11,4 @@ obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o | |||
11 | obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o | 11 | obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o |
12 | obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o | 12 | obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o |
13 | obj-$(CONFIG_PCI_XGENE) += pci-xgene.o | 13 | obj-$(CONFIG_PCI_XGENE) += pci-xgene.o |
14 | obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o | ||
diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c new file mode 100644 index 000000000000..6697b1a4d4fa --- /dev/null +++ b/drivers/pci/host/pci-layerscape.c | |||
@@ -0,0 +1,179 @@ | |||
1 | /* | ||
2 | * PCIe host controller driver for Freescale Layerscape SoCs | ||
3 | * | ||
4 | * Copyright (C) 2014 Freescale Semiconductor. | ||
5 | * | ||
6 | * Author: Minghuan Lian <Minghuan.Lian@freescale.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/of_pci.h> | ||
18 | #include <linux/of_platform.h> | ||
19 | #include <linux/of_irq.h> | ||
20 | #include <linux/of_address.h> | ||
21 | #include <linux/pci.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/resource.h> | ||
24 | #include <linux/mfd/syscon.h> | ||
25 | #include <linux/regmap.h> | ||
26 | |||
27 | #include "pcie-designware.h" | ||
28 | |||
29 | /* PEX1/2 Misc Ports Status Register */ | ||
30 | #define SCFG_PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4) | ||
31 | #define LTSSM_STATE_SHIFT 20 | ||
32 | #define LTSSM_STATE_MASK 0x3f | ||
33 | #define LTSSM_PCIE_L0 0x11 /* L0 state */ | ||
34 | |||
35 | /* Symbol Timer Register and Filter Mask Register 1 */ | ||
36 | #define PCIE_STRFMR1 0x71c | ||
37 | |||
38 | struct ls_pcie { | ||
39 | struct list_head node; | ||
40 | struct device *dev; | ||
41 | struct pci_bus *bus; | ||
42 | void __iomem *dbi; | ||
43 | struct regmap *scfg; | ||
44 | struct pcie_port pp; | ||
45 | int index; | ||
46 | int msi_irq; | ||
47 | }; | ||
48 | |||
49 | #define to_ls_pcie(x) container_of(x, struct ls_pcie, pp) | ||
50 | |||
51 | static int ls_pcie_link_up(struct pcie_port *pp) | ||
52 | { | ||
53 | u32 state; | ||
54 | struct ls_pcie *pcie = to_ls_pcie(pp); | ||
55 | |||
56 | regmap_read(pcie->scfg, SCFG_PEXMSCPORTSR(pcie->index), &state); | ||
57 | state = (state >> LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK; | ||
58 | |||
59 | if (state < LTSSM_PCIE_L0) | ||
60 | return 0; | ||
61 | |||
62 | return 1; | ||
63 | } | ||
64 | |||
65 | static void ls_pcie_host_init(struct pcie_port *pp) | ||
66 | { | ||
67 | struct ls_pcie *pcie = to_ls_pcie(pp); | ||
68 | int count = 0; | ||
69 | u32 val; | ||
70 | |||
71 | dw_pcie_setup_rc(pp); | ||
72 | |||
73 | while (!ls_pcie_link_up(pp)) { | ||
74 | usleep_range(100, 1000); | ||
75 | count++; | ||
76 | if (count >= 200) { | ||
77 | dev_err(pp->dev, "phy link never came up\n"); | ||
78 | return; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * LS1021A Workaround for internal TKT228622 | ||
84 | * to fix the INTx hang issue | ||
85 | */ | ||
86 | val = ioread32(pcie->dbi + PCIE_STRFMR1); | ||
87 | val &= 0xffff; | ||
88 | iowrite32(val, pcie->dbi + PCIE_STRFMR1); | ||
89 | } | ||
90 | |||
91 | static struct pcie_host_ops ls_pcie_host_ops = { | ||
92 | .link_up = ls_pcie_link_up, | ||
93 | .host_init = ls_pcie_host_init, | ||
94 | }; | ||
95 | |||
96 | static int ls_add_pcie_port(struct ls_pcie *pcie) | ||
97 | { | ||
98 | struct pcie_port *pp; | ||
99 | int ret; | ||
100 | |||
101 | pp = &pcie->pp; | ||
102 | pp->dev = pcie->dev; | ||
103 | pp->dbi_base = pcie->dbi; | ||
104 | pp->root_bus_nr = -1; | ||
105 | pp->ops = &ls_pcie_host_ops; | ||
106 | |||
107 | ret = dw_pcie_host_init(pp); | ||
108 | if (ret) { | ||
109 | dev_err(pp->dev, "failed to initialize host\n"); | ||
110 | return ret; | ||
111 | } | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int __init ls_pcie_probe(struct platform_device *pdev) | ||
117 | { | ||
118 | struct ls_pcie *pcie; | ||
119 | struct resource *dbi_base; | ||
120 | u32 index[2]; | ||
121 | int ret; | ||
122 | |||
123 | pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); | ||
124 | if (!pcie) | ||
125 | return -ENOMEM; | ||
126 | |||
127 | pcie->dev = &pdev->dev; | ||
128 | |||
129 | dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); | ||
130 | if (!dbi_base) { | ||
131 | dev_err(&pdev->dev, "missing *regs* space\n"); | ||
132 | return -ENODEV; | ||
133 | } | ||
134 | |||
135 | pcie->dbi = devm_ioremap_resource(&pdev->dev, dbi_base); | ||
136 | if (IS_ERR(pcie->dbi)) | ||
137 | return PTR_ERR(pcie->dbi); | ||
138 | |||
139 | pcie->scfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, | ||
140 | "fsl,pcie-scfg"); | ||
141 | if (IS_ERR(pcie->scfg)) { | ||
142 | dev_err(&pdev->dev, "No syscfg phandle specified\n"); | ||
143 | return PTR_ERR(pcie->scfg); | ||
144 | } | ||
145 | |||
146 | ret = of_property_read_u32_array(pdev->dev.of_node, | ||
147 | "fsl,pcie-scfg", index, 2); | ||
148 | if (ret) | ||
149 | return ret; | ||
150 | pcie->index = index[1]; | ||
151 | |||
152 | ret = ls_add_pcie_port(pcie); | ||
153 | if (ret < 0) | ||
154 | return ret; | ||
155 | |||
156 | platform_set_drvdata(pdev, pcie); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static const struct of_device_id ls_pcie_of_match[] = { | ||
162 | { .compatible = "fsl,ls1021a-pcie" }, | ||
163 | { }, | ||
164 | }; | ||
165 | MODULE_DEVICE_TABLE(of, ls_pcie_of_match); | ||
166 | |||
167 | static struct platform_driver ls_pcie_driver = { | ||
168 | .driver = { | ||
169 | .name = "layerscape-pcie", | ||
170 | .owner = THIS_MODULE, | ||
171 | .of_match_table = ls_pcie_of_match, | ||
172 | }, | ||
173 | }; | ||
174 | |||
175 | module_platform_driver_probe(ls_pcie_driver, ls_pcie_probe); | ||
176 | |||
177 | MODULE_AUTHOR("Minghuan Lian <Minghuan.Lian@freescale.com>"); | ||
178 | MODULE_DESCRIPTION("Freescale Layerscape PCIe host controller driver"); | ||
179 | MODULE_LICENSE("GPL v2"); | ||