73d1e76463
Tested by todd. ok Matthieu.
2098 lines
63 KiB
C
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]);
|
|
}
|