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
 * ics_gendac.c:
3
 *
4
 * This works only with ARK, since it has ARK specific code.
5
 */
6
 
7
#include <stdio.h>
8
#include "libvga.h"
9
#include "timing.h"
10
#include "vgaregs.h"
11
#include "driver.h"             /* for __svgalib_driver_report */
12
#include "ramdac.h"
13
 
14
/* SDAC/GENDAC registers */
15
#define SDAC_COMMAND            0
16
#define GENDAC_COMMAND          0
17
#define SDAC_PLL_WRITEINDEX     1
18
#define SDAC_PLL_READINDEX      2
19
#define SDAC_PLL_M              3       /* f2 programmed clock */
20
#define SDAC_PLL_N1_N2          4
21
#define SDAC_PLL_CONTROL        5
22
 
23
#define GENDAC_STATESIZE 6
24
 
25
static void GENDAC_init(void)
26
{
27
}
28
 
29
 
30
/*
31
 * From XFree86 common_hw/S3gendac.c and S3gendac.h.
32
 *
33
 * Progaming of the S3 gendac programable clocks, from the S3 Gendac
34
 * programing documentation by S3 Inc.
35
 * Jon Tombs <jon@esix2.us.es>
36
 *
37
 * Returns nonzero if success, 0 if failure.
38
 */
39
#define BASE_FREQ            14.31818   /* MHz */
40
 
41
#define DEBUG_FINDCLOCK 0
42
 
43
static int S3dacsFindClock(int freq_in, int min_n2, int freq_min, int freq_max,
44
                     int *best_m_out, int *best_n1_out, int *best_n2_out)
45
{
46
    double ffreq_in, ffreq_min, ffreq_max;
47
    double ffreq_out, diff, best_diff;
48
    unsigned int m;
49
    unsigned char n1, n2;
50
    unsigned char best_n1 = 16 + 2, best_n2 = 2, best_m = 125 + 2;
51
 
52
#if DEBUG_FINDCLOCK
81 giacomo 53
    cprintf("S3dacsFindClock: Trying to match clock of %0.3f MHz\n", freq_in / 1000.0);
54 pj 54
#endif
55
 
56
    ffreq_in = freq_in / 1000.0 / BASE_FREQ;
57
    ffreq_min = freq_min / 1000.0 / BASE_FREQ;
58
    ffreq_max = freq_max / 1000.0 / BASE_FREQ;
59
 
60
    /* Check if getting freq_in is possible at all */
61
    if (freq_in < freq_min / 8) {
62
#if DEBUG_FINDCLOCK
81 giacomo 63
        cprintf("S3dacsFindClock: %0.3f MHz is too low (lowest is %0.3f MHz)\n",
54 pj 64
               freq_in / 1000.0, freq_min / 1000.0 / 8);
65
#endif
66
        return 0;
67
    }  
68
    if (freq_in > freq_max / (1 << min_n2)) {
69
#if DEBUG_FINDCLOCK
81 giacomo 70
        cprintf("S3dacsFindClock: %0.3f MHz is too high (highest is %0.3f MHz)\n",
54 pj 71
               freq_in / 1000.0, freq_max / 1000.0 / (1 << min_n2));
72
#endif
73
        return 0;
74
    }
75
 
76
    /* work out suitable timings */
77
    best_diff = ffreq_in;
78
    for (n2 = min_n2; n2 <= 3; n2++) {
79
        for (n1 = 1 + 2; n1 <= 31 + 2; n1++) {
80
            m = (int) (ffreq_in * n1 * (1 << n2) + 0.5);
81
            if (m < 1 + 2 || m > 127 + 2)
82
                continue;
83
            ffreq_out = (double) (m) / (double) (n1);
84
            if ((ffreq_out >= ffreq_min) && (ffreq_out <= ffreq_max)) {
85
                diff = ffreq_in - ffreq_out / (1 << n2);
86
                if (diff < 0.0)
87
                    diff = -diff;
88
                if (diff < best_diff) {
89
                    best_diff = diff;
90
                    best_m = m;
91
                    best_n1 = n1;
92
                    best_n2 = n2;
93
                }
94
            }
95
        }
96
    }
97
 
98
#if DEBUG_FINDCLOCK
81 giacomo 99
    cprintf("S3dacsFindClock: clock wanted %1.6f MHz, found %1.6f MHz (m %d, n1 %d, n2 %d)\n",
54 pj 100
           freq_in / 1000.0,
101
           best_m / ((double) best_n1 * (1 << best_n2)) * BASE_FREQ,
102
           best_m, best_n1, best_n2);
103
#endif
104
 
105
    *best_m_out = best_m;
106
    *best_n1_out = best_n1;
107
    *best_n2_out = best_n2;
108
 
109
    return 1;
110
}
111
 
