/********************************************************** * 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