1 /* $NetBSD: news3400.c,v 1.19 2007/12/03 15:34:05 ad 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.19 2007/12/03 15:34:05 ad 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(uint8_t *); 57 58 static volatile 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(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending) 67 { 68 struct clockframe cf; 69 struct cpu_info *ci; 70 71 ci = curcpu(); 72 ci->ci_idepth++; 73 74 /* handle clock interrupts ASAP */ 75 if (ipending & MIPS_INT_MASK_2) { 76 int stat; 77 78 stat = *(volatile uint8_t *)INTST0; 79 stat &= INTST0_TIMINT|INTST0_KBDINT|INTST0_MSINT; 80 81 *(volatile uint8_t *)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 uint8_t *)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 uint8_t *)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 ci->ci_idepth--; 136 } 137 138 #define LEVEL0_MASK \ 139 (INTST1_DMA|INTST1_SLOT1|INTST1_SLOT3|INTST1_EXT1|INTST1_EXT3) 140 141 static void 142 news3400_level0_intr(void) 143 { 144 volatile uint8_t *intst1 = (void *)INTST1; 145 volatile uint8_t *intclr1 = (void *)INTCLR1; 146 uint8_t stat; 147 148 stat = *intst1 & LEVEL0_MASK; 149 *intclr1 = stat; 150 151 hb_intr_dispatch(0, stat); 152 153 if (stat & INTST1_SLOT1) 154 intrcnt[SLOT1_INTR]++; 155 if (stat & INTST1_SLOT3) 156 intrcnt[SLOT3_INTR]++; 157 } 158 159 #define LEVEL1_MASK0 (INTST0_CFLT|INTST0_CBSY) 160 #define LEVEL1_MASK1 (INTST1_BEEP|INTST1_SCC|INTST1_LANCE) 161 162 static void 163 news3400_level1_intr(void) 164 { 165 volatile uint8_t *inten1 = (void *)INTEN1; 166 volatile uint8_t *intst1 = (void *)INTST1; 167 volatile uint8_t *intclr1 = (void *)INTCLR1; 168 uint8_t stat1, saved_inten1; 169 170 saved_inten1 = *inten1; 171 172 *inten1 = 0; /* disable BEEP, LANCE, and SCC */ 173 174 stat1 = *intst1 & LEVEL1_MASK1; 175 *intclr1 = stat1; 176 177 stat1 &= saved_inten1; 178 179 hb_intr_dispatch(1, stat1); 180 181 *inten1 = saved_inten1; 182 183 if (stat1 & INTST1_SCC) 184 intrcnt[SERIAL0_INTR]++; 185 if (stat1 & INTST1_LANCE) 186 intrcnt[LANCE_INTR]++; 187 } 188 189 int 190 news3400_badaddr(void *addr, u_int size) 191 { 192 volatile u_int x; 193 194 badaddr_flag = 0; 195 196 switch (size) { 197 case 1: 198 x = *(volatile uint8_t *)addr; 199 break; 200 case 2: 201 x = *(volatile uint16_t *)addr; 202 break; 203 case 4: 204 x = *(volatile uint32_t *)addr; 205 break; 206 } 207 208 return badaddr_flag; 209 } 210 211 static void 212 news3400_enable_intr(void) 213 { 214 volatile uint8_t *inten0 = (void *)INTEN0; 215 volatile uint8_t *inten1 = (void *)INTEN1; 216 volatile uint8_t *intclr0 = (void *)INTCLR0; 217 volatile uint8_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 uint8_t *inten0 = (void *)INTEN0; 244 volatile uint8_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 uint8_t *)ITIMER = IOCLOCK / 6144 / 100 - 1; 256 257 /* enable timer interrupt */ 258 *(volatile uint8_t *)INTEN0 |= (uint8_t)INTEN0_TIMINT; 259 } 260 261 static void 262 news3400_readidrom(uint8_t *rom) 263 { 264 uint8_t *p = (uint8_t *)IDROM; 265 int i; 266 267 for (i = 0; i < sizeof (struct idrom); i++, p += 2) 268 *rom++ = ((*p & 0x0f) << 4) + (*(p + 1) & 0x0f); 269 } 270 271 extern struct idrom idrom; 272 273 void 274 news3400_init(void) 275 { 276 277 enable_intr = news3400_enable_intr; 278 disable_intr = news3400_disable_intr; 279 enable_timer = news3400_enable_timer; 280 281 news3400_readidrom((uint8_t *)&idrom); 282 hostid = idrom.id_serial; 283 } 284