1dfe64dd3Smacallan/*
2dfe64dd3Smacallan * DAC helper functions (Save/Restore, MemClk, etc)
3dfe64dd3Smacallan *
4dfe64dd3Smacallan * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria.
5dfe64dd3Smacallan *
6dfe64dd3Smacallan * Redistribution and use in source and binary forms, with or without
7dfe64dd3Smacallan * modification, are permitted provided that the following conditions
8dfe64dd3Smacallan * are met:
9dfe64dd3Smacallan * 1) Redistributions of source code must retain the above copyright
10dfe64dd3Smacallan *    notice, this list of conditions and the following disclaimer.
11dfe64dd3Smacallan * 2) Redistributions in binary form must reproduce the above copyright
12dfe64dd3Smacallan *    notice, this list of conditions and the following disclaimer in the
13dfe64dd3Smacallan *    documentation and/or other materials provided with the distribution.
14dfe64dd3Smacallan * 3) The name of the author may not be used to endorse or promote products
15dfe64dd3Smacallan *    derived from this software without specific prior written permission.
16dfe64dd3Smacallan *
17dfe64dd3Smacallan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
18dfe64dd3Smacallan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19dfe64dd3Smacallan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20dfe64dd3Smacallan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21dfe64dd3Smacallan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22dfe64dd3Smacallan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23dfe64dd3Smacallan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24dfe64dd3Smacallan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25dfe64dd3Smacallan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26dfe64dd3Smacallan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27dfe64dd3Smacallan *
28dfe64dd3Smacallan * Author:  	Thomas Winischhofer <thomas@winischhofer.net>
29dfe64dd3Smacallan *
30dfe64dd3Smacallan * XGI_compute_vclk(), XGICalcClock() and parts of XGIMclk():
31dfe64dd3Smacallan * Copyright (C) 1998, 1999 by Alan Hourihane, Wigan, England
32dfe64dd3Smacallan * Written by:
33dfe64dd3Smacallan *	 Alan Hourihane <alanh@fairlite.demon.co.uk>,
34dfe64dd3Smacallan *       Mike Chapman <mike@paranoia.com>,
35dfe64dd3Smacallan *       Juanjo Santamarta <santamarta@ctv.es>,
36dfe64dd3Smacallan *       Mitani Hiroshi <hmitani@drl.mei.co.jp>,
37dfe64dd3Smacallan *       David Thomas <davtom@dream.org.uk>,
38dfe64dd3Smacallan *	 Thomas Winischhofer <thomas@winischhofer.net>.
39dfe64dd3Smacallan * Licensed under the terms of the XFree86 license
40dfe64dd3Smacallan * (http://www.xfree86.org/current/LICENSE1.html)
41dfe64dd3Smacallan *
42dfe64dd3Smacallan */
43dfe64dd3Smacallan
44dfe64dd3Smacallan#ifdef HAVE_CONFIG_H
45dfe64dd3Smacallan#include "config.h"
46dfe64dd3Smacallan#endif
47dfe64dd3Smacallan
48dfe64dd3Smacallan#include "xf86.h"
49dfe64dd3Smacallan#include "xf86_OSproc.h"
50dfe64dd3Smacallan#include "xorgVersion.h"
51dfe64dd3Smacallan#include "xf86PciInfo.h"
52dfe64dd3Smacallan#include "xf86Pci.h"
53dfe64dd3Smacallan#include "xf86DDC.h"
54dfe64dd3Smacallan
55dfe64dd3Smacallan#include "xgi.h"
56dfe64dd3Smacallan#include "xgi_dac.h"
57dfe64dd3Smacallan#include "xgi_regs.h"
58dfe64dd3Smacallan#include "xgi_vb.h"
59dfe64dd3Smacallan
60dfe64dd3Smacallanstatic void Volari_Save(ScrnInfoPtr pScrn, XGIRegPtr xgiReg) ;
61dfe64dd3Smacallanstatic void Volari_Restore(ScrnInfoPtr pScrn, XGIRegPtr xgiReg) ;
62dfe64dd3Smacallanstatic void Volari_Threshold(ScrnInfoPtr pScrn, DisplayModePtr mode,
63dfe64dd3Smacallan                                unsigned short *Low, unsigned short *High);
64dfe64dd3Smacallanint
65dfe64dd3Smacallancompute_vclk(
66dfe64dd3Smacallan        int Clock,
67dfe64dd3Smacallan        int *out_n,
68dfe64dd3Smacallan        int *out_dn,
69dfe64dd3Smacallan        int *out_div,
70dfe64dd3Smacallan        int *out_sbit,
71dfe64dd3Smacallan        int *out_scale)
72dfe64dd3Smacallan{
73dfe64dd3Smacallan        float f,x,y,t, error, min_error;
74dfe64dd3Smacallan        int n, dn, best_n=0, best_dn=0;
75dfe64dd3Smacallan
76dfe64dd3Smacallan        /*
77dfe64dd3Smacallan         * Rules
78dfe64dd3Smacallan         *
79dfe64dd3Smacallan         * VCLK = 14.318 * (Divider/Post Scalar) * (Numerator/DeNumerator)
80dfe64dd3Smacallan         * Factor = (Divider/Post Scalar)
81dfe64dd3Smacallan         * Divider is 1 or 2
82dfe64dd3Smacallan         * Post Scalar is 1, 2, 3, 4, 6 or 8
83dfe64dd3Smacallan         * Numberator ranged from 1 to 128
84dfe64dd3Smacallan         * DeNumerator ranged from 1 to 32
85dfe64dd3Smacallan         * a. VCO = VCLK/Factor, suggest range is 150 to 250 Mhz
86dfe64dd3Smacallan         * b. Post Scalar selected from 1, 2, 4 or 8 first.
87dfe64dd3Smacallan         * c. DeNumerator selected from 2.
88dfe64dd3Smacallan         *
89dfe64dd3Smacallan         * According to rule a and b, the VCO ranges that can be scaled by
90dfe64dd3Smacallan         * rule b are:
91dfe64dd3Smacallan         *      150    - 250    (Factor = 1)
92dfe64dd3Smacallan         *       75    - 125    (Factor = 2)
93dfe64dd3Smacallan         *       37.5  -  62.5  (Factor = 4)
94dfe64dd3Smacallan         *       18.75 -  31.25 (Factor = 8)
95dfe64dd3Smacallan         *
96dfe64dd3Smacallan         * The following ranges use Post Scalar 3 or 6:
97dfe64dd3Smacallan         *      125    - 150    (Factor = 1.5)
98dfe64dd3Smacallan         *       62.5  -  75    (Factor = 3)
99dfe64dd3Smacallan         *       31.25 -  37.5  (Factor = 6)
100dfe64dd3Smacallan         *
101dfe64dd3Smacallan         * Steps:
102dfe64dd3Smacallan         * 1. divide the Clock by 2 until the Clock is less or equal to 31.25.
103dfe64dd3Smacallan         * 2. if the divided Clock is range from 18.25 to 31.25, than
104dfe64dd3Smacallan         *    the Factor is 1, 2, 4 or 8.
105dfe64dd3Smacallan         * 3. if the divided Clock is range from 15.625 to 18.25, than
106dfe64dd3Smacallan         *    the Factor is 1.5, 3 or 6.
107dfe64dd3Smacallan         * 4. select the Numberator and DeNumberator with minimum deviation.
108dfe64dd3Smacallan         *
109dfe64dd3Smacallan         * ** this function can select VCLK ranged from 18.75 to 250 Mhz
110dfe64dd3Smacallan         */
111dfe64dd3Smacallan        f = (float) Clock;
112dfe64dd3Smacallan        f /= 1000.0;
113dfe64dd3Smacallan        if ((f > 250.0) || (f < 18.75))
114dfe64dd3Smacallan                return 0;
115dfe64dd3Smacallan
116dfe64dd3Smacallan        min_error = f;
117dfe64dd3Smacallan        y = 1.0;
118dfe64dd3Smacallan        x = f;
119dfe64dd3Smacallan        while (x > 31.25) {
120dfe64dd3Smacallan                y *= 2.0;
121dfe64dd3Smacallan                x /= 2.0;
122dfe64dd3Smacallan        }
123dfe64dd3Smacallan        if (x >= 18.25) {
124dfe64dd3Smacallan                x *= 8.0;
125dfe64dd3Smacallan                y = 8.0 / y;
126dfe64dd3Smacallan        } else if (x >= 15.625) {
127dfe64dd3Smacallan                x *= 12.0;
128dfe64dd3Smacallan                y = 12.0 / y;
129dfe64dd3Smacallan        }
130dfe64dd3Smacallan
131dfe64dd3Smacallan        t = y;
132dfe64dd3Smacallan        if (t == (float) 1.5) {
133dfe64dd3Smacallan                *out_div = 2;
134dfe64dd3Smacallan                t *= 2.0;
135dfe64dd3Smacallan        } else {
136dfe64dd3Smacallan                *out_div = 1;
137dfe64dd3Smacallan        }
138dfe64dd3Smacallan        if (t > (float) 4.0) {
139dfe64dd3Smacallan                *out_sbit = 1;
140dfe64dd3Smacallan                t /= 2.0;
141dfe64dd3Smacallan        } else {
142dfe64dd3Smacallan                *out_sbit = 0;
143dfe64dd3Smacallan        }
144dfe64dd3Smacallan
145dfe64dd3Smacallan        *out_scale = (int) t;
146dfe64dd3Smacallan
147dfe64dd3Smacallan        for (dn=2;dn<=32;dn++) {
148dfe64dd3Smacallan                for (n=1;n<=128;n++) {
149dfe64dd3Smacallan                        error = x;
150dfe64dd3Smacallan                        error -= ((float) 14.318 * (float) n / (float) dn);
151dfe64dd3Smacallan                        if (error < (float) 0)
152dfe64dd3Smacallan                                error = -error;
153dfe64dd3Smacallan                        if (error < min_error) {
154dfe64dd3Smacallan                                min_error = error;
155dfe64dd3Smacallan                                best_n = n;
156dfe64dd3Smacallan                                best_dn = dn;
157dfe64dd3Smacallan                        }
158dfe64dd3Smacallan                }
159dfe64dd3Smacallan        }
160dfe64dd3Smacallan        *out_n = best_n;
161dfe64dd3Smacallan        *out_dn = best_dn;
162dfe64dd3Smacallan        PDEBUG(ErrorF("compute_vclk: Clock=%d, n=%d, dn=%d, div=%d, sbit=%d,"
163dfe64dd3Smacallan                        " scale=%d\n", Clock, best_n, best_dn, *out_div,
164dfe64dd3Smacallan                        *out_sbit, *out_scale));
165dfe64dd3Smacallan        return 1;
166dfe64dd3Smacallan}
167dfe64dd3Smacallan
168dfe64dd3Smacallanvoid
169dfe64dd3SmacallanXGICalcClock(ScrnInfoPtr pScrn, int clock, int max_VLD, unsigned int *vclk)
170dfe64dd3Smacallan{
171dfe64dd3Smacallan/*    XGIPtr pXGI = XGIPTR(pScrn); */
172dfe64dd3Smacallan    int M, N, P , PSN, VLD , PSNx ;
173dfe64dd3Smacallan    int bestM=0, bestN=0, bestP=0, bestPSN=0, bestVLD=0;
174dfe64dd3Smacallan    double abest = 42.0;
175dfe64dd3Smacallan    double target;
176dfe64dd3Smacallan    double Fvco, Fout;
177dfe64dd3Smacallan    double error, aerror;
178dfe64dd3Smacallan#ifdef DEBUG
179dfe64dd3Smacallan    double bestFout;
180dfe64dd3Smacallan#endif
181dfe64dd3Smacallan
182dfe64dd3Smacallan    /*
183dfe64dd3Smacallan     *  fd = fref*(Numerator/Denumerator)*(Divider/PostScaler)
184dfe64dd3Smacallan     *
185dfe64dd3Smacallan     *  M       = Numerator [1:128]
186dfe64dd3Smacallan     *  N       = DeNumerator [1:32]
187dfe64dd3Smacallan     *  VLD     = Divider (Vco Loop Divider) : divide by 1, 2
188dfe64dd3Smacallan     *  P       = Post Scaler : divide by 1, 2, 3, 4
189dfe64dd3Smacallan     *  PSN     = Pre Scaler (Reference Divisor Select)
190dfe64dd3Smacallan     *
191dfe64dd3Smacallan     * result in vclk[]
192dfe64dd3Smacallan     */
193dfe64dd3Smacallan#define Midx    0
194dfe64dd3Smacallan#define Nidx    1
195dfe64dd3Smacallan#define VLDidx  2
196dfe64dd3Smacallan#define Pidx    3
197dfe64dd3Smacallan#define PSNidx  4
198dfe64dd3Smacallan#define Fref 14318180
199dfe64dd3Smacallan/* stability constraints for internal VCO -- MAX_VCO also determines
200dfe64dd3Smacallan * the maximum Video pixel clock */
201dfe64dd3Smacallan#define MIN_VCO      Fref
202dfe64dd3Smacallan#define MAX_VCO      135000000
203dfe64dd3Smacallan#define MAX_VCO_5597 353000000
204dfe64dd3Smacallan#define MAX_PSN      0          /* no pre scaler for this chip */
205dfe64dd3Smacallan#define TOLERANCE    0.01       /* search smallest M and N in this tolerance */
206dfe64dd3Smacallan
207dfe64dd3Smacallan  int M_min = 2;
208dfe64dd3Smacallan  int M_max = 128;
209dfe64dd3Smacallan
210dfe64dd3Smacallan  target = clock * 1000;
211dfe64dd3Smacallan
212dfe64dd3Smacallan     for(PSNx = 0; PSNx <= MAX_PSN ; PSNx++) {
213dfe64dd3Smacallan
214dfe64dd3Smacallan        int low_N, high_N;
215dfe64dd3Smacallan        double FrefVLDPSN;
216dfe64dd3Smacallan
217dfe64dd3Smacallan        PSN = !PSNx ? 1 : 4;
218dfe64dd3Smacallan
219dfe64dd3Smacallan        low_N = 2;
220dfe64dd3Smacallan        high_N = 32;
221dfe64dd3Smacallan
222dfe64dd3Smacallan        for(VLD = 1 ; VLD <= max_VLD ; VLD++) {
223dfe64dd3Smacallan
224dfe64dd3Smacallan           FrefVLDPSN = (double)Fref * VLD / PSN;
225dfe64dd3Smacallan
226dfe64dd3Smacallan	   for(N = low_N; N <= high_N; N++) {
227dfe64dd3Smacallan              double tmp = FrefVLDPSN / N;
228dfe64dd3Smacallan
229dfe64dd3Smacallan              for(P = 1; P <= 4; P++) {
230dfe64dd3Smacallan                 double Fvco_desired = target * ( P );
231dfe64dd3Smacallan                 double M_desired = Fvco_desired / tmp;
232dfe64dd3Smacallan
233dfe64dd3Smacallan                 /* Which way will M_desired be rounded?
234dfe64dd3Smacallan                  *  Do all three just to be safe.
235dfe64dd3Smacallan                  */
236dfe64dd3Smacallan                 int M_low = M_desired - 1;
237dfe64dd3Smacallan                 int M_hi = M_desired + 1;
238dfe64dd3Smacallan
239dfe64dd3Smacallan                 if(M_hi < M_min || M_low > M_max) continue;
240dfe64dd3Smacallan
241dfe64dd3Smacallan		 if(M_low < M_min)  M_low = M_min;
242dfe64dd3Smacallan
243dfe64dd3Smacallan		 if(M_hi > M_max)   M_hi = M_max;
244dfe64dd3Smacallan
245dfe64dd3Smacallan                 for(M = M_low; M <= M_hi; M++) {
246dfe64dd3Smacallan                    Fvco = tmp * M;
247dfe64dd3Smacallan                    if(Fvco <= MIN_VCO) continue;
248dfe64dd3Smacallan                    if(Fvco > MAX_VCO)  break;
249dfe64dd3Smacallan
250dfe64dd3Smacallan                    Fout = Fvco / ( P );
251dfe64dd3Smacallan
252dfe64dd3Smacallan                    error = (target - Fout) / target;
253dfe64dd3Smacallan                    aerror = (error < 0) ? -error : error;
254dfe64dd3Smacallan                    if(aerror < abest) {
255dfe64dd3Smacallan                       abest = aerror;
256dfe64dd3Smacallan                       bestM = M;
257dfe64dd3Smacallan                       bestN = N;
258dfe64dd3Smacallan                       bestP = P;
259dfe64dd3Smacallan                       bestPSN = PSN;
260dfe64dd3Smacallan                       bestVLD = VLD;
261dfe64dd3Smacallan#ifdef DEBUG
262dfe64dd3Smacallan                       bestFout = Fout;
263dfe64dd3Smacallan#endif
264dfe64dd3Smacallan                    }
265dfe64dd3Smacallan#ifdef TWDEBUG
266dfe64dd3Smacallan                    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO,3,
267dfe64dd3Smacallan			       "Freq. selected: %.2f MHz, M=%d, N=%d, VLD=%d, P=%d, PSN=%d\n",
268dfe64dd3Smacallan                               (float)(clock / 1000.), M, N, P, VLD, PSN);
269dfe64dd3Smacallan                    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO,3,
270dfe64dd3Smacallan			       "Freq. set: %.2f MHz\n", Fout / 1.0e6);
271dfe64dd3Smacallan#endif
272dfe64dd3Smacallan                 }
273dfe64dd3Smacallan              }
274dfe64dd3Smacallan           }
275dfe64dd3Smacallan        }
276dfe64dd3Smacallan     }
277dfe64dd3Smacallan
278dfe64dd3Smacallan  vclk[Midx]   = bestM;
279dfe64dd3Smacallan  vclk[Nidx]   = bestN;
280dfe64dd3Smacallan  vclk[VLDidx] = bestVLD;
281dfe64dd3Smacallan  vclk[Pidx]   = bestP;
282dfe64dd3Smacallan  vclk[PSNidx] = bestPSN;
283dfe64dd3Smacallan/*
284dfe64dd3Smacallan  PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
285dfe64dd3Smacallan                "Freq. selected: %.2f MHz, M=%d, N=%d, VLD=%d, P=%d, PSN=%d\n",
286dfe64dd3Smacallan                (float)(clock / 1000.), vclk[Midx], vclk[Nidx], vclk[VLDidx],
287dfe64dd3Smacallan                vclk[Pidx], vclk[PSNidx]));
288dfe64dd3Smacallan  PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
289dfe64dd3Smacallan                "Freq. set: %.2f MHz\n", bestFout / 1.0e6));
290dfe64dd3Smacallan  PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
291dfe64dd3Smacallan                "VCO Freq.: %.2f MHz\n", bestFout*bestP / 1.0e6));
292dfe64dd3Smacallan*/
293dfe64dd3Smacallan
294dfe64dd3Smacallan}
295dfe64dd3Smacallan
296dfe64dd3Smacallanstatic void
297dfe64dd3SmacallanVolari_Save(ScrnInfoPtr pScrn, XGIRegPtr xgiReg)
298dfe64dd3Smacallan{
299dfe64dd3Smacallan    XGIPtr pXGI = XGIPTR(pScrn);
300dfe64dd3Smacallan    int vgaIOBase;
301dfe64dd3Smacallan    int i;
302dfe64dd3Smacallan
303dfe64dd3Smacallan    PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
304dfe64dd3Smacallan           "Volari_Save(ScrnInfoPtr pScrn, XGIRegPtr xgiReg)\n"));
305dfe64dd3Smacallan
306dfe64dd3Smacallan    vgaHWGetIOBase(VGAHWPTR(pScrn));
307dfe64dd3Smacallan    vgaIOBase = VGAHWPTR(pScrn)->IOBase;
308dfe64dd3Smacallan
309dfe64dd3Smacallan#if !defined(__arm__)
310dfe64dd3Smacallan    outw(VGA_SEQ_INDEX, 0x8605);
311dfe64dd3Smacallan#else
312dfe64dd3Smacallan    moutl(XGISR, 0x8605);
313dfe64dd3Smacallan#endif
314dfe64dd3Smacallan
315dfe64dd3Smacallan    for (i = 0x06; i <= 0x3F; i++) {
316dfe64dd3Smacallan        /* outb(VGA_SEQ_INDEX, i); */
317dfe64dd3Smacallan        outb(XGISR, i);
318dfe64dd3Smacallan
319dfe64dd3Smacallan        /* xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4,
320dfe64dd3Smacallan                    "XR%02X Contents - %02X \n", i, inb(VGA_SEQ_DATA));
321dfe64dd3Smacallan        xgiReg->xgiRegs3C4[i] = inb(VGA_SEQ_DATA); */
322dfe64dd3Smacallan        xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4,
323dfe64dd3Smacallan                    "XR%02X Contents - %02X \n", i, inb(XGISR+1));
324dfe64dd3Smacallan        xgiReg->xgiRegs3C4[i] = inb(XGISR+1);
325dfe64dd3Smacallan    }
326dfe64dd3Smacallan
327dfe64dd3Smacallan    for (i=0x19; i<0x5C; i++)  {
328dfe64dd3Smacallan        inXGIIDXREG(XGICR, i, xgiReg->xgiRegs3D4[i]);
329dfe64dd3Smacallan    }
330dfe64dd3Smacallan
331dfe64dd3Smacallan    /*xgiReg->xgiRegs3C2 = inb(0x3CC);*/
332dfe64dd3Smacallan
333dfe64dd3Smacallan    xgiReg->xgiRegs3C2 = inb(pXGI->RelIO+0x4c);
334dfe64dd3Smacallan
335dfe64dd3Smacallan    for (i=0x19; i<0x5C; i++)  {
336dfe64dd3Smacallan        inXGIIDXREG(XGICR, i, xgiReg->xgiRegs3D4[i]);
337dfe64dd3Smacallan    }
338dfe64dd3Smacallan
339dfe64dd3Smacallan// yilin save the VB register
340dfe64dd3Smacallan    outXGIIDXREG(XGIPART1, 0x2f, 0x01);
341dfe64dd3Smacallan
342dfe64dd3Smacallan    for (i=0; i<0x50; i++)
343dfe64dd3Smacallan    {
344dfe64dd3Smacallan        inXGIIDXREG(XGIPART1, i, xgiReg->VBPart1[i]);
345dfe64dd3Smacallan    }
346dfe64dd3Smacallan    for (i=0; i<0x50; i++)
347dfe64dd3Smacallan    {
348dfe64dd3Smacallan        inXGIIDXREG(XGIPART2, i, xgiReg->VBPart2[i]);
349dfe64dd3Smacallan    }
350dfe64dd3Smacallan    for (i=0; i<0x50; i++)
351dfe64dd3Smacallan    {
352dfe64dd3Smacallan        inXGIIDXREG(XGIPART3, i, xgiReg->VBPart3[i]);
353dfe64dd3Smacallan    }
354dfe64dd3Smacallan    for (i=0; i<0x50; i++)
355dfe64dd3Smacallan    {
356dfe64dd3Smacallan        inXGIIDXREG(XGIPART4, i, xgiReg->VBPart4[i]);
357dfe64dd3Smacallan    }
358dfe64dd3Smacallan
359dfe64dd3Smacallan    PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
360dfe64dd3Smacallan           "Volari_Save(ScrnInfoPtr pScrn, XGIRegPtr xgiReg) Done\n"));
361dfe64dd3Smacallan
362dfe64dd3Smacallan}
363dfe64dd3Smacallan
364dfe64dd3Smacallanstatic void
365dfe64dd3SmacallanVolari_Restore(ScrnInfoPtr pScrn, XGIRegPtr xgiReg)
366dfe64dd3Smacallan{
367dfe64dd3Smacallan    XGIPtr pXGI = XGIPTR(pScrn);
368dfe64dd3Smacallan    int vgaIOBase;
369dfe64dd3Smacallan    int i;
370dfe64dd3Smacallan
371dfe64dd3Smacallan	PDEBUG(ErrorF("--- Volari_Restore(). \n")) ;
372dfe64dd3Smacallan    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4,
373dfe64dd3Smacallan                "Volari_Restore(ScrnInfoPtr pScrn, XGIRegPtr xgiReg)\n");
374dfe64dd3Smacallan
375dfe64dd3Smacallan    vgaHWGetIOBase(VGAHWPTR(pScrn));
376dfe64dd3Smacallan    vgaIOBase = VGAHWPTR(pScrn)->IOBase;
377dfe64dd3Smacallan
378dfe64dd3Smacallan    outXGIIDXREG(XGISR, 0x05, 0x86);
379dfe64dd3Smacallan
380dfe64dd3Smacallan
381dfe64dd3Smacallan#if 1
382dfe64dd3Smacallan	/* Jong@08112009; recover this line */
383dfe64dd3Smacallan	/* Volari_DisableAccelerator(pScrn) ; */
384dfe64dd3Smacallan#else
385dfe64dd3Smacallan    inXGIIDXREG(XGISR, 0x1E, temp);
386dfe64dd3Smacallan
387dfe64dd3Smacallan    if (temp & (SR1E_ENABLE_2D | SR1E_ENABLE_3D)) {
388dfe64dd3Smacallan        Volari_Idle(pXGI);
389dfe64dd3Smacallan    }
390dfe64dd3Smacallan
391dfe64dd3Smacallan    PDEBUG(XGIDumpRegs(pScrn));
392dfe64dd3Smacallan
393dfe64dd3Smacallan    outXGIIDXREG(XGICR, 0x55, 0);
394dfe64dd3Smacallan    andXGIIDXREG(XGISR, 0x1E,
395dfe64dd3Smacallan                 ~(SR1E_ENABLE_3D_TRANSFORM_ENGINE
396dfe64dd3Smacallan                   | SR1E_ENABLE_2D
397dfe64dd3Smacallan                   | SR1E_ENABLE_3D));
398dfe64dd3Smacallan    PDEBUG(XGIDumpRegs(pScrn));
399dfe64dd3Smacallan#endif
400dfe64dd3Smacallan
401dfe64dd3Smacallan	PDEBUG(XGIDumpRegs(pScrn)) ; //yilin
402dfe64dd3Smacallan
403dfe64dd3Smacallan    for (i = 0x19; i < 0x5C; i++)  {
404dfe64dd3Smacallan     /* Jong 09/19/2007; added for ??? */
405dfe64dd3Smacallan     if((i!=0x48 && i!=0x4a)|| ((pXGI->Chipset != PCI_CHIP_XGIXG20)&&(pXGI->Chipset != PCI_CHIP_XGIXG21)&&(pXGI->Chipset != PCI_CHIP_XGIXG27)))
406dfe64dd3Smacallan        outXGIIDXREG(XGICR, i, xgiReg->xgiRegs3D4[i]);
407dfe64dd3Smacallan    }
408dfe64dd3Smacallan
409dfe64dd3Smacallan    for (i = 0x06; i <= 0x3F; i++) {
410dfe64dd3Smacallan /* if( !(i==0x16 || i==0x18 || i==0x19 || i==0x28 || i==0x29 || i==0x2E || i==0x2F) ) { */
411dfe64dd3Smacallan        if( !(i==0x16 ) ) {
412dfe64dd3Smacallan           /* outb(VGA_SEQ_INDEX,i); */
413dfe64dd3Smacallan           outb(XGISR,i);
414dfe64dd3Smacallan
415dfe64dd3Smacallan            /* xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO,4,
416dfe64dd3Smacallan                    "XR%X Contents - %02X ", i, inb(VGA_SEQ_DATA));
417dfe64dd3Smacallan
418dfe64dd3Smacallan            outb(VGA_SEQ_DATA,xgiReg->xgiRegs3C4[i]);
419dfe64dd3Smacallan
420dfe64dd3Smacallan            xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO,4,
421dfe64dd3Smacallan                        "Restore to - %02X Read after - %02X\n",
422dfe64dd3Smacallan                        xgiReg->xgiRegs3C4[i], inb(VGA_SEQ_DATA)); */
423dfe64dd3Smacallan
424dfe64dd3Smacallan            xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO,4,
425dfe64dd3Smacallan                    "XR%X Contents - %02X ", i, inb(XGISR+1));
426dfe64dd3Smacallan
427dfe64dd3Smacallan            outb(XGISR+1,xgiReg->xgiRegs3C4[i]);
428dfe64dd3Smacallan
429dfe64dd3Smacallan            xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO,4,
430dfe64dd3Smacallan                        "Restore to - %02X Read after - %02X\n",
431dfe64dd3Smacallan                        xgiReg->xgiRegs3C4[i], inb(XGISR+1));
432dfe64dd3Smacallan        }
433dfe64dd3Smacallan    }
434dfe64dd3Smacallan
435dfe64dd3Smacallan
436dfe64dd3Smacallan#if 0
437dfe64dd3Smacallan	// yilin restore the VB register
438dfe64dd3Smacallan    outXGIIDXREG(XGIPART1, 0x2f, 0x01);
439dfe64dd3Smacallan    for (i=0; i<0x50; i++)
440dfe64dd3Smacallan    {
441dfe64dd3Smacallan        outXGIIDXREG(XGIPART1, i, xgiReg->VBPart1[i]);
442dfe64dd3Smacallan    }
443dfe64dd3Smacallan    for (i=0; i<0x50; i++)
444dfe64dd3Smacallan    {
445dfe64dd3Smacallan        outXGIIDXREG(XGIPART2, i, xgiReg->VBPart2[i]);
446dfe64dd3Smacallan    }
447dfe64dd3Smacallan    for (i=0; i<0x50; i++)
448dfe64dd3Smacallan    {
449dfe64dd3Smacallan        outXGIIDXREG(XGIPART3, i, xgiReg->VBPart3[i]);
450dfe64dd3Smacallan    }
451dfe64dd3Smacallan    for (i=0; i<0x50; i++)
452dfe64dd3Smacallan    {
453dfe64dd3Smacallan        outXGIIDXREG(XGIPART4, i, xgiReg->VBPart4[i]);
454dfe64dd3Smacallan    }
455dfe64dd3Smacallan#endif
456dfe64dd3Smacallan
457dfe64dd3Smacallan    outb(pXGI->RelIO+0x42, xgiReg->xgiRegs3C2);
458dfe64dd3Smacallan
459dfe64dd3Smacallan    /* MemClock needs this to take effect */
460dfe64dd3Smacallan
461dfe64dd3Smacallan#if !defined(__arm__)
462dfe64dd3Smacallan    outw(VGA_SEQ_INDEX, 0x0100); /* Synchronous Reset */
463dfe64dd3Smacallan#else
464dfe64dd3Smacallan    moutl(XGISR, 0x0100);        /* Synchronous Reset */
465dfe64dd3Smacallan#endif
466dfe64dd3Smacallan
467dfe64dd3Smacallan	PDEBUG(XGIDumpRegs(pScrn)) ; //yilin
468dfe64dd3Smacallan    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4,
469dfe64dd3Smacallan                "Volari_Restore(ScrnInfoPtr pScrn, XGIRegPtr xgiReg) Done\n");
470dfe64dd3Smacallan
471dfe64dd3Smacallan
472dfe64dd3Smacallan}
473dfe64dd3Smacallan
474dfe64dd3Smacallanstatic void
475dfe64dd3SmacallanVolari_Threshold(ScrnInfoPtr pScrn, DisplayModePtr mode,
476dfe64dd3Smacallan		 unsigned short *Low, unsigned short *High)
477dfe64dd3Smacallan{
478dfe64dd3Smacallan        XGIPtr pXGI = XGIPTR(pScrn);
479dfe64dd3Smacallan
480dfe64dd3Smacallan        orXGIIDXREG(XGISR, 0x3D, 0x01);
481dfe64dd3Smacallan}
482dfe64dd3Smacallan
483dfe64dd3Smacallan
484dfe64dd3Smacallan/**
485dfe64dd3Smacallan * Calculate available memory bandwidth for an XG40 series chip.
486dfe64dd3Smacallan *
487dfe64dd3Smacallan * \sa XG40_MemBandWidth
488dfe64dd3Smacallan */
489dfe64dd3Smacallanstatic int XG40_MemBandWidth(ScrnInfoPtr pScrn)
490dfe64dd3Smacallan{
491dfe64dd3Smacallan    static const float magic315[4] = { 1.2, 1.368421, 2.263158, 1.2 };
492dfe64dd3Smacallan    XGIPtr pXGI = XGIPTR(pScrn);
493dfe64dd3Smacallan    const int bus = (pXGI->BusWidth > 128) ? 128 : pXGI->BusWidth;
494dfe64dd3Smacallan    const int mclk = pXGI->MemClock;
495dfe64dd3Smacallan    const int bpp = pScrn->bitsPerPixel;
496dfe64dd3Smacallan    const float magic = magic315[bus / 64];
497dfe64dd3Smacallan    float  total  = (mclk * bus) / bpp;
498dfe64dd3Smacallan
499dfe64dd3Smacallan    PDEBUG5(ErrorF("mclk: %d, bus: %d, magic: %f, bpp: %d\n",
500dfe64dd3Smacallan                   mclk, bus, magic, bpp));
501dfe64dd3Smacallan    PDEBUG5(ErrorF("Total Adapter Bandwidth is %fM\n", total/1000));
502dfe64dd3Smacallan
503dfe64dd3Smacallan    if (pXGI->VBFlags & CRT2_ENABLE)  {
504dfe64dd3Smacallan	total = ((total / 2) > 540000)
505dfe64dd3Smacallan	    ? (total - 540000) : (total / 2);
506dfe64dd3Smacallan    }
507dfe64dd3Smacallan
508dfe64dd3Smacallan    return  (int)(total / magic);
509dfe64dd3Smacallan}
510dfe64dd3Smacallan
511dfe64dd3Smacallan
512dfe64dd3Smacallan/**
513dfe64dd3Smacallan * Calculate available memory bandwidth for an XG20 series chip.
514dfe64dd3Smacallan *
515dfe64dd3Smacallan * \sa XG20_MemBandWidth
516dfe64dd3Smacallan */
517dfe64dd3Smacallanstatic int XG20_MemBandWidth(ScrnInfoPtr pScrn)
518dfe64dd3Smacallan{
519dfe64dd3Smacallan    XGIPtr pXGI = XGIPTR(pScrn);
520dfe64dd3Smacallan    const int bus = (pXGI->BusWidth > 128) ? 128 : pXGI->BusWidth;
521dfe64dd3Smacallan    const int mclk = pXGI->MemClock;
522dfe64dd3Smacallan    const int bpp = pScrn->bitsPerPixel;
523dfe64dd3Smacallan    const float magic = 1.44;
524dfe64dd3Smacallan    float  total  = (mclk * bus) / bpp;
525dfe64dd3Smacallan
526dfe64dd3Smacallan    /* Jong 09/19/2007; support DDRII and double pixel clock */
527dfe64dd3Smacallan    unsigned long SR39, CR97 ;
528dfe64dd3Smacallan
529dfe64dd3Smacallan    PDEBUG5(ErrorF("mclk: %d, bus: %d, magic: %f, bpp: %d\n",
530dfe64dd3Smacallan                   mclk, bus, magic, bpp));
531dfe64dd3Smacallan
532dfe64dd3Smacallan    total = mclk*bus/bpp;
533dfe64dd3Smacallan
534dfe64dd3Smacallan    /* Jong 04/26/2007; support DDRII and double pixel clock */
535dfe64dd3Smacallan    /*-------------------------------------------------------*/
536dfe64dd3Smacallan    inXGIIDXREG(XGISR, 0x39, SR39);
537dfe64dd3Smacallan    inXGIIDXREG(XGICR, 0x97, CR97);
538dfe64dd3Smacallan
539dfe64dd3Smacallan	/* Jong@09082009; modify for XG27 */
540dfe64dd3Smacallan    if(pXGI->Chipset == PCI_CHIP_XGIXG27)
541dfe64dd3Smacallan	{
542dfe64dd3Smacallan		if (CR97 & 0xC1)
543dfe64dd3Smacallan   			total *= 2;
544dfe64dd3Smacallan	}
545dfe64dd3Smacallan	else /* XG20/21 */
546dfe64dd3Smacallan	{
547dfe64dd3Smacallan		if (CR97 & 0x10)
548dfe64dd3Smacallan		{
549dfe64dd3Smacallan   			if (CR97 & 0x01)
550dfe64dd3Smacallan			{
551dfe64dd3Smacallan    			total *= 2;
552dfe64dd3Smacallan			}
553dfe64dd3Smacallan		}
554dfe64dd3Smacallan		else
555dfe64dd3Smacallan		{
556dfe64dd3Smacallan			if (SR39 & 0x2)
557dfe64dd3Smacallan 			{
558dfe64dd3Smacallan  				total *= 2;
559dfe64dd3Smacallan			}
560dfe64dd3Smacallan		}
561dfe64dd3Smacallan	}
562dfe64dd3Smacallan    /*-------------------------------------------------------*/
563dfe64dd3Smacallan
564dfe64dd3Smacallan    PDEBUG5(ErrorF("Total Adapter Bandwidth is %fM\n", total/1000));
565dfe64dd3Smacallan
566dfe64dd3Smacallan    return (int)(total / magic);
567dfe64dd3Smacallan}
568dfe64dd3Smacallan
569dfe64dd3Smacallanextern unsigned int g_GammaRed;
570dfe64dd3Smacallanextern unsigned int g_GammaGreen;
571dfe64dd3Smacallanextern unsigned int g_GammaBlue;
572dfe64dd3Smacallan
573dfe64dd3Smacallanvoid XGIAdjustGamma(ScrnInfoPtr pScrn, unsigned int gammaRed, unsigned int gammaGreen, unsigned int gammaBlue)
574dfe64dd3Smacallan{
575dfe64dd3Smacallan    XGIPtr  pXGI = XGIPTR(pScrn);
576dfe64dd3Smacallan    int num = 255, i;
577dfe64dd3Smacallan	double red = 1.0 / (double)((double)gammaRed / 1000);
578dfe64dd3Smacallan    double green = 1.0 / (double)((double)gammaGreen / 1000);
579dfe64dd3Smacallan    double blue = 1.0 / (double)((double)gammaBlue / 1000);
580dfe64dd3Smacallan	CARD8  GammaRampRed[256], GammaRampGreen[256], GammaRampBlue[256];
581dfe64dd3Smacallan
582dfe64dd3Smacallan    for(i = 0; i <= num; i++) {
583dfe64dd3Smacallan        GammaRampRed[i] =
584dfe64dd3Smacallan	    (red == 1.0) ? i : (CARD8)(pow((double)i / (double)num, red) * (double)num + 0.5);
585dfe64dd3Smacallan
586dfe64dd3Smacallan		GammaRampGreen[i] =
587dfe64dd3Smacallan	    (green == 1.0) ? i : (CARD8)(pow((double)i / (double)num, green) * (double)num + 0.5);
588dfe64dd3Smacallan
589dfe64dd3Smacallan		GammaRampBlue[i] =
590dfe64dd3Smacallan	    (blue == 1.0) ? i : (CARD8)(pow((double)i / (double)num, blue) * (double)num + 0.5);
591dfe64dd3Smacallan    }
592dfe64dd3Smacallan
593dfe64dd3Smacallan	/* set gamma ramp to HW */
594dfe64dd3Smacallan    for(i = 0; i <= 255; i++) {
595dfe64dd3Smacallan       MMIO_OUT32(pXGI->IOBase, 0x8570,
596dfe64dd3Smacallan       		(i << 24)					|
597dfe64dd3Smacallan			(GammaRampBlue[i] << 16)	|
598dfe64dd3Smacallan			(GammaRampGreen[i] << 8)	|
599dfe64dd3Smacallan			GammaRampRed[i]);
600dfe64dd3Smacallan    }
601dfe64dd3Smacallan}
602dfe64dd3Smacallan
603dfe64dd3Smacallanvoid
604dfe64dd3SmacallanXGILoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors,
605dfe64dd3Smacallan               VisualPtr pVisual)
606dfe64dd3Smacallan{
607dfe64dd3Smacallan     XGIPtr  pXGI = XGIPTR(pScrn);
608dfe64dd3Smacallan     int     i, j, index;
609dfe64dd3Smacallan/*     unsigned char backup = 0; */
610dfe64dd3Smacallan     unsigned char SR7;
611dfe64dd3Smacallan     Bool    dogamma1 = pXGI->CRT1gamma;
612dfe64dd3Smacallan/*     Bool    resetxvgamma = FALSE; */
613dfe64dd3Smacallan
614dfe64dd3Smacallan    if (IS_DUAL_HEAD(pXGI)) {
615dfe64dd3Smacallan        XGIEntPtr pXGIEnt = ENTITY_PRIVATE(pXGI);
616dfe64dd3Smacallan        dogamma1 = pXGIEnt->CRT1gamma;
617dfe64dd3Smacallan    }
618dfe64dd3Smacallan
619dfe64dd3Smacallan     PDEBUG(ErrorF("xgiLoadPalette(%d)\n", numColors));
620dfe64dd3Smacallan
621dfe64dd3Smacallan     if (!IS_DUAL_HEAD(pXGI) || IS_SECOND_HEAD(pXGI)) {
622dfe64dd3Smacallan        switch(pXGI->CurrentLayout.depth) {
623dfe64dd3Smacallan#ifdef XGIGAMMA
624dfe64dd3Smacallan          case 15:
625dfe64dd3Smacallan	     if(dogamma1) {
626dfe64dd3Smacallan	        orXGIIDXREG(XGISR, 0x07, 0x04);
627dfe64dd3Smacallan	        for(i=0; i<numColors; i++) {
628dfe64dd3Smacallan                   index = indices[i];
629dfe64dd3Smacallan		   if(index < 32) {   /* Paranoia */
630dfe64dd3Smacallan		      for(j=0; j<8; j++) {
631dfe64dd3Smacallan		         outXGIREG(XGICOLIDX, (index * 8) + j);
632dfe64dd3Smacallan                         outXGIREG(XGICOLDATA, colors[index].red << (8- pScrn->rgbBits));
633dfe64dd3Smacallan                         outXGIREG(XGICOLDATA, colors[index].green << (8 - pScrn->rgbBits));
634dfe64dd3Smacallan                         outXGIREG(XGICOLDATA, colors[index].blue << (8 - pScrn->rgbBits));
635dfe64dd3Smacallan		      }
636dfe64dd3Smacallan		   }
637dfe64dd3Smacallan                }
638dfe64dd3Smacallan	     } else {
639dfe64dd3Smacallan	        andXGIIDXREG(XGISR, 0x07, ~0x04);
640dfe64dd3Smacallan	     }
641dfe64dd3Smacallan	     break;
642dfe64dd3Smacallan	  case 16:
643dfe64dd3Smacallan	     if(dogamma1) {
644dfe64dd3Smacallan		orXGIIDXREG(XGISR, 0x07, 0x04);
645dfe64dd3Smacallan                inXGIIDXREG(XGISR, 0x07, SR7);
646dfe64dd3SmacallanPDEBUG(ErrorF("\ndogamma1 SR7=%x ", SR7));
647dfe64dd3Smacallan		for(i=0; i<numColors; i++) {
648dfe64dd3Smacallan                   index = indices[i];
649dfe64dd3Smacallan		   if(index < 64) {  /* Paranoia */
650dfe64dd3Smacallan		      for(j=0; j<4; j++) {
651dfe64dd3Smacallan		         outXGIREG(XGICOLIDX, (index * 4) + j);
652dfe64dd3Smacallan                         outXGIREG(XGICOLDATA, colors[index/2].red << (8 - pScrn->rgbBits));
653dfe64dd3Smacallan                         outXGIREG(XGICOLDATA, colors[index].green << (8 - pScrn->rgbBits));
654dfe64dd3Smacallan                         outXGIREG(XGICOLDATA, colors[index/2].blue << (8 - pScrn->rgbBits));
655dfe64dd3Smacallan		      }
656dfe64dd3Smacallan		   }
657dfe64dd3Smacallan                }
658dfe64dd3Smacallan	     } else {
659dfe64dd3Smacallan	        andXGIIDXREG(XGISR, 0x07, ~0x04);
660dfe64dd3Smacallan	     }
661dfe64dd3Smacallan	     break;
662dfe64dd3Smacallan          case 24:
663dfe64dd3Smacallan	     if(dogamma1) {
664dfe64dd3Smacallan	        orXGIIDXREG(XGISR, 0x07, 0x04);
665dfe64dd3Smacallan                for(i=0; i<numColors; i++)  {
666dfe64dd3Smacallan                   index = indices[i];
667dfe64dd3Smacallan		   if(index < 256) {   /* Paranoia */
668dfe64dd3Smacallan                      outXGIREG(XGICOLIDX, index);
669dfe64dd3Smacallan                      outXGIREG(XGICOLDATA, colors[index].red);
670dfe64dd3Smacallan                      outXGIREG(XGICOLDATA, colors[index].green);
671dfe64dd3Smacallan                      outXGIREG(XGICOLDATA, colors[index].blue);
672dfe64dd3Smacallan		   }
673dfe64dd3Smacallan                }
674dfe64dd3Smacallan	     } else {
675dfe64dd3Smacallan	        andXGIIDXREG(XGISR, 0x07, ~0x04);
676dfe64dd3Smacallan	     }
677dfe64dd3Smacallan	     break;
678dfe64dd3Smacallan#endif
679dfe64dd3Smacallan	  default:
680dfe64dd3Smacallan	     if((pScrn->rgbBits == 8) && (dogamma1))
681dfe64dd3Smacallan	        orXGIIDXREG(XGISR, 0x07, 0x04);
682dfe64dd3Smacallan	     else
683dfe64dd3Smacallan	        andXGIIDXREG(XGISR, 0x07, ~0x04);
684dfe64dd3Smacallan             for(i=0; i<numColors; i++)  {
685dfe64dd3Smacallan                index = indices[i];
686dfe64dd3Smacallan                outXGIREG(XGICOLIDX, index);
687dfe64dd3Smacallan                outXGIREG(XGICOLDATA, colors[index].red >> (8 - pScrn->rgbBits));
688dfe64dd3Smacallan                outXGIREG(XGICOLDATA, colors[index].green >> (8 - pScrn->rgbBits));
689dfe64dd3Smacallan                outXGIREG(XGICOLDATA, colors[index].blue >> (8 - pScrn->rgbBits));
690dfe64dd3Smacallan             }
691dfe64dd3Smacallan	}
692dfe64dd3Smacallan
693dfe64dd3Smacallan    }
694dfe64dd3Smacallan
695dfe64dd3Smacallan    if (!IS_DUAL_HEAD(pXGI) || !IS_SECOND_HEAD(pXGI)) {
696dfe64dd3Smacallan
697dfe64dd3Smacallan    }
698dfe64dd3Smacallan
699dfe64dd3Smacallan	if(pXGI->CurrentLayout.depth != 8)
700dfe64dd3Smacallan		XGIAdjustGamma(pScrn, g_GammaRed, g_GammaGreen, g_GammaBlue);
701dfe64dd3Smacallan}
702dfe64dd3Smacallan
703dfe64dd3Smacallanvoid
704dfe64dd3SmacallanXGIDACPreInit(ScrnInfoPtr pScrn)
705dfe64dd3Smacallan{
706dfe64dd3Smacallan    XGIPtr  pXGI = XGIPTR(pScrn);
707dfe64dd3Smacallan
708dfe64dd3SmacallanPDEBUG(ErrorF("XGIDACPreInit()\n"));
709dfe64dd3Smacallan
710dfe64dd3Smacallan    pXGI->XGISave = Volari_Save;
711dfe64dd3Smacallan    pXGI->XGIRestore = Volari_Restore;
712dfe64dd3Smacallan    pXGI->SetThreshold = Volari_Threshold;
713dfe64dd3Smacallan
714dfe64dd3Smacallan    pXGI->MaxClock = ((pXGI->Chipset == PCI_CHIP_XGIXG20) || (pXGI->Chipset == PCI_CHIP_XGIXG21) || (pXGI->Chipset == PCI_CHIP_XGIXG27))
715dfe64dd3Smacallan	? XG20_MemBandWidth(pScrn) : XG40_MemBandWidth(pScrn);
716dfe64dd3Smacallan}
717dfe64dd3Smacallan
718dfe64dd3Smacallan
719dfe64dd3Smacallanint
720dfe64dd3SmacallanXG40Mclk(XGIPtr pXGI)
721dfe64dd3Smacallan{
722dfe64dd3Smacallan    int mclk;
723dfe64dd3Smacallan    unsigned char Num, Denum;
724dfe64dd3Smacallan
725dfe64dd3Smacallan    /* Numerator */
726dfe64dd3Smacallan    /* inXGIIDXREG(0x3c4, 0x28, Num); */
727dfe64dd3Smacallan    inXGIIDXREG(XGISR, 0x28, Num);
728dfe64dd3Smacallan    mclk = 14318 * ((Num & 0x7f) + 1);
729dfe64dd3Smacallan
730dfe64dd3Smacallan    /* Denumerator */
731dfe64dd3Smacallan    /* inXGIIDXREG(0x3c4, 0x29, Denum); */
732dfe64dd3Smacallan    inXGIIDXREG(XGISR, 0x29, Denum);
733dfe64dd3Smacallan    mclk = mclk / ((Denum & 0x1f) + 1);
734dfe64dd3Smacallan
735dfe64dd3Smacallan    /* Divider */
736dfe64dd3Smacallan    if ((Num & 0x80)!=0)  {
737dfe64dd3Smacallan	mclk = mclk * 2;
738dfe64dd3Smacallan    }
739dfe64dd3Smacallan
740dfe64dd3Smacallan    /* Post-Scaler */
741dfe64dd3Smacallan    mclk /= ((Denum & 0x80) == 0)
742dfe64dd3Smacallan	?  (((Denum & 0x60) >> 5) + 1)
743dfe64dd3Smacallan	: ((((Denum & 0x60) >> 5) + 1) * 2);
744dfe64dd3Smacallan
745dfe64dd3Smacallan    return mclk;
746dfe64dd3Smacallan}
747dfe64dd3Smacallan
748dfe64dd3Smacallan
749dfe64dd3Smacallanstatic int
750dfe64dd3Smacallanretrace_signals_active(XGIIOADDRESS RelIO)
751dfe64dd3Smacallan{
752dfe64dd3Smacallan    unsigned char temp;
753dfe64dd3Smacallan
754dfe64dd3Smacallan    /* Make sure the vertical retrace signal is enabled.
755dfe64dd3Smacallan     */
756dfe64dd3Smacallan    inXGIIDXREG(RelIO + CROFFSET, 0x17, temp);
757dfe64dd3Smacallan    if (!(temp & 0x80))
758dfe64dd3Smacallan	return 0;
759dfe64dd3Smacallan
760dfe64dd3Smacallan    /* FIXME: Magic offset, what are you?
761dfe64dd3Smacallan     */
762dfe64dd3Smacallan    inXGIIDXREG(RelIO + SROFFSET, 0x1f, temp);
763dfe64dd3Smacallan    if(temp & 0xc0)
764dfe64dd3Smacallan	return 0;
765dfe64dd3Smacallan
766dfe64dd3Smacallan    return 1;
767dfe64dd3Smacallan}
768dfe64dd3Smacallan
769dfe64dd3Smacallan
770dfe64dd3Smacallan/**
771dfe64dd3Smacallan * Wait for beginning of next vertical retrace.
772dfe64dd3Smacallan *
773dfe64dd3Smacallan * \bugs
774dfe64dd3Smacallan * The functions \c XGI_WaitBeginRetrace and \c XGI_WaitEndRetrace are
775dfe64dd3Smacallan * nearly identical.  Are both \b really necessary?
776dfe64dd3Smacallan */
777dfe64dd3Smacallanvoid
778dfe64dd3SmacallanXGI_WaitBeginRetrace(XGIIOADDRESS RelIO)
779dfe64dd3Smacallan{
780dfe64dd3Smacallan    int           watchdog;
781dfe64dd3Smacallan
782dfe64dd3Smacallan    if (retrace_signals_active(RelIO)) {
783dfe64dd3Smacallan	/* Wait for the CRTC to leave then re-enter the vertical retrace
784dfe64dd3Smacallan	 * period.
785dfe64dd3Smacallan	 */
786dfe64dd3Smacallan	watchdog = 65536;
787dfe64dd3Smacallan	while ((inXGIREG(RelIO + INPUTSTATOFFSET) & IS_BIT_VERT_ACTIVE) && --watchdog)
788dfe64dd3Smacallan	    /* empty */ ;
789dfe64dd3Smacallan
790dfe64dd3Smacallan	watchdog = 65536;
791dfe64dd3Smacallan	while ((!(inXGIREG(RelIO + INPUTSTATOFFSET) & IS_BIT_VERT_ACTIVE)) && --watchdog)
792dfe64dd3Smacallan	    /* empty */ ;
793dfe64dd3Smacallan    }
794dfe64dd3Smacallan}
795dfe64dd3Smacallan
796dfe64dd3Smacallan
797dfe64dd3Smacallan/**
798dfe64dd3Smacallan * Wait for end of next vertical retrace.
799dfe64dd3Smacallan *
800dfe64dd3Smacallan * \bugs
801dfe64dd3Smacallan * The functions \c XGI_WaitBeginRetrace and \c XGI_WaitEndRetrace are
802dfe64dd3Smacallan * nearly identical.  Are both \b really necessary?
803dfe64dd3Smacallan */
804dfe64dd3Smacallanvoid
805dfe64dd3SmacallanXGI_WaitEndRetrace(XGIIOADDRESS RelIO)
806dfe64dd3Smacallan{
807dfe64dd3Smacallan    int           watchdog;
808dfe64dd3Smacallan
809dfe64dd3Smacallan    if (retrace_signals_active(RelIO)) {
810dfe64dd3Smacallan	/* Wait for the CRTC to enter then leave the vertical retrace
811dfe64dd3Smacallan	 * period.
812dfe64dd3Smacallan	 */
813dfe64dd3Smacallan	watchdog = 65536;
814dfe64dd3Smacallan	while ((!(inXGIREG(RelIO + INPUTSTATOFFSET) & IS_BIT_VERT_ACTIVE)) && --watchdog)
815dfe64dd3Smacallan	    /* empty */ ;
816dfe64dd3Smacallan
817dfe64dd3Smacallan	watchdog = 65536;
818dfe64dd3Smacallan	while ((inXGIREG(RelIO + INPUTSTATOFFSET) & IS_BIT_VERT_ACTIVE) && --watchdog)
819dfe64dd3Smacallan	    /* empty */ ;
820dfe64dd3Smacallan    }
821dfe64dd3Smacallan}
822