diff options
-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/pcie-cadence-host.c | 397 | ||||
-rw-r--r-- | drivers/pci/host/pcie-cadence.h | 189 |
5 files changed, 604 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index a6e86e20761e..460d5580f87e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -10402,6 +10402,13 @@ S: Maintained | |||
10402 | F: Documentation/devicetree/bindings/pci/pci-armada8k.txt | 10402 | F: Documentation/devicetree/bindings/pci/pci-armada8k.txt |
10403 | F: drivers/pci/dwc/pcie-armada8k.c | 10403 | F: drivers/pci/dwc/pcie-armada8k.c |
10404 | 10404 | ||
10405 | PCI DRIVER FOR CADENCE PCIE IP | ||
10406 | M: Alan Douglas <adouglas@cadence.com> | ||
10407 | L: linux-pci@vger.kernel.org | ||
10408 | S: Maintained | ||
10409 | F: Documentation/devicetree/bindings/pci/cdns,*.txt | ||
10410 | F: drivers/pci/host/pcie-cadence* | ||
10411 | |||
10405 | PCI DRIVER FOR FREESCALE LAYERSCAPE | 10412 | PCI DRIVER FOR FREESCALE LAYERSCAPE |
10406 | M: Minghuan Lian <minghuan.Lian@freescale.com> | 10413 | M: Minghuan Lian <minghuan.Lian@freescale.com> |
10407 | M: Mingkai Hu <mingkai.hu@freescale.com> | 10414 | M: Mingkai Hu <mingkai.hu@freescale.com> |
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 38d12980db0f..d6866733d69d 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig | |||
@@ -210,6 +210,16 @@ config PCIE_TANGO_SMP8759 | |||
210 | This can lead to data corruption if drivers perform concurrent | 210 | This can lead to data corruption if drivers perform concurrent |
211 | config and MMIO accesses. | 211 | config and MMIO accesses. |
212 | 212 | ||
213 | config PCIE_CADENCE_HOST | ||
214 | bool "Cadence PCIe host controller" | ||
215 | depends on OF | ||
216 | depends on PCI | ||
217 | select IRQ_DOMAIN | ||
218 | help | ||
219 | Say Y here if you want to support the Cadence PCIe controller in host | ||
220 | mode. This PCIe controller may be embedded into many different vendors | ||
221 | SoCs. | ||
222 | |||
213 | config VMD | 223 | config VMD |
214 | depends on PCI_MSI && X86_64 && SRCU | 224 | depends on PCI_MSI && X86_64 && SRCU |
215 | tristate "Intel Volume Management Device Driver" | 225 | tristate "Intel Volume Management Device Driver" |
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 3b1059190867..2460f0785120 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile | |||
@@ -22,6 +22,7 @@ obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o | |||
22 | obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o | 22 | obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o |
23 | obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o | 23 | obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o |
24 | obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o | 24 | obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o |
25 | obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o | ||
25 | obj-$(CONFIG_VMD) += vmd.o | 26 | obj-$(CONFIG_VMD) += vmd.o |
26 | 27 | ||
27 | # The following drivers are for devices that use the generic ACPI | 28 | # The following drivers are for devices that use the generic ACPI |
diff --git a/drivers/pci/host/pcie-cadence-host.c b/drivers/pci/host/pcie-cadence-host.c new file mode 100644 index 000000000000..9332601845ea --- /dev/null +++ b/drivers/pci/host/pcie-cadence-host.c | |||
@@ -0,0 +1,397 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | // Copyright (c) 2017 Cadence | ||
3 | // Cadence PCIe host controller driver. | ||
4 | // Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> | ||
5 | |||
6 | #include <linux/kernel.h> | ||
7 | #include <linux/of_address.h> | ||
8 | #include <linux/of_pci.h> | ||
9 | #include <linux/platform_device.h> | ||
10 | #include <linux/pm_runtime.h> | ||
11 | |||
12 | #include "pcie-cadence.h" | ||
13 | |||
14 | /** | ||
15 | * struct cdns_pcie_rc - private data for this PCIe Root Complex driver | ||
16 | * @pcie: Cadence PCIe controller | ||
17 | * @dev: pointer to PCIe device | ||
18 | * @cfg_res: start/end offsets in the physical system memory to map PCI | ||
19 | * configuration space accesses | ||
20 | * @bus_range: first/last buses behind the PCIe host controller | ||
21 | * @cfg_base: IO mapped window to access the PCI configuration space of a | ||
22 | * single function at a time | ||
23 | * @max_regions: maximum number of regions supported by the hardware | ||
24 | * @no_bar_nbits: Number of bits to keep for inbound (PCIe -> CPU) address | ||
25 | * translation (nbits sets into the "no BAR match" register) | ||
26 | * @vendor_id: PCI vendor ID | ||
27 | * @device_id: PCI device ID | ||
28 | */ | ||
29 | struct cdns_pcie_rc { | ||
30 | struct cdns_pcie pcie; | ||
31 | struct device *dev; | ||
32 | struct resource *cfg_res; | ||
33 | struct resource *bus_range; | ||
34 | void __iomem *cfg_base; | ||
35 | u32 max_regions; | ||
36 | u32 no_bar_nbits; | ||
37 | u16 vendor_id; | ||
38 | u16 device_id; | ||
39 | }; | ||
40 | |||
41 | static void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, | ||
42 | u32 r, bool is_io, | ||
43 | u64 cpu_addr, u64 pci_addr, size_t size) | ||
44 | { | ||
45 | /* | ||
46 | * roundup_pow_of_two() returns an unsigned long, which is not suited | ||
47 | * for 64bit values. | ||
48 | */ | ||
49 | u64 sz = 1ULL << fls64(size - 1); | ||
50 | int nbits = ilog2(sz); | ||
51 | u32 addr0, addr1, desc0, desc1; | ||
52 | |||
53 | if (nbits < 8) | ||
54 | nbits = 8; | ||
55 | |||
56 | /* Set the PCI address */ | ||
57 | addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) | | ||
58 | (lower_32_bits(pci_addr) & GENMASK(31, 8)); | ||
59 | addr1 = upper_32_bits(pci_addr); | ||
60 | |||
61 | cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), addr0); | ||
62 | cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), addr1); | ||
63 | |||
64 | /* Set the PCIe header descriptor */ | ||
65 | if (is_io) | ||
66 | desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO; | ||
67 | else | ||
68 | desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM; | ||
69 | desc1 = 0; | ||
70 | |||
71 | /* | ||
72 | * Whatever Bit [23] is set or not inside DESC0 register of the outbound | ||
73 | * PCIe descriptor, the PCI function number must be set into | ||
74 | * Bits [26:24] of DESC0 anyway. | ||
75 | * | ||
76 | * In Root Complex mode, the function number is always 0 but in Endpoint | ||
77 | * mode, the PCIe controller may support more than one function. This | ||
78 | * function number needs to be set properly into the outbound PCIe | ||
79 | * descriptor. | ||
80 | * | ||
81 | * Besides, setting Bit [23] is mandatory when in Root Complex mode: | ||
82 | * then the driver must provide the bus, resp. device, number in | ||
83 | * Bits [7:0] of DESC1, resp. Bits[31:27] of DESC0. Like the function | ||
84 | * number, the device number is always 0 in Root Complex mode. | ||
85 | */ | ||
86 | desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID | | ||
87 | CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0); | ||
88 | desc1 |= CDNS_PCIE_AT_OB_REGION_DESC1_BUS(pcie->bus); | ||
89 | |||
90 | cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), desc0); | ||
91 | cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1); | ||
92 | |||
93 | /* Set the CPU address */ | ||
94 | cpu_addr -= pcie->mem_res->start; | ||
95 | addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) | | ||
96 | (lower_32_bits(cpu_addr) & GENMASK(31, 8)); | ||
97 | addr1 = upper_32_bits(cpu_addr); | ||
98 | |||
99 | cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), addr0); | ||
100 | cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), addr1); | ||
101 | } | ||
102 | |||
103 | static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn, | ||
104 | int where) | ||
105 | { | ||
106 | struct pci_host_bridge *bridge = pci_find_host_bridge(bus); | ||
107 | struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge); | ||
108 | struct cdns_pcie *pcie = &rc->pcie; | ||
109 | unsigned int busn = bus->number; | ||
110 | u32 addr0, desc0; | ||
111 | |||
112 | if (busn == rc->bus_range->start) { | ||
113 | /* | ||
114 | * Only the root port (devfn == 0) is connected to this bus. | ||
115 | * All other PCI devices are behind some bridge hence on another | ||
116 | * bus. | ||
117 | */ | ||
118 | if (devfn) | ||
119 | return NULL; | ||
120 | |||
121 | return pcie->reg_base + (where & 0xfff); | ||
122 | } | ||
123 | |||
124 | /* Update Output registers for AXI region 0. */ | ||
125 | addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) | | ||
126 | CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) | | ||
127 | CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(busn); | ||
128 | cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(0), addr0); | ||
129 | |||
130 | /* Configuration Type 0 or Type 1 access. */ | ||
131 | desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID | | ||
132 | CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0); | ||
133 | /* | ||
134 | * The bus number was already set once for all in desc1 by | ||
135 | * cdns_pcie_host_init_address_translation(). | ||
136 | */ | ||
137 | if (busn == rc->bus_range->start + 1) | ||
138 | desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0; | ||
139 | else | ||
140 | desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1; | ||
141 | cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(0), desc0); | ||
142 | |||
143 | return rc->cfg_base + (where & 0xfff); | ||
144 | } | ||
145 | |||
146 | static struct pci_ops cdns_pcie_host_ops = { | ||
147 | .map_bus = cdns_pci_map_bus, | ||
148 | .read = pci_generic_config_read, | ||
149 | .write = pci_generic_config_write, | ||
150 | }; | ||
151 | |||
152 | static const struct of_device_id cdns_pcie_host_of_match[] = { | ||
153 | { .compatible = "cdns,cdns-pcie-host" }, | ||
154 | |||
155 | { }, | ||
156 | }; | ||
157 | |||
158 | static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc) | ||
159 | { | ||
160 | struct cdns_pcie *pcie = &rc->pcie; | ||
161 | u32 value, ctrl; | ||
162 | |||
163 | /* | ||
164 | * Set the root complex BAR configuration register: | ||
165 | * - disable both BAR0 and BAR1. | ||
166 | * - enable Prefetchable Memory Base and Limit registers in type 1 | ||
167 | * config space (64 bits). | ||
168 | * - enable IO Base and Limit registers in type 1 config | ||
169 | * space (32 bits). | ||
170 | */ | ||
171 | ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED; | ||
172 | value = CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) | | ||
173 | CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) | | ||
174 | CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE | | ||
175 | CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS | | ||
176 | CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE | | ||
177 | CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS; | ||
178 | cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value); | ||
179 | |||
180 | /* Set root port configuration space */ | ||
181 | if (rc->vendor_id != 0xffff) | ||
182 | cdns_pcie_rp_writew(pcie, PCI_VENDOR_ID, rc->vendor_id); | ||
183 | if (rc->device_id != 0xffff) | ||
184 | cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id); | ||
185 | |||
186 | cdns_pcie_rp_writeb(pcie, PCI_CLASS_REVISION, 0); | ||
187 | cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0); | ||
188 | cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI); | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc) | ||
194 | { | ||
195 | struct cdns_pcie *pcie = &rc->pcie; | ||
196 | struct resource *cfg_res = rc->cfg_res; | ||
197 | struct resource *mem_res = pcie->mem_res; | ||
198 | struct resource *bus_range = rc->bus_range; | ||
199 | struct device *dev = rc->dev; | ||
200 | struct device_node *np = dev->of_node; | ||
201 | struct of_pci_range_parser parser; | ||
202 | struct of_pci_range range; | ||
203 | u32 addr0, addr1, desc1; | ||
204 | u64 cpu_addr; | ||
205 | int r, err; | ||
206 | |||
207 | /* | ||
208 | * Reserve region 0 for PCI configure space accesses: | ||
209 | * OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by | ||
210 | * cdns_pci_map_bus(), other region registers are set here once for all. | ||
211 | */ | ||
212 | addr1 = 0; /* Should be programmed to zero. */ | ||
213 | desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus_range->start); | ||
214 | cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1); | ||
215 | cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1); | ||
216 | |||
217 | cpu_addr = cfg_res->start - mem_res->start; | ||
218 | addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) | | ||
219 | (lower_32_bits(cpu_addr) & GENMASK(31, 8)); | ||
220 | addr1 = upper_32_bits(cpu_addr); | ||
221 | cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(0), addr0); | ||
222 | cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(0), addr1); | ||
223 | |||
224 | err = of_pci_range_parser_init(&parser, np); | ||
225 | if (err) | ||
226 | return err; | ||
227 | |||
228 | r = 1; | ||
229 | for_each_of_pci_range(&parser, &range) { | ||
230 | bool is_io; | ||
231 | |||
232 | if (r >= rc->max_regions) | ||
233 | break; | ||
234 | |||
235 | if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM) | ||
236 | is_io = false; | ||
237 | else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO) | ||
238 | is_io = true; | ||
239 | else | ||
240 | continue; | ||
241 | |||
242 | cdns_pcie_set_outbound_region(pcie, r, is_io, | ||
243 | range.cpu_addr, | ||
244 | range.pci_addr, | ||
245 | range.size); | ||
246 | r++; | ||
247 | } | ||
248 | |||
249 | /* | ||
250 | * Set Root Port no BAR match Inbound Translation registers: | ||
251 | * needed for MSI and DMA. | ||
252 | * Root Port BAR0 and BAR1 are disabled, hence no need to set their | ||
253 | * inbound translation registers. | ||
254 | */ | ||
255 | addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(rc->no_bar_nbits); | ||
256 | addr1 = 0; | ||
257 | cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(RP_NO_BAR), addr0); | ||
258 | cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(RP_NO_BAR), addr1); | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static int cdns_pcie_host_init(struct device *dev, | ||
264 | struct list_head *resources, | ||
265 | struct cdns_pcie_rc *rc) | ||
266 | { | ||
267 | struct resource *bus_range = NULL; | ||
268 | int err; | ||
269 | |||
270 | /* Parse our PCI ranges and request their resources */ | ||
271 | err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range); | ||
272 | if (err) | ||
273 | return err; | ||
274 | |||
275 | rc->bus_range = bus_range; | ||
276 | rc->pcie.bus = bus_range->start; | ||
277 | |||
278 | err = cdns_pcie_host_init_root_port(rc); | ||
279 | if (err) | ||
280 | goto err_out; | ||
281 | |||
282 | err = cdns_pcie_host_init_address_translation(rc); | ||
283 | if (err) | ||
284 | goto err_out; | ||
285 | |||
286 | return 0; | ||
287 | |||
288 | err_out: | ||
289 | pci_free_resource_list(resources); | ||
290 | return err; | ||
291 | } | ||
292 | |||
293 | static int cdns_pcie_host_probe(struct platform_device *pdev) | ||
294 | { | ||
295 | const char *type; | ||
296 | struct device *dev = &pdev->dev; | ||
297 | struct device_node *np = dev->of_node; | ||
298 | struct pci_host_bridge *bridge; | ||
299 | struct list_head resources; | ||
300 | struct cdns_pcie_rc *rc; | ||
301 | struct cdns_pcie *pcie; | ||
302 | struct resource *res; | ||
303 | int ret; | ||
304 | |||
305 | bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc)); | ||
306 | if (!bridge) | ||
307 | return -ENOMEM; | ||
308 | |||
309 | rc = pci_host_bridge_priv(bridge); | ||
310 | rc->dev = dev; | ||
311 | |||
312 | pcie = &rc->pcie; | ||
313 | |||
314 | rc->max_regions = 32; | ||
315 | of_property_read_u32(np, "cdns,max-outbound-regions", &rc->max_regions); | ||
316 | |||
317 | rc->no_bar_nbits = 32; | ||
318 | of_property_read_u32(np, "cdns,no-bar-match-nbits", &rc->no_bar_nbits); | ||
319 | |||
320 | rc->vendor_id = 0xffff; | ||
321 | of_property_read_u16(np, "vendor-id", &rc->vendor_id); | ||
322 | |||
323 | rc->device_id = 0xffff; | ||
324 | of_property_read_u16(np, "device-id", &rc->device_id); | ||
325 | |||
326 | type = of_get_property(np, "device_type", NULL); | ||
327 | if (!type || strcmp(type, "pci")) { | ||
328 | dev_err(dev, "invalid \"device_type\" %s\n", type); | ||
329 | return -EINVAL; | ||
330 | } | ||
331 | |||
332 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg"); | ||
333 | pcie->reg_base = devm_ioremap_resource(dev, res); | ||
334 | if (IS_ERR(pcie->reg_base)) { | ||
335 | dev_err(dev, "missing \"reg\"\n"); | ||
336 | return PTR_ERR(pcie->reg_base); | ||
337 | } | ||
338 | |||
339 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); | ||
340 | rc->cfg_base = devm_pci_remap_cfg_resource(dev, res); | ||
341 | if (IS_ERR(rc->cfg_base)) { | ||
342 | dev_err(dev, "missing \"cfg\"\n"); | ||
343 | return PTR_ERR(rc->cfg_base); | ||
344 | } | ||
345 | rc->cfg_res = res; | ||
346 | |||
347 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem"); | ||
348 | if (!res) { | ||
349 | dev_err(dev, "missing \"mem\"\n"); | ||
350 | return -EINVAL; | ||
351 | } | ||
352 | pcie->mem_res = res; | ||
353 | |||
354 | pm_runtime_enable(dev); | ||
355 | ret = pm_runtime_get_sync(dev); | ||
356 | if (ret < 0) { | ||
357 | dev_err(dev, "pm_runtime_get_sync() failed\n"); | ||
358 | goto err_get_sync; | ||
359 | } | ||
360 | |||
361 | ret = cdns_pcie_host_init(dev, &resources, rc); | ||
362 | if (ret) | ||
363 | goto err_init; | ||
364 | |||
365 | list_splice_init(&resources, &bridge->windows); | ||
366 | bridge->dev.parent = dev; | ||
367 | bridge->busnr = pcie->bus; | ||
368 | bridge->ops = &cdns_pcie_host_ops; | ||
369 | bridge->map_irq = of_irq_parse_and_map_pci; | ||
370 | bridge->swizzle_irq = pci_common_swizzle; | ||
371 | |||
372 | ret = pci_host_probe(bridge); | ||
373 | if (ret < 0) | ||
374 | goto err_host_probe; | ||
375 | |||
376 | return 0; | ||
377 | |||
378 | err_host_probe: | ||
379 | pci_free_resource_list(&resources); | ||
380 | |||
381 | err_init: | ||
382 | pm_runtime_put_sync(dev); | ||
383 | |||
384 | err_get_sync: | ||
385 | pm_runtime_disable(dev); | ||
386 | |||
387 | return ret; | ||
388 | } | ||
389 | |||
390 | static struct platform_driver cdns_pcie_host_driver = { | ||
391 | .driver = { | ||
392 | .name = "cdns-pcie-host", | ||
393 | .of_match_table = cdns_pcie_host_of_match, | ||
394 | }, | ||
395 | .probe = cdns_pcie_host_probe, | ||
396 | }; | ||
397 | builtin_platform_driver(cdns_pcie_host_driver); | ||
diff --git a/drivers/pci/host/pcie-cadence.h b/drivers/pci/host/pcie-cadence.h new file mode 100644 index 000000000000..a28afdee0d02 --- /dev/null +++ b/drivers/pci/host/pcie-cadence.h | |||
@@ -0,0 +1,189 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | // Copyright (c) 2017 Cadence | ||
3 | // Cadence PCIe controller driver. | ||
4 | // Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> | ||
5 | |||
6 | #ifndef _PCIE_CADENCE_H | ||
7 | #define _PCIE_CADENCE_H | ||
8 | |||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/pci.h> | ||
11 | |||
12 | /* | ||
13 | * Local Management Registers | ||
14 | */ | ||
15 | #define CDNS_PCIE_LM_BASE 0x00100000 | ||
16 | |||
17 | /* Vendor ID Register */ | ||
18 | #define CDNS_PCIE_LM_ID (CDNS_PCIE_LM_BASE + 0x0044) | ||
19 | #define CDNS_PCIE_LM_ID_VENDOR_MASK GENMASK(15, 0) | ||
20 | #define CDNS_PCIE_LM_ID_VENDOR_SHIFT 0 | ||
21 | #define CDNS_PCIE_LM_ID_VENDOR(vid) \ | ||
22 | (((vid) << CDNS_PCIE_LM_ID_VENDOR_SHIFT) & CDNS_PCIE_LM_ID_VENDOR_MASK) | ||
23 | #define CDNS_PCIE_LM_ID_SUBSYS_MASK GENMASK(31, 16) | ||
24 | #define CDNS_PCIE_LM_ID_SUBSYS_SHIFT 16 | ||
25 | #define CDNS_PCIE_LM_ID_SUBSYS(sub) \ | ||
26 | (((sub) << CDNS_PCIE_LM_ID_SUBSYS_SHIFT) & CDNS_PCIE_LM_ID_SUBSYS_MASK) | ||
27 | |||
28 | /* Root Port Requestor ID Register */ | ||
29 | #define CDNS_PCIE_LM_RP_RID (CDNS_PCIE_LM_BASE + 0x0228) | ||
30 | #define CDNS_PCIE_LM_RP_RID_MASK GENMASK(15, 0) | ||
31 | #define CDNS_PCIE_LM_RP_RID_SHIFT 0 | ||
32 | #define CDNS_PCIE_LM_RP_RID_(rid) \ | ||
33 | (((rid) << CDNS_PCIE_LM_RP_RID_SHIFT) & CDNS_PCIE_LM_RP_RID_MASK) | ||
34 | |||
35 | /* Root Complex BAR Configuration Register */ | ||
36 | #define CDNS_PCIE_LM_RC_BAR_CFG (CDNS_PCIE_LM_BASE + 0x0300) | ||
37 | #define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK GENMASK(5, 0) | ||
38 | #define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE(a) \ | ||
39 | (((a) << 0) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK) | ||
40 | #define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK GENMASK(8, 6) | ||
41 | #define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(c) \ | ||
42 | (((c) << 6) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK) | ||
43 | #define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK GENMASK(13, 9) | ||
44 | #define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE(a) \ | ||
45 | (((a) << 9) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK) | ||
46 | #define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK GENMASK(16, 14) | ||
47 | #define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(c) \ | ||
48 | (((c) << 14) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK) | ||
49 | #define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE BIT(17) | ||
50 | #define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_32BITS 0 | ||
51 | #define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS BIT(18) | ||
52 | #define CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE BIT(19) | ||
53 | #define CDNS_PCIE_LM_RC_BAR_CFG_IO_16BITS 0 | ||
54 | #define CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS BIT(20) | ||
55 | #define CDNS_PCIE_LM_RC_BAR_CFG_CHECK_ENABLE BIT(31) | ||
56 | |||
57 | /* BAR control values applicable to both Endpoint Function and Root Complex */ | ||
58 | #define CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED 0x0 | ||
59 | #define CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS 0x1 | ||
60 | #define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS 0x4 | ||
61 | #define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS 0x5 | ||
62 | #define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS 0x6 | ||
63 | #define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7 | ||
64 | |||
65 | |||
66 | /* | ||
67 | * Root Port Registers (PCI configuration space for the root port function) | ||
68 | */ | ||
69 | #define CDNS_PCIE_RP_BASE 0x00200000 | ||
70 | |||
71 | |||
72 | /* | ||
73 | * Address Translation Registers | ||
74 | */ | ||
75 | #define CDNS_PCIE_AT_BASE 0x00400000 | ||
76 | |||
77 | /* Region r Outbound AXI to PCIe Address Translation Register 0 */ | ||
78 | #define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r) \ | ||
79 | (CDNS_PCIE_AT_BASE + 0x0000 + ((r) & 0x1f) * 0x0020) | ||
80 | #define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK GENMASK(5, 0) | ||
81 | #define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) \ | ||
82 | (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK) | ||
83 | #define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK GENMASK(19, 12) | ||
84 | #define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \ | ||
85 | (((devfn) << 12) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK) | ||
86 | #define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK GENMASK(27, 20) | ||
87 | #define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \ | ||
88 | (((bus) << 20) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK) | ||
89 | |||
90 | /* Region r Outbound AXI to PCIe Address Translation Register 1 */ | ||
91 | #define CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r) \ | ||
92 | (CDNS_PCIE_AT_BASE + 0x0004 + ((r) & 0x1f) * 0x0020) | ||
93 | |||
94 | /* Region r Outbound PCIe Descriptor Register 0 */ | ||
95 | #define CDNS_PCIE_AT_OB_REGION_DESC0(r) \ | ||
96 | (CDNS_PCIE_AT_BASE + 0x0008 + ((r) & 0x1f) * 0x0020) | ||
97 | #define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MASK GENMASK(3, 0) | ||
98 | #define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM 0x2 | ||
99 | #define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO 0x6 | ||
100 | #define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0 0xa | ||
101 | #define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1 0xb | ||
102 | #define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG 0xc | ||
103 | #define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_VENDOR_MSG 0xd | ||
104 | /* Bit 23 MUST be set in RC mode. */ | ||
105 | #define CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID BIT(23) | ||
106 | #define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK GENMASK(31, 24) | ||
107 | #define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \ | ||
108 | (((devfn) << 24) & CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK) | ||
109 | |||
110 | /* Region r Outbound PCIe Descriptor Register 1 */ | ||
111 | #define CDNS_PCIE_AT_OB_REGION_DESC1(r) \ | ||
112 | (CDNS_PCIE_AT_BASE + 0x000c + ((r) & 0x1f) * 0x0020) | ||
113 | #define CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK GENMASK(7, 0) | ||
114 | #define CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus) \ | ||
115 | ((bus) & CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK) | ||
116 | |||
117 | /* Region r AXI Region Base Address Register 0 */ | ||
118 | #define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r) \ | ||
119 | (CDNS_PCIE_AT_BASE + 0x0018 + ((r) & 0x1f) * 0x0020) | ||
120 | #define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK GENMASK(5, 0) | ||
121 | #define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) \ | ||
122 | (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK) | ||
123 | |||
124 | /* Region r AXI Region Base Address Register 1 */ | ||
125 | #define CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r) \ | ||
126 | (CDNS_PCIE_AT_BASE + 0x001c + ((r) & 0x1f) * 0x0020) | ||
127 | |||
128 | /* Root Port BAR Inbound PCIe to AXI Address Translation Register */ | ||
129 | #define CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar) \ | ||
130 | (CDNS_PCIE_AT_BASE + 0x0800 + (bar) * 0x0008) | ||
131 | #define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK GENMASK(5, 0) | ||
132 | #define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(nbits) \ | ||
133 | (((nbits) - 1) & CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK) | ||
134 | #define CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar) \ | ||
135 | (CDNS_PCIE_AT_BASE + 0x0804 + (bar) * 0x0008) | ||
136 | |||
137 | enum cdns_pcie_rp_bar { | ||
138 | RP_BAR0, | ||
139 | RP_BAR1, | ||
140 | RP_NO_BAR | ||
141 | }; | ||
142 | |||
143 | /** | ||
144 | * struct cdns_pcie - private data for Cadence PCIe controller drivers | ||
145 | * @reg_base: IO mapped register base | ||
146 | * @mem_res: start/end offsets in the physical system memory to map PCI accesses | ||
147 | * @bus: In Root Complex mode, the bus number | ||
148 | */ | ||
149 | struct cdns_pcie { | ||
150 | void __iomem *reg_base; | ||
151 | struct resource *mem_res; | ||
152 | u8 bus; | ||
153 | }; | ||
154 | |||
155 | /* Register access */ | ||
156 | static inline void cdns_pcie_writeb(struct cdns_pcie *pcie, u32 reg, u8 value) | ||
157 | { | ||
158 | writeb(value, pcie->reg_base + reg); | ||
159 | } | ||
160 | |||
161 | static inline void cdns_pcie_writew(struct cdns_pcie *pcie, u32 reg, u16 value) | ||
162 | { | ||
163 | writew(value, pcie->reg_base + reg); | ||
164 | } | ||
165 | |||
166 | static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value) | ||
167 | { | ||
168 | writel(value, pcie->reg_base + reg); | ||
169 | } | ||
170 | |||
171 | static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg) | ||
172 | { | ||
173 | return readl(pcie->reg_base + reg); | ||
174 | } | ||
175 | |||
176 | /* Root Port register access */ | ||
177 | static inline void cdns_pcie_rp_writeb(struct cdns_pcie *pcie, | ||
178 | u32 reg, u8 value) | ||
179 | { | ||
180 | writeb(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg); | ||
181 | } | ||
182 | |||
183 | static inline void cdns_pcie_rp_writew(struct cdns_pcie *pcie, | ||
184 | u32 reg, u16 value) | ||
185 | { | ||
186 | writew(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg); | ||
187 | } | ||
188 | |||
189 | #endif /* _PCIE_CADENCE_H */ | ||