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