]> git.sur5r.net Git - u-boot/blob - arch/x86/cpu/irq.c
x86: irq: Remove chipset specific irq router drivers
[u-boot] / arch / x86 / cpu / irq.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
4  */
5
6 #include <common.h>
7 #include <dm.h>
8 #include <errno.h>
9 #include <fdtdec.h>
10 #include <malloc.h>
11 #include <asm/io.h>
12 #include <asm/irq.h>
13 #include <asm/pci.h>
14 #include <asm/pirq_routing.h>
15 #include <asm/tables.h>
16
17 DECLARE_GLOBAL_DATA_PTR;
18
19 bool pirq_check_irq_routed(struct udevice *dev, int link, u8 irq)
20 {
21         struct irq_router *priv = dev_get_priv(dev);
22         u8 pirq;
23         int base = priv->link_base;
24
25         if (priv->config == PIRQ_VIA_PCI)
26                 dm_pci_read_config8(dev->parent, LINK_N2V(link, base), &pirq);
27         else
28                 pirq = readb((uintptr_t)priv->ibase + LINK_N2V(link, base));
29
30         pirq &= 0xf;
31
32         /* IRQ# 0/1/2/8/13 are reserved */
33         if (pirq < 3 || pirq == 8 || pirq == 13)
34                 return false;
35
36         return pirq == irq ? true : false;
37 }
38
39 int pirq_translate_link(struct udevice *dev, int link)
40 {
41         struct irq_router *priv = dev_get_priv(dev);
42
43         return LINK_V2N(link, priv->link_base);
44 }
45
46 void pirq_assign_irq(struct udevice *dev, int link, u8 irq)
47 {
48         struct irq_router *priv = dev_get_priv(dev);
49         int base = priv->link_base;
50
51         /* IRQ# 0/1/2/8/13 are reserved */
52         if (irq < 3 || irq == 8 || irq == 13)
53                 return;
54
55         if (priv->config == PIRQ_VIA_PCI)
56                 dm_pci_write_config8(dev->parent, LINK_N2V(link, base), irq);
57         else
58                 writeb(irq, (uintptr_t)priv->ibase + LINK_N2V(link, base));
59 }
60
61 static struct irq_info *check_dup_entry(struct irq_info *slot_base,
62                                         int entry_num, int bus, int device)
63 {
64         struct irq_info *slot = slot_base;
65         int i;
66
67         for (i = 0; i < entry_num; i++) {
68                 if (slot->bus == bus && slot->devfn == (device << 3))
69                         break;
70                 slot++;
71         }
72
73         return (i == entry_num) ? NULL : slot;
74 }
75
76 static inline void fill_irq_info(struct irq_router *priv, struct irq_info *slot,
77                                  int bus, int device, int pin, int pirq)
78 {
79         slot->bus = bus;
80         slot->devfn = (device << 3) | 0;
81         slot->irq[pin - 1].link = LINK_N2V(pirq, priv->link_base);
82         slot->irq[pin - 1].bitmap = priv->irq_mask;
83 }
84
85 static int create_pirq_routing_table(struct udevice *dev)
86 {
87         struct irq_router *priv = dev_get_priv(dev);
88         const void *blob = gd->fdt_blob;
89         int node;
90         int len, count;
91         const u32 *cell;
92         struct irq_routing_table *rt;
93         struct irq_info *slot, *slot_base;
94         int irq_entries = 0;
95         int i;
96         int ret;
97
98         node = dev_of_offset(dev);
99
100         /* extract the bdf from fdt_pci_addr */
101         priv->bdf = dm_pci_get_bdf(dev->parent);
102
103         ret = fdt_stringlist_search(blob, node, "intel,pirq-config", "pci");
104         if (!ret) {
105                 priv->config = PIRQ_VIA_PCI;
106         } else {
107                 ret = fdt_stringlist_search(blob, node, "intel,pirq-config",
108                                             "ibase");
109                 if (!ret)
110                         priv->config = PIRQ_VIA_IBASE;
111                 else
112                         return -EINVAL;
113         }
114
115         ret = fdtdec_get_int(blob, node, "intel,pirq-link", -1);
116         if (ret == -1)
117                 return ret;
118         priv->link_base = ret;
119
120         priv->irq_mask = fdtdec_get_int(blob, node,
121                                         "intel,pirq-mask", PIRQ_BITMAP);
122
123         if (IS_ENABLED(CONFIG_GENERATE_ACPI_TABLE)) {
124                 /* Reserve IRQ9 for SCI */
125                 priv->irq_mask &= ~(1 << 9);
126         }
127
128         if (priv->config == PIRQ_VIA_IBASE) {
129                 int ibase_off;
130
131                 ibase_off = fdtdec_get_int(blob, node, "intel,ibase-offset", 0);
132                 if (!ibase_off)
133                         return -EINVAL;
134
135                 /*
136                  * Here we assume that the IBASE register has already been
137                  * properly configured by U-Boot before.
138                  *
139                  * By 'valid' we mean:
140                  *   1) a valid memory space carved within system memory space
141                  *      assigned to IBASE register block.
142                  *   2) memory range decoding is enabled.
143                  * Hence we don't do any santify test here.
144                  */
145                 dm_pci_read_config32(dev->parent, ibase_off, &priv->ibase);
146                 priv->ibase &= ~0xf;
147         }
148
149         priv->actl_8bit = fdtdec_get_bool(blob, node, "intel,actl-8bit");
150         priv->actl_addr = fdtdec_get_int(blob, node, "intel,actl-addr", 0);
151
152         cell = fdt_getprop(blob, node, "intel,pirq-routing", &len);
153         if (!cell || len % sizeof(struct pirq_routing))
154                 return -EINVAL;
155         count = len / sizeof(struct pirq_routing);
156
157         rt = calloc(1, sizeof(struct irq_routing_table));
158         if (!rt)
159                 return -ENOMEM;
160
161         /* Populate the PIRQ table fields */
162         rt->signature = PIRQ_SIGNATURE;
163         rt->version = PIRQ_VERSION;
164         rt->rtr_bus = PCI_BUS(priv->bdf);
165         rt->rtr_devfn = (PCI_DEV(priv->bdf) << 3) | PCI_FUNC(priv->bdf);
166         rt->rtr_vendor = PCI_VENDOR_ID_INTEL;
167         rt->rtr_device = PCI_DEVICE_ID_INTEL_ICH7_31;
168
169         slot_base = rt->slots;
170
171         /* Now fill in the irq_info entries in the PIRQ table */
172         for (i = 0; i < count;
173              i++, cell += sizeof(struct pirq_routing) / sizeof(u32)) {
174                 struct pirq_routing pr;
175
176                 pr.bdf = fdt_addr_to_cpu(cell[0]);
177                 pr.pin = fdt_addr_to_cpu(cell[1]);
178                 pr.pirq = fdt_addr_to_cpu(cell[2]);
179
180                 debug("irq_info %d: b.d.f %x.%x.%x INT%c PIRQ%c\n",
181                       i, PCI_BUS(pr.bdf), PCI_DEV(pr.bdf),
182                       PCI_FUNC(pr.bdf), 'A' + pr.pin - 1,
183                       'A' + pr.pirq);
184
185                 slot = check_dup_entry(slot_base, irq_entries,
186                                        PCI_BUS(pr.bdf), PCI_DEV(pr.bdf));
187                 if (slot) {
188                         debug("found entry for bus %d device %d, ",
189                               PCI_BUS(pr.bdf), PCI_DEV(pr.bdf));
190
191                         if (slot->irq[pr.pin - 1].link) {
192                                 debug("skipping\n");
193
194                                 /*
195                                  * Sanity test on the routed PIRQ pin
196                                  *
197                                  * If they don't match, show a warning to tell
198                                  * there might be something wrong with the PIRQ
199                                  * routing information in the device tree.
200                                  */
201                                 if (slot->irq[pr.pin - 1].link !=
202                                         LINK_N2V(pr.pirq, priv->link_base))
203                                         debug("WARNING: Inconsistent PIRQ routing information\n");
204                                 continue;
205                         }
206                 } else {
207                         slot = slot_base + irq_entries++;
208                 }
209                 debug("writing INT%c\n", 'A' + pr.pin - 1);
210                 fill_irq_info(priv, slot, PCI_BUS(pr.bdf), PCI_DEV(pr.bdf),
211                               pr.pin, pr.pirq);
212         }
213
214         rt->size = irq_entries * sizeof(struct irq_info) + 32;
215
216         /* Fix up the table checksum */
217         rt->checksum = table_compute_checksum(rt, rt->size);
218
219         gd->arch.pirq_routing_table = rt;
220
221         return 0;
222 }
223
224 static void irq_enable_sci(struct udevice *dev)
225 {
226         struct irq_router *priv = dev_get_priv(dev);
227
228         if (priv->actl_8bit) {
229                 /* Bit7 must be turned on to enable ACPI */
230                 dm_pci_write_config8(dev->parent, priv->actl_addr, 0x80);
231         } else {
232                 /* Write 0 to enable SCI on IRQ9 */
233                 if (priv->config == PIRQ_VIA_PCI)
234                         dm_pci_write_config32(dev->parent, priv->actl_addr, 0);
235                 else
236                         writel(0, (uintptr_t)priv->ibase + priv->actl_addr);
237         }
238 }
239
240 int irq_router_probe(struct udevice *dev)
241 {
242         int ret;
243
244         ret = create_pirq_routing_table(dev);
245         if (ret) {
246                 debug("Failed to create pirq routing table\n");
247                 return ret;
248         }
249         /* Route PIRQ */
250         pirq_route_irqs(dev, gd->arch.pirq_routing_table->slots,
251                         get_irq_slot_count(gd->arch.pirq_routing_table));
252
253         if (IS_ENABLED(CONFIG_GENERATE_ACPI_TABLE))
254                 irq_enable_sci(dev);
255
256         return 0;
257 }
258
259 ulong write_pirq_routing_table(ulong addr)
260 {
261         if (!gd->arch.pirq_routing_table)
262                 return addr;
263
264         return copy_pirq_routing_table(addr, gd->arch.pirq_routing_table);
265 }
266
267 static const struct udevice_id irq_router_ids[] = {
268         { .compatible = "intel,irq-router" },
269         { }
270 };
271
272 U_BOOT_DRIVER(irq_router_drv) = {
273         .name           = "intel_irq",
274         .id             = UCLASS_IRQ,
275         .of_match       = irq_router_ids,
276         .probe          = irq_router_probe,
277         .priv_auto_alloc_size = sizeof(struct irq_router),
278 };
279
280 UCLASS_DRIVER(irq) = {
281         .id             = UCLASS_IRQ,
282         .name           = "irq",
283 };