1 /* $NetBSD: tr2a_intr.c,v 1.15 2011/03/10 17:05:41 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 2004, 2005 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: tr2a_intr.c,v 1.15 2011/03/10 17:05:41 tsutsui Exp $"); 34 35 #define __INTR_PRIVATE 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/kernel.h> 39 #include <sys/evcnt.h> 40 #include <sys/lwp.h> 41 #include <sys/cpu.h> 42 #include <sys/intr.h> 43 44 #include <machine/locore.h> /* mips3_cp0* */ 45 #include <machine/sbdvar.h> 46 #define _SBD_TR2A_PRIVATE 47 #include <machine/sbd_tr2a.h> 48 49 SBD_DECL(tr2a); 50 51 const struct ipl_sr_map tr2a_ipl_sr_map = { 52 .sr_bits = { 53 [IPL_NONE] = 0, 54 [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0, 55 [IPL_SOFTNET] = MIPS_SOFT_INT_MASK, 56 [IPL_VM] = MIPS_INT_MASK & ~MIPS_INT_MASK_5, 57 [IPL_SCHED] = MIPS_INT_MASK, 58 [IPL_DDB] = MIPS_INT_MASK, 59 [IPL_HIGH] = MIPS_INT_MASK, 60 }, 61 }; 62 63 #define NIRQ 16 64 enum bustype { 65 ASOBUS, 66 APBUS, 67 }; 68 69 /* ASO + APbus interrupt */ 70 struct tr2a_intr_handler { 71 int (*func)(void *); 72 void *arg; 73 enum bustype bustype; 74 uint32_t cpu_int; 75 uint32_t aso_mask; 76 struct evcnt evcnt; 77 char evname[32]; 78 } tr2a_intr_handler[NIRQ] = { 79 [0] = { NULL, NULL, ASOBUS, 2, 0x00000001 }, /* AM79C90 */ 80 [4] = { NULL, NULL, ASOBUS, 4, 0x00300010 }, /* Z85230 (SIO) */ 81 [6] = { NULL, NULL, ASOBUS, 2, 0x00000200 }, /* 53C710 SCSI-A */ 82 [9] = { NULL, NULL, ASOBUS, 4, 0x00000040 }, /* Z85230 (KBMS) */ 83 [10] = { NULL, NULL, ASOBUS, 2, 0x00000100 }, /* 53C710 SCSI-B */ 84 }; 85 86 /* CPU interrupt */ 87 struct tr2a_intc_handler { 88 int ref_cnt; 89 uint32_t mask; 90 } tr2a_intc_handler[6] = { 91 [0] = { 0, 0x00000020 }, 92 [1] = { 0, 0x00000800 }, 93 [2] = { 0, 0x00010000 }, 94 [3] = { 0, 0x00200000 }, 95 [4] = { 0, 0x04000000 }, 96 [5] = { 0, 0x80000000 } 97 }; 98 99 struct evcnt timer_tr2a_ev = 100 EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, "intc", "timer"); 101 102 void 103 tr2a_intr_init(void) 104 { 105 106 /* Disable all ASObus interrupt */ 107 #if 1 108 *ASO_INT_MASK_REG &= ~TR2A_ASO_INTMASK_ALL; 109 #else 110 /* open all interrupt for development. */ 111 *ASO_INT_MASK_REG |= TR2A_ASO_INTMASK_ALL; 112 #endif 113 tr2a_wbflush(); 114 115 /* set up interval timer clock */ 116 *INTC_MASK_REG = 0; 117 *CLOCK_REG = 0x80; 118 tr2a_wbflush(); 119 if ((*CLOCK_REG & 0x80) != 0) 120 *ASO_INT_MASK_REG |= 0x8000; /* NMI (what UX does.) -uch */ 121 tr2a_wbflush(); 122 123 evcnt_attach_static(&timer_tr2a_ev); 124 } 125 126 void * 127 tr2a_intr_establish(int irq, int (*func)(void *), void *arg) 128 { 129 struct tr2a_intr_handler *ih = &tr2a_intr_handler[irq]; 130 struct tr2a_intc_handler *ic = &tr2a_intc_handler[ih->cpu_int]; 131 int s; 132 133 s = splhigh(); 134 ih->func = func; 135 ih->arg = arg; 136 snprintf(ih->evname, sizeof(ih->evname), "irq %d", irq); 137 evcnt_attach_dynamic(&ih->evcnt, EVCNT_TYPE_INTR, 138 NULL, "intc", ih->evname); 139 140 if (ih->bustype == ASOBUS) 141 *ASO_INT_MASK_REG |= ih->aso_mask; 142 143 if (ic->ref_cnt++ == 0) 144 *INTC_MASK_REG |= ic->mask; 145 146 tr2a_wbflush(); 147 splx(s); 148 149 return (void *)irq; 150 } 151 152 void 153 tr2a_intr_disestablish(void *arg) 154 { 155 int s, irq = (int)arg; 156 struct tr2a_intr_handler *ih = &tr2a_intr_handler[irq]; 157 struct tr2a_intc_handler *ic = &tr2a_intc_handler[ih->cpu_int]; 158 159 s = splhigh(); 160 if (ih->bustype == ASOBUS) 161 *ASO_INT_MASK_REG &= ~ih->aso_mask; 162 163 if (--ic->ref_cnt == 0) 164 *INTC_MASK_REG &= ~ic->mask; 165 166 ih->func = NULL; 167 ih->arg = NULL; 168 evcnt_detach(&ih->evcnt); 169 splx(s); 170 } 171 172 void 173 tr2a_intr(int ppl, vaddr_t pc, uint32_t status) 174 { 175 struct tr2a_intr_handler *ih; 176 struct clockframe cf; 177 uint32_t r, intc_cause, ipending; 178 int ipl; 179 180 intc_cause = *INTC_STATUS_REG & *INTC_MASK_REG; 181 182 while (ppl < (ipl = splintr(&ipending))) { 183 if ((ipending & MIPS_INT_MASK_5) && (intc_cause & INTC_INT5)) { 184 cf.pc = pc; 185 cf.sr = status; 186 cf.intr = (curcpu()->ci_idepth > 1); 187 tr2a_wbflush(); 188 *INTC_CLEAR_REG = 0x7c; 189 *INTC_STATUS_REG; 190 191 hardclock(&cf); 192 timer_tr2a_ev.ev_count++; 193 } 194 195 if ((ipending & MIPS_INT_MASK_4) && (intc_cause & INTC_INT4)) { 196 /* KBD, MOUSE, SERIAL */ 197 r = *ASO_INT_STATUS_REG; 198 if (r & 0x300010) { 199 ih = &tr2a_intr_handler[4]; 200 if (ih->func) { 201 ih->func(ih->arg); 202 ih->evcnt.ev_count++; 203 } 204 } else if (r & 0x40) { 205 /* kbms */ 206 ih = &tr2a_intr_handler[9]; 207 if (ih->func) { 208 ih->func(ih->arg); 209 ih->evcnt.ev_count++; 210 } 211 } else if (r & 0x20) { 212 printf("INT4 (1)\n"); 213 } else if (r & 0x00800000) { 214 printf("INT4 (2)\n"); 215 } else if (r & 0x00400000) { 216 printf("INT4 (3)\n"); 217 } else if (r != 0) { 218 printf("not for INT4 %x\n", r); 219 } 220 221 tr2a_wbflush(); 222 *INTC_CLEAR_REG = 0x68; 223 *INTC_STATUS_REG; 224 } 225 226 if ((ipending & MIPS_INT_MASK_3) && (intc_cause & INTC_INT3)) { 227 /* APbus HI */ 228 printf("APbus HI\n"); 229 tr2a_wbflush(); 230 *INTC_CLEAR_REG = 0x54; 231 *INTC_STATUS_REG; 232 } 233 234 if ((ipending & MIPS_INT_MASK_2) && (intc_cause & INTC_INT2)) { 235 /* SCSI, ETHER */ 236 r = *ASO_INT_STATUS_REG; 237 if (r & 0x100) { /* SCSI-A */ 238 ih = &tr2a_intr_handler[6]; 239 if (ih->func) { 240 ih->func(ih->arg); 241 ih->evcnt.ev_count++; 242 } 243 } else if (r & 0x200) { /* SCSI-B */ 244 ih = &tr2a_intr_handler[10]; 245 if (ih->func) { 246 ih->func(ih->arg); 247 ih->evcnt.ev_count++; 248 } 249 } else if (r & 0x1) { /* LANCE */ 250 ih = &tr2a_intr_handler[0]; 251 if (ih->func) { 252 ih->func(ih->arg); 253 ih->evcnt.ev_count++; 254 } 255 } else if (r != 0) { 256 printf("not for INT2 %x %x\n", r, 257 *ASO_DMAINT_STATUS_REG); 258 } 259 260 tr2a_wbflush(); 261 *INTC_CLEAR_REG = 0x40; 262 *INTC_STATUS_REG; 263 } 264 265 if ((ipending & MIPS_INT_MASK_1) && (intc_cause & INTC_INT1)) { 266 /* APbus LO */ 267 printf("APbus LO\n"); 268 tr2a_wbflush(); 269 *INTC_CLEAR_REG = 0x2c; 270 *INTC_STATUS_REG; 271 } 272 273 if ((ipending & MIPS_INT_MASK_0) && (intc_cause & INTC_INT0)) { 274 /* NMI etc. */ 275 r = *ASO_INT_STATUS_REG; 276 printf("INT0 %08x\n", r); 277 if (r & 0x8000) { 278 printf("INT0(1) NMI\n"); 279 } else if (r & 0x8) { 280 printf("INT0(2)\n"); 281 } else if (r & 0x4) { 282 printf("INT0(3)\n"); 283 } else if (r != 0) { 284 printf("not for INT0 %x\n", r); 285 } 286 tr2a_wbflush(); 287 *INTC_CLEAR_REG = 0x14; 288 *INTC_STATUS_REG; 289 } 290 intc_cause = *INTC_STATUS_REG & *INTC_MASK_REG; 291 } 292 } 293 294 void 295 tr2a_initclocks(void) 296 { 297 298 /* Enable INT5 */ 299 *INTC_MASK_REG |= INTC_INT5; 300 tr2a_wbflush(); 301 } 302