1 /* $NetBSD: dec_3maxplus.c,v 1.71 2016/03/22 04:48:25 mrg 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_3maxplus.c,v 1.71 2016/03/22 04:48:25 mrg Exp $");
74
75 #include <sys/param.h>
76 #include <sys/cpu.h>
77 #include <sys/evcnt.h>
78 #include <sys/lwp.h>
79 #include <sys/systm.h>
80 #include <sys/timetc.h>
81
82 #include <mips/locore.h>
83
84 #include <mips/mips/mips_mcclock.h> /* mclock CPUspeed estimation */
85
86 /* all these to get ioasic_base */
87 #include <dev/tc/tcvar.h> /* tc type definitions for.. */
88 #include <dev/tc/ioasicreg.h> /* ioasic interrrupt masks */
89 #include <dev/tc/ioasicvar.h> /* ioasic_base */
90
91 #include <pmax/sysconf.h>
92
93 #include <pmax/pmax/machdep.h>
94 #include <pmax/pmax/kn03.h>
95 #include <pmax/pmax/memc.h>
96
97 #include <dev/ic/z8530sc.h>
98 #include <dev/tc/zs_ioasicvar.h>
99 #include <pmax/pmax/cons.h>
100 #include "wsdisplay.h"
101
102 void dec_3maxplus_init(void); /* XXX */
103 static void dec_3maxplus_bus_reset(void);
104 static void dec_3maxplus_cons_init(void);
105 static void dec_3maxplus_errintr(void);
106 static void dec_3maxplus_intr(uint32_t, vaddr_t, uint32_t);
107 static void dec_3maxplus_intr_establish(device_t, void *,
108 int, int (*)(void *), void *);
109
110 static void kn03_wbflush(void);
111
112 static void dec_3maxplus_tc_init(void);
113
114 /*
115 * Local declarations
116 */
117 static uint32_t kn03_tc3_imask;
118 static unsigned int latched_cycle_cnt;
119
120 static const struct ipl_sr_map dec_3maxplus_ipl_sr_map = {
121 .sr_bits = {
122 [IPL_NONE] = 0,
123 [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0,
124 [IPL_SOFTNET] = MIPS_SOFT_INT_MASK,
125 /*
126 * 3MAX+ IOASIC interrupts come through INT 0, while
127 * clock interrupt does via INT 1. splclock and splstatclock
128 * should block IOASIC activities.
129 */
130 [IPL_VM] = MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0,
131 [IPL_SCHED] = MIPS_INT_MASK,
132 [IPL_DDB] = MIPS_INT_MASK,
133 [IPL_HIGH] = MIPS_INT_MASK,
134 },
135 };
136
137 void
dec_3maxplus_init(void)138 dec_3maxplus_init(void)
139 {
140 uint32_t prodtype;
141
142 platform.iobus = "tcbus";
143 platform.bus_reset = dec_3maxplus_bus_reset;
144 platform.cons_init = dec_3maxplus_cons_init;
145 platform.iointr = dec_3maxplus_intr;
146 platform.intr_establish = dec_3maxplus_intr_establish;
147 platform.memsize = memsize_bitmap;
148 /* 3MAX+ has IOASIC free-running high resolution timer */
149 platform.tc_init = dec_3maxplus_tc_init;
150
151 /* clear any memory errors */
152 *(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(KN03_SYS_ERRADR) = 0;
153 kn03_wbflush();
154
155 ioasic_base = MIPS_PHYS_TO_KSEG1(KN03_SYS_ASIC);
156
157 ipl_sr_map = dec_3maxplus_ipl_sr_map;
158
159 /* calibrate cpu_mhz value */
160 mc_cpuspeed(ioasic_base+IOASIC_SLOT_8_START, MIPS_INT_MASK_1);
161
162 *(volatile uint32_t *)(ioasic_base + IOASIC_LANCE_DECODE) = 0x3;
163 *(volatile uint32_t *)(ioasic_base + IOASIC_SCSI_DECODE) = 0xe;
164 #if 0
165 *(volatile uint32_t *)(ioasic_base + IOASIC_SCC0_DECODE) = (0x10|4);
166 *(volatile uint32_t *)(ioasic_base + IOASIC_SCC1_DECODE) = (0x10|6);
167 *(volatile uint32_t *)(ioasic_base + IOASIC_CSR) = 0x00000f00;
168 #endif
169
170 /* XXX hard-reset LANCE */
171 *(volatile uint32_t *)(ioasic_base + IOASIC_CSR) |= 0x100;
172
173 /* sanitize interrupt mask */
174 kn03_tc3_imask = KN03_INTR_PSWARN;
175 *(volatile uint32_t *)(ioasic_base + IOASIC_INTR) = 0;
176 *(volatile uint32_t *)(ioasic_base + IOASIC_IMSK) = kn03_tc3_imask;
177 kn03_wbflush();
178
179 prodtype = *(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(KN03_REG_INTR);
180 prodtype &= KN03_INTR_PROD_JUMPER;
181 /* the bit persists even if INTR register is assigned value 0 */
182 if (prodtype)
183 cpu_setmodel("DECstation 5000/%s (3MAXPLUS)",
184 (CPUISMIPS3) ? "260" : "240");
185 else
186 cpu_setmodel("DECsystem 5900%s (3MAXPLUS)",
187 (CPUISMIPS3) ? "-260" : "");
188 }
189
190 /*
191 * Initialize the memory system and I/O buses.
192 */
193 static void
dec_3maxplus_bus_reset(void)194 dec_3maxplus_bus_reset(void)
195 {
196
197 /*
198 * Reset interrupts, clear any errors from newconf probes
199 */
200
201 *(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(KN03_SYS_ERRADR) = 0;
202 kn03_wbflush();
203
204 *(volatile uint32_t *)(ioasic_base + IOASIC_INTR) = 0;
205 kn03_wbflush();
206 }
207
208 static void
dec_3maxplus_cons_init(void)209 dec_3maxplus_cons_init(void)
210 {
211 int kbd, crt, screen;
212
213 kbd = crt = screen = 0;
214 prom_findcons(&kbd, &crt, &screen);
215
216 if (screen > 0) {
217 #if NWSDISPLAY > 0
218 if (tcfb_cnattach(crt) > 0) {
219 zs_ioasic_lk201_cnattach(ioasic_base, 0x180000, 0);
220 return;
221 }
222 #endif
223 printf("No framebuffer device configured for slot %d: ", crt);
224 printf("using serial console\n");
225 }
226 /*
227 * Delay to allow PROM putchars to complete.
228 * FIFO depth * character time,
229 * character time = (1000000 / (defaultrate / 10))
230 */
231 DELAY(160000000 / 9600); /* XXX */
232
233 zs_ioasic_cnattach(ioasic_base, 0x180000, 1);
234 }
235
236 static void
dec_3maxplus_intr_establish(device_t dev,void * cookie,int level,int (* handler)(void *),void * arg)237 dec_3maxplus_intr_establish(device_t dev, void *cookie, int level,
238 int (*handler)(void *), void *arg)
239 {
240 uint32_t mask;
241
242 switch ((uintptr_t)cookie) {
243 case SYS_DEV_OPT0:
244 mask = KN03_INTR_TC_0;
245 break;
246 case SYS_DEV_OPT1:
247 mask = KN03_INTR_TC_1;
248 break;
249 case SYS_DEV_OPT2:
250 mask = KN03_INTR_TC_2;
251 break;
252 case SYS_DEV_SCSI:
253 mask = (IOASIC_INTR_SCSI | IOASIC_INTR_SCSI_PTR_LOAD |
254 IOASIC_INTR_SCSI_OVRUN | IOASIC_INTR_SCSI_READ_E);
255 break;
256 case SYS_DEV_LANCE:
257 mask = KN03_INTR_LANCE | IOASIC_INTR_LANCE_READ_E;
258 break;
259 case SYS_DEV_SCC0:
260 mask = KN03_INTR_SCC_0;
261 break;
262 case SYS_DEV_SCC1:
263 mask = KN03_INTR_SCC_1;
264 break;
265 default:
266 #ifdef DIAGNOSTIC
267 printf("warning: enabling unknown intr %x\n", (int)cookie);
268 #endif
269 return;
270 }
271
272 kn03_tc3_imask |= mask;
273 intrtab[(uintptr_t)cookie].ih_func = handler;
274 intrtab[(uintptr_t)cookie].ih_arg = arg;
275
276 *(volatile uint32_t *)(ioasic_base + IOASIC_IMSK) = kn03_tc3_imask;
277 kn03_wbflush();
278 }
279
280 #define CHECKINTR(vvv, bits) \
281 do { \
282 if (can_serve & (bits)) { \
283 ifound = true; \
284 intrtab[vvv].ih_count.ev_count++; \
285 (*intrtab[vvv].ih_func)(intrtab[vvv].ih_arg); \
286 } \
287 } while (/*CONSTCOND*/0)
288
289 static void
dec_3maxplus_ioasic_intr(void)290 dec_3maxplus_ioasic_intr(void)
291 {
292 static int warned = 0;
293 bool ifound;
294 uint32_t imsk, intr, can_serve, xxxintr;
295
296 do {
297 ifound = false;
298 imsk = *(uint32_t *)(ioasic_base + IOASIC_IMSK);
299 intr = *(uint32_t *)(ioasic_base + IOASIC_INTR);
300 can_serve = intr & imsk;
301
302 CHECKINTR(SYS_DEV_SCC0, IOASIC_INTR_SCC_0);
303 CHECKINTR(SYS_DEV_SCC1, IOASIC_INTR_SCC_1);
304 CHECKINTR(SYS_DEV_LANCE, IOASIC_INTR_LANCE);
305 CHECKINTR(SYS_DEV_SCSI, IOASIC_INTR_SCSI);
306 CHECKINTR(SYS_DEV_OPT2, KN03_INTR_TC_2);
307 CHECKINTR(SYS_DEV_OPT1, KN03_INTR_TC_1);
308 CHECKINTR(SYS_DEV_OPT0, KN03_INTR_TC_0);
309
310 if (warned && !(can_serve & KN03_INTR_PSWARN)) {
311 printf("%s\n", "Power supply ok now.");
312 warned = 0;
313 }
314 if ((can_serve & KN03_INTR_PSWARN) && (warned < 3)) {
315 warned++;
316 printf("%s\n", "Power supply overheating");
317 }
318
319 #define ERRORS (IOASIC_INTR_SCSI_OVRUN|IOASIC_INTR_SCSI_READ_E|IOASIC_INTR_LANCE_READ_E)
320 #define PTRLOAD (IOASIC_INTR_SCSI_PTR_LOAD)
321 /*
322 * XXX future project is here XXX
323 * IOASIC DMA completion interrupt (PTR_LOAD) should be checked
324 * here, and DMA pointers serviced as soon as possible.
325 */
326 /*
327 * All of IOASIC device interrupts comes through a single service
328 * request line coupled with MIPS CPU INT 0.
329 * Disabling INT 0 makes entire IOASIC interrupt services blocked,
330 * and it's harmful because it causes DMA overruns during network
331 * disk I/O interrupts.
332 * So, Non-DMA interrupts should be selectively disabled by masking
333 * IOASIC_IMSK register, and INT 3 itself be reenabled immediately,
334 * and made available all the time.
335 * DMA interrupts can then be serviced whilst still servicing
336 * non-DMA interrupts from ioctl devices or TC options.
337 */
338 xxxintr = can_serve & (ERRORS | PTRLOAD);
339 if (xxxintr) {
340 ifound = true;
341 *(uint32_t *)(ioasic_base + IOASIC_INTR) = intr &~ xxxintr;
342 }
343 } while (ifound);
344 }
345
346 static void
dec_3maxplus_intr(uint32_t status,vaddr_t pc,uint32_t ipending)347 dec_3maxplus_intr(uint32_t status, vaddr_t pc, uint32_t ipending)
348 {
349 unsigned int old_buscycle;
350
351 if (ipending & MIPS_INT_MASK_4)
352 prom_haltbutton();
353
354 /* handle clock interrupts ASAP */
355 old_buscycle = latched_cycle_cnt;
356 if (ipending & MIPS_INT_MASK_1) {
357 struct clockframe cf;
358
359 __asm volatile("lbu $0,48(%0)" ::
360 "r"(ioasic_base + IOASIC_SLOT_8_START));
361 cf.pc = pc;
362 cf.sr = status;
363 cf.intr = (curcpu()->ci_idepth > 1);
364 hardclock(&cf);
365 pmax_clock_evcnt.ev_count++;
366 old_buscycle = latched_cycle_cnt - old_buscycle;
367 /* keep clock interrupts enabled when we return */
368 }
369
370 #ifdef notdef
371 /*
372 * Check for late clock interrupts (allow 10% slop). Be careful
373 * to do so only after calling hardclock(), due to logging cost.
374 * Even then, logging dropped ticks just causes more clock
375 * ticks to be missed.
376 */
377 if ((ipending & MIPS_INT_MASK_1) && old_buscycle > (tick+49) * 25) {
378 /* XXX need to include <sys/msgbug.h> for msgbufmapped */
379 if (msgbufmapped && 0)
380 addlog("kn03: clock intr %d usec late\n",
381 old_buscycle/25);
382 }
383 #endif
384 if (ipending & MIPS_INT_MASK_0) {
385 dec_3maxplus_ioasic_intr();
386 }
387 if (ipending & MIPS_INT_MASK_3) {
388 dec_3maxplus_errintr();
389 pmax_memerr_evcnt.ev_count++;
390 }
391 }
392
393 /*
394 * Handle Memory error. 3max, 3maxplus has ECC.
395 * Correct single-bit error, panic on double-bit error.
396 * XXX on double-error on clean user page, mark bad and reload frame?
397 */
398 static void
dec_3maxplus_errintr(void)399 dec_3maxplus_errintr(void)
400 {
401 uint32_t erradr, csr;
402 vaddr_t errsyn;
403
404 /* Fetch error address, ECC chk/syn bits, clear interrupt */
405 erradr = *(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(KN03_SYS_ERRADR);
406 errsyn = MIPS_PHYS_TO_KSEG1(KN03_SYS_ERRSYN);
407 *(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(KN03_SYS_ERRADR) = 0;
408 kn03_wbflush();
409 csr = *(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(KN03_SYS_CSR);
410
411 /* Send to kn02/kn03 memory subsystem handler */
412 dec_mtasic_err(erradr, errsyn, csr & KN03_CSR_BNK32M);
413 }
414
415 static void
kn03_wbflush(void)416 kn03_wbflush(void)
417 {
418
419 /* read once IOASIC SLOT 0 */
420 __asm volatile("lw $0,%0" :: "i"(0xbf840000));
421 }
422
423 /*
424 * TURBOchannel bus-cycle counter provided by IOASIC; 25 MHz
425 */
426
427 static u_int
dec_3maxplus_get_timecount(struct timecounter * tc)428 dec_3maxplus_get_timecount(struct timecounter *tc)
429 {
430
431 return *(volatile uint32_t *)(ioasic_base + IOASIC_CTR);
432 }
433
434 static void
dec_3maxplus_tc_init(void)435 dec_3maxplus_tc_init(void)
436 {
437 #if defined(MIPS3)
438 static struct timecounter tc3 = {
439 .tc_get_timecount = (timecounter_get_t *)mips3_cp0_count_read,
440 .tc_counter_mask = ~0u,
441 .tc_name = "mips3_cp0_counter",
442 .tc_quality = 200,
443 };
444 #endif
445 static struct timecounter tc = {
446 .tc_get_timecount = dec_3maxplus_get_timecount,
447 .tc_quality = 100,
448 .tc_frequency = 25000000,
449 .tc_counter_mask = ~0,
450 .tc_name = "turbochannel_counter",
451 };
452
453 tc_init(&tc);
454
455 #if defined(MIPS3)
456 if (MIPS_HAS_CLOCK) {
457 tc3.tc_frequency = mips_options.mips_cpu_mhz * 1000000;
458
459 tc_init(&tc3);
460 }
461 #endif
462 }
463