/* * DAC helper functions (Save/Restore, MemClk, etc) * * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1) Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2) Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3) The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Author: Thomas Winischhofer * * -------------------------------------------------------------------------- * * SiS_compute_vclk(), SiSCalcClock() and parts of SiSMclk(): * * Copyright (C) 1998, 1999 by Alan Hourihane, Wigan, England * Written by: * Alan Hourihane , * Mike Chapman , * Juanjo Santamarta , * Mitani Hiroshi , * David Thomas , * Thomas Winischhofer . * * Licensed under the following terms: * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appears in all copies and that both that copyright * notice and this permission notice appear in supporting documentation, and * and that the name of the copyright holder not be used in advertising * or publicity pertaining to distribution of the software without specific, * written prior permission. The copyright holder makes no representations * about the suitability of this software for any purpose. It is provided * "as is" without expressed or implied warranty. * * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sis.h" #define SIS_NEED_inSISREG #define SIS_NEED_inSISREGW #define SIS_NEED_inSISREGL #define SIS_NEED_outSISREG #define SIS_NEED_outSISREGW #define SIS_NEED_outSISREGL #define SIS_NEED_inSISIDXREG #define SIS_NEED_outSISIDXREG #define SIS_NEED_orSISIDXREG #define SIS_NEED_andSISIDXREG #define SIS_NEED_MYMMIO #include "sis_regs.h" #include "sis_dac.h" static void SiSSave(ScrnInfoPtr pScrn, SISRegPtr sisReg); static void SiSRestore(ScrnInfoPtr pScrn, SISRegPtr sisReg); static void SiS300Save(ScrnInfoPtr pScrn, SISRegPtr sisReg); static void SiS300Restore(ScrnInfoPtr pScrn, SISRegPtr sisReg); static void SiS315Save(ScrnInfoPtr pScrn, SISRegPtr sisReg); static void SiS315Restore(ScrnInfoPtr pScrn, SISRegPtr sisReg); static void SiS301Save(ScrnInfoPtr pScrn, SISRegPtr sisReg); static void SiS301BSave(ScrnInfoPtr pScrn, SISRegPtr sisReg); static void SiSLVDSChrontelSave(ScrnInfoPtr pScrn, SISRegPtr sisReg); static void SiS301Restore(ScrnInfoPtr pScrn, SISRegPtr sisReg); static void SiS301BRestore(ScrnInfoPtr pScrn, SISRegPtr sisReg); static void SiSLVDSChrontelRestore(ScrnInfoPtr pScrn, SISRegPtr sisReg); static void SiS301LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies, LOCO *colors, int myshift); static void SetBlock(CARD16 port, CARD8 from, CARD8 to, CARD8 *DataPtr); UChar SiSGetCopyROP(int rop); UChar SiSGetPatternROP(int rop); static const UShort ch700xidx[] = { 0x00,0x07,0x08,0x0a,0x0b,0x04,0x09,0x20,0x21,0x18,0x19,0x1a, 0x1b,0x1c,0x1d,0x1e,0x1f, /* 0x0e, - Don't save the power register */ 0x01,0x03,0x06,0x0d,0x11,0x13,0x14,0x15,0x17,0x22,0x23,0x24 }; static const UShort ch701xidx[] = { 0x1c,0x5f,0x64,0x6f,0x70,0x71,0x72,0x73,0x74,0x76,0x78,0x7d, 0x67,0x68,0x69,0x6a,0x6b,0x1e,0x00,0x01,0x02,0x04,0x03,0x05, 0x06,0x07,0x08,0x15,0x1f,0x0c,0x0d,0x0e,0x0f,0x10,0x66 }; int SiS_compute_vclk( int Clock, int *out_n, int *out_dn, int *out_div, int *out_sbit, int *out_scale) { float f,x,y,t, error, min_error; int n, dn, best_n=0, best_dn=0; /* * Rules * * VCLK = 14.318 * (Divider/Post Scalar) * (Numerator/DeNumerator) * Factor = (Divider/Post Scalar) * Divider is 1 or 2 * Post Scalar is 1, 2, 3, 4, 6 or 8 * Numberator ranged from 1 to 128 * DeNumerator ranged from 1 to 32 * a. VCO = VCLK/Factor, suggest range is 150 to 250 Mhz * b. Post Scalar selected from 1, 2, 4 or 8 first. * c. DeNumerator selected from 2. * * According to rule a and b, the VCO ranges that can be scaled by * rule b are: * 150 - 250 (Factor = 1) * 75 - 125 (Factor = 2) * 37.5 - 62.5 (Factor = 4) * 18.75 - 31.25 (Factor = 8) * * The following ranges use Post Scalar 3 or 6: * 125 - 150 (Factor = 1.5) * 62.5 - 75 (Factor = 3) * 31.25 - 37.5 (Factor = 6) * * Steps: * 1. divide the Clock by 2 until the Clock is less or equal to 31.25. * 2. if the divided Clock is range from 18.25 to 31.25, than * the Factor is 1, 2, 4 or 8. * 3. if the divided Clock is range from 15.625 to 18.25, than * the Factor is 1.5, 3 or 6. * 4. select the Numberator and DeNumberator with minimum deviation. * * ** this function can select VCLK ranged from 18.75 to 250 Mhz */ f = (float) Clock; f /= 1000.0; if((f > 250.0) || (f < 18.75)) return 0; min_error = f; y = 1.0; x = f; while(x > 31.25) { y *= 2.0; x /= 2.0; } if(x >= 18.25) { x *= 8.0; y = 8.0 / y; } else if(x >= 15.625) { x *= 12.0; y = 12.0 / y; } t = y; if(t == (float) 1.5) { *out_div = 2; t *= 2.0; } else { *out_div = 1; } if(t > (float) 4.0) { *out_sbit = 1; t /= 2.0; } else { *out_sbit = 0; } *out_scale = (int) t; for(dn = 2; dn <= 32; dn++) { for(n = 1; n <= 128; n++) { error = x; error -= ((float) 14.318 * (float) n / (float) dn); if(error < (float) 0) error = -error; if(error < min_error) { min_error = error; best_n = n; best_dn = dn; } } } *out_n = best_n; *out_dn = best_dn; PDEBUG(ErrorF("SiS_compute_vclk: Clock=%d, n=%d, dn=%d, div=%d, sbit=%d," " scale=%d\n", Clock, best_n, best_dn, *out_div, *out_sbit, *out_scale)); return 1; } void SiSCalcClock(ScrnInfoPtr pScrn, int clock, int max_VLD, unsigned int *vclk) { SISPtr pSiS = SISPTR(pScrn); int M, N, P , PSN, VLD , PSNx ; int bestM=0, bestN=0, bestP=0, bestPSN=0, bestVLD=0; double abest = 42.0; double target; double Fvco, Fout; double error, aerror; /* * fd = fref*(Numerator/Denumerator)*(Divider/PostScaler) * * M = Numerator [1:128] * N = DeNumerator [1:32] * VLD = Divider (Vco Loop Divider) : divide by 1, 2 * P = Post Scaler : divide by 1, 2, 3, 4 * PSN = Pre Scaler (Reference Divisor Select) * * result in vclk[] */ #define Midx 0 #define Nidx 1 #define VLDidx 2 #define Pidx 3 #define PSNidx 4 #define Fref 14318180 /* stability constraints for internal VCO -- MAX_VCO also determines * the maximum Video pixel clock */ #define MIN_VCO Fref #define MAX_VCO 135000000 #define MAX_VCO_5597 353000000 #define MAX_PSN 0 /* no pre scaler for this chip */ #define TOLERANCE 0.01 /* search smallest M and N in this tolerance */ int M_min = 2; int M_max = 128; target = clock * 1000; if(pSiS->Chipset == PCI_CHIP_SIS5597 || pSiS->Chipset == PCI_CHIP_SIS6326) { int low_N = 2; int high_N = 5; PSN = 1; P = 1; if(target < MAX_VCO_5597 / 2) P = 2; if(target < MAX_VCO_5597 / 3) P = 3; if(target < MAX_VCO_5597 / 4) P = 4; if(target < MAX_VCO_5597 / 6) P = 6; if(target < MAX_VCO_5597 / 8) P = 8; Fvco = P * target; for(N = low_N; N <= high_N; N++) { double M_desired = Fvco / Fref * N; if(M_desired > M_max * max_VLD) continue; if(M_desired > M_max) { M = M_desired / 2 + 0.5; VLD = 2; } else { M = Fvco / Fref * N + 0.5; VLD = 1; } Fout = (double)Fref * (M * VLD)/(N * P); error = (target - Fout) / target; aerror = (error < 0) ? -error : error; if(aerror < abest) { abest = aerror; bestM = M; bestN = N; bestP = P; bestPSN = PSN; bestVLD = VLD; } } } else { for(PSNx = 0; PSNx <= MAX_PSN ; PSNx++) { int low_N, high_N; double FrefVLDPSN; PSN = !PSNx ? 1 : 4; low_N = 2; high_N = 32; for(VLD = 1 ; VLD <= max_VLD ; VLD++) { FrefVLDPSN = (double)Fref * VLD / PSN; for(N = low_N; N <= high_N; N++) { double tmp = FrefVLDPSN / N; for(P = 1; P <= 4; P++) { double Fvco_desired = target * ( P ); double M_desired = Fvco_desired / tmp; /* Which way will M_desired be rounded? * Do all three just to be safe. */ int M_low = M_desired - 1; int M_hi = M_desired + 1; if(M_hi < M_min || M_low > M_max) continue; if(M_low < M_min) M_low = M_min; if(M_hi > M_max) M_hi = M_max; for(M = M_low; M <= M_hi; M++) { Fvco = tmp * M; if(Fvco <= MIN_VCO) continue; if(Fvco > MAX_VCO) break; Fout = Fvco / ( P ); error = (target - Fout) / target; aerror = (error < 0) ? -error : error; if(aerror < abest) { abest = aerror; bestM = M; bestN = N; bestP = P; bestPSN = PSN; bestVLD = VLD; } #ifdef TWDEBUG xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO,3, "Freq. selected: %.2f MHz, M=%d, N=%d, VLD=%d, P=%d, PSN=%d\n", (float)(clock / 1000.), M, N, P, VLD, PSN); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO,3, "Freq. set: %.2f MHz\n", Fout / 1.0e6); #endif } } } } } } vclk[Midx] = bestM; vclk[Nidx] = bestN; vclk[VLDidx] = bestVLD; vclk[Pidx] = bestP; vclk[PSNidx] = bestPSN; } static void SiSSave(ScrnInfoPtr pScrn, SISRegPtr sisReg) { SISPtr pSiS = SISPTR(pScrn); int i, max; PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "SiSSave()\n")); #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif switch(pSiS->Chipset) { case PCI_CHIP_SIS5597: max=0x3C; break; case PCI_CHIP_SIS6326: case PCI_CHIP_SIS530: max=0x3F; break; default: max=0x37; } /* Save extended SR registers */ for(i = 0x00; i <= max; i++) { inSISIDXREG(SISSR, i, sisReg->sisRegs3C4[i]); #ifdef TWDEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "SR%02X - %02X \n", i, sisReg->sisRegs3C4[i]); #endif } #ifdef TWDEBUG for(i = 0x00; i <= 0x3f; i++) { inSISIDXREG(SISCR, i, max); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CR%02X - %02X \n", i, max); } #endif /* Save lock (will not be restored in SiSRestore()!) */ inSISIDXREG(SISCR, 0x80, sisReg->sisRegs3D4[0x80]); sisReg->sisRegs3C2 = inSISREG(SISMISCR); /* Misc */ /* Save TV registers */ if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) { outSISIDXREG(SISCR, 0x80, 0x86); for(i = 0x00; i <= 0x44; i++) { sisReg->sis6326tv[i] = SiS6326GetTVReg(pScrn, i); #ifdef TWDEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VR%02X - %02X \n", i,sisReg->sis6326tv[i]); #endif } } } static void SiSRestore(ScrnInfoPtr pScrn, SISRegPtr sisReg) { SISPtr pSiS = SISPTR(pScrn); int i, max; UChar tmp; PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4, "SiSRestore()\n")); #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif switch(pSiS->Chipset) { case PCI_CHIP_SIS5597: max = 0x3C; break; case PCI_CHIP_SIS6326: case PCI_CHIP_SIS530: max = 0x3F; break; default: max = 0x37; } /* Disable TV on 6326 before restoring */ if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) { outSISIDXREG(SISCR, 0x80, 0x86); tmp = SiS6326GetTVReg(pScrn, 0x00); tmp &= ~0x04; SiS6326SetTVReg(pScrn, 0x00, tmp); } /* Restore other extended SR registers */ for(i = 0x06; i <= max; i++) { if((i == 0x13) || (i == 0x2a) || (i == 0x2b)) continue; outSISIDXREG(SISSR, i, sisReg->sisRegs3C4[i]); } /* Now restore VCLK (with correct SR38 setting) */ outSISIDXREG(SISSR, 0x13, sisReg->sisRegs3C4[0x13]); outSISIDXREG(SISSR, 0x2a, sisReg->sisRegs3C4[0x2a]); outSISIDXREG(SISSR, 0x2b, sisReg->sisRegs3C4[0x2b]); /* Misc */ outSISREG(SISMISCW, sisReg->sisRegs3C2); /* MemClock needs this to take effect */ outSISIDXREG(SISSR, 0x00, 0x01); /* Synchronous Reset */ usleep(10000); outSISIDXREG(SISSR, 0x00, 0x03); /* End Reset */ /* Restore TV registers */ pSiS->SiS6326Flags &= ~SIS6326_TVON; if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) { for(i = 0x01; i <= 0x44; i++) { SiS6326SetTVReg(pScrn, i, sisReg->sis6326tv[i]); #ifdef TWDEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VR%02x restored to %02x\n", i, sisReg->sis6326tv[i]); #endif } tmp = SiS6326GetXXReg(pScrn, 0x13); SiS6326SetXXReg(pScrn, 0x13, 0xfa); tmp = SiS6326GetXXReg(pScrn, 0x14); SiS6326SetXXReg(pScrn, 0x14, 0xc8); if(!(sisReg->sisRegs3C4[0x0D] & 0x04)) { tmp = SiS6326GetXXReg(pScrn, 0x13); SiS6326SetXXReg(pScrn, 0x13, 0xf6); tmp = SiS6326GetXXReg(pScrn, 0x14); SiS6326SetXXReg(pScrn, 0x14, 0xbf); } if(sisReg->sis6326tv[0] & 0x04) pSiS->SiS6326Flags |= SIS6326_TVON; } } /* Save SiS 300 series register contents */ static void SiS300Save(ScrnInfoPtr pScrn, SISRegPtr sisReg) { SISPtr pSiS = SISPTR(pScrn); int i; PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "SiS300Save()\n")); #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif /* Save SR registers */ for(i = 0x00; i <= 0x3D; i++) { inSISIDXREG(SISSR, i, sisReg->sisRegs3C4[i]); #ifdef TWDEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "SR%02X - %02X \n", i,sisReg->sisRegs3C4[i]); #endif } /* Save CR registers */ for(i = 0x00; i < 0x40; i++) { inSISIDXREG(SISCR, i, sisReg->sisRegs3D4[i]); #ifdef TWDEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CR%02X Contents - %02X \n", i,sisReg->sisRegs3D4[i]); #endif } /* Save Misc register */ sisReg->sisRegs3C2 = inSISREG(SISMISCR); /* Save FQBQ and GUI timer settings */ if(pSiS->Chipset == PCI_CHIP_SIS630) { sisReg->sisRegsPCI50 = sis_pci_read_host_bridge_u32(0x50); sisReg->sisRegsPCIA0 = sis_pci_read_host_bridge_u32(0xA0); #ifdef TWDEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PCI Config 50 = %lx\n", sisReg->sisRegsPCI50); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PCI Config A0 = %lx\n", sisReg->sisRegsPCIA0); #endif } /* Save panel link/video bridge registers */ #ifndef TWDEBUG if(!pSiS->UseVESA) { #endif if(pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) SiSLVDSChrontelSave(pScrn, sisReg); else if(pSiS->VBFlags2 & VB2_301) SiS301Save(pScrn, sisReg); else if(pSiS->VBFlags2 & VB2_30xBLV) SiS301BSave(pScrn, sisReg); #ifndef TWDEBUG } #endif /* Save Mode number */ sisReg->BIOSModeSave = SiS_GetSetModeID(pScrn,0xFF); #ifdef TWDEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS mode ds:449 = 0x%x\n", sisReg->BIOSModeSave); #endif } /* Restore SiS300 series register contents */ static void SiS300Restore(ScrnInfoPtr pScrn, SISRegPtr sisReg) { SISPtr pSiS = SISPTR(pScrn); int i,temp; CARD32 temp1, temp2; PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4, "SiS300Restore()\n")); #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif /* Wait for accelerator to finish on-going drawing operations. */ inSISIDXREG(SISSR, 0x1E, temp); if(temp & (0x40|0x10|0x02)) { while ( (SIS_MMIO_IN16(pSiS->IOBase, 0x8242) & 0xE000) != 0xE000){}; while ( (SIS_MMIO_IN16(pSiS->IOBase, 0x8242) & 0xE000) != 0xE000){}; while ( (SIS_MMIO_IN16(pSiS->IOBase, 0x8242) & 0xE000) != 0xE000){}; } if(!(pSiS->UseVESA)) { if(pSiS->VBFlags2 & VB2_LVDS) { SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30); SiSSetLVDSetc(pSiS->SiS_Pr); SiS_GetVBType(pSiS->SiS_Pr); SiS_UnLockCRT2(pSiS->SiS_Pr); SiS_DisableBridge(pSiS->SiS_Pr); } } /* Restore extended CR registers */ for(i = 0x19; i < 0x40; i++) { outSISIDXREG(SISCR, i, sisReg->sisRegs3D4[i]); } if(pSiS->Chipset != PCI_CHIP_SIS300) { UChar val; inSISIDXREG(SISCR, 0x1A, val); if(val == sisReg->sisRegs3D4[0x19]) outSISIDXREG(SISCR, 0x1A, sisReg->sisRegs3D4[0x19]); inSISIDXREG(SISCR,0x19,val); if(val == sisReg->sisRegs3D4[0x1A]) outSISIDXREG(SISCR, 0x19, sisReg->sisRegs3D4[0x1A]); } /* Set (and leave) PCI_IO_ENABLE on if accelerators are on */ if(sisReg->sisRegs3C4[0x1e] & 0x50) { sisReg->sisRegs3C4[0x20] |= 0x20; outSISIDXREG(SISSR, 0x20, sisReg->sisRegs3C4[0x20]); } /* If TQ is switched on, don't switch it off ever again! * Therefore, always restore registers with TQ enabled. */ if((!pSiS->NoAccel) && (pSiS->TurboQueue)) { temp = (pScrn->videoRam/64) - 8; sisReg->sisRegs3C4[0x26] = temp & 0xFF; sisReg->sisRegs3C4[0x27] = ((temp >> 8) & 3) | 0xF0; } /* Restore extended SR registers */ for(i = 0x06; i <= 0x3D; i++) { temp = sisReg->sisRegs3C4[i]; if(!(pSiS->UseVESA)) { if(pSiS->VBFlags2 & VB2_LVDS) { if(i == 0x11) { inSISIDXREG(SISSR,0x11,temp); temp &= 0x0c; temp |= (sisReg->sisRegs3C4[i] & 0xf3); } } } outSISIDXREG(SISSR, i, temp); } /* Restore VCLK and ECLK */ if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xB)) { outSISIDXREG(SISSR,0x31,0x20); outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]); outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]); outSISIDXREG(SISSR,0x2d,0x80); outSISIDXREG(SISSR,0x31,0x10); outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]); outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]); outSISIDXREG(SISSR,0x2d,0x80); } outSISIDXREG(SISSR,0x31,0x00); outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]); outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]); outSISIDXREG(SISSR,0x2d,0x80); if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xB)) { outSISIDXREG(SISSR,0x31,0x20); outSISIDXREG(SISSR,0x2e,sisReg->sisRegs3C4[0x2e]); outSISIDXREG(SISSR,0x2f,sisReg->sisRegs3C4[0x2f]); outSISIDXREG(SISSR,0x31,0x10); outSISIDXREG(SISSR,0x2e,sisReg->sisRegs3C4[0x2e]); outSISIDXREG(SISSR,0x2f,sisReg->sisRegs3C4[0x2f]); outSISIDXREG(SISSR,0x31,0x00); outSISIDXREG(SISSR,0x2e,sisReg->sisRegs3C4[0x2e]); outSISIDXREG(SISSR,0x2f,sisReg->sisRegs3C4[0x2f]); } /* Restore Misc register */ outSISREG(SISMISCW, sisReg->sisRegs3C2); /* Restore FQBQ and GUI timer settings */ if(pSiS->Chipset == PCI_CHIP_SIS630) { temp1 = sis_pci_read_host_bridge_u32(0x50); temp2 = sis_pci_read_host_bridge_u32(0xA0); if(sis_pci_read_host_bridge_u32(0x00) == 0x06301039) { temp1 &= 0xf0ffffff; temp1 |= (sisReg->sisRegsPCI50 & ~0xf0ffffff); temp2 &= 0xf0ffffff; temp2 |= (sisReg->sisRegsPCIA0 & ~0xf0ffffff); } else { /* 730 */ temp1 &= 0xfffff9ff; temp1 |= (sisReg->sisRegsPCI50 & ~0xfffff9ff); temp2 &= 0x00ffffff; temp2 |= (sisReg->sisRegsPCIA0 & ~0x00ffffff); } sis_pci_write_host_bridge_u32(0x50, temp1); sis_pci_write_host_bridge_u32(0xA0, temp2); } /* Restore panel link/video bridge registers */ if(!(pSiS->UseVESA)) { if(pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) SiSLVDSChrontelRestore(pScrn, sisReg); else if(pSiS->VBFlags2 & VB2_301) SiS301Restore(pScrn, sisReg); else if(pSiS->VBFlags2 & VB2_30xBLV) SiS301BRestore(pScrn, sisReg); } /* MemClock needs this to take effect */ outSISIDXREG(SISSR, 0x00, 0x01); /* Synchronous Reset */ outSISIDXREG(SISSR, 0x00, 0x03); /* End Reset */ /* Restore mode number */ SiS_GetSetModeID(pScrn,sisReg->BIOSModeSave); } /* Save SiS315 series register contents */ static void SiS315Save(ScrnInfoPtr pScrn, SISRegPtr sisReg) { SISPtr pSiS = SISPTR(pScrn); int i, max; PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "SiS315Save()\n")); #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif /* Save SR registers */ for(i = 0x00; i <= 0x60; i++) { inSISIDXREG(SISSR, i, sisReg->sisRegs3C4[i]); #ifdef TWDEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "SR%02X - %02X \n", i,sisReg->sisRegs3C4[i]); #endif } /* Save command queue location */ sisReg->sisMMIO85C0 = SIS_MMIO_IN32(pSiS->IOBase, 0x85C0); /* Save CR registers */ max = 0x7c; if(pSiS->ChipType >= XGI_20) max = 0xff; for(i = 0x00; i <= max; i++) { inSISIDXREG(SISCR, i, sisReg->sisRegs3D4[i]); #ifdef TWDEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CR%02X Contents - %02X \n", i,sisReg->sisRegs3D4[i]); #endif } /* Save video capture registers */ for(i = 0x00; i <= 0x4f; i++) { inSISIDXREG(SISCAP, i, sisReg->sisCapt[i]); #ifdef TWDEBUG_VID xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Capt%02X Contents - %02X \n", i,sisReg->sisCapt[i]); #endif } /* Save video playback registers */ for(i = 0x00; i <= 0x3f; i++) { inSISIDXREG(SISVID, i, sisReg->sisVid[i]); #ifdef TWDEBUG_VID xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Vid%02X Contents - %02X \n", i,sisReg->sisVid[i]); #endif } /* Save Misc register */ sisReg->sisRegs3C2 = inSISREG(SISMISCR); /* Save panel link/video bridge registers */ #ifndef TWDEBUG if(!pSiS->UseVESA) { #endif if(pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) SiSLVDSChrontelSave(pScrn, sisReg); else if(pSiS->VBFlags2 & VB2_301) SiS301Save(pScrn, sisReg); else if(pSiS->VBFlags2 & VB2_30xBLV) SiS301BSave(pScrn, sisReg); #ifndef TWDEBUG } #endif /* Save mode number */ sisReg->BIOSModeSave = SiS_GetSetModeID(pScrn,0xFF); #ifdef TWDEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS mode ds:449 = 0x%x\n", sisReg->BIOSModeSave); #endif } /* Restore SiS315/330 series register contents */ static void SiS315Restore(ScrnInfoPtr pScrn, SISRegPtr sisReg) { SISPtr pSiS = SISPTR(pScrn); int i,temp; PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4, "SiS315Restore()\n")); #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif /* Wait for accelerator to finish on-going drawing operations. */ inSISIDXREG(SISSR, 0x1E, temp); if(temp & (0x40|0x10|0x02)) { /* 0x40 = 2D, 0x02 = 3D enabled*/ while ( (SIS_MMIO_IN32(pSiS->IOBase, 0x85CC) & 0x80000000) != 0x80000000){}; while ( (SIS_MMIO_IN32(pSiS->IOBase, 0x85CC) & 0x80000000) != 0x80000000){}; while ( (SIS_MMIO_IN32(pSiS->IOBase, 0x85CC) & 0x80000000) != 0x80000000){}; } /* We reset the command queue before restoring. * This might be required because we never know what * console driver (like the kernel framebuffer driver) * or application is running and which queue mode it * uses. */ andSISIDXREG(SISCR, 0x55, 0x33); orSISIDXREG(SISSR, 0x26, 0x01); outSISIDXREG(SISSR, 0x27, 0x1F); /* Restore extended CR registers */ for(i = 0x19; i < 0x5C; i++) { outSISIDXREG(SISCR, i, sisReg->sisRegs3D4[i]); } if(pSiS->ChipType < SIS_661) { outSISIDXREG(SISCR, 0x79, sisReg->sisRegs3D4[0x79]); } outSISIDXREG(SISCR, pSiS->myCR63, sisReg->sisRegs3D4[pSiS->myCR63]); /* Leave PCI_IO_ENABLE on if accelerators are on (Is this required?) */ if(sisReg->sisRegs3C4[0x1e] & 0x52) { /* 0x40=2D, 0x02=3D */ sisReg->sisRegs3C4[0x20] |= 0x20; outSISIDXREG(SISSR, 0x20, sisReg->sisRegs3C4[0x20]); } if(pSiS->SiS_Pr->SiS_SensibleSR11) { sisReg->sisRegs3C4[0x11] &= 0x0f; } /* Restore extended SR registers */ for(i = 0x06; i <= 0x3F; i++) { if(i == 0x26) { continue; } else if(i == 0x27) { outSISIDXREG(SISSR, 0x27, sisReg->sisRegs3C4[0x27]); outSISIDXREG(SISSR, 0x26, sisReg->sisRegs3C4[0x26]); } else { outSISIDXREG(SISSR, i, sisReg->sisRegs3C4[i]); } } /* Restore VCLK and ECLK */ andSISIDXREG(SISSR,0x31,0xcf); if(pSiS->VBFlags2 & VB2_LVDS) { orSISIDXREG(SISSR,0x31,0x20); outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]); outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]); outSISIDXREG(SISSR,0x2d,0x80); andSISIDXREG(SISSR,0x31,0xcf); orSISIDXREG(SISSR,0x31,0x10); outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]); outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]); outSISIDXREG(SISSR,0x2d,0x80); andSISIDXREG(SISSR,0x31,0xcf); outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]); outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]); outSISIDXREG(SISSR,0x2d,0x01); outSISIDXREG(SISSR,0x31,0x20); outSISIDXREG(SISSR,0x2e,sisReg->sisRegs3C4[0x2e]); outSISIDXREG(SISSR,0x2f,sisReg->sisRegs3C4[0x2f]); outSISIDXREG(SISSR,0x31,0x10); outSISIDXREG(SISSR,0x2e,sisReg->sisRegs3C4[0x2e]); outSISIDXREG(SISSR,0x2f,sisReg->sisRegs3C4[0x2f]); outSISIDXREG(SISSR,0x31,0x00); outSISIDXREG(SISSR,0x2e,sisReg->sisRegs3C4[0x2e]); outSISIDXREG(SISSR,0x2f,sisReg->sisRegs3C4[0x2f]); } else { outSISIDXREG(SISSR,0x2b,sisReg->sisRegs3C4[0x2b]); outSISIDXREG(SISSR,0x2c,sisReg->sisRegs3C4[0x2c]); outSISIDXREG(SISSR,0x2d,0x01); } #ifndef SISVRAMQ /* Initialize read/write pointer for command queue */ SIS_MMIO_OUT32(pSiS->IOBase, 0x85C4, SIS_MMIO_IN32(pSiS->IOBase, 0x85C8)); #endif /* Restore queue location */ SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, sisReg->sisMMIO85C0); /* Restore Misc register */ outSISREG(SISMISCW, sisReg->sisRegs3C2); /* Restore panel link/video bridge registers */ if(!(pSiS->UseVESA)) { if(pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) SiSLVDSChrontelRestore(pScrn, sisReg); else if(pSiS->VBFlags2 & VB2_301) SiS301Restore(pScrn, sisReg); else if(pSiS->VBFlags2 & VB2_30xBLV) SiS301BRestore(pScrn, sisReg); } /* MemClock needs this to take effect */ outSISIDXREG(SISSR, 0x00, 0x01); /* Synchronous Reset */ outSISIDXREG(SISSR, 0x00, 0x03); /* End Reset */ /* Restore Mode number */ SiS_GetSetModeID(pScrn,sisReg->BIOSModeSave); } static void SiSVBSave(ScrnInfoPtr pScrn, SISRegPtr sisReg, int p1, int p2, int p3, int p4) { SISPtr pSiS = SISPTR(pScrn); int i; for(i=0; i<=p1; i++) { inSISIDXREG(SISPART1, i, sisReg->VBPart1[i]); #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "301xSave: Part1 0x%02x = 0x%02x\n", i, sisReg->VBPart1[i]); #endif } for(i=0; i<=p2; i++) { inSISIDXREG(SISPART2, i, sisReg->VBPart2[i]); #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "301xSave: Part2 0x%02x = 0x%02x\n", i, sisReg->VBPart2[i]); #endif } for(i=0; i<=p3; i++) { inSISIDXREG(SISPART3, i, sisReg->VBPart3[i]); #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "301xSave: Part3 0x%02x = 0x%02x\n", i, sisReg->VBPart3[i]); #endif } for(i=0; i<=p4; i++) { inSISIDXREG(SISPART4, i, sisReg->VBPart4[i]); #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "301xSave: Part4 0x%02x = 0x%02x\n", i, sisReg->VBPart4[i]); #endif } } /* Save SiS301 bridge register contents */ static void SiS301Save(ScrnInfoPtr pScrn, SISRegPtr sisReg) { SISPtr pSiS = SISPTR(pScrn); int Part1max, Part2max, Part3max, Part4max; /* Highest register number to save/restore */ if(pSiS->VGAEngine == SIS_300_VGA) Part1max = 0x1d; else Part1max = 0x2e; /* 0x23, but we also need 2d-2e */ Part2max = 0x45; Part3max = 0x3e; Part4max = 0x1b; SiSVBSave(pScrn, sisReg, Part1max, Part2max, Part3max, Part4max); sisReg->VBPart2[0x00] &= ~0x20; /* Disable VB Processor */ sisReg->sisRegs3C4[0x32] &= ~0x20; /* Disable Lock Mode */ } /* Restore SiS301 bridge register contents */ static void SiS301Restore(ScrnInfoPtr pScrn, SISRegPtr sisReg) { SISPtr pSiS = SISPTR(pScrn); int Part1max, Part2max, Part3max, Part4max; /* Highest register number to save/restore */ if(pSiS->VGAEngine == SIS_300_VGA) Part1max = 0x1d; else Part1max = 0x23; Part2max = 0x45; Part3max = 0x3e; Part4max = 0x1b; SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30); SiSSetLVDSetc(pSiS->SiS_Pr); SiS_GetVBType(pSiS->SiS_Pr); SiS_DisableBridge(pSiS->SiS_Pr); SiS_UnLockCRT2(pSiS->SiS_Pr); /* Pre-restore Part1 */ outSISIDXREG(SISPART1, 0x04, 0x00); outSISIDXREG(SISPART1, 0x05, 0x00); outSISIDXREG(SISPART1, 0x06, 0x00); outSISIDXREG(SISPART1, 0x00, sisReg->VBPart1[0]); outSISIDXREG(SISPART1, 0x01, sisReg->VBPart1[1]); /* Pre-restore Part4 */ outSISIDXREG(SISPART4, 0x0D, sisReg->VBPart4[0x0D]); outSISIDXREG(SISPART4, 0x0C, sisReg->VBPart4[0x0C]); if((!(sisReg->sisRegs3D4[0x30] & 0x03)) && (sisReg->sisRegs3D4[0x31] & 0x20)) { /* disable CRT2 */ SiS_LockCRT2(pSiS->SiS_Pr); return; } /* Restore Part1 */ SetBlock(SISPART1, 0x02, Part1max, &(sisReg->VBPart1[0x02])); if(pSiS->VGAEngine == SIS_315_VGA) { /* Restore extra registers on 315 series */ SetBlock(SISPART1, 0x2C, 0x2E, &(sisReg->VBPart1[0x2C])); } /* Restore Part2 */ SetBlock(SISPART2, 0x00, Part2max, &(sisReg->VBPart2[0x00])); /* Restore Part3 */ SetBlock(SISPART3, 0x00, Part3max, &(sisReg->VBPart3[0x00])); /* Restore Part4 */ SetBlock(SISPART4, 0x0E, 0x11, &(sisReg->VBPart4[0x0E])); SetBlock(SISPART4, 0x13, Part4max, &(sisReg->VBPart4[0x13])); /* Post-restore Part4 (CRT2VCLK) */ outSISIDXREG(SISPART4, 0x0A, 0x01); outSISIDXREG(SISPART4, 0x0B, sisReg->VBPart4[0x0B]); outSISIDXREG(SISPART4, 0x0A, sisReg->VBPart4[0x0A]); outSISIDXREG(SISPART4, 0x12, 0x00); outSISIDXREG(SISPART4, 0x12, sisReg->VBPart4[0x12]); SiS_EnableBridge(pSiS->SiS_Pr); SiS_DisplayOn(pSiS->SiS_Pr); SiS_LockCRT2(pSiS->SiS_Pr); } /* Save SiS30xB/30xLV bridge register contents */ static void SiS301BSave(ScrnInfoPtr pScrn, SISRegPtr sisReg) { SISPtr pSiS = SISPTR(pScrn); int Part1max, Part2max, Part3max, Part4max; Part1max = 0x60; Part2max = 0x4d; Part3max = 0x3e; Part4max = 0x23; if(pSiS->VBFlags2 & (VB2_301LV | VB2_302LV)) { Part4max = 0x34; } else if(pSiS->VBFlags2 & (VB2_301C | VB2_302ELV)) { Part2max = 0xff; Part4max = 0x3c; } /* TODO for 307 */ SiSVBSave(pScrn, sisReg, Part1max, Part2max, Part3max, Part4max); sisReg->VBPart2[0x00] &= ~0x20; /* Disable VB Processor */ sisReg->sisRegs3C4[0x32] &= ~0x20; /* Disable Lock Mode */ } /* Restore SiS30xB/30xLV bridge register contents */ static void SiS301BRestore(ScrnInfoPtr pScrn, SISRegPtr sisReg) { SISPtr pSiS = SISPTR(pScrn); int Part1max, Part2max, Part3max, Part4max; Part1max = 0x23; Part2max = 0x4d; Part3max = 0x3e; Part4max = 0x22; if(pSiS->VBFlags2 & (VB2_301LV|VB2_302LV)) { Part4max = 0x34; } else if(pSiS->VBFlags2 & (VB2_301C|VB2_302ELV)) { Part2max = 0xff; Part4max = 0x3c; } /* TODO for 307 */ SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30); SiSSetLVDSetc(pSiS->SiS_Pr); SiS_GetVBType(pSiS->SiS_Pr); SiS_DisableBridge(pSiS->SiS_Pr); SiS_UnLockCRT2(pSiS->SiS_Pr); /* Pre-restore Part1 */ outSISIDXREG(SISPART1, 0x04, 0x00); outSISIDXREG(SISPART1, 0x05, 0x00); outSISIDXREG(SISPART1, 0x06, 0x00); outSISIDXREG(SISPART1, 0x00, sisReg->VBPart1[0x00]); outSISIDXREG(SISPART1, 0x01, sisReg->VBPart1[0x01]); /* Mode reg 0x01 became 0x2e on 315 series (0x01 still contains FIFO) */ if(pSiS->VGAEngine == SIS_315_VGA) { outSISIDXREG(SISPART1, 0x2e, sisReg->VBPart1[0x2e]); } /* Pre-restore Part4 */ outSISIDXREG(SISPART4, 0x0D, sisReg->VBPart4[0x0D]); outSISIDXREG(SISPART4, 0x0C, sisReg->VBPart4[0x0C]); if((!(sisReg->sisRegs3D4[0x30] & 0x03)) && (sisReg->sisRegs3D4[0x31] & 0x20)) { /* disable CRT2 */ SiS_LockCRT2(pSiS->SiS_Pr); return; } /* Restore Part1 */ SetBlock(SISPART1, 0x02, Part1max, &(sisReg->VBPart1[0x02])); if(pSiS->VGAEngine == SIS_315_VGA) { SetBlock(SISPART1, 0x2C, 0x2D, &(sisReg->VBPart1[0x2C])); SetBlock(SISPART1, 0x35, 0x37, &(sisReg->VBPart1[0x35])); if((pSiS->ChipFlags & SiSCF_Is65x) || (pSiS->ChipType >= SIS_661)) { outSISIDXREG(SISPART1, 0x4c, sisReg->VBPart1[0x4c]); } outSISIDXREG(SISPART1, 0x2e, sisReg->VBPart1[0x2e] & 0x7f); } /* Restore Part2 */ SetBlock(SISPART2, 0x00, Part2max, &(sisReg->VBPart2[0x00])); /* Restore Part3 */ SetBlock(SISPART3, 0x00, Part3max, &(sisReg->VBPart3[0x00])); /* Restore Part4 */ SetBlock(SISPART4, 0x0E, 0x11, &(sisReg->VBPart4[0x0E])); SetBlock(SISPART4, 0x13, Part4max, &(sisReg->VBPart4[0x13])); /* Post-restore Part4 (CRT2VCLK) */ outSISIDXREG(SISPART4, 0x0A, sisReg->VBPart4[0x0A]); outSISIDXREG(SISPART4, 0x0B, sisReg->VBPart4[0x0B]); outSISIDXREG(SISPART4, 0x12, 0x00); outSISIDXREG(SISPART4, 0x12, sisReg->VBPart4[0x12]); SiS_EnableBridge(pSiS->SiS_Pr); SiS_DisplayOn(pSiS->SiS_Pr); SiS_LockCRT2(pSiS->SiS_Pr); } /* Save LVDS bridge (+ Chrontel) register contents */ static void SiSLVDSChrontelSave(ScrnInfoPtr pScrn, SISRegPtr sisReg) { SISPtr pSiS = SISPTR(pScrn); int i; /* Save Part1 */ for(i=0; i<0x46; i++) { inSISIDXREG(SISPART1, i, sisReg->VBPart1[i]); #ifdef TWDEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LVDSSave: Part1Port 0x%02x = 0x%02x\n", i, sisReg->VBPart1[i]); #endif } /* Save Chrontel registers */ if(pSiS->VBFlags2 & VB2_CHRONTEL) { if(pSiS->ChrontelType == CHRONTEL_700x) { for(i=0; i<0x1D; i++) { sisReg->ch70xx[i] = SiS_GetCH700x(pSiS->SiS_Pr, ch700xidx[i]); #ifdef TWDEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LVDSSave: Chrontel 0x%02x = 0x%02x\n", ch700xidx[i], sisReg->ch70xx[i]); #endif } } else { for(i=0; i<35; i++) { sisReg->ch70xx[i] = SiS_GetCH701x(pSiS->SiS_Pr, ch701xidx[i]); #ifdef TWDEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LVDSSave: Chrontel 0x%02x = 0x%02x\n", ch701xidx[i], sisReg->ch70xx[i]); #endif } } } sisReg->sisRegs3C4[0x32] &= ~0x20; /* Disable Lock Mode */ } /* Restore LVDS bridge (+ Chrontel) register contents */ static void SiSLVDSChrontelRestore(ScrnInfoPtr pScrn, SISRegPtr sisReg) { SISPtr pSiS = SISPTR(pScrn); int i; SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30); SiSSetLVDSetc(pSiS->SiS_Pr); SiS_GetVBType(pSiS->SiS_Pr); SiS_DisableBridge(pSiS->SiS_Pr); if(pSiS->ChipType == SIS_730) { outSISIDXREG(SISPART1, 0x00, 0x80); } SiS_UnLockCRT2(pSiS->SiS_Pr); if(pSiS->VBFlags2 & VB2_CHRONTEL) { /* Restore Chrontel registers */ if(pSiS->ChrontelType == CHRONTEL_700x) { for(i=0; i<0x11; i++) { SiS_SetCH700x(pSiS->SiS_Pr, ch700xidx[i] & 0xFF, sisReg->ch70xx[i]); } } else { for(i=0; i<34; i++) { SiS_SetCH701x(pSiS->SiS_Pr, ch701xidx[i] & 0xFF, sisReg->ch70xx[i]); } } } /* pre-restore Part1 */ outSISIDXREG(SISPART1, 0x04, 0x00); outSISIDXREG(SISPART1, 0x05, 0x00); outSISIDXREG(SISPART1, 0x06, 0x00); outSISIDXREG(SISPART1, 0x00, sisReg->VBPart1[0]); if(pSiS->VGAEngine == SIS_300_VGA) { outSISIDXREG(SISPART1, 0x01, (sisReg->VBPart1[1] | 0x80)); } else { outSISIDXREG(SISPART1, 0x01, sisReg->VBPart1[1]); } if((!(sisReg->sisRegs3D4[0x30] & 0x03)) && (sisReg->sisRegs3D4[0x31] & 0x20)) { /* disable CRT2 */ SiS_LockCRT2(pSiS->SiS_Pr); return; } /* Restore Part1 */ if(pSiS->VGAEngine == SIS_300_VGA) { outSISIDXREG(SISPART1, 0x02, (sisReg->VBPart1[2] | 0x40)); } else { outSISIDXREG(SISPART1, 0x02, sisReg->VBPart1[2]); } SetBlock(SISPART1, 0x03, 0x23, &(sisReg->VBPart1[0x03])); if(pSiS->VGAEngine == SIS_315_VGA) { SetBlock(SISPART1, 0x2C, 0x2E, &(sisReg->VBPart1[0x2C])); SetBlock(SISPART1, 0x35, 0x37, &(sisReg->VBPart1[0x35])); /* Panel Link Scaler */ } /* For 550 DSTN registers */ if(pSiS->DSTN || pSiS->FSTN) { SetBlock(SISPART1, 0x25, 0x2E, &(sisReg->VBPart1[0x25])); SetBlock(SISPART1, 0x30, 0x45, &(sisReg->VBPart1[0x30])); } SiS_EnableBridge(pSiS->SiS_Pr); SiS_DisplayOn(pSiS->SiS_Pr); SiS_LockCRT2(pSiS->SiS_Pr); } /* Restore output selection registers */ void SiSRestoreBridge(ScrnInfoPtr pScrn, SISRegPtr sisReg) { SISPtr pSiS = SISPTR(pScrn); int i; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif for(i = 0x30; i <= 0x3b; i++) { if(i == 0x34) continue; outSISIDXREG(SISCR, i, sisReg->sisRegs3D4[i]); } if(pSiS->VGAEngine == SIS_315_VGA) { outSISIDXREG(SISCR, pSiS->myCR63, sisReg->sisRegs3D4[pSiS->myCR63]); if(pSiS->ChipType < SIS_661) { outSISIDXREG(SISCR, 0x79, sisReg->sisRegs3D4[0x79]); } } } /* Auxiliary function to find real memory clock (in Khz) */ /* Not for 530/620 if UMA (on these, the mclk is stored in SR10) */ int SiSMclk(SISPtr pSiS) { int mclk=0; UChar Num, Denum, Base; switch (pSiS->Chipset) { case PCI_CHIP_SIS300: case PCI_CHIP_SIS540: case PCI_CHIP_SIS630: case PCI_CHIP_SIS315: case PCI_CHIP_SIS315H: case PCI_CHIP_SIS315PRO: case PCI_CHIP_SIS550: case PCI_CHIP_SIS650: case PCI_CHIP_SIS330: case PCI_CHIP_SIS660: case PCI_CHIP_SIS340: case PCI_CHIP_XGIXG20: case PCI_CHIP_XGIXG40: /* Numerator */ inSISIDXREG(SISSR, 0x28, Num); mclk = 14318 * ((Num & 0x7f) + 1); /* Denumerator */ inSISIDXREG(SISSR, 0x29, Denum); mclk = mclk / ((Denum & 0x1f) + 1); /* Divider */ if((Num & 0x80) != 0) mclk *= 2; /* Post-Scaler */ if((Denum & 0x80) == 0) { mclk = mclk / (((Denum & 0x60) >> 5) + 1); } else { mclk = mclk / ((((Denum & 0x60) >> 5) + 1) * 2); } break; case PCI_CHIP_SIS5597: case PCI_CHIP_SIS6326: case PCI_CHIP_SIS530: default: /* Numerator */ inSISIDXREG(SISSR, 0x28, Num); mclk = 14318 * ((Num & 0x7f) + 1); /* Denumerator */ inSISIDXREG(SISSR, 0x29, Denum); mclk = mclk / ((Denum & 0x1f) + 1); /* Divider. Doesn't work on older cards */ if(pSiS->oldChipset >= OC_SIS5597) { if(Num & 0x80) mclk *= 2; } /* Post-scaler. Values' meaning depends on SR13 bit 7 */ inSISIDXREG(SISSR, 0x13, Base); if((Base & 0x80) == 0) { mclk = mclk / (((Denum & 0x60) >> 5) + 1); } else { /* Values 00 and 01 are reserved */ if ((Denum & 0x60) == 0x40) mclk /= 6; if ((Denum & 0x60) == 0x60) mclk /= 8; } break; } return(mclk); } /* This estimates the CRT2 clock we are going to use. * The total bandwidth is to be reduced by the value * returned here in order to get an idea of the maximum * dotclock left for CRT1. * Since we don't know yet, what mode the user chose, * we return the maximum dotclock used by * - either the LCD attached, or * - TV * For VGA2, we share the bandwith equally. */ static int SiSEstimateCRT2Clock(ScrnInfoPtr pScrn, Bool FakeForCRT2) { SISPtr pSiS = SISPTR(pScrn); if(pSiS->VBFlags & CRT2_LCD) { if(pSiS->VBLCDFlags & (VB_LCD_320x480 | VB_LCD_800x600 | VB_LCD_640x480)) { return 40000; } else if(pSiS->VBLCDFlags & (VB_LCD_1024x768 | VB_LCD_1024x600 | VB_LCD_1152x768)) { return 65000; } else if(pSiS->VBLCDFlags & VB_LCD_1280x720) { /* Fake clock; VGA (4:3) mode is 108, but uses only 75 for LCD */ if(FakeForCRT2) return 108000; else return 75000; } else if(pSiS->VBLCDFlags & VB_LCD_1280x768) { /* Fake clock; VGA (4:3) mode is 108, but uses only 81 for LCD */ if(FakeForCRT2) return 108000; else return 81000; } else if(pSiS->VBLCDFlags & VB_LCD_1280x800) { /* Fake clock; VGA (4:3) mode is 108, but uses only 83 for LCD */ if(FakeForCRT2) return 108000; else return 83000; } else if(pSiS->VBLCDFlags & VB_LCD_1280x854) { /* Fake clock; VGA (4:3) mode is 108, but uses only 84 for LCD */ if(FakeForCRT2) return 108000; else return 84000; } else if(pSiS->VBLCDFlags & (VB_LCD_1280x1024 | VB_LCD_1280x960)) { return 108000; } else if(pSiS->VBLCDFlags & VB_LCD_1400x1050) { /* Fake clock; VGA mode is 122, but uses only 108 for LCD */ if(FakeForCRT2) return 123000; else return 108000; } else if(pSiS->VBLCDFlags & VB_LCD_1680x1050) { /* Fake clock; VGA mode is 147, but uses only 122 for LCD */ if(FakeForCRT2) return 148000; else return 122000; } else if(pSiS->VBLCDFlags & VB_LCD_1600x1200) { return 162000; } else if((pSiS->VBLCDFlags & VB_LCD_CUSTOM) && (pSiS->SiS_Pr->CP_MaxClock)) { return pSiS->SiS_Pr->CP_MaxClock; } else { if(pSiS->VBFlags2 & VB2_30xC) return 162000; else return 108000; } } else if(pSiS->VBFlags & CRT2_TV) { if(pSiS->VBFlags2 & VB2_CHRONTEL) { switch(pSiS->VGAEngine) { case SIS_300_VGA: return 50000; /* 700x: <= 800x600 */ case SIS_315_VGA: default: return 70000; /* 701x: <= 1024x768 */ } } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) { if(pSiS->SiS_SD_Flags & (SiS_SD_SUPPORTYPBPR|SiS_SD_SUPPORTHIVISION)) { if(FakeForCRT2) return 108000; /* 1280x1024@60 (faked) */ else return 75000; /* Really used clock */ } else { return 70000; } } } return 0; } /* Calculate the maximum dotclock */ int SiSMemBandWidth(ScrnInfoPtr pScrn, Bool IsForCRT2) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif int bus = pSiS->BusWidth; int mclk = pSiS->MemClock; int bpp = pSiS->CurrentLayout.bitsPerPixel; int max = 0; float magic = 0.0, total; int bytesperpixel = (bpp + 7) / 8; float crt2used, maxcrt2; int crt2clock; Bool DHM, GetForCRT1; #ifdef __SUNPRO_C #define const #endif const float magicDED[4] = { 1.2, 1.368421, 2.263158, 1.2}; const float magicINT[4] = { 1.441177, 1.441177, 2.588235, 1.441177 }; #ifdef __SUNPRO_C #undef const #endif switch(pSiS->Chipset) { case PCI_CHIP_SIS5597: total = ((mclk * (bus / 8)) * 0.7) / bytesperpixel; if(total > 135000) total = 135000; xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Maximum pixel clock at %d bpp is %g MHz\n", bpp, total/1000); return(int)(total); case PCI_CHIP_SIS6326: total = ((mclk * (bus / 8)) * 0.7) / bytesperpixel; if(total > 175500) total = 175500; xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Maximum pixel clock at %d bpp is %g MHz\n", bpp, total/1000); return(int)(total); case PCI_CHIP_SIS530: total = ((mclk * (bus / 8)) * 0.7) / bytesperpixel; if(total > 230000) total = 230000; xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Maximum pixel clock at %d bpp is %g MHz\n", bpp, total/1000); return(int)(total); case PCI_CHIP_SIS300: case PCI_CHIP_SIS540: case PCI_CHIP_SIS630: case PCI_CHIP_SIS315: case PCI_CHIP_SIS315H: case PCI_CHIP_SIS315PRO: case PCI_CHIP_SIS550: case PCI_CHIP_SIS650: case PCI_CHIP_SIS330: case PCI_CHIP_SIS660: case PCI_CHIP_SIS340: case PCI_CHIP_XGIXG20: case PCI_CHIP_XGIXG40: switch(pSiS->Chipset) { case PCI_CHIP_SIS300: magic = magicDED[bus/64]; max = 540000; break; case PCI_CHIP_SIS540: case PCI_CHIP_SIS630: magic = magicINT[bus/64]; max = 540000; break; case PCI_CHIP_SIS315: case PCI_CHIP_SIS315H: case PCI_CHIP_SIS315PRO: case PCI_CHIP_SIS330: magic = magicDED[bus/64]; max = 780000; break; case PCI_CHIP_SIS550: magic = magicINT[bus/64]; max = 610000; break; case PCI_CHIP_SIS650: magic = magicINT[bus/64]; max = 680000; break; case PCI_CHIP_SIS660: if((pSiS->ChipType >= SIS_660) && (pSiS->ChipFlags & SiSCF_760LFB)) { magic = magicDED[bus/64]; } else { magic = magicINT[bus/64]; } max = 680000; case PCI_CHIP_SIS340: case PCI_CHIP_XGIXG40: magic = magicDED[bus/64]; max = 800000; break; case PCI_CHIP_XGIXG20: magic = 1.0; /* magicDED[bus/64]; */ max = 332000; break; } PDEBUG(ErrorF("mclk: %d, bus: %d, magic: %g, bpp: %d\n", mclk, bus, magic, bpp)); total = mclk * bus / bpp; xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Memory bandwidth at %d bpp is %g MHz\n", bpp, total/1000); if((pSiS->VBFlags & CRT2_ENABLE) && (!pSiS->CRT1off)) { maxcrt2 = 135000; if(pSiS->VBFlags2 & (VB2_301B|VB2_302B)) maxcrt2 = 162000; else if(pSiS->VBFlags2 & VB2_301C) maxcrt2 = 203000; else if(pSiS->VBFlags2 & VB2_307T) maxcrt2 = 203000; /* TODO */ /* if(pSiS->VBFlags2 & VB2_30xBDH) maxcrt2 = 100000; Ignore 301B-DH here; seems the current version is like 301B anyway */ crt2used = 0.0; crt2clock = SiSEstimateCRT2Clock(pScrn, IsForCRT2); if(crt2clock) { crt2used = crt2clock + 2000; } DHM = FALSE; GetForCRT1 = FALSE; #ifdef SISDUALHEAD if((pSiS->DualHeadMode) && (pSiSEnt)) { DHM = TRUE; if(pSiS->SecondHead) GetForCRT1 = TRUE; } #endif #ifdef SISMERGED if(pSiS->MergedFB && IsForCRT2) { DHM = TRUE; GetForCRT1 = FALSE; } #endif if(DHM) { if(!GetForCRT1) { /* First head = CRT2 */ if(crt2clock) { /* We use the mem bandwidth as max clock; this * might exceed the 70% limit a bit, but that * does not matter; we take care of that limit * when we calc CRT1. Overall, we might use up * to 85% of the memory bandwidth, which seems * enough to use accel and video. * The "* macic" is just to compensate the * calculation below. */ total = crt2used * magic; } else { /* We don't know about the second head's * depth yet. So we assume it uses the * same. But since the maximum dotclock * is limited on CRT2, we can assume a * maximum here. */ if((total / 2) > (maxcrt2 + 2000)) { total = (maxcrt2 + 2000) * magic; crt2used = maxcrt2 + 2000; } else { total /= 2; crt2used = total; } } xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Bandwidth reserved for CRT2 is %g MHz\n", crt2used/1000); } else { #ifdef SISDUALHEAD /* Second head = CRT1 */ /* Now We know about the first head's depth, * so we can calculate more accurately. */ if(crt2clock) { total -= (crt2used * pSiSEnt->pScrn_1->bitsPerPixel / bpp); xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Bandwidth reserved for CRT2 at %d bpp is %g Mhz\n", bpp, (crt2used * pSiSEnt->pScrn_1->bitsPerPixel / bpp)/1000); } else { total -= (pSiSEnt->maxUsedClock * pSiSEnt->pScrn_1->bitsPerPixel / bpp); xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Bandwidth reserved for CRT2 at %d bpp is %d Mhz\n", bpp, (pSiSEnt->maxUsedClock * pSiSEnt->pScrn_1->bitsPerPixel / bpp)/1000); } xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Bandwidth available for CRT1 is %g MHz\n", total/1000); #endif } } else { if(crt2clock) { total -= crt2used; } else { if((total / 2) > (maxcrt2 + 2000)) { total -= (maxcrt2 + 2000); crt2used = maxcrt2 + 2000; } else { total /= 2; crt2used = total; } } xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Bandwidth reserved for CRT2 is %g Mhz\n", crt2used/1000); xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Bandwidth available for CRT1 is %g MHz\n", total/1000); } } total /= magic; if(total > (max / 2)) total = max / 2; return(int)(total); default: return(135000); } } /* Load the palette. We do this for all supported color depths * in order to support gamma correction. We hereby convert the * given colormap to a complete 24bit color palette and enable * the correspoding bit in SR7 to enable the 24bit lookup table. * Gamma correction for CRT2 is only supported on SiS video bridges. * There are there 6-bit-RGB values submitted even if bpp is 16 and * weight is 565, because SetWeight() sets rgbBits to the maximum * (which is 6 in the 565 case). */ void SISLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, VisualPtr pVisual) { SISPtr pSiS = SISPTR(pScrn); int i, j, index; int myshift = 8 - pScrn->rgbBits; UChar backup = 0; Bool dogamma1 = pSiS->CRT1gamma; Bool resetxvgamma = FALSE; #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; if(pSiS->DualHeadMode) dogamma1 = pSiSEnt->CRT1gamma; #endif PDEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LoadPalette()\n")); #ifdef SISDUALHEAD if((!pSiS->DualHeadMode) || (pSiS->SecondHead)) { #endif if(pSiS->VGAEngine == SIS_315_VGA) { inSISIDXREG(SISSR, 0x1f, backup); andSISIDXREG(SISSR, 0x1f, 0xe7); if( (pSiS->XvGamma) && (pSiS->MiscFlags & MISC_CRT1OVERLAYGAMMA) && ((pSiS->CurrentLayout.depth == 16) || (pSiS->CurrentLayout.depth == 24)) ) { orSISIDXREG(SISSR, 0x1f, 0x10); resetxvgamma = TRUE; } } switch(pSiS->CurrentLayout.depth) { case 15: if(dogamma1) { orSISIDXREG(SISSR, 0x07, 0x04); /* 315/330: depth 15 not supported, no MMIO code needed */ for(i=0; iChipFlags & SiSCF_MMIOPalette) { for(i=0; iIOBase, 0x8570, (colors[index].green << (myshift + 8)) | (colors[index >> 1].blue << (myshift + 16)) | (colors[index >> 1].red << myshift) | (((index << 2) + j) << 24)); } } } } else { for(i=0; i> 1].red << myshift); outSISREG(SISCOLDATA, colors[index].green << myshift); outSISREG(SISCOLDATA, colors[index >> 1].blue << myshift); } } } } } else { andSISIDXREG(SISSR, 0x07, ~0x04); } break; case 24: if(dogamma1) { orSISIDXREG(SISSR, 0x07, 0x04); if(pSiS->ChipFlags & SiSCF_MMIOPalette) { for(i=0; iIOBase, 0x8570, (colors[index].blue << 16) | (colors[index].green << 8) | (colors[index].red) | (index << 24)); } } } else { for(i=0; iChipFlags & SiSCF_MMIOPalette) { for(i=0; iIOBase, 0x8570, ((colors[index].blue) << 16) | ((colors[index].green) << 8) | (colors[index].red) | (index << 24)); } } else { for(i=0; i> 2); outSISREG(SISCOLDATA, colors[index].green >> 2); outSISREG(SISCOLDATA, colors[index].blue >> 2); } } } if(pSiS->VGAEngine == SIS_315_VGA) { outSISIDXREG(SISSR, 0x1f, backup); inSISIDXREG(SISSR, 0x07, backup); if((backup & 0x04) && (resetxvgamma) && (pSiS->ResetXvGamma)) { (pSiS->ResetXvGamma)(pScrn); } } #ifdef SISDUALHEAD } #endif #ifdef SISDUALHEAD if((!pSiS->DualHeadMode) || (!pSiS->SecondHead)) { #endif switch(pSiS->VGAEngine) { case SIS_300_VGA: case SIS_315_VGA: if(pSiS->VBFlags & CRT2_ENABLE) { /* Only the SiS bridges support a CRT2 palette */ if(pSiS->VBFlags2 & VB2_SISBRIDGE) { if((pSiS->CRT2SepGamma) && (pSiS->crt2cindices) && (pSiS->crt2colors)) { SiS301LoadPalette(pScrn, numColors, pSiS->crt2cindices, pSiS->crt2colors, myshift); } else { SiS301LoadPalette(pScrn, numColors, indices, colors, myshift); } } } } #ifdef SISDUALHEAD } #endif } void SiS_UpdateGammaCRT2(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); if((!pSiS->CRT2SepGamma) || (!pSiS->crt2cindices) || (!pSiS->crt2gcolortable)) return; #ifdef SISDUALHEAD if(pSiS->DualHeadMode) return; #endif SISCalculateGammaRampCRT2(pScrn); SiS301LoadPalette(pScrn, pSiS->CRT2ColNum, pSiS->crt2cindices, pSiS->crt2colors, (8 - pScrn->rgbBits)); } static void SiS301LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, int myshift) { SISPtr pSiS = SISPTR(pScrn); int i, j, index; Bool dogamma2 = pSiS->CRT2gamma; #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; if(pSiS->DualHeadMode) dogamma2 = pSiSEnt->CRT2gamma; #endif /* 301B-DH does not support a color palette for LCD */ if((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) return; switch(pSiS->CurrentLayout.depth) { case 15: if(dogamma2) { orSISIDXREG(SISPART4, 0x0d, 0x08); for(i=0; i> 1].red << myshift); outSISREG(SISCOL2DATA, colors[index].green << myshift); outSISREG(SISCOL2DATA, colors[index >> 1].blue << myshift); } } } } else { andSISIDXREG(SISPART4, 0x0d, ~0x08); } break; case 24: if(dogamma2) { orSISIDXREG(SISPART4, 0x0d, 0x08); for(i = 0; i < numColors; i++) { index = indices[i]; if(index < 256) { /* Paranoia */ outSISREG(SISCOL2IDX, index); outSISREG(SISCOL2DATA, colors[index].red); outSISREG(SISCOL2DATA, colors[index].green); outSISREG(SISCOL2DATA, colors[index].blue); } } } else { andSISIDXREG(SISPART4, 0x0d, ~0x08); } break; default: orSISIDXREG(SISPART4, 0x0d, 0x08); for(i = 0; i < numColors; i++) { index = indices[i]; outSISREG(SISCOL2IDX, index); outSISREG(SISCOL2DATA, colors[index].red); outSISREG(SISCOL2DATA, colors[index].green); outSISREG(SISCOL2DATA, colors[index].blue); } } } void SISDACPreInit(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); Bool IsForCRT2 = FALSE; #ifdef SISDUALHEAD if((pSiS->DualHeadMode) && (!pSiS->SecondHead)) IsForCRT2 = TRUE; #endif pSiS->MaxClock = SiSMemBandWidth(pScrn, IsForCRT2); switch (pSiS->Chipset) { case PCI_CHIP_SIS550: case PCI_CHIP_SIS315: case PCI_CHIP_SIS315H: case PCI_CHIP_SIS315PRO: case PCI_CHIP_SIS650: case PCI_CHIP_SIS330: case PCI_CHIP_SIS660: case PCI_CHIP_SIS340: case PCI_CHIP_XGIXG20: case PCI_CHIP_XGIXG40: pSiS->SiSSave = SiS315Save; pSiS->SiSRestore = SiS315Restore; break; case PCI_CHIP_SIS300: case PCI_CHIP_SIS540: case PCI_CHIP_SIS630: pSiS->SiSSave = SiS300Save; pSiS->SiSRestore = SiS300Restore; break; case PCI_CHIP_SIS5597: case PCI_CHIP_SIS6326: case PCI_CHIP_SIS530: default: pSiS->SiSSave = SiSSave; pSiS->SiSRestore = SiSRestore; break; } } static void SetBlock(CARD16 port, CARD8 from, CARD8 to, CARD8 *DataPtr) { CARD8 index; for(index = from; index <= to; index++, DataPtr++) { outSISIDXREG(port, index, *DataPtr); } } void SiS6326SetTVReg(ScrnInfoPtr pScrn, CARD8 index, CARD8 data) { SISPtr pSiS = SISPTR(pScrn); outSISIDXREG(SISCR, 0xE0, index); outSISIDXREG(SISCR, 0xE1, data); #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "SiS6326: Setting Tv %02x to %02x\n", index, data); #endif } UChar SiS6326GetTVReg(ScrnInfoPtr pScrn, CARD8 index) { SISPtr pSiS = SISPTR(pScrn); UChar data; outSISIDXREG(SISCR, 0xE0, index); inSISIDXREG(SISCR, 0xE1, data); return(data); } void SiS6326SetXXReg(ScrnInfoPtr pScrn, CARD8 index, CARD8 data) { SISPtr pSiS = SISPTR(pScrn); outSISIDXREG(SISCR, 0xE2, index); outSISIDXREG(SISCR, 0xE3, data); } UChar SiS6326GetXXReg(ScrnInfoPtr pScrn, CARD8 index) { SISPtr pSiS = SISPTR(pScrn); UChar data; outSISIDXREG(SISCR, 0xE2, index); inSISIDXREG(SISCR, 0xE3, data); return(data); } UChar SiSGetCopyROP(int rop) { const UChar sisALUConv[] = { 0x00, /* dest = 0; 0, GXclear, 0 */ 0x88, /* dest &= src; DSa, GXand, 0x1 */ 0x44, /* dest = src & ~dest; SDna, GXandReverse, 0x2 */ 0xCC, /* dest = src; S, GXcopy, 0x3 */ 0x22, /* dest &= ~src; DSna, GXandInverted, 0x4 */ 0xAA, /* dest = dest; D, GXnoop, 0x5 */ 0x66, /* dest = ^src; DSx, GXxor, 0x6 */ 0xEE, /* dest |= src; DSo, GXor, 0x7 */ 0x11, /* dest = ~src & ~dest; DSon, GXnor, 0x8 */ 0x99, /* dest ^= ~src ; DSxn, GXequiv, 0x9 */ 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */ 0xDD, /* dest = src|~dest ; SDno, GXorReverse, 0xB */ 0x33, /* dest = ~src; Sn, GXcopyInverted, 0xC */ 0xBB, /* dest |= ~src; DSno, GXorInverted, 0xD */ 0x77, /* dest = ~src|~dest; DSan, GXnand, 0xE */ 0xFF, /* dest = 0xFF; 1, GXset, 0xF */ }; return(sisALUConv[rop]); } UChar SiSGetPatternROP(int rop) { const UChar sisPatALUConv[] = { 0x00, /* dest = 0; 0, GXclear, 0 */ 0xA0, /* dest &= src; DPa, GXand, 0x1 */ 0x50, /* dest = src & ~dest; PDna, GXandReverse, 0x2 */ 0xF0, /* dest = src; P, GXcopy, 0x3 */ 0x0A, /* dest &= ~src; DPna, GXandInverted, 0x4 */ 0xAA, /* dest = dest; D, GXnoop, 0x5 */ 0x5A, /* dest = ^src; DPx, GXxor, 0x6 */ 0xFA, /* dest |= src; DPo, GXor, 0x7 */ 0x05, /* dest = ~src & ~dest; DPon, GXnor, 0x8 */ 0xA5, /* dest ^= ~src ; DPxn, GXequiv, 0x9 */ 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */ 0xF5, /* dest = src|~dest ; PDno, GXorReverse, 0xB */ 0x0F, /* dest = ~src; Pn, GXcopyInverted, 0xC */ 0xAF, /* dest |= ~src; DPno, GXorInverted, 0xD */ 0x5F, /* dest = ~src|~dest; DPan, GXnand, 0xE */ 0xFF, /* dest = 0xFF; 1, GXset, 0xF */ }; return(sisPatALUConv[rop]); }