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