xref: /openbsd-src/sys/arch/macppc/pci/mpcpcibus.c (revision 89ed722c33692ad18452b9d394c650f8adc43407)
1*89ed722cSmpi /*	$OpenBSD: mpcpcibus.c,v 1.49 2022/03/13 12:33:01 mpi Exp $ */
2a3667f10Sdrahn 
3a3667f10Sdrahn /*
4a3667f10Sdrahn  * Copyright (c) 1997 Per Fogelstrom
5a3667f10Sdrahn  *
6a3667f10Sdrahn  * Redistribution and use in source and binary forms, with or without
7a3667f10Sdrahn  * modification, are permitted provided that the following conditions
8a3667f10Sdrahn  * are met:
9a3667f10Sdrahn  * 1. Redistributions of source code must retain the above copyright
10a3667f10Sdrahn  *    notice, this list of conditions and the following disclaimer.
11a3667f10Sdrahn  * 2. Redistributions in binary form must reproduce the above copyright
12a3667f10Sdrahn  *    notice, this list of conditions and the following disclaimer in the
13a3667f10Sdrahn  *    documentation and/or other materials provided with the distribution.
14a3667f10Sdrahn  *
15a3667f10Sdrahn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16a3667f10Sdrahn  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17a3667f10Sdrahn  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18a3667f10Sdrahn  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19a3667f10Sdrahn  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20a3667f10Sdrahn  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21a3667f10Sdrahn  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22a3667f10Sdrahn  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23a3667f10Sdrahn  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24a3667f10Sdrahn  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25a3667f10Sdrahn  * SUCH DAMAGE.
26a3667f10Sdrahn  *
27a3667f10Sdrahn  */
28a3667f10Sdrahn 
29a3667f10Sdrahn #include <sys/param.h>
30a3667f10Sdrahn #include <sys/systm.h>
31a3667f10Sdrahn #include <sys/device.h>
32d223becfSmpi #include <sys/malloc.h>
33d223becfSmpi #include <sys/extent.h>
34a3667f10Sdrahn 
35a3667f10Sdrahn #include <machine/autoconf.h>
36020ac846Sdrahn #include <machine/pcb.h>
37a3667f10Sdrahn 
38a3667f10Sdrahn #include <dev/pci/pcireg.h>
39a3667f10Sdrahn #include <dev/pci/pcivar.h>
40a3667f10Sdrahn #include <dev/pci/pcidevs.h>
41a3667f10Sdrahn 
42a3667f10Sdrahn #include <dev/ofw/openfirm.h>
43a3667f10Sdrahn 
44c4071fd1Smillert int	mpcpcibrmatch(struct device *, void *, void *);
45c4071fd1Smillert void	mpcpcibrattach(struct device *, struct device *, void *);
46a3667f10Sdrahn 
47c4071fd1Smillert pcireg_t mpc_conf_read(void *, pcitag_t, int);
48c4071fd1Smillert void	mpc_conf_write(void *, pcitag_t, int, pcireg_t);
49a3667f10Sdrahn 
50c4071fd1Smillert u_int32_t mpc_gen_config_reg(void *cpv, pcitag_t tag, int offset);
51601244bbSdrahn 
52d223becfSmpi struct pcibr_config {
53d223becfSmpi 	bus_space_tag_t		lc_memt;
54d223becfSmpi 	bus_space_tag_t		lc_iot;
55d223becfSmpi 	bus_space_handle_t	ioh_cf8;
56d223becfSmpi 	bus_space_handle_t	ioh_cfc;
57d223becfSmpi 	struct ppc_pci_chipset	lc_pc;
58d223becfSmpi 	int			config_type;
59d223becfSmpi };
60d223becfSmpi 
61d223becfSmpi struct pcibr_softc {
62d223becfSmpi 	struct device		sc_dev;
63d223becfSmpi 	struct ppc_bus_space	sc_membus_space;
64d223becfSmpi 	struct ppc_bus_space	sc_iobus_space;
65d223becfSmpi 	struct pcibr_config	pcibr_config;
66d223becfSmpi 	struct extent 		*sc_ioex;
67d223becfSmpi 	struct extent		*sc_memex;
68d223becfSmpi 	char			sc_ioex_name[32];
69d223becfSmpi 	char			sc_memex_name[32];
70d223becfSmpi };
71d223becfSmpi 
72*89ed722cSmpi const struct cfattach mpcpcibr_ca = {
73a3667f10Sdrahn         sizeof(struct pcibr_softc), mpcpcibrmatch, mpcpcibrattach,
74a3667f10Sdrahn };
75a3667f10Sdrahn 
76a3667f10Sdrahn struct cfdriver mpcpcibr_cd = {
77a3667f10Sdrahn 	NULL, "mpcpcibr", DV_DULL,
78a3667f10Sdrahn };
79a3667f10Sdrahn 
80c4071fd1Smillert static int      mpcpcibrprint(void *, const char *pnp);
81a3667f10Sdrahn 
82e90f5639Skettenis void	mpcpcibus_find_ranges_32(struct pcibr_softc *, u_int32_t *, int);
83e90f5639Skettenis void	mpcpcibus_find_ranges_64(struct pcibr_softc *, u_int32_t *, int);
84e90f5639Skettenis 
85a3667f10Sdrahn /*
86a3667f10Sdrahn  * config types
87a3667f10Sdrahn  * bit meanings
88a3667f10Sdrahn  * 0 - standard cf8/cfc type configurations,
89a3667f10Sdrahn  *     sometimes the base addresses for these are different
90a3667f10Sdrahn  * 1 - Config Method #2 configuration - uni-north
91a3667f10Sdrahn  *
92a3667f10Sdrahn  * 2 - 64 bit config bus, data for accesses &4 is at daddr+4;
93a3667f10Sdrahn  */
947caa0606Sdrahn struct config_type{
95a3667f10Sdrahn 	char * compat;
96a3667f10Sdrahn 	u_int32_t addr;	/* offset */
97a3667f10Sdrahn 	u_int32_t data;	/* offset */
98a3667f10Sdrahn 	int config_type;
997caa0606Sdrahn };
1007caa0606Sdrahn struct config_type config_offsets[] = {
101a3667f10Sdrahn 	{"grackle",		0x00c00cf8, 0x00e00cfc, 0 },
102ac780239Sgwk 	{"bandit",		0x00800000, 0x00c00000, 1 },
103a3667f10Sdrahn 	{"uni-north",		0x00800000, 0x00c00000, 3 },
1047caa0606Sdrahn 	{"u3-agp",		0x00800000, 0x00c00000, 3 },
1057caa0606Sdrahn 	{"u3-ht",		0x00000cf8, 0x00000cfc, 3 },
106f6cf1346Smpi 	{"u4-pcie",		0x00800000, 0x00c00000, 7 },
107a3667f10Sdrahn 	{"legacy",		0x00000cf8, 0x00000cfc, 0 },
108a3667f10Sdrahn 	{"IBM,27-82660",	0x00000cf8, 0x00000cfc, 0 },
109a3667f10Sdrahn 	{NULL,			0x00000000, 0x00000000, 0 },
110a3667f10Sdrahn };
111a3667f10Sdrahn 
112a3667f10Sdrahn int
mpcpcibrmatch(struct device * parent,void * match,void * aux)113601244bbSdrahn mpcpcibrmatch(struct device *parent, void *match, void *aux)
114a3667f10Sdrahn {
115a3667f10Sdrahn 	struct confargs *ca = aux;
116a3667f10Sdrahn 	int found = 0;
117a3667f10Sdrahn 
118a3667f10Sdrahn 	if (strcmp(ca->ca_name, mpcpcibr_cd.cd_name) != 0)
119a3667f10Sdrahn 		return (found);
120a3667f10Sdrahn 
121a3667f10Sdrahn 	found = 1;
1226a1aaa0fSderaadt 
123a3667f10Sdrahn 	return found;
124a3667f10Sdrahn }
125a3667f10Sdrahn 
1267caa0606Sdrahn struct ranges_32 {
127e90f5639Skettenis 	u_int32_t cspace;
128e90f5639Skettenis 	u_int32_t child_hi;
129e90f5639Skettenis 	u_int32_t child_lo;
130e90f5639Skettenis 	u_int32_t phys;
131e90f5639Skettenis 	u_int32_t size_hi;
132e90f5639Skettenis 	u_int32_t size_lo;
133a3667f10Sdrahn };
134e90f5639Skettenis 
1357caa0606Sdrahn void
mpcpcibus_find_ranges_32(struct pcibr_softc * sc,u_int32_t * range_store,int rangesize)1367caa0606Sdrahn mpcpcibus_find_ranges_32(struct pcibr_softc *sc, u_int32_t *range_store,
1377caa0606Sdrahn     int rangesize)
138a3667f10Sdrahn {
139e90f5639Skettenis 	int i, found;
140a3667f10Sdrahn 	unsigned int base = 0;
141a3667f10Sdrahn 	unsigned int size = 0;
1427caa0606Sdrahn 	struct ranges_32 *prange = (void *)range_store;
1437caa0606Sdrahn 	int rangelen;
1447caa0606Sdrahn 
1457caa0606Sdrahn 	rangelen = rangesize / sizeof(struct ranges_32);
146a3667f10Sdrahn 
147a3667f10Sdrahn 	/* mac configs */
148a3667f10Sdrahn 	sc->sc_membus_space.bus_base = 0;
1495ae7b674Sdrahn 	sc->sc_membus_space.bus_io = 0;
150a3667f10Sdrahn 	sc->sc_iobus_space.bus_base = 0;
1515ae7b674Sdrahn 	sc->sc_iobus_space.bus_io = 1;
152a3667f10Sdrahn 
153a3667f10Sdrahn 	/* find io(config) base, flag == 0x01000000 */
154a3667f10Sdrahn 	found = 0;
155601244bbSdrahn 	for (i = 0; i < rangelen; i++) {
156e90f5639Skettenis 		if (prange[i].cspace == 0x01000000) {
157a3667f10Sdrahn 			/* find last? */
158a3667f10Sdrahn 			found = i;
159e90f5639Skettenis 
160e90f5639Skettenis 			if (sc->sc_ioex)
161e90f5639Skettenis 				extent_free(sc->sc_ioex, prange[i].child_lo,
162e90f5639Skettenis 				    prange[i].size_lo, EX_NOWAIT);
163a3667f10Sdrahn 		}
164a3667f10Sdrahn 	}
165a3667f10Sdrahn 	/* found the io space ranges */
166e90f5639Skettenis 	if (prange[found].cspace == 0x01000000) {
167e90f5639Skettenis 		sc->sc_iobus_space.bus_base = prange[found].phys;
168e90f5639Skettenis 		sc->sc_iobus_space.bus_size = prange[found].size_lo;
169a3667f10Sdrahn 	}
170a3667f10Sdrahn 
171a3667f10Sdrahn 	/* the mem space ranges
172a3667f10Sdrahn 	 * apple openfirmware always puts full
173a3667f10Sdrahn 	 * addresses in config information,
174a3667f10Sdrahn 	 * it is not necessary to have correct bus
175a3667f10Sdrahn 	 * base address, but since 0 is reserved
176a3667f10Sdrahn 	 * and all IO and device memory will be in
177a3667f10Sdrahn 	 * upper 2G of address space, set to
178a3667f10Sdrahn 	 * 0x80000000
179a3667f10Sdrahn 	 */
180601244bbSdrahn 	for (i = 0; i < rangelen; i++) {
181e90f5639Skettenis 		if (prange[i].cspace == 0x02000000) {
1827caa0606Sdrahn #ifdef DEBUG_PCI
183a3667f10Sdrahn 			printf("\nfound mem %x %x",
184e90f5639Skettenis 				prange[i].phys,
185e90f5639Skettenis 				prange[i].size_lo);
186a3667f10Sdrahn #endif
187a3667f10Sdrahn 			if (base != 0) {
188e90f5639Skettenis 				if ((base + size) == prange[i].phys)
189e90f5639Skettenis 					size += prange[i].size_lo;
1900e4a72beSgwk 				else {
191e90f5639Skettenis 					base = prange[i].phys;
192e90f5639Skettenis 					size = prange[i].size_lo;
193a3667f10Sdrahn 				}
194a3667f10Sdrahn 			} else {
195e90f5639Skettenis 				base = prange[i].phys;
196e90f5639Skettenis 				size = prange[i].size_lo;
197a3667f10Sdrahn 			}
198e90f5639Skettenis 
199e90f5639Skettenis 			if (sc->sc_memex)
200e90f5639Skettenis 				extent_free(sc->sc_memex, prange[i].child_lo,
201e90f5639Skettenis 				    prange[i].size_lo, EX_NOWAIT);
202a3667f10Sdrahn 		}
203a3667f10Sdrahn 	}
204a3667f10Sdrahn 	sc->sc_membus_space.bus_base = base;
205a3667f10Sdrahn 	sc->sc_membus_space.bus_size = size;
206a3667f10Sdrahn }
2077caa0606Sdrahn 
2087caa0606Sdrahn struct ranges_64 {
209e90f5639Skettenis 	u_int32_t cspace;
210e90f5639Skettenis 	u_int32_t child_hi;
211e90f5639Skettenis 	u_int32_t child_lo;
212e90f5639Skettenis 	u_int32_t phys_hi;
213e90f5639Skettenis 	u_int32_t phys_lo;
214e90f5639Skettenis 	u_int32_t size_hi;
215e90f5639Skettenis 	u_int32_t size_lo;
2167caa0606Sdrahn };
217e90f5639Skettenis 
2187caa0606Sdrahn void
mpcpcibus_find_ranges_64(struct pcibr_softc * sc,u_int32_t * range_store,int rangesize)2197caa0606Sdrahn mpcpcibus_find_ranges_64(struct pcibr_softc *sc, u_int32_t *range_store,
2207caa0606Sdrahn     int rangesize)
2217caa0606Sdrahn {
2227caa0606Sdrahn 	int i, found;
2237caa0606Sdrahn 	unsigned int base = 0;
2247caa0606Sdrahn 	unsigned int size = 0;
2257caa0606Sdrahn 	struct ranges_64 *prange = (void *)range_store;
226e90f5639Skettenis 	int rangelen;
2277caa0606Sdrahn 
2287caa0606Sdrahn 	rangelen = rangesize / sizeof(struct ranges_64);
2297caa0606Sdrahn 
2307caa0606Sdrahn 	/* mac configs */
2317caa0606Sdrahn 	sc->sc_membus_space.bus_base = 0;
2327caa0606Sdrahn 	sc->sc_membus_space.bus_io = 0;
2337caa0606Sdrahn 	sc->sc_iobus_space.bus_base = 0;
2347caa0606Sdrahn 	sc->sc_iobus_space.bus_io = 1;
2357caa0606Sdrahn 
236e90f5639Skettenis 	if (prange[0].cspace == 0xabb10113) { /* appl U3; */
237e90f5639Skettenis 		prange[0].cspace = 0x01000000;
238e90f5639Skettenis 		prange[0].child_lo = 0x00000000;
239e90f5639Skettenis 		prange[0].phys_lo = 0xf8070000;
240e90f5639Skettenis 		prange[0].size_lo = 0x00001000;
241e90f5639Skettenis 		prange[1].cspace = 0x02000000;
242e90f5639Skettenis 		prange[1].child_lo = 0xf2000000;
243e90f5639Skettenis 		prange[1].phys_lo = 0xf2000000;
244e90f5639Skettenis 		prange[1].size_lo = 0x02800000;
2457caa0606Sdrahn 		rangelen = 2;
2467caa0606Sdrahn 	}
2477caa0606Sdrahn 
2487caa0606Sdrahn 	/* find io(config) base, flag == 0x01000000 */
2497caa0606Sdrahn 	found = 0;
2507caa0606Sdrahn 	for (i = 0; i < rangelen; i++) {
251e90f5639Skettenis 		if (prange[i].cspace == 0x01000000) {
2527caa0606Sdrahn 			/* find last? */
2537caa0606Sdrahn 			found = i;
254e90f5639Skettenis 
255e90f5639Skettenis 			if (sc->sc_ioex)
256e90f5639Skettenis 				extent_free(sc->sc_ioex, prange[i].child_lo,
257e90f5639Skettenis 				    prange[i].size_lo, EX_NOWAIT);
2587caa0606Sdrahn 		}
2597caa0606Sdrahn 	}
2607caa0606Sdrahn 	/* found the io space ranges */
261e90f5639Skettenis 	if (prange[found].cspace == 0x01000000) {
262e90f5639Skettenis 		sc->sc_iobus_space.bus_base = prange[found].phys_lo;
263e90f5639Skettenis 		sc->sc_iobus_space.bus_size = prange[found].size_lo;
2647caa0606Sdrahn 	}
2657caa0606Sdrahn 
2667caa0606Sdrahn 	/* the mem space ranges
2677caa0606Sdrahn 	 * apple openfirmware always puts full
2687caa0606Sdrahn 	 * addresses in config information,
2697caa0606Sdrahn 	 * it is not necessary to have correct bus
2707caa0606Sdrahn 	 * base address, but since 0 is reserved
2717caa0606Sdrahn 	 * and all IO and device memory will be in
2727caa0606Sdrahn 	 * upper 2G of address space, set to
2737caa0606Sdrahn 	 * 0x80000000
2747caa0606Sdrahn 	 */
2757caa0606Sdrahn 	for (i = 0; i < rangelen; i++) {
276e90f5639Skettenis 		if (prange[i].cspace == 0x02000000) {
2777caa0606Sdrahn #ifdef DEBUG_PCI
2787caa0606Sdrahn 			printf("\nfound mem %x %x",
279e90f5639Skettenis 				prange[i].phys_lo,
280e90f5639Skettenis 				prange[i].size_lo);
2817caa0606Sdrahn #endif
2827caa0606Sdrahn 			if (base != 0) {
283e90f5639Skettenis 				if ((base + size) == prange[i].phys_lo) {
284e90f5639Skettenis 					size += prange[i].size_lo;
2857caa0606Sdrahn 				} else {
286e90f5639Skettenis 					base = prange[i].phys_lo;
287e90f5639Skettenis 					size = prange[i].size_lo;
2887caa0606Sdrahn 				}
2897caa0606Sdrahn 			} else {
290e90f5639Skettenis 				base = prange[i].phys_lo;
291e90f5639Skettenis 				size = prange[i].size_lo;
2927caa0606Sdrahn 			}
293e90f5639Skettenis 
294e90f5639Skettenis 			if (sc->sc_memex)
295e90f5639Skettenis 				extent_free(sc->sc_memex, prange[i].child_lo,
296e90f5639Skettenis 				    prange[i].size_lo, EX_NOWAIT);
2977caa0606Sdrahn 		}
2987caa0606Sdrahn 	}
2997caa0606Sdrahn 	sc->sc_membus_space.bus_base = base;
3007caa0606Sdrahn 	sc->sc_membus_space.bus_size = size;
3017caa0606Sdrahn }
3027caa0606Sdrahn 
3037caa0606Sdrahn void
mpcpcibrattach(struct device * parent,struct device * self,void * aux)3047caa0606Sdrahn mpcpcibrattach(struct device *parent, struct device *self, void *aux)
3057caa0606Sdrahn {
3067caa0606Sdrahn 	struct pcibr_softc *sc = (struct pcibr_softc *)self;
3077caa0606Sdrahn 	struct confargs *ca = aux;
3087caa0606Sdrahn 	struct pcibr_config *lcp;
3097caa0606Sdrahn 	struct pcibus_attach_args pba;
3107caa0606Sdrahn 	char compat[32];
3117caa0606Sdrahn 	u_int32_t addr_offset;
3127caa0606Sdrahn 	u_int32_t data_offset;
3137caa0606Sdrahn 	int i;
3147caa0606Sdrahn 	int len;
3157caa0606Sdrahn 	int rangesize;
3167caa0606Sdrahn 	u_int32_t range_store[32];
3173e0aa7ecSmiod 	int busrange[2];
3187caa0606Sdrahn 
3197caa0606Sdrahn 	if (ca->ca_node == 0) {
3207caa0606Sdrahn 		printf("invalid node on mpcpcibr config\n");
3217caa0606Sdrahn 		return;
3227caa0606Sdrahn 	}
3237caa0606Sdrahn 	len = OF_getprop(ca->ca_node, "name", compat, sizeof(compat));
3247caa0606Sdrahn 	compat[len] = '\0';
3257caa0606Sdrahn 	if (len > 0)
3267caa0606Sdrahn 		printf(" %s", compat);
3277caa0606Sdrahn 
3283e0aa7ecSmiod 	len = OF_getprop(ca->ca_node, "compatible", compat, sizeof(compat));
3297caa0606Sdrahn 	if (len <= 0) {
3303e0aa7ecSmiod 		len = OF_getprop(ca->ca_node, "name", compat, sizeof(compat));
3317caa0606Sdrahn 		if (len <= 0) {
3327caa0606Sdrahn 			printf(" compatible and name not found\n");
3337caa0606Sdrahn 			return;
3347caa0606Sdrahn 		}
3357caa0606Sdrahn 		compat[len] = 0;
3367caa0606Sdrahn 		if (strcmp(compat, "bandit") != 0) {
3377caa0606Sdrahn 			printf(" compatible not found and name %s found\n",
3387caa0606Sdrahn 			    compat);
3397caa0606Sdrahn 			return;
3407caa0606Sdrahn 		}
3417caa0606Sdrahn 	}
3427caa0606Sdrahn 	compat[len] = 0;
3437caa0606Sdrahn 	if ((rangesize = OF_getprop(ca->ca_node, "ranges",
3447caa0606Sdrahn 	    range_store, sizeof (range_store))) <= 0) {
3457caa0606Sdrahn 		if (strcmp(compat, "u3-ht") == 0) {
3467caa0606Sdrahn 			range_store[0] = 0xabb10113; /* appl U3; */
3477caa0606Sdrahn 		} else
3487caa0606Sdrahn 			printf("range lookup failed, node %x\n", ca->ca_node);
3497caa0606Sdrahn 	}
3507caa0606Sdrahn 
351d223becfSmpi 	lcp = &sc->pcibr_config;
3527caa0606Sdrahn 
353e90f5639Skettenis 	snprintf(sc->sc_ioex_name, sizeof(sc->sc_ioex_name),
354e90f5639Skettenis 	    "%s pciio", sc->sc_dev.dv_xname);
355e90f5639Skettenis 	sc->sc_ioex = extent_create(sc->sc_ioex_name, 0x00000000, 0xffffffff,
356e90f5639Skettenis 	    M_DEVBUF, NULL, 0, EX_NOWAIT | EX_FILLED);
357e90f5639Skettenis 	snprintf(sc->sc_memex_name, sizeof(sc->sc_memex_name),
358e90f5639Skettenis 	    "%s pcimem", sc->sc_dev.dv_xname);
359e90f5639Skettenis 	sc->sc_memex = extent_create(sc->sc_memex_name, 0x00000000, 0xffffffff,
360e90f5639Skettenis 	    M_DEVBUF, NULL, 0, EX_NOWAIT | EX_FILLED);
361e90f5639Skettenis 
3627caa0606Sdrahn 	if (ppc_proc_is_64b)
3637caa0606Sdrahn 		mpcpcibus_find_ranges_64(sc, range_store, rangesize);
3647caa0606Sdrahn 	else
3657caa0606Sdrahn 		mpcpcibus_find_ranges_32(sc, range_store, rangesize);
3667caa0606Sdrahn 
367a3667f10Sdrahn 	addr_offset = 0;
368a3667f10Sdrahn 	for (i = 0; config_offsets[i].compat != NULL; i++) {
3697caa0606Sdrahn 		struct config_type *co = &config_offsets[i];
3707caa0606Sdrahn 		if (strcmp(co->compat, compat) == 0) {
3717caa0606Sdrahn 			addr_offset = co->addr;
3727caa0606Sdrahn 			data_offset = co->data;
3737caa0606Sdrahn 			lcp->config_type = co->config_type;
374a3667f10Sdrahn 			break;
375a3667f10Sdrahn 		}
376a3667f10Sdrahn 	}
377a3667f10Sdrahn 	if (addr_offset == 0) {
378a3667f10Sdrahn 		printf("unable to find match for"
379a3667f10Sdrahn 		    " compatible %s\n", compat);
380a3667f10Sdrahn 		return;
381a3667f10Sdrahn 	}
38272ad3cd4Sdrahn #ifdef DEBUG_FIXUP
383601244bbSdrahn 	printf(" mem base %x sz %x io base %x sz %x\n"
384601244bbSdrahn 	    " config addr %x config data %x\n",
385a3667f10Sdrahn 	    sc->sc_membus_space.bus_base,
386a3667f10Sdrahn 	    sc->sc_membus_space.bus_size,
387a3667f10Sdrahn 	    sc->sc_iobus_space.bus_base,
388a3667f10Sdrahn 	    sc->sc_iobus_space.bus_size,
389a3667f10Sdrahn 	    addr_offset, data_offset);
390a3667f10Sdrahn #endif
391a3667f10Sdrahn 
392a3667f10Sdrahn 	if (bus_space_map(&(sc->sc_iobus_space), addr_offset,
3936a1aaa0fSderaadt 		NBPG, 0, &lcp->ioh_cf8) != 0)
394bc84bce2Skrw 		panic("mpcpcibus: unable to map self");
395601244bbSdrahn 
396a3667f10Sdrahn 	if (bus_space_map(&(sc->sc_iobus_space), data_offset,
3976a1aaa0fSderaadt 		NBPG, 0, &lcp->ioh_cfc) != 0)
398bc84bce2Skrw 		panic("mpcpcibus: unable to map self");
399a3667f10Sdrahn 
400a3667f10Sdrahn 	lcp->lc_pc.pc_conf_v = lcp;
4012d3c312aSmpi 	lcp->lc_pc.pc_node = ca->ca_node;
402a3667f10Sdrahn 	lcp->lc_pc.pc_conf_read = mpc_conf_read;
403a3667f10Sdrahn 	lcp->lc_pc.pc_conf_write = mpc_conf_write;
404a3667f10Sdrahn 	lcp->lc_iot = &sc->sc_iobus_space;
405a3667f10Sdrahn 	lcp->lc_memt = &sc->sc_membus_space;
406a3667f10Sdrahn 
4076d211ebcSmpi 	printf(": %s\n", compat);
408a3667f10Sdrahn 
4094eb8f200Skettenis 	bzero(&pba, sizeof(pba));
410a3667f10Sdrahn 	pba.pba_dmat = &pci_bus_dma_tag;
411a3667f10Sdrahn 
412a3667f10Sdrahn 	pba.pba_busname = "pci";
413a3667f10Sdrahn 	pba.pba_iot = &sc->sc_iobus_space;
414a3667f10Sdrahn 	pba.pba_memt = &sc->sc_membus_space;
415e90f5639Skettenis 	pba.pba_ioex = sc->sc_ioex;
416e90f5639Skettenis 	pba.pba_memex = sc->sc_memex;
417a3667f10Sdrahn 	pba.pba_pc = &lcp->lc_pc;
418d307f358Skettenis 	pba.pba_domain = pci_ndomains++;
4193e0aa7ecSmiod 	if (OF_getprop(ca->ca_node, "bus-range", &busrange, sizeof(busrange)) <
4203e0aa7ecSmiod 	    0)
421a3667f10Sdrahn 		pba.pba_bus = 0;
4223e0aa7ecSmiod 	else
4233e0aa7ecSmiod 		pba.pba_bus = busrange[0];
424a3667f10Sdrahn 
425a3667f10Sdrahn 	config_found(self, &pba, mpcpcibrprint);
426a3667f10Sdrahn }
427a3667f10Sdrahn 
428a3667f10Sdrahn static int
mpcpcibrprint(void * aux,const char * pnp)429601244bbSdrahn mpcpcibrprint(void *aux, const char *pnp)
430a3667f10Sdrahn {
431a3667f10Sdrahn 	struct pcibus_attach_args *pba = aux;
432a3667f10Sdrahn 
433a3667f10Sdrahn 	if (pnp)
434a3667f10Sdrahn 		printf("%s at %s", pba->pba_busname, pnp);
435a3667f10Sdrahn 	printf(" bus %d", pba->pba_bus);
436a3667f10Sdrahn 	return(UNCONF);
437a3667f10Sdrahn }
438a3667f10Sdrahn 
439a3667f10Sdrahn u_int32_t
mpc_gen_config_reg(void * cpv,pcitag_t tag,int offset)440601244bbSdrahn mpc_gen_config_reg(void *cpv, pcitag_t tag, int offset)
441a3667f10Sdrahn {
442a3667f10Sdrahn 	struct pcibr_config *cp = cpv;
443a3667f10Sdrahn 	unsigned int bus, dev, fcn;
4442d3c312aSmpi 	u_int32_t reg, val = PCITAG_OFFSET(tag);
445a3667f10Sdrahn 
4462d3c312aSmpi 	pci_decompose_tag(cpv, tag, &bus, &dev, &fcn);
447a3667f10Sdrahn 
448f6cf1346Smpi 	if (cp->config_type & 4) {
449f6cf1346Smpi 		reg = val | offset | 1;
450f6cf1346Smpi 		reg |= (offset >> 8) << 28;
451f6cf1346Smpi 	} else if (cp->config_type & 1) {
452a3667f10Sdrahn 		/* Config Mechanism #2 */
453a3667f10Sdrahn 		if (bus == 0) {
454601244bbSdrahn 			if (dev < 11)
455a3667f10Sdrahn 				return 0xffffffff;
456a3667f10Sdrahn 			/*
457a3667f10Sdrahn 			 * Need to do config type 0 operation
458a3667f10Sdrahn 			 *  1 << (11?+dev) | fcn << 8 | reg
459a3667f10Sdrahn 			 * 11? is because pci spec states
460a3667f10Sdrahn 			 * that 11-15 is reserved.
461a3667f10Sdrahn 			 */
462a3667f10Sdrahn 			reg = 1 << (dev) | fcn << 8 | offset;
463a3667f10Sdrahn 		} else {
464601244bbSdrahn 			if (dev > 15)
465a3667f10Sdrahn 				return 0xffffffff;
466a3667f10Sdrahn 			/*
467a3667f10Sdrahn 			 * config type 1
468a3667f10Sdrahn 			 */
4692d3c312aSmpi 			reg = val | offset | 1;
470a3667f10Sdrahn 		}
471a3667f10Sdrahn 	} else {
472a3667f10Sdrahn 		/* config mechanism #2, type 0
473a3667f10Sdrahn 		 * standard cf8/cfc config
474a3667f10Sdrahn 		 */
4752d3c312aSmpi 		reg =  0x80000000 | val | offset;
476a3667f10Sdrahn 	}
477ac780239Sgwk 
478a3667f10Sdrahn 	return reg;
479a3667f10Sdrahn }
480a3667f10Sdrahn 
481a3667f10Sdrahn /* #define DEBUG_CONFIG  */
482a3667f10Sdrahn pcireg_t
mpc_conf_read(void * cpv,pcitag_t tag,int offset)483601244bbSdrahn mpc_conf_read(void *cpv, pcitag_t tag, int offset)
484a3667f10Sdrahn {
485a3667f10Sdrahn 	struct pcibr_config *cp = cpv;
486a3667f10Sdrahn 	pcireg_t data;
487a3667f10Sdrahn 	u_int32_t reg;
488a3667f10Sdrahn 	int s;
489a3667f10Sdrahn 	int daddr = 0;
490020ac846Sdrahn 	faultbuf env;
491020ac846Sdrahn 	void *oldh;
492020ac846Sdrahn 
493b1926db3Smiod 	if (offset & 3 ||
494b1926db3Smiod 	    offset < 0 || offset >= PCI_CONFIG_SPACE_SIZE) {
495a3667f10Sdrahn #ifdef DEBUG_CONFIG
496a3667f10Sdrahn 		printf ("pci_conf_read: bad reg %x\n", offset);
497a3667f10Sdrahn #endif /* DEBUG_CONFIG */
498a3667f10Sdrahn 		return(~0);
499a3667f10Sdrahn 	}
500a3667f10Sdrahn 
501a3667f10Sdrahn 	reg = mpc_gen_config_reg(cpv, tag, offset);
502a3667f10Sdrahn 	/* if invalid tag, return -1 */
503601244bbSdrahn 	if (reg == 0xffffffff)
504e226fd9fSdrahn 		return(~0);
505a3667f10Sdrahn 
506601244bbSdrahn 	if ((cp->config_type & 2) && (offset & 0x04))
507a3667f10Sdrahn 		daddr += 4;
508a3667f10Sdrahn 
509a3667f10Sdrahn 	s = splhigh();
510a3667f10Sdrahn 
511020ac846Sdrahn 	oldh = curpcb->pcb_onfault;
5124140fb10Sdrahn 	if (setfault(&env)) {
513020ac846Sdrahn 		/* we faulted during the read? */
514020ac846Sdrahn 		curpcb->pcb_onfault = oldh;
515a1ec65acSmiod 		splx(s);
516020ac846Sdrahn 		return 0xffffffff;
517020ac846Sdrahn 	}
518020ac846Sdrahn 
519a3667f10Sdrahn 	bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, reg);
520a3667f10Sdrahn 	bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */
521a3667f10Sdrahn 	data = bus_space_read_4(cp->lc_iot, cp->ioh_cfc, daddr);
522a3667f10Sdrahn 	bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, 0); /* disable */
523a3667f10Sdrahn 	bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */
524a3667f10Sdrahn 
525020ac846Sdrahn 	curpcb->pcb_onfault = oldh;
526020ac846Sdrahn 
527a3667f10Sdrahn 	splx(s);
528a3667f10Sdrahn #ifdef DEBUG_CONFIG
529a3667f10Sdrahn 	if (!((offset == 0) && (data == 0xffffffff))) {
530a3667f10Sdrahn 		unsigned int bus, dev, fcn;
5312d3c312aSmpi 		pci_decompose_tag(cpv, tag, &bus, &dev, &fcn);
532a3667f10Sdrahn 		printf("mpc_conf_read bus %x dev %x fcn %x offset %x", bus, dev, fcn,
533a3667f10Sdrahn 			offset);
534a3667f10Sdrahn 		printf(" daddr %x reg %x",daddr, reg);
535a3667f10Sdrahn 		printf(" data %x\n", data);
536a3667f10Sdrahn 	}
537a3667f10Sdrahn #endif
538a3667f10Sdrahn 
539a3667f10Sdrahn 	return(data);
540a3667f10Sdrahn }
541a3667f10Sdrahn 
542a3667f10Sdrahn void
mpc_conf_write(void * cpv,pcitag_t tag,int offset,pcireg_t data)543601244bbSdrahn mpc_conf_write(void *cpv, pcitag_t tag, int offset, pcireg_t data)
544a3667f10Sdrahn {
545a3667f10Sdrahn 	struct pcibr_config *cp = cpv;
546a3667f10Sdrahn 	u_int32_t reg;
547a3667f10Sdrahn 	int s;
548a3667f10Sdrahn 	int daddr = 0;
549a3667f10Sdrahn 
550a3667f10Sdrahn 	reg = mpc_gen_config_reg(cpv, tag, offset);
551a3667f10Sdrahn 
552a3667f10Sdrahn 	/* if invalid tag, return ??? */
553601244bbSdrahn 	if (reg == 0xffffffff)
554a3667f10Sdrahn 		return;
555601244bbSdrahn 
556601244bbSdrahn 	if ((cp->config_type & 2) && (offset & 0x04))
557a3667f10Sdrahn 		daddr += 4;
558601244bbSdrahn 
559a3667f10Sdrahn #ifdef DEBUG_CONFIG
560a3667f10Sdrahn 	{
561a3667f10Sdrahn 		unsigned int bus, dev, fcn;
5622d3c312aSmpi 		pci_decompose_tag(cpv, tag, &bus, &dev, &fcn);
563a3667f10Sdrahn 		printf("mpc_conf_write bus %x dev %x fcn %x offset %x", bus,
564a3667f10Sdrahn 			dev, fcn, offset);
565a3667f10Sdrahn 		printf(" daddr %x reg %x",daddr, reg);
566a3667f10Sdrahn 		printf(" data %x\n", data);
567a3667f10Sdrahn 	}
568a3667f10Sdrahn #endif
569a3667f10Sdrahn 
570a3667f10Sdrahn 	s = splhigh();
571a3667f10Sdrahn 
572a3667f10Sdrahn 	bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, reg);
573a3667f10Sdrahn 	bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */
574a3667f10Sdrahn 	bus_space_write_4(cp->lc_iot, cp->ioh_cfc, daddr, data);
575a3667f10Sdrahn 	bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, 0); /* disable */
576a3667f10Sdrahn 	bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */
577a3667f10Sdrahn 
578a3667f10Sdrahn 	splx(s);
579a3667f10Sdrahn }
580