1 /* $NetBSD: news3400.c,v 1.4 2000/12/03 01:42:30 matt 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/param.h> 30 #include <sys/kernel.h> 31 #include <sys/proc.h> 32 #include <sys/systm.h> 33 34 #include <machine/adrsmap.h> 35 #include <machine/cpu.h> 36 #include <machine/intr.h> 37 #include <machine/psl.h> 38 #include <newsmips/newsmips/machid.h> 39 40 void level0_intr (void); 41 void level1_intr (void); 42 void hb_intr_dispatch (int); 43 void MachFPInterrupt (unsigned, unsigned, unsigned, struct frame *); 44 45 int news3400_badaddr (void *, u_int); 46 static void enable_intr_3400 (void); 47 static void disable_intr_3400 (void); 48 static void readidrom_3400 (u_char *); 49 void news3400_init (void); 50 51 static int badaddr_flag; 52 53 #define INT_MASK_FPU MIPS_INT_MASK_3 54 55 /* 56 * Handle news3400 interrupts. 57 */ 58 void 59 news3400_intr(status, cause, pc, ipending) 60 u_int status; /* status register at time of the exception */ 61 u_int cause; /* cause register at time of exception */ 62 u_int pc; /* program counter where to continue */ 63 u_int ipending; 64 { 65 struct clockframe cf; 66 67 /* handle clock interrupts ASAP */ 68 if (ipending & MIPS_INT_MASK_2) { 69 register int stat; 70 71 stat = *(volatile u_char *)INTST0; 72 stat &= INTST0_TIMINT|INTST0_KBDINT|INTST0_MSINT; 73 74 *(volatile u_char *)INTCLR0 = stat; 75 if (stat & INTST0_TIMINT) { 76 cf.pc = pc; 77 cf.sr = status; 78 hardclock(&cf); 79 intrcnt[HARDCLOCK_INTR]++; 80 stat &= ~INTST0_TIMINT; 81 } 82 83 if (stat) 84 hb_intr_dispatch(2); 85 86 cause &= ~MIPS_INT_MASK_2; 87 } 88 /* If clock interrupts were enabled, re-enable them ASAP. */ 89 _splset(MIPS_SR_INT_IE | (status & MIPS_INT_MASK_2)); 90 91 if (ipending & MIPS_INT_MASK_5) { 92 *(volatile char *)INTCLR0 = INTCLR0_PERR; 93 printf("Memory error interrupt(?) at 0x%x\n", pc); 94 cause &= ~MIPS_INT_MASK_5; 95 } 96 97 /* asynchronous bus error */ 98 if (ipending & MIPS_INT_MASK_4) { 99 *(volatile char *)INTCLR0 = INTCLR0_BERR; 100 cause &= ~MIPS_INT_MASK_4; 101 badaddr_flag = 1; 102 } 103 104 if (ipending & MIPS_INT_MASK_1) { 105 level1_intr(); 106 cause &= ~MIPS_INT_MASK_1; 107 } 108 109 if (ipending & MIPS_INT_MASK_0) { 110 level0_intr(); 111 cause &= ~MIPS_INT_MASK_0; 112 } 113 114 _splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE); 115 116 /* FPU nofiticaition */ 117 if (ipending & INT_MASK_FPU) { 118 if (!USERMODE(status)) 119 panic("kernel used FPU: PC %x, CR %x, SR %x", 120 pc, cause, status); 121 122 intrcnt[FPU_INTR]++; 123 /* dealfpu(status, cause, pc); */ 124 MachFPInterrupt(status, cause, pc, curproc->p_md.md_regs); 125 } 126 } 127 128 #define LEVEL0_MASK \ 129 (INTST1_DMA|INTST1_SLOT1|INTST1_SLOT3|INTST1_EXT1|INTST1_EXT3) 130 131 void 132 level0_intr() 133 { 134 volatile u_char *istat1 = (void *)INTST1; 135 volatile u_char *iclr1 = (void *)INTCLR1; 136 int stat; 137 138 stat = *istat1 & LEVEL0_MASK; 139 *iclr1 = stat; 140 141 hb_intr_dispatch(0); 142 143 if (stat & INTST1_SLOT1) 144 intrcnt[SLOT1_INTR]++; 145 if (stat & INTST1_SLOT3) 146 intrcnt[SLOT3_INTR]++; 147 } 148 149 #define LEVEL1_MASK0 (INTST0_CFLT|INTST0_CBSY) 150 #define LEVEL1_MASK1 (INTST1_BEEP|INTST1_SCC|INTST1_LANCE) 151 152 void 153 level1_intr() 154 { 155 volatile u_char *ien1 = (void *)INTEN1; 156 volatile u_char *istat1 = (void *)INTST1; 157 volatile u_char *iclr1 = (void *)INTCLR1; 158 int stat1, saved_ie1; 159 160 saved_ie1 = *ien1; 161 162 *ien1 = 0; /* disable BEEP, LANCE, and SCC */ 163 164 stat1 = *istat1 & LEVEL1_MASK1; 165 *iclr1 = stat1; 166 167 stat1 &= saved_ie1; 168 169 hb_intr_dispatch(1); 170 171 *ien1 = saved_ie1; 172 173 if (stat1 & INTST1_SCC) 174 intrcnt[SERIAL0_INTR]++; 175 if (stat1 & INTST1_LANCE) 176 intrcnt[LANCE_INTR]++; 177 } 178 179 int 180 news3400_badaddr(addr, size) 181 void *addr; 182 u_int size; 183 { 184 volatile int x; 185 186 badaddr_flag = 0; 187 188 switch (size) { 189 case 1: 190 x = *(volatile int8_t *)addr; 191 break; 192 case 2: 193 x = *(volatile int16_t *)addr; 194 break; 195 case 4: 196 x = *(volatile int32_t *)addr; 197 break; 198 } 199 200 return badaddr_flag; 201 } 202 203 static void 204 enable_intr_3400(void) 205 { 206 volatile u_int8_t *inten0 = (void *)INTEN0; 207 volatile u_int8_t *inten1 = (void *)INTEN1; 208 volatile u_int8_t *intclr0 = (void *)INTCLR0; 209 volatile u_int8_t *intclr1 = (void *)INTCLR1; 210 211 /* clear all interrupts */ 212 *intclr0 = 0xff; 213 *intclr1 = 0xff; 214 215 /* 216 * It's not a time to enable timer yet. 217 * 218 * INTEN0: PERR ABORT BERR TIMER KBD MS CFLT CBSY 219 * o o o x o o x x 220 * INTEN1: BEEP SCC LANCE DMA SLOT1 SLOT3 EXT1 EXT3 221 * x o o o o o x x 222 */ 223 224 *inten0 = INTEN0_PERR | INTEN0_ABORT | INTEN0_BERR | 225 INTEN0_KBDINT | INTEN0_MSINT; 226 227 *inten1 = INTEN1_SCC | INTEN1_LANCE | INTEN1_DMA | 228 INTEN1_SLOT1 | INTEN1_SLOT3; 229 } 230 231 static void 232 disable_intr_3400(void) 233 { 234 volatile u_int8_t *inten0 = (void *)INTEN0; 235 volatile u_int8_t *inten1 = (void *)INTEN1; 236 237 *inten0 = 0; 238 *inten1 = 0; 239 } 240 241 static void 242 readidrom_3400(rom) 243 register u_char *rom; 244 { 245 register u_char *p = (u_char *)IDROM; 246 register int i; 247 248 for (i = 0; i < sizeof (struct idrom); i++, p += 2) 249 *rom++ = ((*p & 0x0f) << 4) + (*(p + 1) & 0x0f); 250 } 251 252 extern struct idrom idrom; 253 254 void 255 news3400_init() 256 { 257 enable_intr = enable_intr_3400; 258 disable_intr = disable_intr_3400; 259 260 readidrom_3400((u_char *)&idrom); 261 hostid = idrom.id_serial; 262 } 263