Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1441 lines
47 KiB

/**********************************************************
* Copyright Cirrus Logic, 1997. All rights reserved.
***********************************************************
*
* 5465BW.C - Bandwidth functions for CL-GD5465
*
***********************************************************
*
* Author: Rick Tillery
* Date: 03/20/97
*
* Revision History:
* -----------------
* WHO WHEN WHAT/WHY/HOW
* --- ---- ------------
*
***********************************************************/
#include "precomp.h"
#if defined WINNT_VER35 // WINNT_VER35
// If WinNT 3.5 skip all the source code
#elif defined (NTDRIVER_546x)
// If WinNT 4.0 and 5462/64 build skip all the source code
#else
#ifndef WINNT_VER40
#include "5465BW.h"
#endif
/**********************************************************
*
* ScaleMultiply()
*
* Calculates product of two DWORD factors supplied. If the
* result would overflow a DWORD, the larger of the two factors
* is divided by 2 (shifted right) until the overflow will
* not occur.
*
* Returns: Number of right shifts applied to the product.
* Product of the factors shifted by the value above.
*
***********************************************************
* Author: Rick Tillery
* Date: 11/18/95
*
* Revision History:
* -----------------
* WHO WHEN WHAT/WHY/HOW
* --- ---- ------------
*********************************************************/
static int ScaleMultiply(DWORD dw1,
DWORD dw2,
LPDWORD pdwResult)
{
int iShift = 0; // Start with no shifts
DWORD dwLimit;
// ODS("ScaleMultiply() called.\n");
// Either factor 0 will be a zero result and also cause a problem
// in our divide below.
if((0 == dw1) || (0 == dw2))
{
*pdwResult = 0;
}
else
{
// Determine which factor is larger
if(dw1 > dw2)
{
// Determine largest number by with dw2 can be multiplied without
// overflowing a DWORD.
dwLimit = 0xFFFFFFFFul / dw2;
// Shift dw1, keeping track of how many times, until it won't
// overflow when multiplied by dw2.
while(dw1 > dwLimit)
{
dw1 >>= 1;
iShift++;
}
}
else
{
// Determine largest number by with dw1 can be multiplied without
// overflowing a DWORD.
dwLimit = 0xFFFFFFFFul / dw1;
// Shift dw2, keeping track of how many times, until it won't
// overflow when multiplied by dw1.
while(dw2 > dwLimit)
{
dw2 >>= 1;
iShift++;
}
}
// Calculate (scaled) product
*pdwResult = dw1 * dw2;
}
// Return the number of shifts we had to use
return(iShift);
}
/**********************************************************
*
* ChipCalcMCLK()
*
* Determines currently set memory clock (MCLK) based on
* register values provided.
*
* Returns: Success and current MCLK in Hz.
*
***********************************************************
* Author: Rick Tillery
* Date: 03/21/97
*
* Revision History:
* -----------------
* WHO WHEN WHAT/WHY/HOW
* --- ---- ------------
*********************************************************/
BOOL ChipCalcMCLK(LPBWREGS pBWRegs,
LPDWORD pdwMCLK)
{
BOOL fSuccess = FALSE;
// We make the assumption that if the BCLK_Denom /4 is set, the reference
// xtal is 27MHz. If it is not set, we assume the ref xtal is 14.31818MHz.
// This means that 1/2 the 27MHz (13.5MHz) should not be used.
DWORD dwRefXtal = (pBWRegs->BCLK_Denom & 0x02) ? (TVO_XTAL / 4) : REF_XTAL;
ODS("ChipCalcMCLK() called.\n");
*pdwMCLK = (dwRefXtal * (DWORD)pBWRegs->BCLK_Mult) >> 2;
ODS("ChipCalcMCLK(): MCLK = %ld\n", *pdwMCLK);
if(0 == *pdwMCLK)
{
ODS("ChipCalcMCLK(): Calculated invalid MCLK (0).\n");
goto Error;
}
fSuccess = TRUE;
Error:
return(fSuccess);
}
/**********************************************************
*
* ChipCalcVCLK()
*
* Determines currently set pixel clock (VCLK) based on
* register values provided.
*
* Returns: Success and current VCLK in Hz.
*
***********************************************************
* Author: Rick Tillery
* Date: 11/18/95
*
* Revision History:
* -----------------
* WHO WHEN WHAT/WHY/HOW
* --- ---- ------------
*********************************************************/
BOOL ChipCalcVCLK(LPBWREGS pBWRegs,
LPDWORD pdwVCLK)
{
BOOL fSuccess = FALSE;
BYTE bNum, bDenom;
int iShift;
// We make the assumption that if the BCLK_Denom /4 is set, the reference
// xtal is 27MHz. If it is not set, we assume the ref xtal is 14.31818MHz.
// This means that 1/2 the 27MHz (13.5MHz) should not be used.
// Add 20000000ul to increas Bandwidth.
DWORD dwRefXtal = (pBWRegs->BCLK_Denom & 0x02) ? (TVO_XTAL + 2000000ul) : REF_XTAL;
ODS("ChipCalcVCLK() called dwRef= %ld\n",dwRefXtal);
if(pBWRegs->VCLK3Num & 0x80)
{
fSuccess = ChipCalcMCLK(pBWRegs, pdwVCLK);
goto Error;
}
/*
* VCLK is normally based on one of 4 sets of numerator and
* denominator pairs. However, the CL-GD5465 can only access
* VCLK 3 through the MMI/O.
*/
if((pBWRegs->MISCOutput & 0x0C) != 0x0C)
{
ODS("ChipCalcVCLK(): VCLK %d in use. MMI/O can only access VCLK 3.\n",
(int)((pBWRegs->MISCOutput & 0x0C) >> 2));
// goto Error;
}
bNum = pBWRegs->VCLK3Num & 0x7F;
bDenom = (pBWRegs->VCLK3Denom & 0xFE) >> 1;
if(pBWRegs->VCLK3Denom & 0x01)
{
// Apply post scalar
bDenom <<= 1;
}
if(0 == bDenom)
{
ODS("ChipCalcVCLK(): Invalid VCLK denominator (0).\n");
goto Error;
}
// Calculate actual VCLK frequency (Hz)
iShift = ScaleMultiply(dwRefXtal, (DWORD)bNum, pdwVCLK);
*pdwVCLK /= (DWORD)bDenom;
*pdwVCLK >>= iShift;
//Check PLL output Frequency
iShift = ( pBWRegs->GfVdFormat >> 14 );
*pdwVCLK >>= iShift;
ODS("ChipCalcVCLK(): VCLK = %ld\n", *pdwVCLK);
if(0 == *pdwVCLK)
{
ODS("ChipCalcVCLK(): Calculated invalid VCLK (0).\n");
goto Error;
}
fSuccess = TRUE;
Error:
return(fSuccess);
}
/**********************************************************
*
* ChipIsEnoughBandwidth()
*
* Determines whether their is enough bandwidth for the video
* configuration specified in the VIDCONFIG structure with
* the system configuration specified in the BWREGS structure
* and returns the values that need to be programmed into the
* bandwidth related registers. The pProgRegs parameter
* may be NULL to allow checking a configuration only. This
* function gets the register values and passes them to
* ChipCheckBW() to check the bandwidth.
*
*
* Returns: BOOLean indicating whether there is sufficient
* bandwidth for the configuration specified.
* Values to program into bandwidth related registers
* if the pProgRegs parameter is not NULL.
*
***********************************************************
* Author: Rick Tillery
* Date: 03/20/97
*
* Revision History:
* -----------------
* WHO WHEN WHAT/WHY/HOW
* --- ---- ------------
*********************************************************/
BOOL ChipIsEnoughBandwidth(LPPROGREGS pProgRegs,
LPVIDCONFIG pConfig,
LPBWREGS pBWRegs )
{
BOOL fSuccess = FALSE;
DWORD dwMCLK, dwVCLK;
DWORD dwDenom;
int iNumShift, iDenomShift;
DWORD dwGfxFetch, dwBLTFetch;
DWORD dwGfxFill, dwBLTFill;
DWORD dwMaxGfxThresh, dwMinGfxThresh;
DWORD dwMaxVidThresh, dwMinVidThresh;
DWORD dwHitLatency, dwRandom;
BOOL f500MHZ,fConCurrent;
DWORD dwTemp;
BOOL f585MHZ = TRUE; //PDR#11521
// There are some modes that have the same bandwidth parameters
// like MCLK, VCLK, but have different dwScreenWidht. The bandwidth
// related register settings have major differences for these mode.
// For this reason, dwScreenWidth need to be passed for this function.
DWORD dwScreenWidth;
// ODS("ChipIsEnoughBandwidth() called.\n");
if(!ChipCalcMCLK(pBWRegs, &dwMCLK))
{
ODS("ChipIsEnoughBandwidth(): Unable to calculate MCLK.\n");
goto Error;
}
if(!ChipCalcVCLK(pBWRegs, &dwVCLK))
{
ODS("ChipIsEnoughBandwidth(): Unable to calculate VCLK.\n");
goto Error;
}
if( dwMCLK > 70000000 )
f500MHZ = FALSE;
else
f500MHZ = TRUE;
if ((dwMCLK > 70000000) && ( dwMCLK < 72000000)) //PDR#11521
f585MHZ = TRUE;
else
f585MHZ = FALSE;
dwScreenWidth = (pBWRegs->CR1 + 1 ) << 3;
if( pBWRegs->CR1E & 0x40 )
dwScreenWidth += 0x1000;
ODS("ChipIsEnoughBandwidth(): dwScreenWidth = %ld\n",dwScreenWidth);
dwBLTFetch = (pBWRegs->Control2 & 0x0010) ? 256ul : 128ul;
dwGfxFetch = (pBWRegs->DispThrsTiming & 0x0040) ? 256ul : 128ul;
ODS("GraphicDepth%ld,VideoDepth=%ld",pConfig->uGfxDepth,pConfig->uSrcDepth);
if(pBWRegs->RIFControl & 0xC000)
{
ODS("ChipIsEnoughBandwidth(): Concurrent RDRAM detected!\n");
dwHitLatency = CONC_HIT_LATENCY;
dwRandom = CONC_RANDOM;
fConCurrent = TRUE;
}
else
{
ODS("ChipIsEnoughBandwidth(): Normal RDRAM detected.\n");
dwHitLatency = NORM_HIT_LATENCY;
dwRandom = NORM_RANDOM;
fConCurrent = FALSE;
}
// Determine the number of MCLKs to transfer to the graphics FIFO.
dwGfxFill = (dwGfxFetch * 8ul) / FIFOWIDTH;
// And BLTer FIFO.
dwBLTFill = (dwBLTFetch * 8ul) / FIFOWIDTH;
//
// Determine maximum graphics threshold
//
dwMaxGfxThresh = dwHitLatency + dwGfxFill + (GFXFIFOSIZE / 2ul) -10ul;
// ( K * VCLK * GfxDepth ) GFXFIFOSIZE
// INT( ------------------- ) + ----------- - 1
// ( FIFOWIDTH * MCLK ) 2
iNumShift = ScaleMultiply(dwMaxGfxThresh, dwVCLK, &dwMaxGfxThresh);
iNumShift += ScaleMultiply(dwMaxGfxThresh, (DWORD)pConfig->uGfxDepth,
&dwMaxGfxThresh);
iDenomShift = ScaleMultiply(FIFOWIDTH, dwMCLK, &dwDenom);
if(iNumShift > iDenomShift)
{
dwDenom >>= (iNumShift - iDenomShift);
}
else
{
dwMaxGfxThresh >>= (iDenomShift - iNumShift);
}
dwMaxGfxThresh /= dwDenom;
dwMaxGfxThresh += (GFXFIFOSIZE / 2ul) - 1ul;
if(dwMaxGfxThresh > GFXFIFOSIZE -1 )
dwMaxGfxThresh = GFXFIFOSIZE -1;
ODS("ChipIsEnoughBandwidth(): Max graphics thresh = %ld.\n", dwMaxGfxThresh);
/*
* Determine minimum graphics threshold
*/
if(pConfig->dwFlags & VCFLG_DISP)
{
// Video enabled
DWORD dwMinGfxThresh1, dwMinGfxThresh2;
if(pConfig->dwFlags & VCFLG_420)
{
// 4:2:0
dwMinGfxThresh1 = DISP_LATENCY + dwRandom + dwBLTFill
+ dwRandom - RIF_SAVINGS + dwBLTFill
+ dwRandom - RIF_SAVINGS + VID420FILL
+ dwRandom - RIF_SAVINGS + VID420FILL
+ dwRandom - RIF_SAVINGS + 1ul;
dwMinGfxThresh2 = DISP_LATENCY + dwRandom + dwBLTFill
+ dwRandom - RIF_SAVINGS + dwBLTFill
+ dwRandom - RIF_SAVINGS + VID420FILL
+ dwRandom - RIF_SAVINGS + VID420FILL
+ dwRandom - RIF_SAVINGS + dwGfxFill
+ dwRandom - RIF_SAVINGS + dwBLTFill
+ dwRandom - RIF_SAVINGS + VID420FILL
+ dwRandom - RIF_SAVINGS + VID420FILL
+ dwRandom - RIF_SAVINGS + 1ul;
}
else
{
// 4:2:2, 5:5:5, 5:6:5, or X:8:8:8
dwMinGfxThresh1 = DISP_LATENCY + dwRandom + dwBLTFill
+ dwRandom - RIF_SAVINGS + dwBLTFill
+ dwRandom - RIF_SAVINGS + VIDFILL
+ dwRandom - RIF_SAVINGS + 1ul;
dwMinGfxThresh2 = DISP_LATENCY + dwRandom + dwBLTFill
+ dwRandom - RIF_SAVINGS + dwBLTFill
+ dwRandom - RIF_SAVINGS + VIDFILL
+ dwRandom - RIF_SAVINGS + dwGfxFill
+ dwRandom - RIF_SAVINGS + dwBLTFill
+ dwRandom - RIF_SAVINGS + VIDFILL
+ dwRandom - RIF_SAVINGS + 1ul;
}
//
// Finish dwMinGfxThresh1
//
// ( K * VCLK * GfxDepth FIFOWIDTH * MCLK) - 1 )
// INT( ------------------- + --------------------- ) + 1
// ( FIFOWIDTH * MCLK FIFOWIDTH * MCLK )
//
iNumShift = ScaleMultiply(dwMinGfxThresh1, dwVCLK, &dwMinGfxThresh1);
iNumShift += ScaleMultiply(dwMinGfxThresh1, (DWORD)pConfig->uGfxDepth,
&dwMinGfxThresh1);
iDenomShift = ScaleMultiply(FIFOWIDTH, dwMCLK, &dwDenom);
if(iNumShift > iDenomShift)
{
dwDenom >>= (iNumShift - iDenomShift);
}
else
{
dwMinGfxThresh1 >>= (iDenomShift - iNumShift);
}
// Be sure rounding below doesn't overflow.
while((dwMinGfxThresh1 + dwDenom - 1ul) < dwMinGfxThresh1)
{
dwMinGfxThresh1 >>= 1;
dwDenom >>= 1;
}
// Round up
dwMinGfxThresh1 += dwDenom - 1ul;
dwMinGfxThresh1 /= dwDenom;
dwMinGfxThresh1++; // Compensate for decrement by 2
//
// Finish dwMinGfxThresh2
//
// ( K * VCLK * GfxDepth (FIFOWIDTH * MCLK) - 1 ) GfxFetch * 8
// INT( ------------------- + ---------------------- ) - ------------ + 1
// ( FIFOWIDTH * MCLK FIFOWIDTH * MCLK ) FIFOWIDTH
//
iNumShift = ScaleMultiply(dwMinGfxThresh2, dwVCLK, &dwMinGfxThresh2);
iNumShift += ScaleMultiply(dwMinGfxThresh2, (DWORD)pConfig->uGfxDepth,
&dwMinGfxThresh2);
iDenomShift = ScaleMultiply(FIFOWIDTH, dwMCLK, &dwDenom);
if(iNumShift > iDenomShift)
{
dwDenom >>= (iNumShift - iDenomShift);
}
else
{
dwMinGfxThresh2 >>= (iDenomShift - iNumShift);
}
// Be sure rounding below doesn't overflow.
while((dwMinGfxThresh2 + dwDenom - 1ul) < dwMinGfxThresh2)
{
dwMinGfxThresh2 >>= 1;
dwDenom >>= 1;
}
// Round up
dwMinGfxThresh2 += dwDenom - 1ul;
dwMinGfxThresh2 /= dwDenom;
// Adjust for second transfer
dwMinGfxThresh2 -= ((dwGfxFetch * 8ul) / FIFOWIDTH);
// Adjust for decrement by 2
dwMinGfxThresh2++;
if( fConCurrent)
{
if( f500MHZ)
{
if( (pConfig->uGfxDepth == 32) && ( dwVCLK >= 64982518ul ))
{
dwTemp = ( dwVCLK - 64982518ul) /1083333ul + 1ul;
dwMinGfxThresh2 -= dwTemp;
dwMinGfxThresh1 -= 10;
}
else if( (pConfig->uGfxDepth == 24) && (dwVCLK > 94500000ul))
dwMinGfxThresh2 -=5; //Adjust again for 24 bit #xc
}
else //600MHZ
{
if( (pConfig->uGfxDepth == 16) && ( dwVCLK > 156000000ul))
dwMinGfxThresh2 -= 4;
else if( (pConfig->uGfxDepth == 24) && ( dwVCLK > 104000000ul))
{
dwMinGfxThresh2 -= (5ul+ 8ul * (dwVCLK - 104000000ul) / 17000000ul);
}
else if( (pConfig->uGfxDepth == 32) )
{
if( dwVCLK > 94000000ul)
dwMinGfxThresh2 -= 16;
if( dwVCLK > 70000000ul)
dwMinGfxThresh2 -= 4;
else
dwMinGfxThresh2 +=6; //#PDR#11506 10x7x32bit could not
//support YUV420.
}
}
if( (pConfig->uGfxDepth == 8) && (dwVCLK > 18000000ul))
dwMinGfxThresh2 += 6;
}
else //Normal RDRam
{
if( f500MHZ )
{
if( (pConfig->uGfxDepth == 32) && ( dwVCLK > 49500000ul ))
{
dwMinGfxThresh1 -= 4;
dwMinGfxThresh2 -= (( dwVCLK - 49715909ul) / 726981ul + 3ul);
}
else if( (pConfig->uGfxDepth == 24) && ( dwVCLK > 60000000ul )
&& (dwVCLK < 95000000ul))
{
dwTemp= ((dwVCLK - 64982518ul) / 1135287ul + 3ul);
dwMinGfxThresh2 -=dwTemp;
dwMinGfxThresh1 -= 10;
}
}
else //600MHZ case
{
if( (pConfig->uGfxDepth == 32) && ( dwVCLK > 49700000ul ))
{
dwTemp= ((dwVCLK - 49700000ul) / 1252185ul + 5ul);
dwMinGfxThresh2 -= dwTemp;
dwMinGfxThresh1 -= 4ul;
}
else if( (pConfig->uGfxDepth == 24) && ( dwVCLK > 60000000ul ))
{
dwTemp= ((dwVCLK - 64982518ul) / 2270575ul + 4ul);
dwMinGfxThresh2 -=dwTemp;
dwMinGfxThresh1 -= 8;
}
else if( pConfig->uGfxDepth == 16)
{
dwMinGfxThresh2 -= 4;
}
else if( pConfig->uGfxDepth == 8)
{
if(dwVCLK >170000000)
dwMinGfxThresh1 += 10;
else
dwMinGfxThresh1 += 4;
}
}
}
ODS("ChipIsEnoughBandwidth(): Min graphics thresh1 2 = %ld,%ld.\n",
dwMinGfxThresh1, dwMinGfxThresh2);
// Adjust for unsigned overflow
if(dwMinGfxThresh2 > GFXFIFOSIZE + 20ul)
{
dwMinGfxThresh2 = 0ul;
}
//
// Whichever is higher should be the right one
//
dwMinGfxThresh = __max(dwMinGfxThresh1, dwMinGfxThresh2);
}
else
{
// No video enabled
dwMinGfxThresh = DISP_LATENCY + dwRandom + dwBLTFill
+ dwRandom - RIF_SAVINGS + 1ul;
// ( K * VCLK * GfxDepth (FIFOWIDTH * MCLK) - 1 )
// INT( ------------------- + ---------------------- )
// ( FIFOWIDTH * MCLK FIFOWIDTH * MCLK )
iNumShift = ScaleMultiply(dwMinGfxThresh, dwVCLK, &dwMinGfxThresh);
iNumShift += ScaleMultiply(dwMinGfxThresh, (DWORD)pConfig->uGfxDepth,
&dwMinGfxThresh);
iDenomShift = ScaleMultiply(FIFOWIDTH, dwMCLK, &dwDenom);
if(iNumShift > iDenomShift)
{
dwDenom >>= (iNumShift - iDenomShift);
}
else
{
dwMinGfxThresh >>= (iDenomShift - iNumShift);
}
// Be sure rounding below doesn't overflow.
while((dwMinGfxThresh + dwDenom - 1ul) < dwMinGfxThresh)
{
dwMinGfxThresh >>= 1;
dwDenom >>= 1;
}
// Round up
dwMinGfxThresh += dwDenom - 1ul;
dwMinGfxThresh /= dwDenom;
dwMinGfxThresh++; // Compensate for decrement by 2
}
ODS("ChipIsEnoughBandwidth(): Min graphics thresh = %ld.\n", dwMinGfxThresh);
if(dwMaxGfxThresh < dwMinGfxThresh)
{
ODS("ChipIsEnoughBandwidth(): Minimum graphics threshold exceeds maximum.\n");
goto Error;
}
if(pProgRegs)
{
pProgRegs->DispThrsTiming = (WORD)dwMinGfxThresh;
}
ODS("xfer=%x,cap=%x,src=%x,dsp=%x\n",pConfig->sizXfer.cx,pConfig->sizCap.cx,
pConfig->sizSrc.cx,pConfig->sizDisp.cx);
// Start-of-line check is only for capture
if(pConfig->dwFlags & VCFLG_CAP)
{
DWORD dwNonCapMCLKs, dwCapMCLKs;
// Do start-of-line check to be sure capture FIFO does not overflow.
// First determine the number of MCLK cycles at the start of the line.
// We'll compare this to the number of levels of the capture FIFO
// filled during the same time to make sure the capture FIFO doesn't
// overflow.
// Start of line: BLT + HC + V + G + V + G
dwNonCapMCLKs = dwRandom + dwBLTFill;
// Hardware cursor is only necessary if it is on, however, since it can
// be enabled or disabled, and VPM has no way of knowing when this
// occurs, we must always assume it is on.
dwNonCapMCLKs += dwRandom - RIF_SAVINGS + CURSORFILL;
if(pConfig->dwFlags & VCFLG_DISP)
{
// Only one video fill is required, however if the video FIFO threshold
// is greater than 1/2, the second fill will be done. Also, because of
// the tiled architecture, even though the video might not be aligned,
// the transfer will occur on a tile boundary. If the transfer of a
// single tile cannot fulfill the FIFO request, the second fill will be
// done. Since the pitch will vary, and the client can move the source
// around, we must always assume that the second video FIFO fill will
// be done.
if(pConfig->dwFlags & VCFLG_420)
{
dwNonCapMCLKs += 4ul * (dwRandom - RIF_SAVINGS + VID420FILL);
}
else
{
dwNonCapMCLKs += 2ul * (dwRandom - RIF_SAVINGS + VIDFILL);
}
}
// The graphics FIFO fill depends on the fetch size. We also assume that
// the pitch is a multiple of the fetch width.
dwNonCapMCLKs += dwRandom - RIF_SAVINGS + dwGfxFill;
// The second graphics FIFO fill will be done if:
// 1. The graphics is not aligned on a fetch boundary (panning).
// 2. The FIFO threshold is over 1/2 the FIFO (the fill size).
if((dwMinGfxThresh >= dwGfxFill) || (pConfig->dwFlags & VCFLG_PAN))
{
dwNonCapMCLKs += dwRandom - RIF_SAVINGS + dwGfxFill;
}
dwNonCapMCLKs += 3; // Magic number that seems to work for now.
ODS("ChipIsEnoughBandwidth(): dwNonCapMCLKs = %ld\n", dwNonCapMCLKs);
// sizXfer.cx * FIFOWIDTH * (CAPFIFOSIZE / 2) * dwMCLK
// ---------------------------------------------------
// dwXferRate * uCapDepth * sizCap.cx
iNumShift = ScaleMultiply((DWORD)pConfig->sizXfer.cx, FIFOWIDTH,
&dwCapMCLKs);
iNumShift += ScaleMultiply(dwCapMCLKs, (CAPFIFOSIZE / 2), &dwCapMCLKs);
iNumShift += ScaleMultiply(dwCapMCLKs, dwMCLK, &dwCapMCLKs);
iDenomShift = ScaleMultiply(pConfig->dwXferRate, (DWORD)pConfig->uCapDepth,
&dwDenom);
iDenomShift += ScaleMultiply(dwDenom, (DWORD)pConfig->sizCap.cx, &dwDenom);
if(iNumShift > iDenomShift)
{
dwDenom >>= (iNumShift - iDenomShift);
}
else
{
dwCapMCLKs >>= (iDenomShift - iNumShift);
}
dwCapMCLKs /= dwDenom;
ODS("ChipIsEnoughBandwidth(): dwCapMCLKs = %ld\n", dwCapMCLKs);
if(fConCurrent)
{
if( pConfig->uGfxDepth == 32)
dwCapMCLKs -= 44; //adjust 32 bit
}
if(dwNonCapMCLKs > dwCapMCLKs)
{
ODS("ChipIsEnoughBandwidth(): Capture overflow at start of line.\n");
goto Error;
}
}
if(pConfig->dwFlags & VCFLG_DISP)
{
/*
* Determine maximum video threshold
*/
dwMaxVidThresh = dwHitLatency;
if(pConfig->dwFlags & VCFLG_420)
{
dwMaxVidThresh += VID420FILL;
if( !f500MHZ && fConCurrent )
dwMaxVidThresh += 5;
}
else
{
dwMaxVidThresh += VIDFILL;
}
// ( K * VCLK * VidDepth * SrcWidth )
// INT( ------------------------------ ) + VidFill (/ 2) - 1
// ( FIFOWIDTH * MCLK * DispWidth ) ^non-4:2:0 only
iNumShift = ScaleMultiply(dwMaxVidThresh, dwVCLK, &dwMaxVidThresh);
iNumShift += ScaleMultiply(dwMaxVidThresh, (DWORD)pConfig->uSrcDepth,
&dwMaxVidThresh);
iNumShift += ScaleMultiply(dwMaxVidThresh, (DWORD)pConfig->sizSrc.cx,
&dwMaxVidThresh);
iDenomShift = ScaleMultiply(FIFOWIDTH, (DWORD)pConfig->sizDisp.cx, &dwDenom);
iDenomShift += ScaleMultiply(dwDenom, dwMCLK, &dwDenom);
if(iNumShift > iDenomShift)
{
dwDenom >>= (iNumShift - iDenomShift);
}
else
{
dwMaxVidThresh >>= (iDenomShift - iNumShift);
}
dwMaxVidThresh /= dwDenom;
if(pConfig->dwFlags & VCFLG_420)
{
dwMaxVidThresh += VID420FILL;
}
else
{
dwMaxVidThresh += VIDFILL;
// Threshold is programmed in DQWORDS for non-4:2:0
dwMaxVidThresh /= 2ul;
}
dwMaxVidThresh--;
ODS("ChipIsEnoughBandwidth(): Max video thresh = %ld.\n", dwMaxVidThresh);
if( fConCurrent && f500MHZ && ( dwVCLK < 66000000ul))
dwMaxVidThresh = __min(dwMaxVidThresh, 8);
/*
* Determine minimum video threshold
*/
{
DWORD dwMinVidThresh1, dwMinVidThresh2;
if(pConfig->dwFlags & VCFLG_420)
{
// 4:2:0
dwMinVidThresh1 = DISP_LATENCY + dwRandom + dwGfxFill
+ dwRandom - RIF_SAVINGS + VID420FILL
+ dwRandom - RIF_SAVINGS + 1;
dwMinVidThresh2 = DISP_LATENCY + dwRandom + dwGfxFill
+ dwRandom - RIF_SAVINGS + VID420FILL
+ dwRandom - RIF_SAVINGS + VID420FILL
+ dwRandom - RIF_SAVINGS + VID420FILL
+ dwRandom - RIF_SAVINGS + 1;
}
else
{
// 4:2:2, 5:5:5, 5:6:5, or X:8:8:8
dwMinVidThresh1 = DISP_LATENCY + dwRandom + dwGfxFill
+ dwRandom - RIF_SAVINGS + 2;
dwMinVidThresh2 = DISP_LATENCY + dwRandom + dwGfxFill
+ dwRandom - RIF_SAVINGS + VIDFILL
+ 15ul //#xc
// + 10ul
+ dwRandom - RIF_SAVINGS + dwGfxFill
+ dwRandom - RIF_SAVINGS + 2ul;
if(fConCurrent)
{
if(f500MHZ )
{
if( (pConfig->uGfxDepth == 32) && ( dwVCLK > 60000000ul ))
{
if( dwVCLK > 94000000ul)
dwMinVidThresh1 += 105;
else if( dwVCLK > 74000000ul)
dwMinVidThresh1 += 90;
else
dwMinVidThresh1 += 65;
if(pConfig->dwFlags & VCFLG_CAP)
{
if(dwVCLK > 78000000ul)
dwMinVidThresh1 += 260; //disable video
else if( dwVCLK > 74000000ul)
dwMinVidThresh1 += 70;
}
}
else if( pConfig->uGfxDepth == 24)
{
if( dwVCLK > 94500000ul)
{
if(dwScreenWidth == 1024)
dwMinVidThresh2 += 50ul;
else
dwMinVidThresh2 += 90ul;
}
else if( dwVCLK < 41000000ul)
{
dwMinVidThresh2 += 4;
}
else if(dwVCLK < 80000000ul)
{
if( (dwVCLK > 74000000ul) && (dwVCLK < 76000000ul))
{
dwMinVidThresh2 -= 1;
}
else
dwMinVidThresh2 -= 8;
dwMinVidThresh1 -= 4;
}
if(pConfig->dwFlags & VCFLG_CAP)
if( dwVCLK > 94000000ul)
{
if((dwVCLK < 95000000ul) && ( dwGfxFetch == 256 ))
dwMinVidThresh2 += 60;
else
dwMinVidThresh2 += 120;
}
}
else if( (pConfig->uGfxDepth == 16) && ( dwVCLK > 60000000ul ))
{
if( dwVCLK < 94000000ul)
{
dwMinVidThresh2 -= 10;
dwMinVidThresh1 -= 6;
}
else if( dwVCLK > 105000000ul)
dwMinVidThresh2 += 50;
}
else if( (pConfig->uGfxDepth == 8) && ( dwVCLK > 60000000ul ))
{
if( dwVCLK > 216000000ul)
{
dwMinVidThresh2 += 50;
dwMinVidThresh1 += 20;
}
else if( (dwVCLK < 95000000ul) && ( dwScreenWidth <= 1024))
{
dwMinVidThresh2 -= 12;
dwMinVidThresh1 -= 10;
dwMaxVidThresh = __min(dwMaxVidThresh, 9);
}
else if(dwVCLK < 109000000ul)
{
dwMinVidThresh2 += ( 14 - 4 * ( dwVCLK - 94000000ul ) / 14000000ul );
dwMinVidThresh1 += 10;
dwMaxVidThresh = __min(dwMaxVidThresh, 8);
}
else
{
dwMinVidThresh2 += 7;
dwMinVidThresh1 += 4;
}
}
}
#if 1//PDR#11521
else if (f585MHZ) //585MHZ
{
if( (pConfig->uGfxDepth == 8) && ( dwVCLK > 56000000ul))
{
if( dwVCLK > 200000000ul)
{
dwMaxVidThresh++;
dwMinVidThresh1 += 7;
dwMinVidThresh2 += 14;
}
else if( dwVCLK < 60000000ul)
{
dwMinVidThresh2 += 8;
}
else if( dwVCLK < 160000000ul)
{
dwMinVidThresh1 -=20;
dwMinVidThresh2 -=10;
}
if(pConfig->dwFlags & VCFLG_CAP)
{
if( dwVCLK < 76000000ul)
dwMinVidThresh2 +=8;
else if( dwVCLK < 140000000ul)
dwMinVidThresh2 +=25;
else
dwMinVidThresh2 +=32;
}
}
else if( (pConfig->uGfxDepth == 16) && ( dwVCLK > 60000000ul))
{
if( dwVCLK > 157000000ul)
{
dwMinVidThresh1 += 27;
dwMaxVidThresh ++;
}
if( dwVCLK > 125000000ul)
{
dwMinVidThresh1 += 40;
}
else if( dwVCLK > 107000000ul)
{
dwMinVidThresh1 += 34;
}
else
if( dwVCLK > 74000000ul)
{
dwMinVidThresh1 += 18;
}
if( dwVCLK > 189000000ul) //PDR11521
dwMaxVidThresh ++;
if(pConfig->dwFlags & VCFLG_CAP)
{
if( dwVCLK > 74000000ul)
dwMinVidThresh1 +=2;
}
}
else if( pConfig->uGfxDepth == 24)
{
if( dwVCLK < 60000000ul)
{
dwMinVidThresh1 -= 8;
dwMinVidThresh2 -= 16;
}
else if( dwVCLK > 107000000ul )
dwMinVidThresh2 += 84;
else if( (dwVCLK > 94000000ul) && (dwScreenWidth >= 1152))
{
dwMinVidThresh2 += 40;
}
if( dwVCLK > 126000000ul) //PDR11521
dwMaxVidThresh ++;
if(pConfig->dwFlags & VCFLG_CAP)
{
if( dwVCLK > 74000000ul)
dwMinVidThresh2 +=12;
}
}
else if(( pConfig->uGfxDepth == 32) && ( dwVCLK > 60000000ul))
{
if( dwVCLK > 74000000ul)
{
if( (dwVCLK > 77000000ul) && ( dwVCLK < 80000000ul))
dwMinVidThresh2 += 120;
else
dwMinVidThresh2 += 83;
}
else
dwMinVidThresh2 += 30;
if( dwVCLK > 94000000ul) //PDR11521
dwMaxVidThresh ++;
if(pConfig->dwFlags & VCFLG_CAP)
{
if( dwVCLK > 94000000ul)
dwMinVidThresh2 +=2;
}
}
else if(( pConfig->uGfxDepth == 32) && ( dwVCLK > 49000000ul))
{
if(pConfig->dwFlags & VCFLG_CAP)
dwMinVidThresh2 +=2;
}
}
#endif
else //600MZH concurrent
{
if( (pConfig->uGfxDepth == 8) && ( dwVCLK > 56000000ul))
{
if( dwVCLK > 200000000ul)
{
//PDR#11541 dwMaxVidThresh++;
dwMinVidThresh1 += 7;
dwMinVidThresh2 += 14;
}
else if( dwVCLK < 60000000ul)
{
dwMinVidThresh2 += 8;
}
else if( dwVCLK < 160000000ul)
{
dwMinVidThresh1 -=20;
dwMinVidThresh2 -=10;
}
if(pConfig->dwFlags & VCFLG_CAP)
{
if( dwVCLK < 76000000ul)
dwMinVidThresh2 +=8;
else if( dwVCLK < 140000000ul)
dwMinVidThresh2 +=25;
else
dwMinVidThresh2 +=32;
}
}
else if( (pConfig->uGfxDepth == 16) && ( dwVCLK > 60000000ul))
{
if( dwVCLK > 157000000ul)
{
dwMinVidThresh1 += 27;
//PDR#11541 dwMaxVidThresh ++;
}
if( dwVCLK > 125000000ul)
{
dwMinVidThresh1 += 40;
}
else if( dwVCLK > 107000000ul)
{
dwMinVidThresh1 += 34;
}
else
if( dwVCLK > 74000000ul)
{
dwMinVidThresh1 += 18;
}
if(pConfig->dwFlags & VCFLG_CAP)
{
if( dwVCLK > 74000000ul)
dwMinVidThresh1 +=2;
}
}
else if( pConfig->uGfxDepth == 24)
{
if( dwVCLK < 60000000ul)
{
dwMinVidThresh1 -= 8;
dwMinVidThresh2 -= 16;
}
else if( dwVCLK > 107000000ul )
dwMinVidThresh2 += 84;
else if( (dwVCLK > 94000000ul) && (dwScreenWidth >= 1152))
{
dwMinVidThresh2 += 40;
}
if(pConfig->dwFlags & VCFLG_CAP)
{
if( dwVCLK > 74000000ul)
dwMinVidThresh2 +=12;
}
}
else if(( pConfig->uGfxDepth == 32) && ( dwVCLK > 60000000ul))
{
if( dwVCLK > 74000000ul)
{
if( (dwVCLK > 77000000ul) && ( dwVCLK < 80000000ul))
dwMinVidThresh2 += 120;
else
dwMinVidThresh2 += 83;
}
else
dwMinVidThresh2 += 30;
if(pConfig->dwFlags & VCFLG_CAP)
{
if( dwVCLK > 94000000ul)
dwMinVidThresh2 +=2;
}
}
else if(( pConfig->uGfxDepth == 32) && ( dwVCLK > 49000000ul))
{
if(pConfig->dwFlags & VCFLG_CAP)
dwMinVidThresh2 +=2;
}
}
}
else //Normal RDRam case
{
if(f500MHZ )
{
if( (pConfig->uGfxDepth == 32) && ( dwVCLK > 60000000ul ))
{
dwMinVidThresh1 += 75;
if(pConfig->dwFlags & VCFLG_CAP)
dwMinVidThresh1 +=20;
}
else if( (pConfig->uGfxDepth == 24) && ( dwVCLK > 7800000ul ))
{
dwMinVidThresh2 += 52;
if(pConfig->dwFlags & VCFLG_CAP)
{
dwMinVidThresh2 += 50;
}
}
else if(pConfig->uGfxDepth == 16)
{
if((dwVCLK > 36000000 ) && ( dwVCLK < 57000000))
{
dwMinVidThresh2 += 22 - ( dwVCLK - 36000000) * 3L /
4000000;
}
else
{
dwMinVidThresh2 -= 18;
dwMinVidThresh1 -= 8;
}
if(pConfig->dwFlags & VCFLG_CAP)
{
dwMinVidThresh2 += 5;
}
}
else if((pConfig->uGfxDepth == 8) && ( dwVCLK > 36000000ul ))
{
if(dwVCLK > 160000000ul)
dwMinVidThresh2 -= 6;
else if( (dwVCLK > 94000000 ) && (dwVCLK < 109000000) && (dwScreenWidth == 1152))
{
dwMinVidThresh2 -= 2 + 4 * ( dwVCLK - 94000000 ) / 13500000;
}
else if( (dwVCLK < 109000000) && (dwScreenWidth == 1280))
{
dwMinVidThresh2 -= 5;
}
else if( dwVCLK > 60000000ul)
{
dwMinVidThresh2 -= 18;
if(pConfig->dwFlags & VCFLG_CAP)
{
dwMinVidThresh2 += 5;
}
}
else
dwMinVidThresh2 += 6;
dwMinVidThresh1 -= 8;
}
}
else //600 MHZ
{
if(pConfig->uGfxDepth == 32)
{
if( dwVCLK > 60000000ul )
{
dwTemp = ( dwVCLK - 60000000ul ) /300000ul + 38ul;
dwMinVidThresh1 += dwTemp;
}
if((pConfig->dwFlags & VCFLG_CAP) && (dwVCLK > 40000000ul))
{
if(dwVCLK > 94000000ul)
dwTemp = 120; //disable capture;
else
dwTemp = ( dwVCLK - 40006685ul) /1085905ul + 5;
dwMinVidThresh1 +=dwTemp;
}
}
else if( pConfig->uGfxDepth == 24)
{
if( dwVCLK < 50000000ul)
dwMinVidThresh2 -= 5;
else
dwMinVidThresh2 -= 18;
dwMinVidThresh1 -= 8;
if((pConfig->dwFlags & VCFLG_CAP) && (dwVCLK > 94000000ul))
dwMinVidThresh2 += 8;
}
else if(pConfig->uGfxDepth == 16)
{
if( (dwVCLK < 100000000ul ) && (dwVCLK > 66000000ul))
{
dwTemp = 31ul - (dwVCLK -60000000ul) / 1968750ul;
}
else if( dwVCLK <= 66000000ul) //after 1024X768 only adjust constantly
{
if( dwVCLK < 57000000ul)
{
dwTemp = 0ul;
dwMinVidThresh2 += 10ul;
}
else
dwTemp = 5ul;
}
if(dwVCLK > 100000000ul)
{
dwMinVidThresh2 += 40ul;
dwMinVidThresh1 += 20ul;
}
else
{
dwMinVidThresh2 -= dwTemp;
dwMinVidThresh1 -= 8ul;
}
}
else if(pConfig->uGfxDepth == 8)
{
if((dwVCLK > 94000000ul) && ( dwScreenWidth >=1152))
{
if(dwVCLK > 108000000ul)
dwMinVidThresh2 += 10;
else
dwMinVidThresh2 += 20;
dwMinVidThresh1 += 1;
}
else if( dwVCLK > 64000000ul )
{
if( dwVCLK > 70000000ul)
dwTemp = 25;
else
dwTemp = 5;
if(pConfig->dwFlags & VCFLG_CAP)
{
if(dwVCLK < 760000000ul )
dwTemp = 0;
else if(dwVCLK < 950000000ul)
dwTemp -= 10;
}
dwMinVidThresh2 -= dwTemp;
dwMinVidThresh1 -= 15;
}
}
}
}
}
//
// Finish dwMinVidThresh1
//
// ( K * VidDepth * SrcWidth * VCLK (FIFOWIDTH * DispWidth * MCLK) - 1 )
// INT( ------------------------------ + ---------------------------------- ) (/ 2) + 1
// ( FIFOWIDTH * DispWidth * MCLK FIFOWIDTH * DispWidth * MCLK )
iNumShift = ScaleMultiply(dwMinVidThresh1, (DWORD)pConfig->uSrcDepth,
&dwMinVidThresh1);
iNumShift += ScaleMultiply(dwMinVidThresh1, (DWORD)pConfig->sizSrc.cx,
&dwMinVidThresh1);
iNumShift += ScaleMultiply(dwMinVidThresh1, dwVCLK, &dwMinVidThresh1);
iDenomShift = ScaleMultiply(FIFOWIDTH, (DWORD)pConfig->sizDisp.cx,
&dwDenom);
iDenomShift += ScaleMultiply(dwDenom, dwMCLK, &dwDenom);
if(iNumShift > iDenomShift)
{
dwDenom >>= (iNumShift - iDenomShift);
}
else
{
dwMinVidThresh1 >>= (iDenomShift - iNumShift);
}
// Be sure rounding below doesn't overflow (it happened!)
while((dwMinVidThresh1 + dwDenom - 1ul) < dwMinVidThresh1)
{
dwMinVidThresh1 >>= 1;
dwDenom >>= 1;
}
dwMinVidThresh1 += dwDenom - 1ul;
dwMinVidThresh1 /= dwDenom;
if(!(pConfig->dwFlags & VCFLG_420))
{
// Threshold is programmed in DQWORDS for non-4:2:0
dwMinVidThresh1 /= 2ul;
}
dwMinVidThresh1++; // Adjust for -2 decrement of FIFO count done to
// synchronize MCLK with faster VCLK.
//
// Finish dwMinVidThresh2
//
// K * VidDepth * VidWidth * VCLK (FIFOWIDTH * DispWidth * MCLK) - 1
// ------------------------------ + ----------------------------------
// FIFOWIDTH * DispWidth * MCLK FIFOWIDTH * DispWidth * MCLK
//
// VIDFIFOSIZE
// - ----------- (/ 2) + 1
// 2 ^non-4:2:0 only
iNumShift = ScaleMultiply(dwMinVidThresh2, (DWORD)pConfig->uSrcDepth,
&dwMinVidThresh2);
iNumShift += ScaleMultiply(dwMinVidThresh2, (DWORD)pConfig->sizSrc.cx,
&dwMinVidThresh2);
iNumShift += ScaleMultiply(dwMinVidThresh2, dwVCLK, &dwMinVidThresh2);
iDenomShift = ScaleMultiply(FIFOWIDTH, (DWORD)pConfig->sizDisp.cx,
&dwDenom);
iDenomShift += ScaleMultiply(dwDenom, dwMCLK, &dwDenom);
if(iNumShift > iDenomShift)
{
dwDenom >>= (iNumShift - iDenomShift);
}
else
{
dwMinVidThresh2 >>= (iDenomShift - iNumShift);
}
// Be sure rounding below doesn't overflow (it happened!)
while((dwMinVidThresh2 + dwDenom - 1ul) < dwMinVidThresh2)
{
dwMinVidThresh2 >>= 1;
dwDenom >>= 1;
}
dwMinVidThresh2 += dwDenom - 1ul;
dwMinVidThresh2 /= dwDenom;
if(dwMinVidThresh2 > (VIDFIFOSIZE /2ul) )
dwMinVidThresh2 -= (VIDFIFOSIZE / 2ul);
else
dwMinVidThresh2 = 0;
if(!(pConfig->dwFlags & VCFLG_420))
{
// Threshold is programmed in DQWORDS for non-4:2:0
dwMinVidThresh2 /= 2ul;
}
dwMinVidThresh2++; // Adjust for -2 decrement of FIFO count done to
// synchronize MCLK with faster VCLK.
ODS("ChipIsEnoughBandwidth(): Min video thresh1 and 2 = %ld %ld.\n",
dwMinVidThresh1, dwMinVidThresh2);
if(dwMinVidThresh2 > VIDFIFOSIZE -1)
{
dwMinVidThresh2 = VIDFIFOSIZE -1;
}
//
// Whichever is higher should be the right one
//
dwMinVidThresh = __max(dwMinVidThresh1, dwMinVidThresh2);
}
ODS("ChipIsEnoughBandwidth(): Min video thresh = %ld.\n", dwMinVidThresh);
if(dwMaxVidThresh < dwMinVidThresh)
{
ODS("ChipIsEnoughBandwidth(): Minimum video threshold exceeds maximum.\n");
goto Error;
}
//I don't know why, but it need checked for capture. #xc
if((pConfig->dwFlags & VCFLG_CAP) && (dwMaxVidThresh > 8)
&& ((pConfig->uGfxDepth != 8) || fConCurrent) && ( f500MHZ || !fConCurrent))
{
ODS("ChipIsEnoughBandwidth(): Video threshold exceeds non-aligned safe value.\n");
goto Error;
}
if(pProgRegs)
{
if((((pConfig->uGfxDepth == 8) && (dwVCLK > 60000000)) ||
((pConfig->uGfxDepth != 8) && ( dwVCLK > 56000000)) ||
( !f500MHZ && fConCurrent)) && !(pConfig->dwFlags & VCFLG_CAP))
pProgRegs->VW0_FIFO_THRSH = (WORD)dwMaxVidThresh;
else
pProgRegs->VW0_FIFO_THRSH = (WORD)__min( 8, dwMaxVidThresh);
ODS("ChipIsEnoughBandwidth(): thresh = %ld.\n", pProgRegs->VW0_FIFO_THRSH);
}
}
fSuccess = TRUE;
Error:
return(fSuccess);
}
#endif // WINNT_VER35