
/*
 *  Dump the VLSI `Golden Gate II' VAS96011/12 Host Bridge Configuration
 *  Registers
 *
 *  (C) Copyright 1998 by Geert Uytterhoeven
 *
 *  This program is subject to the terms and conditions of the GNU General
 *  Public License
 */

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/gg2.h>

#define KB	*(1024)
#define MB	*(1024*1024)
#define GB	*(1024*1024*1024)

typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;


static int io_fd = -1;
static u32 pci_cfg_base;
static u32 gg2_base;


static void open_io(void)
{
    if ((io_fd = open("/dev/mem", O_RDWR)) == -1) {
	perror("open /dev/mem");
	exit(1);
    }
}

static void close_io(void)
{
    if (io_fd != -1) {
	close(io_fd);
	io_fd = -1;
    }
}

static u32 do_mmap(u32 base, u32 size)
{
    u32 res;

    res = (u32)mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, io_fd, base);
    if (res == -1) {
	fprintf(stderr, "mmap 0x%08x: %s", base, strerror(errno));
	exit(1);
    }
    return res;
}

static void do_munmap(u32 addr, u32 size)
{
    if (addr != -1)
	munmap((caddr_t)addr, size);
}

static u8 dump8(u32 offset, const char *s)
{
    u8 res = in_8((unsigned char *)(gg2_base+offset));
    printf("%02x:       0x%02x %s\n", offset, res, s);
    return res;
}

static u16 dump16(u32 offset, const char *s)
{
    u16 res = in_le16((unsigned short *)(gg2_base+offset));
    printf("%02x:     0x%04x %s\n", offset, res, s);
    return res;
}

static u32 dump32(u32 offset, const char *s)
{
    u32 res = in_le32((unsigned *)(gg2_base+offset));
    printf("%02x: 0x%08x %s\n", offset, res, s);
    return res;
}

static void dump_enable(const char *s, u32 t32, u32 bit)
{
    printf("    %s: %sabled\n", s, t32 & (1<<bit) ? "En" : "Dis");
}

static void dump_notify(const char *s, u32 t32, u32 bit)
{
    printf("    %s: %sotify\n", s, t32 & (1<<bit) ? "N" : "Do not n");
}

static void dump_error(const char *s, u32 t32, u32 bit)
{
    printf("    %s: %sError\n", s, t32 & (1<<bit) ? "" : "No ");
}

static void dump_dram_bank(int bank, u32 t32)
{
    int i;

    i = (t32>>16) & 0x3ff;
    printf("    DRAM bank #%d base address: 0x%08x\n", bank, i<<22);
    printf("    DRAM bank #%d timing set: %d\n", bank, (t32>>13) & 1);
    printf("    DRAM bank #%d size: ", bank);
    switch ((t32>>8) & 0x1f) {
	case 0x1f:
	    puts("4 MB");
	    break;
	case 0x1e:
	    puts("8 MB");
	    break;
	case 0x1c:
	    puts("16 MB");
	    break;
	case 0x18:
	    puts("32 MB");
	    break;
	case 0x10:
	    puts("64 MB");
	    break;
	case 0x00:
	    puts("128 MB");
	    break;
	default:
	    puts("Reserved");
	    break;
    }
    printf("    DRAM bank #%d chip geometry: ", bank);
    if (((t32>>1) & 3) != 1)
	switch ((t32>>4) & 15) {
	    case 0:
		puts("9R x 9C");
		break;
	    case 1:
		puts("10R x 9C");
		break;
	    case 2:
		puts("13R x 9C");
		break;
	    case 3:
		puts("10R x 10C");
		break;
	    case 4:
		puts("11R x 10C");
		break;
	    case 5:
		puts("12R x 10C / 13R x 10C");
		break;
	    case 7:
		puts("11R x 11C");
		break;
	    case 8:
		puts("12R x 12C");
		break;
	    case 10:
		puts("10R x 8C");
		break;
	    case 11:
		puts("12R x 8C");
		break;
	    case 12:
		puts("12R x 11C / 13R x 11C");
		break;
	    default:
		puts("Reserved");
	}
    else
	switch ((t32>>4) & 15) {
	    case 2:
		puts("12R x 9C");
		break;
	    case 5:
		puts("12R x 10C");
		break;
	    case 11:
		puts("12R x 8C");
		break;
	    case 13:
		puts("14R x 9C");
		break;
	    case 14:
		puts("14R x 8C");
		break;
	    case 15:
		puts("14R x 7C");
		break;
	    default:
		puts("Reserved");
	}
    printf("    DRAM bank #%d chip type (don't care if SDRAM controller is "
	   "enabled): ", bank);
    switch ((t32>>1) & 3) {
	case 0:
	    puts("Fast-page Mode");
	    break;
	case 1:
	    puts("SDRAM");
	    break;
	case 2:
	    puts("EDO");
	    break;
	case 3:
	    puts("Burst EDO");
	    break;
    }
    printf("    DRAM bank #%d: %sabled\n", bank, t32 & 1 ? "En" : "Dis");
}

