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