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
 * icd2061a.c
3
 *
4
 * support for the ICD 2061A programmable clockchip and compatibles
5
 * outside of the DAC
6
 *
7
 * Rev history:
8
 * Andreas Arens Dec 95: Created
9
 *
10
 * Andreas Arens Feb 15 1996: A few minor fixes
11
 */
12
 
13
#include "timing.h"
14
#include "libvga.h"
15
#include "ramdac.h"
16
#include "clockchip.h"
17
#include "driver.h"
18
#include "vga.h"
19
 
20
/*
21
 * ATTENTION: The ICD 2061A does not support reading of the currently selected
22
 * pixelclock. XFree86 also fails to restore this value correctly, but always
23
 * estores a 45 MHz pixelclock. My standard text mode (132x25) uses 40 MHz,
24
 * which is the value selected here.
25
 * You can use the SVGATextMode-1.0 'clockprobe' tool right after boot to
26
 * determine the value used with your card and modify here, but since 40 MHz
27
 * is the VESA suggested pixelclock for a 70 Hz 132x25 mode, the value here
28
 * seems fine. Note that 80xXX modes use 25 or 28 MHz clocks, which are fixed
29
 * and not affected by this. This might not be true for Diamond boards using
30
 * the DCS2824-0 clockchip, which is an ICD 2061A clone.
31
 */
32
#define I2061A_DEFAULT_TEXT_FREQUENCY   (40000L)        /* kHz */
33
 
34
/*
35
 * Clockchip code is derived from I2051Aalt.c in XFree86/common_hw which
36
 * in turn is derived from code available from the STB bulletin board.
37
 * A number of modifications have been made to fit this into SVGAlib.
38
 */
39
 
40
#define I2061A_CRYSTAL_FREQUENCY       (14.31818 * 2.0)
41
 
42
static double I2061A_range[15] =
43
{50.0, 51.0, 53.2, 58.5, 60.7, 64.4, 66.8, 73.5,
44
 75.6, 80.9, 83.2, 91.5, 100.0, 120.0, 120.0000001};
45
 
46
static long I2061A_SelectClock(long frequency)
47
                                /* in KHz */
48
{
49
    unsigned int m;
50
    int i;
51
    double freq, fvco;
52
    double dev, devx;
53
    double delta, deltax;
54
    double f0;
55
    unsigned int p, q;
56
    unsigned int bestp = 0, bestq = 0, bestm = 0, besti = 0;
57
 
58
    freq = ((double) frequency) / 1000.0;
59
    if (freq > I2061A_range[13])
60
        freq = I2061A_range[13];
61
    else if (freq < 7.0)
62
        freq = 7.0;
63
 
64
    /*
65
     *  Calculate values to load into ICD 2061A clock chip to set frequency
66
     */
67
    delta = 999.0;
68
    dev = 999.0;
69
 
70
    for (m = 0; m < 8; m++) {
71
        fvco = freq * (1 << m);
72
        if (fvco < 50.0 || fvco > 120.0)
73
            continue;
74
 
75
        f0 = fvco / I2061A_CRYSTAL_FREQUENCY;
76
 
77
        for (q = 14; q <= 71; q++) {    /* q={15..71}:Constraint 2 on page 14 */
78
            p = (int) (f0 * q + 0.5);
79
            if (p < 4 || p > 130)       /* p={4..130}:Constraint 5 on page 14 */
80
                continue;
81
            deltax = (double) (p) / (double) (q) - f0;
82
            if (deltax < 0)
83
                deltax = -deltax;
84
            if (deltax <= delta) {
85
                for (i = 13; i >= 0; i--)
86
                    if (fvco >= I2061A_range[i])
87
                        break;
88
                devx = (fvco - (I2061A_range[i] + I2061A_range[i + 1]) / 2) / fvco;
89
                if (devx < 0)
90
                    devx = -devx;
91
                if (deltax < delta || devx < dev) {
92
                    delta = deltax;
93
                    dev = devx;
94
                    bestp = p;
95
                    bestq = q;
96
                    bestm = m;
97
                    besti = i;
98
                }
99
            }
100
        }
101
    }
102
    return ((((((long) besti << 7) | (bestp - 3)) << 3) | bestm) << 7) | (bestq - 2);
103
}
104
 