static void dump_dram_time(int set, u32 t32)
{
    int i;

    if (set == 0)
	printf("    DRAM timing RAS precharge time: %d clocks\n",
	       ((t32>>21) & 7)+2);

    puts("    DRAM:");
    printf("      DRAM timing set #%d row address setup time: %d clocks\n",
	   set, ((t32>>30) & 1)+1);
    printf("      DRAM timing set #%d row address hold time: %d clocks\n", set,
	   ((t32>>28) & 3)+1);
    if (set == 0)
	printf("      DRAM timing column address setup time: %d clocks\n",
	       ((t32>>26) & 3)+1);
    printf("      DRAM timing set #%d column address hold time: %d clocks\n",
	   set, ((t32>>25) & 1)+1);
    printf("      DRAM timing set #%d CAS precharge time: %d clocks\n", set,
	   ((t32>>24) & 1)+1);
    printf("      DRAM timing set #%d CAS pulse width: %d clocks\n", set,
	   ((t32>>19) & 3)+1);
    printf("      DRAM timing set #%d RAS pulse width: %d clocks\n", set,
	   ((t32>>15) & 15)+1);
    printf("      DRAM timing set #%d MD hold time: %d clocks\n", set,
	   ((t32>>14) & 1)+1);
    printf("      DRAM timing set #%d MD access time: %d clocks\n", set,
	   ((t32>>12) & 3)+2);
    printf("      DRAM timing set #%d CAS to RAS setup time: %d clocks\n", set,
	   ((t32>>11) & 1)+1);
    printf("      DRAM timing set #%d CAS hold time: %d clocks\n", set,
	   ((t32>>10) & 1)+1);
    if (set == 0)
	printf("      DRAM timing MWE to CAS setup time: %d clocks\n",
	       ((t32>>9) & 1)+1);
    printf("      DRAM timing set #%d RAS kept asserted after end of "
	   "transaction: ", set);
    i = ((t32>>2)&7);
    if (i != 7)
	printf("%d clocks\n", i*4);
    else
	puts("Indefinite");

    puts("    SDRAM:");
    printf("      DRAM timing set #%d RAS to CAS delay: %d clocks\n", set,
	   ((t32>>28) & 3)+1);
    if (set == 0)
	printf("      DRAM timing write recovery time: %d clocks\n",
	       ((t32>>26) & 3)+1);
    printf("      DRAM timing set #%d RAS pulse width: ", set);
    switch ((t32>>15) & 15) {
	case 0:
	    puts("1 clock");
	    break;
	case 1:
	    puts("2 clocks");
	    break;
	case 2:
	    puts("3 clocks");
	    break;
	case 3:
	    puts("4 clocks");
	    break;
	case 4:
	    puts("5 clocks");
	    break;
	default:
	    puts("Reserved");
    }
    printf("      DRAM timing set #%d RAS kept asserted after end of "
	   "transaction: %s\n", set, ((t32>>2) & 7) == 0 ? "0 clocks"
							 : "Indefinite");
}

