diff options
-rw-r--r-- | Documentation/devicetree/bindings/pci/pci-keystone.txt | 68 | ||||
-rw-r--r-- | MAINTAINERS | 7 | ||||
-rw-r--r-- | drivers/pci/host/Kconfig | 10 | ||||
-rw-r--r-- | drivers/pci/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/pci/host/pci-keystone-dw.c | 516 | ||||
-rw-r--r-- | drivers/pci/host/pci-keystone.c | 386 | ||||
-rw-r--r-- | drivers/pci/host/pci-keystone.h | 58 |
7 files changed, 1046 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/pci/pci-keystone.txt b/Documentation/devicetree/bindings/pci/pci-keystone.txt new file mode 100644 index 000000000000..ceb3e2424742 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/pci-keystone.txt | |||
@@ -0,0 +1,68 @@ | |||
1 | TI Keystone PCIe interface | ||
2 | |||
3 | Keystone PCI host Controller is based on Designware PCI h/w version 3.65. | ||
4 | It shares common functions with PCIe Designware core driver and inherit | ||
5 | common properties defined in | ||
6 | Documentation/devicetree/bindings/pci/designware-pci.txt | ||
7 | |||
8 | Please refer to Documentation/devicetree/bindings/pci/designware-pci.txt | ||
9 | for the details of Designware DT bindings. Additional properties are | ||
10 | described here as well as properties that are not applicable. | ||
11 | |||
12 | Required Properties:- | ||
13 | |||
14 | compatibility: "ti,keystone-pcie" | ||
15 | reg: index 1 is the base address and length of DW application registers. | ||
16 | index 2 is the base address and length of PCI mode configuration | ||
17 | register. | ||
18 | index 3 is the base address and length of PCI device ID register. | ||
19 | |||
20 | pcie_msi_intc : Interrupt controller device node for MSI IRQ chip | ||
21 | interrupt-cells: should be set to 1 | ||
22 | interrupt-parent: Parent interrupt controller phandle | ||
23 | interrupts: GIC interrupt lines connected to PCI MSI interrupt lines | ||
24 | |||
25 | Example: | ||
26 | pcie_msi_intc: msi-interrupt-controller { | ||
27 | interrupt-controller; | ||
28 | #interrupt-cells = <1>; | ||
29 | interrupt-parent = <&gic>; | ||
30 | interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>, | ||
31 | <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>, | ||
32 | <GIC_SPI 32 IRQ_TYPE_EDGE_RISING>, | ||
33 | <GIC_SPI 33 IRQ_TYPE_EDGE_RISING>, | ||
34 | <GIC_SPI 34 IRQ_TYPE_EDGE_RISING>, | ||
35 | <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>, | ||
36 | <GIC_SPI 36 IRQ_TYPE_EDGE_RISING>, | ||
37 | <GIC_SPI 37 IRQ_TYPE_EDGE_RISING>; | ||
38 | }; | ||
39 | |||
40 | pcie_intc: Interrupt controller device node for Legacy IRQ chip | ||
41 | interrupt-cells: should be set to 1 | ||
42 | interrupt-parent: Parent interrupt controller phandle | ||
43 | interrupts: GIC interrupt lines connected to PCI Legacy interrupt lines | ||
44 | |||
45 | Example: | ||
46 | pcie_intc: legacy-interrupt-controller { | ||
47 | interrupt-controller; | ||
48 | #interrupt-cells = <1>; | ||
49 | interrupt-parent = <&gic>; | ||
50 | interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>, | ||
51 | <GIC_SPI 27 IRQ_TYPE_EDGE_RISING>, | ||
52 | <GIC_SPI 28 IRQ_TYPE_EDGE_RISING>, | ||
53 | <GIC_SPI 29 IRQ_TYPE_EDGE_RISING>; | ||
54 | }; | ||
55 | |||
56 | Optional properties:- | ||
57 | phys: phandle to Generic Keystone SerDes phy for PCI | ||
58 | phy-names: name of the Generic Keystine SerDes phy for PCI | ||
59 | - If boot loader already does PCI link establishment, then phys and | ||
60 | phy-names shouldn't be present. | ||
61 | |||
62 | Designware DT Properties not applicable for Keystone PCI | ||
63 | |||
64 | 1. pcie_bus clock-names not used. Instead, a phandle to phys is used. | ||
65 | |||
66 | Note for PCI driver usage | ||
67 | ========================= | ||
68 | Driver requires pci=pcie_bus_perf in the bootargs for proper functioning. | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 1ff06dee651d..d639df9701cf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -6876,6 +6876,13 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) | |||
6876 | S: Maintained | 6876 | S: Maintained |
6877 | F: drivers/pci/host/*imx6* | 6877 | F: drivers/pci/host/*imx6* |
6878 | 6878 | ||
6879 | PCI DRIVER FOR TI KEYSTONE | ||
6880 | M: Murali Karicheri <m-karicheri2@ti.com> | ||
6881 | L: linux-pci@vger.kernel.org | ||
6882 | L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) | ||
6883 | S: Maintained | ||
6884 | F: drivers/pci/host/*keystone* | ||
6885 | |||
6879 | PCI DRIVER FOR MVEBU (Marvell Armada 370 and Armada XP SOC support) | 6886 | PCI DRIVER FOR MVEBU (Marvell Armada 370 and Armada XP SOC support) |
6880 | M: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> | 6887 | M: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> |
6881 | M: Jason Cooper <jason@lakedaemon.net> | 6888 | M: Jason Cooper <jason@lakedaemon.net> |
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 8922c376456a..3fe8bf627f70 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig | |||
@@ -63,4 +63,14 @@ 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 | config PCI_KEYSTONE | ||
67 | bool "TI Keystone PCIe controller" | ||
68 | depends on ARCH_KEYSTONE | ||
69 | select PCIE_DW | ||
70 | select PCIEPORTBUS | ||
71 | help | ||
72 | Say Y here if you want to enable PCI controller support on Keystone | ||
73 | SoCs. The PCI controller on Keystone is based on Designware hardware | ||
74 | and therefore the driver re-uses the Designware core functions to | ||
75 | implement the driver. | ||
66 | endmenu | 76 | endmenu |
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index d0e88f114ff9..057ea60f5cdd 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile | |||
@@ -8,3 +8,4 @@ obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o | |||
8 | obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o | 8 | obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o |
9 | obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o | 9 | obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o |
10 | obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o | 10 | obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o |
11 | obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o | ||
diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c new file mode 100644 index 000000000000..2434786ca40b --- /dev/null +++ b/drivers/pci/host/pci-keystone-dw.c | |||
@@ -0,0 +1,516 @@ | |||
1 | /* | ||
2 | * Designware application register space functions for Keystone PCI controller | ||
3 | * | ||
4 | * Copyright (C) 2013-2014 Texas Instruments., Ltd. | ||
5 | * http://www.ti.com | ||
6 | * | ||
7 | * Author: Murali Karicheri <m-karicheri2@ti.com> | ||
8 | * | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/irq.h> | ||
16 | #include <linux/irqdomain.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/of_pci.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | |||
23 | #include "pcie-designware.h" | ||
24 | #include "pci-keystone.h" | ||
25 | |||
26 | /* Application register defines */ | ||
27 | #define LTSSM_EN_VAL 1 | ||
28 | #define LTSSM_STATE_MASK 0x1f | ||
29 | #define LTSSM_STATE_L0 0x11 | ||
30 | #define DBI_CS2_EN_VAL 0x20 | ||
31 | #define OB_XLAT_EN_VAL 2 | ||
32 | |||
33 | /* Application registers */ | ||
34 | #define CMD_STATUS 0x004 | ||
35 | #define CFG_SETUP 0x008 | ||
36 | #define OB_SIZE 0x030 | ||
37 | #define CFG_PCIM_WIN_SZ_IDX 3 | ||
38 | #define CFG_PCIM_WIN_CNT 32 | ||
39 | #define SPACE0_REMOTE_CFG_OFFSET 0x1000 | ||
40 | #define OB_OFFSET_INDEX(n) (0x200 + (8 * n)) | ||
41 | #define OB_OFFSET_HI(n) (0x204 + (8 * n)) | ||
42 | |||
43 | /* IRQ register defines */ | ||
44 | #define IRQ_EOI 0x050 | ||
45 | #define IRQ_STATUS 0x184 | ||
46 | #define IRQ_ENABLE_SET 0x188 | ||
47 | #define IRQ_ENABLE_CLR 0x18c | ||
48 | |||
49 | #define MSI_IRQ 0x054 | ||
50 | #define MSI0_IRQ_STATUS 0x104 | ||
51 | #define MSI0_IRQ_ENABLE_SET 0x108 | ||
52 | #define MSI0_IRQ_ENABLE_CLR 0x10c | ||
53 | #define IRQ_STATUS 0x184 | ||
54 | #define MSI_IRQ_OFFSET 4 | ||
55 | |||
56 | /* Config space registers */ | ||
57 | #define DEBUG0 0x728 | ||
58 | |||
59 | #define to_keystone_pcie(x) container_of(x, struct keystone_pcie, pp) | ||
60 | |||
61 | static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) | ||
62 | { | ||
63 | return sys->private_data; | ||
64 | } | ||
65 | |||
66 | static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset, | ||
67 | u32 *bit_pos) | ||
68 | { | ||
69 | *reg_offset = offset % 8; | ||
70 | *bit_pos = offset >> 3; | ||
71 | } | ||
72 | |||
73 | u32 ks_dw_pcie_get_msi_data(struct pcie_port *pp) | ||
74 | { | ||
75 | struct keystone_pcie *ks_pcie = to_keystone_pcie(pp); | ||
76 | |||
77 | return ks_pcie->app.start + MSI_IRQ; | ||
78 | } | ||
79 | |||
80 | void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset) | ||
81 | { | ||
82 | struct pcie_port *pp = &ks_pcie->pp; | ||
83 | u32 pending, vector; | ||
84 | int src, virq; | ||
85 | |||
86 | pending = readl(ks_pcie->va_app_base + MSI0_IRQ_STATUS + (offset << 4)); | ||
87 | |||
88 | /* | ||
89 | * MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit | ||
90 | * shows 1, 9, 17, 25 and so forth | ||
91 | */ | ||
92 | for (src = 0; src < 4; src++) { | ||
93 | if (BIT(src) & pending) { | ||
94 | vector = offset + (src << 3); | ||
95 | virq = irq_linear_revmap(pp->irq_domain, vector); | ||
96 | dev_dbg(pp->dev, "irq: bit %d, vector %d, virq %d\n", | ||
97 | src, vector, virq); | ||
98 | generic_handle_irq(virq); | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | |||
103 | static void ks_dw_pcie_msi_irq_ack(struct irq_data *d) | ||
104 | { | ||
105 | u32 offset, reg_offset, bit_pos; | ||
106 | struct keystone_pcie *ks_pcie; | ||
107 | unsigned int irq = d->irq; | ||
108 | struct msi_desc *msi; | ||
109 | struct pcie_port *pp; | ||
110 | |||
111 | msi = irq_get_msi_desc(irq); | ||
112 | pp = sys_to_pcie(msi->dev->bus->sysdata); | ||
113 | ks_pcie = to_keystone_pcie(pp); | ||
114 | offset = irq - irq_linear_revmap(pp->irq_domain, 0); | ||
115 | update_reg_offset_bit_pos(offset, ®_offset, &bit_pos); | ||
116 | |||
117 | writel(BIT(bit_pos), | ||
118 | ks_pcie->va_app_base + MSI0_IRQ_STATUS + (reg_offset << 4)); | ||
119 | writel(reg_offset + MSI_IRQ_OFFSET, ks_pcie->va_app_base + IRQ_EOI); | ||
120 | } | ||
121 | |||
122 | void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) | ||
123 | { | ||
124 | u32 reg_offset, bit_pos; | ||
125 | struct keystone_pcie *ks_pcie = to_keystone_pcie(pp); | ||
126 | |||
127 | update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); | ||
128 | writel(BIT(bit_pos), | ||
129 | ks_pcie->va_app_base + MSI0_IRQ_ENABLE_SET + (reg_offset << 4)); | ||
130 | } | ||
131 | |||
132 | void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) | ||
133 | { | ||
134 | u32 reg_offset, bit_pos; | ||
135 | struct keystone_pcie *ks_pcie = to_keystone_pcie(pp); | ||
136 | |||
137 | update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); | ||
138 | writel(BIT(bit_pos), | ||
139 | ks_pcie->va_app_base + MSI0_IRQ_ENABLE_CLR + (reg_offset << 4)); | ||
140 | } | ||
141 | |||
142 | static void ks_dw_pcie_msi_irq_mask(struct irq_data *d) | ||
143 | { | ||
144 | struct keystone_pcie *ks_pcie; | ||
145 | unsigned int irq = d->irq; | ||
146 | struct msi_desc *msi; | ||
147 | struct pcie_port *pp; | ||
148 | u32 offset; | ||
149 | |||
150 | msi = irq_get_msi_desc(irq); | ||
151 | pp = sys_to_pcie(msi->dev->bus->sysdata); | ||
152 | ks_pcie = to_keystone_pcie(pp); | ||
153 | offset = irq - irq_linear_revmap(pp->irq_domain, 0); | ||
154 | |||
155 | /* Mask the end point if PVM implemented */ | ||
156 | if (IS_ENABLED(CONFIG_PCI_MSI)) { | ||
157 | if (msi->msi_attrib.maskbit) | ||
158 | mask_msi_irq(d); | ||
159 | } | ||
160 | |||
161 | ks_dw_pcie_msi_clear_irq(pp, offset); | ||
162 | } | ||
163 | |||
164 | static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d) | ||
165 | { | ||
166 | struct keystone_pcie *ks_pcie; | ||
167 | unsigned int irq = d->irq; | ||
168 | struct msi_desc *msi; | ||
169 | struct pcie_port *pp; | ||
170 | u32 offset; | ||
171 | |||
172 | msi = irq_get_msi_desc(irq); | ||
173 | pp = sys_to_pcie(msi->dev->bus->sysdata); | ||
174 | ks_pcie = to_keystone_pcie(pp); | ||
175 | offset = irq - irq_linear_revmap(pp->irq_domain, 0); | ||
176 | |||
177 | /* Mask the end point if PVM implemented */ | ||
178 | if (IS_ENABLED(CONFIG_PCI_MSI)) { | ||
179 | if (msi->msi_attrib.maskbit) | ||
180 | unmask_msi_irq(d); | ||
181 | } | ||
182 | |||
183 | ks_dw_pcie_msi_set_irq(pp, offset); | ||
184 | } | ||
185 | |||
186 | static struct irq_chip ks_dw_pcie_msi_irq_chip = { | ||
187 | .name = "Keystone-PCIe-MSI-IRQ", | ||
188 | .irq_ack = ks_dw_pcie_msi_irq_ack, | ||
189 | .irq_mask = ks_dw_pcie_msi_irq_mask, | ||
190 | .irq_unmask = ks_dw_pcie_msi_irq_unmask, | ||
191 | }; | ||
192 | |||
193 | static int ks_dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq, | ||
194 | irq_hw_number_t hwirq) | ||
195 | { | ||
196 | irq_set_chip_and_handler(irq, &ks_dw_pcie_msi_irq_chip, | ||
197 | handle_level_irq); | ||
198 | irq_set_chip_data(irq, domain->host_data); | ||
199 | set_irq_flags(irq, IRQF_VALID); | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | const struct irq_domain_ops ks_dw_pcie_msi_domain_ops = { | ||
205 | .map = ks_dw_pcie_msi_map, | ||
206 | }; | ||
207 | |||
208 | int ks_dw_pcie_msi_host_init(struct pcie_port *pp, struct msi_chip *chip) | ||
209 | { | ||
210 | struct keystone_pcie *ks_pcie = to_keystone_pcie(pp); | ||
211 | int i; | ||
212 | |||
213 | pp->irq_domain = irq_domain_add_linear(ks_pcie->msi_intc_np, | ||
214 | MAX_MSI_IRQS, | ||
215 | &ks_dw_pcie_msi_domain_ops, | ||
216 | chip); | ||
217 | if (!pp->irq_domain) { | ||
218 | dev_err(pp->dev, "irq domain init failed\n"); | ||
219 | return -ENXIO; | ||
220 | } | ||
221 | |||
222 | for (i = 0; i < MAX_MSI_IRQS; i++) | ||
223 | irq_create_mapping(pp->irq_domain, i); | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie) | ||
229 | { | ||
230 | int i; | ||
231 | |||
232 | for (i = 0; i < MAX_LEGACY_IRQS; i++) | ||
233 | writel(0x1, ks_pcie->va_app_base + IRQ_ENABLE_SET + (i << 4)); | ||
234 | } | ||
235 | |||
236 | void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset) | ||
237 | { | ||
238 | struct pcie_port *pp = &ks_pcie->pp; | ||
239 | u32 pending; | ||
240 | int virq; | ||
241 | |||
242 | pending = readl(ks_pcie->va_app_base + IRQ_STATUS + (offset << 4)); | ||
243 | |||
244 | if (BIT(0) & pending) { | ||
245 | virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset); | ||
246 | dev_dbg(pp->dev, ": irq: irq_offset %d, virq %d\n", offset, | ||
247 | virq); | ||
248 | generic_handle_irq(virq); | ||
249 | } | ||
250 | |||
251 | /* EOI the INTx interrupt */ | ||
252 | writel(offset, ks_pcie->va_app_base + IRQ_EOI); | ||
253 | } | ||
254 | |||
255 | static void ks_dw_pcie_ack_legacy_irq(struct irq_data *d) | ||
256 | { | ||
257 | } | ||
258 | |||
259 | static void ks_dw_pcie_mask_legacy_irq(struct irq_data *d) | ||
260 | { | ||
261 | } | ||
262 | |||
263 | static void ks_dw_pcie_unmask_legacy_irq(struct irq_data *d) | ||
264 | { | ||
265 | } | ||
266 | |||
267 | static struct irq_chip ks_dw_pcie_legacy_irq_chip = { | ||
268 | .name = "Keystone-PCI-Legacy-IRQ", | ||
269 | .irq_ack = ks_dw_pcie_ack_legacy_irq, | ||
270 | .irq_mask = ks_dw_pcie_mask_legacy_irq, | ||
271 | .irq_unmask = ks_dw_pcie_unmask_legacy_irq, | ||
272 | }; | ||
273 | |||
274 | static int ks_dw_pcie_init_legacy_irq_map(struct irq_domain *d, | ||
275 | unsigned int irq, irq_hw_number_t hw_irq) | ||
276 | { | ||
277 | irq_set_chip_and_handler(irq, &ks_dw_pcie_legacy_irq_chip, | ||
278 | handle_level_irq); | ||
279 | irq_set_chip_data(irq, d->host_data); | ||
280 | set_irq_flags(irq, IRQF_VALID); | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static const struct irq_domain_ops ks_dw_pcie_legacy_irq_domain_ops = { | ||
286 | .map = ks_dw_pcie_init_legacy_irq_map, | ||
287 | .xlate = irq_domain_xlate_onetwocell, | ||
288 | }; | ||
289 | |||
290 | /** | ||
291 | * ks_dw_pcie_set_dbi_mode() - Set DBI mode to access overlaid BAR mask | ||
292 | * registers | ||
293 | * | ||
294 | * Since modification of dbi_cs2 involves different clock domain, read the | ||
295 | * status back to ensure the transition is complete. | ||
296 | */ | ||
297 | static void ks_dw_pcie_set_dbi_mode(void __iomem *reg_virt) | ||
298 | { | ||
299 | u32 val; | ||
300 | |||
301 | writel(DBI_CS2_EN_VAL | readl(reg_virt + CMD_STATUS), | ||
302 | reg_virt + CMD_STATUS); | ||
303 | |||
304 | do { | ||
305 | val = readl(reg_virt + CMD_STATUS); | ||
306 | } while (!(val & DBI_CS2_EN_VAL)); | ||
307 | } | ||
308 | |||
309 | /** | ||
310 | * ks_dw_pcie_clear_dbi_mode() - Disable DBI mode | ||
311 | * | ||
312 | * Since modification of dbi_cs2 involves different clock domain, read the | ||
313 | * status back to ensure the transition is complete. | ||
314 | */ | ||
315 | static void ks_dw_pcie_clear_dbi_mode(void __iomem *reg_virt) | ||
316 | { | ||
317 | u32 val; | ||
318 | |||
319 | writel(~DBI_CS2_EN_VAL & readl(reg_virt + CMD_STATUS), | ||
320 | reg_virt + CMD_STATUS); | ||
321 | |||
322 | do { | ||
323 | val = readl(reg_virt + CMD_STATUS); | ||
324 | } while (val & DBI_CS2_EN_VAL); | ||
325 | } | ||
326 | |||
327 | void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) | ||
328 | { | ||
329 | struct pcie_port *pp = &ks_pcie->pp; | ||
330 | u32 start = pp->mem.start, end = pp->mem.end; | ||
331 | int i, tr_size; | ||
332 | |||
333 | /* Disable BARs for inbound access */ | ||
334 | ks_dw_pcie_set_dbi_mode(ks_pcie->va_app_base); | ||
335 | writel(0, pp->dbi_base + PCI_BASE_ADDRESS_0); | ||
336 | writel(0, pp->dbi_base + PCI_BASE_ADDRESS_1); | ||
337 | ks_dw_pcie_clear_dbi_mode(ks_pcie->va_app_base); | ||
338 | |||
339 | /* Set outbound translation size per window division */ | ||
340 | writel(CFG_PCIM_WIN_SZ_IDX & 0x7, ks_pcie->va_app_base + OB_SIZE); | ||
341 | |||
342 | tr_size = (1 << (CFG_PCIM_WIN_SZ_IDX & 0x7)) * SZ_1M; | ||
343 | |||
344 | /* Using Direct 1:1 mapping of RC <-> PCI memory space */ | ||
345 | for (i = 0; (i < CFG_PCIM_WIN_CNT) && (start < end); i++) { | ||
346 | writel(start | 1, ks_pcie->va_app_base + OB_OFFSET_INDEX(i)); | ||
347 | writel(0, ks_pcie->va_app_base + OB_OFFSET_HI(i)); | ||
348 | start += tr_size; | ||
349 | } | ||
350 | |||
351 | /* Enable OB translation */ | ||
352 | writel(OB_XLAT_EN_VAL | readl(ks_pcie->va_app_base + CMD_STATUS), | ||
353 | ks_pcie->va_app_base + CMD_STATUS); | ||
354 | } | ||
355 | |||
356 | /** | ||
357 | * ks_pcie_cfg_setup() - Set up configuration space address for a device | ||
358 | * | ||
359 | * @ks_pcie: ptr to keystone_pcie structure | ||
360 | * @bus: Bus number the device is residing on | ||
361 | * @devfn: device, function number info | ||
362 | * | ||
363 | * Forms and returns the address of configuration space mapped in PCIESS | ||
364 | * address space 0. Also configures CFG_SETUP for remote configuration space | ||
365 | * access. | ||
366 | * | ||
367 | * The address space has two regions to access configuration - local and remote. | ||
368 | * We access local region for bus 0 (as RC is attached on bus 0) and remote | ||
369 | * region for others with TYPE 1 access when bus > 1. As for device on bus = 1, | ||
370 | * we will do TYPE 0 access as it will be on our secondary bus (logical). | ||
371 | * CFG_SETUP is needed only for remote configuration access. | ||
372 | */ | ||
373 | static void __iomem *ks_pcie_cfg_setup(struct keystone_pcie *ks_pcie, u8 bus, | ||
374 | unsigned int devfn) | ||
375 | { | ||
376 | u8 device = PCI_SLOT(devfn), function = PCI_FUNC(devfn); | ||
377 | struct pcie_port *pp = &ks_pcie->pp; | ||
378 | u32 regval; | ||
379 | |||
380 | if (bus == 0) | ||
381 | return pp->dbi_base; | ||
382 | |||
383 | regval = (bus << 16) | (device << 8) | function; | ||
384 | |||
385 | /* | ||
386 | * Since Bus#1 will be a virtual bus, we need to have TYPE0 | ||
387 | * access only. | ||
388 | * TYPE 1 | ||
389 | */ | ||
390 | if (bus != 1) | ||
391 | regval |= BIT(24); | ||
392 | |||
393 | writel(regval, ks_pcie->va_app_base + CFG_SETUP); | ||
394 | return pp->va_cfg0_base; | ||
395 | } | ||
396 | |||
397 | int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, | ||
398 | unsigned int devfn, int where, int size, u32 *val) | ||
399 | { | ||
400 | struct keystone_pcie *ks_pcie = to_keystone_pcie(pp); | ||
401 | u8 bus_num = bus->number; | ||
402 | void __iomem *addr; | ||
403 | |||
404 | addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn); | ||
405 | |||
406 | return dw_pcie_cfg_read(addr + (where & ~0x3), where, size, val); | ||
407 | } | ||
408 | |||
409 | int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, | ||
410 | unsigned int devfn, int where, int size, u32 val) | ||
411 | { | ||
412 | struct keystone_pcie *ks_pcie = to_keystone_pcie(pp); | ||
413 | u8 bus_num = bus->number; | ||
414 | void __iomem *addr; | ||
415 | |||
416 | addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn); | ||
417 | |||
418 | return dw_pcie_cfg_write(addr + (where & ~0x3), where, size, val); | ||
419 | } | ||
420 | |||
421 | /** | ||
422 | * ks_dw_pcie_v3_65_scan_bus() - keystone scan_bus post initialization | ||
423 | * | ||
424 | * This sets BAR0 to enable inbound access for MSI_IRQ register | ||
425 | */ | ||
426 | void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp) | ||
427 | { | ||
428 | struct keystone_pcie *ks_pcie = to_keystone_pcie(pp); | ||
429 | |||
430 | /* Configure and set up BAR0 */ | ||
431 | ks_dw_pcie_set_dbi_mode(ks_pcie->va_app_base); | ||
432 | |||
433 | /* Enable BAR0 */ | ||
434 | writel(1, pp->dbi_base + PCI_BASE_ADDRESS_0); | ||
435 | writel(SZ_4K - 1, pp->dbi_base + PCI_BASE_ADDRESS_0); | ||
436 | |||
437 | ks_dw_pcie_clear_dbi_mode(ks_pcie->va_app_base); | ||
438 | |||
439 | /* | ||
440 | * For BAR0, just setting bus address for inbound writes (MSI) should | ||
441 | * be sufficient. Use physical address to avoid any conflicts. | ||
442 | */ | ||
443 | writel(ks_pcie->app.start, pp->dbi_base + PCI_BASE_ADDRESS_0); | ||
444 | } | ||
445 | |||
446 | /** | ||
447 | * ks_dw_pcie_link_up() - Check if link up | ||
448 | */ | ||
449 | int ks_dw_pcie_link_up(struct pcie_port *pp) | ||
450 | { | ||
451 | u32 val = readl(pp->dbi_base + DEBUG0); | ||
452 | |||
453 | return (val & LTSSM_STATE_MASK) == LTSSM_STATE_L0; | ||
454 | } | ||
455 | |||
456 | void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie) | ||
457 | { | ||
458 | u32 val; | ||
459 | |||
460 | /* Disable Link training */ | ||
461 | val = readl(ks_pcie->va_app_base + CMD_STATUS); | ||
462 | val &= ~LTSSM_EN_VAL; | ||
463 | writel(LTSSM_EN_VAL | val, ks_pcie->va_app_base + CMD_STATUS); | ||
464 | |||
465 | /* Initiate Link Training */ | ||
466 | val = readl(ks_pcie->va_app_base + CMD_STATUS); | ||
467 | writel(LTSSM_EN_VAL | val, ks_pcie->va_app_base + CMD_STATUS); | ||
468 | } | ||
469 | |||
470 | /** | ||
471 | * ks_dw_pcie_host_init() - initialize host for v3_65 dw hardware | ||
472 | * | ||
473 | * Ioremap the register resources, initialize legacy irq domain | ||
474 | * and call dw_pcie_v3_65_host_init() API to initialize the Keystone | ||
475 | * PCI host controller. | ||
476 | */ | ||
477 | int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie, | ||
478 | struct device_node *msi_intc_np) | ||
479 | { | ||
480 | struct pcie_port *pp = &ks_pcie->pp; | ||
481 | struct platform_device *pdev = to_platform_device(pp->dev); | ||
482 | struct resource *res; | ||
483 | |||
484 | /* Index 0 is the config reg. space address */ | ||
485 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
486 | pp->dbi_base = devm_ioremap_resource(pp->dev, res); | ||
487 | if (IS_ERR(pp->dbi_base)) | ||
488 | return PTR_ERR(pp->dbi_base); | ||
489 | |||
490 | /* | ||
491 | * We set these same and is used in pcie rd/wr_other_conf | ||
492 | * functions | ||
493 | */ | ||
494 | pp->va_cfg0_base = pp->dbi_base + SPACE0_REMOTE_CFG_OFFSET; | ||
495 | pp->va_cfg1_base = pp->va_cfg0_base; | ||
496 | |||
497 | /* Index 1 is the application reg. space address */ | ||
498 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
499 | ks_pcie->app = *res; | ||
500 | ks_pcie->va_app_base = devm_ioremap_resource(pp->dev, res); | ||
501 | if (IS_ERR(ks_pcie->va_app_base)) | ||
502 | return PTR_ERR(ks_pcie->va_app_base); | ||
503 | |||
504 | /* Create legacy IRQ domain */ | ||
505 | ks_pcie->legacy_irq_domain = | ||
506 | irq_domain_add_linear(ks_pcie->legacy_intc_np, | ||
507 | MAX_LEGACY_IRQS, | ||
508 | &ks_dw_pcie_legacy_irq_domain_ops, | ||
509 | NULL); | ||
510 | if (!ks_pcie->legacy_irq_domain) { | ||
511 | dev_err(pp->dev, "Failed to add irq domain for legacy irqs\n"); | ||
512 | return -EINVAL; | ||
513 | } | ||
514 | |||
515 | return dw_pcie_host_init(pp); | ||
516 | } | ||
diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c new file mode 100644 index 000000000000..c1cfaef7faf3 --- /dev/null +++ b/drivers/pci/host/pci-keystone.c | |||
@@ -0,0 +1,386 @@ | |||
1 | /* | ||
2 | * PCIe host controller driver for Texas Instruments Keystone SoCs | ||
3 | * | ||
4 | * Copyright (C) 2013-2014 Texas Instruments., Ltd. | ||
5 | * http://www.ti.com | ||
6 | * | ||
7 | * Author: Murali Karicheri <m-karicheri2@ti.com> | ||
8 | * Implementation based on pci-exynos.c and pcie-designware.c | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/irqchip/chained_irq.h> | ||
16 | #include <linux/clk.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/irqdomain.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/msi.h> | ||
21 | #include <linux/of_irq.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/of_pci.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/phy/phy.h> | ||
26 | #include <linux/resource.h> | ||
27 | #include <linux/signal.h> | ||
28 | |||
29 | #include "pcie-designware.h" | ||
30 | #include "pci-keystone.h" | ||
31 | |||
32 | #define DRIVER_NAME "keystone-pcie" | ||
33 | |||
34 | /* driver specific constants */ | ||
35 | #define MAX_MSI_HOST_IRQS 8 | ||
36 | #define MAX_LEGACY_HOST_IRQS 4 | ||
37 | |||
38 | /* RC mode settings masks */ | ||
39 | #define PCIE_RC_MODE BIT(2) | ||
40 | #define PCIE_MODE_MASK (BIT(1) | BIT(2)) | ||
41 | |||
42 | /* DEV_STAT_CTRL */ | ||
43 | #define PCIE_CAP_BASE 0x70 | ||
44 | |||
45 | #define to_keystone_pcie(x) container_of(x, struct keystone_pcie, pp) | ||
46 | |||
47 | static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) | ||
48 | { | ||
49 | struct pcie_port *pp = &ks_pcie->pp; | ||
50 | int count = 200; | ||
51 | |||
52 | dw_pcie_setup_rc(pp); | ||
53 | |||
54 | if (dw_pcie_link_up(pp)) { | ||
55 | dev_err(pp->dev, "Link already up\n"); | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | ks_dw_pcie_initiate_link_train(ks_pcie); | ||
60 | /* check if the link is up or not */ | ||
61 | while (!dw_pcie_link_up(pp)) { | ||
62 | usleep_range(100, 1000); | ||
63 | if (--count) { | ||
64 | ks_dw_pcie_initiate_link_train(ks_pcie); | ||
65 | continue; | ||
66 | } | ||
67 | dev_err(pp->dev, "phy link never came up\n"); | ||
68 | return -EINVAL; | ||
69 | } | ||
70 | |||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
75 | { | ||
76 | struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc); | ||
77 | u32 offset = irq - ks_pcie->msi_host_irqs[0]; | ||
78 | struct pcie_port *pp = &ks_pcie->pp; | ||
79 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
80 | |||
81 | dev_dbg(pp->dev, "ks_pci_msi_irq_handler, irq %d\n", irq); | ||
82 | |||
83 | /* | ||
84 | * The chained irq handler installation would have replaced normal | ||
85 | * interrupt driver handler so we need to take care of mask/unmask and | ||
86 | * ack operation. | ||
87 | */ | ||
88 | chained_irq_enter(chip, desc); | ||
89 | ks_dw_pcie_handle_msi_irq(ks_pcie, offset); | ||
90 | chained_irq_exit(chip, desc); | ||
91 | } | ||
92 | |||
93 | /** | ||
94 | * ks_pcie_legacy_irq_handler() - Handle legacy interrupt | ||
95 | * @irq: IRQ line for legacy interrupts | ||
96 | * @desc: Pointer to irq descriptor | ||
97 | * | ||
98 | * Traverse through pending legacy interrupts and invoke handler for each. Also | ||
99 | * takes care of interrupt controller level mask/ack operation. | ||
100 | */ | ||
101 | static void ks_pcie_legacy_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
102 | { | ||
103 | struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc); | ||
104 | struct pcie_port *pp = &ks_pcie->pp; | ||
105 | u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0]; | ||
106 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
107 | |||
108 | dev_dbg(pp->dev, ": Handling legacy irq %d\n", irq); | ||
109 | |||
110 | /* | ||
111 | * The chained irq handler installation would have replaced normal | ||
112 | * interrupt driver handler so we need to take care of mask/unmask and | ||
113 | * ack operation. | ||
114 | */ | ||
115 | chained_irq_enter(chip, desc); | ||
116 | ks_dw_pcie_handle_legacy_irq(ks_pcie, irq_offset); | ||
117 | chained_irq_exit(chip, desc); | ||
118 | } | ||
119 | |||
120 | static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie, | ||
121 | char *controller, int *num_irqs) | ||
122 | { | ||
123 | int temp, max_host_irqs, legacy = 1, *host_irqs, ret = -EINVAL; | ||
124 | struct device *dev = ks_pcie->pp.dev; | ||
125 | struct device_node *np_pcie = dev->of_node, **np_temp; | ||
126 | |||
127 | if (!strcmp(controller, "msi-interrupt-controller")) | ||
128 | legacy = 0; | ||
129 | |||
130 | if (legacy) { | ||
131 | np_temp = &ks_pcie->legacy_intc_np; | ||
132 | max_host_irqs = MAX_LEGACY_HOST_IRQS; | ||
133 | host_irqs = &ks_pcie->legacy_host_irqs[0]; | ||
134 | } else { | ||
135 | np_temp = &ks_pcie->msi_intc_np; | ||
136 | max_host_irqs = MAX_MSI_HOST_IRQS; | ||
137 | host_irqs = &ks_pcie->msi_host_irqs[0]; | ||
138 | } | ||
139 | |||
140 | /* interrupt controller is in a child node */ | ||
141 | *np_temp = of_find_node_by_name(np_pcie, controller); | ||
142 | if (!(*np_temp)) { | ||
143 | dev_err(dev, "Node for %s is absent\n", controller); | ||
144 | goto out; | ||
145 | } | ||
146 | temp = of_irq_count(*np_temp); | ||
147 | if (!temp) | ||
148 | goto out; | ||
149 | if (temp > max_host_irqs) | ||
150 | dev_warn(dev, "Too many %s interrupts defined %u\n", | ||
151 | (legacy ? "legacy" : "MSI"), temp); | ||
152 | |||
153 | /* | ||
154 | * support upto max_host_irqs. In dt from index 0 to 3 (legacy) or 0 to | ||
155 | * 7 (MSI) | ||
156 | */ | ||
157 | for (temp = 0; temp < max_host_irqs; temp++) { | ||
158 | host_irqs[temp] = irq_of_parse_and_map(*np_temp, temp); | ||
159 | if (host_irqs[temp] < 0) | ||
160 | break; | ||
161 | } | ||
162 | if (temp) { | ||
163 | *num_irqs = temp; | ||
164 | ret = 0; | ||
165 | } | ||
166 | out: | ||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie) | ||
171 | { | ||
172 | int i; | ||
173 | |||
174 | /* Legacy IRQ */ | ||
175 | for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) { | ||
176 | irq_set_handler_data(ks_pcie->legacy_host_irqs[i], ks_pcie); | ||
177 | irq_set_chained_handler(ks_pcie->legacy_host_irqs[i], | ||
178 | ks_pcie_legacy_irq_handler); | ||
179 | } | ||
180 | ks_dw_pcie_enable_legacy_irqs(ks_pcie); | ||
181 | |||
182 | /* MSI IRQ */ | ||
183 | if (IS_ENABLED(CONFIG_PCI_MSI)) { | ||
184 | for (i = 0; i < ks_pcie->num_msi_host_irqs; i++) { | ||
185 | irq_set_chained_handler(ks_pcie->msi_host_irqs[i], | ||
186 | ks_pcie_msi_irq_handler); | ||
187 | irq_set_handler_data(ks_pcie->msi_host_irqs[i], | ||
188 | ks_pcie); | ||
189 | } | ||
190 | } | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | * When a PCI device does not exist during config cycles, keystone host gets a | ||
195 | * bus error instead of returning 0xffffffff. This handler always returns 0 | ||
196 | * for this kind of faults. | ||
197 | */ | ||
198 | static int keystone_pcie_fault(unsigned long addr, unsigned int fsr, | ||
199 | struct pt_regs *regs) | ||
200 | { | ||
201 | unsigned long instr = *(unsigned long *) instruction_pointer(regs); | ||
202 | |||
203 | if ((instr & 0x0e100090) == 0x00100090) { | ||
204 | int reg = (instr >> 12) & 15; | ||
205 | |||
206 | regs->uregs[reg] = -1; | ||
207 | regs->ARM_pc += 4; | ||
208 | } | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static void __init ks_pcie_host_init(struct pcie_port *pp) | ||
214 | { | ||
215 | u32 vendor_device_id, val; | ||
216 | struct keystone_pcie *ks_pcie = to_keystone_pcie(pp); | ||
217 | |||
218 | ks_pcie_establish_link(ks_pcie); | ||
219 | ks_dw_pcie_setup_rc_app_regs(ks_pcie); | ||
220 | ks_pcie_setup_interrupts(ks_pcie); | ||
221 | writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8), | ||
222 | pp->dbi_base + PCI_IO_BASE); | ||
223 | |||
224 | /* update the Vendor ID */ | ||
225 | vendor_device_id = readl(ks_pcie->va_reg_pciid); | ||
226 | writew((vendor_device_id >> 16), pp->dbi_base + PCI_DEVICE_ID); | ||
227 | |||
228 | /* update the DEV_STAT_CTRL to publish right mrrs */ | ||
229 | val = readl(pp->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL); | ||
230 | val &= ~PCI_EXP_DEVCTL_READRQ; | ||
231 | /* set the mrrs to 256 bytes */ | ||
232 | val |= BIT(12); | ||
233 | writel(val, pp->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL); | ||
234 | |||
235 | /* | ||
236 | * PCIe access errors that result into OCP errors are caught by ARM as | ||
237 | * "External aborts" | ||
238 | */ | ||
239 | hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0, | ||
240 | "Asynchronous external abort"); | ||
241 | } | ||
242 | |||
243 | static struct pcie_host_ops keystone_pcie_host_ops = { | ||
244 | .rd_other_conf = ks_dw_pcie_rd_other_conf, | ||
245 | .wr_other_conf = ks_dw_pcie_wr_other_conf, | ||
246 | .link_up = ks_dw_pcie_link_up, | ||
247 | .host_init = ks_pcie_host_init, | ||
248 | .msi_set_irq = ks_dw_pcie_msi_set_irq, | ||
249 | .msi_clear_irq = ks_dw_pcie_msi_clear_irq, | ||
250 | .get_msi_data = ks_dw_pcie_get_msi_data, | ||
251 | .msi_host_init = ks_dw_pcie_msi_host_init, | ||
252 | .scan_bus = ks_dw_pcie_v3_65_scan_bus, | ||
253 | }; | ||
254 | |||
255 | static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie, | ||
256 | struct platform_device *pdev) | ||
257 | { | ||
258 | struct pcie_port *pp = &ks_pcie->pp; | ||
259 | int ret; | ||
260 | |||
261 | ret = ks_pcie_get_irq_controller_info(ks_pcie, | ||
262 | "legacy-interrupt-controller", | ||
263 | &ks_pcie->num_legacy_host_irqs); | ||
264 | if (ret) | ||
265 | return ret; | ||
266 | |||
267 | if (IS_ENABLED(CONFIG_PCI_MSI)) { | ||
268 | ret = ks_pcie_get_irq_controller_info(ks_pcie, | ||
269 | "msi-interrupt-controller", | ||
270 | &ks_pcie->num_msi_host_irqs); | ||
271 | if (ret) | ||
272 | return ret; | ||
273 | } | ||
274 | |||
275 | pp->root_bus_nr = -1; | ||
276 | pp->ops = &keystone_pcie_host_ops; | ||
277 | ret = ks_dw_pcie_host_init(ks_pcie, ks_pcie->msi_intc_np); | ||
278 | if (ret) { | ||
279 | dev_err(&pdev->dev, "failed to initialize host\n"); | ||
280 | return ret; | ||
281 | } | ||
282 | |||
283 | return ret; | ||
284 | } | ||
285 | |||
286 | static const struct of_device_id ks_pcie_of_match[] = { | ||
287 | { | ||
288 | .type = "pci", | ||
289 | .compatible = "ti,keystone-pcie", | ||
290 | }, | ||
291 | { }, | ||
292 | }; | ||
293 | MODULE_DEVICE_TABLE(of, ks_pcie_of_match); | ||
294 | |||
295 | static int __exit ks_pcie_remove(struct platform_device *pdev) | ||
296 | { | ||
297 | struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev); | ||
298 | |||
299 | clk_disable_unprepare(ks_pcie->clk); | ||
300 | |||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | static int __init ks_pcie_probe(struct platform_device *pdev) | ||
305 | { | ||
306 | struct device *dev = &pdev->dev; | ||
307 | struct keystone_pcie *ks_pcie; | ||
308 | struct pcie_port *pp; | ||
309 | struct resource *res; | ||
310 | void __iomem *reg_p; | ||
311 | struct phy *phy; | ||
312 | int ret = 0; | ||
313 | u32 val; | ||
314 | |||
315 | ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie), | ||
316 | GFP_KERNEL); | ||
317 | if (!ks_pcie) { | ||
318 | dev_err(dev, "no memory for keystone pcie\n"); | ||
319 | return -ENOMEM; | ||
320 | } | ||
321 | pp = &ks_pcie->pp; | ||
322 | |||
323 | /* index 2 is the devcfg register for RC mode settings */ | ||
324 | res = platform_get_resource(pdev, IORESOURCE_MEM, 2); | ||
325 | reg_p = devm_ioremap_resource(dev, res); | ||
326 | if (IS_ERR(reg_p)) | ||
327 | return PTR_ERR(reg_p); | ||
328 | |||
329 | /* enable RC mode in devcfg */ | ||
330 | val = readl(reg_p); | ||
331 | val &= ~PCIE_MODE_MASK; | ||
332 | val |= PCIE_RC_MODE; | ||
333 | writel(val, reg_p); | ||
334 | |||
335 | /* initialize SerDes Phy if present */ | ||
336 | phy = devm_phy_get(dev, "pcie-phy"); | ||
337 | if (!IS_ERR_OR_NULL(phy)) { | ||
338 | ret = phy_init(phy); | ||
339 | if (ret < 0) | ||
340 | return ret; | ||
341 | } | ||
342 | |||
343 | /* index 3 is to read PCI DEVICE_ID */ | ||
344 | res = platform_get_resource(pdev, IORESOURCE_MEM, 3); | ||
345 | reg_p = devm_ioremap_resource(dev, res); | ||
346 | if (IS_ERR(reg_p)) | ||
347 | return PTR_ERR(reg_p); | ||
348 | ks_pcie->va_reg_pciid = reg_p; | ||
349 | |||
350 | pp->dev = dev; | ||
351 | platform_set_drvdata(pdev, ks_pcie); | ||
352 | ks_pcie->clk = devm_clk_get(dev, "pcie"); | ||
353 | if (IS_ERR(ks_pcie->clk)) { | ||
354 | dev_err(dev, "Failed to get pcie rc clock\n"); | ||
355 | return PTR_ERR(ks_pcie->clk); | ||
356 | } | ||
357 | ret = clk_prepare_enable(ks_pcie->clk); | ||
358 | if (ret) | ||
359 | return ret; | ||
360 | |||
361 | ret = ks_add_pcie_port(ks_pcie, pdev); | ||
362 | if (ret < 0) | ||
363 | goto fail_clk; | ||
364 | |||
365 | return 0; | ||
366 | fail_clk: | ||
367 | clk_disable_unprepare(ks_pcie->clk); | ||
368 | |||
369 | return ret; | ||
370 | } | ||
371 | |||
372 | static struct platform_driver ks_pcie_driver __refdata = { | ||
373 | .probe = ks_pcie_probe, | ||
374 | .remove = __exit_p(ks_pcie_remove), | ||
375 | .driver = { | ||
376 | .name = "keystone-pcie", | ||
377 | .owner = THIS_MODULE, | ||
378 | .of_match_table = of_match_ptr(ks_pcie_of_match), | ||
379 | }, | ||
380 | }; | ||
381 | |||
382 | module_platform_driver(ks_pcie_driver); | ||
383 | |||
384 | MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>"); | ||
385 | MODULE_DESCRIPTION("Keystone PCIe host controller driver"); | ||
386 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pci/host/pci-keystone.h b/drivers/pci/host/pci-keystone.h new file mode 100644 index 000000000000..729ea7d3994b --- /dev/null +++ b/drivers/pci/host/pci-keystone.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * Keystone PCI Controller's common includes | ||
3 | * | ||
4 | * Copyright (C) 2013-2014 Texas Instruments., Ltd. | ||
5 | * http://www.ti.com | ||
6 | * | ||
7 | * Author: Murali Karicheri <m-karicheri2@ti.com> | ||
8 | * | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #define MAX_LEGACY_IRQS 4 | ||
16 | #define MAX_MSI_HOST_IRQS 8 | ||
17 | #define MAX_LEGACY_HOST_IRQS 4 | ||
18 | |||
19 | struct keystone_pcie { | ||
20 | struct clk *clk; | ||
21 | struct pcie_port pp; | ||
22 | void __iomem *va_reg_pciid; | ||
23 | |||
24 | int num_legacy_host_irqs; | ||
25 | int legacy_host_irqs[MAX_LEGACY_HOST_IRQS]; | ||
26 | struct device_node *legacy_intc_np; | ||
27 | |||
28 | int num_msi_host_irqs; | ||
29 | int msi_host_irqs[MAX_MSI_HOST_IRQS]; | ||
30 | struct device_node *msi_intc_np; | ||
31 | struct irq_domain *legacy_irq_domain; | ||
32 | |||
33 | /* Application register space */ | ||
34 | void __iomem *va_app_base; | ||
35 | struct resource app; | ||
36 | }; | ||
37 | |||
38 | /* Keystone DW specific MSI controller APIs/definitions */ | ||
39 | void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset); | ||
40 | u32 ks_dw_pcie_get_msi_data(struct pcie_port *pp); | ||
41 | |||
42 | /* Keystone specific PCI controller APIs */ | ||
43 | void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie); | ||
44 | void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset); | ||
45 | int ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie, | ||
46 | struct device_node *msi_intc_np); | ||
47 | int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, | ||
48 | unsigned int devfn, int where, int size, u32 val); | ||
49 | int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, | ||
50 | unsigned int devfn, int where, int size, u32 *val); | ||
51 | void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie); | ||
52 | int ks_dw_pcie_link_up(struct pcie_port *pp); | ||
53 | void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie); | ||
54 | void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq); | ||
55 | void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq); | ||
56 | void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp); | ||
57 | int ks_dw_pcie_msi_host_init(struct pcie_port *pp, | ||
58 | struct msi_chip *chip); | ||