1 /* $NetBSD: dec_3maxplus.c,v 1.47 2001/09/18 16:15:20 tsutsui Exp $ */ 2 3 /* 4 * Copyright (c) 1998 Jonathan Stone. 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. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Jonathan Stone for 17 * the NetBSD Project. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1988 University of Utah. 35 * Copyright (c) 1992, 1993 36 * The Regents of the University of California. All rights reserved. 37 * 38 * This code is derived from software contributed to Berkeley by 39 * the Systems Programming Group of the University of Utah Computer 40 * Science Department, The Mach Operating System project at 41 * Carnegie-Mellon University and Ralph Campbell. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by the University of 54 * California, Berkeley and its contributors. 55 * 4. Neither the name of the University nor the names of its contributors 56 * may be used to endorse or promote products derived from this software 57 * without specific prior written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * SUCH DAMAGE. 70 * 71 * @(#)machdep.c 8.3 (Berkeley) 1/12/94 72 */ 73 74 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 75 76 __KERNEL_RCSID(0, "$NetBSD: dec_3maxplus.c,v 1.47 2001/09/18 16:15:20 tsutsui Exp $"); 77 78 #include <sys/param.h> 79 #include <sys/systm.h> 80 #include <sys/device.h> 81 82 #include <machine/cpu.h> 83 #include <machine/sysconf.h> 84 85 #include <mips/mips/mips_mcclock.h> /* mclock CPUspeed estimation */ 86 87 /* all these to get ioasic_base */ 88 #include <dev/tc/tcvar.h> /* tc type definitions for.. */ 89 #include <dev/tc/ioasicreg.h> /* ioasic interrrupt masks */ 90 #include <dev/tc/ioasicvar.h> /* ioasic_base */ 91 92 #include <pmax/pmax/machdep.h> 93 #include <pmax/pmax/kn03.h> 94 #include <pmax/pmax/memc.h> 95 #include <pmax/tc/sccvar.h> 96 97 #include "rasterconsole.h" 98 99 void dec_3maxplus_init __P((void)); /* XXX */ 100 static void dec_3maxplus_bus_reset __P((void)); 101 static void dec_3maxplus_cons_init __P((void)); 102 static void dec_3maxplus_errintr __P((void)); 103 static void dec_3maxplus_intr __P((unsigned, unsigned, unsigned, unsigned)); 104 static void dec_3maxplus_intr_establish __P((struct device *, void *, 105 int, int (*)(void *), void *)); 106 107 static void kn03_wbflush __P((void)); 108 static unsigned kn03_clkread __P((void)); 109 110 /* 111 * Local declarations 112 */ 113 static u_int32_t kn03_tc3_imask; 114 static unsigned latched_cycle_cnt; 115 116 void 117 dec_3maxplus_init() 118 { 119 u_int32_t prodtype; 120 121 platform.iobus = "tcbus"; 122 platform.bus_reset = dec_3maxplus_bus_reset; 123 platform.cons_init = dec_3maxplus_cons_init; 124 platform.iointr = dec_3maxplus_intr; 125 platform.intr_establish = dec_3maxplus_intr_establish; 126 platform.memsize = memsize_bitmap; 127 platform.clkread = kn03_clkread; 128 /* 3MAX+ has IOASIC free-running high resolution timer */ 129 130 /* clear any memory errors */ 131 *(u_int32_t *)MIPS_PHYS_TO_KSEG1(KN03_SYS_ERRADR) = 0; 132 kn03_wbflush(); 133 134 ioasic_base = MIPS_PHYS_TO_KSEG1(KN03_SYS_ASIC); 135 136 /* 137 * 3MAX+ IOASIC interrupts come through INT 0, while 138 * clock interrupt does via INT 1. splclock and splstatclock 139 * should block IOASIC activities. 140 */ 141 splvec.splbio = MIPS_SPL0; 142 splvec.splnet = MIPS_SPL0; 143 splvec.spltty = MIPS_SPL0; 144 splvec.splvm = MIPS_SPL0; 145 splvec.splclock = MIPS_SPL_0_1; 146 splvec.splstatclock = MIPS_SPL_0_1; 147 148 /* calibrate cpu_mhz value */ 149 mc_cpuspeed(ioasic_base+IOASIC_SLOT_8_START, MIPS_INT_MASK_1); 150 151 *(u_int32_t *)(ioasic_base + IOASIC_LANCE_DECODE) = 0x3; 152 *(u_int32_t *)(ioasic_base + IOASIC_SCSI_DECODE) = 0xe; 153 #if 0 154 *(u_int32_t *)(ioasic_base + IOASIC_SCC0_DECODE) = (0x10|4); 155 *(u_int32_t *)(ioasic_base + IOASIC_SCC1_DECODE) = (0x10|6); 156 *(u_int32_t *)(ioasic_base + IOASIC_CSR) = 0x00000f00; 157 #endif 158 159 /* XXX hard-reset LANCE */ 160 *(u_int32_t *)(ioasic_base + IOASIC_CSR) |= 0x100; 161 162 /* sanitize interrupt mask */ 163 kn03_tc3_imask = KN03_INTR_PSWARN; 164 *(u_int32_t *)(ioasic_base + IOASIC_INTR) = 0; 165 *(u_int32_t *)(ioasic_base + IOASIC_IMSK) = kn03_tc3_imask; 166 kn03_wbflush(); 167 168 prodtype = *(u_int32_t *)MIPS_PHYS_TO_KSEG1(KN03_REG_INTR); 169 prodtype &= KN03_INTR_PROD_JUMPER; 170 /* the bit persists even if INTR register is assigned value 0 */ 171 if (prodtype) 172 sprintf(cpu_model, "DECstation 5000/%s (3MAXPLUS)", 173 (CPUISMIPS3) ? "260" : "240"); 174 else 175 sprintf(cpu_model, "DECsystem 5900%s (3MAXPLUS)", 176 (CPUISMIPS3) ? "-260" : ""); 177 } 178 179 /* 180 * Initialize the memory system and I/O buses. 181 */ 182 static void 183 dec_3maxplus_bus_reset() 184 { 185 /* 186 * Reset interrupts, clear any errors from newconf probes 187 */ 188 189 *(u_int32_t *)MIPS_PHYS_TO_KSEG1(KN03_SYS_ERRADR) = 0; 190 kn03_wbflush(); 191 192 *(u_int32_t *)(ioasic_base + IOASIC_INTR) = 0; 193 kn03_wbflush(); 194 } 195 196 static void 197 dec_3maxplus_cons_init() 198 { 199 int kbd, crt, screen; 200 extern int tcfb_cnattach __P((int)); /* XXX */ 201 202 kbd = crt = screen = 0; 203 prom_findcons(&kbd, &crt, &screen); 204 205 if (screen > 0) { 206 #if NRASTERCONSOLE > 0 207 if (tcfb_cnattach(crt) > 0) { 208 scc_lk201_cnattach(ioasic_base, 0x180000); 209 return; 210 } 211 #endif 212 printf("No framebuffer device configured for slot %d: ", crt); 213 printf("using serial console\n"); 214 } 215 /* 216 * Delay to allow PROM putchars to complete. 217 * FIFO depth * character time, 218 * character time = (1000000 / (defaultrate / 10)) 219 */ 220 DELAY(160000000 / 9600); /* XXX */ 221 222 scc_cnattach(ioasic_base, 0x180000); 223 } 224 225 static void 226 dec_3maxplus_intr_establish(dev, cookie, level, handler, arg) 227 struct device *dev; 228 void *cookie; 229 int level; 230 int (*handler) __P((void *)); 231 void *arg; 232 { 233 unsigned mask; 234 235 switch ((int)cookie) { 236 case SYS_DEV_OPT0: 237 mask = KN03_INTR_TC_0; 238 break; 239 case SYS_DEV_OPT1: 240 mask = KN03_INTR_TC_1; 241 break; 242 case SYS_DEV_OPT2: 243 mask = KN03_INTR_TC_2; 244 break; 245 case SYS_DEV_SCSI: 246 mask = (IOASIC_INTR_SCSI | IOASIC_INTR_SCSI_PTR_LOAD | 247 IOASIC_INTR_SCSI_OVRUN | IOASIC_INTR_SCSI_READ_E); 248 break; 249 case SYS_DEV_LANCE: 250 mask = KN03_INTR_LANCE | IOASIC_INTR_LANCE_READ_E; 251 break; 252 case SYS_DEV_SCC0: 253 mask = KN03_INTR_SCC_0; 254 break; 255 case SYS_DEV_SCC1: 256 mask = KN03_INTR_SCC_1; 257 break; 258 default: 259 #ifdef DIAGNOSTIC 260 printf("warning: enabling unknown intr %x\n", (int)cookie); 261 #endif 262 return; 263 } 264 265 kn03_tc3_imask |= mask; 266 intrtab[(int)cookie].ih_func = handler; 267 intrtab[(int)cookie].ih_arg = arg; 268 269 *(u_int32_t *)(ioasic_base + IOASIC_IMSK) = kn03_tc3_imask; 270 kn03_wbflush(); 271 } 272 273 #define CHECKINTR(vvv, bits) \ 274 do { \ 275 if (can_serve & (bits)) { \ 276 ifound = 1; \ 277 intrcnt[vvv] += 1; \ 278 (*intrtab[vvv].ih_func)(intrtab[vvv].ih_arg); \ 279 } \ 280 } while (0) 281 282 static void 283 dec_3maxplus_intr(status, cause, pc, ipending) 284 unsigned status; 285 unsigned cause; 286 unsigned pc; 287 unsigned ipending; 288 { 289 static int warned = 0; 290 unsigned old_buscycle; 291 292 if (ipending & MIPS_INT_MASK_4) 293 prom_haltbutton(); 294 295 /* handle clock interrupts ASAP */ 296 old_buscycle = latched_cycle_cnt; 297 if (ipending & MIPS_INT_MASK_1) { 298 struct clockframe cf; 299 300 __asm __volatile("lbu $0,48(%0)" :: 301 "r"(ioasic_base + IOASIC_SLOT_8_START)); 302 latched_cycle_cnt = *(u_int32_t *)(ioasic_base + IOASIC_CTR); 303 cf.pc = pc; 304 cf.sr = status; 305 hardclock(&cf); 306 pmax_clock_evcnt.ev_count++; 307 old_buscycle = latched_cycle_cnt - old_buscycle; 308 /* keep clock interrupts enabled when we return */ 309 cause &= ~MIPS_INT_MASK_1; 310 } 311 312 /* If clock interrups were enabled, re-enable them ASAP. */ 313 _splset(MIPS_SR_INT_IE | (status & MIPS_INT_MASK_1)); 314 315 #ifdef notdef 316 /* 317 * Check for late clock interrupts (allow 10% slop). Be careful 318 * to do so only after calling hardclock(), due to logging cost. 319 * Even then, logging dropped ticks just causes more clock 320 * ticks to be missed. 321 */ 322 if ((ipending & MIPS_INT_MASK_1) && old_buscycle > (tick+49) * 25) { 323 /* XXX need to include <sys/msgbug.h> for msgbufmapped */ 324 if (msgbufmapped && 0) 325 addlog("kn03: clock intr %d usec late\n", 326 old_buscycle/25); 327 } 328 #endif 329 if (ipending & MIPS_INT_MASK_0) { 330 int ifound; 331 u_int32_t imsk, intr, can_serve, xxxintr; 332 333 do { 334 ifound = 0; 335 imsk = *(u_int32_t *)(ioasic_base + IOASIC_IMSK); 336 intr = *(u_int32_t *)(ioasic_base + IOASIC_INTR); 337 can_serve = intr & imsk; 338 339 CHECKINTR(SYS_DEV_SCC0, IOASIC_INTR_SCC_0); 340 CHECKINTR(SYS_DEV_SCC1, IOASIC_INTR_SCC_1); 341 CHECKINTR(SYS_DEV_LANCE, IOASIC_INTR_LANCE); 342 CHECKINTR(SYS_DEV_SCSI, IOASIC_INTR_SCSI); 343 CHECKINTR(SYS_DEV_OPT2, KN03_INTR_TC_2); 344 CHECKINTR(SYS_DEV_OPT1, KN03_INTR_TC_1); 345 CHECKINTR(SYS_DEV_OPT0, KN03_INTR_TC_0); 346 347 if (warned > 0 && !(can_serve & KN03_INTR_PSWARN)) { 348 printf("%s\n", "Power supply ok now."); 349 warned = 0; 350 } 351 if ((can_serve & KN03_INTR_PSWARN) && (warned < 3)) { 352 warned++; 353 printf("%s\n", "Power supply overheating"); 354 } 355 356 #define ERRORS (IOASIC_INTR_SCSI_OVRUN|IOASIC_INTR_SCSI_READ_E|IOASIC_INTR_LANCE_READ_E) 357 #define PTRLOAD (IOASIC_INTR_SCSI_PTR_LOAD) 358 /* 359 * XXX future project is here XXX 360 * IOASIC DMA completion interrupt (PTR_LOAD) should be checked 361 * here, and DMA pointers serviced as soon as possible. 362 */ 363 /* 364 * All of IOASIC device interrupts comes through a single service 365 * request line coupled with MIPS cpu INT 0. 366 * Disabling INT 0 makes entire IOASIC interrupt services blocked, 367 * and it's harmful because it causes DMA overruns during network 368 * disk I/O interrupts. 369 * So, Non-DMA interrupts should be selectively disabled by masking 370 * IOASIC_IMSK register, and INT 3 itself be reenabled immediately, 371 * and made available all the time. 372 * DMA interrupts can then be serviced whilst still servicing 373 * non-DMA interrupts from ioctl devices or TC options. 374 */ 375 xxxintr = can_serve & (ERRORS | PTRLOAD); 376 if (xxxintr) { 377 ifound = 1; 378 *(u_int32_t *)(ioasic_base + IOASIC_INTR) 379 = intr &~ xxxintr; 380 } 381 } while (ifound); 382 } 383 if (ipending & MIPS_INT_MASK_3) { 384 dec_3maxplus_errintr(); 385 pmax_memerr_evcnt.ev_count++; 386 } 387 388 _splset(MIPS_SR_INT_IE | (status & ~cause & MIPS_HARD_INT_MASK)); 389 } 390 391 /* 392 * Handle Memory error. 3max, 3maxplus has ECC. 393 * Correct single-bit error, panic on double-bit error. 394 * XXX on double-error on clean user page, mark bad and reload frame? 395 */ 396 static void 397 dec_3maxplus_errintr() 398 { 399 u_int32_t erradr, errsyn, csr; 400 401 /* Fetch error address, ECC chk/syn bits, clear interrupt */ 402 erradr = *(u_int32_t *)MIPS_PHYS_TO_KSEG1(KN03_SYS_ERRADR); 403 errsyn = MIPS_PHYS_TO_KSEG1(KN03_SYS_ERRSYN); 404 *(u_int32_t *)MIPS_PHYS_TO_KSEG1(KN03_SYS_ERRADR) = 0; 405 kn03_wbflush(); 406 csr = *(u_int32_t *)MIPS_PHYS_TO_KSEG1(KN03_SYS_CSR); 407 408 /* Send to kn02/kn03 memory subsystem handler */ 409 dec_mtasic_err(erradr, errsyn, csr & KN03_CSR_BNK32M); 410 } 411 412 static void 413 kn03_wbflush() 414 { 415 /* read once IOASIC SLOT 0 */ 416 __asm __volatile("lw $0,%0" :: "i"(0xbf840000)); 417 } 418 419 /* 420 * TURBOchannel bus-cycle counter provided by IOASIC; 421 * Interpolate micro-seconds since the last RTC clock tick. The 422 * interpolation base is the copy of the bus cycle-counter taken by 423 * the RTC interrupt handler. 424 */ 425 static unsigned 426 kn03_clkread() 427 { 428 u_int32_t usec, cycles; 429 430 cycles = *(u_int32_t*)(ioasic_base + IOASIC_CTR); 431 cycles = cycles - latched_cycle_cnt; 432 433 /* 434 * Scale from 40ns to microseconds. 435 * Avoid a kernel FP divide (by 25) using the approximation 436 * 1/25 = 40/1000 =~ 41/ 1024, which is good to 0.0975 % 437 */ 438 usec = cycles + (cycles << 3) + (cycles << 5); 439 usec = usec >> 10; 440 441 #ifdef CLOCK_DEBUG 442 if (usec > 3906 +4) { 443 addlog("clkread: usec %d, counter=%lx\n", 444 usec, latched_cycle_cnt); 445 stacktrace(); 446 } 447 #endif /*CLOCK_DEBUG*/ 448 449 return usec; 450 } 451