2 * This code is derived from code available from the STB bulletin board
4 * $FreeBSD: src/usr.sbin/pcvt/set2061/ICD2061Aalt.c,v 1.5 1999/12/29 05:07:54 peter Exp $
5 * $DragonFly: src/usr.sbin/pcvt/set2061/Attic/ICD2061Aalt.c,v 1.3 2004/03/24 17:46:23 cpressey Exp $
8 /* $XFree86: mit/server/ddx/x386/common_hw/ICD2061Aalt.c,v 2.6 1994/04/15 05:10:30 dawes Exp $ */
14 #define PCVT_STANDALONE 1
18 #define MISCREG 0x03C2
19 #define MISCREAD 0x03CC
21 double fref = 14.31818 * 2.0;
22 char ascclk[] = "VIDEO CLOCK ?";
24 unsigned short clknum;
25 unsigned short vlbus_flag;
27 unsigned short crtcaddr;
28 unsigned short clockreg;
30 static double range[15] = {50.0, 51.0, 53.2, 58.5, 60.7, 64.4, 66.8, 73.5,
31 75.6, 80.9, 83.2, 91.5, 100.0, 120.0, 120.0};
34 static double genratio(unsigned int *p, unsigned int *q, double tgt);
35 static double f(unsigned int p, unsigned int q, double basefreq);
37 static void prtbinary(unsigned int size, unsigned int val);
39 static void wait_vb();
40 static void wrt_clk_bit(unsigned int value);
41 static void init_clock(unsigned long setup, unsigned short crtcport);
43 static double genratio();
46 static void prtbinary();
48 static void wait_vb();
49 static void wrt_clk_bit();
50 static void init_clock();
54 AltICD2061SetClock(long frequency, /* in Hz */
57 unsigned int m, mval, ival;
65 unsigned int bestp, bestq;
68 crtcaddr=(inb(0x3CC) & 0x01) ? 0x3D4 : 0x3B4;
71 outb(crtcaddr, 0x11); /* Unlock CRTC registers */
72 tmp = inb(crtcaddr + 1);
73 outb(crtcaddr + 1, tmp & ~0x80);
75 outw(crtcaddr, 0x4838); /* Unlock S3 register set */
76 outw(crtcaddr, 0xA039);
80 freq = ((double)frequency)/1000000.0;
83 else if (freq <= 6.99)
87 * Calculate values to load into ICD 2061A clock chip to set frequency
95 for (m = 0; m < 8; m++) {
97 for (i = 14; i >= 0; i--)
104 devx = (fvco - (range[i] + range[i+1])/2)/fvco;
107 deltax = genratio(&p, &q, fvco);
110 if (deltax < delta || devx < dev) {
120 for (m=0; m<mval; m++)
122 realval = f(bestp, bestq, fvco);
123 dwv = ((((((long)ival << 7) | bestp) << 3) | mval) << 7) | bestq;
126 * Write ICD 2061A clock chip
128 init_clock(((unsigned long)dwv) | (((long)clknum) << 21), crtcaddr);
136 wait_vb(); /* 0.10 second delay... */
140 f(unsigned int p, unsigned int q, double base)
142 return(base * (p + 3)/(q + 2));
146 genratio(unsigned int *p, unsigned int *q, double tgt)
149 double test, mindiff;
152 mindiff = 999999999.0;
153 for (k = 13; k < 69; k++) { /* q={15..71}:Constraint 2 on page 14 */
157 mmax = 120*k/fref - 3; /* m..mmax is constraint 3 on page 14 */
161 test = f(m, k, fref) - tgt;
162 if (test < 0) test = -test;
163 if (mindiff > test) {
176 prtbinary(unsigned int size, unsigned int val)
183 for (k=size; --k > 0 || mask <= val/2;)
187 fputc((mask&val)? '1': '0' , stderr);
196 while ((inb(crtcaddr+6) & 0x08) == 0)
198 while (inb(crtcaddr+6) & 0x08)
204 init_clock(unsigned long setup, unsigned short crtcport)
206 unsigned char nclk[2], clk[2];
207 unsigned short restore42;
208 unsigned short oldclk;
209 unsigned short bitval;
213 #ifndef PCVT_STANDALONE
214 (void)xf86DisableInterrupts();
219 outb(crtcport, 0x42);
220 restore42 = inb(crtcport+1);
226 outb(0x3C5, 0x20 | c);
228 outb(crtcport, 0x42);
229 outb(crtcport+1, 0x03);
233 nclk[0] = oldclk & 0xF3;
234 nclk[1] = nclk[0] | 0x08;
235 clk[0] = nclk[0] | 0x04;
236 clk[1] = nclk[0] | 0x0C;
238 outb(crtcport, 0x42);
243 wrt_clk_bit(oldclk | 0x08);
244 wrt_clk_bit(oldclk | 0x0C);
245 for (i=0; i<5; i++) {
246 wrt_clk_bit(nclk[1]);
249 wrt_clk_bit(nclk[1]);
250 wrt_clk_bit(nclk[0]);
252 wrt_clk_bit(nclk[0]);
254 for (i=0; i<24; i++) {
255 bitval = setup & 0x01;
257 wrt_clk_bit(clk[1-bitval]);
258 wrt_clk_bit(nclk[1-bitval]);
259 wrt_clk_bit(nclk[bitval]);
260 wrt_clk_bit(clk[bitval]);
263 wrt_clk_bit(nclk[1]);
268 outb(0x3C5, 0xDF & c);
270 outb(crtcport, 0x42);
271 outb(crtcport+1, restore42);
277 #ifndef PCVT_STANDALONE
278 xf86EnableInterrupts();
283 static void wrt_clk_bit(unsigned int value)