This is from http://lists.freedesktop.org/archives/xserver-commit/2004-June/001183.html
/****************************************************************************\
* *
* RIVA Mode State Routines *
* *
\****************************************************************************/
/*
* Calculate the Video Clock parameters for the PLL.
*/
static int CalcVClock
(
int clockIn,
int *clockOut,
int *mOut,
int *nOut,
int *pOut,
RIVA_HW_INST *chip
)
{
unsigned lowM, highM, highP;
unsigned DeltaNew, DeltaOld;
unsigned VClk, Freq;
unsigned M, N, P;
DeltaOld = 0xFFFFFFFF;
VClk = (unsigned)clockIn;
if (chip->CrystalFreqKHz == 13500)
{
lowM = 7;
highM = 12;
}
else
{
lowM = 8;
highM = 13;
}
highP = 3;
for (P = 0; P <= highP; P ++)
{
Freq = VClk << P;
if ((Freq >= 128000) && (Freq <= chip->MaxVClockFreqKHz))
{
for (M = lowM; M <= highM; M++)
{
N = (VClk << P) * M / chip->CrystalFreqKHz;
if(N <= 255) {
Freq = (chip->CrystalFreqKHz * N / M) >> P;
if (Freq > VClk)
DeltaNew = Freq - VClk;
else
DeltaNew = VClk - Freq;
if (DeltaNew < DeltaOld)
{
*mOut = M;
*nOut = N;
*pOut = P;
*clockOut = Freq;
DeltaOld = DeltaNew;
}
}
}
}
}
return (DeltaOld != 0xFFFFFFFF);
}
/*
* Calculate extended mode parameters (SVGA) and save in a
* mode state structure.
*/
static void CalcStateExt
(
RIVA_HW_INST *chip,
RIVA_HW_STATE *state,
int bpp,
int width,
int hDisplaySize,
int height,
int dotClock,
int flags
)
{
int pixelDepth, VClk, m, n, p;
/*
* Save mode parameters.
*/
state->bpp = bpp; /* this is not bitsPerPixel, it's 8,15,16,32 */
state->width = width;
state->height = height;
/*
* Extended RIVA registers.
*/
pixelDepth = (bpp + 1)/8;
CalcVClock(dotClock, &VClk, &m, &n, &p, chip);
nv3UpdateArbitrationSettings(VClk,
pixelDepth * 8,
&(state->arbitration0),
&(state->arbitration1),
chip);
state->cursor0 = 0x00;
state->cursor1 = 0x78;
if (flags & V_DBLSCAN)
state->cursor1 |= 2;
state->cursor2 = 0x00000000;
state->pllsel = 0x10010100;
state->config = ((width + 31)/32)
| (((pixelDepth > 2) ? 3 : pixelDepth) << 8)
| 0x1000;
state->general = 0x00100100;
state->repaint1 = hDisplaySize < 1280 ? 0x06 : 0x02;
state->vpll = (p << 16) | (n << 8) | m;
state->repaint0 = (((width/8)*pixelDepth) & 0x700) >> 3;
state->pixel = pixelDepth > 2 ? 3 : pixelDepth;
state->offset = 0;
state->pitch = pixelDepth * width;
}
/*
* Load fixed function state and pre-calculated/stored state.
*/
#define LOAD_FIXED_STATE(tbl,dev) \
for (i = 0; i < sizeof(tbl##Table##dev)/8; i++) \
chip->dev[tbl##Table##dev[i][0]] = tbl##Table##dev[i][1]
#define LOAD_FIXED_STATE_8BPP(tbl,dev) \
for (i = 0; i < sizeof(tbl##Table##dev##_8BPP)/8; i++) \
chip->dev[tbl##Table##dev##_8BPP[i][0]] = tbl##Table##dev##_8BPP[i][1]
#define LOAD_FIXED_STATE_15BPP(tbl,dev) \
for (i = 0; i < sizeof(tbl##Table##dev##_15BPP)/8; i++) \
chip->dev[tbl##Table##dev##_15BPP[i][0]] = tbl##Table##dev##_15BPP[i][1]
#define LOAD_FIXED_STATE_16BPP(tbl,dev) \
for (i = 0; i < sizeof(tbl##Table##dev##_16BPP)/8; i++) \
chip->dev[tbl##Table##dev##_16BPP[i][0]] = tbl##Table##dev##_16BPP[i][1]
#define LOAD_FIXED_STATE_32BPP(tbl,dev) \
for (i = 0; i < sizeof(tbl##Table##dev##_32BPP)/8; i++) \
chip->dev[tbl##Table##dev##_32BPP[i][0]] = tbl##Table##dev##_32BPP[i][1]
static void UpdateFifoState
(
RIVA_HW_INST *chip
)
{
}
static void LoadStateExt
(
RIVA_HW_INST *chip,
RIVA_HW_STATE *state
)
{
int i;
/*
* Load HW fixed function state.
*/
LOAD_FIXED_STATE(Riva,PMC);
LOAD_FIXED_STATE(Riva,PTIMER);
/*
* Make sure frame buffer config gets set before loading PRAMIN.
*/
chip->PFB[0x00000200/4] = state->config;
LOAD_FIXED_STATE(nv3,PFIFO);
LOAD_FIXED_STATE(nv3,PRAMIN);
LOAD_FIXED_STATE(nv3,PGRAPH);
switch (state->bpp)
{
case 15:
case 16:
LOAD_FIXED_STATE_15BPP(nv3,PRAMIN);
LOAD_FIXED_STATE_15BPP(nv3,PGRAPH);
break;
case 24:
case 32:
LOAD_FIXED_STATE_32BPP(nv3,PRAMIN);
LOAD_FIXED_STATE_32BPP(nv3,PGRAPH);
break;
case 8:
default:
LOAD_FIXED_STATE_8BPP(nv3,PRAMIN);
LOAD_FIXED_STATE_8BPP(nv3,PGRAPH);
break;
}
for (i = 0x00000; i < 0x00800; i++)
chip->PRAMIN[0x00000502 + i] = (i << 12) | 0x03;
chip->PGRAPH[0x00000630/4] = state->offset;
chip->PGRAPH[0x00000634/4] = state->offset;
chip->PGRAPH[0x00000638/4] = state->offset;
chip->PGRAPH[0x0000063C/4] = state->offset;
chip->PGRAPH[0x00000650/4] = state->pitch;
chip->PGRAPH[0x00000654/4] = state->pitch;
chip->PGRAPH[0x00000658/4] = state->pitch;
chip->PGRAPH[0x0000065C/4] = state->pitch;
LOAD_FIXED_STATE(Riva,FIFO);
UpdateFifoState(chip);
/*
* Load HW mode state.
*/
VGA_WR08(chip->PCIO, 0x03D4, 0x19);
VGA_WR08(chip->PCIO, 0x03D5, state->repaint0);
VGA_WR08(chip->PCIO, 0x03D4, 0x1A);
VGA_WR08(chip->PCIO, 0x03D5, state->repaint1);
VGA_WR08(chip->PCIO, 0x03D4, 0x25);
VGA_WR08(chip->PCIO, 0x03D5, state->screen);
VGA_WR08(chip->PCIO, 0x03D4, 0x28);
VGA_WR08(chip->PCIO, 0x03D5, state->pixel);
VGA_WR08(chip->PCIO, 0x03D4, 0x2D);
VGA_WR08(chip->PCIO, 0x03D5, state->horiz);
VGA_WR08(chip->PCIO, 0x03D4, 0x1B);
VGA_WR08(chip->PCIO, 0x03D5, state->arbitration0);
VGA_WR08(chip->PCIO, 0x03D4, 0x20);
VGA_WR08(chip->PCIO, 0x03D5, state->arbitration1);
VGA_WR08(chip->PCIO, 0x03D4, 0x30);
VGA_WR08(chip->PCIO, 0x03D5, state->cursor0);
VGA_WR08(chip->PCIO, 0x03D4, 0x31);
VGA_WR08(chip->PCIO, 0x03D5, state->cursor1);
VGA_WR08(chip->PCIO, 0x03D4, 0x2F);
VGA_WR08(chip->PCIO, 0x03D5, state->cursor2);
VGA_WR08(chip->PCIO, 0x03D4, 0x39);
VGA_WR08(chip->PCIO, 0x03D5, state->interlace);
chip->PRAMDAC[0x00000508/4] = state->vpll;
chip->PRAMDAC[0x0000050C/4] = state->pllsel;
chip->PRAMDAC[0x00000600/4] = state->general;
/*
* Turn off VBlank enable and reset.
*/
chip->PCRTC[0x00000140/4] = 0;
chip->PCRTC[0x00000100/4] = chip->VBlankBit;
/*
* Set interrupt enable.
*/
chip->PMC[0x00000140/4] = chip->EnableIRQ & 0x01;
/*
* Set current state pointer.
*/
chip->CurrentState = state;
/*
* Reset FIFO free and empty counts.
*/
chip->FifoFreeCount = 0;
/* Free count from first subchannel */
chip->FifoEmptyCount = chip->Rop->FifoFree;
}
