summaryrefslogtreecommitdiff
path: root/sys/arch/i386/isa/pcvt/Util/set2061/ICD2061Aalt.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/i386/isa/pcvt/Util/set2061/ICD2061Aalt.c')
-rw-r--r--sys/arch/i386/isa/pcvt/Util/set2061/ICD2061Aalt.c297
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);
+ }