summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/pci/pci-thunder-pem.txt43
-rw-r--r--MAINTAINERS8
-rw-r--r--drivers/pci/host/Kconfig7
-rw-r--r--drivers/pci/host/Makefile1
-rw-r--r--drivers/pci/host/pci-thunder-pem.c346
5 files changed, 405 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/pci/pci-thunder-pem.txt b/Documentation/devicetree/bindings/pci/pci-thunder-pem.txt
new file mode 100644
index 000000000000..f131faea3b7c
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/pci-thunder-pem.txt
@@ -0,0 +1,43 @@
1* ThunderX PEM PCIe host controller
2
3Firmware-initialized PCI host controller found on some Cavium
4ThunderX processors.
5
6The properties and their meanings are identical to those described in
7host-generic-pci.txt except as listed below.
8
9Properties of the host controller node that differ from
10host-generic-pci.txt:
11
12- compatible : Must be "cavium,pci-host-thunder-pem"
13
14- reg : Two entries: First the configuration space for down
15 stream devices base address and size, as accessed
16 from the parent bus. Second, the register bank of
17 the PEM device PCIe bridge.
18
19Example:
20
21 pci@87e0,c2000000 {
22 compatible = "cavium,pci-host-thunder-pem";
23 device_type = "pci";
24 msi-parent = <&its>;
25 msi-map = <0 &its 0x10000 0x10000>;
26 bus-range = <0x8f 0xc7>;
27 #size-cells = <2>;
28 #address-cells = <3>;
29
30 reg = <0x8880 0x8f000000 0x0 0x39000000>, /* Configuration space */
31 <0x87e0 0xc2000000 0x0 0x00010000>; /* PEM space */
32 ranges = <0x01000000 0x00 0x00020000 0x88b0 0x00020000 0x00 0x00010000>, /* I/O */
33 <0x03000000 0x00 0x10000000 0x8890 0x10000000 0x0f 0xf0000000>, /* mem64 */
34 <0x43000000 0x10 0x00000000 0x88a0 0x00000000 0x10 0x00000000>, /* mem64-pref */
35 <0x03000000 0x87e0 0xc2f00000 0x87e0 0xc2000000 0x00 0x00100000>; /* mem64 PEM BAR4 */
36
37 #interrupt-cells = <1>;
38 interrupt-map-mask = <0 0 0 7>;
39 interrupt-map = <0 0 0 1 &gic0 0 0 0 24 4>, /* INTA */
40 <0 0 0 2 &gic0 0 0 0 25 4>, /* INTB */
41 <0 0 0 3 &gic0 0 0 0 26 4>, /* INTC */
42 <0 0 0 4 &gic0 0 0 0 27 4>; /* INTD */
43 };
diff --git a/MAINTAINERS b/MAINTAINERS
index 73c5bde6d167..1aa8f82837ea 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8419,6 +8419,14 @@ L: linux-arm-msm@vger.kernel.org
8419S: Maintained 8419S: Maintained
8420F: drivers/pci/host/*qcom* 8420F: drivers/pci/host/*qcom*
8421 8421
8422PCIE DRIVER FOR CAVIUM THUNDERX
8423M: David Daney <david.daney@cavium.com>
8424L: linux-pci@vger.kernel.org
8425L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
8426S: Supported
8427F: Documentation/devicetree/bindings/pci/pci-thunder-*
8428F: drivers/pci/host/pci-thunder-*
8429
8422PCMCIA SUBSYSTEM 8430PCMCIA SUBSYSTEM
8423P: Linux PCMCIA Team 8431P: Linux PCMCIA Team
8424L: linux-pcmcia@lists.infradead.org 8432L: linux-pcmcia@lists.infradead.org
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 65709b4bb3a4..184df22e4a69 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -195,4 +195,11 @@ config PCIE_QCOM
195 PCIe controller uses the Designware core plus Qualcomm-specific 195 PCIe controller uses the Designware core plus Qualcomm-specific
196 hardware wrappers. 196 hardware wrappers.
197 197
198config PCI_HOST_THUNDER_PEM
199 bool "Cavium Thunder PCIe controller to off-chip devices"
200 depends on OF && ARM64
201 select PCI_HOST_COMMON
202 help
203 Say Y here if you want PCIe support for CN88XX Cavium Thunder SoCs.
204
198endmenu 205endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 3b24af860284..890317234dae 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -23,3 +23,4 @@ obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o
23obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o 23obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o
24obj-$(CONFIG_PCI_HISI) += pcie-hisi.o 24obj-$(CONFIG_PCI_HISI) += pcie-hisi.o
25obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o 25obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
26obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o
diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c
new file mode 100644
index 000000000000..cabb92a514ac
--- /dev/null
+++ b/drivers/pci/host/pci-thunder-pem.c
@@ -0,0 +1,346 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License version 2 as
4 * published by the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * along with this program. If not, see <http://www.gnu.org/licenses/>.
13 *
14 * Copyright (C) 2015 - 2016 Cavium, Inc.
15 */
16
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/of_address.h>
20#include <linux/of_pci.h>
21#include <linux/platform_device.h>
22
23#include "pci-host-common.h"
24
25#define PEM_CFG_WR 0x28
26#define PEM_CFG_RD 0x30
27
28struct thunder_pem_pci {
29 struct gen_pci gen_pci;
30 u32 ea_entry[3];
31 void __iomem *pem_reg_base;
32};
33
34static void __iomem *thunder_pem_map_bus(struct pci_bus *bus,
35 unsigned int devfn, int where)
36{
37 struct gen_pci *pci = bus->sysdata;
38 resource_size_t idx = bus->number - pci->cfg.bus_range->start;
39
40 return pci->cfg.win[idx] + ((devfn << 16) | where);
41}
42
43static int thunder_pem_bridge_read(struct pci_bus *bus, unsigned int devfn,
44 int where, int size, u32 *val)
45{
46 u64 read_val;
47 struct thunder_pem_pci *pem_pci;
48 struct gen_pci *pci = bus->sysdata;
49
50 pem_pci = container_of(pci, struct thunder_pem_pci, gen_pci);
51
52 if (devfn != 0 || where >= 2048) {
53 *val = ~0;
54 return PCIBIOS_DEVICE_NOT_FOUND;
55 }
56
57 /*
58 * 32-bit accesses only. Write the address to the low order
59 * bits of PEM_CFG_RD, then trigger the read by reading back.
60 * The config data lands in the upper 32-bits of PEM_CFG_RD.
61 */
62 read_val = where & ~3ull;
63 writeq(read_val, pem_pci->pem_reg_base + PEM_CFG_RD);
64 read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
65 read_val >>= 32;
66
67 /*
68 * The config space contains some garbage, fix it up. Also
69 * synthesize an EA capability for the BAR used by MSI-X.
70 */
71 switch (where & ~3) {
72 case 0x40:
73 read_val &= 0xffff00ff;
74 read_val |= 0x00007000; /* Skip MSI CAP */
75 break;
76 case 0x70: /* Express Cap */
77 /* PME interrupt on vector 2*/
78 read_val |= (2u << 25);
79 break;
80 case 0xb0: /* MSI-X Cap */
81 /* TableSize=4, Next Cap is EA */
82 read_val &= 0xc00000ff;
83 read_val |= 0x0003bc00;
84 break;
85 case 0xb4:
86 /* Table offset=0, BIR=0 */
87 read_val = 0x00000000;
88 break;
89 case 0xb8:
90 /* BPA offset=0xf0000, BIR=0 */
91 read_val = 0x000f0000;
92 break;
93 case 0xbc:
94 /* EA, 1 entry, no next Cap */
95 read_val = 0x00010014;
96 break;
97 case 0xc0:
98 /* DW2 for type-1 */
99 read_val = 0x00000000;
100 break;
101 case 0xc4:
102 /* Entry BEI=0, PP=0x00, SP=0xff, ES=3 */
103 read_val = 0x80ff0003;
104 break;
105 case 0xc8:
106 read_val = pem_pci->ea_entry[0];
107 break;
108 case 0xcc:
109 read_val = pem_pci->ea_entry[1];
110 break;
111 case 0xd0:
112 read_val = pem_pci->ea_entry[2];
113 break;
114 default:
115 break;
116 }
117 read_val >>= (8 * (where & 3));
118 switch (size) {
119 case 1:
120 read_val &= 0xff;
121 break;
122 case 2:
123 read_val &= 0xffff;
124 break;
125 default:
126 break;
127 }
128 *val = read_val;
129 return PCIBIOS_SUCCESSFUL;
130}
131
132static int thunder_pem_config_read(struct pci_bus *bus, unsigned int devfn,
133 int where, int size, u32 *val)
134{
135 struct gen_pci *pci = bus->sysdata;
136
137 if (bus->number < pci->cfg.bus_range->start ||
138 bus->number > pci->cfg.bus_range->end)
139 return PCIBIOS_DEVICE_NOT_FOUND;
140
141 /*
142 * The first device on the bus is the PEM PCIe bridge.
143 * Special case its config access.
144 */
145 if (bus->number == pci->cfg.bus_range->start)
146 return thunder_pem_bridge_read(bus, devfn, where, size, val);
147
148 return pci_generic_config_read(bus, devfn, where, size, val);
149}
150
151/*
152 * Some of the w1c_bits below also include read-only or non-writable
153 * reserved bits, this makes the code simpler and is OK as the bits
154 * are not affected by writing zeros to them.
155 */
156static u32 thunder_pem_bridge_w1c_bits(int where)
157{
158 u32 w1c_bits = 0;
159
160 switch (where & ~3) {
161 case 0x04: /* Command/Status */
162 case 0x1c: /* Base and I/O Limit/Secondary Status */
163 w1c_bits = 0xff000000;
164 break;
165 case 0x44: /* Power Management Control and Status */
166 w1c_bits = 0xfffffe00;
167 break;
168 case 0x78: /* Device Control/Device Status */
169 case 0x80: /* Link Control/Link Status */
170 case 0x88: /* Slot Control/Slot Status */
171 case 0x90: /* Root Status */
172 case 0xa0: /* Link Control 2 Registers/Link Status 2 */
173 w1c_bits = 0xffff0000;
174 break;
175 case 0x104: /* Uncorrectable Error Status */
176 case 0x110: /* Correctable Error Status */
177 case 0x130: /* Error Status */
178 case 0x160: /* Link Control 4 */
179 w1c_bits = 0xffffffff;
180 break;
181 default:
182 break;
183 }
184 return w1c_bits;
185}
186
187static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
188 int where, int size, u32 val)
189{
190 struct gen_pci *pci = bus->sysdata;
191 struct thunder_pem_pci *pem_pci;
192 u64 write_val, read_val;
193 u32 mask = 0;
194
195 pem_pci = container_of(pci, struct thunder_pem_pci, gen_pci);
196
197 if (devfn != 0 || where >= 2048)
198 return PCIBIOS_DEVICE_NOT_FOUND;
199
200 /*
201 * 32-bit accesses only. If the write is for a size smaller
202 * than 32-bits, we must first read the 32-bit value and merge
203 * in the desired bits and then write the whole 32-bits back
204 * out.
205 */
206 switch (size) {
207 case 1:
208 read_val = where & ~3ull;
209 writeq(read_val, pem_pci->pem_reg_base + PEM_CFG_RD);
210 read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
211 read_val >>= 32;
212 mask = ~(0xff << (8 * (where & 3)));
213 read_val &= mask;
214 val = (val & 0xff) << (8 * (where & 3));
215 val |= (u32)read_val;
216 break;
217 case 2:
218 read_val = where & ~3ull;
219 writeq(read_val, pem_pci->pem_reg_base + PEM_CFG_RD);
220 read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
221 read_val >>= 32;
222 mask = ~(0xffff << (8 * (where & 3)));
223 read_val &= mask;
224 val = (val & 0xffff) << (8 * (where & 3));
225 val |= (u32)read_val;
226 break;
227 default:
228 break;
229 }
230
231 /*
232 * By expanding the write width to 32 bits, we may
233 * inadvertently hit some W1C bits that were not intended to
234 * be written. Calculate the mask that must be applied to the
235 * data to be written to avoid these cases.
236 */
237 if (mask) {
238 u32 w1c_bits = thunder_pem_bridge_w1c_bits(where);
239
240 if (w1c_bits) {
241 mask &= w1c_bits;
242 val &= ~mask;
243 }
244 }
245
246 /*
247 * Low order bits are the config address, the high order 32
248 * bits are the data to be written.
249 */
250 write_val = where & ~3ull;
251 write_val |= (((u64)val) << 32);
252 writeq(write_val, pem_pci->pem_reg_base + PEM_CFG_WR);
253 return PCIBIOS_SUCCESSFUL;
254}
255
256static int thunder_pem_config_write(struct pci_bus *bus, unsigned int devfn,
257 int where, int size, u32 val)
258{
259 struct gen_pci *pci = bus->sysdata;
260
261 if (bus->number < pci->cfg.bus_range->start ||
262 bus->number > pci->cfg.bus_range->end)
263 return PCIBIOS_DEVICE_NOT_FOUND;
264 /*
265 * The first device on the bus is the PEM PCIe bridge.
266 * Special case its config access.
267 */
268 if (bus->number == pci->cfg.bus_range->start)
269 return thunder_pem_bridge_write(bus, devfn, where, size, val);
270
271
272 return pci_generic_config_write(bus, devfn, where, size, val);
273}
274
275static struct gen_pci_cfg_bus_ops thunder_pem_bus_ops = {
276 .bus_shift = 24,
277 .ops = {
278 .map_bus = thunder_pem_map_bus,
279 .read = thunder_pem_config_read,
280 .write = thunder_pem_config_write,
281 }
282};
283
284static const struct of_device_id thunder_pem_of_match[] = {
285 { .compatible = "cavium,pci-host-thunder-pem",
286 .data = &thunder_pem_bus_ops },
287
288 { },
289};
290MODULE_DEVICE_TABLE(of, thunder_pem_of_match);
291
292static int thunder_pem_probe(struct platform_device *pdev)
293{
294 struct device *dev = &pdev->dev;
295 const struct of_device_id *of_id;
296 resource_size_t bar4_start;
297 struct resource *res_pem;
298 struct thunder_pem_pci *pem_pci;
299
300 pem_pci = devm_kzalloc(dev, sizeof(*pem_pci), GFP_KERNEL);
301 if (!pem_pci)
302 return -ENOMEM;
303
304 of_id = of_match_node(thunder_pem_of_match, dev->of_node);
305 pem_pci->gen_pci.cfg.ops = (struct gen_pci_cfg_bus_ops *)of_id->data;
306
307 /*
308 * The second register range is the PEM bridge to the PCIe
309 * bus. It has a different config access method than those
310 * devices behind the bridge.
311 */
312 res_pem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
313 if (!res_pem) {
314 dev_err(dev, "missing \"reg[1]\"property\n");
315 return -EINVAL;
316 }
317
318 pem_pci->pem_reg_base = devm_ioremap(dev, res_pem->start, 0x10000);
319 if (!pem_pci->pem_reg_base)
320 return -ENOMEM;
321
322 /*
323 * The MSI-X BAR for the PEM and AER interrupts is located at
324 * a fixed offset from the PEM register base. Generate a
325 * fragment of the synthesized Enhanced Allocation capability
326 * structure here for the BAR.
327 */
328 bar4_start = res_pem->start + 0xf00000;
329 pem_pci->ea_entry[0] = (u32)bar4_start | 2;
330 pem_pci->ea_entry[1] = (u32)(res_pem->end - bar4_start) & ~3u;
331 pem_pci->ea_entry[2] = (u32)(bar4_start >> 32);
332
333 return pci_host_common_probe(pdev, &pem_pci->gen_pci);
334}
335
336static struct platform_driver thunder_pem_driver = {
337 .driver = {
338 .name = KBUILD_MODNAME,
339 .of_match_table = thunder_pem_of_match,
340 },
341 .probe = thunder_pem_probe,
342};
343module_platform_driver(thunder_pem_driver);
344
345MODULE_DESCRIPTION("Thunder PEM PCIe host driver");
346MODULE_LICENSE("GPL v2");