uninorthpci.c revision 227843
1236769Sobrien/*-
2236769Sobrien * Copyright (C) 2002 Benno Rice.
3236769Sobrien * All rights reserved.
4236769Sobrien *
5236769Sobrien * Redistribution and use in source and binary forms, with or without
6236769Sobrien * modification, are permitted provided that the following conditions
7236769Sobrien * are met:
8236769Sobrien * 1. Redistributions of source code must retain the above copyright
9236769Sobrien *    notice, this list of conditions and the following disclaimer.
10236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright
11236769Sobrien *    notice, this list of conditions and the following disclaimer in the
12236769Sobrien *    documentation and/or other materials provided with the distribution.
13236769Sobrien *
14236769Sobrien * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
15236769Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16236769Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17236769Sobrien * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18236769Sobrien * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19236769Sobrien * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20236769Sobrien * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21236769Sobrien * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22236769Sobrien * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23236769Sobrien * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24236769Sobrien */
25236769Sobrien
26236769Sobrien#include <sys/cdefs.h>
27236769Sobrien__FBSDID("$FreeBSD: head/sys/powerpc/powermac/uninorthpci.c 227843 2011-11-22 21:28:20Z marius $");
28236769Sobrien
29236769Sobrien#include <sys/param.h>
30236769Sobrien#include <sys/systm.h>
31236769Sobrien#include <sys/module.h>
32236769Sobrien#include <sys/bus.h>
33236769Sobrien#include <sys/conf.h>
34236769Sobrien#include <sys/kernel.h>
35236769Sobrien
36236769Sobrien#include <dev/ofw/openfirm.h>
37236769Sobrien#include <dev/ofw/ofw_pci.h>
38236769Sobrien#include <dev/ofw/ofw_bus.h>
39236769Sobrien#include <dev/ofw/ofw_bus_subr.h>
40236769Sobrien
41236769Sobrien#include <dev/pci/pcivar.h>
42236769Sobrien#include <dev/pci/pcireg.h>
43236769Sobrien
44236769Sobrien#include <machine/bus.h>
45236769Sobrien#include <machine/intr_machdep.h>
46236769Sobrien#include <machine/md_var.h>
47236769Sobrien#include <machine/pio.h>
48236769Sobrien#include <machine/resource.h>
49236769Sobrien
50236769Sobrien#include <sys/rman.h>
51236769Sobrien
52236769Sobrien#include <powerpc/powermac/uninorthvar.h>
53236769Sobrien
54236769Sobrien#include <vm/vm.h>
55236769Sobrien#include <vm/pmap.h>
56236769Sobrien
57236769Sobrien#include "pcib_if.h"
58236769Sobrien
59236769Sobrien#define	UNINORTH_DEBUG	0
60236769Sobrien
61236769Sobrien/*
62236769Sobrien * Device interface.
63236769Sobrien */
64236769Sobrienstatic int		uninorth_probe(device_t);
65236769Sobrienstatic int		uninorth_attach(device_t);
66236769Sobrien
67236769Sobrien/*
68236769Sobrien * Bus interface.
69236769Sobrien */
70236769Sobrienstatic int		uninorth_read_ivar(device_t, device_t, int,
71236769Sobrien			    uintptr_t *);
72236769Sobrienstatic struct		resource * uninorth_alloc_resource(device_t bus,
73236769Sobrien			    device_t child, int type, int *rid, u_long start,
74236769Sobrien			    u_long end, u_long count, u_int flags);
75236769Sobrienstatic int		uninorth_activate_resource(device_t bus, device_t child,
76236769Sobrien			    int type, int rid, struct resource *res);
77236769Sobrien
78236769Sobrien/*
79236769Sobrien * pcib interface.
80236769Sobrien */
81236769Sobrienstatic int		uninorth_maxslots(device_t);
82236769Sobrienstatic u_int32_t	uninorth_read_config(device_t, u_int, u_int, u_int,
83236769Sobrien			    u_int, int);
84236769Sobrienstatic void		uninorth_write_config(device_t, u_int, u_int, u_int,
85236769Sobrien			    u_int, u_int32_t, int);
86236769Sobrienstatic int		uninorth_route_interrupt(device_t, device_t, int);
87236769Sobrien
88236769Sobrien/*
89236769Sobrien * OFW Bus interface
90236769Sobrien */
91236769Sobrien
92236769Sobrienstatic phandle_t	 uninorth_get_node(device_t bus, device_t dev);
93236769Sobrien
94236769Sobrien/*
95236769Sobrien * Local routines.
96236769Sobrien */
97236769Sobrienstatic int		uninorth_enable_config(struct uninorth_softc *, u_int,
98236769Sobrien			    u_int, u_int, u_int);
99236769Sobrien
100236769Sobrien/*
101236769Sobrien * Driver methods.
102236769Sobrien */
103236769Sobrienstatic device_method_t	uninorth_methods[] = {
104236769Sobrien	/* Device interface */
105236769Sobrien	DEVMETHOD(device_probe,		uninorth_probe),
106236769Sobrien	DEVMETHOD(device_attach,	uninorth_attach),
107236769Sobrien
108236769Sobrien	/* Bus interface */
109236769Sobrien	DEVMETHOD(bus_read_ivar,	uninorth_read_ivar),
110236769Sobrien	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
111236769Sobrien	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
112236769Sobrien	DEVMETHOD(bus_alloc_resource,	uninorth_alloc_resource),
113236769Sobrien	DEVMETHOD(bus_activate_resource,	uninorth_activate_resource),
114236769Sobrien
115236769Sobrien	/* pcib interface */
116236769Sobrien	DEVMETHOD(pcib_maxslots,	uninorth_maxslots),
117236769Sobrien	DEVMETHOD(pcib_read_config,	uninorth_read_config),
118236769Sobrien	DEVMETHOD(pcib_write_config,	uninorth_write_config),
119236769Sobrien	DEVMETHOD(pcib_route_interrupt,	uninorth_route_interrupt),
120236769Sobrien
121236769Sobrien	/* ofw_bus interface */
122236769Sobrien	DEVMETHOD(ofw_bus_get_node,     uninorth_get_node),
123236769Sobrien
124236769Sobrien	DEVMETHOD_END
125236769Sobrien};
126236769Sobrien
127236769Sobrienstatic driver_t	uninorth_driver = {
128236769Sobrien	"pcib",
129236769Sobrien	uninorth_methods,
130236769Sobrien	sizeof(struct uninorth_softc)
131236769Sobrien};
132236769Sobrien
133236769Sobrienstatic devclass_t	uninorth_devclass;
134236769Sobrien
135236769SobrienDRIVER_MODULE(uninorth, nexus, uninorth_driver, uninorth_devclass, 0, 0);
136236769Sobrien
137236769Sobrienstatic int
138236769Sobrienuninorth_probe(device_t dev)
139236769Sobrien{
140236769Sobrien	const char	*type, *compatible;
141236769Sobrien
142236769Sobrien	type = ofw_bus_get_type(dev);
143236769Sobrien	compatible = ofw_bus_get_compat(dev);
144236769Sobrien
145236769Sobrien	if (type == NULL || compatible == NULL)
146236769Sobrien		return (ENXIO);
147236769Sobrien
148236769Sobrien	if (strcmp(type, "pci") != 0)
149236769Sobrien		return (ENXIO);
150236769Sobrien
151236769Sobrien	if (strcmp(compatible, "uni-north") == 0) {
152236769Sobrien		device_set_desc(dev, "Apple UniNorth Host-PCI bridge");
153236769Sobrien		return (0);
154236769Sobrien	} else if (strcmp(compatible, "u3-agp") == 0) {
155236769Sobrien		device_set_desc(dev, "Apple U3 Host-AGP bridge");
156236769Sobrien		return (0);
157236769Sobrien	} else if (strcmp(compatible, "u4-pcie") == 0) {
158236769Sobrien		device_set_desc(dev, "IBM CPC945 PCI Express Root");
159236769Sobrien		return (0);
160236769Sobrien	}
161236769Sobrien
162236769Sobrien	return (ENXIO);
163236769Sobrien}
164236769Sobrien
165236769Sobrienstatic int
166236769Sobrienuninorth_attach(device_t dev)
167236769Sobrien{
168236769Sobrien	struct		uninorth_softc *sc;
169236769Sobrien	const char	*compatible;
170236769Sobrien	phandle_t	node;
171236769Sobrien	u_int32_t	reg[3], busrange[2];
172236769Sobrien	struct		uninorth_range *rp, *io, *mem[2];
173236769Sobrien	int		nmem, i, error;
174236769Sobrien
175236769Sobrien	node = ofw_bus_get_node(dev);
176236769Sobrien	sc = device_get_softc(dev);
177236769Sobrien
178236769Sobrien	if (OF_getprop(node, "reg", reg, sizeof(reg)) < 8)
179236769Sobrien		return (ENXIO);
180236769Sobrien
181236769Sobrien	if (OF_getprop(node, "bus-range", busrange, sizeof(busrange)) != 8)
182236769Sobrien		return (ENXIO);
183236769Sobrien
184236769Sobrien	sc->sc_ver = 0;
185236769Sobrien	compatible = ofw_bus_get_compat(dev);
186236769Sobrien	if (strcmp(compatible, "u3-agp") == 0)
187236769Sobrien		sc->sc_ver = 3;
188236769Sobrien	if (strcmp(compatible, "u4-pcie") == 0)
189236769Sobrien		sc->sc_ver = 4;
190236769Sobrien
191236769Sobrien	sc->sc_dev = dev;
192236769Sobrien	sc->sc_node = node;
193236769Sobrien	if (sc->sc_ver >= 3) {
194236769Sobrien	   sc->sc_addr = (vm_offset_t)pmap_mapdev(reg[1] + 0x800000, PAGE_SIZE);
195236769Sobrien	   sc->sc_data = (vm_offset_t)pmap_mapdev(reg[1] + 0xc00000, PAGE_SIZE);
196236769Sobrien	} else {
197236769Sobrien	   sc->sc_addr = (vm_offset_t)pmap_mapdev(reg[0] + 0x800000, PAGE_SIZE);
198236769Sobrien	   sc->sc_data = (vm_offset_t)pmap_mapdev(reg[0] + 0xc00000, PAGE_SIZE);
199236769Sobrien	}
200236769Sobrien	sc->sc_bus = busrange[0];
201236769Sobrien
202236769Sobrien	bzero(sc->sc_range, sizeof(sc->sc_range));
203236769Sobrien	if (sc->sc_ver >= 3) {
204236769Sobrien		/*
205236769Sobrien		 * On Apple U3 systems, we have an otherwise standard
206236769Sobrien		 * Uninorth controller driving AGP. The one difference
207236769Sobrien		 * is that it uses a new PCI ranges format, so do the
208236769Sobrien		 * translation.
209236769Sobrien		 */
210236769Sobrien
211236769Sobrien		struct uninorth_range64 range64[6];
212236769Sobrien		bzero(range64, sizeof(range64));
213236769Sobrien
214236769Sobrien		sc->sc_nrange = OF_getprop(node, "ranges", range64,
215236769Sobrien		    sizeof(range64));
216236769Sobrien		for (i = 0; range64[i].pci_hi != 0; i++) {
217236769Sobrien			sc->sc_range[i].pci_hi = range64[i].pci_hi;
218236769Sobrien			sc->sc_range[i].pci_mid = range64[i].pci_mid;
219236769Sobrien			sc->sc_range[i].pci_lo = range64[i].pci_lo;
220236769Sobrien			sc->sc_range[i].host = range64[i].host_lo;
221236769Sobrien			sc->sc_range[i].size_hi = range64[i].size_hi;
222236769Sobrien			sc->sc_range[i].size_lo = range64[i].size_lo;
223236769Sobrien		}
224236769Sobrien	} else {
225236769Sobrien		sc->sc_nrange = OF_getprop(node, "ranges", sc->sc_range,
226236769Sobrien		    sizeof(sc->sc_range));
227236769Sobrien	}
228236769Sobrien
229236769Sobrien	if (sc->sc_nrange == -1) {
230236769Sobrien		device_printf(dev, "could not get ranges\n");
231236769Sobrien		return (ENXIO);
232236769Sobrien	}
233236769Sobrien
234236769Sobrien	sc->sc_nrange /= sizeof(sc->sc_range[0]);
235236769Sobrien
236236769Sobrien	sc->sc_range[6].pci_hi = 0;
237236769Sobrien	io = NULL;
238236769Sobrien	nmem = 0;
239236769Sobrien
240236769Sobrien	for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange &&
241236769Sobrien	       rp->pci_hi != 0; rp++) {
242236769Sobrien		switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
243236769Sobrien		case OFW_PCI_PHYS_HI_SPACE_CONFIG:
244236769Sobrien			break;
245236769Sobrien		case OFW_PCI_PHYS_HI_SPACE_IO:
246236769Sobrien			io = rp;
247236769Sobrien			break;
248236769Sobrien		case OFW_PCI_PHYS_HI_SPACE_MEM32:
249236769Sobrien			mem[nmem] = rp;
250236769Sobrien			nmem++;
251236769Sobrien			break;
252236769Sobrien		case OFW_PCI_PHYS_HI_SPACE_MEM64:
253236769Sobrien			break;
254236769Sobrien		}
255236769Sobrien	}
256236769Sobrien
257236769Sobrien	if (io == NULL) {
258236769Sobrien		device_printf(dev, "can't find io range\n");
259236769Sobrien		return (ENXIO);
260236769Sobrien	}
261236769Sobrien	sc->sc_io_rman.rm_type = RMAN_ARRAY;
262236769Sobrien	sc->sc_io_rman.rm_descr = "UniNorth PCI I/O Ports";
263236769Sobrien	sc->sc_iostart = io->host;
264236769Sobrien	if (rman_init(&sc->sc_io_rman) != 0 ||
265236769Sobrien	    rman_manage_region(&sc->sc_io_rman, io->pci_lo,
266236769Sobrien	    io->pci_lo + io->size_lo - 1) != 0) {
267236769Sobrien		panic("uninorth_attach: failed to set up I/O rman");
268236769Sobrien	}
269236769Sobrien
270236769Sobrien	if (nmem == 0) {
271236769Sobrien		device_printf(dev, "can't find mem ranges\n");
272236769Sobrien		return (ENXIO);
273236769Sobrien	}
274236769Sobrien	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
275236769Sobrien	sc->sc_mem_rman.rm_descr = "UniNorth PCI Memory";
276236769Sobrien	error = rman_init(&sc->sc_mem_rman);
277236769Sobrien	if (error) {
278236769Sobrien		device_printf(dev, "rman_init() failed. error = %d\n", error);
279236769Sobrien		return (error);
280236769Sobrien	}
281236769Sobrien	for (i = 0; i < nmem; i++) {
282236769Sobrien		error = rman_manage_region(&sc->sc_mem_rman, mem[i]->pci_lo,
283236769Sobrien		    mem[i]->pci_lo + mem[i]->size_lo - 1);
284236769Sobrien		if (error) {
285236769Sobrien			device_printf(dev,
286236769Sobrien			    "rman_manage_region() failed. error = %d\n", error);
287236769Sobrien			return (error);
288236769Sobrien		}
289236769Sobrien	}
290236769Sobrien
291236769Sobrien	ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(cell_t));
292236769Sobrien
293236769Sobrien	device_add_child(dev, "pci", device_get_unit(dev));
294236769Sobrien	return (bus_generic_attach(dev));
295236769Sobrien}
296236769Sobrien
297236769Sobrienstatic int
298236769Sobrienuninorth_maxslots(device_t dev)
299236769Sobrien{
300236769Sobrien
301236769Sobrien	return (PCI_SLOTMAX);
302236769Sobrien}
303236769Sobrien
304236769Sobrienstatic u_int32_t
305236769Sobrienuninorth_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
306236769Sobrien    int width)
307236769Sobrien{
308236769Sobrien	struct		uninorth_softc *sc;
309236769Sobrien	vm_offset_t	caoff;
310236769Sobrien
311236769Sobrien	sc = device_get_softc(dev);
312236769Sobrien	caoff = sc->sc_data + (reg & 0x07);
313236769Sobrien
314236769Sobrien	if (uninorth_enable_config(sc, bus, slot, func, reg) != 0) {
315236769Sobrien		switch (width) {
316236769Sobrien		case 1:
317236769Sobrien			return (in8rb(caoff));
318236769Sobrien			break;
319236769Sobrien		case 2:
320236769Sobrien			return (in16rb(caoff));
321236769Sobrien			break;
322236769Sobrien		case 4:
323236769Sobrien			return (in32rb(caoff));
324236769Sobrien			break;
325236769Sobrien		}
326236769Sobrien	}
327236769Sobrien
328236769Sobrien	return (0xffffffff);
329236769Sobrien}
330236769Sobrien
331236769Sobrienstatic void
332236769Sobrienuninorth_write_config(device_t dev, u_int bus, u_int slot, u_int func,
333236769Sobrien    u_int reg, u_int32_t val, int width)
334236769Sobrien{
335236769Sobrien	struct		uninorth_softc *sc;
336236769Sobrien	vm_offset_t	caoff;
337236769Sobrien
338236769Sobrien	sc = device_get_softc(dev);
339236769Sobrien	caoff = sc->sc_data + (reg & 0x07);
340236769Sobrien
341236769Sobrien	if (uninorth_enable_config(sc, bus, slot, func, reg)) {
342236769Sobrien		switch (width) {
343236769Sobrien		case 1:
344236769Sobrien			out8rb(caoff, val);
345236769Sobrien			break;
346236769Sobrien		case 2:
347236769Sobrien			out16rb(caoff, val);
348236769Sobrien			break;
349236769Sobrien		case 4:
350236769Sobrien			out32rb(caoff, val);
351236769Sobrien			break;
352236769Sobrien		}
353236769Sobrien	}
354236769Sobrien}
355236769Sobrien
356236769Sobrienstatic int
357236769Sobrienuninorth_route_interrupt(device_t bus, device_t dev, int pin)
358236769Sobrien{
359236769Sobrien	struct uninorth_softc *sc;
360236769Sobrien	struct ofw_pci_register reg;
361236769Sobrien	uint32_t pintr, mintr;
362236769Sobrien	phandle_t iparent;
363236769Sobrien	uint8_t maskbuf[sizeof(reg) + sizeof(pintr)];
364236769Sobrien
365236769Sobrien	sc = device_get_softc(bus);
366236769Sobrien	pintr = pin;
367236769Sobrien	if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, &reg,
368236769Sobrien	    sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
369236769Sobrien	    &iparent, maskbuf))
370236769Sobrien		return (MAP_IRQ(iparent, mintr));
371236769Sobrien
372236769Sobrien	/* Maybe it's a real interrupt, not an intpin */
373236769Sobrien	if (pin > 4)
374236769Sobrien		return (pin);
375236769Sobrien
376236769Sobrien	device_printf(bus, "could not route pin %d for device %d.%d\n",
377236769Sobrien	    pin, pci_get_slot(dev), pci_get_function(dev));
378236769Sobrien	return (PCI_INVALID_IRQ);
379236769Sobrien}
380236769Sobrien
381236769Sobrienstatic int
382236769Sobrienuninorth_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
383236769Sobrien{
384236769Sobrien	struct	uninorth_softc *sc;
385236769Sobrien
386236769Sobrien	sc = device_get_softc(dev);
387236769Sobrien
388236769Sobrien	switch (which) {
389236769Sobrien	case PCIB_IVAR_DOMAIN:
390236769Sobrien		*result = device_get_unit(dev);
391236769Sobrien		return (0);
392236769Sobrien	case PCIB_IVAR_BUS:
393236769Sobrien		*result = sc->sc_bus;
394236769Sobrien		return (0);
395236769Sobrien	}
396236769Sobrien
397236769Sobrien	return (ENOENT);
398236769Sobrien}
399236769Sobrien
400236769Sobrienstatic struct resource *
401236769Sobrienuninorth_alloc_resource(device_t bus, device_t child, int type, int *rid,
402236769Sobrien    u_long start, u_long end, u_long count, u_int flags)
403236769Sobrien{
404236769Sobrien	struct			uninorth_softc *sc;
405236769Sobrien	struct			resource *rv;
406236769Sobrien	struct			rman *rm;
407236769Sobrien	int			needactivate;
408236769Sobrien
409236769Sobrien	needactivate = flags & RF_ACTIVE;
410236769Sobrien	flags &= ~RF_ACTIVE;
411236769Sobrien
412236769Sobrien	sc = device_get_softc(bus);
413236769Sobrien
414236769Sobrien	switch (type) {
415236769Sobrien	case SYS_RES_MEMORY:
416236769Sobrien		rm = &sc->sc_mem_rman;
417236769Sobrien		break;
418236769Sobrien
419236769Sobrien	case SYS_RES_IOPORT:
420236769Sobrien		rm = &sc->sc_io_rman;
421236769Sobrien		break;
422236769Sobrien
423236769Sobrien	case SYS_RES_IRQ:
424236769Sobrien		return (bus_alloc_resource(bus, type, rid, start, end, count,
425236769Sobrien		    flags));
426236769Sobrien
427236769Sobrien	default:
428236769Sobrien		device_printf(bus, "unknown resource request from %s\n",
429236769Sobrien		    device_get_nameunit(child));
430236769Sobrien		return (NULL);
431236769Sobrien	}
432236769Sobrien
433236769Sobrien	rv = rman_reserve_resource(rm, start, end, count, flags, child);
434236769Sobrien	if (rv == NULL) {
435236769Sobrien		device_printf(bus, "failed to reserve resource for %s\n",
436236769Sobrien		    device_get_nameunit(child));
437236769Sobrien		return (NULL);
438236769Sobrien	}
439236769Sobrien
440236769Sobrien	rman_set_rid(rv, *rid);
441236769Sobrien
442236769Sobrien	if (needactivate) {
443236769Sobrien		if (bus_activate_resource(child, type, *rid, rv) != 0) {
444236769Sobrien			device_printf(bus,
445236769Sobrien			    "failed to activate resource for %s\n",
446236769Sobrien			    device_get_nameunit(child));
447236769Sobrien			rman_release_resource(rv);
448236769Sobrien			return (NULL);
449236769Sobrien		}
450236769Sobrien	}
451236769Sobrien
452236769Sobrien	return (rv);
453236769Sobrien}
454236769Sobrien
455236769Sobrienstatic int
456236769Sobrienuninorth_activate_resource(device_t bus, device_t child, int type, int rid,
457236769Sobrien    struct resource *res)
458236769Sobrien{
459236769Sobrien	void	*p;
460236769Sobrien	struct	uninorth_softc *sc;
461236769Sobrien
462236769Sobrien	sc = device_get_softc(bus);
463236769Sobrien
464236769Sobrien	if (type == SYS_RES_IRQ)
465236769Sobrien		return (bus_activate_resource(bus, type, rid, res));
466236769Sobrien
467236769Sobrien	if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
468236769Sobrien		vm_offset_t start;
469236769Sobrien
470236769Sobrien		start = (vm_offset_t)rman_get_start(res);
471236769Sobrien		/*
472236769Sobrien		 * For i/o-ports, convert the start address to the
473236769Sobrien		 * uninorth PCI i/o window
474236769Sobrien		 */
475236769Sobrien		if (type == SYS_RES_IOPORT)
476236769Sobrien			start += sc->sc_iostart;
477236769Sobrien
478236769Sobrien		if (bootverbose)
479236769Sobrien			printf("uninorth mapdev: start %zx, len %ld\n", start,
480236769Sobrien			    rman_get_size(res));
481236769Sobrien
482236769Sobrien		p = pmap_mapdev(start, (vm_size_t)rman_get_size(res));
483236769Sobrien		if (p == NULL)
484236769Sobrien			return (ENOMEM);
485236769Sobrien		rman_set_virtual(res, p);
486236769Sobrien		rman_set_bustag(res, &bs_le_tag);
487236769Sobrien		rman_set_bushandle(res, (u_long)p);
488236769Sobrien	}
489236769Sobrien
490236769Sobrien	return (rman_activate_resource(res));
491236769Sobrien}
492236769Sobrien
493236769Sobrienstatic int
494236769Sobrienuninorth_enable_config(struct uninorth_softc *sc, u_int bus, u_int slot,
495236769Sobrien    u_int func, u_int reg)
496236769Sobrien{
497236769Sobrien	uint32_t	cfgval;
498236769Sobrien	uint32_t	pass;
499236769Sobrien
500236769Sobrien	if (resource_int_value(device_get_name(sc->sc_dev),
501236769Sobrien	        device_get_unit(sc->sc_dev), "skipslot", &pass) == 0) {
502236769Sobrien		if (pass == slot)
503236769Sobrien			return (0);
504236769Sobrien	}
505236769Sobrien
506236769Sobrien	/*
507236769Sobrien	 * Issue type 0 configuration space accesses for the root bus.
508236769Sobrien	 *
509236769Sobrien	 * NOTE: On U4, issue only type 1 accesses. There is a secret
510236769Sobrien	 * PCI Express <-> PCI Express bridge not present in the device tree,
511236769Sobrien	 * and we need to route all of our configuration space through it.
512236769Sobrien	 */
513236769Sobrien	if (sc->sc_bus == bus && sc->sc_ver < 4) {
514236769Sobrien		/*
515236769Sobrien		 * No slots less than 11 on the primary bus on U3 and lower
516236769Sobrien		 */
517236769Sobrien		if (slot < 11)
518236769Sobrien			return (0);
519236769Sobrien
520236769Sobrien		cfgval = (1 << slot) | (func << 8) | (reg & 0xfc);
521236769Sobrien	} else {
522236769Sobrien		cfgval = (bus << 16) | (slot << 11) | (func << 8) |
523236769Sobrien		    (reg & 0xfc) | 1;
524236769Sobrien	}
525236769Sobrien
526236769Sobrien	/* Set extended register bits on U4 */
527236769Sobrien	if (sc->sc_ver == 4)
528236769Sobrien		cfgval |= (reg >> 8) << 28;
529236769Sobrien
530236769Sobrien	do {
531236769Sobrien		out32rb(sc->sc_addr, cfgval);
532236769Sobrien	} while (in32rb(sc->sc_addr) != cfgval);
533236769Sobrien
534236769Sobrien	return (1);
535236769Sobrien}
536236769Sobrien
537236769Sobrienstatic phandle_t
538236769Sobrienuninorth_get_node(device_t bus, device_t dev)
539236769Sobrien{
540236769Sobrien	struct uninorth_softc *sc;
541236769Sobrien
542236769Sobrien	sc = device_get_softc(bus);
543236769Sobrien	/* We only have one child, the PCI bus, which needs our own node. */
544236769Sobrien
545236769Sobrien	return sc->sc_node;
546236769Sobrien}
547236769Sobrien
548236769Sobrien