112
static int GENDAC_match_programmable_clock(int desiredclock)
113
{
114
    int min_m, min_n1, n2;
115
 
116
    /* Note: For ICS5342, min_n2 parameter should be one. */
117
    if (!S3dacsFindClock(desiredclock, 0, 100000, 250000, &min_m, &min_n1, &n2))
118
        return 0;
119
 
120
    return ((float) (min_m) / (float) (min_n1) / (1 << n2)) * BASE_FREQ * 1000;
121
}
122
 
123
static void GENDAC_initialize_clock_state(unsigned char *regs, int freq)
124
{
125
    int min_m, min_n1, n2;
126
    int n, m;
127
 
128
    if (!S3dacsFindClock(freq, 0, 100000, 250000, &min_m, &min_n1, &n2)) {
81 giacomo 129
        cprintf("Bad dot clock %0.3f MHz.\n", freq / 1000.0);
54 pj 130
        return;
131
    }
132
 
133
    n = (min_n1 - 2) | (n2 << 5);
134
    m = min_m - 2;
135
    regs[SDAC_PLL_M] = m;
136
    regs[SDAC_PLL_N1_N2] = n;
137
#if 0
138
    if (__svgalib_driver_report)
81 giacomo 139
        cprintf("Initializing DAC PLL values; 0x%02X, 0x%02X.\n", m, n);
54 pj 140
#endif
141
}
142
 
143
static void GENDAC_savestate(unsigned char *regs)
144
{
145
    unsigned char tmp;
146
    tmp = __svgalib_inSR(0x1c);
147
    __svgalib_outSR(0x1c, tmp | 0x80);
148
 
149
    regs[SDAC_COMMAND] = inb(0x3c6);
150
    regs[SDAC_PLL_WRITEINDEX] = inb(0x3c8);     /* PLL write index */
151
    regs[SDAC_PLL_READINDEX] = inb(0x3c7);      /* PLL read index */
152
    outb(0x3c7, 2);             /* index to f2 reg */
153
    regs[SDAC_PLL_M] = inb(0x3c9);      /* f2 PLL M divider */
154
    regs[SDAC_PLL_N1_N2] = inb(0x3c9);  /* f2 PLL N1/N2 divider */
155
    outb(0x3c7, 0x0e);          /* index to PLL control */
156
    regs[SDAC_PLL_CONTROL] = inb(0x3c9);        /* PLL control */
157
 
158
    __svgalib_outSR(0x1c, tmp & ~0x80);
159
}
160
 
