vr.c revision 1.45 1 /* $NetBSD: vr.c,v 1.45 2005/01/16 03:21:21 hamajima Exp $ */
2
3 /*-
4 * Copyright (c) 1999-2002
5 * Shin Takemura and PocketBSD Project. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the PocketBSD project
18 * and its contributors.
19 * 4. Neither the name of the project nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: vr.c,v 1.45 2005/01/16 03:21:21 hamajima Exp $");
39
40 #include "opt_vr41xx.h"
41 #include "opt_tx39xx.h"
42 #include "opt_kgdb.h"
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/reboot.h>
47
48 #include <uvm/uvm_extern.h>
49
50 #include <machine/sysconf.h>
51 #include <machine/bootinfo.h>
52 #include <machine/bus.h>
53 #include <machine/bus_space_hpcmips.h>
54 #include <machine/platid.h>
55 #include <machine/platid_mask.h>
56
57 #include <dev/hpc/hpckbdvar.h>
58
59 #include <hpcmips/vr/vr.h>
60 #include <hpcmips/vr/vr_asm.h>
61 #include <hpcmips/vr/vrcpudef.h>
62 #include <hpcmips/vr/vripreg.h>
63 #include <hpcmips/vr/rtcreg.h>
64
65 #include <mips/cache.h>
66
67 #include "vrip_common.h"
68 #if NVRIP_COMMON > 0
69 #include <hpcmips/vr/vripvar.h>
70 #endif
71
72 #include "vrbcu.h"
73 #if NVRBCU > 0
74 #include <hpcmips/vr/bcuvar.h>
75 #endif
76
77 #include "vrdsu.h"
78 #if NVRDSU > 0
79 #include <hpcmips/vr/vrdsuvar.h>
80 #endif
81
82 #include "com.h"
83 #include "com_vrip.h"
84 #include "com_hpcio.h"
85 #if NCOM > 0
86 #include <sys/termios.h>
87 #include <sys/ttydefaults.h>
88 #include <dev/ic/comreg.h>
89 #include <dev/ic/comvar.h>
90 #if NCOM_VRIP > 0
91 #include <hpcmips/vr/siureg.h>
92 #include <hpcmips/vr/com_vripvar.h>
93 #endif
94 #if NCOM_HPCIO > 0
95 #include <hpcmips/dev/com_hpciovar.h>
96 #endif
97 #ifndef CONSPEED
98 #define CONSPEED TTYDEF_SPEED
99 #endif
100 #endif
101
102 #include "hpcfb.h"
103 #include "vrkiu.h"
104 #if (NVRKIU > 0) || (NHPCFB > 0)
105 #include <dev/wscons/wsdisplayvar.h>
106 #include <dev/rasops/rasops.h>
107 #endif
108
109 #if NHPCFB > 0
110 #include <dev/hpc/hpcfbvar.h>
111 #endif
112
113 #if NVRKIU > 0
114 #include <arch/hpcmips/vr/vrkiureg.h>
115 #include <arch/hpcmips/vr/vrkiuvar.h>
116 #endif
117
118 #ifdef DEBUG
119 #define STATIC
120 #else
121 #define STATIC static
122 #endif
123
124 /*
125 * This is a mask of bits to clear in the SR when we go to a
126 * given interrupt priority level.
127 */
128 const u_int32_t __ipl_sr_bits_vr[_IPL_N] = {
129 0, /* IPL_NONE */
130
131 MIPS_SOFT_INT_MASK_0, /* IPL_SOFT */
132
133 MIPS_SOFT_INT_MASK_0, /* IPL_SOFTCLOCK */
134
135 MIPS_SOFT_INT_MASK_0|
136 MIPS_SOFT_INT_MASK_1, /* IPL_SOFTNET */
137
138 MIPS_SOFT_INT_MASK_0|
139 MIPS_SOFT_INT_MASK_1, /* IPL_SOFTSERIAL */
140
141 MIPS_SOFT_INT_MASK_0|
142 MIPS_SOFT_INT_MASK_1|
143 MIPS_INT_MASK_0, /* IPL_BIO */
144
145 MIPS_SOFT_INT_MASK_0|
146 MIPS_SOFT_INT_MASK_1|
147 MIPS_INT_MASK_0, /* IPL_NET */
148
149 MIPS_SOFT_INT_MASK_0|
150 MIPS_SOFT_INT_MASK_1|
151 MIPS_INT_MASK_0, /* IPL_{TTY,SERIAL} */
152
153 MIPS_SOFT_INT_MASK_0|
154 MIPS_SOFT_INT_MASK_1|
155 MIPS_INT_MASK_0|
156 MIPS_INT_MASK_1, /* IPL_{CLOCK,HIGH} */
157 };
158
159 #if defined(VR41XX) && defined(TX39XX)
160 #define VR_INTR vr_intr
161 #else
162 #define VR_INTR cpu_intr /* locore_mips3 directly call this */
163 #endif
164
165 void vr_init(void);
166 void VR_INTR(u_int32_t, u_int32_t, u_int32_t, u_int32_t);
167 extern void vr_idle(void);
168 STATIC void vr_cons_init(void);
169 STATIC void vr_fb_init(caddr_t *);
170 STATIC void vr_mem_init(paddr_t);
171 STATIC void vr_find_dram(paddr_t, paddr_t);
172 STATIC void vr_reboot(int, char *);
173
174 /*
175 * CPU interrupt dispatch table (HwInt[0:3])
176 */
177 STATIC int vr_null_handler(void *, u_int32_t, u_int32_t);
178 STATIC int (*vr_intr_handler[4])(void *, u_int32_t, u_int32_t) =
179 {
180 vr_null_handler,
181 vr_null_handler,
182 vr_null_handler,
183 vr_null_handler
184 };
185 STATIC void *vr_intr_arg[4];
186
187 #if NCOM > 0
188 /*
189 * machine dependent serial console info
190 */
191 static struct vr_com_platdep {
192 platid_mask_t *platidmask;
193 int (*attach)(bus_space_tag_t, int, int, int, tcflag_t, int);
194 int addr;
195 int freq;
196 } platdep_com_table[] = {
197 #if NCOM_HPCIO > 0
198 {
199 &platid_mask_MACH_NEC_MCR_SIGMARION2,
200 com_hpcio_cndb_attach, /* attach proc */
201 0x0b600000, /* base address */
202 COM_FREQ, /* frequency */
203 },
204 #endif
205 #if NCOM_VRIP > 0
206 #ifdef VR4102
207 {
208 &platid_mask_CPU_MIPS_VR_4102,
209 com_vrip_cndb_attach, /* attach proc */
210 VR4102_SIU_ADDR, /* base address */
211 VRCOM_FREQ, /* frequency */
212 },
213 #endif /* VR4102 */
214 #ifdef VR4111
215 {
216 &platid_mask_CPU_MIPS_VR_4111,
217 com_vrip_cndb_attach, /* attach proc */
218 VR4102_SIU_ADDR, /* base address */
219 VRCOM_FREQ, /* frequency */
220 },
221 #endif /* VR4111 */
222 #ifdef VR4121
223 {
224 &platid_mask_CPU_MIPS_VR_4121,
225 com_vrip_cndb_attach, /* attach proc */
226 VR4102_SIU_ADDR, /* base address */
227 VRCOM_FREQ, /* frequency */
228 },
229 #endif /* VR4121 */
230 #ifdef VR4122
231 {
232 &platid_mask_CPU_MIPS_VR_4122,
233 com_vrip_cndb_attach, /* attach proc */
234 VR4122_SIU_ADDR, /* base address */
235 VRCOM_FREQ, /* frequency */
236 },
237 #endif /* VR4122 */
238 #ifdef VR4131
239 {
240 &platid_mask_CPU_MIPS_VR_4122,
241 com_vrip_cndb_attach, /* attach proc */
242 VR4122_SIU_ADDR, /* base address */
243 VRCOM_FREQ, /* frequency */
244 },
245 #endif /* VR4131 */
246 #ifdef SINGLE_VRIP_BASE
247 {
248 &platid_wild,
249 com_vrip_cndb_attach, /* attach proc */
250 VRIP_SIU_ADDR, /* base address */
251 VRCOM_FREQ, /* frequency */
252 },
253 #endif /* SINGLE_VRIP_BASE */
254 #else /* NCOM_VRIP > 0 */
255 /* dummy */
256 {
257 &platid_wild,
258 NULL, /* attach proc */
259 0, /* base address */
260 0, /* frequency */
261 },
262 #endif /* NCOM_VRIP > 0 */
263 };
264 #endif /* NCOM > 0 */
265
266 #if NVRKIU > 0
267 /*
268 * machine dependent keyboard info
269 */
270 static struct vr_kiu_platdep {
271 platid_mask_t *platidmask;
272 int addr;
273 } platdep_kiu_table[] = {
274 #ifdef VR4102
275 {
276 &platid_mask_CPU_MIPS_VR_4102,
277 VR4102_KIU_ADDR, /* base address */
278 },
279 #endif /* VR4102 */
280 #ifdef VR4111
281 {
282 &platid_mask_CPU_MIPS_VR_4111,
283 VR4102_KIU_ADDR, /* base address */
284 },
285 #endif /* VR4111 */
286 #ifdef VR4121
287 {
288 &platid_mask_CPU_MIPS_VR_4121,
289 VR4102_KIU_ADDR, /* base address */
290 },
291 #endif /* VR4121 */
292 {
293 &platid_wild,
294 #ifdef SINGLE_VRIP_BASE
295 VRIP_KIU_ADDR, /* base address */
296 #else
297 VRIP_NO_ADDR, /* base address */
298 #endif /* SINGLE_VRIP_BASE */
299 },
300 };
301 #endif /* NVRKIU > 0 */
302
303 void
304 vr_init()
305 {
306 /*
307 * Platform Specific Function Hooks
308 */
309 platform.cpu_idle = vr_idle;
310 platform.cpu_intr = VR_INTR;
311 platform.cons_init = vr_cons_init;
312 platform.fb_init = vr_fb_init;
313 platform.mem_init = vr_mem_init;
314 platform.reboot = vr_reboot;
315
316 #if NVRBCU > 0
317 sprintf(cpu_name, "NEC %s rev%d.%d %d.%03dMHz",
318 vrbcu_vrip_getcpuname(),
319 vrbcu_vrip_getcpumajor(),
320 vrbcu_vrip_getcpuminor(),
321 vrbcu_vrip_getcpuclock() / 1000000,
322 (vrbcu_vrip_getcpuclock() % 1000000) / 1000);
323 #else
324 sprintf(cpu_name, "NEC VR41xx");
325 #endif
326 }
327
328 void
329 vr_mem_init(paddr_t kernend)
330 {
331
332 mem_clusters[0].start = 0;
333 mem_clusters[0].size = kernend;
334 mem_cluster_cnt = 1;
335
336 vr_find_dram(kernend, 0x02000000);
337 vr_find_dram(0x02000000, 0x04000000);
338 vr_find_dram(0x04000000, 0x06000000);
339 vr_find_dram(0x06000000, 0x08000000);
340 }
341
342 void
343 vr_find_dram(paddr_t addr, paddr_t end)
344 {
345 int n;
346 caddr_t page;
347 #ifdef NARLY_MEMORY_PROBE
348 int x, i;
349 #endif
350
351 #ifdef VR_FIND_DRAMLIM
352 if (VR_FIND_DRAMLIM < end)
353 end = VR_FIND_DRAMLIM;
354 #endif /* VR_FIND_DRAMLIM */
355 n = mem_cluster_cnt;
356 for (; addr < end; addr += PAGE_SIZE) {
357
358 page = (void *)MIPS_PHYS_TO_KSEG1(addr);
359 if (badaddr(page, 4))
360 goto bad;
361
362 /* stop memory probing at first memory image */
363 if (bcmp(page, (void *)MIPS_PHYS_TO_KSEG0(0), 128) == 0)
364 return;
365
366 *(volatile int *)(page+0) = 0xa5a5a5a5;
367 *(volatile int *)(page+4) = 0x5a5a5a5a;
368 wbflush();
369 if (*(volatile int *)(page+0) != 0xa5a5a5a5)
370 goto bad;
371
372 *(volatile int *)(page+0) = 0x5a5a5a5a;
373 *(volatile int *)(page+4) = 0xa5a5a5a5;
374 wbflush();
375 if (*(volatile int *)(page+0) != 0x5a5a5a5a)
376 goto bad;
377
378 #ifdef NARLY_MEMORY_PROBE
379 x = random();
380 for (i = 0; i < PAGE_SIZE; i += 4)
381 *(volatile int *)(page+i) = (x ^ i);
382 wbflush();
383 for (i = 0; i < PAGE_SIZE; i += 4)
384 if (*(volatile int *)(page+i) != (x ^ i))
385 goto bad;
386
387 x = random();
388 for (i = 0; i < PAGE_SIZE; i += 4)
389 *(volatile int *)(page+i) = (x ^ i);
390 wbflush();
391 for (i = 0; i < PAGE_SIZE; i += 4)
392 if (*(volatile int *)(page+i) != (x ^ i))
393 goto bad;
394 #endif /* NARLY_MEMORY_PROBE */
395
396 if (!mem_clusters[n].size)
397 mem_clusters[n].start = addr;
398 mem_clusters[n].size += PAGE_SIZE;
399 continue;
400
401 bad:
402 if (mem_clusters[n].size)
403 ++n;
404 continue;
405 }
406 if (mem_clusters[n].size)
407 ++n;
408 mem_cluster_cnt = n;
409 }
410
411 void
412 vr_fb_init(caddr_t *kernend)
413 {
414 /* Nothing to do */
415 }
416
417 void
418 vr_cons_init()
419 {
420 #if NCOM > 0 || NHPCFB > 0 || NVRKIU > 0
421 bus_space_tag_t iot = hpcmips_system_bus_space();
422 #endif
423 #if NCOM > 0
424 static struct vr_com_platdep *com_info;
425 #endif
426 #if NVRKIU > 0
427 static struct vr_kiu_platdep *kiu_info;
428 #endif
429
430 #if NCOM > 0
431 com_info = platid_search(&platid, platdep_com_table,
432 sizeof(platdep_com_table)/sizeof(*platdep_com_table),
433 sizeof(*platdep_com_table));
434 #ifdef KGDB
435 if (com_info->attach != NULL) {
436 /* if KGDB is defined, always use the serial port for KGDB */
437 if ((*com_info->attach)(iot, com_info->addr, 9600,
438 com_info->freq,
439 (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8, 1)) {
440 printf("%s(%d): can't init kgdb's serial port",
441 __FILE__, __LINE__);
442 }
443 #else /* KGDB */
444 if (com_info->attach != NULL && (bootinfo->bi_cnuse&BI_CNUSE_SERIAL)) {
445 /* Serial console */
446 if ((*com_info->attach)(iot, com_info->addr, CONSPEED,
447 com_info->freq,
448 (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8, 0)) {
449 printf("%s(%d): can't init serial console",
450 __FILE__, __LINE__);
451 } else {
452 return;
453 }
454 }
455 #endif /* KGDB */
456 #endif /* NCOM > 0 */
457
458 #if NHPCFB > 0
459 if (hpcfb_cnattach(NULL)) {
460 printf("%s(%d): can't init fb console", __FILE__, __LINE__);
461 } else {
462 goto find_keyboard;
463 }
464 find_keyboard:
465 #endif /* NHPCFB > 0 */
466
467 #if NVRKIU > 0
468 kiu_info = platid_search(&platid, platdep_kiu_table,
469 sizeof(platdep_kiu_table)/sizeof(*platdep_kiu_table),
470 sizeof(*platdep_kiu_table));
471 if (kiu_info->addr != VRIP_NO_ADDR) {
472 if (vrkiu_cnattach(iot, kiu_info->addr)) {
473 printf("%s(%d): can't init vrkiu as console",
474 __FILE__, __LINE__);
475 } else {
476 return;
477 }
478 }
479 #endif /* NVRKIU > 0 */
480 }
481
482 extern char vr_hibernate[];
483 extern char evr_hibernate[];
484
485 void
486 vr_reboot(int howto, char *bootstr)
487 {
488 /*
489 * power down
490 */
491 if ((howto & RB_POWERDOWN) == RB_POWERDOWN) {
492 printf("fake powerdown\n");
493 /*
494 * copy vr_hibernate() to top of physical memory.
495 */
496 memcpy((void *)MIPS_KSEG0_START, vr_hibernate,
497 evr_hibernate - (char *)vr_hibernate);
498 /* sync I&D cache */
499 mips_dcache_wbinv_all();
500 mips_icache_sync_all();
501 /*
502 * call vr_hibernate() at MIPS_KSEG0_START.
503 */
504 ((void (*)(void *,int))MIPS_KSEG0_START)(
505 (void *)MIPS_KSEG0_START, ptoa(physmem));
506 /* not reach */
507 vr_reboot(howto&~RB_HALT, bootstr);
508 }
509 /*
510 * halt
511 */
512 if (howto & RB_HALT) {
513 #if NVRIP_COMMON > 0
514 _spllower(~MIPS_INT_MASK_0);
515 vrip_intr_suspend();
516 #else
517 splhigh();
518 #endif
519 __asm(".set noreorder");
520 __asm(".word " ___STRING(VR_OPCODE_SUSPEND));
521 __asm("nop");
522 __asm("nop");
523 __asm("nop");
524 __asm("nop");
525 __asm("nop");
526 __asm(".set reorder");
527 #if NVRIP_COMMON > 0
528 vrip_intr_resume();
529 #endif
530 }
531 /*
532 * reset
533 */
534 #if NVRDSU
535 vrdsu_reset();
536 #else
537 printf("%s(%d): There is no DSU.", __FILE__, __LINE__);
538 #endif
539 }
540
541 /*
542 * Handle interrupts.
543 */
544 void
545 VR_INTR(u_int32_t status, u_int32_t cause, u_int32_t pc, u_int32_t ipending)
546 {
547 uvmexp.intrs++;
548
549 /* Deal with unneded compare interrupts occasionally so that we can
550 * keep spllowersoftclock. */
551 if (ipending & MIPS_INT_MASK_5) {
552 mips3_cp0_compare_write(0);
553 }
554
555 if (ipending & MIPS_INT_MASK_1) {
556 _splset(MIPS_SR_INT_IE); /* for spllowersoftclock */
557 /* Remove the lower priority pending bits from status so that
558 * spllowersoftclock will not happen if other interrupts are
559 * pending. */
560 (*vr_intr_handler[1])(vr_intr_arg[1], pc, status & ~(ipending
561 & (MIPS_INT_MASK_0|MIPS_SOFT_INT_MASK_0|MIPS_SOFT_INT_MASK_1)));
562 }
563
564 if (ipending & MIPS_INT_MASK_0) {
565 _splset(MIPS_INT_MASK_1|MIPS_SR_INT_IE);
566 (*vr_intr_handler[0])(vr_intr_arg[0], pc, status);
567 }
568
569 if (ipending & MIPS_SOFT_INT_MASK_1) {
570 _splset(MIPS_INT_MASK_1|MIPS_INT_MASK_0|MIPS_SR_INT_IE);
571 softintr(MIPS_SOFT_INT_MASK_1);
572 }
573
574 if (ipending & MIPS_SOFT_INT_MASK_0) {
575 _splset(MIPS_SOFT_INT_MASK_1|MIPS_INT_MASK_1|MIPS_INT_MASK_0|
576 MIPS_SR_INT_IE);
577 softintr(MIPS_SOFT_INT_MASK_0);
578 }
579 }
580
581 void *
582 vr_intr_establish(int line, int (*ih_fun)(void *, u_int32_t, u_int32_t),
583 void *ih_arg)
584 {
585
586 KDASSERT(vr_intr_handler[line] == vr_null_handler);
587
588 vr_intr_handler[line] = ih_fun;
589 vr_intr_arg[line] = ih_arg;
590
591 return ((void *)line);
592 }
593
594 void
595 vr_intr_disestablish(void *ih)
596 {
597 int line = (int)ih;
598
599 vr_intr_handler[line] = vr_null_handler;
600 vr_intr_arg[line] = NULL;
601 }
602
603 int
604 vr_null_handler(void *arg, u_int32_t pc, u_int32_t status)
605 {
606
607 printf("vr_null_handler\n");
608
609 return (0);
610 }
611
612 /*
613 int x4181 = VR4181;
614 int x4101 = VR4101;
615 int x4102 = VR4102;
616 int x4111 = VR4111;
617 int x4121 = VR4121;
618 int x4122 = VR4122;
619 int xo4181 = ONLY_VR4181;
620 int xo4101 = ONLY_VR4101;
621 int xo4102 = ONLY_VR4102;
622 int xo4111_4121 = ONLY_VR4111_4121;
623 int g4101=VRGROUP_4101;
624 int g4102=VRGROUP_4102;
625 int g4181=VRGROUP_4181;
626 int g4102_4121=VRGROUP_4102_4121;
627 int g4111_4121=VRGROUP_4111_4121;
628 int g4102_4122=VRGROUP_4102_4122;
629 int g4111_4122=VRGROUP_4111_4122;
630 int single_vrip_base=SINGLE_VRIP_BASE;
631 int vrip_base_addr=VRIP_BASE_ADDR;
632 */
633