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