From 12781f2e3deb7f6d86fde53134384996a6004894 Mon Sep 17 00:00:00 2001
From: Mathieu Larouche <mathieu.larouche@matrox.com>
Date: Fri, 17 Jun 2016 10:52:42 -0400
Subject: [PATCH] xf86-video-mga: Add support for a new G200eW3 chipset

- Added support for the new deviceID for G200eW3
- Added PLL algorithm for the G200eW3
- Added some initialization code for G200eW3

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

Signed-off-by: Mathieu Larouche <mathieu.larouche@matrox.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
---
 src/mga.h        |  10 ++++--
 src/mga_dacG.c   | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/mga_driver.c |  49 +++++++++++++++++++++-----
 src/mga_merge.c  |   4 ++-
 src/mga_storm.c  |   1 +
 5 files changed, 149 insertions(+), 17 deletions(-)

Index: xf86-video-mga-1.4.11/src/mga.h
===================================================================
--- xf86-video-mga-1.4.11.orig/src/mga.h
+++ xf86-video-mga-1.4.11/src/mga.h
@@ -145,6 +145,12 @@ void MGAdbg_outreg32(ScrnInfoPtr, int,in
  * Read/write to the DAC via MMIO 
  */
 
+#ifndef PCI_CHIP_MGAG200_EW3_PCI
+#define PCI_CHIP_MGAG200_EW3_PCI 0x0536
+#endif
+
+
+
 /*
  * These were functions.  Use macros instead to avoid the need to
  * pass pMga to them.
@@ -204,9 +210,9 @@ void MGAdbg_outreg32(ScrnInfoPtr, int,in
 typedef struct {
     unsigned char	ExtVga[6];
     unsigned char 	DacClk[6];
-    unsigned char	ExtVga_Index24;
+    unsigned char	ExtVga_MgaReq;
     unsigned char	Dac_Index90;
-    unsigned char * DacRegs;
+    unsigned char       * DacRegs;
     unsigned long	crtc2[0x58];
     unsigned char	dac2[0x21];
     CARD32		Option;
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
@@ -210,6 +210,74 @@ MGAG200WBComputePLLParam(ScrnInfoPtr pSc
 #endif
 }
 
+void
+MGAG200EW3ComputePLLParam(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 ulTestP1;
+    unsigned int ulTestP2;
+    unsigned int ulTestM;
+    unsigned int ulTestN;
+    unsigned int ulPLLFreqRef;
+    unsigned int ulTestP1Start;
+    unsigned int ulTestP1End;
+    unsigned int ulTestP2Start;
+    unsigned int ulTestP2End;
+    unsigned int ulTestMStart;
+    unsigned int ulTestMEnd;
+    unsigned int ulTestNStart;
+    unsigned int ulTestNEnd;
+
+    ulVCOMax        = 800000;
+    ulVCOMin        = 400000;
+    ulPLLFreqRef    = 25000;
+    ulTestP1Start   = 1;
+    ulTestP1End     = 8;
+    ulTestP2Start   = 1;
+    ulTestP2End     = 8;
+    ulTestMStart    = 1;
+    ulTestMEnd      = 26;
+    ulTestNStart    = 32;
+    ulTestNEnd      = 2048;
+
+    ulFDelta = 0xFFFFFFFF;
+    /* Permited delta is 0.5% as VESA Specification */
+    ulFPermitedDelta = lFo * 5 / 1000;
+
+    /* Then we need to minimize the M while staying within 0.5% */
+    for (ulTestP1 = ulTestP1Start; ulTestP1 < ulTestP1End; ulTestP1++) {
+        for (ulTestP2 = ulTestP2Start; ulTestP2 < ulTestP2End; ulTestP2++) {
+            if (ulTestP1 < ulTestP2) continue;
+            if ((lFo * ulTestP1 * ulTestP2) > ulVCOMax) continue;
+            if ((lFo * ulTestP1 * ulTestP2) < ulVCOMin) continue;
+
+            for (ulTestM = ulTestMStart; ulTestM < ulTestMEnd; ulTestM++) {
+                for (ulTestN = ulTestNStart; ulTestN < ulTestNEnd; ulTestN++) {
+                    ulComputedFo = (ulPLLFreqRef * ulTestN) / (ulTestM * ulTestP1 * ulTestP2);
+                    if (ulComputedFo > lFo)
+                        ulFTmpDelta = ulComputedFo - lFo;
+                    else
+                        ulFTmpDelta = lFo - ulComputedFo;
+
+                    if (ulFTmpDelta < ulFDelta) {
+                        ulFDelta = ulFTmpDelta;
+                        *M = (CARD8)((ulTestN & 0x100) >> 1) | 
+                             (CARD8)(ulTestM);
+                        *N = (CARD8)(ulTestN & 0xFF);
+                        *P = (CARD8)((ulTestN & 0x600) >> 3) | 
+                             (CARD8)(ulTestP2 << 3) | 
+                             (CARD8)ulTestP1;
+                    }
+                }
+            }
+        }
+    }
+}
+
 static void
 MGAG200EHComputePLLParam(ScrnInfoPtr pScrn, long lFo, int *M, int *N, int *P)
 {
@@ -887,7 +955,14 @@ MGAGSetPCLK( ScrnInfoPtr pScrn, long f_o
 	    pReg->PllN = n;
 	    pReg->PllP = p;
 	} else if (pMga->is_G200WB) {
-	    MGAG200WBComputePLLParam(pScrn, f_out, &m, &n, &p);
+            if (pMga->Chipset == PCI_CHIP_MGAG200_EW3_PCI)
+            {
+                 MGAG200EW3ComputePLLParam(pScrn, f_out, &m, &n, &p);
+            }
+            else
+            {
+	         MGAG200WBComputePLLParam(pScrn, f_out, &m, &n, &p);
+            }
 
 	    pReg->PllM = m;
 	    pReg->PllN = n;
@@ -1083,6 +1158,7 @@ MGAGInit(ScrnInfoPtr pScrn, DisplayModeP
 		break;
 
         case PCI_CHIP_MGAG200_WINBOND_PCI:
+        case PCI_CHIP_MGAG200_EW3_PCI:
                 pReg->DacRegs[MGA1064_VREF_CTL] = 0x07;
                 pReg->Option = 0x41049120;
                 pReg->Option2 = 0x0000b000;
@@ -1226,10 +1302,7 @@ MGAGInit(ScrnInfoPtr pScrn, DisplayModeP
         if (pMga->is_G200WB){
             pReg->ExtVga[1] |= 0x88;
         }
-	if (pMga->is_G200ER)
-    {
-		pReg->ExtVga_Index24 = 0x05;
-	}
+        pReg->ExtVga_MgaReq = 0x05;
 		
 	pVga->CRTC[0]	= ht - 4;
 	pVga->CRTC[1]	= hd;
@@ -1539,7 +1612,15 @@ MGA_NOT_HAL(
 
            if (pMga->is_G200ER) {
                OUTREG8(MGAREG_CRTCEXT_INDEX, 0x24);
-               OUTREG8(MGAREG_CRTCEXT_DATA,  mgaReg->ExtVga_Index24);			   
+               OUTREG8(MGAREG_CRTCEXT_DATA,  mgaReg->ExtVga_MgaReq);			   
+           }
+
+           if (pMga->is_G200WB) {
+               if(pMga->Chipset == PCI_CHIP_MGAG200_EW3_PCI)
+               {
+                   OUTREG8(MGAREG_CRTCEXT_INDEX, 0x34);
+                   OUTREG8(MGAREG_CRTCEXT_DATA,  mgaReg->ExtVga_MgaReq);
+               } 
            }
 
 	   /* This handles restoring the generic VGA registers. */
@@ -1745,8 +1826,16 @@ MGAGSave(ScrnInfoPtr pScrn, vgaRegPtr vg
 	if (pMga->is_G200ER)
 	{
 		OUTREG8(MGAREG_CRTCEXT_INDEX, 0x24);
-		mgaReg->ExtVga_Index24 = INREG8(MGAREG_CRTCEXT_DATA);
-	}
+		mgaReg->ExtVga_MgaReq = INREG8(MGAREG_CRTCEXT_DATA);
+ 	}
+        if (pMga->is_G200WB) 
+        {
+            if(pMga->Chipset == PCI_CHIP_MGAG200_EW3_PCI)
+            {
+                OUTREG8(MGAREG_CRTCEXT_INDEX, 0x34);
+                mgaReg->ExtVga_MgaReq = INREG8(MGAREG_CRTCEXT_DATA);                
+            }
+        }
 
 #ifdef DEBUG		
 	ErrorF("Saved values:\nDAC:");
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
@@ -418,6 +418,22 @@ static const struct mga_device_attribute
 	},
 
 	16384, 0x4000,          /* Memory probe size & offset values */
+    },
+
+    /* G200WB */
+    [16] = { 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 */
+	    { 50000, 203400 }, /* Pixel VCO frequencies */
+	    { 0, 0 },          /* Video VCO frequencies */
+	    45000,            /* Memory clock */
+	    27050,             /* PLL reference frequency */
+	    0,                 /* Supports fast bitblt? */
+	    MGA_HOST_PCI       /* Host interface */
+	},
+
+	16384, 0x4000,          /* Memory probe size & offset values */
     }
 };
 
@@ -448,7 +464,9 @@ static const struct pci_id_match mga_dev
 
     MGA_DEVICE_MATCH( PCI_CHIP_MGAG200_EH_PCI, 14 ),
 
-	MGA_DEVICE_MATCH(PCI_CHIP_MGAG200_ER_PCI, 15 ),
+    MGA_DEVICE_MATCH(PCI_CHIP_MGAG200_ER_PCI, 15 ),
+
+    MGA_DEVICE_MATCH( PCI_CHIP_MGAG200_EW3_PCI, 16 ),
 
     { 0, 0, 0 },
 };
