172b676d7Smrg/* 272b676d7Smrg * DAC helper functions (Save/Restore, MemClk, etc) 372b676d7Smrg * 472b676d7Smrg * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria. 572b676d7Smrg * 672b676d7Smrg * Redistribution and use in source and binary forms, with or without 772b676d7Smrg * modification, are permitted provided that the following conditions 872b676d7Smrg * are met: 972b676d7Smrg * 1) Redistributions of source code must retain the above copyright 1072b676d7Smrg * notice, this list of conditions and the following disclaimer. 1172b676d7Smrg * 2) Redistributions in binary form must reproduce the above copyright 1272b676d7Smrg * notice, this list of conditions and the following disclaimer in the 1372b676d7Smrg * documentation and/or other materials provided with the distribution. 1472b676d7Smrg * 3) The name of the author may not be used to endorse or promote products 1572b676d7Smrg * derived from this software without specific prior written permission. 1672b676d7Smrg * 1772b676d7Smrg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1872b676d7Smrg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1972b676d7Smrg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2072b676d7Smrg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2172b676d7Smrg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2272b676d7Smrg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2372b676d7Smrg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2472b676d7Smrg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2572b676d7Smrg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2672b676d7Smrg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2772b676d7Smrg * 2872b676d7Smrg * Author: Thomas Winischhofer <thomas@winischhofer.net> 2972b676d7Smrg * 3072b676d7Smrg * -------------------------------------------------------------------------- 3172b676d7Smrg * 3272b676d7Smrg * SiS_compute_vclk(), SiSCalcClock() and parts of SiSMclk(): 3372b676d7Smrg * 3472b676d7Smrg * Copyright (C) 1998, 1999 by Alan Hourihane, Wigan, England 3572b676d7Smrg * Written by: 3672b676d7Smrg * Alan Hourihane <alanh@fairlite.demon.co.uk>, 3772b676d7Smrg * Mike Chapman <mike@paranoia.com>, 3872b676d7Smrg * Juanjo Santamarta <santamarta@ctv.es>, 3972b676d7Smrg * Mitani Hiroshi <hmitani@drl.mei.co.jp>, 4072b676d7Smrg * David Thomas <davtom@dream.org.uk>, 4172b676d7Smrg * Thomas Winischhofer <thomas@winischhofer.net>. 4272b676d7Smrg * 4372b676d7Smrg * Licensed under the following terms: 4472b676d7Smrg * 4572b676d7Smrg * Permission to use, copy, modify, distribute, and sell this software and its 4672b676d7Smrg * documentation for any purpose is hereby granted without fee, provided that 4772b676d7Smrg * the above copyright notice appears in all copies and that both that copyright 4872b676d7Smrg * notice and this permission notice appear in supporting documentation, and 4972b676d7Smrg * and that the name of the copyright holder not be used in advertising 5072b676d7Smrg * or publicity pertaining to distribution of the software without specific, 5172b676d7Smrg * written prior permission. The copyright holder makes no representations 5272b676d7Smrg * about the suitability of this software for any purpose. It is provided 5372b676d7Smrg * "as is" without expressed or implied warranty. 5472b676d7Smrg * 5572b676d7Smrg * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 5672b676d7Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO 5772b676d7Smrg * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR 5872b676d7Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 5972b676d7Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 6072b676d7Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 6172b676d7Smrg * PERFORMANCE OF THIS SOFTWARE. 6272b676d7Smrg */ 6372b676d7Smrg 6472b676d7Smrg#ifdef HAVE_CONFIG_H 6572b676d7Smrg#include "config.h" 6672b676d7Smrg#endif 6772b676d7Smrg 6872b676d7Smrg#include "sis.h" 6972b676d7Smrg#define SIS_NEED_inSISREG 7072b676d7Smrg#define SIS_NEED_inSISREGW 7172b676d7Smrg#define SIS_NEED_inSISREGL 7272b676d7Smrg#define SIS_NEED_outSISREG 7372b676d7Smrg#define SIS_NEED_outSISREGW 7472b676d7Smrg#define SIS_NEED_outSISREGL 7572b676d7Smrg#define SIS_NEED_inSISIDXREG 7672b676d7Smrg#define SIS_NEED_outSISIDXREG 7772b676d7Smrg#define SIS_NEED_orSISIDXREG 7872b676d7Smrg#define SIS_NEED_andSISIDXREG 7972b676d7Smrg#define SIS_NEED_MYMMIO 8072b676d7Smrg#include "sis_regs.h" 8172b676d7Smrg#include "sis_dac.h" 8272b676d7Smrg 8372b676d7Smrgstatic void SiSSave(ScrnInfoPtr pScrn, SISRegPtr sisReg); 8472b676d7Smrgstatic void SiSRestore(ScrnInfoPtr pScrn, SISRegPtr sisReg); 8572b676d7Smrgstatic void SiS300Save(ScrnInfoPtr pScrn, SISRegPtr sisReg); 8672b676d7Smrgstatic void SiS300Restore(ScrnInfoPtr pScrn, SISRegPtr sisReg); 8772b676d7Smrgstatic void SiS315Save(ScrnInfoPtr pScrn, SISRegPtr sisReg); 8872b676d7Smrgstatic void SiS315Restore(ScrnInfoPtr pScrn, SISRegPtr sisReg); 8972b676d7Smrgstatic void SiS301Save(ScrnInfoPtr pScrn, SISRegPtr sisReg); 9072b676d7Smrgstatic void SiS301BSave(ScrnInfoPtr pScrn, SISRegPtr sisReg); 9172b676d7Smrgstatic void SiSLVDSChrontelSave(ScrnInfoPtr pScrn, SISRegPtr sisReg); 9272b676d7Smrgstatic void SiS301Restore(ScrnInfoPtr pScrn, SISRegPtr sisReg); 9372b676d7Smrgstatic void SiS301BRestore(ScrnInfoPtr pScrn, SISRegPtr sisReg); 9472b676d7Smrgstatic void SiSLVDSChrontelRestore(ScrnInfoPtr pScrn, SISRegPtr sisReg); 9572b676d7Smrgstatic void SiS301LoadPalette(ScrnInfoPtr pScrn, int numColors, 9672b676d7Smrg int *indicies, LOCO *colors, int myshift); 9772b676d7Smrgstatic void SetBlock(CARD16 port, CARD8 from, CARD8 to, CARD8 *DataPtr); 9872b676d7Smrg 9972b676d7SmrgUChar SiSGetCopyROP(int rop); 10072b676d7SmrgUChar SiSGetPatternROP(int rop); 10172b676d7Smrg 10272b676d7Smrgstatic const UShort ch700xidx[] = { 10372b676d7Smrg 0x00,0x07,0x08,0x0a,0x0b,0x04,0x09,0x20,0x21,0x18,0x19,0x1a, 10472b676d7Smrg 0x1b,0x1c,0x1d,0x1e,0x1f, /* 0x0e, - Don't save the power register */ 10572b676d7Smrg 0x01,0x03,0x06,0x0d,0x11,0x13,0x14,0x15,0x17,0x22,0x23,0x24 10672b676d7Smrg }; 10772b676d7Smrg 10872b676d7Smrgstatic const UShort ch701xidx[] = { 10972b676d7Smrg 0x1c,0x5f,0x64,0x6f,0x70,0x71,0x72,0x73,0x74,0x76,0x78,0x7d, 11072b676d7Smrg 0x67,0x68,0x69,0x6a,0x6b,0x1e,0x00,0x01,0x02,0x04,0x03,0x05, 11172b676d7Smrg 0x06,0x07,0x08,0x15,0x1f,0x0c,0x0d,0x0e,0x0f,0x10,0x66 11272b676d7Smrg }; 11372b676d7Smrg 11472b676d7Smrgint SiS_compute_vclk( 11572b676d7Smrg int Clock, 11672b676d7Smrg int *out_n, 11772b676d7Smrg int *out_dn, 11872b676d7Smrg int *out_div, 11972b676d7Smrg int *out_sbit, 12072b676d7Smrg int *out_scale) 12172b676d7Smrg{ 12272b676d7Smrg float f,x,y,t, error, min_error; 12372b676d7Smrg int n, dn, best_n=0, best_dn=0; 12472b676d7Smrg 12572b676d7Smrg /* 12672b676d7Smrg * Rules 12772b676d7Smrg * 12872b676d7Smrg * VCLK = 14.318 * (Divider/Post Scalar) * (Numerator/DeNumerator) 12972b676d7Smrg * Factor = (Divider/Post Scalar) 13072b676d7Smrg * Divider is 1 or 2 13172b676d7Smrg * Post Scalar is 1, 2, 3, 4, 6 or 8 13272b676d7Smrg * Numberator ranged from 1 to 128 13372b676d7Smrg * DeNumerator ranged from 1 to 32 13472b676d7Smrg * a. VCO = VCLK/Factor, suggest range is 150 to 250 Mhz 13572b676d7Smrg * b. Post Scalar selected from 1, 2, 4 or 8 first. 13672b676d7Smrg * c. DeNumerator selected from 2. 13772b676d7Smrg * 13872b676d7Smrg * According to rule a and b, the VCO ranges that can be scaled by 13972b676d7Smrg * rule b are: 14072b676d7Smrg * 150 - 250 (Factor = 1) 14172b676d7Smrg * 75 - 125 (Factor = 2) 14272b676d7Smrg * 37.5 - 62.5 (Factor = 4) 14372b676d7Smrg * 18.75 - 31.25 (Factor = 8) 14472b676d7Smrg * 14572b676d7Smrg * The following ranges use Post Scalar 3 or 6: 14672b676d7Smrg * 125 - 150 (Factor = 1.5) 14772b676d7Smrg * 62.5 - 75 (Factor = 3) 14872b676d7Smrg * 31.25 - 37.5 (Factor = 6) 14972b676d7Smrg * 15072b676d7Smrg * Steps: 15172b676d7Smrg * 1. divide the Clock by 2 until the Clock is less or equal to 31.25. 15272b676d7Smrg * 2. if the divided Clock is range from 18.25 to 31.25, than 15372b676d7Smrg * the Factor is 1, 2, 4 or 8. 15472b676d7Smrg * 3. if the divided Clock is range from 15.625 to 18.25, than 15572b676d7Smrg * the Factor is 1.5, 3 or 6. 15672b676d7Smrg * 4. select the Numberator and DeNumberator with minimum deviation. 15772b676d7Smrg * 15872b676d7Smrg * ** this function can select VCLK ranged from 18.75 to 250 Mhz 15972b676d7Smrg */ 16072b676d7Smrg 16172b676d7Smrg f = (float) Clock; 16272b676d7Smrg f /= 1000.0; 16372b676d7Smrg if((f > 250.0) || (f < 18.75)) 16472b676d7Smrg return 0; 16572b676d7Smrg 16672b676d7Smrg min_error = f; 16772b676d7Smrg y = 1.0; 16872b676d7Smrg x = f; 16972b676d7Smrg while(x > 31.25) { 17072b676d7Smrg y *= 2.0; 17172b676d7Smrg x /= 2.0; 17272b676d7Smrg } 17372b676d7Smrg if(x >= 18.25) { 17472b676d7Smrg x *= 8.0; 17572b676d7Smrg y = 8.0 / y; 17672b676d7Smrg } else if(x >= 15.625) { 17772b676d7Smrg x *= 12.0; 17872b676d7Smrg y = 12.0 / y; 17972b676d7Smrg } 18072b676d7Smrg 18172b676d7Smrg t = y; 18272b676d7Smrg if(t == (float) 1.5) { 18372b676d7Smrg *out_div = 2; 18472b676d7Smrg t *= 2.0; 18572b676d7Smrg } else { 18672b676d7Smrg *out_div = 1; 18772b676d7Smrg } 18872b676d7Smrg if(t > (float) 4.0) { 18972b676d7Smrg *out_sbit = 1; 19072b676d7Smrg t /= 2.0; 19172b676d7Smrg } else { 19272b676d7Smrg *out_sbit = 0; 19372b676d7Smrg } 19472b676d7Smrg 19572b676d7Smrg *out_scale = (int) t; 19672b676d7Smrg 19772b676d7Smrg for(dn = 2; dn <= 32; dn++) { 19872b676d7Smrg for(n = 1; n <= 128; n++) { 19972b676d7Smrg error = x; 20072b676d7Smrg error -= ((float) 14.318 * (float) n / (float) dn); 20172b676d7Smrg if(error < (float) 0) 20272b676d7Smrg error = -error; 20372b676d7Smrg if(error < min_error) { 20472b676d7Smrg min_error = error; 20572b676d7Smrg best_n = n; 20672b676d7Smrg best_dn = dn; 20772b676d7Smrg } 20872b676d7Smrg } 20972b676d7Smrg } 21072b676d7Smrg *out_n = best_n; 21172b676d7Smrg *out_dn = best_dn; 21272b676d7Smrg PDEBUG(ErrorF("SiS_compute_vclk: Clock=%d, n=%d, dn=%d, div=%d, sbit=%d," 21372b676d7Smrg " scale=%d\n", Clock, best_n, best_dn, *out_div, 21472b676d7Smrg *out_sbit, *out_scale)); 21572b676d7Smrg return 1; 21672b676d7Smrg} 21772b676d7Smrg 21872b676d7Smrgvoid 21972b676d7SmrgSiSCalcClock(ScrnInfoPtr pScrn, int clock, int max_VLD, unsigned int *vclk) 22072b676d7Smrg{ 22172b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 22272b676d7Smrg int M, N, P , PSN, VLD , PSNx ; 22372b676d7Smrg int bestM=0, bestN=0, bestP=0, bestPSN=0, bestVLD=0; 22472b676d7Smrg double abest = 42.0; 22572b676d7Smrg double target; 22672b676d7Smrg double Fvco, Fout; 22772b676d7Smrg double error, aerror; 22872b676d7Smrg 22972b676d7Smrg /* 23072b676d7Smrg * fd = fref*(Numerator/Denumerator)*(Divider/PostScaler) 23172b676d7Smrg * 23272b676d7Smrg * M = Numerator [1:128] 23372b676d7Smrg * N = DeNumerator [1:32] 23472b676d7Smrg * VLD = Divider (Vco Loop Divider) : divide by 1, 2 23572b676d7Smrg * P = Post Scaler : divide by 1, 2, 3, 4 23672b676d7Smrg * PSN = Pre Scaler (Reference Divisor Select) 23772b676d7Smrg * 23872b676d7Smrg * result in vclk[] 23972b676d7Smrg */ 24072b676d7Smrg#define Midx 0 24172b676d7Smrg#define Nidx 1 24272b676d7Smrg#define VLDidx 2 24372b676d7Smrg#define Pidx 3 24472b676d7Smrg#define PSNidx 4 24572b676d7Smrg#define Fref 14318180 24672b676d7Smrg/* stability constraints for internal VCO -- MAX_VCO also determines 24772b676d7Smrg * the maximum Video pixel clock */ 24872b676d7Smrg#define MIN_VCO Fref 24972b676d7Smrg#define MAX_VCO 135000000 25072b676d7Smrg#define MAX_VCO_5597 353000000 25172b676d7Smrg#define MAX_PSN 0 /* no pre scaler for this chip */ 25272b676d7Smrg#define TOLERANCE 0.01 /* search smallest M and N in this tolerance */ 25372b676d7Smrg 25472b676d7Smrg int M_min = 2; 25572b676d7Smrg int M_max = 128; 25672b676d7Smrg 25772b676d7Smrg target = clock * 1000; 25872b676d7Smrg 25972b676d7Smrg if(pSiS->Chipset == PCI_CHIP_SIS5597 || pSiS->Chipset == PCI_CHIP_SIS6326) { 26072b676d7Smrg 26172b676d7Smrg int low_N = 2; 26272b676d7Smrg int high_N = 5; 26372b676d7Smrg 26472b676d7Smrg PSN = 1; 26572b676d7Smrg P = 1; 26672b676d7Smrg if(target < MAX_VCO_5597 / 2) P = 2; 26772b676d7Smrg if(target < MAX_VCO_5597 / 3) P = 3; 26872b676d7Smrg if(target < MAX_VCO_5597 / 4) P = 4; 26972b676d7Smrg if(target < MAX_VCO_5597 / 6) P = 6; 27072b676d7Smrg if(target < MAX_VCO_5597 / 8) P = 8; 27172b676d7Smrg 27272b676d7Smrg Fvco = P * target; 27372b676d7Smrg 27472b676d7Smrg for(N = low_N; N <= high_N; N++) { 27572b676d7Smrg 27672b676d7Smrg double M_desired = Fvco / Fref * N; 27772b676d7Smrg if(M_desired > M_max * max_VLD) continue; 27872b676d7Smrg 27972b676d7Smrg if(M_desired > M_max) { 28072b676d7Smrg M = M_desired / 2 + 0.5; 28172b676d7Smrg VLD = 2; 28272b676d7Smrg } else { 28372b676d7Smrg M = Fvco / Fref * N + 0.5; 28472b676d7Smrg VLD = 1; 28572b676d7Smrg } 28672b676d7Smrg 28772b676d7Smrg Fout = (double)Fref * (M * VLD)/(N * P); 28872b676d7Smrg 28972b676d7Smrg error = (target - Fout) / target; 29072b676d7Smrg aerror = (error < 0) ? -error : error; 29172b676d7Smrg if(aerror < abest) { 29272b676d7Smrg abest = aerror; 29372b676d7Smrg bestM = M; 29472b676d7Smrg bestN = N; 29572b676d7Smrg bestP = P; 29672b676d7Smrg bestPSN = PSN; 29772b676d7Smrg bestVLD = VLD; 29872b676d7Smrg } 29972b676d7Smrg } 30072b676d7Smrg 30172b676d7Smrg } else { 30272b676d7Smrg 30372b676d7Smrg for(PSNx = 0; PSNx <= MAX_PSN ; PSNx++) { 30472b676d7Smrg 30572b676d7Smrg int low_N, high_N; 30672b676d7Smrg double FrefVLDPSN; 30772b676d7Smrg 30872b676d7Smrg PSN = !PSNx ? 1 : 4; 30972b676d7Smrg 31072b676d7Smrg low_N = 2; 31172b676d7Smrg high_N = 32; 31272b676d7Smrg 31372b676d7Smrg for(VLD = 1 ; VLD <= max_VLD ; VLD++) { 31472b676d7Smrg 31572b676d7Smrg FrefVLDPSN = (double)Fref * VLD / PSN; 31672b676d7Smrg 31772b676d7Smrg for(N = low_N; N <= high_N; N++) { 31872b676d7Smrg double tmp = FrefVLDPSN / N; 31972b676d7Smrg 32072b676d7Smrg for(P = 1; P <= 4; P++) { 32172b676d7Smrg double Fvco_desired = target * ( P ); 32272b676d7Smrg double M_desired = Fvco_desired / tmp; 32372b676d7Smrg 32472b676d7Smrg /* Which way will M_desired be rounded? 32572b676d7Smrg * Do all three just to be safe. 32672b676d7Smrg */ 32772b676d7Smrg int M_low = M_desired - 1; 32872b676d7Smrg int M_hi = M_desired + 1; 32972b676d7Smrg 33072b676d7Smrg if(M_hi < M_min || M_low > M_max) continue; 33172b676d7Smrg 33272b676d7Smrg if(M_low < M_min) M_low = M_min; 33372b676d7Smrg 33472b676d7Smrg if(M_hi > M_max) M_hi = M_max; 33572b676d7Smrg 33672b676d7Smrg for(M = M_low; M <= M_hi; M++) { 33772b676d7Smrg Fvco = tmp * M; 33872b676d7Smrg if(Fvco <= MIN_VCO) continue; 33972b676d7Smrg if(Fvco > MAX_VCO) break; 34072b676d7Smrg 34172b676d7Smrg Fout = Fvco / ( P ); 34272b676d7Smrg 34372b676d7Smrg error = (target - Fout) / target; 34472b676d7Smrg aerror = (error < 0) ? -error : error; 34572b676d7Smrg if(aerror < abest) { 34672b676d7Smrg abest = aerror; 34772b676d7Smrg bestM = M; 34872b676d7Smrg bestN = N; 34972b676d7Smrg bestP = P; 35072b676d7Smrg bestPSN = PSN; 35172b676d7Smrg bestVLD = VLD; 35272b676d7Smrg } 35372b676d7Smrg#ifdef TWDEBUG 35472b676d7Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO,3, 35572b676d7Smrg "Freq. selected: %.2f MHz, M=%d, N=%d, VLD=%d, P=%d, PSN=%d\n", 35672b676d7Smrg (float)(clock / 1000.), M, N, P, VLD, PSN); 35772b676d7Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO,3, 35872b676d7Smrg "Freq. set: %.2f MHz\n", Fout / 1.0e6); 35972b676d7Smrg#endif 36072b676d7Smrg } 36172b676d7Smrg } 36272b676d7Smrg } 36372b676d7Smrg } 36472b676d7Smrg } 36572b676d7Smrg } 36672b676d7Smrg 36772b676d7Smrg vclk[Midx] = bestM; 36872b676d7Smrg vclk[Nidx] = bestN; 36972b676d7Smrg vclk[VLDidx] = bestVLD; 37072b676d7Smrg vclk[Pidx] = bestP; 37172b676d7Smrg vclk[PSNidx] = bestPSN; 37272b676d7Smrg} 37372b676d7Smrg 37472b676d7Smrgstatic void 37572b676d7SmrgSiSSave(ScrnInfoPtr pScrn, SISRegPtr sisReg) 37672b676d7Smrg{ 37772b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 37872b676d7Smrg int i, max; 37972b676d7Smrg 38072b676d7Smrg PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "SiSSave()\n")); 38172b676d7Smrg 38272b676d7Smrg#ifdef UNLOCK_ALWAYS 38372b676d7Smrg sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); 38472b676d7Smrg#endif 38572b676d7Smrg 38672b676d7Smrg switch(pSiS->Chipset) { 38772b676d7Smrg case PCI_CHIP_SIS5597: 38872b676d7Smrg max=0x3C; 38972b676d7Smrg break; 39072b676d7Smrg case PCI_CHIP_SIS6326: 39172b676d7Smrg case PCI_CHIP_SIS530: 39272b676d7Smrg max=0x3F; 39372b676d7Smrg break; 39472b676d7Smrg default: 39572b676d7Smrg max=0x37; 39672b676d7Smrg } 39772b676d7Smrg 39872b676d7Smrg /* Save extended SR registers */ 39972b676d7Smrg for(i = 0x00; i <= max; i++) { 40072b676d7Smrg inSISIDXREG(SISSR, i, sisReg->sisRegs3C4[i]); 40172b676d7Smrg#ifdef TWDEBUG 40272b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 40372b676d7Smrg "SR%02X - %02X \n", i, sisReg->sisRegs3C4[i]); 40472b676d7Smrg#endif 40572b676d7Smrg } 40672b676d7Smrg 40772b676d7Smrg#ifdef TWDEBUG 40872b676d7Smrg for(i = 0x00; i <= 0x3f; i++) { 40972b676d7Smrg inSISIDXREG(SISCR, i, max); 41072b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 41172b676d7Smrg "CR%02X - %02X \n", i, max); 41272b676d7Smrg } 41372b676d7Smrg#endif 41472b676d7Smrg 41572b676d7Smrg /* Save lock (will not be restored in SiSRestore()!) */ 41672b676d7Smrg inSISIDXREG(SISCR, 0x80, sisReg->sisRegs3D4[0x80]); 41772b676d7Smrg 41872b676d7Smrg sisReg->sisRegs3C2 = inSISREG(SISMISCR); /* Misc */ 41972b676d7Smrg 42072b676d7Smrg /* Save TV registers */ 42172b676d7Smrg if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) { 42272b676d7Smrg outSISIDXREG(SISCR, 0x80, 0x86); 42372b676d7Smrg for(i = 0x00; i <= 0x44; i++) { 42472b676d7Smrg sisReg->sis6326tv[i] = SiS6326GetTVReg(pScrn, i); 42572b676d7Smrg#ifdef TWDEBUG 42672b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 42772b676d7Smrg "VR%02X - %02X \n", i,sisReg->sis6326tv[i]); 42872b676d7Smrg#endif 42972b676d7Smrg } 43072b676d7Smrg } 43172b676d7Smrg} 43272b676d7Smrg 43372b676d7Smrgstatic void 43472b676d7SmrgSiSRestore(ScrnInfoPtr pScrn, SISRegPtr sisReg) 43572b676d7Smrg{ 43672b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 43772b676d7Smrg int i, max; 43872b676d7Smrg UChar tmp; 43972b676d7Smrg 44072b676d7Smrg PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4, "SiSRestore()\n")); 44172b676d7Smrg 44272b676d7Smrg#ifdef UNLOCK_ALWAYS 44372b676d7Smrg sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); 44472b676d7Smrg#endif 44572b676d7Smrg 44672b676d7Smrg switch(pSiS->Chipset) { 44772b676d7Smrg case PCI_CHIP_SIS5597: 44872b676d7Smrg max = 0x3C; 44972b676d7Smrg break; 45072b676d7Smrg case PCI_CHIP_SIS6326: 45172b676d7Smrg case PCI_CHIP_SIS530: 45272b676d7Smrg max = 0x3F; 45372b676d7Smrg break; 45472b676d7Smrg default: 45572b676d7Smrg max = 0x37; 45672b676d7Smrg } 45772b676d7Smrg 45872b676d7Smrg /* Disable TV on 6326 before restoring */ 45972b676d7Smrg if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) { 46072b676d7Smrg outSISIDXREG(SISCR, 0x80, 0x86); 46172b676d7Smrg tmp = SiS6326GetTVReg(pScrn, 0x00); 46272b676d7Smrg tmp &= ~0x04; 46372b676d7Smrg SiS6326SetTVReg(pScrn, 0x00, tmp); 46472b676d7Smrg } 46572b676d7Smrg 46672b676d7Smrg /* Restore other extended SR registers */ 46772b676d7Smrg for(i = 0x06; i <= max; i++) { 46872b676d7Smrg if((i == 0x13) || (i == 0x2a) || (i == 0x2b)) continue; 46972b676d7Smrg outSISIDXREG(SISSR, i, sisReg->sisRegs3C4[i]); 47072b676d7Smrg } 47172b676d7Smrg 47272b676d7Smrg /* Now restore VCLK (with correct SR38 setting) */ 47372b676d7Smrg outSISIDXREG(SISSR, 0x13, sisReg->sisRegs3C4[0x13]); 47472b676d7Smrg outSISIDXREG(SISSR, 0x2a, sisReg->sisRegs3C4[0x2a]); 47572b676d7Smrg outSISIDXREG(SISSR, 0x2b, sisReg->sisRegs3C4[0x2b]); 47672b676d7Smrg 47772b676d7Smrg /* Misc */ 47872b676d7Smrg outSISREG(SISMISCW, sisReg->sisRegs3C2); 47972b676d7Smrg 48072b676d7Smrg /* MemClock needs this to take effect */ 48172b676d7Smrg outSISIDXREG(SISSR, 0x00, 0x01); /* Synchronous Reset */ 48272b676d7Smrg usleep(10000); 48372b676d7Smrg outSISIDXREG(SISSR, 0x00, 0x03); /* End Reset */ 48472b676d7Smrg 48572b676d7Smrg /* Restore TV registers */ 48672b676d7Smrg pSiS->SiS6326Flags &= ~SIS6326_TVON; 48772b676d7Smrg if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) { 48872b676d7Smrg for(i = 0x01; i <= 0x44; i++) { 48972b676d7Smrg SiS6326SetTVReg(pScrn, i, sisReg->sis6326tv[i]); 49072b676d7Smrg#ifdef TWDEBUG 49172b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 49272b676d7Smrg "VR%02x restored to %02x\n", 49372b676d7Smrg i, sisReg->sis6326tv[i]); 49472b676d7Smrg#endif 49572b676d7Smrg } 49672b676d7Smrg tmp = SiS6326GetXXReg(pScrn, 0x13); 49772b676d7Smrg SiS6326SetXXReg(pScrn, 0x13, 0xfa); 49872b676d7Smrg tmp = SiS6326GetXXReg(pScrn, 0x14); 49972b676d7Smrg SiS6326SetXXReg(pScrn, 0x14, 0xc8); 50072b676d7Smrg if(!(sisReg->sisRegs3C4[0x0D] & 0x04)) { 50172b676d7Smrg tmp = SiS6326GetXXReg(pScrn, 0x13); 50272b676d7Smrg SiS6326SetXXReg(pScrn, 0x13, 0xf6); 50372b676d7Smrg tmp = SiS6326GetXXReg(pScrn, 0x14); 50472b676d7Smrg SiS6326SetXXReg(pScrn, 0x14, 0xbf); 50572b676d7Smrg } 50672b676d7Smrg if(sisReg->sis6326tv[0] & 0x04) pSiS->SiS6326Flags |= SIS6326_TVON; 50772b676d7Smrg } 50872b676d7Smrg} 50972b676d7Smrg 51072b676d7Smrg/* Save SiS 300 series register contents */ 51172b676d7Smrgstatic void 51272b676d7SmrgSiS300Save(ScrnInfoPtr pScrn, SISRegPtr sisReg) 51372b676d7Smrg{ 51472b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 51572b676d7Smrg int i; 51672b676d7Smrg 51772b676d7Smrg PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "SiS300Save()\n")); 51872b676d7Smrg 51972b676d7Smrg#ifdef UNLOCK_ALWAYS 52072b676d7Smrg sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); 52172b676d7Smrg#endif 52272b676d7Smrg 52372b676d7Smrg /* Save SR registers */ 52472b676d7Smrg for(i = 0x00; i <= 0x3D; i++) { 52572b676d7Smrg inSISIDXREG(SISSR, i, sisReg->sisRegs3C4[i]); 52672b676d7Smrg#ifdef TWDEBUG 52772b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 52872b676d7Smrg "SR%02X - %02X \n", i,sisReg->sisRegs3C4[i]); 52972b676d7Smrg#endif 53072b676d7Smrg } 53172b676d7Smrg 53272b676d7Smrg /* Save CR registers */ 53372b676d7Smrg for(i = 0x00; i < 0x40; i++) { 53472b676d7Smrg inSISIDXREG(SISCR, i, sisReg->sisRegs3D4[i]); 53572b676d7Smrg#ifdef TWDEBUG 53672b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 53772b676d7Smrg "CR%02X Contents - %02X \n", i,sisReg->sisRegs3D4[i]); 53872b676d7Smrg#endif 53972b676d7Smrg } 54072b676d7Smrg 54172b676d7Smrg /* Save Misc register */ 54272b676d7Smrg sisReg->sisRegs3C2 = inSISREG(SISMISCR); 54372b676d7Smrg 54472b676d7Smrg /* Save FQBQ and GUI timer settings */ 54572b676d7Smrg if(pSiS->Chipset == PCI_CHIP_SIS630) { 5461fd23544Smrg sisReg->sisRegsPCI50 = sis_pci_read_host_bridge_u32(0x50); 5471fd23544Smrg sisReg->sisRegsPCIA0 = sis_pci_read_host_bridge_u32(0xA0); 54872b676d7Smrg#ifdef TWDEBUG 54972b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 55072b676d7Smrg "PCI Config 50 = %lx\n", sisReg->sisRegsPCI50); 55172b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 55272b676d7Smrg "PCI Config A0 = %lx\n", sisReg->sisRegsPCIA0); 55372b676d7Smrg#endif 55472b676d7Smrg } 55572b676d7Smrg 55672b676d7Smrg /* Save panel link/video bridge registers */ 55772b676d7Smrg#ifndef TWDEBUG 55872b676d7Smrg if(!pSiS->UseVESA) { 55972b676d7Smrg#endif 56072b676d7Smrg if(pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) 56172b676d7Smrg SiSLVDSChrontelSave(pScrn, sisReg); 56272b676d7Smrg else if(pSiS->VBFlags2 & VB2_301) 56372b676d7Smrg SiS301Save(pScrn, sisReg); 56472b676d7Smrg else if(pSiS->VBFlags2 & VB2_30xBLV) 56572b676d7Smrg SiS301BSave(pScrn, sisReg); 56672b676d7Smrg#ifndef TWDEBUG 56772b676d7Smrg } 56872b676d7Smrg#endif 56972b676d7Smrg 57072b676d7Smrg /* Save Mode number */ 57172b676d7Smrg sisReg->BIOSModeSave = SiS_GetSetModeID(pScrn,0xFF); 57272b676d7Smrg 57372b676d7Smrg#ifdef TWDEBUG 57472b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 57572b676d7Smrg "BIOS mode ds:449 = 0x%x\n", sisReg->BIOSModeSave); 57672b676d7Smrg#endif 57772b676d7Smrg} 57872b676d7Smrg 57972b676d7Smrg/* Restore SiS300 series register contents */ 58072b676d7Smrgstatic void 58172b676d7SmrgSiS300Restore(ScrnInfoPtr pScrn, SISRegPtr sisReg) 58272b676d7Smrg{ 58372b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 58472b676d7Smrg int i,temp; 58572b676d7Smrg CARD32 temp1, temp2; 58672b676d7Smrg 58772b676d7Smrg PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4, "SiS300Restore()\n")); 58872b676d7Smrg 58972b676d7Smrg#ifdef UNLOCK_ALWAYS 59072b676d7Smrg sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); 59172b676d7Smrg#endif 59272b676d7Smrg 59372b676d7Smrg /* Wait for accelerator to finish on-going drawing operations. */ 59472b676d7Smrg inSISIDXREG(SISSR, 0x1E, temp); 59572b676d7Smrg if(temp & (0x40|0x10|0x02)) { 59672b676d7Smrg while ( (SIS_MMIO_IN16(pSiS->IOBase, 0x8242) & 0xE000) != 0xE000){}; 59772b676d7Smrg while ( (SIS_MMIO_IN16(pSiS->IOBase, 0x8242) & 0xE000) != 0xE000){}; 59872b676d7Smrg while ( (SIS_MMIO_IN16(pSiS->IOBase, 0x8242) & 0xE000) != 0xE000){}; 59972b676d7Smrg } 60072b676d7Smrg 60172b676d7Smrg if(!(pSiS->UseVESA)) { 60272b676d7Smrg if(pSiS->VBFlags2 & VB2_LVDS) { 60372b676d7Smrg SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30); 60474c14cd6Smrg SiSSetLVDSetc(pSiS->SiS_Pr); 60572b676d7Smrg SiS_GetVBType(pSiS->SiS_Pr); 60672b676d7Smrg SiS_UnLockCRT2(pSiS->SiS_Pr); 60772b676d7Smrg SiS_DisableBridge(pSiS->SiS_Pr); 60872b676d7Smrg } 60972b676d7Smrg } 61072b676d7Smrg 61172b676d7Smrg /* Restore extended CR registers */ 61272b676d7Smrg for(i = 0x19; i < 0x40; i++) { 61372b676d7Smrg outSISIDXREG(SISCR, i, sisReg->sisRegs3D4[i]); 61472b676d7Smrg } 61572b676d7Smrg 61672b676d7Smrg if(pSiS->Chipset != PCI_CHIP_SIS300) { 61772b676d7Smrg UChar val; 61872b676d7Smrg inSISIDXREG(SISCR, 0x1A, val); 61972b676d7Smrg if(val == sisReg->sisRegs3D4[0x19]) 62072b676d7Smrg outSISIDXREG(SISCR, 0x1A, sisReg->sisRegs3D4[0x19]); 62172b676d7Smrg inSISIDXREG(SISCR,0x19,val); 62272b676d7Smrg if(val == sisReg->sisRegs3D4[0x1A]) 62372b676d7Smrg outSISIDXREG(SISCR, 0x19, sisReg->sisRegs3D4[0x1A]); 62472b676d7Smrg } 62572b676d7Smrg 62672b676d7Smrg /* Set (and leave) PCI_IO_ENABLE on if accelerators are on */ 62772b676d7Smrg if(sisReg->sisRegs3C4[0x1e] & 0x50) { 62872b676d7Smrg sisReg->sisRegs3C4[0x20] |= 0x20; 62972b676d7Smrg outSISIDXREG(SISSR, 0x20, sisReg->sisRegs3C4[0x20]); 63072b676d7Smrg } 63172b676d7Smrg 63272b676d7Smrg /* If TQ is switched on, don't switch it off ever again! 63372b676d7Smrg * Therefore, always restore registers with TQ enabled. 63472b676d7Smrg */ 63572b676d7Smrg if((!pSiS->NoAccel) && (pSiS->TurboQueue)) { 63672b676d7Smrg temp = (pScrn->videoRam/64) - 8; 63772b676d7Smrg sisReg->sisRegs3C4[0x26] = temp & 0xFF; 63872b676d7Smrg sisReg->sisRegs3C4[0x27] = ((temp >> 8) & 3) | 0xF0; 63972b676d7Smrg } 64072b676d7Smrg 64172b676d7Smrg /* Restore extended SR registers */ 64272b676d7Smrg for(i = 0x06; i <= 0x3D; i++) { 64372b676d7Smrg temp = sisReg->sisRegs3C4[i]; 64472b676d7Smrg if(!(pSiS->UseVESA)) { 64572b676d7Smrg if(pSiS->VBFlags2 & VB2_LVDS) { 64672b676d7Smrg if(i == 0x11) { 64772b676d7Smrg inSISIDXREG(SISSR,0x11,temp); 64872b676d7Smrg temp &= 0x0c; 64972b676d7Smrg temp |= (sisReg->sisRegs3C4[i] & 0xf3); 65072b676d7Smrg } 65172b676d7Smrg } 65272b676d7Smrg } 65372b676d7Smrg outSISIDXREG(SISSR, i, temp); 65472b676d7Smrg } 65572b676d7Smrg 65672b676d7Smrg /* Restore VCLK and ECLK */ 65772b676d7Smrg if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xB)) { 65872b676d7Smrg outSISIDXREG(SISSR,0x31,0x20); 65972b676d7Smrg outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]); 66072b676d7Smrg outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]); 66172b676d7Smrg outSISIDXREG(SISSR,0x2d,0x80); 66272b676d7Smrg outSISIDXREG(SISSR,0x31,0x10); 66372b676d7Smrg outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]); 66472b676d7Smrg outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]); 66572b676d7Smrg outSISIDXREG(SISSR,0x2d,0x80); 66672b676d7Smrg } 66772b676d7Smrg outSISIDXREG(SISSR,0x31,0x00); 66872b676d7Smrg outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]); 66972b676d7Smrg outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]); 67072b676d7Smrg outSISIDXREG(SISSR,0x2d,0x80); 67172b676d7Smrg if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xB)) { 67272b676d7Smrg outSISIDXREG(SISSR,0x31,0x20); 67372b676d7Smrg outSISIDXREG(SISSR,0x2e,sisReg->sisRegs3C4[0x2e]); 67472b676d7Smrg outSISIDXREG(SISSR,0x2f,sisReg->sisRegs3C4[0x2f]); 67572b676d7Smrg outSISIDXREG(SISSR,0x31,0x10); 67672b676d7Smrg outSISIDXREG(SISSR,0x2e,sisReg->sisRegs3C4[0x2e]); 67772b676d7Smrg outSISIDXREG(SISSR,0x2f,sisReg->sisRegs3C4[0x2f]); 67872b676d7Smrg outSISIDXREG(SISSR,0x31,0x00); 67972b676d7Smrg outSISIDXREG(SISSR,0x2e,sisReg->sisRegs3C4[0x2e]); 68072b676d7Smrg outSISIDXREG(SISSR,0x2f,sisReg->sisRegs3C4[0x2f]); 68172b676d7Smrg } 68272b676d7Smrg 68372b676d7Smrg /* Restore Misc register */ 68472b676d7Smrg outSISREG(SISMISCW, sisReg->sisRegs3C2); 68572b676d7Smrg 68672b676d7Smrg /* Restore FQBQ and GUI timer settings */ 68772b676d7Smrg if(pSiS->Chipset == PCI_CHIP_SIS630) { 6881fd23544Smrg temp1 = sis_pci_read_host_bridge_u32(0x50); 6891fd23544Smrg temp2 = sis_pci_read_host_bridge_u32(0xA0); 6901fd23544Smrg if(sis_pci_read_host_bridge_u32(0x00) == 0x06301039) { 69172b676d7Smrg temp1 &= 0xf0ffffff; 69272b676d7Smrg temp1 |= (sisReg->sisRegsPCI50 & ~0xf0ffffff); 69372b676d7Smrg temp2 &= 0xf0ffffff; 69472b676d7Smrg temp2 |= (sisReg->sisRegsPCIA0 & ~0xf0ffffff); 69572b676d7Smrg } else { /* 730 */ 69672b676d7Smrg temp1 &= 0xfffff9ff; 69772b676d7Smrg temp1 |= (sisReg->sisRegsPCI50 & ~0xfffff9ff); 69872b676d7Smrg temp2 &= 0x00ffffff; 69972b676d7Smrg temp2 |= (sisReg->sisRegsPCIA0 & ~0x00ffffff); 70072b676d7Smrg } 7011fd23544Smrg sis_pci_write_host_bridge_u32(0x50, temp1); 7021fd23544Smrg sis_pci_write_host_bridge_u32(0xA0, temp2); 70372b676d7Smrg } 70472b676d7Smrg 70572b676d7Smrg /* Restore panel link/video bridge registers */ 70672b676d7Smrg if(!(pSiS->UseVESA)) { 70772b676d7Smrg if(pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) 70872b676d7Smrg SiSLVDSChrontelRestore(pScrn, sisReg); 70972b676d7Smrg else if(pSiS->VBFlags2 & VB2_301) 71072b676d7Smrg SiS301Restore(pScrn, sisReg); 71172b676d7Smrg else if(pSiS->VBFlags2 & VB2_30xBLV) 71272b676d7Smrg SiS301BRestore(pScrn, sisReg); 71372b676d7Smrg } 71472b676d7Smrg 71572b676d7Smrg /* MemClock needs this to take effect */ 71672b676d7Smrg outSISIDXREG(SISSR, 0x00, 0x01); /* Synchronous Reset */ 71772b676d7Smrg outSISIDXREG(SISSR, 0x00, 0x03); /* End Reset */ 71872b676d7Smrg 71972b676d7Smrg /* Restore mode number */ 72072b676d7Smrg SiS_GetSetModeID(pScrn,sisReg->BIOSModeSave); 72172b676d7Smrg} 72272b676d7Smrg 72372b676d7Smrg/* Save SiS315 series register contents */ 72472b676d7Smrgstatic void 72572b676d7SmrgSiS315Save(ScrnInfoPtr pScrn, SISRegPtr sisReg) 72672b676d7Smrg{ 72772b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 72872b676d7Smrg int i, max; 72972b676d7Smrg 73072b676d7Smrg PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "SiS315Save()\n")); 73172b676d7Smrg 73272b676d7Smrg#ifdef UNLOCK_ALWAYS 73372b676d7Smrg sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); 73472b676d7Smrg#endif 73572b676d7Smrg 73672b676d7Smrg /* Save SR registers */ 73772b676d7Smrg for(i = 0x00; i <= 0x60; i++) { 73872b676d7Smrg inSISIDXREG(SISSR, i, sisReg->sisRegs3C4[i]); 73972b676d7Smrg#ifdef TWDEBUG 74072b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 74172b676d7Smrg "SR%02X - %02X \n", i,sisReg->sisRegs3C4[i]); 74272b676d7Smrg#endif 74372b676d7Smrg } 74472b676d7Smrg 74572b676d7Smrg /* Save command queue location */ 74672b676d7Smrg sisReg->sisMMIO85C0 = SIS_MMIO_IN32(pSiS->IOBase, 0x85C0); 74772b676d7Smrg 74872b676d7Smrg /* Save CR registers */ 74972b676d7Smrg max = 0x7c; 75072b676d7Smrg if(pSiS->ChipType >= XGI_20) max = 0xff; 75172b676d7Smrg for(i = 0x00; i <= max; i++) { 75272b676d7Smrg inSISIDXREG(SISCR, i, sisReg->sisRegs3D4[i]); 75372b676d7Smrg#ifdef TWDEBUG 75472b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 75572b676d7Smrg "CR%02X Contents - %02X \n", i,sisReg->sisRegs3D4[i]); 75672b676d7Smrg#endif 75772b676d7Smrg } 75872b676d7Smrg 75972b676d7Smrg /* Save video capture registers */ 76072b676d7Smrg for(i = 0x00; i <= 0x4f; i++) { 76172b676d7Smrg inSISIDXREG(SISCAP, i, sisReg->sisCapt[i]); 76272b676d7Smrg#ifdef TWDEBUG_VID 76372b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 76472b676d7Smrg "Capt%02X Contents - %02X \n", i,sisReg->sisCapt[i]); 76572b676d7Smrg#endif 76672b676d7Smrg } 76772b676d7Smrg 76872b676d7Smrg /* Save video playback registers */ 76972b676d7Smrg for(i = 0x00; i <= 0x3f; i++) { 77072b676d7Smrg inSISIDXREG(SISVID, i, sisReg->sisVid[i]); 77172b676d7Smrg#ifdef TWDEBUG_VID 77272b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 77372b676d7Smrg "Vid%02X Contents - %02X \n", i,sisReg->sisVid[i]); 77472b676d7Smrg#endif 77572b676d7Smrg } 77672b676d7Smrg 77772b676d7Smrg /* Save Misc register */ 77872b676d7Smrg sisReg->sisRegs3C2 = inSISREG(SISMISCR); 77972b676d7Smrg 78072b676d7Smrg /* Save panel link/video bridge registers */ 78172b676d7Smrg#ifndef TWDEBUG 78272b676d7Smrg if(!pSiS->UseVESA) { 78372b676d7Smrg#endif 78472b676d7Smrg if(pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) 78572b676d7Smrg SiSLVDSChrontelSave(pScrn, sisReg); 78672b676d7Smrg else if(pSiS->VBFlags2 & VB2_301) 78772b676d7Smrg SiS301Save(pScrn, sisReg); 78872b676d7Smrg else if(pSiS->VBFlags2 & VB2_30xBLV) 78972b676d7Smrg SiS301BSave(pScrn, sisReg); 79072b676d7Smrg#ifndef TWDEBUG 79172b676d7Smrg } 79272b676d7Smrg#endif 79372b676d7Smrg 79472b676d7Smrg /* Save mode number */ 79572b676d7Smrg sisReg->BIOSModeSave = SiS_GetSetModeID(pScrn,0xFF); 79672b676d7Smrg 79772b676d7Smrg#ifdef TWDEBUG 79872b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 79972b676d7Smrg "BIOS mode ds:449 = 0x%x\n", sisReg->BIOSModeSave); 80072b676d7Smrg#endif 80172b676d7Smrg} 80272b676d7Smrg 80372b676d7Smrg/* Restore SiS315/330 series register contents */ 80472b676d7Smrgstatic void 80572b676d7SmrgSiS315Restore(ScrnInfoPtr pScrn, SISRegPtr sisReg) 80672b676d7Smrg{ 80772b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 80872b676d7Smrg int i,temp; 80972b676d7Smrg 81072b676d7Smrg PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4, "SiS315Restore()\n")); 81172b676d7Smrg 81272b676d7Smrg#ifdef UNLOCK_ALWAYS 81372b676d7Smrg sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); 81472b676d7Smrg#endif 81572b676d7Smrg 81672b676d7Smrg /* Wait for accelerator to finish on-going drawing operations. */ 81772b676d7Smrg inSISIDXREG(SISSR, 0x1E, temp); 81872b676d7Smrg if(temp & (0x40|0x10|0x02)) { /* 0x40 = 2D, 0x02 = 3D enabled*/ 81972b676d7Smrg while ( (SIS_MMIO_IN32(pSiS->IOBase, 0x85CC) & 0x80000000) != 0x80000000){}; 82072b676d7Smrg while ( (SIS_MMIO_IN32(pSiS->IOBase, 0x85CC) & 0x80000000) != 0x80000000){}; 82172b676d7Smrg while ( (SIS_MMIO_IN32(pSiS->IOBase, 0x85CC) & 0x80000000) != 0x80000000){}; 82272b676d7Smrg } 82372b676d7Smrg 82472b676d7Smrg /* We reset the command queue before restoring. 82572b676d7Smrg * This might be required because we never know what 82672b676d7Smrg * console driver (like the kernel framebuffer driver) 82772b676d7Smrg * or application is running and which queue mode it 82872b676d7Smrg * uses. 82972b676d7Smrg */ 83072b676d7Smrg andSISIDXREG(SISCR, 0x55, 0x33); 83172b676d7Smrg orSISIDXREG(SISSR, 0x26, 0x01); 83272b676d7Smrg outSISIDXREG(SISSR, 0x27, 0x1F); 83372b676d7Smrg 83472b676d7Smrg /* Restore extended CR registers */ 83572b676d7Smrg for(i = 0x19; i < 0x5C; i++) { 83672b676d7Smrg outSISIDXREG(SISCR, i, sisReg->sisRegs3D4[i]); 83772b676d7Smrg } 83872b676d7Smrg if(pSiS->ChipType < SIS_661) { 83972b676d7Smrg outSISIDXREG(SISCR, 0x79, sisReg->sisRegs3D4[0x79]); 84072b676d7Smrg } 84172b676d7Smrg outSISIDXREG(SISCR, pSiS->myCR63, sisReg->sisRegs3D4[pSiS->myCR63]); 84272b676d7Smrg 84372b676d7Smrg /* Leave PCI_IO_ENABLE on if accelerators are on (Is this required?) */ 84472b676d7Smrg if(sisReg->sisRegs3C4[0x1e] & 0x52) { /* 0x40=2D, 0x02=3D */ 84572b676d7Smrg sisReg->sisRegs3C4[0x20] |= 0x20; 84672b676d7Smrg outSISIDXREG(SISSR, 0x20, sisReg->sisRegs3C4[0x20]); 84772b676d7Smrg } 84872b676d7Smrg 84972b676d7Smrg if(pSiS->SiS_Pr->SiS_SensibleSR11) { 85072b676d7Smrg sisReg->sisRegs3C4[0x11] &= 0x0f; 85172b676d7Smrg } 85272b676d7Smrg 85372b676d7Smrg /* Restore extended SR registers */ 85472b676d7Smrg for(i = 0x06; i <= 0x3F; i++) { 85572b676d7Smrg if(i == 0x26) { 85672b676d7Smrg continue; 85772b676d7Smrg } else if(i == 0x27) { 85872b676d7Smrg outSISIDXREG(SISSR, 0x27, sisReg->sisRegs3C4[0x27]); 85972b676d7Smrg outSISIDXREG(SISSR, 0x26, sisReg->sisRegs3C4[0x26]); 86072b676d7Smrg } else { 86172b676d7Smrg outSISIDXREG(SISSR, i, sisReg->sisRegs3C4[i]); 86272b676d7Smrg } 86372b676d7Smrg } 86472b676d7Smrg 86572b676d7Smrg /* Restore VCLK and ECLK */ 86672b676d7Smrg andSISIDXREG(SISSR,0x31,0xcf); 86772b676d7Smrg if(pSiS->VBFlags2 & VB2_LVDS) { 86872b676d7Smrg orSISIDXREG(SISSR,0x31,0x20); 86972b676d7Smrg outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]); 87072b676d7Smrg outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]); 87172b676d7Smrg outSISIDXREG(SISSR,0x2d,0x80); 87272b676d7Smrg andSISIDXREG(SISSR,0x31,0xcf); 87372b676d7Smrg orSISIDXREG(SISSR,0x31,0x10); 87472b676d7Smrg outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]); 87572b676d7Smrg outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]); 87672b676d7Smrg outSISIDXREG(SISSR,0x2d,0x80); 87772b676d7Smrg andSISIDXREG(SISSR,0x31,0xcf); 87872b676d7Smrg outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]); 87972b676d7Smrg outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]); 88072b676d7Smrg outSISIDXREG(SISSR,0x2d,0x01); 88172b676d7Smrg outSISIDXREG(SISSR,0x31,0x20); 88272b676d7Smrg outSISIDXREG(SISSR,0x2e,sisReg->sisRegs3C4[0x2e]); 88372b676d7Smrg outSISIDXREG(SISSR,0x2f,sisReg->sisRegs3C4[0x2f]); 88472b676d7Smrg outSISIDXREG(SISSR,0x31,0x10); 88572b676d7Smrg outSISIDXREG(SISSR,0x2e,sisReg->sisRegs3C4[0x2e]); 88672b676d7Smrg outSISIDXREG(SISSR,0x2f,sisReg->sisRegs3C4[0x2f]); 88772b676d7Smrg outSISIDXREG(SISSR,0x31,0x00); 88872b676d7Smrg outSISIDXREG(SISSR,0x2e,sisReg->sisRegs3C4[0x2e]); 88972b676d7Smrg outSISIDXREG(SISSR,0x2f,sisReg->sisRegs3C4[0x2f]); 89072b676d7Smrg } else { 89172b676d7Smrg outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]); 89272b676d7Smrg outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]); 89372b676d7Smrg outSISIDXREG(SISSR,0x2d,0x01); 89472b676d7Smrg } 89572b676d7Smrg 89672b676d7Smrg#ifndef SISVRAMQ 89772b676d7Smrg /* Initialize read/write pointer for command queue */ 89872b676d7Smrg SIS_MMIO_OUT32(pSiS->IOBase, 0x85C4, SIS_MMIO_IN32(pSiS->IOBase, 0x85C8)); 89972b676d7Smrg#endif 90072b676d7Smrg /* Restore queue location */ 90172b676d7Smrg SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, sisReg->sisMMIO85C0); 90272b676d7Smrg 90372b676d7Smrg /* Restore Misc register */ 90472b676d7Smrg outSISREG(SISMISCW, sisReg->sisRegs3C2); 90572b676d7Smrg 90672b676d7Smrg /* Restore panel link/video bridge registers */ 90772b676d7Smrg if(!(pSiS->UseVESA)) { 90872b676d7Smrg if(pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) 90972b676d7Smrg SiSLVDSChrontelRestore(pScrn, sisReg); 91072b676d7Smrg else if(pSiS->VBFlags2 & VB2_301) 91172b676d7Smrg SiS301Restore(pScrn, sisReg); 91272b676d7Smrg else if(pSiS->VBFlags2 & VB2_30xBLV) 91372b676d7Smrg SiS301BRestore(pScrn, sisReg); 91472b676d7Smrg } 91572b676d7Smrg 91672b676d7Smrg /* MemClock needs this to take effect */ 91772b676d7Smrg outSISIDXREG(SISSR, 0x00, 0x01); /* Synchronous Reset */ 91872b676d7Smrg outSISIDXREG(SISSR, 0x00, 0x03); /* End Reset */ 91972b676d7Smrg 92072b676d7Smrg /* Restore Mode number */ 92172b676d7Smrg SiS_GetSetModeID(pScrn,sisReg->BIOSModeSave); 92272b676d7Smrg} 92372b676d7Smrg 92472b676d7Smrgstatic void 92572b676d7SmrgSiSVBSave(ScrnInfoPtr pScrn, SISRegPtr sisReg, int p1, int p2, int p3, int p4) 92672b676d7Smrg{ 92772b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 92872b676d7Smrg int i; 92972b676d7Smrg 93072b676d7Smrg for(i=0; i<=p1; i++) { 93172b676d7Smrg inSISIDXREG(SISPART1, i, sisReg->VBPart1[i]); 93272b676d7Smrg#ifdef TWDEBUG 93372b676d7Smrg xf86DrvMsg(0, X_INFO, "301xSave: Part1 0x%02x = 0x%02x\n", i, sisReg->VBPart1[i]); 93472b676d7Smrg#endif 93572b676d7Smrg } 93672b676d7Smrg for(i=0; i<=p2; i++) { 93772b676d7Smrg inSISIDXREG(SISPART2, i, sisReg->VBPart2[i]); 93872b676d7Smrg#ifdef TWDEBUG 93972b676d7Smrg xf86DrvMsg(0, X_INFO, "301xSave: Part2 0x%02x = 0x%02x\n", i, sisReg->VBPart2[i]); 94072b676d7Smrg#endif 94172b676d7Smrg } 94272b676d7Smrg for(i=0; i<=p3; i++) { 94372b676d7Smrg inSISIDXREG(SISPART3, i, sisReg->VBPart3[i]); 94472b676d7Smrg#ifdef TWDEBUG 94572b676d7Smrg xf86DrvMsg(0, X_INFO, "301xSave: Part3 0x%02x = 0x%02x\n", i, sisReg->VBPart3[i]); 94672b676d7Smrg#endif 94772b676d7Smrg } 94872b676d7Smrg for(i=0; i<=p4; i++) { 94972b676d7Smrg inSISIDXREG(SISPART4, i, sisReg->VBPart4[i]); 95072b676d7Smrg#ifdef TWDEBUG 95172b676d7Smrg xf86DrvMsg(0, X_INFO, "301xSave: Part4 0x%02x = 0x%02x\n", i, sisReg->VBPart4[i]); 95272b676d7Smrg#endif 95372b676d7Smrg } 95472b676d7Smrg} 95572b676d7Smrg 95672b676d7Smrg/* Save SiS301 bridge register contents */ 95772b676d7Smrgstatic void 95872b676d7SmrgSiS301Save(ScrnInfoPtr pScrn, SISRegPtr sisReg) 95972b676d7Smrg{ 96072b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 96172b676d7Smrg int Part1max, Part2max, Part3max, Part4max; 96272b676d7Smrg 96372b676d7Smrg /* Highest register number to save/restore */ 96472b676d7Smrg if(pSiS->VGAEngine == SIS_300_VGA) Part1max = 0x1d; 96572b676d7Smrg else Part1max = 0x2e; /* 0x23, but we also need 2d-2e */ 96672b676d7Smrg 96772b676d7Smrg Part2max = 0x45; 96872b676d7Smrg Part3max = 0x3e; 96972b676d7Smrg Part4max = 0x1b; 97072b676d7Smrg 97172b676d7Smrg SiSVBSave(pScrn, sisReg, Part1max, Part2max, Part3max, Part4max); 97272b676d7Smrg 97372b676d7Smrg sisReg->VBPart2[0x00] &= ~0x20; /* Disable VB Processor */ 97472b676d7Smrg sisReg->sisRegs3C4[0x32] &= ~0x20; /* Disable Lock Mode */ 97572b676d7Smrg} 97672b676d7Smrg 97772b676d7Smrg/* Restore SiS301 bridge register contents */ 97872b676d7Smrgstatic void 97972b676d7SmrgSiS301Restore(ScrnInfoPtr pScrn, SISRegPtr sisReg) 98072b676d7Smrg{ 98172b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 98272b676d7Smrg int Part1max, Part2max, Part3max, Part4max; 98372b676d7Smrg 98472b676d7Smrg /* Highest register number to save/restore */ 98572b676d7Smrg if(pSiS->VGAEngine == SIS_300_VGA) Part1max = 0x1d; 98672b676d7Smrg else Part1max = 0x23; 98772b676d7Smrg 98872b676d7Smrg Part2max = 0x45; 98972b676d7Smrg Part3max = 0x3e; 99072b676d7Smrg Part4max = 0x1b; 99172b676d7Smrg 99272b676d7Smrg SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30); 99374c14cd6Smrg SiSSetLVDSetc(pSiS->SiS_Pr); 99472b676d7Smrg SiS_GetVBType(pSiS->SiS_Pr); 99572b676d7Smrg SiS_DisableBridge(pSiS->SiS_Pr); 99672b676d7Smrg SiS_UnLockCRT2(pSiS->SiS_Pr); 99772b676d7Smrg 99872b676d7Smrg /* Pre-restore Part1 */ 99972b676d7Smrg outSISIDXREG(SISPART1, 0x04, 0x00); 100072b676d7Smrg outSISIDXREG(SISPART1, 0x05, 0x00); 100172b676d7Smrg outSISIDXREG(SISPART1, 0x06, 0x00); 100272b676d7Smrg outSISIDXREG(SISPART1, 0x00, sisReg->VBPart1[0]); 100372b676d7Smrg outSISIDXREG(SISPART1, 0x01, sisReg->VBPart1[1]); 100472b676d7Smrg 100572b676d7Smrg /* Pre-restore Part4 */ 100672b676d7Smrg outSISIDXREG(SISPART4, 0x0D, sisReg->VBPart4[0x0D]); 100772b676d7Smrg outSISIDXREG(SISPART4, 0x0C, sisReg->VBPart4[0x0C]); 100872b676d7Smrg 100972b676d7Smrg if((!(sisReg->sisRegs3D4[0x30] & 0x03)) && 101072b676d7Smrg (sisReg->sisRegs3D4[0x31] & 0x20)) { /* disable CRT2 */ 101172b676d7Smrg SiS_LockCRT2(pSiS->SiS_Pr); 101272b676d7Smrg return; 101372b676d7Smrg } 101472b676d7Smrg 101572b676d7Smrg /* Restore Part1 */ 101672b676d7Smrg SetBlock(SISPART1, 0x02, Part1max, &(sisReg->VBPart1[0x02])); 101772b676d7Smrg if(pSiS->VGAEngine == SIS_315_VGA) { 101872b676d7Smrg /* Restore extra registers on 315 series */ 101972b676d7Smrg SetBlock(SISPART1, 0x2C, 0x2E, &(sisReg->VBPart1[0x2C])); 102072b676d7Smrg } 102172b676d7Smrg 102272b676d7Smrg /* Restore Part2 */ 102372b676d7Smrg SetBlock(SISPART2, 0x00, Part2max, &(sisReg->VBPart2[0x00])); 102472b676d7Smrg 102572b676d7Smrg /* Restore Part3 */ 102672b676d7Smrg SetBlock(SISPART3, 0x00, Part3max, &(sisReg->VBPart3[0x00])); 102772b676d7Smrg 102872b676d7Smrg /* Restore Part4 */ 102972b676d7Smrg SetBlock(SISPART4, 0x0E, 0x11, &(sisReg->VBPart4[0x0E])); 103072b676d7Smrg SetBlock(SISPART4, 0x13, Part4max, &(sisReg->VBPart4[0x13])); 103172b676d7Smrg 103272b676d7Smrg /* Post-restore Part4 (CRT2VCLK) */ 103372b676d7Smrg outSISIDXREG(SISPART4, 0x0A, 0x01); 103472b676d7Smrg outSISIDXREG(SISPART4, 0x0B, sisReg->VBPart4[0x0B]); 103572b676d7Smrg outSISIDXREG(SISPART4, 0x0A, sisReg->VBPart4[0x0A]); 103672b676d7Smrg outSISIDXREG(SISPART4, 0x12, 0x00); 103772b676d7Smrg outSISIDXREG(SISPART4, 0x12, sisReg->VBPart4[0x12]); 103872b676d7Smrg 103972b676d7Smrg SiS_EnableBridge(pSiS->SiS_Pr); 104072b676d7Smrg SiS_DisplayOn(pSiS->SiS_Pr); 104172b676d7Smrg SiS_LockCRT2(pSiS->SiS_Pr); 104272b676d7Smrg} 104372b676d7Smrg 104472b676d7Smrg/* Save SiS30xB/30xLV bridge register contents */ 104572b676d7Smrgstatic void 104672b676d7SmrgSiS301BSave(ScrnInfoPtr pScrn, SISRegPtr sisReg) 104772b676d7Smrg{ 104872b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 104972b676d7Smrg int Part1max, Part2max, Part3max, Part4max; 105072b676d7Smrg 105172b676d7Smrg Part1max = 0x60; 105272b676d7Smrg Part2max = 0x4d; 105372b676d7Smrg Part3max = 0x3e; 105472b676d7Smrg Part4max = 0x23; 105572b676d7Smrg if(pSiS->VBFlags2 & (VB2_301LV | VB2_302LV)) { 105672b676d7Smrg Part4max = 0x34; 105772b676d7Smrg } else if(pSiS->VBFlags2 & (VB2_301C | VB2_302ELV)) { 105872b676d7Smrg Part2max = 0xff; 105972b676d7Smrg Part4max = 0x3c; 106072b676d7Smrg } /* TODO for 307 */ 106172b676d7Smrg 106272b676d7Smrg SiSVBSave(pScrn, sisReg, Part1max, Part2max, Part3max, Part4max); 106372b676d7Smrg 106472b676d7Smrg sisReg->VBPart2[0x00] &= ~0x20; /* Disable VB Processor */ 106572b676d7Smrg sisReg->sisRegs3C4[0x32] &= ~0x20; /* Disable Lock Mode */ 106672b676d7Smrg} 106772b676d7Smrg 106872b676d7Smrg/* Restore SiS30xB/30xLV bridge register contents */ 106972b676d7Smrgstatic void 107072b676d7SmrgSiS301BRestore(ScrnInfoPtr pScrn, SISRegPtr sisReg) 107172b676d7Smrg{ 107272b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 107372b676d7Smrg int Part1max, Part2max, Part3max, Part4max; 107472b676d7Smrg 107572b676d7Smrg Part1max = 0x23; 107672b676d7Smrg Part2max = 0x4d; 107772b676d7Smrg Part3max = 0x3e; 107872b676d7Smrg Part4max = 0x22; 107972b676d7Smrg if(pSiS->VBFlags2 & (VB2_301LV|VB2_302LV)) { 108072b676d7Smrg Part4max = 0x34; 108172b676d7Smrg } else if(pSiS->VBFlags2 & (VB2_301C|VB2_302ELV)) { 108272b676d7Smrg Part2max = 0xff; 108372b676d7Smrg Part4max = 0x3c; 108472b676d7Smrg } /* TODO for 307 */ 108572b676d7Smrg 108672b676d7Smrg SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30); 108774c14cd6Smrg SiSSetLVDSetc(pSiS->SiS_Pr); 108872b676d7Smrg SiS_GetVBType(pSiS->SiS_Pr); 108972b676d7Smrg SiS_DisableBridge(pSiS->SiS_Pr); 109072b676d7Smrg SiS_UnLockCRT2(pSiS->SiS_Pr); 109172b676d7Smrg 109272b676d7Smrg /* Pre-restore Part1 */ 109372b676d7Smrg outSISIDXREG(SISPART1, 0x04, 0x00); 109472b676d7Smrg outSISIDXREG(SISPART1, 0x05, 0x00); 109572b676d7Smrg outSISIDXREG(SISPART1, 0x06, 0x00); 109672b676d7Smrg outSISIDXREG(SISPART1, 0x00, sisReg->VBPart1[0x00]); 109772b676d7Smrg outSISIDXREG(SISPART1, 0x01, sisReg->VBPart1[0x01]); 109872b676d7Smrg /* Mode reg 0x01 became 0x2e on 315 series (0x01 still contains FIFO) */ 109972b676d7Smrg if(pSiS->VGAEngine == SIS_315_VGA) { 110072b676d7Smrg outSISIDXREG(SISPART1, 0x2e, sisReg->VBPart1[0x2e]); 110172b676d7Smrg } 110272b676d7Smrg 110372b676d7Smrg /* Pre-restore Part4 */ 110472b676d7Smrg outSISIDXREG(SISPART4, 0x0D, sisReg->VBPart4[0x0D]); 110572b676d7Smrg outSISIDXREG(SISPART4, 0x0C, sisReg->VBPart4[0x0C]); 110672b676d7Smrg 110772b676d7Smrg if((!(sisReg->sisRegs3D4[0x30] & 0x03)) && 110872b676d7Smrg (sisReg->sisRegs3D4[0x31] & 0x20)) { /* disable CRT2 */ 110972b676d7Smrg SiS_LockCRT2(pSiS->SiS_Pr); 111072b676d7Smrg return; 111172b676d7Smrg } 111272b676d7Smrg 111372b676d7Smrg /* Restore Part1 */ 111472b676d7Smrg SetBlock(SISPART1, 0x02, Part1max, &(sisReg->VBPart1[0x02])); 111572b676d7Smrg if(pSiS->VGAEngine == SIS_315_VGA) { 111672b676d7Smrg SetBlock(SISPART1, 0x2C, 0x2D, &(sisReg->VBPart1[0x2C])); 111772b676d7Smrg SetBlock(SISPART1, 0x35, 0x37, &(sisReg->VBPart1[0x35])); 111872b676d7Smrg if((pSiS->ChipFlags & SiSCF_Is65x) || (pSiS->ChipType >= SIS_661)) { 111972b676d7Smrg outSISIDXREG(SISPART1, 0x4c, sisReg->VBPart1[0x4c]); 112072b676d7Smrg } 112172b676d7Smrg outSISIDXREG(SISPART1, 0x2e, sisReg->VBPart1[0x2e] & 0x7f); 112272b676d7Smrg } 112372b676d7Smrg 112472b676d7Smrg /* Restore Part2 */ 112572b676d7Smrg SetBlock(SISPART2, 0x00, Part2max, &(sisReg->VBPart2[0x00])); 112672b676d7Smrg 112772b676d7Smrg /* Restore Part3 */ 112872b676d7Smrg SetBlock(SISPART3, 0x00, Part3max, &(sisReg->VBPart3[0x00])); 112972b676d7Smrg 113072b676d7Smrg /* Restore Part4 */ 113172b676d7Smrg SetBlock(SISPART4, 0x0E, 0x11, &(sisReg->VBPart4[0x0E])); 113272b676d7Smrg SetBlock(SISPART4, 0x13, Part4max, &(sisReg->VBPart4[0x13])); 113372b676d7Smrg 113472b676d7Smrg /* Post-restore Part4 (CRT2VCLK) */ 113572b676d7Smrg outSISIDXREG(SISPART4, 0x0A, sisReg->VBPart4[0x0A]); 113672b676d7Smrg outSISIDXREG(SISPART4, 0x0B, sisReg->VBPart4[0x0B]); 113772b676d7Smrg outSISIDXREG(SISPART4, 0x12, 0x00); 113872b676d7Smrg outSISIDXREG(SISPART4, 0x12, sisReg->VBPart4[0x12]); 113972b676d7Smrg 114072b676d7Smrg SiS_EnableBridge(pSiS->SiS_Pr); 114172b676d7Smrg SiS_DisplayOn(pSiS->SiS_Pr); 114272b676d7Smrg SiS_LockCRT2(pSiS->SiS_Pr); 114372b676d7Smrg} 114472b676d7Smrg 114572b676d7Smrg/* Save LVDS bridge (+ Chrontel) register contents */ 114672b676d7Smrgstatic void 114772b676d7SmrgSiSLVDSChrontelSave(ScrnInfoPtr pScrn, SISRegPtr sisReg) 114872b676d7Smrg{ 114972b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 115072b676d7Smrg int i; 115172b676d7Smrg 115272b676d7Smrg /* Save Part1 */ 115372b676d7Smrg for(i=0; i<0x46; i++) { 115472b676d7Smrg inSISIDXREG(SISPART1, i, sisReg->VBPart1[i]); 115572b676d7Smrg#ifdef TWDEBUG 115672b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 115772b676d7Smrg "LVDSSave: Part1Port 0x%02x = 0x%02x\n", 115872b676d7Smrg i, sisReg->VBPart1[i]); 115972b676d7Smrg#endif 116072b676d7Smrg } 116172b676d7Smrg 116272b676d7Smrg /* Save Chrontel registers */ 116372b676d7Smrg if(pSiS->VBFlags2 & VB2_CHRONTEL) { 116472b676d7Smrg if(pSiS->ChrontelType == CHRONTEL_700x) { 116572b676d7Smrg for(i=0; i<0x1D; i++) { 116672b676d7Smrg sisReg->ch70xx[i] = SiS_GetCH700x(pSiS->SiS_Pr, ch700xidx[i]); 116772b676d7Smrg#ifdef TWDEBUG 116872b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 116972b676d7Smrg "LVDSSave: Chrontel 0x%02x = 0x%02x\n", 117072b676d7Smrg ch700xidx[i], sisReg->ch70xx[i]); 117172b676d7Smrg#endif 117272b676d7Smrg } 117372b676d7Smrg } else { 117472b676d7Smrg for(i=0; i<35; i++) { 117572b676d7Smrg sisReg->ch70xx[i] = SiS_GetCH701x(pSiS->SiS_Pr, ch701xidx[i]); 117672b676d7Smrg#ifdef TWDEBUG 117772b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 117872b676d7Smrg "LVDSSave: Chrontel 0x%02x = 0x%02x\n", 117972b676d7Smrg ch701xidx[i], sisReg->ch70xx[i]); 118072b676d7Smrg#endif 118172b676d7Smrg } 118272b676d7Smrg } 118372b676d7Smrg } 118472b676d7Smrg 118572b676d7Smrg sisReg->sisRegs3C4[0x32] &= ~0x20; /* Disable Lock Mode */ 118672b676d7Smrg} 118772b676d7Smrg 118872b676d7Smrg/* Restore LVDS bridge (+ Chrontel) register contents */ 118972b676d7Smrgstatic void 119072b676d7SmrgSiSLVDSChrontelRestore(ScrnInfoPtr pScrn, SISRegPtr sisReg) 119172b676d7Smrg{ 119272b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 119372b676d7Smrg int i; 119472b676d7Smrg 119572b676d7Smrg SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30); 119674c14cd6Smrg SiSSetLVDSetc(pSiS->SiS_Pr); 119772b676d7Smrg SiS_GetVBType(pSiS->SiS_Pr); 119872b676d7Smrg SiS_DisableBridge(pSiS->SiS_Pr); 119972b676d7Smrg if(pSiS->ChipType == SIS_730) { 120072b676d7Smrg outSISIDXREG(SISPART1, 0x00, 0x80); 120172b676d7Smrg } 120272b676d7Smrg SiS_UnLockCRT2(pSiS->SiS_Pr); 120372b676d7Smrg 120472b676d7Smrg if(pSiS->VBFlags2 & VB2_CHRONTEL) { 120572b676d7Smrg /* Restore Chrontel registers */ 120672b676d7Smrg if(pSiS->ChrontelType == CHRONTEL_700x) { 120772b676d7Smrg for(i=0; i<0x11; i++) { 120872b676d7Smrg SiS_SetCH700x(pSiS->SiS_Pr, ch700xidx[i] & 0xFF, sisReg->ch70xx[i]); 120972b676d7Smrg } 121072b676d7Smrg } else { 121172b676d7Smrg for(i=0; i<34; i++) { 121272b676d7Smrg SiS_SetCH701x(pSiS->SiS_Pr, ch701xidx[i] & 0xFF, sisReg->ch70xx[i]); 121372b676d7Smrg } 121472b676d7Smrg } 121572b676d7Smrg } 121672b676d7Smrg 121772b676d7Smrg /* pre-restore Part1 */ 121872b676d7Smrg outSISIDXREG(SISPART1, 0x04, 0x00); 121972b676d7Smrg outSISIDXREG(SISPART1, 0x05, 0x00); 122072b676d7Smrg outSISIDXREG(SISPART1, 0x06, 0x00); 122172b676d7Smrg outSISIDXREG(SISPART1, 0x00, sisReg->VBPart1[0]); 122272b676d7Smrg if(pSiS->VGAEngine == SIS_300_VGA) { 122372b676d7Smrg outSISIDXREG(SISPART1, 0x01, (sisReg->VBPart1[1] | 0x80)); 122472b676d7Smrg } else { 122572b676d7Smrg outSISIDXREG(SISPART1, 0x01, sisReg->VBPart1[1]); 122672b676d7Smrg } 122772b676d7Smrg 122872b676d7Smrg if((!(sisReg->sisRegs3D4[0x30] & 0x03)) && 122972b676d7Smrg (sisReg->sisRegs3D4[0x31] & 0x20)) { /* disable CRT2 */ 123072b676d7Smrg SiS_LockCRT2(pSiS->SiS_Pr); 123172b676d7Smrg return; 123272b676d7Smrg } 123372b676d7Smrg 123472b676d7Smrg /* Restore Part1 */ 123572b676d7Smrg if(pSiS->VGAEngine == SIS_300_VGA) { 123672b676d7Smrg outSISIDXREG(SISPART1, 0x02, (sisReg->VBPart1[2] | 0x40)); 123772b676d7Smrg } else { 123872b676d7Smrg outSISIDXREG(SISPART1, 0x02, sisReg->VBPart1[2]); 123972b676d7Smrg } 124072b676d7Smrg SetBlock(SISPART1, 0x03, 0x23, &(sisReg->VBPart1[0x03])); 124172b676d7Smrg if(pSiS->VGAEngine == SIS_315_VGA) { 124272b676d7Smrg SetBlock(SISPART1, 0x2C, 0x2E, &(sisReg->VBPart1[0x2C])); 124372b676d7Smrg SetBlock(SISPART1, 0x35, 0x37, &(sisReg->VBPart1[0x35])); /* Panel Link Scaler */ 124472b676d7Smrg } 124572b676d7Smrg 124672b676d7Smrg /* For 550 DSTN registers */ 124772b676d7Smrg if(pSiS->DSTN || pSiS->FSTN) { 124872b676d7Smrg SetBlock(SISPART1, 0x25, 0x2E, &(sisReg->VBPart1[0x25])); 124972b676d7Smrg SetBlock(SISPART1, 0x30, 0x45, &(sisReg->VBPart1[0x30])); 125072b676d7Smrg } 125172b676d7Smrg 125272b676d7Smrg SiS_EnableBridge(pSiS->SiS_Pr); 125372b676d7Smrg SiS_DisplayOn(pSiS->SiS_Pr); 125472b676d7Smrg SiS_LockCRT2(pSiS->SiS_Pr); 125572b676d7Smrg} 125672b676d7Smrg 125772b676d7Smrg/* Restore output selection registers */ 125872b676d7Smrgvoid 125972b676d7SmrgSiSRestoreBridge(ScrnInfoPtr pScrn, SISRegPtr sisReg) 126072b676d7Smrg{ 126172b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 126272b676d7Smrg int i; 126372b676d7Smrg 126472b676d7Smrg#ifdef UNLOCK_ALWAYS 126572b676d7Smrg sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); 126672b676d7Smrg#endif 126772b676d7Smrg 126872b676d7Smrg for(i = 0x30; i <= 0x3b; i++) { 126972b676d7Smrg if(i == 0x34) continue; 127072b676d7Smrg outSISIDXREG(SISCR, i, sisReg->sisRegs3D4[i]); 127172b676d7Smrg } 127272b676d7Smrg 127372b676d7Smrg if(pSiS->VGAEngine == SIS_315_VGA) { 127472b676d7Smrg outSISIDXREG(SISCR, pSiS->myCR63, sisReg->sisRegs3D4[pSiS->myCR63]); 127572b676d7Smrg if(pSiS->ChipType < SIS_661) { 127672b676d7Smrg outSISIDXREG(SISCR, 0x79, sisReg->sisRegs3D4[0x79]); 127772b676d7Smrg } 127872b676d7Smrg } 127972b676d7Smrg} 128072b676d7Smrg 128172b676d7Smrg/* Auxiliary function to find real memory clock (in Khz) */ 128272b676d7Smrg/* Not for 530/620 if UMA (on these, the mclk is stored in SR10) */ 128372b676d7Smrgint 128472b676d7SmrgSiSMclk(SISPtr pSiS) 128572b676d7Smrg{ 128672b676d7Smrg int mclk=0; 128772b676d7Smrg UChar Num, Denum, Base; 128872b676d7Smrg 128972b676d7Smrg switch (pSiS->Chipset) { 129072b676d7Smrg 129172b676d7Smrg case PCI_CHIP_SIS300: 129272b676d7Smrg case PCI_CHIP_SIS540: 129372b676d7Smrg case PCI_CHIP_SIS630: 129472b676d7Smrg case PCI_CHIP_SIS315: 129572b676d7Smrg case PCI_CHIP_SIS315H: 129672b676d7Smrg case PCI_CHIP_SIS315PRO: 129772b676d7Smrg case PCI_CHIP_SIS550: 129872b676d7Smrg case PCI_CHIP_SIS650: 129972b676d7Smrg case PCI_CHIP_SIS330: 130072b676d7Smrg case PCI_CHIP_SIS660: 130172b676d7Smrg case PCI_CHIP_SIS340: 130272b676d7Smrg case PCI_CHIP_XGIXG20: 130372b676d7Smrg case PCI_CHIP_XGIXG40: 130472b676d7Smrg 130572b676d7Smrg /* Numerator */ 130672b676d7Smrg inSISIDXREG(SISSR, 0x28, Num); 130772b676d7Smrg mclk = 14318 * ((Num & 0x7f) + 1); 130872b676d7Smrg 130972b676d7Smrg /* Denumerator */ 131072b676d7Smrg inSISIDXREG(SISSR, 0x29, Denum); 131172b676d7Smrg mclk = mclk / ((Denum & 0x1f) + 1); 131272b676d7Smrg 131372b676d7Smrg /* Divider */ 131472b676d7Smrg if((Num & 0x80) != 0) mclk *= 2; 131572b676d7Smrg 131672b676d7Smrg /* Post-Scaler */ 131772b676d7Smrg if((Denum & 0x80) == 0) { 131872b676d7Smrg mclk = mclk / (((Denum & 0x60) >> 5) + 1); 131972b676d7Smrg } else { 132072b676d7Smrg mclk = mclk / ((((Denum & 0x60) >> 5) + 1) * 2); 132172b676d7Smrg } 132272b676d7Smrg break; 132372b676d7Smrg 132472b676d7Smrg case PCI_CHIP_SIS5597: 132572b676d7Smrg case PCI_CHIP_SIS6326: 132672b676d7Smrg case PCI_CHIP_SIS530: 132772b676d7Smrg default: 132872b676d7Smrg /* Numerator */ 132972b676d7Smrg inSISIDXREG(SISSR, 0x28, Num); 133072b676d7Smrg mclk = 14318 * ((Num & 0x7f) + 1); 133172b676d7Smrg 133272b676d7Smrg /* Denumerator */ 133372b676d7Smrg inSISIDXREG(SISSR, 0x29, Denum); 133472b676d7Smrg mclk = mclk / ((Denum & 0x1f) + 1); 133572b676d7Smrg 133672b676d7Smrg /* Divider. Doesn't work on older cards */ 133772b676d7Smrg if(pSiS->oldChipset >= OC_SIS5597) { 133872b676d7Smrg if(Num & 0x80) mclk *= 2; 133972b676d7Smrg } 134072b676d7Smrg 134172b676d7Smrg /* Post-scaler. Values' meaning depends on SR13 bit 7 */ 134272b676d7Smrg inSISIDXREG(SISSR, 0x13, Base); 134372b676d7Smrg if((Base & 0x80) == 0) { 134472b676d7Smrg mclk = mclk / (((Denum & 0x60) >> 5) + 1); 134572b676d7Smrg } else { 134672b676d7Smrg /* Values 00 and 01 are reserved */ 134772b676d7Smrg if ((Denum & 0x60) == 0x40) mclk /= 6; 134872b676d7Smrg if ((Denum & 0x60) == 0x60) mclk /= 8; 134972b676d7Smrg } 135072b676d7Smrg break; 135172b676d7Smrg } 135272b676d7Smrg 135372b676d7Smrg return(mclk); 135472b676d7Smrg} 135572b676d7Smrg 135672b676d7Smrg/* This estimates the CRT2 clock we are going to use. 135772b676d7Smrg * The total bandwidth is to be reduced by the value 135872b676d7Smrg * returned here in order to get an idea of the maximum 135972b676d7Smrg * dotclock left for CRT1. 136072b676d7Smrg * Since we don't know yet, what mode the user chose, 136172b676d7Smrg * we return the maximum dotclock used by 136272b676d7Smrg * - either the LCD attached, or 136372b676d7Smrg * - TV 136472b676d7Smrg * For VGA2, we share the bandwith equally. 136572b676d7Smrg */ 136672b676d7Smrgstatic int 136772b676d7SmrgSiSEstimateCRT2Clock(ScrnInfoPtr pScrn, Bool FakeForCRT2) 136872b676d7Smrg{ 136972b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 137072b676d7Smrg 137172b676d7Smrg if(pSiS->VBFlags & CRT2_LCD) { 137272b676d7Smrg if(pSiS->VBLCDFlags & (VB_LCD_320x480 | VB_LCD_800x600 | VB_LCD_640x480)) { 137372b676d7Smrg return 40000; 137472b676d7Smrg } else if(pSiS->VBLCDFlags & (VB_LCD_1024x768 | VB_LCD_1024x600 | VB_LCD_1152x768)) { 137572b676d7Smrg return 65000; 137672b676d7Smrg } else if(pSiS->VBLCDFlags & VB_LCD_1280x720) { 137772b676d7Smrg /* Fake clock; VGA (4:3) mode is 108, but uses only 75 for LCD */ 137872b676d7Smrg if(FakeForCRT2) return 108000; 137972b676d7Smrg else return 75000; 138072b676d7Smrg } else if(pSiS->VBLCDFlags & VB_LCD_1280x768) { 138172b676d7Smrg /* Fake clock; VGA (4:3) mode is 108, but uses only 81 for LCD */ 138272b676d7Smrg if(FakeForCRT2) return 108000; 138372b676d7Smrg else return 81000; 138472b676d7Smrg } else if(pSiS->VBLCDFlags & VB_LCD_1280x800) { 138572b676d7Smrg /* Fake clock; VGA (4:3) mode is 108, but uses only 83 for LCD */ 138672b676d7Smrg if(FakeForCRT2) return 108000; 138772b676d7Smrg else return 83000; 138872b676d7Smrg } else if(pSiS->VBLCDFlags & VB_LCD_1280x854) { 138972b676d7Smrg /* Fake clock; VGA (4:3) mode is 108, but uses only 84 for LCD */ 139072b676d7Smrg if(FakeForCRT2) return 108000; 139172b676d7Smrg else return 84000; 139272b676d7Smrg } else if(pSiS->VBLCDFlags & (VB_LCD_1280x1024 | VB_LCD_1280x960)) { 139372b676d7Smrg return 108000; 139472b676d7Smrg } else if(pSiS->VBLCDFlags & VB_LCD_1400x1050) { 139572b676d7Smrg /* Fake clock; VGA mode is 122, but uses only 108 for LCD */ 139672b676d7Smrg if(FakeForCRT2) return 123000; 139772b676d7Smrg else return 108000; 139872b676d7Smrg } else if(pSiS->VBLCDFlags & VB_LCD_1680x1050) { 139972b676d7Smrg /* Fake clock; VGA mode is 147, but uses only 122 for LCD */ 140072b676d7Smrg if(FakeForCRT2) return 148000; 140172b676d7Smrg else return 122000; 140272b676d7Smrg } else if(pSiS->VBLCDFlags & VB_LCD_1600x1200) { 140372b676d7Smrg return 162000; 140472b676d7Smrg } else if((pSiS->VBLCDFlags & VB_LCD_CUSTOM) && (pSiS->SiS_Pr->CP_MaxClock)) { 140572b676d7Smrg return pSiS->SiS_Pr->CP_MaxClock; 140672b676d7Smrg } else { 140772b676d7Smrg if(pSiS->VBFlags2 & VB2_30xC) return 162000; 140872b676d7Smrg else return 108000; 140972b676d7Smrg } 141072b676d7Smrg } else if(pSiS->VBFlags & CRT2_TV) { 141172b676d7Smrg if(pSiS->VBFlags2 & VB2_CHRONTEL) { 141272b676d7Smrg switch(pSiS->VGAEngine) { 141372b676d7Smrg case SIS_300_VGA: 141472b676d7Smrg return 50000; /* 700x: <= 800x600 */ 141572b676d7Smrg case SIS_315_VGA: 141672b676d7Smrg default: 141772b676d7Smrg return 70000; /* 701x: <= 1024x768 */ 141872b676d7Smrg } 141972b676d7Smrg } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) { 142072b676d7Smrg if(pSiS->SiS_SD_Flags & (SiS_SD_SUPPORTYPBPR|SiS_SD_SUPPORTHIVISION)) { 142172b676d7Smrg if(FakeForCRT2) return 108000; /* 1280x1024@60 (faked) */ 142272b676d7Smrg else return 75000; /* Really used clock */ 142372b676d7Smrg } else { 142472b676d7Smrg return 70000; 142572b676d7Smrg } 142672b676d7Smrg } 142772b676d7Smrg } 142872b676d7Smrg 142972b676d7Smrg return 0; 143072b676d7Smrg} 143172b676d7Smrg 143272b676d7Smrg/* Calculate the maximum dotclock */ 143372b676d7Smrgint SiSMemBandWidth(ScrnInfoPtr pScrn, Bool IsForCRT2) 143472b676d7Smrg{ 143572b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 143672b676d7Smrg#ifdef SISDUALHEAD 143772b676d7Smrg SISEntPtr pSiSEnt = pSiS->entityPrivate; 143872b676d7Smrg#endif 143972b676d7Smrg int bus = pSiS->BusWidth; 144072b676d7Smrg int mclk = pSiS->MemClock; 144172b676d7Smrg int bpp = pSiS->CurrentLayout.bitsPerPixel; 144272b676d7Smrg int max = 0; 144372b676d7Smrg float magic = 0.0, total; 144472b676d7Smrg int bytesperpixel = (bpp + 7) / 8; 144572b676d7Smrg float crt2used, maxcrt2; 144672b676d7Smrg int crt2clock; 144772b676d7Smrg Bool DHM, GetForCRT1; 144872b676d7Smrg#ifdef __SUNPRO_C 144972b676d7Smrg#define const 145072b676d7Smrg#endif 145172b676d7Smrg const float magicDED[4] = { 1.2, 1.368421, 2.263158, 1.2}; 145272b676d7Smrg const float magicINT[4] = { 1.441177, 1.441177, 2.588235, 1.441177 }; 145372b676d7Smrg#ifdef __SUNPRO_C 145472b676d7Smrg#undef const 145572b676d7Smrg#endif 145672b676d7Smrg 145772b676d7Smrg switch(pSiS->Chipset) { 145872b676d7Smrg 145972b676d7Smrg case PCI_CHIP_SIS5597: 146072b676d7Smrg total = ((mclk * (bus / 8)) * 0.7) / bytesperpixel; 146172b676d7Smrg if(total > 135000) total = 135000; 146272b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 146372b676d7Smrg "Maximum pixel clock at %d bpp is %g MHz\n", 146472b676d7Smrg bpp, total/1000); 146572b676d7Smrg return(int)(total); 146672b676d7Smrg 146772b676d7Smrg case PCI_CHIP_SIS6326: 146872b676d7Smrg total = ((mclk * (bus / 8)) * 0.7) / bytesperpixel; 146972b676d7Smrg if(total > 175500) total = 175500; 147072b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 147172b676d7Smrg "Maximum pixel clock at %d bpp is %g MHz\n", 147272b676d7Smrg bpp, total/1000); 147372b676d7Smrg return(int)(total); 147472b676d7Smrg 147572b676d7Smrg case PCI_CHIP_SIS530: 147672b676d7Smrg total = ((mclk * (bus / 8)) * 0.7) / bytesperpixel; 147772b676d7Smrg if(total > 230000) total = 230000; 147872b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 147972b676d7Smrg "Maximum pixel clock at %d bpp is %g MHz\n", 148072b676d7Smrg bpp, total/1000); 148172b676d7Smrg return(int)(total); 148272b676d7Smrg 148372b676d7Smrg case PCI_CHIP_SIS300: 148472b676d7Smrg case PCI_CHIP_SIS540: 148572b676d7Smrg case PCI_CHIP_SIS630: 148672b676d7Smrg case PCI_CHIP_SIS315: 148772b676d7Smrg case PCI_CHIP_SIS315H: 148872b676d7Smrg case PCI_CHIP_SIS315PRO: 148972b676d7Smrg case PCI_CHIP_SIS550: 149072b676d7Smrg case PCI_CHIP_SIS650: 149172b676d7Smrg case PCI_CHIP_SIS330: 149272b676d7Smrg case PCI_CHIP_SIS660: 149372b676d7Smrg case PCI_CHIP_SIS340: 149472b676d7Smrg case PCI_CHIP_XGIXG20: 149572b676d7Smrg case PCI_CHIP_XGIXG40: 149672b676d7Smrg switch(pSiS->Chipset) { 149772b676d7Smrg case PCI_CHIP_SIS300: 149872b676d7Smrg magic = magicDED[bus/64]; 149972b676d7Smrg max = 540000; 150072b676d7Smrg break; 150172b676d7Smrg case PCI_CHIP_SIS540: 150272b676d7Smrg case PCI_CHIP_SIS630: 150372b676d7Smrg magic = magicINT[bus/64]; 150472b676d7Smrg max = 540000; 150572b676d7Smrg break; 150672b676d7Smrg case PCI_CHIP_SIS315: 150772b676d7Smrg case PCI_CHIP_SIS315H: 150872b676d7Smrg case PCI_CHIP_SIS315PRO: 150972b676d7Smrg case PCI_CHIP_SIS330: 151072b676d7Smrg magic = magicDED[bus/64]; 151172b676d7Smrg max = 780000; 151272b676d7Smrg break; 151372b676d7Smrg case PCI_CHIP_SIS550: 151472b676d7Smrg magic = magicINT[bus/64]; 151572b676d7Smrg max = 610000; 151672b676d7Smrg break; 151772b676d7Smrg case PCI_CHIP_SIS650: 151872b676d7Smrg magic = magicINT[bus/64]; 151972b676d7Smrg max = 680000; 152072b676d7Smrg break; 152172b676d7Smrg case PCI_CHIP_SIS660: 152272b676d7Smrg if((pSiS->ChipType >= SIS_660) && 152372b676d7Smrg (pSiS->ChipFlags & SiSCF_760LFB)) { 152472b676d7Smrg magic = magicDED[bus/64]; 152572b676d7Smrg } else { 152672b676d7Smrg magic = magicINT[bus/64]; 152772b676d7Smrg } 152872b676d7Smrg max = 680000; 152972b676d7Smrg case PCI_CHIP_SIS340: 153072b676d7Smrg case PCI_CHIP_XGIXG40: 153172b676d7Smrg magic = magicDED[bus/64]; 153272b676d7Smrg max = 800000; 153372b676d7Smrg break; 153472b676d7Smrg case PCI_CHIP_XGIXG20: 153572b676d7Smrg magic = 1.0; /* magicDED[bus/64]; */ 153672b676d7Smrg max = 332000; 153772b676d7Smrg break; 153872b676d7Smrg } 153972b676d7Smrg 154072b676d7Smrg PDEBUG(ErrorF("mclk: %d, bus: %d, magic: %g, bpp: %d\n", 154172b676d7Smrg mclk, bus, magic, bpp)); 154272b676d7Smrg 154372b676d7Smrg total = mclk * bus / bpp; 154472b676d7Smrg 154572b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 154672b676d7Smrg "Memory bandwidth at %d bpp is %g MHz\n", bpp, total/1000); 154772b676d7Smrg 154872b676d7Smrg if((pSiS->VBFlags & CRT2_ENABLE) && (!pSiS->CRT1off)) { 154972b676d7Smrg 155072b676d7Smrg maxcrt2 = 135000; 155172b676d7Smrg if(pSiS->VBFlags2 & (VB2_301B|VB2_302B)) maxcrt2 = 162000; 155272b676d7Smrg else if(pSiS->VBFlags2 & VB2_301C) maxcrt2 = 203000; 155372b676d7Smrg else if(pSiS->VBFlags2 & VB2_307T) maxcrt2 = 203000; /* TODO */ 155472b676d7Smrg /* if(pSiS->VBFlags2 & VB2_30xBDH) maxcrt2 = 100000; 155572b676d7Smrg Ignore 301B-DH here; seems the current version is like 155672b676d7Smrg 301B anyway */ 155772b676d7Smrg 155872b676d7Smrg crt2used = 0.0; 155972b676d7Smrg crt2clock = SiSEstimateCRT2Clock(pScrn, IsForCRT2); 156072b676d7Smrg if(crt2clock) { 156172b676d7Smrg crt2used = crt2clock + 2000; 156272b676d7Smrg } 156372b676d7Smrg DHM = FALSE; 156472b676d7Smrg GetForCRT1 = FALSE; 156572b676d7Smrg 156672b676d7Smrg#ifdef SISDUALHEAD 156772b676d7Smrg if((pSiS->DualHeadMode) && (pSiSEnt)) { 156872b676d7Smrg DHM = TRUE; 156972b676d7Smrg if(pSiS->SecondHead) GetForCRT1 = TRUE; 157072b676d7Smrg } 157172b676d7Smrg#endif 157272b676d7Smrg#ifdef SISMERGED 157372b676d7Smrg if(pSiS->MergedFB && IsForCRT2) { 157472b676d7Smrg DHM = TRUE; 157572b676d7Smrg GetForCRT1 = FALSE; 157672b676d7Smrg } 157772b676d7Smrg#endif 157872b676d7Smrg 157972b676d7Smrg if(DHM) { 158072b676d7Smrg 158172b676d7Smrg if(!GetForCRT1) { 158272b676d7Smrg 158372b676d7Smrg /* First head = CRT2 */ 158472b676d7Smrg 158572b676d7Smrg if(crt2clock) { 158672b676d7Smrg /* We use the mem bandwidth as max clock; this 158772b676d7Smrg * might exceed the 70% limit a bit, but that 158872b676d7Smrg * does not matter; we take care of that limit 158972b676d7Smrg * when we calc CRT1. Overall, we might use up 159072b676d7Smrg * to 85% of the memory bandwidth, which seems 159172b676d7Smrg * enough to use accel and video. 159272b676d7Smrg * The "* macic" is just to compensate the 159372b676d7Smrg * calculation below. 159472b676d7Smrg */ 159572b676d7Smrg total = crt2used * magic; 159672b676d7Smrg 159772b676d7Smrg } else { 159872b676d7Smrg /* We don't know about the second head's 159972b676d7Smrg * depth yet. So we assume it uses the 160072b676d7Smrg * same. But since the maximum dotclock 160172b676d7Smrg * is limited on CRT2, we can assume a 160272b676d7Smrg * maximum here. 160372b676d7Smrg */ 160472b676d7Smrg if((total / 2) > (maxcrt2 + 2000)) { 160572b676d7Smrg total = (maxcrt2 + 2000) * magic; 160672b676d7Smrg crt2used = maxcrt2 + 2000; 160772b676d7Smrg } else { 160872b676d7Smrg total /= 2; 160972b676d7Smrg crt2used = total; 161072b676d7Smrg } 161172b676d7Smrg 161272b676d7Smrg } 161372b676d7Smrg 161472b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 161572b676d7Smrg "Bandwidth reserved for CRT2 is %g MHz\n", 161672b676d7Smrg crt2used/1000); 161772b676d7Smrg 161872b676d7Smrg } else { 161972b676d7Smrg#ifdef SISDUALHEAD 162072b676d7Smrg /* Second head = CRT1 */ 162172b676d7Smrg 162272b676d7Smrg /* Now We know about the first head's depth, 162372b676d7Smrg * so we can calculate more accurately. 162472b676d7Smrg */ 162572b676d7Smrg 162672b676d7Smrg if(crt2clock) { 162772b676d7Smrg total -= (crt2used * pSiSEnt->pScrn_1->bitsPerPixel / bpp); 162872b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 162972b676d7Smrg "Bandwidth reserved for CRT2 at %d bpp is %g Mhz\n", 163072b676d7Smrg bpp, 163172b676d7Smrg (crt2used * pSiSEnt->pScrn_1->bitsPerPixel / bpp)/1000); 163272b676d7Smrg } else { 163372b676d7Smrg total -= (pSiSEnt->maxUsedClock * pSiSEnt->pScrn_1->bitsPerPixel / bpp); 163472b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 163572b676d7Smrg "Bandwidth reserved for CRT2 at %d bpp is %d Mhz\n", 163672b676d7Smrg bpp, 163772b676d7Smrg (pSiSEnt->maxUsedClock * pSiSEnt->pScrn_1->bitsPerPixel / bpp)/1000); 163872b676d7Smrg } 163972b676d7Smrg 164072b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 164172b676d7Smrg "Bandwidth available for CRT1 is %g MHz\n", total/1000); 164272b676d7Smrg#endif 164372b676d7Smrg } 164472b676d7Smrg 164572b676d7Smrg } else { 164672b676d7Smrg 164772b676d7Smrg if(crt2clock) { 164872b676d7Smrg total -= crt2used; 164972b676d7Smrg } else { 165072b676d7Smrg if((total / 2) > (maxcrt2 + 2000)) { 165172b676d7Smrg total -= (maxcrt2 + 2000); 165272b676d7Smrg crt2used = maxcrt2 + 2000; 165372b676d7Smrg } else { 165472b676d7Smrg total /= 2; 165572b676d7Smrg crt2used = total; 165672b676d7Smrg } 165772b676d7Smrg } 165872b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 165972b676d7Smrg "Bandwidth reserved for CRT2 is %g Mhz\n", crt2used/1000); 166072b676d7Smrg 166172b676d7Smrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 166272b676d7Smrg "Bandwidth available for CRT1 is %g MHz\n", total/1000); 166372b676d7Smrg 166472b676d7Smrg } 166572b676d7Smrg 166672b676d7Smrg } 166772b676d7Smrg 166872b676d7Smrg total /= magic; 166972b676d7Smrg if(total > (max / 2)) total = max / 2; 167072b676d7Smrg return(int)(total); 167172b676d7Smrg 167272b676d7Smrg default: 167372b676d7Smrg return(135000); 167472b676d7Smrg } 167572b676d7Smrg} 167672b676d7Smrg 167772b676d7Smrg/* Load the palette. We do this for all supported color depths 167872b676d7Smrg * in order to support gamma correction. We hereby convert the 167972b676d7Smrg * given colormap to a complete 24bit color palette and enable 168072b676d7Smrg * the correspoding bit in SR7 to enable the 24bit lookup table. 168172b676d7Smrg * Gamma correction for CRT2 is only supported on SiS video bridges. 168272b676d7Smrg * There are there 6-bit-RGB values submitted even if bpp is 16 and 168372b676d7Smrg * weight is 565, because SetWeight() sets rgbBits to the maximum 168472b676d7Smrg * (which is 6 in the 565 case). 168572b676d7Smrg */ 168672b676d7Smrgvoid 168772b676d7SmrgSISLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, 168872b676d7Smrg VisualPtr pVisual) 168972b676d7Smrg{ 169072b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 169172b676d7Smrg int i, j, index; 169272b676d7Smrg int myshift = 8 - pScrn->rgbBits; 169372b676d7Smrg UChar backup = 0; 169472b676d7Smrg Bool dogamma1 = pSiS->CRT1gamma; 169572b676d7Smrg Bool resetxvgamma = FALSE; 169672b676d7Smrg#ifdef SISDUALHEAD 169772b676d7Smrg SISEntPtr pSiSEnt = pSiS->entityPrivate; 169872b676d7Smrg 169972b676d7Smrg if(pSiS->DualHeadMode) dogamma1 = pSiSEnt->CRT1gamma; 170072b676d7Smrg#endif 170172b676d7Smrg 170272b676d7Smrg PDEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LoadPalette()\n")); 170372b676d7Smrg 170472b676d7Smrg#ifdef SISDUALHEAD 170572b676d7Smrg if((!pSiS->DualHeadMode) || (pSiS->SecondHead)) { 170672b676d7Smrg#endif 170772b676d7Smrg 170872b676d7Smrg if(pSiS->VGAEngine == SIS_315_VGA) { 170972b676d7Smrg inSISIDXREG(SISSR, 0x1f, backup); 171072b676d7Smrg andSISIDXREG(SISSR, 0x1f, 0xe7); 171172b676d7Smrg if( (pSiS->XvGamma) && 171272b676d7Smrg (pSiS->MiscFlags & MISC_CRT1OVERLAYGAMMA) && 171372b676d7Smrg ((pSiS->CurrentLayout.depth == 16) || 171472b676d7Smrg (pSiS->CurrentLayout.depth == 24)) ) { 171572b676d7Smrg orSISIDXREG(SISSR, 0x1f, 0x10); 171672b676d7Smrg resetxvgamma = TRUE; 171772b676d7Smrg } 171872b676d7Smrg } 171972b676d7Smrg 172072b676d7Smrg switch(pSiS->CurrentLayout.depth) { 172172b676d7Smrg case 15: 172272b676d7Smrg if(dogamma1) { 172372b676d7Smrg orSISIDXREG(SISSR, 0x07, 0x04); 172472b676d7Smrg /* 315/330: depth 15 not supported, no MMIO code needed */ 172572b676d7Smrg for(i=0; i<numColors; i++) { 172672b676d7Smrg index = indices[i]; 172772b676d7Smrg if(index < 32) { /* Paranoia */ 172872b676d7Smrg for(j=0; j<8; j++) { 172972b676d7Smrg outSISREG(SISCOLIDX, (index << 3) + j); 173072b676d7Smrg outSISREG(SISCOLDATA, colors[index].red << myshift); 173172b676d7Smrg outSISREG(SISCOLDATA, colors[index].green << myshift); 173272b676d7Smrg outSISREG(SISCOLDATA, colors[index].blue << myshift); 173372b676d7Smrg } 173472b676d7Smrg } 173572b676d7Smrg } 173672b676d7Smrg } else { 173772b676d7Smrg andSISIDXREG(SISSR, 0x07, ~0x04); 173872b676d7Smrg } 173972b676d7Smrg break; 174072b676d7Smrg case 16: 174172b676d7Smrg if(dogamma1) { 174272b676d7Smrg orSISIDXREG(SISSR, 0x07, 0x04); 174372b676d7Smrg if(pSiS->ChipFlags & SiSCF_MMIOPalette) { 174472b676d7Smrg for(i=0; i<numColors; i++) { 174572b676d7Smrg index = indices[i]; 174672b676d7Smrg if(index < 64) { /* Paranoia */ 174772b676d7Smrg for(j=0; j<4; j++) { 174872b676d7Smrg SIS_MMIO_OUT32(pSiS->IOBase, 0x8570, 174972b676d7Smrg (colors[index].green << (myshift + 8)) | 175072b676d7Smrg (colors[index >> 1].blue << (myshift + 16)) | 175172b676d7Smrg (colors[index >> 1].red << myshift) | 175272b676d7Smrg (((index << 2) + j) << 24)); 175372b676d7Smrg } 175472b676d7Smrg } 175572b676d7Smrg } 175672b676d7Smrg } else { 175772b676d7Smrg for(i=0; i<numColors; i++) { 175872b676d7Smrg index = indices[i]; 175972b676d7Smrg if(index < 64) { /* Paranoia */ 176072b676d7Smrg for(j=0; j<4; j++) { 176172b676d7Smrg outSISREG(SISCOLIDX, (index << 2) + j); 176272b676d7Smrg outSISREG(SISCOLDATA, colors[index >> 1].red << myshift); 176372b676d7Smrg outSISREG(SISCOLDATA, colors[index].green << myshift); 176472b676d7Smrg outSISREG(SISCOLDATA, colors[index >> 1].blue << myshift); 176572b676d7Smrg } 176672b676d7Smrg } 176772b676d7Smrg } 176872b676d7Smrg } 176972b676d7Smrg } else { 177072b676d7Smrg andSISIDXREG(SISSR, 0x07, ~0x04); 177172b676d7Smrg } 177272b676d7Smrg break; 177372b676d7Smrg case 24: 177472b676d7Smrg if(dogamma1) { 177572b676d7Smrg orSISIDXREG(SISSR, 0x07, 0x04); 177672b676d7Smrg if(pSiS->ChipFlags & SiSCF_MMIOPalette) { 177772b676d7Smrg for(i=0; i<numColors; i++) { 177872b676d7Smrg index = indices[i]; 177972b676d7Smrg if(index < 256) { /* Paranoia */ 178072b676d7Smrg SIS_MMIO_OUT32(pSiS->IOBase, 0x8570, 178172b676d7Smrg (colors[index].blue << 16) | 178272b676d7Smrg (colors[index].green << 8) | 178372b676d7Smrg (colors[index].red) | 178472b676d7Smrg (index << 24)); 178572b676d7Smrg } 178672b676d7Smrg } 178772b676d7Smrg } else { 178872b676d7Smrg for(i=0; i<numColors; i++) { 178972b676d7Smrg index = indices[i]; 179072b676d7Smrg if(index < 256) { /* Paranoia */ 179172b676d7Smrg outSISREG(SISCOLIDX, index); 179272b676d7Smrg outSISREG(SISCOLDATA, colors[index].red); 179372b676d7Smrg outSISREG(SISCOLDATA, colors[index].green); 179472b676d7Smrg outSISREG(SISCOLDATA, colors[index].blue); 179572b676d7Smrg } 179672b676d7Smrg } 179772b676d7Smrg } 179872b676d7Smrg } else { 179972b676d7Smrg andSISIDXREG(SISSR, 0x07, ~0x04); 180072b676d7Smrg } 180172b676d7Smrg break; 180272b676d7Smrg default: 180372b676d7Smrg andSISIDXREG(SISSR, 0x07, ~0x04); 180472b676d7Smrg if(pSiS->ChipFlags & SiSCF_MMIOPalette) { 180572b676d7Smrg for(i=0; i<numColors; i++) { 180672b676d7Smrg index = indices[i]; 180772b676d7Smrg SIS_MMIO_OUT32(pSiS->IOBase, 0x8570, 180872b676d7Smrg ((colors[index].blue) << 16) | 180972b676d7Smrg ((colors[index].green) << 8) | 181072b676d7Smrg (colors[index].red) | 181172b676d7Smrg (index << 24)); 181272b676d7Smrg } 181372b676d7Smrg } else { 181472b676d7Smrg for(i=0; i<numColors; i++) { 181572b676d7Smrg /* In pio mode, only 6 bits are supported */ 181672b676d7Smrg index = indices[i]; 181772b676d7Smrg outSISREG(SISCOLIDX, index); 181872b676d7Smrg outSISREG(SISCOLDATA, colors[index].red >> 2); 181972b676d7Smrg outSISREG(SISCOLDATA, colors[index].green >> 2); 182072b676d7Smrg outSISREG(SISCOLDATA, colors[index].blue >> 2); 182172b676d7Smrg } 182272b676d7Smrg } 182372b676d7Smrg } 182472b676d7Smrg 182572b676d7Smrg if(pSiS->VGAEngine == SIS_315_VGA) { 182672b676d7Smrg outSISIDXREG(SISSR, 0x1f, backup); 182772b676d7Smrg inSISIDXREG(SISSR, 0x07, backup); 182872b676d7Smrg if((backup & 0x04) && (resetxvgamma) && (pSiS->ResetXvGamma)) { 182972b676d7Smrg (pSiS->ResetXvGamma)(pScrn); 183072b676d7Smrg } 183172b676d7Smrg } 183272b676d7Smrg 183372b676d7Smrg#ifdef SISDUALHEAD 183472b676d7Smrg } 183572b676d7Smrg#endif 183672b676d7Smrg 183772b676d7Smrg#ifdef SISDUALHEAD 183872b676d7Smrg if((!pSiS->DualHeadMode) || (!pSiS->SecondHead)) { 183972b676d7Smrg#endif 184072b676d7Smrg switch(pSiS->VGAEngine) { 184172b676d7Smrg case SIS_300_VGA: 184272b676d7Smrg case SIS_315_VGA: 184372b676d7Smrg if(pSiS->VBFlags & CRT2_ENABLE) { 184472b676d7Smrg /* Only the SiS bridges support a CRT2 palette */ 184572b676d7Smrg if(pSiS->VBFlags2 & VB2_SISBRIDGE) { 184672b676d7Smrg if((pSiS->CRT2SepGamma) && (pSiS->crt2cindices) && (pSiS->crt2colors)) { 184772b676d7Smrg SiS301LoadPalette(pScrn, numColors, pSiS->crt2cindices, pSiS->crt2colors, myshift); 184872b676d7Smrg } else { 184972b676d7Smrg SiS301LoadPalette(pScrn, numColors, indices, colors, myshift); 185072b676d7Smrg } 185172b676d7Smrg } 185272b676d7Smrg } 185372b676d7Smrg } 185472b676d7Smrg#ifdef SISDUALHEAD 185572b676d7Smrg } 185672b676d7Smrg#endif 185772b676d7Smrg 185872b676d7Smrg} 185972b676d7Smrg 186072b676d7Smrgvoid 186172b676d7SmrgSiS_UpdateGammaCRT2(ScrnInfoPtr pScrn) 186272b676d7Smrg{ 186372b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 186472b676d7Smrg 186572b676d7Smrg if((!pSiS->CRT2SepGamma) || (!pSiS->crt2cindices) || (!pSiS->crt2gcolortable)) return; 186672b676d7Smrg 186772b676d7Smrg#ifdef SISDUALHEAD 186872b676d7Smrg if(pSiS->DualHeadMode) return; 186972b676d7Smrg#endif 187072b676d7Smrg 187172b676d7Smrg SISCalculateGammaRampCRT2(pScrn); 187272b676d7Smrg SiS301LoadPalette(pScrn, pSiS->CRT2ColNum, pSiS->crt2cindices, pSiS->crt2colors, (8 - pScrn->rgbBits)); 187372b676d7Smrg} 187472b676d7Smrg 187572b676d7Smrgstatic void 187672b676d7SmrgSiS301LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, int myshift) 187772b676d7Smrg{ 187872b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 187972b676d7Smrg int i, j, index; 188072b676d7Smrg Bool dogamma2 = pSiS->CRT2gamma; 188172b676d7Smrg#ifdef SISDUALHEAD 188272b676d7Smrg SISEntPtr pSiSEnt = pSiS->entityPrivate; 188372b676d7Smrg 188472b676d7Smrg if(pSiS->DualHeadMode) dogamma2 = pSiSEnt->CRT2gamma; 188572b676d7Smrg#endif 188672b676d7Smrg 188772b676d7Smrg /* 301B-DH does not support a color palette for LCD */ 188872b676d7Smrg if((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) return; 188972b676d7Smrg 189072b676d7Smrg switch(pSiS->CurrentLayout.depth) { 189172b676d7Smrg case 15: 189272b676d7Smrg if(dogamma2) { 189372b676d7Smrg orSISIDXREG(SISPART4, 0x0d, 0x08); 189472b676d7Smrg for(i=0; i<numColors; i++) { 189572b676d7Smrg index = indices[i]; 189672b676d7Smrg if(index < 32) { /* Paranoia */ 189772b676d7Smrg for(j=0; j<8; j++) { 189872b676d7Smrg outSISREG(SISCOL2IDX, (index << 3) + j); 189972b676d7Smrg outSISREG(SISCOL2DATA, colors[index].red << myshift); 190072b676d7Smrg outSISREG(SISCOL2DATA, colors[index].green << myshift); 190172b676d7Smrg outSISREG(SISCOL2DATA, colors[index].blue << myshift); 190272b676d7Smrg } 190372b676d7Smrg } 190472b676d7Smrg } 190572b676d7Smrg } else { 190672b676d7Smrg andSISIDXREG(SISPART4, 0x0d, ~0x08); 190772b676d7Smrg } 190872b676d7Smrg break; 190972b676d7Smrg case 16: 191072b676d7Smrg if(dogamma2) { 191172b676d7Smrg orSISIDXREG(SISPART4, 0x0d, 0x08); 191272b676d7Smrg for(i = 0; i < numColors; i++) { 191372b676d7Smrg index = indices[i]; 191472b676d7Smrg if(index < 64) { /* Paranoia */ 191572b676d7Smrg for(j = 0; j < 4; j++) { 191672b676d7Smrg outSISREG(SISCOL2IDX, (index << 2) + j); 191772b676d7Smrg outSISREG(SISCOL2DATA, colors[index >> 1].red << myshift); 191872b676d7Smrg outSISREG(SISCOL2DATA, colors[index].green << myshift); 191972b676d7Smrg outSISREG(SISCOL2DATA, colors[index >> 1].blue << myshift); 192072b676d7Smrg } 192172b676d7Smrg } 192272b676d7Smrg } 192372b676d7Smrg } else { 192472b676d7Smrg andSISIDXREG(SISPART4, 0x0d, ~0x08); 192572b676d7Smrg } 192672b676d7Smrg break; 192772b676d7Smrg case 24: 192872b676d7Smrg if(dogamma2) { 192972b676d7Smrg orSISIDXREG(SISPART4, 0x0d, 0x08); 193072b676d7Smrg for(i = 0; i < numColors; i++) { 193172b676d7Smrg index = indices[i]; 193272b676d7Smrg if(index < 256) { /* Paranoia */ 193372b676d7Smrg outSISREG(SISCOL2IDX, index); 193472b676d7Smrg outSISREG(SISCOL2DATA, colors[index].red); 193572b676d7Smrg outSISREG(SISCOL2DATA, colors[index].green); 193672b676d7Smrg outSISREG(SISCOL2DATA, colors[index].blue); 193772b676d7Smrg } 193872b676d7Smrg } 193972b676d7Smrg } else { 194072b676d7Smrg andSISIDXREG(SISPART4, 0x0d, ~0x08); 194172b676d7Smrg } 194272b676d7Smrg break; 194372b676d7Smrg default: 194472b676d7Smrg orSISIDXREG(SISPART4, 0x0d, 0x08); 194572b676d7Smrg for(i = 0; i < numColors; i++) { 194672b676d7Smrg index = indices[i]; 194772b676d7Smrg outSISREG(SISCOL2IDX, index); 194872b676d7Smrg outSISREG(SISCOL2DATA, colors[index].red); 194972b676d7Smrg outSISREG(SISCOL2DATA, colors[index].green); 195072b676d7Smrg outSISREG(SISCOL2DATA, colors[index].blue); 195172b676d7Smrg } 195272b676d7Smrg } 195372b676d7Smrg} 195472b676d7Smrg 195572b676d7Smrgvoid 195672b676d7SmrgSISDACPreInit(ScrnInfoPtr pScrn) 195772b676d7Smrg{ 195872b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 195972b676d7Smrg Bool IsForCRT2 = FALSE; 196072b676d7Smrg 196172b676d7Smrg#ifdef SISDUALHEAD 196272b676d7Smrg if((pSiS->DualHeadMode) && (!pSiS->SecondHead)) 196372b676d7Smrg IsForCRT2 = TRUE; 196472b676d7Smrg#endif 196572b676d7Smrg 196672b676d7Smrg pSiS->MaxClock = SiSMemBandWidth(pScrn, IsForCRT2); 196772b676d7Smrg 196872b676d7Smrg switch (pSiS->Chipset) { 196972b676d7Smrg case PCI_CHIP_SIS550: 197072b676d7Smrg case PCI_CHIP_SIS315: 197172b676d7Smrg case PCI_CHIP_SIS315H: 197272b676d7Smrg case PCI_CHIP_SIS315PRO: 197372b676d7Smrg case PCI_CHIP_SIS650: 197472b676d7Smrg case PCI_CHIP_SIS330: 197572b676d7Smrg case PCI_CHIP_SIS660: 197672b676d7Smrg case PCI_CHIP_SIS340: 197772b676d7Smrg case PCI_CHIP_XGIXG20: 197872b676d7Smrg case PCI_CHIP_XGIXG40: 197972b676d7Smrg pSiS->SiSSave = SiS315Save; 198072b676d7Smrg pSiS->SiSRestore = SiS315Restore; 198172b676d7Smrg break; 198272b676d7Smrg case PCI_CHIP_SIS300: 198372b676d7Smrg case PCI_CHIP_SIS540: 198472b676d7Smrg case PCI_CHIP_SIS630: 198572b676d7Smrg pSiS->SiSSave = SiS300Save; 198672b676d7Smrg pSiS->SiSRestore = SiS300Restore; 198772b676d7Smrg break; 198872b676d7Smrg case PCI_CHIP_SIS5597: 198972b676d7Smrg case PCI_CHIP_SIS6326: 199072b676d7Smrg case PCI_CHIP_SIS530: 199172b676d7Smrg default: 199272b676d7Smrg pSiS->SiSSave = SiSSave; 199372b676d7Smrg pSiS->SiSRestore = SiSRestore; 199472b676d7Smrg break; 199572b676d7Smrg } 199672b676d7Smrg} 199772b676d7Smrg 199872b676d7Smrgstatic void 199972b676d7SmrgSetBlock(CARD16 port, CARD8 from, CARD8 to, CARD8 *DataPtr) 200072b676d7Smrg{ 200172b676d7Smrg CARD8 index; 200272b676d7Smrg 200372b676d7Smrg for(index = from; index <= to; index++, DataPtr++) { 200472b676d7Smrg outSISIDXREG(port, index, *DataPtr); 200572b676d7Smrg } 200672b676d7Smrg} 200772b676d7Smrg 200872b676d7Smrgvoid 200972b676d7SmrgSiS6326SetTVReg(ScrnInfoPtr pScrn, CARD8 index, CARD8 data) 201072b676d7Smrg{ 201172b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 201272b676d7Smrg outSISIDXREG(SISCR, 0xE0, index); 201372b676d7Smrg outSISIDXREG(SISCR, 0xE1, data); 201472b676d7Smrg#ifdef TWDEBUG 201572b676d7Smrg xf86DrvMsg(0, X_INFO, "SiS6326: Setting Tv %02x to %02x\n", index, data); 201672b676d7Smrg#endif 201772b676d7Smrg} 201872b676d7Smrg 201972b676d7SmrgUChar 202072b676d7SmrgSiS6326GetTVReg(ScrnInfoPtr pScrn, CARD8 index) 202172b676d7Smrg{ 202272b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 202372b676d7Smrg UChar data; 202472b676d7Smrg 202572b676d7Smrg outSISIDXREG(SISCR, 0xE0, index); 202672b676d7Smrg inSISIDXREG(SISCR, 0xE1, data); 202772b676d7Smrg return(data); 202872b676d7Smrg} 202972b676d7Smrg 203072b676d7Smrgvoid 203172b676d7SmrgSiS6326SetXXReg(ScrnInfoPtr pScrn, CARD8 index, CARD8 data) 203272b676d7Smrg{ 203372b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 203472b676d7Smrg outSISIDXREG(SISCR, 0xE2, index); 203572b676d7Smrg outSISIDXREG(SISCR, 0xE3, data); 203672b676d7Smrg} 203772b676d7Smrg 203872b676d7SmrgUChar 203972b676d7SmrgSiS6326GetXXReg(ScrnInfoPtr pScrn, CARD8 index) 204072b676d7Smrg{ 204172b676d7Smrg SISPtr pSiS = SISPTR(pScrn); 204272b676d7Smrg UChar data; 204372b676d7Smrg 204472b676d7Smrg outSISIDXREG(SISCR, 0xE2, index); 204572b676d7Smrg inSISIDXREG(SISCR, 0xE3, data); 204672b676d7Smrg return(data); 204772b676d7Smrg} 204872b676d7Smrg 204972b676d7SmrgUChar SiSGetCopyROP(int rop) 205072b676d7Smrg{ 205172b676d7Smrg const UChar sisALUConv[] = 205272b676d7Smrg { 205372b676d7Smrg 0x00, /* dest = 0; 0, GXclear, 0 */ 205472b676d7Smrg 0x88, /* dest &= src; DSa, GXand, 0x1 */ 205572b676d7Smrg 0x44, /* dest = src & ~dest; SDna, GXandReverse, 0x2 */ 205672b676d7Smrg 0xCC, /* dest = src; S, GXcopy, 0x3 */ 205772b676d7Smrg 0x22, /* dest &= ~src; DSna, GXandInverted, 0x4 */ 205872b676d7Smrg 0xAA, /* dest = dest; D, GXnoop, 0x5 */ 205972b676d7Smrg 0x66, /* dest = ^src; DSx, GXxor, 0x6 */ 206072b676d7Smrg 0xEE, /* dest |= src; DSo, GXor, 0x7 */ 206172b676d7Smrg 0x11, /* dest = ~src & ~dest; DSon, GXnor, 0x8 */ 206272b676d7Smrg 0x99, /* dest ^= ~src ; DSxn, GXequiv, 0x9 */ 206372b676d7Smrg 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */ 206472b676d7Smrg 0xDD, /* dest = src|~dest ; SDno, GXorReverse, 0xB */ 206572b676d7Smrg 0x33, /* dest = ~src; Sn, GXcopyInverted, 0xC */ 206672b676d7Smrg 0xBB, /* dest |= ~src; DSno, GXorInverted, 0xD */ 206772b676d7Smrg 0x77, /* dest = ~src|~dest; DSan, GXnand, 0xE */ 206872b676d7Smrg 0xFF, /* dest = 0xFF; 1, GXset, 0xF */ 206972b676d7Smrg }; 207072b676d7Smrg 207172b676d7Smrg return(sisALUConv[rop]); 207272b676d7Smrg} 207372b676d7Smrg 207472b676d7SmrgUChar SiSGetPatternROP(int rop) 207572b676d7Smrg{ 207672b676d7Smrg const UChar sisPatALUConv[] = 207772b676d7Smrg { 207872b676d7Smrg 0x00, /* dest = 0; 0, GXclear, 0 */ 207972b676d7Smrg 0xA0, /* dest &= src; DPa, GXand, 0x1 */ 208072b676d7Smrg 0x50, /* dest = src & ~dest; PDna, GXandReverse, 0x2 */ 208172b676d7Smrg 0xF0, /* dest = src; P, GXcopy, 0x3 */ 208272b676d7Smrg 0x0A, /* dest &= ~src; DPna, GXandInverted, 0x4 */ 208372b676d7Smrg 0xAA, /* dest = dest; D, GXnoop, 0x5 */ 208472b676d7Smrg 0x5A, /* dest = ^src; DPx, GXxor, 0x6 */ 208572b676d7Smrg 0xFA, /* dest |= src; DPo, GXor, 0x7 */ 208672b676d7Smrg 0x05, /* dest = ~src & ~dest; DPon, GXnor, 0x8 */ 208772b676d7Smrg 0xA5, /* dest ^= ~src ; DPxn, GXequiv, 0x9 */ 208872b676d7Smrg 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */ 208972b676d7Smrg 0xF5, /* dest = src|~dest ; PDno, GXorReverse, 0xB */ 209072b676d7Smrg 0x0F, /* dest = ~src; Pn, GXcopyInverted, 0xC */ 209172b676d7Smrg 0xAF, /* dest |= ~src; DPno, GXorInverted, 0xD */ 209272b676d7Smrg 0x5F, /* dest = ~src|~dest; DPan, GXnand, 0xE */ 209372b676d7Smrg 0xFF, /* dest = 0xFF; 1, GXset, 0xF */ 209472b676d7Smrg }; 209572b676d7Smrg 209672b676d7Smrg return(sisPatALUConv[rop]); 209772b676d7Smrg} 2098