105
static int I2061A_GetClock(long dwv)
106
{
107
    int clock_q = (dwv & 0x7f) + 2;
108
    int clock_m = (dwv >> 7) & 7;
109
    int clock_p = ((dwv >> 10) & 0x7f) + 3;
110
    double fvco;
111
 
112
    fvco = I2061A_CRYSTAL_FREQUENCY / (1 << clock_m);
113
    return (int) (((fvco * clock_p) / clock_q) * 1000);
114
}
115
 
116
/* needs some delay for really fast cpus */
117
#define wrt_clk_bit(v) outb(MIS_W, v), (void)inb(crtcaddr), (void)inb(crtcaddr)
118
 
119
/* ATTENTION: This assumes CRTC registers and S3 registers to be UNLOCKED! */
120
static void I2061A_init_clock(unsigned long setup)
121
{
122
    unsigned char nclk[2], clk[2];
123
    unsigned short restore42;
124
    unsigned short oldclk;
125
    unsigned short bitval;
126
    int i;
127
    unsigned char c;
128
    unsigned short crtcaddr = (inb(MIS_R) & 0x01) ? CRT_IC : CRT_IM;
129
 
130
    oldclk = inb(MIS_R);
131
 
132
    outb(crtcaddr, 0x42);
133
    restore42 = inb(crtcaddr + 1);
134
 
135
    outw(SEQ_I, 0x0100);
136
 
137
    outb(SEQ_I, 1);
138
    c = inb(SEQ_D);
139
    outb(SEQ_D, 0x20 | c);
140
 
141
    outb(crtcaddr, 0x42);
142
    outb(crtcaddr + 1, 0x03);
143
 
144
    outw(SEQ_I, 0x0300);
145
 
146
    nclk[0] = oldclk & 0xF3;
147
    nclk[1] = nclk[0] | 0x08;
148
    clk[0] = nclk[0] | 0x04;
149
    clk[1] = nclk[0] | 0x0C;
150
 
151
    outb(crtcaddr, 0x42);
152
    (void) inb(crtcaddr + 1);
153
 
154
    outw(SEQ_I, 0x0100);
155
 
156
    wrt_clk_bit(oldclk | 0x08);
157
    wrt_clk_bit(oldclk | 0x0C);
158
    for (i = 0; i < 5; i++) {
159
        wrt_clk_bit(nclk[1]);
160
        wrt_clk_bit(clk[1]);
161
    }
162
    wrt_clk_bit(nclk[1]);
163
    wrt_clk_bit(nclk[0]);
164
    wrt_clk_bit(clk[0]);
165
    wrt_clk_bit(nclk[0]);
166
    wrt_clk_bit(clk[0]);
167
    for (i = 0; i < 24; i++) {
168
        bitval = setup & 0x01;
169
        setup >>= 1;
170
        wrt_clk_bit(clk[1 - bitval]);
171
        wrt_clk_bit(nclk[1 - bitval]);
172
        wrt_clk_bit(nclk[bitval]);
173
        wrt_clk_bit(clk[bitval]);
174
    }
175
    wrt_clk_bit(clk[1]);
176
    wrt_clk_bit(nclk[1]);
177
    wrt_clk_bit(clk[1]);
178
 
179
    outb(SEQ_I, 1);
180
    c = inb(SEQ_D);
181
    outb(SEQ_D, 0xDF & c);
182
 
183
    outb(crtcaddr, 0x42);
184
    outb(crtcaddr + 1, restore42);
185
 
186
    outb(MIS_W, oldclk);
187
 
188
    outw(SEQ_I, 0x0300);
189
 
190
    vga_waitretrace();
191
    vga_waitretrace();
192
    vga_waitretrace();
193
    vga_waitretrace();
194
    vga_waitretrace();
195
    vga_waitretrace();
196
    vga_waitretrace();          /* 0.10 second delay... */
197
}
198
 