static void dump_gg2_pci_cfg(void)
{
    u8 t8;
    u16 t16;
    u32 t32;

    puts("");
    puts("***************** PCI Configuration Registers ******************");
    puts("");
    dump16(PCI_VENDOR_ID, "Vendor ID (0x1004)");
    dump16(PCI_DEVICE_ID, "Device ID (0x0702)");
    t16 = dump16(PCI_COMMAND, "Command (default: 0x0004)");
    if (t16 & PCI_COMMAND_IO)
    if (t16 & PCI_COMMAND_IO)
	puts("    Enable response in I/O space");
    if (t16 & PCI_COMMAND_MEMORY)
	puts("    Enable response in Memory space");
    if (t16 & PCI_COMMAND_MASTER)
	puts("    Enable bus mastering");
    if (t16 & PCI_COMMAND_SPECIAL)
	puts("    Enable response to special cycles");
    if (t16 & PCI_COMMAND_INVALIDATE)
	puts("    Use memory write and invalidate");
    if (t16 & PCI_COMMAND_VGA_PALETTE)
	puts("    Enable palette snooping");
    if (t16 & PCI_COMMAND_PARITY)
	puts("    Enable parity checking");
    if (t16 & PCI_COMMAND_WAIT)
	puts("    Enable address/data stepping");
    if (t16 & PCI_COMMAND_SERR)
	puts("    Enable system error");
    if (t16 & PCI_COMMAND_FAST_BACK)
	puts("    Enable back-to-back writes");
    t16 = dump16(PCI_STATUS, "Status (default: 0x0680)");
    if (t16 & PCI_STATUS_66MHZ)
	puts("    Support 66 Mhz PCI 2.1 bus");
    if (t16 & PCI_STATUS_UDF)
	puts("    Support User Definable Features");
    if (t16 & PCI_STATUS_FAST_BACK)
	puts("    Accept fast-back to back");
    if (t16 & PCI_STATUS_PARITY)
	puts("    Detected parity error");
    printf("    DEVSEL timing: ");
    switch (t16 & PCI_STATUS_DEVSEL_MASK) {
	case PCI_STATUS_DEVSEL_FAST:
	    puts("Fast");
	    break;
	case PCI_STATUS_DEVSEL_MEDIUM:
	    puts("Medium");
	    break;
	case PCI_STATUS_DEVSEL_SLOW:
	    puts("Slow");
	    break;
	default:
	    puts("Reserved");
	    break;
    }
    if (t16 & PCI_STATUS_SIG_TARGET_ABORT)
	puts("    Target abort");
    if (t16 & PCI_STATUS_REC_TARGET_ABORT)
	puts("    Master ack off");
    if (t16 & PCI_STATUS_REC_MASTER_ABORT)
	puts("    Master abort");
    if (t16 & PCI_STATUS_SIG_SYSTEM_ERROR)
	puts("    System error");
    if (t16 & PCI_STATUS_DETECTED_PARITY)
	puts("    Parity error");

    t32 = dump32(PCI_CLASS_REVISION, "Class / Revision");
    printf("    Class: 0x%06x (0x060000)\n", (t32>>8) & 0xffffff);
    printf("    Revision: ");
    switch (t32 & 0xff) {
	case 0x11:
	    puts("VAS96011-P2");
	    break;
	case 0x14:
	    puts("VAS96011-P4");
	    break;
	case 0x04:
	    puts("VAS96011-5");
	    break;
	default:
	    puts("Unknown");
	    break;
    }
    t8 = dump8 (PCI_CACHE_LINE_SIZE, "Cache Line Size (default: 0x08)");
    switch (t8) {
	case 1:
	    puts("    4 bytes");
	    break;
	case 2:
	    puts("    8 bytes");
	    break;
	case 4:
	    puts("    16 bytes");
	    break;
	case 8:
	    puts("    32 bytes");
	    break;
	default:
	    puts("    Unknown");
	    break;
    }
    dump8 (PCI_LATENCY_TIMER, "Latency Timer (default: 0x00)");
    dump8 (PCI_HEADER_TYPE, "Header Type (0x00)");
    dump8 (PCI_BIST, "BIST (0x00)");
    dump32(PCI_BASE_ADDRESS_0, "Base Address 0 (0x00000000)");
    dump32(PCI_BASE_ADDRESS_1, "Base Address 1 (0x00000000)");
    dump32(PCI_BASE_ADDRESS_2, "Base Address 2 (0x00000000)");
    dump32(PCI_BASE_ADDRESS_3, "Base Address 3 (0x00000000)");
    dump32(PCI_BASE_ADDRESS_4, "Base Address 4 (0x00000000)");
    dump32(PCI_BASE_ADDRESS_5, "Base Address 5 (0x00000000)");
    dump32(PCI_CARDBUS_CIS, "Cardbus CIS (0x00000000)");
    dump16(PCI_SUBSYSTEM_ID, "Subsystem ID (0x0000)");
    dump16(PCI_SUBSYSTEM_VENDOR_ID, "Subsystem Vendor ID (0x0000)");
    dump32(PCI_ROM_ADDRESS, "ROM Address (0x00000000)");
    dump32(0x34, "(0x00000000)");
    dump32(0x38, "(0x00000000)");
    dump8 (PCI_INTERRUPT_LINE, "Interrupt Line (0x00)");
    dump8 (PCI_INTERRUPT_PIN, "Interrupt Pin (0x00)");
    dump8 (PCI_MIN_GNT, "Minimum Grant (0x00)");
    dump8 (PCI_MAX_LAT, "Maximum Latency (0x00)");
    dump8 (GG2_PCI_BUSNO, "Bus Number (default: 0x00)");
    dump8 (GG2_PCI_SUBBUSNO, "Subordinate Bus Number (default: 0x00)");
    dump8 (GG2_PCI_DISCCTR, "Disconnect Counter (0x00)");
    dump8 (0x43, "(0x00)");
    dump32(0x44, "(0x00000000)");
    dump32(0x48, "(0x00000000)");
    dump32(0x4c, "(0x00000000)");

}

