root/sys/arch/hpcmips/stand/pbsdboot/disptest.c
/*      $NetBSD: disptest.c,v 1.6 2009/03/18 10:22:29 cegger Exp $      */

/*-
 * Copyright (c) 1999 Shin Takemura.
 * All rights reserved.
 *
 * This software is part of the PocketBSD.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by the PocketBSD project
 *      and its contributors.
 * 4. Neither the name of the project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */
#include <pbsdboot.h>

extern BOOL SetKMode(BOOL);
#define ARRAYSIZEOF(a)  (sizeof(a)/sizeof(*(a)))

static struct area {
  long start, end;
} targets[] = {
        { 0x0a000000, 0x0b000000 },
        { 0x10000000, 0x14000000 },
};
int ntargets = ARRAYSIZEOF(targets);

void
flush_XX(void)
{
  static volatile unsigned char tmp[1024*64];
  int i, s;

  for (i = 0; i < ARRAYSIZEOF(tmp); i++) {
          s += tmp[i];
  }
}

static void
gpio_test(void)
{
#define GIUBASE 0xab000000
#define GIUOFFSET 0x0100
        volatile unsigned short *giusell;
        volatile unsigned short *giuselh;
        volatile unsigned short *giupiodl;
        volatile unsigned short *giupiodh;
        unsigned short sell = 0;
        unsigned short selh = 0;
        unsigned short piodl = 0;
        unsigned short piodh = 0;
        int res, i;
        unsigned short regs[16];
        unsigned short prev_regs[16];

        unsigned char* p = (char*)VirtualAlloc(0, 1024, MEM_RESERVE,
                                      PAGE_NOACCESS);
        res = VirtualCopy((LPVOID)p, (LPVOID)(GIUBASE >> 8), 1024,
                          PAGE_READWRITE|PAGE_NOCACHE|PAGE_PHYSICAL);
        if (!res) {
                win_printf(TEXT("VirtualCopy() failed."));
        }

        for (i = 0; i < 16; i++) {
                prev_regs[i] = ~0;
        }

        giusell = (unsigned short*)(p + GIUOFFSET + 0);
        giuselh = (unsigned short*)(p + GIUOFFSET + 2);
        giupiodl = (unsigned short*)(p + GIUOFFSET + 4);
        giupiodh = (unsigned short*)(p + GIUOFFSET + 6);

        while (1) {
                sell = *giusell;
                selh = *giuselh;
                *giusell = sell;
                *giuselh = selh;

                piodl = *giupiodl;
                piodh = *giupiodh;
                *giupiodl = piodl;
                *giupiodh = piodh;
                for (i = 0; i < 16; i++) {
                        regs[i] = *(unsigned short*)(p + GIUOFFSET + i * 2);
                }
                for (i = 0; i < 16; i++) {
                        if (i != 3 && i != 5 && regs[i] != prev_regs[i]) {
                                win_printf(TEXT("IOSEL=%04x%04x "),
                                           regs[1], regs[0]);
                                win_printf(TEXT("PIOD=%04x%04x "),
                                           regs[3], regs[2]);
                                win_printf(TEXT("STAT=%04x%04x "),
                                           regs[5], regs[4]);
                                win_printf(TEXT("(%04x%04x) "),
                                           regs[5]&regs[7], regs[4]&regs[6]);
                                win_printf(TEXT("EN=%04x%04x "),
                                           regs[7], regs[6]);
                                win_printf(TEXT("TYP=%04x%04x "),
                                           regs[9], regs[8]);
                                win_printf(TEXT("ALSEL=%04x%04x "),
                                           regs[11], regs[10]);
                                win_printf(TEXT("HTSEL=%04x%04x "),
                                           regs[13], regs[12]);
                                win_printf(TEXT("PODAT=%04x%04x "),
                                           regs[15], regs[14]);
                                win_printf(TEXT("\n"));
                                for (i = 0; i < 16; i++) {
                                        prev_regs[i] = regs[i];
                                }
                                break;
                        }
                }
        }
}

