/* 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 free software; you can redistribute it and/or */ /* modify it without any restrictions. This library 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@vm.hrz.uni-essen.de */ /* eowmob@pollux.exp-math.uni-essen.de mat42b@de0hrz1a.bitnet */ /* * * MICHAEL WELLER 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. * */ /* 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 /* 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-487 (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" "\tprints out almost all info about your mach32 card. Please\n" "\treport this information in case of any problems with the mach32\n" "\tdriver of svgalib.\n" "\tIt does also measure the Mach32 clocks. This needs a completely\n" "\tidle system. Also it screws up video signals for about 3-4 seconds.\n\n" "\tIf your monitor does not switch off when getting a video signal it can't\n" "\tstand (fixed freq. monitors) better switch it off during clock probing/\n" "\tbefore starting mach32info, it will beep when it is ready. You would\n" "\thave to put the bunch of output mach32info in a file anyway to view\n" "\tit easily.\n\n" "\tThe force option disables the sanity check that tries to\n" "\tdetect the mach32. Do not use it except you are really really sure\n" "\tyou have a Mach32 compatible vga card.\n\n" "\tNote that this tool comes WITHOUT ANY WARRANTY!\n" "\tUse at OWN risk!\n\n" "\tWarning, this tool does not check for VC changes etc..\n" "\tJust let it run in its own virtual console and don't try to fool it..\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; } /* Shameless ripped out of Xfree2.1 (with slight changes) : */ static void mach32_scan_clocks(void) { const int knownind=7; const double knownfreq=44.9; char hdisp,htotal,hstrt,hsync; int 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 "\n(Enter Y to continue, any other text to bail out)"); if(getchar()!='Y') exit(0); if(getchar()!='\n') exit(0); #else ); #endif hdisp=inb(H_DISP); htotal=inb(H_TOTAL); hstrt=inb(H_SYNC_STRT); hsync=inb(H_SYNC_WID); vdisp=inw(V_DISP); vtotal=inw(V_TOTAL); vstrt=inw(V_SYNC_STRT); vsync=inw(V_SYNC_WID); clck=inw(CLOCK_SEL); 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); outb(DISP_CNTL,0x63); outb(DISP_CNTL,0x23); for(i=0;i<16;i++) { outw(CLOCK_SEL, (i << 2) | 0xac1); 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; } outw(CLOCK_SEL,clck); outb(H_DISP,hdisp); outb(H_TOTAL,htotal); 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."); 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\n\aParsing for chip id..."); lastfound=inb(CHIP_ID)&0xff; flag=0; for(i=0;i<10240;i++) { j=inb(CHIP_ID)&0xff; 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 (more email-addresses in\n" "the source of this utility))." ); } 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",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); putflag("16-bit hostdata I/O",!(j&0x0002)); 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); putflag("ATI68800-3: 2 clock sequencer timing",j&0x0001); putflag("Memory address range FE0000-FFFFFF",!(j&0x0002)); putflag("16-bit ISA Bus (ISA cards only)",(j&0x0004)); 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"); if(bus==1) putflag("Enable POS register function (EISA)",(j&0x0800)); else putflag("Local decode of 102h register (Local Bus only)",!(j&0x0800)); 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); 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( "WARNING! Strange EEPROM checksum! If you are sure that you installed the\n" "Mach32 correctly with the ATI install tool (from DOS yuck!) and wrote the\n" "config in the EEPROM with it... and all other tools/DOS bios read out the\n" "Mach32 EEPROM with out problems and obey all settings (for example, power up\n" "video mode). Then 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 (more email-addresses in\n" "the source of this utility))." ); } 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]&0x5f00) 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); }