diff options
Diffstat (limited to 'drivers/pci/host/pci-ftpci100.c')
-rw-r--r-- | drivers/pci/host/pci-ftpci100.c | 563 |
1 files changed, 563 insertions, 0 deletions
diff --git a/drivers/pci/host/pci-ftpci100.c b/drivers/pci/host/pci-ftpci100.c new file mode 100644 index 000000000000..d26501c4145a --- /dev/null +++ b/drivers/pci/host/pci-ftpci100.c | |||
@@ -0,0 +1,563 @@ | |||
1 | /* | ||
2 | * Support for Faraday Technology FTPC100 PCI Controller | ||
3 | * | ||
4 | * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> | ||
5 | * | ||
6 | * Based on the out-of-tree OpenWRT patch for Cortina Gemini: | ||
7 | * Copyright (C) 2009 Janos Laube <janos.dev@gmail.com> | ||
8 | * Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> | ||
9 | * Based on SL2312 PCI controller code | ||
10 | * Storlink (C) 2003 | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/of_address.h> | ||
18 | #include <linux/of_device.h> | ||
19 | #include <linux/of_irq.h> | ||
20 | #include <linux/of_pci.h> | ||
21 | #include <linux/pci.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/irqdomain.h> | ||
25 | #include <linux/irqchip/chained_irq.h> | ||
26 | #include <linux/bitops.h> | ||
27 | #include <linux/irq.h> | ||
28 | |||
29 | /* | ||
30 | * Special configuration registers directly in the first few words | ||
31 | * in I/O space. | ||
32 | */ | ||
33 | #define PCI_IOSIZE 0x00 | ||
34 | #define PCI_PROT 0x04 /* AHB protection */ | ||
35 | #define PCI_CTRL 0x08 /* PCI control signal */ | ||
36 | #define PCI_SOFTRST 0x10 /* Soft reset counter and response error enable */ | ||
37 | #define PCI_CONFIG 0x28 /* PCI configuration command register */ | ||
38 | #define PCI_DATA 0x2C | ||
39 | |||
40 | #define FARADAY_PCI_PMC 0x40 /* Power management control */ | ||
41 | #define FARADAY_PCI_PMCSR 0x44 /* Power management status */ | ||
42 | #define FARADAY_PCI_CTRL1 0x48 /* Control register 1 */ | ||
43 | #define FARADAY_PCI_CTRL2 0x4C /* Control register 2 */ | ||
44 | #define FARADAY_PCI_MEM1_BASE_SIZE 0x50 /* Memory base and size #1 */ | ||
45 | #define FARADAY_PCI_MEM2_BASE_SIZE 0x54 /* Memory base and size #2 */ | ||
46 | #define FARADAY_PCI_MEM3_BASE_SIZE 0x58 /* Memory base and size #3 */ | ||
47 | |||
48 | /* Bits 31..28 gives INTD..INTA status */ | ||
49 | #define PCI_CTRL2_INTSTS_SHIFT 28 | ||
50 | #define PCI_CTRL2_INTMASK_CMDERR BIT(27) | ||
51 | #define PCI_CTRL2_INTMASK_PARERR BIT(26) | ||
52 | /* Bits 25..22 masks INTD..INTA */ | ||
53 | #define PCI_CTRL2_INTMASK_SHIFT 22 | ||
54 | #define PCI_CTRL2_INTMASK_MABRT_RX BIT(21) | ||
55 | #define PCI_CTRL2_INTMASK_TABRT_RX BIT(20) | ||
56 | #define PCI_CTRL2_INTMASK_TABRT_TX BIT(19) | ||
57 | #define PCI_CTRL2_INTMASK_RETRY4 BIT(18) | ||
58 | #define PCI_CTRL2_INTMASK_SERR_RX BIT(17) | ||
59 | #define PCI_CTRL2_INTMASK_PERR_RX BIT(16) | ||
60 | /* Bit 15 reserved */ | ||
61 | #define PCI_CTRL2_MSTPRI_REQ6 BIT(14) | ||
62 | #define PCI_CTRL2_MSTPRI_REQ5 BIT(13) | ||
63 | #define PCI_CTRL2_MSTPRI_REQ4 BIT(12) | ||
64 | #define PCI_CTRL2_MSTPRI_REQ3 BIT(11) | ||
65 | #define PCI_CTRL2_MSTPRI_REQ2 BIT(10) | ||
66 | #define PCI_CTRL2_MSTPRI_REQ1 BIT(9) | ||
67 | #define PCI_CTRL2_MSTPRI_REQ0 BIT(8) | ||
68 | /* Bits 7..4 reserved */ | ||
69 | /* Bits 3..0 TRDYW */ | ||
70 | |||
71 | /* | ||
72 | * Memory configs: | ||
73 | * Bit 31..20 defines the PCI side memory base | ||
74 | * Bit 19..16 (4 bits) defines the size per below | ||
75 | */ | ||
76 | #define FARADAY_PCI_MEMBASE_MASK 0xfff00000 | ||
77 | #define FARADAY_PCI_MEMSIZE_1MB 0x0 | ||
78 | #define FARADAY_PCI_MEMSIZE_2MB 0x1 | ||
79 | #define FARADAY_PCI_MEMSIZE_4MB 0x2 | ||
80 | #define FARADAY_PCI_MEMSIZE_8MB 0x3 | ||
81 | #define FARADAY_PCI_MEMSIZE_16MB 0x4 | ||
82 | #define FARADAY_PCI_MEMSIZE_32MB 0x5 | ||
83 | #define FARADAY_PCI_MEMSIZE_64MB 0x6 | ||
84 | #define FARADAY_PCI_MEMSIZE_128MB 0x7 | ||
85 | #define FARADAY_PCI_MEMSIZE_256MB 0x8 | ||
86 | #define FARADAY_PCI_MEMSIZE_512MB 0x9 | ||
87 | #define FARADAY_PCI_MEMSIZE_1GB 0xa | ||
88 | #define FARADAY_PCI_MEMSIZE_2GB 0xb | ||
89 | #define FARADAY_PCI_MEMSIZE_SHIFT 16 | ||
90 | |||
91 | /* | ||
92 | * The DMA base is set to 0x0 for all memory segments, it reflects the | ||
93 | * fact that the memory of the host system starts at 0x0. | ||
94 | */ | ||
95 | #define FARADAY_PCI_DMA_MEM1_BASE 0x00000000 | ||
96 | #define FARADAY_PCI_DMA_MEM2_BASE 0x00000000 | ||
97 | #define FARADAY_PCI_DMA_MEM3_BASE 0x00000000 | ||
98 | |||
99 | /* Defines for PCI configuration command register */ | ||
100 | #define PCI_CONF_ENABLE BIT(31) | ||
101 | #define PCI_CONF_WHERE(r) ((r) & 0xFC) | ||
102 | #define PCI_CONF_BUS(b) (((b) & 0xFF) << 16) | ||
103 | #define PCI_CONF_DEVICE(d) (((d) & 0x1F) << 11) | ||
104 | #define PCI_CONF_FUNCTION(f) (((f) & 0x07) << 8) | ||
105 | |||
106 | /** | ||
107 | * struct faraday_pci_variant - encodes IP block differences | ||
108 | * @cascaded_irq: this host has cascaded IRQs from an interrupt controller | ||
109 | * embedded in the host bridge. | ||
110 | */ | ||
111 | struct faraday_pci_variant { | ||
112 | bool cascaded_irq; | ||
113 | }; | ||
114 | |||
115 | struct faraday_pci { | ||
116 | struct device *dev; | ||
117 | void __iomem *base; | ||
118 | struct irq_domain *irqdomain; | ||
119 | struct pci_bus *bus; | ||
120 | }; | ||
121 | |||
122 | static int faraday_res_to_memcfg(resource_size_t mem_base, | ||
123 | resource_size_t mem_size, u32 *val) | ||
124 | { | ||
125 | u32 outval; | ||
126 | |||
127 | switch (mem_size) { | ||
128 | case SZ_1M: | ||
129 | outval = FARADAY_PCI_MEMSIZE_1MB; | ||
130 | break; | ||
131 | case SZ_2M: | ||
132 | outval = FARADAY_PCI_MEMSIZE_2MB; | ||
133 | break; | ||
134 | case SZ_4M: | ||
135 | outval = FARADAY_PCI_MEMSIZE_4MB; | ||
136 | break; | ||
137 | case SZ_8M: | ||
138 | outval = FARADAY_PCI_MEMSIZE_8MB; | ||
139 | break; | ||
140 | case SZ_16M: | ||
141 | outval = FARADAY_PCI_MEMSIZE_16MB; | ||
142 | break; | ||
143 | case SZ_32M: | ||
144 | outval = FARADAY_PCI_MEMSIZE_32MB; | ||
145 | break; | ||
146 | case SZ_64M: | ||
147 | outval = FARADAY_PCI_MEMSIZE_64MB; | ||
148 | break; | ||
149 | case SZ_128M: | ||
150 | outval = FARADAY_PCI_MEMSIZE_128MB; | ||
151 | break; | ||
152 | case SZ_256M: | ||
153 | outval = FARADAY_PCI_MEMSIZE_256MB; | ||
154 | break; | ||
155 | case SZ_512M: | ||
156 | outval = FARADAY_PCI_MEMSIZE_512MB; | ||
157 | break; | ||
158 | case SZ_1G: | ||
159 | outval = FARADAY_PCI_MEMSIZE_1GB; | ||
160 | break; | ||
161 | case SZ_2G: | ||
162 | outval = FARADAY_PCI_MEMSIZE_2GB; | ||
163 | break; | ||
164 | default: | ||
165 | return -EINVAL; | ||
166 | } | ||
167 | outval <<= FARADAY_PCI_MEMSIZE_SHIFT; | ||
168 | |||
169 | /* This is probably not good */ | ||
170 | if (mem_base & ~(FARADAY_PCI_MEMBASE_MASK)) | ||
171 | pr_warn("truncated PCI memory base\n"); | ||
172 | /* Translate to bridge side address space */ | ||
173 | outval |= (mem_base & FARADAY_PCI_MEMBASE_MASK); | ||
174 | pr_debug("Translated pci base @%pap, size %pap to config %08x\n", | ||
175 | &mem_base, &mem_size, outval); | ||
176 | |||
177 | *val = outval; | ||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int faraday_pci_read_config(struct pci_bus *bus, unsigned int fn, | ||
182 | int config, int size, u32 *value) | ||
183 | { | ||
184 | struct faraday_pci *p = bus->sysdata; | ||
185 | |||
186 | writel(PCI_CONF_BUS(bus->number) | | ||
187 | PCI_CONF_DEVICE(PCI_SLOT(fn)) | | ||
188 | PCI_CONF_FUNCTION(PCI_FUNC(fn)) | | ||
189 | PCI_CONF_WHERE(config) | | ||
190 | PCI_CONF_ENABLE, | ||
191 | p->base + PCI_CONFIG); | ||
192 | |||
193 | *value = readl(p->base + PCI_DATA); | ||
194 | |||
195 | if (size == 1) | ||
196 | *value = (*value >> (8 * (config & 3))) & 0xFF; | ||
197 | else if (size == 2) | ||
198 | *value = (*value >> (8 * (config & 3))) & 0xFFFF; | ||
199 | |||
200 | dev_dbg(&bus->dev, | ||
201 | "[read] slt: %.2d, fnc: %d, cnf: 0x%.2X, val (%d bytes): 0x%.8X\n", | ||
202 | PCI_SLOT(fn), PCI_FUNC(fn), config, size, *value); | ||
203 | |||
204 | return PCIBIOS_SUCCESSFUL; | ||
205 | } | ||
206 | |||
207 | static int faraday_pci_write_config(struct pci_bus *bus, unsigned int fn, | ||
208 | int config, int size, u32 value) | ||
209 | { | ||
210 | struct faraday_pci *p = bus->sysdata; | ||
211 | int ret = PCIBIOS_SUCCESSFUL; | ||
212 | |||
213 | dev_dbg(&bus->dev, | ||
214 | "[write] slt: %.2d, fnc: %d, cnf: 0x%.2X, val (%d bytes): 0x%.8X\n", | ||
215 | PCI_SLOT(fn), PCI_FUNC(fn), config, size, value); | ||
216 | |||
217 | writel(PCI_CONF_BUS(bus->number) | | ||
218 | PCI_CONF_DEVICE(PCI_SLOT(fn)) | | ||
219 | PCI_CONF_FUNCTION(PCI_FUNC(fn)) | | ||
220 | PCI_CONF_WHERE(config) | | ||
221 | PCI_CONF_ENABLE, | ||
222 | p->base + PCI_CONFIG); | ||
223 | |||
224 | switch (size) { | ||
225 | case 4: | ||
226 | writel(value, p->base + PCI_DATA); | ||
227 | break; | ||
228 | case 2: | ||
229 | writew(value, p->base + PCI_DATA + (config & 3)); | ||
230 | break; | ||
231 | case 1: | ||
232 | writeb(value, p->base + PCI_DATA + (config & 3)); | ||
233 | break; | ||
234 | default: | ||
235 | ret = PCIBIOS_BAD_REGISTER_NUMBER; | ||
236 | } | ||
237 | |||
238 | return ret; | ||
239 | } | ||
240 | |||
241 | static struct pci_ops faraday_pci_ops = { | ||
242 | .read = faraday_pci_read_config, | ||
243 | .write = faraday_pci_write_config, | ||
244 | }; | ||
245 | |||
246 | static void faraday_pci_ack_irq(struct irq_data *d) | ||
247 | { | ||
248 | struct faraday_pci *p = irq_data_get_irq_chip_data(d); | ||
249 | unsigned int reg; | ||
250 | |||
251 | faraday_pci_read_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, ®); | ||
252 | reg &= ~(0xF << PCI_CTRL2_INTSTS_SHIFT); | ||
253 | reg |= BIT(irqd_to_hwirq(d) + PCI_CTRL2_INTSTS_SHIFT); | ||
254 | faraday_pci_write_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, reg); | ||
255 | } | ||
256 | |||
257 | static void faraday_pci_mask_irq(struct irq_data *d) | ||
258 | { | ||
259 | struct faraday_pci *p = irq_data_get_irq_chip_data(d); | ||
260 | unsigned int reg; | ||
261 | |||
262 | faraday_pci_read_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, ®); | ||
263 | reg &= ~((0xF << PCI_CTRL2_INTSTS_SHIFT) | ||
264 | | BIT(irqd_to_hwirq(d) + PCI_CTRL2_INTMASK_SHIFT)); | ||
265 | faraday_pci_write_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, reg); | ||
266 | } | ||
267 | |||
268 | static void faraday_pci_unmask_irq(struct irq_data *d) | ||
269 | { | ||
270 | struct faraday_pci *p = irq_data_get_irq_chip_data(d); | ||
271 | unsigned int reg; | ||
272 | |||
273 | faraday_pci_read_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, ®); | ||
274 | reg &= ~(0xF << PCI_CTRL2_INTSTS_SHIFT); | ||
275 | reg |= BIT(irqd_to_hwirq(d) + PCI_CTRL2_INTMASK_SHIFT); | ||
276 | faraday_pci_write_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, reg); | ||
277 | } | ||
278 | |||
279 | static void faraday_pci_irq_handler(struct irq_desc *desc) | ||
280 | { | ||
281 | struct faraday_pci *p = irq_desc_get_handler_data(desc); | ||
282 | struct irq_chip *irqchip = irq_desc_get_chip(desc); | ||
283 | unsigned int irq_stat, reg, i; | ||
284 | |||
285 | faraday_pci_read_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, ®); | ||
286 | irq_stat = reg >> PCI_CTRL2_INTSTS_SHIFT; | ||
287 | |||
288 | chained_irq_enter(irqchip, desc); | ||
289 | |||
290 | for (i = 0; i < 4; i++) { | ||
291 | if ((irq_stat & BIT(i)) == 0) | ||
292 | continue; | ||
293 | generic_handle_irq(irq_find_mapping(p->irqdomain, i)); | ||
294 | } | ||
295 | |||
296 | chained_irq_exit(irqchip, desc); | ||
297 | } | ||
298 | |||
299 | static struct irq_chip faraday_pci_irq_chip = { | ||
300 | .name = "PCI", | ||
301 | .irq_ack = faraday_pci_ack_irq, | ||
302 | .irq_mask = faraday_pci_mask_irq, | ||
303 | .irq_unmask = faraday_pci_unmask_irq, | ||
304 | }; | ||
305 | |||
306 | static int faraday_pci_irq_map(struct irq_domain *domain, unsigned int irq, | ||
307 | irq_hw_number_t hwirq) | ||
308 | { | ||
309 | irq_set_chip_and_handler(irq, &faraday_pci_irq_chip, handle_level_irq); | ||
310 | irq_set_chip_data(irq, domain->host_data); | ||
311 | |||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static const struct irq_domain_ops faraday_pci_irqdomain_ops = { | ||
316 | .map = faraday_pci_irq_map, | ||
317 | }; | ||
318 | |||
319 | static int faraday_pci_setup_cascaded_irq(struct faraday_pci *p) | ||
320 | { | ||
321 | struct device_node *intc = of_get_next_child(p->dev->of_node, NULL); | ||
322 | int irq; | ||
323 | int i; | ||
324 | |||
325 | if (!intc) { | ||
326 | dev_err(p->dev, "missing child interrupt-controller node\n"); | ||
327 | return -EINVAL; | ||
328 | } | ||
329 | |||
330 | /* All PCI IRQs cascade off this one */ | ||
331 | irq = of_irq_get(intc, 0); | ||
332 | if (!irq) { | ||
333 | dev_err(p->dev, "failed to get parent IRQ\n"); | ||
334 | return -EINVAL; | ||
335 | } | ||
336 | |||
337 | p->irqdomain = irq_domain_add_linear(intc, 4, | ||
338 | &faraday_pci_irqdomain_ops, p); | ||
339 | if (!p->irqdomain) { | ||
340 | dev_err(p->dev, "failed to create Gemini PCI IRQ domain\n"); | ||
341 | return -EINVAL; | ||
342 | } | ||
343 | |||
344 | irq_set_chained_handler_and_data(irq, faraday_pci_irq_handler, p); | ||
345 | |||
346 | for (i = 0; i < 4; i++) | ||
347 | irq_create_mapping(p->irqdomain, i); | ||
348 | |||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | static int pci_dma_range_parser_init(struct of_pci_range_parser *parser, | ||
353 | struct device_node *node) | ||
354 | { | ||
355 | const int na = 3, ns = 2; | ||
356 | int rlen; | ||
357 | |||
358 | parser->node = node; | ||
359 | parser->pna = of_n_addr_cells(node); | ||
360 | parser->np = parser->pna + na + ns; | ||
361 | |||
362 | parser->range = of_get_property(node, "dma-ranges", &rlen); | ||
363 | if (!parser->range) | ||
364 | return -ENOENT; | ||
365 | parser->end = parser->range + rlen / sizeof(__be32); | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static int faraday_pci_parse_map_dma_ranges(struct faraday_pci *p, | ||
371 | struct device_node *np) | ||
372 | { | ||
373 | struct of_pci_range range; | ||
374 | struct of_pci_range_parser parser; | ||
375 | struct device *dev = p->dev; | ||
376 | u32 confreg[3] = { | ||
377 | FARADAY_PCI_MEM1_BASE_SIZE, | ||
378 | FARADAY_PCI_MEM2_BASE_SIZE, | ||
379 | FARADAY_PCI_MEM3_BASE_SIZE, | ||
380 | }; | ||
381 | int i = 0; | ||
382 | u32 val; | ||
383 | |||
384 | if (pci_dma_range_parser_init(&parser, np)) { | ||
385 | dev_err(dev, "missing dma-ranges property\n"); | ||
386 | return -EINVAL; | ||
387 | } | ||
388 | |||
389 | /* | ||
390 | * Get the dma-ranges from the device tree | ||
391 | */ | ||
392 | for_each_of_pci_range(&parser, &range) { | ||
393 | u64 end = range.pci_addr + range.size - 1; | ||
394 | int ret; | ||
395 | |||
396 | ret = faraday_res_to_memcfg(range.pci_addr, range.size, &val); | ||
397 | if (ret) { | ||
398 | dev_err(dev, | ||
399 | "DMA range %d: illegal MEM resource size\n", i); | ||
400 | return -EINVAL; | ||
401 | } | ||
402 | |||
403 | dev_info(dev, "DMA MEM%d BASE: 0x%016llx -> 0x%016llx config %08x\n", | ||
404 | i + 1, range.pci_addr, end, val); | ||
405 | if (i <= 2) { | ||
406 | faraday_pci_write_config(p->bus, 0, confreg[i], | ||
407 | 4, val); | ||
408 | } else { | ||
409 | dev_err(dev, "ignore extraneous dma-range %d\n", i); | ||
410 | break; | ||
411 | } | ||
412 | |||
413 | i++; | ||
414 | } | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | static int faraday_pci_probe(struct platform_device *pdev) | ||
420 | { | ||
421 | struct device *dev = &pdev->dev; | ||
422 | const struct faraday_pci_variant *variant = | ||
423 | of_device_get_match_data(dev); | ||
424 | struct resource *regs; | ||
425 | resource_size_t io_base; | ||
426 | struct resource_entry *win; | ||
427 | struct faraday_pci *p; | ||
428 | struct resource *mem; | ||
429 | struct resource *io; | ||
430 | struct pci_host_bridge *host; | ||
431 | int ret; | ||
432 | u32 val; | ||
433 | LIST_HEAD(res); | ||
434 | |||
435 | host = pci_alloc_host_bridge(sizeof(*p)); | ||
436 | if (!host) | ||
437 | return -ENOMEM; | ||
438 | |||
439 | host->dev.parent = dev; | ||
440 | host->ops = &faraday_pci_ops; | ||
441 | host->busnr = 0; | ||
442 | host->msi = NULL; | ||
443 | p = pci_host_bridge_priv(host); | ||
444 | host->sysdata = p; | ||
445 | p->dev = dev; | ||
446 | |||
447 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
448 | p->base = devm_ioremap_resource(dev, regs); | ||
449 | if (IS_ERR(p->base)) | ||
450 | return PTR_ERR(p->base); | ||
451 | |||
452 | ret = of_pci_get_host_bridge_resources(dev->of_node, 0, 0xff, | ||
453 | &res, &io_base); | ||
454 | if (ret) | ||
455 | return ret; | ||
456 | |||
457 | ret = devm_request_pci_bus_resources(dev, &res); | ||
458 | if (ret) | ||
459 | return ret; | ||
460 | |||
461 | /* Get the I/O and memory ranges from DT */ | ||
462 | resource_list_for_each_entry(win, &res) { | ||
463 | switch (resource_type(win->res)) { | ||
464 | case IORESOURCE_IO: | ||
465 | io = win->res; | ||
466 | io->name = "Gemini PCI I/O"; | ||
467 | if (!faraday_res_to_memcfg(io->start - win->offset, | ||
468 | resource_size(io), &val)) { | ||
469 | /* setup I/O space size */ | ||
470 | writel(val, p->base + PCI_IOSIZE); | ||
471 | } else { | ||
472 | dev_err(dev, "illegal IO mem size\n"); | ||
473 | return -EINVAL; | ||
474 | } | ||
475 | ret = pci_remap_iospace(io, io_base); | ||
476 | if (ret) { | ||
477 | dev_warn(dev, "error %d: failed to map resource %pR\n", | ||
478 | ret, io); | ||
479 | continue; | ||
480 | } | ||
481 | break; | ||
482 | case IORESOURCE_MEM: | ||
483 | mem = win->res; | ||
484 | mem->name = "Gemini PCI MEM"; | ||
485 | break; | ||
486 | case IORESOURCE_BUS: | ||
487 | break; | ||
488 | default: | ||
489 | break; | ||
490 | } | ||
491 | } | ||
492 | |||
493 | /* Setup hostbridge */ | ||
494 | val = readl(p->base + PCI_CTRL); | ||
495 | val |= PCI_COMMAND_IO; | ||
496 | val |= PCI_COMMAND_MEMORY; | ||
497 | val |= PCI_COMMAND_MASTER; | ||
498 | writel(val, p->base + PCI_CTRL); | ||
499 | |||
500 | list_splice_init(&res, &host->windows); | ||
501 | ret = pci_register_host_bridge(host); | ||
502 | if (ret) { | ||
503 | dev_err(dev, "failed to register host: %d\n", ret); | ||
504 | return ret; | ||
505 | } | ||
506 | p->bus = host->bus; | ||
507 | |||
508 | /* Mask and clear all interrupts */ | ||
509 | faraday_pci_write_config(p->bus, 0, FARADAY_PCI_CTRL2 + 2, 2, 0xF000); | ||
510 | if (variant->cascaded_irq) { | ||
511 | ret = faraday_pci_setup_cascaded_irq(p); | ||
512 | if (ret) { | ||
513 | dev_err(dev, "failed to setup cascaded IRQ\n"); | ||
514 | return ret; | ||
515 | } | ||
516 | } | ||
517 | |||
518 | ret = faraday_pci_parse_map_dma_ranges(p, dev->of_node); | ||
519 | if (ret) | ||
520 | return ret; | ||
521 | |||
522 | pci_scan_child_bus(p->bus); | ||
523 | pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); | ||
524 | pci_bus_assign_resources(p->bus); | ||
525 | pci_bus_add_devices(p->bus); | ||
526 | pci_free_resource_list(&res); | ||
527 | |||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | /* | ||
532 | * We encode bridge variants here, we have at least two so it doesn't | ||
533 | * hurt to have infrastructure to encompass future variants as well. | ||
534 | */ | ||
535 | const struct faraday_pci_variant faraday_regular = { | ||
536 | .cascaded_irq = true, | ||
537 | }; | ||
538 | |||
539 | const struct faraday_pci_variant faraday_dual = { | ||
540 | .cascaded_irq = false, | ||
541 | }; | ||
542 | |||
543 | static const struct of_device_id faraday_pci_of_match[] = { | ||
544 | { | ||
545 | .compatible = "faraday,ftpci100", | ||
546 | .data = &faraday_regular, | ||
547 | }, | ||
548 | { | ||
549 | .compatible = "faraday,ftpci100-dual", | ||
550 | .data = &faraday_dual, | ||
551 | }, | ||
552 | {}, | ||
553 | }; | ||
554 | |||
555 | static struct platform_driver faraday_pci_driver = { | ||
556 | .driver = { | ||
557 | .name = "ftpci100", | ||
558 | .of_match_table = of_match_ptr(faraday_pci_of_match), | ||
559 | .suppress_bind_attrs = true, | ||
560 | }, | ||
561 | .probe = faraday_pci_probe, | ||
562 | }; | ||
563 | builtin_platform_driver(faraday_pci_driver); | ||