1244197Sgonzo/*
2244197Sgonzo * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
3244197Sgonzo * All rights reserved.
4244197Sgonzo *
5244197Sgonzo * Redistribution and use in source and binary forms, with or without
6244197Sgonzo * modification, are permitted provided that the following conditions
7244197Sgonzo * are met:
8244197Sgonzo * 1. Redistributions of source code must retain the above copyright
9244197Sgonzo *    notice, this list of conditions and the following disclaimer.
10244197Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
11244197Sgonzo *    notice, this list of conditions and the following disclaimer in the
12244197Sgonzo *    documentation and/or other materials provided with the distribution.
13244197Sgonzo *
14244197Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15244197Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16244197Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17244197Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18244197Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19244197Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20244197Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21244197Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22244197Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23244197Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24244197Sgonzo * SUCH DAMAGE.
25244197Sgonzo */
26244197Sgonzo
27244197Sgonzo#include <sys/cdefs.h>
28244197Sgonzo__FBSDID("$FreeBSD: releng/10.2/sys/arm/versatile/versatile_pci.c 278727 2015-02-13 22:32:02Z ian $");
29244197Sgonzo
30244197Sgonzo#include <sys/param.h>
31244197Sgonzo#include <sys/systm.h>
32244197Sgonzo#include <sys/bus.h>
33244197Sgonzo#include <sys/kernel.h>
34244197Sgonzo#include <sys/module.h>
35244197Sgonzo#include <sys/malloc.h>
36244197Sgonzo#include <sys/rman.h>
37244197Sgonzo#include <sys/watchdog.h>
38244197Sgonzo#include <machine/bus.h>
39244197Sgonzo#include <machine/cpu.h>
40244197Sgonzo#include <machine/intr.h>
41244197Sgonzo
42244197Sgonzo#include <dev/pci/pcivar.h>
43244197Sgonzo#include <dev/pci/pcireg.h>
44244197Sgonzo
45244197Sgonzo#include <dev/pci/pcib_private.h>
46244197Sgonzo#include "pcib_if.h"
47244197Sgonzo
48244197Sgonzo#include <dev/fdt/fdt_common.h>
49244197Sgonzo#include <dev/ofw/openfirm.h>
50244197Sgonzo#include <dev/ofw/ofw_bus.h>
51244197Sgonzo#include <dev/ofw/ofw_bus_subr.h>
52244197Sgonzo
53244197Sgonzo#include <machine/bus.h>
54244197Sgonzo#include <machine/fdt.h>
55244197Sgonzo
56244197Sgonzo#define	MEM_SYS		0
57244197Sgonzo#define	MEM_CORE	1
58244197Sgonzo#define	MEM_BASE	2
59244197Sgonzo#define	MEM_CONF_BASE	3
60244197Sgonzo#define MEM_REGIONS	4
61244197Sgonzo
62244197Sgonzo#define	SYS_PCICTL		0x00
63244197Sgonzo
64244197Sgonzo#define	PCI_CORE_IMAP0		0x00
65244197Sgonzo#define	PCI_CORE_IMAP1		0x04
66244197Sgonzo#define	PCI_CORE_IMAP2		0x08
67244197Sgonzo#define	PCI_CORE_SELFID		0x0C
68244197Sgonzo#define	PCI_CORE_SMAP0		0x10
69244197Sgonzo#define	PCI_CORE_SMAP1		0x14
70244197Sgonzo#define	PCI_CORE_SMAP2		0x18
71244197Sgonzo
72244197Sgonzo#define	VERSATILE_PCI_DEV	0x030010ee
73244197Sgonzo#define	VERSATILE_PCI_CLASS	0x0b400000
74244197Sgonzo
75244197Sgonzo#define	PCI_IO_WINDOW		0x44000000
76244197Sgonzo#define	PCI_IO_SIZE		0x0c000000
77244197Sgonzo#define	PCI_NPREFETCH_WINDOW	0x50000000
78244197Sgonzo#define	PCI_NPREFETCH_SIZE	0x10000000
79244197Sgonzo#define	PCI_PREFETCH_WINDOW	0x60000000
80244197Sgonzo#define	PCI_PREFETCH_SIZE	0x10000000
81244197Sgonzo
82244197Sgonzo#define	VERSATILE_PCI_IRQ_START	27
83244197Sgonzo#define	VERSATILE_PCI_IRQ_END	30
84244197Sgonzo
85244197Sgonzo#ifdef DEBUG
86244197Sgonzo#define dprintf(fmt, args...) do { printf("%s(): ", __func__);   \
87244197Sgonzo    printf(fmt,##args); } while (0)
88244197Sgonzo#else
89244197Sgonzo#define dprintf(fmt, args...)
90244197Sgonzo#endif
91244197Sgonzo
92244197Sgonzo
93244197Sgonzo#define	versatile_pci_sys_read_4(reg)	\
94244197Sgonzo	bus_read_4(sc->mem_res[MEM_SYS], (reg))
95244197Sgonzo#define	versatile_pci_sys_write_4(reg, val)	\
96244197Sgonzo	bus_write_4(sc->mem_res[MEM_SYS], (reg), (val))
97244197Sgonzo
98244197Sgonzo#define	versatile_pci_core_read_4(reg)	\
99244197Sgonzo	bus_read_4(sc->mem_res[MEM_CORE], (reg))
100244197Sgonzo#define	versatile_pci_core_write_4(reg, val)	\
101244197Sgonzo	bus_write_4(sc->mem_res[MEM_CORE], (reg), (val))
102244197Sgonzo
103244197Sgonzo#define	versatile_pci_read_4(reg)	\
104244197Sgonzo	bus_read_4(sc->mem_res[MEM_BASE], (reg))
105244197Sgonzo#define	versatile_pci_write_4(reg, val)	\
106244197Sgonzo	bus_write_4(sc->mem_res[MEM_BASE], (reg), (val))
107244197Sgonzo
108244197Sgonzo#define	versatile_pci_conf_read_4(reg)	\
109244197Sgonzo	bus_read_4(sc->mem_res[MEM_CONF_BASE], (reg))
110244197Sgonzo#define	versatile_pci_conf_write_4(reg, val)	\
111244197Sgonzo	bus_write_4(sc->mem_res[MEM_CONF_BASE], (reg), (val))
112244197Sgonzo#define	versatile_pci_conf_write_2(reg, val)	\
113244197Sgonzo	bus_write_2(sc->mem_res[MEM_CONF_BASE], (reg), (val))
114244197Sgonzo#define	versatile_pci_conf_write_1(reg, val)	\
115244197Sgonzo	bus_write_1(sc->mem_res[MEM_CONF_BASE], (reg), (val))
116244197Sgonzo
117244197Sgonzostruct versatile_pci_softc {
118244197Sgonzo	struct resource*	mem_res[MEM_REGIONS];
119244197Sgonzo	struct resource*	irq_res;
120244197Sgonzo	void*			intr_hl;
121244197Sgonzo
122244197Sgonzo	int			pcib_slot;
123244197Sgonzo
124244197Sgonzo	/* Bus part */
125244197Sgonzo	int			busno;
126244197Sgonzo	struct rman		io_rman;
127244197Sgonzo	struct rman		irq_rman;
128244197Sgonzo	struct rman		mem_rman;
129244197Sgonzo
130244197Sgonzo	struct mtx		mtx;
131244197Sgonzo};
132244197Sgonzo
133244197Sgonzostatic struct resource_spec versatile_pci_mem_spec[] = {
134244197Sgonzo	{ SYS_RES_MEMORY, 0, RF_ACTIVE },
135244197Sgonzo	{ SYS_RES_MEMORY, 1, RF_ACTIVE },
136244197Sgonzo	{ SYS_RES_MEMORY, 2, RF_ACTIVE },
137244197Sgonzo	{ SYS_RES_MEMORY, 3, RF_ACTIVE },
138244197Sgonzo	{ -1, 0, 0 }
139244197Sgonzo};
140244197Sgonzo
141244197Sgonzostatic int
142244197Sgonzoversatile_pci_probe(device_t dev)
143244197Sgonzo{
144244197Sgonzo
145266152Sian	if (!ofw_bus_status_okay(dev))
146266152Sian		return (ENXIO);
147266152Sian
148244197Sgonzo	if (ofw_bus_is_compatible(dev, "versatile,pci")) {
149244197Sgonzo		device_set_desc(dev, "Versatile PCI controller");
150244197Sgonzo		return (BUS_PROBE_DEFAULT);
151244197Sgonzo	}
152244197Sgonzo
153244197Sgonzo	return (ENXIO);
154244197Sgonzo}
155244197Sgonzo
156244197Sgonzostatic int
157244197Sgonzoversatile_pci_attach(device_t dev)
158244197Sgonzo{
159244197Sgonzo	struct versatile_pci_softc *sc = device_get_softc(dev);
160244197Sgonzo	int err;
161244197Sgonzo	int slot;
162244197Sgonzo	uint32_t vendordev_id, class_id;
163244197Sgonzo	uint32_t val;
164244197Sgonzo
165244197Sgonzo	/* Request memory resources */
166244197Sgonzo	err = bus_alloc_resources(dev, versatile_pci_mem_spec,
167244197Sgonzo		sc->mem_res);
168244197Sgonzo	if (err) {
169244197Sgonzo		device_printf(dev, "Error: could not allocate memory resources\n");
170244197Sgonzo		return (ENXIO);
171244197Sgonzo	}
172244197Sgonzo
173244197Sgonzo	/*
174244197Sgonzo	 * Setup memory windows
175244197Sgonzo	 */
176252395Sgonzo	versatile_pci_core_write_4(PCI_CORE_IMAP0, (PCI_IO_WINDOW >> 28));
177252395Sgonzo	versatile_pci_core_write_4(PCI_CORE_IMAP1, (PCI_NPREFETCH_WINDOW >> 28));
178252395Sgonzo	versatile_pci_core_write_4(PCI_CORE_IMAP2, (PCI_PREFETCH_WINDOW >> 28));
179244197Sgonzo
180244197Sgonzo	/*
181244197Sgonzo	 * XXX: this is SDRAM offset >> 28
182252395Sgonzo	 * Unused as of QEMU 1.5
183244197Sgonzo	 */
184252395Sgonzo	versatile_pci_core_write_4(PCI_CORE_SMAP0, (PCI_IO_WINDOW >> 28));
185252395Sgonzo	versatile_pci_core_write_4(PCI_CORE_SMAP1, (PCI_NPREFETCH_WINDOW >> 28));
186252395Sgonzo	versatile_pci_core_write_4(PCI_CORE_SMAP2, (PCI_NPREFETCH_WINDOW >> 28));
187244197Sgonzo
188244197Sgonzo	versatile_pci_sys_write_4(SYS_PCICTL, 1);
189244197Sgonzo
190244197Sgonzo	for (slot = 0; slot <= PCI_SLOTMAX; slot++) {
191244197Sgonzo		vendordev_id = versatile_pci_read_4((slot << 11) + PCIR_DEVVENDOR);
192244197Sgonzo		class_id = versatile_pci_read_4((slot << 11) + PCIR_REVID);
193244197Sgonzo		if ((vendordev_id == VERSATILE_PCI_DEV) &&
194244197Sgonzo		    (class_id == VERSATILE_PCI_CLASS))
195244197Sgonzo			break;
196244197Sgonzo	}
197244197Sgonzo
198244197Sgonzo	if (slot == (PCI_SLOTMAX + 1)) {
199244197Sgonzo		bus_release_resources(dev, versatile_pci_mem_spec,
200244197Sgonzo		    sc->mem_res);
201244197Sgonzo		device_printf(dev, "Versatile PCI core not found\n");
202244197Sgonzo		return (ENXIO);
203244197Sgonzo	}
204244197Sgonzo
205244197Sgonzo	sc->pcib_slot = slot;
206244197Sgonzo	device_printf(dev, "PCI core at slot #%d\n", slot);
207244197Sgonzo
208244197Sgonzo	versatile_pci_core_write_4(PCI_CORE_SELFID, slot);
209244197Sgonzo	val = versatile_pci_conf_read_4((slot << 11) + PCIR_COMMAND);
210244197Sgonzo	val |= (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN | PCIM_CMD_MWRICEN);
211244197Sgonzo	versatile_pci_conf_write_4((slot << 11) + PCIR_COMMAND, val);
212244197Sgonzo
213244197Sgonzo	/* Again SDRAM start >> 28  */
214244197Sgonzo	versatile_pci_write_4((slot << 11) + PCIR_BAR(0), 0);
215244197Sgonzo	versatile_pci_write_4((slot << 11) + PCIR_BAR(1), 0);
216244197Sgonzo	versatile_pci_write_4((slot << 11) + PCIR_BAR(2), 0);
217244197Sgonzo
218244197Sgonzo	/* Prepare resource managers */
219244197Sgonzo	sc->mem_rman.rm_type = RMAN_ARRAY;
220244197Sgonzo	sc->mem_rman.rm_descr = "versatile PCI memory window";
221244197Sgonzo	if (rman_init(&sc->mem_rman) != 0 ||
222244197Sgonzo	    rman_manage_region(&sc->mem_rman, PCI_NPREFETCH_WINDOW,
223244197Sgonzo		PCI_NPREFETCH_WINDOW + PCI_NPREFETCH_SIZE - 1) != 0) {
224244197Sgonzo		panic("versatile_pci_attach: failed to set up memory rman");
225244197Sgonzo	}
226244197Sgonzo
227244197Sgonzo	bootverbose = 1;
228244197Sgonzo	sc->io_rman.rm_type = RMAN_ARRAY;
229244197Sgonzo	sc->io_rman.rm_descr = "versatile PCI IO window";
230244197Sgonzo	if (rman_init(&sc->io_rman) != 0 ||
231244197Sgonzo	    rman_manage_region(&sc->io_rman, PCI_IO_WINDOW,
232244197Sgonzo		PCI_IO_WINDOW + PCI_IO_SIZE - 1) != 0) {
233244197Sgonzo		panic("versatile_pci_attach: failed to set up I/O rman");
234244197Sgonzo	}
235244197Sgonzo
236244197Sgonzo	sc->irq_rman.rm_type = RMAN_ARRAY;
237244197Sgonzo	sc->irq_rman.rm_descr = "versatile PCI IRQs";
238244197Sgonzo	if (rman_init(&sc->irq_rman) != 0 ||
239244197Sgonzo	    rman_manage_region(&sc->irq_rman, VERSATILE_PCI_IRQ_START,
240244197Sgonzo	        VERSATILE_PCI_IRQ_END) != 0) {
241244197Sgonzo		panic("versatile_pci_attach: failed to set up IRQ rman");
242244197Sgonzo	}
243244197Sgonzo
244244197Sgonzo	mtx_init(&sc->mtx, device_get_nameunit(dev), "versatilepci",
245244197Sgonzo			MTX_SPIN);
246244197Sgonzo
247244197Sgonzo	val = versatile_pci_conf_read_4((12 << 11) + PCIR_COMMAND);
248244197Sgonzo
249244197Sgonzo	for (slot = 0; slot <= PCI_SLOTMAX; slot++) {
250244197Sgonzo		vendordev_id = versatile_pci_read_4((slot << 11) + PCIR_DEVVENDOR);
251244197Sgonzo		class_id = versatile_pci_read_4((slot << 11) + PCIR_REVID);
252244197Sgonzo
253244197Sgonzo		if (slot == sc->pcib_slot)
254244197Sgonzo			continue;
255244197Sgonzo
256244197Sgonzo		if ((vendordev_id == 0xffffffff) &&
257244197Sgonzo		    (class_id == 0xffffffff))
258244197Sgonzo			continue;
259244197Sgonzo
260244197Sgonzo		val = versatile_pci_conf_read_4((slot << 11) + PCIR_COMMAND);
261244197Sgonzo		val |= PCIM_CMD_MEMEN | PCIM_CMD_PORTEN;
262244197Sgonzo		versatile_pci_conf_write_4((slot << 11) + PCIR_COMMAND, val);
263244197Sgonzo	}
264244197Sgonzo
265244197Sgonzo	device_add_child(dev, "pci", 0);
266244197Sgonzo	return (bus_generic_attach(dev));
267244197Sgonzo}
268244197Sgonzo
269244197Sgonzostatic int
270244197Sgonzoversatile_pci_read_ivar(device_t dev, device_t child, int which,
271244197Sgonzo    uintptr_t *result)
272244197Sgonzo{
273244197Sgonzo	struct versatile_pci_softc *sc = device_get_softc(dev);
274244197Sgonzo
275244197Sgonzo	switch (which) {
276244197Sgonzo	case PCIB_IVAR_DOMAIN:
277244197Sgonzo		*result = 0;
278244197Sgonzo		return (0);
279244197Sgonzo	case PCIB_IVAR_BUS:
280244197Sgonzo		*result = sc->busno;
281244197Sgonzo		return (0);
282244197Sgonzo	}
283244197Sgonzo
284244197Sgonzo	return (ENOENT);
285244197Sgonzo}
286244197Sgonzo
287244197Sgonzostatic int
288244197Sgonzoversatile_pci_write_ivar(device_t dev, device_t child, int which,
289244197Sgonzo    uintptr_t result)
290244197Sgonzo{
291244197Sgonzo	struct versatile_pci_softc * sc = device_get_softc(dev);
292244197Sgonzo
293244197Sgonzo	switch (which) {
294244197Sgonzo	case PCIB_IVAR_BUS:
295244197Sgonzo		sc->busno = result;
296244197Sgonzo		return (0);
297244197Sgonzo	}
298244197Sgonzo
299244197Sgonzo	return (ENOENT);
300244197Sgonzo}
301244197Sgonzo
302244197Sgonzostatic struct resource *
303244197Sgonzoversatile_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
304244197Sgonzo    u_long start, u_long end, u_long count, u_int flags)
305244197Sgonzo{
306244197Sgonzo
307244197Sgonzo	struct versatile_pci_softc *sc = device_get_softc(bus);
308244197Sgonzo	struct resource *rv;
309244197Sgonzo	struct rman *rm;
310244197Sgonzo
311252395Sgonzo	dprintf("Alloc resources %d, %08lx..%08lx, %ld\n", type, start, end, count);
312244197Sgonzo
313244197Sgonzo	switch (type) {
314244197Sgonzo	case SYS_RES_IOPORT:
315244197Sgonzo		rm = &sc->io_rman;
316244197Sgonzo		break;
317244197Sgonzo	case SYS_RES_IRQ:
318244197Sgonzo		rm = &sc->irq_rman;
319244197Sgonzo		break;
320244197Sgonzo	case SYS_RES_MEMORY:
321244197Sgonzo		rm = &sc->mem_rman;
322244197Sgonzo		break;
323244197Sgonzo	default:
324244197Sgonzo		return (NULL);
325244197Sgonzo	}
326244197Sgonzo
327244197Sgonzo	rv = rman_reserve_resource(rm, start, end, count, flags, child);
328244197Sgonzo
329244197Sgonzo	if (rv == NULL)
330244197Sgonzo		return (NULL);
331244197Sgonzo
332244197Sgonzo	rman_set_rid(rv, *rid);
333244197Sgonzo
334244197Sgonzo	if (flags & RF_ACTIVE) {
335244197Sgonzo		if (bus_activate_resource(child, type, *rid, rv)) {
336244197Sgonzo			rman_release_resource(rv);
337244197Sgonzo			return (NULL);
338244197Sgonzo		}
339244197Sgonzo	}
340244197Sgonzo	return (rv);
341244197Sgonzo}
342244197Sgonzo
343244197Sgonzostatic int
344244197Sgonzoversatile_pci_activate_resource(device_t bus, device_t child, int type, int rid,
345244197Sgonzo    struct resource *r)
346244197Sgonzo{
347244197Sgonzo	vm_offset_t vaddr;
348252395Sgonzo	int res;
349244197Sgonzo
350252395Sgonzo	switch(type) {
351252395Sgonzo	case SYS_RES_MEMORY:
352252395Sgonzo	case SYS_RES_IOPORT:
353252395Sgonzo		vaddr = (vm_offset_t)pmap_mapdev(rman_get_start(r),
354252395Sgonzo				rman_get_size(r));
355252395Sgonzo		rman_set_bushandle(r, vaddr);
356278727Sian		rman_set_bustag(r, arm_base_bs_tag);
357252395Sgonzo		res = rman_activate_resource(r);
358252395Sgonzo		break;
359252395Sgonzo	case SYS_RES_IRQ:
360252395Sgonzo		res = (BUS_ACTIVATE_RESOURCE(device_get_parent(bus),
361252395Sgonzo		    child, type, rid, r));
362252395Sgonzo		break;
363256292Sdim	default:
364256292Sdim		res = ENXIO;
365256292Sdim		break;
366244197Sgonzo	}
367252395Sgonzo
368244197Sgonzo	return (res);
369244197Sgonzo}
370244197Sgonzo
371244197Sgonzostatic int
372244197Sgonzoversatile_pci_setup_intr(device_t bus, device_t child, struct resource *ires,
373244197Sgonzo	    int flags, driver_filter_t *filt, driver_intr_t *handler,
374244197Sgonzo	    void *arg, void **cookiep)
375244197Sgonzo{
376244197Sgonzo
377244197Sgonzo	return BUS_SETUP_INTR(device_get_parent(bus), bus, ires, flags,
378244197Sgonzo	    filt, handler, arg, cookiep);
379244197Sgonzo}
380244197Sgonzo
381244197Sgonzostatic int
382244197Sgonzoversatile_pci_teardown_intr(device_t dev, device_t child, struct resource *ires,
383244197Sgonzo    void *cookie)
384244197Sgonzo{
385244197Sgonzo
386244197Sgonzo	return BUS_TEARDOWN_INTR(device_get_parent(dev), dev, ires, cookie);
387244197Sgonzo}
388244197Sgonzo
389244197Sgonzo
390244197Sgonzo
391244197Sgonzostatic int
392244197Sgonzoversatile_pci_maxslots(device_t dev)
393244197Sgonzo{
394244197Sgonzo
395244197Sgonzo	return (PCI_SLOTMAX);
396244197Sgonzo}
397244197Sgonzo
398244197Sgonzostatic int
399244197Sgonzoversatile_pci_route_interrupt(device_t pcib, device_t device, int pin)
400244197Sgonzo{
401244197Sgonzo
402244197Sgonzo	return (27 + ((pci_get_slot(device) + pin - 1) & 3));
403244197Sgonzo}
404244197Sgonzo
405244197Sgonzostatic uint32_t
406244197Sgonzoversatile_pci_read_config(device_t dev, u_int bus, u_int slot, u_int func,
407244197Sgonzo    u_int reg, int bytes)
408244197Sgonzo{
409244197Sgonzo	struct versatile_pci_softc *sc = device_get_softc(dev);
410244197Sgonzo	uint32_t data;
411244197Sgonzo	uint32_t shift, mask;
412244197Sgonzo	uint32_t addr;
413244197Sgonzo
414244197Sgonzo	if (sc->pcib_slot == slot) {
415244197Sgonzo		switch (bytes) {
416244197Sgonzo			case 4:
417244197Sgonzo				return (0xffffffff);
418244197Sgonzo				break;
419244197Sgonzo			case 2:
420244197Sgonzo				return (0xffff);
421244197Sgonzo				break;
422244197Sgonzo			case 1:
423244197Sgonzo				return (0xff);
424244197Sgonzo				break;
425244197Sgonzo		}
426244197Sgonzo	}
427244197Sgonzo
428244197Sgonzo	addr = (bus << 16) | (slot << 11) | (func << 8) | (reg & ~3);
429244197Sgonzo
430244197Sgonzo	/* register access is 32-bit aligned */
431244197Sgonzo	shift = (reg & 3) * 8;
432244197Sgonzo
433244197Sgonzo	/* Create a mask based on the width, post-shift */
434244197Sgonzo	if (bytes == 2)
435244197Sgonzo		mask = 0xffff;
436244197Sgonzo	else if (bytes == 1)
437244197Sgonzo		mask = 0xff;
438244197Sgonzo	else
439244197Sgonzo		mask = 0xffffffff;
440244197Sgonzo
441244197Sgonzo	dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot,
442244197Sgonzo	    func, reg, bytes);
443244197Sgonzo
444244197Sgonzo	mtx_lock_spin(&sc->mtx);
445244197Sgonzo	data = versatile_pci_conf_read_4(addr);
446244197Sgonzo	mtx_unlock_spin(&sc->mtx);
447244197Sgonzo
448244197Sgonzo	/* get request bytes from 32-bit word */
449244197Sgonzo	data = (data >> shift) & mask;
450244197Sgonzo
451244197Sgonzo	dprintf("%s: read 0x%x\n", __func__, data);
452244197Sgonzo
453244197Sgonzo	return (data);
454244197Sgonzo}
455244197Sgonzo
456244197Sgonzostatic void
457244197Sgonzoversatile_pci_write_config(device_t dev, u_int bus, u_int slot, u_int func,
458244197Sgonzo    u_int reg, uint32_t data, int bytes)
459244197Sgonzo{
460244197Sgonzo
461244197Sgonzo	struct versatile_pci_softc *sc = device_get_softc(dev);
462244197Sgonzo	uint32_t addr;
463244197Sgonzo
464244197Sgonzo	dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot,
465244197Sgonzo	    func, reg, bytes);
466244197Sgonzo
467244197Sgonzo	if (sc->pcib_slot == slot)
468244197Sgonzo		return;
469244197Sgonzo
470244197Sgonzo	addr = (bus << 16) | (slot << 11) | (func << 8) | reg;
471244197Sgonzo	mtx_lock_spin(&sc->mtx);
472244197Sgonzo	switch (bytes) {
473244197Sgonzo		case 4:
474244197Sgonzo			versatile_pci_conf_write_4(addr, data);
475244197Sgonzo			break;
476244197Sgonzo		case 2:
477244197Sgonzo			versatile_pci_conf_write_2(addr, data);
478244197Sgonzo			break;
479244197Sgonzo		case 1:
480244197Sgonzo			versatile_pci_conf_write_1(addr, data);
481244197Sgonzo			break;
482244197Sgonzo	}
483244197Sgonzo	mtx_unlock_spin(&sc->mtx);
484244197Sgonzo}
485244197Sgonzo
486244197Sgonzostatic device_method_t versatile_pci_methods[] = {
487244197Sgonzo	DEVMETHOD(device_probe,		versatile_pci_probe),
488244197Sgonzo	DEVMETHOD(device_attach,	versatile_pci_attach),
489244197Sgonzo
490244197Sgonzo	/* Bus interface */
491244197Sgonzo	DEVMETHOD(bus_read_ivar,	versatile_pci_read_ivar),
492244197Sgonzo	DEVMETHOD(bus_write_ivar,	versatile_pci_write_ivar),
493244197Sgonzo	DEVMETHOD(bus_alloc_resource,	versatile_pci_alloc_resource),
494244197Sgonzo	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
495244197Sgonzo	DEVMETHOD(bus_activate_resource, versatile_pci_activate_resource),
496244197Sgonzo	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
497244197Sgonzo	DEVMETHOD(bus_setup_intr,	versatile_pci_setup_intr),
498244197Sgonzo	DEVMETHOD(bus_teardown_intr,	versatile_pci_teardown_intr),
499244197Sgonzo
500244197Sgonzo	/* pcib interface */
501244197Sgonzo	DEVMETHOD(pcib_maxslots,	versatile_pci_maxslots),
502244197Sgonzo	DEVMETHOD(pcib_read_config,	versatile_pci_read_config),
503244197Sgonzo	DEVMETHOD(pcib_write_config,	versatile_pci_write_config),
504244197Sgonzo	DEVMETHOD(pcib_route_interrupt,	versatile_pci_route_interrupt),
505244197Sgonzo
506244197Sgonzo	DEVMETHOD_END
507244197Sgonzo};
508244197Sgonzo
509244197Sgonzostatic driver_t versatile_pci_driver = {
510244197Sgonzo	"pcib",
511244197Sgonzo	versatile_pci_methods,
512244197Sgonzo	sizeof(struct versatile_pci_softc),
513244197Sgonzo};
514244197Sgonzo
515244197Sgonzostatic devclass_t versatile_pci_devclass;
516244197Sgonzo
517244197SgonzoDRIVER_MODULE(versatile_pci, simplebus, versatile_pci_driver, versatile_pci_devclass, 0, 0);
518