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