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