1209908Sraj/*-
2209908Sraj * Copyright 2006-2007 by Juniper Networks.
3209908Sraj * Copyright 2008 Semihalf.
4209908Sraj * Copyright 2010 The FreeBSD Foundation
5209908Sraj * All rights reserved.
6209908Sraj *
7209908Sraj * Portions of this software were developed by Semihalf
8209908Sraj * under sponsorship from the FreeBSD Foundation.
9209908Sraj *
10209908Sraj * Redistribution and use in source and binary forms, with or without
11209908Sraj * modification, are permitted provided that the following conditions
12209908Sraj * are met:
13209908Sraj * 1. Redistributions of source code must retain the above copyright
14209908Sraj *    notice, this list of conditions and the following disclaimer.
15209908Sraj * 2. Redistributions in binary form must reproduce the above copyright
16209908Sraj *    notice, this list of conditions and the following disclaimer in the
17209908Sraj *    documentation and/or other materials provided with the distribution.
18209908Sraj * 3. The name of the author may not be used to endorse or promote products
19209908Sraj *    derived from this software without specific prior written permission.
20209908Sraj *
21209908Sraj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22209908Sraj * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23209908Sraj * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24209908Sraj * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25209908Sraj * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26209908Sraj * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27209908Sraj * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28209908Sraj * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29209908Sraj * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30209908Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31209908Sraj * SUCH DAMAGE.
32209908Sraj *
33209908Sraj * From: FreeBSD: src/sys/powerpc/mpc85xx/pci_ocp.c,v 1.9 2010/03/23 23:46:28 marcel
34209908Sraj */
35209908Sraj
36209908Sraj#include <sys/cdefs.h>
37209908Sraj__FBSDID("$FreeBSD$");
38209908Sraj
39209908Sraj#include <sys/param.h>
40209908Sraj#include <sys/systm.h>
41209908Sraj#include <sys/ktr.h>
42209908Sraj#include <sys/sockio.h>
43209908Sraj#include <sys/mbuf.h>
44209908Sraj#include <sys/malloc.h>
45209908Sraj#include <sys/kernel.h>
46209908Sraj#include <sys/module.h>
47209908Sraj#include <sys/socket.h>
48209908Sraj#include <sys/queue.h>
49209908Sraj#include <sys/bus.h>
50209908Sraj#include <sys/lock.h>
51209908Sraj#include <sys/mutex.h>
52209908Sraj#include <sys/rman.h>
53209908Sraj#include <sys/endian.h>
54209908Sraj
55209908Sraj#include <vm/vm.h>
56209908Sraj#include <vm/pmap.h>
57209908Sraj
58209908Sraj#include <dev/fdt/fdt_common.h>
59209908Sraj#include <dev/ofw/ofw_bus.h>
60209908Sraj#include <dev/ofw/ofw_bus_subr.h>
61209908Sraj#include <dev/pci/pcivar.h>
62209908Sraj#include <dev/pci/pcireg.h>
63209908Sraj#include <dev/pci/pcib_private.h>
64209908Sraj
65209908Sraj#include "ofw_bus_if.h"
66209908Sraj#include "pcib_if.h"
67209908Sraj
68209908Sraj#include <machine/resource.h>
69209908Sraj#include <machine/bus.h>
70209908Sraj#include <machine/intr_machdep.h>
71209908Sraj
72209908Sraj#include <powerpc/mpc85xx/mpc85xx.h>
73209908Sraj
74209908Sraj#define	REG_CFG_ADDR	0x0000
75209908Sraj#define	CONFIG_ACCESS_ENABLE	0x80000000
76209908Sraj
77209908Sraj#define	REG_CFG_DATA	0x0004
78209908Sraj#define	REG_INT_ACK	0x0008
79209908Sraj
80209908Sraj#define	REG_POTAR(n)	(0x0c00 + 0x20 * (n))
81209908Sraj#define	REG_POTEAR(n)	(0x0c04 + 0x20 * (n))
82209908Sraj#define	REG_POWBAR(n)	(0x0c08 + 0x20 * (n))
83209908Sraj#define	REG_POWAR(n)	(0x0c10 + 0x20 * (n))
84209908Sraj
85209908Sraj#define	REG_PITAR(n)	(0x0e00 - 0x20 * (n))
86209908Sraj#define	REG_PIWBAR(n)	(0x0e08 - 0x20 * (n))
87209908Sraj#define	REG_PIWBEAR(n)	(0x0e0c - 0x20 * (n))
88209908Sraj#define	REG_PIWAR(n)	(0x0e10 - 0x20 * (n))
89209908Sraj
90209908Sraj#define	REG_PEX_MES_DR	0x0020
91209908Sraj#define	REG_PEX_MES_IER	0x0028
92209908Sraj#define	REG_PEX_ERR_DR	0x0e00
93209908Sraj#define	REG_PEX_ERR_EN	0x0e08
94209908Sraj
95209908Sraj#define PCIR_LTSSM	0x404
96209908Sraj#define LTSSM_STAT_L0	0x16
97209908Sraj
98209908Sraj#define	DEVFN(b, s, f)	((b << 16) | (s << 8) | f)
99209908Sraj
100209908Srajstruct fsl_pcib_softc {
101209908Sraj	device_t	sc_dev;
102209908Sraj
103209908Sraj	struct rman	sc_iomem;
104209908Sraj	bus_addr_t	sc_iomem_va;		/* Virtual mapping. */
105209908Sraj	bus_addr_t	sc_iomem_size;
106209908Sraj	bus_addr_t	sc_iomem_alloc;		/* Next allocation. */
107209908Sraj	int		sc_iomem_target;
108209908Sraj	struct rman	sc_ioport;
109209908Sraj	bus_addr_t	sc_ioport_va;		/* Virtual mapping. */
110209908Sraj	bus_addr_t	sc_ioport_size;
111209908Sraj	bus_addr_t	sc_ioport_alloc;	/* Next allocation. */
112209908Sraj	int		sc_ioport_target;
113209908Sraj
114209908Sraj	struct resource	*sc_res;
115209908Sraj	bus_space_handle_t sc_bsh;
116209908Sraj	bus_space_tag_t	sc_bst;
117209908Sraj	int		sc_rid;
118209908Sraj
119209908Sraj	int		sc_busnr;
120209908Sraj	int		sc_pcie;
121209908Sraj	uint8_t		sc_pcie_capreg;		/* PCI-E Capability Reg Set */
122209908Sraj
123209908Sraj	/* Devices that need special attention. */
124209908Sraj	int		sc_devfn_tundra;
125209908Sraj	int		sc_devfn_via_ide;
126209908Sraj
127209908Sraj	struct fdt_pci_intr	sc_intr_info;
128209908Sraj};
129209908Sraj
130209908Sraj/* Local forward declerations. */
131209908Srajstatic uint32_t fsl_pcib_cfgread(struct fsl_pcib_softc *, u_int, u_int, u_int,
132209908Sraj    u_int, int);
133209908Srajstatic void fsl_pcib_cfgwrite(struct fsl_pcib_softc *, u_int, u_int, u_int,
134209908Sraj    u_int, uint32_t, int);
135209908Srajstatic int fsl_pcib_decode_win(phandle_t, struct fsl_pcib_softc *);
136209908Srajstatic void fsl_pcib_err_init(device_t);
137209908Srajstatic void fsl_pcib_inbound(struct fsl_pcib_softc *, int, int, u_long,
138209908Sraj    u_long, u_long);
139218075Smarcelstatic int fsl_pcib_init(struct fsl_pcib_softc *, int, int);
140209908Srajstatic int fsl_pcib_intr_info(phandle_t, struct fsl_pcib_softc *);
141209908Srajstatic int fsl_pcib_set_range(struct fsl_pcib_softc *, int, int, u_long,
142209908Sraj    u_long);
143209908Srajstatic void fsl_pcib_outbound(struct fsl_pcib_softc *, int, int, u_long,
144209908Sraj    u_long, u_long);
145209908Sraj
146209908Sraj/* Forward declerations. */
147209908Srajstatic int fsl_pcib_attach(device_t);
148209908Srajstatic int fsl_pcib_detach(device_t);
149209908Srajstatic int fsl_pcib_probe(device_t);
150209908Sraj
151209908Srajstatic struct resource *fsl_pcib_alloc_resource(device_t, device_t, int, int *,
152209908Sraj    u_long, u_long, u_long, u_int);
153209908Srajstatic int fsl_pcib_read_ivar(device_t, device_t, int, uintptr_t *);
154209908Srajstatic int fsl_pcib_release_resource(device_t, device_t, int, int,
155209908Sraj    struct resource *);
156209908Srajstatic int fsl_pcib_write_ivar(device_t, device_t, int, uintptr_t);
157209908Sraj
158209908Srajstatic int fsl_pcib_maxslots(device_t);
159209908Srajstatic uint32_t fsl_pcib_read_config(device_t, u_int, u_int, u_int, u_int, int);
160209908Srajstatic void fsl_pcib_write_config(device_t, u_int, u_int, u_int, u_int,
161209908Sraj    uint32_t, int);
162209908Sraj
163209908Sraj/* Configuration r/w mutex. */
164209908Srajstruct mtx pcicfg_mtx;
165209908Srajstatic int mtx_initialized = 0;
166209908Sraj
167209908Sraj/*
168209908Sraj * Bus interface definitions.
169209908Sraj */
170209908Srajstatic device_method_t fsl_pcib_methods[] = {
171209908Sraj	/* Device interface */
172209908Sraj	DEVMETHOD(device_probe,		fsl_pcib_probe),
173209908Sraj	DEVMETHOD(device_attach,	fsl_pcib_attach),
174209908Sraj	DEVMETHOD(device_detach,	fsl_pcib_detach),
175209908Sraj
176209908Sraj	/* Bus interface */
177209908Sraj	DEVMETHOD(bus_read_ivar,	fsl_pcib_read_ivar),
178209908Sraj	DEVMETHOD(bus_write_ivar,	fsl_pcib_write_ivar),
179209908Sraj	DEVMETHOD(bus_alloc_resource,	fsl_pcib_alloc_resource),
180209908Sraj	DEVMETHOD(bus_release_resource,	fsl_pcib_release_resource),
181209908Sraj	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
182209908Sraj	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
183209908Sraj	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
184209908Sraj	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
185209908Sraj
186209908Sraj	/* pcib interface */
187209908Sraj	DEVMETHOD(pcib_maxslots,	fsl_pcib_maxslots),
188209908Sraj	DEVMETHOD(pcib_read_config,	fsl_pcib_read_config),
189209908Sraj	DEVMETHOD(pcib_write_config,	fsl_pcib_write_config),
190209908Sraj	DEVMETHOD(pcib_route_interrupt,	pcib_route_interrupt),
191209908Sraj
192209908Sraj	/* OFW bus interface */
193209908Sraj	DEVMETHOD(ofw_bus_get_compat,   ofw_bus_gen_get_compat),
194209908Sraj	DEVMETHOD(ofw_bus_get_model,    ofw_bus_gen_get_model),
195209908Sraj	DEVMETHOD(ofw_bus_get_name,     ofw_bus_gen_get_name),
196209908Sraj	DEVMETHOD(ofw_bus_get_node,     ofw_bus_gen_get_node),
197209908Sraj	DEVMETHOD(ofw_bus_get_type,     ofw_bus_gen_get_type),
198209908Sraj
199227843Smarius	DEVMETHOD_END
200209908Sraj};
201209908Sraj
202209908Srajstatic driver_t fsl_pcib_driver = {
203209908Sraj	"pcib",
204209908Sraj	fsl_pcib_methods,
205209908Sraj	sizeof(struct fsl_pcib_softc),
206209908Sraj};
207209908Sraj
208209908Srajdevclass_t pcib_devclass;
209209908Sraj
210209908SrajDRIVER_MODULE(pcib, fdtbus, fsl_pcib_driver, pcib_devclass, 0, 0);
211209908Sraj
212209908Srajstatic int
213209908Srajfsl_pcib_probe(device_t dev)
214209908Sraj{
215218075Smarcel	phandle_t node;
216209908Sraj
217218075Smarcel	node = ofw_bus_get_node(dev);
218218075Smarcel	if (!fdt_is_type(node, "pci"))
219209908Sraj		return (ENXIO);
220218075Smarcel
221218075Smarcel	if (!(fdt_is_compatible(node, "fsl,mpc8540-pci") ||
222218075Smarcel	    fdt_is_compatible(node, "fsl,mpc8548-pcie")))
223209908Sraj		return (ENXIO);
224209908Sraj
225209908Sraj	device_set_desc(dev, "Freescale Integrated PCI/PCI-E Controller");
226209908Sraj	return (BUS_PROBE_DEFAULT);
227209908Sraj}
228209908Sraj
229209908Srajstatic int
230209908Srajfsl_pcib_attach(device_t dev)
231209908Sraj{
232209908Sraj	struct fsl_pcib_softc *sc;
233209908Sraj	phandle_t node;
234209908Sraj	uint32_t cfgreg;
235218075Smarcel	int maxslot;
236209908Sraj	uint8_t ltssm, capptr;
237209908Sraj
238209908Sraj	sc = device_get_softc(dev);
239209908Sraj	sc->sc_dev = dev;
240209908Sraj
241209908Sraj	sc->sc_rid = 0;
242209908Sraj	sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
243209908Sraj	    RF_ACTIVE);
244209908Sraj	if (sc->sc_res == NULL) {
245209908Sraj		device_printf(dev, "could not map I/O memory\n");
246209908Sraj		return (ENXIO);
247209908Sraj	}
248209908Sraj	sc->sc_bst = rman_get_bustag(sc->sc_res);
249209908Sraj	sc->sc_bsh = rman_get_bushandle(sc->sc_res);
250209908Sraj	sc->sc_busnr = 0;
251209908Sraj
252209908Sraj	if (!mtx_initialized) {
253209908Sraj		mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN);
254209908Sraj		mtx_initialized = 1;
255209908Sraj	}
256209908Sraj
257209908Sraj	cfgreg = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_VENDOR, 2);
258209908Sraj	if (cfgreg != 0x1057 && cfgreg != 0x1957)
259209908Sraj		goto err;
260209908Sraj
261209908Sraj	capptr = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_CAP_PTR, 1);
262209908Sraj	while (capptr != 0) {
263209908Sraj		cfgreg = fsl_pcib_cfgread(sc, 0, 0, 0, capptr, 2);
264209908Sraj		switch (cfgreg & 0xff) {
265209908Sraj		case PCIY_PCIX:
266209908Sraj			break;
267209908Sraj		case PCIY_EXPRESS:
268209908Sraj			sc->sc_pcie = 1;
269209908Sraj			sc->sc_pcie_capreg = capptr;
270209908Sraj			break;
271209908Sraj		}
272209908Sraj		capptr = (cfgreg >> 8) & 0xff;
273209908Sraj	}
274209908Sraj
275209908Sraj	node = ofw_bus_get_node(dev);
276209908Sraj	/*
277209908Sraj	 * Get PCI interrupt info.
278209908Sraj	 */
279209908Sraj	if (fsl_pcib_intr_info(node, sc) != 0) {
280209908Sraj		device_printf(dev, "could not retrieve interrupt info\n");
281209908Sraj		goto err;
282209908Sraj	}
283209908Sraj
284209908Sraj	/*
285209908Sraj	 * Configure decode windows for PCI(E) access.
286209908Sraj	 */
287209908Sraj	if (fsl_pcib_decode_win(node, sc) != 0)
288209908Sraj		goto err;
289209908Sraj
290209908Sraj	cfgreg = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_COMMAND, 2);
291209908Sraj	cfgreg |= PCIM_CMD_SERRESPEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN |
292209908Sraj	    PCIM_CMD_PORTEN;
293209908Sraj	fsl_pcib_cfgwrite(sc, 0, 0, 0, PCIR_COMMAND, cfgreg, 2);
294209908Sraj
295209908Sraj	sc->sc_devfn_tundra = -1;
296209908Sraj	sc->sc_devfn_via_ide = -1;
297209908Sraj
298209908Sraj
299209908Sraj	/*
300218075Smarcel	 * Scan bus using firmware configured, 0 based bus numbering.
301209908Sraj	 */
302218075Smarcel	sc->sc_busnr = 0;
303218075Smarcel	maxslot = (sc->sc_pcie) ? 0 : PCI_SLOTMAX;
304218075Smarcel	fsl_pcib_init(sc, sc->sc_busnr, maxslot);
305209908Sraj
306209908Sraj	if (sc->sc_pcie) {
307209908Sraj		ltssm = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_LTSSM, 1);
308209908Sraj		if (ltssm < LTSSM_STAT_L0) {
309209908Sraj			if (bootverbose)
310209908Sraj				printf("PCI %d: no PCIE link, skipping\n",
311209908Sraj				    device_get_unit(dev));
312209908Sraj			return (0);
313209908Sraj		}
314209908Sraj	}
315209908Sraj
316209908Sraj	fsl_pcib_err_init(dev);
317209908Sraj
318209908Sraj	device_add_child(dev, "pci", -1);
319209908Sraj	return (bus_generic_attach(dev));
320209908Sraj
321209908Srajerr:
322209908Sraj	bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res);
323209908Sraj	return (ENXIO);
324209908Sraj}
325209908Sraj
326209908Srajstatic uint32_t
327209908Srajfsl_pcib_cfgread(struct fsl_pcib_softc *sc, u_int bus, u_int slot, u_int func,
328209908Sraj    u_int reg, int bytes)
329209908Sraj{
330209908Sraj	uint32_t addr, data;
331209908Sraj
332209908Sraj	if (bus == sc->sc_busnr - 1)
333209908Sraj		bus = 0;
334209908Sraj
335209908Sraj	addr = CONFIG_ACCESS_ENABLE;
336209908Sraj	addr |= (bus & 0xff) << 16;
337209908Sraj	addr |= (slot & 0x1f) << 11;
338209908Sraj	addr |= (func & 0x7) << 8;
339209908Sraj	addr |= reg & 0xfc;
340209908Sraj	if (sc->sc_pcie)
341209908Sraj		addr |= (reg & 0xf00) << 16;
342209908Sraj
343209908Sraj	mtx_lock_spin(&pcicfg_mtx);
344209908Sraj	bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_CFG_ADDR, addr);
345209908Sraj
346209908Sraj	switch (bytes) {
347209908Sraj	case 1:
348209908Sraj		data = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
349209908Sraj		    REG_CFG_DATA + (reg & 3));
350209908Sraj		break;
351209908Sraj	case 2:
352209908Sraj		data = le16toh(bus_space_read_2(sc->sc_bst, sc->sc_bsh,
353209908Sraj		    REG_CFG_DATA + (reg & 2)));
354209908Sraj		break;
355209908Sraj	case 4:
356209908Sraj		data = le32toh(bus_space_read_4(sc->sc_bst, sc->sc_bsh,
357209908Sraj		    REG_CFG_DATA));
358209908Sraj		break;
359209908Sraj	default:
360209908Sraj		data = ~0;
361209908Sraj		break;
362209908Sraj	}
363209908Sraj	mtx_unlock_spin(&pcicfg_mtx);
364209908Sraj	return (data);
365209908Sraj}
366209908Sraj
367209908Srajstatic void
368209908Srajfsl_pcib_cfgwrite(struct fsl_pcib_softc *sc, u_int bus, u_int slot, u_int func,
369209908Sraj    u_int reg, uint32_t data, int bytes)
370209908Sraj{
371209908Sraj	uint32_t addr;
372209908Sraj
373209908Sraj	if (bus == sc->sc_busnr - 1)
374209908Sraj		bus = 0;
375209908Sraj
376209908Sraj	addr = CONFIG_ACCESS_ENABLE;
377209908Sraj	addr |= (bus & 0xff) << 16;
378209908Sraj	addr |= (slot & 0x1f) << 11;
379209908Sraj	addr |= (func & 0x7) << 8;
380209908Sraj	addr |= reg & 0xfc;
381209908Sraj	if (sc->sc_pcie)
382209908Sraj		addr |= (reg & 0xf00) << 16;
383209908Sraj
384209908Sraj	mtx_lock_spin(&pcicfg_mtx);
385209908Sraj	bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_CFG_ADDR, addr);
386209908Sraj
387209908Sraj	switch (bytes) {
388209908Sraj	case 1:
389209908Sraj		bus_space_write_1(sc->sc_bst, sc->sc_bsh,
390209908Sraj		    REG_CFG_DATA + (reg & 3), data);
391209908Sraj		break;
392209908Sraj	case 2:
393209908Sraj		bus_space_write_2(sc->sc_bst, sc->sc_bsh,
394209908Sraj		    REG_CFG_DATA + (reg & 2), htole16(data));
395209908Sraj		break;
396209908Sraj	case 4:
397209908Sraj		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
398209908Sraj		    REG_CFG_DATA, htole32(data));
399209908Sraj		break;
400209908Sraj	}
401209908Sraj	mtx_unlock_spin(&pcicfg_mtx);
402209908Sraj}
403209908Sraj
404209908Sraj#if 0
405209908Srajstatic void
406209908Srajdump(struct fsl_pcib_softc *sc)
407209908Sraj{
408209908Sraj	unsigned int i;
409209908Sraj
410209908Sraj#define RD(o)	bus_space_read_4(sc->sc_bst, sc->sc_bsh, o)
411209908Sraj	for (i = 0; i < 5; i++) {
412209908Sraj		printf("POTAR%u  =0x%08x\n", i, RD(REG_POTAR(i)));
413209908Sraj		printf("POTEAR%u =0x%08x\n", i, RD(REG_POTEAR(i)));
414209908Sraj		printf("POWBAR%u =0x%08x\n", i, RD(REG_POWBAR(i)));
415209908Sraj		printf("POWAR%u  =0x%08x\n", i, RD(REG_POWAR(i)));
416209908Sraj	}
417209908Sraj	printf("\n");
418209908Sraj	for (i = 1; i < 4; i++) {
419209908Sraj		printf("PITAR%u  =0x%08x\n", i, RD(REG_PITAR(i)));
420209908Sraj		printf("PIWBAR%u =0x%08x\n", i, RD(REG_PIWBAR(i)));
421209908Sraj		printf("PIWBEAR%u=0x%08x\n", i, RD(REG_PIWBEAR(i)));
422209908Sraj		printf("PIWAR%u  =0x%08x\n", i, RD(REG_PIWAR(i)));
423209908Sraj	}
424209908Sraj	printf("\n");
425209908Sraj#undef RD
426209908Sraj
427209908Sraj	for (i = 0; i < 0x48; i += 4) {
428209908Sraj		printf("cfg%02x=0x%08x\n", i, fsl_pcib_cfgread(sc, 0, 0, 0,
429209908Sraj		    i, 4));
430209908Sraj	}
431209908Sraj}
432209908Sraj#endif
433209908Sraj
434209908Srajstatic int
435209908Srajfsl_pcib_maxslots(device_t dev)
436209908Sraj{
437209908Sraj	struct fsl_pcib_softc *sc = device_get_softc(dev);
438209908Sraj
439218075Smarcel	return ((sc->sc_pcie) ? 0 : PCI_SLOTMAX);
440209908Sraj}
441209908Sraj
442209908Srajstatic uint32_t
443209908Srajfsl_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func,
444209908Sraj    u_int reg, int bytes)
445209908Sraj{
446209908Sraj	struct fsl_pcib_softc *sc = device_get_softc(dev);
447209908Sraj	u_int devfn;
448209908Sraj
449209908Sraj	if (bus == sc->sc_busnr && !sc->sc_pcie && slot < 10)
450209908Sraj		return (~0);
451209908Sraj	devfn = DEVFN(bus, slot, func);
452209908Sraj	if (devfn == sc->sc_devfn_tundra)
453209908Sraj		return (~0);
454209908Sraj	if (devfn == sc->sc_devfn_via_ide && reg == PCIR_INTPIN)
455209908Sraj		return (1);
456209908Sraj	return (fsl_pcib_cfgread(sc, bus, slot, func, reg, bytes));
457209908Sraj}
458209908Sraj
459209908Srajstatic void
460209908Srajfsl_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func,
461209908Sraj    u_int reg, uint32_t val, int bytes)
462209908Sraj{
463209908Sraj	struct fsl_pcib_softc *sc = device_get_softc(dev);
464209908Sraj
465209908Sraj	if (bus == sc->sc_busnr && !sc->sc_pcie && slot < 10)
466209908Sraj		return;
467209908Sraj	fsl_pcib_cfgwrite(sc, bus, slot, func, reg, val, bytes);
468209908Sraj}
469209908Sraj
470209908Srajstatic void
471209908Srajfsl_pcib_init_via(struct fsl_pcib_softc *sc, uint16_t device, int bus,
472209908Sraj    int slot, int fn)
473209908Sraj{
474209908Sraj
475209908Sraj	if (device == 0x0686) {
476209908Sraj		fsl_pcib_write_config(sc->sc_dev, bus, slot, fn, 0x52, 0x34, 1);
477209908Sraj		fsl_pcib_write_config(sc->sc_dev, bus, slot, fn, 0x77, 0x00, 1);
478209908Sraj		fsl_pcib_write_config(sc->sc_dev, bus, slot, fn, 0x83, 0x98, 1);
479209908Sraj		fsl_pcib_write_config(sc->sc_dev, bus, slot, fn, 0x85, 0x03, 1);
480209908Sraj	} else if (device == 0x0571) {
481209908Sraj		sc->sc_devfn_via_ide = DEVFN(bus, slot, fn);
482209908Sraj		fsl_pcib_write_config(sc->sc_dev, bus, slot, fn, 0x40, 0x0b, 1);
483209908Sraj	}
484209908Sraj}
485209908Sraj
486209908Srajstatic int
487209908Srajfsl_pcib_init_bar(struct fsl_pcib_softc *sc, int bus, int slot, int func,
488209908Sraj    int barno)
489209908Sraj{
490209908Sraj	bus_addr_t *allocp;
491209908Sraj	uint32_t addr, mask, size;
492209908Sraj	int reg, width;
493209908Sraj
494209908Sraj	reg = PCIR_BAR(barno);
495209908Sraj
496209908Sraj	if (DEVFN(bus, slot, func) == sc->sc_devfn_via_ide) {
497209908Sraj		switch (barno) {
498209908Sraj		case 0:	addr = 0x1f0; break;
499209908Sraj		case 1: addr = 0x3f4; break;
500209908Sraj		case 2: addr = 0x170; break;
501209908Sraj		case 3: addr = 0x374; break;
502209908Sraj		case 4: addr = 0xcc0; break;
503209908Sraj		default: return (1);
504209908Sraj		}
505209908Sraj		fsl_pcib_write_config(sc->sc_dev, bus, slot, func, reg, addr, 4);
506209908Sraj		return (1);
507209908Sraj	}
508209908Sraj
509209908Sraj	fsl_pcib_write_config(sc->sc_dev, bus, slot, func, reg, ~0, 4);
510209908Sraj	size = fsl_pcib_read_config(sc->sc_dev, bus, slot, func, reg, 4);
511209908Sraj	if (size == 0)
512209908Sraj		return (1);
513209908Sraj	width = ((size & 7) == 4) ? 2 : 1;
514209908Sraj
515209908Sraj	if (size & 1) {		/* I/O port */
516209908Sraj		allocp = &sc->sc_ioport_alloc;
517209908Sraj		size &= ~3;
518209908Sraj		if ((size & 0xffff0000) == 0)
519209908Sraj			size |= 0xffff0000;
520209908Sraj	} else {		/* memory */
521209908Sraj		allocp = &sc->sc_iomem_alloc;
522209908Sraj		size &= ~15;
523209908Sraj	}
524209908Sraj	mask = ~size;
525209908Sraj	size = mask + 1;
526209908Sraj	/* Sanity check (must be a power of 2). */
527209908Sraj	if (size & mask)
528209908Sraj		return (width);
529209908Sraj
530209908Sraj	addr = (*allocp + mask) & ~mask;
531209908Sraj	*allocp = addr + size;
532209908Sraj
533209908Sraj	if (bootverbose)
534209908Sraj		printf("PCI %u:%u:%u:%u: reg %x: size=%08x: addr=%08x\n",
535209908Sraj		    device_get_unit(sc->sc_dev), bus, slot, func, reg,
536209908Sraj		    size, addr);
537209908Sraj
538209908Sraj	fsl_pcib_write_config(sc->sc_dev, bus, slot, func, reg, addr, 4);
539209908Sraj	if (width == 2)
540209908Sraj		fsl_pcib_write_config(sc->sc_dev, bus, slot, func, reg + 4,
541209908Sraj		    0, 4);
542209908Sraj	return (width);
543209908Sraj}
544209908Sraj
545209908Srajstatic u_int
546209908Srajfsl_pcib_route_int(struct fsl_pcib_softc *sc, u_int bus, u_int slot, u_int func,
547209908Sraj    u_int intpin)
548209908Sraj{
549209908Sraj	int err, unit;
550209908Sraj	u_int devfn, intline;
551209908Sraj
552209908Sraj	unit = device_get_unit(sc->sc_dev);
553209908Sraj
554209908Sraj	devfn = DEVFN(bus, slot, func);
555209908Sraj	if (devfn == sc->sc_devfn_via_ide)
556218184Smarcel		intline = MAP_IRQ(0, 14);
557209908Sraj	else if (devfn == sc->sc_devfn_via_ide + 1)
558218184Smarcel		intline = MAP_IRQ(0, 10);
559209908Sraj	else if (devfn == sc->sc_devfn_via_ide + 2)
560218184Smarcel		intline = MAP_IRQ(0, 10);
561209908Sraj	else {
562209908Sraj		if (intpin != 0)
563209908Sraj			err = fdt_pci_route_intr(bus, slot, func, intpin,
564209908Sraj			    &sc->sc_intr_info, &intline);
565209908Sraj		else
566209908Sraj			intline = 0xff;
567209908Sraj	}
568209908Sraj
569209908Sraj	if (bootverbose)
570209908Sraj		printf("PCI %u:%u:%u:%u: intpin %u: intline=%u\n",
571209908Sraj		    unit, bus, slot, func, intpin, intline);
572209908Sraj
573209908Sraj	return (intline);
574209908Sraj}
575209908Sraj
576209908Srajstatic int
577218075Smarcelfsl_pcib_init(struct fsl_pcib_softc *sc, int bus, int maxslot)
578209908Sraj{
579218075Smarcel	int secbus;
580209908Sraj	int old_pribus, old_secbus, old_subbus;
581209908Sraj	int new_pribus, new_secbus, new_subbus;
582209908Sraj	int slot, func, maxfunc;
583209908Sraj	int bar, maxbar;
584209908Sraj	uint16_t vendor, device;
585209908Sraj	uint8_t command, hdrtype, class, subclass;
586209908Sraj	uint8_t intline, intpin;
587209908Sraj
588218075Smarcel	secbus = bus;
589209908Sraj	for (slot = 0; slot <= maxslot; slot++) {
590209908Sraj		maxfunc = 0;
591209908Sraj		for (func = 0; func <= maxfunc; func++) {
592209908Sraj			hdrtype = fsl_pcib_read_config(sc->sc_dev, bus, slot,
593209908Sraj			    func, PCIR_HDRTYPE, 1);
594209908Sraj
595209908Sraj			if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
596209908Sraj				continue;
597209908Sraj
598209908Sraj			if (func == 0 && (hdrtype & PCIM_MFDEV))
599209908Sraj				maxfunc = PCI_FUNCMAX;
600209908Sraj
601209908Sraj			vendor = fsl_pcib_read_config(sc->sc_dev, bus, slot,
602209908Sraj			    func, PCIR_VENDOR, 2);
603209908Sraj			device = fsl_pcib_read_config(sc->sc_dev, bus, slot,
604209908Sraj			    func, PCIR_DEVICE, 2);
605209908Sraj
606209908Sraj			if (vendor == 0x1957 && device == 0x3fff) {
607209908Sraj				sc->sc_devfn_tundra = DEVFN(bus, slot, func);
608209908Sraj				continue;
609209908Sraj			}
610209908Sraj
611209908Sraj			command = fsl_pcib_read_config(sc->sc_dev, bus, slot,
612209908Sraj			    func, PCIR_COMMAND, 1);
613209908Sraj			command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN);
614209908Sraj			fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
615209908Sraj			    PCIR_COMMAND, command, 1);
616209908Sraj
617209908Sraj			if (vendor == 0x1106)
618209908Sraj				fsl_pcib_init_via(sc, device, bus, slot, func);
619209908Sraj
620209908Sraj			/* Program the base address registers. */
621209908Sraj			maxbar = (hdrtype & PCIM_HDRTYPE) ? 1 : 6;
622209908Sraj			bar = 0;
623209908Sraj			while (bar < maxbar)
624209908Sraj				bar += fsl_pcib_init_bar(sc, bus, slot, func,
625209908Sraj				    bar);
626209908Sraj
627209908Sraj			/* Perform interrupt routing. */
628209908Sraj			intpin = fsl_pcib_read_config(sc->sc_dev, bus, slot,
629209908Sraj			    func, PCIR_INTPIN, 1);
630209908Sraj			intline = fsl_pcib_route_int(sc, bus, slot, func,
631209908Sraj			    intpin);
632209908Sraj			fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
633209908Sraj			    PCIR_INTLINE, intline, 1);
634209908Sraj
635209908Sraj			command |= PCIM_CMD_MEMEN | PCIM_CMD_PORTEN;
636209908Sraj			fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
637209908Sraj			    PCIR_COMMAND, command, 1);
638209908Sraj
639209908Sraj			/*
640209908Sraj			 * Handle PCI-PCI bridges
641209908Sraj			 */
642209908Sraj			class = fsl_pcib_read_config(sc->sc_dev, bus, slot,
643209908Sraj			    func, PCIR_CLASS, 1);
644209908Sraj			subclass = fsl_pcib_read_config(sc->sc_dev, bus, slot,
645209908Sraj			    func, PCIR_SUBCLASS, 1);
646218075Smarcel
647209908Sraj			/* Allow only proper PCI-PCI briges */
648209908Sraj			if (class != PCIC_BRIDGE)
649209908Sraj				continue;
650209908Sraj			if (subclass != PCIS_BRIDGE_PCI)
651209908Sraj				continue;
652209908Sraj
653218075Smarcel			secbus++;
654209908Sraj
655209908Sraj			/* Program I/O decoder. */
656209908Sraj			fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
657209908Sraj			    PCIR_IOBASEL_1, sc->sc_ioport.rm_start >> 8, 1);
658209908Sraj			fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
659209908Sraj			    PCIR_IOLIMITL_1, sc->sc_ioport.rm_end >> 8, 1);
660209908Sraj			fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
661209908Sraj			    PCIR_IOBASEH_1, sc->sc_ioport.rm_start >> 16, 2);
662209908Sraj			fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
663209908Sraj			    PCIR_IOLIMITH_1, sc->sc_ioport.rm_end >> 16, 2);
664209908Sraj
665209908Sraj			/* Program (non-prefetchable) memory decoder. */
666209908Sraj			fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
667209908Sraj			    PCIR_MEMBASE_1, sc->sc_iomem.rm_start >> 16, 2);
668209908Sraj			fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
669209908Sraj			    PCIR_MEMLIMIT_1, sc->sc_iomem.rm_end >> 16, 2);
670209908Sraj
671209908Sraj			/* Program prefetchable memory decoder. */
672209908Sraj			fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
673209908Sraj			    PCIR_PMBASEL_1, 0x0010, 2);
674209908Sraj			fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
675209908Sraj			    PCIR_PMLIMITL_1, 0x000f, 2);
676209908Sraj			fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
677209908Sraj			    PCIR_PMBASEH_1, 0x00000000, 4);
678209908Sraj			fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
679209908Sraj			    PCIR_PMLIMITH_1, 0x00000000, 4);
680209908Sraj
681209908Sraj			/* Read currect bus register configuration */
682209908Sraj			old_pribus = fsl_pcib_read_config(sc->sc_dev, bus,
683209908Sraj			    slot, func, PCIR_PRIBUS_1, 1);
684209908Sraj			old_secbus = fsl_pcib_read_config(sc->sc_dev, bus,
685209908Sraj			    slot, func, PCIR_SECBUS_1, 1);
686209908Sraj			old_subbus = fsl_pcib_read_config(sc->sc_dev, bus,
687209908Sraj			    slot, func, PCIR_SUBBUS_1, 1);
688209908Sraj
689209908Sraj			if (bootverbose)
690209908Sraj				printf("PCI: reading firmware bus numbers for "
691209908Sraj				    "secbus = %d (bus/sec/sub) = (%d/%d/%d)\n",
692218075Smarcel				    secbus, old_pribus, old_secbus, old_subbus);
693209908Sraj
694218075Smarcel			new_pribus = bus;
695218075Smarcel			new_secbus = secbus;
696209908Sraj
697218075Smarcel			secbus = fsl_pcib_init(sc, secbus,
698218075Smarcel			    (subclass == PCIS_BRIDGE_PCI) ? PCI_SLOTMAX : 0);
699209908Sraj
700218075Smarcel			new_subbus = secbus;
701209908Sraj
702209908Sraj			if (bootverbose)
703218075Smarcel				printf("PCI: translate firmware bus numbers "
704218075Smarcel				    "for secbus %d (%d/%d/%d) -> (%d/%d/%d)\n",
705218075Smarcel				    secbus, old_pribus, old_secbus, old_subbus,
706209908Sraj				    new_pribus, new_secbus, new_subbus);
707209908Sraj
708209908Sraj			fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
709209908Sraj			    PCIR_PRIBUS_1, new_pribus, 1);
710209908Sraj			fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
711209908Sraj			    PCIR_SECBUS_1, new_secbus, 1);
712209908Sraj			fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
713209908Sraj			    PCIR_SUBBUS_1, new_subbus, 1);
714209908Sraj		}
715209908Sraj	}
716209908Sraj
717218075Smarcel	return (secbus);
718209908Sraj}
719209908Sraj
720209908Srajstatic void
721209908Srajfsl_pcib_inbound(struct fsl_pcib_softc *sc, int wnd, int tgt, u_long start,
722209908Sraj    u_long size, u_long pci_start)
723209908Sraj{
724209908Sraj	uint32_t attr, bar, tar;
725209908Sraj
726209908Sraj	KASSERT(wnd > 0, ("%s: inbound window 0 is invalid", __func__));
727209908Sraj
728209908Sraj	switch (tgt) {
729209908Sraj	/* XXX OCP85XX_TGTIF_RAM2, OCP85XX_TGTIF_RAM_INTL should be handled */
730209908Sraj	case OCP85XX_TGTIF_RAM1:
731209908Sraj		attr = 0xa0f55000 | (ffsl(size) - 2);
732209908Sraj		break;
733209908Sraj	default:
734209908Sraj		attr = 0;
735209908Sraj		break;
736209908Sraj	}
737209908Sraj	tar = start >> 12;
738209908Sraj	bar = pci_start >> 12;
739209908Sraj
740209908Sraj	bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PITAR(wnd), tar);
741209908Sraj	bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PIWBEAR(wnd), 0);
742209908Sraj	bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PIWBAR(wnd), bar);
743209908Sraj	bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PIWAR(wnd), attr);
744209908Sraj}
745209908Sraj
746209908Srajstatic void
747209908Srajfsl_pcib_outbound(struct fsl_pcib_softc *sc, int wnd, int res, u_long start,
748209908Sraj    u_long size, u_long pci_start)
749209908Sraj{
750209908Sraj	uint32_t attr, bar, tar;
751209908Sraj
752209908Sraj	switch (res) {
753209908Sraj	case SYS_RES_MEMORY:
754209908Sraj		attr = 0x80044000 | (ffsl(size) - 2);
755209908Sraj		break;
756209908Sraj	case SYS_RES_IOPORT:
757209908Sraj		attr = 0x80088000 | (ffsl(size) - 2);
758209908Sraj		break;
759209908Sraj	default:
760209908Sraj		attr = 0x0004401f;
761209908Sraj		break;
762209908Sraj	}
763209908Sraj	bar = start >> 12;
764209908Sraj	tar = pci_start >> 12;
765209908Sraj
766209908Sraj	bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_POTAR(wnd), tar);
767209908Sraj	bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_POTEAR(wnd), 0);
768209908Sraj	bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_POWBAR(wnd), bar);
769209908Sraj	bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_POWAR(wnd), attr);
770209908Sraj}
771209908Sraj
772209908Srajstatic int
773209908Srajfsl_pcib_set_range(struct fsl_pcib_softc *sc, int type, int wnd, u_long start,
774209908Sraj    u_long size)
775209908Sraj{
776209908Sraj	struct rman *rm;
777209908Sraj	u_long end, alloc;
778209908Sraj	bus_addr_t pci_start, pci_end;
779209908Sraj	bus_addr_t *vap, *allocp;
780209908Sraj	int error;
781209908Sraj
782209908Sraj	end = start + size - 1;
783209908Sraj
784209908Sraj	switch (type) {
785209908Sraj	case SYS_RES_IOPORT:
786209908Sraj		rm = &sc->sc_ioport;
787209908Sraj		pci_start = 0x0000;
788209908Sraj		pci_end = 0xffff;
789209908Sraj		alloc = 0x1000;
790209908Sraj		vap = &sc->sc_ioport_va;
791209908Sraj		allocp = &sc->sc_ioport_alloc;
792209908Sraj		break;
793209908Sraj	case SYS_RES_MEMORY:
794209908Sraj		rm = &sc->sc_iomem;
795209908Sraj		pci_start = start;
796209908Sraj		pci_end = end;
797209908Sraj		alloc = 0;
798209908Sraj		vap = &sc->sc_iomem_va;
799209908Sraj		allocp = &sc->sc_iomem_alloc;
800209908Sraj		break;
801209908Sraj	default:
802209908Sraj		return (EINVAL);
803209908Sraj	}
804209908Sraj
805209908Sraj	rm->rm_type = RMAN_ARRAY;
806209908Sraj	rm->rm_start = pci_start;
807209908Sraj	rm->rm_end = pci_end;
808209908Sraj	error = rman_init(rm);
809209908Sraj	if (error)
810209908Sraj		return (error);
811209908Sraj
812209908Sraj	error = rman_manage_region(rm, pci_start, pci_end);
813209908Sraj	if (error) {
814209908Sraj		rman_fini(rm);
815209908Sraj		return (error);
816209908Sraj	}
817209908Sraj
818209908Sraj	*allocp = pci_start + alloc;
819235933Smarcel	if (size > 0) {
820235933Smarcel		*vap = (uintptr_t)pmap_mapdev(start, size);
821235933Smarcel		fsl_pcib_outbound(sc, wnd, type, start, size, pci_start);
822235933Smarcel	} else {
823235933Smarcel		*vap = 0;
824235933Smarcel		fsl_pcib_outbound(sc, wnd, -1, 0, 0, 0);
825235933Smarcel	}
826209908Sraj	return (0);
827209908Sraj}
828209908Sraj
829209908Srajstatic void
830209908Srajfsl_pcib_err_init(device_t dev)
831209908Sraj{
832209908Sraj	struct fsl_pcib_softc *sc;
833209908Sraj	uint16_t sec_stat, dsr;
834209908Sraj	uint32_t dcr, err_en;
835209908Sraj
836209908Sraj	sc = device_get_softc(dev);
837209908Sraj
838209908Sraj	sec_stat = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_SECSTAT_1, 2);
839209908Sraj	if (sec_stat)
840209908Sraj		fsl_pcib_cfgwrite(sc, 0, 0, 0, PCIR_SECSTAT_1, 0xffff, 2);
841209908Sraj	if (sc->sc_pcie) {
842209908Sraj		/* Clear error bits */
843209908Sraj		bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_MES_IER,
844209908Sraj		    0xffffffff);
845209908Sraj		bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_MES_DR,
846209908Sraj		    0xffffffff);
847209908Sraj		bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_ERR_DR,
848209908Sraj		    0xffffffff);
849209908Sraj
850209908Sraj		dsr = fsl_pcib_cfgread(sc, 0, 0, 0,
851240680Sgavin		    sc->sc_pcie_capreg + PCIER_DEVICE_STA, 2);
852209908Sraj		if (dsr)
853209908Sraj			fsl_pcib_cfgwrite(sc, 0, 0, 0,
854240680Sgavin			    sc->sc_pcie_capreg + PCIER_DEVICE_STA,
855209908Sraj			    0xffff, 2);
856209908Sraj
857209908Sraj		/* Enable all errors reporting */
858209908Sraj		err_en = 0x00bfff00;
859209908Sraj		bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_ERR_EN,
860209908Sraj		    err_en);
861209908Sraj
862209908Sraj		/* Enable error reporting: URR, FER, NFER */
863209908Sraj		dcr = fsl_pcib_cfgread(sc, 0, 0, 0,
864240680Sgavin		    sc->sc_pcie_capreg + PCIER_DEVICE_CTL, 4);
865240680Sgavin		dcr |= PCIEM_CTL_URR_ENABLE | PCIEM_CTL_FER_ENABLE |
866240680Sgavin		    PCIEM_CTL_NFER_ENABLE;
867209908Sraj		fsl_pcib_cfgwrite(sc, 0, 0, 0,
868240680Sgavin		    sc->sc_pcie_capreg + PCIER_DEVICE_CTL, dcr, 4);
869209908Sraj	}
870209908Sraj}
871209908Sraj
872209908Srajstatic int
873209908Srajfsl_pcib_detach(device_t dev)
874209908Sraj{
875209908Sraj
876209908Sraj	if (mtx_initialized) {
877209908Sraj		mtx_destroy(&pcicfg_mtx);
878209908Sraj		mtx_initialized = 0;
879209908Sraj	}
880209908Sraj	return (bus_generic_detach(dev));
881209908Sraj}
882209908Sraj
883209908Srajstatic struct resource *
884209908Srajfsl_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
885209908Sraj    u_long start, u_long end, u_long count, u_int flags)
886209908Sraj{
887209908Sraj	struct fsl_pcib_softc *sc = device_get_softc(dev);
888209908Sraj	struct rman *rm;
889209908Sraj	struct resource *res;
890209908Sraj	bus_addr_t va;
891209908Sraj
892209908Sraj	switch (type) {
893209908Sraj	case SYS_RES_IOPORT:
894209908Sraj		rm = &sc->sc_ioport;
895209908Sraj		va = sc->sc_ioport_va;
896209908Sraj		break;
897209908Sraj	case SYS_RES_MEMORY:
898209908Sraj		rm = &sc->sc_iomem;
899209908Sraj		va = sc->sc_iomem_va;
900209908Sraj		break;
901209908Sraj	case SYS_RES_IRQ:
902218075Smarcel		if (start < 16) {
903209908Sraj			device_printf(dev, "%s requested ISA interrupt %lu\n",
904209908Sraj			    device_get_nameunit(child), start);
905209908Sraj		}
906209908Sraj		flags |= RF_SHAREABLE;
907209908Sraj		return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
908209908Sraj		    type, rid, start, end, count, flags));
909209908Sraj	default:
910209908Sraj		return (NULL);
911209908Sraj	}
912209908Sraj
913209908Sraj	res = rman_reserve_resource(rm, start, end, count, flags, child);
914209908Sraj	if (res == NULL)
915209908Sraj		return (NULL);
916209908Sraj
917209908Sraj	rman_set_bustag(res, &bs_le_tag);
918209908Sraj	rman_set_bushandle(res, va + rman_get_start(res) - rm->rm_start);
919209908Sraj	return (res);
920209908Sraj}
921209908Sraj
922209908Srajstatic int
923209908Srajfsl_pcib_release_resource(device_t dev, device_t child, int type, int rid,
924209908Sraj    struct resource *res)
925209908Sraj{
926209908Sraj
927209908Sraj	return (rman_release_resource(res));
928209908Sraj}
929209908Sraj
930209908Srajstatic int
931209908Srajfsl_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
932209908Sraj{
933209908Sraj	struct fsl_pcib_softc *sc = device_get_softc(dev);
934209908Sraj
935209908Sraj	switch (which) {
936209908Sraj	case PCIB_IVAR_BUS:
937209908Sraj		*result = sc->sc_busnr;
938209908Sraj		return (0);
939209908Sraj	case PCIB_IVAR_DOMAIN:
940209908Sraj		*result = device_get_unit(dev);
941209908Sraj		return (0);
942209908Sraj	}
943209908Sraj	return (ENOENT);
944209908Sraj}
945209908Sraj
946209908Srajstatic int
947209908Srajfsl_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
948209908Sraj{
949209908Sraj	struct fsl_pcib_softc *sc = device_get_softc(dev);
950209908Sraj
951209908Sraj	switch (which) {
952209908Sraj	case PCIB_IVAR_BUS:
953209908Sraj		sc->sc_busnr = value;
954209908Sraj		return (0);
955209908Sraj	}
956209908Sraj	return (ENOENT);
957209908Sraj}
958209908Sraj
959209908Srajstatic int
960209908Srajfsl_pcib_intr_info(phandle_t node, struct fsl_pcib_softc *sc)
961209908Sraj{
962209908Sraj	int error;
963209908Sraj
964209908Sraj	if ((error = fdt_pci_intr_info(node, &sc->sc_intr_info)) != 0)
965209908Sraj		return (error);
966209908Sraj
967209908Sraj	return (0);
968209908Sraj}
969209908Sraj
970209908Srajstatic int
971209908Srajfsl_pcib_decode_win(phandle_t node, struct fsl_pcib_softc *sc)
972209908Sraj{
973209908Sraj	struct fdt_pci_range io_space, mem_space;
974209908Sraj	device_t dev;
975209908Sraj	int error;
976209908Sraj
977209908Sraj	dev = sc->sc_dev;
978209908Sraj
979209908Sraj	if ((error = fdt_pci_ranges(node, &io_space, &mem_space)) != 0) {
980209908Sraj		device_printf(dev, "could not retrieve 'ranges' data\n");
981209908Sraj		return (error);
982209908Sraj	}
983209908Sraj
984209908Sraj	/*
985209908Sraj	 * Configure LAW decode windows.
986209908Sraj	 */
987209908Sraj	error = law_pci_target(sc->sc_res, &sc->sc_iomem_target,
988209908Sraj	    &sc->sc_ioport_target);
989209908Sraj	if (error != 0) {
990209908Sraj		device_printf(dev, "could not retrieve PCI LAW target info\n");
991209908Sraj		return (error);
992209908Sraj	}
993209908Sraj	error = law_enable(sc->sc_iomem_target, mem_space.base_parent,
994209908Sraj	    mem_space.len);
995209908Sraj	if (error != 0) {
996209908Sraj		device_printf(dev, "could not program LAW for PCI MEM range\n");
997209908Sraj		return (error);
998209908Sraj	}
999209908Sraj	error = law_enable(sc->sc_ioport_target, io_space.base_parent,
1000209908Sraj	    io_space.len);
1001209908Sraj	if (error != 0) {
1002209908Sraj		device_printf(dev, "could not program LAW for PCI IO range\n");
1003209908Sraj		return (error);
1004209908Sraj	}
1005209908Sraj
1006209908Sraj	/*
1007209908Sraj	 * Set outbout and inbound windows.
1008209908Sraj	 */
1009209908Sraj	fsl_pcib_outbound(sc, 0, -1, 0, 0, 0);
1010209908Sraj	if ((error = fsl_pcib_set_range(sc, SYS_RES_MEMORY, 1,
1011209908Sraj	    mem_space.base_parent, mem_space.len)) != 0)
1012209908Sraj		return (error);
1013209908Sraj	if ((error = fsl_pcib_set_range(sc, SYS_RES_IOPORT, 2,
1014209908Sraj	    io_space.base_parent, io_space.len)) != 0)
1015209908Sraj		return (error);
1016209908Sraj
1017209908Sraj	fsl_pcib_outbound(sc, 3, -1, 0, 0, 0);
1018209908Sraj	fsl_pcib_outbound(sc, 4, -1, 0, 0, 0);
1019209908Sraj
1020209908Sraj	fsl_pcib_inbound(sc, 1, -1, 0, 0, 0);
1021209908Sraj	fsl_pcib_inbound(sc, 2, -1, 0, 0, 0);
1022209908Sraj	fsl_pcib_inbound(sc, 3, OCP85XX_TGTIF_RAM1, 0,
1023209908Sraj	    2U * 1024U * 1024U * 1024U, 0);
1024209908Sraj
1025209908Sraj	return (0);
1026209908Sraj}
1027