aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2014-10-06 11:59:15 -0400
committerBjorn Helgaas <bhelgaas@google.com>2014-10-06 11:59:15 -0400
commitf92d9ee3ab39841d1f29f2d1aa96ff7c74b36ee1 (patch)
treec747c9ce1882b9a08d284603717890c5ef81bbf7
parent55dd4175a4bc10d943c159dabef552baaf459a59 (diff)
parent767ebaff4ef7235eb49ddec5d48db97b17c37cf5 (diff)
Merge branch 'pci/host-xgene' into next
* pci/host-xgene: arm64: dts: Add APM X-Gene PCIe device tree nodes PCI: xgene: Add APM X-Gene PCIe driver Conflicts: drivers/pci/host/Kconfig drivers/pci/host/Makefile
-rw-r--r--Documentation/devicetree/bindings/pci/xgene-pci.txt57
-rw-r--r--MAINTAINERS8
-rw-r--r--arch/arm64/boot/dts/apm-mustang.dts8
-rw-r--r--arch/arm64/boot/dts/apm-storm.dtsi165
-rw-r--r--drivers/pci/host/Kconfig11
-rw-r--r--drivers/pci/host/Makefile1
-rw-r--r--drivers/pci/host/pci-xgene.c659
7 files changed, 908 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/pci/xgene-pci.txt b/Documentation/devicetree/bindings/pci/xgene-pci.txt
new file mode 100644
index 000000000000..1070b068c7c6
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/xgene-pci.txt
@@ -0,0 +1,57 @@
1* AppliedMicro X-Gene PCIe interface
2
3Required properties:
4- device_type: set to "pci"
5- compatible: should contain "apm,xgene-pcie" to identify the core.
6- reg: A list of physical base address and length for each set of controller
7 registers. Must contain an entry for each entry in the reg-names
8 property.
9- reg-names: Must include the following entries:
10 "csr": controller configuration registers.
11 "cfg": pcie configuration space registers.
12- #address-cells: set to <3>
13- #size-cells: set to <2>
14- ranges: ranges for the outbound memory, I/O regions.
15- dma-ranges: ranges for the inbound memory regions.
16- #interrupt-cells: set to <1>
17- interrupt-map-mask and interrupt-map: standard PCI properties
18 to define the mapping of the PCIe interface to interrupt
19 numbers.
20- clocks: from common clock binding: handle to pci clock.
21
22Optional properties:
23- status: Either "ok" or "disabled".
24- dma-coherent: Present if dma operations are coherent
25
26Example:
27
28SoC specific DT Entry:
29
30 pcie0: pcie@1f2b0000 {
31 status = "disabled";
32 device_type = "pci";
33 compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
34 #interrupt-cells = <1>;
35 #size-cells = <2>;
36 #address-cells = <3>;
37 reg = < 0x00 0x1f2b0000 0x0 0x00010000 /* Controller registers */
38 0xe0 0xd0000000 0x0 0x00040000>; /* PCI config space */
39 reg-names = "csr", "cfg";
40 ranges = <0x01000000 0x00 0x00000000 0xe0 0x10000000 0x00 0x00010000 /* io */
41 0x02000000 0x00 0x80000000 0xe1 0x80000000 0x00 0x80000000>; /* mem */
42 dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
43 0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
44 interrupt-map-mask = <0x0 0x0 0x0 0x7>;
45 interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1
46 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1
47 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1
48 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>;
49 dma-coherent;
50 clocks = <&pcie0clk 0>;
51 };
52
53
54Board specific DT Entry:
55 &pcie0 {
56 status = "ok";
57 };
diff --git a/MAINTAINERS b/MAINTAINERS
index 07fd7e279700..fac7057ba67c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6868,6 +6868,14 @@ F: include/linux/pci*
6868F: arch/x86/pci/ 6868F: arch/x86/pci/
6869F: arch/x86/kernel/quirks.c 6869F: arch/x86/kernel/quirks.c
6870 6870
6871PCI DRIVER FOR APPLIEDMICRO XGENE
6872M: Tanmay Inamdar <tinamdar@apm.com>
6873L: linux-pci@vger.kernel.org
6874L: linux-arm-kernel@lists.infradead.org
6875S: Maintained
6876F: Documentation/devicetree/bindings/pci/xgene-pci.txt
6877F: drivers/pci/host/pci-xgene.c
6878
6871PCI DRIVER FOR IMX6 6879PCI DRIVER FOR IMX6
6872M: Richard Zhu <r65037@freescale.com> 6880M: Richard Zhu <r65037@freescale.com>
6873M: Lucas Stach <l.stach@pengutronix.de> 6881M: Lucas Stach <l.stach@pengutronix.de>
diff --git a/arch/arm64/boot/dts/apm-mustang.dts b/arch/arm64/boot/dts/apm-mustang.dts
index b2f56229aa5e..f64900052f4e 100644
--- a/arch/arm64/boot/dts/apm-mustang.dts
+++ b/arch/arm64/boot/dts/apm-mustang.dts
@@ -25,6 +25,14 @@
25 }; 25 };
26}; 26};
27 27
28&pcie0clk {
29 status = "ok";
30};
31
32&pcie0 {
33 status = "ok";
34};
35
28&serial0 { 36&serial0 {
29 status = "ok"; 37 status = "ok";
30}; 38};
diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi
index c0aceef7f5b3..403197a0e621 100644
--- a/arch/arm64/boot/dts/apm-storm.dtsi
+++ b/arch/arm64/boot/dts/apm-storm.dtsi
@@ -269,6 +269,171 @@
269 enable-mask = <0x2>; 269 enable-mask = <0x2>;
270 clock-output-names = "rtcclk"; 270 clock-output-names = "rtcclk";
271 }; 271 };
272
273 pcie0clk: pcie0clk@1f2bc000 {
274 status = "disabled";
275 compatible = "apm,xgene-device-clock";
276 #clock-cells = <1>;
277 clocks = <&socplldiv2 0>;
278 reg = <0x0 0x1f2bc000 0x0 0x1000>;
279 reg-names = "csr-reg";
280 clock-output-names = "pcie0clk";
281 };
282
283 pcie1clk: pcie1clk@1f2cc000 {
284 status = "disabled";
285 compatible = "apm,xgene-device-clock";
286 #clock-cells = <1>;
287 clocks = <&socplldiv2 0>;
288 reg = <0x0 0x1f2cc000 0x0 0x1000>;
289 reg-names = "csr-reg";
290 clock-output-names = "pcie1clk";
291 };
292
293 pcie2clk: pcie2clk@1f2dc000 {
294 status = "disabled";
295 compatible = "apm,xgene-device-clock";
296 #clock-cells = <1>;
297 clocks = <&socplldiv2 0>;
298 reg = <0x0 0x1f2dc000 0x0 0x1000>;
299 reg-names = "csr-reg";
300 clock-output-names = "pcie2clk";
301 };
302
303 pcie3clk: pcie3clk@1f50c000 {
304 status = "disabled";
305 compatible = "apm,xgene-device-clock";
306 #clock-cells = <1>;
307 clocks = <&socplldiv2 0>;
308 reg = <0x0 0x1f50c000 0x0 0x1000>;
309 reg-names = "csr-reg";
310 clock-output-names = "pcie3clk";
311 };
312
313 pcie4clk: pcie4clk@1f51c000 {
314 status = "disabled";
315 compatible = "apm,xgene-device-clock";
316 #clock-cells = <1>;
317 clocks = <&socplldiv2 0>;
318 reg = <0x0 0x1f51c000 0x0 0x1000>;
319 reg-names = "csr-reg";
320 clock-output-names = "pcie4clk";
321 };
322 };
323
324 pcie0: pcie@1f2b0000 {
325 status = "disabled";
326 device_type = "pci";
327 compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
328 #interrupt-cells = <1>;
329 #size-cells = <2>;
330 #address-cells = <3>;
331 reg = < 0x00 0x1f2b0000 0x0 0x00010000 /* Controller registers */
332 0xe0 0xd0000000 0x0 0x00040000>; /* PCI config space */
333 reg-names = "csr", "cfg";
334 ranges = <0x01000000 0x00 0x00000000 0xe0 0x10000000 0x00 0x00010000 /* io */
335 0x02000000 0x00 0x80000000 0xe1 0x80000000 0x00 0x80000000>; /* mem */
336 dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
337 0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
338 interrupt-map-mask = <0x0 0x0 0x0 0x7>;
339 interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1
340 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1
341 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1
342 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>;
343 dma-coherent;
344 clocks = <&pcie0clk 0>;
345 };
346
347 pcie1: pcie@1f2c0000 {
348 status = "disabled";
349 device_type = "pci";
350 compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
351 #interrupt-cells = <1>;
352 #size-cells = <2>;
353 #address-cells = <3>;
354 reg = < 0x00 0x1f2c0000 0x0 0x00010000 /* Controller registers */
355 0xd0 0xd0000000 0x0 0x00040000>; /* PCI config space */
356 reg-names = "csr", "cfg";
357 ranges = <0x01000000 0x0 0x00000000 0xd0 0x10000000 0x00 0x00010000 /* io */
358 0x02000000 0x0 0x80000000 0xd1 0x80000000 0x00 0x80000000>; /* mem */
359 dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
360 0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
361 interrupt-map-mask = <0x0 0x0 0x0 0x7>;
362 interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc8 0x1
363 0x0 0x0 0x0 0x2 &gic 0x0 0xc9 0x1
364 0x0 0x0 0x0 0x3 &gic 0x0 0xca 0x1
365 0x0 0x0 0x0 0x4 &gic 0x0 0xcb 0x1>;
366 dma-coherent;
367 clocks = <&pcie1clk 0>;
368 };
369
370 pcie2: pcie@1f2d0000 {
371 status = "disabled";
372 device_type = "pci";
373 compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
374 #interrupt-cells = <1>;
375 #size-cells = <2>;
376 #address-cells = <3>;
377 reg = < 0x00 0x1f2d0000 0x0 0x00010000 /* Controller registers */
378 0x90 0xd0000000 0x0 0x00040000>; /* PCI config space */
379 reg-names = "csr", "cfg";
380 ranges = <0x01000000 0x0 0x00000000 0x90 0x10000000 0x0 0x00010000 /* io */
381 0x02000000 0x0 0x80000000 0x91 0x80000000 0x0 0x80000000>; /* mem */
382 dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
383 0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
384 interrupt-map-mask = <0x0 0x0 0x0 0x7>;
385 interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xce 0x1
386 0x0 0x0 0x0 0x2 &gic 0x0 0xcf 0x1
387 0x0 0x0 0x0 0x3 &gic 0x0 0xd0 0x1
388 0x0 0x0 0x0 0x4 &gic 0x0 0xd1 0x1>;
389 dma-coherent;
390 clocks = <&pcie2clk 0>;
391 };
392
393 pcie3: pcie@1f500000 {
394 status = "disabled";
395 device_type = "pci";
396 compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
397 #interrupt-cells = <1>;
398 #size-cells = <2>;
399 #address-cells = <3>;
400 reg = < 0x00 0x1f500000 0x0 0x00010000 /* Controller registers */
401 0xa0 0xd0000000 0x0 0x00040000>; /* PCI config space */
402 reg-names = "csr", "cfg";
403 ranges = <0x01000000 0x0 0x00000000 0xa0 0x10000000 0x0 0x00010000 /* io */
404 0x02000000 0x0 0x80000000 0xa1 0x80000000 0x0 0x80000000>; /* mem */
405 dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
406 0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
407 interrupt-map-mask = <0x0 0x0 0x0 0x7>;
408 interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xd4 0x1
409 0x0 0x0 0x0 0x2 &gic 0x0 0xd5 0x1
410 0x0 0x0 0x0 0x3 &gic 0x0 0xd6 0x1
411 0x0 0x0 0x0 0x4 &gic 0x0 0xd7 0x1>;
412 dma-coherent;
413 clocks = <&pcie3clk 0>;
414 };
415
416 pcie4: pcie@1f510000 {
417 status = "disabled";
418 device_type = "pci";
419 compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
420 #interrupt-cells = <1>;
421 #size-cells = <2>;
422 #address-cells = <3>;
423 reg = < 0x00 0x1f510000 0x0 0x00010000 /* Controller registers */
424 0xc0 0xd0000000 0x0 0x00200000>; /* PCI config space */
425 reg-names = "csr", "cfg";
426 ranges = <0x01000000 0x0 0x00000000 0xc0 0x10000000 0x0 0x00010000 /* io */
427 0x02000000 0x0 0x80000000 0xc1 0x80000000 0x0 0x80000000>; /* mem */
428 dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
429 0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
430 interrupt-map-mask = <0x0 0x0 0x0 0x7>;
431 interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xda 0x1
432 0x0 0x0 0x0 0x2 &gic 0x0 0xdb 0x1
433 0x0 0x0 0x0 0x3 &gic 0x0 0xdc 0x1
434 0x0 0x0 0x0 0x4 &gic 0x0 0xdd 0x1>;
435 dma-coherent;
436 clocks = <&pcie4clk 0>;
272 }; 437 };
273 438
274 serial0: serial@1c020000 { 439 serial0: serial@1c020000 {
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 34134d64f35a..413c3611886a 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -63,7 +63,6 @@ config PCIE_SPEAR13XX
63 help 63 help
64 Say Y here if you want PCIe support on SPEAr13XX SoCs. 64 Say Y here if you want PCIe support on SPEAr13XX SoCs.
65 65
66
67config PCI_KEYSTONE 66config PCI_KEYSTONE
68 bool "TI Keystone PCIe controller" 67 bool "TI Keystone PCIe controller"
69 depends on ARCH_KEYSTONE 68 depends on ARCH_KEYSTONE
@@ -82,4 +81,14 @@ config PCIE_XILINX
82 Say 'Y' here if you want kernel to support the Xilinx AXI PCIe 81 Say 'Y' here if you want kernel to support the Xilinx AXI PCIe
83 Host Bridge driver. 82 Host Bridge driver.
84 83
84config PCI_XGENE
85 bool "X-Gene PCIe controller"
86 depends on ARCH_XGENE
87 depends on OF
88 select PCIEPORTBUS
89 help
90 Say Y here if you want internal PCI support on APM X-Gene SoC.
91 There are 5 internal PCIe ports available. Each port is GEN3 capable
92 and have varied lanes from x1 to x8.
93
85endmenu 94endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 182929cdbcd9..26b3461d68d7 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
10obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o 10obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
11obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o 11obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
12obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o 12obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
13obj-$(CONFIG_PCI_XGENE) += pci-xgene.o
diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c
new file mode 100644
index 000000000000..9ecabfa8c634
--- /dev/null
+++ b/drivers/pci/host/pci-xgene.c
@@ -0,0 +1,659 @@
1/**
2 * APM X-Gene PCIe Driver
3 *
4 * Copyright (c) 2014 Applied Micro Circuits Corporation.
5 *
6 * Author: Tanmay Inamdar <tinamdar@apm.com>.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19#include <linux/clk-private.h>
20#include <linux/delay.h>
21#include <linux/io.h>
22#include <linux/jiffies.h>
23#include <linux/memblock.h>
24#include <linux/module.h>
25#include <linux/of.h>
26#include <linux/of_address.h>
27#include <linux/of_irq.h>
28#include <linux/of_pci.h>
29#include <linux/pci.h>
30#include <linux/platform_device.h>
31#include <linux/slab.h>
32
33#define PCIECORE_CTLANDSTATUS 0x50
34#define PIM1_1L 0x80
35#define IBAR2 0x98
36#define IR2MSK 0x9c
37#define PIM2_1L 0xa0
38#define IBAR3L 0xb4
39#define IR3MSKL 0xbc
40#define PIM3_1L 0xc4
41#define OMR1BARL 0x100
42#define OMR2BARL 0x118
43#define OMR3BARL 0x130
44#define CFGBARL 0x154
45#define CFGBARH 0x158
46#define CFGCTL 0x15c
47#define RTDID 0x160
48#define BRIDGE_CFG_0 0x2000
49#define BRIDGE_CFG_4 0x2010
50#define BRIDGE_STATUS_0 0x2600
51
52#define LINK_UP_MASK 0x00000100
53#define AXI_EP_CFG_ACCESS 0x10000
54#define EN_COHERENCY 0xF0000000
55#define EN_REG 0x00000001
56#define OB_LO_IO 0x00000002
57#define XGENE_PCIE_VENDORID 0x10E8
58#define XGENE_PCIE_DEVICEID 0xE004
59#define SZ_1T (SZ_1G*1024ULL)
60#define PIPE_PHY_RATE_RD(src) ((0xc000 & (u32)(src)) >> 0xe)
61
62struct xgene_pcie_port {
63 struct device_node *node;
64 struct device *dev;
65 struct clk *clk;
66 void __iomem *csr_base;
67 void __iomem *cfg_base;
68 unsigned long cfg_addr;
69 bool link_up;
70};
71
72static inline u32 pcie_bar_low_val(u32 addr, u32 flags)
73{
74 return (addr & PCI_BASE_ADDRESS_MEM_MASK) | flags;
75}
76
77/* PCIe Configuration Out/In */
78static inline void xgene_pcie_cfg_out32(void __iomem *addr, int offset, u32 val)
79{
80 writel(val, addr + offset);
81}
82
83static inline void xgene_pcie_cfg_out16(void __iomem *addr, int offset, u16 val)
84{
85 u32 val32 = readl(addr + (offset & ~0x3));
86
87 switch (offset & 0x3) {
88 case 2:
89 val32 &= ~0xFFFF0000;
90 val32 |= (u32)val << 16;
91 break;
92 case 0:
93 default:
94 val32 &= ~0xFFFF;
95 val32 |= val;
96 break;
97 }
98 writel(val32, addr + (offset & ~0x3));
99}
100
101static inline void xgene_pcie_cfg_out8(void __iomem *addr, int offset, u8 val)
102{
103 u32 val32 = readl(addr + (offset & ~0x3));
104
105 switch (offset & 0x3) {
106 case 0:
107 val32 &= ~0xFF;
108 val32 |= val;
109 break;
110 case 1:
111 val32 &= ~0xFF00;
112 val32 |= (u32)val << 8;
113 break;
114 case 2:
115 val32 &= ~0xFF0000;
116 val32 |= (u32)val << 16;
117 break;
118 case 3:
119 default:
120 val32 &= ~0xFF000000;
121 val32 |= (u32)val << 24;
122 break;
123 }
124 writel(val32, addr + (offset & ~0x3));
125}
126
127static inline void xgene_pcie_cfg_in32(void __iomem *addr, int offset, u32 *val)
128{
129 *val = readl(addr + offset);
130}
131
132static inline void xgene_pcie_cfg_in16(void __iomem *addr, int offset, u32 *val)
133{
134 *val = readl(addr + (offset & ~0x3));
135
136 switch (offset & 0x3) {
137 case 2:
138 *val >>= 16;
139 break;
140 }
141
142 *val &= 0xFFFF;
143}
144
145static inline void xgene_pcie_cfg_in8(void __iomem *addr, int offset, u32 *val)
146{
147 *val = readl(addr + (offset & ~0x3));
148
149 switch (offset & 0x3) {
150 case 3:
151 *val = *val >> 24;
152 break;
153 case 2:
154 *val = *val >> 16;
155 break;
156 case 1:
157 *val = *val >> 8;
158 break;
159 }
160 *val &= 0xFF;
161}
162
163/*
164 * When the address bit [17:16] is 2'b01, the Configuration access will be
165 * treated as Type 1 and it will be forwarded to external PCIe device.
166 */
167static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus)
168{
169 struct xgene_pcie_port *port = bus->sysdata;
170
171 if (bus->number >= (bus->primary + 1))
172 return port->cfg_base + AXI_EP_CFG_ACCESS;
173
174 return port->cfg_base;
175}
176
177/*
178 * For Configuration request, RTDID register is used as Bus Number,
179 * Device Number and Function number of the header fields.
180 */
181static void xgene_pcie_set_rtdid_reg(struct pci_bus *bus, uint devfn)
182{
183 struct xgene_pcie_port *port = bus->sysdata;
184 unsigned int b, d, f;
185 u32 rtdid_val = 0;
186
187 b = bus->number;
188 d = PCI_SLOT(devfn);
189 f = PCI_FUNC(devfn);
190
191 if (!pci_is_root_bus(bus))
192 rtdid_val = (b << 8) | (d << 3) | f;
193
194 writel(rtdid_val, port->csr_base + RTDID);
195 /* read the register back to ensure flush */
196 readl(port->csr_base + RTDID);
197}
198
199/*
200 * X-Gene PCIe port uses BAR0-BAR1 of RC's configuration space as
201 * the translation from PCI bus to native BUS. Entire DDR region
202 * is mapped into PCIe space using these registers, so it can be
203 * reached by DMA from EP devices. The BAR0/1 of bridge should be
204 * hidden during enumeration to avoid the sizing and resource allocation
205 * by PCIe core.
206 */
207static bool xgene_pcie_hide_rc_bars(struct pci_bus *bus, int offset)
208{
209 if (pci_is_root_bus(bus) && ((offset == PCI_BASE_ADDRESS_0) ||
210 (offset == PCI_BASE_ADDRESS_1)))
211 return true;
212
213 return false;
214}
215
216static int xgene_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
217 int offset, int len, u32 *val)
218{
219 struct xgene_pcie_port *port = bus->sysdata;
220 void __iomem *addr;
221
222 if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up)
223 return PCIBIOS_DEVICE_NOT_FOUND;
224
225 if (xgene_pcie_hide_rc_bars(bus, offset)) {
226 *val = 0;
227 return PCIBIOS_SUCCESSFUL;
228 }
229
230 xgene_pcie_set_rtdid_reg(bus, devfn);
231 addr = xgene_pcie_get_cfg_base(bus);
232 switch (len) {
233 case 1:
234 xgene_pcie_cfg_in8(addr, offset, val);
235 break;
236 case 2:
237 xgene_pcie_cfg_in16(addr, offset, val);
238 break;
239 default:
240 xgene_pcie_cfg_in32(addr, offset, val);
241 break;
242 }
243
244 return PCIBIOS_SUCCESSFUL;
245}
246
247static int xgene_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
248 int offset, int len, u32 val)
249{
250 struct xgene_pcie_port *port = bus->sysdata;
251 void __iomem *addr;
252
253 if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up)
254 return PCIBIOS_DEVICE_NOT_FOUND;
255
256 if (xgene_pcie_hide_rc_bars(bus, offset))
257 return PCIBIOS_SUCCESSFUL;
258
259 xgene_pcie_set_rtdid_reg(bus, devfn);
260 addr = xgene_pcie_get_cfg_base(bus);
261 switch (len) {
262 case 1:
263 xgene_pcie_cfg_out8(addr, offset, (u8)val);
264 break;
265 case 2:
266 xgene_pcie_cfg_out16(addr, offset, (u16)val);
267 break;
268 default:
269 xgene_pcie_cfg_out32(addr, offset, val);
270 break;
271 }
272
273 return PCIBIOS_SUCCESSFUL;
274}
275
276static struct pci_ops xgene_pcie_ops = {
277 .read = xgene_pcie_read_config,
278 .write = xgene_pcie_write_config
279};
280
281static u64 xgene_pcie_set_ib_mask(void __iomem *csr_base, u32 addr,
282 u32 flags, u64 size)
283{
284 u64 mask = (~(size - 1) & PCI_BASE_ADDRESS_MEM_MASK) | flags;
285 u32 val32 = 0;
286 u32 val;
287
288 val32 = readl(csr_base + addr);
289 val = (val32 & 0x0000ffff) | (lower_32_bits(mask) << 16);
290 writel(val, csr_base + addr);
291
292 val32 = readl(csr_base + addr + 0x04);
293 val = (val32 & 0xffff0000) | (lower_32_bits(mask) >> 16);
294 writel(val, csr_base + addr + 0x04);
295
296 val32 = readl(csr_base + addr + 0x04);
297 val = (val32 & 0x0000ffff) | (upper_32_bits(mask) << 16);
298 writel(val, csr_base + addr + 0x04);
299
300 val32 = readl(csr_base + addr + 0x08);
301 val = (val32 & 0xffff0000) | (upper_32_bits(mask) >> 16);
302 writel(val, csr_base + addr + 0x08);
303
304 return mask;
305}
306
307static void xgene_pcie_linkup(struct xgene_pcie_port *port,
308 u32 *lanes, u32 *speed)
309{
310 void __iomem *csr_base = port->csr_base;
311 u32 val32;
312
313 port->link_up = false;
314 val32 = readl(csr_base + PCIECORE_CTLANDSTATUS);
315 if (val32 & LINK_UP_MASK) {
316 port->link_up = true;
317 *speed = PIPE_PHY_RATE_RD(val32);
318 val32 = readl(csr_base + BRIDGE_STATUS_0);
319 *lanes = val32 >> 26;
320 }
321}
322
323static int xgene_pcie_init_port(struct xgene_pcie_port *port)
324{
325 int rc;
326
327 port->clk = clk_get(port->dev, NULL);
328 if (IS_ERR(port->clk)) {
329 dev_err(port->dev, "clock not available\n");
330 return -ENODEV;
331 }
332
333 rc = clk_prepare_enable(port->clk);
334 if (rc) {
335 dev_err(port->dev, "clock enable failed\n");
336 return rc;
337 }
338
339 return 0;
340}
341
342static int xgene_pcie_map_reg(struct xgene_pcie_port *port,
343 struct platform_device *pdev)
344{
345 struct resource *res;
346
347 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr");
348 port->csr_base = devm_ioremap_resource(port->dev, res);
349 if (IS_ERR(port->csr_base))
350 return PTR_ERR(port->csr_base);
351
352 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
353 port->cfg_base = devm_ioremap_resource(port->dev, res);
354 if (IS_ERR(port->cfg_base))
355 return PTR_ERR(port->cfg_base);
356 port->cfg_addr = res->start;
357
358 return 0;
359}
360
361static void xgene_pcie_setup_ob_reg(struct xgene_pcie_port *port,
362 struct resource *res, u32 offset,
363 u64 cpu_addr, u64 pci_addr)
364{
365 void __iomem *base = port->csr_base + offset;
366 resource_size_t size = resource_size(res);
367 u64 restype = resource_type(res);
368 u64 mask = 0;
369 u32 min_size;
370 u32 flag = EN_REG;
371
372 if (restype == IORESOURCE_MEM) {
373 min_size = SZ_128M;
374 } else {
375 min_size = 128;
376 flag |= OB_LO_IO;
377 }
378
379 if (size >= min_size)
380 mask = ~(size - 1) | flag;
381 else
382 dev_warn(port->dev, "res size 0x%llx less than minimum 0x%x\n",
383 (u64)size, min_size);
384
385 writel(lower_32_bits(cpu_addr), base);
386 writel(upper_32_bits(cpu_addr), base + 0x04);
387 writel(lower_32_bits(mask), base + 0x08);
388 writel(upper_32_bits(mask), base + 0x0c);
389 writel(lower_32_bits(pci_addr), base + 0x10);
390 writel(upper_32_bits(pci_addr), base + 0x14);
391}
392
393static void xgene_pcie_setup_cfg_reg(void __iomem *csr_base, u64 addr)
394{
395 writel(lower_32_bits(addr), csr_base + CFGBARL);
396 writel(upper_32_bits(addr), csr_base + CFGBARH);
397 writel(EN_REG, csr_base + CFGCTL);
398}
399
400static int xgene_pcie_map_ranges(struct xgene_pcie_port *port,
401 struct list_head *res,
402 resource_size_t io_base)
403{
404 struct pci_host_bridge_window *window;
405 struct device *dev = port->dev;
406 int ret;
407
408 list_for_each_entry(window, res, list) {
409 struct resource *res = window->res;
410 u64 restype = resource_type(res);
411
412 dev_dbg(port->dev, "%pR\n", res);
413
414 switch (restype) {
415 case IORESOURCE_IO:
416 xgene_pcie_setup_ob_reg(port, res, OMR3BARL, io_base,
417 res->start - window->offset);
418 ret = pci_remap_iospace(res, io_base);
419 if (ret < 0)
420 return ret;
421 break;
422 case IORESOURCE_MEM:
423 xgene_pcie_setup_ob_reg(port, res, OMR1BARL, res->start,
424 res->start - window->offset);
425 break;
426 case IORESOURCE_BUS:
427 break;
428 default:
429 dev_err(dev, "invalid resource %pR\n", res);
430 return -EINVAL;
431 }
432 }
433 xgene_pcie_setup_cfg_reg(port->csr_base, port->cfg_addr);
434
435 return 0;
436}
437
438static void xgene_pcie_setup_pims(void *addr, u64 pim, u64 size)
439{
440 writel(lower_32_bits(pim), addr);
441 writel(upper_32_bits(pim) | EN_COHERENCY, addr + 0x04);
442 writel(lower_32_bits(size), addr + 0x10);
443 writel(upper_32_bits(size), addr + 0x14);
444}
445
446/*
447 * X-Gene PCIe support maximum 3 inbound memory regions
448 * This function helps to select a region based on size of region
449 */
450static int xgene_pcie_select_ib_reg(u8 *ib_reg_mask, u64 size)
451{
452 if ((size > 4) && (size < SZ_16M) && !(*ib_reg_mask & (1 << 1))) {
453 *ib_reg_mask |= (1 << 1);
454 return 1;
455 }
456
457 if ((size > SZ_1K) && (size < SZ_1T) && !(*ib_reg_mask & (1 << 0))) {
458 *ib_reg_mask |= (1 << 0);
459 return 0;
460 }
461
462 if ((size > SZ_1M) && (size < SZ_1T) && !(*ib_reg_mask & (1 << 2))) {
463 *ib_reg_mask |= (1 << 2);
464 return 2;
465 }
466
467 return -EINVAL;
468}
469
470static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port,
471 struct of_pci_range *range, u8 *ib_reg_mask)
472{
473 void __iomem *csr_base = port->csr_base;
474 void __iomem *cfg_base = port->cfg_base;
475 void *bar_addr;
476 void *pim_addr;
477 u64 cpu_addr = range->cpu_addr;
478 u64 pci_addr = range->pci_addr;
479 u64 size = range->size;
480 u64 mask = ~(size - 1) | EN_REG;
481 u32 flags = PCI_BASE_ADDRESS_MEM_TYPE_64;
482 u32 bar_low;
483 int region;
484
485 region = xgene_pcie_select_ib_reg(ib_reg_mask, range->size);
486 if (region < 0) {
487 dev_warn(port->dev, "invalid pcie dma-range config\n");
488 return;
489 }
490
491 if (range->flags & IORESOURCE_PREFETCH)
492 flags |= PCI_BASE_ADDRESS_MEM_PREFETCH;
493
494 bar_low = pcie_bar_low_val((u32)cpu_addr, flags);
495 switch (region) {
496 case 0:
497 xgene_pcie_set_ib_mask(csr_base, BRIDGE_CFG_4, flags, size);
498 bar_addr = cfg_base + PCI_BASE_ADDRESS_0;
499 writel(bar_low, bar_addr);
500 writel(upper_32_bits(cpu_addr), bar_addr + 0x4);
501 pim_addr = csr_base + PIM1_1L;
502 break;
503 case 1:
504 bar_addr = csr_base + IBAR2;
505 writel(bar_low, bar_addr);
506 writel(lower_32_bits(mask), csr_base + IR2MSK);
507 pim_addr = csr_base + PIM2_1L;
508 break;
509 case 2:
510 bar_addr = csr_base + IBAR3L;
511 writel(bar_low, bar_addr);
512 writel(upper_32_bits(cpu_addr), bar_addr + 0x4);
513 writel(lower_32_bits(mask), csr_base + IR3MSKL);
514 writel(upper_32_bits(mask), csr_base + IR3MSKL + 0x4);
515 pim_addr = csr_base + PIM3_1L;
516 break;
517 }
518
519 xgene_pcie_setup_pims(pim_addr, pci_addr, ~(size - 1));
520}
521
522static int pci_dma_range_parser_init(struct of_pci_range_parser *parser,
523 struct device_node *node)
524{
525 const int na = 3, ns = 2;
526 int rlen;
527
528 parser->node = node;
529 parser->pna = of_n_addr_cells(node);
530 parser->np = parser->pna + na + ns;
531
532 parser->range = of_get_property(node, "dma-ranges", &rlen);
533 if (!parser->range)
534 return -ENOENT;
535 parser->end = parser->range + rlen / sizeof(__be32);
536
537 return 0;
538}
539
540static int xgene_pcie_parse_map_dma_ranges(struct xgene_pcie_port *port)
541{
542 struct device_node *np = port->node;
543 struct of_pci_range range;
544 struct of_pci_range_parser parser;
545 struct device *dev = port->dev;
546 u8 ib_reg_mask = 0;
547
548 if (pci_dma_range_parser_init(&parser, np)) {
549 dev_err(dev, "missing dma-ranges property\n");
550 return -EINVAL;
551 }
552
553 /* Get the dma-ranges from DT */
554 for_each_of_pci_range(&parser, &range) {
555 u64 end = range.cpu_addr + range.size - 1;
556
557 dev_dbg(port->dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n",
558 range.flags, range.cpu_addr, end, range.pci_addr);
559 xgene_pcie_setup_ib_reg(port, &range, &ib_reg_mask);
560 }
561 return 0;
562}
563
564/* clear BAR configuration which was done by firmware */
565static void xgene_pcie_clear_config(struct xgene_pcie_port *port)
566{
567 int i;
568
569 for (i = PIM1_1L; i <= CFGCTL; i += 4)
570 writel(0x0, port->csr_base + i);
571}
572
573static int xgene_pcie_setup(struct xgene_pcie_port *port,
574 struct list_head *res,
575 resource_size_t io_base)
576{
577 u32 val, lanes = 0, speed = 0;
578 int ret;
579
580 xgene_pcie_clear_config(port);
581
582 /* setup the vendor and device IDs correctly */
583 val = (XGENE_PCIE_DEVICEID << 16) | XGENE_PCIE_VENDORID;
584 writel(val, port->csr_base + BRIDGE_CFG_0);
585
586 ret = xgene_pcie_map_ranges(port, res, io_base);
587 if (ret)
588 return ret;
589
590 ret = xgene_pcie_parse_map_dma_ranges(port);
591 if (ret)
592 return ret;
593
594 xgene_pcie_linkup(port, &lanes, &speed);
595 if (!port->link_up)
596 dev_info(port->dev, "(rc) link down\n");
597 else
598 dev_info(port->dev, "(rc) x%d gen-%d link up\n",
599 lanes, speed + 1);
600 return 0;
601}
602
603static int xgene_pcie_probe_bridge(struct platform_device *pdev)
604{
605 struct device_node *dn = pdev->dev.of_node;
606 struct xgene_pcie_port *port;
607 resource_size_t iobase = 0;
608 struct pci_bus *bus;
609 int ret;
610 LIST_HEAD(res);
611
612 port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
613 if (!port)
614 return -ENOMEM;
615 port->node = of_node_get(pdev->dev.of_node);
616 port->dev = &pdev->dev;
617
618 ret = xgene_pcie_map_reg(port, pdev);
619 if (ret)
620 return ret;
621
622 ret = xgene_pcie_init_port(port);
623 if (ret)
624 return ret;
625
626 ret = of_pci_get_host_bridge_resources(dn, 0, 0xff, &res, &iobase);
627 if (ret)
628 return ret;
629
630 ret = xgene_pcie_setup(port, &res, iobase);
631 if (ret)
632 return ret;
633
634 bus = pci_scan_root_bus(&pdev->dev, 0, &xgene_pcie_ops, port, &res);
635 if (!bus)
636 return -ENOMEM;
637
638 platform_set_drvdata(pdev, port);
639 return 0;
640}
641
642static const struct of_device_id xgene_pcie_match_table[] = {
643 {.compatible = "apm,xgene-pcie",},
644 {},
645};
646
647static struct platform_driver xgene_pcie_driver = {
648 .driver = {
649 .name = "xgene-pcie",
650 .owner = THIS_MODULE,
651 .of_match_table = of_match_ptr(xgene_pcie_match_table),
652 },
653 .probe = xgene_pcie_probe_bridge,
654};
655module_platform_driver(xgene_pcie_driver);
656
657MODULE_AUTHOR("Tanmay Inamdar <tinamdar@apm.com>");
658MODULE_DESCRIPTION("APM X-Gene PCIe driver");
659MODULE_LICENSE("GPL v2");