static struct regdesc {
        TCHAR *name;
        int physaddr;
        int size;
        int mask;
        //void *addr;
        unsigned long val;
        unsigned long preval;
} test_regs[] = {
#if 0
        /*
         * Vrc4172 GPIO and PWM
         */
        { TEXT("EXGPDATA0"),    0x15001080,     2,      0xfffd          },
        { TEXT("EXGPDATA1"),    0x150010c0,     2,      0xffff          },
        { TEXT("LCDDUTYEN"),    0x15003880,     2,      0xffff          },
        { TEXT("LCDFREQ"),      0x15003882,     2,      0xffff          },
        { TEXT("LCDDUTY"),      0x15003884,     2,      0xffff          },
#endif

#if 0
        /*
         * Vr41xx GPIO
         */
        { TEXT("GIUPIODL"),     0x0b000104,     2,      0xffff          },
        { TEXT("GIUPIODH"),     0x0b000106,     2,      0xffff          },
        { TEXT("GIUPODATL"),    0x0b00011c,     2,      0xffff          },
        { TEXT("GIUPODATH"),    0x0b00011e,     2,      0xffff          },
        { TEXT("GIUUSEUPDN"),   0x0b0002e0,     2,      0xffff          },
        { TEXT("GIUTERMUPDN"),  0x0b0002e2,     2,      0xffff          },
#endif

        /*
         * MQ200
         */
        { TEXT("PM00R"),        0x0a600000,     4,      0xffffffff      },
        { TEXT("PM01R"),        0x0a600004,     4,      0xffffffff      },
        { TEXT("PM02R"),        0x0a600008,     4,      0xffffffff      },
        { TEXT("PM06R"),        0x0a600018,     4,      0xffffffff      },
        { TEXT("PM07R"),        0x0a60001c,     4,      0xffffffff      },

        { TEXT("CC00R"),        0x0a602000,     4,      0x0000003f      },
        { TEXT("CC01R"),        0x0a602004,     4,      0x00000000      },

        { TEXT("MM00R"),        0x0a604000,     4,      0x00000007      },
        { TEXT("MM01R"),        0x0a604004,     4,      0xffffffff      },
        { TEXT("MM02R"),        0x0a604008,     4,      0xffffffff      },
        { TEXT("MM03R"),        0x0a60400c,     4,      0x00000001      },
        { TEXT("MM04R"),        0x0a604010,     4,      0x00000001      },

        { TEXT("IN00R"),        0x0a608000,     4,      0x0000001f      },
        { TEXT("IN01R"),        0x0a608004,     4,      0x0000ffff      },
        { TEXT("IN02R"),        0x0a608008,     4,      0x00000000      },
        { TEXT("IN03R"),        0x0a60800c,     4,      0x00000000      },

        { TEXT("GC00R"),        0x0a60a000,     4,      0xfffff9ff      },
        { TEXT("GC01R"),        0x0a60a004,     4,      0x10ffffff      },
        { TEXT("GC20R"),        0x0a60a080,     4,      0xffffffff      },
        { TEXT("GC21R"),        0x0a60a084,     4,      0x0000007f      },

        { TEXT("FP00R"),        0x0a60e000,     4,      0xffffffff      },
        { TEXT("FP01R"),        0x0a60e004,     4,      0xffffffff      },
        { TEXT("FP02R"),        0x0a60e008,     4,      0x007fffff      },
        { TEXT("FP03R"),        0x0a60e00c,     4,      0x0707003f      },
        { TEXT("FP04R"),        0x0a60e010,     4,      0xffff3fff      },
        { TEXT("FP05R"),        0x0a60e014,     4,      0xffffffff      },
        { TEXT("FP0FR"),        0x0a60e03c,     4,      0xffffffff      },

        { TEXT("DC00R"),        0x0a614000,     4,      0xffffffff      },
        { TEXT("DC01R"),        0x0a614004,     4,      0x0000003f      },
        { TEXT("DC02R"),        0x0a614008,     4,      0xffffffff      },
        { TEXT("DC03R"),        0x0a61400c,     4,      0xffffffff      },

        { TEXT("PC00R"),        0x0a616000,     4,      0xffffffff      },
        { TEXT("PC04R"),        0x0a616004,     4,      0xffffffff      },
        { TEXT("PC08R"),        0x0a616008,     4,      0xffffffff      },
        { TEXT("PC0CR"),        0x0a61600c,     4,      0xffffffff      },
        { TEXT("PC10R"),        0x0a616010,     4,      0xffffffff      },
        { TEXT("PC14R"),        0x0a616014,     4,      0xffffffff      },
        { TEXT("PC2CR"),        0x0a61602c,     4,      0xffffffff      },
        { TEXT("PC3CR"),        0x0a61603c,     4,      0xffffffff      },
        { TEXT("PC40R"),        0x0a616040,     4,      0xffffffff      },
        { TEXT("PC44R"),        0x0a616044,     4,      0x00000003      },
};

