diff options
Diffstat (limited to 'drivers/pci/controller/pcie-tango.c')
-rw-r--r-- | drivers/pci/controller/pcie-tango.c | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/drivers/pci/controller/pcie-tango.c b/drivers/pci/controller/pcie-tango.c new file mode 100644 index 000000000000..21a208da3f59 --- /dev/null +++ b/drivers/pci/controller/pcie-tango.c | |||
@@ -0,0 +1,341 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #include <linux/irqchip/chained_irq.h> | ||
3 | #include <linux/irqdomain.h> | ||
4 | #include <linux/pci-ecam.h> | ||
5 | #include <linux/delay.h> | ||
6 | #include <linux/msi.h> | ||
7 | #include <linux/of_address.h> | ||
8 | |||
9 | #define MSI_MAX 256 | ||
10 | |||
11 | #define SMP8759_MUX 0x48 | ||
12 | #define SMP8759_TEST_OUT 0x74 | ||
13 | #define SMP8759_DOORBELL 0x7c | ||
14 | #define SMP8759_STATUS 0x80 | ||
15 | #define SMP8759_ENABLE 0xa0 | ||
16 | |||
17 | struct tango_pcie { | ||
18 | DECLARE_BITMAP(used_msi, MSI_MAX); | ||
19 | u64 msi_doorbell; | ||
20 | spinlock_t used_msi_lock; | ||
21 | void __iomem *base; | ||
22 | struct irq_domain *dom; | ||
23 | }; | ||
24 | |||
25 | static void tango_msi_isr(struct irq_desc *desc) | ||
26 | { | ||
27 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
28 | struct tango_pcie *pcie = irq_desc_get_handler_data(desc); | ||
29 | unsigned long status, base, virq, idx, pos = 0; | ||
30 | |||
31 | chained_irq_enter(chip, desc); | ||
32 | spin_lock(&pcie->used_msi_lock); | ||
33 | |||
34 | while ((pos = find_next_bit(pcie->used_msi, MSI_MAX, pos)) < MSI_MAX) { | ||
35 | base = round_down(pos, 32); | ||
36 | status = readl_relaxed(pcie->base + SMP8759_STATUS + base / 8); | ||
37 | for_each_set_bit(idx, &status, 32) { | ||
38 | virq = irq_find_mapping(pcie->dom, base + idx); | ||
39 | generic_handle_irq(virq); | ||
40 | } | ||
41 | pos = base + 32; | ||
42 | } | ||
43 | |||
44 | spin_unlock(&pcie->used_msi_lock); | ||
45 | chained_irq_exit(chip, desc); | ||
46 | } | ||
47 | |||
48 | static void tango_ack(struct irq_data *d) | ||
49 | { | ||
50 | struct tango_pcie *pcie = d->chip_data; | ||
51 | u32 offset = (d->hwirq / 32) * 4; | ||
52 | u32 bit = BIT(d->hwirq % 32); | ||
53 | |||
54 | writel_relaxed(bit, pcie->base + SMP8759_STATUS + offset); | ||
55 | } | ||
56 | |||
57 | static void update_msi_enable(struct irq_data *d, bool unmask) | ||
58 | { | ||
59 | unsigned long flags; | ||
60 | struct tango_pcie *pcie = d->chip_data; | ||
61 | u32 offset = (d->hwirq / 32) * 4; | ||
62 | u32 bit = BIT(d->hwirq % 32); | ||
63 | u32 val; | ||
64 | |||
65 | spin_lock_irqsave(&pcie->used_msi_lock, flags); | ||
66 | val = readl_relaxed(pcie->base + SMP8759_ENABLE + offset); | ||
67 | val = unmask ? val | bit : val & ~bit; | ||
68 | writel_relaxed(val, pcie->base + SMP8759_ENABLE + offset); | ||
69 | spin_unlock_irqrestore(&pcie->used_msi_lock, flags); | ||
70 | } | ||
71 | |||
72 | static void tango_mask(struct irq_data *d) | ||
73 | { | ||
74 | update_msi_enable(d, false); | ||
75 | } | ||
76 | |||
77 | static void tango_unmask(struct irq_data *d) | ||
78 | { | ||
79 | update_msi_enable(d, true); | ||
80 | } | ||
81 | |||
82 | static int tango_set_affinity(struct irq_data *d, const struct cpumask *mask, | ||
83 | bool force) | ||
84 | { | ||
85 | return -EINVAL; | ||
86 | } | ||
87 | |||
88 | static void tango_compose_msi_msg(struct irq_data *d, struct msi_msg *msg) | ||
89 | { | ||
90 | struct tango_pcie *pcie = d->chip_data; | ||
91 | msg->address_lo = lower_32_bits(pcie->msi_doorbell); | ||
92 | msg->address_hi = upper_32_bits(pcie->msi_doorbell); | ||
93 | msg->data = d->hwirq; | ||
94 | } | ||
95 | |||
96 | static struct irq_chip tango_chip = { | ||
97 | .irq_ack = tango_ack, | ||
98 | .irq_mask = tango_mask, | ||
99 | .irq_unmask = tango_unmask, | ||
100 | .irq_set_affinity = tango_set_affinity, | ||
101 | .irq_compose_msi_msg = tango_compose_msi_msg, | ||
102 | }; | ||
103 | |||
104 | static void msi_ack(struct irq_data *d) | ||
105 | { | ||
106 | irq_chip_ack_parent(d); | ||
107 | } | ||
108 | |||
109 | static void msi_mask(struct irq_data *d) | ||
110 | { | ||
111 | pci_msi_mask_irq(d); | ||
112 | irq_chip_mask_parent(d); | ||
113 | } | ||
114 | |||
115 | static void msi_unmask(struct irq_data *d) | ||
116 | { | ||
117 | pci_msi_unmask_irq(d); | ||
118 | irq_chip_unmask_parent(d); | ||
119 | } | ||
120 | |||
121 | static struct irq_chip msi_chip = { | ||
122 | .name = "MSI", | ||
123 | .irq_ack = msi_ack, | ||
124 | .irq_mask = msi_mask, | ||
125 | .irq_unmask = msi_unmask, | ||
126 | }; | ||
127 | |||
128 | static struct msi_domain_info msi_dom_info = { | ||
129 | .flags = MSI_FLAG_PCI_MSIX | ||
130 | | MSI_FLAG_USE_DEF_DOM_OPS | ||
131 | | MSI_FLAG_USE_DEF_CHIP_OPS, | ||
132 | .chip = &msi_chip, | ||
133 | }; | ||
134 | |||
135 | static int tango_irq_domain_alloc(struct irq_domain *dom, unsigned int virq, | ||
136 | unsigned int nr_irqs, void *args) | ||
137 | { | ||
138 | struct tango_pcie *pcie = dom->host_data; | ||
139 | unsigned long flags; | ||
140 | int pos; | ||
141 | |||
142 | spin_lock_irqsave(&pcie->used_msi_lock, flags); | ||
143 | pos = find_first_zero_bit(pcie->used_msi, MSI_MAX); | ||
144 | if (pos >= MSI_MAX) { | ||
145 | spin_unlock_irqrestore(&pcie->used_msi_lock, flags); | ||
146 | return -ENOSPC; | ||
147 | } | ||
148 | __set_bit(pos, pcie->used_msi); | ||
149 | spin_unlock_irqrestore(&pcie->used_msi_lock, flags); | ||
150 | irq_domain_set_info(dom, virq, pos, &tango_chip, | ||
151 | pcie, handle_edge_irq, NULL, NULL); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static void tango_irq_domain_free(struct irq_domain *dom, unsigned int virq, | ||
157 | unsigned int nr_irqs) | ||
158 | { | ||
159 | unsigned long flags; | ||
160 | struct irq_data *d = irq_domain_get_irq_data(dom, virq); | ||
161 | struct tango_pcie *pcie = d->chip_data; | ||
162 | |||
163 | spin_lock_irqsave(&pcie->used_msi_lock, flags); | ||
164 | __clear_bit(d->hwirq, pcie->used_msi); | ||
165 | spin_unlock_irqrestore(&pcie->used_msi_lock, flags); | ||
166 | } | ||
167 | |||
168 | static const struct irq_domain_ops dom_ops = { | ||
169 | .alloc = tango_irq_domain_alloc, | ||
170 | .free = tango_irq_domain_free, | ||
171 | }; | ||
172 | |||
173 | static int smp8759_config_read(struct pci_bus *bus, unsigned int devfn, | ||
174 | int where, int size, u32 *val) | ||
175 | { | ||
176 | struct pci_config_window *cfg = bus->sysdata; | ||
177 | struct tango_pcie *pcie = dev_get_drvdata(cfg->parent); | ||
178 | int ret; | ||
179 | |||
180 | /* Reads in configuration space outside devfn 0 return garbage */ | ||
181 | if (devfn != 0) | ||
182 | return PCIBIOS_FUNC_NOT_SUPPORTED; | ||
183 | |||
184 | /* | ||
185 | * PCI config and MMIO accesses are muxed. Linux doesn't have a | ||
186 | * mutual exclusion mechanism for config vs. MMIO accesses, so | ||
187 | * concurrent accesses may cause corruption. | ||
188 | */ | ||
189 | writel_relaxed(1, pcie->base + SMP8759_MUX); | ||
190 | ret = pci_generic_config_read(bus, devfn, where, size, val); | ||
191 | writel_relaxed(0, pcie->base + SMP8759_MUX); | ||
192 | |||
193 | return ret; | ||
194 | } | ||
195 | |||
196 | static int smp8759_config_write(struct pci_bus *bus, unsigned int devfn, | ||
197 | int where, int size, u32 val) | ||
198 | { | ||
199 | struct pci_config_window *cfg = bus->sysdata; | ||
200 | struct tango_pcie *pcie = dev_get_drvdata(cfg->parent); | ||
201 | int ret; | ||
202 | |||
203 | writel_relaxed(1, pcie->base + SMP8759_MUX); | ||
204 | ret = pci_generic_config_write(bus, devfn, where, size, val); | ||
205 | writel_relaxed(0, pcie->base + SMP8759_MUX); | ||
206 | |||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | static struct pci_ecam_ops smp8759_ecam_ops = { | ||
211 | .bus_shift = 20, | ||
212 | .pci_ops = { | ||
213 | .map_bus = pci_ecam_map_bus, | ||
214 | .read = smp8759_config_read, | ||
215 | .write = smp8759_config_write, | ||
216 | } | ||
217 | }; | ||
218 | |||
219 | static int tango_pcie_link_up(struct tango_pcie *pcie) | ||
220 | { | ||
221 | void __iomem *test_out = pcie->base + SMP8759_TEST_OUT; | ||
222 | int i; | ||
223 | |||
224 | writel_relaxed(16, test_out); | ||
225 | for (i = 0; i < 10; ++i) { | ||
226 | u32 ltssm_state = readl_relaxed(test_out) >> 8; | ||
227 | if ((ltssm_state & 0x1f) == 0xf) /* L0 */ | ||
228 | return 1; | ||
229 | usleep_range(3000, 4000); | ||
230 | } | ||
231 | |||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | static int tango_pcie_probe(struct platform_device *pdev) | ||
236 | { | ||
237 | struct device *dev = &pdev->dev; | ||
238 | struct tango_pcie *pcie; | ||
239 | struct resource *res; | ||
240 | struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node); | ||
241 | struct irq_domain *msi_dom, *irq_dom; | ||
242 | struct of_pci_range_parser parser; | ||
243 | struct of_pci_range range; | ||
244 | int virq, offset; | ||
245 | |||
246 | dev_warn(dev, "simultaneous PCI config and MMIO accesses may cause data corruption\n"); | ||
247 | add_taint(TAINT_CRAP, LOCKDEP_STILL_OK); | ||
248 | |||
249 | pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); | ||
250 | if (!pcie) | ||
251 | return -ENOMEM; | ||
252 | |||
253 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
254 | pcie->base = devm_ioremap_resource(dev, res); | ||
255 | if (IS_ERR(pcie->base)) | ||
256 | return PTR_ERR(pcie->base); | ||
257 | |||
258 | platform_set_drvdata(pdev, pcie); | ||
259 | |||
260 | if (!tango_pcie_link_up(pcie)) | ||
261 | return -ENODEV; | ||
262 | |||
263 | if (of_pci_dma_range_parser_init(&parser, dev->of_node) < 0) | ||
264 | return -ENOENT; | ||
265 | |||
266 | if (of_pci_range_parser_one(&parser, &range) == NULL) | ||
267 | return -ENOENT; | ||
268 | |||
269 | range.pci_addr += range.size; | ||
270 | pcie->msi_doorbell = range.pci_addr + res->start + SMP8759_DOORBELL; | ||
271 | |||
272 | for (offset = 0; offset < MSI_MAX / 8; offset += 4) | ||
273 | writel_relaxed(0, pcie->base + SMP8759_ENABLE + offset); | ||
274 | |||
275 | virq = platform_get_irq(pdev, 1); | ||
276 | if (virq <= 0) { | ||
277 | dev_err(dev, "Failed to map IRQ\n"); | ||
278 | return -ENXIO; | ||
279 | } | ||
280 | |||
281 | irq_dom = irq_domain_create_linear(fwnode, MSI_MAX, &dom_ops, pcie); | ||
282 | if (!irq_dom) { | ||
283 | dev_err(dev, "Failed to create IRQ domain\n"); | ||
284 | return -ENOMEM; | ||
285 | } | ||
286 | |||
287 | msi_dom = pci_msi_create_irq_domain(fwnode, &msi_dom_info, irq_dom); | ||
288 | if (!msi_dom) { | ||
289 | dev_err(dev, "Failed to create MSI domain\n"); | ||
290 | irq_domain_remove(irq_dom); | ||
291 | return -ENOMEM; | ||
292 | } | ||
293 | |||
294 | pcie->dom = irq_dom; | ||
295 | spin_lock_init(&pcie->used_msi_lock); | ||
296 | irq_set_chained_handler_and_data(virq, tango_msi_isr, pcie); | ||
297 | |||
298 | return pci_host_common_probe(pdev, &smp8759_ecam_ops); | ||
299 | } | ||
300 | |||
301 | static const struct of_device_id tango_pcie_ids[] = { | ||
302 | { .compatible = "sigma,smp8759-pcie" }, | ||
303 | { }, | ||
304 | }; | ||
305 | |||
306 | static struct platform_driver tango_pcie_driver = { | ||
307 | .probe = tango_pcie_probe, | ||
308 | .driver = { | ||
309 | .name = KBUILD_MODNAME, | ||
310 | .of_match_table = tango_pcie_ids, | ||
311 | .suppress_bind_attrs = true, | ||
312 | }, | ||
313 | }; | ||
314 | builtin_platform_driver(tango_pcie_driver); | ||
315 | |||
316 | /* | ||
317 | * The root complex advertises the wrong device class. | ||
318 | * Header Type 1 is for PCI-to-PCI bridges. | ||
319 | */ | ||
320 | static void tango_fixup_class(struct pci_dev *dev) | ||
321 | { | ||
322 | dev->class = PCI_CLASS_BRIDGE_PCI << 8; | ||
323 | } | ||
324 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIGMA, 0x0024, tango_fixup_class); | ||
325 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIGMA, 0x0028, tango_fixup_class); | ||
326 | |||
327 | /* | ||
328 | * The root complex exposes a "fake" BAR, which is used to filter | ||
329 | * bus-to-system accesses. Only accesses within the range defined by this | ||
330 | * BAR are forwarded to the host, others are ignored. | ||
331 | * | ||
332 | * By default, the DMA framework expects an identity mapping, and DRAM0 is | ||
333 | * mapped at 0x80000000. | ||
334 | */ | ||
335 | static void tango_fixup_bar(struct pci_dev *dev) | ||
336 | { | ||
337 | dev->non_compliant_bars = true; | ||
338 | pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0x80000000); | ||
339 | } | ||
340 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIGMA, 0x0024, tango_fixup_bar); | ||
341 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIGMA, 0x0028, tango_fixup_bar); | ||