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