xref: /netbsd/sys/arch/pmax/pmax/dec_3min.c (revision bf9ec67e)
1 /* $NetBSD: dec_3min.c,v 1.49 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_3min.c,v 1.49 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/intr.h>
84 #include <machine/sysconf.h>
85 
86 #include <mips/mips/mips_mcclock.h>	/* mcclock CPUspeed estimation */
87 
88 /* all these to get ioasic_base */
89 #include <dev/tc/tcvar.h>		/* tc type definitions for.. */
90 #include <dev/tc/ioasicreg.h>		/* ioasic interrrupt masks */
91 #include <dev/tc/ioasicvar.h>		/* ioasic_base */
92 
93 #include <pmax/pmax/machdep.h>
94 #include <pmax/pmax/kmin.h>		/* 3min baseboard addresses */
95 #include <pmax/pmax/memc.h>		/* 3min/maxine memory errors */
96 #include <pmax/tc/sccvar.h>
97 
98 #include "rasterconsole.h"
99 
100 void		dec_3min_init __P((void));		/* XXX */
101 static void	dec_3min_bus_reset __P((void));
102 static void	dec_3min_cons_init __P((void));
103 static void	dec_3min_intr __P((unsigned, unsigned, unsigned, unsigned));
104 static void	dec_3min_intr_establish __P((struct device *, void *,
105 		    int, int (*)(void *), void *));
106 
107 static void	kn02ba_wbflush __P((void));
108 static unsigned	kn02ba_clkread __P((void));
109 
110 
111 /*
112  * Local declarations.
113  */
114 static u_int32_t kmin_tc3_imask;
115 
116 #ifdef MIPS3
117 static unsigned latched_cycle_cnt;
118 #endif
119 
120 
121 void
122 dec_3min_init()
123 {
124 	platform.iobus = "tcbus";
125 	platform.bus_reset = dec_3min_bus_reset;
126 	platform.cons_init = dec_3min_cons_init;
127 	platform.iointr = dec_3min_intr;
128 	platform.intr_establish = dec_3min_intr_establish;
129 	platform.memsize = memsize_bitmap;
130 	platform.clkread = kn02ba_clkread;
131 
132 	/* clear any memory errors */
133 	*(u_int32_t *)MIPS_PHYS_TO_KSEG1(KMIN_REG_TIMEOUT) = 0;
134 	kn02ba_wbflush();
135 
136 	ioasic_base = MIPS_PHYS_TO_KSEG1(KMIN_SYS_ASIC);
137 
138 	/*
139 	 * Since all the motherboard interrupts come through the
140 	 * IOASIC, it has to be turned off for all the spls and
141 	 * since we don't know what kinds of devices are in the
142 	 * TURBOchannel option slots, just splhigh().
143 	 */
144 	splvec.splbio = MIPS_SPL_0_1_2_3;
145 	splvec.splnet = MIPS_SPL_0_1_2_3;
146 	splvec.spltty = MIPS_SPL_0_1_2_3;
147 	splvec.splvm = MIPS_SPL_0_1_2_3;
148 	splvec.splclock = MIPS_SPL_0_1_2_3;
149 	splvec.splstatclock = MIPS_SPL_0_1_2_3;
150 
151 	/* enable posting of MIPS_INT_MASK_3 to CAUSE register */
152 	*(u_int32_t *)(ioasic_base + IOASIC_IMSK) = KMIN_INTR_CLOCK;
153 	/* calibrate cpu_mhz value */
154 	mc_cpuspeed(ioasic_base+IOASIC_SLOT_8_START, MIPS_INT_MASK_3);
155 
156 	*(u_int32_t *)(ioasic_base + IOASIC_LANCE_DECODE) = 0x3;
157 	*(u_int32_t *)(ioasic_base + IOASIC_SCSI_DECODE) = 0xe;
158 #if 0
159 	*(u_int32_t *)(ioasic_base + IOASIC_SCC0_DECODE) = (0x10|4);
160 	*(u_int32_t *)(ioasic_base + IOASIC_SCC1_DECODE) = (0x10|6);
161 	*(u_int32_t *)(ioasic_base + IOASIC_CSR) = 0x00000f00;
162 #endif
163 
164 	/* sanitize interrupt mask */
165 	kmin_tc3_imask = (KMIN_INTR_CLOCK|KMIN_INTR_PSWARN|KMIN_INTR_TIMEOUT);
166 	*(u_int32_t *)(ioasic_base + IOASIC_INTR) = 0;
167 	*(u_int32_t *)(ioasic_base + IOASIC_IMSK) = kmin_tc3_imask;
168 
169 	/*
170 	 * The kmin memory hardware seems to wrap memory addresses
171 	 * with 4Mbyte SIMMs, which causes the physmem computation
172 	 * to lose.  Find out how big the SIMMS are and set
173 	 * max_ physmem accordingly.
174 	 * XXX Do MAXINEs lose the same way?
175 	 */
176 	physmem_boardmax = KMIN_PHYS_MEMORY_END + 1;
177 	if ((KMIN_MSR_SIZE_16Mb & *(int *)MIPS_PHYS_TO_KSEG1(KMIN_REG_MSR))
178 			== 0)
179 		physmem_boardmax = physmem_boardmax >> 2;
180 	physmem_boardmax = MIPS_PHYS_TO_KSEG1(physmem_boardmax);
181 
182 	sprintf(cpu_model, "DECstation 5000/1%d (3MIN)", cpu_mhz);
183 }
184 
185 /*
186  * Initialize the memory system and I/O buses.
187  */
188 static void
189 dec_3min_bus_reset()
190 {
191 
192 	/*
193 	 * Reset interrupts, clear any errors from newconf probes
194 	 */
195 
196 	*(u_int32_t *)MIPS_PHYS_TO_KSEG1(KMIN_REG_TIMEOUT) = 0;
197 	kn02ba_wbflush();
198 
199 	*(u_int32_t *)(ioasic_base + IOASIC_INTR) = 0;
200 	kn02ba_wbflush();
201 }
202 
203 static void
204 dec_3min_cons_init()
205 {
206 	int kbd, crt, screen;
207 	extern int tcfb_cnattach __P((int));		/* XXX */
208 
209 	kbd = crt = screen = 0;
210 	prom_findcons(&kbd, &crt, &screen);
211 
212 	if (screen > 0) {
213 #if NRASTERCONSOLE > 0
214 		if (tcfb_cnattach(crt) > 0) {
215 			scc_lk201_cnattach(ioasic_base, 0x180000);
216 			return;
217 		}
218 #endif
219 		printf("No framebuffer device configured for slot %d: ", crt);
220 		printf("using serial console\n");
221 	}
222 	/*
223 	 * Delay to allow PROM putchars to complete.
224 	 * FIFO depth * character time,
225 	 * character time = (1000000 / (defaultrate / 10))
226 	 */
227 	DELAY(160000000 / 9600);	/* XXX */
228 
229 	scc_cnattach(ioasic_base, 0x180000);
230 }
231 
232 static void
233 dec_3min_intr_establish(dev, cookie, level, handler, arg)
234 	struct device *dev;
235 	void *cookie;
236 	int level;
237 	int (*handler) __P((void *));
238 	void *arg;
239 {
240 	unsigned mask;
241 
242 	switch ((int)cookie) {
243 		/* slots 0-2 don't interrupt through the IOASIC. */
244 	  case SYS_DEV_OPT0:
245 		mask = MIPS_INT_MASK_0;
246 		break;
247 	  case SYS_DEV_OPT1:
248 		mask = MIPS_INT_MASK_1;
249 		break;
250 	  case SYS_DEV_OPT2:
251 		mask = MIPS_INT_MASK_2;
252 		break;
253 
254 	  case SYS_DEV_SCSI:
255 		mask = (IOASIC_INTR_SCSI | IOASIC_INTR_SCSI_PTR_LOAD |
256 			IOASIC_INTR_SCSI_OVRUN | IOASIC_INTR_SCSI_READ_E);
257 		break;
258 	  case SYS_DEV_LANCE:
259 		mask = KMIN_INTR_LANCE;
260 		break;
261 	  case SYS_DEV_SCC0:
262 		mask = KMIN_INTR_SCC_0;
263 		break;
264 	  case SYS_DEV_SCC1:
265 		mask = KMIN_INTR_SCC_1;
266 		break;
267 	  default:
268 #ifdef DIAGNOSTIC
269 		printf("warning: enabling unknown intr %x\n", (int)cookie);
270 #endif
271 		return;
272 	}
273 
274 #if defined(DEBUG)
275 	printf("3MIN: imask %x, enabling slot %d, dev %p handler %p\n",
276 	    kmin_tc3_imask, (int)cookie, dev, handler);
277 #endif
278 
279 	/*
280 	 * Enable the interrupt  handler, and if it's an IOASIC
281 	 * slot, set the IOASIC interrupt mask.
282 	 * Otherwise, set the appropriate spl level in the R3000
283 	 * register.
284 	 * Be careful to set handlers before enabling, and disable
285 	 * interrupts before clearing handlers.
286 	 */
287 
288 	/* Set the interrupt handler and argument ... */
289 	intrtab[(int)cookie].ih_func = handler;
290 	intrtab[(int)cookie].ih_arg = arg;
291 	/* ... and set the relevant mask */
292 	switch ((int)cookie) {
293 	case SYS_DEV_OPT0:
294 	case SYS_DEV_OPT1:
295 	case SYS_DEV_OPT2:
296 		/* it's an option slot */
297 		{
298 		int s = splhigh();
299 		s |= mask;
300 		splx(s);
301 		}
302 		break;
303 	default:
304 		/* it's a baseboard device going via the IOASIC */
305 		kmin_tc3_imask |= mask;
306 		break;
307 	}
308 
309 	*(u_int32_t *)(ioasic_base + IOASIC_IMSK) = kmin_tc3_imask;
310 	kn02ba_wbflush();
311 }
312 
313 
314 #define CHECKINTR(slot, bits)					\
315     do {							\
316 	if (can_serve & (bits)) {				\
317 		intrcnt[slot] += 1;				\
318 		(*intrtab[slot].ih_func)(intrtab[slot].ih_arg);	\
319 	}							\
320     } while (0)
321 
322 static void
323 dec_3min_intr(status, cause, pc, ipending)
324 	unsigned status;
325 	unsigned cause;
326 	unsigned pc;
327 	unsigned ipending;
328 {
329 	static int user_warned = 0;
330 	static int intr_depth = 0;
331 	u_int32_t old_mask;
332 
333 	intr_depth++;
334 	old_mask = *(u_int32_t *)(ioasic_base + IOASIC_IMSK);
335 
336 	if (ipending & MIPS_INT_MASK_4)
337 		prom_haltbutton();
338 
339 	if (ipending & MIPS_INT_MASK_3) {
340 		/* NB: status & MIPS_INT_MASK3 must also be set */
341 		/* masked interrupts are still observable */
342 		u_int32_t intr, imsk, can_serve, turnoff;
343 
344 		turnoff = 0;
345 		intr = *(u_int32_t *)(ioasic_base + IOASIC_INTR);
346 		imsk = *(u_int32_t *)(ioasic_base + IOASIC_IMSK);
347 		can_serve = intr & imsk;
348 
349 		if (intr & IOASIC_INTR_SCSI_PTR_LOAD) {
350 			turnoff |= IOASIC_INTR_SCSI_PTR_LOAD;
351 #ifdef notdef
352 			asc_dma_intr();
353 #endif
354 		}
355 
356 		if (intr & (IOASIC_INTR_SCSI_OVRUN | IOASIC_INTR_SCSI_READ_E))
357 			turnoff |= IOASIC_INTR_SCSI_OVRUN | IOASIC_INTR_SCSI_READ_E;
358 
359 		if (intr & IOASIC_INTR_LANCE_READ_E)
360 			turnoff |= IOASIC_INTR_LANCE_READ_E;
361 
362 		if (turnoff)
363 			*(u_int32_t *)(ioasic_base + IOASIC_INTR) = ~turnoff;
364 
365 		if (intr & KMIN_INTR_TIMEOUT) {
366 			kn02ba_errintr();
367 			pmax_memerr_evcnt.ev_count++;
368 		}
369 
370 		if (intr & KMIN_INTR_CLOCK) {
371 			struct clockframe cf;
372 
373 			__asm __volatile("lbu $0,48(%0)" ::
374 				"r"(ioasic_base + IOASIC_SLOT_8_START));
375 #ifdef MIPS3
376 			if (CPUISMIPS3) {
377 				latched_cycle_cnt = mips3_cp0_count_read();
378 			}
379 #endif
380 			cf.pc = pc;
381 			cf.sr = status;
382 			hardclock(&cf);
383 			pmax_clock_evcnt.ev_count++;
384 		}
385 
386 		/* If clock interrups were enabled, re-enable them ASAP. */
387 		if (old_mask & KMIN_INTR_CLOCK) {
388 			/* ioctl interrupt mask to splclock and higher */
389 			*(u_int32_t *)(ioasic_base + IOASIC_IMSK)
390 				= old_mask &
391 					~(KMIN_INTR_SCC_0|KMIN_INTR_SCC_1 |
392 					  IOASIC_INTR_LANCE|IOASIC_INTR_SCSI);
393 			kn02ba_wbflush();
394 			_splset(MIPS_SR_INT_IE | (status & MIPS_INT_MASK_3));
395 		}
396 
397 		if (intr_depth > 1)
398 			 goto done;
399 
400 		CHECKINTR(SYS_DEV_SCC0, IOASIC_INTR_SCC_0);
401 		CHECKINTR(SYS_DEV_SCC1, IOASIC_INTR_SCC_1);
402 
403 #ifdef notyet /* untested */
404 		/* If tty interrupts were enabled, re-enable them ASAP. */
405 		if ((old_mask & (KMIN_INTR_SCC_1|KMIN_INTR_SCC_0)) ==
406 		     (KMIN_INTR_SCC_1|KMIN_INTR_SCC_0)) {
407 			*imaskp = old_mask &
408 			  ~(KMIN_INTR_SCC_0|KMIN_INTR_SCC_1 |
409 			  IOASIC_INTR_LANCE|IOASIC_INTR_SCSI);
410 			kn02ba_wbflush();
411 		}
412 
413 		/* XXX until we know about SPLs of TC options. */
414 		if (intr_depth > 1)
415 			 goto done;
416 #endif
417 		CHECKINTR(SYS_DEV_LANCE, IOASIC_INTR_LANCE);
418 		CHECKINTR(SYS_DEV_SCSI, IOASIC_INTR_SCSI);
419 
420 		if (user_warned && ((intr & KMIN_INTR_PSWARN) == 0)) {
421 			printf("%s\n", "Power supply ok now.");
422 			user_warned = 0;
423 		}
424 		if ((intr & KMIN_INTR_PSWARN) && (user_warned < 3)) {
425 			user_warned++;
426 			printf("%s\n", "Power supply overheating");
427 		}
428 	}
429 	if ((ipending & MIPS_INT_MASK_0) && intrtab[SYS_DEV_OPT0].ih_func) {
430 		(*intrtab[SYS_DEV_OPT0].ih_func)(intrtab[SYS_DEV_OPT0].ih_arg);
431 		intrcnt[SYS_DEV_OPT0]++;
432  	}
433 
434 	if ((ipending & MIPS_INT_MASK_1) && intrtab[SYS_DEV_OPT1].ih_func) {
435 		(*intrtab[SYS_DEV_OPT1].ih_func)(intrtab[SYS_DEV_OPT1].ih_arg);
436 		intrcnt[SYS_DEV_OPT1]++;
437 	}
438 	if ((ipending & MIPS_INT_MASK_2) && intrtab[SYS_DEV_OPT2].ih_func) {
439 		(*intrtab[SYS_DEV_OPT2].ih_func)(intrtab[SYS_DEV_OPT2].ih_arg);
440 		intrcnt[SYS_DEV_OPT2]++;
441 	}
442 
443 done:
444 	/* restore entry state */
445 	splhigh();
446 	intr_depth--;
447 	*(u_int32_t *)(ioasic_base + IOASIC_IMSK) = old_mask;
448 
449 	_splset(MIPS_SR_INT_IE | (status & ~cause & MIPS_HARD_INT_MASK));
450 }
451 
452 
453 
454 /*
455  ************************************************************************
456  * Extra functions
457  ************************************************************************
458  */
459 
460 static void
461 kn02ba_wbflush()
462 {
463 	/* read twice IOASIC_IMSK */
464 	__asm __volatile("lw $0,%0; lw $0,%0" ::
465 	    "i"(MIPS_PHYS_TO_KSEG1(KMIN_REG_IMSK)));
466 }
467 
468 static unsigned
469 kn02ba_clkread()
470 {
471 #ifdef MIPS3
472 	if (CPUISMIPS3) {
473 		u_int32_t mips3_cycles;
474 
475 		mips3_cycles = mips3_cp0_count_read() - latched_cycle_cnt;
476 		/* XXX divides take 78 cycles: approximate with * 41/2048 */
477 		return((mips3_cycles >> 6) + (mips3_cycles >> 8) +
478 		       (mips3_cycles >> 11));
479 	}
480 #endif
481 	return 0;
482 }
483