xref: /netbsd-src/sys/arch/evbarm/iq80310/iq80310_pci.c (revision 7977047465c45dfd96a8e1e038af7d575dae6eb2)
1*79770474Smsaitoh /*	$NetBSD: iq80310_pci.c,v 1.16 2019/03/01 09:25:59 msaitoh Exp $	*/
2393b381aSthorpej 
3393b381aSthorpej /*
42b9837b4Sthorpej  * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
5393b381aSthorpej  * All rights reserved.
6393b381aSthorpej  *
7393b381aSthorpej  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8393b381aSthorpej  *
9393b381aSthorpej  * Redistribution and use in source and binary forms, with or without
10393b381aSthorpej  * modification, are permitted provided that the following conditions
11393b381aSthorpej  * are met:
12393b381aSthorpej  * 1. Redistributions of source code must retain the above copyright
13393b381aSthorpej  *    notice, this list of conditions and the following disclaimer.
14393b381aSthorpej  * 2. Redistributions in binary form must reproduce the above copyright
15393b381aSthorpej  *    notice, this list of conditions and the following disclaimer in the
16393b381aSthorpej  *    documentation and/or other materials provided with the distribution.
17393b381aSthorpej  * 3. All advertising materials mentioning features or use of this software
18393b381aSthorpej  *    must display the following acknowledgement:
19393b381aSthorpej  *	This product includes software developed for the NetBSD Project by
20393b381aSthorpej  *	Wasabi Systems, Inc.
21393b381aSthorpej  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22393b381aSthorpej  *    or promote products derived from this software without specific prior
23393b381aSthorpej  *    written permission.
24393b381aSthorpej  *
25393b381aSthorpej  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26393b381aSthorpej  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27393b381aSthorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28393b381aSthorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29393b381aSthorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30393b381aSthorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31393b381aSthorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32393b381aSthorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33393b381aSthorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34393b381aSthorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35393b381aSthorpej  * POSSIBILITY OF SUCH DAMAGE.
36393b381aSthorpej  */
37393b381aSthorpej 
38393b381aSthorpej /*
39393b381aSthorpej  * IQ80310 PCI interrupt support, using he i80312 Companion I/O chip.
40393b381aSthorpej  */
41393b381aSthorpej 
4208716eaeSlukem #include <sys/cdefs.h>
43*79770474Smsaitoh __KERNEL_RCSID(0, "$NetBSD: iq80310_pci.c,v 1.16 2019/03/01 09:25:59 msaitoh Exp $");
4408716eaeSlukem 
45393b381aSthorpej #include <sys/param.h>
46393b381aSthorpej #include <sys/systm.h>
47393b381aSthorpej #include <sys/device.h>
48393b381aSthorpej 
49393b381aSthorpej #include <machine/autoconf.h>
50fea15f47Sdyoung #include <sys/bus.h>
51393b381aSthorpej 
52393b381aSthorpej #include <evbarm/iq80310/iq80310reg.h>
53393b381aSthorpej #include <evbarm/iq80310/iq80310var.h>
54393b381aSthorpej 
55393b381aSthorpej #include <arm/xscale/i80312reg.h>
56393b381aSthorpej #include <arm/xscale/i80312var.h>
57393b381aSthorpej 
58393b381aSthorpej #include <dev/pci/pcidevs.h>
59393b381aSthorpej #include <dev/pci/ppbreg.h>
60393b381aSthorpej 
61a184f1f4Sdyoung int	iq80310_pci_intr_map(const struct pci_attach_args *,
62a184f1f4Sdyoung 	    pci_intr_handle_t *);
63e58a356cSchristos const char *iq80310_pci_intr_string(void *, pci_intr_handle_t, char *, size_t);
64393b381aSthorpej const struct evcnt *iq80310_pci_intr_evcnt(void *, pci_intr_handle_t);
65393b381aSthorpej void	*iq80310_pci_intr_establish(void *, pci_intr_handle_t,
66cce19cc2Sjmcneill 	    int, int (*func)(void *), void *, const char *);
67393b381aSthorpej void	iq80310_pci_intr_disestablish(void *, void *);
68393b381aSthorpej 
69393b381aSthorpej void
iq80310_pci_init(pci_chipset_tag_t pc,void * cookie)70393b381aSthorpej iq80310_pci_init(pci_chipset_tag_t pc, void *cookie)
71393b381aSthorpej {
72393b381aSthorpej 
73393b381aSthorpej 	pc->pc_intr_v = cookie;		/* the i80312 softc */
74393b381aSthorpej 	pc->pc_intr_map = iq80310_pci_intr_map;
75393b381aSthorpej 	pc->pc_intr_string = iq80310_pci_intr_string;
76393b381aSthorpej 	pc->pc_intr_evcnt = iq80310_pci_intr_evcnt;
77393b381aSthorpej 	pc->pc_intr_establish = iq80310_pci_intr_establish;
78393b381aSthorpej 	pc->pc_intr_disestablish = iq80310_pci_intr_disestablish;
79393b381aSthorpej }
80393b381aSthorpej 
812b9837b4Sthorpej #if defined(IOP310_TEAMASA_NPWR)
822b9837b4Sthorpej int
iq80310_pci_intr_map(const struct pci_attach_args * pa,pci_intr_handle_t * ihp)83a184f1f4Sdyoung iq80310_pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp)
842b9837b4Sthorpej {
852b9837b4Sthorpej 	struct i80312_softc *sc = pa->pa_pc->pc_intr_v;
866331bb5bSbriggs 	pcireg_t reg;
872b9837b4Sthorpej 	int sbus;
882b9837b4Sthorpej 
892b9837b4Sthorpej 	/*
902b9837b4Sthorpej 	 * The Npwr routes #INTA of the on-board PCI devices directly
912b9837b4Sthorpej 	 * through the CPLD.  There is no PCI-PCI bridge and no PCI
922b9837b4Sthorpej 	 * slots on the Npwr.
932b9837b4Sthorpej 	 *
942b9837b4Sthorpej 	 * We also expect the devices to be on the Secondary side of
952b9837b4Sthorpej 	 * the i80312.
962b9837b4Sthorpej 	 */
972b9837b4Sthorpej 
98*79770474Smsaitoh 	reg = bus_space_read_4(sc->sc_st, sc->sc_ppb_sh, PCI_BRIDGE_BUS_REG);
99*79770474Smsaitoh 	sbus = PCI_BRIDGE_BUS_NUM_SECONDARY(reg);
1002b9837b4Sthorpej 
1016331bb5bSbriggs 	if (pa->pa_bus != sbus) {
1022b9837b4Sthorpej 		printf("iq80310_pci_intr_map: %d/%d/%d not on Secondary bus\n",
1032b9837b4Sthorpej 		    pa->pa_bus, pa->pa_device, pa->pa_function);
1042b9837b4Sthorpej 		return (1);
1052b9837b4Sthorpej 	}
1062b9837b4Sthorpej 
1072b9837b4Sthorpej 	switch (pa->pa_device) {
108efca4d52Sbriggs 	case 5:		/* LSI 53c1010 SCSI */
1092b9837b4Sthorpej 		*ihp = XINT3_IRQ(2);
1102b9837b4Sthorpej 		break;
111efca4d52Sbriggs 	case 6:		/* Intel i82544GC Gig-E #1 */
1122b9837b4Sthorpej 		*ihp = XINT3_IRQ(1);
1132b9837b4Sthorpej 		break;
114efca4d52Sbriggs 	case 7:		/* Intel i82544GC Gig-E #2 */
1152b9837b4Sthorpej 		*ihp = XINT3_IRQ(4);
1162b9837b4Sthorpej 		break;
1172b9837b4Sthorpej 	default:
1182b9837b4Sthorpej 		printf("iq80310_pci_intr_map: no mapping for %d/%d/%d\n",
1192b9837b4Sthorpej 		    pa->pa_bus, pa->pa_device, pa->pa_function);
1202b9837b4Sthorpej 		return (1);
1212b9837b4Sthorpej 	}
1222b9837b4Sthorpej 
1232b9837b4Sthorpej 	return (0);
1242b9837b4Sthorpej }
1252b9837b4Sthorpej #else /* Default to stock IQ80310 */
126393b381aSthorpej int
iq80310_pci_intr_map(const struct pci_attach_args * pa,pci_intr_handle_t * ihp)127a184f1f4Sdyoung iq80310_pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp)
128393b381aSthorpej {
129393b381aSthorpej 	struct i80312_softc *sc = pa->pa_pc->pc_intr_v;
130393b381aSthorpej 	pcitag_t tag;
131393b381aSthorpej 	pcireg_t reg;
132393b381aSthorpej 	int sbus, pbus;
133393b381aSthorpej 
134393b381aSthorpej 	/*
135393b381aSthorpej 	 * Mapping of PCI interrupts on the IQ80310 is pretty easy; there
136393b381aSthorpej 	 * is a single interrupt line for all PCI devices on pre-F boards,
137393b381aSthorpej 	 * and an interrupt line for each INTx# signal on F and later boards.
138393b381aSthorpej 	 *
139393b381aSthorpej 	 * The only exception is the on-board Ethernet; this devices has
140393b381aSthorpej 	 * its own dedicated interrupt line.  The location of this device
141393b381aSthorpej 	 * looks like this:
142393b381aSthorpej 	 *
143393b381aSthorpej 	 *	80312 Secondary -> PPB at dev #7 -> i82559 at dev #0
144393b381aSthorpej 	 *
145393b381aSthorpej 	 * In order to determine if we're mapping the interrupt for the
146393b381aSthorpej 	 * on-board Ethernet, we must read the Secondary Bus # of the
147393b381aSthorpej 	 * i80312, then use that to read the Secondary Bus # of the
148393b381aSthorpej 	 * 21154 PPB.  At that point, we know that b/d/f of the i82559,
149393b381aSthorpej 	 * and can determine if we're looking at that device.
150393b381aSthorpej 	 */
151393b381aSthorpej 
152*79770474Smsaitoh 	reg = bus_space_read_4(sc->sc_st, sc->sc_ppb_sh, PCI_BRIDGE_BUS_REG);
153*79770474Smsaitoh 	pbus = PCI_BRIDGE_BUS_NUM_PRIMARY(reg);
154*79770474Smsaitoh 	sbus = PCI_BRIDGE_BUS_NUM_SECONDARY(reg);
155393b381aSthorpej 
156393b381aSthorpej 	/*
157393b381aSthorpej 	 * XXX We don't know how to map interrupts on the Primary
158393b381aSthorpej 	 * XXX PCI bus right now.
159393b381aSthorpej 	 */
160393b381aSthorpej 	if (pa->pa_bus == pbus) {
161393b381aSthorpej 		printf("iq80310_pci_intr_map: can't map interrupts on "
162393b381aSthorpej 		    "Primary bus\n");
163393b381aSthorpej 		return (1);
164393b381aSthorpej 	}
165393b381aSthorpej 
166393b381aSthorpej 	tag = pci_make_tag(pa->pa_pc, sbus, 7, 0);
167393b381aSthorpej 
168393b381aSthorpej 	/* Make sure the PPB is there. */
169393b381aSthorpej 	reg = pci_conf_read(pa->pa_pc, tag, PCI_ID_REG);
170393b381aSthorpej 	if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
171393b381aSthorpej 	    PCI_VENDOR(reg) == 0) {
172393b381aSthorpej 		/*
173393b381aSthorpej 		 * That's odd... no PPB there?  Oh well, issue a warning
174393b381aSthorpej 		 * and continue on.
175393b381aSthorpej 		 */
176393b381aSthorpej 		printf("iq80310_pci_intr_map: PPB not found at %d/%d/%d ??\n",
177393b381aSthorpej 		    sbus, 7, 0);
178393b381aSthorpej 		goto pinmap;
179393b381aSthorpej 	}
180393b381aSthorpej 
181393b381aSthorpej 	/* Make sure the device that's there is a PPB. */
182393b381aSthorpej 	reg = pci_conf_read(pa->pa_pc, tag, PCI_CLASS_REG);
183393b381aSthorpej 	if (PCI_CLASS(reg) != PCI_CLASS_BRIDGE ||
184393b381aSthorpej 	    PCI_SUBCLASS(reg) != PCI_SUBCLASS_BRIDGE_PCI) {
185393b381aSthorpej 		/*
186393b381aSthorpej 		 * That's odd... the device that's there isn't a PPB.
187393b381aSthorpej 		 * Oh well, issue a warning and continue on.
188393b381aSthorpej 		 */
189393b381aSthorpej 		printf("iq80310_pci_intr_map: %d/%d/%d isn't a PPB ??\n",
190393b381aSthorpej 		    sbus, 7, 0);
191393b381aSthorpej 		goto pinmap;
192393b381aSthorpej 	}
193393b381aSthorpej 
194393b381aSthorpej 	/* Now read the PPB's secondary bus number. */
195*79770474Smsaitoh 	reg = pci_conf_read(pa->pa_pc, tag, PCI_BRIDGE_BUS_REG);
196*79770474Smsaitoh 	sbus = PCI_BRIDGE_BUS_NUM_SECONDARY(reg);
197393b381aSthorpej 
198393b381aSthorpej 	if (pa->pa_bus == sbus && pa->pa_device == 0 &&
199393b381aSthorpej 	    pa->pa_function == 0) {
200393b381aSthorpej 		/* On-board i82559 Ethernet! */
201393b381aSthorpej 		*ihp = XINT3_IRQ(XINT3_ETHERNET);
202393b381aSthorpej 		return (0);
203393b381aSthorpej 	}
204393b381aSthorpej 
205393b381aSthorpej  pinmap:
206393b381aSthorpej 	if (pa->pa_intrpin == 0) {
207393b381aSthorpej 		/* No IRQ used. */
208393b381aSthorpej 		return (1);
209393b381aSthorpej 	}
210393b381aSthorpej 	if (pa->pa_intrpin > 4) {
211393b381aSthorpej 		printf("iq80310_pci_intr_map: bad interrupt pin %d\n",
212393b381aSthorpej 		    pa->pa_intrpin);
213393b381aSthorpej 		return (1);
214393b381aSthorpej 	}
215393b381aSthorpej 
216393b381aSthorpej 	/* INTD# is always in XINT3. */
217393b381aSthorpej 	if (pa->pa_intrpin == 4) {
218393b381aSthorpej 		*ihp = XINT3_IRQ(XINT3_SINTD);
219393b381aSthorpej 		return (0);
220393b381aSthorpej 	}
221393b381aSthorpej 
222393b381aSthorpej 	/* On pre-F boards, ALL of them are on XINT3. */
223393b381aSthorpej 	if (/*pre-F*/0)
224393b381aSthorpej 		*ihp = XINT3_IRQ(XINT3_SINTD);
225393b381aSthorpej 	else
226393b381aSthorpej 		*ihp = XINT0_IRQ(pa->pa_intrpin - 1);
227393b381aSthorpej 
228393b381aSthorpej 	return (0);
229393b381aSthorpej }
2302b9837b4Sthorpej #endif /* list of IQ80310-based designs */
231393b381aSthorpej 
232393b381aSthorpej const char *
iq80310_pci_intr_string(void * v,pci_intr_handle_t ih,char * buf,size_t len)233e58a356cSchristos iq80310_pci_intr_string(void *v, pci_intr_handle_t ih, char *buf, size_t len)
234393b381aSthorpej {
2350c5ccc02Sjmcneill 	snprintf(buf, len, "iq80310 irq %" PRIu64, ih);
236e58a356cSchristos 	return buf;
237393b381aSthorpej }
238393b381aSthorpej 
239393b381aSthorpej const struct evcnt *
iq80310_pci_intr_evcnt(void * v,pci_intr_handle_t ih)240393b381aSthorpej iq80310_pci_intr_evcnt(void *v, pci_intr_handle_t ih)
241393b381aSthorpej {
242393b381aSthorpej 
243393b381aSthorpej 	/* XXX For now. */
244393b381aSthorpej 	return (NULL);
245393b381aSthorpej }
246393b381aSthorpej 
247393b381aSthorpej void *
iq80310_pci_intr_establish(void * v,pci_intr_handle_t ih,int ipl,int (* func)(void *),void * arg,const char * xname)248393b381aSthorpej iq80310_pci_intr_establish(void *v, pci_intr_handle_t ih, int ipl,
249cce19cc2Sjmcneill     int (*func)(void *), void *arg, const char *xname)
250393b381aSthorpej {
251393b381aSthorpej 
252393b381aSthorpej 	return (iq80310_intr_establish(ih, ipl, func, arg));
253393b381aSthorpej }
254393b381aSthorpej 
255393b381aSthorpej void
iq80310_pci_intr_disestablish(void * v,void * cookie)256393b381aSthorpej iq80310_pci_intr_disestablish(void *v, void *cookie)
257393b381aSthorpej {
258393b381aSthorpej 
259393b381aSthorpej 	iq80310_intr_disestablish(cookie);
260393b381aSthorpej }
261