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