📄 g400.c
字号:
/*Matrox G200/G400/G450 chipset driver Based on the XFree86 driver.Tested only on a G450. TODO: SDRAM, reference frequency checking.*/#include <stdlib.h>#include <stdio.h> #include <string.h>#include <unistd.h>#include "vga.h"#include "libvga.h"#include "driver.h"#include "timing.h"#include "vgaregs.h"#include "interface.h"#include "accel.h"#include "vgapci.h"#define SKREG_SAVE(i) (VGA_TOTAL_REGS+i)#define G400_TOTAL_REGS (VGA_TOTAL_REGS + 0x50 + 9 + 12)static void __svgalib_outpal(int i, int r, int g, int b){ outb(PEL_IW,i); outb(PEL_D,r); outb(PEL_D,g); outb(PEL_D,b);}enum { ID_G100 = 0, ID_G200, ID_G400, ID_G450 };static int g400_init(int, int, int);static void g400_unlock(void);static void g400_lock(void);void __svgalib_g400accel_init(AccelSpecs * accelspecs, int bpp, int width_in_pixels);static int g400_memory, id;static int g400_is_linear, g400_linear_base, g400_mmio_base;static int HasSDRAM;static CardSpecs *cardspecs;static int g400_inExt(int i) { *(MMIO_POINTER + 0x1fde) = i; return *(MMIO_POINTER + 0x1fdf);}static void g400_outExt(int i, int d) { *(unsigned short *)(MMIO_POINTER + 0x1fde) = (d<<8) | i;}static int g400_inDAC(int i) { *(MMIO_POINTER + 0x3c00) = i; return *(MMIO_POINTER + 0x3c0a);}static void g400_outDAC(int i, int d) { *(MMIO_POINTER + 0x3c00) = i; *(MMIO_POINTER + 0x3c0a) = d;}static void g400_setpage(int page){ g400_outExt(4,page);}static int __svgalib_g400_inlinearmode(void){return g400_is_linear;}/* Fill in chipset specific mode information */static void g400_getmodeinfo(int mode, vga_modeinfo *modeinfo){ if(modeinfo->colors==16)return; modeinfo->maxpixels = g400_memory*1024/modeinfo->bytesperpixel; modeinfo->maxlogicalwidth = 8184; modeinfo->startaddressrange = g400_memory * 1024 - 1; modeinfo->haveblit = 0; modeinfo->flags &= ~HAVE_RWPAGE; if (modeinfo->bytesperpixel >= 1) { if(g400_linear_base)modeinfo->flags |= CAPABLE_LINEAR; if (__svgalib_g400_inlinearmode()) modeinfo->flags |= IS_LINEAR; }}/* Read and save chipset-specific registers */#define PCI_CONF_ADDR 0xcf8#define PCI_CONF_DATA 0xcfc static int g400_saveregs(unsigned char regs[]){ int i; g400_unlock(); outl (PCI_CONF_ADDR, 0x80010000 + 0x40); *(unsigned int *)(regs + VGA_TOTAL_REGS + 0x50 + 9 + 0 ) = inl (PCI_CONF_DATA); outl (PCI_CONF_ADDR, 0x80010000 + 0x50); *(unsigned int *)(regs + VGA_TOTAL_REGS + 0x50 + 9 + 4 ) = inl (PCI_CONF_DATA); outl (PCI_CONF_ADDR, 0x80010000 + 0x54); *(unsigned int *)(regs + VGA_TOTAL_REGS + 0x50 + 9 + 8 ) = inl (PCI_CONF_DATA); for(i=0;i<0x50;i++) regs[VGA_TOTAL_REGS + i]=g400_inDAC(i); for(i=0;i<9;i++) regs[VGA_TOTAL_REGS + 0x50 + i]=g400_inExt(i); return G400_TOTAL_REGS - VGA_TOTAL_REGS;}/* Set chipset-specific registers */static void g400_setregs(const unsigned char regs[], int mode){ int i; g400_unlock(); for(i=0;i<0x50;i++) {#if 0 if( (i> 0x03) && (i!=0x07) && (i!=0x0b) && (i!=0x0f) && (i< 0x13) && (i> 0x17) && (i!=0x1b) && (i!=0x1c) && (i< 0x1f) && (i> 0x29) && (i< 0x30) && (i> 0x37) && (i!=0x39) && (i!=0x3b) && (i!=0x3f) && (i!=0x41) && (i!=0x43) && (i!=0x47) && (i!=0x4b) )#endif g400_outDAC(i,regs[VGA_TOTAL_REGS + i]); } outl (PCI_CONF_ADDR, 0x80010000 + 0x40); outl(PCI_CONF_DATA, *(unsigned int *)(regs + VGA_TOTAL_REGS + 0x50 + 9 )); outl (PCI_CONF_ADDR, 0x80010000 + 0x50); outl(PCI_CONF_DATA, *(unsigned int *)(regs + VGA_TOTAL_REGS + 0x50 + 9 + 4 )); outl (PCI_CONF_ADDR, 0x80010000 + 0x54); outl(PCI_CONF_DATA, *(unsigned int *)(regs + VGA_TOTAL_REGS + 0x50 + 9 + 8 )); for(i=0;i<9;i++) g400_outExt(i, regs[VGA_TOTAL_REGS + 0x50 + i]);}/* Return nonzero if mode is available */static int g400_modeavailable(int mode){ struct info *info; ModeTiming *modetiming; ModeInfo *modeinfo; if (IS_IN_STANDARD_VGA_DRIVER(mode)) return __svgalib_vga_driverspecs.modeavailable(mode); info = &__svgalib_infotable[mode]; if (g400_memory * 1024 < info->ydim * info->xbytes) return 0; modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode); modetiming = malloc(sizeof(ModeTiming)); if (__svgalib_getmodetiming(modetiming, modeinfo, cardspecs)) { free(modetiming); free(modeinfo); return 0; } free(modetiming); free(modeinfo); return SVGADRV;}#define MGA_MIN_VCO_FREQ 120000#define MGA_MAX_VCO_FREQ 250000#define MGA_MAX_PCLK_FREQ 250000#define MGA_MAX_MCLK_FREQ 100000#define MGA_REF_FREQ 27050.0#define MGA_ALT_REF_FREQ 14318.0#define MGA_FEED_DIV_MIN 8#define MGA_FEED_DIV_MAX 127#define MGA_IN_DIV_MIN 1#define MGA_IN_DIV_MAX 30#define MGA_ALT_IN_DIV_MAX 6#define MGA_POST_DIV_MIN 0#define MGA_POST_DIV_MAX 3static doubleMGACalcClock ( long f_out, long f_max, int *m, int *n, int *p, int *s ){ int best_m=0, best_n=0; double f_pll, f_vco; double m_err, calc_f, base_freq; int mga_in_div_max; static double ref = 0.0; switch(id) { case ID_G400: case ID_G450: ref = MGA_REF_FREQ; mga_in_div_max = MGA_IN_DIV_MAX; mga_in_div_max = MGA_ALT_IN_DIV_MAX; /* 31 should be allowed, but does not work. */ break; case ID_G200: ref = MGA_ALT_REF_FREQ; mga_in_div_max = MGA_ALT_IN_DIV_MAX; break; default: ref = MGA_ALT_REF_FREQ; mga_in_div_max = MGA_ALT_IN_DIV_MAX; break; } /* Make sure that f_min <= f_out <= f_max */ if ( f_out < ( MGA_MIN_VCO_FREQ / 8)) f_out = MGA_MIN_VCO_FREQ / 8; if ( f_out > f_max ) f_out = f_max; /* * f_pll = f_vco / (2^p) * Choose p so that MGA_MIN_VCO_FREQ <= f_vco <= MGA_MAX_VCO_FREQ * we don't have to bother checking for this maximum limit. */ f_vco = ( double ) f_out; for ( *p = 0; *p < MGA_POST_DIV_MAX && f_vco < MGA_MIN_VCO_FREQ; ( *p )++ ) f_vco *= 2.0; /* Initial value of calc_f for the loop */ calc_f = 0; base_freq = ref / ( 1 << *p ); /* Initial amount of error for frequency maximum */ m_err = f_out; /* Search for the different values of ( *m ) */ for ( *m = MGA_IN_DIV_MIN ; *m < mga_in_div_max ; ( *m )++ ) { /* see values of ( *n ) which we can't use */ for ( *n = MGA_FEED_DIV_MIN; *n <= MGA_FEED_DIV_MAX; ( *n )++ ) { calc_f = (base_freq * (*n)) / *m ; /* * Pick the closest frequency. */ if (abs( calc_f - f_out ) < m_err ) { m_err = abs(calc_f - f_out); best_m = *m; best_n = *n; } } } /* Now all the calculations can be completed */ f_vco = ref * best_n / best_m; /* Adjustments for filtering pll feed back */ switch(id) { case ID_G450: *s=0; break; case ID_G400: if ( (50000.0 <= f_vco) && (f_vco < 110000.0) ) *s = 0; if ( (110000.0 <= f_vco) && (f_vco < 170000.0) ) *s = 1; if ( (170000.0 <= f_vco) && (f_vco < 240000.0) ) *s = 2; if ( (240000.0 <= f_vco) && (f_vco < 310000.0) ) *s = 3; break; case ID_G200: if ( (50000.0 <= f_vco) && (f_vco < 100000.0) ) *s = 0; if ( (100000.0 <= f_vco) && (f_vco < 140000.0) ) *s = 1; if ( (140000.0 <= f_vco) && (f_vco < 180000.0) ) *s = 2; if ( (180000.0 <= f_vco) && (f_vco < 250000.0) ) *s = 3; break; } f_pll = f_vco / ( 1 << *p ); *m = best_m - 1; *n = best_n - 1; *p = ( 1 << *p ) - 1 ; return f_pll;}/* * MGASetPCLK - Set the pixel (PCLK) and loop (LCLK) clocks. * * PARAMETERS * f_pll IN Pixel clock PLL frequencly in kHz. */static void MGASetPCLK( long f_out, unsigned char *initDAC ){ /* Pixel clock values */ int m, n, p, s; /* The actual frequency output by the clock */ double f_pll; long f_max; /* Get the maximum pixel clock frequency from the BIOS, * or from a reasonable default */ if ( 0 ) f_max = (/*MGABios2.PclkMax+*/100) * 1000; /* [ajv - scale it] */ else f_max = MGA_MAX_PCLK_FREQ; /* Do the calculations for m, n, and p */ f_pll = MGACalcClock( f_out, f_max, &m, &n, &p , &s); /* Values for the pixel clock PLL registers */ if((id == ID_G450) && (p==3))p=2; initDAC[ 0x4c ] = ( m & 0x1f ); initDAC[ 0x4d ] = ( n & 0x7f ); initDAC[ 0x4e ] = ( (p & 0x07) | ((s & 0x3) << 3) );}static void g400_initializemode(unsigned char *moderegs, ModeTiming * modetiming, ModeInfo * modeinfo, int mode){ static unsigned char initDAC[] = { /* 0x00: */ 0, 0, 0, 0, 0, 0, 0x00, 0, /* 0x08: */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08: */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x18: */ 0x03, 0, 0x09, 0xFF, 0xBF, 0x20, 0x1F, 0x20, /* 0x20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28: */ 0x00, 0x00, 0x00, 0x77, 0x04, 0x2D, 0x19, 0x40, /* 0x30: */ 0x00, 0xB0, 0x00, 0xC2, 0x34, 0x14, 0x02, 0x83, /* 0x38: */ 0x00, 0x93, 0x00, 0x77, 0x71, 0xDB, 0x02, 0x3A, /* 0x40: */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x48: */ 0, 0, 0, 0, 0, 0, 0, 0 }; int hd, hs, he, ht, vd, vs, ve, vt, wd; int i; int weight555 = 0; int MGABppShft = 0; __svgalib_setup_VGA_registers(moderegs, modetiming, modeinfo); switch(modeinfo->bitsPerPixel) { case 8: initDAC[ 0x19 ] = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -