1 /* $NetBSD: plumicu.c,v 1.13 2023/09/10 11:30:13 andvar 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.13 2023/09/10 11:30:13 andvar 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_ENABLE
49 #define DPRINTF_DEBUG plumicu_debug
50 #endif
51 #include <machine/debug.h>
52
53 int plumicu_match(device_t, cfdata_t, void *);
54 void plumicu_attach(device_t, device_t, 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 plum_chipset_tag_t sc_pc;
146 bus_space_tag_t sc_regt;
147 bus_space_handle_t sc_regh;
148 void *sc_ih;
149 int sc_enable_count;
150 struct plum_intr_entry sc_intr[PLUM_INTR_MAX];
151 };
152
153 CFATTACH_DECL_NEW(plumicu, sizeof(struct plumicu_softc),
154 plumicu_match, plumicu_attach, NULL, NULL);
155
156 #ifdef PLUMICUDEBUG
157 void plumicu_dump(struct plumicu_softc *);
158 #endif
159
160 int
plumicu_match(device_t parent,cfdata_t cf,void * aux)161 plumicu_match(device_t parent, cfdata_t cf, void *aux)
162 {
163
164 return (2); /* 1st attach group */
165 }
166
167 void
plumicu_attach(device_t parent,device_t self,void * aux)168 plumicu_attach(device_t parent, device_t self, void *aux)
169 {
170 struct plum_attach_args *pa = aux;
171 struct plumicu_softc *sc = device_private(self);
172 const struct plum_intr_ctrl *pic;
173 bus_space_tag_t regt;
174 bus_space_handle_t regh;
175 plumreg_t reg;
176 int i;
177
178 sc->sc_pc = pa->pa_pc;
179 sc->sc_regt = pa->pa_regt;
180
181 /* map plum2 interrupt controller register space */
182 if (bus_space_map(sc->sc_regt, PLUM_INT_REGBASE,
183 PLUM_INT_REGSIZE, 0, &sc->sc_regh)) {
184 printf(":interrupt register map failed\n");
185 return;
186 }
187 #ifdef PLUMICUDEBUG
188 plumicu_dump(sc);
189 #endif
190 /* disable all interrupt */
191 regt = sc->sc_regt;
192 regh = sc->sc_regh;
193 for (i = 0; i < PLUM_INTR_MAX; i++) {
194 pic = &pi_ctrl[i];
195 if (pic->ic_ienreg) {
196 reg = plum_conf_read(regt, regh, pic->ic_ienreg);
197 reg &= ~pic->ic_ienpat;
198 plum_conf_write(regt, regh, pic->ic_ienreg, reg);
199 }
200 if (pic->ic_senreg) {
201 reg = plum_conf_read(regt, regh, pic->ic_senreg);
202 reg &= ~pic->ic_senpat;
203 plum_conf_write(regt, regh, pic->ic_senreg, reg);
204 }
205 }
206
207 /* register handle to plum_chipset_tag */
208 plum_conf_register_intr(sc->sc_pc, (void*)sc);
209
210 /* disable interrupt redirect to TX39 core */
211 plum_di(sc->sc_pc);
212
213 if (!(sc->sc_ih = tx_intr_establish(sc->sc_pc->pc_tc, pa->pa_irq,
214 IST_EDGE, IPL_BIO,
215 plumicu_intr, sc))) {
216 printf(": can't establish interrupt\n");
217 }
218 printf("\n");
219 }
220
221 inline void
plum_di(plum_chipset_tag_t pc)222 plum_di(plum_chipset_tag_t pc)
223 {
224 struct plumicu_softc *sc = pc->pc_intrt;
225
226 plum_conf_write(sc->sc_regt, sc->sc_regh, PLUM_INT_INTIEN_REG, 0);
227 }
228
229 inline void
plum_ei(plum_chipset_tag_t pc)230 plum_ei(plum_chipset_tag_t pc)
231 {
232 struct plumicu_softc *sc = pc->pc_intrt;
233
234 plum_conf_write(sc->sc_regt, sc->sc_regh, PLUM_INT_INTIEN_REG,
235 PLUM_INT_INTIEN);
236 }
237
238 void*
plum_intr_establish(plum_chipset_tag_t pc,int line,int mode,int level,int (* ih_fun)(void *),void * ih_arg)239 plum_intr_establish(plum_chipset_tag_t pc, int line, int mode, int level,
240 int (*ih_fun)(void *), void *ih_arg)
241 {
242 struct plumicu_softc *sc = pc->pc_intrt;
243 bus_space_tag_t regt = sc->sc_regt;
244 bus_space_handle_t regh = sc->sc_regh;
245 plumreg_t reg;
246 struct plum_intr_entry *pi;
247
248 if (!LEGAL_PRUM_INTR(line)) {
249 panic("plum_intr_establish: bogus interrupt line");
250 }
251
252 pi = &sc->sc_intr[line];
253 pi->pi_line = line;
254 pi->pi_fun = ih_fun;
255 pi->pi_arg = ih_arg;
256 pi->pi_ctrl = &pi_ctrl[line];
257
258 /* Enable interrupt */
259
260 /* status enable */
261 if (pi->pi_ctrl->ic_senreg) {
262 reg = plum_conf_read(regt, regh, pi->pi_ctrl->ic_senreg);
263 reg |= pi->pi_ctrl->ic_senpat;
264 plum_conf_write(regt, regh, pi->pi_ctrl->ic_senreg, reg);
265 }
266 /* interrupt enable */
267 if (pi->pi_ctrl->ic_ienreg) {
268 reg = plum_conf_read(regt, regh, pi->pi_ctrl->ic_ienreg);
269 reg |= pi->pi_ctrl->ic_ienpat;
270 plum_conf_write(regt, regh, pi->pi_ctrl->ic_ienreg, reg);
271 }
272
273 /* Enable redirect to TX39 core */
274 DPRINTF("plum_intr_establish: %d (count=%d)\n", line,
275 sc->sc_enable_count);
276
277 if (sc->sc_enable_count++ == 0)
278 plum_ei(pc);
279
280 pi->pi_enabled = 1;
281
282 return (ih_fun);
283 }
284
285 void
plum_intr_disestablish(plum_chipset_tag_t pc,void * arg)286 plum_intr_disestablish(plum_chipset_tag_t pc, void *arg)
287 {
288 struct plumicu_softc *sc = pc->pc_intrt;
289 bus_space_tag_t regt = sc->sc_regt;
290 bus_space_handle_t regh = sc->sc_regh;
291 plumreg_t reg;
292 struct plum_intr_entry *pi;
293 int i;
294
295 sc = pc->pc_intrt;
296
297 for (i = 0; i < PLUM_INTR_MAX; i++) {
298 pi = &sc->sc_intr[i];
299 if (pi->pi_fun != arg)
300 continue;
301 DPRINTF("plum_intr_disestablish: %d (count=%d)\n",
302 pi->pi_line, sc->sc_enable_count - 1);
303 goto found;
304 }
305 panic("plum_intr_disestablish: can't find entry.");
306 /* NOTREACHED */
307 found:
308 pi->pi_enabled = 0;
309 /* Disable interrupt */
310 if (pi->pi_ctrl->ic_ienreg) {
311 reg = plum_conf_read(regt, regh, pi->pi_ctrl->ic_ienreg);
312 reg &= ~(pi->pi_ctrl->ic_ienpat);
313 plum_conf_write(regt, regh, pi->pi_ctrl->ic_ienreg, reg);
314 }
315 if (pi->pi_ctrl->ic_senreg) {
316 reg = plum_conf_read(regt, regh, pi->pi_ctrl->ic_senreg);
317 reg &= ~(pi->pi_ctrl->ic_senpat);
318 plum_conf_write(regt, regh, pi->pi_ctrl->ic_senreg, reg);
319 }
320
321 /* Disable/Enable interrupt redirect to TX39 core */
322 if (--sc->sc_enable_count == 0)
323 plum_di(pc);
324 }
325
326 int
plumicu_intr(void * arg)327 plumicu_intr(void *arg)
328 {
329 struct plumicu_softc *sc = arg;
330 bus_space_tag_t regt = sc->sc_regt;
331 bus_space_handle_t regh = sc->sc_regh;
332 plumreg_t reg1, reg2, reg_ext, reg_pccard;
333 int i;
334
335 plum_di(sc->sc_pc);
336 /* read level 1 status */
337 reg1 = plum_conf_read(regt, regh, PLUM_INT_INTSTA_REG);
338
339 /* read level 2 status and acknowledge */
340 reg_ext = plum_conf_read(regt, regh, PLUM_INT_EXTINTS_REG);
341 plum_conf_write(regt, regh, PLUM_INT_EXTINTS_REG, reg_ext);
342
343 reg_pccard = plum_conf_read(regt, regh, PLUM_INT_PCCINTS_REG);
344 plum_conf_write(regt, regh, PLUM_INT_PCCINTS_REG, reg_pccard);
345
346 for (i = 0; i < PLUM_INTR_MAX; i++) {
347 register struct plum_intr_entry *pi;
348 register const struct plum_intr_ctrl *pic = &pi_ctrl[i];
349
350 if (!(pic->ic_ackpat1 & reg1))
351 continue;
352
353 pi = &sc->sc_intr[i];
354 if (!pi->pi_enabled)
355 continue;
356
357 if (pic->ic_ackreg2 == 0) {
358 (*pi->pi_fun)(pi->pi_arg);
359 continue;
360 }
361
362 reg2 = pic->ic_ackreg2 == PLUM_INT_PCCINTS_REG
363 ? reg_pccard : reg_ext;
364
365 if (pic->ic_ackpat2 & reg2)
366 (*pi->pi_fun)(pi->pi_arg);
367 }
368 plum_ei(sc->sc_pc);
369
370 return (0);
371 }
372
373 #ifdef PLUMICUDEBUG
374 void
plumicu_dump(struct plumicu_softc * sc)375 plumicu_dump(struct plumicu_softc *sc)
376 {
377 bus_space_tag_t regt = sc->sc_regt;
378 bus_space_handle_t regh = sc->sc_regh;
379 plumreg_t reg;
380
381 printf("status:");
382 reg = plum_conf_read(regt, regh, PLUM_INT_INTSTA_REG);
383 dbg_bit_print(reg);
384 printf("ExtIO\n");
385 printf("status:");
386 reg = plum_conf_read(regt, regh, PLUM_INT_EXTINTS_REG);
387 dbg_bit_print(reg);
388 printf("enable:");
389 reg = plum_conf_read(regt, regh, PLUM_INT_EXTIEN_REG);
390 dbg_bit_print(reg);
391
392 }
393 #endif /* PLUMICUDEBUG */
394