Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
d76bdce3 MG |
2 | #include <linux/irqchip/chained_irq.h> |
3 | #include <linux/irqdomain.h> | |
5e14e9fa MG |
4 | #include <linux/pci-ecam.h> |
5 | #include <linux/delay.h> | |
d76bdce3 MG |
6 | #include <linux/msi.h> |
7 | #include <linux/of_address.h> | |
8 | ||
9 | #define MSI_MAX 256 | |
5e14e9fa MG |
10 | |
11 | #define SMP8759_MUX 0x48 | |
12 | #define SMP8759_TEST_OUT 0x74 | |
d76bdce3 MG |
13 | #define SMP8759_DOORBELL 0x7c |
14 | #define SMP8759_STATUS 0x80 | |
15 | #define SMP8759_ENABLE 0xa0 | |
5e14e9fa MG |
16 | |
17 | struct tango_pcie { | |
d76bdce3 MG |
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, | |
5e14e9fa MG |
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; | |
d76bdce3 MG |
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; | |
5e14e9fa MG |
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 | ||
d76bdce3 MG |
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 | ||
5e14e9fa MG |
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); |