1 /* $NetBSD: news3400.c,v 1.5 2002/07/07 00:22:19 gmcgarry 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 #if !defined(SOFTFLOAT) 124 MachFPInterrupt(status, cause, pc, curproc->p_md.md_regs); 125 #endif 126 } 127 } 128 129 #define LEVEL0_MASK \ 130 (INTST1_DMA|INTST1_SLOT1|INTST1_SLOT3|INTST1_EXT1|INTST1_EXT3) 131 132 void 133 level0_intr() 134 { 135 volatile u_char *istat1 = (void *)INTST1; 136 volatile u_char *iclr1 = (void *)INTCLR1; 137 int stat; 138 139 stat = *istat1 & LEVEL0_MASK; 140 *iclr1 = stat; 141 142 hb_intr_dispatch(0); 143 144 if (stat & INTST1_SLOT1) 145 intrcnt[SLOT1_INTR]++; 146 if (stat & INTST1_SLOT3) 147 intrcnt[SLOT3_INTR]++; 148 } 149 150 #define LEVEL1_MASK0 (INTST0_CFLT|INTST0_CBSY) 151 #define LEVEL1_MASK1 (INTST1_BEEP|INTST1_SCC|INTST1_LANCE) 152 153 void 154 level1_intr() 155 { 156 volatile u_char *ien1 = (void *)INTEN1; 157 volatile u_char *istat1 = (void *)INTST1; 158 volatile u_char *iclr1 = (void *)INTCLR1; 159 int stat1, saved_ie1; 160 161 saved_ie1 = *ien1; 162 163 *ien1 = 0; /* disable BEEP, LANCE, and SCC */ 164 165 stat1 = *istat1 & LEVEL1_MASK1; 166 *iclr1 = stat1; 167 168 stat1 &= saved_ie1; 169 170 hb_intr_dispatch(1); 171 172 *ien1 = saved_ie1; 173 174 if (stat1 & INTST1_SCC) 175 intrcnt[SERIAL0_INTR]++; 176 if (stat1 & INTST1_LANCE) 177 intrcnt[LANCE_INTR]++; 178 } 179 180 int 181 news3400_badaddr(addr, size) 182 void *addr; 183 u_int size; 184 { 185 volatile int x; 186 187 badaddr_flag = 0; 188 189 switch (size) { 190 case 1: 191 x = *(volatile int8_t *)addr; 192 break; 193 case 2: 194 x = *(volatile int16_t *)addr; 195 break; 196 case 4: 197 x = *(volatile int32_t *)addr; 198 break; 199 } 200 201 return badaddr_flag; 202 } 203 204 static void 205 enable_intr_3400(void) 206 { 207 volatile u_int8_t *inten0 = (void *)INTEN0; 208 volatile u_int8_t *inten1 = (void *)INTEN1; 209 volatile u_int8_t *intclr0 = (void *)INTCLR0; 210 volatile u_int8_t *intclr1 = (void *)INTCLR1; 211 212 /* clear all interrupts */ 213 *intclr0 = 0xff; 214 *intclr1 = 0xff; 215 216 /* 217 * It's not a time to enable timer yet. 218 * 219 * INTEN0: PERR ABORT BERR TIMER KBD MS CFLT CBSY 220 * o o o x o o x x 221 * INTEN1: BEEP SCC LANCE DMA SLOT1 SLOT3 EXT1 EXT3 222 * x o o o o o x x 223 */ 224 225 *inten0 = INTEN0_PERR | INTEN0_ABORT | INTEN0_BERR | 226 INTEN0_KBDINT | INTEN0_MSINT; 227 228 *inten1 = INTEN1_SCC | INTEN1_LANCE | INTEN1_DMA | 229 INTEN1_SLOT1 | INTEN1_SLOT3; 230 } 231 232 static void 233 disable_intr_3400(void) 234 { 235 volatile u_int8_t *inten0 = (void *)INTEN0; 236 volatile u_int8_t *inten1 = (void *)INTEN1; 237 238 *inten0 = 0; 239 *inten1 = 0; 240 } 241 242 static void 243 readidrom_3400(rom) 244 register u_char *rom; 245 { 246 register u_char *p = (u_char *)IDROM; 247 register int i; 248 249 for (i = 0; i < sizeof (struct idrom); i++, p += 2) 250 *rom++ = ((*p & 0x0f) << 4) + (*(p + 1) & 0x0f); 251 } 252 253 extern struct idrom idrom; 254 255 void 256 news3400_init() 257 { 258 enable_intr = enable_intr_3400; 259 disable_intr = disable_intr_3400; 260 261 readidrom_3400((u_char *)&idrom); 262 hostid = idrom.id_serial; 263 } 264