|
|
1.1 ! root 1: /* ! 2: * OpenBIOS Sparc OBIO driver ! 3: * ! 4: * (C) 2004 Stefan Reinauer <[email protected]> ! 5: * (C) 2005 Ed Schouten <[email protected]> ! 6: * ! 7: * This program is free software; you can redistribute it and/or ! 8: * modify it under the terms of the GNU General Public License ! 9: * version 2 ! 10: * ! 11: */ ! 12: ! 13: #include "config.h" ! 14: #include "libopenbios/bindings.h" ! 15: #include "kernel/kernel.h" ! 16: #include "libc/byteorder.h" ! 17: #include "libc/vsprintf.h" ! 18: ! 19: #include "drivers/drivers.h" ! 20: #include "arch/common/nvram.h" ! 21: #include "libopenbios/ofmem.h" ! 22: #include "obio.h" ! 23: #include "escc.h" ! 24: ! 25: #define PROMDEV_KBD 0 /* input from keyboard */ ! 26: #define PROMDEV_SCREEN 0 /* output to screen */ ! 27: #define PROMDEV_TTYA 1 /* in/out to ttya */ ! 28: ! 29: /* "NCPU" is an historical name that's now a bit of a misnomer. The sun4m ! 30: * architecture registers NCPU CPU-specific interrupts along with one ! 31: * system-wide interrupt, regardless of the number of actual CPUs installed. ! 32: * See the comment on "NCPU" at <http://stuff.mit.edu/afs/athena/astaff/ ! 33: * project/opssrc/sys.sunos/sun4m/devaddr.h>. ! 34: */ ! 35: #define SUN4M_NCPU 4 ! 36: ! 37: /* DECLARE data structures for the nodes. */ ! 38: DECLARE_UNNAMED_NODE( ob_obio, INSTALL_OPEN, sizeof(int) ); ! 39: ! 40: void ! 41: ob_new_obio_device(const char *name, const char *type) ! 42: { ! 43: push_str("/obio"); ! 44: fword("find-device"); ! 45: fword("new-device"); ! 46: ! 47: push_str(name); ! 48: fword("device-name"); ! 49: ! 50: if (type) { ! 51: push_str(type); ! 52: fword("device-type"); ! 53: } ! 54: } ! 55: ! 56: static unsigned long ! 57: map_reg(uint64_t base, uint64_t offset, unsigned long size, int map, ! 58: int phys_hi) ! 59: { ! 60: PUSH(phys_hi); ! 61: fword("encode-int"); ! 62: PUSH(offset); ! 63: fword("encode-int"); ! 64: fword("encode+"); ! 65: PUSH(size); ! 66: fword("encode-int"); ! 67: fword("encode+"); ! 68: push_str("reg"); ! 69: fword("property"); ! 70: ! 71: if (map) { ! 72: unsigned long addr; ! 73: ! 74: addr = (unsigned long)ofmem_map_io(base + offset, size); ! 75: ! 76: PUSH(addr); ! 77: fword("encode-int"); ! 78: push_str("address"); ! 79: fword("property"); ! 80: return addr; ! 81: } ! 82: return 0; ! 83: } ! 84: ! 85: unsigned long ! 86: ob_reg(uint64_t base, uint64_t offset, unsigned long size, int map) ! 87: { ! 88: return map_reg(base, offset, size, map, 0); ! 89: } ! 90: ! 91: void ! 92: ob_intr(int intr) ! 93: { ! 94: PUSH(intr); ! 95: fword("encode-int"); ! 96: PUSH(0); ! 97: fword("encode-int"); ! 98: fword("encode+"); ! 99: push_str("intr"); ! 100: fword("property"); ! 101: } ! 102: ! 103: void ! 104: ob_eccmemctl_init(uint64_t base) ! 105: { ! 106: uint32_t version, *regs; ! 107: const char *mc_type; ! 108: ! 109: push_str("/"); ! 110: fword("find-device"); ! 111: fword("new-device"); ! 112: ! 113: push_str("eccmemctl"); ! 114: fword("device-name"); ! 115: ! 116: PUSH(0x20); ! 117: fword("encode-int"); ! 118: push_str("width"); ! 119: fword("property"); ! 120: ! 121: regs = (uint32_t *)map_reg(ECC_BASE, 0, ECC_SIZE, 1, ECC_BASE >> 32); ! 122: ! 123: version = regs[0]; ! 124: switch (version) { ! 125: case 0x00000000: ! 126: mc_type = "MCC"; ! 127: break; ! 128: case 0x10000000: ! 129: mc_type = "EMC"; ! 130: break; ! 131: default: ! 132: case 0x20000000: ! 133: mc_type = "SMC"; ! 134: break; ! 135: } ! 136: push_str(mc_type); ! 137: fword("encode-string"); ! 138: push_str("mc-type"); ! 139: fword("property"); ! 140: ! 141: fword("finish-device"); ! 142: } ! 143: ! 144: static unsigned char *nvram; ! 145: ! 146: #define NVRAM_OB_START (0) ! 147: #define NVRAM_OB_SIZE ((NVRAM_IDPROM - NVRAM_OB_START) & ~15) ! 148: ! 149: void ! 150: arch_nvram_get(char *data) ! 151: { ! 152: memcpy(data, &nvram[NVRAM_OB_START], NVRAM_OB_SIZE); ! 153: } ! 154: ! 155: void ! 156: arch_nvram_put(char *data) ! 157: { ! 158: memcpy(&nvram[NVRAM_OB_START], data, NVRAM_OB_SIZE); ! 159: } ! 160: ! 161: int ! 162: arch_nvram_size(void) ! 163: { ! 164: return NVRAM_OB_SIZE; ! 165: } ! 166: ! 167: void ! 168: ss5_init(uint64_t base) ! 169: { ! 170: ob_new_obio_device("slavioconfig", NULL); ! 171: ! 172: ob_reg(base, SLAVIO_SCONFIG, SCONFIG_REGS, 0); ! 173: ! 174: fword("finish-device"); ! 175: } ! 176: ! 177: static void ! 178: ob_nvram_init(uint64_t base, uint64_t offset) ! 179: { ! 180: ob_new_obio_device("eeprom", NULL); ! 181: ! 182: nvram = (unsigned char *)ob_reg(base, offset, NVRAM_SIZE, 1); ! 183: ! 184: PUSH((unsigned long)nvram); ! 185: fword("encode-int"); ! 186: push_str("address"); ! 187: fword("property"); ! 188: ! 189: push_str("mk48t08"); ! 190: fword("model"); ! 191: ! 192: fword("finish-device"); ! 193: ! 194: // Add /idprom ! 195: push_str("/"); ! 196: fword("find-device"); ! 197: ! 198: PUSH((long)&nvram[NVRAM_IDPROM]); ! 199: PUSH(32); ! 200: fword("encode-bytes"); ! 201: push_str("idprom"); ! 202: fword("property"); ! 203: } ! 204: ! 205: static void ! 206: ob_fd_init(uint64_t base, uint64_t offset, int intr) ! 207: { ! 208: unsigned long addr; ! 209: ! 210: ob_new_obio_device("SUNW,fdtwo", "block"); ! 211: ! 212: addr = ob_reg(base, offset, FD_REGS, 1); ! 213: ! 214: ob_intr(intr); ! 215: ! 216: fword("is-deblocker"); ! 217: ! 218: ob_floppy_init("/obio", "SUNW,fdtwo", 0, addr); ! 219: ! 220: fword("finish-device"); ! 221: } ! 222: ! 223: static void ! 224: ob_auxio_init(uint64_t base, uint64_t offset) ! 225: { ! 226: ob_new_obio_device("auxio", NULL); ! 227: ! 228: ob_reg(base, offset, AUXIO_REGS, 1); ! 229: ! 230: fword("finish-device"); ! 231: } ! 232: ! 233: volatile unsigned char *power_reg; ! 234: volatile unsigned int *reset_reg; ! 235: ! 236: static void ! 237: sparc32_reset_all(void) ! 238: { ! 239: *reset_reg = 1; ! 240: } ! 241: ! 242: // AUX 2 (Software Powerdown Control) and reset ! 243: static void ! 244: ob_aux2_reset_init(uint64_t base, uint64_t offset, int intr) ! 245: { ! 246: ob_new_obio_device("power", NULL); ! 247: ! 248: power_reg = (void *)ob_reg(base, offset, AUXIO2_REGS, 1); ! 249: ! 250: // Not in device tree ! 251: reset_reg = (unsigned int *)ofmem_map_io(base + (uint64_t)SLAVIO_RESET, RESET_REGS); ! 252: ! 253: bind_func("sparc32-reset-all", sparc32_reset_all); ! 254: push_str("' sparc32-reset-all to reset-all"); ! 255: fword("eval"); ! 256: ! 257: ob_intr(intr); ! 258: ! 259: fword("finish-device"); ! 260: } ! 261: ! 262: volatile struct sun4m_timer_regs *counter_regs; ! 263: ! 264: static void ! 265: ob_counter_init(uint64_t base, unsigned long offset) ! 266: { ! 267: int i; ! 268: ! 269: ob_new_obio_device("counter", NULL); ! 270: ! 271: for (i = 0; i < SUN4M_NCPU; i++) { ! 272: PUSH(0); ! 273: fword("encode-int"); ! 274: if (i != 0) fword("encode+"); ! 275: PUSH(offset + (i * PAGE_SIZE)); ! 276: fword("encode-int"); ! 277: fword("encode+"); ! 278: PUSH(COUNTER_REGS); ! 279: fword("encode-int"); ! 280: fword("encode+"); ! 281: } ! 282: ! 283: PUSH(0); ! 284: fword("encode-int"); ! 285: fword("encode+"); ! 286: PUSH(offset + 0x10000); ! 287: fword("encode-int"); ! 288: fword("encode+"); ! 289: PUSH(COUNTER_REGS); ! 290: fword("encode-int"); ! 291: fword("encode+"); ! 292: ! 293: push_str("reg"); ! 294: fword("property"); ! 295: ! 296: ! 297: counter_regs = (struct sun4m_timer_regs *)ofmem_map_io(base + (uint64_t)offset, sizeof(*counter_regs)); ! 298: counter_regs->cfg = 0xffffffff; ! 299: counter_regs->l10_timer_limit = 0; ! 300: counter_regs->cpu_timers[0].l14_timer_limit = 0x9c4000; /* see comment in obio.h */ ! 301: counter_regs->cpu_timers[0].cntrl = 1; ! 302: ! 303: for (i = 0; i < SUN4M_NCPU; i++) { ! 304: PUSH((unsigned long)&counter_regs->cpu_timers[i]); ! 305: fword("encode-int"); ! 306: if (i != 0) ! 307: fword("encode+"); ! 308: } ! 309: PUSH((unsigned long)&counter_regs->l10_timer_limit); ! 310: fword("encode-int"); ! 311: fword("encode+"); ! 312: push_str("address"); ! 313: fword("property"); ! 314: ! 315: fword("finish-device"); ! 316: } ! 317: ! 318: static volatile struct sun4m_intregs *intregs; ! 319: ! 320: static void ! 321: ob_interrupt_init(uint64_t base, unsigned long offset) ! 322: { ! 323: int i; ! 324: ! 325: ob_new_obio_device("interrupt", NULL); ! 326: ! 327: for (i = 0; i < SUN4M_NCPU; i++) { ! 328: PUSH(0); ! 329: fword("encode-int"); ! 330: if (i != 0) fword("encode+"); ! 331: PUSH(offset + (i * PAGE_SIZE)); ! 332: fword("encode-int"); ! 333: fword("encode+"); ! 334: PUSH(INTERRUPT_REGS); ! 335: fword("encode-int"); ! 336: fword("encode+"); ! 337: } ! 338: ! 339: PUSH(0); ! 340: fword("encode-int"); ! 341: fword("encode+"); ! 342: PUSH(offset + 0x10000); ! 343: fword("encode-int"); ! 344: fword("encode+"); ! 345: PUSH(INTERRUPT_REGS); ! 346: fword("encode-int"); ! 347: fword("encode+"); ! 348: ! 349: push_str("reg"); ! 350: fword("property"); ! 351: ! 352: intregs = (struct sun4m_intregs *)ofmem_map_io(base | (uint64_t)offset, sizeof(*intregs)); ! 353: intregs->clear = ~SUN4M_INT_MASKALL; ! 354: intregs->cpu_intregs[0].clear = ~0x17fff; ! 355: ! 356: for (i = 0; i < SUN4M_NCPU; i++) { ! 357: PUSH((unsigned long)&intregs->cpu_intregs[i]); ! 358: fword("encode-int"); ! 359: if (i != 0) ! 360: fword("encode+"); ! 361: } ! 362: PUSH((unsigned long)&intregs->tbt); ! 363: fword("encode-int"); ! 364: fword("encode+"); ! 365: push_str("address"); ! 366: fword("property"); ! 367: ! 368: fword("finish-device"); ! 369: } ! 370: ! 371: /* SMP CPU boot structure */ ! 372: struct smp_cfg { ! 373: uint32_t smp_ctx; ! 374: uint32_t smp_ctxtbl; ! 375: uint32_t smp_entry; ! 376: uint32_t valid; ! 377: }; ! 378: ! 379: static struct smp_cfg *smp_header; ! 380: ! 381: int ! 382: start_cpu(unsigned int pc, unsigned int context_ptr, unsigned int context, int cpu) ! 383: { ! 384: if (!cpu) ! 385: return -1; ! 386: ! 387: cpu &= 7; ! 388: ! 389: smp_header->smp_entry = pc; ! 390: smp_header->smp_ctxtbl = context_ptr; ! 391: smp_header->smp_ctx = context; ! 392: smp_header->valid = cpu; ! 393: ! 394: intregs->cpu_intregs[cpu].set = SUN4M_SOFT_INT(14); ! 395: ! 396: return 0; ! 397: } ! 398: ! 399: static void ! 400: ob_smp_init(unsigned long mem_size) ! 401: { ! 402: // See arch/sparc32/entry.S for memory layout ! 403: smp_header = (struct smp_cfg *)ofmem_map_io((uint64_t)(mem_size - 0x100), ! 404: sizeof(struct smp_cfg)); ! 405: } ! 406: ! 407: static void ! 408: ob_obio_open(__attribute__((unused))int *idx) ! 409: { ! 410: int ret=1; ! 411: RET ( -ret ); ! 412: } ! 413: ! 414: static void ! 415: ob_obio_close(__attribute__((unused))int *idx) ! 416: { ! 417: selfword("close-deblocker"); ! 418: } ! 419: ! 420: static void ! 421: ob_obio_initialize(__attribute__((unused))int *idx) ! 422: { ! 423: push_str("/"); ! 424: fword("find-device"); ! 425: fword("new-device"); ! 426: ! 427: push_str("obio"); ! 428: fword("device-name"); ! 429: ! 430: push_str("hierarchical"); ! 431: fword("device-type"); ! 432: ! 433: PUSH(2); ! 434: fword("encode-int"); ! 435: push_str("#address-cells"); ! 436: fword("property"); ! 437: ! 438: PUSH(1); ! 439: fword("encode-int"); ! 440: push_str("#size-cells"); ! 441: fword("property"); ! 442: ! 443: fword("finish-device"); ! 444: } ! 445: ! 446: static void ! 447: ob_set_obio_ranges(uint64_t base) ! 448: { ! 449: push_str("/obio"); ! 450: fword("find-device"); ! 451: PUSH(0); ! 452: fword("encode-int"); ! 453: PUSH(0); ! 454: fword("encode-int"); ! 455: fword("encode+"); ! 456: PUSH(base >> 32); ! 457: fword("encode-int"); ! 458: fword("encode+"); ! 459: PUSH(base & 0xffffffff); ! 460: fword("encode-int"); ! 461: fword("encode+"); ! 462: PUSH(SLAVIO_SIZE); ! 463: fword("encode-int"); ! 464: fword("encode+"); ! 465: push_str("ranges"); ! 466: fword("property"); ! 467: } ! 468: ! 469: static void ! 470: ob_obio_decodeunit(__attribute__((unused)) int *idx) ! 471: { ! 472: fword("decode-unit-sbus"); ! 473: } ! 474: ! 475: ! 476: static void ! 477: ob_obio_encodeunit(__attribute__((unused)) int *idx) ! 478: { ! 479: fword("encode-unit-sbus"); ! 480: } ! 481: ! 482: NODE_METHODS(ob_obio) = { ! 483: { NULL, ob_obio_initialize }, ! 484: { "open", ob_obio_open }, ! 485: { "close", ob_obio_close }, ! 486: { "encode-unit", ob_obio_encodeunit }, ! 487: { "decode-unit", ob_obio_decodeunit }, ! 488: }; ! 489: ! 490: ! 491: int ! 492: ob_obio_init(uint64_t slavio_base, unsigned long fd_offset, ! 493: unsigned long counter_offset, unsigned long intr_offset, ! 494: unsigned long aux1_offset, unsigned long aux2_offset, ! 495: unsigned long mem_size) ! 496: { ! 497: ! 498: // All devices were integrated to NCR89C105, see ! 499: // http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt ! 500: ! 501: //printk("Initializing OBIO devices...\n"); ! 502: #if 0 // XXX ! 503: REGISTER_NAMED_NODE(ob_obio, "/obio"); ! 504: device_end(); ! 505: #endif ! 506: ob_set_obio_ranges(slavio_base); ! 507: ! 508: // Zilog Z8530 serial ports, see http://www.zilog.com ! 509: // Must be before zs@0,0 or Linux won't boot ! 510: ob_zs_init(slavio_base, SLAVIO_ZS1, ZS_INTR, 0, 0); ! 511: ! 512: ob_zs_init(slavio_base, SLAVIO_ZS, ZS_INTR, 1, 1); ! 513: ! 514: // M48T08 NVRAM, see http://www.st.com ! 515: ob_nvram_init(slavio_base, SLAVIO_NVRAM); ! 516: ! 517: // 82078 FDC ! 518: if (fd_offset != (unsigned long) -1) ! 519: ob_fd_init(slavio_base, fd_offset, FD_INTR); ! 520: ! 521: ob_auxio_init(slavio_base, aux1_offset); ! 522: ! 523: if (aux2_offset != (unsigned long) -1) ! 524: ob_aux2_reset_init(slavio_base, aux2_offset, AUXIO2_INTR); ! 525: ! 526: ob_counter_init(slavio_base, counter_offset); ! 527: ! 528: ob_interrupt_init(slavio_base, intr_offset); ! 529: ! 530: ob_smp_init(mem_size); ! 531: ! 532: return 0; ! 533: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.