plumicu.c revision 1.10.74.1 1 /* $NetBSD: plumicu.c,v 1.10.74.1 2008/06/02 13:22:10 mjf Exp $ */
2
3 /*-
4 * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by UCHIYAMA Yasushi.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: plumicu.c,v 1.10.74.1 2008/06/02 13:22:10 mjf Exp $");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
38
39 #include <machine/bus.h>
40 #include <machine/intr.h>
41
42 #include <hpcmips/tx/tx39var.h>
43 #include <hpcmips/dev/plumvar.h>
44 #include <hpcmips/dev/plumicuvar.h>
45 #include <hpcmips/dev/plumicureg.h>
46
47 #ifdef PLUMICUDEBUG
48 #define DPRINTF(arg) printf arg
49 #else
50 #define DPRINTF(arg)
51 #endif
52
53 int plumicu_match(struct device *, struct cfdata *, void *);
54 void plumicu_attach(struct device *, struct device *, void *);
55 int plumicu_intr(void *);
56
57 static inline void plum_di(plum_chipset_tag_t);
58 static inline void plum_ei(plum_chipset_tag_t);
59
60 const struct plum_intr_ctrl {
61 plumreg_t ic_ackpat1;
62 plumreg_t ic_ackpat2; int ic_ackreg2;
63 plumreg_t ic_ienpat; int ic_ienreg;
64 plumreg_t ic_senpat; int ic_senreg;
65 } pi_ctrl[PLUM_INTR_MAX] = {
66 [PLUM_INT_C1IO] = {PLUM_INT_INTSTA_PCCINT,
67 PLUM_INT_PCCINTS_C1IO, PLUM_INT_PCCINTS_REG,
68 PLUM_INT_PCCIEN_IENC1IO, PLUM_INT_PCCIEN_REG,
69 PLUM_INT_PCCIEN_SENC1IO, PLUM_INT_PCCIEN_REG
70 },
71 [PLUM_INT_C1RI] = {PLUM_INT_INTSTA_PCCINT,
72 PLUM_INT_PCCINTS_C1RI, PLUM_INT_PCCINTS_REG,
73 PLUM_INT_PCCIEN_IENC1RI, PLUM_INT_PCCIEN_REG,
74 PLUM_INT_PCCIEN_SENC1RI, PLUM_INT_PCCIEN_REG
75 },
76 [PLUM_INT_C1SC] = {PLUM_INT_INTSTA_C1SCINT, 0, 0, 0, 0, 0, 0},
77 [PLUM_INT_C2IO] = {PLUM_INT_INTSTA_PCCINT,
78 PLUM_INT_PCCINTS_C2IO, PLUM_INT_PCCINTS_REG,
79 PLUM_INT_PCCIEN_IENC2IO, PLUM_INT_PCCIEN_REG,
80 PLUM_INT_PCCIEN_SENC2IO, PLUM_INT_PCCIEN_REG
81 },
82 [PLUM_INT_C2RI] = {PLUM_INT_INTSTA_PCCINT,
83 PLUM_INT_PCCINTS_C2RI, PLUM_INT_PCCINTS_REG,
84 PLUM_INT_PCCIEN_IENC2RI, PLUM_INT_PCCIEN_REG,
85 PLUM_INT_PCCIEN_SENC2RI, PLUM_INT_PCCIEN_REG
86 },
87 [PLUM_INT_C2SC] = {PLUM_INT_INTSTA_C2SCINT, 0, 0, 0, 0, 0, 0},
88 [PLUM_INT_DISP] = {PLUM_INT_INTSTA_DISPINT, 0, 0, 0, 0, 0, 0},
89 [PLUM_INT_USB] = {PLUM_INT_INTSTA_USBINT,
90 0, 0,
91 PLUM_INT_USBINTEN_IEN, PLUM_INT_USBINTEN_REG,
92 0, 0
93 },
94 [PLUM_INT_USBWAKE] = {PLUM_INT_INTSTA_USBWAKE,
95 0, 0,
96 PLUM_INT_USBINTEN_WIEN, PLUM_INT_USBINTEN_REG,
97 0, 0
98 },
99 [PLUM_INT_SM] = {PLUM_INT_INTSTA_SMINT,
100 0, 0,
101 PLUM_INT_SMIEN, PLUM_INT_SMIEN_REG,
102 0, 0
103 },
104 [PLUM_INT_EXT5IO0] = {PLUM_INT_INTSTA_EXTINT,
105 PLUM_INT_EXTINTS_IO5INT0, PLUM_INT_EXTINTS_REG,
106 PLUM_INT_EXTIEN_IENIO5INT0, PLUM_INT_EXTIEN_REG,
107 PLUM_INT_EXTIEN_SENIO5INT0, PLUM_INT_EXTIEN_REG,
108 },
109 [PLUM_INT_EXT5IO1] = {PLUM_INT_INTSTA_EXTINT,
110 PLUM_INT_EXTINTS_IO5INT1, PLUM_INT_EXTINTS_REG,
111 PLUM_INT_EXTIEN_IENIO5INT1, PLUM_INT_EXTIEN_REG,
112 PLUM_INT_EXTIEN_SENIO5INT1, PLUM_INT_EXTIEN_REG,
113 },
114 [PLUM_INT_EXT5IO2] = {PLUM_INT_INTSTA_EXTINT,
115 PLUM_INT_EXTINTS_IO5INT2, PLUM_INT_EXTINTS_REG,
116 PLUM_INT_EXTIEN_IENIO5INT2, PLUM_INT_EXTIEN_REG,
117 PLUM_INT_EXTIEN_SENIO5INT2, PLUM_INT_EXTIEN_REG,
118 },
119 [PLUM_INT_EXT5IO3] = {PLUM_INT_INTSTA_EXTINT,
120 PLUM_INT_EXTINTS_IO5INT3, PLUM_INT_EXTINTS_REG,
121 PLUM_INT_EXTIEN_IENIO5INT0, PLUM_INT_EXTIEN_REG,
122 PLUM_INT_EXTIEN_SENIO5INT0, PLUM_INT_EXTIEN_REG,
123 },
124 [PLUM_INT_EXT3IO0] = {PLUM_INT_INTSTA_EXTINT,
125 PLUM_INT_EXTINTS_IO3INT0, PLUM_INT_EXTINTS_REG,
126 PLUM_INT_EXTIEN_IENIO3INT0, PLUM_INT_EXTIEN_REG,
127 PLUM_INT_EXTIEN_SENIO3INT0, PLUM_INT_EXTIEN_REG,
128 },
129 [PLUM_INT_EXT3IO1] = {PLUM_INT_INTSTA_EXTINT,
130 PLUM_INT_EXTINTS_IO3INT1, PLUM_INT_EXTINTS_REG,
131 PLUM_INT_EXTIEN_IENIO3INT1, PLUM_INT_EXTIEN_REG,
132 PLUM_INT_EXTIEN_SENIO3INT1, PLUM_INT_EXTIEN_REG,
133 }
134 };
135
136 struct plum_intr_entry {
137 int pi_enabled;
138 int pi_line;
139 int (*pi_fun)(void *);
140 void *pi_arg;
141 const struct plum_intr_ctrl *pi_ctrl;
142 };
143
144 struct plumicu_softc {
145 struct device sc_dev;
146 plum_chipset_tag_t sc_pc;
147 bus_space_tag_t sc_regt;
148 bus_space_handle_t sc_regh;
149 void *sc_ih;
150 int sc_enable_count;
151 struct plum_intr_entry sc_intr[PLUM_INTR_MAX];
152 };
153
154 CFATTACH_DECL(plumicu, sizeof(struct plumicu_softc),
155 plumicu_match, plumicu_attach, NULL, NULL);
156
157 #ifdef PLUMICUDEBUG
158 void plumicu_dump(struct plumicu_softc *);
159 #endif
160
161 int
162 plumicu_match(struct device *parent, struct cfdata *cf, void *aux)
163 {
164
165 return (2); /* 1st attach group */
166 }
167
168 void
169 plumicu_attach(struct device *parent, struct device *self, void *aux)
170 {
171 struct plum_attach_args *pa = aux;
172 struct plumicu_softc *sc = (void*)self;
173 const struct plum_intr_ctrl *pic;
174 bus_space_tag_t regt;
175 bus_space_handle_t regh;
176 plumreg_t reg;
177 int i;
178
179 sc->sc_pc = pa->pa_pc;
180 sc->sc_regt = pa->pa_regt;
181
182 /* map plum2 interrupt controller register space */
183 if (bus_space_map(sc->sc_regt, PLUM_INT_REGBASE,
184 PLUM_INT_REGSIZE, 0, &sc->sc_regh)) {
185 printf(":interrupt register map failed\n");
186 return;
187 }
188 #ifdef PLUMICUDEBUG
189 plumicu_dump(sc);
190 #endif
191 /* disable all interrupt */
192 regt = sc->sc_regt;
193 regh = sc->sc_regh;
194 for (i = 0; i < PLUM_INTR_MAX; i++) {
195 pic = &pi_ctrl[i];
196 if (pic->ic_ienreg) {
197 reg = plum_conf_read(regt, regh, pic->ic_ienreg);
198 reg &= ~pic->ic_ienpat;
199 plum_conf_write(regt, regh, pic->ic_ienreg, reg);
200 }
201 if (pic->ic_senreg) {
202 reg = plum_conf_read(regt, regh, pic->ic_senreg);
203 reg &= ~pic->ic_senpat;
204 plum_conf_write(regt, regh, pic->ic_senreg, reg);
205 }
206 }
207
208 /* register handle to plum_chipset_tag */
209 plum_conf_register_intr(sc->sc_pc, (void*)sc);
210
211 /* disable interrupt redirect to TX39 core */
212 plum_di(sc->sc_pc);
213
214 if (!(sc->sc_ih = tx_intr_establish(sc->sc_pc->pc_tc, pa->pa_irq,
215 IST_EDGE, IPL_BIO,
216 plumicu_intr, sc))) {
217 printf(": can't establish interrupt\n");
218 }
219 printf("\n");
220 }
221
222 inline void
223 plum_di(plum_chipset_tag_t pc)
224 {
225 struct plumicu_softc *sc = pc->pc_intrt;
226
227 plum_conf_write(sc->sc_regt, sc->sc_regh, PLUM_INT_INTIEN_REG, 0);
228 }
229
230 inline void
231 plum_ei(plum_chipset_tag_t pc)
232 {
233 struct plumicu_softc *sc = pc->pc_intrt;
234
235 plum_conf_write(sc->sc_regt, sc->sc_regh, PLUM_INT_INTIEN_REG,
236 PLUM_INT_INTIEN);
237 }
238
239 void*
240 plum_intr_establish(plum_chipset_tag_t pc, int line, int mode, int level,
241 int (*ih_fun)(void *), void *ih_arg)
242 {
243 struct plumicu_softc *sc = pc->pc_intrt;
244 bus_space_tag_t regt = sc->sc_regt;
245 bus_space_handle_t regh = sc->sc_regh;
246 plumreg_t reg;
247 struct plum_intr_entry *pi;
248
249 if (!LEGAL_PRUM_INTR(line)) {
250 panic("plum_intr_establish: bogus interrupt line");
251 }
252
253 pi = &sc->sc_intr[line];
254 pi->pi_line = line;
255 pi->pi_fun = ih_fun;
256 pi->pi_arg = ih_arg;
257 pi->pi_ctrl = &pi_ctrl[line];
258
259 /* Enable interrupt */
260
261 /* status enable */
262 if (pi->pi_ctrl->ic_senreg) {
263 reg = plum_conf_read(regt, regh, pi->pi_ctrl->ic_senreg);
264 reg |= pi->pi_ctrl->ic_senpat;
265 plum_conf_write(regt, regh, pi->pi_ctrl->ic_senreg, reg);
266 }
267 /* interrupt enable */
268 if (pi->pi_ctrl->ic_ienreg) {
269 reg = plum_conf_read(regt, regh, pi->pi_ctrl->ic_ienreg);
270 reg |= pi->pi_ctrl->ic_ienpat;
271 plum_conf_write(regt, regh, pi->pi_ctrl->ic_ienreg, reg);
272 }
273
274 /* Enable redirect to TX39 core */
275 DPRINTF(("plum_intr_establish: %d (count=%d)\n", line,
276 sc->sc_enable_count));
277
278 if (sc->sc_enable_count++ == 0)
279 plum_ei(pc);
280
281 pi->pi_enabled = 1;
282
283 return (ih_fun);
284 }
285
286 void
287 plum_intr_disestablish(plum_chipset_tag_t pc, void *arg)
288 {
289 struct plumicu_softc *sc = pc->pc_intrt;
290 bus_space_tag_t regt = sc->sc_regt;
291 bus_space_handle_t regh = sc->sc_regh;
292 plumreg_t reg;
293 struct plum_intr_entry *pi;
294 int i;
295
296 sc = pc->pc_intrt;
297
298 for (i = 0; i < PLUM_INTR_MAX; i++) {
299 pi = &sc->sc_intr[i];
300 if (pi->pi_fun != arg)
301 continue;
302 DPRINTF(("plum_intr_disestablish: %d (count=%d)\n",
303 pi->pi_line, sc->sc_enable_count - 1));
304 goto found;
305 }
306 panic("plum_intr_disestablish: can't find entry.");
307 /* NOTREACHED */
308 found:
309 pi->pi_enabled = 0;
310 /* Disable interrupt */
311 if (pi->pi_ctrl->ic_ienreg) {
312 reg = plum_conf_read(regt, regh, pi->pi_ctrl->ic_ienreg);
313 reg &= ~(pi->pi_ctrl->ic_ienpat);
314 plum_conf_write(regt, regh, pi->pi_ctrl->ic_ienreg, reg);
315 }
316 if (pi->pi_ctrl->ic_senreg) {
317 reg = plum_conf_read(regt, regh, pi->pi_ctrl->ic_senreg);
318 reg &= ~(pi->pi_ctrl->ic_senpat);
319 plum_conf_write(regt, regh, pi->pi_ctrl->ic_senreg, reg);
320 }
321
322 /* Disable/Enable interrupt redirect to TX39 core */
323 if (--sc->sc_enable_count == 0)
324 plum_di(pc);
325 }
326
327 int
328 plumicu_intr(void *arg)
329 {
330 struct plumicu_softc *sc = arg;
331 bus_space_tag_t regt = sc->sc_regt;
332 bus_space_handle_t regh = sc->sc_regh;
333 plumreg_t reg1, reg2, reg_ext, reg_pccard;
334 int i;
335
336 plum_di(sc->sc_pc);
337 /* read level 1 status */
338 reg1 = plum_conf_read(regt, regh, PLUM_INT_INTSTA_REG);
339
340 /* read level 2 status and acknowledge */
341 reg_ext = plum_conf_read(regt, regh, PLUM_INT_EXTINTS_REG);
342 plum_conf_write(regt, regh, PLUM_INT_EXTINTS_REG, reg_ext);
343
344 reg_pccard = plum_conf_read(regt, regh, PLUM_INT_PCCINTS_REG);
345 plum_conf_write(regt, regh, PLUM_INT_PCCINTS_REG, reg_pccard);
346
347 for (i = 0; i < PLUM_INTR_MAX; i++) {
348 register struct plum_intr_entry *pi;
349 register const struct plum_intr_ctrl *pic = &pi_ctrl[i];
350
351 if (!(pic->ic_ackpat1 & reg1))
352 continue;
353
354 pi = &sc->sc_intr[i];
355 if (!pi->pi_enabled)
356 continue;
357
358 if (pic->ic_ackreg2 == 0) {
359 (*pi->pi_fun)(pi->pi_arg);
360 continue;
361 }
362
363 reg2 = pic->ic_ackreg2 == PLUM_INT_PCCINTS_REG
364 ? reg_pccard : reg_ext;
365
366 if (pic->ic_ackpat2 & reg2)
367 (*pi->pi_fun)(pi->pi_arg);
368 }
369 plum_ei(sc->sc_pc);
370
371 return (0);
372 }
373
374 #ifdef PLUMICUDEBUG
375 void
376 plumicu_dump(struct plumicu_softc *sc)
377 {
378 bus_space_tag_t regt = sc->sc_regt;
379 bus_space_handle_t regh = sc->sc_regh;
380 plumreg_t reg;
381
382 printf("status:");
383 reg = plum_conf_read(regt, regh, PLUM_INT_INTSTA_REG);
384 dbg_bit_print(reg);
385 printf("ExtIO\n");
386 printf("status:");
387 reg = plum_conf_read(regt, regh, PLUM_INT_EXTINTS_REG);
388 dbg_bit_print(reg);
389 printf("enable:");
390 reg = plum_conf_read(regt, regh, PLUM_INT_EXTIEN_REG);
391 dbg_bit_print(reg);
392
393 }
394 #endif /* PLUMICUDEBUG */
395