extern int SetKMode(int);
static void
regfetch(struct regdesc* desc)
{
        SetKMode(1);
        switch (desc->size) {
        case 1:
                desc->val = *(unsigned char*)(desc->physaddr | 0xa0000000);
                break;
        case 2:
                desc->val = *(unsigned short*)(desc->physaddr | 0xa0000000);
                break;
        case 4:
                desc->val = *(unsigned long*)(desc->physaddr | 0xa0000000);
                break;
        default:
                win_printf(TEXT("Invalid size"));
                break;
        }
        SetKMode(0);
        desc->val &= desc->mask;
}

static void
register_test(void)
{
    int i;
    int nregs = sizeof(test_regs)/sizeof(*test_regs);

    for (i = 0; i < nregs; i++) {
        regfetch(&test_regs[i]);
        test_regs[i].preval = test_regs[i].val;
    }

    while (1) {
        for (i = 0; i < nregs; i++) {
            regfetch(&test_regs[i]);
            if (test_regs[i].val != test_regs[i].preval) {
                win_printf(TEXT("%20s(%08x) %08x -> %08x\n"),
                    test_regs[i].name,
                    test_regs[i].physaddr,
                    test_regs[i].preval,
                    test_regs[i].val);
                test_regs[i].preval = test_regs[i].val;
            }
        }
        Sleep(10); /* 10 msec */
    }
}

static void
dump_memory(void)
{
        HANDLE fh = INVALID_HANDLE_VALUE;
#define UNICODE_MEMORY_CARD \
        TEXT('\\'), 0xff92, 0xff93, 0xff98, TEXT(' '), 0xff76, 0xff70, \
        0xff84, 0xff9e
        TCHAR filename[] = { UNICODE_MEMORY_CARD,  TEXT('2'), TEXT('\\'),
                             TEXT('d'), TEXT('u'),  TEXT('m'), TEXT('p'), 0 };
        unsigned long *addr;
        int found;

        win_printf(TEXT("dump to %s\n"), filename);
        fh = CreateFile(
                filename,       /* file name */
                GENERIC_WRITE,  /* access (read-write) mode */
                FILE_SHARE_WRITE,/* share mode */
                NULL,           /* pointer to security attributes */
                CREATE_ALWAYS,  /* how to create */
                FILE_ATTRIBUTE_NORMAL,  /* file attributes*/
                NULL            /* handle to file with attributes to */
            );
        if (fh == INVALID_HANDLE_VALUE) {
                return;
        }

        for (addr = (unsigned long*)0xbe000000;
            addr < (unsigned long*)0xbfffffff;
            addr += 2048) {
                char buf[2048];
                DWORD n;

                SetKMode(1);
                memcpy(buf, addr, 2048);
                SetKMode(0);
                if (WriteFile(fh, buf, 2048, &n, NULL) == 0 ||
                    n != 2048) {
                        win_printf(TEXT("dump failed\n"));
                        break;
                }
        }

        CloseHandle(fh);
}