static void dump_gg2_ppc_if(void)
{
    u32 t32;

    puts("");
    puts("***************** PowerPC Interface Registers ******************");
    puts("");
    t32 = dump32(GG2_PCI_PPC_CTRL, "PPC Interface Control");
    printf("    Snoop Type: %s\n", (t32>>27) & 1 ? "Address-only"
						 : "Single Beat Access");
    if ((t32>>17) & 0x1ff)
	printf("    Timeout Count: %d\n", (t32>>17) & 0x1ff);
    else
	printf("    Timeout Count: Disabled\n");
    printf("    Endianness: %s\n", (t32>>16) & 1 ? "Little" : "Big");
    printf("    Allowed CPU cycles while pending PCI-to-memory cycle: ");
    switch ((t32>>4) & 3) {
	case 0:
	case 1:
	    puts("Disabled");
	    break;
	case 2:
	    puts("5");
	    break;
	case 3:
	    puts("10");
	    break;
    }
    dump_enable("Fast L2 and NO DRTRY", t32, 3);
    dump_enable("Arbiter Pipeline", t32, 2);
    dump_enable("Internal Arbiter", t32, 0);
    dump32(0x54, "(0x00000000)");
    dump32(0x58, "(0x00000000)");
}

static void dump_gg2_addr_map(void)
{
    u32 t32;

    puts("");
    puts("********************* Address Map Register *********************");
    puts("");
    t32 = dump32(GG2_PCI_ADDR_MAP, "Address Map");
    printf("    Top of emulated memory: 0x%03x MB\n", (t32>>17) & 0xfff);
    dump_enable("CHRP PC emulation", t32, 16);
    dump_enable("PReP ISA master fix", t32, 6);
    dump_enable("Discontiguous ISA I/O", t32, 5);
    dump_enable("CHRP system memory alias and peripheral memory alias options",
		t32, 4);
    dump_enable("CHRP processor hole", t32, 3);
    dump_enable("CHRP I/O hole", t32, 2);
    printf("    Address map: %s\n", t32 & 1 ? "PReP" : "CHRP");

}

