1171626Scognet/*-
2171626Scognet * Copyright (c) 2006 Olivier Houchard
3171626Scognet * All rights reserved.
4171626Scognet *
5171626Scognet * Redistribution and use in source and binary forms, with or without
6171626Scognet * modification, are permitted provided that the following conditions
7171626Scognet * are met:
8171626Scognet * 1. Redistributions of source code must retain the above copyright
9171626Scognet *    notice, this list of conditions and the following disclaimer.
10171626Scognet * 2. Redistributions in binary form must reproduce the above copyright
11171626Scognet *    notice, this list of conditions and the following disclaimer in the
12171626Scognet *    documentation and/or other materials provided with the distribution.
13171626Scognet *
14171626Scognet * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
15171626Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16171626Scognet * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17171626Scognet * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR
18171626Scognet * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19171626Scognet * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20171626Scognet * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21171626Scognet * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22171626Scognet * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23171626Scognet * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24171626Scognet * POSSIBILITY OF SUCH DAMAGE.
25171626Scognet */
26171626Scognet
27171626Scognet#include <sys/cdefs.h>
28171626Scognet__FBSDID("$FreeBSD$");
29171626Scognet
30171626Scognet#include <sys/param.h>
31171626Scognet#include <sys/systm.h>
32171626Scognet#include <sys/bus.h>
33171626Scognet#include <sys/kernel.h>
34171626Scognet#include <sys/module.h>
35171626Scognet#include <sys/types.h>
36171626Scognet#include <sys/rman.h>
37171626Scognet
38171626Scognet#include <machine/bus.h>
39171626Scognet#include <machine/cpu.h>
40171626Scognet#include <machine/pcb.h>
41171626Scognet#include <vm/vm.h>
42171626Scognet#include <vm/pmap.h>
43171626Scognet#include <vm/vm_extern.h>
44171626Scognet
45171626Scognet#include <arm/xscale/i8134x/i81342reg.h>
46171626Scognet#include <arm/xscale/i8134x/i81342var.h>
47171626Scognet
48171626Scognet#include <dev/pci/pcivar.h>
49171626Scognet#include <dev/pci/pcib_private.h>
50171626Scognet#include "pcib_if.h"
51171626Scognet
52171626Scognet#include <dev/pci/pcireg.h>
53171626Scognet
54171626Scognetstatic pcib_read_config_t i81342_pci_read_config;
55171626Scognetstatic pcib_write_config_t i81342_pci_write_config;
56171626Scognet
57171626Scognetstatic int
58171626Scogneti81342_pci_probe(device_t dev)
59171626Scognet{
60171626Scognet	struct i81342_pci_softc *sc;
61171626Scognet
62171626Scognet	sc = device_get_softc(dev);
63171626Scognet	if (device_get_unit(dev) == 0) {
64171626Scognet		device_set_desc(dev, "i81342 PCI-X bus");
65171626Scognet		sc->sc_is_atux = 1;
66171626Scognet	} else {
67171626Scognet		device_set_desc(dev, "i81342 PCIe bus");
68171626Scognet		sc->sc_is_atux = 0;
69171626Scognet	}
70171626Scognet	return (0);
71171626Scognet}
72171626Scognet
73171626Scognet#define PCI_MAPREG_MEM_PREFETCHABLE_MASK	0x00000008
74171626Scognet#define PCI_MAPREG_MEM_TYPE_64BIT		0x00000004
75171626Scognet
76171626Scognetstatic int
77171626Scogneti81342_pci_attach(device_t dev)
78171626Scognet{
79171626Scognet	struct i81342_softc *parent_sc;
80171626Scognet	struct i81342_pci_softc *sc;
81171626Scognet	uint32_t memsize, memstart;
82171626Scognet	uint32_t reg;
83171626Scognet	int func;
84171626Scognet	uint32_t busno;
85171626Scognet
86171626Scognet	sc = device_get_softc(dev);
87171626Scognet	parent_sc = device_get_softc(device_get_parent(dev));
88171626Scognet	sc->sc_atu_sh = sc->sc_is_atux ? parent_sc->sc_atux_sh :
89171626Scognet	    parent_sc->sc_atue_sh;
90171626Scognet	sc->sc_st = parent_sc->sc_st;
91171626Scognet	if (bus_space_read_4(sc->sc_st, parent_sc->sc_sh, IOP34X_ESSTSR0)
92171626Scognet	    & IOP34X_INT_SEL_PCIX) {
93171626Scognet		if (sc->sc_is_atux)
94171626Scognet			func = 5;
95171626Scognet		else
96171626Scognet			func = 0;
97171626Scognet	} else {
98171626Scognet		if (sc->sc_is_atux)
99171626Scognet			func = 0;
100171626Scognet		else
101171626Scognet			func = 5;
102171626Scognet	}
103171626Scognet	i81342_io_bs_init(&sc->sc_pciio, sc);
104171626Scognet	i81342_mem_bs_init(&sc->sc_pcimem, sc);
105171626Scognet	i81342_sdram_bounds(sc->sc_st, IOP34X_VADDR, &memstart, &memsize);
106171626Scognet	if (sc->sc_is_atux) {
107171626Scognet		reg = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCSR);
108171626Scognet		if (reg & ATUX_P_RSTOUT) {
109171626Scognet			bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_PCSR,
110171626Scognet			    reg &~ ATUX_P_RSTOUT);
111171626Scognet			DELAY(200);
112171626Scognet		}
113171626Scognet	}
114171626Scognet	/* Setup the Inbound windows. */
115171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IABAR0, 0);
116171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IAUBAR0, 0);
117171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR0, 0);
118171626Scognet
119171626Scognet	/* Set the mapping Physical address <=> PCI address */
120171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IABAR1,
121171626Scognet	    memstart | PCI_MAPREG_MEM_PREFETCHABLE_MASK |
122171626Scognet	    PCI_MAPREG_MEM_TYPE_64BIT);
123171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IAUBAR1, 0);
124171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR1, ~(memsize - 1)
125171626Scognet	     &~(0xfff));
126171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR1, memstart);
127171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IAUTVR1, 0);
128171626Scognet
129171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IABAR2, 0);
130171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IAUBAR2, 0);
131171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR2, 0);
132171626Scognet
133171626Scognet	/* Setup the Outbound IO Bar */
134171626Scognet	if (sc->sc_is_atux)
135171626Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OIOBAR,
136171626Scognet		    (IOP34X_PCIX_OIOBAR >> 4) | func);
137171626Scognet	else
138171626Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OIOBAR,
139171626Scognet		    (IOP34X_PCIE_OIOBAR >> 4) | func);
140171626Scognet
141171626Scognet	/* Setup the Outbound windows */
142171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OUMBAR0, 0);
143171626Scognet	if (sc->sc_is_atux)
144171626Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OUMBAR1,
145171626Scognet		    (IOP34X_PCIX_OMBAR >> 32) | (func << ATU_OUMBAR_FUNC) |
146171626Scognet		    ATU_OUMBAR_EN);
147171626Scognet	else
148171626Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OUMBAR1,
149171626Scognet		    (IOP34X_PCIE_OMBAR >> 32) | (func << ATU_OUMBAR_FUNC) |
150171626Scognet		    ATU_OUMBAR_EN);
151171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OUMWTVR1, 0);
152171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OUMBAR2, 0);
153171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OUMBAR3, 0);
154171626Scognet
155171626Scognet	/* Enable the outbound windows. */
156171626Scognet	reg = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_CR);
157171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_CR,
158171626Scognet	    reg | ATU_CR_OUT_EN);
159171626Scognet
160171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_ISR,
161171626Scognet	    bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_ISR) & ATUX_ISR_ERRMSK);
162171626Scognet	/*
163171626Scognet	 * Enable bus mastering, memory access, SERR, and parity
164171626Scognet	 * checking on the ATU.
165171626Scognet	 */
166171626Scognet	if (sc->sc_is_atux) {
167171626Scognet		busno = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCIXSR);
168171626Scognet		busno = PCIXSR_BUSNO(busno);
169171626Scognet	} else {
170171626Scognet		busno = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCSR);
171171626Scognet		busno = PCIE_BUSNO(busno);
172171626Scognet	}
173171626Scognet	reg = bus_space_read_2(sc->sc_st, sc->sc_atu_sh, ATU_CMD);
174171626Scognet	reg |= PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_PERRESPEN |
175171626Scognet	    PCIM_CMD_SERRESPEN;
176171626Scognet	bus_space_write_2(sc->sc_st, sc->sc_atu_sh, ATU_CMD, reg);
177171626Scognet	sc->sc_busno = busno;
178171626Scognet	/* Initialize memory and i/o rmans. */
179171626Scognet	sc->sc_io_rman.rm_type = RMAN_ARRAY;
180171626Scognet	sc->sc_io_rman.rm_descr = "I81342 PCI I/O Ports";
181171626Scognet	if (rman_init(&sc->sc_io_rman) != 0 ||
182236987Simp		rman_manage_region(&sc->sc_io_rman,
183171626Scognet		sc->sc_is_atux ? IOP34X_PCIX_OIOBAR_VADDR :
184171626Scognet		IOP34X_PCIE_OIOBAR_VADDR,
185171626Scognet		(sc->sc_is_atux ? IOP34X_PCIX_OIOBAR_VADDR :
186171626Scognet		IOP34X_PCIE_OIOBAR_VADDR) + IOP34X_OIOBAR_SIZE) != 0) {
187179745Skevlo		panic("i81342_pci_probe: failed to set up I/O rman");
188171626Scognet	}
189171626Scognet	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
190171626Scognet	sc->sc_mem_rman.rm_descr = "I81342 PCI Memory";
191171626Scognet	if (rman_init(&sc->sc_mem_rman) != 0 ||
192236987Simp	    rman_manage_region(&sc->sc_mem_rman,
193171626Scognet	    0, 0xffffffff) != 0) {
194171626Scognet		panic("i81342_pci_attach: failed to set up memory rman");
195171626Scognet	}
196171626Scognet	sc->sc_irq_rman.rm_type = RMAN_ARRAY;
197171626Scognet	sc->sc_irq_rman.rm_descr = "i81342 PCI IRQs";
198171626Scognet	if (sc->sc_is_atux) {
199171626Scognet		if (rman_init(&sc->sc_irq_rman) != 0 ||
200236987Simp		    rman_manage_region(&sc->sc_irq_rman, ICU_INT_XINT0,
201171626Scognet		    ICU_INT_XINT3) != 0)
202171626Scognet			panic("i83142_pci_attach: failed to set up IRQ rman");
203171626Scognet	} else {
204171626Scognet		if (rman_init(&sc->sc_irq_rman) != 0 ||
205236987Simp		    rman_manage_region(&sc->sc_irq_rman, ICU_INT_ATUE_MA,
206171626Scognet		    ICU_INT_ATUE_MD) != 0)
207171626Scognet			panic("i81342_pci_attach: failed to set up IRQ rman");
208171626Scognet
209171626Scognet	}
210171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_ISR,
211171626Scognet	    bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_ISR) & ATUX_ISR_ERRMSK);
212171626Scognet	device_add_child(dev, "pci", busno);
213171626Scognet	return (bus_generic_attach(dev));
214171626Scognet}
215171626Scognet
216171626Scognetstatic int
217171626Scogneti81342_pci_maxslots(device_t dev)
218171626Scognet{
219171626Scognet
220171626Scognet	return (PCI_SLOTMAX);
221171626Scognet}
222171626Scognet
223171626Scognetstatic void
224171626Scogneti81342_pci_conf_setup(struct i81342_pci_softc *sc, int bus, int slot, int func,
225171626Scognet    int reg, uint32_t *addr)
226171626Scognet{
227171626Scognet	uint32_t busno;
228171626Scognet
229171626Scognet	if (sc->sc_is_atux) {
230171626Scognet		busno = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCIXSR);
231171626Scognet		busno = PCIXSR_BUSNO(busno);
232171626Scognet	} else {
233171626Scognet		busno = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCSR);
234171626Scognet		busno = PCIE_BUSNO(busno);
235171626Scognet	}
236171626Scognet	bus &= 0xff;
237171626Scognet	slot &= 0x1f;
238171626Scognet	func &= 0x7;
239171626Scognet	if (sc->sc_is_atux) {
240171626Scognet		if (busno == bus)
241171626Scognet			*addr = (1 << (slot + 16)) | (slot << 11) |
242171626Scognet			    (func << 8) | reg;
243171626Scognet		else
244236987Simp			*addr = (bus << 16) | (slot << 11) | (func << 11) |
245171626Scognet			    reg | 1;
246171626Scognet	} else {
247171626Scognet		*addr = (bus << 24) | (slot << 19) | (func << 16) | reg;
248171626Scognet		if (bus != busno)
249171626Scognet			*addr |= 1;
250171626Scognet	}
251171626Scognet}
252171626Scognet
253171626Scognetstatic u_int32_t
254171626Scogneti81342_pci_read_config(device_t dev, u_int bus, u_int slot, u_int func,
255171626Scognet    u_int reg, int bytes)
256171626Scognet{
257171626Scognet	struct i81342_pci_softc *sc = device_get_softc(dev);
258171626Scognet	uint32_t addr;
259171626Scognet	uint32_t ret = 0;
260171626Scognet	uint32_t isr;
261171626Scognet	int err = 0;
262171626Scognet	vm_offset_t va;
263171626Scognet
264171626Scognet	i81342_pci_conf_setup(sc, bus, slot, func, reg & ~3, &addr);
265171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, sc->sc_is_atux ?
266171626Scognet	    ATUX_OCCAR : ATUE_OCCAR, addr);
267171626Scognet	if (sc->sc_is_atux)
268171626Scognet		va = sc->sc_atu_sh + ATUX_OCCDR;
269171626Scognet	else
270171626Scognet		va = sc->sc_atu_sh + ATUE_OCCDR;
271171626Scognet	switch (bytes) {
272171626Scognet	case 1:
273171626Scognet		err = badaddr_read((void*)(va + (reg & 3)), 1, &ret);
274171626Scognet		break;
275171626Scognet	case 2:
276171626Scognet		err = badaddr_read((void*)(va + (reg & 3)), 2, &ret);
277171626Scognet		break;
278171626Scognet	case 4:
279171626Scognet		err = badaddr_read((void *)(va) , 4, &ret);
280171626Scognet		break;
281171626Scognet	default:
282171626Scognet		printf("i81342_read_config: invalid size %d\n", bytes);
283171626Scognet		ret = -1;
284171626Scognet	}
285171626Scognet	if (err) {
286171626Scognet		isr = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_ISR);
287171626Scognet		if (sc->sc_is_atux)
288171626Scognet			isr &= ATUX_ISR_ERRMSK;
289171626Scognet		else
290171626Scognet			isr &= ATUE_ISR_ERRMSK;
291171626Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_ISR, isr);
292171626Scognet		ret = -1;
293171626Scognet	}
294171626Scognet
295171626Scognet	return (ret);
296171626Scognet}
297171626Scognet
298171626Scognetstatic void
299236987Simpi81342_pci_write_config(device_t dev, u_int bus, u_int slot, u_int func,
300171626Scognet    u_int reg, u_int32_t data, int bytes)
301171626Scognet{
302171626Scognet	struct i81342_pci_softc *sc = device_get_softc(dev);
303171626Scognet	uint32_t addr;
304171626Scognet	vm_offset_t va;
305171626Scognet
306171626Scognet	i81342_pci_conf_setup(sc, bus, slot, func, reg & ~3, &addr);
307171626Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, sc->sc_is_atux ?
308171626Scognet	    ATUX_OCCAR : ATUE_OCCAR, addr);
309171626Scognet	va = sc->sc_is_atux ? ATUX_OCCDR : ATUE_OCCDR;
310171626Scognet		switch (bytes) {
311171626Scognet	case 1:
312171626Scognet		bus_space_write_1(sc->sc_st, sc->sc_atu_sh, va + (reg & 3)
313171626Scognet		    , data);
314171626Scognet		break;
315171626Scognet	case 2:
316171626Scognet		bus_space_write_2(sc->sc_st, sc->sc_atu_sh, va + (reg & 3)
317171626Scognet		    , data);
318171626Scognet		break;
319171626Scognet	case 4:
320171626Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh, va, data);
321171626Scognet		break;
322171626Scognet	default:
323171626Scognet		printf("i81342_pci_write_config: Invalid size : %d\n", bytes);
324171626Scognet	}
325171626Scognet
326171626Scognet
327171626Scognet}
328171626Scognet
329171626Scognetstatic struct resource *
330171626Scogneti81342_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
331171626Scognet   u_long start, u_long end, u_long count, u_int flags)
332171626Scognet{
333171626Scognet	struct i81342_pci_softc *sc = device_get_softc(bus);
334171626Scognet	struct resource *rv;
335171626Scognet	struct rman *rm;
336171626Scognet	bus_space_tag_t bt = NULL;
337171626Scognet	bus_space_handle_t bh = 0;
338171626Scognet
339171626Scognet	switch (type) {
340171626Scognet	case SYS_RES_IRQ:
341171626Scognet		rm = &sc->sc_irq_rman;
342171626Scognet		break;
343171626Scognet	case SYS_RES_MEMORY:
344171626Scognet		rm = &sc->sc_mem_rman;
345171626Scognet		bt = &sc->sc_pcimem;
346171626Scognet		bh = 0;
347171626Scognet		break;
348171626Scognet	case SYS_RES_IOPORT:
349171626Scognet		rm = &sc->sc_io_rman;
350171626Scognet		bt = &sc->sc_pciio;
351171626Scognet		bh = sc->sc_is_atux ? IOP34X_PCIX_OIOBAR_VADDR :
352171626Scognet		    IOP34X_PCIE_OIOBAR_VADDR;
353171626Scognet		start += bh;
354171626Scognet		end += bh;
355171626Scognet		break;
356171626Scognet	default:
357171626Scognet		return (NULL);
358171626Scognet	}
359171626Scognet
360171626Scognet	rv = rman_reserve_resource(rm, start, end, count, flags, child);
361171626Scognet	if (rv == NULL)
362171626Scognet		return (NULL);
363171626Scognet	rman_set_rid(rv, *rid);
364171626Scognet	if (type != SYS_RES_IRQ) {
365171626Scognet		if (type == SYS_RES_MEMORY)
366171626Scognet			bh += (rman_get_start(rv));
367171626Scognet		rman_set_bustag(rv, bt);
368171626Scognet		rman_set_bushandle(rv, bh);
369171626Scognet		if (flags & RF_ACTIVE) {
370171626Scognet			if (bus_activate_resource(child, type, *rid, rv)) {
371171626Scognet				rman_release_resource(rv);
372171626Scognet				return (NULL);
373171626Scognet			}
374236987Simp		}
375171626Scognet	}
376171626Scognet	return (rv);
377171626Scognet
378171626Scognet
379171626Scognet	return (NULL);
380171626Scognet}
381171626Scognet
382171626Scognetstatic int
383171626Scogneti81342_pci_activate_resource(device_t bus, device_t child, int type, int rid,
384171626Scognet    struct resource *r)
385171626Scognet{
386171626Scognet	u_long p;
387171626Scognet	int error;
388171626Scognet
389171626Scognet	if (type == SYS_RES_MEMORY) {
390171626Scognet		error = bus_space_map(rman_get_bustag(r),
391171626Scognet		    rman_get_bushandle(r), rman_get_size(r), 0, &p);
392171626Scognet		if (error)
393171626Scognet			return (error);
394171626Scognet		rman_set_bushandle(r, p);
395171626Scognet
396171626Scognet	}
397171626Scognet	return (rman_activate_resource(r));
398171626Scognet}
399171626Scognet
400171626Scognetstatic int
401171626Scogneti81342_pci_setup_intr(device_t dev, device_t child, struct resource *ires,
402171626Scognet    int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg,
403171626Scognet    void **cookiep)
404171626Scognet{
405171626Scognet
406171626Scognet	return (BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags,
407171626Scognet	    filt, intr, arg, cookiep));
408171626Scognet}
409171626Scognet
410171626Scognet
411171626Scognet
412171626Scognetstatic int
413171626Scogneti81342_pci_teardown_intr(device_t dev, device_t child, struct resource *res,
414171626Scognet    void *cookie)
415171626Scognet{
416171626Scognet	return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
417171626Scognet}
418171626Scognet
419171626Scognetstatic int
420171626Scogneti81342_pci_route_interrupt(device_t pcib, device_t dev, int pin)
421171626Scognet{
422171626Scognet	struct i81342_pci_softc *sc;
423171626Scognet	int device;
424171626Scognet
425171626Scognet	device = pci_get_slot(dev);
426171626Scognet	sc = device_get_softc(pcib);
427171626Scognet	/* XXX: Is board specific */
428171626Scognet	if (sc->sc_is_atux) {
429171626Scognet		/* PCI-X */
430171626Scognet		switch(device) {
431171626Scognet		case 1:
432171626Scognet			switch (pin) {
433171626Scognet			case 1:
434171626Scognet				return (ICU_INT_XINT1);
435171626Scognet			case 2:
436171626Scognet				return (ICU_INT_XINT2);
437171626Scognet			case 3:
438171626Scognet				return (ICU_INT_XINT3);
439171626Scognet			case 4:
440171626Scognet				return (ICU_INT_XINT0);
441171626Scognet			default:
442171626Scognet				break;
443171626Scognet			}
444171626Scognet		case 2:
445171626Scognet			switch (pin) {
446171626Scognet			case 1:
447171626Scognet				return (ICU_INT_XINT2);
448171626Scognet			case 2:
449171626Scognet				return (ICU_INT_XINT3);
450171626Scognet			case 3:
451171626Scognet				return (ICU_INT_XINT2);
452171626Scognet			case 4:
453171626Scognet				return (ICU_INT_XINT3);
454171626Scognet			default:
455171626Scognet				break;
456171626Scognet			}
457171626Scognet		}
458171626Scognet
459171626Scognet	} else {
460171626Scognet		switch (pin) {
461171626Scognet		case 1:
462171626Scognet			return (ICU_INT_ATUE_MA);
463171626Scognet		case 2:
464171626Scognet			return (ICU_INT_ATUE_MB);
465171626Scognet		case 3:
466171626Scognet			return (ICU_INT_ATUE_MC);
467171626Scognet		case 4:
468171626Scognet			return (ICU_INT_ATUE_MD);
469171626Scognet		default:
470171626Scognet			break;
471171626Scognet		}
472171626Scognet	}
473171626Scognet	printf("Warning: couldn't map %s IRQ for device %d pin %d\n",
474171626Scognet	    sc->sc_is_atux ? "PCI-X" : "PCIe", device, pin);
475171626Scognet	return (-1);
476171626Scognet}
477171626Scognet
478171626Scognetstatic int
479171626Scogneti81342_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
480171626Scognet{
481171626Scognet	struct i81342_pci_softc *sc = device_get_softc(dev);
482171626Scognet	switch (which) {
483172394Smarius	case PCIB_IVAR_DOMAIN:
484172394Smarius		*result = 0;
485172394Smarius		return (0);
486171626Scognet	case PCIB_IVAR_BUS:
487171626Scognet		*result = sc->sc_busno;
488171626Scognet		return (0);
489171626Scognet
490171626Scognet	}
491171626Scognet	return (ENOENT);
492171626Scognet}
493171626Scognet
494171626Scognetstatic int
495171626Scogneti81342_write_ivar(device_t dev, device_t child, int which, uintptr_t result)
496171626Scognet{
497171626Scognet	struct i81342_pci_softc * sc = device_get_softc(dev);
498171626Scognet
499171626Scognet	switch (which) {
500172394Smarius	case PCIB_IVAR_DOMAIN:
501172394Smarius		return (EINVAL);
502171626Scognet	case PCIB_IVAR_BUS:
503171626Scognet		sc->sc_busno = result;
504171626Scognet		return (0);
505171626Scognet	}
506171626Scognet	return (ENOENT);
507171626Scognet}
508171626Scognet
509171626Scognetstatic device_method_t i81342_pci_methods[] = {
510171626Scognet	/* Device interface */
511171626Scognet	DEVMETHOD(device_probe,		i81342_pci_probe),
512171626Scognet	DEVMETHOD(device_attach,	i81342_pci_attach),
513171626Scognet	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
514171626Scognet	DEVMETHOD(device_suspend,	bus_generic_suspend),
515171626Scognet	DEVMETHOD(device_resume,	bus_generic_resume),
516171626Scognet
517171626Scognet	/* Bus interface */
518171626Scognet	DEVMETHOD(bus_read_ivar,	i81342_read_ivar),
519171626Scognet	DEVMETHOD(bus_write_ivar,	i81342_write_ivar),
520171626Scognet	DEVMETHOD(bus_alloc_resource,	i81342_pci_alloc_resource),
521171626Scognet	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
522171626Scognet	DEVMETHOD(bus_activate_resource, i81342_pci_activate_resource),
523171626Scognet	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
524171626Scognet	DEVMETHOD(bus_setup_intr,	i81342_pci_setup_intr),
525171626Scognet	DEVMETHOD(bus_teardown_intr,	i81342_pci_teardown_intr),
526171626Scognet
527171626Scognet	/* pcib interface */
528171626Scognet	DEVMETHOD(pcib_maxslots,	i81342_pci_maxslots),
529171626Scognet	DEVMETHOD(pcib_read_config,	i81342_pci_read_config),
530171626Scognet	DEVMETHOD(pcib_write_config,	i81342_pci_write_config),
531171626Scognet	DEVMETHOD(pcib_route_interrupt,	i81342_pci_route_interrupt),
532171626Scognet
533227843Smarius	DEVMETHOD_END
534171626Scognet};
535171626Scognet
536171626Scognetstatic driver_t i81342_pci_driver = {
537171626Scognet	"pcib",
538171626Scognet	i81342_pci_methods,
539171626Scognet	sizeof(struct i81342_pci_softc),
540171626Scognet};
541171626Scognet
542171626Scognetstatic devclass_t i81342_pci_devclass;
543171626Scognet
544171626ScognetDRIVER_MODULE(ipci, iq, i81342_pci_driver, i81342_pci_devclass, 0, 0);
545