1 /* $NetBSD: dec_maxine.c,v 1.65 2014/03/24 19:31:40 christos 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. Neither the name of the University nor the names of its contributors 52 * may be used to endorse or promote products derived from this software 53 * without specific prior written permission. 54 * 55 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 58 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 65 * SUCH DAMAGE. 66 * 67 * @(#)machdep.c 8.3 (Berkeley) 1/12/94 68 */ 69 70 #define __INTR_PRIVATE 71 72 #include <sys/cdefs.h> 73 __KERNEL_RCSID(0, "$NetBSD: dec_maxine.c,v 1.65 2014/03/24 19:31:40 christos Exp $"); 74 75 #include <sys/param.h> 76 #include <sys/cpu.h> 77 #include <sys/device.h> 78 #include <sys/lwp.h> 79 #include <sys/systm.h> 80 #include <sys/timetc.h> 81 82 #include <pmax/sysconf.h> 83 84 #include <mips/mips/mips_mcclock.h> 85 86 #include <dev/tc/tcvar.h> 87 #include <dev/tc/ioasicvar.h> 88 #include <dev/tc/ioasicreg.h> 89 90 #include <pmax/pmax/maxine.h> 91 #include <pmax/pmax/machdep.h> 92 #include <pmax/pmax/memc.h> 93 94 #include <dev/ic/z8530sc.h> 95 #include <dev/tc/zs_ioasicvar.h> 96 #include <pmax/pmax/cons.h> 97 #include "wsdisplay.h" 98 #include "xcfb.h" 99 100 void dec_maxine_init(void); /* XXX */ 101 static void dec_maxine_bus_reset(void); 102 static void dec_maxine_cons_init(void); 103 static void dec_maxine_intr(uint32_t, vaddr_t, uint32_t); 104 static void dec_maxine_intr_establish(device_t, void *, 105 int, int (*)(void *), void *); 106 107 static void dec_maxine_tc_init(void); 108 109 static void kn02ca_wbflush(void); 110 111 /* 112 * local declarations 113 */ 114 static uint32_t xine_tc3_imask; 115 116 static const struct ipl_sr_map dec_maxine_ipl_sr_map = { 117 .sr_bits = { 118 [IPL_NONE] = 0, 119 [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0, 120 [IPL_SOFTNET] = MIPS_SOFT_INT_MASK, 121 /* 122 * MAXINE IOASIC interrupts come through INT 3, while 123 * clock interrupt does via INT 1. splclock and splstatclock 124 * should block IOASIC activities. 125 */ 126 [IPL_VM] = MIPS_SOFT_INT_MASK | MIPS_INT_MASK_3, 127 [IPL_SCHED] = MIPS_INT_MASK, 128 [IPL_DDB] = MIPS_INT_MASK, 129 [IPL_HIGH] = MIPS_INT_MASK, 130 }, 131 }; 132 133 void 134 dec_maxine_init(void) 135 { 136 137 platform.iobus = "tcbus"; 138 platform.bus_reset = dec_maxine_bus_reset; 139 platform.cons_init = dec_maxine_cons_init; 140 platform.iointr = dec_maxine_intr; 141 platform.intr_establish = dec_maxine_intr_establish; 142 platform.memsize = memsize_bitmap; 143 platform.tc_init = dec_maxine_tc_init; 144 /* MAXINE has 1 microsec. free-running high resolution timer */ 145 146 /* clear any memory errors */ 147 *(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(XINE_REG_TIMEOUT) = 0; 148 kn02ca_wbflush(); 149 150 ioasic_base = MIPS_PHYS_TO_KSEG1(XINE_SYS_ASIC); 151 152 ipl_sr_map = dec_maxine_ipl_sr_map; 153 154 /* calibrate cpu_mhz value */ 155 mc_cpuspeed(ioasic_base+IOASIC_SLOT_8_START, MIPS_INT_MASK_1); 156 157 *(volatile uint32_t *)(ioasic_base + IOASIC_LANCE_DECODE) = 0x3; 158 *(volatile uint32_t *)(ioasic_base + IOASIC_SCSI_DECODE) = 0xe; 159 #if 0 160 *(volatile uint32_t *)(ioasic_base + IOASIC_SCC0_DECODE) = (0x10|4); 161 *(volatile uint32_t *)(ioasic_base + IOASIC_DTOP_DECODE) = 10; 162 *(volatile uint32_t *)(ioasic_base + IOASIC_FLOPPY_DECODE) = 13; 163 *(volatile uint32_t *)(ioasic_base + IOASIC_CSR) = 0x00001fc1; 164 #endif 165 166 /* sanitize interrupt mask */ 167 xine_tc3_imask = 0; 168 *(volatile uint32_t *)(ioasic_base + IOASIC_INTR) = 0; 169 *(volatile uint32_t *)(ioasic_base + IOASIC_IMSK) = xine_tc3_imask; 170 kn02ca_wbflush(); 171 172 cpu_setmodel("Personal DECstation 5000/%d (MAXINE)", mips_options.mips_cpu_mhz); 173 } 174 175 /* 176 * Initialize the memory system and I/O buses. 177 */ 178 static void 179 dec_maxine_bus_reset(void) 180 { 181 182 /* 183 * Reset interrupts, clear any errors from newconf probes 184 */ 185 186 *(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(XINE_REG_TIMEOUT) = 0; 187 kn02ca_wbflush(); 188 189 *(volatile uint32_t *)(ioasic_base + IOASIC_INTR) = 0; 190 kn02ca_wbflush(); 191 } 192 193 194 static void 195 dec_maxine_cons_init(void) 196 { 197 int kbd, crt, screen; 198 199 kbd = crt = screen = 0; 200 prom_findcons(&kbd, &crt, &screen); 201 202 if (screen > 0) { 203 #if NWSDISPLAY > 0 204 #if NXCFB > 0 205 if (crt == 3) { 206 xcfb_cnattach((tc_addr_t)XINE_PHYS_CFB_START); 207 dtkbd_cnattach(); 208 return; 209 } 210 #endif 211 if (tcfb_cnattach(crt) > 0) { 212 dtkbd_cnattach(); 213 return; 214 } 215 #endif 216 printf("No framebuffer device configured for slot %d: ", crt); 217 printf("using serial console\n"); 218 } 219 /* 220 * Delay to allow PROM putchars to complete. 221 * FIFO depth * character time, 222 * character time = (1000000 / (defaultrate / 10)) 223 */ 224 DELAY(160000000 / 9600); /* XXX */ 225 226 zs_ioasic_cnattach(ioasic_base, 0x100000, 1); 227 } 228 229 static void 230 dec_maxine_intr_establish(device_t dev, void *cookie, int level, 231 int (*handler)(void *), void *arg) 232 { 233 uint32_t mask; 234 235 switch ((uintptr_t)cookie) { 236 case SYS_DEV_OPT0: 237 mask = XINE_INTR_TC_0; 238 break; 239 case SYS_DEV_OPT1: 240 mask = XINE_INTR_TC_1; 241 break; 242 case SYS_DEV_FDC: 243 mask = XINE_INTR_FLOPPY; 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 = IOASIC_INTR_LANCE; 251 break; 252 case SYS_DEV_SCC0: 253 mask = IOASIC_INTR_SCC_0; 254 break; 255 case SYS_DEV_DTOP: 256 mask = XINE_INTR_DTOP_RX; 257 break; 258 case SYS_DEV_ISDN: 259 mask = (IOASIC_INTR_ISDN_TXLOAD | IOASIC_INTR_ISDN_RXLOAD | 260 IOASIC_INTR_ISDN_OVRUN); 261 break; 262 default: 263 #ifdef DIAGNOSTIC 264 printf("warning: enabling unknown intr %p\n", cookie); 265 #endif 266 return; 267 } 268 269 xine_tc3_imask |= mask; 270 intrtab[(uintptr_t)cookie].ih_func = handler; 271 intrtab[(uintptr_t)cookie].ih_arg = arg; 272 273 *(volatile uint32_t *)(ioasic_base + IOASIC_IMSK) = xine_tc3_imask; 274 kn02ca_wbflush(); 275 } 276 277 #define CHECKINTR(vvv, bits) \ 278 do { \ 279 if (can_serve & (bits)) { \ 280 ifound = true; \ 281 intrtab[vvv].ih_count.ev_count++; \ 282 (*intrtab[vvv].ih_func)(intrtab[vvv].ih_arg); \ 283 } \ 284 } while (/*CONSTCOND*/0) 285 286 static void 287 dec_maxine_ioasic_intr(void) 288 { 289 bool ifound; 290 uint32_t imsk, intr, can_serve, xxxintr; 291 292 do { 293 ifound = false; 294 intr = *(uint32_t *)(ioasic_base + IOASIC_INTR); 295 imsk = *(uint32_t *)(ioasic_base + IOASIC_IMSK); 296 can_serve = intr & imsk; 297 298 CHECKINTR(SYS_DEV_DTOP, XINE_INTR_DTOP); 299 CHECKINTR(SYS_DEV_SCC0, IOASIC_INTR_SCC_0); 300 CHECKINTR(SYS_DEV_LANCE, IOASIC_INTR_LANCE); 301 CHECKINTR(SYS_DEV_SCSI, IOASIC_INTR_SCSI); 302 /* CHECKINTR(SYS_DEV_OPT2, XINE_INTR_VINT); */ 303 CHECKINTR(SYS_DEV_ISDN, (IOASIC_INTR_ISDN_TXLOAD | IOASIC_INTR_ISDN_RXLOAD)); 304 /* CHECKINTR(SYS_DEV_FDC, IOASIC_INTR_FDC); */ 305 CHECKINTR(SYS_DEV_OPT1, XINE_INTR_TC_1); 306 CHECKINTR(SYS_DEV_OPT0, XINE_INTR_TC_0); 307 308 #define ERRORS (IOASIC_INTR_ISDN_OVRUN|IOASIC_INTR_SCSI_OVRUN|IOASIC_INTR_SCSI_READ_E|IOASIC_INTR_LANCE_READ_E) 309 #define PTRLOAD (IOASIC_INTR_ISDN_TXLOAD|IOASIC_INTR_ISDN_RXLOAD|IOASIC_INTR_SCSI_PTR_LOAD) 310 311 /* 312 * XXX future project is here XXX 313 * IOASIC DMA completion interrupt (PTR_LOAD) should be checked 314 * here, and DMA pointers serviced as soon as possible. 315 */ 316 /* 317 * All of IOASIC device interrupts comes through a single service 318 * request line coupled with MIPS CPU INT 3. 319 * Disabling INT 3 makes entire IOASIC interrupt services blocked, 320 * and it's harmful because it causes DMA overruns during network 321 * disk I/O interrupts. 322 * So, Non-DMA interrupts should be selectively disabled by masking 323 * IOASIC_IMSK register, and INT 3 itself be reenabled immediately, 324 * and made available all the time. 325 * DMA interrupts can then be serviced whilst still servicing 326 * non-DMA interrupts from ioctl devices or TC options. 327 */ 328 xxxintr = can_serve & (ERRORS | PTRLOAD); 329 if (xxxintr) { 330 ifound = true; 331 *(uint32_t *)(ioasic_base + IOASIC_INTR) 332 = intr &~ xxxintr; 333 } 334 } while (ifound); 335 } 336 337 static void 338 dec_maxine_intr(uint32_t status, vaddr_t pc, uint32_t ipending) 339 { 340 if (ipending & MIPS_INT_MASK_4) 341 prom_haltbutton(); 342 343 /* handle clock interrupts ASAP */ 344 if (ipending & MIPS_INT_MASK_1) { 345 struct clockframe cf; 346 347 __asm volatile("lbu $0,48(%0)" :: 348 "r"(ioasic_base + IOASIC_SLOT_8_START)); 349 cf.pc = pc; 350 cf.sr = status; 351 cf.intr = (curcpu()->ci_idepth > 1); 352 hardclock(&cf); 353 pmax_clock_evcnt.ev_count++; 354 } 355 356 if (ipending & MIPS_INT_MASK_3) { 357 dec_maxine_ioasic_intr(); 358 } 359 if (ipending & MIPS_INT_MASK_2) { 360 kn02ba_errintr(); 361 pmax_memerr_evcnt.ev_count++; 362 } 363 } 364 365 static void 366 kn02ca_wbflush(void) 367 { 368 369 /* read once IOASIC_IMSK */ 370 __asm volatile("lw $0,%0" :: 371 "i"(MIPS_PHYS_TO_KSEG1(XINE_REG_IMSK))); 372 } 373 374 static u_int 375 dec_maxine_get_timecount(struct timecounter *tc) 376 { 377 378 return *(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(XINE_REG_FCTR); 379 } 380 381 static void 382 dec_maxine_tc_init(void) 383 { 384 #if defined(MIPS3) 385 static struct timecounter tc3 = { 386 .tc_get_timecount = (timecounter_get_t *)mips3_cp0_count_read, 387 .tc_counter_mask = ~0u, 388 .tc_name = "mips3_cp0_counter", 389 .tc_quality = 200, 390 }; 391 #endif 392 static struct timecounter tc = { 393 .tc_get_timecount = dec_maxine_get_timecount, 394 .tc_quality = 100, 395 .tc_frequency = 1000000, 396 .tc_counter_mask = ~0, 397 .tc_name = "maxine_fctr", 398 }; 399 400 tc_init(&tc); 401 402 #if defined(MIPS3) 403 if (MIPS_HAS_CLOCK) { 404 tc3.tc_frequency = mips_options.mips_cpu_mhz * 1000000; 405 406 tc_init(&tc3); 407 } 408 #endif 409 } 410