161
static void GENDAC_restorestate(const unsigned char *regs)
162
{
163
    unsigned char tmp;
164
 
165
    tmp = __svgalib_inseq(0x1c);
166
    __svgalib_outseq(0x1c, tmp | 0x80);
167
 
168
    outb(0x3c6, regs[SDAC_COMMAND]);
169
    outb(0x3c8, 2);             /* index to f2 reg */
170
    outb(0x3c9, regs[SDAC_PLL_M]);      /* f2 PLL M divider */
171
    outb(0x3c9, regs[SDAC_PLL_N1_N2]);  /* f2 PLL N1/N2 divider */
172
    outb(0x3c8, 0x0e);          /* index to PLL control */
173
    outb(0x3c9, regs[SDAC_PLL_CONTROL]);        /* PLL control */
174
    outb(0x3c8, regs[SDAC_PLL_WRITEINDEX]);     /* PLL write index */
175
    outb(0x3c7, regs[SDAC_PLL_READINDEX]);      /* PLL read index */
176
 
177
    __svgalib_outseq(0x1c, tmp);
178
}
179
 
180
/*
181
 * SDAC: 16-bit DAC, 110 MHz raw clock limit.
182
 *
183
 * The 135 MHz version supports pixel multiplexing in 8bpp modes with a
184
 * halved raw clock. (SL: at least mine doesn't.)
185
 */
186
 
187
static int GENDAC_probe(void)
188
{
189
    int i;
190
    inb(0x3c6);
191
    inb(0x3c6);
192
    inb(0x3c6);
193
    i=inb(0x3c6);
194
    if(i==177) return 1;
195
    return 0;
196
}
197
 
198
static int GENDAC_map_clock(int bpp, int pixelclock)
199
{
200
    if (bpp == 16)
201
        return pixelclock * 2;
202
    if (bpp == 24)
203
        return pixelclock * 3;
204
    if (bpp == 32)
205
        return pixelclock * 4;
206
    return pixelclock;
207
}
208
 
209
static int GENDAC_map_horizontal_crtc(int bpp, int pixelclock, int htiming)
210
{
211
    /* XXXX Not sure. */
212
    if (bpp == 24)
213
        return htiming * 3;
214
    if (bpp == 16)
215
        return htiming * 2;
216
    return htiming;
217
}
218
 
219
static void GENDAC_initializestate(unsigned char *regs, int bpp, int colormode,
220
                                   int pixelclock)
221
{
222
    int daccomm;                /* DAC command register. */
223
    daccomm = 0;
224
    if (colormode == RGB16_555)
225
        daccomm = 0x20;
226
    else if (colormode == RGB16_565)
227
        daccomm = 0x60;
228
    else if (colormode == RGB24_888_B)
229
        daccomm = 0x40;
230
    regs[GENDAC_COMMAND] = daccomm;
231
    GENDAC_initialize_clock_state(regs,
232
                                       GENDAC_map_clock(bpp, pixelclock));
233
}
234
 
235
static void GENDAC_qualify_cardspecs(CardSpecs * cardspecs, int dacspeed)
236
{
237
    dacspeed = __svgalib_setDacSpeed(dacspeed, 110000);
238
    cardspecs->maxPixelClock4bpp = dacspeed;
239
    cardspecs->maxPixelClock8bpp = dacspeed;
240
    cardspecs->maxPixelClock16bpp = dacspeed / 2;
241
    cardspecs->maxPixelClock24bpp = dacspeed / 3;
242
    cardspecs->maxPixelClock32bpp = 0;
243
    cardspecs->mapClock = GENDAC_map_clock;
244
    cardspecs->matchProgrammableClock = GENDAC_match_programmable_clock;
245
    cardspecs->mapHorizontalCrtc = GENDAC_map_horizontal_crtc;
246
    cardspecs->flags |= CLOCK_PROGRAMMABLE;
247
}
248
 
249
DacMethods __svgalib_ICS_GENDAC_methods =
250
{
251
    S3_GENDAC,
252
    "ICS-GENDAC (5342)",
253
    DAC_HAS_PROGRAMMABLE_CLOCKS,
254
    GENDAC_probe,
255
    GENDAC_init,
256
    GENDAC_qualify_cardspecs,
257
    GENDAC_savestate,
258
    GENDAC_restorestate,
259
    GENDAC_initializestate,
260
    GENDAC_STATESIZE
261
};