static void dump_gg2_pci_if(void)
{
    u32 t32;
    int i;

    puts("");
    puts("******************* PCI Interface Registers ********************");
    puts("");
    t32 = dump32(GG2_PCI_PCI_CTRL, "PCI Interface Control");
    printf("    PCI clock: %sychronous\n", (t32>>30) & 1 ? "S" : "As");
    printf("    Frame buffer size: %d MB\n", (1 << ((t32>>28) & 3)));
    printf("    Frame buffer base: +0x%03x MB\n", (t32>>18) & 0xfff);
    dump_enable("Frame buffer byte-merging", t32, 17);
    dump_enable("Word-combining", t32, 16);
    dump_enable("PCI transaction snooping", t32, 13);
    dump_enable("Prefetch from PCI slaves in frame buffer range", t32, 12);
    dump_enable("Prefetch from PCI memory", t32, 11);
    printf("    Timeout for first data-beat: %d PCI clocks\n",
	   (t32>>10) & 1 ? 32 : 16);
    dump_enable("PCI Bus Read streaming from memory", t32, 5);
    i = (t32>>3) & 3 ? 16*((t32>>3) & 3) : 255;
    printf("    Number of retries before target abort: %d\n", i);
    dump32(0x64, "(0x00000000)");
    dump32(0x68, "(0x00000000)");
    dump32(0x6c, "(0x00000000)");
}

static void dump_gg2_rom_ctrl(void)
{
    u32 t32;
    int i;

    puts("");
    puts("******************* ROM Controller Registers *******************");
    puts("");
    t32 = dump32(GG2_PCI_ROM_CTRL, "ROM Interface Control");
    i = ((t32>>24) & 0xff);
    if (i)
	i <<= 2;
    else
	i = 1<<10;
    printf("    ROM bank 1 shadow size: 0x%03x KB\n", i);
    printf("    ROM shadow base address: 0x%08x\n", ((i>>14) & 0x3ff)<<20);
    printf("    ROM bank 0 shadow size: 0x%03x KB\n", (t32>>13) & 1 ? 8192
								    : 4096);
    switch ((t32>>11) & 3) {
	case 0:
	    i = 16;
	    break;
	case 1:
	    i = 8;
	    break;
	case 2:
	    i = 64;
	    break;
	case 3:
	    i = 32;
	    break;
    }
    printf("    ROM bank 1 width: %d bit\n", i);
    dump_enable("Flash ROM bank 1 write", t32, 10);
    printf("    ROM bank 0 operating mode: ");
    switch ((t32>>8) & 3) {
	case 0:
	    puts("Disabled");
	    break;
	case 1:
	    puts("Enabled");
	    break;
	case 2:
	    puts("Shadow");
	    break;
	case 3:
	    puts("Shadow Program");
	    break;
    }
    switch ((t32>>3) & 3) {
	case 0:
	    i = 16;
	    break;
	case 1:
	    i = 8;
	    break;
	case 2:
	    i = 64;
	    break;
	case 3:
	    i = 32;
	    break;
    }
    printf("    ROM bank 0 width: %d bit\n", i);
    dump_enable("Flash ROM bank 0 write", t32, 2);
    printf("    ROM bank 0 operating mode: ");
    switch (t32 & 3) {
	case 0:
	    puts("Disabled");
	    break;
	case 1:
	    puts("Enabled");
	    break;
	case 2:
	    puts("Shadow");
	    break;
	case 3:
	    puts("Shadow Program");
	    break;
    }

    t32 = dump32(GG2_PCI_ROM_TIME, "ROM Timing");
    i = (t32>>24) & 15;
    if (i)
	i += 3;
    else
	i = 19;
    printf("    ROM bank 1 access time for 2nd to last data beat: %d clocks\n",
	   i);
    i = (t32>>20) & 15;
    if (i)
	i += 6;
    else
	i = 22;
    printf("    ROM bank 1 access time for first data beat: %d clocks\n", i);
    i = (t32>>17) & 7;
    if (i)
	i += 2;
    else
	i = 13;
    printf("    ROM bank 1 off time: %d clocks\n", i);
    i = (t32>>8) & 15;
    if (i)
	i += 3;
    else
	i = 19;
    printf("    ROM bank 0 access time for 2nd to last data beat: %d clocks\n",
	   i);
    i = (t32>>4) & 15;
    if (i)
	i += 6;
    else
	i = 22;
    printf("    ROM bank 0 access time for first data beat: %d clocks\n", i);
    i = (t32>>1) & 7;
    if (i)
	i += 2;
    else
	i = 13;
    printf("    ROM bank 0 off time: %d clocks\n", i);
    dump32(0x78, "(0x00000000)");
    dump32(0x7c, "(0x00000000)");

}