@@ -469,6 +487,7 @@ static SymTabRec MGAChipsets[] = {
     { PCI_CHIP_MGAG200_EV_PCI,	"mgag200 EV Maxim" },
     { PCI_CHIP_MGAG200_ER_PCI,	"mgag200 ER SH7757" },	
     { PCI_CHIP_MGAG200_WINBOND_PCI,	"mgag200 eW Nuvoton" },
+    { PCI_CHIP_MGAG200_EW3_PCI,	"mgag200 eW3 Nuvoton" },
     { PCI_CHIP_MGAG200_EH_PCI,	"mgag200eH" },
     { PCI_CHIP_MGAG400,		"mgag400" },
     { PCI_CHIP_MGAG550,		"mgag550" },
@@ -494,6 +513,8 @@ static PciChipsets MGAPciChipsets[] = {
 	RES_SHARED_VGA },
     { PCI_CHIP_MGAG200_WINBOND_PCI, PCI_CHIP_MGAG200_WINBOND_PCI,
 	RES_SHARED_VGA },
+    { PCI_CHIP_MGAG200_EW3_PCI, PCI_CHIP_MGAG200_EW3_PCI,
+	RES_SHARED_VGA },
     { PCI_CHIP_MGAG200_EH_PCI, PCI_CHIP_MGAG200_EH_PCI,
 	RES_SHARED_VGA },
     { PCI_CHIP_MGAG400,	    PCI_CHIP_MGAG400,	RES_SHARED_VGA },
@@ -938,6 +959,9 @@ MGAProbe(DriverPtr drv, int flags)
                 attrib_no = 15;
                 break;
 				
+            case PCI_CHIP_MGAG200_EW3_PCI:
+                attrib_no = 16;
+                break;
 
 	    default:
 		return FALSE;
@@ -1654,7 +1678,8 @@ MGAPreInit(ScrnInfoPtr pScrn, int flags)
     pMga->is_G200SE = (pMga->Chipset == PCI_CHIP_MGAG200_SE_A_PCI)
 	|| (pMga->Chipset == PCI_CHIP_MGAG200_SE_B_PCI);
     pMga->is_G200EV = (pMga->Chipset == PCI_CHIP_MGAG200_EV_PCI);
-    pMga->is_G200WB = (pMga->Chipset == PCI_CHIP_MGAG200_WINBOND_PCI);
+    pMga->is_G200WB = (pMga->Chipset == PCI_CHIP_MGAG200_WINBOND_PCI)
+	|| (pMga->Chipset ==  PCI_CHIP_MGAG200_EW3_PCI);
     pMga->is_G200EH = (pMga->Chipset == PCI_CHIP_MGAG200_EH_PCI);
     pMga->is_G200ER = (pMga->Chipset == PCI_CHIP_MGAG200_ER_PCI);
 
@@ -2195,6 +2220,7 @@ MGAPreInit(ScrnInfoPtr pScrn, int flags)
     case PCI_CHIP_MGAG200_SE_A_PCI:
     case PCI_CHIP_MGAG200_SE_B_PCI:
     case PCI_CHIP_MGAG200_WINBOND_PCI:
+    case PCI_CHIP_MGAG200_EW3_PCI:
     case PCI_CHIP_MGAG200_EV_PCI:
     case PCI_CHIP_MGAG200_EH_PCI:
     case PCI_CHIP_MGAG200_ER_PCI:	
@@ -2309,8 +2335,9 @@ MGAPreInit(ScrnInfoPtr pScrn, int flags)
 	  case PCI_CHIP_MGAG200_SE_A_PCI:
 	  case PCI_CHIP_MGAG200_SE_B_PCI:
           case PCI_CHIP_MGAG200_WINBOND_PCI:
+	  case PCI_CHIP_MGAG200_EW3_PCI:
 	  case PCI_CHIP_MGAG200_EV_PCI:
-      case PCI_CHIP_MGAG200_EH_PCI:
+	  case PCI_CHIP_MGAG200_EH_PCI:
 	  case PCI_CHIP_MGAG200_ER_PCI:	  
 	    pMga->SrcOrg = 0;
 	    pMga->DstOrg = 0;
@@ -2497,6 +2524,7 @@ MGAPreInit(ScrnInfoPtr pScrn, int flags)
 	case PCI_CHIP_MGAG200_PCI:
 	case PCI_CHIP_MGAG200_SE_B_PCI:
         case PCI_CHIP_MGAG200_WINBOND_PCI:
+	case PCI_CHIP_MGAG200_EW3_PCI:
 	case PCI_CHIP_MGAG200_EV_PCI:
     case PCI_CHIP_MGAG200_EH_PCI:
 	case PCI_CHIP_MGAG200_ER_PCI:	
@@ -4478,12 +4506,15 @@ MGAValidMode(int scrnIndex, DisplayModeP
     } else if (pMga->is_G200WB){
         if (mode->Flags & V_DBLSCAN)
             return MODE_NO_DBLESCAN;
-	if (pMga->KVM && mode->HDisplay > 1280)
-	    return MODE_VIRTUAL_X;
-	if (pMga->KVM && mode->VDisplay > 1024)
-	    return MODE_VIRTUAL_Y;
-	if (xf86ModeBandwidth(mode, pScrn->bitsPerPixel) > 318.77)
-	    return MODE_BANDWIDTH;
+        if (pMga->Chipset != PCI_CHIP_MGAG200_EW3_PCI)
+        {
+	    if (pMga->KVM && mode->HDisplay > 1280)
+	        return MODE_VIRTUAL_X;
+	    if (pMga->KVM && mode->VDisplay > 1024)
+	        return MODE_VIRTUAL_Y;
+	    if (xf86ModeBandwidth(mode, pScrn->bitsPerPixel) > 318.77)
+	        return MODE_BANDWIDTH;
+        }
     } else if (pMga->is_G200EV
 	       && (xf86ModeBandwidth(mode, pScrn->bitsPerPixel) > 327)) {
         return MODE_BANDWIDTH;
Index: xf86-video-mga-1.4.11/src/mga_merge.c
===================================================================
--- xf86-video-mga-1.4.11.orig/src/mga_merge.c
+++ xf86-video-mga-1.4.11/src/mga_merge.c
@@ -361,9 +361,10 @@ MGAPreInitMergedFB(ScrnInfoPtr pScrn1, i
     case PCI_CHIP_MGAG200_SE_A_PCI:
     case PCI_CHIP_MGAG200_SE_B_PCI:
     case PCI_CHIP_MGAG200_WINBOND_PCI:
+    case PCI_CHIP_MGAG200_EW3_PCI:
     case PCI_CHIP_MGAG200_EV_PCI:
     case PCI_CHIP_MGAG200_EH_PCI:
-	case PCI_CHIP_MGAG200_ER_PCI:
+    case PCI_CHIP_MGAG200_ER_PCI:
     case PCI_CHIP_MGAG400:
     case PCI_CHIP_MGAG550:
 	MGAGSetupFuncs(pScrn);
@@ -517,6 +518,7 @@ MGAPreInitMergedFB(ScrnInfoPtr pScrn1, i
 	case PCI_CHIP_MGAG200_SE_A_PCI:
 	case PCI_CHIP_MGAG200_SE_B_PCI:
         case PCI_CHIP_MGAG200_WINBOND_PCI:
+	case PCI_CHIP_MGAG200_EW3_PCI:		
         case PCI_CHIP_MGAG200_EV_PCI:
         case PCI_CHIP_MGAG200_EH_PCI:
 	case PCI_CHIP_MGAG200_ER_PCI:		
Index: xf86-video-mga-1.4.11/src/mga_storm.c
===================================================================
--- xf86-video-mga-1.4.11.orig/src/mga_storm.c
+++ xf86-video-mga-1.4.11/src/mga_storm.c
@@ -1132,6 +1132,7 @@ void MGAStormEngineInit( ScrnInfoPtr pSc
     case PCI_CHIP_MGAG200_SE_A_PCI:
     case PCI_CHIP_MGAG200_SE_B_PCI:
     case PCI_CHIP_MGAG200_WINBOND_PCI:
+    case PCI_CHIP_MGAG200_EW3_PCI:
     case PCI_CHIP_MGAG200_EV_PCI:
     case PCI_CHIP_MGAG200_EH_PCI:
     case PCI_CHIP_MGAG200_ER_PCI:	
