#include "xf86.h"
#include "xf86_OSproc.h"
#include "xf86_ansic.h"
#include "xf86PciInfo.h"
#include "xf86Pci.h"
#include "mga_bios.h"
#include "mga_reg.h"
#include "mga.h"
#include "mga_macros.h"
#include "xf86DDC.h"
#define OPTION_MASK 0xFFEFFEFF
static void MGA3026LoadPalette(ScrnInfoPtr, int, int*, LOCO*, VisualPtr);
static void MGA3026SavePalette(ScrnInfoPtr, unsigned char*);
static void MGA3026RestorePalette(ScrnInfoPtr, unsigned char*);
static void MGA3026RamdacInit(ScrnInfoPtr);
static void MGA3026Save(ScrnInfoPtr, vgaRegPtr, MGARegPtr, Bool);
static void MGA3026Restore(ScrnInfoPtr, vgaRegPtr, MGARegPtr, Bool);
static Bool MGA3026Init(ScrnInfoPtr, DisplayModePtr);
static Bool MGA3026_i2cInit(ScrnInfoPtr pScrn);
const static unsigned char MGADACregs[] = {
0x0F, 0x18, 0x19, 0x1A, 0x1C, 0x1D, 0x1E, 0x2A, 0x2B, 0x30,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
0x06
};
#define DACREGSIZE sizeof(MGADACregs)
const static unsigned char MGADACbpp8[DACREGSIZE] = {
0x06, 0x80, 0x4b, 0x25, 0x00, 0x00, 0x0C, 0x00, 0x1E, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0, 0x00,
0x00
};
const static unsigned char MGADACbpp16[DACREGSIZE] = {
0x07, 0x45, 0x53, 0x15, 0x00, 0x00, 0x2C, 0x00, 0x1E, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x10, 0, 0x00,
0x00
};
const static unsigned char MGADACbpp24[DACREGSIZE] = {
0x06, 0x56, 0x5b, 0x25, 0x00, 0x00, 0x2C, 0x00, 0x1E, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x10, 0, 0x00,
0x00
};
const static unsigned char MGADACbpp32[DACREGSIZE] = {
0x07, 0x46, 0x5b, 0x05, 0x00, 0x00, 0x2C, 0x00, 0x1E, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x10, 0, 0x00,
0x00
};
const static unsigned char MGADACbpp8plus24[DACREGSIZE] = {
0x07, 0x06, 0x5b, 0x05, 0x00, 0x00, 0x2C, 0x00, 0x1E, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x00,
0x00
};
#define inTi3026dreg(reg) INREG8(RAMDAC_OFFSET + (reg))
#define outTi3026dreg(reg, val) OUTREG8(RAMDAC_OFFSET + (reg), val)
#define inTi3026(reg) \
(outTi3026dreg(TVP3026_INDEX, reg), inTi3026dreg(TVP3026_DATA))
#define outTi3026(reg, mask, val) \
do { \
unsigned char tmp = (mask) ? (inTi3026(reg) & (mask)) : 0; \
outTi3026dreg(TVP3026_INDEX, reg); \
outTi3026dreg(TVP3026_DATA, tmp | (val)); \
} while (0)
#define TI_MIN_VCO_FREQ 110000
#define TI_MAX_VCO_FREQ 220000
#define TI_MAX_MCLK_FREQ 100000
#define TI_REF_FREQ 14318.18
static double
MGATi3026CalcClock (
long f_out, long f_max,
int *m, int *n, int *p
){
int best_m = 0, best_n = 0;
double f_pll, f_vco;
double m_err, inc_m, calc_m;
if ( f_out < ( TI_MIN_VCO_FREQ / 8 ))
f_out = TI_MIN_VCO_FREQ / 8;
if ( f_out > f_max )
f_out = f_max;
f_vco = ( double ) f_out;
for ( *p = 0; *p < 3 && f_vco < TI_MIN_VCO_FREQ; ( *p )++ )
f_vco *= 2.0;
inc_m = f_vco / ( TI_REF_FREQ * 8.0 );
calc_m = inc_m + inc_m + inc_m;
m_err = 2.0;
for ( *n = 3; *n <= 25; ( *n )++, calc_m += inc_m ) {
if ( calc_m < 3.0 || calc_m > 64.0 )
continue;
if (( calc_m - ( int ) calc_m ) < m_err ) {
m_err = calc_m - ( int ) calc_m;
best_m = ( int ) calc_m;
best_n = *n;
}
}
*m = 65 - best_m;
*n = 65 - best_n;
f_vco = 8.0 * TI_REF_FREQ * best_m / best_n;
f_pll = f_vco / ( 1 << *p );
#ifdef DEBUG
ErrorF( "f_out=%ld f_pll=%.1f f_vco=%.1f n=%d m=%d p=%d\n",
f_out, f_pll, f_vco, *n, *m, *p );
#endif
return f_pll;
}
static void
MGATi3026SetMCLK( ScrnInfoPtr pScrn, long f_out )
{
int mclk_m, mclk_n, mclk_p;
int pclk_m, pclk_n, pclk_p;
int mclk_ctl;
MGAPtr pMga = MGAPTR(pScrn);
MGATi3026CalcClock(f_out, TI_MAX_MCLK_FREQ, &mclk_m, &mclk_n, &mclk_p);
outTi3026( TVP3026_PLL_ADDR, 0, 0xfc );
pclk_n = inTi3026( TVP3026_PIX_CLK_DATA );
outTi3026( TVP3026_PLL_ADDR, 0, 0xfd );
pclk_m = inTi3026( TVP3026_PIX_CLK_DATA );
outTi3026( TVP3026_PLL_ADDR, 0, 0xfe );
pclk_p = inTi3026( TVP3026_PIX_CLK_DATA );
outTi3026( TVP3026_PLL_ADDR, 0, 0xfe );
outTi3026( TVP3026_PIX_CLK_DATA, 0, 0x00 );
outTi3026( TVP3026_PLL_ADDR, 0, 0xfc );
outTi3026( TVP3026_PIX_CLK_DATA, 0, ( mclk_n & 0x3f ) | 0xc0 );
outTi3026( TVP3026_PIX_CLK_DATA, 0, mclk_m & 0x3f );
outTi3026( TVP3026_PIX_CLK_DATA, 0, ( mclk_p & 0x03 ) | 0xb0 );
while (( inTi3026( TVP3026_PIX_CLK_DATA ) & 0x40 ) == 0 ) {
;
}
mclk_ctl = inTi3026( TVP3026_MCLK_CTL );
outTi3026( TVP3026_MCLK_CTL, 0, mclk_ctl & 0xe7 );
outTi3026( TVP3026_MCLK_CTL, 0, ( mclk_ctl & 0xe7 ) | 0x08 );
outTi3026( TVP3026_PLL_ADDR, 0, 0xfb );
outTi3026( TVP3026_MEM_CLK_DATA, 0, 0x00 );
outTi3026( TVP3026_PLL_ADDR, 0, 0xf3 );
outTi3026( TVP3026_MEM_CLK_DATA, 0, ( mclk_n & 0x3f ) | 0xc0 );
outTi3026( TVP3026_MEM_CLK_DATA, 0, mclk_m & 0x3f );
outTi3026( TVP3026_MEM_CLK_DATA, 0, ( mclk_p & 0x03 ) | 0xb0 );
while (( inTi3026( TVP3026_MEM_CLK_DATA ) & 0x40 ) == 0 ) {
;
}
outTi3026( TVP3026_MCLK_CTL, 0, ( mclk_ctl & 0xe7 ) | 0x10 );
outTi3026( TVP3026_MCLK_CTL, 0, ( mclk_ctl & 0xe7 ) | 0x18 );
outTi3026( TVP3026_PLL_ADDR, 0, 0xfe );
outTi3026( TVP3026_PIX_CLK_DATA, 0, 0x00 );
outTi3026( TVP3026_PLL_ADDR, 0, 0xfc );
outTi3026( TVP3026_PIX_CLK_DATA, 0, pclk_n );
outTi3026( TVP3026_PIX_CLK_DATA, 0, pclk_m );
outTi3026( TVP3026_PIX_CLK_DATA, 0, pclk_p );
while (( inTi3026( TVP3026_PIX_CLK_DATA ) & 0x40 ) == 0 ) {
;
}
}
static void
MGATi3026SetPCLK( ScrnInfoPtr pScrn, long f_out, int bpp )
{
int m, n, p;
int lm, ln, lp, lq;
double z;
double f_pll;
long f_max = TI_MAX_VCO_FREQ;
MGAPtr pMga = MGAPTR(pScrn);
MGARegPtr pReg = &pMga->ModeReg;
if ( pMga->MaxClock > TI_MAX_VCO_FREQ )
f_max = pMga->MaxClock;
f_pll = MGATi3026CalcClock( f_out, f_max, & m, & n, & p );
pReg->DacClk[ 0 ] = ( n & 0x3f ) | 0xc0;
pReg->DacClk[ 1 ] = ( m & 0x3f );
pReg->DacClk[ 2 ] = ( p & 0x03 ) | 0xb0;
if ( pMga->CurrentLayout.bitsPerPixel == 24 ) {
lm = 65 - 3;
if ( bpp == 2 )
ln = 65 - 4;
else
ln = 65 - 8;
z = ( 11000 * ( 65 - ln )) / (( f_pll / 1000 ) * ( 65 - lm ));
}
else {
lm = 65 - 4;
ln = 65 - 4 * ( 64 / 8 ) / bpp;
z = (( 11000 / 4 ) * ( 65 - ln )) / ( f_pll / 1000 );
}
lq = 0;
if ( z <= 200.0 )
lp = 0;
else if ( z <= 400.0 )
lp = 1;
else if ( z <= 800.0 )
lp = 2;
else if ( z <= 1600.0 )
lp = 3;
else {
lp = 3;
lq = ( int )( z / 1600.0 );
}
if ( pMga->CurrentLayout.bitsPerPixel == 24 ) {
pReg->DacClk[ 3 ] = ( ln & 0x3f ) | 0x80;
pReg->DacClk[ 4 ] = ( lm & 0x3f ) | 0x80;
pReg->DacClk[ 5 ] = ( lp & 0x03 ) | 0xf8;
} else {
pReg->DacClk[ 3 ] = ( ln & 0x3f ) | 0xc0;
pReg->DacClk[ 4 ] = ( lm & 0x3f );
pReg->DacClk[ 5 ] = ( lp & 0x03 ) | 0xf0;
}
pReg->DacRegs[ 18 ] = lq | 0x38;
#ifdef DEBUG
ErrorF( "bpp=%d z=%.1f ln=%d lm=%d lp=%d lq=%d\n",
bpp, z, ln, lm, lp, lq );
#endif
}
static Bool
MGA3026Init(ScrnInfoPtr pScrn, DisplayModePtr mode)
{
int hd, hs, he, ht, vd, vs, ve, vt, wd;
int i, BppShift, index_1d = 0;
const unsigned char* initDAC;
MGAPtr pMga = MGAPTR(pScrn);
MGARamdacPtr MGAdac = &pMga->Dac;
MGAFBLayout *pLayout = &pMga->CurrentLayout;
MGARegPtr pReg = &pMga->ModeReg;
vgaRegPtr pVga = &VGAHWPTR(pScrn)->ModeReg;
BppShift = pMga->BppShifts[(pLayout->bitsPerPixel >> 3) - 1];
switch(pLayout->bitsPerPixel)
{
case 8:
initDAC = MGADACbpp8;
break;
case 16:
initDAC = MGADACbpp16;
break;
case 24:
initDAC = MGADACbpp24;
break;
case 32:
if(pLayout->Overlay8Plus24)
initDAC = MGADACbpp8plus24;
else
initDAC = MGADACbpp32;
break;
default:
FatalError("MGA: unsupported bits per pixel\n");
}
if (pReg->DacRegs == NULL) {
pReg->DacRegs = xnfcalloc(DACREGSIZE, 1);
}
for (i = 0; i < DACREGSIZE; i++) {
pReg->DacRegs[i] = initDAC[i];
if (MGADACregs[i] == 0x1D)
index_1d = i;
}
if((pLayout->bitsPerPixel == 32) && pLayout->Overlay8Plus24) {
pReg->DacRegs[9] = pMga->colorKey;
pReg->DacRegs[10] = pMga->colorKey;
}
if ( (pLayout->bitsPerPixel == 16) && (pLayout->weight.red == 5)
&& (pLayout->weight.green == 5) && (pLayout->weight.blue == 5) ) {
pReg->DacRegs[1] &= ~0x01;
}
if (pMga->Interleave ) pReg->DacRegs[2] += 1;
if ( pLayout->bitsPerPixel == 24 ) {
int silicon_rev;
silicon_rev = inTi3026(TVP3026_SILICON_REV);
#ifdef DEBUG
ErrorF("TVP3026 revision 0x%x (rev %s)\n",
silicon_rev, (silicon_rev <= 0x20) ? "A" : "B");
#endif
if(silicon_rev <= 0x20) {
pReg->DacRegs[0] = 0x07;
} else {
pReg->DacRegs[0] = 0x06;
}
}
if (!vgaHWInit(pScrn, mode))
return(FALSE);
hd = (mode->CrtcHDisplay >> 3) - 1;
hs = (mode->CrtcHSyncStart >> 3) - 1;
he = (mode->CrtcHSyncEnd >> 3) - 1;
ht = (mode->CrtcHTotal >> 3) - 1;
vd = mode->CrtcVDisplay - 1;
vs = mode->CrtcVSyncStart - 1;
ve = mode->CrtcVSyncEnd - 1;
vt = mode->CrtcVTotal - 2;
if((ht & 0x07) == 0x06 || (ht & 0x07) == 0x04)
ht++;
if (pLayout->bitsPerPixel == 24)
wd = (pLayout->displayWidth * 3) >> (4 - BppShift);
else
wd = pLayout->displayWidth >> (4 - BppShift);
pReg->ExtVga[0] = 0;
pReg->ExtVga[5] = 0;
if (mode->Flags & V_INTERLACE)
{
pReg->ExtVga[0] = 0x80;
pReg->ExtVga[5] = (hs + he - ht) >> 1;
wd <<= 1;
vt &= 0xFFFE;
pReg->DacRegs[20] |= 0x20;
}
pReg->ExtVga[0] |= (wd & 0x300) >> 4;
pReg->ExtVga[1] = (((ht - 4) & 0x100) >> 8) |
((hd & 0x100) >> 7) |
((hs & 0x100) >> 6) |
(ht & 0x40);
pReg->ExtVga[2] = ((vt & 0xc00) >> 10) |
((vd & 0x400) >> 8) |
((vd & 0xc00) >> 7) |
((vs & 0xc00) >> 5);
if (pLayout->bitsPerPixel == 24)
pReg->ExtVga[3] = (((1 << BppShift) * 3) - 1) | 0x80;
else
pReg->ExtVga[3] = ((1 << BppShift) - 1) | 0x80;
pReg->ExtVga[3] |= (pScrn->videoRam == 8192 ? 0x10
: pScrn->videoRam == 2048 ? 0x08 : 0x00);
pReg->ExtVga[4] = 0;
pVga->CRTC[0] = ht - 4;
pVga->CRTC[1] = hd;
pVga->CRTC[2] = hd;
pVga->CRTC[3] = (ht & 0x1F) | 0x80;
pVga->CRTC[4] = hs;
pVga->CRTC[5] = ((ht & 0x20) << 2) | (he & 0x1F);
pVga->CRTC[6] = vt & 0xFF;
pVga->CRTC[7] = ((vt & 0x100) >> 8 ) |
((vd & 0x100) >> 7 ) |
((vs & 0x100) >> 6 ) |
((vd & 0x100) >> 5 ) |
0x10 |
((vt & 0x200) >> 4 ) |
((vd & 0x200) >> 3 ) |
((vs & 0x200) >> 2 );
pVga->CRTC[9] = ((vd & 0x200) >> 4) | 0x40;
pVga->CRTC[16] = vs & 0xFF;
pVga->CRTC[17] = (ve & 0x0F) | 0x20;
pVga->CRTC[18] = vd & 0xFF;
pVga->CRTC[19] = wd & 0xFF;
pVga->CRTC[21] = vd & 0xFF;
pVga->CRTC[22] = (vt + 1) & 0xFF;
if (mode->Flags & V_DBLSCAN)
pVga->CRTC[9] |= 0x80;
pVga->MiscOutReg |= 0xC0;
if ((mode->Flags & (V_PHSYNC | V_NHSYNC)) &&
(mode->Flags & (V_PVSYNC | V_NVSYNC)))
{
if (mode->Flags & V_PHSYNC)
pReg->DacRegs[index_1d] |= 0x01;
if (mode->Flags & V_PVSYNC)
pReg->DacRegs[index_1d] |= 0x02;
}
else
{
int VDisplay = mode->VDisplay;
if (mode->Flags & V_DBLSCAN)
VDisplay *= 2;
if (VDisplay < 400)
pReg->DacRegs[index_1d] |= 0x01;
else if (VDisplay < 480)
pReg->DacRegs[index_1d] |= 0x02;
else if (VDisplay < 768)
pReg->DacRegs[index_1d] |= 0x00;
else
pReg->DacRegs[index_1d] |= 0x03;
}
if (pMga->SyncOnGreen)
pReg->DacRegs[index_1d] |= 0x20;
pReg->Option = 0x402C0100;
if (pMga->Interleave)
pReg->Option |= 0x1000;
else
pReg->Option &= ~0x1000;
pReg->Option &= ~0x20000000;
pVga->MiscOutReg |= 0x0C;
MGATi3026SetPCLK( pScrn, mode->Clock, 1 << BppShift );
MGA_NOT_HAL(MGATi3026SetMCLK(pScrn, MGAdac->MemoryClock));
#ifdef DEBUG
ErrorF("%6ld: %02X %02X %02X %02X %02X %02X %08lX\n", mode->Clock,
pReg->DacClk[0], pReg->DacClk[1], pReg->DacClk[2], pReg->DacClk[3], pReg->DacClk[4], pReg->DacClk[5], pReg->Option);
for (i=0; i<sizeof(MGADACregs); i++) ErrorF("%02X ", pReg->DacRegs[i]);
for (i=0; i<6; i++) ErrorF(" %02X", pReg->ExtVga[i]);
ErrorF("\n");
#endif
pVga->MiscOutReg &= ~0x02;
return(TRUE);
}
static void
MGA3026Restore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, MGARegPtr mgaReg,
Bool restoreFonts)
{
int i;
MGAPtr pMga = MGAPTR(pScrn);
for (i = 0; i < 6; i++)
OUTREG16(0x1FDE, (mgaReg->ExtVga[i] << 8) | i);
pciSetBitsLong(pMga->PciTag, PCI_OPTION_REG, OPTION_MASK,
mgaReg->Option);
MGA_NOT_HAL(
outTi3026(TVP3026_CLK_SEL, 0, mgaReg->DacRegs[3]);
outTi3026(TVP3026_PLL_ADDR, 0, 0x2A);
outTi3026(TVP3026_LOAD_CLK_DATA, 0, 0);
outTi3026(TVP3026_PIX_CLK_DATA, 0, 0);
);
vgaHWRestore(pScrn, vgaReg,
VGA_SR_MODE | (restoreFonts ? VGA_SR_FONTS : 0));
MGA3026RestorePalette(pScrn, vgaReg->DAC);
MGA_NOT_HAL(
outTi3026(TVP3026_PLL_ADDR, 0, 0x00);
for (i = 0; i < 3; i++)
outTi3026(TVP3026_PIX_CLK_DATA, 0, mgaReg->DacClk[i]);
if (vgaReg->MiscOutReg & 0x08) {
outTi3026(TVP3026_PLL_ADDR, 0, 0x3F);
while ( ! (inTi3026(TVP3026_PIX_CLK_DATA) & 0x40) );
}
outTi3026(TVP3026_MCLK_CTL, 0, mgaReg->DacRegs[18]);
);
outTi3026(TVP3026_PLL_ADDR, 0, 0x00);
for (i = 3; i < 6; i++)
outTi3026(TVP3026_LOAD_CLK_DATA, 0, mgaReg->DacClk[i]);
MGA_NOT_HAL(
if ((vgaReg->MiscOutReg & 0x08) && ((mgaReg->DacClk[3] & 0xC0) == 0xC0) ) {
outTi3026(TVP3026_PLL_ADDR, 0, 0x3F);
while ( ! (inTi3026(TVP3026_LOAD_CLK_DATA) & 0x40) );
}
);
for (i = 0; i < DACREGSIZE; i++)
outTi3026(MGADACregs[i], 0, mgaReg->DacRegs[i]);
#ifdef DEBUG
ErrorF("PCI retry (0-enabled / 1-disabled): %d\n",
!!(mgaReg->Option & 0x20000000));
#endif
}
static void
MGA3026Save(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, MGARegPtr mgaReg,
Bool saveFonts)
{
int i;
MGAPtr pMga = MGAPTR(pScrn);
if (mgaReg->DacRegs == NULL) {
mgaReg->DacRegs = xnfcalloc(DACREGSIZE, 1);
}
OUTREG16(0x1FDE, 0x0004);
vgaHWSave(pScrn, vgaReg, VGA_SR_MODE | (saveFonts ? VGA_SR_FONTS : 0));
MGA3026SavePalette(pScrn, vgaReg->DAC);
for (i = 0; i < 6; i++)
{
OUTREG8(0x1FDE, i);
mgaReg->ExtVga[i] = INREG8(0x1FDF);
}
MGA_NOT_HAL(
outTi3026(TVP3026_PLL_ADDR, 0, 0x00);
for (i = 0; i < 3; i++)
outTi3026(TVP3026_PIX_CLK_DATA, 0, mgaReg->DacClk[i] =
inTi3026(TVP3026_PIX_CLK_DATA));
outTi3026(TVP3026_PLL_ADDR, 0, 0x00);
for (i = 3; i < 6; i++)
outTi3026(TVP3026_LOAD_CLK_DATA, 0, mgaReg->DacClk[i] =
inTi3026(TVP3026_LOAD_CLK_DATA));
);
for (i = 0; i < DACREGSIZE; i++)
mgaReg->DacRegs[i] = inTi3026(MGADACregs[i]);
mgaReg->Option = pciReadLong(pMga->PciTag, PCI_OPTION_REG);
#ifdef DEBUG
ErrorF("read: %02X %02X %02X %02X %02X %02X %08lX\n",
mgaReg->DacClk[0], mgaReg->DacClk[1], mgaReg->DacClk[2], mgaReg->DacClk[3], mgaReg->DacClk[4], mgaReg->DacClk[5], mgaReg->Option);
for (i=0; i<sizeof(MGADACregs); i++) ErrorF("%02X ", mgaReg->DacRegs[i]);
for (i=0; i<6; i++) ErrorF(" %02X", mgaReg->ExtVga[i]);
ErrorF("\n");
#endif
}
static void
MGA3026LoadCursorImage(
ScrnInfoPtr pScrn,
unsigned char *src
)
{
MGAPtr pMga = MGAPTR(pScrn);
int i = 1024;
outTi3026(TVP3026_CURSOR_CTL, 0xf3, 0x00);
outTi3026dreg(TVP3026_WADR_PAL, 0x00);
while(i--) {
while (INREG8(0x1FDA) & 0x01);
while (!(INREG8(0x1FDA) & 0x01));
outTi3026dreg(TVP3026_CUR_RAM, *(src++));
}
}
static void
MGA3026ShowCursor(ScrnInfoPtr pScrn)
{
MGAPtr pMga = MGAPTR(pScrn);
outTi3026(TVP3026_CURSOR_CTL, 0x6c, 0x13);
}
static void
MGA3026HideCursor(ScrnInfoPtr pScrn)
{
MGAPtr pMga = MGAPTR(pScrn);
outTi3026(TVP3026_CURSOR_CTL, 0xfc, 0x00);
}
static void
MGA3026SetCursorPosition(
ScrnInfoPtr pScrn,
int x, int y
)
{
MGAPtr pMga = MGAPTR(pScrn);
x += 64;
y += 64;
outTi3026dreg(TVP3026_CUR_XLOW, x & 0xFF);
outTi3026dreg(TVP3026_CUR_XHI, (x >> 8) & 0x0F);
outTi3026dreg(TVP3026_CUR_YLOW, y & 0xFF);
outTi3026dreg(TVP3026_CUR_YHI, (y >> 8) & 0x0F);
}
static void
MGA3026SetCursorColors(
ScrnInfoPtr pScrn,
int bg, int fg
)
{
MGAPtr pMga = MGAPTR(pScrn);
outTi3026dreg(TVP3026_CUR_COL_ADDR, 1);
outTi3026dreg(TVP3026_CUR_COL_DATA, (bg & 0x00FF0000) >> 16);
outTi3026dreg(TVP3026_CUR_COL_DATA, (bg & 0x0000FF00) >> 8);
outTi3026dreg(TVP3026_CUR_COL_DATA, (bg & 0x000000FF));
outTi3026dreg(TVP3026_CUR_COL_ADDR, 2);
outTi3026dreg(TVP3026_CUR_COL_DATA, (fg & 0x00FF0000) >> 16);
outTi3026dreg(TVP3026_CUR_COL_DATA, (fg & 0x0000FF00) >> 8);
outTi3026dreg(TVP3026_CUR_COL_DATA, (fg & 0x000000FF));
}
static Bool
MGA3026UseHWCursor(ScreenPtr pScrn, CursorPtr pCurs)
{
if( XF86SCRNINFO(pScrn)->currentMode->Flags & V_DBLSCAN )
return FALSE;
return TRUE;
}
static const int DDC_SDA_MASK = 1 << 2;
static const int DDC_SCL_MASK = 1 << 4;
static unsigned int
MGA3026_ddc1Read(ScrnInfoPtr pScrn)
{
MGAPtr pMga = MGAPTR(pScrn);
outTi3026(TVP3026_GEN_IO_CTL, 0xfb, 0);
while( INREG( MGAREG_Status ) & 0x08 );
while( ! (INREG( MGAREG_Status ) & 0x08) );
return (inTi3026(TVP3026_GEN_IO_DATA) & DDC_SDA_MASK) >> 2 ;
}
static void
MGA3026_I2CGetBits(I2CBusPtr b, int *clock, int *data)
{
ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex];
MGAPtr pMga = MGAPTR(pScrn);
unsigned char val;
val = inTi3026(TVP3026_GEN_IO_DATA);
*clock = (val & DDC_SCL_MASK) != 0;
*data = (val & DDC_SDA_MASK) != 0;
#ifdef DEBUG
ErrorF("MGA3026_I2CGetBits(%p,...) val=0x%x, returns clock %d, data %d\n", b, val, *clock, *data);
#endif
}
static void
MGA3026_I2CPutBits(I2CBusPtr b, int clock, int data)
{
ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex];
MGAPtr pMga = MGAPTR(pScrn);
unsigned char val,drv;
val = (clock ? DDC_SCL_MASK : 0) | (data ? DDC_SDA_MASK : 0);
drv = ((!clock) ? DDC_SCL_MASK : 0) | ((!data) ? DDC_SDA_MASK : 0);
outTi3026(TVP3026_GEN_IO_CTL, ~(DDC_SDA_MASK | DDC_SCL_MASK), drv);
outTi3026(TVP3026_GEN_IO_DATA, ~(DDC_SDA_MASK | DDC_SCL_MASK), val);
#ifdef DEBUG
ErrorF("MGA3026_I2CPutBits(%p, %d, %d) val=0x%x\n", b, clock, data, val);
#endif
}
Bool
MGA3026_i2cInit(ScrnInfoPtr pScrn)
{
MGAPtr pMga = MGAPTR(pScrn);
I2CBusPtr I2CPtr;
I2CPtr = xf86CreateI2CBusRec();
if(!I2CPtr) return FALSE;
pMga->I2C = I2CPtr;
I2CPtr->BusName = "DDC";
I2CPtr->scrnIndex = pScrn->scrnIndex;
I2CPtr->I2CPutBits = MGA3026_I2CPutBits;
I2CPtr->I2CGetBits = MGA3026_I2CGetBits;
if (!xf86I2CBusInit(I2CPtr)) {
return FALSE;
}
return TRUE;
}
static void
MGA3026RamdacInit(ScrnInfoPtr pScrn)
{
MGAPtr pMga;
MGARamdacPtr MGAdac;
pMga = MGAPTR(pScrn);
MGAdac = &pMga->Dac;
MGAdac->isHwCursor = TRUE;
MGAdac->CursorMaxWidth = 64;
MGAdac->CursorMaxHeight = 64;
MGAdac->SetCursorColors = MGA3026SetCursorColors;
MGAdac->SetCursorPosition = MGA3026SetCursorPosition;
MGAdac->LoadCursorImage = MGA3026LoadCursorImage;
MGAdac->HideCursor = MGA3026HideCursor;
MGAdac->ShowCursor = MGA3026ShowCursor;
MGAdac->UseHWCursor = MGA3026UseHWCursor;
MGAdac->CursorFlags =
#if X_BYTE_ORDER == X_LITTLE_ENDIAN
HARDWARE_CURSOR_BIT_ORDER_MSBFIRST |
#endif
HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
HARDWARE_CURSOR_SOURCE_MASK_NOT_INTERLEAVED;
MGAdac->LoadPalette = MGA3026LoadPalette;
MGAdac->RestorePalette = MGA3026RestorePalette;
MGAdac->ClockFrom = X_PROBED;
if ( pMga->Chipset == PCI_CHIP_MGA2064 && pMga->Bios2.PinID == 0 )
{
switch( pMga->Bios.RamdacType & 0xff )
{
case 1: MGAdac->maxPixelClock = 220000;
break;
case 2: MGAdac->maxPixelClock = 250000;
break;
default:
MGAdac->maxPixelClock = 175000;
MGAdac->ClockFrom = X_DEFAULT;
break;
}
if(pMga->OverclockMem) {
if ( pScrn->videoRam < 4096 )
MGAdac->MemoryClock = pMga->Bios.ClkBase * 12;
else if ( pScrn->videoRam < 8192 )
MGAdac->MemoryClock = pMga->Bios.Clk4MB * 12;
else
MGAdac->MemoryClock = pMga->Bios.Clk8MB * 12;
MGAdac->MemClkFrom = X_CONFIG;
MGAdac->SetMemClk = TRUE;
#if 0
ErrorF("BIOS Memory clock settings: 2Mb %d, 4Mb %d, 8MB %d\n",
pMga->Bios.ClkBase, pMga->Bios.Clk4MB, pMga->Bios.Clk8MB);
#endif
} else {
if ( pScrn->videoRam < 4096 )
MGAdac->MemoryClock = pMga->Bios.ClkBase * 10;
else if ( pScrn->videoRam < 8192 )
MGAdac->MemoryClock = pMga->Bios.Clk4MB * 10;
else
MGAdac->MemoryClock = pMga->Bios.Clk8MB * 10;
MGAdac->MemClkFrom = X_PROBED;
MGAdac->SetMemClk = TRUE;
}
}
else
{
if ( pMga->Bios2.PinID )
{
if ( pMga->Bios2.PclkMax != 0xff )
{
MGAdac->maxPixelClock = (pMga->Bios2.PclkMax + 100) * 1000;
}
else
MGAdac->maxPixelClock = 220000;
switch ( pScrn->videoRam )
{
case 4096:
if (pMga->Bios2.Clk4MB != 0xff)
pMga->Bios2.ClkGE = pMga->Bios2.Clk4MB;
break;
case 8192:
if (pMga->Bios2.Clk8MB != 0xff)
pMga->Bios2.ClkGE = pMga->Bios2.Clk8MB;
break;
case 12288:
if (pMga->Bios2.Clk12MB != 0xff)
pMga->Bios2.ClkGE = pMga->Bios2.Clk12MB;
break;
case 16384:
if (pMga->Bios2.Clk16MB != 0xff)
pMga->Bios2.ClkGE = pMga->Bios2.Clk16MB;
break;
default:
break;
}
if ( pMga->Bios2.ClkGE != 0xff && pMga->Bios2.ClkMem == 0xff )
pMga->Bios2.ClkMem = pMga->Bios2.ClkGE;
else if ( pMga->Bios2.ClkGE == 0xff && pMga->Bios2.ClkMem != 0xff )
;
else if ( pMga->Bios2.ClkGE == pMga->Bios2.ClkMem && pMga->Bios2.ClkGE != 0xff )
pMga->Bios2.ClkMem = pMga->Bios2.ClkGE;
else
pMga->Bios2.ClkMem = 60;
MGAdac->MemoryClock = pMga->Bios2.ClkMem * 1000;
MGAdac->MemClkFrom = X_PROBED;
MGAdac->SetMemClk = TRUE;
}
else
{
MGAdac->MemoryClock = 60000;
MGAdac->maxPixelClock = 220000;
MGAdac->ClockFrom = X_DEFAULT;
}
}
if ( (MGAdac->MemoryClock < 40000) ||
(MGAdac->MemoryClock > 70000) )
MGAdac->MemoryClock = 50000;
if (pScrn->videoRam > 2048)
pMga->Interleave = TRUE;
else {
pMga->Interleave = FALSE;
pMga->BppShifts[0]++;
pMga->BppShifts[1]++;
pMga->BppShifts[2]++;
pMga->BppShifts[3]++;
}
pMga->Roundings[0] = 128 >> pMga->BppShifts[0];
pMga->Roundings[1] = 128 >> pMga->BppShifts[1];
pMga->Roundings[2] = 128 >> pMga->BppShifts[2];
pMga->Roundings[3] = 128 >> pMga->BppShifts[3];
pMga->HasFBitBlt = !(pMga->Bios.FeatFlag & 0x00000001);
}
void MGA3026LoadPalette(
ScrnInfoPtr pScrn,
int numColors,
int *indices,
LOCO *colors,
VisualPtr pVisual
){
MGAPtr pMga = MGAPTR(pScrn);
int i, index;
if(pMga->CurrentLayout.Overlay8Plus24 && (pVisual->nplanes != 8))
return;
if (pVisual->nplanes == 16) {
for(i = 0; i < numColors; i++) {
index = indices[i];
outTi3026dreg(MGA1064_WADR_PAL, index << 2);
outTi3026dreg(MGA1064_COL_PAL, colors[index >> 1].red);
outTi3026dreg(MGA1064_COL_PAL, colors[index].green);
outTi3026dreg(MGA1064_COL_PAL, colors[index >> 1].blue);
if(index <= 31) {
outTi3026dreg(MGA1064_WADR_PAL, index << 3);
outTi3026dreg(MGA1064_COL_PAL, colors[index].red);
outTi3026dreg(MGA1064_COL_PAL, colors[(index << 1) + 1].green);
outTi3026dreg(MGA1064_COL_PAL, colors[index].blue);
}
}
} else {
int shift = (pVisual->nplanes == 15) ? 3 : 0;
for(i = 0; i < numColors; i++) {
index = indices[i];
outTi3026dreg(MGA1064_WADR_PAL, index << shift);
outTi3026dreg(MGA1064_COL_PAL, colors[index].red);
outTi3026dreg(MGA1064_COL_PAL, colors[index].green);
outTi3026dreg(MGA1064_COL_PAL, colors[index].blue);
}
}
}
static void
MGA3026SavePalette(ScrnInfoPtr pScrn, unsigned char* pntr)
{
MGAPtr pMga = MGAPTR(pScrn);
int i = 768;
outTi3026dreg(TVP3026_RADR_PAL, 0x00);
while(i--)
*(pntr++) = inTi3026dreg(TVP3026_COL_PAL);
}
static void
MGA3026RestorePalette(ScrnInfoPtr pScrn, unsigned char* pntr)
{
MGAPtr pMga = MGAPTR(pScrn);
int i = 768;
outTi3026dreg(TVP3026_WADR_PAL, 0x00);
while(i--)
outTi3026dreg(TVP3026_COL_PAL, *(pntr++));
}
void MGA2064SetupFuncs(ScrnInfoPtr pScrn)
{
MGAPtr pMga = MGAPTR(pScrn);
pMga->PreInit = MGA3026RamdacInit;
pMga->Save = MGA3026Save;
pMga->Restore = MGA3026Restore;
pMga->ModeInit = MGA3026Init;
pMga->ddc1Read = MGA3026_ddc1Read;
pMga->DDC1SetSpeed = vgaHWddc1SetSpeed;
pMga->i2cInit = MGA3026_i2cInit;
}