static void dump_gg2_cache_ctrl(void)
{
    u32 t32;
    int i;

    puts("");
    puts("****************** Cache Controller Registers ******************");
    puts("");
    t32 = dump32(GG2_PCI_CC_CTRL, "Cache Controller Control");
    printf("    Tag pattern for invalid lines: 0x%03x\n", (t32>>16) & 0x3ff);
    dump_enable("ROM caching", t32, 15);
    printf("    Write-back policy for dirty write misses: %s\n",
	   (t32>>14) & 1 ? "Immediate" : "Deferred");
    printf("    Write-back policy for dirty read misses: %s\n",
	   (t32>>13) & 1 ? "Immediate" : "Deferred");
    i = (t32>>7) & 3;
    printf("    Tag mask: ");
    switch ((t32>>9) & 15) {
	case 0:
	    switch (i) {
		case 0:
		    puts("256K/8 bit tag");
		    break;
		case 1:
		    puts("512K/7 bit tag");
		    break;
		default:
		    goto unknown_tag_mask;
	    }
	    break;
	case 1:
	    switch (i) {
		case 0:
		    puts("256K/9 bit tag");
		    break;
		case 1:
		    puts("512K/8 bit tag");
		    break;
		case 2:
		    puts("1M/7 bit tag");
		    break;
		default:
		    goto unknown_tag_mask;
	    }
	    break;
	case 3:
	    switch (i) {
		case 0:
		    puts("256K/10 bit tag");
		    break;
		case 1:
		    puts("512K/9 bit tag");
		    break;
		case 2:
		    puts("1M/8 bit tag");
		    break;
		default:
		    goto unknown_tag_mask;
	    }
	    break;
	case 7:
	    switch (i) {
		case 1:
		    puts("512K/10 bit tag");
		    break;
		case 2:
		    puts("1M/9 bit tag");
		    break;
		default:
		    goto unknown_tag_mask;
	    }
	    break;
	case 15:
	    switch (i) {
		case 2:
		    puts("1M/8 bit tag");
		    break;
		default:
		    goto unknown_tag_mask;
	    }
	    break;
	default:
unknown_tag_mask:
	    puts("Unknown");
    }
    printf("    Cache size: ");
    switch (i) {
	case 0:
	    puts("256 KB");
	    break;
	case 1:
	    puts("512 KB");
	    break;
	case 2:
	    puts("1 MB");
	    break;
	default:
	    puts("Reserved");
	    break;
    }
    printf("    Tag SRAM access time: %c 15 s\n", (t32>>5) & 1 ? '>' : '<');
    printf("    Data SRAM type: ");
    switch ((t32>>2) & 3) {
	case 0:
	    puts("Asynchronous");
	    break;
	case 1:
	    puts("Reserved");
	    break;
	case 2:
	    puts("Flow-thru synchronous");
	    break;
	case 3:
	    puts("Pipelined Synchronous");
	    break;
    }
    printf("    Cache mode: ");
    switch (t32 & 3) {
	case 0:
	    puts("Off");
	    break;
	case 1:
	    puts("Write-thru");
	    break;
	case 2:
	    puts("Copy-back");
	    break;
	case 3:
	    puts("Transparent Mode");
	    break;
    }
    dump32(0x84, "(0x00000000)");
    dump32(0x88, "(0x00000000)");
    dump32(0x8c, "(0x00000000)");
}

