xref: /netbsd/sys/arch/pmax/pmax/dec_3min.c (revision 6550d01e)
1 /* $NetBSD: dec_3min.c,v 1.66 2009/12/14 00:46:10 matt 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) 1992, 1993
35  *	The Regents of the University of California.  All rights reserved.
36  *
37  * This code is derived from software contributed to Berkeley by
38  * the Systems Programming Group of the University of Utah Computer
39  * Science Department, The Mach Operating System project at
40  * Carnegie-Mellon University and Ralph Campbell.
41  *
42  * Redistribution and use in source and binary forms, with or without
43  * modification, are permitted provided that the following conditions
44  * are met:
45  * 1. Redistributions of source code must retain the above copyright
46  *    notice, this list of conditions and the following disclaimer.
47  * 2. Redistributions in binary form must reproduce the above copyright
48  *    notice, this list of conditions and the following disclaimer in the
49  *    documentation and/or other materials provided with the distribution.
50  * 3. Neither the name of the University nor the names of its contributors
51  *    may be used to endorse or promote products derived from this software
52  *    without specific prior written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64  * SUCH DAMAGE.
65  *
66  *	@(#)machdep.c	8.3 (Berkeley) 1/12/94
67  */
68 /*
69  * Copyright (c) 1988 University of Utah.
70  *
71  * This code is derived from software contributed to Berkeley by
72  * the Systems Programming Group of the University of Utah Computer
73  * Science Department, The Mach Operating System project at
74  * Carnegie-Mellon University and Ralph Campbell.
75  *
76  * Redistribution and use in source and binary forms, with or without
77  * modification, are permitted provided that the following conditions
78  * are met:
79  * 1. Redistributions of source code must retain the above copyright
80  *    notice, this list of conditions and the following disclaimer.
81  * 2. Redistributions in binary form must reproduce the above copyright
82  *    notice, this list of conditions and the following disclaimer in the
83  *    documentation and/or other materials provided with the distribution.
84  * 3. All advertising materials mentioning features or use of this software
85  *    must display the following acknowledgement:
86  *	This product includes software developed by the University of
87  *	California, Berkeley and its contributors.
88  * 4. Neither the name of the University nor the names of its contributors
89  *    may be used to endorse or promote products derived from this software
90  *    without specific prior written permission.
91  *
92  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
93  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
94  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
95  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
96  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
97  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
98  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
99  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
100  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
101  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
102  * SUCH DAMAGE.
103  *
104  *	@(#)machdep.c	8.3 (Berkeley) 1/12/94
105  */
106 
107 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
108 
109 __KERNEL_RCSID(0, "$NetBSD: dec_3min.c,v 1.66 2009/12/14 00:46:10 matt Exp $");
110 
111 #include <sys/param.h>
112 #include <sys/systm.h>
113 #include <sys/device.h>
114 #include <sys/timetc.h>
115 
116 #include <machine/cpu.h>
117 #include <machine/intr.h>
118 #include <machine/sysconf.h>
119 
120 #include <mips/mips/mips_mcclock.h>	/* mcclock CPUspeed estimation */
121 
122 /* all these to get ioasic_base */
123 #include <dev/tc/tcvar.h>		/* tc type definitions for.. */
124 #include <dev/tc/ioasicreg.h>		/* ioasic interrrupt masks */
125 #include <dev/tc/ioasicvar.h>		/* ioasic_base */
126 
127 #include <pmax/pmax/machdep.h>
128 #include <pmax/pmax/kmin.h>		/* 3min baseboard addresses */
129 #include <pmax/pmax/memc.h>		/* 3min/maxine memory errors */
130 
131 #include <pmax/pmax/cons.h>
132 #include <dev/ic/z8530sc.h>
133 #include <dev/tc/zs_ioasicvar.h>
134 #include "wsdisplay.h"
135 
136 void		dec_3min_init(void);		/* XXX */
137 static void	dec_3min_bus_reset(void);
138 static void	dec_3min_cons_init(void);
139 static void	dec_3min_intr(unsigned, unsigned, unsigned, unsigned);
140 static void	dec_3min_intr_establish(struct device *, void *,
141 		    int, int (*)(void *), void *);
142 
143 static void	kn02ba_wbflush(void);
144 
145 static void	dec_3min_tc_init(void);
146 
147 /*
148  * Local declarations.
149  */
150 static uint32_t kmin_tc3_imask;
151 
152 static const int dec_3min_ipl2spl_table[] = {
153 	[IPL_NONE] = 0,
154 	[IPL_SOFTCLOCK] = _SPL_SOFTCLOCK,
155 	[IPL_SOFTNET] = _SPL_SOFTNET,
156 	/*
157 	 * Since all the motherboard interrupts come through the
158 	 * IOASIC, it has to be turned off for all the spls and
159 	 * since we don't know what kinds of devices are in the
160 	 * TURBOchannel option slots, just splhigh().
161 	 */
162 	[IPL_VM] = MIPS_SPL_0_1_2_3,
163 	[IPL_SCHED] = MIPS_SPL_0_1_2_3,
164 	[IPL_HIGH] = MIPS_SPL_0_1_2_3,
165 };
166 
167 void
168 dec_3min_init(void)
169 {
170 
171 	platform.iobus = "tcbus";
172 	platform.bus_reset = dec_3min_bus_reset;
173 	platform.cons_init = dec_3min_cons_init;
174 	platform.iointr = dec_3min_intr;
175 	platform.intr_establish = dec_3min_intr_establish;
176 	platform.memsize = memsize_bitmap;
177 	platform.tc_init = dec_3min_tc_init;
178 
179 	/* clear any memory errors */
180 	*(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(KMIN_REG_TIMEOUT) = 0;
181 	kn02ba_wbflush();
182 
183 	ioasic_base = MIPS_PHYS_TO_KSEG1(KMIN_SYS_ASIC);
184 
185 	ipl2spl_table = dec_3min_ipl2spl_table;
186 
187 	/* enable posting of MIPS_INT_MASK_3 to CAUSE register */
188 	*(volatile uint32_t *)(ioasic_base + IOASIC_IMSK) = KMIN_INTR_CLOCK;
189 	/* calibrate cpu_mhz value */
190 	mc_cpuspeed(ioasic_base+IOASIC_SLOT_8_START, MIPS_INT_MASK_3);
191 
192 	*(volatile uint32_t *)(ioasic_base + IOASIC_LANCE_DECODE) = 0x3;
193 	*(volatile uint32_t *)(ioasic_base + IOASIC_SCSI_DECODE) = 0xe;
194 #if 0
195 	*(volatile uint32_t *)(ioasic_base + IOASIC_SCC0_DECODE) = (0x10|4);
196 	*(volatile uint32_t *)(ioasic_base + IOASIC_SCC1_DECODE) = (0x10|6);
197 	*(volatile uint32_t *)(ioasic_base + IOASIC_CSR) = 0x00000f00;
198 #endif
199 
200 	/* sanitize interrupt mask */
201 	kmin_tc3_imask = (KMIN_INTR_CLOCK|KMIN_INTR_PSWARN|KMIN_INTR_TIMEOUT);
202 	*(volatile uint32_t *)(ioasic_base + IOASIC_INTR) = 0;
203 	*(volatile uint32_t *)(ioasic_base + IOASIC_IMSK) = kmin_tc3_imask;
204 
205 	/*
206 	 * The kmin memory hardware seems to wrap memory addresses
207 	 * with 4Mbyte SIMMs, which causes the physmem computation
208 	 * to lose.  Find out how big the SIMMS are and set
209 	 * max_ physmem accordingly.
210 	 * XXX Do MAXINEs lose the same way?
211 	 */
212 	physmem_boardmax = KMIN_PHYS_MEMORY_END + 1;
213 	if ((KMIN_MSR_SIZE_16Mb & *(int *)MIPS_PHYS_TO_KSEG1(KMIN_REG_MSR))
214 	    == 0)
215 		physmem_boardmax = physmem_boardmax >> 2;
216 	physmem_boardmax = MIPS_PHYS_TO_KSEG1(physmem_boardmax);
217 
218 	sprintf(cpu_model, "DECstation 5000/1%d (3MIN)", cpu_mhz);
219 }
220 
221 /*
222  * Initialize the memory system and I/O buses.
223  */
224 static void
225 dec_3min_bus_reset(void)
226 {
227 
228 	/*
229 	 * Reset interrupts, clear any errors from newconf probes
230 	 */
231 
232 	*(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(KMIN_REG_TIMEOUT) = 0;
233 	kn02ba_wbflush();
234 
235 	*(volatile uint32_t *)(ioasic_base + IOASIC_INTR) = 0;
236 	kn02ba_wbflush();
237 }
238 
239 static void
240 dec_3min_cons_init(void)
241 {
242 	int kbd, crt, screen;
243 
244 	kbd = crt = screen = 0;
245 	prom_findcons(&kbd, &crt, &screen);
246 
247 	if (screen > 0) {
248 #if NWSDISPLAY > 0
249  		if (tcfb_cnattach(crt) > 0) {
250 			zs_ioasic_lk201_cnattach(ioasic_base, 0x180000, 0);
251  			return;
252  		}
253 #endif
254 		printf("No framebuffer device configured for slot %d: ", crt);
255 		printf("using serial console\n");
256 	}
257 	/*
258 	 * Delay to allow PROM putchars to complete.
259 	 * FIFO depth * character time,
260 	 * character time = (1000000 / (defaultrate / 10))
261 	 */
262 	DELAY(160000000 / 9600);	/* XXX */
263 
264 	zs_ioasic_cnattach(ioasic_base, 0x180000, 1);
265 }
266 
267 static void
268 dec_3min_intr_establish(struct device *dev, void *cookie, int level,
269     int (*handler)(void *), void *arg)
270 {
271 	uint32_t mask;
272 
273 	switch ((uintptr_t)cookie) {
274 		/* slots 0-2 don't interrupt through the IOASIC. */
275 	case SYS_DEV_OPT0:
276 		mask = MIPS_INT_MASK_0;
277 		break;
278 	case SYS_DEV_OPT1:
279 		mask = MIPS_INT_MASK_1;
280 		break;
281 	case SYS_DEV_OPT2:
282 		mask = MIPS_INT_MASK_2;
283 		break;
284 
285 	case SYS_DEV_SCSI:
286 		mask = (IOASIC_INTR_SCSI | IOASIC_INTR_SCSI_PTR_LOAD |
287 			IOASIC_INTR_SCSI_OVRUN | IOASIC_INTR_SCSI_READ_E);
288 		break;
289 	case SYS_DEV_LANCE:
290 		mask = KMIN_INTR_LANCE;
291 		break;
292 	case SYS_DEV_SCC0:
293 		mask = KMIN_INTR_SCC_0;
294 		break;
295 	case SYS_DEV_SCC1:
296 		mask = KMIN_INTR_SCC_1;
297 		break;
298 	default:
299 #ifdef DIAGNOSTIC
300 		printf("warning: enabling unknown intr %p\n", cookie);
301 #endif
302 		return;
303 	}
304 
305 #if defined(DEBUG)
306 	printf("3MIN: imask %x, enabling slot %p, dev %p handler %p\n",
307 	    kmin_tc3_imask, cookie, dev, handler);
308 #endif
309 
310 	/*
311 	 * Enable the interrupt  handler, and if it's an IOASIC
312 	 * slot, set the IOASIC interrupt mask.
313 	 * Otherwise, set the appropriate spl level in the R3000
314 	 * register.
315 	 * Be careful to set handlers before enabling, and disable
316 	 * interrupts before clearing handlers.
317 	 */
318 
319 	/* Set the interrupt handler and argument ... */
320 	intrtab[(uintptr_t)cookie].ih_func = handler;
321 	intrtab[(uintptr_t)cookie].ih_arg = arg;
322 	/* ... and set the relevant mask */
323 	switch ((uintptr_t)cookie) {
324 	case SYS_DEV_OPT0:
325 	case SYS_DEV_OPT1:
326 	case SYS_DEV_OPT2:
327 		/* it's an option slot */
328 		{
329 		int s = splhigh();
330 		s |= mask;
331 		splx(s);
332 		}
333 		break;
334 	default:
335 		/* it's a baseboard device going via the IOASIC */
336 		kmin_tc3_imask |= mask;
337 		break;
338 	}
339 
340 	*(volatile uint32_t *)(ioasic_base + IOASIC_IMSK) = kmin_tc3_imask;
341 	kn02ba_wbflush();
342 }
343 
344 
345 #define CHECKINTR(slot, bits)					\
346     do {							\
347 	if (can_serve & (bits)) {				\
348 		intrtab[slot].ih_count.ev_count++;		\
349 		(*intrtab[slot].ih_func)(intrtab[slot].ih_arg);	\
350 	}							\
351     } while (/*CONSTCOND*/0)
352 
353 static void
354 dec_3min_intr(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending)
355 {
356 	static int user_warned = 0;
357 	static int intr_depth = 0;
358 	uint32_t old_mask;
359 
360 	intr_depth++;
361 	old_mask = *(volatile uint32_t *)(ioasic_base + IOASIC_IMSK);
362 
363 	if (ipending & MIPS_INT_MASK_4)
364 		prom_haltbutton();
365 
366 	if (ipending & MIPS_INT_MASK_3) {
367 		/* NB: status & MIPS_INT_MASK3 must also be set */
368 		/* masked interrupts are still observable */
369 		uint32_t intr, imsk, can_serve, turnoff;
370 
371 		turnoff = 0;
372 		intr = *(volatile uint32_t *)(ioasic_base + IOASIC_INTR);
373 		imsk = *(volatile uint32_t *)(ioasic_base + IOASIC_IMSK);
374 		can_serve = intr & imsk;
375 
376 		if (intr & IOASIC_INTR_SCSI_PTR_LOAD) {
377 			turnoff |= IOASIC_INTR_SCSI_PTR_LOAD;
378 #ifdef notdef
379 			asc_dma_intr();
380 #endif
381 		}
382 
383 		if (intr & (IOASIC_INTR_SCSI_OVRUN | IOASIC_INTR_SCSI_READ_E))
384 			turnoff |=
385 			    IOASIC_INTR_SCSI_OVRUN | IOASIC_INTR_SCSI_READ_E;
386 
387 		if (intr & IOASIC_INTR_LANCE_READ_E)
388 			turnoff |= IOASIC_INTR_LANCE_READ_E;
389 
390 		if (turnoff)
391 			*(volatile uint32_t *)(ioasic_base + IOASIC_INTR) =
392 			    ~turnoff;
393 
394 		if (intr & KMIN_INTR_TIMEOUT) {
395 			kn02ba_errintr();
396 			pmax_memerr_evcnt.ev_count++;
397 		}
398 
399 		if (intr & KMIN_INTR_CLOCK) {
400 			struct clockframe cf;
401 
402 			__asm volatile("lbu $0,48(%0)" ::
403 				"r"(ioasic_base + IOASIC_SLOT_8_START));
404 
405 			cf.pc = pc;
406 			cf.sr = status;
407 			hardclock(&cf);
408 			pmax_clock_evcnt.ev_count++;
409 		}
410 
411 		/* If clock interrupts were enabled, re-enable them ASAP. */
412 		if (old_mask & KMIN_INTR_CLOCK) {
413 			/* ioctl interrupt mask to splclock and higher */
414 			*(volatile uint32_t *)(ioasic_base + IOASIC_IMSK)
415 				= old_mask &
416 					~(KMIN_INTR_SCC_0|KMIN_INTR_SCC_1 |
417 					  IOASIC_INTR_LANCE|IOASIC_INTR_SCSI);
418 			kn02ba_wbflush();
419 			_splset(MIPS_SR_INT_IE | (status & MIPS_INT_MASK_3));
420 		}
421 
422 		if (intr_depth > 1)
423 			 goto done;
424 
425 		CHECKINTR(SYS_DEV_SCC0, IOASIC_INTR_SCC_0);
426 		CHECKINTR(SYS_DEV_SCC1, IOASIC_INTR_SCC_1);
427 
428 #ifdef notyet /* untested */
429 		/* If tty interrupts were enabled, re-enable them ASAP. */
430 		if ((old_mask & (KMIN_INTR_SCC_1|KMIN_INTR_SCC_0)) ==
431 		     (KMIN_INTR_SCC_1|KMIN_INTR_SCC_0)) {
432 			*imaskp = old_mask &
433 			  ~(KMIN_INTR_SCC_0|KMIN_INTR_SCC_1 |
434 			  IOASIC_INTR_LANCE|IOASIC_INTR_SCSI);
435 			kn02ba_wbflush();
436 		}
437 
438 		/* XXX until we know about SPLs of TC options. */
439 		if (intr_depth > 1)
440 			 goto done;
441 #endif
442 		CHECKINTR(SYS_DEV_LANCE, IOASIC_INTR_LANCE);
443 		CHECKINTR(SYS_DEV_SCSI, IOASIC_INTR_SCSI);
444 
445 		if (user_warned && ((intr & KMIN_INTR_PSWARN) == 0)) {
446 			printf("%s\n", "Power supply ok now.");
447 			user_warned = 0;
448 		}
449 		if ((intr & KMIN_INTR_PSWARN) && (user_warned < 3)) {
450 			user_warned++;
451 			printf("%s\n", "Power supply overheating");
452 		}
453 	}
454 	if ((ipending & MIPS_INT_MASK_0) && intrtab[SYS_DEV_OPT0].ih_func) {
455 		(*intrtab[SYS_DEV_OPT0].ih_func)(intrtab[SYS_DEV_OPT0].ih_arg);
456 		intrtab[SYS_DEV_OPT0].ih_count.ev_count++;
457  	}
458 
459 	if ((ipending & MIPS_INT_MASK_1) && intrtab[SYS_DEV_OPT1].ih_func) {
460 		(*intrtab[SYS_DEV_OPT1].ih_func)(intrtab[SYS_DEV_OPT1].ih_arg);
461 		intrtab[SYS_DEV_OPT1].ih_count.ev_count++;
462 	}
463 	if ((ipending & MIPS_INT_MASK_2) && intrtab[SYS_DEV_OPT2].ih_func) {
464 		(*intrtab[SYS_DEV_OPT2].ih_func)(intrtab[SYS_DEV_OPT2].ih_arg);
465 		intrtab[SYS_DEV_OPT2].ih_count.ev_count++;
466 	}
467 
468 done:
469 	/* restore entry state */
470 	splhigh();
471 	intr_depth--;
472 	*(volatile uint32_t *)(ioasic_base + IOASIC_IMSK) = old_mask;
473 
474 	_splset(MIPS_SR_INT_IE | (status & ~cause & MIPS_HARD_INT_MASK));
475 }
476 
477 
478 
479 /*
480  ************************************************************************
481  * Extra functions
482  ************************************************************************
483  */
484 
485 static void
486 kn02ba_wbflush(void)
487 {
488 
489 	/* read twice IOASIC_IMSK */
490 	__asm volatile("lw $0,%0; lw $0,%0" ::
491 	    "i"(MIPS_PHYS_TO_KSEG1(KMIN_REG_IMSK)));
492 }
493 
494 /*
495  * Support for using the MIPS 3 clock as a timecounter.
496  */
497 
498 void
499 dec_3min_tc_init(void)
500 {
501 #if defined(MIPS3)
502 	static struct timecounter tc =  {
503 		.tc_get_timecount = (timecounter_get_t *)mips3_cp0_count_read,
504 		.tc_counter_mask = ~0u,
505 		.tc_name = "mips3_cp0_counter",
506 		.tc_quality = 100,
507 	};
508 
509 	if (MIPS_HAS_CLOCK) {
510 		tc.tc_frequency = cpu_mhz * 1000000;
511 		if (mips_cpu_flags & CPU_MIPS_DOUBLE_COUNT) {
512 			tc.tc_frequency /= 2;
513 		}
514 
515 		tc_init(&tc);
516 	}
517 #endif
518 }
519