diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-19 10:45:31 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-19 10:45:31 -0400 |
commit | f17a6f78595e52761b7b2dece8c11b04b65f19dd (patch) | |
tree | c83b5598d14050ae61a784277573b694f1fb4b67 /drivers/pci | |
parent | 7ac0bbf99d44c827c88aa7a9064050526e723ebb (diff) | |
parent | 981c191778a4f92bc82456205a444d522843a630 (diff) |
Merge tag 'pci-v3.17-changes-3' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI changes from Bjorn Helgaas:
"Marvell MVEBU
- Remove ARCH_KIRKWOOD dependency (Andrew Lunn)
NVIDIA Tegra
- Add debugfs support (Thierry Reding)
Synopsys DesignWare
- Look for configuration space in 'reg', not 'ranges' (Kishon Vijay Abraham I)
- Program ATU with untranslated address (Kishon Vijay Abraham I)
- Add config access-related pcie_host_ops for v3.65 hardware (Murali Karicheri)
- Add MSI-related pcie_host_ops for v3.65 hardware (Murali Karicheri)
TI DRA7xx
- Add TI DR7xx PCIe driver (Kishon Vijay Abraham I)"
* tag 'pci-v3.17-changes-3' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci:
PCI: designware: Add MSI-related pcie_host_ops for v3.65 hardware
PCI: designware: Add config access-related pcie_host_ops for v3.65 hardware
PCI: dra7xx: Add TI DRA7xx PCIe driver
PCI: designware: Program ATU with untranslated address
PCI: designware: Look for configuration space in 'reg', not 'ranges'
PCI: tegra: Add debugfs support
PCI: mvebu: Remove ARCH_KIRKWOOD dependency
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/host/Kconfig | 11 | ||||
-rw-r--r-- | drivers/pci/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/pci/host/pci-dra7xx.c | 458 | ||||
-rw-r--r-- | drivers/pci/host/pci-tegra.c | 118 | ||||
-rw-r--r-- | drivers/pci/host/pcie-designware.c | 134 | ||||
-rw-r--r-- | drivers/pci/host/pcie-designware.h | 11 |
6 files changed, 700 insertions, 33 deletions
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 2d8a4d05d78f..8922c376456a 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig | |||
@@ -1,9 +1,18 @@ | |||
1 | menu "PCI host controller drivers" | 1 | menu "PCI host controller drivers" |
2 | depends on PCI | 2 | depends on PCI |
3 | 3 | ||
4 | config PCI_DRA7XX | ||
5 | bool "TI DRA7xx PCIe controller" | ||
6 | select PCIE_DW | ||
7 | depends on OF && HAS_IOMEM && TI_PIPE3 | ||
8 | help | ||
9 | Enables support for the PCIe controller in the DRA7xx SoC. There | ||
10 | are two instances of PCIe controller in DRA7xx. This controller can | ||
11 | act both as EP and RC. This reuses the Designware core. | ||
12 | |||
4 | config PCI_MVEBU | 13 | config PCI_MVEBU |
5 | bool "Marvell EBU PCIe controller" | 14 | bool "Marvell EBU PCIe controller" |
6 | depends on ARCH_MVEBU || ARCH_DOVE || ARCH_KIRKWOOD | 15 | depends on ARCH_MVEBU || ARCH_DOVE |
7 | depends on OF | 16 | depends on OF |
8 | 17 | ||
9 | config PCIE_DW | 18 | config PCIE_DW |
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 0daec7941aba..d0e88f114ff9 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | obj-$(CONFIG_PCIE_DW) += pcie-designware.o | 1 | obj-$(CONFIG_PCIE_DW) += pcie-designware.o |
2 | obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o | ||
2 | obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o | 3 | obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o |
3 | obj-$(CONFIG_PCI_IMX6) += pci-imx6.o | 4 | obj-$(CONFIG_PCI_IMX6) += pci-imx6.o |
4 | obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o | 5 | obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o |
diff --git a/drivers/pci/host/pci-dra7xx.c b/drivers/pci/host/pci-dra7xx.c new file mode 100644 index 000000000000..52b34fee07fd --- /dev/null +++ b/drivers/pci/host/pci-dra7xx.c | |||
@@ -0,0 +1,458 @@ | |||
1 | /* | ||
2 | * pcie-dra7xx - PCIe controller driver for TI DRA7xx SoCs | ||
3 | * | ||
4 | * Copyright (C) 2013-2014 Texas Instruments Incorporated - http://www.ti.com | ||
5 | * | ||
6 | * Authors: Kishon Vijay Abraham I <kishon@ti.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/delay.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/irqdomain.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include <linux/phy/phy.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/pm_runtime.h> | ||
24 | #include <linux/resource.h> | ||
25 | #include <linux/types.h> | ||
26 | |||
27 | #include "pcie-designware.h" | ||
28 | |||
29 | /* PCIe controller wrapper DRA7XX configuration registers */ | ||
30 | |||
31 | #define PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN 0x0024 | ||
32 | #define PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MAIN 0x0028 | ||
33 | #define ERR_SYS BIT(0) | ||
34 | #define ERR_FATAL BIT(1) | ||
35 | #define ERR_NONFATAL BIT(2) | ||
36 | #define ERR_COR BIT(3) | ||
37 | #define ERR_AXI BIT(4) | ||
38 | #define ERR_ECRC BIT(5) | ||
39 | #define PME_TURN_OFF BIT(8) | ||
40 | #define PME_TO_ACK BIT(9) | ||
41 | #define PM_PME BIT(10) | ||
42 | #define LINK_REQ_RST BIT(11) | ||
43 | #define LINK_UP_EVT BIT(12) | ||
44 | #define CFG_BME_EVT BIT(13) | ||
45 | #define CFG_MSE_EVT BIT(14) | ||
46 | #define INTERRUPTS (ERR_SYS | ERR_FATAL | ERR_NONFATAL | ERR_COR | ERR_AXI | \ | ||
47 | ERR_ECRC | PME_TURN_OFF | PME_TO_ACK | PM_PME | \ | ||
48 | LINK_REQ_RST | LINK_UP_EVT | CFG_BME_EVT | CFG_MSE_EVT) | ||
49 | |||
50 | #define PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI 0x0034 | ||
51 | #define PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI 0x0038 | ||
52 | #define INTA BIT(0) | ||
53 | #define INTB BIT(1) | ||
54 | #define INTC BIT(2) | ||
55 | #define INTD BIT(3) | ||
56 | #define MSI BIT(4) | ||
57 | #define LEG_EP_INTERRUPTS (INTA | INTB | INTC | INTD) | ||
58 | |||
59 | #define PCIECTRL_DRA7XX_CONF_DEVICE_CMD 0x0104 | ||
60 | #define LTSSM_EN 0x1 | ||
61 | |||
62 | #define PCIECTRL_DRA7XX_CONF_PHY_CS 0x010C | ||
63 | #define LINK_UP BIT(16) | ||
64 | |||
65 | struct dra7xx_pcie { | ||
66 | void __iomem *base; | ||
67 | struct phy **phy; | ||
68 | int phy_count; | ||
69 | struct device *dev; | ||
70 | struct pcie_port pp; | ||
71 | }; | ||
72 | |||
73 | #define to_dra7xx_pcie(x) container_of((x), struct dra7xx_pcie, pp) | ||
74 | |||
75 | static inline u32 dra7xx_pcie_readl(struct dra7xx_pcie *pcie, u32 offset) | ||
76 | { | ||
77 | return readl(pcie->base + offset); | ||
78 | } | ||
79 | |||
80 | static inline void dra7xx_pcie_writel(struct dra7xx_pcie *pcie, u32 offset, | ||
81 | u32 value) | ||
82 | { | ||
83 | writel(value, pcie->base + offset); | ||
84 | } | ||
85 | |||
86 | static int dra7xx_pcie_link_up(struct pcie_port *pp) | ||
87 | { | ||
88 | struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); | ||
89 | u32 reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_PHY_CS); | ||
90 | |||
91 | return !!(reg & LINK_UP); | ||
92 | } | ||
93 | |||
94 | static int dra7xx_pcie_establish_link(struct pcie_port *pp) | ||
95 | { | ||
96 | u32 reg; | ||
97 | unsigned int retries = 1000; | ||
98 | struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); | ||
99 | |||
100 | if (dw_pcie_link_up(pp)) { | ||
101 | dev_err(pp->dev, "link is already up\n"); | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD); | ||
106 | reg |= LTSSM_EN; | ||
107 | dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); | ||
108 | |||
109 | while (retries--) { | ||
110 | reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_PHY_CS); | ||
111 | if (reg & LINK_UP) | ||
112 | break; | ||
113 | usleep_range(10, 20); | ||
114 | } | ||
115 | |||
116 | if (retries == 0) { | ||
117 | dev_err(pp->dev, "link is not up\n"); | ||
118 | return -ETIMEDOUT; | ||
119 | } | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static void dra7xx_pcie_enable_interrupts(struct pcie_port *pp) | ||
125 | { | ||
126 | struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); | ||
127 | |||
128 | dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN, | ||
129 | ~INTERRUPTS); | ||
130 | dra7xx_pcie_writel(dra7xx, | ||
131 | PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MAIN, INTERRUPTS); | ||
132 | dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI, | ||
133 | ~LEG_EP_INTERRUPTS & ~MSI); | ||
134 | |||
135 | if (IS_ENABLED(CONFIG_PCI_MSI)) | ||
136 | dra7xx_pcie_writel(dra7xx, | ||
137 | PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI, MSI); | ||
138 | else | ||
139 | dra7xx_pcie_writel(dra7xx, | ||
140 | PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI, | ||
141 | LEG_EP_INTERRUPTS); | ||
142 | } | ||
143 | |||
144 | static void dra7xx_pcie_host_init(struct pcie_port *pp) | ||
145 | { | ||
146 | dw_pcie_setup_rc(pp); | ||
147 | dra7xx_pcie_establish_link(pp); | ||
148 | if (IS_ENABLED(CONFIG_PCI_MSI)) | ||
149 | dw_pcie_msi_init(pp); | ||
150 | dra7xx_pcie_enable_interrupts(pp); | ||
151 | } | ||
152 | |||
153 | static struct pcie_host_ops dra7xx_pcie_host_ops = { | ||
154 | .link_up = dra7xx_pcie_link_up, | ||
155 | .host_init = dra7xx_pcie_host_init, | ||
156 | }; | ||
157 | |||
158 | static int dra7xx_pcie_intx_map(struct irq_domain *domain, unsigned int irq, | ||
159 | irq_hw_number_t hwirq) | ||
160 | { | ||
161 | irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq); | ||
162 | irq_set_chip_data(irq, domain->host_data); | ||
163 | set_irq_flags(irq, IRQF_VALID); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static const struct irq_domain_ops intx_domain_ops = { | ||
169 | .map = dra7xx_pcie_intx_map, | ||
170 | }; | ||
171 | |||
172 | static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp) | ||
173 | { | ||
174 | struct device *dev = pp->dev; | ||
175 | struct device_node *node = dev->of_node; | ||
176 | struct device_node *pcie_intc_node = of_get_next_child(node, NULL); | ||
177 | |||
178 | if (!pcie_intc_node) { | ||
179 | dev_err(dev, "No PCIe Intc node found\n"); | ||
180 | return PTR_ERR(pcie_intc_node); | ||
181 | } | ||
182 | |||
183 | pp->irq_domain = irq_domain_add_linear(pcie_intc_node, 4, | ||
184 | &intx_domain_ops, pp); | ||
185 | if (!pp->irq_domain) { | ||
186 | dev_err(dev, "Failed to get a INTx IRQ domain\n"); | ||
187 | return PTR_ERR(pp->irq_domain); | ||
188 | } | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static irqreturn_t dra7xx_pcie_msi_irq_handler(int irq, void *arg) | ||
194 | { | ||
195 | struct pcie_port *pp = arg; | ||
196 | struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); | ||
197 | u32 reg; | ||
198 | |||
199 | reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI); | ||
200 | |||
201 | switch (reg) { | ||
202 | case MSI: | ||
203 | dw_handle_msi_irq(pp); | ||
204 | break; | ||
205 | case INTA: | ||
206 | case INTB: | ||
207 | case INTC: | ||
208 | case INTD: | ||
209 | generic_handle_irq(irq_find_mapping(pp->irq_domain, ffs(reg))); | ||
210 | break; | ||
211 | } | ||
212 | |||
213 | dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI, reg); | ||
214 | |||
215 | return IRQ_HANDLED; | ||
216 | } | ||
217 | |||
218 | |||
219 | static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg) | ||
220 | { | ||
221 | struct dra7xx_pcie *dra7xx = arg; | ||
222 | u32 reg; | ||
223 | |||
224 | reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN); | ||
225 | |||
226 | if (reg & ERR_SYS) | ||
227 | dev_dbg(dra7xx->dev, "System Error\n"); | ||
228 | |||
229 | if (reg & ERR_FATAL) | ||
230 | dev_dbg(dra7xx->dev, "Fatal Error\n"); | ||
231 | |||
232 | if (reg & ERR_NONFATAL) | ||
233 | dev_dbg(dra7xx->dev, "Non Fatal Error\n"); | ||
234 | |||
235 | if (reg & ERR_COR) | ||
236 | dev_dbg(dra7xx->dev, "Correctable Error\n"); | ||
237 | |||
238 | if (reg & ERR_AXI) | ||
239 | dev_dbg(dra7xx->dev, "AXI tag lookup fatal Error\n"); | ||
240 | |||
241 | if (reg & ERR_ECRC) | ||
242 | dev_dbg(dra7xx->dev, "ECRC Error\n"); | ||
243 | |||
244 | if (reg & PME_TURN_OFF) | ||
245 | dev_dbg(dra7xx->dev, | ||
246 | "Power Management Event Turn-Off message received\n"); | ||
247 | |||
248 | if (reg & PME_TO_ACK) | ||
249 | dev_dbg(dra7xx->dev, | ||
250 | "Power Management Turn-Off Ack message received\n"); | ||
251 | |||
252 | if (reg & PM_PME) | ||
253 | dev_dbg(dra7xx->dev, | ||
254 | "PM Power Management Event message received\n"); | ||
255 | |||
256 | if (reg & LINK_REQ_RST) | ||
257 | dev_dbg(dra7xx->dev, "Link Request Reset\n"); | ||
258 | |||
259 | if (reg & LINK_UP_EVT) | ||
260 | dev_dbg(dra7xx->dev, "Link-up state change\n"); | ||
261 | |||
262 | if (reg & CFG_BME_EVT) | ||
263 | dev_dbg(dra7xx->dev, "CFG 'Bus Master Enable' change\n"); | ||
264 | |||
265 | if (reg & CFG_MSE_EVT) | ||
266 | dev_dbg(dra7xx->dev, "CFG 'Memory Space Enable' change\n"); | ||
267 | |||
268 | dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN, reg); | ||
269 | |||
270 | return IRQ_HANDLED; | ||
271 | } | ||
272 | |||
273 | static int add_pcie_port(struct dra7xx_pcie *dra7xx, | ||
274 | struct platform_device *pdev) | ||
275 | { | ||
276 | int ret; | ||
277 | struct pcie_port *pp; | ||
278 | struct resource *res; | ||
279 | struct device *dev = &pdev->dev; | ||
280 | |||
281 | pp = &dra7xx->pp; | ||
282 | pp->dev = dev; | ||
283 | pp->ops = &dra7xx_pcie_host_ops; | ||
284 | |||
285 | pp->irq = platform_get_irq(pdev, 1); | ||
286 | if (pp->irq < 0) { | ||
287 | dev_err(dev, "missing IRQ resource\n"); | ||
288 | return -EINVAL; | ||
289 | } | ||
290 | |||
291 | ret = devm_request_irq(&pdev->dev, pp->irq, | ||
292 | dra7xx_pcie_msi_irq_handler, IRQF_SHARED, | ||
293 | "dra7-pcie-msi", pp); | ||
294 | if (ret) { | ||
295 | dev_err(&pdev->dev, "failed to request irq\n"); | ||
296 | return ret; | ||
297 | } | ||
298 | |||
299 | if (!IS_ENABLED(CONFIG_PCI_MSI)) { | ||
300 | ret = dra7xx_pcie_init_irq_domain(pp); | ||
301 | if (ret < 0) | ||
302 | return ret; | ||
303 | } | ||
304 | |||
305 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rc_dbics"); | ||
306 | pp->dbi_base = devm_ioremap(dev, res->start, resource_size(res)); | ||
307 | if (!pp->dbi_base) | ||
308 | return -ENOMEM; | ||
309 | |||
310 | ret = dw_pcie_host_init(pp); | ||
311 | if (ret) { | ||
312 | dev_err(dra7xx->dev, "failed to initialize host\n"); | ||
313 | return ret; | ||
314 | } | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static int __init dra7xx_pcie_probe(struct platform_device *pdev) | ||
320 | { | ||
321 | u32 reg; | ||
322 | int ret; | ||
323 | int irq; | ||
324 | int i; | ||
325 | int phy_count; | ||
326 | struct phy **phy; | ||
327 | void __iomem *base; | ||
328 | struct resource *res; | ||
329 | struct dra7xx_pcie *dra7xx; | ||
330 | struct device *dev = &pdev->dev; | ||
331 | struct device_node *np = dev->of_node; | ||
332 | char name[10]; | ||
333 | |||
334 | dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL); | ||
335 | if (!dra7xx) | ||
336 | return -ENOMEM; | ||
337 | |||
338 | irq = platform_get_irq(pdev, 0); | ||
339 | if (irq < 0) { | ||
340 | dev_err(dev, "missing IRQ resource\n"); | ||
341 | return -EINVAL; | ||
342 | } | ||
343 | |||
344 | ret = devm_request_irq(dev, irq, dra7xx_pcie_irq_handler, | ||
345 | IRQF_SHARED, "dra7xx-pcie-main", dra7xx); | ||
346 | if (ret) { | ||
347 | dev_err(dev, "failed to request irq\n"); | ||
348 | return ret; | ||
349 | } | ||
350 | |||
351 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ti_conf"); | ||
352 | base = devm_ioremap_nocache(dev, res->start, resource_size(res)); | ||
353 | if (!base) | ||
354 | return -ENOMEM; | ||
355 | |||
356 | phy_count = of_property_count_strings(np, "phy-names"); | ||
357 | if (phy_count < 0) { | ||
358 | dev_err(dev, "unable to find the strings\n"); | ||
359 | return phy_count; | ||
360 | } | ||
361 | |||
362 | phy = devm_kzalloc(dev, sizeof(*phy) * phy_count, GFP_KERNEL); | ||
363 | if (!phy) | ||
364 | return -ENOMEM; | ||
365 | |||
366 | for (i = 0; i < phy_count; i++) { | ||
367 | snprintf(name, sizeof(name), "pcie-phy%d", i); | ||
368 | phy[i] = devm_phy_get(dev, name); | ||
369 | if (IS_ERR(phy[i])) | ||
370 | return PTR_ERR(phy[i]); | ||
371 | |||
372 | ret = phy_init(phy[i]); | ||
373 | if (ret < 0) | ||
374 | goto err_phy; | ||
375 | |||
376 | ret = phy_power_on(phy[i]); | ||
377 | if (ret < 0) { | ||
378 | phy_exit(phy[i]); | ||
379 | goto err_phy; | ||
380 | } | ||
381 | } | ||
382 | |||
383 | dra7xx->base = base; | ||
384 | dra7xx->phy = phy; | ||
385 | dra7xx->dev = dev; | ||
386 | dra7xx->phy_count = phy_count; | ||
387 | |||
388 | pm_runtime_enable(dev); | ||
389 | ret = pm_runtime_get_sync(dev); | ||
390 | if (IS_ERR_VALUE(ret)) { | ||
391 | dev_err(dev, "pm_runtime_get_sync failed\n"); | ||
392 | goto err_phy; | ||
393 | } | ||
394 | |||
395 | reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD); | ||
396 | reg &= ~LTSSM_EN; | ||
397 | dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); | ||
398 | |||
399 | platform_set_drvdata(pdev, dra7xx); | ||
400 | |||
401 | ret = add_pcie_port(dra7xx, pdev); | ||
402 | if (ret < 0) | ||
403 | goto err_add_port; | ||
404 | |||
405 | return 0; | ||
406 | |||
407 | err_add_port: | ||
408 | pm_runtime_put(dev); | ||
409 | pm_runtime_disable(dev); | ||
410 | |||
411 | err_phy: | ||
412 | while (--i >= 0) { | ||
413 | phy_power_off(phy[i]); | ||
414 | phy_exit(phy[i]); | ||
415 | } | ||
416 | |||
417 | return ret; | ||
418 | } | ||
419 | |||
420 | static int __exit dra7xx_pcie_remove(struct platform_device *pdev) | ||
421 | { | ||
422 | struct dra7xx_pcie *dra7xx = platform_get_drvdata(pdev); | ||
423 | struct pcie_port *pp = &dra7xx->pp; | ||
424 | struct device *dev = &pdev->dev; | ||
425 | int count = dra7xx->phy_count; | ||
426 | |||
427 | if (pp->irq_domain) | ||
428 | irq_domain_remove(pp->irq_domain); | ||
429 | pm_runtime_put(dev); | ||
430 | pm_runtime_disable(dev); | ||
431 | while (count--) { | ||
432 | phy_power_off(dra7xx->phy[count]); | ||
433 | phy_exit(dra7xx->phy[count]); | ||
434 | } | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static const struct of_device_id of_dra7xx_pcie_match[] = { | ||
440 | { .compatible = "ti,dra7-pcie", }, | ||
441 | {}, | ||
442 | }; | ||
443 | MODULE_DEVICE_TABLE(of, of_dra7xx_pcie_match); | ||
444 | |||
445 | static struct platform_driver dra7xx_pcie_driver = { | ||
446 | .remove = __exit_p(dra7xx_pcie_remove), | ||
447 | .driver = { | ||
448 | .name = "dra7-pcie", | ||
449 | .owner = THIS_MODULE, | ||
450 | .of_match_table = of_dra7xx_pcie_match, | ||
451 | }, | ||
452 | }; | ||
453 | |||
454 | module_platform_driver_probe(dra7xx_pcie_driver, dra7xx_pcie_probe); | ||
455 | |||
456 | MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); | ||
457 | MODULE_DESCRIPTION("TI PCIe controller driver"); | ||
458 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index abd65784618d..0fb0fdb223d5 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c | |||
@@ -25,6 +25,7 @@ | |||
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <linux/clk.h> | 27 | #include <linux/clk.h> |
28 | #include <linux/debugfs.h> | ||
28 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
29 | #include <linux/export.h> | 30 | #include <linux/export.h> |
30 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
@@ -276,6 +277,7 @@ struct tegra_pcie { | |||
276 | unsigned int num_supplies; | 277 | unsigned int num_supplies; |
277 | 278 | ||
278 | const struct tegra_pcie_soc_data *soc_data; | 279 | const struct tegra_pcie_soc_data *soc_data; |
280 | struct dentry *debugfs; | ||
279 | }; | 281 | }; |
280 | 282 | ||
281 | struct tegra_pcie_port { | 283 | struct tegra_pcie_port { |
@@ -1739,6 +1741,115 @@ static const struct of_device_id tegra_pcie_of_match[] = { | |||
1739 | }; | 1741 | }; |
1740 | MODULE_DEVICE_TABLE(of, tegra_pcie_of_match); | 1742 | MODULE_DEVICE_TABLE(of, tegra_pcie_of_match); |
1741 | 1743 | ||
1744 | static void *tegra_pcie_ports_seq_start(struct seq_file *s, loff_t *pos) | ||
1745 | { | ||
1746 | struct tegra_pcie *pcie = s->private; | ||
1747 | |||
1748 | if (list_empty(&pcie->ports)) | ||
1749 | return NULL; | ||
1750 | |||
1751 | seq_printf(s, "Index Status\n"); | ||
1752 | |||
1753 | return seq_list_start(&pcie->ports, *pos); | ||
1754 | } | ||
1755 | |||
1756 | static void *tegra_pcie_ports_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
1757 | { | ||
1758 | struct tegra_pcie *pcie = s->private; | ||
1759 | |||
1760 | return seq_list_next(v, &pcie->ports, pos); | ||
1761 | } | ||
1762 | |||
1763 | static void tegra_pcie_ports_seq_stop(struct seq_file *s, void *v) | ||
1764 | { | ||
1765 | } | ||
1766 | |||
1767 | static int tegra_pcie_ports_seq_show(struct seq_file *s, void *v) | ||
1768 | { | ||
1769 | bool up = false, active = false; | ||
1770 | struct tegra_pcie_port *port; | ||
1771 | unsigned int value; | ||
1772 | |||
1773 | port = list_entry(v, struct tegra_pcie_port, list); | ||
1774 | |||
1775 | value = readl(port->base + RP_VEND_XP); | ||
1776 | |||
1777 | if (value & RP_VEND_XP_DL_UP) | ||
1778 | up = true; | ||
1779 | |||
1780 | value = readl(port->base + RP_LINK_CONTROL_STATUS); | ||
1781 | |||
1782 | if (value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE) | ||
1783 | active = true; | ||
1784 | |||
1785 | seq_printf(s, "%2u ", port->index); | ||
1786 | |||
1787 | if (up) | ||
1788 | seq_printf(s, "up"); | ||
1789 | |||
1790 | if (active) { | ||
1791 | if (up) | ||
1792 | seq_printf(s, ", "); | ||
1793 | |||
1794 | seq_printf(s, "active"); | ||
1795 | } | ||
1796 | |||
1797 | seq_printf(s, "\n"); | ||
1798 | return 0; | ||
1799 | } | ||
1800 | |||
1801 | static const struct seq_operations tegra_pcie_ports_seq_ops = { | ||
1802 | .start = tegra_pcie_ports_seq_start, | ||
1803 | .next = tegra_pcie_ports_seq_next, | ||
1804 | .stop = tegra_pcie_ports_seq_stop, | ||
1805 | .show = tegra_pcie_ports_seq_show, | ||
1806 | }; | ||
1807 | |||
1808 | static int tegra_pcie_ports_open(struct inode *inode, struct file *file) | ||
1809 | { | ||
1810 | struct tegra_pcie *pcie = inode->i_private; | ||
1811 | struct seq_file *s; | ||
1812 | int err; | ||
1813 | |||
1814 | err = seq_open(file, &tegra_pcie_ports_seq_ops); | ||
1815 | if (err) | ||
1816 | return err; | ||
1817 | |||
1818 | s = file->private_data; | ||
1819 | s->private = pcie; | ||
1820 | |||
1821 | return 0; | ||
1822 | } | ||
1823 | |||
1824 | static const struct file_operations tegra_pcie_ports_ops = { | ||
1825 | .owner = THIS_MODULE, | ||
1826 | .open = tegra_pcie_ports_open, | ||
1827 | .read = seq_read, | ||
1828 | .llseek = seq_lseek, | ||
1829 | .release = seq_release, | ||
1830 | }; | ||
1831 | |||
1832 | static int tegra_pcie_debugfs_init(struct tegra_pcie *pcie) | ||
1833 | { | ||
1834 | struct dentry *file; | ||
1835 | |||
1836 | pcie->debugfs = debugfs_create_dir("pcie", NULL); | ||
1837 | if (!pcie->debugfs) | ||
1838 | return -ENOMEM; | ||
1839 | |||
1840 | file = debugfs_create_file("ports", S_IFREG | S_IRUGO, pcie->debugfs, | ||
1841 | pcie, &tegra_pcie_ports_ops); | ||
1842 | if (!file) | ||
1843 | goto remove; | ||
1844 | |||
1845 | return 0; | ||
1846 | |||
1847 | remove: | ||
1848 | debugfs_remove_recursive(pcie->debugfs); | ||
1849 | pcie->debugfs = NULL; | ||
1850 | return -ENOMEM; | ||
1851 | } | ||
1852 | |||
1742 | static int tegra_pcie_probe(struct platform_device *pdev) | 1853 | static int tegra_pcie_probe(struct platform_device *pdev) |
1743 | { | 1854 | { |
1744 | const struct of_device_id *match; | 1855 | const struct of_device_id *match; |
@@ -1793,6 +1904,13 @@ static int tegra_pcie_probe(struct platform_device *pdev) | |||
1793 | goto disable_msi; | 1904 | goto disable_msi; |
1794 | } | 1905 | } |
1795 | 1906 | ||
1907 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | ||
1908 | err = tegra_pcie_debugfs_init(pcie); | ||
1909 | if (err < 0) | ||
1910 | dev_err(&pdev->dev, "failed to setup debugfs: %d\n", | ||
1911 | err); | ||
1912 | } | ||
1913 | |||
1796 | platform_set_drvdata(pdev, pcie); | 1914 | platform_set_drvdata(pdev, pcie); |
1797 | return 0; | 1915 | return 0; |
1798 | 1916 | ||
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 1eaf4df3618a..52bd3a143563 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/of_pci.h> | 20 | #include <linux/of_pci.h> |
21 | #include <linux/pci.h> | 21 | #include <linux/pci.h> |
22 | #include <linux/pci_regs.h> | 22 | #include <linux/pci_regs.h> |
23 | #include <linux/platform_device.h> | ||
23 | #include <linux/types.h> | 24 | #include <linux/types.h> |
24 | 25 | ||
25 | #include "pcie-designware.h" | 26 | #include "pcie-designware.h" |
@@ -217,27 +218,47 @@ static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0) | |||
217 | return 0; | 218 | return 0; |
218 | } | 219 | } |
219 | 220 | ||
221 | static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) | ||
222 | { | ||
223 | unsigned int res, bit, val; | ||
224 | |||
225 | res = (irq / 32) * 12; | ||
226 | bit = irq % 32; | ||
227 | dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val); | ||
228 | val &= ~(1 << bit); | ||
229 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); | ||
230 | } | ||
231 | |||
220 | static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base, | 232 | static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base, |
221 | unsigned int nvec, unsigned int pos) | 233 | unsigned int nvec, unsigned int pos) |
222 | { | 234 | { |
223 | unsigned int i, res, bit, val; | 235 | unsigned int i; |
224 | 236 | ||
225 | for (i = 0; i < nvec; i++) { | 237 | for (i = 0; i < nvec; i++) { |
226 | irq_set_msi_desc_off(irq_base, i, NULL); | 238 | irq_set_msi_desc_off(irq_base, i, NULL); |
227 | clear_bit(pos + i, pp->msi_irq_in_use); | 239 | clear_bit(pos + i, pp->msi_irq_in_use); |
228 | /* Disable corresponding interrupt on MSI controller */ | 240 | /* Disable corresponding interrupt on MSI controller */ |
229 | res = ((pos + i) / 32) * 12; | 241 | if (pp->ops->msi_clear_irq) |
230 | bit = (pos + i) % 32; | 242 | pp->ops->msi_clear_irq(pp, pos + i); |
231 | dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val); | 243 | else |
232 | val &= ~(1 << bit); | 244 | dw_pcie_msi_clear_irq(pp, pos + i); |
233 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); | ||
234 | } | 245 | } |
235 | } | 246 | } |
236 | 247 | ||
248 | static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) | ||
249 | { | ||
250 | unsigned int res, bit, val; | ||
251 | |||
252 | res = (irq / 32) * 12; | ||
253 | bit = irq % 32; | ||
254 | dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val); | ||
255 | val |= 1 << bit; | ||
256 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); | ||
257 | } | ||
258 | |||
237 | static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) | 259 | static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) |
238 | { | 260 | { |
239 | int res, bit, irq, pos0, pos1, i; | 261 | int irq, pos0, pos1, i; |
240 | u32 val; | ||
241 | struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata); | 262 | struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata); |
242 | 263 | ||
243 | if (!pp) { | 264 | if (!pp) { |
@@ -281,11 +302,10 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) | |||
281 | } | 302 | } |
282 | set_bit(pos0 + i, pp->msi_irq_in_use); | 303 | set_bit(pos0 + i, pp->msi_irq_in_use); |
283 | /*Enable corresponding interrupt in MSI interrupt controller */ | 304 | /*Enable corresponding interrupt in MSI interrupt controller */ |
284 | res = ((pos0 + i) / 32) * 12; | 305 | if (pp->ops->msi_set_irq) |
285 | bit = (pos0 + i) % 32; | 306 | pp->ops->msi_set_irq(pp, pos0 + i); |
286 | dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val); | 307 | else |
287 | val |= 1 << bit; | 308 | dw_pcie_msi_set_irq(pp, pos0 + i); |
288 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); | ||
289 | } | 309 | } |
290 | 310 | ||
291 | *pos = pos0; | 311 | *pos = pos0; |
@@ -353,7 +373,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, | |||
353 | */ | 373 | */ |
354 | desc->msi_attrib.multiple = msgvec; | 374 | desc->msi_attrib.multiple = msgvec; |
355 | 375 | ||
356 | msg.address_lo = virt_to_phys((void *)pp->msi_data); | 376 | if (pp->ops->get_msi_data) |
377 | msg.address_lo = pp->ops->get_msi_data(pp); | ||
378 | else | ||
379 | msg.address_lo = virt_to_phys((void *)pp->msi_data); | ||
357 | msg.address_hi = 0x0; | 380 | msg.address_hi = 0x0; |
358 | msg.data = pos; | 381 | msg.data = pos; |
359 | write_msi_msg(irq, &msg); | 382 | write_msi_msg(irq, &msg); |
@@ -396,10 +419,35 @@ static const struct irq_domain_ops msi_domain_ops = { | |||
396 | int __init dw_pcie_host_init(struct pcie_port *pp) | 419 | int __init dw_pcie_host_init(struct pcie_port *pp) |
397 | { | 420 | { |
398 | struct device_node *np = pp->dev->of_node; | 421 | struct device_node *np = pp->dev->of_node; |
422 | struct platform_device *pdev = to_platform_device(pp->dev); | ||
399 | struct of_pci_range range; | 423 | struct of_pci_range range; |
400 | struct of_pci_range_parser parser; | 424 | struct of_pci_range_parser parser; |
401 | u32 val; | 425 | struct resource *cfg_res; |
402 | int i; | 426 | u32 val, na, ns; |
427 | const __be32 *addrp; | ||
428 | int i, index; | ||
429 | |||
430 | /* Find the address cell size and the number of cells in order to get | ||
431 | * the untranslated address. | ||
432 | */ | ||
433 | of_property_read_u32(np, "#address-cells", &na); | ||
434 | ns = of_n_size_cells(np); | ||
435 | |||
436 | cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); | ||
437 | if (cfg_res) { | ||
438 | pp->config.cfg0_size = resource_size(cfg_res)/2; | ||
439 | pp->config.cfg1_size = resource_size(cfg_res)/2; | ||
440 | pp->cfg0_base = cfg_res->start; | ||
441 | pp->cfg1_base = cfg_res->start + pp->config.cfg0_size; | ||
442 | |||
443 | /* Find the untranslated configuration space address */ | ||
444 | index = of_property_match_string(np, "reg-names", "config"); | ||
445 | addrp = of_get_address(np, index, false, false); | ||
446 | pp->cfg0_mod_base = of_read_number(addrp, ns); | ||
447 | pp->cfg1_mod_base = pp->cfg0_mod_base + pp->config.cfg0_size; | ||
448 | } else { | ||
449 | dev_err(pp->dev, "missing *config* reg space\n"); | ||
450 | } | ||
403 | 451 | ||
404 | if (of_pci_range_parser_init(&parser, np)) { | 452 | if (of_pci_range_parser_init(&parser, np)) { |
405 | dev_err(pp->dev, "missing ranges property\n"); | 453 | dev_err(pp->dev, "missing ranges property\n"); |
@@ -422,17 +470,33 @@ int __init dw_pcie_host_init(struct pcie_port *pp) | |||
422 | pp->config.io_size = resource_size(&pp->io); | 470 | pp->config.io_size = resource_size(&pp->io); |
423 | pp->config.io_bus_addr = range.pci_addr; | 471 | pp->config.io_bus_addr = range.pci_addr; |
424 | pp->io_base = range.cpu_addr; | 472 | pp->io_base = range.cpu_addr; |
473 | |||
474 | /* Find the untranslated IO space address */ | ||
475 | pp->io_mod_base = of_read_number(parser.range - | ||
476 | parser.np + na, ns); | ||
425 | } | 477 | } |
426 | if (restype == IORESOURCE_MEM) { | 478 | if (restype == IORESOURCE_MEM) { |
427 | of_pci_range_to_resource(&range, np, &pp->mem); | 479 | of_pci_range_to_resource(&range, np, &pp->mem); |
428 | pp->mem.name = "MEM"; | 480 | pp->mem.name = "MEM"; |
429 | pp->config.mem_size = resource_size(&pp->mem); | 481 | pp->config.mem_size = resource_size(&pp->mem); |
430 | pp->config.mem_bus_addr = range.pci_addr; | 482 | pp->config.mem_bus_addr = range.pci_addr; |
483 | |||
484 | /* Find the untranslated MEM space address */ | ||
485 | pp->mem_mod_base = of_read_number(parser.range - | ||
486 | parser.np + na, ns); | ||
431 | } | 487 | } |
432 | if (restype == 0) { | 488 | if (restype == 0) { |
433 | of_pci_range_to_resource(&range, np, &pp->cfg); | 489 | of_pci_range_to_resource(&range, np, &pp->cfg); |
434 | pp->config.cfg0_size = resource_size(&pp->cfg)/2; | 490 | pp->config.cfg0_size = resource_size(&pp->cfg)/2; |
435 | pp->config.cfg1_size = resource_size(&pp->cfg)/2; | 491 | pp->config.cfg1_size = resource_size(&pp->cfg)/2; |
492 | pp->cfg0_base = pp->cfg.start; | ||
493 | pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size; | ||
494 | |||
495 | /* Find the untranslated configuration space address */ | ||
496 | pp->cfg0_mod_base = of_read_number(parser.range - | ||
497 | parser.np + na, ns); | ||
498 | pp->cfg1_mod_base = pp->cfg0_mod_base + | ||
499 | pp->config.cfg0_size; | ||
436 | } | 500 | } |
437 | } | 501 | } |
438 | 502 | ||
@@ -445,8 +509,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp) | |||
445 | } | 509 | } |
446 | } | 510 | } |
447 | 511 | ||
448 | pp->cfg0_base = pp->cfg.start; | ||
449 | pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size; | ||
450 | pp->mem_base = pp->mem.start; | 512 | pp->mem_base = pp->mem.start; |
451 | 513 | ||
452 | pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base, | 514 | pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base, |
@@ -509,9 +571,9 @@ static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev) | |||
509 | /* Program viewport 0 : OUTBOUND : CFG0 */ | 571 | /* Program viewport 0 : OUTBOUND : CFG0 */ |
510 | dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0, | 572 | dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0, |
511 | PCIE_ATU_VIEWPORT); | 573 | PCIE_ATU_VIEWPORT); |
512 | dw_pcie_writel_rc(pp, pp->cfg0_base, PCIE_ATU_LOWER_BASE); | 574 | dw_pcie_writel_rc(pp, pp->cfg0_mod_base, PCIE_ATU_LOWER_BASE); |
513 | dw_pcie_writel_rc(pp, (pp->cfg0_base >> 32), PCIE_ATU_UPPER_BASE); | 575 | dw_pcie_writel_rc(pp, (pp->cfg0_mod_base >> 32), PCIE_ATU_UPPER_BASE); |
514 | dw_pcie_writel_rc(pp, pp->cfg0_base + pp->config.cfg0_size - 1, | 576 | dw_pcie_writel_rc(pp, pp->cfg0_mod_base + pp->config.cfg0_size - 1, |
515 | PCIE_ATU_LIMIT); | 577 | PCIE_ATU_LIMIT); |
516 | dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET); | 578 | dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET); |
517 | dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET); | 579 | dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET); |
@@ -525,9 +587,9 @@ static void dw_pcie_prog_viewport_cfg1(struct pcie_port *pp, u32 busdev) | |||
525 | dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1, | 587 | dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1, |
526 | PCIE_ATU_VIEWPORT); | 588 | PCIE_ATU_VIEWPORT); |
527 | dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG1, PCIE_ATU_CR1); | 589 | dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG1, PCIE_ATU_CR1); |
528 | dw_pcie_writel_rc(pp, pp->cfg1_base, PCIE_ATU_LOWER_BASE); | 590 | dw_pcie_writel_rc(pp, pp->cfg1_mod_base, PCIE_ATU_LOWER_BASE); |
529 | dw_pcie_writel_rc(pp, (pp->cfg1_base >> 32), PCIE_ATU_UPPER_BASE); | 591 | dw_pcie_writel_rc(pp, (pp->cfg1_mod_base >> 32), PCIE_ATU_UPPER_BASE); |
530 | dw_pcie_writel_rc(pp, pp->cfg1_base + pp->config.cfg1_size - 1, | 592 | dw_pcie_writel_rc(pp, pp->cfg1_mod_base + pp->config.cfg1_size - 1, |
531 | PCIE_ATU_LIMIT); | 593 | PCIE_ATU_LIMIT); |
532 | dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET); | 594 | dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET); |
533 | dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET); | 595 | dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET); |
@@ -540,9 +602,9 @@ static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp) | |||
540 | dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0, | 602 | dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0, |
541 | PCIE_ATU_VIEWPORT); | 603 | PCIE_ATU_VIEWPORT); |
542 | dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_MEM, PCIE_ATU_CR1); | 604 | dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_MEM, PCIE_ATU_CR1); |
543 | dw_pcie_writel_rc(pp, pp->mem_base, PCIE_ATU_LOWER_BASE); | 605 | dw_pcie_writel_rc(pp, pp->mem_mod_base, PCIE_ATU_LOWER_BASE); |
544 | dw_pcie_writel_rc(pp, (pp->mem_base >> 32), PCIE_ATU_UPPER_BASE); | 606 | dw_pcie_writel_rc(pp, (pp->mem_mod_base >> 32), PCIE_ATU_UPPER_BASE); |
545 | dw_pcie_writel_rc(pp, pp->mem_base + pp->config.mem_size - 1, | 607 | dw_pcie_writel_rc(pp, pp->mem_mod_base + pp->config.mem_size - 1, |
546 | PCIE_ATU_LIMIT); | 608 | PCIE_ATU_LIMIT); |
547 | dw_pcie_writel_rc(pp, pp->config.mem_bus_addr, PCIE_ATU_LOWER_TARGET); | 609 | dw_pcie_writel_rc(pp, pp->config.mem_bus_addr, PCIE_ATU_LOWER_TARGET); |
548 | dw_pcie_writel_rc(pp, upper_32_bits(pp->config.mem_bus_addr), | 610 | dw_pcie_writel_rc(pp, upper_32_bits(pp->config.mem_bus_addr), |
@@ -556,9 +618,9 @@ static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp) | |||
556 | dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1, | 618 | dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1, |
557 | PCIE_ATU_VIEWPORT); | 619 | PCIE_ATU_VIEWPORT); |
558 | dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_IO, PCIE_ATU_CR1); | 620 | dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_IO, PCIE_ATU_CR1); |
559 | dw_pcie_writel_rc(pp, pp->io_base, PCIE_ATU_LOWER_BASE); | 621 | dw_pcie_writel_rc(pp, pp->io_mod_base, PCIE_ATU_LOWER_BASE); |
560 | dw_pcie_writel_rc(pp, (pp->io_base >> 32), PCIE_ATU_UPPER_BASE); | 622 | dw_pcie_writel_rc(pp, (pp->io_mod_base >> 32), PCIE_ATU_UPPER_BASE); |
561 | dw_pcie_writel_rc(pp, pp->io_base + pp->config.io_size - 1, | 623 | dw_pcie_writel_rc(pp, pp->io_mod_base + pp->config.io_size - 1, |
562 | PCIE_ATU_LIMIT); | 624 | PCIE_ATU_LIMIT); |
563 | dw_pcie_writel_rc(pp, pp->config.io_bus_addr, PCIE_ATU_LOWER_TARGET); | 625 | dw_pcie_writel_rc(pp, pp->config.io_bus_addr, PCIE_ATU_LOWER_TARGET); |
564 | dw_pcie_writel_rc(pp, upper_32_bits(pp->config.io_bus_addr), | 626 | dw_pcie_writel_rc(pp, upper_32_bits(pp->config.io_bus_addr), |
@@ -656,7 +718,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, | |||
656 | } | 718 | } |
657 | 719 | ||
658 | if (bus->number != pp->root_bus_nr) | 720 | if (bus->number != pp->root_bus_nr) |
659 | ret = dw_pcie_rd_other_conf(pp, bus, devfn, | 721 | if (pp->ops->rd_other_conf) |
722 | ret = pp->ops->rd_other_conf(pp, bus, devfn, | ||
723 | where, size, val); | ||
724 | else | ||
725 | ret = dw_pcie_rd_other_conf(pp, bus, devfn, | ||
660 | where, size, val); | 726 | where, size, val); |
661 | else | 727 | else |
662 | ret = dw_pcie_rd_own_conf(pp, where, size, val); | 728 | ret = dw_pcie_rd_own_conf(pp, where, size, val); |
@@ -679,7 +745,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn, | |||
679 | return PCIBIOS_DEVICE_NOT_FOUND; | 745 | return PCIBIOS_DEVICE_NOT_FOUND; |
680 | 746 | ||
681 | if (bus->number != pp->root_bus_nr) | 747 | if (bus->number != pp->root_bus_nr) |
682 | ret = dw_pcie_wr_other_conf(pp, bus, devfn, | 748 | if (pp->ops->wr_other_conf) |
749 | ret = pp->ops->wr_other_conf(pp, bus, devfn, | ||
750 | where, size, val); | ||
751 | else | ||
752 | ret = dw_pcie_wr_other_conf(pp, bus, devfn, | ||
683 | where, size, val); | 753 | where, size, val); |
684 | else | 754 | else |
685 | ret = dw_pcie_wr_own_conf(pp, where, size, val); | 755 | ret = dw_pcie_wr_own_conf(pp, where, size, val); |
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h index 77f592faa7bf..daf81f922cda 100644 --- a/drivers/pci/host/pcie-designware.h +++ b/drivers/pci/host/pcie-designware.h | |||
@@ -36,11 +36,15 @@ struct pcie_port { | |||
36 | u8 root_bus_nr; | 36 | u8 root_bus_nr; |
37 | void __iomem *dbi_base; | 37 | void __iomem *dbi_base; |
38 | u64 cfg0_base; | 38 | u64 cfg0_base; |
39 | u64 cfg0_mod_base; | ||
39 | void __iomem *va_cfg0_base; | 40 | void __iomem *va_cfg0_base; |
40 | u64 cfg1_base; | 41 | u64 cfg1_base; |
42 | u64 cfg1_mod_base; | ||
41 | void __iomem *va_cfg1_base; | 43 | void __iomem *va_cfg1_base; |
42 | u64 io_base; | 44 | u64 io_base; |
45 | u64 io_mod_base; | ||
43 | u64 mem_base; | 46 | u64 mem_base; |
47 | u64 mem_mod_base; | ||
44 | struct resource cfg; | 48 | struct resource cfg; |
45 | struct resource io; | 49 | struct resource io; |
46 | struct resource mem; | 50 | struct resource mem; |
@@ -61,8 +65,15 @@ struct pcie_host_ops { | |||
61 | u32 val, void __iomem *dbi_base); | 65 | u32 val, void __iomem *dbi_base); |
62 | int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val); | 66 | int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val); |
63 | int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val); | 67 | int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val); |
68 | int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus, | ||
69 | unsigned int devfn, int where, int size, u32 *val); | ||
70 | int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus, | ||
71 | unsigned int devfn, int where, int size, u32 val); | ||
64 | int (*link_up)(struct pcie_port *pp); | 72 | int (*link_up)(struct pcie_port *pp); |
65 | void (*host_init)(struct pcie_port *pp); | 73 | void (*host_init)(struct pcie_port *pp); |
74 | void (*msi_set_irq)(struct pcie_port *pp, int irq); | ||
75 | void (*msi_clear_irq)(struct pcie_port *pp, int irq); | ||
76 | u32 (*get_msi_data)(struct pcie_port *pp); | ||
66 | }; | 77 | }; |
67 | 78 | ||
68 | int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val); | 79 | int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val); |