static void dump_gg2_dram_ctrl(void)
{
    u32 t32;
    int i;

    puts("");
    puts("****************** DRAM Controller Registers *******************");
    puts("");
    t32 = dump32(GG2_PCI_DRAM_BANK0, "DRAM Bank #0 Control");
    dump_dram_bank(0, t32);
    t32 = dump32(GG2_PCI_DRAM_BANK1, "DRAM Bank #1 Control");
    dump_dram_bank(1, t32);
    t32 = dump32(GG2_PCI_DRAM_BANK2, "DRAM Bank #2 Control");
    dump_dram_bank(2, t32);
    t32 = dump32(GG2_PCI_DRAM_BANK3, "DRAM Bank #3 Control");
    dump_dram_bank(3, t32);
    t32 = dump32(GG2_PCI_DRAM_BANK4, "DRAM Bank #4 Control");
    dump_dram_bank(4, t32);
    t32 = dump32(GG2_PCI_DRAM_BANK5, "DRAM Bank #5 Control");
    dump_dram_bank(5, t32);
    dump32(0xa8, "(0x00000000)");
    dump32(0xac, "(0x00000000)");
    t32 = dump32(GG2_PCI_DRAM_TIME0, "DRAM Timing Set #0");
    dump_dram_time(0, t32);
    t32 = dump32(GG2_PCI_DRAM_TIME1, "DRAM Timing Set #1");
    dump_dram_time(1, t32);
    dump32(0xb8, "(0x00000000)");
    dump32(0xbc, "(0x00000000)");
    t32 = dump32(GG2_PCI_DRAM_CTRL, "DRAM Control");
    dump_enable("SDRAM controller", t32, 31);
    printf("    SDRAM controller reset: %s\n", (t32>>30) & 1 ? "Reset SDRAM"
							     : "No Action");
    printf("    SDRAM controller 2N rule: %sEnforced\n", 
	   (t32>>29) & 1 ? "" : "Not ");
    printf("    SDRAM controller CAS latency: %d clocks\n", ((t32>>28) & 1)+2);
    printf("    SDRAM controller refresh cycle time: ");
    i = (t32>>25) & 7;
    if (i < 6)
	printf("%d clocks\n", i+5);
    else
	puts("Reserved");
    dump_enable("SDRAM early SDCKE", t32, 24);
    dump_enable("SDRAM clock 2", t32, 23);
    printf("    CAS lines: Gating %s\n", (t32>>20) & 1 ? "On (Test)"
						       : "Off (ormal)");
    dump_enable("Read latch bypass for DRAM reads", t32, 17);
    printf("    DRAM refresh recovery when exiting from self-refresh: %d "
	   "cycles\n", ((t32>>10) & 31)*512);
    printf("    DRAM refresh interval between succesive refresh cycles: %d "
	   "clocks\n", ((t32>>6) & 15)*256);
    printf("    DRAM refresh staggering mode: ");
    switch ((t32>>4) & 3) {
	case 0:
	    puts("All banks at the same time");
	    break;
	case 1:
	    puts("1 bank at a time");
	    break;
	case 2:
	    puts("2 banks at a time");
	    break;
	case 3:
	    puts("Reserved");
	    break;
    }
    printf("    DRAM refresh type: ");
    switch ((t32>>2) & 3) {
	case 0:
	    puts("CBR refresh");
	    break;
	case 1:
	    puts("Slow refresh");
	    break;
	case 2:
	    puts("Self refresh");
	    break;
	case 3:
	    puts("Disabled");
	    break;
    }
    printf("    DRAM parity check/generate: %sParity\n", (t32>>31) & 1 ? ""
								       : "No");

    dump32(0xc4, "(0x00000000)");
    dump32(0xc8, "(0x00000000)");
    dump32(0xcc, "(0x00000000)");
}

