1 /* $NetBSD: news3400.c,v 1.15 2005/02/06 02:58:15 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.15 2005/02/06 02:58:15 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(uint8_t *); 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(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending) 67 { 68 struct clockframe cf; 69 70 /* handle clock interrupts ASAP */ 71 if (ipending & MIPS_INT_MASK_2) { 72 int stat; 73 74 stat = *(volatile uint8_t *)INTST0; 75 stat &= INTST0_TIMINT|INTST0_KBDINT|INTST0_MSINT; 76 77 *(volatile uint8_t *)INTCLR0 = stat; 78 if (stat & INTST0_TIMINT) { 79 cf.pc = pc; 80 cf.sr = status; 81 hardclock(&cf); 82 intrcnt[HARDCLOCK_INTR]++; 83 stat &= ~INTST0_TIMINT; 84 } 85 86 if (stat) 87 hb_intr_dispatch(2, stat); 88 89 cause &= ~MIPS_INT_MASK_2; 90 } 91 /* If clock interrupts were enabled, re-enable them ASAP. */ 92 _splset(MIPS_SR_INT_IE | (status & MIPS_INT_MASK_2)); 93 94 if (ipending & MIPS_INT_MASK_5) { 95 *(volatile uint8_t *)INTCLR0 = INTCLR0_PERR; 96 printf("Memory error interrupt(?) at 0x%x\n", pc); 97 cause &= ~MIPS_INT_MASK_5; 98 } 99 100 /* asynchronous bus error */ 101 if (ipending & MIPS_INT_MASK_4) { 102 *(volatile uint8_t *)INTCLR0 = INTCLR0_BERR; 103 cause &= ~MIPS_INT_MASK_4; 104 badaddr_flag = 1; 105 } 106 107 if (ipending & MIPS_INT_MASK_1) { 108 news3400_level1_intr(); 109 cause &= ~MIPS_INT_MASK_1; 110 } 111 112 if (ipending & MIPS_INT_MASK_0) { 113 news3400_level0_intr(); 114 cause &= ~MIPS_INT_MASK_0; 115 } 116 117 _splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE); 118 119 /* FPU nofiticaition */ 120 if (ipending & INT_MASK_FPU) { 121 if (!USERMODE(status)) 122 panic("kernel used FPU: PC %x, CR %x, SR %x", 123 pc, cause, status); 124 125 intrcnt[FPU_INTR]++; 126 #if !defined(SOFTFLOAT) 127 MachFPInterrupt(status, cause, pc, curlwp->l_md.md_regs); 128 #endif 129 } 130 } 131 132 #define LEVEL0_MASK \ 133 (INTST1_DMA|INTST1_SLOT1|INTST1_SLOT3|INTST1_EXT1|INTST1_EXT3) 134 135 static void 136 news3400_level0_intr(void) 137 { 138 volatile uint8_t *intst1 = (void *)INTST1; 139 volatile uint8_t *intclr1 = (void *)INTCLR1; 140 uint8_t stat; 141 142 stat = *intst1 & LEVEL0_MASK; 143 *intclr1 = stat; 144 145 hb_intr_dispatch(0, stat); 146 147 if (stat & INTST1_SLOT1) 148 intrcnt[SLOT1_INTR]++; 149 if (stat & INTST1_SLOT3) 150 intrcnt[SLOT3_INTR]++; 151 } 152 153 #define LEVEL1_MASK0 (INTST0_CFLT|INTST0_CBSY) 154 #define LEVEL1_MASK1 (INTST1_BEEP|INTST1_SCC|INTST1_LANCE) 155 156 static void 157 news3400_level1_intr(void) 158 { 159 volatile uint8_t *inten1 = (void *)INTEN1; 160 volatile uint8_t *intst1 = (void *)INTST1; 161 volatile uint8_t *intclr1 = (void *)INTCLR1; 162 uint8_t stat1, saved_inten1; 163 164 saved_inten1 = *inten1; 165 166 *inten1 = 0; /* disable BEEP, LANCE, and SCC */ 167 168 stat1 = *intst1 & LEVEL1_MASK1; 169 *intclr1 = stat1; 170 171 stat1 &= saved_inten1; 172 173 hb_intr_dispatch(1, stat1); 174 175 *inten1 = saved_inten1; 176 177 if (stat1 & INTST1_SCC) 178 intrcnt[SERIAL0_INTR]++; 179 if (stat1 & INTST1_LANCE) 180 intrcnt[LANCE_INTR]++; 181 } 182 183 int 184 news3400_badaddr(void *addr, u_int size) 185 { 186 volatile int x; 187 188 badaddr_flag = 0; 189 190 switch (size) { 191 case 1: 192 x = *(volatile int8_t *)addr; 193 break; 194 case 2: 195 x = *(volatile int16_t *)addr; 196 break; 197 case 4: 198 x = *(volatile int32_t *)addr; 199 break; 200 } 201 202 return badaddr_flag; 203 } 204 205 static void 206 news3400_enable_intr(void) 207 { 208 volatile uint8_t *inten0 = (void *)INTEN0; 209 volatile uint8_t *inten1 = (void *)INTEN1; 210 volatile uint8_t *intclr0 = (void *)INTCLR0; 211 volatile uint8_t *intclr1 = (void *)INTCLR1; 212 213 /* clear all interrupts */ 214 *intclr0 = 0xff; 215 *intclr1 = 0xff; 216 217 /* 218 * It's not a time to enable timer yet. 219 * 220 * INTEN0: PERR ABORT BERR TIMER KBD MS CFLT CBSY 221 * o o o x o o x x 222 * INTEN1: BEEP SCC LANCE DMA SLOT1 SLOT3 EXT1 EXT3 223 * x o o o o o x x 224 */ 225 226 *inten0 = INTEN0_PERR | INTEN0_ABORT | INTEN0_BERR | 227 INTEN0_KBDINT | INTEN0_MSINT; 228 229 *inten1 = INTEN1_SCC | INTEN1_LANCE | INTEN1_DMA | 230 INTEN1_SLOT1 | INTEN1_SLOT3; 231 } 232 233 static void 234 news3400_disable_intr(void) 235 { 236 237 volatile uint8_t *inten0 = (void *)INTEN0; 238 volatile uint8_t *inten1 = (void *)INTEN1; 239 240 *inten0 = 0; 241 *inten1 = 0; 242 } 243 244 static void 245 news3400_enable_timer(void) 246 { 247 248 /* initialize interval timer */ 249 *(volatile uint8_t *)ITIMER = IOCLOCK / 6144 / 100 - 1; 250 251 /* enable timer interrupt */ 252 *(volatile uint8_t *)INTEN0 |= (uint8_t)INTEN0_TIMINT; 253 } 254 255 static void 256 news3400_readidrom(uint8_t *rom) 257 { 258 uint8_t *p = (uint8_t *)IDROM; 259 int i; 260 261 for (i = 0; i < sizeof (struct idrom); i++, p += 2) 262 *rom++ = ((*p & 0x0f) << 4) + (*(p + 1) & 0x0f); 263 } 264 265 extern struct idrom idrom; 266 267 void 268 news3400_init(void) 269 { 270 271 enable_intr = news3400_enable_intr; 272 disable_intr = news3400_disable_intr; 273 enable_timer = news3400_enable_timer; 274 275 news3400_readidrom((uint8_t *)&idrom); 276 hostid = idrom.id_serial; 277 } 278