1 /* $NetBSD: vr.c,v 1.58 2010/12/20 00:25:34 matt 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.58 2010/12/20 00:25:34 matt 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 #include <sys/device.h> 48 #include <sys/bus.h> 49 #include <sys/cpu.h> 50 51 #include <uvm/uvm_extern.h> 52 53 #include <machine/sysconf.h> 54 #include <machine/bootinfo.h> 55 #include <machine/bus_space_hpcmips.h> 56 #include <machine/platid.h> 57 #include <machine/platid_mask.h> 58 59 #include <dev/hpc/hpckbdvar.h> 60 61 #include <hpcmips/vr/vr.h> 62 #include <hpcmips/vr/vr_asm.h> 63 #include <hpcmips/vr/vrcpudef.h> 64 #include <hpcmips/vr/vripreg.h> 65 #include <hpcmips/vr/rtcreg.h> 66 67 #include <mips/cache.h> 68 69 #include "vrip_common.h" 70 #if NVRIP_COMMON > 0 71 #include <hpcmips/vr/vripvar.h> 72 #endif 73 74 #include "vrbcu.h" 75 #if NVRBCU > 0 76 #include <hpcmips/vr/bcuvar.h> 77 #endif 78 79 #include "vrdsu.h" 80 #if NVRDSU > 0 81 #include <hpcmips/vr/vrdsuvar.h> 82 #endif 83 84 #include "com.h" 85 #include "com_vrip.h" 86 #include "com_hpcio.h" 87 #if NCOM > 0 88 #include <sys/termios.h> 89 #include <sys/ttydefaults.h> 90 #include <dev/ic/comreg.h> 91 #include <dev/ic/comvar.h> 92 #if NCOM_VRIP > 0 93 #include <hpcmips/vr/siureg.h> 94 #include <hpcmips/vr/com_vripvar.h> 95 #endif 96 #if NCOM_HPCIO > 0 97 #include <hpcmips/dev/com_hpciovar.h> 98 #endif 99 #ifndef CONSPEED 100 #define CONSPEED TTYDEF_SPEED 101 #endif 102 #endif 103 104 #include "hpcfb.h" 105 #include "vrkiu.h" 106 #if (NVRKIU > 0) || (NHPCFB > 0) 107 #include <dev/wscons/wsdisplayvar.h> 108 #include <dev/rasops/rasops.h> 109 #endif 110 111 #if NHPCFB > 0 112 #include <dev/hpc/hpcfbvar.h> 113 #endif 114 115 #if NVRKIU > 0 116 #include <arch/hpcmips/vr/vrkiureg.h> 117 #include <arch/hpcmips/vr/vrkiuvar.h> 118 #endif 119 120 #ifdef DEBUG 121 #define STATIC 122 #else 123 #define STATIC static 124 #endif 125 126 /* 127 * This is a mask of bits to clear in the SR when we go to a 128 * given interrupt priority level. 129 */ 130 const u_int32_t __ipl_sr_bits_vr[_IPL_N] = { 131 0, /* IPL_NONE */ 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| 140 MIPS_INT_MASK_0, /* IPL_VM */ 141 142 MIPS_SOFT_INT_MASK_0| 143 MIPS_SOFT_INT_MASK_1| 144 MIPS_INT_MASK_0| 145 MIPS_INT_MASK_1, /* IPL_SCHED */ 146 }; 147 148 #if defined(VR41XX) && defined(TX39XX) 149 #define VR_INTR vr_intr 150 #else 151 #define VR_INTR cpu_intr /* locore_mips3 directly call this */ 152 #endif 153 154 void vr_init(void); 155 void VR_INTR(u_int32_t, u_int32_t, u_int32_t, u_int32_t); 156 extern void vr_idle(void); 157 STATIC void vr_cons_init(void); 158 STATIC void vr_fb_init(void **); 159 STATIC void vr_mem_init(paddr_t); 160 STATIC void vr_find_dram(paddr_t, paddr_t); 161 STATIC void vr_reboot(int, char *); 162 163 /* 164 * CPU interrupt dispatch table (HwInt[0:3]) 165 */ 166 STATIC int vr_null_handler(void *, u_int32_t, u_int32_t); 167 STATIC int (*vr_intr_handler[4])(void *, u_int32_t, u_int32_t) = 168 { 169 vr_null_handler, 170 vr_null_handler, 171 vr_null_handler, 172 vr_null_handler 173 }; 174 STATIC void *vr_intr_arg[4]; 175 176 #if NCOM > 0 177 /* 178 * machine dependent serial console info 179 */ 180 static struct vr_com_platdep { 181 platid_mask_t *platidmask; 182 int (*attach)(bus_space_tag_t, int, int, int, tcflag_t, int); 183 int addr; 184 int freq; 185 } platdep_com_table[] = { 186 #if NCOM_HPCIO > 0 187 { 188 &platid_mask_MACH_NEC_MCR_SIGMARION2, 189 com_hpcio_cndb_attach, /* attach proc */ 190 0x0b600000, /* base address */ 191 COM_FREQ, /* frequency */ 192 }, 193 #endif 194 #if NCOM_VRIP > 0 195 #ifdef VR4102 196 { 197 &platid_mask_CPU_MIPS_VR_4102, 198 com_vrip_cndb_attach, /* attach proc */ 199 VR4102_SIU_ADDR, /* base address */ 200 VRCOM_FREQ, /* frequency */ 201 }, 202 #endif /* VR4102 */ 203 #ifdef VR4111 204 { 205 &platid_mask_CPU_MIPS_VR_4111, 206 com_vrip_cndb_attach, /* attach proc */ 207 VR4102_SIU_ADDR, /* base address */ 208 VRCOM_FREQ, /* frequency */ 209 }, 210 #endif /* VR4111 */ 211 #ifdef VR4121 212 { 213 &platid_mask_CPU_MIPS_VR_4121, 214 com_vrip_cndb_attach, /* attach proc */ 215 VR4102_SIU_ADDR, /* base address */ 216 VRCOM_FREQ, /* frequency */ 217 }, 218 #endif /* VR4121 */ 219 #ifdef VR4122 220 { 221 &platid_mask_CPU_MIPS_VR_4122, 222 com_vrip_cndb_attach, /* attach proc */ 223 VR4122_SIU_ADDR, /* base address */ 224 VRCOM_FREQ, /* frequency */ 225 }, 226 #endif /* VR4122 */ 227 #ifdef VR4131 228 { 229 &platid_mask_CPU_MIPS_VR_4122, 230 com_vrip_cndb_attach, /* attach proc */ 231 VR4122_SIU_ADDR, /* base address */ 232 VRCOM_FREQ, /* frequency */ 233 }, 234 #endif /* VR4131 */ 235 #ifdef SINGLE_VRIP_BASE 236 { 237 &platid_wild, 238 com_vrip_cndb_attach, /* attach proc */ 239 VRIP_SIU_ADDR, /* base address */ 240 VRCOM_FREQ, /* frequency */ 241 }, 242 #endif /* SINGLE_VRIP_BASE */ 243 #else /* NCOM_VRIP > 0 */ 244 /* dummy */ 245 { 246 &platid_wild, 247 NULL, /* attach proc */ 248 0, /* base address */ 249 0, /* frequency */ 250 }, 251 #endif /* NCOM_VRIP > 0 */ 252 }; 253 #endif /* NCOM > 0 */ 254 255 #if NVRKIU > 0 256 /* 257 * machine dependent keyboard info 258 */ 259 static struct vr_kiu_platdep { 260 platid_mask_t *platidmask; 261 int addr; 262 } platdep_kiu_table[] = { 263 #ifdef VR4102 264 { 265 &platid_mask_CPU_MIPS_VR_4102, 266 VR4102_KIU_ADDR, /* base address */ 267 }, 268 #endif /* VR4102 */ 269 #ifdef VR4111 270 { 271 &platid_mask_CPU_MIPS_VR_4111, 272 VR4102_KIU_ADDR, /* base address */ 273 }, 274 #endif /* VR4111 */ 275 #ifdef VR4121 276 { 277 &platid_mask_CPU_MIPS_VR_4121, 278 VR4102_KIU_ADDR, /* base address */ 279 }, 280 #endif /* VR4121 */ 281 { 282 &platid_wild, 283 #ifdef SINGLE_VRIP_BASE 284 VRIP_KIU_ADDR, /* base address */ 285 #else 286 VRIP_NO_ADDR, /* base address */ 287 #endif /* SINGLE_VRIP_BASE */ 288 }, 289 }; 290 #endif /* NVRKIU > 0 */ 291 292 void 293 vr_init(void) 294 { 295 /* 296 * Platform Specific Function Hooks 297 */ 298 platform.cpu_idle = vr_idle; 299 platform.cpu_intr = VR_INTR; 300 platform.cons_init = vr_cons_init; 301 platform.fb_init = vr_fb_init; 302 platform.mem_init = vr_mem_init; 303 platform.reboot = vr_reboot; 304 305 #if NVRBCU > 0 306 sprintf(hpcmips_cpuname, "NEC %s rev%d.%d %d.%03dMHz", 307 vrbcu_vrip_getcpuname(), 308 vrbcu_vrip_getcpumajor(), 309 vrbcu_vrip_getcpuminor(), 310 vrbcu_vrip_getcpuclock() / 1000000, 311 (vrbcu_vrip_getcpuclock() % 1000000) / 1000); 312 #else 313 sprintf(hpcmips_cpuname, "NEC VR41xx"); 314 #endif 315 } 316 317 void 318 vr_mem_init(paddr_t kernend) 319 { 320 321 mem_clusters[0].start = 0; 322 mem_clusters[0].size = kernend; 323 mem_cluster_cnt = 1; 324 325 vr_find_dram(kernend, 0x02000000); 326 vr_find_dram(0x02000000, 0x04000000); 327 vr_find_dram(0x04000000, 0x06000000); 328 vr_find_dram(0x06000000, 0x08000000); 329 } 330 331 void 332 vr_find_dram(paddr_t addr, paddr_t end) 333 { 334 int n; 335 char *page; 336 #ifdef NARLY_MEMORY_PROBE 337 int x, i; 338 #endif 339 340 #ifdef VR_FIND_DRAMLIM 341 if (VR_FIND_DRAMLIM < end) 342 end = VR_FIND_DRAMLIM; 343 #endif /* VR_FIND_DRAMLIM */ 344 n = mem_cluster_cnt; 345 for (; addr < end; addr += PAGE_SIZE) { 346 347 page = (char *)MIPS_PHYS_TO_KSEG1(addr); 348 /* 349 XXX see port-hpcmips/42934 350 if (badaddr(page, 4)) 351 goto bad; 352 */ 353 354 /* stop memory probing at first memory image */ 355 if (memcmp(page, (void *)MIPS_PHYS_TO_KSEG0(0), 128) == 0) 356 return; 357 358 *(volatile int *)(page+0) = 0xa5a5a5a5; 359 *(volatile int *)(page+4) = 0x5a5a5a5a; 360 wbflush(); 361 if (*(volatile int *)(page+0) != 0xa5a5a5a5) 362 goto bad; 363 364 *(volatile int *)(page+0) = 0x5a5a5a5a; 365 *(volatile int *)(page+4) = 0xa5a5a5a5; 366 wbflush(); 367 if (*(volatile int *)(page+0) != 0x5a5a5a5a) 368 goto bad; 369 370 #ifdef NARLY_MEMORY_PROBE 371 x = random(); 372 for (i = 0; i < PAGE_SIZE; i += 4) 373 *(volatile int *)(page+i) = (x ^ i); 374 wbflush(); 375 for (i = 0; i < PAGE_SIZE; i += 4) 376 if (*(volatile int *)(page+i) != (x ^ i)) 377 goto bad; 378 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 #endif /* NARLY_MEMORY_PROBE */ 387 388 if (!mem_clusters[n].size) 389 mem_clusters[n].start = addr; 390 mem_clusters[n].size += PAGE_SIZE; 391 continue; 392 393 bad: 394 if (mem_clusters[n].size) 395 ++n; 396 continue; 397 } 398 if (mem_clusters[n].size) 399 ++n; 400 mem_cluster_cnt = n; 401 } 402 403 void 404 vr_fb_init(void **kernend) 405 { 406 /* Nothing to do */ 407 } 408 409 void 410 vr_cons_init(void) 411 { 412 #if NCOM > 0 || NHPCFB > 0 || NVRKIU > 0 413 bus_space_tag_t iot = hpcmips_system_bus_space(); 414 #endif 415 #if NCOM > 0 416 static struct vr_com_platdep *com_info; 417 #endif 418 #if NVRKIU > 0 419 static struct vr_kiu_platdep *kiu_info; 420 #endif 421 422 #if NCOM > 0 423 com_info = platid_search(&platid, platdep_com_table, 424 sizeof(platdep_com_table)/sizeof(*platdep_com_table), 425 sizeof(*platdep_com_table)); 426 #ifdef KGDB 427 if (com_info->attach != NULL) { 428 /* if KGDB is defined, always use the serial port for KGDB */ 429 if ((*com_info->attach)(iot, com_info->addr, 9600, 430 com_info->freq, 431 (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8, 1)) { 432 printf("%s(%d): can't init kgdb's serial port", 433 __FILE__, __LINE__); 434 } 435 } 436 #else /* KGDB */ 437 if (com_info->attach != NULL && (bootinfo->bi_cnuse&BI_CNUSE_SERIAL)) { 438 /* Serial console */ 439 if ((*com_info->attach)(iot, com_info->addr, CONSPEED, 440 com_info->freq, 441 (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8, 0)) { 442 printf("%s(%d): can't init serial console", 443 __FILE__, __LINE__); 444 } else { 445 return; 446 } 447 } 448 #endif /* KGDB */ 449 #endif /* NCOM > 0 */ 450 451 #if NHPCFB > 0 452 if (hpcfb_cnattach(NULL)) { 453 printf("%s(%d): can't init fb console", __FILE__, __LINE__); 454 } else { 455 goto find_keyboard; 456 } 457 find_keyboard: 458 #endif /* NHPCFB > 0 */ 459 460 #if NVRKIU > 0 461 kiu_info = platid_search(&platid, platdep_kiu_table, 462 sizeof(platdep_kiu_table)/sizeof(*platdep_kiu_table), 463 sizeof(*platdep_kiu_table)); 464 if (kiu_info->addr != VRIP_NO_ADDR) { 465 if (vrkiu_cnattach(iot, kiu_info->addr)) { 466 printf("%s(%d): can't init vrkiu as console", 467 __FILE__, __LINE__); 468 } else { 469 return; 470 } 471 } 472 #endif /* NVRKIU > 0 */ 473 } 474 475 extern char vr_hibernate[]; 476 extern char evr_hibernate[]; 477 478 void 479 vr_reboot(int howto, char *bootstr) 480 { 481 /* 482 * power down 483 */ 484 if ((howto & RB_POWERDOWN) == RB_POWERDOWN) { 485 printf("fake powerdown\n"); 486 /* 487 * copy vr_hibernate() to top of physical memory. 488 */ 489 memcpy((void *)MIPS_KSEG0_START, vr_hibernate, 490 evr_hibernate - (char *)vr_hibernate); 491 /* sync I&D cache */ 492 mips_dcache_wbinv_all(); 493 mips_icache_sync_all(); 494 /* 495 * call vr_hibernate() at MIPS_KSEG0_START. 496 */ 497 ((void (*)(void *,int))MIPS_KSEG0_START)( 498 (void *)MIPS_KSEG0_START, ptoa(physmem)); 499 /* not reach */ 500 vr_reboot(howto&~RB_HALT, bootstr); 501 } 502 /* 503 * halt 504 */ 505 if (howto & RB_HALT) { 506 #if NVRIP_COMMON > 0 507 _spllower(~MIPS_INT_MASK_0); 508 vrip_intr_suspend(); 509 #else 510 splhigh(); 511 #endif 512 __asm(".set noreorder"); 513 __asm(".word " ___STRING(VR_OPCODE_SUSPEND)); 514 __asm("nop"); 515 __asm("nop"); 516 __asm("nop"); 517 __asm("nop"); 518 __asm("nop"); 519 __asm(".set reorder"); 520 #if NVRIP_COMMON > 0 521 vrip_intr_resume(); 522 #endif 523 } 524 /* 525 * reset 526 */ 527 #if NVRDSU 528 vrdsu_reset(); 529 #else 530 printf("%s(%d): There is no DSU.", __FILE__, __LINE__); 531 #endif 532 } 533 534 /* 535 * Handle interrupts. 536 */ 537 void 538 VR_INTR(u_int32_t status, u_int32_t cause, u_int32_t pc, u_int32_t ipending) 539 { 540 struct cpu_info *ci; 541 542 ci = curcpu(); 543 ci->ci_idepth++; 544 ci->ci_data.cpu_nintr++; 545 546 /* Deal with unneded compare interrupts occasionally so that we can 547 * keep spllowersoftclock. */ 548 if (ipending & MIPS_INT_MASK_5) { 549 mips3_cp0_compare_write(0); 550 } 551 552 if (ipending & MIPS_INT_MASK_1) { 553 _splset(MIPS_SR_INT_IE); /* for spllowersoftclock */ 554 /* Remove the lower priority pending bits from status so that 555 * spllowersoftclock will not happen if other interrupts are 556 * pending. */ 557 (*vr_intr_handler[1])(vr_intr_arg[1], pc, status & ~(ipending 558 & (MIPS_INT_MASK_0|MIPS_SOFT_INT_MASK_0|MIPS_SOFT_INT_MASK_1))); 559 } 560 561 if (ipending & MIPS_INT_MASK_0) { 562 _splset(MIPS_INT_MASK_1|MIPS_SR_INT_IE); 563 (*vr_intr_handler[0])(vr_intr_arg[0], pc, status); 564 } 565 ci->ci_idepth--; 566 567 #ifdef __HAVE_FAST_SOFTINTS 568 if (ipending & MIPS_SOFT_INT_MASK_1) { 569 _splset(MIPS_INT_MASK_1|MIPS_INT_MASK_0|MIPS_SR_INT_IE); 570 softintr(MIPS_SOFT_INT_MASK_1); 571 } 572 573 if (ipending & MIPS_SOFT_INT_MASK_0) { 574 _splset(MIPS_SOFT_INT_MASK_1|MIPS_INT_MASK_1|MIPS_INT_MASK_0| 575 MIPS_SR_INT_IE); 576 softintr(MIPS_SOFT_INT_MASK_0); 577 } 578 #endif 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