1 /*
2  * s3dacs.c:
3  *
4  * RAMDAC definitions for the S3-SDAC (86C716), S3-GENDAC, and Trio64.
5  *
6  * These contain S3-specific code.
7  */
8 
9 #include <stdio.h>
10 #include "libvga.h"
11 #include "timing.h"
12 #include "vgaregs.h"
13 #include "driver.h"		/* for __svgalib_driver_report */
14 #include "ramdac.h"
15 
16 /* SDAC/GENDAC registers */
17 #if defined(INCLUDE_S3_SDAC_DAC) || defined(INCLUDE_S3_GENDAC_DAC)
18 #define SDAC_COMMAND		0	/* Register offsets into state. */
19 #define GENDAC_COMMAND		0
20 #define SDAC_PLL_WRITEINDEX	1
21 #define SDAC_PLL_READINDEX	2
22 #define SDAC_PLL_M		3	/* f2 programmed clock */
23 #define SDAC_PLL_N1_N2		4
24 #define SDAC_PLL_CONTROL	5
25 
26 #define SDAC_STATESIZE 6	/* 6 registers. */
27 #define GENDAC_STATESIZE 6
28 #endif
29 
30 #if defined(INCLUDE_S3_SDAC_DAC_TEST) || defined(INCLUDE_S3_GENDAC_DAC_TEST)
GENDAC_SDAC_probe(void)31 static int GENDAC_SDAC_probe(void)
32 {
33 /* Taken from XFree86, accel/s3.c. */
34 /* Return 1 if GENDAC found, 2 if SDAC, 0 otherwise. */
35     /* probe for S3 GENDAC or SDAC */
36     /*
37      * S3 GENDAC and SDAC have two fixed read only PLL clocks
38      *     CLK0 f0: 25.255MHz   M-byte 0x28  N-byte 0x61
39      *     CLK0 f1: 28.311MHz   M-byte 0x3d  N-byte 0x62
40      * which can be used to detect GENDAC and SDAC since there is no chip-id
41      * for the GENDAC.
42      *
43      * NOTE: for the GENDAC on a MIRO 10SD (805+GENDAC) reading PLL values
44      * for CLK0 f0 and f1 always returns 0x7f (but is documented "read only")
45      */
46 
47     unsigned char saveCR55, savelut[6];
48     int i;
49     long clock01, clock23;
50 
51     saveCR55 = __svgalib_inCR(0x55);
52     __svgalib_outbCR(0x55, saveCR55 & ~1);
53 
54     outb(0x3c7, 0);
55     for (i = 0; i < 2 * 3; i++)	/* save first two LUT entries */
56 	savelut[i] = inb(0x3c9);
57     outb(0x3c8, 0);
58     for (i = 0; i < 2 * 3; i++)	/* set first two LUT entries to zero */
59 	outb(0x3c9, 0);
60 
61     __svgalib_outbCR(0x55, saveCR55 | 1);
62 
63     outb(0x3c7, 0);
64     for (i = clock01 = 0; i < 4; i++)
65 	clock01 = (clock01 << 8) | (inb(0x3c9) & 0xff);
66     for (i = clock23 = 0; i < 4; i++)
67 	clock23 = (clock23 << 8) | (inb(0x3c9) & 0xff);
68 
69     __svgalib_outbCR(0x55, saveCR55 & ~1);
70 
71     outb(0x3c8, 0);
72     for (i = 0; i < 2 * 3; i++)	/* restore first two LUT entries */
73 	outb(0x3c9, savelut[i]);
74 
75     __svgalib_outbCR(0x55, saveCR55);
76 
77     if (clock01 == 0x28613d62 ||
78 	(clock01 == 0x7f7f7f7f && clock23 != 0x7f7f7f7f)) {
79 
80 	inb(0x3c8);		/* dactopel */
81 
82 	inb(0x3c6);
83 	inb(0x3c6);
84 	inb(0x3c6);
85 
86 	/* the forth read will show the SDAC chip ID and revision */
87 	if (((i = inb(0x3c6)) & 0xf0) == 0x70) {
88 	    return 2;		/* SDAC found. */
89 	} else {
90 	    return 1;		/* GENDAC found. */
91 	}
92 	inb(0x3c8);		/* dactopel */
93     }
94     return 0;
95 }
96 #endif
97 
98 #if defined(INCLUDE_S3_SDAC_DAC) || defined(INCLUDE_S3_GENDAC_DAC)
GENDAC_SDAC_init(void)99 static void GENDAC_SDAC_init(void)
100 {
101     unsigned char val;
102     int m, n, n1, n2, MCLK;
103     val = __svgalib_inCR(0x55);
104     __svgalib_outbCR(0x55, val | 0x01);
105 
106     outb(0x3C7, 10);		/* Read MCLK. */
107     m = inb(0x3C9);
108     n = inb(0x3C9);
109 
110     __svgalib_outbCR(0x55, val);		/* Restore CR55. */
111 
112     m &= 0x7f;
113     n1 = n & 0x1f;
114     n2 = (n >> 5) & 0x03;
115     /* Calculate MCLK in kHz. */
116     MCLK = 14318 * (m + 2) / (n1 + 2) / (1 << n2);
117     if (__svgalib_driver_report)
118 	printf("svgalib: S3-GENDAC/SDAC: MCLK = %d.%03d MHz\n",
119 	       MCLK / 1000, MCLK % 1000);
120 }
121 #endif
122 
123 
124 #if defined(INCLUDE_S3_SDAC_DAC) || defined(INCLUDE_S3_GENDAC_DAC) || defined(INCLUDE_S3_TRIO64_DAC)
125 /*
126  * From XFree86 common_hw/S3gendac.c and S3gendac.h.
127  *
128  * Progaming of the S3 gendac programable clocks, from the S3 Gendac
129  * programing documentation by S3 Inc.
130  * Jon Tombs <jon@esix2.us.es>
131  *
132  * Returns nonzero if success, 0 if failure.
133  */
134 #define BASE_FREQ	     14.31818	/* MHz */
135 
136 #define DEBUG_FINDCLOCK 0
137 
S3dacsFindClock(int freq_in,int min_n2,int freq_min,int freq_max,int * best_m_out,int * best_n1_out,int * best_n2_out)138 static int S3dacsFindClock(int freq_in, int min_n2, int freq_min, int freq_max,
139 		     int *best_m_out, int *best_n1_out, int *best_n2_out)
140 {
141     double ffreq_in, ffreq_min, ffreq_max;
142     double ffreq_out, diff, best_diff;
143     unsigned int m;
144     unsigned char n1, n2;
145     unsigned char best_n1 = 16 + 2, best_n2 = 2, best_m = 125 + 2;
146 
147 #if DEBUG_FINDCLOCK
148     printf("S3dacsFindClock: Trying to match clock of %0.3f MHz\n", freq_in / 1000.0);
149 #endif
150 
151     ffreq_in = freq_in / 1000.0 / BASE_FREQ;
152     ffreq_min = freq_min / 1000.0 / BASE_FREQ;
153     ffreq_max = freq_max / 1000.0 / BASE_FREQ;
154 
155     /* Check if getting freq_in is possible at all */
156     if (freq_in < freq_min / 8) {
157 #if DEBUG_FINDCLOCK
158 	printf("S3dacsFindClock: %0.3f MHz is too low (lowest is %0.3f MHz)\n",
159 	       freq_in / 1000.0, freq_min / 1000.0 / 8);
160 #endif
161 	return 0;
162     }
163     if (freq_in > freq_max / (1 << min_n2)) {
164 #if DEBUG_FINDCLOCK
165 	printf("S3dacsFindClock: %0.3f MHz is too high (highest is %0.3f MHz)\n",
166 	       freq_in / 1000.0, freq_max / 1000.0 / (1 << min_n2));
167 #endif
168 	return 0;
169     }
170 
171     /* work out suitable timings */
172     best_diff = ffreq_in;
173     for (n2 = min_n2; n2 <= 3; n2++) {
174 	for (n1 = 1 + 2; n1 <= 31 + 2; n1++) {
175 	    m = (int) (ffreq_in * n1 * (1 << n2) + 0.5);
176 	    if (m < 1 + 2 || m > 127 + 2)
177 		continue;
178 	    ffreq_out = (double) (m) / (double) (n1);
179 	    if ((ffreq_out >= ffreq_min) && (ffreq_out <= ffreq_max)) {
180 		diff = ffreq_in - ffreq_out / (1 << n2);
181 		if (diff < 0.0)
182 		    diff = -diff;
183 		if (diff < best_diff) {
184 		    best_diff = diff;
185 		    best_m = m;
186 		    best_n1 = n1;
187 		    best_n2 = n2;
188 		}
189 	    }
190 	}
191     }
192 
193 #if DEBUG_FINDCLOCK
194     printf("S3dacsFindClock: clock wanted %1.6f MHz, found %1.6f MHz (m %d, n1 %d, n2 %d)\n",
195 	   freq_in / 1000.0,
196 	   best_m / ((double) best_n1 * (1 << best_n2)) * BASE_FREQ,
197 	   best_m, best_n1, best_n2);
198 #endif
199 
200     *best_m_out = best_m;
201     *best_n1_out = best_n1;
202     *best_n2_out = best_n2;
203 
204     return 1;
205 }
206 #endif
207 
208 #if defined(INCLUDE_S3_SDAC_DAC) || defined(INCLUDE_S3_GENDAC_DAC)
GENDAC_SDAC_match_programmable_clock(int desiredclock)209 static int GENDAC_SDAC_match_programmable_clock(int desiredclock)
210 {
211     int min_m, min_n1, n2;
212 
213     /* Note: For ICS5342, min_n2 parameter should be one. */
214     if (!S3dacsFindClock(desiredclock, 0, 100000, 250000, &min_m, &min_n1, &n2))
215 	return 0;
216 
217     return ((float) (min_m) / (float) (min_n1) / (1 << n2)) * BASE_FREQ * 1000;
218 }
219 
220 #if 0				/* Retained for reference. */
221 static void setdacpll(reg, data1, data2)
222 int reg;
223 unsigned char data1;
224 unsigned char data2;
225 {
226     unsigned char tmp, tmp1;
227     int vgaCRIndex = vgaIOBase + 4;
228     int vgaCRReg = vgaIOBase + 5;
229 
230     /* set RS2 via CR55, yuck */
231     tmp = __svgalib_inCR(0x55) & 0xFC;
232     __svgalib_outCR(tmp | 0x01);
233     tmp1 = inb(GENDAC_INDEX);
234 
235     outb(GENDAC_INDEX, reg);
236     outb(GENDAC_DATA, data1);
237     outb(GENDAC_DATA, data2);
238 
239     /* Now clean up our mess */
240     outb(GENDAC_INDEX, tmp1);
241     __svgalib_outbCR(0x55, tmp);
242 }
243 #endif
244 
GENDAC_SDAC_initialize_clock_state(unsigned char * regs,int freq)245 static void GENDAC_SDAC_initialize_clock_state(unsigned char *regs, int freq)
246 {
247     int min_m, min_n1, n2;
248     int n, m;
249 
250     if (!S3dacsFindClock(freq, 0, 100000, 250000, &min_m, &min_n1, &n2)) {
251 	printf("Bad dot clock %0.3f MHz.\n", freq / 1000.0);
252 	return;
253     }
254 
255     n = (min_n1 - 2) | (n2 << 5);
256     m = min_m - 2;
257     regs[SDAC_PLL_M] = m;
258     regs[SDAC_PLL_N1_N2] = n;
259     if (__svgalib_driver_report)
260 	printf("Initializing DAC PLL values; 0x%02X, 0x%02X.\n", m, n);
261 }
262 
GENDAC_SDAC_savestate(unsigned char * regs)263 static void GENDAC_SDAC_savestate(unsigned char *regs)
264 {
265     unsigned char tmp;
266     tmp = __svgalib_inCR(0x55);
267     __svgalib_outbCR(0x55, tmp | 1);
268 
269     regs[SDAC_COMMAND] = inb(0x3c6);
270     regs[SDAC_PLL_WRITEINDEX] = inb(0x3c8);	/* PLL write index */
271     regs[SDAC_PLL_READINDEX] = inb(0x3c7);	/* PLL read index */
272     outb(0x3c7, 2);		/* index to f2 reg */
273     regs[SDAC_PLL_M] = inb(0x3c9);	/* f2 PLL M divider */
274     regs[SDAC_PLL_N1_N2] = inb(0x3c9);	/* f2 PLL N1/N2 divider */
275     outb(0x3c7, 0x0e);		/* index to PLL control */
276     regs[SDAC_PLL_CONTROL] = inb(0x3c9);	/* PLL control */
277 
278     __svgalib_outbCR(0x55, tmp & ~1);
279 }
280 
GENDAC_SDAC_restorestate(const unsigned char * regs)281 static void GENDAC_SDAC_restorestate(const unsigned char *regs)
282 {
283     unsigned char tmp;
284 
285     /* set RS2 via CR55, yuck */
286     tmp = __svgalib_inCR(0x55) & 0xFC;
287     __svgalib_outbCR(0x55, tmp | 0x01);
288 
289 #ifdef DEBUG
290     do {
291 	int m, n1, n2, clk;
292 
293 	m = regs[SDAC_PLL_M] & 0x7f;
294 	n1 = regs[SDAC_PLL_N1_N2] & 0x1f;
295 	n2 = (regs[SDAC_PLL_N1_N2] & 0x60) >> 5;
296 
297 	clk = 14318 * (m + 2) / (n1 + 2) / (1 << n2);
298 	printf("SDAC.restorestate, setting clock 0x%02X 0x%02X (%d.%3dMHz)\n",
299 	       regs[SDAC_PLL_M],
300 	       regs[SDAC_PLL_N1_N2], clk / 1000, clk % 1000);
301     } while (0);
302 #endif
303 
304     outb(0x3c6, regs[SDAC_COMMAND]);
305     outb(0x3c8, 2);		/* index to f2 reg */
306     outb(0x3c9, regs[SDAC_PLL_M]);	/* f2 PLL M divider */
307     outb(0x3c9, regs[SDAC_PLL_N1_N2]);	/* f2 PLL N1/N2 divider */
308     outb(0x3c8, 0x0e);		/* index to PLL control */
309     outb(0x3c9, regs[SDAC_PLL_CONTROL]);	/* PLL control */
310     outb(0x3c8, regs[SDAC_PLL_WRITEINDEX]);	/* PLL write index */
311     outb(0x3c7, regs[SDAC_PLL_READINDEX]);	/* PLL read index */
312 
313     __svgalib_outbCR(0x55, tmp);
314 }
315 
316 #endif				/* defined(INCLUDE_S3_SDAC_DAC) || defined(INCLUDE_S3_GENDAC_DAC) */
317 
318 /*
319  * SDAC: 16-bit DAC, 110 MHz raw clock limit.
320  *
321  * The 135 MHz version supports pixel multiplexing in 8bpp modes with a
322  * halved raw clock. (SL: at least mine doesn't.)
323  */
324 
325 #ifdef INCLUDE_S3_SDAC_DAC_TEST
SDAC_probe(void)326 static int SDAC_probe(void)
327 {
328     return GENDAC_SDAC_probe() == 2;
329 }
330 #else
331 #define SDAC_probe 0
332 #endif
333 
334 #ifdef INCLUDE_S3_SDAC_DAC
SDAC_map_clock(int bpp,int pixelclock)335 static int SDAC_map_clock(int bpp, int pixelclock)
336 {
337     switch (bpp) {
338     case 4:
339     case 8:
340 #ifdef SDAC_8BPP_PIXMUX		/* SL: AFAIK it doesn't work */
341 	if (pixelclock >= 67500)
342 	    /* Use pixel multiplexing. */
343 	    return pixelclock / 2;
344 #endif
345 	break;
346     case 24:
347 	return pixelclock * 3 / 2;
348     case 32:
349 	return pixelclock * 2;
350     }
351     return pixelclock;
352 }
353 
SDAC_map_horizontal_crtc(int bpp,int pixelclock,int htiming)354 static int SDAC_map_horizontal_crtc(int bpp, int pixelclock, int htiming)
355 {
356     switch (bpp) {
357     case 16:
358 	return htiming * 2;
359     case 24:
360 	return htiming * 3;
361     case 32:
362 	return htiming * 4;
363     }
364     return htiming;
365 }
366 
SDAC_initializestate(unsigned char * regs,int bpp,int colormode,int pixelclock)367 static void SDAC_initializestate(unsigned char *regs, int bpp, int colormode,
368 				 int pixelclock)
369 {
370     int pixmux;			/* SDAC command register. */
371     pixmux = 0;
372     switch (colormode) {
373     case CLUT8_6:
374 #ifdef SDAC_8BPP_PIXMUX
375 	if (pixelclock >= 67500)
376 	    pixmux = 0x10;
377 #endif
378 	break;
379     case RGB16_555:
380 	pixmux = 0x30;
381 	break;
382     case RGB16_565:
383 	pixmux = 0x50;
384 	break;
385     case RGB24_888_B:
386 	/* Use 0x40 for 3 VCLK/pixel.  Change SDAC_map_clock and CR67 as well. */
387 	pixmux = 0x90;
388 	break;
389     case RGB32_888_B:
390 	pixmux = 0x70;
391 	break;
392     }
393     regs[SDAC_COMMAND] = pixmux;
394     GENDAC_SDAC_initialize_clock_state(regs,
395 				       SDAC_map_clock(bpp, pixelclock));
396 }
397 
SDAC_qualify_cardspecs(CardSpecs * cardspecs,int dacspeed)398 static void SDAC_qualify_cardspecs(CardSpecs * cardspecs, int dacspeed)
399 {
400     dacspeed = __svgalib_setDacSpeed(dacspeed, 110000);	/* most can do 135MHz. */
401     cardspecs->maxPixelClock4bpp = dacspeed;
402     cardspecs->maxPixelClock8bpp = dacspeed;
403     cardspecs->maxPixelClock16bpp = dacspeed;
404     cardspecs->maxPixelClock24bpp = dacspeed * 2 / 3;
405     cardspecs->maxPixelClock32bpp = dacspeed / 2;
406     cardspecs->mapClock = SDAC_map_clock;
407     cardspecs->matchProgrammableClock = GENDAC_SDAC_match_programmable_clock;
408     cardspecs->mapHorizontalCrtc = SDAC_map_horizontal_crtc;
409     cardspecs->flags |= CLOCK_PROGRAMMABLE;
410 }
411 
412 DacMethods __svgalib_S3_SDAC_methods =
413 {
414     S3_SDAC,
415     "S3-SDAC (86C716)",
416     DAC_HAS_PROGRAMMABLE_CLOCKS,
417     SDAC_probe,
418     GENDAC_SDAC_init,
419     SDAC_qualify_cardspecs,
420     GENDAC_SDAC_savestate,
421     GENDAC_SDAC_restorestate,
422     SDAC_initializestate,
423     SDAC_STATESIZE
424 };
425 #endif
426 
427 
428 /* S3-GENDAC, 8-bit DAC. */
429 
430 #ifdef INCLUDE_S3_GENDAC_DAC_TEST
GENDAC_probe(void)431 static int GENDAC_probe(void)
432 {
433     return GENDAC_SDAC_probe() == 1;
434 }
435 #else
436 #define GENDAC_probe 0
437 #endif
438 
439 #ifdef INCLUDE_S3_GENDAC_DAC
GENDAC_map_clock(int bpp,int pixelclock)440 static int GENDAC_map_clock(int bpp, int pixelclock)
441 {
442     if (bpp == 16)
443 	return pixelclock * 2;
444     if (bpp == 24)
445 	return pixelclock * 3;
446     if (bpp == 32)
447 	return pixelclock * 4;
448     return pixelclock;
449 }
450 
GENDAC_map_horizontal_crtc(int bpp,int pixelclock,int htiming)451 static int GENDAC_map_horizontal_crtc(int bpp, int pixelclock, int htiming)
452 {
453     /* XXXX Not sure. */
454     if (bpp == 24)
455 	return htiming * 3;
456     if (bpp == 16)
457 	return htiming * 2;
458     return htiming;
459 }
460 
GENDAC_initializestate(unsigned char * regs,int bpp,int colormode,int pixelclock)461 static void GENDAC_initializestate(unsigned char *regs, int bpp, int colormode,
462 				   int pixelclock)
463 {
464     int daccomm;		/* DAC command register. */
465     daccomm = 0;
466     if (colormode == RGB16_555)
467 	daccomm = 0x20;
468     else if (colormode == RGB16_565)
469 	daccomm = 0x60;
470     else if (colormode == RGB24_888_B)
471 	daccomm = 0x40;
472     regs[GENDAC_COMMAND] = daccomm;
473     GENDAC_SDAC_initialize_clock_state(regs,
474 				       GENDAC_map_clock(bpp, pixelclock));
475 }
476 
GENDAC_qualify_cardspecs(CardSpecs * cardspecs,int dacspeed)477 static void GENDAC_qualify_cardspecs(CardSpecs * cardspecs, int dacspeed)
478 {
479     dacspeed = __svgalib_setDacSpeed(dacspeed, 110000);
480     cardspecs->maxPixelClock4bpp = dacspeed;
481     cardspecs->maxPixelClock8bpp = dacspeed;
482     cardspecs->maxPixelClock16bpp = dacspeed / 2;
483     cardspecs->maxPixelClock24bpp = dacspeed / 3;
484     cardspecs->maxPixelClock32bpp = 0;
485     cardspecs->mapClock = GENDAC_map_clock;
486     cardspecs->matchProgrammableClock = GENDAC_SDAC_match_programmable_clock;
487     cardspecs->mapHorizontalCrtc = GENDAC_map_horizontal_crtc;
488     cardspecs->flags |= CLOCK_PROGRAMMABLE;
489 }
490 
491 DacMethods __svgalib_S3_GENDAC_methods =
492 {
493     S3_GENDAC,
494     "S3-GENDAC (86C708)",
495     DAC_HAS_PROGRAMMABLE_CLOCKS,
496     GENDAC_probe,
497     GENDAC_SDAC_init,
498     GENDAC_qualify_cardspecs,
499     GENDAC_SDAC_savestate,
500     GENDAC_SDAC_restorestate,
501     GENDAC_initializestate,
502     GENDAC_STATESIZE
503 };
504 #endif
505 
506 
507 #ifdef INCLUDE_S3_TRIO64_DAC
508 /* S3-Trio64, 16-bit integrated DAC. */
509 
510 #define	TRIO64_SR15		0
511 #define TRIO64_SR18		1
512 #define TRIO64_PLL_N1_N2	2
513 #define TRIO64_PLL_M		3
514 #define TRIO64_CR67		4
515 #define TRIO64_SRB		5
516 #define TRIO64_STATESIZE	6
517 
518 /* Note: s3.c also defines CR67, but doesn't use it for the Trio64. */
519 
520 extern int s3Mclk;
521 
Trio64_get_mclk(void)522 static int Trio64_get_mclk(void)
523 {
524     unsigned char sr8;
525     int m, n, n1, n2;
526 
527     outb(0x3c4, 0x08);
528     sr8 = inb(0x3c5);
529     outb(0x3c5, 0x06);
530 
531     outb(0x3c4, 0x11);
532     m = inb(0x3c5);
533     outb(0x3c4, 0x10);
534     n = inb(0x3c5);
535 
536     outb(0x3c4, 0x08);
537     outb(0x3c5, sr8);
538 
539     m &= 0x7f;
540     n1 = n & 0x1f;
541     n2 = (n >> 5) & 0x03;
542     /* Calculate MCLK in kHz. */
543     return ((1431818 * (m + 2)) / (n1 + 2) / (1 << n2) + 50) / 100;
544 }
545 
546 #if 0
547 static void Trio64_set_mclk(int khz)
548 /* Doesn't work.  Locks computer up.  Why? */
549 {
550     int sr8;
551     int min_m, min_n1, n2;
552 
553     if (!S3dacsFindClock(khz, 0, 40000, 70000, &min_m, &min_n1, &n2)) {
554 	printf("Bad MCLK %0.3f MHz.\n", khz / 1000.0);
555 	return;
556     }
557 
558     printf("%0.3f MHz MCLK, m = %d, n = %d, r = %d\n", khz / 1000.0, min_m - 2, min_n1 - 2, n2);
559     outb(0x3C4, 0x08);
560     sr8 = inb(0x3C5);
561     outb(0x3C5, 0x06);		/* Unlock. */
562 
563     outb(0x3c4, 0x15);
564     outb(0x3c5, inb(0x3c5) & ~0x20);
565 
566     /* MCLK. */
567     __svgalib_outSR(0x10, (min_n1 - 2) | (n2 << 5));
568     __svgalib_outSR(0x11, min_m - 2);
569 
570     outb(0x3c4, 0x15);
571     outb(0x3c5, inb(0x3c5) | 0x20);
572     outb(0x3c5, inb(0x3c5) & ~0x20);
573 
574     __svgalib_outSR(0x08, sr8);
575 }
576 #endif
577 
Trio64_init(void)578 static void Trio64_init(void)
579 {
580     int mclk;
581 
582     mclk = Trio64_get_mclk();
583     if (__svgalib_driver_report)
584 	printf("svgalib: RAMDAC: Trio64: MCLK = %0.3f MHz\n",
585 	       mclk / 1000.0);
586     s3Mclk = mclk;
587 }
588 
Trio64_map_clock(int bpp,int pixelclock)589 static int Trio64_map_clock(int bpp, int pixelclock)
590 {
591     if (bpp == 8 && pixelclock >= 67500) /* use pixel doubling */
592 	return pixelclock / 2;
593     if (bpp == 24)
594 	return pixelclock * 3;
595     return pixelclock;
596 }
597 
Trio64_map_horizontal_crtc(int bpp,int pixelclock,int htiming)598 static int Trio64_map_horizontal_crtc(int bpp, int pixelclock, int htiming)
599 {
600     if (bpp == 16)
601 	return htiming * 2;
602     /* Normal mapping for 8bpp and 32bpp. */
603     return htiming;
604 }
605 
Trio64_initialize_clock_state(unsigned char * regs,int freq)606 static void Trio64_initialize_clock_state(unsigned char *regs, int freq)
607 {
608     int min_m, min_n1, n2;
609     int n, m;
610 
611     if (!S3dacsFindClock(freq, 0, 130000, 270000, &min_m, &min_n1, &n2)) {
612 	printf("Bad dot clock %0.3f MHz.\n", freq / 1000.0);
613 	return;
614     }
615 
616     n = (min_n1 - 2) | (n2 << 5);
617     m = min_m - 2;
618     regs[TRIO64_PLL_M] = m;
619     regs[TRIO64_PLL_N1_N2] = n;
620 }
621 
Trio64_match_programmable_clock(int desiredclock)622 static int Trio64_match_programmable_clock(int desiredclock)
623 {
624     int min_m, min_n1, n2;
625 
626     if (!S3dacsFindClock(desiredclock, 0, 130000, 270000, &min_m, &min_n1, &n2))
627 	return 0;
628 
629     return ((float) (min_m) / (float) (min_n1) / (1 << n2)) * BASE_FREQ * 1000;
630 }
631 
Trio64_initializestate(unsigned char * regs,int bpp,int colormode,int pixelclock)632 static void Trio64_initializestate(unsigned char *regs, int bpp, int colormode,
633 				   int pixelclock)
634 {
635     int pixmux, reserved_CR67_1;
636 
637     regs[TRIO64_SR15] &= ~0x50;
638     regs[TRIO64_SR18] &= ~0x80;
639     pixmux = 0;
640     reserved_CR67_1 = 0;
641     if (bpp == 8 && pixelclock >= 67500) {
642 	pixmux = 0x10;
643 	reserved_CR67_1 = 2;
644 	regs[TRIO64_SR15] |= 0x50;
645 	regs[TRIO64_SR18] |= 0x80;
646     } else if (bpp == 16) {
647 	/* moderegs[S3_CR33] |= 0x08; *//* done in s3.c. */
648 	if (colormode == RGB16_555)
649 	    pixmux = 0x30;
650 	else
651 	    pixmux = 0x50;
652 	reserved_CR67_1 = 2;
653     } else if (colormode == RGB24_888_B) {
654 	/* remember to adjust SRB as well. */
655 	pixmux = 0x00;
656     } else if (colormode == RGB32_888_B) {
657 	pixmux = 0xD0;		/* 32-bit color, 2 VCLKs/pixel. */
658 	reserved_CR67_1 = 2;
659     }
660     regs[TRIO64_CR67] = pixmux | reserved_CR67_1;
661 
662     Trio64_initialize_clock_state(regs, pixelclock);
663 }
664 
Trio64_savestate(unsigned char * regs)665 static void Trio64_savestate(unsigned char *regs)
666 {
667     unsigned char sr8;
668     outb(0x3C4, 0x08);
669     sr8 = inb(0x3C5);
670     outb(0x3C5, 0x06);		/* Unlock. */
671 
672     regs[TRIO64_SR15] = __svgalib_inSR(0x15);
673     regs[TRIO64_SR18] = __svgalib_inSR(0x18);
674     regs[TRIO64_PLL_N1_N2] = __svgalib_inSR(0x12);
675     regs[TRIO64_PLL_M] = __svgalib_inSR(0x13);
676     regs[TRIO64_CR67] = __svgalib_inCR(0x67);
677 
678     __svgalib_outSR(0x08, sr8);
679 }
680 
Trio64_restorestate(const unsigned char * regs)681 static void Trio64_restorestate(const unsigned char *regs)
682 {
683     unsigned char sr8, tmp;
684 
685     outb(0x3C4, 0x08);
686     sr8 = inb(0x3C5);
687     outb(0x3C5, 0x06);		/* Unlock. */
688 
689     __svgalib_outCR(0x67, regs[TRIO64_CR67]);
690 
691     __svgalib_outSR(0x15, regs[TRIO64_SR15]);
692     __svgalib_outSR(0x18, regs[TRIO64_SR18]);
693 
694     /* Clock. */
695     __svgalib_outSR(0x12, regs[TRIO64_PLL_N1_N2]);
696     __svgalib_outSR(0x13, regs[TRIO64_PLL_M]);
697 
698 #if 0
699     /*
700      * XFree86 XF86_S3 (common_hw/gendac.c) has this, but it looks
701      * incorrect, it should flip the bit by writing to 0x3c5, not
702      * 0x3c4.
703      */
704     outb(0x3c4, 0x15);
705     tmp = inb(0x3c5);
706     outb(0x3c4, tmp & ~0x20);
707     outb(0x3c4, tmp | 0x20);
708     outb(0x3c4, tmp & ~0x20);
709 #else
710     outb(0x3c4, 0x15);
711     tmp = inb(0x3c5);
712     outb(0x3c5, tmp & ~0x20);
713     outb(0x3c5, tmp | 0x20);
714     outb(0x3c5, tmp & ~0x20);
715 #endif
716 
717     __svgalib_outSR(0x08, sr8);
718 }
719 
720 
Trio64_qualify_cardspecs(CardSpecs * cardspecs,int dacspeed)721 static void Trio64_qualify_cardspecs(CardSpecs * cardspecs, int dacspeed)
722 {
723     if (dacspeed) {
724 	if (__svgalib_driver_report)
725 	    printf("svgalib: using 'dacspeed' not recommended for this RAMDAC.\n");
726 	cardspecs->maxPixelClock4bpp = dacspeed;
727 	cardspecs->maxPixelClock8bpp = 135000;
728 	cardspecs->maxPixelClock16bpp = dacspeed;
729 	cardspecs->maxPixelClock24bpp = 0; /* dacspeed / 3; *//* How to program? */
730 	cardspecs->maxPixelClock32bpp = 50000;
731     } else {
732 	cardspecs->maxPixelClock4bpp = 80000;
733 	cardspecs->maxPixelClock8bpp = 135000;
734 	cardspecs->maxPixelClock16bpp = 80000;
735 	cardspecs->maxPixelClock24bpp = 0; /* 25000; *//* How to program? */
736 	cardspecs->maxPixelClock32bpp = 50000;
737     }
738     cardspecs->mapClock = Trio64_map_clock;
739     cardspecs->matchProgrammableClock = Trio64_match_programmable_clock;
740     cardspecs->mapHorizontalCrtc = Trio64_map_horizontal_crtc;
741     cardspecs->flags |= CLOCK_PROGRAMMABLE;
742 }
743 
744 DacMethods __svgalib_Trio64_methods =
745 {
746     TRIO64,
747     "S3-Trio64 internal DAC",
748     DAC_HAS_PROGRAMMABLE_CLOCKS,
749     NULL,			/* probe */
750     Trio64_init,
751     Trio64_qualify_cardspecs,
752     Trio64_savestate,
753     Trio64_restorestate,
754     Trio64_initializestate,
755     TRIO64_STATESIZE
756 };
757 #endif
758