No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / hpcmips / dev / plumicu.c
blob227e4661ca16afe74bc3b700f5e1bdb312d2f49e
1 /* $NetBSD: plumicu.c,v 1.10 2005/12/24 23:24:00 perry Exp $ */
3 /*-
4 * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by UCHIYAMA Yasushi.
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.
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.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: plumicu.c,v 1.10 2005/12/24 23:24:00 perry Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
39 #include <machine/bus.h>
40 #include <machine/intr.h>
42 #include <hpcmips/tx/tx39var.h>
43 #include <hpcmips/dev/plumvar.h>
44 #include <hpcmips/dev/plumicuvar.h>
45 #include <hpcmips/dev/plumicureg.h>
47 #ifdef PLUMICUDEBUG
48 #define DPRINTF(arg) printf arg
49 #else
50 #define DPRINTF(arg)
51 #endif
53 int plumicu_match(struct device *, struct cfdata *, void *);
54 void plumicu_attach(struct device *, struct device *, void *);
55 int plumicu_intr(void *);
57 static inline void plum_di(plum_chipset_tag_t);
58 static inline void plum_ei(plum_chipset_tag_t);
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
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
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
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
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
94 [PLUM_INT_USBWAKE] = {PLUM_INT_INTSTA_USBWAKE,
95 0, 0,
96 PLUM_INT_USBINTEN_WIEN, PLUM_INT_USBINTEN_REG,
97 0, 0
99 [PLUM_INT_SM] = {PLUM_INT_INTSTA_SMINT,
100 0, 0,
101 PLUM_INT_SMIEN, PLUM_INT_SMIEN_REG,
102 0, 0
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,
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,
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,
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,
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,
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,
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;
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];
154 CFATTACH_DECL(plumicu, sizeof(struct plumicu_softc),
155 plumicu_match, plumicu_attach, NULL, NULL);
157 #ifdef PLUMICUDEBUG
158 void plumicu_dump(struct plumicu_softc *);
159 #endif
162 plumicu_match(struct device *parent, struct cfdata *cf, void *aux)
165 return (2); /* 1st attach group */
168 void
169 plumicu_attach(struct device *parent, struct device *self, void *aux)
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;
179 sc->sc_pc = pa->pa_pc;
180 sc->sc_regt = pa->pa_regt;
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;
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);
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);
208 /* register handle to plum_chipset_tag */
209 plum_conf_register_intr(sc->sc_pc, (void*)sc);
211 /* disable interrupt redirect to TX39 core */
212 plum_di(sc->sc_pc);
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");
219 printf("\n");
222 inline void
223 plum_di(plum_chipset_tag_t pc)
225 struct plumicu_softc *sc = pc->pc_intrt;
227 plum_conf_write(sc->sc_regt, sc->sc_regh, PLUM_INT_INTIEN_REG, 0);
230 inline void
231 plum_ei(plum_chipset_tag_t pc)
233 struct plumicu_softc *sc = pc->pc_intrt;
235 plum_conf_write(sc->sc_regt, sc->sc_regh, PLUM_INT_INTIEN_REG,
236 PLUM_INT_INTIEN);
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)
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;
249 if (!LEGAL_PRUM_INTR(line)) {
250 panic("plum_intr_establish: bogus interrupt line");
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];
259 /* Enable interrupt */
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);
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);
274 /* Enable redirect to TX39 core */
275 DPRINTF(("plum_intr_establish: %d (count=%d)\n", line,
276 sc->sc_enable_count));
278 if (sc->sc_enable_count++ == 0)
279 plum_ei(pc);
281 pi->pi_enabled = 1;
283 return (ih_fun);
286 void
287 plum_intr_disestablish(plum_chipset_tag_t pc, void *arg)
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;
296 sc = pc->pc_intrt;
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;
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);
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);
322 /* Disable/Enable interrupt redirect to TX39 core */
323 if (--sc->sc_enable_count == 0)
324 plum_di(pc);
328 plumicu_intr(void *arg)
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;
336 plum_di(sc->sc_pc);
337 /* read level 1 status */
338 reg1 = plum_conf_read(regt, regh, PLUM_INT_INTSTA_REG);
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);
344 reg_pccard = plum_conf_read(regt, regh, PLUM_INT_PCCINTS_REG);
345 plum_conf_write(regt, regh, PLUM_INT_PCCINTS_REG, reg_pccard);
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];
351 if (!(pic->ic_ackpat1 & reg1))
352 continue;
354 pi = &sc->sc_intr[i];
355 if (!pi->pi_enabled)
356 continue;
358 if (pic->ic_ackreg2 == 0) {
359 (*pi->pi_fun)(pi->pi_arg);
360 continue;
363 reg2 = pic->ic_ackreg2 == PLUM_INT_PCCINTS_REG
364 ? reg_pccard : reg_ext;
366 if (pic->ic_ackpat2 & reg2)
367 (*pi->pi_fun)(pi->pi_arg);
369 plum_ei(sc->sc_pc);
371 return (0);
374 #ifdef PLUMICUDEBUG
375 void
376 plumicu_dump(struct plumicu_softc *sc)
378 bus_space_tag_t regt = sc->sc_regt;
379 bus_space_handle_t regh = sc->sc_regh;
380 plumreg_t reg;
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);
394 #endif /* PLUMICUDEBUG */