199
static int I2061A_match_programmable_clock(int desiredclock)
200
{
201
    long dvw;
202
 
203
    dvw = I2061A_SelectClock((long) desiredclock);
204
    if (dvw)
205
        return I2061A_GetClock(dvw);
206
    return 0;
207
}
208
 
209
static void I2061A_saveState(unsigned char *regs)
210
{
211
    long *dvwp;
212
 
213
    if (__svgalib_I2061A_clockchip_methods.DAC_saveState)
214
        __svgalib_I2061A_clockchip_methods.DAC_saveState(regs);
215
 
216
    dvwp = (long *) (regs + __svgalib_I2061A_clockchip_methods.DAC_stateSize);
217
    *dvwp = I2061A_SelectClock(__svgalib_I2061A_clockchip_methods.TextFrequency);
218
}
219
 
220
static void I2061A_restoreState(const unsigned char *regs)
221
{
222
    unsigned int clknum = 2;
223
    long *dvwp;
224
 
225
    if (__svgalib_I2061A_clockchip_methods.DAC_restoreState)
226
        __svgalib_I2061A_clockchip_methods.DAC_restoreState(regs);
227
    dvwp = (long *) (regs + __svgalib_I2061A_clockchip_methods.DAC_stateSize);
228
    if (*dvwp) {
229
        /*
230
         * Write ICD 2061A clock chip - assumes S3 to be unlocked!
231
         */
232
        I2061A_init_clock(((unsigned long) *dvwp) | (((long) clknum) << 21));
233
    }
234
}
235
 
236
static void I2061A_initializeState(unsigned char *regs, int bpp, int colormode, int pixelclock)
237
{
238
    long *dvwp;
239
 
240
    if (__svgalib_I2061A_clockchip_methods.DAC_initializeState)
241
        __svgalib_I2061A_clockchip_methods.DAC_initializeState(regs, bpp, colormode, pixelclock);
242
 
243
    dvwp = (long *) (regs + __svgalib_I2061A_clockchip_methods.DAC_stateSize);
244
 
245
    if (bpp > 16)
246
        pixelclock *= 4;
247
    else if (bpp > 8)
248
        pixelclock *= 2;
249
 
250
    *dvwp = I2061A_SelectClock((long) pixelclock);
251
}
252
 
253
/* This functions patches the DacMethod to route through the ClockChip Method */
254
static void I2061A_init(CardSpecs * cardspecs, DacMethods * DAC)
255
{
256
    if (DAC && !__svgalib_I2061A_clockchip_methods.DAC_initializeState) {
257
        if (__svgalib_driver_report)
81 giacomo 258
            cprintf("svgalib: Using ICD2061A or compatible clockchip.\n");
54 pj 259
        __svgalib_I2061A_clockchip_methods.DAC_initializeState = DAC->initializeState;
260
        __svgalib_I2061A_clockchip_methods.DAC_saveState = DAC->saveState;
261
        __svgalib_I2061A_clockchip_methods.DAC_restoreState = DAC->restoreState;
262
        __svgalib_I2061A_clockchip_methods.DAC_stateSize = DAC->stateSize;
263
        DAC->initializeState = I2061A_initializeState;
264
        DAC->saveState = I2061A_saveState;
265
        DAC->restoreState = I2061A_restoreState;
266
        DAC->stateSize += sizeof(long);
267
        cardspecs->matchProgrammableClock = I2061A_match_programmable_clock;
268
        cardspecs->flags |= CLOCK_PROGRAMMABLE;
269
    }
270
}
271
 
272
ClockChipMethods __svgalib_I2061A_clockchip_methods =
273
{
274
    I2061A_init,
275
    I2061A_saveState,
276
    I2061A_restoreState,
277
    I2061A_initializeState,
278
    NULL,                       /* DAC function save area */
279
    NULL,
280
    NULL,
281
    I2061A_DEFAULT_TEXT_FREQUENCY,
282
    0,
283
};