|
|
1.1 ! root 1: /* ! 2: * OpenBIOS SBus 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: #include "drivers/drivers.h" ! 19: #include "libopenbios/ofmem.h" ! 20: ! 21: #define SBUS_REGS 0x28 ! 22: #define SBUS_SLOTS 16 ! 23: #define APC_REGS 0x10 ! 24: #define APC_OFFSET 0x0a000000ULL ! 25: #define CS4231_REGS 0x40 ! 26: #define CS4231_OFFSET 0x0c000000ULL ! 27: #define MACIO_ESPDMA 0x00400000ULL /* ESP DMA controller */ ! 28: #define MACIO_ESP 0x00800000ULL /* ESP SCSI */ ! 29: #define SS600MP_ESPDMA 0x00081000ULL ! 30: #define SS600MP_ESP 0x00080000ULL ! 31: #define SS600MP_LEBUFFER (SS600MP_ESPDMA + 0x10) // XXX should be 0x40000 ! 32: #define LEDMA_REGS 0x4 ! 33: #define LE_REGS 0x20 ! 34: ! 35: #ifdef CONFIG_DEBUG_SBUS ! 36: #define DPRINTF(fmt, args...) \ ! 37: do { printk(fmt , ##args); } while (0) ! 38: #else ! 39: #define DPRINTF(fmt, args...) ! 40: #endif ! 41: ! 42: typedef struct le_private { ! 43: uint32_t *dmaregs; ! 44: uint32_t *regs; ! 45: } le_private_t; ! 46: ! 47: static void ! 48: ob_sbus_node_init(uint64_t base) ! 49: { ! 50: void *regs; ! 51: ! 52: push_str("/iommu/sbus"); ! 53: fword("find-device"); ! 54: ! 55: PUSH(base >> 32); ! 56: fword("encode-int"); ! 57: PUSH(base & 0xffffffff); ! 58: fword("encode-int"); ! 59: fword("encode+"); ! 60: PUSH(SBUS_REGS); ! 61: fword("encode-int"); ! 62: fword("encode+"); ! 63: push_str("reg"); ! 64: fword("property"); ! 65: ! 66: regs = (void *)ofmem_map_io(base, SBUS_REGS); ! 67: PUSH((unsigned long)regs); ! 68: fword("encode-int"); ! 69: push_str("address"); ! 70: fword("property"); ! 71: } ! 72: ! 73: static void ! 74: ob_le_init(unsigned int slot, uint64_t base, unsigned long leoffset, unsigned long dmaoffset) ! 75: { ! 76: le_private_t *le; ! 77: ! 78: le = malloc(sizeof(le_private_t)); ! 79: if (!le) { ! 80: DPRINTF("Can't allocate LANCE private structure\n"); ! 81: return; ! 82: } ! 83: ! 84: /* Get the IO region for DMA registers */ ! 85: le->dmaregs = (void *)ofmem_map_io(base + (uint64_t)dmaoffset, LEDMA_REGS); ! 86: if (le->dmaregs == NULL) { ! 87: DPRINTF("Can't map LANCE DMA registers\n"); ! 88: return; ! 89: } ! 90: ! 91: /* Now it appears that the Solaris kernel forgets to set up the LANCE DMA mapping ! 92: and so it must inherit the one from OpenBIOS. The symptom of this is that the ! 93: LANCE DMA base addr register is still zero, and so we start sending network ! 94: packets containing random areas of memory. ! 95: ! 96: The correct fix for this should be to use dvma_alloc() to grab a section of ! 97: memory and point the LANCE DMA buffers to use that instead; this gets ! 98: slightly further but still crashes. Time-consuming investigation on various ! 99: hacked versions of QEMU seems to indicate that Solaris always assumes the LANCE ! 100: DMA base address is fixed 0xff000000 when setting up the IOMMU for the LANCE ! 101: card. Hence we imitate this behaviour here. */ ! 102: le->dmaregs[3] = 0xff000000; ! 103: ! 104: push_str("/iommu/sbus/ledma"); ! 105: fword("find-device"); ! 106: PUSH(slot); ! 107: fword("encode-int"); ! 108: PUSH(dmaoffset); ! 109: fword("encode-int"); ! 110: fword("encode+"); ! 111: PUSH(0x00000020); ! 112: fword("encode-int"); ! 113: fword("encode+"); ! 114: push_str("reg"); ! 115: fword("property"); ! 116: ! 117: /* Get the IO region for Lance registers */ ! 118: le->regs = (void *)ofmem_map_io(base + (uint64_t)leoffset, LE_REGS); ! 119: if (le->regs == NULL) { ! 120: DPRINTF("Can't map LANCE registers\n"); ! 121: return; ! 122: } ! 123: ! 124: push_str("/iommu/sbus/ledma/le"); ! 125: fword("find-device"); ! 126: PUSH(slot); ! 127: fword("encode-int"); ! 128: PUSH(leoffset); ! 129: fword("encode-int"); ! 130: fword("encode+"); ! 131: PUSH(0x00000004); ! 132: fword("encode-int"); ! 133: fword("encode+"); ! 134: push_str("reg"); ! 135: fword("property"); ! 136: } ! 137: ! 138: uint16_t graphic_depth; ! 139: ! 140: static void ! 141: ob_tcx_init(unsigned int slot, const char *path) ! 142: { ! 143: phandle_t chosen, aliases; ! 144: ! 145: push_str(path); ! 146: fword("find-device"); ! 147: ! 148: PUSH(slot); ! 149: fword("encode-int"); ! 150: PUSH(0x00800000); ! 151: fword("encode-int"); ! 152: fword("encode+"); ! 153: PUSH(0x00100000); ! 154: fword("encode-int"); ! 155: fword("encode+"); ! 156: ! 157: PUSH(slot); ! 158: fword("encode-int"); ! 159: fword("encode+"); ! 160: PUSH(0x02000000); ! 161: fword("encode-int"); ! 162: fword("encode+"); ! 163: if (graphic_depth == 24) { ! 164: PUSH(0x00400000); ! 165: } else { ! 166: PUSH(0x00000001); ! 167: } ! 168: fword("encode-int"); ! 169: fword("encode+"); ! 170: ! 171: PUSH(slot); ! 172: fword("encode-int"); ! 173: fword("encode+"); ! 174: PUSH(0x04000000); ! 175: fword("encode-int"); ! 176: fword("encode+"); ! 177: if (graphic_depth == 24) { ! 178: PUSH(0x00400000); ! 179: } else { ! 180: PUSH(0x00000001); ! 181: } ! 182: fword("encode-int"); ! 183: fword("encode+"); ! 184: ! 185: PUSH(slot); ! 186: fword("encode-int"); ! 187: fword("encode+"); ! 188: PUSH(0x06000000); ! 189: fword("encode-int"); ! 190: fword("encode+"); ! 191: PUSH(0x00800000); ! 192: fword("encode-int"); ! 193: fword("encode+"); ! 194: ! 195: PUSH(slot); ! 196: fword("encode-int"); ! 197: fword("encode+"); ! 198: PUSH(0x0a000000); ! 199: fword("encode-int"); ! 200: fword("encode+"); ! 201: if (graphic_depth == 24) { ! 202: PUSH(0x00400000); ! 203: } else { ! 204: PUSH(0x00000001); ! 205: } ! 206: fword("encode-int"); ! 207: fword("encode+"); ! 208: ! 209: PUSH(slot); ! 210: fword("encode-int"); ! 211: fword("encode+"); ! 212: PUSH(0x0c000000); ! 213: fword("encode-int"); ! 214: fword("encode+"); ! 215: if (graphic_depth == 24) { ! 216: PUSH(0x00800000); ! 217: } else { ! 218: PUSH(0x00000001); ! 219: } ! 220: fword("encode-int"); ! 221: fword("encode+"); ! 222: ! 223: PUSH(slot); ! 224: fword("encode-int"); ! 225: fword("encode+"); ! 226: PUSH(0x0e000000); ! 227: fword("encode-int"); ! 228: fword("encode+"); ! 229: if (graphic_depth == 24) { ! 230: PUSH(0x00800000); ! 231: } else { ! 232: PUSH(0x00000001); ! 233: } ! 234: fword("encode-int"); ! 235: fword("encode+"); ! 236: ! 237: PUSH(slot); ! 238: fword("encode-int"); ! 239: fword("encode+"); ! 240: PUSH(0x00700000); ! 241: fword("encode-int"); ! 242: fword("encode+"); ! 243: PUSH(0x00001000); ! 244: fword("encode-int"); ! 245: fword("encode+"); ! 246: ! 247: PUSH(slot); ! 248: fword("encode-int"); ! 249: fword("encode+"); ! 250: PUSH(0x00200000); ! 251: fword("encode-int"); ! 252: fword("encode+"); ! 253: if (graphic_depth == 24) { ! 254: PUSH(0x00004000); ! 255: } else { ! 256: PUSH(0x00000004); ! 257: } ! 258: fword("encode-int"); ! 259: fword("encode+"); ! 260: ! 261: PUSH(slot); ! 262: fword("encode-int"); ! 263: fword("encode+"); ! 264: if (graphic_depth == 24) { ! 265: PUSH(0x00301000); ! 266: } else { ! 267: PUSH(0x00300000); ! 268: } ! 269: fword("encode-int"); ! 270: fword("encode+"); ! 271: if (graphic_depth == 24) { ! 272: PUSH(0x00001000); ! 273: } else { ! 274: PUSH(0x0000081c); ! 275: } ! 276: fword("encode-int"); ! 277: fword("encode+"); ! 278: ! 279: PUSH(slot); ! 280: fword("encode-int"); ! 281: fword("encode+"); ! 282: PUSH(0x00000000); ! 283: fword("encode-int"); ! 284: fword("encode+"); ! 285: PUSH(0x00010000); ! 286: fword("encode-int"); ! 287: fword("encode+"); ! 288: ! 289: PUSH(slot); ! 290: fword("encode-int"); ! 291: fword("encode+"); ! 292: PUSH(0x00240000); ! 293: fword("encode-int"); ! 294: fword("encode+"); ! 295: if (graphic_depth == 24) { ! 296: PUSH(0x00004000); ! 297: } else { ! 298: PUSH(0x00000004); ! 299: } ! 300: fword("encode-int"); ! 301: fword("encode+"); ! 302: ! 303: PUSH(slot); ! 304: fword("encode-int"); ! 305: fword("encode+"); ! 306: PUSH(0x00280000); ! 307: fword("encode-int"); ! 308: fword("encode+"); ! 309: if (graphic_depth == 24) { ! 310: PUSH(0x00008000); ! 311: } else { ! 312: PUSH(0x00000001); ! 313: } ! 314: fword("encode-int"); ! 315: fword("encode+"); ! 316: ! 317: push_str("reg"); ! 318: fword("property"); ! 319: ! 320: PUSH((int)graphic_depth); ! 321: fword("encode-int"); ! 322: push_str("depth"); ! 323: fword("property"); ! 324: ! 325: if (graphic_depth == 8) { ! 326: push_str("true"); ! 327: fword("encode-string"); ! 328: push_str("tcx-8-bit"); ! 329: fword("property"); ! 330: } ! 331: ! 332: chosen = find_dev("/chosen"); ! 333: push_str(path); ! 334: fword("open-dev"); ! 335: set_int_property(chosen, "screen", POP()); ! 336: ! 337: aliases = find_dev("/aliases"); ! 338: set_property(aliases, "screen", path, strlen(path) + 1); ! 339: } ! 340: ! 341: static void ! 342: ob_apc_init(unsigned int slot, unsigned long base) ! 343: { ! 344: push_str("/iommu/sbus"); ! 345: fword("find-device"); ! 346: fword("new-device"); ! 347: ! 348: push_str("power-management"); ! 349: fword("device-name"); ! 350: ! 351: PUSH(slot); ! 352: fword("encode-int"); ! 353: PUSH(base); ! 354: fword("encode-int"); ! 355: fword("encode+"); ! 356: PUSH(APC_REGS); ! 357: fword("encode-int"); ! 358: fword("encode+"); ! 359: push_str("reg"); ! 360: fword("property"); ! 361: ! 362: fword("finish-device"); ! 363: } ! 364: ! 365: static void ! 366: ob_cs4231_init(unsigned int slot) ! 367: { ! 368: push_str("/iommu/sbus"); ! 369: fword("find-device"); ! 370: fword("new-device"); ! 371: ! 372: push_str("SUNW,CS4231"); ! 373: fword("device-name"); ! 374: ! 375: push_str("serial"); ! 376: fword("device-type"); ! 377: ! 378: PUSH(slot); ! 379: fword("encode-int"); ! 380: PUSH(CS4231_OFFSET); ! 381: fword("encode-int"); ! 382: fword("encode+"); ! 383: PUSH(CS4231_REGS); ! 384: fword("encode-int"); ! 385: fword("encode+"); ! 386: push_str("reg"); ! 387: fword("property"); ! 388: ! 389: PUSH(5); ! 390: fword("encode-int"); ! 391: PUSH(0); ! 392: fword("encode-int"); ! 393: fword("encode+"); ! 394: push_str("intr"); ! 395: fword("property"); ! 396: ! 397: PUSH(5); ! 398: fword("encode-int"); ! 399: push_str("interrupts"); ! 400: fword("property"); ! 401: ! 402: push_str("audio"); ! 403: fword("encode-string"); ! 404: push_str("alias"); ! 405: fword("property"); ! 406: ! 407: fword("finish-device"); ! 408: } ! 409: ! 410: static void ! 411: ob_macio_init(unsigned int slot, uint64_t base, unsigned long offset) ! 412: { ! 413: // All devices were integrated to NCR89C100, see ! 414: // http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt ! 415: ! 416: // NCR 53c9x, aka ESP. See ! 417: // http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt ! 418: #ifdef CONFIG_DRIVER_ESP ! 419: ob_esp_init(slot, base, offset + MACIO_ESP, offset + MACIO_ESPDMA); ! 420: #endif ! 421: ! 422: // NCR 92C990, Am7990, Lance. See http://www.amd.com ! 423: ob_le_init(slot, base, offset + 0x00c00000, offset + 0x00400010); ! 424: ! 425: // Parallel port ! 426: //ob_bpp_init(base); ! 427: } ! 428: ! 429: static void ! 430: sbus_probe_slot_ss5(unsigned int slot, uint64_t base) ! 431: { ! 432: // OpenBIOS and Qemu don't know how to do Sbus probing ! 433: switch(slot) { ! 434: case 3: // SUNW,tcx ! 435: ob_tcx_init(slot, "/iommu/sbus/SUNW,tcx"); ! 436: break; ! 437: case 4: ! 438: // SUNW,CS4231 ! 439: ob_cs4231_init(slot); ! 440: // Power management (APC) ! 441: ob_apc_init(slot, APC_OFFSET); ! 442: break; ! 443: case 5: // MACIO: le, esp, bpp ! 444: ob_macio_init(slot, base, 0x08000000); ! 445: break; ! 446: default: ! 447: break; ! 448: } ! 449: } ! 450: ! 451: static void ! 452: sbus_probe_slot_ss10(unsigned int slot, uint64_t base) ! 453: { ! 454: // OpenBIOS and Qemu don't know how to do Sbus probing ! 455: switch(slot) { ! 456: case 2: // SUNW,tcx ! 457: ob_tcx_init(slot, "/iommu/sbus/SUNW,tcx"); ! 458: break; ! 459: case 0xf: // le, esp, bpp, power-management ! 460: ob_macio_init(slot, base, 0); ! 461: // Power management (APC) XXX should not exist ! 462: ob_apc_init(slot, APC_OFFSET); ! 463: break; ! 464: default: ! 465: break; ! 466: } ! 467: } ! 468: ! 469: static void ! 470: sbus_probe_slot_ss600mp(unsigned int slot, uint64_t base) ! 471: { ! 472: // OpenBIOS and Qemu don't know how to do Sbus probing ! 473: switch(slot) { ! 474: case 2: // SUNW,tcx ! 475: ob_tcx_init(slot, "/iommu/sbus/SUNW,tcx"); ! 476: break; ! 477: case 0xf: // le, esp, bpp, power-management ! 478: #ifdef CONFIG_DRIVER_ESP ! 479: ob_esp_init(slot, base, SS600MP_ESP, SS600MP_ESPDMA); ! 480: #endif ! 481: // NCR 92C990, Am7990, Lance. See http://www.amd.com ! 482: ob_le_init(slot, base, 0x00060000, SS600MP_LEBUFFER); ! 483: // Power management (APC) XXX should not exist ! 484: ob_apc_init(slot, APC_OFFSET); ! 485: break; ! 486: default: ! 487: break; ! 488: } ! 489: } ! 490: ! 491: static void ! 492: ob_sbus_open(void) ! 493: { ! 494: int ret=1; ! 495: RET ( -ret ); ! 496: } ! 497: ! 498: static void ! 499: ob_sbus_close(void) ! 500: { ! 501: selfword("close-deblocker"); ! 502: } ! 503: ! 504: static void ! 505: ob_sbus_initialize(void) ! 506: { ! 507: } ! 508: ! 509: ! 510: NODE_METHODS(ob_sbus_node) = { ! 511: { NULL, ob_sbus_initialize }, ! 512: { "open", ob_sbus_open }, ! 513: { "close", ob_sbus_close }, ! 514: }; ! 515: ! 516: struct sbus_offset { ! 517: int slot, type; ! 518: uint64_t base; ! 519: unsigned long size; ! 520: }; ! 521: ! 522: static const struct sbus_offset sbus_offsets_ss5[SBUS_SLOTS] = { ! 523: { 0, 0, 0x20000000, 0x10000000,}, ! 524: { 1, 0, 0x30000000, 0x10000000,}, ! 525: { 2, 0, 0x40000000, 0x10000000,}, ! 526: { 3, 0, 0x50000000, 0x10000000,}, ! 527: { 4, 0, 0x60000000, 0x10000000,}, ! 528: { 5, 0, 0x70000000, 0x10000000,}, ! 529: }; ! 530: ! 531: /* Shared with ss600mp */ ! 532: static const struct sbus_offset sbus_offsets_ss10[SBUS_SLOTS] = { ! 533: { 0, 0, 0xe00000000ULL, 0x10000000,}, ! 534: { 1, 0, 0xe10000000ULL, 0x10000000,}, ! 535: { 2, 0, 0xe20000000ULL, 0x10000000,}, ! 536: { 3, 0, 0xe30000000ULL, 0x10000000,}, ! 537: [0xf] = { 0xf, 0, 0xef0000000ULL, 0x10000000,}, ! 538: }; ! 539: ! 540: static void ! 541: ob_add_sbus_range(const struct sbus_offset *range, int notfirst) ! 542: { ! 543: if (!notfirst) { ! 544: push_str("/iommu/sbus"); ! 545: fword("find-device"); ! 546: } ! 547: PUSH(range->slot); ! 548: fword("encode-int"); ! 549: if (notfirst) ! 550: fword("encode+"); ! 551: PUSH(range->type); ! 552: fword("encode-int"); ! 553: fword("encode+"); ! 554: PUSH(range->base >> 32); ! 555: fword("encode-int"); ! 556: fword("encode+"); ! 557: PUSH(range->base & 0xffffffff); ! 558: fword("encode-int"); ! 559: fword("encode+"); ! 560: PUSH(range->size); ! 561: fword("encode-int"); ! 562: fword("encode+"); ! 563: } ! 564: ! 565: static int ! 566: ob_sbus_init_ss5(void) ! 567: { ! 568: unsigned int slot; ! 569: int notfirst = 0; ! 570: ! 571: for (slot = 0; slot < SBUS_SLOTS; slot++) { ! 572: if (sbus_offsets_ss5[slot].size > 0) ! 573: ob_add_sbus_range(&sbus_offsets_ss5[slot], notfirst++); ! 574: } ! 575: push_str("ranges"); ! 576: fword("property"); ! 577: ! 578: for (slot = 0; slot < SBUS_SLOTS; slot++) { ! 579: if (sbus_offsets_ss5[slot].size > 0) ! 580: sbus_probe_slot_ss5(slot, sbus_offsets_ss5[slot].base); ! 581: } ! 582: ! 583: return 0; ! 584: } ! 585: ! 586: static int ! 587: ob_sbus_init_ss10(void) ! 588: { ! 589: unsigned int slot; ! 590: int notfirst = 0; ! 591: ! 592: for (slot = 0; slot < SBUS_SLOTS; slot++) { ! 593: if (sbus_offsets_ss10[slot].size > 0) ! 594: ob_add_sbus_range(&sbus_offsets_ss10[slot], notfirst++); ! 595: } ! 596: push_str("ranges"); ! 597: fword("property"); ! 598: ! 599: for (slot = 0; slot < SBUS_SLOTS; slot++) { ! 600: if (sbus_offsets_ss10[slot].size > 0) ! 601: sbus_probe_slot_ss10(slot, sbus_offsets_ss10[slot].base); ! 602: } ! 603: ! 604: return 0; ! 605: } ! 606: ! 607: static int ! 608: ob_sbus_init_ss600mp(void) ! 609: { ! 610: unsigned int slot; ! 611: int notfirst = 0; ! 612: ! 613: for (slot = 0; slot < SBUS_SLOTS; slot++) { ! 614: if (sbus_offsets_ss10[slot].size > 0) ! 615: ob_add_sbus_range(&sbus_offsets_ss10[slot], notfirst++); ! 616: } ! 617: push_str("ranges"); ! 618: fword("property"); ! 619: ! 620: for (slot = 0; slot < SBUS_SLOTS; slot++) { ! 621: if (sbus_offsets_ss10[slot].size > 0) ! 622: sbus_probe_slot_ss600mp(slot, sbus_offsets_ss10[slot].base); ! 623: } ! 624: ! 625: return 0; ! 626: } ! 627: ! 628: int ob_sbus_init(uint64_t base, int machine_id) ! 629: { ! 630: ob_sbus_node_init(base); ! 631: ! 632: switch (machine_id) { ! 633: case 66: ! 634: return ob_sbus_init_ss600mp(); ! 635: case 64 ... 65: ! 636: return ob_sbus_init_ss10(); ! 637: case 32 ... 63: ! 638: return ob_sbus_init_ss5(); ! 639: default: ! 640: return -1; ! 641: } ! 642: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.