static void
serial_test(void)
{
#if 1
#  define SIUADDR 0xac000000
#  define REGOFFSET 0x0
#else
#  define SIUADDR 0xab000000
#  define REGOFFSET 0x1a0
#endif
#define REGSIZE 32
        int i, changed, res;
        unsigned char regs[REGSIZE], prev_regs[REGSIZE];
        unsigned char* p = (char*)VirtualAlloc(0, 1024, MEM_RESERVE,
                                      PAGE_NOACCESS);
        
        for (i = 0; i < ARRAYSIZEOF(prev_regs); i++) {
                prev_regs[i] = ~0;
        }

        res = VirtualCopy((LPVOID)p, (LPVOID)(SIUADDR >> 8), 1024,
                          PAGE_READWRITE|PAGE_NOCACHE|PAGE_PHYSICAL);
        if (!res) {
                win_printf(TEXT("VirtualCopy() failed."));
        }

        while (1) {
                flush_XX();

                for (i = 0; i < ARRAYSIZEOF(regs); i++) {
                        regs[i] = p[REGOFFSET + i];
                }

                changed = 0;
                for (i = 0; i < ARRAYSIZEOF(regs); i++) {
                        if (regs[i] != prev_regs[i]) {
                                changed++;
                        }
                        prev_regs[i] = regs[i];
                }
                if (changed) {
                        win_printf(TEXT("SIU regs: "));
                        for (i = 0; i < ARRAYSIZEOF(regs); i++) {
                                win_printf(TEXT("%02x "), regs[i]);
                        }
                        win_printf(TEXT("\n"));
                }
        }

        VirtualFree(p, 0, MEM_RELEASE);
}

static long
checksum(char* addr, int size)
{
        long sum = 0;
        int i;

        for (i = 0; i < size; i++) {
                sum += *addr++ * i;
        }
        return (sum);
}

static int
examine(char* addr, int size)
{
        long random_data[256];
        long dijest;
        int i;

        for (i = 0; i < ARRAYSIZEOF(random_data); i++) {
                random_data[i] = Random();
        }
        if (sizeof(random_data) < size) {
                size = sizeof(random_data);
        }
        memcpy(addr, (char*)random_data, size);
        dijest= checksum((char*)random_data, size);

        return (dijest == checksum(addr, size));
}

void
display_search(void)
{
        int step = 0x10000;
        int i;
        long addr;

        for (i = 0; i < ntargets; i++) {
                int prevres = -1;
                for (addr = targets[i].start;
                     addr < targets[i].end;
                     addr += step) {
                        int res;
#if 0
                        char* p = (char*)VirtualAlloc(0, step, MEM_RESERVE,
                                                      PAGE_NOACCESS);
                        res = VirtualCopy((LPVOID)p, (LPVOID)(addr >> 8), step,
                                   PAGE_READWRITE|PAGE_NOCACHE|PAGE_PHYSICAL);
                        if (!res) {
                                win_printf(TEXT("VirtualCopy() failed."));
                        }
                        res = examine(p, step);
                        VirtualFree(p, 0, MEM_RELEASE);
#else
                        SetKMode(1);
                        res = examine((char*)((int)addr | 0xa0000000), step);
                        SetKMode(0);
#endif
                        if (res != prevres && prevres != -1) {
                                if (res) {
                                        win_printf(TEXT("0x%x "), addr);
                                } else {
                                        win_printf(TEXT("- 0x%x\n"), addr);
                                }
                        } else
                        if (res && prevres == -1) {
                                win_printf(TEXT("0x%x "), addr);
                        }
                        prevres = res;
                }
                if (prevres) {
                        win_printf(TEXT("\n"));
                }
        }
}

void
display_draw(void)
{
        long addr = 0x13000000;
        int size = 0x80000;
        char* p;
        int i, j, res;
        int x, y;
        int stride = 1280;

        p = (char*)VirtualAlloc(0, size, MEM_RESERVE,
                                PAGE_NOACCESS);
        res = VirtualCopy((LPVOID)p, (LPVOID)(addr >> 8), size,
                          PAGE_READWRITE|PAGE_NOCACHE|PAGE_PHYSICAL);
        if (!res) {
                win_printf(TEXT("VirtualCopy() failed."));
        }

        for (i = 0; i < 10000; i++) {
                p[i] = i;
        }
        for (x = 0; x < 640; x += 10) {
                for (y = 0; y < 240; y += 1) {
                        p[stride * y + x] = (char)0xff;
                }
        }
        for (y = 0; y < 240; y += 10) {
                for (x = 0; x < 640; x += 1) {
                        p[stride * y + x] = (char)0xff;
                }
        }
        for (i = 0; i < 16; i++) {
                for (j = 0; j < 16; j++) {
                        for (x = i * 32; x < i * 32 + 32; x++) {
                                for (y = j * 15; y < j * 15 + 15; y++) {
                                        p[stride * y + x] = j * 16 + i;
                                }
                        }
                }
        }

        VirtualFree(p, 0, MEM_RELEASE);
}

