1 /* $NetBSD: tr2_intr.c,v 1.10 2008/04/28 20:23:18 martin 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: tr2_intr.c,v 1.10 2008/04/28 20:23:18 martin Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/device.h> 39 #include <sys/intr.h> 40 41 #include <machine/locore.h> /* mips3_cp0* */ 42 #include <machine/sbdvar.h> 43 #define _SBD_TR2_PRIVATE 44 #include <machine/sbd_tr2.h> 45 46 #include <mips/cpuregs.h> 47 48 SBD_DECL(tr2); 49 50 const uint32_t tr2_sr_bits[_IPL_N] = { 51 [IPL_NONE] = 0, 52 [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0, 53 [IPL_SOFTNET] = 54 MIPS_SOFT_INT_MASK_0 | MIPS_SOFT_INT_MASK_1, 55 [IPL_VM] = 56 MIPS_SOFT_INT_MASK_0 | MIPS_SOFT_INT_MASK_1 | 57 MIPS_INT_MASK_0 | 58 MIPS_INT_MASK_2 | 59 MIPS_INT_MASK_4, 60 [IPL_SCHED] = 61 MIPS_SOFT_INT_MASK_0 | MIPS_SOFT_INT_MASK_1 | 62 MIPS_INT_MASK_0 | 63 MIPS_INT_MASK_2 | 64 MIPS_INT_MASK_4 | 65 MIPS_INT_MASK_5, 66 /* !!! TEST !!! VME INTERRUPT IS NOT MASKED */ 67 }; 68 69 #define NIRQ 8 70 struct tr2_intr_handler { 71 int (*func)(void *); 72 void *arg; 73 volatile uint8_t *picnic_reg; 74 uint8_t picnic_mask; 75 struct evcnt evcnt; 76 char evname[32]; 77 } tr2_intr_handler[NIRQ] = { 78 [0] = { NULL, NULL, PICNIC_INT4_MASK_REG, PICNIC_INT_KBMS }, 79 [2] = { NULL, NULL, PICNIC_INT4_MASK_REG, PICNIC_INT_SERIAL }, 80 [5] = { NULL, NULL, PICNIC_INT2_MASK_REG, PICNIC_INT_SCSI }, 81 [6] = { NULL, NULL, PICNIC_INT2_MASK_REG, PICNIC_INT_ETHER }, 82 [7] = { NULL, NULL, PICNIC_INT0_MASK_REG, PICNIC_INT_FDDLPT }, 83 }; 84 85 struct evcnt timer_tr2_ev = 86 EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, "picnic", "timer"); 87 88 void 89 tr2_intr_init(void) 90 { 91 uint32_t a = (uint32_t)ews4800mips_nmi_vec; 92 93 /* Install dump button handler address to NVSRAM (jumped from ROM) */ 94 *(NVSRAM_CDUMP_ADDR + 0) = (a >> 24) & 0xff; 95 *(NVSRAM_CDUMP_ADDR + 4) = (a >> 16) & 0xff; 96 *(NVSRAM_CDUMP_ADDR + 8) = (a >> 8) & 0xff; 97 *(NVSRAM_CDUMP_ADDR +12) = a & 0xff; 98 99 /* Disable external interrupts */ 100 *PICNIC_INT0_MASK_REG = 0; 101 *PICNIC_INT2_MASK_REG = 0; 102 *PICNIC_INT4_MASK_REG = 0; 103 *PICNIC_INT5_MASK_REG = 0; 104 105 evcnt_attach_static(&timer_tr2_ev); 106 } 107 108 void * 109 tr2_intr_establish(int irq, int (*func)(void *), void *arg) 110 { 111 struct tr2_intr_handler *ih = &tr2_intr_handler[irq]; 112 int s; 113 114 s = splhigh(); 115 ih->func = func; 116 ih->arg = arg; 117 snprintf(ih->evname, sizeof(ih->evname), "irq %d", irq); 118 evcnt_attach_dynamic(&ih->evcnt, EVCNT_TYPE_INTR, NULL, 119 "picnic", ih->evname); 120 121 *ih->picnic_reg |= ih->picnic_mask; 122 splx(s); 123 124 return (void *)irq; 125 } 126 127 void 128 tr2_intr_disestablish(void *arg) 129 { 130 int s, irq = (int)arg; 131 struct tr2_intr_handler *ih = &tr2_intr_handler[irq]; 132 133 s = splhigh(); 134 *ih->picnic_reg &= ~ih->picnic_mask; 135 ih->func = NULL; 136 ih->arg = NULL; 137 evcnt_detach(&ih->evcnt); 138 splx(s); 139 } 140 141 void 142 tr2_intr(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending) 143 { 144 struct tr2_intr_handler *ih; 145 struct clockframe cf; 146 uint32_t r, handled; 147 148 handled = 0; 149 150 if (ipending & MIPS_INT_MASK_5) { /* CLOCK */ 151 cf.pc = pc; 152 cf.sr = status; 153 154 *PICNIC_INT5_STATUS_REG = 0; 155 r = *PICNIC_INT5_STATUS_REG; 156 157 hardclock(&cf); 158 timer_tr2_ev.ev_count++; 159 handled |= MIPS_INT_MASK_5; 160 } 161 _splset((status & handled) | MIPS_SR_INT_IE); 162 163 if (ipending & MIPS_INT_MASK_4) { /* KBD, MOUSE, SERIAL */ 164 r = *PICNIC_INT4_STATUS_REG; 165 166 if (r & PICNIC_INT_KBMS) { 167 ih = &tr2_intr_handler[0]; 168 if (ih->func) { 169 ih->func(ih->arg); 170 ih->evcnt.ev_count++; 171 } 172 r &= ~PICNIC_INT_KBMS; 173 } 174 175 if (r & PICNIC_INT_SERIAL) { 176 #if 0 177 printf("SIO interrupt\n"); 178 #endif 179 ih = &tr2_intr_handler[2]; 180 if (ih->func) { 181 ih->func(ih->arg); 182 ih->evcnt.ev_count++; 183 } 184 r &= ~PICNIC_INT_SERIAL; 185 } 186 187 handled |= MIPS_INT_MASK_4; 188 } 189 _splset((status & handled) | MIPS_SR_INT_IE); 190 191 if (ipending & MIPS_INT_MASK_3) { /* VME */ 192 printf("VME interrupt\n"); 193 194 r = *(volatile uint32_t *)0xbfb00018; /* NABI? */ 195 if ((r & 0x10) != 0) { 196 /* vme high interrupt */ 197 } else if ((r & 0x4) != 0) { 198 /* vme lo interrupt */ 199 } else { 200 /* error */ 201 } 202 } 203 204 if (ipending & MIPS_INT_MASK_2) { /* ETHER, SCSI */ 205 r = *PICNIC_INT2_STATUS_REG; 206 207 if (r & PICNIC_INT_ETHER) { 208 ih = &tr2_intr_handler[6]; 209 if (ih->func) { 210 ih->func(ih->arg); 211 ih->evcnt.ev_count++; 212 } 213 r &= ~PICNIC_INT_ETHER; 214 } 215 216 if (r & PICNIC_INT_SCSI) { 217 ih = &tr2_intr_handler[5]; 218 if (ih->func) { 219 ih->func(ih->arg); 220 ih->evcnt.ev_count++; 221 } 222 r &= ~PICNIC_INT_SCSI; 223 } 224 225 if ((r & PICNIC_INT_FDDLPT) && 226 ((cause & status) & MIPS_INT_MASK_5)) { 227 #ifdef DEBUG 228 printf("FDD LPT interrupt\n"); 229 #endif 230 ih = &tr2_intr_handler[7]; 231 if (ih->func) { 232 ih->func(ih->arg); 233 ih->evcnt.ev_count++; 234 } 235 r &= ~PICNIC_INT_FDDLPT; 236 } 237 238 handled |= MIPS_INT_MASK_2; 239 } 240 _splset((status & handled) | MIPS_SR_INT_IE); 241 242 if (ipending & MIPS_INT_MASK_1) 243 panic("unknown interrupt INT1\n"); 244 245 if (ipending & MIPS_INT_MASK_0) { /* FDD, PRINTER */ 246 printf("printer, printer interrupt\n"); 247 r = *PICNIC_INT0_STATUS_REG; 248 if (r & PICNIC_INT_FDDLPT) { 249 printf("FDD, Printer interrupt.\n"); 250 } else { 251 printf("unknown interrupt INT0\n"); 252 } 253 handled |= MIPS_INT_MASK_0; 254 } 255 cause &= ~handled; 256 _splset(((status & ~cause) & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE); 257 } 258 259 void 260 tr2_initclocks(void) 261 { 262 263 /* Enable clock interrupt */ 264 *PICNIC_INT5_MASK_REG |= PICNIC_INT_CLOCK; 265 } 266