?? s3gendac.c
字號:
/* $XFree86: xc/programs/Xserver/hw/xfree86/common_hw/S3gendac.c,v 3.23.2.2 1997/05/11 02:56:20 dawes Exp $ */ /* * Progaming of the S3 gendac programable clocks, from the S3 Gendac * programing documentation by S3 Inc. * Jon Tombs <jon@esix2.us.es> * Also used for GenDAC and GenDAC-like chips on non-S3 chipsets. *//* $XConsortium: S3gendac.c /main/16 1996/10/25 14:11:48 kaleb $ */ #include <math.h>#include "Xfuncproto.h"#include "S3gendac.h" #include "compiler.h"#define NO_OSLIB_PROTOTYPES#include "xf86.h"#include "xf86_OSlib.h"#include "xf86_HWlib.h"#define CLK_MCLK 10#define PLL_S3GENDAC 1#define PLL_S3TRIO 2#define PLL_ET4000GENDAC 3#define PLL_ARK2000GENDAC 4#define PLL_ET6000 5extern int vgaIOBase;static void setS3gendacpll(#if NeedFunctionPrototypesint reg, unsigned char data1, unsigned char data2#endif);static void settriopll(#if NeedFunctionPrototypesint reg, unsigned char data1, unsigned char data2#endif);static void setET4000gendacpll(#if NeedFunctionPrototypesint reg, unsigned char data1, unsigned char data2#endif);static void setET6000pll(#if NeedFunctionPrototypesint reg, unsigned char data1, unsigned char data2#endif);static void setARK2000gendacpll(#if NeedFunctionPrototypesint reg, unsigned char data1, unsigned char data2#endif);static int commonSetClock( #if NeedFunctionPrototypes long freq, int clock, int min_m, int min_n1, int max_n1, int min_n2, int max_n2, int pll_type, long freq_min, long freq_max#endif); intS3gendacSetClock(freq, clk)long freq;int clk;{ return commonSetClock(freq, clk, 1, 1, 31, 0, 3, PLL_S3GENDAC, 100000, 250000);}intET4000gendacSetClock(freq, clk)long freq;int clk;{ return commonSetClock(freq, clk, 1, 1, 31, 0, 3, PLL_ET4000GENDAC, 100000, 270000);}intET6000SetClock(freq, clk)long freq;int clk;{ return commonSetClock(freq, clk, 1, 1, 31, 0, 3, PLL_ET6000, 100000, 270000);}intET4000gendacSetpixmuxClock(freq, clk)long freq;int clk;{ return commonSetClock(freq, clk, 1, 1, 31, 2, 3, PLL_ET4000GENDAC, 100000, 270000);}intARK2000gendacSetClock(freq, clk)long freq;int clk;{ return commonSetClock(freq, clk, 1, 1, 31, 0, 3, PLL_ARK2000GENDAC, 100000, 270000);}intICS5342SetClock(freq, clk)long freq;int clk;{ return commonSetClock(freq, clk, 1, 1, 31, 1, 3, PLL_S3GENDAC, 100000, 270000);}intS3TrioSetClock(freq, clk)long freq;int clk;{ return commonSetClock(freq, clk, 1, 1, 31, 0, 3, PLL_S3TRIO, 135000, 270000);}intS3Trio64V2SetClock(freq, clk)long freq;int clk;{ return commonSetClock(freq, clk, 1, 1, 31, 0, 4, PLL_S3TRIO, 170000, 340000);}intS3ViRGE_VXSetClock(freq, clk)long freq;int clk;{ if (clk != CLK_MCLK) return commonSetClock(freq, clk, 0, 0, 31, 0, 4, PLL_S3TRIO, 220000, 440000); else return commonSetClock(freq, clk, 0, 0, 31, 0, 3, PLL_S3TRIO, 220000, 440000);}intS3AuroraSetClock(freq, clk)long freq;int clk;{ if (clk == CLK_MCLK) return commonSetClock(freq, clk, 1, 1, 31, 0, 3, PLL_S3TRIO, 135000, 270000); else return commonSetClock(freq, clk, 1, 1, 63, 0, 3, PLL_S3TRIO, 135000, 270000);}int#if NeedFunctionPrototypescommonCalcClock(long freq, int min_m, int min_n1, int max_n1, int min_n2, int max_n2, long freq_min, long freq_max, unsigned char * mdiv, unsigned char * ndiv)#elsecommonCalcClock(freq, min_m, min_n1, max_n1, min_n2, max_n2, freq_min, freq_max, mdiv, ndiv)long freq;int min_m, min_n1, max_n1, min_n2, max_n2;long freq_min, freq_max;unsigned char *mdiv, *ndiv;#endif{ double ffreq, ffreq_min, ffreq_max; double div, diff, best_diff; unsigned int m; unsigned char n1, n2; unsigned char best_n1=16+2, best_n2=2, best_m=125+2; ffreq = freq / 1000.0 / BASE_FREQ; ffreq_min = freq_min / 1000.0 / BASE_FREQ; ffreq_max = freq_max / 1000.0 / BASE_FREQ; if (ffreq < ffreq_min / (1<<max_n2)) { ErrorF("invalid frequency %1.3f MHz [freq >= %1.3f MHz]\n", ffreq*BASE_FREQ, ffreq_min*BASE_FREQ / (1<<max_n2)); ffreq = ffreq_min / (1<<max_n2); } if (ffreq > ffreq_max / (1<<min_n2)) { ErrorF("invalid frequency %1.3f MHz [freq <= %1.3f MHz]\n", ffreq*BASE_FREQ, ffreq_max*BASE_FREQ / (1<<min_n2)); ffreq = ffreq_max / (1<<min_n2); } /* work out suitable timings */ best_diff = ffreq; for (n2=min_n2; n2<=max_n2; n2++) { for (n1 = min_n1+2; n1 <= max_n1+2; n1++) { m = (int)(ffreq * n1 * (1<<n2) + 0.5) ; if (m < min_m+2 || m > 127+2) continue; div = (double)(m) / (double)(n1); if ((div >= ffreq_min) && (div <= ffreq_max)) { diff = ffreq - div / (1<<n2); if (diff < 0.0) diff = -diff; if (diff < best_diff) { best_diff = diff; best_m = m; best_n1 = n1; best_n2 = n2; } } } } #if EXTENDED_DEBUG ErrorF("Clock parameters for %1.6f MHz: m=%d, n1=%d, n2=%d\n", ((double)(best_m) / (double)(best_n1) / (1 << best_n2)) * BASE_FREQ, best_m-2, best_n1-2, best_n2);#endif if (max_n1 == 63) *ndiv = (best_n1 - 2) | (best_n2 << 6); else *ndiv = (best_n1 - 2) | (best_n2 << 5); *mdiv = best_m - 2;} static int#if NeedFunctionPrototypescommonSetClock(long freq, int clk, int min_m, int min_n1, int max_n1, int min_n2, int max_n2, int pll_type, long freq_min, long freq_max)#elsecommonSetClock(freq, clk, min_m, min_n1, max_n1, min_n2, max_n2, pll_type, freq_min, freq_max)long freq;int clk;int min_m, min_n1, max_n1, min_n2, max_n2, pll_type;long freq_min, freq_max;#endif{ unsigned char m, n; commonCalcClock(freq, min_m, min_n1, max_n1, min_n2, max_n2, freq_min, freq_max, &m, &n); switch(pll_type) { case PLL_S3GENDAC: setS3gendacpll(clk, m, n); break; case PLL_S3TRIO: settriopll(clk, m, n); break; case PLL_ET4000GENDAC: setET4000gendacpll(clk, m, n); break; case PLL_ARK2000GENDAC: setARK2000gendacpll(clk, m, n); break; case PLL_ET6000: setET6000pll(clk, m, n); break; default: ErrorF("Internal error: unknown pll_type in S3gendac.c"); return -1; } return 0;} static void#if NeedFunctionPrototypessetS3gendacpll(int reg, unsigned char data1, unsigned char data2)#elsesetS3gendacpll(reg, data1, data2)int reg;unsigned char data1;unsigned char data2;#endif{ unsigned char tmp, tmp1; int vgaCRIndex = vgaIOBase + 4; int vgaCRReg = vgaIOBase + 5; /* set RS2 via CR55, yuck */ outb(vgaCRIndex, 0x55); tmp = inb(vgaCRReg) & 0xFC; outb(vgaCRReg, tmp | 0x01); tmp1 = inb(GENDAC_INDEX); outb(GENDAC_INDEX, reg); outb(GENDAC_DATA, data1); outb(GENDAC_DATA, data2); /* Now clean up our mess */ outb(GENDAC_INDEX, tmp1); outb(vgaCRReg, tmp);}static void#if NeedFunctionPrototypessetET4000gendacpll(int reg, unsigned char data1, unsigned char data2)#elsesetET4000gendacpll(reg, data1, data2)int reg;unsigned char data1;unsigned char data2;#endif{ unsigned char tmp, tmp1; int vgaCRIndex = vgaIOBase + 4; int vgaCRReg = vgaIOBase + 5; /* set RS2 via CR31 */ outb(vgaCRIndex, 0x31); tmp = inb(vgaCRReg) & 0xBF; outb(vgaCRReg, tmp | 0x40); tmp1 = inb(GENDAC_INDEX); outb(GENDAC_INDEX, reg); outb(GENDAC_DATA, data1); outb(GENDAC_DATA, data2); /* Now clean up our mess */ outb(GENDAC_INDEX, tmp1); outb(vgaCRReg, tmp);}static void#if NeedFunctionPrototypessetET6000pll(int reg, unsigned char data1, unsigned char data2)#elsesetET6000pll(reg, data1, data2)int reg;unsigned char data1;unsigned char data2;#endif{ /* Tseng Labs engineers were wise enough to use the same * PLL scheme used in other standard GenDACs -- good! * Clocks 0..7 are pixel clocks, clock 10 is the memory clock */ unsigned long PCIIOBase = 0xDEADBEEF; unsigned char tmp; int vgaCRIndex = vgaIOBase + 4; int vgaCRReg = vgaIOBase + 5; /* get PCI IO base address first */ outb(vgaCRIndex, 0x21); PCIIOBase = (inb(vgaCRReg)<<8); outb(vgaCRIndex, 0x22); PCIIOBase += (inb(vgaCRReg)<<16); outb(vgaCRIndex, 0x23); PCIIOBase += (inb(vgaCRReg)<<24);#if EXTENDED_DEBUG ErrorF("ET6000: PCIIOBase: 0x%lX ; M/N parameters: 0x%X 0x%X ; clk index: %d\n", PCIIOBase, data1, data2, reg);#endif /* set the PLL parameters for specified clock */ tmp = inb(PCIIOBase+0x67); /* remember old CLKDAC index register pointer */ outb(PCIIOBase+0x67, reg); outb(PCIIOBase+0x69, data1); outb(PCIIOBase+0x69, data2); /* restore old index register */ outb(PCIIOBase+0x67, tmp);}static void#if NeedFunctionPrototypessetARK2000gendacpll(int reg, unsigned char data1, unsigned char data2)#elsesetARK2000gendacpll(reg, data1, data2)int reg;unsigned char data1;unsigned char data2;#endif{ unsigned char tmp, tmp1; int vgaCRIndex = vgaIOBase + 4; int vgaCRReg = vgaIOBase + 5; /* set RS2 via CR1C, bit 0x80 */ outb(vgaCRIndex, 0x1C); tmp = inb(vgaCRReg) & ~0x80; outb(vgaCRReg, tmp | 0x80); tmp1 = inb(GENDAC_INDEX); outb(GENDAC_INDEX, reg); outb(GENDAC_DATA, data1); outb(GENDAC_DATA, data2); /* Now clean up our mess */ outb(GENDAC_INDEX, tmp1); outb(vgaCRReg, tmp);}static void#if NeedFunctionPrototypessettriopll(int clk, unsigned char m, unsigned char n)#elsesettriopll(clk, m, n) int clk; unsigned char m; unsigned char n;#endif{ unsigned char tmp; int index2; /* * simlulate S3 GENDAC clock numbers: * 0,1 for fixed 25 and 28 MHz clocks * 2-8 free programmable * 10 MCLK */ if (clk < 2) { tmp = inb(0x3cc); outb(0x3c2, (tmp & 0xf3) | (clk << 2)); } else { tmp = inb(0x3cc); outb(0x3c2, tmp | 0x0c); outb(0x3c4, 0x08); outb(0x3c5, 0x06); /* unlock extended CR9-CR18 */ if (clk != CLK_MCLK) { /* DCLK */ outb(0x3c4, 0x12); outb(0x3c5, n); outb(0x3c4, 0x13); outb(0x3c5, m); outb(0x3c4, 0x15); tmp = inb(0x3c5) & ~0x21; outb(0x3c5, tmp | 0x02); outb(0x3c5, tmp | 0x22); outb(0x3c5, tmp | 0x02); } else { /* MCLK */ index2 = 0x10; outb(0x3c4, 0x10); outb(0x3c5, n); outb(0x3c4, 0x11); outb(0x3c5, m); outb(0x3c4, 0x1a); outb(0x3c5, n); outb(0x3c4, 0x15); tmp = inb(0x3c5) & ~0x21; outb(0x3c5, tmp | 0x01); outb(0x3c5, tmp | 0x21); outb(0x3c5, tmp | 0x01); outb(0x3c5, tmp); } outb(0x3c4, 0x08); outb(0x3c5, 0x00); /* lock extended CR9-CR18 */ }}int#if NeedFunctionPrototypesgendacMNToClock(unsigned char m,unsigned char n)#elsegendacMNToClock(m,n) unsigned char m; unsigned char n;#endif{ int rtn; rtn = (1431818 * (m + 2) / ((n & 0x1f)+2) / (1 << ((n & 0x60) >> 5))) / 100; return rtn;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -