1d87a3195Smrg/*
2d87a3195Smrg * Copyright 1992-2003 by Alan Hourihane, North Wales, UK.
3d87a3195Smrg *
4d87a3195Smrg * Permission to use, copy, modify, distribute, and sell this software
5d87a3195Smrg * and its documentation for any purpose is hereby granted without
6d87a3195Smrg * fee, provided that the above copyright notice appear in all copies
7d87a3195Smrg * and that both that copyright notice and this permission notice
8d87a3195Smrg * appear in supporting documentation, and that the name of Alan
9d87a3195Smrg * Hourihane not be used in advertising or publicity pertaining to
10d87a3195Smrg * distribution of the software without specific, written prior
11d87a3195Smrg * permission.  Alan Hourihane makes no representations about the
12d87a3195Smrg * suitability of this software for any purpose.  It is provided
13d87a3195Smrg * "as is" without express or implied warranty.
14d87a3195Smrg *
15d87a3195Smrg * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
16d87a3195Smrg * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17d87a3195Smrg * FITNESS, IN NO EVENT SHALL ALAN HOURIHANE BE LIABLE FOR ANY
18d87a3195Smrg * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19d87a3195Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
20d87a3195Smrg * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
21d87a3195Smrg * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
22d87a3195Smrg * SOFTWARE.
23d87a3195Smrg *
24d87a3195Smrg * Author:  Alan Hourihane, alanh@fairlite.demon.co.uk
25d87a3195Smrg */
26d87a3195Smrg
27d87a3195Smrg#ifdef HAVE_CONFIG_H
28d87a3195Smrg#include "config.h"
29d87a3195Smrg#endif
30d87a3195Smrg
31d87a3195Smrg#include "xf86.h"
32d87a3195Smrg#include "xf86_OSproc.h"
33d87a3195Smrg#include "xf86Pci.h"
34d87a3195Smrg
35d87a3195Smrg#include "vgaHW.h"
36d87a3195Smrg
37d87a3195Smrg#include "trident.h"
38d87a3195Smrg#include "trident_regs.h"
39d87a3195Smrg
40d87a3195Smrg
41d87a3195Smrgstatic void
42d87a3195SmrgIsClearTV(ScrnInfoPtr pScrn)
43d87a3195Smrg{
44d87a3195Smrg    int vgaIOBase = VGAHWPTR(pScrn)->IOBase;
45d87a3195Smrg    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
46d87a3195Smrg    CARD8 temp;
47d87a3195Smrg
48d87a3195Smrg    if (pTrident->frequency != 0) return;
49d87a3195Smrg
50d87a3195Smrg    OUTB(vgaIOBase + 4, 0xC0);
51d87a3195Smrg    temp = INB(vgaIOBase + 5);
52d87a3195Smrg    if (temp & 0x80)
53d87a3195Smrg        pTrident->frequency = PAL;
54d87a3195Smrg    else
55d87a3195Smrg        pTrident->frequency = NTSC;
56d87a3195Smrg}
57d87a3195Smrg
58d87a3195Smrgvoid
59d87a3195SmrgTGUISetClock(ScrnInfoPtr pScrn, int clock, CARD8 *a, CARD8 *b)
60d87a3195Smrg{
61d87a3195Smrg    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
62d87a3195Smrg    int powerup[4] = { 1, 2, 4, 8 };
63d87a3195Smrg    int clock_diff = 750;
64d87a3195Smrg    int freq, ffreq;
65d87a3195Smrg    int m, n, k;
66d87a3195Smrg    int p, q, r, s;
67d87a3195Smrg    int endn, endm, endk, startk;
68d87a3195Smrg
69d87a3195Smrg    p = q = r = s = 0;
70d87a3195Smrg
71d87a3195Smrg    IsClearTV(pScrn);
72d87a3195Smrg
73d87a3195Smrg    if (pTrident->NewClockCode) {
74d87a3195Smrg        endn = 255;
75d87a3195Smrg        endm = 63;
76d87a3195Smrg        endk = 2;
77d87a3195Smrg        if (clock >= 100000) startk = 0; else
78d87a3195Smrg            if (clock >=  50000) startk = 1; else
79d87a3195Smrg                startk = 2;
80d87a3195Smrg    } else {
81d87a3195Smrg        endn = 121;
82d87a3195Smrg        endm = 31;
83d87a3195Smrg        endk = 1;
84d87a3195Smrg        if (clock > 50000) startk = 1; else
85d87a3195Smrg            startk = 0;
86d87a3195Smrg    }
87d87a3195Smrg
88d87a3195Smrg    freq = clock;
89d87a3195Smrg
90d87a3195Smrg    for (k = startk; k <= endk; k++) {
91d87a3195Smrg        for (n = 0; n <= endn; n++) {
92d87a3195Smrg            for (m = 1; m <= endm; m++) {
93d87a3195Smrg                ffreq = ((((n + 8) * pTrident->frequency) /
94d87a3195Smrg                            ((m + 2) * powerup[k])) * 1000);
95d87a3195Smrg                if ((ffreq > freq - clock_diff) &&
96d87a3195Smrg                    (ffreq < freq + clock_diff)) {
97d87a3195Smrg                    /*
98d87a3195Smrg                     * It seems that the 9440 docs have this STRICT
99d87a3195Smrg                     * limitation, although most 9440 boards seem to
100d87a3195Smrg                     * cope. 96xx/Cyber chips don't need this limit
101d87a3195Smrg                     * so, I'm gonna remove it and it allows lower
102d87a3195Smrg                     * clocks < 25.175 too!
103d87a3195Smrg                     */
104d87a3195Smrg#ifdef STRICT
105d87a3195Smrg                    if ((n + 8) * 100 / (m + 2) < 978 &&
106d87a3195Smrg                        (n + 8) * 100 / (m + 2) > 349) {
107d87a3195Smrg#endif
108d87a3195Smrg                        clock_diff = (freq > ffreq) ?
109d87a3195Smrg                                        freq - ffreq : ffreq - freq;
110d87a3195Smrg                        p = n; q = m; r = k; s = ffreq;
111d87a3195Smrg#ifdef STRICT
112d87a3195Smrg                    }
113d87a3195Smrg#endif
114d87a3195Smrg                }
115d87a3195Smrg            }
116d87a3195Smrg        }
117d87a3195Smrg    }
118d87a3195Smrg
119d87a3195Smrg    if (s == 0) {
120d87a3195Smrg        FatalError("Unable to set programmable clock.\n"
121d87a3195Smrg                "Frequency %d is not a valid clock.\n"
122d87a3195Smrg                "Please modify XF86Config for a new clock.\n",
123d87a3195Smrg                freq);
124d87a3195Smrg    }
125d87a3195Smrg
126d87a3195Smrg    if (pTrident->NewClockCode) {
127d87a3195Smrg        /* N is all 8bits */
128d87a3195Smrg        *a = p;
129d87a3195Smrg        /* M is first 6bits, with K last 2bits */
130d87a3195Smrg        *b = (q & 0x3F) | (r << 6);
131d87a3195Smrg    } else {
132d87a3195Smrg        /* N is first 7bits, first M bit is 8th bit */
133d87a3195Smrg        *a = ((1 & q) << 7) | p;
134d87a3195Smrg        /* first 4bits are rest of M, 1bit for K value */
135d87a3195Smrg        *b = (((q & 0xFE) >> 1) | (r << 4));
136d87a3195Smrg    }
137d87a3195Smrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
138d87a3195Smrg                   "Found Clock %6.2f n=%i m=%i k=%i\n",
139d87a3195Smrg                   clock/1000., p, q, r);
140d87a3195Smrg}
141d87a3195Smrg
142d87a3195Smrgvoid
143d87a3195SmrgTridentFindClock(ScrnInfoPtr pScrn, int clock)
144d87a3195Smrg{
145d87a3195Smrg    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
146d87a3195Smrg
147d87a3195Smrg    pTrident->MUX = FALSE;
148d87a3195Smrg#ifdef READOUT
149d87a3195Smrg    pTrident->DontSetClock = FALSE;
150d87a3195Smrg#endif
151d87a3195Smrg    pTrident->currentClock = clock;
152d87a3195Smrg
153d87a3195Smrg    if (pTrident->IsCyber) {
154d87a3195Smrg        Bool LCDActive;
155d87a3195Smrg#ifdef READOUT
156d87a3195Smrg        Bool ShadowModeActive;
157d87a3195Smrg        Bool HStretch;
158d87a3195Smrg        Bool VStretch;
159d87a3195Smrg#endif
160d87a3195Smrg        OUTB(0x3CE, FPConfig);
161d87a3195Smrg        LCDActive = (INB(0x3CF) & 0x10);
162d87a3195Smrg#ifdef READOUT
163d87a3195Smrg        OUTB(0x3CE, HorStretch);
164d87a3195Smrg        HStretch = (INB(0x3CF) & 0x01);
165d87a3195Smrg        OUTB(0x3CE, VertStretch);
166d87a3195Smrg        VStretch = (INB(0x3CF) & 0x01);
167d87a3195Smrg
168d87a3195Smrg        if (!(VStretch || HStretch) && LCDActive) {
169d87a3195Smrg            CARD8 temp;
170d87a3195Smrg            temp = INB(0x3C8);
171d87a3195Smrg            temp = INB(0x3C6);
172d87a3195Smrg            temp = INB(0x3C6);
173d87a3195Smrg            temp = INB(0x3C6);
174d87a3195Smrg            temp = INB(0x3C6);
175d87a3195Smrg            pTrident->MUX = ((INB(0x3C6) & 0x20) == 0x20);
176d87a3195Smrg            temp = INB(0x3C8);
177d87a3195Smrg            pTrident->DontSetClock = TRUE;
178d87a3195Smrg            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
179d87a3195Smrg                        "Keeping Clock for LCD Mode\n");
180d87a3195Smrg            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
181d87a3195Smrg                        "MUX is %s\n",
182d87a3195Smrg                        pTrident->MUX ? "on" : "off");
183d87a3195Smrg            return;
184d87a3195Smrg        } else
185d87a3195Smrg#endif
186d87a3195Smrg        {
187d87a3195Smrg            if (pTrident->lcdMode != 0xff && LCDActive)
188d87a3195Smrg                pTrident->currentClock = clock =
189d87a3195Smrg                                        LCD[pTrident->lcdMode].clock;
190d87a3195Smrg        }
191d87a3195Smrg
192d87a3195Smrg    }
193d87a3195Smrg#ifndef READOUT
194d87a3195Smrg    if (pTrident->Chipset != BLADEXP &&
195d87a3195Smrg        clock > pTrident->MUXThreshold)
196d87a3195Smrg        pTrident->MUX = TRUE;
197d87a3195Smrg    else
198d87a3195Smrg        pTrident->MUX = FALSE;
199d87a3195Smrg#endif
200d87a3195Smrg}
201d87a3195Smrg
202d87a3195Smrgfloat
203d87a3195SmrgCalculateMCLK(ScrnInfoPtr pScrn)
204d87a3195Smrg{
205d87a3195Smrg    int vgaIOBase = VGAHWPTR(pScrn)->IOBase;
206d87a3195Smrg    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
207d87a3195Smrg    int a, b;
208d87a3195Smrg    int m, n, k;
209d87a3195Smrg    float freq = 0.0;
210d87a3195Smrg    int powerup[4] = { 1, 2, 4, 8 };
211d87a3195Smrg    CARD8 temp;
212d87a3195Smrg
213d87a3195Smrg    if (pTrident->HasSGRAM) {
214d87a3195Smrg        OUTB(vgaIOBase + 4, 0x28);
215d87a3195Smrg        switch(INB(vgaIOBase + 5) & 0x07) {
216d87a3195Smrg        case 0:
217d87a3195Smrg            freq = 60;
218d87a3195Smrg            break;
219d87a3195Smrg        case 1:
220d87a3195Smrg            freq = 78;
221d87a3195Smrg            break;
222d87a3195Smrg        case 2:
223d87a3195Smrg            freq = 90;
224d87a3195Smrg            break;
225d87a3195Smrg        case 3:
226d87a3195Smrg            freq = 120;
227d87a3195Smrg            break;
228d87a3195Smrg        case 4:
229d87a3195Smrg            freq = 66;
230d87a3195Smrg            break;
231d87a3195Smrg        case 5:
232d87a3195Smrg            freq = 83;
233d87a3195Smrg            break;
234d87a3195Smrg        case 6:
235d87a3195Smrg            freq = 100;
236d87a3195Smrg            break;
237d87a3195Smrg        case 7:
238d87a3195Smrg            freq = 132;
239d87a3195Smrg            break;
240d87a3195Smrg        }
241d87a3195Smrg    } else {
242d87a3195Smrg        OUTB(0x3C4, NewMode1);
243d87a3195Smrg        temp = INB(0x3C5);
244d87a3195Smrg
245d87a3195Smrg        OUTB(0x3C5, 0xC2);
246d87a3195Smrg        if (!Is3Dchip) {
247d87a3195Smrg            a = INB(0x43C6);
248d87a3195Smrg            b = INB(0x43C7);
249d87a3195Smrg        } else {
250d87a3195Smrg            OUTB(0x3C4, 0x16);
251d87a3195Smrg            a = INB(0x3C5);
252d87a3195Smrg            OUTB(0x3C4, 0x17);
253d87a3195Smrg            b = INB(0x3C5);
254d87a3195Smrg        }
255d87a3195Smrg
256d87a3195Smrg        OUTB(0x3C4, NewMode1);
257d87a3195Smrg        OUTB(0x3C5, temp);
258d87a3195Smrg
259d87a3195Smrg        IsClearTV(pScrn);
260d87a3195Smrg
261d87a3195Smrg        if (pTrident->NewClockCode) {
262d87a3195Smrg            m = b & 0x3F;
263d87a3195Smrg            n = a;
264d87a3195Smrg            k = (b & 0xC0) >> 6;
265d87a3195Smrg        } else {
266d87a3195Smrg            m = (a & 0x07);
267d87a3195Smrg            k = (b & 0x02) >> 1;
268d87a3195Smrg            n = ((a & 0xF8) >> 3) | ((b&0x01) << 5);
269d87a3195Smrg        }
270d87a3195Smrg
271d87a3195Smrg        freq = ((n + 8) * pTrident->frequency) /
272d87a3195Smrg                ((m + 2) * powerup[k]);
273d87a3195Smrg    }
274d87a3195Smrg
275d87a3195Smrg    return (freq);
276d87a3195Smrg}
277d87a3195Smrg
278d87a3195Smrgvoid
279d87a3195SmrgTGUISetMCLK(ScrnInfoPtr pScrn, int clock, CARD8 *a, CARD8 *b)
280d87a3195Smrg{
281d87a3195Smrg    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
282d87a3195Smrg    int powerup[4] = { 1,2,4,8 };
283d87a3195Smrg    int clock_diff = 750;
284d87a3195Smrg    int freq, ffreq;
285d87a3195Smrg    int m,n,k;
286d87a3195Smrg    int p, q, r, s;
287d87a3195Smrg    int startn, endn;
288d87a3195Smrg    int endm, endk;
289d87a3195Smrg
290d87a3195Smrg    p = q = r = s = 0;
291d87a3195Smrg
292d87a3195Smrg    IsClearTV(pScrn);
293d87a3195Smrg
294d87a3195Smrg    if (pTrident->NewClockCode) {
295d87a3195Smrg        startn = 64;
296d87a3195Smrg        endn = 255;
297d87a3195Smrg        endm = 63;
298d87a3195Smrg        endk = 3;
299d87a3195Smrg    } else {
300d87a3195Smrg        startn = 0;
301d87a3195Smrg        endn = 121;
302d87a3195Smrg        endm = 31;
303d87a3195Smrg        endk = 1;
304d87a3195Smrg    }
305d87a3195Smrg
306d87a3195Smrg    freq = clock;
307d87a3195Smrg
308d87a3195Smrg    if (!pTrident->HasSGRAM) {
309d87a3195Smrg        for (k = 0; k <= endk; k++) {
310d87a3195Smrg            for (n = startn; n <= endn; n++) {
311d87a3195Smrg                for (m = 1;m <= endm; m++) {
312d87a3195Smrg                    ffreq = ((((n + 8) * pTrident->frequency) /
313d87a3195Smrg                            ((m + 2) * powerup[k])) * 1000);
314d87a3195Smrg                    if ((ffreq > freq - clock_diff) &&
315d87a3195Smrg                        (ffreq < freq + clock_diff)) {
316d87a3195Smrg                        clock_diff = (freq > ffreq) ?
317d87a3195Smrg                                        freq - ffreq : ffreq - freq;
318d87a3195Smrg                        p = n; q = m; r = k; s = ffreq;
319d87a3195Smrg                    }
320d87a3195Smrg                }
321d87a3195Smrg            }
322d87a3195Smrg        }
323d87a3195Smrg
324d87a3195Smrg        if (s == 0) {
325d87a3195Smrg            FatalError("Unable to set memory clock.\n"
326d87a3195Smrg                        "Frequency %d is not a valid clock.\n"
327d87a3195Smrg                        "Please modify XF86Config for a new clock.\n",
328d87a3195Smrg                        freq);
329d87a3195Smrg        }
330d87a3195Smrg
331d87a3195Smrg        if (pTrident->NewClockCode) {
332d87a3195Smrg            /* N is all 8bits */
333d87a3195Smrg            *a = p;
334d87a3195Smrg            /* M is first 6bits, with K last 2bits */
335d87a3195Smrg            *b = (q & 0x3F) | (r << 6);
336d87a3195Smrg        }
337d87a3195Smrg        else {
338d87a3195Smrg            /* N is first 7bits, first M bit is 8th bit */
339d87a3195Smrg            *a = ((1 & q) << 7) | p;
340d87a3195Smrg            /* first 4bits are rest of M, 1bit for K value */
341d87a3195Smrg            *b = (((q & 0xFE) >> 1) | (r << 4));
342d87a3195Smrg        }
343d87a3195Smrg    }
344d87a3195Smrg}
345