1 /* $NetBSD: plumicu.c,v 1.10 2005/12/24 23:24:00 perry Exp $ */
4 * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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>
48 #define DPRINTF(arg) printf arg
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
{
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
,
91 PLUM_INT_USBINTEN_IEN
, PLUM_INT_USBINTEN_REG
,
94 [PLUM_INT_USBWAKE
] = {PLUM_INT_INTSTA_USBWAKE
,
96 PLUM_INT_USBINTEN_WIEN
, PLUM_INT_USBINTEN_REG
,
99 [PLUM_INT_SM
] = {PLUM_INT_INTSTA_SMINT
,
101 PLUM_INT_SMIEN
, PLUM_INT_SMIEN_REG
,
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
{
139 int (*pi_fun
)(void *);
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
;
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
);
158 void plumicu_dump(struct plumicu_softc
*);
162 plumicu_match(struct device
*parent
, struct cfdata
*cf
, void *aux
)
165 return (2); /* 1st attach group */
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
;
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");
191 /* disable all interrupt */
194 for (i
= 0; i
< PLUM_INTR_MAX
; 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 */
214 if (!(sc
->sc_ih
= tx_intr_establish(sc
->sc_pc
->pc_tc
, pa
->pa_irq
,
216 plumicu_intr
, sc
))) {
217 printf(": can't establish interrupt\n");
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);
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
,
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
;
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
];
257 pi
->pi_ctrl
= &pi_ctrl
[line
];
259 /* Enable interrupt */
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)
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
;
293 struct plum_intr_entry
*pi
;
298 for (i
= 0; i
< PLUM_INTR_MAX
; i
++) {
299 pi
= &sc
->sc_intr
[i
];
300 if (pi
->pi_fun
!= arg
)
302 DPRINTF(("plum_intr_disestablish: %d (count=%d)\n",
303 pi
->pi_line
, sc
->sc_enable_count
- 1));
306 panic("plum_intr_disestablish: can't find entry.");
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)
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
;
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
))
354 pi
= &sc
->sc_intr
[i
];
358 if (pic
->ic_ackreg2
== 0) {
359 (*pi
->pi_fun
)(pi
->pi_arg
);
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
);
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
;
383 reg
= plum_conf_read(regt
, regh
, PLUM_INT_INTSTA_REG
);
387 reg
= plum_conf_read(regt
, regh
, PLUM_INT_EXTINTS_REG
);
390 reg
= plum_conf_read(regt
, regh
, PLUM_INT_EXTIEN_REG
);
394 #endif /* PLUMICUDEBUG */