Subversion Repositories shark

Rev

Rev 54 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
54 pj 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)
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)
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
        printk(KERN_INFO "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
 
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
    printk(KERN_INFO "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
        printk(KERN_INFO "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
        printk(KERN_INFO "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
    printk(KERN_INFO "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)
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
 
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
        printk(KERN_INFO "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
        printk(KERN_INFO "Initializing DAC PLL values; 0x%02X, 0x%02X.\n", m, n);
261
}
262
 
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
 
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
        printk(KERN_INFO "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
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
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
 
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
 
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
 
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
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
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
 
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
 
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
 
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 __svgalib_s3_s3Mclk;
521
 
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)) {
81 giacomo 554
        printk(KERN_INFO "Bad MCLK %0.3f MHz.\n", khz / 1000.0);
54 pj 555
        return;
556
    }
557
 
81 giacomo 558
    printk(KERN_INFO "%0.3f MHz MCLK, m = %d, n = %d, r = %d\n", khz / 1000.0, min_m - 2, min_n1 - 2, n2);
54 pj 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
 
578
static void Trio64_init(void)
579
{
580
    int mclk;
581
 
582
    mclk = Trio64_get_mclk();
583
    if (__svgalib_driver_report)
584
        printk(KERN_INFO "svgalib: RAMDAC: Trio64: MCLK = %0.3f MHz\n",
585
               mclk / 1000.0);
586
    __svgalib_s3_s3Mclk = mclk;
587
}
588
 
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
 
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
 
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
        printk(KERN_INFO "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
 
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
 
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
 
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
 
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
 
721
static void Trio64_qualify_cardspecs(CardSpecs * cardspecs, int dacspeed)
722
{
723
    if (dacspeed) {
724
        if (__svgalib_driver_report)
725
            printk(KERN_INFO "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