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