/* 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); }