static void dump_gg2_error(void)
{
    u32 t32;

    puts("");
    puts("*********************** Error Registers ************************");
    puts("");
    t32 = dump32(GG2_PCI_ERR_CTRL, "Error Control");
    dump_enable("General enable for MCP interrupts", t32, 31);
    printf("    NMI forwarding: %sorward\n", ((t32>>28) & 1) ? "F"
							     : "Do not f");
    dump_notify("PowerPC shadow overwrite", t32, 25);
    dump_notify("PowerPC bus timeout error", t32, 24);
    dump_notify("DRAM out of bounds access error for PCI masters", t32, 18);
    dump_notify("DRAM out of bounds access error for PowerPC masters", t32, 17);
    dump_notify("DRAM parity error", t32, 16);
    dump_notify("PCI system error", t32, 9);
    dump_notify("PCI bus retry timeout error", t32, 7);
    dump_notify("PCI general parity error", t32, 6);
    dump_notify("PCI master abort error", t32, 2);
    dump_notify("PCI target abort error", t32, 1);
    t32 = dump32(GG2_PCI_ERR_STATUS, "Error Status");
    dump_error("NMI flag", t32, 28);
    dump_error("PowerPC shadow overwrite", t32, 25);
    dump_error("PowerPC bus timeout error", t32, 24);
    dump_error("DRAM out of bounds access error for PCI masters", t32, 18);
    dump_error("DRAM out of bounds access error for PowerPC masters", t32, 17);
    dump_error("DRAM parity error", t32, 16);
    dump_error("PCI system error", t32, 9);
    dump_error("PCI bus retry timeout error", t32, 7);
    dump_error("PCI general parity error", t32, 6);
    dump_error("PCI master parity error", t32, 5);
    dump_error("PCI target parity error", t32, 4);
    dump_error("PCI address parity error", t32, 3);
    dump_error("PCI master abort error", t32, 2);
    dump_error("PCI target abort error", t32, 1);
    dump32(0xd8, "(0x00000000)");
    dump32(0xdc, "(0x00000000)");
    dump32(0xe8, "(0x00000000)");
    dump32(0xec, "(0x00000000)");
    dump32(0xe8, "(0x00000000)");
    dump32(0xec, "(0x00000000)");
    dump32(0xf8, "(0x00000000)");
    dump32(0xfc, "(0x00000000)");
    dump32(0xf8, "(0x00000000)");
    dump32(0xfc, "(0x00000000)");
}

static void dump_gg2(void)
{
    dump_gg2_pci_cfg();
    dump_gg2_ppc_if();
    dump_gg2_addr_map();
    dump_gg2_pci_if();
    dump_gg2_rom_ctrl();
    dump_gg2_cache_ctrl();
    dump_gg2_dram_ctrl();
    dump_gg2_error();
}


int main(int argc, char *argv[])
{
    open_io();
    pci_cfg_base = do_mmap(GG2_PCI_CONFIG_BASE, 512 KB);
    gg2_base = pci_cfg_base;
    dump_gg2();
    do_munmap(pci_cfg_base, 512 KB);
    close_io();
    exit(0);
}
