diff options
Diffstat (limited to 'sys/arch/i386/isa/pcvt/Util/set2061/ICD2061Aalt.c')
-rw-r--r-- | sys/arch/i386/isa/pcvt/Util/set2061/ICD2061Aalt.c | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/sys/arch/i386/isa/pcvt/Util/set2061/ICD2061Aalt.c b/sys/arch/i386/isa/pcvt/Util/set2061/ICD2061Aalt.c new file mode 100644 index 00000000000..248476ad728 --- /dev/null +++ b/sys/arch/i386/isa/pcvt/Util/set2061/ICD2061Aalt.c @@ -0,0 +1,297 @@ +/* + * This code is derived from code available from the STB bulletin board + */ + +/* $XFree86: mit/server/ddx/x386/common_hw/ICD2061Aalt.c,v 2.6 1994/04/15 05:10:30 dawes Exp $ */ + +#ifndef KERNEL +#include "compiler.h" +#else +#define GCCUSESGAS +#define PCVT_STANDALONE 1 +#endif + +#define SEQREG 0x03C4 +#define MISCREG 0x03C2 +#define MISCREAD 0x03CC + +double fref = 14.31818 * 2.0; +char ascclk[] = "VIDEO CLOCK ?"; + +unsigned short clknum; +unsigned short vlbus_flag; +unsigned short card; +unsigned short crtcaddr; +unsigned short clockreg; + +static double range[15] = {50.0, 51.0, 53.2, 58.5, 60.7, 64.4, 66.8, 73.5, + 75.6, 80.9, 83.2, 91.5, 100.0, 120.0, 120.0}; + +#ifdef __STDC__ +static double genratio(unsigned int *p, unsigned int *q, double tgt); +static double f(unsigned int p, unsigned int q, double basefreq); +#if 0 +static void prtbinary(unsigned int size, unsigned int val); +#endif +static void wait_vb(); +static void wrt_clk_bit(unsigned int value); +static void init_clock(unsigned long setup, unsigned short crtcport); +#else +static double genratio(); +static double f(); +#if 0 +static void prtbinary(); +#endif +static void wait_vb(); +static void wrt_clk_bit(); +static void init_clock(); +#endif + +void AltICD2061SetClock(frequency, select) +register long frequency; /* in Hz */ +int select; +{ + unsigned int m, mval, ival; + int i; + long dwv; + double realval; + double freq, fvco; + double dev, devx; + double delta, deltax; + unsigned int p, q; + unsigned int bestp, bestq; + unsigned char tmp; + + crtcaddr=(inb(0x3CC) & 0x01) ? 0x3D4 : 0x3B4; + + + outb(crtcaddr, 0x11); /* Unlock CRTC registers */ + tmp = inb(crtcaddr + 1); + outb(crtcaddr + 1, tmp & ~0x80); + + outw(crtcaddr, 0x4838); /* Unlock S3 register set */ + outw(crtcaddr, 0xA039); + + clknum = select; + + freq = ((double)frequency)/1000000.0; + if (freq > range[14]) + freq =range[14]; + else if (freq <= 6.99) + freq = 7.0; + +/* + * Calculate values to load into ICD 2061A clock chip to set frequency + */ + delta = 999.0; + dev = 999.0; + ival = 99; + mval = 99; + + fvco = freq / 2; + for (m = 0; m < 8; m++) { + fvco *= 2.0; + for (i = 14; i >= 0; i--) + if (fvco >= range[i]) + break; + if (i < 0) + continue; + if (i == 14) + break; + devx = (fvco - (range[i] + range[i+1])/2)/fvco; + if (devx < 0) + devx = -devx; + deltax = genratio(&p, &q, fvco); + if (delta < deltax) + continue; + if (deltax < delta || devx < dev) { + bestp = p; + bestq = q; + delta = deltax; + dev = devx; + ival = i; + mval = m; + } + } + fvco = fref; + for (m=0; m<mval; m++) + fvco /= 2.0; + realval = f(bestp, bestq, fvco); + dwv = ((((((long)ival << 7) | bestp) << 3) | mval) << 7) | bestq; + +/* + * Write ICD 2061A clock chip + */ + init_clock(((unsigned long)dwv) | (((long)clknum) << 21), crtcaddr); + + wait_vb(); + wait_vb(); + wait_vb(); + wait_vb(); + wait_vb(); + wait_vb(); + wait_vb(); /* 0.10 second delay... */ +} + +static double f(p, q, base) + unsigned int p; + unsigned int q; + double base; + { + return(base * (p + 3)/(q + 2)); + } + +static double genratio(p, q, tgt) + unsigned int *p; + unsigned int *q; + double tgt; + { + int k, m; + double test, mindiff; + unsigned int mmax; + + mindiff = 999999999.0; + for (k = 13; k < 69; k++) { /* q={15..71}:Constraint 2 on page 14 */ + m = 50.0*k/fref - 3; + if (m < 0) + m = 0; + mmax = 120*k/fref - 3; /* m..mmax is constraint 3 on page 14 */ + if (mmax > 128) + mmax = 128; + while (m < mmax) { + test = f(m, k, fref) - tgt; + if (test < 0) test = -test; + if (mindiff > test) { + mindiff = test; + *p = m; + *q = k; + } + m++; + } + } + return (mindiff); + } + +#if 0 +static void prtbinary(size, val) + unsigned int size; + unsigned int val; + { + unsigned int mask; + int k; + + mask = 1; + + for (k=size; --k > 0 || mask <= val/2;) + mask <<= 1; + + while (mask) { + fputc((mask&val)? '1': '0' , stderr); + mask >>= 1; + } + } +#endif + +static void wait_vb() + { + while ((inb(crtcaddr+6) & 0x08) == 0) + ; + while (inb(crtcaddr+6) & 0x08) + ; + } + + +#ifdef __STDC__ +static void init_clock(unsigned long setup, unsigned short crtcport) +#else +static void init_clock(setup, crtcport) + unsigned long setup; + unsigned short crtcport; +#endif + { + unsigned char nclk[2], clk[2]; + unsigned short restore42; + unsigned short oldclk; + unsigned short bitval; + int i; + unsigned char c; + +#ifndef PCVT_STANDALONE + (void)xf86DisableInterrupts(); +#endif + + oldclk = inb(0x3CC); + + outb(crtcport, 0x42); + restore42 = inb(crtcport+1); + + outw(0x3C4, 0x0100); + + outb(0x3C4, 1); + c = inb(0x3C5); + outb(0x3C5, 0x20 | c); + + outb(crtcport, 0x42); + outb(crtcport+1, 0x03); + + outw(0x3C4, 0x0300); + + nclk[0] = oldclk & 0xF3; + nclk[1] = nclk[0] | 0x08; + clk[0] = nclk[0] | 0x04; + clk[1] = nclk[0] | 0x0C; + + outb(crtcport, 0x42); + i = inw(crtcport); + + outw(0x3C4, 0x0100); + + wrt_clk_bit(oldclk | 0x08); + wrt_clk_bit(oldclk | 0x0C); + for (i=0; i<5; i++) { + wrt_clk_bit(nclk[1]); + wrt_clk_bit(clk[1]); + } + wrt_clk_bit(nclk[1]); + wrt_clk_bit(nclk[0]); + wrt_clk_bit(clk[0]); + wrt_clk_bit(nclk[0]); + wrt_clk_bit(clk[0]); + for (i=0; i<24; i++) { + bitval = setup & 0x01; + setup >>= 1; + wrt_clk_bit(clk[1-bitval]); + wrt_clk_bit(nclk[1-bitval]); + wrt_clk_bit(nclk[bitval]); + wrt_clk_bit(clk[bitval]); + } + wrt_clk_bit(clk[1]); + wrt_clk_bit(nclk[1]); + wrt_clk_bit(clk[1]); + + outb(0x3C4, 1); + c = inb(0x3C5); + outb(0x3C5, 0xDF & c); + + outb(crtcport, 0x42); + outb(crtcport+1, restore42); + + outb(0x3C2, oldclk); + + outw(0x3C4, 0x0300); + +#ifndef PCVT_STANDALONE + xf86EnableInterrupts(); +#endif + + } + +static void wrt_clk_bit(value) + unsigned int value; + { + int j; + + outb(0x3C2, value); + for (j=2; --j; ) + inb(0x200); + } |