/* 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 * Copyright 1993 by David Wexelblat * * 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 #include #include #include /* 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 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); }