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 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 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 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 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 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 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 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 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 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 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