xref: /netbsd/sys/arch/pmax/pmax/dec_3maxplus.c (revision bf9ec67e)
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