These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / mgag200 / mgag200_mode.c
index ad4b901..c99d3fe 100644 (file)
@@ -104,6 +104,8 @@ static bool mga_crtc_mode_fixup(struct drm_crtc *crtc,
        return true;
 }
 
+#define P_ARRAY_SIZE 9
+
 static int mga_g200se_set_plls(struct mga_device *mdev, long clock)
 {
        unsigned int vcomax, vcomin, pllreffreq;
@@ -111,37 +113,97 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock)
        unsigned int testp, testm, testn;
        unsigned int p, m, n;
        unsigned int computed;
+       unsigned int pvalues_e4[P_ARRAY_SIZE] = {16, 14, 12, 10, 8, 6, 4, 2, 1};
+       unsigned int fvv;
+       unsigned int i;
+
+       if (mdev->unique_rev_id <= 0x03) {
+
+               m = n = p = 0;
+               vcomax = 320000;
+               vcomin = 160000;
+               pllreffreq = 25000;
+
+               delta = 0xffffffff;
+               permitteddelta = clock * 5 / 1000;
+
+               for (testp = 8; testp > 0; testp /= 2) {
+                       if (clock * testp > vcomax)
+                               continue;
+                       if (clock * testp < vcomin)
+                               continue;
+
+                       for (testn = 17; testn < 256; testn++) {
+                               for (testm = 1; testm < 32; testm++) {
+                                       computed = (pllreffreq * testn) /
+                                               (testm * testp);
+                                       if (computed > clock)
+                                               tmpdelta = computed - clock;
+                                       else
+                                               tmpdelta = clock - computed;
+                                       if (tmpdelta < delta) {
+                                               delta = tmpdelta;
+                                               m = testm - 1;
+                                               n = testn - 1;
+                                               p = testp - 1;
+                                       }
+                               }
+                       }
+               }
+       } else {
 
-       m = n = p = 0;
-       vcomax = 320000;
-       vcomin = 160000;
-       pllreffreq = 25000;
 
-       delta = 0xffffffff;
-       permitteddelta = clock * 5 / 1000;
+               m = n = p = 0;
+               vcomax        = 1600000;
+               vcomin        = 800000;
+               pllreffreq    = 25000;
 
-       for (testp = 8; testp > 0; testp /= 2) {
-               if (clock * testp > vcomax)
-                       continue;
-               if (clock * testp < vcomin)
-                       continue;
+               if (clock < 25000)
+                       clock = 25000;
 
-               for (testn = 17; testn < 256; testn++) {
-                       for (testm = 1; testm < 32; testm++) {
-                               computed = (pllreffreq * testn) /
-                                       (testm * testp);
-                               if (computed > clock)
-                                       tmpdelta = computed - clock;
-                               else
-                                       tmpdelta = clock - computed;
-                               if (tmpdelta < delta) {
-                                       delta = tmpdelta;
-                                       m = testm - 1;
-                                       n = testn - 1;
-                                       p = testp - 1;
+               clock = clock * 2;
+
+               delta = 0xFFFFFFFF;
+               /* Permited delta is 0.5% as VESA Specification */
+               permitteddelta = clock * 5 / 1000;
+
+               for (i = 0 ; i < P_ARRAY_SIZE ; i++) {
+                       testp = pvalues_e4[i];
+
+                       if ((clock * testp) > vcomax)
+                               continue;
+                       if ((clock * testp) < vcomin)
+                               continue;
+
+                       for (testn = 50; testn <= 256; testn++) {
+                               for (testm = 1; testm <= 32; testm++) {
+                                       computed = (pllreffreq * testn) /
+                                               (testm * testp);
+                                       if (computed > clock)
+                                               tmpdelta = computed - clock;
+                                       else
+                                               tmpdelta = clock - computed;
+
+                                       if (tmpdelta < delta) {
+                                               delta = tmpdelta;
+                                               m = testm - 1;
+                                               n = testn - 1;
+                                               p = testp - 1;
+                                       }
                                }
                        }
                }
+
+               fvv = pllreffreq * testn / testm;
+               fvv = (fvv - 800000) / 50000;
+
+               if (fvv > 15)
+                       fvv = 15;
+
+               p |= (fvv << 4);
+               m |= 0x80;
+
+               clock = clock / 2;
        }
 
        if (delta > permitteddelta) {
@@ -158,8 +220,8 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock)
 static int mga_g200wb_set_plls(struct mga_device *mdev, long clock)
 {
        unsigned int vcomax, vcomin, pllreffreq;
-       unsigned int delta, tmpdelta, permitteddelta;
-       unsigned int testp, testm, testn;
+       unsigned int delta, tmpdelta;
+       unsigned int testp, testm, testn, testp2;
        unsigned int p, m, n;
        unsigned int computed;
        int i, j, tmpcount, vcount;
@@ -167,32 +229,71 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock)
        u8 tmp;
 
        m = n = p = 0;
-       vcomax = 550000;
-       vcomin = 150000;
-       pllreffreq = 48000;
 
        delta = 0xffffffff;
-       permitteddelta = clock * 5 / 1000;
 
-       for (testp = 1; testp < 9; testp++) {
-               if (clock * testp > vcomax)
-                       continue;
-               if (clock * testp < vcomin)
-                       continue;
+       if (mdev->type == G200_EW3) {
+
+               vcomax = 800000;
+               vcomin = 400000;
+               pllreffreq = 25000;
+
+               for (testp = 1; testp < 8; testp++) {
+                       for (testp2 = 1; testp2 < 8; testp2++) {
+                               if (testp < testp2)
+                                       continue;
+                               if ((clock * testp * testp2) > vcomax)
+                                       continue;
+                               if ((clock * testp * testp2) < vcomin)
+                                       continue;
+                               for (testm = 1; testm < 26; testm++) {
+                                       for (testn = 32; testn < 2048 ; testn++) {
+                                               computed = (pllreffreq * testn) /
+                                                       (testm * testp * testp2);
+                                               if (computed > clock)
+                                                       tmpdelta = computed - clock;
+                                               else
+                                                       tmpdelta = clock - computed;
+                                               if (tmpdelta < delta) {
+                                                       delta = tmpdelta;
+                                                       m = ((testn & 0x100) >> 1) |
+                                                               (testm);
+                                                       n = (testn & 0xFF);
+                                                       p = ((testn & 0x600) >> 3) |
+                                                               (testp2 << 3) |
+                                                               (testp);
+                                               }
+                                       }
+                               }
+                       }
+               }
+       } else {
 
-               for (testm = 1; testm < 17; testm++) {
-                       for (testn = 1; testn < 151; testn++) {
-                               computed = (pllreffreq * testn) /
-                                       (testm * testp);
-                               if (computed > clock)
-                                       tmpdelta = computed - clock;
-                               else
-                                       tmpdelta = clock - computed;
-                               if (tmpdelta < delta) {
-                                       delta = tmpdelta;
-                                       n = testn - 1;
-                                       m = (testm - 1) | ((n >> 1) & 0x80);
-                                       p = testp - 1;
+               vcomax = 550000;
+               vcomin = 150000;
+               pllreffreq = 48000;
+
+               for (testp = 1; testp < 9; testp++) {
+                       if (clock * testp > vcomax)
+                               continue;
+                       if (clock * testp < vcomin)
+                               continue;
+
+                       for (testm = 1; testm < 17; testm++) {
+                               for (testn = 1; testn < 151; testn++) {
+                                       computed = (pllreffreq * testn) /
+                                               (testm * testp);
+                                       if (computed > clock)
+                                               tmpdelta = computed - clock;
+                                       else
+                                               tmpdelta = clock - computed;
+                                       if (tmpdelta < delta) {
+                                               delta = tmpdelta;
+                                               n = testn - 1;
+                                               m = (testm - 1) |
+                                                       ((n >> 1) & 0x80);
+                                               p = testp - 1;
+                                       }
                                }
                        }
                }
@@ -298,7 +399,7 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock)
 static int mga_g200ev_set_plls(struct mga_device *mdev, long clock)
 {
        unsigned int vcomax, vcomin, pllreffreq;
-       unsigned int delta, tmpdelta, permitteddelta;
+       unsigned int delta, tmpdelta;
        unsigned int testp, testm, testn;
        unsigned int p, m, n;
        unsigned int computed;
@@ -310,7 +411,6 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock)
        pllreffreq = 50000;
 
        delta = 0xffffffff;
-       permitteddelta = clock * 5 / 1000;
 
        for (testp = 16; testp > 0; testp--) {
                if (clock * testp > vcomax)
@@ -392,7 +492,7 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock)
 static int mga_g200eh_set_plls(struct mga_device *mdev, long clock)
 {
        unsigned int vcomax, vcomin, pllreffreq;
-       unsigned int delta, tmpdelta, permitteddelta;
+       unsigned int delta, tmpdelta;
        unsigned int testp, testm, testn;
        unsigned int p, m, n;
        unsigned int computed;
@@ -406,7 +506,6 @@ static int mga_g200eh_set_plls(struct mga_device *mdev, long clock)
        pllreffreq = 33333;
 
        delta = 0xffffffff;
-       permitteddelta = clock * 5 / 1000;
 
        for (testp = 16; testp > 0; testp >>= 1) {
                if (clock * testp > vcomax)
@@ -572,6 +671,7 @@ static int mga_crtc_set_plls(struct mga_device *mdev, long clock)
                return mga_g200se_set_plls(mdev, clock);
                break;
        case G200_WB:
+       case G200_EW3:
                return mga_g200wb_set_plls(mdev, clock);
                break;
        case G200_EV:
@@ -823,6 +923,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
                option2 = 0x00008000;
                break;
        case G200_WB:
+       case G200_EW3:
                dacvalue[MGA1064_VREF_CTL] = 0x07;
                option = 0x41049120;
                option2 = 0x0000b000;
@@ -878,7 +979,10 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
                if (IS_G200_SE(mdev) &&
                    ((i == 0x2c) || (i == 0x2d) || (i == 0x2e)))
                        continue;
-               if ((mdev->type == G200_EV || mdev->type == G200_WB || mdev->type == G200_EH) &&
+               if ((mdev->type == G200_EV ||
+                   mdev->type == G200_WB ||
+                   mdev->type == G200_EH ||
+                   mdev->type == G200_EW3) &&
                    (i >= 0x44) && (i <= 0x4e))
                        continue;
 
@@ -980,7 +1084,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
        else
                ext_vga[3] = ((1 << bppshift) - 1) | 0x80;
        ext_vga[4] = 0;
-       if (mdev->type == G200_WB)
+       if (mdev->type == G200_WB || mdev->type == G200_EW3)
                ext_vga[1] |= 0x88;
 
        /* Set pixel clocks */
@@ -996,6 +1100,9 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
        if (mdev->type == G200_ER)
                WREG_ECRT(0x24, 0x5);
 
+       if (mdev->type == G200_EW3)
+               WREG_ECRT(0x34, 0x5);
+
        if (mdev->type == G200_EV) {
                WREG_ECRT(6, 0);
        }
@@ -1208,7 +1315,7 @@ static void mga_crtc_prepare(struct drm_crtc *crtc)
                WREG_SEQ(1, tmp | 0x20);
        }
 
-       if (mdev->type == G200_WB)
+       if (mdev->type == G200_WB || mdev->type == G200_EW3)
                mga_g200wb_prepare(crtc);
 
        WREG_CRT(17, 0);
@@ -1225,7 +1332,7 @@ static void mga_crtc_commit(struct drm_crtc *crtc)
        const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
        u8 tmp;
 
-       if (mdev->type == G200_WB)
+       if (mdev->type == G200_WB || mdev->type == G200_EW3)
                mga_g200wb_commit(crtc);
 
        if (mdev->type == G200_SE_A || mdev->type == G200_SE_B) {
@@ -1495,7 +1602,7 @@ static int mga_vga_mode_valid(struct drm_connector *connector,
                        if (mga_vga_calculate_mode_bandwidth(mode, bpp)
                                > (24400 * 1024))
                                return MODE_BANDWIDTH;
-               } else if (mdev->unique_rev_id >= 0x02) {
+               } else if (mdev->unique_rev_id == 0x02) {
                        if (mode->hdisplay > 1920)
                                return MODE_VIRTUAL_X;
                        if (mode->vdisplay > 1200)