1 /* $NetBSD: news3400.c,v 1.13 2003/10/25 04:07:28 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (C) 1999 Tsubai Masanari. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: news3400.c,v 1.13 2003/10/25 04:07:28 tsutsui Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/kernel.h> 34 #include <sys/proc.h> 35 #include <sys/systm.h> 36 37 #include <machine/adrsmap.h> 38 #include <machine/cpu.h> 39 #include <machine/intr.h> 40 #include <machine/psl.h> 41 #include <newsmips/newsmips/machid.h> 42 43 #include <newsmips/dev/hbvar.h> 44 45 #if !defined(SOFTFLOAT) 46 extern void MachFPInterrupt(unsigned, unsigned, unsigned, struct frame *); 47 #endif 48 49 int news3400_badaddr(void *, u_int); 50 51 static void news3400_level0_intr(void); 52 static void news3400_level1_intr(void); 53 static void news3400_enable_intr(void); 54 static void news3400_disable_intr(void); 55 static void news3400_enable_timer(void); 56 static void news3400_readidrom(u_char *); 57 58 static int badaddr_flag; 59 60 #define INT_MASK_FPU MIPS_INT_MASK_3 61 62 /* 63 * Handle news3400 interrupts. 64 */ 65 void 66 news3400_intr(status, cause, pc, ipending) 67 u_int status; /* status register at time of the exception */ 68 u_int cause; /* cause register at time of exception */ 69 u_int pc; /* program counter where to continue */ 70 u_int ipending; 71 { 72 struct clockframe cf; 73 74 /* handle clock interrupts ASAP */ 75 if (ipending & MIPS_INT_MASK_2) { 76 int stat; 77 78 stat = *(volatile u_char *)INTST0; 79 stat &= INTST0_TIMINT|INTST0_KBDINT|INTST0_MSINT; 80 81 *(volatile u_char *)INTCLR0 = stat; 82 if (stat & INTST0_TIMINT) { 83 cf.pc = pc; 84 cf.sr = status; 85 hardclock(&cf); 86 intrcnt[HARDCLOCK_INTR]++; 87 stat &= ~INTST0_TIMINT; 88 } 89 90 if (stat) 91 hb_intr_dispatch(2, stat); 92 93 cause &= ~MIPS_INT_MASK_2; 94 } 95 /* If clock interrupts were enabled, re-enable them ASAP. */ 96 _splset(MIPS_SR_INT_IE | (status & MIPS_INT_MASK_2)); 97 98 if (ipending & MIPS_INT_MASK_5) { 99 *(volatile char *)INTCLR0 = INTCLR0_PERR; 100 printf("Memory error interrupt(?) at 0x%x\n", pc); 101 cause &= ~MIPS_INT_MASK_5; 102 } 103 104 /* asynchronous bus error */ 105 if (ipending & MIPS_INT_MASK_4) { 106 *(volatile char *)INTCLR0 = INTCLR0_BERR; 107 cause &= ~MIPS_INT_MASK_4; 108 badaddr_flag = 1; 109 } 110 111 if (ipending & MIPS_INT_MASK_1) { 112 news3400_level1_intr(); 113 cause &= ~MIPS_INT_MASK_1; 114 } 115 116 if (ipending & MIPS_INT_MASK_0) { 117 news3400_level0_intr(); 118 cause &= ~MIPS_INT_MASK_0; 119 } 120 121 _splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE); 122 123 /* FPU nofiticaition */ 124 if (ipending & INT_MASK_FPU) { 125 if (!USERMODE(status)) 126 panic("kernel used FPU: PC %x, CR %x, SR %x", 127 pc, cause, status); 128 129 intrcnt[FPU_INTR]++; 130 #if !defined(SOFTFLOAT) 131 MachFPInterrupt(status, cause, pc, curlwp->l_md.md_regs); 132 #endif 133 } 134 } 135 136 #define LEVEL0_MASK \ 137 (INTST1_DMA|INTST1_SLOT1|INTST1_SLOT3|INTST1_EXT1|INTST1_EXT3) 138 139 static void 140 news3400_level0_intr() 141 { 142 volatile u_char *intst1 = (void *)INTST1; 143 volatile u_char *intclr1 = (void *)INTCLR1; 144 int stat; 145 146 stat = *intst1 & LEVEL0_MASK; 147 *intclr1 = stat; 148 149 hb_intr_dispatch(0, stat); 150 151 if (stat & INTST1_SLOT1) 152 intrcnt[SLOT1_INTR]++; 153 if (stat & INTST1_SLOT3) 154 intrcnt[SLOT3_INTR]++; 155 } 156 157 #define LEVEL1_MASK0 (INTST0_CFLT|INTST0_CBSY) 158 #define LEVEL1_MASK1 (INTST1_BEEP|INTST1_SCC|INTST1_LANCE) 159 160 static void 161 news3400_level1_intr() 162 { 163 volatile u_char *inten1 = (void *)INTEN1; 164 volatile u_char *intst1 = (void *)INTST1; 165 volatile u_char *intclr1 = (void *)INTCLR1; 166 int stat1, saved_inten1; 167 168 saved_inten1 = *inten1; 169 170 *inten1 = 0; /* disable BEEP, LANCE, and SCC */ 171 172 stat1 = *intst1 & LEVEL1_MASK1; 173 *intclr1 = stat1; 174 175 stat1 &= saved_inten1; 176 177 hb_intr_dispatch(1, stat1); 178 179 *inten1 = saved_inten1; 180 181 if (stat1 & INTST1_SCC) 182 intrcnt[SERIAL0_INTR]++; 183 if (stat1 & INTST1_LANCE) 184 intrcnt[LANCE_INTR]++; 185 } 186 187 int 188 news3400_badaddr(addr, size) 189 void *addr; 190 u_int size; 191 { 192 volatile int x; 193 194 badaddr_flag = 0; 195 196 switch (size) { 197 case 1: 198 x = *(volatile int8_t *)addr; 199 break; 200 case 2: 201 x = *(volatile int16_t *)addr; 202 break; 203 case 4: 204 x = *(volatile int32_t *)addr; 205 break; 206 } 207 208 return badaddr_flag; 209 } 210 211 static void 212 news3400_enable_intr(void) 213 { 214 volatile u_int8_t *inten0 = (void *)INTEN0; 215 volatile u_int8_t *inten1 = (void *)INTEN1; 216 volatile u_int8_t *intclr0 = (void *)INTCLR0; 217 volatile u_int8_t *intclr1 = (void *)INTCLR1; 218 219 /* clear all interrupts */ 220 *intclr0 = 0xff; 221 *intclr1 = 0xff; 222 223 /* 224 * It's not a time to enable timer yet. 225 * 226 * INTEN0: PERR ABORT BERR TIMER KBD MS CFLT CBSY 227 * o o o x o o x x 228 * INTEN1: BEEP SCC LANCE DMA SLOT1 SLOT3 EXT1 EXT3 229 * x o o o o o x x 230 */ 231 232 *inten0 = INTEN0_PERR | INTEN0_ABORT | INTEN0_BERR | 233 INTEN0_KBDINT | INTEN0_MSINT; 234 235 *inten1 = INTEN1_SCC | INTEN1_LANCE | INTEN1_DMA | 236 INTEN1_SLOT1 | INTEN1_SLOT3; 237 } 238 239 static void 240 news3400_disable_intr(void) 241 { 242 243 volatile u_int8_t *inten0 = (void *)INTEN0; 244 volatile u_int8_t *inten1 = (void *)INTEN1; 245 246 *inten0 = 0; 247 *inten1 = 0; 248 } 249 250 static void 251 news3400_enable_timer(void) 252 { 253 254 /* initialize interval timer */ 255 *(volatile u_int8_t *)ITIMER = IOCLOCK / 6144 / 100 - 1; 256 257 /* enable timer interrupt */ 258 *(volatile u_int8_t *)INTEN0 |= (u_int8_t)INTEN0_TIMINT; 259 } 260 261 static void 262 news3400_readidrom(rom) 263 u_char *rom; 264 { 265 u_char *p = (u_char *)IDROM; 266 int i; 267 268 for (i = 0; i < sizeof (struct idrom); i++, p += 2) 269 *rom++ = ((*p & 0x0f) << 4) + (*(p + 1) & 0x0f); 270 } 271 272 extern struct idrom idrom; 273 274 void 275 news3400_init() 276 { 277 278 enable_intr = news3400_enable_intr; 279 disable_intr = news3400_disable_intr; 280 enable_timer = news3400_enable_timer; 281 282 news3400_readidrom((u_char *)&idrom); 283 hostid = idrom.id_serial; 284 } 285