xenocara/driver/xf86-video-sis/src/sis_dac.c
oga 73d1e76463 Update SiS driver to 0.10
Tested by todd.
ok Matthieu.
2008-04-19 14:03:12 +00:00

2098 lines
63 KiB
C

/*
* 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 <thomas@winischhofer.net>
*
* --------------------------------------------------------------------------
*
* SiS_compute_vclk(), SiSCalcClock() and parts of SiSMclk():
*
* Copyright (C) 1998, 1999 by Alan Hourihane, Wigan, England
* Written by:
* Alan Hourihane <alanh@fairlite.demon.co.uk>,
* Mike Chapman <mike@paranoia.com>,
* Juanjo Santamarta <santamarta@ctv.es>,
* Mitani Hiroshi <hmitani@drl.mei.co.jp>,
* David Thomas <davtom@dream.org.uk>,
* Thomas Winischhofer <thomas@winischhofer.net>.
*
* 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, 0);
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, 0);
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, 0);
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, 0);
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; i<numColors; i++) {
index = indices[i];
if(index < 32) { /* Paranoia */
for(j=0; j<8; j++) {
outSISREG(SISCOLIDX, (index << 3) + j);
outSISREG(SISCOLDATA, colors[index].red << myshift);
outSISREG(SISCOLDATA, colors[index].green << myshift);
outSISREG(SISCOLDATA, colors[index].blue << myshift);
}
}
}
} else {
andSISIDXREG(SISSR, 0x07, ~0x04);
}
break;
case 16:
if(dogamma1) {
orSISIDXREG(SISSR, 0x07, 0x04);
if(pSiS->ChipFlags & SiSCF_MMIOPalette) {
for(i=0; i<numColors; i++) {
index = indices[i];
if(index < 64) { /* Paranoia */
for(j=0; j<4; j++) {
SIS_MMIO_OUT32(pSiS->IOBase, 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<numColors; i++) {
index = indices[i];
if(index < 64) { /* Paranoia */
for(j=0; j<4; j++) {
outSISREG(SISCOLIDX, (index << 2) + j);
outSISREG(SISCOLDATA, colors[index >> 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; i<numColors; i++) {
index = indices[i];
if(index < 256) { /* Paranoia */
SIS_MMIO_OUT32(pSiS->IOBase, 0x8570,
(colors[index].blue << 16) |
(colors[index].green << 8) |
(colors[index].red) |
(index << 24));
}
}
} else {
for(i=0; i<numColors; i++) {
index = indices[i];
if(index < 256) { /* Paranoia */
outSISREG(SISCOLIDX, index);
outSISREG(SISCOLDATA, colors[index].red);
outSISREG(SISCOLDATA, colors[index].green);
outSISREG(SISCOLDATA, colors[index].blue);
}
}
}
} else {
andSISIDXREG(SISSR, 0x07, ~0x04);
}
break;
default:
andSISIDXREG(SISSR, 0x07, ~0x04);
if(pSiS->ChipFlags & SiSCF_MMIOPalette) {
for(i=0; i<numColors; i++) {
index = indices[i];
SIS_MMIO_OUT32(pSiS->IOBase, 0x8570,
((colors[index].blue) << 16) |
((colors[index].green) << 8) |
(colors[index].red) |
(index << 24));
}
} else {
for(i=0; i<numColors; i++) {
/* In pio mode, only 6 bits are supported */
index = indices[i];
outSISREG(SISCOLIDX, index);
outSISREG(SISCOLDATA, colors[index].red >> 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<numColors; i++) {
index = indices[i];
if(index < 32) { /* Paranoia */
for(j=0; j<8; j++) {
outSISREG(SISCOL2IDX, (index << 3) + j);
outSISREG(SISCOL2DATA, colors[index].red << myshift);
outSISREG(SISCOL2DATA, colors[index].green << myshift);
outSISREG(SISCOL2DATA, colors[index].blue << myshift);
}
}
}
} else {
andSISIDXREG(SISPART4, 0x0d, ~0x08);
}
break;
case 16:
if(dogamma2) {
orSISIDXREG(SISPART4, 0x0d, 0x08);
for(i = 0; i < numColors; i++) {
index = indices[i];
if(index < 64) { /* Paranoia */
for(j = 0; j < 4; j++) {
outSISREG(SISCOL2IDX, (index << 2) + j);
outSISREG(SISCOL2DATA, colors[index >> 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]);
}