1 /* $NetBSD: platform.c,v 1.29 2023/12/20 15:29:06 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by NONAKA Kimihiro.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: platform.c,v 1.29 2023/12/20 15:29:06 thorpej Exp $");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/intr.h>
38 #include <sys/inttypes.h>
39
40 #include <powerpc/pio.h>
41 #include <powerpc/psl.h>
42
43 #include <dev/pci/pcivar.h>
44
45 #include <machine/platform.h>
46 #include <machine/pcipnp.h>
47 #include <machine/residual.h>
48
49 u_int32_t prep_pci_baseaddr = 0x80000cf8;
50 u_int32_t prep_pci_basedata = 0x80000cfc;
51
52 struct pciroutinginfo *pciroutinginfo;
53 extern struct prep_pci_chipset *genppc_pct;
54
55 extern void pci_intr_fixup_ibm_6015(void);
56 #if NMCCLOCK > 0
57 /* from mcclock_pnpbus.c */
58 extern void ds1585_reboot(void);
59 #endif
60
61 struct platform_quirkdata platform_quirks[] = {
62 { "IBM PPS Model 6015", PLAT_QUIRK_INTRFIXUP,
63 pci_intr_fixup_ibm_6015, NULL, 0 },
64 { "(e1)", PLAT_QUIRK_ISA_HANDLER, NULL, NULL, EXT_INTR_I8259 },
65 { "000000000000000000000000000(e2)", PLAT_QUIRK_ISA_HANDLER, NULL,
66 NULL, EXT_INTR_I8259 },
67 { NULL, 0, NULL, NULL, 0 }
68 };
69
70 /* find the platform quirk entry for this model, -1 if none */
71
72 int
find_platform_quirk(const char * model)73 find_platform_quirk(const char *model)
74 {
75 int i;
76
77 for (i = 0; platform_quirks[i].model != NULL; i++)
78 if (strcmp(model, platform_quirks[i].model) == 0)
79 return i;
80 return -1;
81 }
82
83 /* XXX This should be conditional on finding L2 in residual */
84 void
cpu_setup_prep_generic(device_t dev)85 cpu_setup_prep_generic(device_t dev)
86 {
87 u_int8_t l2ctrl;
88
89 /* system control register */
90 l2ctrl = inb(PREP_BUS_SPACE_IO + 0x81c);
91 /* device status register */
92 (void)inb(PREP_BUS_SPACE_IO + 0x80c);
93
94 /* Enable L2 cache */
95 outb(PREP_BUS_SPACE_IO + 0x81c, l2ctrl | 0xc0);
96 }
97
98 /* We don't bus_space_map this because it can happen early in boot */
99 static void
reset_prep_generic(void)100 reset_prep_generic(void)
101 {
102 u_int8_t reg;
103
104 mtmsr(mfmsr() | PSL_IP);
105
106 #if NMCCLOCK > 0
107 /* XXX This is a special hack for 7024 and 7025 models, which have
108 * no obvious method of rebooting. We call this, because it will
109 * return if we do not have a 1585.
110 */
111 ds1585_reboot();
112 #endif
113
114 reg = inb(PREP_BUS_SPACE_IO + 0x92);
115 reg &= ~1UL;
116 outb(PREP_BUS_SPACE_IO + 0x92, reg);
117 reg = inb(PREP_BUS_SPACE_IO + 0x92);
118 reg |= 1;
119 outb(PREP_BUS_SPACE_IO + 0x92, reg);
120 }
121
122 void
reset_prep(void)123 reset_prep(void)
124 {
125 int i;
126
127 i = find_platform_quirk(res->VitalProductData.PrintableModel);
128 if (i != -1) {
129 if (platform_quirks[i].quirk & PLAT_QUIRK_RESET &&
130 platform_quirks[i].reset != NULL)
131 (*platform_quirks[i].reset)();
132 }
133 reset_prep_generic();
134 }
135
136 /*
137 * Gather the data needed to route interrupts on this machine from
138 * the residual data.
139 */
140
141
142 /* Count the number of PCI devices on a given pci bus */
143
144 static int
count_pnp_pci_devices(void * v,int * device)145 count_pnp_pci_devices(void *v, int *device)
146 {
147
148 int item, size, i;
149 int tag = *(unsigned char *)v;
150 unsigned char *q = v;
151 struct _L4_Pack *pack = v;
152 struct _L4_PPCPack *p = &pack->L4_Data.L4_PPCPack;
153
154 item = tag_large_item_name(tag);
155 size = (q[1] | (q[2] << 8)) + 3 /* tag + length */;
156
157 if (item != LargeVendorItem)
158 return size;
159 if (p->Type != LV_PCIBridge)
160 return size;
161
162 /* offset 20 begins irqmap, of 12 bytes each */
163 for (i = 20; i < size - 4; i += 12)
164 (*device)++;
165
166 return size;
167 }
168
169 /* Nop for small pnp packets */
170
171 static int
pnp_small_pkt(void * v)172 pnp_small_pkt(void *v)
173 {
174 int tag = *(unsigned char *)v;
175
176 return tag_small_count(tag) + 1 /* tag */;
177 }
178
179 /*
180 * We look to see what kind of bridge this is, and return it. If we have
181 * 1.1 residual, we also look up the bridge data, and get the config base
182 * address from it. We set a default sane value for the config base addr
183 * at initialization, so it shouldn't matter if we can't find one here.
184 */
185
186 int
pci_chipset_tag_type(void)187 pci_chipset_tag_type(void)
188 {
189 PPC_DEVICE *dev;
190 uint32_t addr, data, l;
191 unsigned char *p;
192 int size;
193
194 dev = find_nth_pnp_device("PNP0A03", 0, 0);
195 if (dev == NULL)
196 return PCIBridgeIndirect;
197
198 l = be32toh(dev->AllocatedOffset);
199 p = res->DevicePnPHeap + l;
200 if (p == NULL)
201 return PCIBridgeIndirect;
202
203 /* gather the pci base address from PNP */
204 for (; p[0] != END_TAG; p += size) {
205 if (tag_type(p[0]) == PNP_SMALL)
206 size = pnp_small_pkt(p);
207 else {
208 size = pnp_pci_configbase(p, &addr, &data);
209 if (addr != 0 && data != 0) {
210 prep_pci_baseaddr = addr;
211 prep_pci_basedata = data;
212 break;
213 }
214 }
215 }
216
217 return dev->DeviceId.Interface;
218 }
219
220 static int
create_intr_map(void * v,prop_dictionary_t dict)221 create_intr_map(void *v, prop_dictionary_t dict)
222 {
223 prop_dictionary_t sub;
224 int item, size, i, j, numslots;
225 int tag = *(unsigned char *)v;
226 unsigned char *q = v;
227 PCIInfoPack *pi = v;
228 struct _L4_Pack *pack = v;
229 struct _L4_PPCPack *p = &pack->L4_Data.L4_PPCPack;
230
231 item = tag_large_item_name(tag);
232 size = (q[1] | (q[2] << 8)) + 3 /* tag + length */;
233
234 if (item != LargeVendorItem)
235 return size;
236 if (p->Type != LV_PCIBridge) /* PCI Bridge type */
237 return size;
238
239 numslots = (le16dec(&pi->count0)-21)/sizeof(IntrMap);
240
241 for (i = 0; i < numslots; i++) {
242 int lines[MAX_PCI_INTRS] = { 0, 0, 0, 0 };
243 int offset = 0;
244 int dev;
245 char key[20];
246
247 sub = prop_dictionary_create_with_capacity(MAX_PCI_INTRS);
248 dev = pi->map[i].devfunc / 0x8;
249
250 for (j = 0; j < MAX_PCI_INTRS; j++) {
251 int line = bswap16(pi->map[i].intr[j]);
252
253 if (line != 0xffff) /*unusable*/
254 lines[j] = 1;
255 }
256 if (pi->map[i].intrctrltype == 2) /* MPIC */
257 offset += I8259_INTR_NUM;
258 for (j = 0; j < MAX_PCI_INTRS; j++) {
259 int line = bswap16(pi->map[i].intr[j]);
260 prop_number_t intr_num;
261
262 if (line == 0xffff || lines[j] == 0)
263 intr_num = prop_number_create_integer(0);
264 else
265 intr_num = prop_number_create_integer(
266 (line & 0x7fff) + offset);
267 snprintf(key, sizeof(key), "pin-%c", 'A' + j);
268 prop_dictionary_set(sub, key, intr_num);
269 prop_object_release(intr_num);
270 }
271 snprintf(key, sizeof(key), "devfunc-%d", dev);
272 prop_dictionary_set(dict, key, sub);
273 prop_object_release(sub);
274 }
275 return size;
276 }
277
278 /*
279 * Decode the interrupt mappings from PnP, and write them into a device
280 * property attached to the PCI bus.
281 * The bus, device and func arguments are the PCI locators where the bridge
282 * device was FOUND.
283 */
284 void
setup_pciintr_map(struct genppc_pci_chipset_businfo * pbi,int bus,int device,int func)285 setup_pciintr_map(struct genppc_pci_chipset_businfo *pbi, int bus, int device,
286 int func)
287 {
288 int devfunc, nbus, size, i, found = 0, nrofpcidevs = 0;
289 uint32_t l;
290 PPC_DEVICE *dev;
291 BUS_ACCESS *busacc;
292 unsigned char *p;
293 prop_dictionary_t dict;
294
295 /* revision 0 residual does not have valid pci bridge data */
296 if (res->Revision == 0)
297 return;
298
299 devfunc = device * 8 + func;
300
301 nbus = count_pnp_devices("PNP0A03");
302 for (i = 0; i < nbus; i++) {
303 dev = find_nth_pnp_device("PNP0A03", 0, i);
304 busacc = &dev->BusAccess;
305 l = be32toh(dev->AllocatedOffset);
306 p = res->DevicePnPHeap + l;
307 if (p == NULL)
308 return;
309 if (busacc->PCIAccess.BusNumber == bus &&
310 busacc->PCIAccess.DevFuncNumber == devfunc) {
311 found++;
312 break;
313 }
314 }
315 if (!found) {
316 aprint_error("Couldn't find PNP data for bus %d devfunc 0x%x\n",
317 bus, devfunc);
318 return;
319 }
320 /* p, l and dev should be valid now */
321
322 /* count the number of PCI device slots on the bus */
323 for (; p[0] != END_TAG; p += size) {
324 if (tag_type(p[0]) == PNP_SMALL)
325 size = pnp_small_pkt(p);
326 else
327 size = count_pnp_pci_devices(p, &nrofpcidevs);
328 }
329 dict = prop_dictionary_create_with_capacity(nrofpcidevs*2);
330 KASSERT(dict != NULL);
331
332 prop_dictionary_set(pbi->pbi_properties, "prep-pci-intrmap", dict);
333
334 /* reset p */
335 p = res->DevicePnPHeap + l;
336 /* now we've created the dictionary, loop again and add the sub-dicts */
337 for (; p[0] != END_TAG; p += size) {
338 if (tag_type(p[0]) == PNP_SMALL)
339 size = pnp_small_pkt(p);
340 else
341 size = create_intr_map(p, dict);
342 }
343 prop_object_release(dict);
344 }
345
346
347 /*
348 * Some platforms have invalid or insufficient PCI routing information
349 * in the residual. Check the quirk table and if we find one, call it.
350 */
351
352 void
setup_pciroutinginfo(void)353 setup_pciroutinginfo(void)
354 {
355 int i;
356
357 i = find_platform_quirk(res->VitalProductData.PrintableModel);
358 if (i == -1)
359 return;
360 if (platform_quirks[i].quirk & PLAT_QUIRK_INTRFIXUP &&
361 platform_quirks[i].pci_intr_fixup != NULL)
362 (*platform_quirks[i].pci_intr_fixup)();
363 }
364