sis_dac.c revision 72b676d7
1/* $XFree86$ */
2/* $XdotOrg$ */
3/*
4 * DAC helper functions (Save/Restore, MemClk, etc)
5 *
6 * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1) Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2) Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3) The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Author:  	Thomas Winischhofer <thomas@winischhofer.net>
31 *
32 * --------------------------------------------------------------------------
33 *
34 * SiS_compute_vclk(), SiSCalcClock() and parts of SiSMclk():
35 *
36 * Copyright (C) 1998, 1999 by Alan Hourihane, Wigan, England
37 * Written by:
38 *	 Alan Hourihane <alanh@fairlite.demon.co.uk>,
39 *       Mike Chapman <mike@paranoia.com>,
40 *       Juanjo Santamarta <santamarta@ctv.es>,
41 *       Mitani Hiroshi <hmitani@drl.mei.co.jp>,
42 *       David Thomas <davtom@dream.org.uk>,
43 *	 Thomas Winischhofer <thomas@winischhofer.net>.
44 *
45 * Licensed under the following terms:
46 *
47 * Permission to use, copy, modify, distribute, and sell this software and its
48 * documentation for any purpose is hereby granted without fee, provided that
49 * the above copyright notice appears in all copies and that both that copyright
50 * notice and this permission notice appear in supporting documentation, and
51 * and that the name of the copyright holder not be used in advertising
52 * or publicity pertaining to distribution of the software without specific,
53 * written prior permission. The copyright holder makes no representations
54 * about the suitability of this software for any purpose.  It is provided
55 * "as is" without expressed or implied warranty.
56 *
57 * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
58 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
59 * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
60 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
61 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
62 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
63 * PERFORMANCE OF THIS SOFTWARE.
64 */
65
66#ifdef HAVE_CONFIG_H
67#include "config.h"
68#endif
69
70#include "sis.h"
71#define SIS_NEED_inSISREG
72#define SIS_NEED_inSISREGW
73#define SIS_NEED_inSISREGL
74#define SIS_NEED_outSISREG
75#define SIS_NEED_outSISREGW
76#define SIS_NEED_outSISREGL
77#define SIS_NEED_inSISIDXREG
78#define SIS_NEED_outSISIDXREG
79#define SIS_NEED_orSISIDXREG
80#define SIS_NEED_andSISIDXREG
81#define SIS_NEED_MYMMIO
82#include "sis_regs.h"
83#include "sis_dac.h"
84
85static void SiSSave(ScrnInfoPtr pScrn, SISRegPtr sisReg);
86static void SiSRestore(ScrnInfoPtr pScrn, SISRegPtr sisReg);
87static void SiS300Save(ScrnInfoPtr pScrn, SISRegPtr sisReg);
88static void SiS300Restore(ScrnInfoPtr pScrn, SISRegPtr sisReg);
89static void SiS315Save(ScrnInfoPtr pScrn, SISRegPtr sisReg);
90static void SiS315Restore(ScrnInfoPtr pScrn, SISRegPtr sisReg);
91static void SiS301Save(ScrnInfoPtr pScrn, SISRegPtr sisReg);
92static void SiS301BSave(ScrnInfoPtr pScrn, SISRegPtr sisReg);
93static void SiSLVDSChrontelSave(ScrnInfoPtr pScrn, SISRegPtr sisReg);
94static void SiS301Restore(ScrnInfoPtr pScrn, SISRegPtr sisReg);
95static void SiS301BRestore(ScrnInfoPtr pScrn, SISRegPtr sisReg);
96static void SiSLVDSChrontelRestore(ScrnInfoPtr pScrn, SISRegPtr sisReg);
97static void SiS301LoadPalette(ScrnInfoPtr pScrn, int numColors,
98                      int *indicies, LOCO *colors, int myshift);
99static void SetBlock(CARD16 port, CARD8 from, CARD8 to, CARD8 *DataPtr);
100
101UChar       SiSGetCopyROP(int rop);
102UChar       SiSGetPatternROP(int rop);
103
104static const UShort ch700xidx[] = {
105      0x00,0x07,0x08,0x0a,0x0b,0x04,0x09,0x20,0x21,0x18,0x19,0x1a,
106      0x1b,0x1c,0x1d,0x1e,0x1f,  /* 0x0e,  - Don't save the power register */
107      0x01,0x03,0x06,0x0d,0x11,0x13,0x14,0x15,0x17,0x22,0x23,0x24
108   };
109
110static const UShort ch701xidx[] = {
111      0x1c,0x5f,0x64,0x6f,0x70,0x71,0x72,0x73,0x74,0x76,0x78,0x7d,
112      0x67,0x68,0x69,0x6a,0x6b,0x1e,0x00,0x01,0x02,0x04,0x03,0x05,
113      0x06,0x07,0x08,0x15,0x1f,0x0c,0x0d,0x0e,0x0f,0x10,0x66
114   };
115
116int SiS_compute_vclk(
117        int Clock,
118        int *out_n,
119        int *out_dn,
120        int *out_div,
121        int *out_sbit,
122        int *out_scale)
123{
124    float f,x,y,t, error, min_error;
125    int n, dn, best_n=0, best_dn=0;
126
127    /*
128     * Rules
129     *
130     * VCLK = 14.318 * (Divider/Post Scalar) * (Numerator/DeNumerator)
131     * Factor = (Divider/Post Scalar)
132     * Divider is 1 or 2
133     * Post Scalar is 1, 2, 3, 4, 6 or 8
134     * Numberator ranged from 1 to 128
135     * DeNumerator ranged from 1 to 32
136     * a. VCO = VCLK/Factor, suggest range is 150 to 250 Mhz
137     * b. Post Scalar selected from 1, 2, 4 or 8 first.
138     * c. DeNumerator selected from 2.
139     *
140     * According to rule a and b, the VCO ranges that can be scaled by
141     * rule b are:
142     *      150    - 250    (Factor = 1)
143     *       75    - 125    (Factor = 2)
144     *       37.5  -  62.5  (Factor = 4)
145     *       18.75 -  31.25 (Factor = 8)
146     *
147     * The following ranges use Post Scalar 3 or 6:
148     *      125    - 150    (Factor = 1.5)
149     *       62.5  -  75    (Factor = 3)
150     *       31.25 -  37.5  (Factor = 6)
151     *
152     * Steps:
153     * 1. divide the Clock by 2 until the Clock is less or equal to 31.25.
154     * 2. if the divided Clock is range from 18.25 to 31.25, than
155     *    the Factor is 1, 2, 4 or 8.
156     * 3. if the divided Clock is range from 15.625 to 18.25, than
157     *    the Factor is 1.5, 3 or 6.
158     * 4. select the Numberator and DeNumberator with minimum deviation.
159     *
160     * ** this function can select VCLK ranged from 18.75 to 250 Mhz
161     */
162
163    f = (float) Clock;
164    f /= 1000.0;
165    if((f > 250.0) || (f < 18.75))
166       return 0;
167
168    min_error = f;
169    y = 1.0;
170    x = f;
171    while(x > 31.25) {
172       y *= 2.0;
173       x /= 2.0;
174    }
175    if(x >= 18.25) {
176       x *= 8.0;
177       y = 8.0 / y;
178    } else if(x >= 15.625) {
179       x *= 12.0;
180       y = 12.0 / y;
181    }
182
183    t = y;
184    if(t == (float) 1.5) {
185       *out_div = 2;
186       t *= 2.0;
187    } else {
188       *out_div = 1;
189    }
190    if(t > (float) 4.0) {
191       *out_sbit = 1;
192       t /= 2.0;
193    } else {
194       *out_sbit = 0;
195    }
196
197    *out_scale = (int) t;
198
199    for(dn = 2; dn <= 32; dn++) {
200       for(n = 1; n <= 128; n++) {
201          error = x;
202          error -= ((float) 14.318 * (float) n / (float) dn);
203          if(error < (float) 0)
204             error = -error;
205          if(error < min_error) {
206             min_error = error;
207             best_n = n;
208             best_dn = dn;
209          }
210       }
211    }
212    *out_n = best_n;
213    *out_dn = best_dn;
214    PDEBUG(ErrorF("SiS_compute_vclk: Clock=%d, n=%d, dn=%d, div=%d, sbit=%d,"
215                    " scale=%d\n", Clock, best_n, best_dn, *out_div,
216                    *out_sbit, *out_scale));
217    return 1;
218}
219
220void
221SiSCalcClock(ScrnInfoPtr pScrn, int clock, int max_VLD, unsigned int *vclk)
222{
223    SISPtr pSiS = SISPTR(pScrn);
224    int M, N, P , PSN, VLD , PSNx ;
225    int bestM=0, bestN=0, bestP=0, bestPSN=0, bestVLD=0;
226    double abest = 42.0;
227    double target;
228    double Fvco, Fout;
229    double error, aerror;
230
231    /*
232     *  fd = fref*(Numerator/Denumerator)*(Divider/PostScaler)
233     *
234     *  M       = Numerator [1:128]
235     *  N       = DeNumerator [1:32]
236     *  VLD     = Divider (Vco Loop Divider) : divide by 1, 2
237     *  P       = Post Scaler : divide by 1, 2, 3, 4
238     *  PSN     = Pre Scaler (Reference Divisor Select)
239     *
240     * result in vclk[]
241     */
242#define Midx    0
243#define Nidx    1
244#define VLDidx  2
245#define Pidx    3
246#define PSNidx  4
247#define Fref 14318180
248/* stability constraints for internal VCO -- MAX_VCO also determines
249 * the maximum Video pixel clock */
250#define MIN_VCO      Fref
251#define MAX_VCO      135000000
252#define MAX_VCO_5597 353000000
253#define MAX_PSN      0          /* no pre scaler for this chip */
254#define TOLERANCE    0.01       /* search smallest M and N in this tolerance */
255
256  int M_min = 2;
257  int M_max = 128;
258
259  target = clock * 1000;
260
261  if(pSiS->Chipset == PCI_CHIP_SIS5597 || pSiS->Chipset == PCI_CHIP_SIS6326) {
262
263     int low_N = 2;
264     int high_N = 5;
265
266     PSN = 1;
267     P = 1;
268     if(target < MAX_VCO_5597 / 2)  P = 2;
269     if(target < MAX_VCO_5597 / 3)  P = 3;
270     if(target < MAX_VCO_5597 / 4)  P = 4;
271     if(target < MAX_VCO_5597 / 6)  P = 6;
272     if(target < MAX_VCO_5597 / 8)  P = 8;
273
274     Fvco = P * target;
275
276     for(N = low_N; N <= high_N; N++) {
277
278         double M_desired = Fvco / Fref * N;
279         if(M_desired > M_max * max_VLD)  continue;
280
281         if(M_desired > M_max) {
282            M = M_desired / 2 + 0.5;
283            VLD = 2;
284         } else {
285            M = Fvco / Fref * N + 0.5;
286            VLD = 1;
287         }
288
289         Fout = (double)Fref * (M * VLD)/(N * P);
290
291         error = (target - Fout) / target;
292         aerror = (error < 0) ? -error : error;
293         if(aerror < abest) {
294            abest = aerror;
295            bestM = M;
296            bestN = N;
297            bestP = P;
298            bestPSN = PSN;
299            bestVLD = VLD;
300         }
301     }
302
303  } else {
304
305     for(PSNx = 0; PSNx <= MAX_PSN ; PSNx++) {
306
307        int low_N, high_N;
308        double FrefVLDPSN;
309
310        PSN = !PSNx ? 1 : 4;
311
312        low_N = 2;
313        high_N = 32;
314
315        for(VLD = 1 ; VLD <= max_VLD ; VLD++) {
316
317           FrefVLDPSN = (double)Fref * VLD / PSN;
318
319	   for(N = low_N; N <= high_N; N++) {
320              double tmp = FrefVLDPSN / N;
321
322              for(P = 1; P <= 4; P++) {
323                 double Fvco_desired = target * ( P );
324                 double M_desired = Fvco_desired / tmp;
325
326                 /* Which way will M_desired be rounded?
327                  *  Do all three just to be safe.
328                  */
329                 int M_low = M_desired - 1;
330                 int M_hi = M_desired + 1;
331
332                 if(M_hi < M_min || M_low > M_max) continue;
333
334		 if(M_low < M_min)  M_low = M_min;
335
336		 if(M_hi > M_max)   M_hi = M_max;
337
338                 for(M = M_low; M <= M_hi; M++) {
339                    Fvco = tmp * M;
340                    if(Fvco <= MIN_VCO) continue;
341                    if(Fvco > MAX_VCO)  break;
342
343                    Fout = Fvco / ( P );
344
345                    error = (target - Fout) / target;
346                    aerror = (error < 0) ? -error : error;
347                    if(aerror < abest) {
348                       abest = aerror;
349                       bestM = M;
350                       bestN = N;
351                       bestP = P;
352                       bestPSN = PSN;
353                       bestVLD = VLD;
354                    }
355#ifdef TWDEBUG
356                    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO,3,
357			       "Freq. selected: %.2f MHz, M=%d, N=%d, VLD=%d, P=%d, PSN=%d\n",
358                               (float)(clock / 1000.), M, N, P, VLD, PSN);
359                    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO,3,
360			       "Freq. set: %.2f MHz\n", Fout / 1.0e6);
361#endif
362                 }
363              }
364           }
365        }
366     }
367  }
368
369  vclk[Midx]   = bestM;
370  vclk[Nidx]   = bestN;
371  vclk[VLDidx] = bestVLD;
372  vclk[Pidx]   = bestP;
373  vclk[PSNidx] = bestPSN;
374}
375
376static void
377SiSSave(ScrnInfoPtr pScrn, SISRegPtr sisReg)
378{
379    SISPtr pSiS = SISPTR(pScrn);
380    int i, max;
381
382    PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "SiSSave()\n"));
383
384#ifdef UNLOCK_ALWAYS
385    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
386#endif
387
388    switch(pSiS->Chipset) {
389        case PCI_CHIP_SIS5597:
390           max=0x3C;
391           break;
392        case PCI_CHIP_SIS6326:
393        case PCI_CHIP_SIS530:
394           max=0x3F;
395           break;
396        default:
397           max=0x37;
398    }
399
400    /* Save extended SR registers */
401    for(i = 0x00; i <= max; i++) {
402       inSISIDXREG(SISSR, i, sisReg->sisRegs3C4[i]);
403#ifdef TWDEBUG
404       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
405		 "SR%02X - %02X \n", i, sisReg->sisRegs3C4[i]);
406#endif
407    }
408
409#ifdef TWDEBUG
410    for(i = 0x00; i <= 0x3f; i++) {
411       inSISIDXREG(SISCR, i, max);
412       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
413		 "CR%02X - %02X \n", i, max);
414    }
415#endif
416
417    /* Save lock (will not be restored in SiSRestore()!) */
418    inSISIDXREG(SISCR, 0x80, sisReg->sisRegs3D4[0x80]);
419
420    sisReg->sisRegs3C2 = inSISREG(SISMISCR);	 /* Misc */
421
422    /* Save TV registers */
423    if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
424       outSISIDXREG(SISCR, 0x80, 0x86);
425       for(i = 0x00; i <= 0x44; i++) {
426          sisReg->sis6326tv[i] = SiS6326GetTVReg(pScrn, i);
427#ifdef TWDEBUG
428          xf86DrvMsg(pScrn->scrnIndex, X_INFO,
429		 "VR%02X - %02X \n", i,sisReg->sis6326tv[i]);
430#endif
431       }
432    }
433}
434
435static void
436SiSRestore(ScrnInfoPtr pScrn, SISRegPtr sisReg)
437{
438    SISPtr pSiS = SISPTR(pScrn);
439    int i, max;
440    UChar tmp;
441
442    PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4, "SiSRestore()\n"));
443
444#ifdef UNLOCK_ALWAYS
445    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
446#endif
447
448    switch(pSiS->Chipset) {
449        case PCI_CHIP_SIS5597:
450           max = 0x3C;
451           break;
452        case PCI_CHIP_SIS6326:
453	case PCI_CHIP_SIS530:
454           max = 0x3F;
455           break;
456        default:
457           max = 0x37;
458    }
459
460    /* Disable TV on 6326 before restoring */
461    if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
462       outSISIDXREG(SISCR, 0x80, 0x86);
463       tmp = SiS6326GetTVReg(pScrn, 0x00);
464       tmp &= ~0x04;
465       SiS6326SetTVReg(pScrn, 0x00, tmp);
466    }
467
468    /* Restore other extended SR registers */
469    for(i = 0x06; i <= max; i++) {
470       if((i == 0x13) || (i == 0x2a) || (i == 0x2b)) continue;
471       outSISIDXREG(SISSR, i, sisReg->sisRegs3C4[i]);
472    }
473
474    /* Now restore VCLK (with correct SR38 setting) */
475    outSISIDXREG(SISSR, 0x13, sisReg->sisRegs3C4[0x13]);
476    outSISIDXREG(SISSR, 0x2a, sisReg->sisRegs3C4[0x2a]);
477    outSISIDXREG(SISSR, 0x2b, sisReg->sisRegs3C4[0x2b]);
478
479    /* Misc */
480    outSISREG(SISMISCW, sisReg->sisRegs3C2);
481
482    /* MemClock needs this to take effect */
483    outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
484    usleep(10000);
485    outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
486
487    /* Restore TV registers */
488    pSiS->SiS6326Flags &= ~SIS6326_TVON;
489    if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
490       for(i = 0x01; i <= 0x44; i++) {
491          SiS6326SetTVReg(pScrn, i, sisReg->sis6326tv[i]);
492#ifdef TWDEBUG
493          xf86DrvMsg(pScrn->scrnIndex, X_INFO,
494		"VR%02x restored to %02x\n",
495		i, sisReg->sis6326tv[i]);
496#endif
497       }
498       tmp = SiS6326GetXXReg(pScrn, 0x13);
499       SiS6326SetXXReg(pScrn, 0x13, 0xfa);
500       tmp = SiS6326GetXXReg(pScrn, 0x14);
501       SiS6326SetXXReg(pScrn, 0x14, 0xc8);
502       if(!(sisReg->sisRegs3C4[0x0D] & 0x04)) {
503	  tmp = SiS6326GetXXReg(pScrn, 0x13);
504	  SiS6326SetXXReg(pScrn, 0x13, 0xf6);
505	  tmp = SiS6326GetXXReg(pScrn, 0x14);
506	  SiS6326SetXXReg(pScrn, 0x14, 0xbf);
507       }
508       if(sisReg->sis6326tv[0] & 0x04) pSiS->SiS6326Flags |= SIS6326_TVON;
509    }
510}
511
512/* Save SiS 300 series register contents */
513static void
514SiS300Save(ScrnInfoPtr pScrn, SISRegPtr sisReg)
515{
516    SISPtr pSiS = SISPTR(pScrn);
517    int i;
518
519    PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "SiS300Save()\n"));
520
521#ifdef UNLOCK_ALWAYS
522    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
523#endif
524
525    /* Save SR registers */
526    for(i = 0x00; i <= 0x3D; i++) {
527       inSISIDXREG(SISSR, i, sisReg->sisRegs3C4[i]);
528#ifdef TWDEBUG
529       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
530		 "SR%02X - %02X \n", i,sisReg->sisRegs3C4[i]);
531#endif
532    }
533
534    /* Save CR registers */
535    for(i = 0x00; i < 0x40; i++)  {
536       inSISIDXREG(SISCR, i, sisReg->sisRegs3D4[i]);
537#ifdef TWDEBUG
538       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
539		"CR%02X Contents - %02X \n", i,sisReg->sisRegs3D4[i]);
540#endif
541    }
542
543    /* Save Misc register */
544    sisReg->sisRegs3C2 = inSISREG(SISMISCR);
545
546    /* Save FQBQ and GUI timer settings */
547    if(pSiS->Chipset == PCI_CHIP_SIS630) {
548       sisReg->sisRegsPCI50 = pciReadLong(0x00000000, 0x50);
549       sisReg->sisRegsPCIA0 = pciReadLong(0x00000000, 0xA0);
550#ifdef TWDEBUG
551       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
552		"PCI Config 50 = %lx\n", sisReg->sisRegsPCI50);
553       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
554		"PCI Config A0 = %lx\n", sisReg->sisRegsPCIA0);
555#endif
556    }
557
558    /* Save panel link/video bridge registers */
559#ifndef TWDEBUG
560    if(!pSiS->UseVESA) {
561#endif
562       if(pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL))
563          SiSLVDSChrontelSave(pScrn, sisReg);
564       else if(pSiS->VBFlags2 & VB2_301)
565          SiS301Save(pScrn, sisReg);
566       else if(pSiS->VBFlags2 & VB2_30xBLV)
567          SiS301BSave(pScrn, sisReg);
568#ifndef TWDEBUG
569    }
570#endif
571
572    /* Save Mode number */
573    sisReg->BIOSModeSave = SiS_GetSetModeID(pScrn,0xFF);
574
575#ifdef TWDEBUG
576    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
577	"BIOS mode ds:449 = 0x%x\n", sisReg->BIOSModeSave);
578#endif
579}
580
581/* Restore SiS300 series register contents */
582static void
583SiS300Restore(ScrnInfoPtr pScrn, SISRegPtr sisReg)
584{
585    SISPtr pSiS = SISPTR(pScrn);
586    int i,temp;
587    CARD32 temp1, temp2;
588
589    PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4, "SiS300Restore()\n"));
590
591#ifdef UNLOCK_ALWAYS
592    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
593#endif
594
595    /* Wait for accelerator to finish on-going drawing operations. */
596    inSISIDXREG(SISSR, 0x1E, temp);
597    if(temp & (0x40|0x10|0x02))  {
598       while ( (SIS_MMIO_IN16(pSiS->IOBase, 0x8242) & 0xE000) != 0xE000){};
599       while ( (SIS_MMIO_IN16(pSiS->IOBase, 0x8242) & 0xE000) != 0xE000){};
600       while ( (SIS_MMIO_IN16(pSiS->IOBase, 0x8242) & 0xE000) != 0xE000){};
601    }
602
603    if(!(pSiS->UseVESA)) {
604       if(pSiS->VBFlags2 & VB2_LVDS) {
605	  SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30);
606	  SiSSetLVDSetc(pSiS->SiS_Pr, 0);
607	  SiS_GetVBType(pSiS->SiS_Pr);
608	  SiS_UnLockCRT2(pSiS->SiS_Pr);
609	  SiS_DisableBridge(pSiS->SiS_Pr);
610       }
611    }
612
613    /* Restore extended CR registers */
614    for(i = 0x19; i < 0x40; i++) {
615       outSISIDXREG(SISCR, i, sisReg->sisRegs3D4[i]);
616    }
617
618    if(pSiS->Chipset != PCI_CHIP_SIS300)  {
619       UChar val;
620       inSISIDXREG(SISCR, 0x1A, val);
621       if(val == sisReg->sisRegs3D4[0x19])
622	  outSISIDXREG(SISCR, 0x1A, sisReg->sisRegs3D4[0x19]);
623       inSISIDXREG(SISCR,0x19,val);
624       if(val == sisReg->sisRegs3D4[0x1A])
625	  outSISIDXREG(SISCR, 0x19, sisReg->sisRegs3D4[0x1A]);
626    }
627
628    /* Set (and leave) PCI_IO_ENABLE on if accelerators are on */
629    if(sisReg->sisRegs3C4[0x1e] & 0x50) {
630       sisReg->sisRegs3C4[0x20] |= 0x20;
631       outSISIDXREG(SISSR, 0x20, sisReg->sisRegs3C4[0x20]);
632    }
633
634    /* If TQ is switched on, don't switch it off ever again!
635     * Therefore, always restore registers with TQ enabled.
636     */
637    if((!pSiS->NoAccel) && (pSiS->TurboQueue)) {
638       temp = (pScrn->videoRam/64) - 8;
639       sisReg->sisRegs3C4[0x26] = temp & 0xFF;
640       sisReg->sisRegs3C4[0x27] = ((temp >> 8) & 3) | 0xF0;
641    }
642
643    /* Restore extended SR registers */
644    for(i = 0x06; i <= 0x3D; i++) {
645       temp = sisReg->sisRegs3C4[i];
646       if(!(pSiS->UseVESA)) {
647	  if(pSiS->VBFlags2 & VB2_LVDS) {
648	     if(i == 0x11) {
649		inSISIDXREG(SISSR,0x11,temp);
650		temp &= 0x0c;
651		temp |= (sisReg->sisRegs3C4[i] & 0xf3);
652	     }
653          }
654       }
655       outSISIDXREG(SISSR, i, temp);
656    }
657
658    /* Restore VCLK and ECLK */
659    if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xB)) {
660       outSISIDXREG(SISSR,0x31,0x20);
661       outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]);
662       outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]);
663       outSISIDXREG(SISSR,0x2d,0x80);
664       outSISIDXREG(SISSR,0x31,0x10);
665       outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]);
666       outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]);
667       outSISIDXREG(SISSR,0x2d,0x80);
668    }
669    outSISIDXREG(SISSR,0x31,0x00);
670    outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]);
671    outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]);
672    outSISIDXREG(SISSR,0x2d,0x80);
673    if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xB)) {
674       outSISIDXREG(SISSR,0x31,0x20);
675       outSISIDXREG(SISSR,0x2e,sisReg->sisRegs3C4[0x2e]);
676       outSISIDXREG(SISSR,0x2f,sisReg->sisRegs3C4[0x2f]);
677       outSISIDXREG(SISSR,0x31,0x10);
678       outSISIDXREG(SISSR,0x2e,sisReg->sisRegs3C4[0x2e]);
679       outSISIDXREG(SISSR,0x2f,sisReg->sisRegs3C4[0x2f]);
680       outSISIDXREG(SISSR,0x31,0x00);
681       outSISIDXREG(SISSR,0x2e,sisReg->sisRegs3C4[0x2e]);
682       outSISIDXREG(SISSR,0x2f,sisReg->sisRegs3C4[0x2f]);
683    }
684
685    /* Restore Misc register */
686    outSISREG(SISMISCW, sisReg->sisRegs3C2);
687
688    /* Restore FQBQ and GUI timer settings */
689    if(pSiS->Chipset == PCI_CHIP_SIS630) {
690       temp1 = pciReadLong(0x00000000, 0x50);
691       temp2 = pciReadLong(0x00000000, 0xA0);
692       if(pciReadLong(0x00000000, 0x00) == 0x06301039) {
693          temp1 &= 0xf0ffffff;
694          temp1 |= (sisReg->sisRegsPCI50 & ~0xf0ffffff);
695	  temp2 &= 0xf0ffffff;
696          temp2 |= (sisReg->sisRegsPCIA0 & ~0xf0ffffff);
697       } else {  /* 730 */
698          temp1 &= 0xfffff9ff;
699          temp1 |= (sisReg->sisRegsPCI50 & ~0xfffff9ff);
700	  temp2 &= 0x00ffffff;
701          temp2 |= (sisReg->sisRegsPCIA0 & ~0x00ffffff);
702       }
703       pciWriteLong(0x00000000, 0x50, temp1);
704       pciWriteLong(0x00000000, 0xA0, temp2);
705    }
706
707    /* Restore panel link/video bridge registers */
708    if(!(pSiS->UseVESA)) {
709       if(pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL))
710          SiSLVDSChrontelRestore(pScrn, sisReg);
711       else if(pSiS->VBFlags2 & VB2_301)
712          SiS301Restore(pScrn, sisReg);
713       else if(pSiS->VBFlags2 & VB2_30xBLV)
714          SiS301BRestore(pScrn, sisReg);
715    }
716
717    /* MemClock needs this to take effect */
718    outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
719    outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
720
721    /* Restore mode number */
722    SiS_GetSetModeID(pScrn,sisReg->BIOSModeSave);
723}
724
725/* Save SiS315 series register contents */
726static void
727SiS315Save(ScrnInfoPtr pScrn, SISRegPtr sisReg)
728{
729    SISPtr pSiS = SISPTR(pScrn);
730    int i, max;
731
732    PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "SiS315Save()\n"));
733
734#ifdef UNLOCK_ALWAYS
735    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
736#endif
737
738    /* Save SR registers */
739    for(i = 0x00; i <= 0x60; i++) {
740       inSISIDXREG(SISSR, i, sisReg->sisRegs3C4[i]);
741#ifdef TWDEBUG
742       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
743			 "SR%02X - %02X \n", i,sisReg->sisRegs3C4[i]);
744#endif
745    }
746
747    /* Save command queue location */
748    sisReg->sisMMIO85C0 = SIS_MMIO_IN32(pSiS->IOBase, 0x85C0);
749
750    /* Save CR registers */
751    max = 0x7c;
752    if(pSiS->ChipType >= XGI_20) max = 0xff;
753    for(i = 0x00; i <= max; i++)  {
754       inSISIDXREG(SISCR, i, sisReg->sisRegs3D4[i]);
755#ifdef TWDEBUG
756       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
757		"CR%02X Contents - %02X \n", i,sisReg->sisRegs3D4[i]);
758#endif
759    }
760
761    /* Save video capture registers */
762    for(i = 0x00; i <= 0x4f; i++)  {
763       inSISIDXREG(SISCAP, i, sisReg->sisCapt[i]);
764#ifdef TWDEBUG_VID
765       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
766		"Capt%02X Contents - %02X \n", i,sisReg->sisCapt[i]);
767#endif
768    }
769
770    /* Save video playback registers */
771    for(i = 0x00; i <= 0x3f; i++) {
772       inSISIDXREG(SISVID, i, sisReg->sisVid[i]);
773#ifdef TWDEBUG_VID
774       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
775		"Vid%02X Contents - %02X \n", i,sisReg->sisVid[i]);
776#endif
777    }
778
779    /* Save Misc register */
780    sisReg->sisRegs3C2 = inSISREG(SISMISCR);
781
782    /* Save panel link/video bridge registers */
783#ifndef TWDEBUG
784    if(!pSiS->UseVESA) {
785#endif
786       if(pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL))
787          SiSLVDSChrontelSave(pScrn, sisReg);
788       else if(pSiS->VBFlags2 & VB2_301)
789          SiS301Save(pScrn, sisReg);
790       else if(pSiS->VBFlags2 & VB2_30xBLV)
791          SiS301BSave(pScrn, sisReg);
792#ifndef TWDEBUG
793    }
794#endif
795
796    /* Save mode number */
797    sisReg->BIOSModeSave = SiS_GetSetModeID(pScrn,0xFF);
798
799#ifdef TWDEBUG
800    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
801    	"BIOS mode ds:449 = 0x%x\n", sisReg->BIOSModeSave);
802#endif
803}
804
805/* Restore SiS315/330 series register contents */
806static void
807SiS315Restore(ScrnInfoPtr pScrn, SISRegPtr sisReg)
808{
809    SISPtr pSiS = SISPTR(pScrn);
810    int i,temp;
811
812    PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4, "SiS315Restore()\n"));
813
814#ifdef UNLOCK_ALWAYS
815    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
816#endif
817
818    /* Wait for accelerator to finish on-going drawing operations. */
819    inSISIDXREG(SISSR, 0x1E, temp);
820    if(temp & (0x40|0x10|0x02))  {	/* 0x40 = 2D, 0x02 = 3D enabled*/
821       while ( (SIS_MMIO_IN32(pSiS->IOBase, 0x85CC) & 0x80000000) != 0x80000000){};
822       while ( (SIS_MMIO_IN32(pSiS->IOBase, 0x85CC) & 0x80000000) != 0x80000000){};
823       while ( (SIS_MMIO_IN32(pSiS->IOBase, 0x85CC) & 0x80000000) != 0x80000000){};
824    }
825
826    /* We reset the command queue before restoring.
827     * This might be required because we never know what
828     * console driver (like the kernel framebuffer driver)
829     * or application is running and which queue mode it
830     * uses.
831     */
832    andSISIDXREG(SISCR, 0x55, 0x33);
833    orSISIDXREG(SISSR, 0x26, 0x01);
834    outSISIDXREG(SISSR, 0x27, 0x1F);
835
836    /* Restore extended CR registers */
837    for(i = 0x19; i < 0x5C; i++) {
838       outSISIDXREG(SISCR, i, sisReg->sisRegs3D4[i]);
839    }
840    if(pSiS->ChipType < SIS_661) {
841       outSISIDXREG(SISCR, 0x79, sisReg->sisRegs3D4[0x79]);
842    }
843    outSISIDXREG(SISCR, pSiS->myCR63, sisReg->sisRegs3D4[pSiS->myCR63]);
844
845    /* Leave PCI_IO_ENABLE on if accelerators are on (Is this required?) */
846    if(sisReg->sisRegs3C4[0x1e] & 0x52) {  /* 0x40=2D, 0x02=3D */
847       sisReg->sisRegs3C4[0x20] |= 0x20;
848       outSISIDXREG(SISSR, 0x20, sisReg->sisRegs3C4[0x20]);
849    }
850
851    if(pSiS->SiS_Pr->SiS_SensibleSR11) {
852       sisReg->sisRegs3C4[0x11] &= 0x0f;
853    }
854
855    /* Restore extended SR registers */
856    for(i = 0x06; i <= 0x3F; i++) {
857       if(i == 0x26) {
858          continue;
859       } else if(i == 0x27) {
860          outSISIDXREG(SISSR, 0x27, sisReg->sisRegs3C4[0x27]);
861          outSISIDXREG(SISSR, 0x26, sisReg->sisRegs3C4[0x26]);
862       } else {
863          outSISIDXREG(SISSR, i, sisReg->sisRegs3C4[i]);
864       }
865    }
866
867    /* Restore VCLK and ECLK */
868    andSISIDXREG(SISSR,0x31,0xcf);
869    if(pSiS->VBFlags2 & VB2_LVDS) {
870       orSISIDXREG(SISSR,0x31,0x20);
871       outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]);
872       outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]);
873       outSISIDXREG(SISSR,0x2d,0x80);
874       andSISIDXREG(SISSR,0x31,0xcf);
875       orSISIDXREG(SISSR,0x31,0x10);
876       outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]);
877       outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]);
878       outSISIDXREG(SISSR,0x2d,0x80);
879       andSISIDXREG(SISSR,0x31,0xcf);
880       outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]);
881       outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]);
882       outSISIDXREG(SISSR,0x2d,0x01);
883       outSISIDXREG(SISSR,0x31,0x20);
884       outSISIDXREG(SISSR,0x2e,sisReg->sisRegs3C4[0x2e]);
885       outSISIDXREG(SISSR,0x2f,sisReg->sisRegs3C4[0x2f]);
886       outSISIDXREG(SISSR,0x31,0x10);
887       outSISIDXREG(SISSR,0x2e,sisReg->sisRegs3C4[0x2e]);
888       outSISIDXREG(SISSR,0x2f,sisReg->sisRegs3C4[0x2f]);
889       outSISIDXREG(SISSR,0x31,0x00);
890       outSISIDXREG(SISSR,0x2e,sisReg->sisRegs3C4[0x2e]);
891       outSISIDXREG(SISSR,0x2f,sisReg->sisRegs3C4[0x2f]);
892    } else {
893       outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]);
894       outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]);
895       outSISIDXREG(SISSR,0x2d,0x01);
896    }
897
898#ifndef SISVRAMQ
899    /* Initialize read/write pointer for command queue */
900    SIS_MMIO_OUT32(pSiS->IOBase, 0x85C4, SIS_MMIO_IN32(pSiS->IOBase, 0x85C8));
901#endif
902    /* Restore queue location */
903    SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, sisReg->sisMMIO85C0);
904
905    /* Restore Misc register */
906    outSISREG(SISMISCW, sisReg->sisRegs3C2);
907
908    /* Restore panel link/video bridge registers */
909    if(!(pSiS->UseVESA)) {
910       if(pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL))
911          SiSLVDSChrontelRestore(pScrn, sisReg);
912       else if(pSiS->VBFlags2 & VB2_301)
913          SiS301Restore(pScrn, sisReg);
914       else if(pSiS->VBFlags2 & VB2_30xBLV)
915          SiS301BRestore(pScrn, sisReg);
916    }
917
918    /* MemClock needs this to take effect */
919    outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
920    outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
921
922    /* Restore Mode number */
923    SiS_GetSetModeID(pScrn,sisReg->BIOSModeSave);
924}
925
926static void
927SiSVBSave(ScrnInfoPtr pScrn, SISRegPtr sisReg, int p1, int p2, int p3, int p4)
928{
929    SISPtr  pSiS = SISPTR(pScrn);
930    int     i;
931
932    for(i=0; i<=p1; i++)  {
933       inSISIDXREG(SISPART1, i, sisReg->VBPart1[i]);
934#ifdef TWDEBUG
935       xf86DrvMsg(0, X_INFO, "301xSave: Part1 0x%02x = 0x%02x\n", i, sisReg->VBPart1[i]);
936#endif
937    }
938    for(i=0; i<=p2; i++)  {
939       inSISIDXREG(SISPART2, i, sisReg->VBPart2[i]);
940#ifdef TWDEBUG
941       xf86DrvMsg(0, X_INFO, "301xSave: Part2 0x%02x = 0x%02x\n", i, sisReg->VBPart2[i]);
942#endif
943    }
944    for(i=0; i<=p3; i++)  {
945       inSISIDXREG(SISPART3, i, sisReg->VBPart3[i]);
946#ifdef TWDEBUG
947       xf86DrvMsg(0, X_INFO, "301xSave: Part3 0x%02x = 0x%02x\n", i, sisReg->VBPart3[i]);
948#endif
949    }
950    for(i=0; i<=p4; i++)  {
951       inSISIDXREG(SISPART4, i, sisReg->VBPart4[i]);
952#ifdef TWDEBUG
953       xf86DrvMsg(0, X_INFO, "301xSave: Part4 0x%02x = 0x%02x\n", i, sisReg->VBPart4[i]);
954#endif
955    }
956}
957
958/* Save SiS301 bridge register contents */
959static void
960SiS301Save(ScrnInfoPtr pScrn, SISRegPtr sisReg)
961{
962    SISPtr  pSiS = SISPTR(pScrn);
963    int     Part1max, Part2max, Part3max, Part4max;
964
965    /* Highest register number to save/restore */
966    if(pSiS->VGAEngine == SIS_300_VGA) Part1max = 0x1d;
967    else Part1max = 0x2e;  /* 0x23, but we also need 2d-2e */
968
969    Part2max = 0x45;
970    Part3max = 0x3e;
971    Part4max = 0x1b;
972
973    SiSVBSave(pScrn, sisReg, Part1max, Part2max, Part3max, Part4max);
974
975    sisReg->VBPart2[0x00] &= ~0x20;      /* Disable VB Processor */
976    sisReg->sisRegs3C4[0x32] &= ~0x20;   /* Disable Lock Mode */
977}
978
979/* Restore SiS301 bridge register contents */
980static void
981SiS301Restore(ScrnInfoPtr pScrn, SISRegPtr sisReg)
982{
983    SISPtr  pSiS = SISPTR(pScrn);
984    int     Part1max, Part2max, Part3max, Part4max;
985
986    /* Highest register number to save/restore */
987    if(pSiS->VGAEngine == SIS_300_VGA) Part1max = 0x1d;
988    else Part1max = 0x23;
989
990    Part2max = 0x45;
991    Part3max = 0x3e;
992    Part4max = 0x1b;
993
994    SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30);
995    SiSSetLVDSetc(pSiS->SiS_Pr, 0);
996    SiS_GetVBType(pSiS->SiS_Pr);
997    SiS_DisableBridge(pSiS->SiS_Pr);
998    SiS_UnLockCRT2(pSiS->SiS_Pr);
999
1000    /* Pre-restore Part1 */
1001    outSISIDXREG(SISPART1, 0x04, 0x00);
1002    outSISIDXREG(SISPART1, 0x05, 0x00);
1003    outSISIDXREG(SISPART1, 0x06, 0x00);
1004    outSISIDXREG(SISPART1, 0x00, sisReg->VBPart1[0]);
1005    outSISIDXREG(SISPART1, 0x01, sisReg->VBPart1[1]);
1006
1007    /* Pre-restore Part4 */
1008    outSISIDXREG(SISPART4, 0x0D, sisReg->VBPart4[0x0D]);
1009    outSISIDXREG(SISPART4, 0x0C, sisReg->VBPart4[0x0C]);
1010
1011    if((!(sisReg->sisRegs3D4[0x30] & 0x03)) &&
1012       (sisReg->sisRegs3D4[0x31] & 0x20))  {      /* disable CRT2 */
1013       SiS_LockCRT2(pSiS->SiS_Pr);
1014       return;
1015    }
1016
1017    /* Restore Part1 */
1018    SetBlock(SISPART1, 0x02, Part1max, &(sisReg->VBPart1[0x02]));
1019    if(pSiS->VGAEngine == SIS_315_VGA) {
1020       /* Restore extra registers on 315 series */
1021       SetBlock(SISPART1, 0x2C, 0x2E, &(sisReg->VBPart1[0x2C]));
1022    }
1023
1024    /* Restore Part2 */
1025    SetBlock(SISPART2, 0x00, Part2max, &(sisReg->VBPart2[0x00]));
1026
1027    /* Restore Part3 */
1028    SetBlock(SISPART3, 0x00, Part3max, &(sisReg->VBPart3[0x00]));
1029
1030    /* Restore Part4 */
1031    SetBlock(SISPART4, 0x0E, 0x11, &(sisReg->VBPart4[0x0E]));
1032    SetBlock(SISPART4, 0x13, Part4max, &(sisReg->VBPart4[0x13]));
1033
1034    /* Post-restore Part4 (CRT2VCLK) */
1035    outSISIDXREG(SISPART4, 0x0A, 0x01);
1036    outSISIDXREG(SISPART4, 0x0B, sisReg->VBPart4[0x0B]);
1037    outSISIDXREG(SISPART4, 0x0A, sisReg->VBPart4[0x0A]);
1038    outSISIDXREG(SISPART4, 0x12, 0x00);
1039    outSISIDXREG(SISPART4, 0x12, sisReg->VBPart4[0x12]);
1040
1041    SiS_EnableBridge(pSiS->SiS_Pr);
1042    SiS_DisplayOn(pSiS->SiS_Pr);
1043    SiS_LockCRT2(pSiS->SiS_Pr);
1044}
1045
1046/* Save SiS30xB/30xLV bridge register contents */
1047static void
1048SiS301BSave(ScrnInfoPtr pScrn, SISRegPtr sisReg)
1049{
1050    SISPtr  pSiS = SISPTR(pScrn);
1051    int     Part1max, Part2max, Part3max, Part4max;
1052
1053    Part1max = 0x60;
1054    Part2max = 0x4d;
1055    Part3max = 0x3e;
1056    Part4max = 0x23;
1057    if(pSiS->VBFlags2 & (VB2_301LV | VB2_302LV)) {
1058       Part4max = 0x34;
1059    } else if(pSiS->VBFlags2 & (VB2_301C | VB2_302ELV)) {
1060       Part2max = 0xff;
1061       Part4max = 0x3c;
1062    } /* TODO for 307 */
1063
1064    SiSVBSave(pScrn, sisReg, Part1max, Part2max, Part3max, Part4max);
1065
1066    sisReg->VBPart2[0x00] &= ~0x20;      /* Disable VB Processor */
1067    sisReg->sisRegs3C4[0x32] &= ~0x20;   /* Disable Lock Mode */
1068}
1069
1070/* Restore SiS30xB/30xLV bridge register contents */
1071static void
1072SiS301BRestore(ScrnInfoPtr pScrn, SISRegPtr sisReg)
1073{
1074    SISPtr  pSiS = SISPTR(pScrn);
1075    int     Part1max, Part2max, Part3max, Part4max;
1076
1077    Part1max = 0x23;
1078    Part2max = 0x4d;
1079    Part3max = 0x3e;
1080    Part4max = 0x22;
1081    if(pSiS->VBFlags2 & (VB2_301LV|VB2_302LV)) {
1082       Part4max = 0x34;
1083    } else if(pSiS->VBFlags2 & (VB2_301C|VB2_302ELV)) {
1084       Part2max = 0xff;
1085       Part4max = 0x3c;
1086    } /* TODO for 307 */
1087
1088    SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30);
1089    SiSSetLVDSetc(pSiS->SiS_Pr, 0);
1090    SiS_GetVBType(pSiS->SiS_Pr);
1091    SiS_DisableBridge(pSiS->SiS_Pr);
1092    SiS_UnLockCRT2(pSiS->SiS_Pr);
1093
1094    /* Pre-restore Part1 */
1095    outSISIDXREG(SISPART1, 0x04, 0x00);
1096    outSISIDXREG(SISPART1, 0x05, 0x00);
1097    outSISIDXREG(SISPART1, 0x06, 0x00);
1098    outSISIDXREG(SISPART1, 0x00, sisReg->VBPart1[0x00]);
1099    outSISIDXREG(SISPART1, 0x01, sisReg->VBPart1[0x01]);
1100    /* Mode reg 0x01 became 0x2e on 315 series (0x01 still contains FIFO) */
1101    if(pSiS->VGAEngine == SIS_315_VGA) {
1102       outSISIDXREG(SISPART1, 0x2e, sisReg->VBPart1[0x2e]);
1103    }
1104
1105    /* Pre-restore Part4 */
1106    outSISIDXREG(SISPART4, 0x0D, sisReg->VBPart4[0x0D]);
1107    outSISIDXREG(SISPART4, 0x0C, sisReg->VBPart4[0x0C]);
1108
1109    if((!(sisReg->sisRegs3D4[0x30] & 0x03)) &&
1110       (sisReg->sisRegs3D4[0x31] & 0x20)) {      /* disable CRT2 */
1111       SiS_LockCRT2(pSiS->SiS_Pr);
1112       return;
1113    }
1114
1115    /* Restore Part1  */
1116    SetBlock(SISPART1, 0x02, Part1max, &(sisReg->VBPart1[0x02]));
1117    if(pSiS->VGAEngine == SIS_315_VGA) {
1118       SetBlock(SISPART1, 0x2C, 0x2D, &(sisReg->VBPart1[0x2C]));
1119       SetBlock(SISPART1, 0x35, 0x37, &(sisReg->VBPart1[0x35]));
1120       if((pSiS->ChipFlags & SiSCF_Is65x) || (pSiS->ChipType >= SIS_661)) {
1121          outSISIDXREG(SISPART1, 0x4c, sisReg->VBPart1[0x4c]);
1122       }
1123       outSISIDXREG(SISPART1, 0x2e, sisReg->VBPart1[0x2e] & 0x7f);
1124    }
1125
1126    /* Restore Part2 */
1127    SetBlock(SISPART2, 0x00, Part2max, &(sisReg->VBPart2[0x00]));
1128
1129    /* Restore Part3 */
1130    SetBlock(SISPART3, 0x00, Part3max, &(sisReg->VBPart3[0x00]));
1131
1132    /* Restore Part4 */
1133    SetBlock(SISPART4, 0x0E, 0x11, &(sisReg->VBPart4[0x0E]));
1134    SetBlock(SISPART4, 0x13, Part4max, &(sisReg->VBPart4[0x13]));
1135
1136    /* Post-restore Part4 (CRT2VCLK) */
1137    outSISIDXREG(SISPART4, 0x0A, sisReg->VBPart4[0x0A]);
1138    outSISIDXREG(SISPART4, 0x0B, sisReg->VBPart4[0x0B]);
1139    outSISIDXREG(SISPART4, 0x12, 0x00);
1140    outSISIDXREG(SISPART4, 0x12, sisReg->VBPart4[0x12]);
1141
1142    SiS_EnableBridge(pSiS->SiS_Pr);
1143    SiS_DisplayOn(pSiS->SiS_Pr);
1144    SiS_LockCRT2(pSiS->SiS_Pr);
1145}
1146
1147/* Save LVDS bridge (+ Chrontel) register contents */
1148static void
1149SiSLVDSChrontelSave(ScrnInfoPtr pScrn, SISRegPtr sisReg)
1150{
1151    SISPtr  pSiS = SISPTR(pScrn);
1152    int     i;
1153
1154    /* Save Part1 */
1155    for(i=0; i<0x46; i++) {
1156       inSISIDXREG(SISPART1, i, sisReg->VBPart1[i]);
1157#ifdef TWDEBUG
1158       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1159	                "LVDSSave: Part1Port 0x%02x = 0x%02x\n",
1160			i, sisReg->VBPart1[i]);
1161#endif
1162    }
1163
1164    /* Save Chrontel registers */
1165    if(pSiS->VBFlags2 & VB2_CHRONTEL) {
1166       if(pSiS->ChrontelType == CHRONTEL_700x) {
1167          for(i=0; i<0x1D; i++)  {
1168             sisReg->ch70xx[i] = SiS_GetCH700x(pSiS->SiS_Pr, ch700xidx[i]);
1169#ifdef TWDEBUG
1170	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1171	                "LVDSSave: Chrontel 0x%02x = 0x%02x\n",
1172			ch700xidx[i], sisReg->ch70xx[i]);
1173#endif
1174	  }
1175       } else {
1176          for(i=0; i<35; i++)  {
1177             sisReg->ch70xx[i] = SiS_GetCH701x(pSiS->SiS_Pr, ch701xidx[i]);
1178#ifdef TWDEBUG
1179	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1180	                "LVDSSave: Chrontel 0x%02x = 0x%02x\n",
1181			ch701xidx[i], sisReg->ch70xx[i]);
1182#endif
1183          }
1184       }
1185    }
1186
1187    sisReg->sisRegs3C4[0x32] &= ~0x20;      /* Disable Lock Mode */
1188}
1189
1190/* Restore LVDS bridge (+ Chrontel) register contents */
1191static void
1192SiSLVDSChrontelRestore(ScrnInfoPtr pScrn, SISRegPtr sisReg)
1193{
1194    SISPtr pSiS = SISPTR(pScrn);
1195    int i;
1196
1197    SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30);
1198    SiSSetLVDSetc(pSiS->SiS_Pr, 0);
1199    SiS_GetVBType(pSiS->SiS_Pr);
1200    SiS_DisableBridge(pSiS->SiS_Pr);
1201    if(pSiS->ChipType == SIS_730) {
1202       outSISIDXREG(SISPART1, 0x00, 0x80);
1203    }
1204    SiS_UnLockCRT2(pSiS->SiS_Pr);
1205
1206    if(pSiS->VBFlags2 & VB2_CHRONTEL) {
1207       /* Restore Chrontel registers */
1208       if(pSiS->ChrontelType == CHRONTEL_700x) {
1209          for(i=0; i<0x11; i++) {
1210             SiS_SetCH700x(pSiS->SiS_Pr, ch700xidx[i] & 0xFF, sisReg->ch70xx[i]);
1211          }
1212       } else {
1213          for(i=0; i<34; i++) {
1214             SiS_SetCH701x(pSiS->SiS_Pr, ch701xidx[i] & 0xFF, sisReg->ch70xx[i]);
1215          }
1216       }
1217    }
1218
1219    /* pre-restore Part1 */
1220    outSISIDXREG(SISPART1, 0x04, 0x00);
1221    outSISIDXREG(SISPART1, 0x05, 0x00);
1222    outSISIDXREG(SISPART1, 0x06, 0x00);
1223    outSISIDXREG(SISPART1, 0x00, sisReg->VBPart1[0]);
1224    if(pSiS->VGAEngine == SIS_300_VGA) {
1225       outSISIDXREG(SISPART1, 0x01, (sisReg->VBPart1[1] | 0x80));
1226    } else {
1227       outSISIDXREG(SISPART1, 0x01, sisReg->VBPart1[1]);
1228    }
1229
1230    if((!(sisReg->sisRegs3D4[0x30] & 0x03)) &&
1231       (sisReg->sisRegs3D4[0x31] & 0x20)) {      /* disable CRT2 */
1232       SiS_LockCRT2(pSiS->SiS_Pr);
1233       return;
1234    }
1235
1236    /* Restore Part1 */
1237    if(pSiS->VGAEngine == SIS_300_VGA) {
1238       outSISIDXREG(SISPART1, 0x02, (sisReg->VBPart1[2] | 0x40));
1239    } else {
1240       outSISIDXREG(SISPART1, 0x02, sisReg->VBPart1[2]);
1241    }
1242    SetBlock(SISPART1, 0x03, 0x23, &(sisReg->VBPart1[0x03]));
1243    if(pSiS->VGAEngine == SIS_315_VGA) {
1244       SetBlock(SISPART1, 0x2C, 0x2E, &(sisReg->VBPart1[0x2C]));
1245       SetBlock(SISPART1, 0x35, 0x37, &(sisReg->VBPart1[0x35]));  /* Panel Link Scaler */
1246    }
1247
1248    /* For 550 DSTN registers */
1249    if(pSiS->DSTN || pSiS->FSTN) {
1250       SetBlock(SISPART1, 0x25, 0x2E, &(sisReg->VBPart1[0x25]));
1251       SetBlock(SISPART1, 0x30, 0x45, &(sisReg->VBPart1[0x30]));
1252    }
1253
1254    SiS_EnableBridge(pSiS->SiS_Pr);
1255    SiS_DisplayOn(pSiS->SiS_Pr);
1256    SiS_LockCRT2(pSiS->SiS_Pr);
1257}
1258
1259/* Restore output selection registers */
1260void
1261SiSRestoreBridge(ScrnInfoPtr pScrn, SISRegPtr sisReg)
1262{
1263   SISPtr pSiS = SISPTR(pScrn);
1264   int i;
1265
1266#ifdef UNLOCK_ALWAYS
1267   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1268#endif
1269
1270   for(i = 0x30; i <= 0x3b; i++) {
1271      if(i == 0x34) continue;
1272      outSISIDXREG(SISCR, i, sisReg->sisRegs3D4[i]);
1273   }
1274
1275   if(pSiS->VGAEngine == SIS_315_VGA) {
1276      outSISIDXREG(SISCR, pSiS->myCR63, sisReg->sisRegs3D4[pSiS->myCR63]);
1277      if(pSiS->ChipType < SIS_661) {
1278         outSISIDXREG(SISCR, 0x79, sisReg->sisRegs3D4[0x79]);
1279      }
1280   }
1281}
1282
1283/* Auxiliary function to find real memory clock (in Khz) */
1284/* Not for 530/620 if UMA (on these, the mclk is stored in SR10) */
1285int
1286SiSMclk(SISPtr pSiS)
1287{
1288    int mclk=0;
1289    UChar Num, Denum, Base;
1290
1291    switch (pSiS->Chipset)  {
1292
1293    case PCI_CHIP_SIS300:
1294    case PCI_CHIP_SIS540:
1295    case PCI_CHIP_SIS630:
1296    case PCI_CHIP_SIS315:
1297    case PCI_CHIP_SIS315H:
1298    case PCI_CHIP_SIS315PRO:
1299    case PCI_CHIP_SIS550:
1300    case PCI_CHIP_SIS650:
1301    case PCI_CHIP_SIS330:
1302    case PCI_CHIP_SIS660:
1303    case PCI_CHIP_SIS340:
1304    case PCI_CHIP_XGIXG20:
1305    case PCI_CHIP_XGIXG40:
1306
1307	/* Numerator */
1308	inSISIDXREG(SISSR, 0x28, Num);
1309	mclk = 14318 * ((Num & 0x7f) + 1);
1310
1311	/* Denumerator */
1312	inSISIDXREG(SISSR, 0x29, Denum);
1313	mclk = mclk / ((Denum & 0x1f) + 1);
1314
1315	/* Divider */
1316	if((Num & 0x80) != 0)  mclk *= 2;
1317
1318	/* Post-Scaler */
1319	if((Denum & 0x80) == 0) {
1320	   mclk = mclk / (((Denum & 0x60) >> 5) + 1);
1321	} else {
1322	   mclk = mclk / ((((Denum & 0x60) >> 5) + 1) * 2);
1323	}
1324	break;
1325
1326    case PCI_CHIP_SIS5597:
1327    case PCI_CHIP_SIS6326:
1328    case PCI_CHIP_SIS530:
1329    default:
1330	/* Numerator */
1331	inSISIDXREG(SISSR, 0x28, Num);
1332	mclk = 14318 * ((Num & 0x7f) + 1);
1333
1334	/* Denumerator */
1335	inSISIDXREG(SISSR, 0x29, Denum);
1336	mclk = mclk / ((Denum & 0x1f) + 1);
1337
1338	/* Divider. Doesn't work on older cards */
1339	if(pSiS->oldChipset >= OC_SIS5597) {
1340	   if(Num & 0x80) mclk *= 2;
1341	}
1342
1343	/* Post-scaler. Values' meaning depends on SR13 bit 7  */
1344	inSISIDXREG(SISSR, 0x13, Base);
1345	if((Base & 0x80) == 0) {
1346	   mclk = mclk / (((Denum & 0x60) >> 5) + 1);
1347	} else {
1348	   /* Values 00 and 01 are reserved */
1349	   if ((Denum & 0x60) == 0x40)  mclk /= 6;
1350	   if ((Denum & 0x60) == 0x60)  mclk /= 8;
1351	}
1352	break;
1353    }
1354
1355    return(mclk);
1356}
1357
1358/* This estimates the CRT2 clock we are going to use.
1359 * The total bandwidth is to be reduced by the value
1360 * returned here in order to get an idea of the maximum
1361 * dotclock left for CRT1.
1362 * Since we don't know yet, what mode the user chose,
1363 * we return the maximum dotclock used by
1364 * - either the LCD attached, or
1365 * - TV
1366 * For VGA2, we share the bandwith equally.
1367 */
1368static int
1369SiSEstimateCRT2Clock(ScrnInfoPtr pScrn, Bool FakeForCRT2)
1370{
1371	SISPtr pSiS = SISPTR(pScrn);
1372
1373	if(pSiS->VBFlags & CRT2_LCD) {
1374	   if(pSiS->VBLCDFlags & (VB_LCD_320x480 | VB_LCD_800x600 | VB_LCD_640x480)) {
1375	      return 40000;
1376	   } else if(pSiS->VBLCDFlags & (VB_LCD_1024x768 | VB_LCD_1024x600 | VB_LCD_1152x768)) {
1377	      return 65000;
1378	   } else if(pSiS->VBLCDFlags & VB_LCD_1280x720) {
1379	      /* Fake clock; VGA (4:3) mode is 108, but uses only 75 for LCD */
1380	      if(FakeForCRT2) return 108000;
1381	      else            return 75000;
1382	   } else if(pSiS->VBLCDFlags & VB_LCD_1280x768) {
1383	      /* Fake clock; VGA (4:3) mode is 108, but uses only 81 for LCD */
1384	      if(FakeForCRT2) return 108000;
1385	      else            return 81000;
1386	   } else if(pSiS->VBLCDFlags & VB_LCD_1280x800) {
1387	      /* Fake clock; VGA (4:3) mode is 108, but uses only 83 for LCD */
1388	      if(FakeForCRT2) return 108000;
1389	      else            return 83000;
1390	   } else if(pSiS->VBLCDFlags & VB_LCD_1280x854) {
1391	      /* Fake clock; VGA (4:3) mode is 108, but uses only 84 for LCD */
1392	      if(FakeForCRT2) return 108000;
1393	      else            return 84000;
1394	   } else if(pSiS->VBLCDFlags & (VB_LCD_1280x1024 | VB_LCD_1280x960)) {
1395	      return 108000;
1396	   } else if(pSiS->VBLCDFlags & VB_LCD_1400x1050) {
1397	      /* Fake clock; VGA mode is 122, but uses only 108 for LCD */
1398	      if(FakeForCRT2) return 123000;
1399	      else            return 108000;
1400	   } else if(pSiS->VBLCDFlags & VB_LCD_1680x1050) {
1401	      /* Fake clock; VGA mode is 147, but uses only 122 for LCD */
1402	      if(FakeForCRT2) return 148000;
1403	      else            return 122000;
1404	   } else if(pSiS->VBLCDFlags & VB_LCD_1600x1200) {
1405	      return 162000;
1406	   } else if((pSiS->VBLCDFlags & VB_LCD_CUSTOM) && (pSiS->SiS_Pr->CP_MaxClock)) {
1407	      return pSiS->SiS_Pr->CP_MaxClock;
1408	   } else {
1409	      if(pSiS->VBFlags2 & VB2_30xC) return 162000;
1410	      else                          return 108000;
1411	   }
1412	} else if(pSiS->VBFlags & CRT2_TV) {
1413	   if(pSiS->VBFlags2 & VB2_CHRONTEL) {
1414	      switch(pSiS->VGAEngine) {
1415	      case SIS_300_VGA:
1416		 return 50000;	/* 700x: <= 800x600 */
1417	      case SIS_315_VGA:
1418	      default:
1419		 return 70000;  /* 701x: <= 1024x768 */
1420	      }
1421	   } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
1422	      if(pSiS->SiS_SD_Flags & (SiS_SD_SUPPORTYPBPR|SiS_SD_SUPPORTHIVISION)) {
1423	         if(FakeForCRT2) return 108000;  /* 1280x1024@60 (faked) */
1424	         else            return 75000;   /* Really used clock */
1425	      } else {
1426		 return 70000;
1427	      }
1428	   }
1429	}
1430
1431	return 0;
1432}
1433
1434/* Calculate the maximum dotclock */
1435int SiSMemBandWidth(ScrnInfoPtr pScrn, Bool IsForCRT2)
1436{
1437	SISPtr pSiS = SISPTR(pScrn);
1438#ifdef SISDUALHEAD
1439	SISEntPtr pSiSEnt = pSiS->entityPrivate;
1440#endif
1441	int          bus = pSiS->BusWidth;
1442	int          mclk = pSiS->MemClock;
1443	int          bpp = pSiS->CurrentLayout.bitsPerPixel;
1444	int	     max = 0;
1445	float        magic = 0.0, total;
1446	int          bytesperpixel = (bpp + 7) / 8;
1447	float  	     crt2used, maxcrt2;
1448	int	     crt2clock;
1449	Bool	     DHM, GetForCRT1;
1450#ifdef __SUNPRO_C
1451#define const
1452#endif
1453	const float  magicDED[4] = { 1.2,      1.368421, 2.263158, 1.2};
1454	const float  magicINT[4] = { 1.441177, 1.441177, 2.588235, 1.441177 };
1455#ifdef __SUNPRO_C
1456#undef const
1457#endif
1458
1459	switch(pSiS->Chipset) {
1460
1461	case PCI_CHIP_SIS5597:
1462		total = ((mclk * (bus / 8)) * 0.7) / bytesperpixel;
1463		if(total > 135000) total = 135000;
1464		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1465			"Maximum pixel clock at %d bpp is %g MHz\n",
1466			bpp, total/1000);
1467		return(int)(total);
1468
1469	case PCI_CHIP_SIS6326:
1470		total = ((mclk * (bus / 8)) * 0.7) / bytesperpixel;
1471		if(total > 175500) total = 175500;
1472		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1473			"Maximum pixel clock at %d bpp is %g MHz\n",
1474			bpp, total/1000);
1475		return(int)(total);
1476
1477	case PCI_CHIP_SIS530:
1478		total = ((mclk * (bus / 8)) * 0.7) / bytesperpixel;
1479		if(total > 230000) total = 230000;
1480		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1481			"Maximum pixel clock at %d bpp is %g MHz\n",
1482			bpp, total/1000);
1483		return(int)(total);
1484
1485	case PCI_CHIP_SIS300:
1486	case PCI_CHIP_SIS540:
1487	case PCI_CHIP_SIS630:
1488	case PCI_CHIP_SIS315:
1489	case PCI_CHIP_SIS315H:
1490	case PCI_CHIP_SIS315PRO:
1491	case PCI_CHIP_SIS550:
1492	case PCI_CHIP_SIS650:
1493	case PCI_CHIP_SIS330:
1494	case PCI_CHIP_SIS660:
1495	case PCI_CHIP_SIS340:
1496	case PCI_CHIP_XGIXG20:
1497	case PCI_CHIP_XGIXG40:
1498		switch(pSiS->Chipset) {
1499		case PCI_CHIP_SIS300:
1500		    magic = magicDED[bus/64];
1501		    max = 540000;
1502		    break;
1503		case PCI_CHIP_SIS540:
1504		case PCI_CHIP_SIS630:
1505		    magic = magicINT[bus/64];
1506		    max = 540000;
1507		    break;
1508		case PCI_CHIP_SIS315:
1509		case PCI_CHIP_SIS315H:
1510		case PCI_CHIP_SIS315PRO:
1511		case PCI_CHIP_SIS330:
1512		    magic = magicDED[bus/64];
1513		    max = 780000;
1514		    break;
1515		case PCI_CHIP_SIS550:
1516		    magic = magicINT[bus/64];
1517		    max = 610000;
1518		    break;
1519		case PCI_CHIP_SIS650:
1520		    magic = magicINT[bus/64];
1521		    max = 680000;
1522		    break;
1523		case PCI_CHIP_SIS660:
1524		    if((pSiS->ChipType >= SIS_660) &&
1525		       (pSiS->ChipFlags & SiSCF_760LFB)) {
1526		       magic = magicDED[bus/64];
1527		    } else {
1528		       magic = magicINT[bus/64];
1529		    }
1530		    max = 680000;
1531		case PCI_CHIP_SIS340:
1532		case PCI_CHIP_XGIXG40:
1533		    magic = magicDED[bus/64];
1534		    max = 800000;
1535		    break;
1536		case PCI_CHIP_XGIXG20:
1537		    magic = 1.0; /* magicDED[bus/64]; */
1538		    max = 332000;
1539		    break;
1540		}
1541
1542		PDEBUG(ErrorF("mclk: %d, bus: %d, magic: %g, bpp: %d\n",
1543				mclk, bus, magic, bpp));
1544
1545		total = mclk * bus / bpp;
1546
1547		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1548			"Memory bandwidth at %d bpp is %g MHz\n", bpp, total/1000);
1549
1550		if((pSiS->VBFlags & CRT2_ENABLE) && (!pSiS->CRT1off)) {
1551
1552		    maxcrt2 = 135000;
1553		    if(pSiS->VBFlags2 & (VB2_301B|VB2_302B)) maxcrt2 = 162000;
1554		    else if(pSiS->VBFlags2 & VB2_301C)       maxcrt2 = 203000;
1555		    else if(pSiS->VBFlags2 & VB2_307T)       maxcrt2 = 203000; /* TODO */
1556		    /* if(pSiS->VBFlags2 & VB2_30xBDH)       maxcrt2 = 100000;
1557		       Ignore 301B-DH here; seems the current version is like
1558		       301B anyway */
1559
1560		    crt2used = 0.0;
1561		    crt2clock = SiSEstimateCRT2Clock(pScrn, IsForCRT2);
1562		    if(crt2clock) {
1563		       crt2used = crt2clock + 2000;
1564		    }
1565		    DHM = FALSE;
1566		    GetForCRT1 = FALSE;
1567
1568#ifdef SISDUALHEAD
1569		    if((pSiS->DualHeadMode) && (pSiSEnt)) {
1570		       DHM = TRUE;
1571		       if(pSiS->SecondHead) GetForCRT1 = TRUE;
1572		    }
1573#endif
1574#ifdef SISMERGED
1575		    if(pSiS->MergedFB && IsForCRT2) {
1576		       DHM = TRUE;
1577		       GetForCRT1 = FALSE;
1578		    }
1579#endif
1580
1581		    if(DHM) {
1582
1583			if(!GetForCRT1) {
1584
1585			     /* First head = CRT2 */
1586
1587			     if(crt2clock) {
1588				/* We use the mem bandwidth as max clock; this
1589				 * might exceed the 70% limit a bit, but that
1590				 * does not matter; we take care of that limit
1591				 * when we calc CRT1. Overall, we might use up
1592				 * to 85% of the memory bandwidth, which seems
1593				 * enough to use accel and video.
1594				 * The "* macic" is just to compensate the
1595				 * calculation below.
1596				*/
1597				total = crt2used * magic;
1598
1599			     } else {
1600				/*  We don't know about the second head's
1601				 *  depth yet. So we assume it uses the
1602				 *  same. But since the maximum dotclock
1603				 *  is limited on CRT2, we can assume a
1604				 *  maximum here.
1605				 */
1606				if((total / 2) > (maxcrt2 + 2000)) {
1607				    total = (maxcrt2 + 2000) * magic;
1608				    crt2used = maxcrt2 + 2000;
1609				} else {
1610				    total /= 2;
1611				    crt2used = total;
1612				}
1613
1614			     }
1615
1616			     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1617				  "Bandwidth reserved for CRT2 is %g MHz\n",
1618				      crt2used/1000);
1619
1620			} else {
1621#ifdef SISDUALHEAD
1622			     /* Second head = CRT1 */
1623
1624			     /*     Now We know about the first head's depth,
1625			      *     so we can calculate more accurately.
1626			      */
1627
1628			     if(crt2clock) {
1629				total -= (crt2used * pSiSEnt->pScrn_1->bitsPerPixel / bpp);
1630				xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1631				   "Bandwidth reserved for CRT2 at %d bpp is %g Mhz\n",
1632				      bpp,
1633				      (crt2used * pSiSEnt->pScrn_1->bitsPerPixel / bpp)/1000);
1634			     } else {
1635				total -= (pSiSEnt->maxUsedClock * pSiSEnt->pScrn_1->bitsPerPixel / bpp);
1636				xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1637				   "Bandwidth reserved for CRT2 at %d bpp is %d Mhz\n",
1638				      bpp,
1639				      (pSiSEnt->maxUsedClock * pSiSEnt->pScrn_1->bitsPerPixel / bpp)/1000);
1640			     }
1641
1642			     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1643				 "Bandwidth available for CRT1 is %g MHz\n", total/1000);
1644#endif
1645			}
1646
1647		    } else {
1648
1649			if(crt2clock) {
1650			    total -= crt2used;
1651			} else {
1652                            if((total / 2) > (maxcrt2 + 2000)) {
1653				total -= (maxcrt2 + 2000);
1654				crt2used = maxcrt2 + 2000;
1655			    } else {
1656				total /= 2;
1657				crt2used = total;
1658			    }
1659			}
1660			xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1661			  "Bandwidth reserved for CRT2 is %g Mhz\n", crt2used/1000);
1662
1663			xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1664			  "Bandwidth available for CRT1 is %g MHz\n", total/1000);
1665
1666		    }
1667
1668		}
1669
1670		total /= magic;
1671		if(total > (max / 2)) total = max / 2;
1672		return(int)(total);
1673
1674        default:
1675		return(135000);
1676        }
1677}
1678
1679/* Load the palette. We do this for all supported color depths
1680 * in order to support gamma correction. We hereby convert the
1681 * given colormap to a complete 24bit color palette and enable
1682 * the correspoding bit in SR7 to enable the 24bit lookup table.
1683 * Gamma correction for CRT2 is only supported on SiS video bridges.
1684 * There are there 6-bit-RGB values submitted even if bpp is 16 and
1685 * weight is 565, because SetWeight() sets rgbBits to the maximum
1686 * (which is 6 in the 565 case).
1687 */
1688void
1689SISLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors,
1690               VisualPtr pVisual)
1691{
1692     SISPtr  pSiS = SISPTR(pScrn);
1693     int     i, j, index;
1694     int     myshift = 8 - pScrn->rgbBits;
1695     UChar   backup = 0;
1696     Bool    dogamma1 = pSiS->CRT1gamma;
1697     Bool    resetxvgamma = FALSE;
1698#ifdef SISDUALHEAD
1699     SISEntPtr pSiSEnt = pSiS->entityPrivate;
1700
1701     if(pSiS->DualHeadMode) dogamma1 = pSiSEnt->CRT1gamma;
1702#endif
1703
1704     PDEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LoadPalette()\n"));
1705
1706#ifdef SISDUALHEAD
1707     if((!pSiS->DualHeadMode) || (pSiS->SecondHead)) {
1708#endif
1709
1710	if(pSiS->VGAEngine == SIS_315_VGA) {
1711	   inSISIDXREG(SISSR, 0x1f, backup);
1712	   andSISIDXREG(SISSR, 0x1f, 0xe7);
1713	   if( (pSiS->XvGamma) &&
1714	       (pSiS->MiscFlags & MISC_CRT1OVERLAYGAMMA) &&
1715	       ((pSiS->CurrentLayout.depth == 16) ||
1716	        (pSiS->CurrentLayout.depth == 24)) ) {
1717	      orSISIDXREG(SISSR, 0x1f, 0x10);
1718	      resetxvgamma = TRUE;
1719	   }
1720	}
1721
1722	switch(pSiS->CurrentLayout.depth) {
1723	  case 15:
1724	     if(dogamma1) {
1725		orSISIDXREG(SISSR, 0x07, 0x04);
1726		/* 315/330: depth 15 not supported, no MMIO code needed */
1727		for(i=0; i<numColors; i++) {
1728		   index = indices[i];
1729		   if(index < 32) {   /* Paranoia */
1730		      for(j=0; j<8; j++) {
1731			 outSISREG(SISCOLIDX, (index << 3) + j);
1732			 outSISREG(SISCOLDATA, colors[index].red   << myshift);
1733			 outSISREG(SISCOLDATA, colors[index].green << myshift);
1734			 outSISREG(SISCOLDATA, colors[index].blue  << myshift);
1735		      }
1736		   }
1737		}
1738	     } else {
1739		andSISIDXREG(SISSR, 0x07, ~0x04);
1740	     }
1741	     break;
1742	  case 16:
1743	     if(dogamma1) {
1744		orSISIDXREG(SISSR, 0x07, 0x04);
1745		if(pSiS->ChipFlags & SiSCF_MMIOPalette) {
1746		   for(i=0; i<numColors; i++) {
1747		      index = indices[i];
1748		      if(index < 64) {  /* Paranoia */
1749			 for(j=0; j<4; j++) {
1750			    SIS_MMIO_OUT32(pSiS->IOBase, 0x8570,
1751					   (colors[index].green     << (myshift + 8))  |
1752					   (colors[index >> 1].blue << (myshift + 16)) |
1753					   (colors[index >> 1].red  << myshift)        |
1754					   (((index << 2) + j)      << 24));
1755			 }
1756		      }
1757		   }
1758		} else {
1759		   for(i=0; i<numColors; i++) {
1760		      index = indices[i];
1761		      if(index < 64) {  /* Paranoia */
1762			 for(j=0; j<4; j++) {
1763			    outSISREG(SISCOLIDX, (index << 2) + j);
1764			    outSISREG(SISCOLDATA, colors[index >> 1].red  << myshift);
1765			    outSISREG(SISCOLDATA, colors[index].green     << myshift);
1766			    outSISREG(SISCOLDATA, colors[index >> 1].blue << myshift);
1767			 }
1768		      }
1769		   }
1770		}
1771	     } else {
1772		andSISIDXREG(SISSR, 0x07, ~0x04);
1773	     }
1774	     break;
1775          case 24:
1776	     if(dogamma1) {
1777		orSISIDXREG(SISSR, 0x07, 0x04);
1778		if(pSiS->ChipFlags & SiSCF_MMIOPalette) {
1779		   for(i=0; i<numColors; i++)  {
1780		      index = indices[i];
1781		      if(index < 256) {   /* Paranoia */
1782			 SIS_MMIO_OUT32(pSiS->IOBase, 0x8570,
1783					(colors[index].blue  << 16) |
1784					(colors[index].green <<  8) |
1785					(colors[index].red)         |
1786					(index               << 24));
1787		      }
1788		   }
1789		} else {
1790		   for(i=0; i<numColors; i++)  {
1791		      index = indices[i];
1792		      if(index < 256) {   /* Paranoia */
1793			 outSISREG(SISCOLIDX, index);
1794			 outSISREG(SISCOLDATA, colors[index].red);
1795			 outSISREG(SISCOLDATA, colors[index].green);
1796			 outSISREG(SISCOLDATA, colors[index].blue);
1797		      }
1798		   }
1799		}
1800	     } else {
1801		andSISIDXREG(SISSR, 0x07, ~0x04);
1802	     }
1803	     break;
1804	  default:
1805	     andSISIDXREG(SISSR, 0x07, ~0x04);
1806	     if(pSiS->ChipFlags & SiSCF_MMIOPalette) {
1807	        for(i=0; i<numColors; i++)  {
1808		   index = indices[i];
1809		   SIS_MMIO_OUT32(pSiS->IOBase, 0x8570,
1810				  ((colors[index].blue)  << 16) |
1811				  ((colors[index].green) <<  8) |
1812				  (colors[index].red)           |
1813				  (index                 << 24));
1814		}
1815	     } else {
1816		for(i=0; i<numColors; i++) {
1817		   /* In pio mode, only 6 bits are supported */
1818		   index = indices[i];
1819		   outSISREG(SISCOLIDX, index);
1820		   outSISREG(SISCOLDATA, colors[index].red   >> 2);
1821		   outSISREG(SISCOLDATA, colors[index].green >> 2);
1822		   outSISREG(SISCOLDATA, colors[index].blue  >> 2);
1823		}
1824	     }
1825	}
1826
1827	if(pSiS->VGAEngine == SIS_315_VGA) {
1828	   outSISIDXREG(SISSR, 0x1f, backup);
1829	   inSISIDXREG(SISSR, 0x07, backup);
1830	   if((backup & 0x04) && (resetxvgamma) && (pSiS->ResetXvGamma)) {
1831	      (pSiS->ResetXvGamma)(pScrn);
1832	   }
1833	}
1834
1835#ifdef SISDUALHEAD
1836    }
1837#endif
1838
1839#ifdef SISDUALHEAD
1840    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead)) {
1841#endif
1842       switch(pSiS->VGAEngine) {
1843       case SIS_300_VGA:
1844       case SIS_315_VGA:
1845	  if(pSiS->VBFlags & CRT2_ENABLE) {
1846	     /* Only the SiS bridges support a CRT2 palette */
1847	     if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
1848		if((pSiS->CRT2SepGamma) && (pSiS->crt2cindices) && (pSiS->crt2colors)) {
1849		   SiS301LoadPalette(pScrn, numColors, pSiS->crt2cindices, pSiS->crt2colors, myshift);
1850		} else {
1851		   SiS301LoadPalette(pScrn, numColors, indices, colors, myshift);
1852		}
1853	     }
1854          }
1855       }
1856#ifdef SISDUALHEAD
1857    }
1858#endif
1859
1860}
1861
1862void
1863SiS_UpdateGammaCRT2(ScrnInfoPtr pScrn)
1864{
1865    SISPtr  pSiS = SISPTR(pScrn);
1866
1867    if((!pSiS->CRT2SepGamma) || (!pSiS->crt2cindices) || (!pSiS->crt2gcolortable)) return;
1868
1869#ifdef SISDUALHEAD
1870    if(pSiS->DualHeadMode) return;
1871#endif
1872
1873    SISCalculateGammaRampCRT2(pScrn);
1874    SiS301LoadPalette(pScrn, pSiS->CRT2ColNum, pSiS->crt2cindices, pSiS->crt2colors, (8 - pScrn->rgbBits));
1875}
1876
1877static  void
1878SiS301LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, int myshift)
1879{
1880	SISPtr  pSiS = SISPTR(pScrn);
1881	int     i, j, index;
1882	Bool    dogamma2 = pSiS->CRT2gamma;
1883#ifdef SISDUALHEAD
1884	SISEntPtr pSiSEnt = pSiS->entityPrivate;
1885
1886	if(pSiS->DualHeadMode) dogamma2 = pSiSEnt->CRT2gamma;
1887#endif
1888
1889	/* 301B-DH does not support a color palette for LCD */
1890	if((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) return;
1891
1892	switch(pSiS->CurrentLayout.depth) {
1893          case 15:
1894	     if(dogamma2) {
1895		orSISIDXREG(SISPART4, 0x0d, 0x08);
1896		for(i=0; i<numColors; i++) {
1897		   index = indices[i];
1898		   if(index < 32) {   /* Paranoia */
1899		      for(j=0; j<8; j++) {
1900			 outSISREG(SISCOL2IDX, (index << 3) + j);
1901			 outSISREG(SISCOL2DATA, colors[index].red   << myshift);
1902			 outSISREG(SISCOL2DATA, colors[index].green << myshift);
1903			 outSISREG(SISCOL2DATA, colors[index].blue  << myshift);
1904		      }
1905		   }
1906		}
1907	     } else {
1908		andSISIDXREG(SISPART4, 0x0d, ~0x08);
1909	     }
1910	     break;
1911	  case 16:
1912	     if(dogamma2) {
1913		orSISIDXREG(SISPART4, 0x0d, 0x08);
1914		for(i = 0; i < numColors; i++) {
1915		   index = indices[i];
1916		   if(index < 64) {  /* Paranoia */
1917		      for(j = 0; j < 4; j++) {
1918			 outSISREG(SISCOL2IDX, (index << 2) + j);
1919			 outSISREG(SISCOL2DATA, colors[index >> 1].red  << myshift);
1920			 outSISREG(SISCOL2DATA, colors[index].green     << myshift);
1921			 outSISREG(SISCOL2DATA, colors[index >> 1].blue << myshift);
1922		      }
1923		   }
1924		}
1925	     } else {
1926		andSISIDXREG(SISPART4, 0x0d, ~0x08);
1927	     }
1928	     break;
1929          case 24:
1930	     if(dogamma2) {
1931		orSISIDXREG(SISPART4, 0x0d, 0x08);
1932		for(i = 0; i < numColors; i++) {
1933		   index = indices[i];
1934		   if(index < 256) {   /* Paranoia */
1935		      outSISREG(SISCOL2IDX, index);
1936		      outSISREG(SISCOL2DATA, colors[index].red);
1937		      outSISREG(SISCOL2DATA, colors[index].green);
1938		      outSISREG(SISCOL2DATA, colors[index].blue);
1939		   }
1940        	}
1941	     } else {
1942		andSISIDXREG(SISPART4, 0x0d, ~0x08);
1943	     }
1944	     break;
1945	  default:
1946	     orSISIDXREG(SISPART4, 0x0d, 0x08);
1947	     for(i = 0; i < numColors; i++) {
1948		index = indices[i];
1949		outSISREG(SISCOL2IDX,  index);
1950		outSISREG(SISCOL2DATA, colors[index].red);
1951		outSISREG(SISCOL2DATA, colors[index].green);
1952		outSISREG(SISCOL2DATA, colors[index].blue);
1953             }
1954	 }
1955}
1956
1957void
1958SISDACPreInit(ScrnInfoPtr pScrn)
1959{
1960    SISPtr pSiS = SISPTR(pScrn);
1961    Bool IsForCRT2 = FALSE;
1962
1963#ifdef SISDUALHEAD
1964    if((pSiS->DualHeadMode) && (!pSiS->SecondHead))
1965       IsForCRT2 = TRUE;
1966#endif
1967
1968    pSiS->MaxClock = SiSMemBandWidth(pScrn, IsForCRT2);
1969
1970    switch (pSiS->Chipset) {
1971       case PCI_CHIP_SIS550:
1972       case PCI_CHIP_SIS315:
1973       case PCI_CHIP_SIS315H:
1974       case PCI_CHIP_SIS315PRO:
1975       case PCI_CHIP_SIS650:
1976       case PCI_CHIP_SIS330:
1977       case PCI_CHIP_SIS660:
1978       case PCI_CHIP_SIS340:
1979       case PCI_CHIP_XGIXG20:
1980       case PCI_CHIP_XGIXG40:
1981          pSiS->SiSSave     = SiS315Save;
1982          pSiS->SiSRestore  = SiS315Restore;
1983          break;
1984       case PCI_CHIP_SIS300:
1985       case PCI_CHIP_SIS540:
1986       case PCI_CHIP_SIS630:
1987          pSiS->SiSSave     = SiS300Save;
1988          pSiS->SiSRestore  = SiS300Restore;
1989          break;
1990       case PCI_CHIP_SIS5597:
1991       case PCI_CHIP_SIS6326:
1992       case PCI_CHIP_SIS530:
1993       default:
1994          pSiS->SiSSave     = SiSSave;
1995          pSiS->SiSRestore  = SiSRestore;
1996          break;
1997    }
1998}
1999
2000static void
2001SetBlock(CARD16 port, CARD8 from, CARD8 to, CARD8 *DataPtr)
2002{
2003    CARD8 index;
2004
2005    for(index = from; index <= to; index++, DataPtr++) {
2006       outSISIDXREG(port, index, *DataPtr);
2007    }
2008}
2009
2010void
2011SiS6326SetTVReg(ScrnInfoPtr pScrn, CARD8 index, CARD8 data)
2012{
2013    SISPtr  pSiS = SISPTR(pScrn);
2014    outSISIDXREG(SISCR, 0xE0, index);
2015    outSISIDXREG(SISCR, 0xE1, data);
2016#ifdef TWDEBUG
2017    xf86DrvMsg(0, X_INFO, "SiS6326: Setting Tv %02x to %02x\n", index, data);
2018#endif
2019}
2020
2021UChar
2022SiS6326GetTVReg(ScrnInfoPtr pScrn, CARD8 index)
2023{
2024    SISPtr pSiS = SISPTR(pScrn);
2025    UChar  data;
2026
2027    outSISIDXREG(SISCR, 0xE0, index);
2028    inSISIDXREG(SISCR, 0xE1, data);
2029    return(data);
2030}
2031
2032void
2033SiS6326SetXXReg(ScrnInfoPtr pScrn, CARD8 index, CARD8 data)
2034{
2035    SISPtr  pSiS = SISPTR(pScrn);
2036    outSISIDXREG(SISCR, 0xE2, index);
2037    outSISIDXREG(SISCR, 0xE3, data);
2038}
2039
2040UChar
2041SiS6326GetXXReg(ScrnInfoPtr pScrn, CARD8 index)
2042{
2043    SISPtr pSiS = SISPTR(pScrn);
2044    UChar  data;
2045
2046    outSISIDXREG(SISCR, 0xE2, index);
2047    inSISIDXREG(SISCR, 0xE3, data);
2048    return(data);
2049}
2050
2051UChar SiSGetCopyROP(int rop)
2052{
2053    const UChar sisALUConv[] =
2054    {
2055       0x00,       /* dest = 0;            0,      GXclear,        0 */
2056       0x88,       /* dest &= src;         DSa,    GXand,          0x1 */
2057       0x44,       /* dest = src & ~dest;  SDna,   GXandReverse,   0x2 */
2058       0xCC,       /* dest = src;          S,      GXcopy,         0x3 */
2059       0x22,       /* dest &= ~src;        DSna,   GXandInverted,  0x4 */
2060       0xAA,       /* dest = dest;         D,      GXnoop,         0x5 */
2061       0x66,       /* dest = ^src;         DSx,    GXxor,          0x6 */
2062       0xEE,       /* dest |= src;         DSo,    GXor,           0x7 */
2063       0x11,       /* dest = ~src & ~dest; DSon,   GXnor,          0x8 */
2064       0x99,       /* dest ^= ~src ;       DSxn,   GXequiv,        0x9 */
2065       0x55,       /* dest = ~dest;        Dn,     GXInvert,       0xA */
2066       0xDD,       /* dest = src|~dest ;   SDno,   GXorReverse,    0xB */
2067       0x33,       /* dest = ~src;         Sn,     GXcopyInverted, 0xC */
2068       0xBB,       /* dest |= ~src;        DSno,   GXorInverted,   0xD */
2069       0x77,       /* dest = ~src|~dest;   DSan,   GXnand,         0xE */
2070       0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
2071    };
2072
2073    return(sisALUConv[rop]);
2074}
2075
2076UChar SiSGetPatternROP(int rop)
2077{
2078    const UChar sisPatALUConv[] =
2079    {
2080       0x00,       /* dest = 0;            0,      GXclear,        0 */
2081       0xA0,       /* dest &= src;         DPa,    GXand,          0x1 */
2082       0x50,       /* dest = src & ~dest;  PDna,   GXandReverse,   0x2 */
2083       0xF0,       /* dest = src;          P,      GXcopy,         0x3 */
2084       0x0A,       /* dest &= ~src;        DPna,   GXandInverted,  0x4 */
2085       0xAA,       /* dest = dest;         D,      GXnoop,         0x5 */
2086       0x5A,       /* dest = ^src;         DPx,    GXxor,          0x6 */
2087       0xFA,       /* dest |= src;         DPo,    GXor,           0x7 */
2088       0x05,       /* dest = ~src & ~dest; DPon,   GXnor,          0x8 */
2089       0xA5,       /* dest ^= ~src ;       DPxn,   GXequiv,        0x9 */
2090       0x55,       /* dest = ~dest;        Dn,     GXInvert,       0xA */
2091       0xF5,       /* dest = src|~dest ;   PDno,   GXorReverse,    0xB */
2092       0x0F,       /* dest = ~src;         Pn,     GXcopyInverted, 0xC */
2093       0xAF,       /* dest |= ~src;        DPno,   GXorInverted,   0xD */
2094       0x5F,       /* dest = ~src|~dest;   DPan,   GXnand,         0xE */
2095       0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
2096    };
2097
2098    return(sisPatALUConv[rop]);
2099}
2100