Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id ; Tue, 6 Feb 2001 15:53:23 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id ; Tue, 6 Feb 2001 15:53:14 -0500 Received: from imladris.demon.co.uk ([193.237.130.41]:268 "EHLO imladris.demon.co.uk") by vger.kernel.org with ESMTP id ; Tue, 6 Feb 2001 15:53:02 -0500 Date: Tue, 6 Feb 2001 20:52:15 +0000 (GMT) From: David Woodhouse To: "Mike A. Harris" cc: Petr Vandrovec , J Brook , Subject: Re: [OT] Re: Matrox G450 problems with 2.4.0 and xfree In-Reply-To: Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org On Tue, 6 Feb 2001, Mike A. Harris wrote: > If anyone has open source g450 patches against stock 4.0.2 that > get the thing to work at all, _please_ send me unified diffs, and > I will put them into my next build. I've yet to have my g450 do > anything but turn off my monitor, although a handful of people > claim they get it working to various degrees... I don't have > g450 specs either so.. We're getting significantly off-topic for linux-kernel. But the patch below worked for me in my limited testing - starting the X server twice in different modes on a colleague's G450. It's almost, but not quite, identical to the changes in the RH7.1 beta RPM. It's against (and was tested with) the current CVS, but applies cleanly to 4.0.2 as well. Almost _functionally_ identical, that is - some of their original offended me so much it just had to be cleaned up. diff -uNr mga-preg450/Imakefile mga/Imakefile --- mga-preg450/Imakefile Sat Feb 3 23:53:49 2001 +++ mga/Imakefile Sun Feb 4 00:05:36 2001 @@ -57,10 +57,10 @@ MGASRCS = mga_driver.c mga_hwcurs.c /* mga_cmap.c */ mga_dac3026.c mga_dacG.c \ mga_storm8.c mga_storm16.c mga_storm24.c mga_storm32.c mga_arc.c \ - mga_dga.c mga_shadow.c mga_video.c $(DRISRCS) + mga_dga.c mga_shadow.c mga_video.c mga_g450pll.c $(DRISRCS) MGAOBJS = mga_driver.o mga_hwcurs.o /* mga_cmap.o */ mga_dac3026.o mga_dacG.o \ mga_storm8.o mga_storm16.o mga_storm24.o mga_storm32.o mga_arc.o \ - mga_dga.o mga_shadow.o mga_video.o $(DRIOBJS) + mga_dga.o mga_shadow.o mga_video.o mga_g450pll.o $(DRIOBJS) SRCS = $(MGASRCS) $(MGAHALSRCS) OBJS = $(MGAOBJS) $(MGAHALOBJS) diff -uNr mga-preg450/mga.h mga/mga.h --- mga-preg450/mga.h Sat Feb 3 23:53:50 2001 +++ mga/mga.h Sun Feb 4 00:06:02 2001 @@ -414,4 +414,5 @@ void MGAInitVideo(ScreenPtr pScreen); void MGAResetVideo(ScrnInfoPtr pScrn); +double G450SetPLLFreq(ScrnInfoPtr pScrn, long f_out); #endif diff -uNr mga-preg450/mga_dacG.c mga/mga_dacG.c --- mga-preg450/mga_dacG.c Sat Feb 3 23:53:53 2001 +++ mga/mga_dacG.c Sun Feb 4 00:29:12 2001 @@ -237,6 +237,11 @@ /* The actual frequency output by the clock */ double f_pll; + if(MGAISG450(pMga)) { + G450SetPLLFreq(pScrn, f_out); + return; + } + /* Do the calculations for m, n, p and s */ f_pll = MGAGCalcClock( pScrn, f_out, &m, &n, &p, &s ); @@ -338,6 +343,9 @@ #ifdef USEMGAHAL MGA_HAL(break;); #endif + if (MGAISG450(pMga)) + break; + if(pMga->Dac.maxPixelClock == 360000) { /* G400 MAX */ if(pMga->OverclockMem) { /* 150/200 */ @@ -528,6 +536,10 @@ if (mode->Flags & V_DBLSCAN) pVga->CRTC[9] |= 0x80; + if(MGAISG450(pMga)) { + OUTREG(MGAREG_ZORG, 0); + } + MGAGSetPCLK(pScrn, mode->Clock); ); /* MGA_NOT_HAL */ @@ -656,7 +668,10 @@ (i == 0x1b) || (i == 0x1c) || ((i >= 0x1f) && (i <= 0x29)) || - ((i >= 0x30) && (i <= 0x37)) ) + ((i >= 0x30) && (i <= 0x37)) || + (MGAISG450(pMga) && + ((i == 0x2c) || (i == 0x2d) || (i == 0x2e) || + (i == 0x4c) || (i == 0x4d) || (i == 0x4e)))) continue; outMGAdac(i, mgaReg->DacRegs[i]); } @@ -665,15 +680,17 @@ should be correct already */ optionMask = (pMga->Primary) ? OPTION1_MASK_PRIMARY : OPTION1_MASK; - /* restore pci_option register */ - pciSetBitsLong(pMga->PciTag, PCI_OPTION_REG, optionMask, - mgaReg->Option); - if (pMga->Chipset != PCI_CHIP_MGA1064) - pciSetBitsLong(pMga->PciTag, PCI_MGA_OPTION2, OPTION2_MASK, - mgaReg->Option2); - if (pMga->Chipset == PCI_CHIP_MGAG400) - pciSetBitsLong(pMga->PciTag, PCI_MGA_OPTION3, OPTION3_MASK, - mgaReg->Option3); + if (!MGAISG450(pMga)) { + /* restore pci_option register */ + pciSetBitsLong(pMga->PciTag, PCI_OPTION_REG, optionMask, + mgaReg->Option); + if (pMga->Chipset != PCI_CHIP_MGA1064) + pciSetBitsLong(pMga->PciTag, PCI_MGA_OPTION2, OPTION2_MASK, + mgaReg->Option2); + if (pMga->Chipset == PCI_CHIP_MGAG400) + pciSetBitsLong(pMga->PciTag, PCI_MGA_OPTION3, OPTION3_MASK, + mgaReg->Option3); + } ); /* MGA_NOT_HAL */ /* restore CRTCEXT regs */ diff -uNr mga-preg450/mga_g450pll.c mga/mga_g450pll.c --- mga-preg450/mga_g450pll.c Thu Jan 1 01:00:00 1970 +++ mga/mga_g450pll.c Sun Feb 4 00:00:04 2001 @@ -0,0 +1,444 @@ +/* All drivers should typically include these */ +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" + +/* Drivers for PCI hardware need this */ +#include "xf86PciInfo.h" + +/* Drivers that need to access the PCI config space directly need this */ +#include "xf86Pci.h" + +#include "mga_bios.h" +#include "mga_reg.h" +#include "mga.h" + +#define DEBUG + +#define MNP_TABLE_SIZE 64 +#define CLKSEL_MGA 0x0c +#define PLLLOCK 0x40 + +#define outMGAdreg(reg, val) OUTREG8(RAMDAC_OFFSET + (reg), val) + +#define outMGAdac(reg, val) \ + (outMGAdreg(MGA1064_INDEX, reg), outMGAdreg(MGA1064_DATA, val)) + +static CARD32 G450ApplyPFactor(ScrnInfoPtr pScrn, CARD8 ucP, CARD32 *pulFIn) +{ + if(!(ucP & 0x40)) + { + *pulFIn = *pulFIn / (2L << (ucP & 3)); + } + + return TRUE; +} + + +static CARD32 G450RemovePFactor(ScrnInfoPtr pScrn, CARD8 ucP, CARD32 *pulFIn) +{ + if(!(ucP & 0x40)) + { + *pulFIn = *pulFIn * (2L << (ucP & 3)); + } + + return TRUE; +} + + +static CARD32 G450CalculVCO(ScrnInfoPtr pScrn, CARD32 ulMNP, CARD32 *pulF) +{ + CARD8 ucM, ucN, ucP; + + ucM = (CARD8)((ulMNP >> 16) & 0xff); + ucN = (CARD8)((ulMNP >> 8) & 0xff); + ucP = (CARD8)(ulMNP & 0x03); + + *pulF = (27000 * (2 * (ucN + 2)) + ((ucM + 1) >> 1)) / (ucM + 1); + + return TRUE; +} + + +static CARD32 G450CalculDeltaFreq(ScrnInfoPtr pScrn, CARD32 ulF1, + CARD32 ulF2, CARD32 *pulDelta) +{ + if(ulF2 < ulF1) + { + *pulDelta = ((ulF1 - ulF2) * 1000) / ulF1; + } + else + { + *pulDelta = ((ulF2 - ulF1) * 1000) / ulF1; + } + + return TRUE; +} + + + + +static CARD32 G450FindNextPLLParam(ScrnInfoPtr pScrn, CARD32 ulFout, + CARD32 *pulPLLMNP) +{ + CARD8 ucM, ucN, ucP, ucS; + CARD32 ulVCO, ulVCOMin; + + ucM = (CARD8)((*pulPLLMNP >> 16) & 0xff); + ucN = (CARD8)((*pulPLLMNP >> 8) & 0xff); + ucP = (CARD8)(*pulPLLMNP & 0x43); + + ulVCOMin = 256000; + + if(ulVCOMin >= (255L * 8000)) + { + ulVCOMin = 230000; + } + + if((ucM == 9) && (ucP & 0x40)) + { + *pulPLLMNP = 0xffffffff; + } else if (ucM == 9) + { + if(ucP) + { + ucP--; + } + else + { + ucP = 0x40; + } + ucM = 0; + } + else + { + ucM++; + } + + ulVCO = ulFout; + + G450RemovePFactor(pScrn, ucP, &ulVCO); + + if(ulVCO < ulVCOMin) + { + *pulPLLMNP = 0xffffffff; + } + + if(*pulPLLMNP != 0xffffffff) + { + ucN = (CARD8)(((ulVCO * (ucM+1) + 27000)/(27000 * 2)) - 2); + + ucS = 5; + if(ulVCO < 1300000) ucS = 4; + if(ulVCO < 1100000) ucS = 3; + if(ulVCO < 900000) ucS = 2; + if(ulVCO < 700000) ucS = 1; + if(ulVCO < 550000) ucS = 0; + + ucP |= (CARD8)(ucS << 3); + + *pulPLLMNP &= 0xff000000; + *pulPLLMNP |= (CARD32)ucM << 16; + *pulPLLMNP |= (CARD32)ucN << 8; + *pulPLLMNP |= (CARD32)ucP; + } + + return TRUE; +} + + +static CARD32 G450FindFirstPLLParam(ScrnInfoPtr pScrn, CARD32 ulFout, + CARD32 *pulPLLMNP) +{ + CARD8 ucP; + CARD32 ulVCO; + CARD32 ulVCOMax; + + /* Default value */ + ulVCOMax = 1300000; + + if(ulFout > (ulVCOMax/2)) + { + ucP = 0x40; + ulVCO = ulFout; + } + else + { + ucP = 3; + ulVCO = ulFout; + G450RemovePFactor(pScrn, ucP, &ulVCO); + while(ucP && (ulVCO > ulVCOMax)) + { + ucP--; + ulVCO = ulFout; + G450RemovePFactor(pScrn, ucP, &ulVCO); + } + } + + if(ulVCO > ulVCOMax) + { + *pulPLLMNP = 0xffffffff; + } + else + { + /* Pixel clock: 1 */ + *pulPLLMNP = (1 << 24) + 0xff0000 + ucP; + G450FindNextPLLParam(pScrn, ulFout, pulPLLMNP); + } + + return TRUE; + +} + + +static CARD32 G450WriteMNP(ScrnInfoPtr pScrn, CARD32 ulMNP) +{ + MGAPtr pMga = MGAPTR(pScrn); + + /* Pixel Pll */ + outMGAdac(MGA1064_PIX_PLLC_M, (CARD8)(ulMNP >> 16)); + outMGAdac(MGA1064_PIX_PLLC_N, (CARD8)(ulMNP >> 8)); + outMGAdac(MGA1064_PIX_PLLC_P, (CARD8) ulMNP); + OUTREG8(0x3c00, 0x4f); + return TRUE; +} + + +static CARD32 G450CompareMNP(ScrnInfoPtr pScrn, CARD32 ulFout, CARD32 ulMNP1, + CARD32 ulMNP2, long *pulResult) +{ + CARD32 ulFreq, ulDelta1, ulDelta2; + + G450CalculVCO(pScrn, ulMNP1, &ulFreq); + G450ApplyPFactor(pScrn, (CARD8) ulMNP1, &ulFreq); + G450CalculDeltaFreq(pScrn, ulFout, ulFreq, &ulDelta1); + + G450CalculVCO(pScrn, ulMNP2, &ulFreq); + G450ApplyPFactor(pScrn, (CARD8) ulMNP2, &ulFreq); + G450CalculDeltaFreq(pScrn, ulFout, ulFreq, &ulDelta2); + + if(ulDelta1 < ulDelta2) + { + *pulResult = -1; + } + else if(ulDelta1 > ulDelta2) + { + *pulResult = 1; + } + else + { + *pulResult = 0; + } + + if((ulDelta1 <= 5) && (ulDelta2 <= 5)) + { + if((ulMNP1 & 0xff0000) < (ulMNP2 & 0xff0000)) + { + *pulResult = -1; + } + else if((ulMNP1 & 0xff0000) > (ulMNP2 & 0xff0000)) + { + *pulResult = 1; + } + } + + return TRUE; +} + + +static CARD32 G450IsPllLocked(ScrnInfoPtr pScrn, Bool *lpbLocked) +{ + CARD32 ulFallBackCounter, ulLockCount, ulCount; + CARD8 ucPLLStatus; + + MGAPtr pMga = MGAPTR(pScrn); + + /* Pixel PLL */ + OUTREG8(0x3c00, 0x4f); + + ulFallBackCounter = 0; + + do + { + ucPLLStatus = INREG8(0x3c0a); + ulFallBackCounter++; + } while(!(ucPLLStatus & PLLLOCK) && (ulFallBackCounter < 1000)); + + ulLockCount = 0; + if(ulFallBackCounter < 1000) + { + for(ulCount = 0; ulCount < 100; ulCount++) + { + ucPLLStatus = INREG8(0x3c0a); + if(ucPLLStatus & PLLLOCK) + { + ulLockCount++; + } + } + } + + *lpbLocked = ulLockCount >= 90; + + return TRUE; +} + + +double G450SetPLLFreq(ScrnInfoPtr pScrn, long f_out) +{ + Bool bFoundValidPLL; + Bool bLocked; + CARD8 ucMisc; + CARD8 ucS; + CARD32 ulMaxIndex; + CARD32 ulMNP; + CARD32 ulMNPTable[MNP_TABLE_SIZE]; + CARD32 ulIndex; + CARD32 ulTryMNP; + long lCompareResult; + + MGAPtr pMga = MGAPTR(pScrn); + + G450FindFirstPLLParam(pScrn, f_out, &ulMNP); + ulMNPTable[0] = ulMNP; + G450FindNextPLLParam(pScrn, f_out, &ulMNP); + ulMaxIndex = 1; + while(ulMNP != 0xffffffff) + { + int ulIndex; + Bool bSkipValue; + + bSkipValue = FALSE; + if(ulMaxIndex == MNP_TABLE_SIZE) + { + G450CompareMNP(pScrn, f_out, ulMNP, ulMNPTable[MNP_TABLE_SIZE - 1], + &lCompareResult); + + if(lCompareResult > 0) + { + bSkipValue = TRUE; + } + else + { + ulMaxIndex--; + } + } + + if(!bSkipValue) + { + for(ulIndex = ulMaxIndex; !bSkipValue && (ulIndex > 0); ulIndex--) + { + G450CompareMNP(pScrn, f_out, ulMNP, ulMNPTable[ulIndex - 1], + &lCompareResult); + + if(lCompareResult < 0) + { + ulMNPTable[ulIndex] = ulMNPTable[ulIndex - 1]; + } + else + { + break; + } + } + ulMNPTable[ulIndex] = ulMNP; + ulMaxIndex++; + } + + G450FindNextPLLParam(pScrn, f_out, &ulMNP); + } + + bFoundValidPLL = FALSE; + ulMNP = 0; + + /* For pixel pll */ + ucMisc = INREG8(0x1FCC); + OUTREG8(0x1fc2, (CARD8)(ucMisc | CLKSEL_MGA)); + + for(ulIndex = 0; !bFoundValidPLL && (ulIndex < ulMaxIndex); ulIndex++) + { + ulTryMNP = ulMNPTable[ulIndex]; + + for(ucS = 0; !bFoundValidPLL && (ucS < 0x40); ucS += 8) + { + ulTryMNP &= 0xffffffc7; + ulTryMNP |= (CARD32)ucS; + + bLocked = TRUE; + if((ulMNPTable[ulIndex] & 0xff00) < 0x300 || + (ulMNPTable[ulIndex] & 0xff00) > 0x7a00) + { + bLocked = FALSE; + } + + if(bLocked) + { + G450WriteMNP(pScrn, ulTryMNP - 0x300); + G450IsPllLocked(pScrn, &bLocked); + } + + if(bLocked) + { + G450WriteMNP(pScrn, ulTryMNP + 0x300); + G450IsPllLocked(pScrn, &bLocked); + } + + if(bLocked) + { + G450WriteMNP(pScrn, ulTryMNP - 0x200); + G450IsPllLocked(pScrn, &bLocked); + } + + if(bLocked) + { + G450WriteMNP(pScrn, ulTryMNP + 0x200); + G450IsPllLocked(pScrn, &bLocked); + } + + if(bLocked) + { + G450WriteMNP(pScrn, ulTryMNP - 0x100); + G450IsPllLocked(pScrn, &bLocked); + } + + if(bLocked) + { + G450WriteMNP(pScrn, ulTryMNP + 0x100); + G450IsPllLocked(pScrn, &bLocked); + } + + if(bLocked) + { + G450WriteMNP(pScrn, ulTryMNP); + G450IsPllLocked(pScrn, &bLocked); + } + else if(!ulMNP) + { + G450WriteMNP(pScrn, ulTryMNP); + G450IsPllLocked(pScrn, &bLocked); + if(bLocked) + { + ulMNP = ulMNPTable[ulIndex]; + } + bLocked = FALSE; + } + + if(bLocked) + { + bFoundValidPLL = TRUE; + } + } + } + + if(!bFoundValidPLL) + { + if(ulMNP) + { + G450WriteMNP(pScrn, ulMNP); + } + else + { + G450WriteMNP(pScrn, ulMNPTable[0]); + } + } + + return TRUE; +} diff -uNr mga-preg450/mga_macros.h mga/mga_macros.h --- mga-preg450/mga_macros.h Sat Feb 3 23:53:59 2001 +++ mga/mga_macros.h Sun Feb 4 00:24:14 2001 @@ -107,4 +107,6 @@ #define MGA_NOT_HAL(x) { x; } #endif +#define MGAISG450(x) ( ((x)->Chipset == PCI_CHIP_MGAG400) && ((x)->ChipRev >= 0x80) ) + #endif /* _MGA_MACROS_H_ */ -- dwmw2 - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org Please read the FAQ at http://www.tux.org/lkml/