From fc5d7acc23fcec9d87ca26fadf466fcf107671c0 Mon Sep 17 00:00:00 2001
From: Mathieu Larouche <mathieu.larouche@matrox.com>
Date: Wed, 20 Jul 2016 09:18:49 -0400
Subject: [PATCH] xf86-video-mga: Add support for the new G200e chipset -- V2

- Added PLL algorithm for a new rev of G200e
- Removed the bandwidth limitation for the new G200e

Fixes : https://bugs.freedesktop.org/show_bug.cgi?id=92540

Change from V1 :
- Make sure we don't cause issue on previous chips. (Dave Airlie review)

Signed-off-by: Mathieu Larouche <mathieu.larouche@matrox.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
---
 src/mga_dacG.c   | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/mga_driver.c |  6 ++---
 2 files changed, 83 insertions(+), 5 deletions(-)

Index: xf86-video-mga-1.4.11/src/mga_dacG.c
===================================================================
--- xf86-video-mga-1.4.11.orig/src/mga_dacG.c
+++ xf86-video-mga-1.4.11/src/mga_dacG.c
@@ -54,6 +54,75 @@ static Bool MGAGInit(ScrnInfoPtr, Displa
 static void MGAGLoadPalette(ScrnInfoPtr, int, int*, LOCO*, VisualPtr);
 static Bool MGAG_i2cInit(ScrnInfoPtr pScrn);
 
+#define P_ARRAY_SIZE 9
+
+void
+MGAG200E4ComputePLLParam(ScrnInfoPtr pScrn, long lFo, int *M, int *N, int *P)
+{
+    unsigned int ulComputedFo;
+    unsigned int ulFDelta;
+    unsigned int ulFPermitedDelta;
+    unsigned int ulFTmpDelta;
+    unsigned int ulVCOMax, ulVCOMin;
+    unsigned int ulTestP;
+    unsigned int ulTestM;
+    unsigned int ulTestN;
+    unsigned int ulFoInternal;
+    unsigned int ulPLLFreqRef;
+    unsigned int pulPValues[P_ARRAY_SIZE] = {16, 14, 12, 10, 8, 6, 4, 2, 1};
+    unsigned int i;
+    unsigned int ulVCO;
+    unsigned int ulFVV;
+
+    ulVCOMax        = 1600000;
+    ulVCOMin        = 800000;
+    ulPLLFreqRef    = 25000;
+
+    if(lFo < 25000)
+        lFo = 25000;
+
+    ulFoInternal = lFo * 2;
+
+    ulFDelta = 0xFFFFFFFF;
+    /* Permited delta is 0.5% as VESA Specification */
+    ulFPermitedDelta = ulFoInternal * 5 / 1000;  
+
+    for (i = 0 ; i < P_ARRAY_SIZE ; i++)
+    {
+        ulTestP = pulPValues[i];
+
+        if ((ulFoInternal * ulTestP) > ulVCOMax) continue;
+        if ((ulFoInternal * ulTestP) < ulVCOMin) continue;
+
+        for (ulTestN = 50; ulTestN <= 256; ulTestN++) {
+            for (ulTestM = 1; ulTestM <= 32; ulTestM++) {
+                ulComputedFo = (ulPLLFreqRef * ulTestN) / (ulTestM * ulTestP);
+                if (ulComputedFo > ulFoInternal)
+                    ulFTmpDelta = ulComputedFo - ulFoInternal;
+                else
+                    ulFTmpDelta = ulFoInternal - ulComputedFo;
+
+                if (ulFTmpDelta < ulFDelta) {
+                    ulFDelta = ulFTmpDelta;
+                    *M = ulTestM - 1;
+                    *N = ulTestN - 1;
+                    *P = ulTestP - 1;
+                }
+            }
+        }
+    }
+                                                                                                                    
+    ulVCO = ulPLLFreqRef * ((*N)+1) / ((*M)+1);
+    ulFVV = (ulVCO - 800000) / 50000;
+
+    if (ulFVV > 15)
+        ulFVV = 15;
+
+    *P |= (ulFVV << 4);                                                                                             
+
+    *M |= 0x80;
+}
+
 static void
 MGAG200SEComputePLLParam(ScrnInfoPtr pScrn, long lFo, int *M, int *N, int *P)
 {
@@ -943,7 +1012,11 @@ MGAGSetPCLK( ScrnInfoPtr pScrn, long f_o
 	}
 
 	if (pMga->is_G200SE) {
-	    MGAG200SEComputePLLParam(pScrn, f_out, &m, &n, &p);
+            if (pMga->reg_1e24 >= 0x04) {
+                MGAG200E4ComputePLLParam(pScrn, f_out, &m, &n, &p);
+            } else {
+                MGAG200SEComputePLLParam(pScrn, f_out, &m, &n, &p);
+            }
 
 	    pReg->DacRegs[ MGA1064_PIX_PLLC_M ] = m;
 	    pReg->DacRegs[ MGA1064_PIX_PLLC_N ] = n;
@@ -1553,7 +1626,12 @@ MGA_NOT_HAL(
         {
 			outMGAdac(0x90, mgaReg->Dac_Index90);
         }
-   
+           if (pMga->is_G200SE && (pMga->reg_1e24 >= 0x04)) {
+              outMGAdac( 0x1a, 0x09);
+              usleep(500);
+              outMGAdac( 0x1a, 0x01);
+           }
+    
 	   if (!MGAISGx50(pMga)) {
 	       /* restore pci_option register */
 #ifdef XSERVER_LIBPCIACCESS
Index: xf86-video-mga-1.4.11/src/mga_driver.c
===================================================================
--- xf86-video-mga-1.4.11.orig/src/mga_driver.c
+++ xf86-video-mga-1.4.11/src/mga_driver.c
@@ -325,7 +325,7 @@ static const struct mga_device_attribute
     },
 
     /* G200SE A PCI */
-    [10] = { 0, 1, 0, 0, 1, 0, 0, 1, new_BARs,
+    [10] = { 0, 1, 0, 0, 1, 0, 0, 0, new_BARs,
             (TRANSC_SOLID_FILL | TWO_PASS_COLOR_EXPAND | USE_LINEAR_EXPANSION),
 	{
 	    { 50000, 230000 }, /* System VCO frequencies */
@@ -341,7 +341,7 @@ static const struct mga_device_attribute
     },
 
     /* G200SE B PCI */
-    [11] = { 0, 1, 0, 0, 1, 0, 0, 1, new_BARs,
+    [11] = { 0, 1, 0, 0, 1, 0, 0, 0, new_BARs,
             (TRANSC_SOLID_FILL | TWO_PASS_COLOR_EXPAND | USE_LINEAR_EXPANSION),
 	{
 	    { 50000, 114000 }, /* System VCO frequencies */
@@ -4494,7 +4494,7 @@ MGAValidMode(int scrnIndex, DisplayModeP
 	        if (xf86ModeBandwidth(mode, pScrn->bitsPerPixel) > 244)
 	            return MODE_BANDWIDTH;
         } else {
-            if (pMga->reg_1e24 >= 0x02) {
+            if (pMga->reg_1e24 == 0x02) {
 	            if (mode->HDisplay > 1920)
 	                return MODE_VIRTUAL_X;
 	            if (mode->VDisplay > 1200)
