Home | History | Annotate | Line # | Download | only in prep
      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