#define PCIC_IDENT              0x00
#define PCIC_REG_INDEX          0
#define PCIC_REG_DATA           1
#define PCIC_IDENT_EXPECTED     0x83

void
pcic_search(void)
{
        long addr;
        int window_size = 0x10000;
        int i;

        for (addr = 0x14000000; addr < 0x18000000; addr += window_size) {
                int res;
                unsigned char* p;
                p = (char*)VirtualAlloc(0, window_size, MEM_RESERVE,
                                        PAGE_NOACCESS);
                res = VirtualCopy((LPVOID)p, (LPVOID)(addr >> 8), window_size,
                                  PAGE_READWRITE|PAGE_NOCACHE|PAGE_PHYSICAL);
                if (!res) {
                        win_printf(TEXT("VirtualCopy() failed."));
                }

                for (i = 0; i < window_size; i += 2) {
                        p[i + PCIC_REG_INDEX] = PCIC_IDENT;
                        if (p[i + PCIC_REG_DATA] == PCIC_IDENT_EXPECTED) {
                                win_printf(TEXT("pcic is found at 0x%x\n"),
                                           addr + i);
                        }
                }

                VirtualFree(p, 0, MEM_RELEASE);
        }
}

#define VRPCIU_CONFA    (*(u_int32_t*)0xaf000c18)
#define VRPCIU_CONFD    (*(u_int32_t*)0xaf000c14)

void
pci_dump(void)
{
        int mode, i;
        BOOL SetKMode(BOOL);
        int bus, dev;
        u_int32_t addr, val;
        u_int32_t addrs[] = {
                0x00000800,
                0x00001000,
                0x00002000,
                0x00004000,
                0x00008000,
                0x00010000,
                0x00020000,
                0x00040000,
                0x00080000,
                0x00100000,
                0x00200000,
                0x00400000,
                0x00800000,
                0x01000000,
                0x02000000,
                0x04000000,
                0x08000000,
                0x10000000,
                0x20000000,
                0x40000000,
                0x80000000,
        };

#if 0 /* You can find Vrc4173 BCU at 0xb6010000 on Sigmarion II */
        win_printf(TEXT("Vrc4173 CMUCLKMSK:     %04X\n"),
            *(u_int16_t*)0xb6010040);
        win_printf(TEXT("Vrc4173 CMUSRST:       %04X\n"),
            *(u_int16_t*)0xb6010042);

        /* enable CARDU clock */
        *(u_int16_t*)0xb6010042 = 0x0006; /* enable CARD1RST and CARD2RST */
        *(u_int16_t*)0xb6010040 = *(u_int16_t*)0xb6010040 | 0x00c0;
        *(u_int16_t*)0xb6010042 = 0x0000; /* disable CARD1RST and CARD2RST */

        win_printf(TEXT("Vrc4173 CMUCLKMSK:     %04X\n"),
            *(u_int16_t*)0xb6010040);
        win_printf(TEXT("Vrc4173 CMUSRST:       %04X\n"),
            *(u_int16_t*)0xb6010042);
#endif

        for (i = 0; i < sizeof(addrs)/sizeof(*addrs); i++) {
                VRPCIU_CONFA = addrs[i];
                val = VRPCIU_CONFD;
                win_printf(TEXT("%2d:   %08X    %04X %04X\n"),
                    i, addrs[i], val & 0xffff, (val >> 16) & 0xffff);
        }

        mode = SetKMode(1);
        SetKMode(mode);
}

void
hardware_test(void)
{
        int do_gpio_test = 0;
        int do_register_test = 0;
        int do_serial_test = 0;
        int do_display_draw = 0;
        int do_display_search = 0;
        int do_pcic_search = 0;
        int do_dump_memory = 0;
        int do_pci_dump = 0;

        if (do_gpio_test) {
                gpio_test();
        }
        if (do_register_test) {
                register_test();
        }
        if (do_serial_test) {
                serial_test();
        }
        if (do_display_draw) {
                display_draw();
        }
        if (do_display_search) {
                display_search();
        }
        if (do_pcic_search) {
                pcic_search();
        }
        if (do_dump_memory) {
                dump_memory();
        }
        if (do_pci_dump) {
                pci_dump();
        }
}