SvgaLib/obsolete/mach/mach32info.c

1123 lines
37 KiB
C
Raw Permalink Normal View History

/* mach32info.c prints out some info about your mach32card */
/* Please report the info it produces if the mach32driver of svgalib */
/* works not like expected. */
/* This tool is part of svgalib. Although it's output maybe useful to */
/* debug Xfree86 Mach32 Servers, I am NOT related to Xfree86!! */
/* PLEASE DO NOT SEND ME (MICHAEL WELLER) ANY XFREE86 BUG REPORTS!!! */
/* Thanx in advance. */
/* This tool is free software; you can redistribute it and/or */
/* modify it without any restrictions. This tool is distributed */
/* in the hope that it will be useful, but without any warranty. */
/* Copyright 1994 by Michael Weller */
/* eowmob@exp-math.uni-essen.de mat42b@aixrs1.hrz.uni-essen.de */
/* eowmob@pollux.exp-math.uni-essen.de */
/*
* MICHAEL WELLER DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL MICHAEL WELLER BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
/* This tool contains one routine out of Xfree86, therefore I repeat */
/* its copyright here: (Actually it is longer than the copied code) */
/*
* Copyright 1992 by Orest Zborowski <obz@Kodak.com>
* Copyright 1993 by David Wexelblat <dwex@goblin.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the names of Orest Zborowski and David Wexelblat
* not be used in advertising or publicity pertaining to distribution of
* the software without specific, written prior permission. Orest Zborowski
* and David Wexelblat make no representations about the suitability of this
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*
* OREST ZBOROWSKI AND DAVID WEXELBLAT DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL OREST ZBOROWSKI OR DAVID WEXELBLAT BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
* Copyright 1993 by Kevin E. Martin, Chapel Hill, North Carolina.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Thomas Roell not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Thomas Roell makes no representations
* about the suitability of this software for any purpose. It is provided
* "as is" without express or implied warranty.
*
* THOMAS ROELL, KEVIN E. MARTIN, AND RICKARD E. FAITH DISCLAIM ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE AUTHORS
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Thomas Roell, roell@informatik.tu-muenchen.de
*
* Rewritten for the 8514/A by Kevin E. Martin (martin@cs.unc.edu)
* Modified for the Mach-8 by Rickard E. Faith (faith@cs.unc.edu)
* Rewritten for the Mach32 by Kevin E. Martin (martin@cs.unc.edu)
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
/* Some stuff for the ATI VGA */
#define ATIPORT 0x1ce
#define ATIOFF 0x80
#define ATISEL(reg) (ATIOFF+reg)
/* Ports we use: */
#define SUBSYS_CNTL 0x42E8
#define GE_STAT 0x9AE8
#define CONF_STAT1 0x12EE
#define CONF_STAT2 0x16EE
#define MISC_OPTIONS 0x36EE
#define MEM_CFG 0x5EEE
#define MEM_BNDRY 0x42EE
#define SCRATCH_PAD_0 0x52EE
#define DESTX_DIASTP 0x8EE8
#define R_SRC_X 0xDAEE
#define R_EXT_GE_CONF 0x8EEE
#define CHIP_ID 0xFAEE
#define MAX_WAITSTATES 0x6AEE
#define LOCAL_CNTL 0x32EE
#define R_MISC_CNTL 0x92EE
#define PCI_CNTL 0x22EE
#define DISP_STATUS 0x2E8
#define DISP_CNTL 0x22E8
#define CLOCK_SEL 0x4AEE
#define H_DISP 0x06E8
#define H_TOTAL 0x02E8
#define H_SYNC_WID 0x0EE8
#define H_SYNC_STRT 0x0AE8
#define V_DISP 0x16E8
#define V_SYNC_STRT 0x1AE8
#define V_SYNC_WID 0x1EE8
#define V_TOTAL 0x12E8
#define R_H_TOTAL 0xB2EE
#define R_H_SYNC_STRT 0xB6EE
#define R_H_SYNC_WID 0xBAEE
#define R_V_TOTAL 0xC2EE
#define R_V_DISP 0xC6EE
#define R_V_SYNC_STRT 0xCAEE
#define R_V_SYNC_WID 0xD2EE
/* Bit masks: */
#define GE_BUSY 0x0200
/* Chip_id's */
#define ATI68800_3 ('A'*256+'A')
#define ATI68800_6 ('X'*256+'X')
#define ATI68800_6HX ('H'*256+'X')
#define ATI68800LX ('L'*256+'X')
#define ATI68800AX ('A'*256+'X')
static inline void port_out(int value, int port)
{
__asm__ volatile ("outb %0,%1"
::"a" ((unsigned char) value), "d"((unsigned short) port));
}
static inline void port_outw(int value, int port)
{
__asm__ volatile ("outw %0,%1"
::"a" ((unsigned short) value), "d"((unsigned short) port));
}
static inline int port_in(int port)
{
unsigned char value;
__asm__ volatile ("inb %1,%0"
:"=a" (value)
:"d"((unsigned short) port));
return value;
}
static inline int port_inw(int port)
{
unsigned short value;
__asm__ volatile ("inw %1,%0"
:"=a" (value)
:"d"((unsigned short) port));
return value;
}
#define inb port_in
#define inw port_inw
#define outb(port, value) port_out(value, port)
#define outw(port, value) port_outw(value, port)
int force = 0, chip_id, bus;
unsigned short eeprom[128];
char *pel_width[] =
{" 4bpp", " 8bpp", " 16bpp", " 24bpp"};
char *bpp16mode[] =
{" 5-5-5", " 5-6-5", " 6-5-5", " 6-6-4"};
char *bpp24mode[] =
{" RGB", " RGBa", " BGR", " aBGR"};
char *bustype[] =
{" 16-bit ISA", " EISA", " 16-bit MicroChannel",
" 32-bit MicroChannel", " LocalBus SX, 386SX",
" LocalBus 1/2, 386DX",
" LocalBus 1/2, 486DX", " PCI"};
char *memtype3[] =
{" 256Kx4 DRAM", " 256Kx4 VRAM, 512 bit serial transfer",
" 256Kx4 VRAM, 256 bit serial transfer", " 256Kx16 DRAM",
" invalid", " invalid", " invalid", " invalid"};
char *memtype6[] =
{" 256Kx4 DRAM", " 256Kx4 VRAM, 512 bit serial transfer",
" 256Kx16 VRAM, 256 bit serial transfer", " 256Kx16 DRAM",
" 256Kx4 Graphics DRAM",
" 256Kx4 VRAM, 512 bit split transfer",
" 256Kx16 VRAM, 256 bit split transfer",
" invalid"};
char *dactype[] =
{" ATI-68830 (Type 0)", " SC-11483 (Type 1)",
" ATI-68875 (Type 2)", " Bt-476 (Type 3)",
" Bt-481 (Type 4)", " ATI-68860 (Type 5)",
" Unknown type 6", " Unknown type 7"};
char *localbus[] =
{" reserved", " LOCAL#2", " LOCAL#3", " LOCAL#1"};
char *aperture[] =
{" memory aperture disabled", " 1 MB memory aperture",
" 4 MB memory aperture", " reserved"};
char *mono_color[] =
{" white", " green", " amber", " reserved"};
char *videomonames[] =
{"lores color - secondary",
"(hires) color - secondary",
"monochrome - secondary",
"lores color - primary",
"hires color - primary",
"monochrome - primary"};
char *clockdiv[] =
{" 1", " 2", " reserved", " reserved"};
char *transwid[] =
{" auto select", " 16 bit", " 8 bit", " 8 bit hostdata/16 bit other"};
char *vgabound[] =
{" shared", " 256 KB", " 512 KB", " 1 MB"};
char *maxpix[] =
{" 8 bpp", " 16 bpp", " 24 bpp", " reserved"};
static int mach32_clocks[16];
void puttable(int table);
void usage(void)
{
fputs("Usage: mach32info {info|force}\n"
" prints out almost all the info about your mach32 card from configuration\n"
" registers and Mach32 EEPROM. It also measures the Mach32 clocks. A\n"
" completely idle system is required when these measurements are being\n"
" performed. During these measurements, the video signals will be screwed up\n"
" for about 3-4 seconds.\n"
"* If your monitor does not switch off when getting a video signal it can't\n"
" stand (fixed freq. monitors) better switch it off before starting\n"
" mach32info. Your computer will beep when it is finished probing.\n"
" You can redirect the 'stdout' of 'mach32info' to some file for viewing\n"
" the results easier. Do not redirect 'stderr' as you won't hear the beep.\n"
"* The 'force' option disables the sanity check that tries to detect the\n"
" presence of the mach32. Do not use this option unless you are really,\n"
" really sure that you have a Mach32 compatible vga card installed.\n"
"* This tool is part of svgalib. Although it's output maybe useful to debug\n"
" Xfree86 Mach32 Servers, I am NOT related to Xfree86! PLEASE DO NOT SEND\n"
" ME (MICHAEL WELLER) ANY XFREE86 BUG REPORTS! Thanx in advance.\n"
"* Note that this tool comes WITHOUT ANY WARRANTY! Use it at your OWN risk!\n"
"* Warning, this tool does not check for VC changes etc.. Just let it run in\n"
" its own virtual console and don't try to fool it.\n"
"Please report any problems with running 'mach32info' or with config-\n"
"uring the 'svgalib' mach32 driver to 'eowmob@exp-math.uni-essen.de'.\n"
"Include the results from running this test with your report.\n",
stderr);
exit(2);
}
static void mach32_i_bltwait()
{
int i;
for (i = 0; i < 100000; i++)
if (!(inw(GE_STAT) & (GE_BUSY | 1)))
break;
if (i >= 100000)
puts("GE idled out");
}
static int mach32_test()
{
int result = 0;
short tmp;
tmp = inw(SCRATCH_PAD_0);
outw(SCRATCH_PAD_0, 0x5555);
mach32_i_bltwait();
if (inw(SCRATCH_PAD_0) == 0x5555) {
outw(SCRATCH_PAD_0, 0x2a2a);
mach32_i_bltwait();
if (inw(SCRATCH_PAD_0) == 0x2a2a) {
/* Aha.. 8514/a detected.. */
result = 1;
}
}
outw(SCRATCH_PAD_0, tmp);
if (!result)
goto quit;
/* Now ensure it is not a plain 8514/a: */
result = 0;
outw(DESTX_DIASTP, 0xaaaa);
mach32_i_bltwait();
if (inw(R_SRC_X) == 0x02aa) {
outw(DESTX_DIASTP, 0x5555);
mach32_i_bltwait();
if (inw(R_SRC_X) == 0x0555)
result = 1;
}
quit:
return result;
}
static void mach32_wait()
{
/* Wait for at least 22 us.. (got that out of a BIOS disassemble on my 486/50 ;-) ) ... */
register int i;
volatile dummy;
for (i = 0; i < 16; i++)
dummy++; /*Dummy is volatile.. */
}
static int mach32_eeclock(register int ati33)
{
outw(ATIPORT, ati33 |= 0x200); /* clock on */
mach32_wait();
outw(ATIPORT, ati33 &= ~0x200); /* clock off */
mach32_wait();
return ati33;
}
static void mach32_eekeyout(register int ati33, register int offset, register int mask)
{
do {
if (mask & offset)
ati33 |= 0x100;
else
ati33 &= ~0x100;
outw(ATIPORT, ati33);
mach32_eeclock(ati33);
}
while (mask >>= 1);
}
static int mach32_eeget(int offset)
{
register int ati33;
register int result, i;
/* get current ATI33 */
outb(ATIPORT, ATISEL(0x33));
ati33 = ((int) inw(ATIPORT + 1)) << 8;
ati33 |= ATISEL(0x33);
/* prepare offset.. cut and add header and trailer */
offset = (0x600 | (offset & 0x7f)) << 1;
/* enable eeprom sequence */
ati33 = mach32_eeclock(ati33);
/*input to zero.. */
outw(ATIPORT, ati33 &= ~0x100);
/*enable to one */
outw(ATIPORT, ati33 |= 0x400);
mach32_eeclock(ati33);
/*select to one */
outw(ATIPORT, ati33 |= 0x800);
mach32_eeclock(ati33);
mach32_eekeyout(ati33, offset, 0x800);
for (i = 0, result = 0; i < 16; i++) {
result <<= 1;
outb(ATIPORT, ATISEL(0x37));
if (inb(ATIPORT + 1) & 0x8)
result |= 1;
mach32_eeclock(ati33);
}
/*deselect... */
outw(ATIPORT, ati33 &= ~0x800);
mach32_eeclock(ati33);
/*disable... */
outw(ATIPORT, ati33 &= ~0x400);
mach32_eeclock(ati33);
return result;
}
void putflag(char *str, int flag)
{
int i;
i = 72 - strlen(str) - 10;
printf(" %s ", str);
while (i-- > 0)
putchar('.');
puts(flag ? ". enabled" : " disabled");
}
void putint(char *str, char *format, int value)
{
char buffer[128];
int i;
sprintf(buffer, format, value);
i = 72 - strlen(str) - strlen(buffer);
printf(" %s ", str);
while (i-- > 0)
putchar('.');
puts(buffer);
}
void putstr(char *str, char *strval)
{
putint(str, strval, 0);
}
unsigned short putword(int word)
{
printf("\n EEPROM Word %02xh:\t%04x\n", word, eeprom[word]);
return eeprom[word];
}
char *
offset(char *buffer, int word)
{
int tab;
word >>= 8;
if ((word < 0x0d) || (word > 0x67)) {
illegal:
sprintf(buffer, " %02xh words (no table there)", word);
} else {
tab = word - 0x0d;
if (tab % (0x1c - 0x0d))
goto illegal;
sprintf(buffer, " %02xh words (table %d)", word, tab / (0x1c - 0x0d) + 1);
}
return buffer;
}
char *
hsyncstr(int pixels, int clock, double fclock)
{
static char buffer[50];
if (!clock)
sprintf(buffer, " %d pixels", pixels);
else
sprintf(buffer, " %d pixels, %.3f us",
pixels, pixels / fclock);
return buffer;
}
char *
vsyncstr(int lines, int clock, double lilen)
{
static char buffer[50];
if (!clock)
sprintf(buffer, " %d lines", lines);
else
sprintf(buffer, " %d lines, %.3f ms",
lines, lines / lilen);
return buffer;
}
/* Shamelessly ripped out of Xfree2.1 (with slight changes) : */
static void mach32_scan_clocks(void)
{
const int knownind = 7;
const double knownfreq = 44.9;
char hstrt, hsync;
int htotndisp, vdisp, vtotal, vstrt, vsync, clck, i;
int count, saved_nice, loop;
double scale;
saved_nice = nice(0);
nice(-20 - saved_nice);
puts(
"Warning, about to measure clocks. Wait until system is completely idle!\n"
"Any activity will disturb measuring, and therefor hinder correct driver\n"
"function. Test will need about 3-4 seconds.");
#if 0
puts("\n(Enter Y<Return> to continue, any other text to bail out)");
if (getchar() != 'Y')
exit(0);
if (getchar() != '\n')
exit(0);
#endif
htotndisp = inw(R_H_TOTAL);
hstrt = inb(R_H_SYNC_STRT);
hsync = inb(R_H_SYNC_WID);
vdisp = inw(R_V_DISP);
vtotal = inw(R_V_TOTAL);
vstrt = inw(R_V_SYNC_STRT);
vsync = inw(R_V_SYNC_WID);
clck = inw(CLOCK_SEL);
outb(DISP_CNTL, 0x63);
outb(H_TOTAL, 0x63);
outb(H_DISP, 0x4f);
outb(H_SYNC_STRT, 0x52);
outb(H_SYNC_WID, 0x2c);
outw(V_TOTAL, 0x418);
outw(V_DISP, 0x3bf);
outw(V_SYNC_STRT, 0x3d6);
outw(V_SYNC_WID, 0x22);
for (i = 0; i < 16; i++) {
outw(CLOCK_SEL, (i << 2) | 0xac1);
outb(DISP_CNTL, 0x23);
usleep(50000);
count = 0;
loop = 200000;
while (!(inb(DISP_STATUS) & 2))
if (loop-- == 0)
goto done;
while (inb(DISP_STATUS) & 2)
if (loop-- == 0)
goto done;
while (!(inb(DISP_STATUS) & 2))
if (loop-- == 0)
goto done;
for (loop = 0; loop < 5; loop++) {
while (!(inb(DISP_STATUS) & 2))
count++;
while ((inb(DISP_STATUS) & 2))
count++;
}
done:
mach32_clocks[i] = count;
outb(DISP_CNTL, 0x63);
}
outw(CLOCK_SEL, clck);
outw(H_DISP, htotndisp);
outb(H_SYNC_STRT, hstrt);
outb(H_SYNC_WID, hsync);
outw(V_DISP, vdisp);
outw(V_TOTAL, vtotal);
outw(V_SYNC_STRT, vstrt);
outw(V_SYNC_WID, vsync);
nice(20 + saved_nice);
/*Recalculation: */
scale = ((double) mach32_clocks[knownind]) * knownfreq;
for (i = 0; i < 16; i++) {
if (i == knownind)
continue;
if (mach32_clocks[i])
mach32_clocks[i] = 0.5 + scale / ((double) mach32_clocks[i]);
}
mach32_clocks[knownind] = knownfreq + 0.5;
}
int main(int argc, char *argv[])
{
char *ptr, buffer[40];
int i, j, lastfound, mask, index, flag;
memset(eeprom, 0, sizeof(unsigned short) * (size_t) 256);
if (argc != 2)
usage();
if (strcmp(argv[1], "info")) {
if (strcmp(argv[1], "force"))
usage();
force = 1;
}
if (iopl(3) < 0) {
fputs("mach32info needs to be run as root!\n", stderr);
exit(1);
}
if (!force) {
if (mach32_test())
puts("Mach32 succesful detected.");
else {
fputs("Sorry, no Mach32 detected.\n", stderr);
exit(1);
}
} else
puts("Mach32 autodetection skipped.");
puts("\nThis tool is part of svgalib. Although this output maybe useful\n"
"to debug Xfree86 Mach32 Servers, I am NOT related to Xfree86!!\n"
"PLEASE DO NOT SEND ME (MICHAEL WELLER) ANY XFREE86 BUG REPORTS!!!\n"
"Thanx in advance.\n");
mach32_scan_clocks();
puts("\nResulting clocks command for your libvga.config should be:\n");
fputs("clocks", stdout);
for (i = 0; i < 16; i++)
printf(" %3d", mach32_clocks[i]);
fputs("\a", stderr);
fflush(stderr);
puts("\n\nParsing for chip id...");
lastfound = inw(CHIP_ID) & 0x3ff;
flag = 0;
for (i = 0; i < 10240; i++) {
j = inw(CHIP_ID) & 0x3ff;
index = (j >> 4);
mask = 1 << (j & 15);
if (!(eeprom[index] & mask))
printf("\tfound id: %c%c\n",
0x41 + ((j >> 5) & 0x1f), 0x41 + (j & 0x1f));
eeprom[index] |= mask;
if (lastfound != j)
flag = 1;
}
/* Build chip_id from last found id: */
chip_id = (j & 0x1f) + ((j << 3) & 0x1f00);
chip_id += ATI68800_3;
switch (chip_id) {
case ATI68800_3:
ptr = "ATI68800-3 (guessed)";
break;
case ATI68800_6:
ptr = "ATI68800-6";
break;
case ATI68800_6HX:
ptr = "ATI68800-6 (HX-id)";
break;
case ATI68800LX:
ptr = "ATI68800LX";
break;
case ATI68800AX:
ptr = "ATI68800AX";
break;
default:
ptr = "Unknown (assuming ATI68800-3)";
chip_id = ATI68800_3;
flag = 1;
break;
}
printf("Chipset: %s, Class: %d, Revision: %d\n",
ptr, (j >> 10) & 3, (j >> 12) & 15);
if (flag) {
puts(
"WARNING! Strange chipset id! Please report all output of this utility\n"
"together with exact type of your card / type printed on your videochips\n"
"to me, Michael Weller, eowmob@exp-math.uni-essen.de. Alternate\n"
"email-addresses are in the source of this utility and in 'README.mach32'.\n"
);
}
j = inw(MAX_WAITSTATES);
if (chip_id == ATI68800AX) {
printf("\nAPERTURE_CNTL:\t\t%04x\n", j);
putflag("Zero waitstates for PCI aperture", j & 0x400);
putflag("Fifo read ahead for PCI aperture", j & 0x800);
putflag("Pixel stream 1 SCLK delay", j & 0x1000);
putflag("Decrement burst", j & 0x2000);
putstr("Direction of burst", (j & 0x4000) ?
"Increments burst" : "Decrements burst");
putflag("Bus timeout on burst read/writes", !(j & 0x8000));
} else {
printf("\nMAX_WAITSTATES:\t\t%04x\n", j);
putint("Max. I/O waitstates", " %d", 4 * (j & 15));
putint("BIOS-ROM waitstates", " %d", (j >> 4) & 15);
putflag("Linedraw optimizations", j & 0x100);
}
j = inw(MISC_OPTIONS);
printf("\nMISC_OPTIONS:\t\t%04x\n", j);
putflag("Waitstates if FIFO is half full", j & 0x0001);
putstr("Host data I/O size", (j & 0x0002) ? "8-bit" : "16-bit");
putint("Memory size", " %d KB", (1 << ((j >> 2) & 3)) * 512);
putflag("VGA-controller", !(j & 0x0010));
putflag("16-bit 8514 I/O cycles", j & 0x0020);
putflag("Local RAMDAC", !(j & 0x0040));
putflag("VRAM-serial/DRAM-memory(bits 63:0) data delay latch", j & 0x0080);
putflag("Test-mode", j & 0x0100);
putflag("Non ATI68800-3: Block-write", j & 0x0400);
putflag("Non ATI68800-3: 64-bit Draw", j & 0x0800);
putflag("Latch video memory read data", j & 0x1000);
putflag("Memory data delay latch(bits 63:0)", j & 0x2000);
putflag("Memory data latch full clock pulse", j & 0x4000);
j = inw(R_EXT_GE_CONF);
printf("\nR_EXT_GE_CONF:\t\t%04x\n", j);
putint("Monitor alias id", " %d", j & 7);
putflag("Monitor alias", j & 0x0008);
putstr("Pixel width", pel_width[(j >> 4) & 3]);
putstr("16 bit per plane organization", bpp16mode[(j >> 6) & 3]);
putflag("Multiplex pixels", j & 0x0100);
putstr("24 bit per plane organization", bpp24mode[(j >> 9) & 3]);
putstr("Reserved (11)", (j & 0x0800) ? " 1" : " 0");
putint("Extended RAMDAC address", " %d", (j >> 12) & 3);
putflag("8 bit RAMDAC operation", j & 0x4000);
putstr("Reserved (15)", (j & 0x8000) ? " 1" : " 0");
j = inw(CONF_STAT1);
printf("\nCONF_STAT1:\t\t%04x\n", j);
putflag("VGA circuitry", !(j & 0x0001));
putstr("Bus Type", bustype[bus = ((j >> 1) & 7)]);
putstr("Memory Type", (chip_id == ATI68800_3) ? memtype3[(j >> 4) & 7] :
memtype6[(j >> 4) & 7]);
putflag("Chip", !(j & 0x0080));
putflag("Delay memory write for tests", (j & 0x0100));
putstr("RAMDAC Type", dactype[(j >> 9) & 7]);
putflag("Internal MicroChannel address decode", !(j & 0x1000));
putint("Controller id (0 if unsupported)", " %d", (j >> 13) & 7);
j = inw(CONF_STAT2);
printf("\nCONF_STAT2:\t\t%04x\n", j);
if (chip_id == ATI68800_3)
putflag("ATI68800-3: 2 clock sequencer timing", j & 0x0001);
else
putstr("Reserved (0)", (j & 0x0001) ? " 1" : " 0");
putflag("Memory address range FE0000-FFFFFF", !(j & 0x0002));
if (!bus)
putflag("16-bit ISA Bus (ISA cards only)", (j & 0x0004));
else
putstr("Reserved (2)", (j & 0x0004) ? " 1" : " 0");
putflag("Korean character font support", (j & 0x0008));
putstr("Local Bus signal (Local Bus only)", localbus[(j >> 4) & 3]);
putflag("Local Bus 2 (non multiplexed) configuration", (j & 0x0040));
putflag("Read data 1 clk after RDY (Local Bus only)", (j & 0x0080));
putflag("Local decode of RAMDAC write (Local Bus only)", !(j & 0x0100));
putflag("1 clk RDY delay for write (Local Bus only)", !(j & 0x0200));
putstr("BIOS EPROM at", (j & 0x0400) ? " C000:0-C7FF:F" : " E000:0-E7FF:F");
switch (bus) {
case 1:
putflag("Enable POS register function (EISA)", (j & 0x0800));
break;
case 4:
case 5:
case 6:
putflag("Local decode of 102h register (Local Bus only)",
!(j & 0x0800));
break;
default:
putstr("Reserved (11)", (j & 0x0800) ? " 1" : " 0");
break;
}
putflag("VESA compliant RDY format (Local Bus only)", !(j & 0x1000));
putflag("Non ATI68800-3: 4 GB aperture address", (j & 0x2000));
putstr("Non ATI68800-3: Memory support in LBus 2 config",
(j & 0x4000) ? " 2MB DRAM" : " 1MB DRAM");
putstr("Reserved (15)", (j & 0x8000) ? " 1" : " 0");
j = inw(MEM_BNDRY);
printf("\nMEM_BNDRY:\t\t%04x\n", j);
putint("Video memory partition (VGA <, Mach32 >=)", " %d KB", (j & 15) * 256);
putflag("Video memory partition write protection", j & 0x0010);
putint("Reserved (15:5)", " %03xh", (j >> 5));
j = inw(MEM_CFG);
printf("\nMEM_CFG:\t\t%04x\n", j);
putstr("Memory aperture", aperture[j & 3]);
putint("Memory aperture page (for 1MB aperture)", " %d", (j >> 2) & 3);
if ((bus == 7) || (((bus == 5) || (bus == 6)) && (inw(CONF_STAT2) & 0x2000)))
putint("Memory aperture location (0-4 GB)", " %d MB", j >> 4);
else {
putint("Reserved (7:4)", " %x", (j >> 4) & 0xf);
putint("Memory aperture location (0-128 MB)", " %d MB", j >> 8);
}
j = inw(LOCAL_CNTL);
printf("\nLOCAL_CNTL:\t\t%04x\n", j);
putflag("6 clock non page cycle", j & 0x0001);
putflag("7 clock non page cycle", j & 0x0002);
putflag("1/2 memory clock CAS precharge time", j & 0x0004);
putflag("RAMDAC clocked on positive clock edge", j & 0x0008);
putflag("FIFO testing", j & 0x0010);
if (chip_id == ATI68800_3)
putint("Filtering of 1 clock IOW low or high pulse", " %d", (j >> 5) & 3);
else {
putflag("Memory mapped registers", j & 0x0020);
putflag("Local Bus BIOS ROM decode", j & 0x0040);
}
putint("ROM wait states", " %d", (j >> 7) & 7);
putint("Memory read wait states", " %d", (j >> 10) & 3);
if (chip_id == ATI68800AX)
putint("Additional I/O waitstates", " %d", (j >> 12) & 15);
else
putint("Minimum Local Bus waistates", " %d", (j >> 12) & 15);
j = inw(R_MISC_CNTL);
printf("\nR_MISC_CNTL:\t\t%04x\n", j);
putint("Reserved (3:0)", " %x", j & 15);
putint("ROM page select", " %d KB", (j >> 3) & 0x1e);
putint("Blank adjust (delays BLANK_1_PCLK for RAMDAC type 2)", " %d", (j >> 8) & 3);
putint("Pixel data skew from PCLK (pixel delay)", " %d", (j >> 10) & 3);
putint("Reserved (15:12)", " %x", (j >> 12) & 15);
j = inw(PCI_CNTL);
printf("\nPCI_CNTL:\t\t%04x\n", j);
putint("RAMDAC read/write waitstates", " %d", j & 7);
putflag("Target abort cycle", j & 0x0004);
putflag("PCI RAMDAC delay", j & 0x0010);
putflag("Snooping on DAC read", j & 0x0020);
putflag("0 waitstates on aperture burst write", j & 0x0040);
putflag("Fast memory mapped I/O read/write", j & 0x0080);
putint("Reserved (15:8)", " %02x", (j >> 8) & 0xff);
fputs("\nReading in EEPROM... (some screen flicker will occur)", stdout);
fflush(stdout);
for (i = 0; i < 128; i++)
eeprom[i] = mach32_eeget(i);
puts(" ...done.\n");
fputs("EEPROM contents:", stdout);
for (i = 0; i < 128; i++) {
if (i & 7)
putchar(' ');
else
fputs("\n ", stdout);
printf(" %02x-%04x", i, eeprom[i]);
}
puts("\n\nDecoded info out of EEPROM:");
putword(0);
putint("EEPROM write counter", " %d", eeprom[0]);
putword(1);
switch (eeprom[1] & 0xff) {
case 0x00:
ptr = " disabled";
break;
case 0x08:
ptr = " secondary address";
break;
case 0x18:
ptr = " primary address";
break;
default:
ptr = " reserved";
}
putstr("Mouse address select", ptr);
switch ((eeprom[1] >> 8) & 0xff) {
case 0x20:
ptr = " IRQ 5";
break;
case 0x28:
ptr = " IRQ 4";
break;
case 0x30:
ptr = " IRQ 3";
break;
case 0x38:
ptr = " IRQ 2";
break;
default:
ptr = " reserved";
}
putstr("Mouse interrupt handler select", ptr);
j = putword(2);
switch ((j >> 8) & 0xff) {
case 0x03:
case 0x05:
case 0x07:
case 0x09:
case 0x0b:
case 0x12:
case 0x13:
case 0x15:
case 0x17:
case 0x19:
case 0x1b:
sprintf(ptr = buffer, " %cGA %s", (j & 0x1000) ? 'E' : 'V',
videomonames[(((j >> 8) & 0xf) - 1) >> 1]);
break;
case 0x20:
ptr = " CGA";
break;
case 0x30:
ptr = " Hercules 720x348";
break;
case 0x40:
ptr = " Hercules 640x400";
break;
default:
ptr = " reserved";
}
putstr("Power up video mode", ptr);
putstr("Monochrome color", mono_color[(j >> 6) & 3]);
putflag("Dual monitor", j & 0x0020);
putstr("Power up font", (j & 0x0010) ? " 8x16 or 9x16" : " 8x14 or 9x14");
putint("VGA Bus I/O", " %d bits", (j & 0x0008) + 8);
putflag("0 waitstates RAM read/write", j & 0x0004);
putflag("0 waitstates ROM read", j & 0x0002);
putflag("ROM 16 bit", j & 0x0001);
j = putword(3);
putflag("Scrolling fix", j & 0x8000);
putflag("Korean BIOS support", j & 0x4000);
putint("Reserved (13:4)", " %03xh", (j >> 4) & 0x3ff);
putint("EEPROM table revision", " %d", j & 15);
j = putword(4);
putint("Custom monitor indices", " %04x", j);
j = putword(5);
putstr("Host data transfer width", transwid[(j >> 14) & 3]);
putint("Monitor code", " %02xh", (j >> 8) & 0x3f);
putint("Reserved (7)", " %d", (j >> 7) & 1);
putstr("VGA boundary", vgabound[(j >> 4) & 3]);
putflag("Monitor alias", j & 0x0008);
putint("Monitor alias setting", " %d", j & 0x0007);
j = putword(6);
putint("Memory aperture location", " %d MB", (j >> 4));
j &= 15;
putstr("Memory aperture size", aperture[(j > 3) ? 3 : j]);
j = putword(7);
putstr("Offset to 640x480 mode table", offset(buffer, j));
putint("Reserved (7:2)", " %02xh", (j >> 2) & 0x3f);
putflag("Use stored params for 640x480", j & 2);
putflag("640x480 72Hz", j & 1);
j = putword(8);
putstr("Offset to 800x600 mode table", offset(buffer, j));
putflag("Use stored params for 800x600", j & 0x80);
putint("Reserved (6)", " %d", (j >> 6) & 1);
putflag("800x600 72Hz", j & 0x20);
putflag("800x600 70Hz", j & 0x10);
putflag("800x600 60Hz", j & 8);
putflag("800x600 56Hz", j & 4);
putflag("800x600 89Hz Interlaced", j & 2);
putflag("800x600 95Hz Interlaced", j & 1);
j = putword(9);
putstr("Offset to 1024x768 mode table", offset(buffer, j));
putflag("Use stored params for 1024x768", j & 0x80);
putint("Reserved (6:5)", " %d", (j >> 5) & 3);
putflag("1024x768 66Hz", j & 0x10);
putflag("1024x768 72Hz", j & 8);
putflag("1024x768 70Hz", j & 4);
putflag("1024x768 60Hz", j & 2);
putflag("1024x768 87Hz Interlaced", j & 1);
j = putword(10);
putstr("Offset to 1280x1024 mode table", offset(buffer, j));
putflag("Use stored params for 1280x1024", j & 0x80);
putint("Reserved (6:2)", " %02xh", (j >> 2) & 0x1f);
putflag("1280x1024 95Hz Interlaced", j & 2);
putflag("1280x1024 87Hz Interlaced", j & 1);
j = putword(11);
putstr("Offset to alternate mode table", offset(buffer, j));
putflag("Use stored params for alternate", j & 0x80);
putint("Reserved (6:2)", " %02xh", (j >> 2) & 0x1f);
putflag("1152x900", j & 2);
putflag("1120x760", j & 1);
for (j = 0; j < 7; j++)
puttable(j);
puts("\n EEPROM Words 76h-7dh: reserved.");
j = putword(0x7e);
putint("Reserved (15)", " %d", j >> 15);
putflag("VGA circuitry", j & 0x4000);
putint("Memory size", " %d KB", 1 << (((j >> 11) & 7) + 8));
putstr("DAC type", dactype[(j >> 8) & 7]);
putint("Reserved (7:0)", " %02xh", j & 0xff);
j = putword(0x7f);
putint("EEPROM Checksum", " %04x", j);
j = 0;
for (i = 0; i <= 0x7f;)
j += eeprom[i++];
printf("\nEEPROM contents sum up to %04x:%04x.\n", j >> 16, j & 0xffff);
if (!(j & 0xffff)) {
puts("ATI style checksum.");
} else {
j -= (eeprom[0x7f] << 1) - 1;
if (!(j & 0xffff))
puts("AST style checksum.");
else
puts(
"WARNING! Strange EEPROM checksum!\n"
"Be sure that:\n"
"1. You installed the Mach32 correctly with the ATI install tool from\n"
" DOS (yuck!).\n"
"2. Wrote the proper config to the EEPROM with it.\n"
"3. DOS bios reads out the Mach32 EEPROM with out problems and obeys\n"
" all settings (for example, power up video mode).\n"
"If you can't get a correct checksum, read the section \"EEPROM woes\"\n"
"in \"README.mach32\" of your svgalib distribution.\n"
);
}
return 0;
}
void puttable(int table)
{
int i;
int clock;
char buffer[80];
unsigned short *tab;
tab = eeprom + (table * 15 + 0xd);
printf("\n EEPROM Words %02xh-%02xh:\tCRT Parameter table %d", table * 15 + 0xd,
(table + 1) * 15 + 0xc, table + 1);
if (tab[10] & 0x3f00)
puts(":");
else {
puts(" ..................... invalid");
return;
}
table = tab[0];
putstr("Vertical sync polarity", (table & 0x8000) ? " -" : " +");
putstr("Horizontal sync polarity", (table & 0x4000) ? " -" : " +");
putflag("Interlace", table & 0x2000);
putflag("Multiplex pixels", table & 0x1000);
i = (table >> 9) & 7;
putstr("Maximum pixel depth", maxpix[(i > 3) ? 3 : i]);
putstr("Parameter type", (table & 0x0100) ? " 8514/Mach32" : " VGA");
putstr("Dotclock select", (table & 0x0080) ? " user supplied" : " default");
putstr("Usage of CRTC parameters", (table & 0x0040) ? " all"
: " sync polarities only");
putint("Dotclock chip select", " #%d", table & 15);
clock = mach32_clocks[table & 15];
putstr("Dotclock divide by", clockdiv[(table >> 4) & 3]);
if (!(table & 0x20))
if (table & 0x10)
clock /= 2;
if (clock)
putint("Pixel clock (approximate value)", " %d MHz", (int) (clock + 0.5));
else
putstr("Pixel clock", " (sorry, don't know the frequency)");
if (table & 0x0100) { /*8514/Mach32 */
double fclock, lilen;
int xpels = ((tab[3] & 0xff) + 1) << 3, ypels = tab[6], xtotal = ((tab[3] >> 8) + 1) << 3,
ytotal = tab[5], xstart = ((tab[4] >> 8) + 1) << 3, ystart = tab[7],
xsync = (tab[4] & 0x1f) * 8, ysync = (tab[8] >> 8) & 0x1f;
puts(" Mach32 / 8514/A CRT parameters:");
putint("Video fifo 16bpp", " %d", tab[2] & 0xff);
putint("Video fifo 24bpp", " %d", tab[2] >> 8);
putint("H_TOTAL", " %d", tab[3] >> 8);
putint("H_DISP", " %d", tab[3] & 0xff);
putint("H_SYNC_STRT", " %d", tab[4] >> 8);
putint("H_SYNC_WID", " %02xh", tab[4] & 0xff);
putint("V_TOTAL", " %xh", tab[5]);
putint("V_DISP", " %xh", tab[6]);
putint("V_SYNC_STRT", " %xh", tab[7]);
putint("V_SYNC_WID", " %02xh", tab[8] >> 8);
putint("DISP_CNTL", " %02xh", tab[8] & 0xff);
putint("CLOCK_SEL", " %xh", tab[9]);
clock = mach32_clocks[(tab[9] >> 2) & 15];
if (!(tab[9] & 0x40))
clock *= 2;
puts(" Resulting video timings:");
if (clock) {
sprintf(buffer, " %.1f MHz", fclock = ((double) clock) / 2);
} else {
sprintf(buffer, " #%d, don't know clock frequency, so no timings",
(tab[9] >> 2) & 15);
fclock = 0;
}
putstr("Pixel clock", buffer);
switch (tab[8] & 0x6) {
case 0:
ypels = ((ypels >> 2) & ~1) | (ypels & 1);
ytotal = ((ytotal >> 2) & ~1) | (ytotal & 1);
ystart = ((ystart >> 2) & ~1) | (ystart & 1);
break;
case 2:
ypels = ((ypels >> 1) & 0xFFFC) | (ypels & 3);
ytotal = ((ytotal >> 1) & 0xFFFC) | (ytotal & 3);
ystart = ((ystart >> 1) & 0xFFFC) | (ystart & 3);
break;
default:
puts(" Unknown DISP_CNTL, vertical values are probably wrong.");
}
ypels++;
ytotal++;
ystart++;
sprintf(buffer, " %d x %d%s", xpels, ypels, (tab[8] & 0x10) ? ", Interlaced" :
"");
putstr("Resolution", buffer);
if (clock) {
sprintf(buffer, " %.3f KHz", lilen = (fclock * 1e3) / xtotal);
putstr("Horizontal frequency", buffer);
sprintf(buffer, " %.2f Hz", (lilen * 1000) / ytotal);
putstr("Vertical frequency", buffer);
} else
lilen = 0;
putstr("Horizontal sync polarity", (tab[4] & 0x20) ? " -" : " +");
putstr("Horizontal sync width", hsyncstr(xsync, clock, fclock));
putstr("Horizontal front porch", hsyncstr(xstart - xpels, clock, fclock));
putstr("Horizontal back porch", hsyncstr(xtotal - xsync - xstart,
clock, fclock));
putstr("Horizontal active time", hsyncstr(xpels, clock, fclock));
putstr("Horizontal blank time", hsyncstr(xtotal - xpels, clock, fclock));
putstr("Vertical sync polarity", (tab[8] & 0x2000) ? " -" : " +");
putstr("Vertical sync width", vsyncstr(ysync, clock, lilen));
putstr("Vertical front porch", vsyncstr(ystart - ypels, clock, lilen));
putstr("Vertical back porch", vsyncstr(ytotal - ysync - ystart,
clock, lilen));
putstr("Vertical active time", vsyncstr(ypels, clock, lilen));
putstr("Vertical blank time", vsyncstr(ytotal - ypels, clock, lilen));
} else { /*VGA mode */
puts(" VGA CRT parameters:");
putint("VIDEO_MODE_SEL_1", " %02xh", tab[1] >> 8);
putint("VIDEO_MODE_SEL_2", " %02xh", tab[1] & 0xff);
putint("VIDEO_MODE_SEL_3", " %02xh", tab[2] >> 8);
putint("VIDEO_MODE_SEL_4", " %02xh", tab[2] & 0xff);
putint("H_TOTAL (CRT00)", " %02xh", tab[3] >> 8);
putint("V_TOTAL (CRT06)", " %02xh", tab[3] & 0xff);
putint("H_RETRACE_START (CRT04)", " %02xh", tab[4] >> 8);
putint("H_RETRACE_END (CRT05)", " %02xh", tab[4] & 0xff);
putint("V_RETRACE_START (CRT10)", " %02xh", tab[5] >> 8);
putint("V_RETRACE_END (CRT11)", " %02xh", tab[5] & 0xff);
putint("H_BLANK_START (CRT02)", " %02xh", tab[6] >> 8);
putint("H_BLANK_END (CRT03)", " %02xh", tab[6] & 0xff);
putint("V_BLANK_START (CRT15)", " %02xh", tab[7] >> 8);
putint("V_BLANK_END (CRT16)", " %02xh", tab[7] & 0xff);
putint("CRT_OVERFLOW (CRT07)", " %02xh", tab[8] >> 8);
putint("MAX_SCANLINE (CRT09)", " %02xh", tab[8] & 0xff);
putint("V_DISPLAYED (CRT12)", " %02xh", tab[9] >> 8);
putint("CRT_MODE (CRT17)", " %02xh", tab[9] & 0xff);
puts(
" Resulting video timings ......................... not implemented for VGA"
);
}
table = tab[10];
puts(" Additional mode flags:");
putflag("Pixel clock divide by 2", table & 0x8000);
putflag("Multiplex (MUX flag)", table & 0x4000);
putint("Size of mode table", " %d words", (table >> 8) & 0x3f);
putstr("Offset to alternate table", offset(buffer, (table << 8) & 0xff00));
putint("Horizontal overscan", " %d", tab[11]);
putint("Vertival overscan", " %d", tab[12]);
putint("Overscan color blue", " %d", tab[13] >> 8);
putint("Overscan color index 8bpp", " %d", tab[13] & 0xff);
putint("Overscan color red", " %d", tab[14] >> 8);
putint("Overscan color green", " %d", tab[14] & 0xff);
}