pcib.c revision 1.2.8.2 1 1.2.8.2 jdolecek /* $NetBSD: pcib.c,v 1.2.8.2 2002/06/23 17:36:01 jdolecek Exp $ */
2 1.2.8.2 jdolecek
3 1.2.8.2 jdolecek /*
4 1.2.8.2 jdolecek * Copyright 2002 Wasabi Systems, Inc.
5 1.2.8.2 jdolecek * All rights reserved.
6 1.2.8.2 jdolecek *
7 1.2.8.2 jdolecek * Written by Simon Burge for Wasabi Systems, Inc.
8 1.2.8.2 jdolecek *
9 1.2.8.2 jdolecek * Redistribution and use in source and binary forms, with or without
10 1.2.8.2 jdolecek * modification, are permitted provided that the following conditions
11 1.2.8.2 jdolecek * are met:
12 1.2.8.2 jdolecek * 1. Redistributions of source code must retain the above copyright
13 1.2.8.2 jdolecek * notice, this list of conditions and the following disclaimer.
14 1.2.8.2 jdolecek * 2. Redistributions in binary form must reproduce the above copyright
15 1.2.8.2 jdolecek * notice, this list of conditions and the following disclaimer in the
16 1.2.8.2 jdolecek * documentation and/or other materials provided with the distribution.
17 1.2.8.2 jdolecek * 3. All advertising materials mentioning features or use of this software
18 1.2.8.2 jdolecek * must display the following acknowledgement:
19 1.2.8.2 jdolecek * This product includes software developed for the NetBSD Project by
20 1.2.8.2 jdolecek * Wasabi Systems, Inc.
21 1.2.8.2 jdolecek * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 1.2.8.2 jdolecek * or promote products derived from this software without specific prior
23 1.2.8.2 jdolecek * written permission.
24 1.2.8.2 jdolecek *
25 1.2.8.2 jdolecek * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 1.2.8.2 jdolecek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 1.2.8.2 jdolecek * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 1.2.8.2 jdolecek * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 1.2.8.2 jdolecek * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 1.2.8.2 jdolecek * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 1.2.8.2 jdolecek * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 1.2.8.2 jdolecek * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 1.2.8.2 jdolecek * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 1.2.8.2 jdolecek * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 1.2.8.2 jdolecek * POSSIBILITY OF SUCH DAMAGE.
36 1.2.8.2 jdolecek */
37 1.2.8.2 jdolecek
38 1.2.8.2 jdolecek #include <sys/param.h>
39 1.2.8.2 jdolecek #include <sys/systm.h>
40 1.2.8.2 jdolecek #include <sys/kernel.h>
41 1.2.8.2 jdolecek #include <sys/device.h>
42 1.2.8.2 jdolecek #include <sys/malloc.h>
43 1.2.8.2 jdolecek
44 1.2.8.2 jdolecek #include <machine/bus.h>
45 1.2.8.2 jdolecek #include <evbmips/malta/maltareg.h>
46 1.2.8.2 jdolecek #include <evbmips/malta/maltavar.h>
47 1.2.8.2 jdolecek #include <evbmips/malta/dev/gtreg.h>
48 1.2.8.2 jdolecek #include <evbmips/malta/pci/pcibvar.h>
49 1.2.8.2 jdolecek
50 1.2.8.2 jdolecek #include <dev/isa/isareg.h>
51 1.2.8.2 jdolecek #include <dev/isa/isavar.h>
52 1.2.8.2 jdolecek
53 1.2.8.2 jdolecek #include <dev/pci/pcireg.h>
54 1.2.8.2 jdolecek #include <dev/pci/pcivar.h>
55 1.2.8.2 jdolecek #include <dev/pci/pcidevs.h>
56 1.2.8.2 jdolecek
57 1.2.8.2 jdolecek #include <dev/ic/i8259reg.h>
58 1.2.8.2 jdolecek
59 1.2.8.2 jdolecek
60 1.2.8.2 jdolecek #define ICU_LEN 16 /* number of ISA IRQs */
61 1.2.8.2 jdolecek
62 1.2.8.2 jdolecek const char *isa_intrnames[ICU_LEN] = {
63 1.2.8.2 jdolecek "timer",
64 1.2.8.2 jdolecek "keyboard",
65 1.2.8.2 jdolecek "reserved", /* by South Bridge (for cascading) */
66 1.2.8.2 jdolecek "com1",
67 1.2.8.2 jdolecek "com0",
68 1.2.8.2 jdolecek "not used",
69 1.2.8.2 jdolecek "floppy",
70 1.2.8.2 jdolecek "centronics",
71 1.2.8.2 jdolecek "mcclock",
72 1.2.8.2 jdolecek "i2c",
73 1.2.8.2 jdolecek "pci A,B", /* PCI slots 1..4, ethernet */
74 1.2.8.2 jdolecek "pci C,D", /* PCI slots 1..4, audio, usb */
75 1.2.8.2 jdolecek "mouse",
76 1.2.8.2 jdolecek "reserved",
77 1.2.8.2 jdolecek "ide primary",
78 1.2.8.2 jdolecek "ide secondary", /* and compact flash connector */
79 1.2.8.2 jdolecek };
80 1.2.8.2 jdolecek
81 1.2.8.2 jdolecek struct pcib_intrhead {
82 1.2.8.2 jdolecek LIST_HEAD(, evbmips_intrhand) intr_q;
83 1.2.8.2 jdolecek struct evcnt intr_count;
84 1.2.8.2 jdolecek int intr_type;
85 1.2.8.2 jdolecek };
86 1.2.8.2 jdolecek
87 1.2.8.2 jdolecek struct pcib_softc {
88 1.2.8.2 jdolecek struct device sc_dev;
89 1.2.8.2 jdolecek
90 1.2.8.2 jdolecek bus_space_tag_t sc_iot;
91 1.2.8.2 jdolecek bus_space_handle_t sc_ioh_icu1;
92 1.2.8.2 jdolecek bus_space_handle_t sc_ioh_icu2;
93 1.2.8.2 jdolecek bus_space_handle_t sc_ioh_elcr;
94 1.2.8.2 jdolecek
95 1.2.8.2 jdolecek struct mips_isa_chipset sc_ic;
96 1.2.8.2 jdolecek
97 1.2.8.2 jdolecek struct pcib_intrhead sc_intrtab[ICU_LEN];
98 1.2.8.2 jdolecek
99 1.2.8.2 jdolecek u_int16_t sc_imask;
100 1.2.8.2 jdolecek u_int16_t sc_elcr;
101 1.2.8.2 jdolecek
102 1.2.8.2 jdolecek u_int16_t sc_reserved;
103 1.2.8.2 jdolecek
104 1.2.8.2 jdolecek void *sc_ih;
105 1.2.8.2 jdolecek };
106 1.2.8.2 jdolecek
107 1.2.8.2 jdolecek /*
108 1.2.8.2 jdolecek * XXX
109 1.2.8.2 jdolecek * There is only one pci-isa bridge, and all external interrupts
110 1.2.8.2 jdolecek * are routed through it, so we need to remember the softc when
111 1.2.8.2 jdolecek * called from other interrupt handling code.
112 1.2.8.2 jdolecek */
113 1.2.8.2 jdolecek static struct pcib_softc *my_sc;
114 1.2.8.2 jdolecek struct mips_isa_chipset *pcib_ic;
115 1.2.8.2 jdolecek
116 1.2.8.2 jdolecek static int pcib_match(struct device *, struct cfdata *, void *);
117 1.2.8.2 jdolecek static void pcib_attach(struct device *, struct device *, void *);
118 1.2.8.2 jdolecek static int pcib_intr(void *v);
119 1.2.8.2 jdolecek static void pcib_bridge_callback(struct device *);
120 1.2.8.2 jdolecek static int pcib_print(void *, const char *);
121 1.2.8.2 jdolecek static void pcib_set_icus(struct pcib_softc *sc);
122 1.2.8.2 jdolecek static void pcib_cleanup(void *arg);
123 1.2.8.2 jdolecek
124 1.2.8.2 jdolecek static const struct evcnt *
125 1.2.8.2 jdolecek pcib_isa_intr_evcnt(void *, int);
126 1.2.8.2 jdolecek static void *pcib_isa_intr_establish(void *, int, int, int,
127 1.2.8.2 jdolecek int (*)(void *), void *);
128 1.2.8.2 jdolecek static void pcib_isa_intr_disestablish(void *, void *);
129 1.2.8.2 jdolecek static void pcib_isa_attach_hook(struct device *, struct device *,
130 1.2.8.2 jdolecek struct isabus_attach_args *);
131 1.2.8.2 jdolecek static int pcib_isa_intr_alloc(void *, int, int, int *);
132 1.2.8.2 jdolecek static const char *
133 1.2.8.2 jdolecek pcib_isa_intr_string(void *, int);
134 1.2.8.2 jdolecek
135 1.2.8.2 jdolecek struct cfattach pcib_ca = {
136 1.2.8.2 jdolecek sizeof(struct pcib_softc), pcib_match, pcib_attach
137 1.2.8.2 jdolecek };
138 1.2.8.2 jdolecek
139 1.2.8.2 jdolecek static int
140 1.2.8.2 jdolecek pcib_match(struct device *parent, struct cfdata *match, void *aux)
141 1.2.8.2 jdolecek {
142 1.2.8.2 jdolecek struct pci_attach_args *pa = aux;
143 1.2.8.2 jdolecek
144 1.2.8.2 jdolecek if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
145 1.2.8.2 jdolecek PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA)
146 1.2.8.2 jdolecek return (1);
147 1.2.8.2 jdolecek
148 1.2.8.2 jdolecek return (0);
149 1.2.8.2 jdolecek }
150 1.2.8.2 jdolecek
151 1.2.8.2 jdolecek static void
152 1.2.8.2 jdolecek pcib_attach(struct device *parent, struct device *self, void *aux)
153 1.2.8.2 jdolecek {
154 1.2.8.2 jdolecek struct pci_attach_args *pa = aux;
155 1.2.8.2 jdolecek char devinfo[256];
156 1.2.8.2 jdolecek int i;
157 1.2.8.2 jdolecek
158 1.2.8.2 jdolecek printf("\n");
159 1.2.8.2 jdolecek
160 1.2.8.2 jdolecek if (my_sc != NULL)
161 1.2.8.2 jdolecek panic("pcib_attach: already attached!\n");
162 1.2.8.2 jdolecek my_sc = (void *)self;
163 1.2.8.2 jdolecek
164 1.2.8.2 jdolecek /*
165 1.2.8.2 jdolecek * Just print out a description and defer configuration
166 1.2.8.2 jdolecek * until all PCI devices have been attached.
167 1.2.8.2 jdolecek */
168 1.2.8.2 jdolecek pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo);
169 1.2.8.2 jdolecek printf("%s: %s, (rev . 0x%02x)\n", self->dv_xname, devinfo,
170 1.2.8.2 jdolecek PCI_REVISION(pa->pa_class));
171 1.2.8.2 jdolecek
172 1.2.8.2 jdolecek my_sc->sc_iot = pa->pa_iot;
173 1.2.8.2 jdolecek
174 1.2.8.2 jdolecek /*
175 1.2.8.2 jdolecek * Map the PIC/ELCR registers.
176 1.2.8.2 jdolecek */
177 1.2.8.2 jdolecek if (bus_space_map(my_sc->sc_iot, 0x4d0, 2, 0, &my_sc->sc_ioh_elcr) != 0)
178 1.2.8.2 jdolecek printf("%s: unable to map ELCR registers\n",
179 1.2.8.2 jdolecek my_sc->sc_dev.dv_xname);
180 1.2.8.2 jdolecek if (bus_space_map(my_sc->sc_iot, IO_ICU1, 2, 0, &my_sc->sc_ioh_icu1) != 0)
181 1.2.8.2 jdolecek printf("%s: unable to map ICU1 registers\n",
182 1.2.8.2 jdolecek my_sc->sc_dev.dv_xname);
183 1.2.8.2 jdolecek if (bus_space_map(my_sc->sc_iot, IO_ICU2, 2, 0, &my_sc->sc_ioh_icu2) != 0)
184 1.2.8.2 jdolecek printf("%s: unable to map ICU2 registers\n",
185 1.2.8.2 jdolecek my_sc->sc_dev.dv_xname);
186 1.2.8.2 jdolecek
187 1.2.8.2 jdolecek /* All interrupts default to "masked off". */
188 1.2.8.2 jdolecek my_sc->sc_imask = 0xffff;
189 1.2.8.2 jdolecek
190 1.2.8.2 jdolecek /* All interrupts default to edge-triggered. */
191 1.2.8.2 jdolecek my_sc->sc_elcr = 0;
192 1.2.8.2 jdolecek
193 1.2.8.2 jdolecek /*
194 1.2.8.2 jdolecek * Initialize the 8259s.
195 1.2.8.2 jdolecek */
196 1.2.8.2 jdolecek /* reset, program device, 4 bytes */
197 1.2.8.2 jdolecek bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW1,
198 1.2.8.2 jdolecek ICW1_SELECT | ICW1_IC4);
199 1.2.8.2 jdolecek bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW2,
200 1.2.8.2 jdolecek ICW2_VECTOR(0)/*XXX*/);
201 1.2.8.2 jdolecek bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW3,
202 1.2.8.2 jdolecek ICW3_CASCADE(2));
203 1.2.8.2 jdolecek bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW4,
204 1.2.8.2 jdolecek ICW4_8086);
205 1.2.8.2 jdolecek
206 1.2.8.2 jdolecek /* mask all interrupts */
207 1.2.8.2 jdolecek bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_OCW1,
208 1.2.8.2 jdolecek my_sc->sc_imask & 0xff);
209 1.2.8.2 jdolecek
210 1.2.8.2 jdolecek /* enable special mask mode */
211 1.2.8.2 jdolecek bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_OCW3,
212 1.2.8.2 jdolecek OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
213 1.2.8.2 jdolecek
214 1.2.8.2 jdolecek /* read IRR by default */
215 1.2.8.2 jdolecek bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_OCW3,
216 1.2.8.2 jdolecek OCW3_SELECT | OCW3_RR);
217 1.2.8.2 jdolecek
218 1.2.8.2 jdolecek /* reset, program device, 4 bytes */
219 1.2.8.2 jdolecek bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW1,
220 1.2.8.2 jdolecek ICW1_SELECT | ICW1_IC4);
221 1.2.8.2 jdolecek bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW2,
222 1.2.8.2 jdolecek ICW2_VECTOR(0)/*XXX*/);
223 1.2.8.2 jdolecek bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW3,
224 1.2.8.2 jdolecek ICW3_CASCADE(2));
225 1.2.8.2 jdolecek bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW4,
226 1.2.8.2 jdolecek ICW4_8086);
227 1.2.8.2 jdolecek
228 1.2.8.2 jdolecek /* mask all interrupts */
229 1.2.8.2 jdolecek bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_OCW1,
230 1.2.8.2 jdolecek my_sc->sc_imask & 0xff);
231 1.2.8.2 jdolecek
232 1.2.8.2 jdolecek /* enable special mask mode */
233 1.2.8.2 jdolecek bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_OCW3,
234 1.2.8.2 jdolecek OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
235 1.2.8.2 jdolecek
236 1.2.8.2 jdolecek /* read IRR by default */
237 1.2.8.2 jdolecek bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_OCW3,
238 1.2.8.2 jdolecek OCW3_SELECT | OCW3_RR);
239 1.2.8.2 jdolecek
240 1.2.8.2 jdolecek /*
241 1.2.8.2 jdolecek * Default all interrupts to edge-triggered.
242 1.2.8.2 jdolecek */
243 1.2.8.2 jdolecek bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_elcr, 0,
244 1.2.8.2 jdolecek my_sc->sc_elcr & 0xff);
245 1.2.8.2 jdolecek bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_elcr, 1,
246 1.2.8.2 jdolecek (my_sc->sc_elcr >> 8) & 0xff);
247 1.2.8.2 jdolecek
248 1.2.8.2 jdolecek /*
249 1.2.8.2 jdolecek * Some ISA interrupts are reserved for devices that
250 1.2.8.2 jdolecek * we know are hard-wired to certain IRQs.
251 1.2.8.2 jdolecek */
252 1.2.8.2 jdolecek my_sc->sc_reserved =
253 1.2.8.2 jdolecek (1U << 0) | /* timer */
254 1.2.8.2 jdolecek (1U << 1) | /* keyboard controller (keyboard) */
255 1.2.8.2 jdolecek (1U << 2) | /* PIC cascade */
256 1.2.8.2 jdolecek (1U << 3) | /* COM 2 */
257 1.2.8.2 jdolecek (1U << 4) | /* COM 1 */
258 1.2.8.2 jdolecek (1U << 6) | /* floppy */
259 1.2.8.2 jdolecek (1U << 7) | /* centronics */
260 1.2.8.2 jdolecek (1U << 8) | /* RTC */
261 1.2.8.2 jdolecek (1U << 9) | /* I2C */
262 1.2.8.2 jdolecek (1U << 12) | /* keyboard controller (mouse) */
263 1.2.8.2 jdolecek (1U << 14) | /* IDE primary */
264 1.2.8.2 jdolecek (1U << 15); /* IDE secondary */
265 1.2.8.2 jdolecek
266 1.2.8.2 jdolecek /* Set up our ISA chipset. */
267 1.2.8.2 jdolecek my_sc->sc_ic.ic_v = my_sc;
268 1.2.8.2 jdolecek my_sc->sc_ic.ic_intr_evcnt = pcib_isa_intr_evcnt;
269 1.2.8.2 jdolecek my_sc->sc_ic.ic_intr_establish = pcib_isa_intr_establish;
270 1.2.8.2 jdolecek my_sc->sc_ic.ic_intr_disestablish = pcib_isa_intr_disestablish;
271 1.2.8.2 jdolecek my_sc->sc_ic.ic_intr_alloc = pcib_isa_intr_alloc;
272 1.2.8.2 jdolecek my_sc->sc_ic.ic_intr_string = pcib_isa_intr_string;
273 1.2.8.2 jdolecek
274 1.2.8.2 jdolecek pcib_ic = &my_sc->sc_ic; /* XXX for external use */
275 1.2.8.2 jdolecek
276 1.2.8.2 jdolecek /* Initialize our interrupt table. */
277 1.2.8.2 jdolecek for (i = 0; i < ICU_LEN; i++) {
278 1.2.8.2 jdolecek #if 0
279 1.2.8.2 jdolecek char irqstr[8]; /* 4 + 2 + NULL + sanity */
280 1.2.8.2 jdolecek
281 1.2.8.2 jdolecek sprintf(irqstr, "irq %d", i);
282 1.2.8.2 jdolecek evcnt_attach_dynamic(&my_sc->sc_intrtab[i].intr_count,
283 1.2.8.2 jdolecek EVCNT_TYPE_INTR, NULL, "pcib", irqstr);
284 1.2.8.2 jdolecek #else
285 1.2.8.2 jdolecek evcnt_attach_dynamic(&my_sc->sc_intrtab[i].intr_count,
286 1.2.8.2 jdolecek EVCNT_TYPE_INTR, NULL, "pcib", isa_intrnames[i]);
287 1.2.8.2 jdolecek #endif
288 1.2.8.2 jdolecek LIST_INIT(&my_sc->sc_intrtab[i].intr_q);
289 1.2.8.2 jdolecek my_sc->sc_intrtab[i].intr_type = IST_NONE;
290 1.2.8.2 jdolecek }
291 1.2.8.2 jdolecek
292 1.2.8.2 jdolecek /* Hook up our interrupt handler. */
293 1.2.8.2 jdolecek my_sc->sc_ih = evbmips_intr_establish(MALTA_SOUTHBRIDGE_INTR, pcib_intr, my_sc);
294 1.2.8.2 jdolecek if (my_sc->sc_ih == NULL)
295 1.2.8.2 jdolecek printf("%s: WARNING: unable to register interrupt handler\n",
296 1.2.8.2 jdolecek my_sc->sc_dev.dv_xname);
297 1.2.8.2 jdolecek
298 1.2.8.2 jdolecek
299 1.2.8.2 jdolecek /*
300 1.2.8.2 jdolecek * Disable ISA interrupts before returning to YAMON.
301 1.2.8.2 jdolecek */
302 1.2.8.2 jdolecek if (shutdownhook_establish(pcib_cleanup, my_sc) == NULL)
303 1.2.8.2 jdolecek panic("pcib_attach: could not establish shutdown hook");
304 1.2.8.2 jdolecek
305 1.2.8.2 jdolecek config_defer(self, pcib_bridge_callback);
306 1.2.8.2 jdolecek }
307 1.2.8.2 jdolecek
308 1.2.8.2 jdolecek static void
309 1.2.8.2 jdolecek pcib_bridge_callback(struct device *self)
310 1.2.8.2 jdolecek {
311 1.2.8.2 jdolecek struct pcib_softc *sc = (void *)self;
312 1.2.8.2 jdolecek struct malta_config *mcp = &malta_configuration;
313 1.2.8.2 jdolecek struct isabus_attach_args iba;
314 1.2.8.2 jdolecek
315 1.2.8.2 jdolecek /*
316 1.2.8.2 jdolecek * Attach the ISA bus behind this bridge.
317 1.2.8.2 jdolecek */
318 1.2.8.2 jdolecek memset(&iba, 0, sizeof(iba));
319 1.2.8.2 jdolecek
320 1.2.8.2 jdolecek iba.iba_busname = "isa";
321 1.2.8.2 jdolecek iba.iba_iot = &mcp->mc_iot;
322 1.2.8.2 jdolecek iba.iba_memt = &mcp->mc_memt;
323 1.2.8.2 jdolecek iba.iba_dmat = &mcp->mc_isa_dmat;
324 1.2.8.2 jdolecek
325 1.2.8.2 jdolecek iba.iba_ic = &sc->sc_ic;
326 1.2.8.2 jdolecek iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook;
327 1.2.8.2 jdolecek
328 1.2.8.2 jdolecek config_found(&sc->sc_dev, &iba, pcib_print);
329 1.2.8.2 jdolecek }
330 1.2.8.2 jdolecek
331 1.2.8.2 jdolecek static int
332 1.2.8.2 jdolecek pcib_print(void *aux, const char *pnp)
333 1.2.8.2 jdolecek {
334 1.2.8.2 jdolecek
335 1.2.8.2 jdolecek /* Only ISAs can attach to pcib's; easy. */
336 1.2.8.2 jdolecek if (pnp)
337 1.2.8.2 jdolecek printf("isa at %s", pnp);
338 1.2.8.2 jdolecek return (UNCONF);
339 1.2.8.2 jdolecek }
340 1.2.8.2 jdolecek
341 1.2.8.2 jdolecek static void
342 1.2.8.2 jdolecek pcib_isa_attach_hook(struct device *parent, struct device *self,
343 1.2.8.2 jdolecek struct isabus_attach_args *iba)
344 1.2.8.2 jdolecek {
345 1.2.8.2 jdolecek
346 1.2.8.2 jdolecek /* Nothing to do. */
347 1.2.8.2 jdolecek }
348 1.2.8.2 jdolecek
349 1.2.8.2 jdolecek static void
350 1.2.8.2 jdolecek pcib_set_icus(struct pcib_softc *sc)
351 1.2.8.2 jdolecek {
352 1.2.8.2 jdolecek
353 1.2.8.2 jdolecek /* Enable the cascade IRQ (2) if 8-15 is enabled. */
354 1.2.8.2 jdolecek if ((sc->sc_imask & 0xff00) != 0xff00)
355 1.2.8.2 jdolecek sc->sc_imask &= ~(1U << 2);
356 1.2.8.2 jdolecek else
357 1.2.8.2 jdolecek sc->sc_imask |= (1U << 2);
358 1.2.8.2 jdolecek
359 1.2.8.2 jdolecek bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
360 1.2.8.2 jdolecek sc->sc_imask & 0xff);
361 1.2.8.2 jdolecek bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
362 1.2.8.2 jdolecek (sc->sc_imask >> 8) & 0xff);
363 1.2.8.2 jdolecek
364 1.2.8.2 jdolecek bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
365 1.2.8.2 jdolecek sc->sc_elcr & 0xff);
366 1.2.8.2 jdolecek bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
367 1.2.8.2 jdolecek (sc->sc_elcr >> 8) & 0xff);
368 1.2.8.2 jdolecek }
369 1.2.8.2 jdolecek
370 1.2.8.2 jdolecek static int
371 1.2.8.2 jdolecek pcib_intr(void *v)
372 1.2.8.2 jdolecek {
373 1.2.8.2 jdolecek struct pcib_softc *sc = v;
374 1.2.8.2 jdolecek struct evbmips_intrhand *ih;
375 1.2.8.2 jdolecek int irq;
376 1.2.8.2 jdolecek
377 1.2.8.2 jdolecek for (;;) {
378 1.2.8.2 jdolecek #if 1
379 1.2.8.2 jdolecek bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
380 1.2.8.2 jdolecek OCW3_SELECT | OCW3_POLL);
381 1.2.8.2 jdolecek irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3);
382 1.2.8.2 jdolecek if ((irq & OCW3_POLL_PENDING) == 0)
383 1.2.8.2 jdolecek return (1);
384 1.2.8.2 jdolecek
385 1.2.8.2 jdolecek irq = OCW3_POLL_IRQ(irq);
386 1.2.8.2 jdolecek
387 1.2.8.2 jdolecek if (irq == 2) {
388 1.2.8.2 jdolecek bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
389 1.2.8.2 jdolecek PIC_OCW3, OCW3_SELECT | OCW3_POLL);
390 1.2.8.2 jdolecek irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2,
391 1.2.8.2 jdolecek PIC_OCW3);
392 1.2.8.2 jdolecek if (irq & OCW3_POLL_PENDING)
393 1.2.8.2 jdolecek irq = OCW3_POLL_IRQ(irq) + 8;
394 1.2.8.2 jdolecek else
395 1.2.8.2 jdolecek irq = 2;
396 1.2.8.2 jdolecek }
397 1.2.8.2 jdolecek #else
398 1.2.8.2 jdolecek /* XXX - should be a function call to gt.c? */
399 1.2.8.2 jdolecek irq = GT_REGVAL(GT_PCI0_INTR_ACK) & 0xff;
400 1.2.8.2 jdolecek
401 1.2.8.2 jdolecek /*
402 1.2.8.2 jdolecek * From YAMON source code:
403 1.2.8.2 jdolecek *
404 1.2.8.2 jdolecek * IRQ7 is used to detect spurious interrupts.
405 1.2.8.2 jdolecek * The interrupt acknowledge cycle returns IRQ7, if no
406 1.2.8.2 jdolecek * interrupts is requested.
407 1.2.8.2 jdolecek * We can differentiate between this situation and a
408 1.2.8.2 jdolecek * "Normal" IRQ7 by reading the ISR.
409 1.2.8.2 jdolecek */
410 1.2.8.2 jdolecek
411 1.2.8.2 jdolecek if (irq == 7) {
412 1.2.8.2 jdolecek int reg;
413 1.2.8.2 jdolecek
414 1.2.8.2 jdolecek bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
415 1.2.8.2 jdolecek OCW3_SELECT | OCW3_RR | OCW3_RIS);
416 1.2.8.2 jdolecek reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1,
417 1.2.8.2 jdolecek PIC_OCW3);
418 1.2.8.2 jdolecek if (!(reg & (1 << 7)))
419 1.2.8.2 jdolecek break; /* spurious interrupt */
420 1.2.8.2 jdolecek }
421 1.2.8.2 jdolecek #endif
422 1.2.8.2 jdolecek
423 1.2.8.2 jdolecek sc->sc_intrtab[irq].intr_count.ev_count++;
424 1.2.8.2 jdolecek LIST_FOREACH(ih, &sc->sc_intrtab[irq].intr_q, ih_q)
425 1.2.8.2 jdolecek (*ih->ih_func)(ih->ih_arg);
426 1.2.8.2 jdolecek
427 1.2.8.2 jdolecek /* Send a specific EOI to the 8259. */
428 1.2.8.2 jdolecek if (irq > 7) {
429 1.2.8.2 jdolecek bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
430 1.2.8.2 jdolecek PIC_OCW2, OCW2_SELECT | OCW3_EOI | OCW3_SL |
431 1.2.8.2 jdolecek OCW2_ILS(irq & 7));
432 1.2.8.2 jdolecek irq = 2;
433 1.2.8.2 jdolecek }
434 1.2.8.2 jdolecek
435 1.2.8.2 jdolecek bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2,
436 1.2.8.2 jdolecek OCW2_SELECT | OCW3_EOI | OCW3_SL | OCW2_ILS(irq));
437 1.2.8.2 jdolecek }
438 1.2.8.2 jdolecek }
439 1.2.8.2 jdolecek
440 1.2.8.2 jdolecek const char *
441 1.2.8.2 jdolecek pcib_isa_intr_string(void *v, int irq)
442 1.2.8.2 jdolecek {
443 1.2.8.2 jdolecek static char irqstr[12]; /* 8 + 2 + NULL + sanity */
444 1.2.8.2 jdolecek
445 1.2.8.2 jdolecek if (irq == 0 || irq >= ICU_LEN || irq == 2)
446 1.2.8.2 jdolecek panic("pcib_isa_intr_string: bogus isa irq 0x%x\n", irq);
447 1.2.8.2 jdolecek
448 1.2.8.2 jdolecek sprintf(irqstr, "isa irq %d", irq);
449 1.2.8.2 jdolecek return (irqstr);
450 1.2.8.2 jdolecek }
451 1.2.8.2 jdolecek
452 1.2.8.2 jdolecek const struct evcnt *
453 1.2.8.2 jdolecek pcib_isa_intr_evcnt(void *v, int irq)
454 1.2.8.2 jdolecek {
455 1.2.8.2 jdolecek
456 1.2.8.2 jdolecek if (irq == 0 || irq >= ICU_LEN || irq == 2)
457 1.2.8.2 jdolecek panic("pcib_isa_intr_evcnt: bogus isa irq 0x%x\n", irq);
458 1.2.8.2 jdolecek
459 1.2.8.2 jdolecek return (&my_sc->sc_intrtab[irq].intr_count);
460 1.2.8.2 jdolecek }
461 1.2.8.2 jdolecek
462 1.2.8.2 jdolecek void *
463 1.2.8.2 jdolecek pcib_isa_intr_establish(void *v, int irq, int type, int level,
464 1.2.8.2 jdolecek int (*func)(void *), void *arg)
465 1.2.8.2 jdolecek {
466 1.2.8.2 jdolecek struct evbmips_intrhand *ih;
467 1.2.8.2 jdolecek int s;
468 1.2.8.2 jdolecek
469 1.2.8.2 jdolecek if (irq >= ICU_LEN || irq == 2 || type == IST_NONE)
470 1.2.8.2 jdolecek panic("pcib_isa_intr_establish: bad irq or type");
471 1.2.8.2 jdolecek
472 1.2.8.2 jdolecek switch (my_sc->sc_intrtab[irq].intr_type) {
473 1.2.8.2 jdolecek case IST_NONE:
474 1.2.8.2 jdolecek my_sc->sc_intrtab[irq].intr_type = type;
475 1.2.8.2 jdolecek break;
476 1.2.8.2 jdolecek
477 1.2.8.2 jdolecek case IST_EDGE:
478 1.2.8.2 jdolecek case IST_LEVEL:
479 1.2.8.2 jdolecek if (type == my_sc->sc_intrtab[irq].intr_type)
480 1.2.8.2 jdolecek break;
481 1.2.8.2 jdolecek /* FALLTHROUGH */
482 1.2.8.2 jdolecek case IST_PULSE:
483 1.2.8.2 jdolecek /*
484 1.2.8.2 jdolecek * We can't share interrupts in this case.
485 1.2.8.2 jdolecek */
486 1.2.8.2 jdolecek return (NULL);
487 1.2.8.2 jdolecek }
488 1.2.8.2 jdolecek
489 1.2.8.2 jdolecek ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
490 1.2.8.2 jdolecek if (ih == NULL)
491 1.2.8.2 jdolecek return (NULL);
492 1.2.8.2 jdolecek
493 1.2.8.2 jdolecek ih->ih_func = func;
494 1.2.8.2 jdolecek ih->ih_arg = arg;
495 1.2.8.2 jdolecek ih->ih_irq = irq;
496 1.2.8.2 jdolecek
497 1.2.8.2 jdolecek s = splhigh();
498 1.2.8.2 jdolecek
499 1.2.8.2 jdolecek /* Insert the handler into the table. */
500 1.2.8.2 jdolecek LIST_INSERT_HEAD(&my_sc->sc_intrtab[irq].intr_q, ih, ih_q);
501 1.2.8.2 jdolecek my_sc->sc_intrtab[irq].intr_type = type;
502 1.2.8.2 jdolecek
503 1.2.8.2 jdolecek /* Enable it, set trigger mode. */
504 1.2.8.2 jdolecek my_sc->sc_imask &= ~(1 << irq);
505 1.2.8.2 jdolecek if (my_sc->sc_intrtab[irq].intr_type == IST_LEVEL)
506 1.2.8.2 jdolecek my_sc->sc_elcr |= (1 << irq);
507 1.2.8.2 jdolecek else
508 1.2.8.2 jdolecek my_sc->sc_elcr &= ~(1 << irq);
509 1.2.8.2 jdolecek
510 1.2.8.2 jdolecek pcib_set_icus(my_sc);
511 1.2.8.2 jdolecek
512 1.2.8.2 jdolecek splx(s);
513 1.2.8.2 jdolecek
514 1.2.8.2 jdolecek return (ih);
515 1.2.8.2 jdolecek }
516 1.2.8.2 jdolecek
517 1.2.8.2 jdolecek void
518 1.2.8.2 jdolecek pcib_isa_intr_disestablish(void *v, void *arg)
519 1.2.8.2 jdolecek {
520 1.2.8.2 jdolecek struct evbmips_intrhand *ih = arg;
521 1.2.8.2 jdolecek int s;
522 1.2.8.2 jdolecek
523 1.2.8.2 jdolecek s = splhigh();
524 1.2.8.2 jdolecek
525 1.2.8.2 jdolecek LIST_REMOVE(ih, ih_q);
526 1.2.8.2 jdolecek
527 1.2.8.2 jdolecek /* If there are no more handlers on this IRQ, disable it. */
528 1.2.8.2 jdolecek if (LIST_FIRST(&my_sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) {
529 1.2.8.2 jdolecek my_sc->sc_imask |= (1 << ih->ih_irq);
530 1.2.8.2 jdolecek pcib_set_icus(my_sc);
531 1.2.8.2 jdolecek }
532 1.2.8.2 jdolecek
533 1.2.8.2 jdolecek splx(s);
534 1.2.8.2 jdolecek
535 1.2.8.2 jdolecek free(ih, M_DEVBUF);
536 1.2.8.2 jdolecek }
537 1.2.8.2 jdolecek
538 1.2.8.2 jdolecek static int
539 1.2.8.2 jdolecek pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
540 1.2.8.2 jdolecek {
541 1.2.8.2 jdolecek int i, tmp, bestirq, count;
542 1.2.8.2 jdolecek struct evbmips_intrhand *ih;
543 1.2.8.2 jdolecek
544 1.2.8.2 jdolecek if (type == IST_NONE)
545 1.2.8.2 jdolecek panic("pcib_intr_alloc: bogus type");
546 1.2.8.2 jdolecek
547 1.2.8.2 jdolecek bestirq = -1;
548 1.2.8.2 jdolecek count = -1;
549 1.2.8.2 jdolecek
550 1.2.8.2 jdolecek mask &= ~my_sc->sc_reserved;
551 1.2.8.2 jdolecek
552 1.2.8.2 jdolecek for (i = 0; i < ICU_LEN; i++) {
553 1.2.8.2 jdolecek if ((mask & (1 << i)) == 0)
554 1.2.8.2 jdolecek continue;
555 1.2.8.2 jdolecek
556 1.2.8.2 jdolecek switch (my_sc->sc_intrtab[i].intr_type) {
557 1.2.8.2 jdolecek case IST_NONE:
558 1.2.8.2 jdolecek /*
559 1.2.8.2 jdolecek * If nothing's using the IRQ, just return it.
560 1.2.8.2 jdolecek */
561 1.2.8.2 jdolecek *irq = i;
562 1.2.8.2 jdolecek return (0);
563 1.2.8.2 jdolecek
564 1.2.8.2 jdolecek case IST_EDGE:
565 1.2.8.2 jdolecek case IST_LEVEL:
566 1.2.8.2 jdolecek if (type != my_sc->sc_intrtab[i].intr_type)
567 1.2.8.2 jdolecek continue;
568 1.2.8.2 jdolecek /*
569 1.2.8.2 jdolecek * If the IRQ is sharable, count the number of
570 1.2.8.2 jdolecek * other handlers, and if it's smaller than the
571 1.2.8.2 jdolecek * last IRQ like this, remember it.
572 1.2.8.2 jdolecek */
573 1.2.8.2 jdolecek tmp = 0;
574 1.2.8.2 jdolecek for (ih = LIST_FIRST(&my_sc->sc_intrtab[i].intr_q);
575 1.2.8.2 jdolecek ih != NULL; ih = LIST_NEXT(ih, ih_q))
576 1.2.8.2 jdolecek tmp++;
577 1.2.8.2 jdolecek if (bestirq == -1 || count > tmp) {
578 1.2.8.2 jdolecek bestirq = i;
579 1.2.8.2 jdolecek count = tmp;
580 1.2.8.2 jdolecek }
581 1.2.8.2 jdolecek break;
582 1.2.8.2 jdolecek
583 1.2.8.2 jdolecek case IST_PULSE:
584 1.2.8.2 jdolecek /* This just isn't sharable. */
585 1.2.8.2 jdolecek continue;
586 1.2.8.2 jdolecek }
587 1.2.8.2 jdolecek }
588 1.2.8.2 jdolecek
589 1.2.8.2 jdolecek if (bestirq == -1)
590 1.2.8.2 jdolecek return (1);
591 1.2.8.2 jdolecek
592 1.2.8.2 jdolecek *irq = bestirq;
593 1.2.8.2 jdolecek return (0);
594 1.2.8.2 jdolecek }
595 1.2.8.2 jdolecek
596 1.2.8.2 jdolecek static void
597 1.2.8.2 jdolecek pcib_cleanup(void *arg)
598 1.2.8.2 jdolecek {
599 1.2.8.2 jdolecek
600 1.2.8.2 jdolecek my_sc->sc_imask = 0xffff;
601 1.2.8.2 jdolecek pcib_set_icus(my_sc);
602 1.2.8.2 jdolecek }
603