drm/mgag200: Provide per-device callbacks for PIXPLLC
authorThomas Zimmermann <tzimmermann@suse.de>
Thu, 28 Jul 2022 12:41:00 +0000 (14:41 +0200)
committerThomas Zimmermann <tzimmermann@suse.de>
Fri, 29 Jul 2022 14:01:47 +0000 (16:01 +0200)
Move the PIXPLLC code into per-model source files and wire it up
with per-model callbacks. No functional changes.

The PIXPLLC pixel-clock is part of the CRTC, but really separate
hardware that varies with each model of the G200. Move the PIXPLLC
code for each model into the per-model source file and call it from
CRTC helpers via device functions.

This allows to remove struct mgag200_pll and the related code. The
new callbacks behave like the CRTC's atomic_check and atomic_enable
functions.

v3:
* clean up style

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Jocelyn Falempe <jfalempe@redhat.com>
Tested-by: Jocelyn Falempe <jfalempe@redhat.com>
Acked-by: Sam Ravnborg <sam@ravnborg.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20220728124103.30159-12-tzimmermann@suse.de
12 files changed:
drivers/gpu/drm/mgag200/Makefile
drivers/gpu/drm/mgag200/mgag200_drv.h
drivers/gpu/drm/mgag200/mgag200_g200.c
drivers/gpu/drm/mgag200/mgag200_g200eh.c
drivers/gpu/drm/mgag200/mgag200_g200eh3.c
drivers/gpu/drm/mgag200/mgag200_g200er.c
drivers/gpu/drm/mgag200/mgag200_g200ev.c
drivers/gpu/drm/mgag200/mgag200_g200ew3.c
drivers/gpu/drm/mgag200/mgag200_g200se.c
drivers/gpu/drm/mgag200/mgag200_g200wb.c
drivers/gpu/drm/mgag200/mgag200_mode.c
drivers/gpu/drm/mgag200/mgag200_pll.c [deleted file]

index 94d465a..182e224 100644 (file)
@@ -11,7 +11,6 @@ mgag200-y := \
        mgag200_g200se.o \
        mgag200_g200wb.o \
        mgag200_i2c.o \
-       mgag200_mode.o \
-       mgag200_pll.o
+       mgag200_mode.o
 
 obj-$(CONFIG_DRM_MGAG200) += mgag200.o
index e78c1b2..cc14028 100644 (file)
 #define MGAG200_MAX_FB_WIDTH 4096
 
 struct mga_device;
-struct mgag200_pll;
 
 /*
  * Stores parameters for programming the PLLs
@@ -175,17 +174,6 @@ struct mgag200_pll_values {
        unsigned int s;
 };
 
-struct mgag200_pll_funcs {
-       int (*compute)(struct mgag200_pll *pll, long clock, struct mgag200_pll_values *pllc);
-       void (*update)(struct mgag200_pll *pll, const struct mgag200_pll_values *pllc);
-};
-
-struct mgag200_pll {
-       struct mga_device *mdev;
-
-       const struct mgag200_pll_funcs *funcs;
-};
-
 struct mgag200_crtc_state {
        struct drm_crtc_state base;
 
@@ -274,6 +262,20 @@ struct mgag200_device_funcs {
         * a new display mode.
         */
        void (*enable_vidrst)(struct mga_device *mdev);
+
+       /*
+        * Validate that the given state can be programmed into PIXPLLC. On
+        * success, the calculated parameters should be stored in the CRTC's
+        * state in struct @mgag200_crtc_state.pixpllc.
+        */
+       int (*pixpllc_atomic_check)(struct drm_crtc *crtc, struct drm_atomic_state *new_state);
+
+       /*
+        * Program PIXPLLC from the CRTC state. The parameters should have been
+        * stored in struct @mgag200_crtc_state.pixpllc by the corresponding
+        * implementation of @pixpllc_atomic_check.
+        */
+       void (*pixpllc_atomic_update)(struct drm_crtc *crtc, struct drm_atomic_state *old_state);
 };
 
 struct mga_device {
@@ -292,7 +294,6 @@ struct mga_device {
 
        enum mga_type                   type;
 
-       struct mgag200_pll pixpll;
        struct drm_plane primary_plane;
        struct drm_crtc crtc;
        struct drm_encoder encoder;
@@ -346,11 +347,13 @@ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct
 struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
                                                enum mga_type type);
 void mgag200_g200wb_init_registers(struct mga_device *mdev);
+void mgag200_g200wb_pixpllc_atomic_update(struct drm_crtc *crtc, struct drm_atomic_state *old_state);
 struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
                                                enum mga_type type);
 struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
                                                enum mga_type type);
 void mgag200_g200eh_init_registers(struct mga_device *mdev);
+void mgag200_g200eh_pixpllc_atomic_update(struct drm_crtc *crtc, struct drm_atomic_state *old_state);
 struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
                                                enum mga_type type);
 struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
@@ -372,7 +375,4 @@ void mgag200_bmc_enable_vidrst(struct mga_device *mdev);
                                /* mgag200_i2c.c */
 int mgag200_i2c_init(struct mga_device *mdev, struct mga_i2c_chan *i2c);
 
-                               /* mgag200_pll.c */
-int mgag200_pixpll_init(struct mgag200_pll *pixpll, struct mga_device *mdev);
-
 #endif                         /* __MGAG200_DRV_H__ */
index e11b485..ae1669d 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_drv.h>
 
 #include "mgag200_drv.h"
@@ -54,6 +55,112 @@ static void mgag200_g200_init_registers(struct mgag200_g200_device *g200)
 }
 
 /*
+ * PIXPLLC
+ */
+
+static int mgag200_g200_pixpllc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state)
+{
+       static const int post_div_max = 7;
+       static const int in_div_min = 1;
+       static const int in_div_max = 6;
+       static const int feed_div_min = 7;
+       static const int feed_div_max = 127;
+
+       struct drm_device *dev = crtc->dev;
+       struct mgag200_g200_device *g200 = to_mgag200_g200_device(dev);
+       struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+       struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+       long clock = new_crtc_state->mode.clock;
+       struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
+       u8 testp, testm, testn;
+       u8 n = 0, m = 0, p, s;
+       long f_vco;
+       long computed;
+       long delta, tmp_delta;
+       long ref_clk = g200->ref_clk;
+       long p_clk_min = g200->pclk_min;
+       long p_clk_max = g200->pclk_max;
+
+       if (clock > p_clk_max) {
+               drm_err(dev, "Pixel Clock %ld too high\n", clock);
+               return -EINVAL;
+       }
+
+       if (clock < p_clk_min >> 3)
+               clock = p_clk_min >> 3;
+
+       f_vco = clock;
+       for (testp = 0;
+            testp <= post_div_max && f_vco < p_clk_min;
+            testp = (testp << 1) + 1, f_vco <<= 1)
+               ;
+       p = testp + 1;
+
+       delta = clock;
+
+       for (testm = in_div_min; testm <= in_div_max; testm++) {
+               for (testn = feed_div_min; testn <= feed_div_max; testn++) {
+                       computed = ref_clk * (testn + 1) / (testm + 1);
+                       if (computed < f_vco)
+                               tmp_delta = f_vco - computed;
+                       else
+                               tmp_delta = computed - f_vco;
+                       if (tmp_delta < delta) {
+                               delta = tmp_delta;
+                               m = testm + 1;
+                               n = testn + 1;
+                       }
+               }
+       }
+       f_vco = ref_clk * n / m;
+       if (f_vco < 100000)
+               s = 0;
+       else if (f_vco < 140000)
+               s = 1;
+       else if (f_vco < 180000)
+               s = 2;
+       else
+               s = 3;
+
+       drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n",
+                   clock, f_vco, m, n, p, s);
+
+       pixpllc->m = m;
+       pixpllc->n = n;
+       pixpllc->p = p;
+       pixpllc->s = s;
+
+       return 0;
+}
+
+static void mgag200_g200_pixpllc_atomic_update(struct drm_crtc *crtc,
+                                              struct drm_atomic_state *old_state)
+{
+       struct drm_device *dev = crtc->dev;
+       struct mga_device *mdev = to_mga_device(dev);
+       struct drm_crtc_state *crtc_state = crtc->state;
+       struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+       struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
+       unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
+       u8 xpixpllcm, xpixpllcn, xpixpllcp;
+
+       pixpllcm = pixpllc->m - 1;
+       pixpllcn = pixpllc->n - 1;
+       pixpllcp = pixpllc->p - 1;
+       pixpllcs = pixpllc->s;
+
+       xpixpllcm = pixpllcm;
+       xpixpllcn = pixpllcn;
+       xpixpllcp = (pixpllcs << 3) | pixpllcp;
+
+       WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
+
+       WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
+       WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
+       WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
+}
+
+/*
  * DRM Device
  */
 
@@ -184,6 +291,8 @@ out:
 }
 
 static const struct mgag200_device_funcs mgag200_g200_device_funcs = {
+       .pixpllc_atomic_check = mgag200_g200_pixpllc_atomic_check,
+       .pixpllc_atomic_update = mgag200_g200_pixpllc_atomic_update,
 };
 
 struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
index 473ff52..fd44d19 100644 (file)
@@ -1,7 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
+#include <linux/delay.h>
 #include <linux/pci.h>
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_drv.h>
 
 #include "mgag200_drv.h"
@@ -31,6 +33,133 @@ void mgag200_g200eh_init_registers(struct mga_device *mdev)
 }
 
 /*
+ * PIXPLLC
+ */
+
+static int mgag200_g200eh_pixpllc_atomic_check(struct drm_crtc *crtc,
+                                              struct drm_atomic_state *new_state)
+{
+       static const unsigned int vcomax = 800000;
+       static const unsigned int vcomin = 400000;
+       static const unsigned int pllreffreq = 33333;
+
+       struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+       struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+       long clock = new_crtc_state->mode.clock;
+       struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
+       unsigned int delta, tmpdelta;
+       unsigned int testp, testm, testn;
+       unsigned int p, m, n, s;
+       unsigned int computed;
+
+       m = n = p = s = 0;
+       delta = 0xffffffff;
+
+       for (testp = 16; testp > 0; testp >>= 1) {
+               if (clock * testp > vcomax)
+                       continue;
+               if (clock * testp < vcomin)
+                       continue;
+
+               for (testm = 1; testm < 33; testm++) {
+                       for (testn = 17; testn < 257; testn++) {
+                               computed = (pllreffreq * testn) / (testm * testp);
+                               if (computed > clock)
+                                       tmpdelta = computed - clock;
+                               else
+                                       tmpdelta = clock - computed;
+                               if (tmpdelta < delta) {
+                                       delta = tmpdelta;
+                                       n = testn;
+                                       m = testm;
+                                       p = testp;
+                               }
+                       }
+               }
+       }
+
+       pixpllc->m = m;
+       pixpllc->n = n;
+       pixpllc->p = p;
+       pixpllc->s = s;
+
+       return 0;
+}
+
+void mgag200_g200eh_pixpllc_atomic_update(struct drm_crtc *crtc,
+                                         struct drm_atomic_state *old_state)
+{
+       struct drm_device *dev = crtc->dev;
+       struct mga_device *mdev = to_mga_device(dev);
+       struct drm_crtc_state *crtc_state = crtc->state;
+       struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+       struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
+       unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
+       u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
+       int i, j, tmpcount, vcount;
+       bool pll_locked = false;
+
+       pixpllcm = pixpllc->m - 1;
+       pixpllcn = pixpllc->n - 1;
+       pixpllcp = pixpllc->p - 1;
+       pixpllcs = pixpllc->s;
+
+       xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm;
+       xpixpllcn = pixpllcn;
+       xpixpllcp = (pixpllcs << 3) | pixpllcp;
+
+       WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
+
+       for (i = 0; i <= 32 && pll_locked == false; i++) {
+               WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+               tmp = RREG8(DAC_DATA);
+               tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
+               WREG8(DAC_DATA, tmp);
+
+               tmp = RREG8(MGAREG_MEM_MISC_READ);
+               tmp |= 0x3 << 2;
+               WREG8(MGAREG_MEM_MISC_WRITE, tmp);
+
+               WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+               tmp = RREG8(DAC_DATA);
+               tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
+               WREG8(DAC_DATA, tmp);
+
+               udelay(500);
+
+               WREG_DAC(MGA1064_EH_PIX_PLLC_M, xpixpllcm);
+               WREG_DAC(MGA1064_EH_PIX_PLLC_N, xpixpllcn);
+               WREG_DAC(MGA1064_EH_PIX_PLLC_P, xpixpllcp);
+
+               udelay(500);
+
+               WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+               tmp = RREG8(DAC_DATA);
+               tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
+               tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
+               WREG8(DAC_DATA, tmp);
+
+               WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+               tmp = RREG8(DAC_DATA);
+               tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
+               tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
+               WREG8(DAC_DATA, tmp);
+
+               vcount = RREG8(MGAREG_VCOUNT);
+
+               for (j = 0; j < 30 && pll_locked == false; j++) {
+                       tmpcount = RREG8(MGAREG_VCOUNT);
+                       if (tmpcount < vcount)
+                               vcount = 0;
+                       if ((tmpcount - vcount) > 2)
+                               pll_locked = true;
+                       else
+                               udelay(5);
+               }
+       }
+}
+
+/*
  * DRM device
  */
 
@@ -38,6 +167,8 @@ static const struct mgag200_device_info mgag200_g200eh_device_info =
        MGAG200_DEVICE_INFO_INIT(2048, 2048, 37500, false, 1, 0, false);
 
 static const struct mgag200_device_funcs mgag200_g200eh_device_funcs = {
+       .pixpllc_atomic_check = mgag200_g200eh_pixpllc_atomic_check,
+       .pixpllc_atomic_update = mgag200_g200eh_pixpllc_atomic_update,
 };
 
 struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
index 99e00aa..b47b100 100644 (file)
@@ -2,11 +2,68 @@
 
 #include <linux/pci.h>
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_drv.h>
 
 #include "mgag200_drv.h"
 
 /*
+ * PIXPLLC
+ */
+
+static int mgag200_g200eh3_pixpllc_atomic_check(struct drm_crtc *crtc,
+                                               struct drm_atomic_state *new_state)
+{
+       static const unsigned int vcomax = 3000000;
+       static const unsigned int vcomin = 1500000;
+       static const unsigned int pllreffreq = 25000;
+
+       struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+       struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+       long clock = new_crtc_state->mode.clock;
+       struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
+       unsigned int delta, tmpdelta;
+       unsigned int testp, testm, testn;
+       unsigned int p, m, n, s;
+       unsigned int computed;
+
+       m = n = p = s = 0;
+       delta = 0xffffffff;
+       testp = 0;
+
+       for (testm = 150; testm >= 6; testm--) {
+               if (clock * testm > vcomax)
+                       continue;
+               if (clock * testm < vcomin)
+                       continue;
+               for (testn = 120; testn >= 60; testn--) {
+                       computed = (pllreffreq * testn) / testm;
+                       if (computed > clock)
+                               tmpdelta = computed - clock;
+                       else
+                               tmpdelta = clock - computed;
+                       if (tmpdelta < delta) {
+                               delta = tmpdelta;
+                               n = testn + 1;
+                               m = testm + 1;
+                               p = testp + 1;
+                       }
+                       if (delta == 0)
+                               break;
+               }
+               if (delta == 0)
+                       break;
+       }
+
+       pixpllc->m = m;
+       pixpllc->n = n;
+       pixpllc->p = p;
+       pixpllc->s = s;
+
+       return 0;
+}
+
+/*
  * DRM device
  */
 
@@ -14,6 +71,8 @@ static const struct mgag200_device_info mgag200_g200eh3_device_info =
        MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false, 1, 0, false);
 
 static const struct mgag200_device_funcs mgag200_g200eh3_device_funcs = {
+       .pixpllc_atomic_check = mgag200_g200eh3_pixpllc_atomic_check,
+       .pixpllc_atomic_update = mgag200_g200eh_pixpllc_atomic_update, // same as G200EH
 };
 
 struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev,
index 1c9a963..8a85fd0 100644 (file)
@@ -1,7 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
+#include <linux/delay.h>
 #include <linux/pci.h>
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_drv.h>
 
 #include "mgag200_drv.h"
@@ -32,6 +34,122 @@ static void mgag200_g200er_init_registers(struct mga_device *mdev)
 }
 
 /*
+ * PIXPLLC
+ */
+
+static int mgag200_g200er_pixpllc_atomic_check(struct drm_crtc *crtc,
+                                              struct drm_atomic_state *new_state)
+{
+       static const unsigned int vcomax = 1488000;
+       static const unsigned int vcomin = 1056000;
+       static const unsigned int pllreffreq = 48000;
+       static const unsigned int m_div_val[] = { 1, 2, 4, 8 };
+
+       struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+       struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+       long clock = new_crtc_state->mode.clock;
+       struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
+       unsigned int delta, tmpdelta;
+       int testr, testn, testm, testo;
+       unsigned int p, m, n, s;
+       unsigned int computed, vco;
+
+       m = n = p = s = 0;
+       delta = 0xffffffff;
+
+       for (testr = 0; testr < 4; testr++) {
+               if (delta == 0)
+                       break;
+               for (testn = 5; testn < 129; testn++) {
+                       if (delta == 0)
+                               break;
+                       for (testm = 3; testm >= 0; testm--) {
+                               if (delta == 0)
+                                       break;
+                               for (testo = 5; testo < 33; testo++) {
+                                       vco = pllreffreq * (testn + 1) /
+                                               (testr + 1);
+                                       if (vco < vcomin)
+                                               continue;
+                                       if (vco > vcomax)
+                                               continue;
+                                       computed = vco / (m_div_val[testm] * (testo + 1));
+                                       if (computed > clock)
+                                               tmpdelta = computed - clock;
+                                       else
+                                               tmpdelta = clock - computed;
+                                       if (tmpdelta < delta) {
+                                               delta = tmpdelta;
+                                               m = (testm | (testo << 3)) + 1;
+                                               n = testn + 1;
+                                               p = testr + 1;
+                                               s = testr;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       pixpllc->m = m;
+       pixpllc->n = n;
+       pixpllc->p = p;
+       pixpllc->s = s;
+
+       return 0;
+}
+
+static void mgag200_g200er_pixpllc_atomic_update(struct drm_crtc *crtc,
+                                                struct drm_atomic_state *old_state)
+{
+       struct drm_device *dev = crtc->dev;
+       struct mga_device *mdev = to_mga_device(dev);
+       struct drm_crtc_state *crtc_state = crtc->state;
+       struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+       struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
+       unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
+       u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
+
+       pixpllcm = pixpllc->m - 1;
+       pixpllcn = pixpllc->n - 1;
+       pixpllcp = pixpllc->p - 1;
+       pixpllcs = pixpllc->s;
+
+       xpixpllcm = pixpllcm;
+       xpixpllcn = pixpllcn;
+       xpixpllcp = (pixpllcs << 3) | pixpllcp;
+
+       WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
+
+       WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+       tmp = RREG8(DAC_DATA);
+       tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
+       WREG8(DAC_DATA, tmp);
+
+       WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
+       tmp = RREG8(DAC_DATA);
+       tmp |= MGA1064_REMHEADCTL_CLKDIS;
+       WREG8(DAC_DATA, tmp);
+
+       tmp = RREG8(MGAREG_MEM_MISC_READ);
+       tmp |= (0x3<<2) | 0xc0;
+       WREG8(MGAREG_MEM_MISC_WRITE, tmp);
+
+       WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+       tmp = RREG8(DAC_DATA);
+       tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
+       tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
+       WREG8(DAC_DATA, tmp);
+
+       udelay(500);
+
+       WREG_DAC(MGA1064_ER_PIX_PLLC_N, xpixpllcn);
+       WREG_DAC(MGA1064_ER_PIX_PLLC_M, xpixpllcm);
+       WREG_DAC(MGA1064_ER_PIX_PLLC_P, xpixpllcp);
+
+       udelay(50);
+}
+
+/*
  * DRM device
  */
 
@@ -39,6 +157,8 @@ static const struct mgag200_device_info mgag200_g200er_device_info =
        MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 1, 0, false);
 
 static const struct mgag200_device_funcs mgag200_g200er_device_funcs = {
+       .pixpllc_atomic_check = mgag200_g200er_pixpllc_atomic_check,
+       .pixpllc_atomic_update = mgag200_g200er_pixpllc_atomic_update,
 };
 
 struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
index a0dc72a..54c8056 100644 (file)
@@ -1,7 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
+#include <linux/delay.h>
 #include <linux/pci.h>
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_drv.h>
 
 #include "mgag200_drv.h"
@@ -32,6 +34,134 @@ static void mgag200_g200ev_init_registers(struct mga_device *mdev)
 }
 
 /*
+ * PIXPLLC
+ */
+
+static int mgag200_g200ev_pixpllc_atomic_check(struct drm_crtc *crtc,
+                                              struct drm_atomic_state *new_state)
+{
+       static const unsigned int vcomax = 550000;
+       static const unsigned int vcomin = 150000;
+       static const unsigned int pllreffreq = 50000;
+
+       struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+       struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+       long clock = new_crtc_state->mode.clock;
+       struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
+       unsigned int delta, tmpdelta;
+       unsigned int testp, testm, testn;
+       unsigned int p, m, n, s;
+       unsigned int computed;
+
+       m = n = p = s = 0;
+       delta = 0xffffffff;
+
+       for (testp = 16; testp > 0; testp--) {
+               if (clock * testp > vcomax)
+                       continue;
+               if (clock * testp < vcomin)
+                       continue;
+
+               for (testn = 1; testn < 257; testn++) {
+                       for (testm = 1; testm < 17; testm++) {
+                               computed = (pllreffreq * testn) /
+                                       (testm * testp);
+                               if (computed > clock)
+                                       tmpdelta = computed - clock;
+                               else
+                                       tmpdelta = clock - computed;
+                               if (tmpdelta < delta) {
+                                       delta = tmpdelta;
+                                       n = testn;
+                                       m = testm;
+                                       p = testp;
+                               }
+                       }
+               }
+       }
+
+       pixpllc->m = m;
+       pixpllc->n = n;
+       pixpllc->p = p;
+       pixpllc->s = s;
+
+       return 0;
+}
+
+static void mgag200_g200ev_pixpllc_atomic_update(struct drm_crtc *crtc,
+                                                struct drm_atomic_state *old_state)
+{
+       struct drm_device *dev = crtc->dev;
+       struct mga_device *mdev = to_mga_device(dev);
+       struct drm_crtc_state *crtc_state = crtc->state;
+       struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+       struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
+       unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
+       u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
+
+       pixpllcm = pixpllc->m - 1;
+       pixpllcn = pixpllc->n - 1;
+       pixpllcp = pixpllc->p - 1;
+       pixpllcs = pixpllc->s;
+
+       xpixpllcm = pixpllcm;
+       xpixpllcn = pixpllcn;
+       xpixpllcp = (pixpllcs << 3) | pixpllcp;
+
+       WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
+
+       WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+       tmp = RREG8(DAC_DATA);
+       tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
+       WREG8(DAC_DATA, tmp);
+
+       tmp = RREG8(MGAREG_MEM_MISC_READ);
+       tmp |= 0x3 << 2;
+       WREG8(MGAREG_MEM_MISC_WRITE, tmp);
+
+       WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);
+       tmp = RREG8(DAC_DATA);
+       WREG8(DAC_DATA, tmp & ~0x40);
+
+       WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+       tmp = RREG8(DAC_DATA);
+       tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
+       WREG8(DAC_DATA, tmp);
+
+       WREG_DAC(MGA1064_EV_PIX_PLLC_M, xpixpllcm);
+       WREG_DAC(MGA1064_EV_PIX_PLLC_N, xpixpllcn);
+       WREG_DAC(MGA1064_EV_PIX_PLLC_P, xpixpllcp);
+
+       udelay(50);
+
+       WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+       tmp = RREG8(DAC_DATA);
+       tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
+       WREG8(DAC_DATA, tmp);
+
+       udelay(500);
+
+       WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+       tmp = RREG8(DAC_DATA);
+       tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
+       tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
+       WREG8(DAC_DATA, tmp);
+
+       WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);
+       tmp = RREG8(DAC_DATA);
+       WREG8(DAC_DATA, tmp | 0x40);
+
+       tmp = RREG8(MGAREG_MEM_MISC_READ);
+       tmp |= (0x3 << 2);
+       WREG8(MGAREG_MEM_MISC_WRITE, tmp);
+
+       WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+       tmp = RREG8(DAC_DATA);
+       tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
+       WREG8(DAC_DATA, tmp);
+}
+
+/*
  * DRM device
  */
 
@@ -39,6 +169,8 @@ static const struct mgag200_device_info mgag200_g200ev_device_info =
        MGAG200_DEVICE_INFO_INIT(2048, 2048, 32700, false, 0, 1, false);
 
 static const struct mgag200_device_funcs mgag200_g200ev_device_funcs = {
+       .pixpllc_atomic_check = mgag200_g200ev_pixpllc_atomic_check,
+       .pixpllc_atomic_update = mgag200_g200ev_pixpllc_atomic_update,
 };
 
 struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
index 19a8701..29aa8a3 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <linux/pci.h>
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_drv.h>
 
 #include "mgag200_drv.h"
@@ -14,6 +15,64 @@ static void mgag200_g200ew3_init_registers(struct mga_device *mdev)
 }
 
 /*
+ * PIXPLLC
+ */
+
+static int mgag200_g200ew3_pixpllc_atomic_check(struct drm_crtc *crtc,
+                                               struct drm_atomic_state *new_state)
+{
+       static const unsigned int vcomax = 800000;
+       static const unsigned int vcomin = 400000;
+       static const unsigned int pllreffreq = 25000;
+
+       struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+       struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+       long clock = new_crtc_state->mode.clock;
+       struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
+       unsigned int delta, tmpdelta;
+       unsigned int testp, testm, testn, testp2;
+       unsigned int p, m, n, s;
+       unsigned int computed;
+
+       m = n = p = s = 0;
+       delta = 0xffffffff;
+
+       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 = testm + 1;
+                                               n = testn + 1;
+                                               p = testp + 1;
+                                               s = testp2;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       pixpllc->m = m;
+       pixpllc->n = n;
+       pixpllc->p = p;
+       pixpllc->s = s;
+
+       return 0;
+}
+
+/*
  * DRM device
  */
 
@@ -23,6 +82,8 @@ static const struct mgag200_device_info mgag200_g200ew3_device_info =
 static const struct mgag200_device_funcs mgag200_g200ew3_device_funcs = {
        .disable_vidrst = mgag200_bmc_disable_vidrst,
        .enable_vidrst = mgag200_bmc_enable_vidrst,
+       .pixpllc_atomic_check = mgag200_g200ew3_pixpllc_atomic_check,
+       .pixpllc_atomic_update = mgag200_g200wb_pixpllc_atomic_update, // same as G200WB
 };
 
 static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev)
index 7a7648d..ca9ea26 100644 (file)
@@ -1,7 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
+#include <linux/delay.h>
 #include <linux/pci.h>
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_drv.h>
 
 #include "mgag200_drv.h"
@@ -57,6 +59,198 @@ static void mgag200_g200se_init_registers(struct mgag200_g200se_device *g200se)
 }
 
 /*
+ * PIXPLLC
+ */
+
+static int mgag200_g200se_00_pixpllc_atomic_check(struct drm_crtc *crtc,
+                                                 struct drm_atomic_state *new_state)
+{
+       static const unsigned int vcomax = 320000;
+       static const unsigned int vcomin = 160000;
+       static const unsigned int pllreffreq = 25000;
+
+       struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+       struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+       long clock = new_crtc_state->mode.clock;
+       struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
+       unsigned int delta, tmpdelta, permitteddelta;
+       unsigned int testp, testm, testn;
+       unsigned int p, m, n, s;
+       unsigned int computed;
+
+       m = n = p = s = 0;
+       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;
+                                       n = testn;
+                                       p = testp;
+                               }
+                       }
+               }
+       }
+
+       if (delta > permitteddelta) {
+               pr_warn("PLL delta too large\n");
+               return -EINVAL;
+       }
+
+       pixpllc->m = m;
+       pixpllc->n = n;
+       pixpllc->p = p;
+       pixpllc->s = s;
+
+       return 0;
+}
+
+static void mgag200_g200se_00_pixpllc_atomic_update(struct drm_crtc *crtc,
+                                                   struct drm_atomic_state *old_state)
+{
+       struct drm_device *dev = crtc->dev;
+       struct mga_device *mdev = to_mga_device(dev);
+       struct drm_crtc_state *crtc_state = crtc->state;
+       struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+       struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
+       unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
+       u8 xpixpllcm, xpixpllcn, xpixpllcp;
+
+       pixpllcm = pixpllc->m - 1;
+       pixpllcn = pixpllc->n - 1;
+       pixpllcp = pixpllc->p - 1;
+       pixpllcs = pixpllc->s;
+
+       xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1);
+       xpixpllcn = pixpllcn;
+       xpixpllcp = (pixpllcs << 3) | pixpllcp;
+
+       WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
+
+       WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
+       WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
+       WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
+}
+
+static int mgag200_g200se_04_pixpllc_atomic_check(struct drm_crtc *crtc,
+                                                 struct drm_atomic_state *new_state)
+{
+       static const unsigned int vcomax = 1600000;
+       static const unsigned int vcomin = 800000;
+       static const unsigned int pllreffreq = 25000;
+       static const unsigned int pvalues_e4[] = {16, 14, 12, 10, 8, 6, 4, 2, 1};
+
+       struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+       struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+       long clock = new_crtc_state->mode.clock;
+       struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
+       unsigned int delta, tmpdelta, permitteddelta;
+       unsigned int testp, testm, testn;
+       unsigned int p, m, n, s;
+       unsigned int computed;
+       unsigned int fvv;
+       unsigned int i;
+
+       m = n = p = s = 0;
+       delta = 0xffffffff;
+
+       if (clock < 25000)
+               clock = 25000;
+       clock = clock * 2;
+
+       /* Permited delta is 0.5% as VESA Specification */
+       permitteddelta = clock * 5 / 1000;
+
+       for (i = 0 ; i < ARRAY_SIZE(pvalues_e4); 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;
+                                       n = testn;
+                                       p = testp;
+                               }
+                       }
+               }
+       }
+
+       fvv = pllreffreq * n / m;
+       fvv = (fvv - 800000) / 50000;
+       if (fvv > 15)
+               fvv = 15;
+       s = fvv << 1;
+
+       if (delta > permitteddelta) {
+               pr_warn("PLL delta too large\n");
+               return -EINVAL;
+       }
+
+       pixpllc->m = m;
+       pixpllc->n = n;
+       pixpllc->p = p;
+       pixpllc->s = s;
+
+       return 0;
+}
+
+static void mgag200_g200se_04_pixpllc_atomic_update(struct drm_crtc *crtc,
+                                                   struct drm_atomic_state *old_state)
+{
+       struct drm_device *dev = crtc->dev;
+       struct mga_device *mdev = to_mga_device(dev);
+       struct drm_crtc_state *crtc_state = crtc->state;
+       struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+       struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
+       unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
+       u8 xpixpllcm, xpixpllcn, xpixpllcp;
+
+       pixpllcm = pixpllc->m - 1;
+       pixpllcn = pixpllc->n - 1;
+       pixpllcp = pixpllc->p - 1;
+       pixpllcs = pixpllc->s;
+
+       xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1);
+       xpixpllcn = pixpllcn;
+       xpixpllcp = (pixpllcs << 3) | pixpllcp;
+
+       WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
+
+       WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
+       WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
+       WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
+
+       WREG_DAC(0x1a, 0x09);
+       msleep(20);
+       WREG_DAC(0x1a, 0x01);
+}
+
+/*
  * DRM device
  */
 
@@ -93,7 +287,14 @@ static int mgag200_g200se_init_unique_rev_id(struct mgag200_g200se_device *g200s
        return 0;
 }
 
-static const struct mgag200_device_funcs mgag200_g200se_device_funcs = {
+static const struct mgag200_device_funcs mgag200_g200se_00_device_funcs = {
+       .pixpllc_atomic_check = mgag200_g200se_00_pixpllc_atomic_check,
+       .pixpllc_atomic_update = mgag200_g200se_00_pixpllc_atomic_update,
+};
+
+static const struct mgag200_device_funcs mgag200_g200se_04_device_funcs = {
+       .pixpllc_atomic_check = mgag200_g200se_04_pixpllc_atomic_check,
+       .pixpllc_atomic_update = mgag200_g200se_04_pixpllc_atomic_update,
 };
 
 struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
@@ -101,6 +302,7 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru
 {
        struct mgag200_g200se_device *g200se;
        const struct mgag200_device_info *info;
+       const struct mgag200_device_funcs *funcs;
        struct mga_device *mdev;
        struct drm_device *dev;
        resource_size_t vram_available;
@@ -147,7 +349,12 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru
                return ERR_PTR(-EINVAL);
        }
 
-       ret = mgag200_device_init(mdev, type, info, &mgag200_g200se_device_funcs);
+       if (g200se->unique_rev_id >= 0x04)
+               funcs = &mgag200_g200se_04_device_funcs;
+       else
+               funcs = &mgag200_g200se_00_device_funcs;
+
+       ret = mgag200_device_init(mdev, type, info, funcs);
        if (ret)
                return ERR_PTR(ret);
 
index 91d2848..1e0c80c 100644 (file)
@@ -1,7 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
+#include <linux/delay.h>
 #include <linux/pci.h>
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_drv.h>
 
 #include "mgag200_drv.h"
@@ -29,6 +31,182 @@ void mgag200_g200wb_init_registers(struct mga_device *mdev)
 }
 
 /*
+ * PIXPLLC
+ */
+
+static int mgag200_g200wb_pixpllc_atomic_check(struct drm_crtc *crtc,
+                                              struct drm_atomic_state *new_state)
+{
+       static const unsigned int vcomax = 550000;
+       static const unsigned int vcomin = 150000;
+       static const unsigned int pllreffreq = 48000;
+
+       struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+       struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+       long clock = new_crtc_state->mode.clock;
+       struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
+       unsigned int delta, tmpdelta;
+       unsigned int testp, testm, testn;
+       unsigned int p, m, n, s;
+       unsigned int computed;
+
+       m = n = p = s = 0;
+       delta = 0xffffffff;
+
+       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;
+                                       m = testm;
+                                       p = testp;
+                                       s = 0;
+                               }
+                       }
+               }
+       }
+
+       pixpllc->m = m;
+       pixpllc->n = n;
+       pixpllc->p = p;
+       pixpllc->s = s;
+
+       return 0;
+}
+
+void mgag200_g200wb_pixpllc_atomic_update(struct drm_crtc *crtc,
+                                         struct drm_atomic_state *old_state)
+{
+       struct drm_device *dev = crtc->dev;
+       struct mga_device *mdev = to_mga_device(dev);
+       struct drm_crtc_state *crtc_state = crtc->state;
+       struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+       struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
+       bool pll_locked = false;
+       unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
+       u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
+       int i, j, tmpcount, vcount;
+
+       pixpllcm = pixpllc->m - 1;
+       pixpllcn = pixpllc->n - 1;
+       pixpllcp = pixpllc->p - 1;
+       pixpllcs = pixpllc->s;
+
+       xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm;
+       xpixpllcn = pixpllcn;
+       xpixpllcp = ((pixpllcn & GENMASK(10, 9)) >> 3) | (pixpllcs << 3) | pixpllcp;
+
+       WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
+
+       for (i = 0; i <= 32 && pll_locked == false; i++) {
+               if (i > 0) {
+                       WREG8(MGAREG_CRTC_INDEX, 0x1e);
+                       tmp = RREG8(MGAREG_CRTC_DATA);
+                       if (tmp < 0xff)
+                               WREG8(MGAREG_CRTC_DATA, tmp+1);
+               }
+
+               /* set pixclkdis to 1 */
+               WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+               tmp = RREG8(DAC_DATA);
+               tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
+               WREG8(DAC_DATA, tmp);
+
+               WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
+               tmp = RREG8(DAC_DATA);
+               tmp |= MGA1064_REMHEADCTL_CLKDIS;
+               WREG8(DAC_DATA, tmp);
+
+               /* select PLL Set C */
+               tmp = RREG8(MGAREG_MEM_MISC_READ);
+               tmp |= 0x3 << 2;
+               WREG8(MGAREG_MEM_MISC_WRITE, tmp);
+
+               WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+               tmp = RREG8(DAC_DATA);
+               tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80;
+               WREG8(DAC_DATA, tmp);
+
+               udelay(500);
+
+               /* reset the PLL */
+               WREG8(DAC_INDEX, MGA1064_VREF_CTL);
+               tmp = RREG8(DAC_DATA);
+               tmp &= ~0x04;
+               WREG8(DAC_DATA, tmp);
+
+               udelay(50);
+
+               /* program pixel pll register */
+               WREG_DAC(MGA1064_WB_PIX_PLLC_N, xpixpllcn);
+               WREG_DAC(MGA1064_WB_PIX_PLLC_M, xpixpllcm);
+               WREG_DAC(MGA1064_WB_PIX_PLLC_P, xpixpllcp);
+
+               udelay(50);
+
+               /* turn pll on */
+               WREG8(DAC_INDEX, MGA1064_VREF_CTL);
+               tmp = RREG8(DAC_DATA);
+               tmp |= 0x04;
+               WREG_DAC(MGA1064_VREF_CTL, tmp);
+
+               udelay(500);
+
+               /* select the pixel pll */
+               WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+               tmp = RREG8(DAC_DATA);
+               tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
+               tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
+               WREG8(DAC_DATA, tmp);
+
+               WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
+               tmp = RREG8(DAC_DATA);
+               tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK;
+               tmp |= MGA1064_REMHEADCTL_CLKSL_PLL;
+               WREG8(DAC_DATA, tmp);
+
+               /* reset dotclock rate bit */
+               WREG8(MGAREG_SEQ_INDEX, 1);
+               tmp = RREG8(MGAREG_SEQ_DATA);
+               tmp &= ~0x8;
+               WREG8(MGAREG_SEQ_DATA, tmp);
+
+               WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+               tmp = RREG8(DAC_DATA);
+               tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
+               WREG8(DAC_DATA, tmp);
+
+               vcount = RREG8(MGAREG_VCOUNT);
+
+               for (j = 0; j < 30 && pll_locked == false; j++) {
+                       tmpcount = RREG8(MGAREG_VCOUNT);
+                       if (tmpcount < vcount)
+                               vcount = 0;
+                       if ((tmpcount - vcount) > 2)
+                               pll_locked = true;
+                       else
+                               udelay(5);
+               }
+       }
+
+       WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
+       tmp = RREG8(DAC_DATA);
+       tmp &= ~MGA1064_REMHEADCTL_CLKDIS;
+       WREG_DAC(MGA1064_REMHEADCTL, tmp);
+}
+
+/*
  * DRM device
  */
 
@@ -38,6 +216,8 @@ static const struct mgag200_device_info mgag200_g200wb_device_info =
 static const struct mgag200_device_funcs mgag200_g200wb_device_funcs = {
        .disable_vidrst = mgag200_bmc_disable_vidrst,
        .enable_vidrst = mgag200_bmc_enable_vidrst,
+       .pixpllc_atomic_check = mgag200_g200wb_pixpllc_atomic_check,
+       .pixpllc_atomic_update = mgag200_g200wb_pixpllc_atomic_update,
 };
 
 struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
index 2b1e9f0..d999673 100644 (file)
@@ -660,9 +660,8 @@ static int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        struct mga_device *mdev = to_mga_device(dev);
+       const struct mgag200_device_funcs *funcs = mdev->funcs;
        struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
-       struct mgag200_pll *pixpll = &mdev->pixpll;
-       struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
        struct drm_property_blob *new_gamma_lut = new_crtc_state->gamma_lut;
        int ret;
 
@@ -674,10 +673,11 @@ static int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc,
                return 0;
 
        if (new_crtc_state->mode_changed) {
-               ret = pixpll->funcs->compute(pixpll, new_crtc_state->mode.clock,
-                                            &mgag200_crtc_state->pixpllc);
-               if (ret)
-                       return ret;
+               if (funcs->pixpllc_atomic_check) {
+                       ret = funcs->pixpllc_atomic_check(crtc, new_state);
+                       if (ret)
+                               return ret;
+               }
        }
 
        if (new_crtc_state->color_mgmt_changed && new_gamma_lut) {
@@ -718,7 +718,6 @@ static void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc,
        struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
        struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
        const struct drm_format_info *format = mgag200_crtc_state->format;
-       struct mgag200_pll *pixpll = &mdev->pixpll;
 
        if (funcs->disable_vidrst)
                funcs->disable_vidrst(mdev);
@@ -726,7 +725,8 @@ static void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc,
        mgag200_set_format_regs(mdev, format);
        mgag200_set_mode_regs(mdev, adjusted_mode);
 
-       pixpll->funcs->update(pixpll, &mgag200_crtc_state->pixpllc);
+       if (funcs->pixpllc_atomic_update)
+               funcs->pixpllc_atomic_update(crtc, old_state);
 
        if (mdev->type == G200_ER)
                mgag200_g200er_reset_tagfifo(mdev);
@@ -976,10 +976,6 @@ static int mgag200_pipeline_init(struct mga_device *mdev)
        struct drm_connector *connector = &mdev->connector;
        int ret;
 
-       ret = mgag200_pixpll_init(&mdev->pixpll, mdev);
-       if (ret)
-               return ret;
-
        ret = drm_universal_plane_init(dev, primary_plane, 0,
                                       &mgag200_primary_plane_funcs,
                                       mgag200_primary_plane_formats,
diff --git a/drivers/gpu/drm/mgag200/mgag200_pll.c b/drivers/gpu/drm/mgag200/mgag200_pll.c
deleted file mode 100644 (file)
index 8065ca5..0000000
+++ /dev/null
@@ -1,997 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include <linux/delay.h>
-
-#include "mgag200_drv.h"
-
-/*
- * G200
- */
-
-static int mgag200_pixpll_compute_g200(struct mgag200_pll *pixpll, long clock,
-                                      struct mgag200_pll_values *pixpllc)
-{
-       struct mga_device *mdev = pixpll->mdev;
-       struct drm_device *dev = &mdev->base;
-       struct mgag200_g200_device *g200 = to_mgag200_g200_device(dev);
-       const int post_div_max = 7;
-       const int in_div_min = 1;
-       const int in_div_max = 6;
-       const int feed_div_min = 7;
-       const int feed_div_max = 127;
-       u8 testp, testm, testn;
-       u8 n = 0, m = 0, p, s;
-       long f_vco;
-       long computed;
-       long delta, tmp_delta;
-       long ref_clk = g200->ref_clk;
-       long p_clk_min = g200->pclk_min;
-       long p_clk_max = g200->pclk_max;
-
-       if (clock > p_clk_max) {
-               drm_err(dev, "Pixel Clock %ld too high\n", clock);
-               return -EINVAL;
-       }
-
-       if (clock < p_clk_min >> 3)
-               clock = p_clk_min >> 3;
-
-       f_vco = clock;
-       for (testp = 0;
-            testp <= post_div_max && f_vco < p_clk_min;
-            testp = (testp << 1) + 1, f_vco <<= 1)
-               ;
-       p = testp + 1;
-
-       delta = clock;
-
-       for (testm = in_div_min; testm <= in_div_max; testm++) {
-               for (testn = feed_div_min; testn <= feed_div_max; testn++) {
-                       computed = ref_clk * (testn + 1) / (testm + 1);
-                       if (computed < f_vco)
-                               tmp_delta = f_vco - computed;
-                       else
-                               tmp_delta = computed - f_vco;
-                       if (tmp_delta < delta) {
-                               delta = tmp_delta;
-                               m = testm + 1;
-                               n = testn + 1;
-                       }
-               }
-       }
-       f_vco = ref_clk * n / m;
-       if (f_vco < 100000)
-               s = 0;
-       else if (f_vco < 140000)
-               s = 1;
-       else if (f_vco < 180000)
-               s = 2;
-       else
-               s = 3;
-
-       drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n",
-                   clock, f_vco, m, n, p, s);
-
-       pixpllc->m = m;
-       pixpllc->n = n;
-       pixpllc->p = p;
-       pixpllc->s = s;
-
-       return 0;
-}
-
-static void
-mgag200_pixpll_update_g200(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
-{
-       struct mga_device *mdev = pixpll->mdev;
-       unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
-       u8 xpixpllcm, xpixpllcn, xpixpllcp;
-
-       pixpllcm = pixpllc->m - 1;
-       pixpllcn = pixpllc->n - 1;
-       pixpllcp = pixpllc->p - 1;
-       pixpllcs = pixpllc->s;
-
-       xpixpllcm = pixpllcm;
-       xpixpllcn = pixpllcn;
-       xpixpllcp = (pixpllcs << 3) | pixpllcp;
-
-       WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
-
-       WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
-       WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
-       WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
-}
-
-static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200 = {
-       .compute = mgag200_pixpll_compute_g200,
-       .update = mgag200_pixpll_update_g200,
-};
-
-/*
- * G200SE
- */
-
-static int mgag200_pixpll_compute_g200se_00(struct mgag200_pll *pixpll, long clock,
-                                           struct mgag200_pll_values *pixpllc)
-{
-       static const unsigned int vcomax = 320000;
-       static const unsigned int vcomin = 160000;
-       static const unsigned int pllreffreq = 25000;
-
-       unsigned int delta, tmpdelta, permitteddelta;
-       unsigned int testp, testm, testn;
-       unsigned int p, m, n, s;
-       unsigned int computed;
-
-       m = n = p = s = 0;
-       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;
-                                       n = testn;
-                                       p = testp;
-                               }
-                       }
-               }
-       }
-
-       if (delta > permitteddelta) {
-               pr_warn("PLL delta too large\n");
-               return -EINVAL;
-       }
-
-       pixpllc->m = m;
-       pixpllc->n = n;
-       pixpllc->p = p;
-       pixpllc->s = s;
-
-       return 0;
-}
-
-static void mgag200_pixpll_update_g200se_00(struct mgag200_pll *pixpll,
-                                           const struct mgag200_pll_values *pixpllc)
-{
-       unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
-       u8 xpixpllcm, xpixpllcn, xpixpllcp;
-       struct mga_device *mdev = pixpll->mdev;
-
-       pixpllcm = pixpllc->m - 1;
-       pixpllcn = pixpllc->n - 1;
-       pixpllcp = pixpllc->p - 1;
-       pixpllcs = pixpllc->s;
-
-       xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1);
-       xpixpllcn = pixpllcn;
-       xpixpllcp = (pixpllcs << 3) | pixpllcp;
-
-       WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
-
-       WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
-       WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
-       WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
-}
-
-static int mgag200_pixpll_compute_g200se_04(struct mgag200_pll *pixpll, long clock,
-                                           struct mgag200_pll_values *pixpllc)
-{
-       static const unsigned int vcomax = 1600000;
-       static const unsigned int vcomin = 800000;
-       static const unsigned int pllreffreq = 25000;
-       static const unsigned int pvalues_e4[] = {16, 14, 12, 10, 8, 6, 4, 2, 1};
-
-       unsigned int delta, tmpdelta, permitteddelta;
-       unsigned int testp, testm, testn;
-       unsigned int p, m, n, s;
-       unsigned int computed;
-       unsigned int fvv;
-       unsigned int i;
-
-       m = n = p = s = 0;
-       delta = 0xffffffff;
-
-       if (clock < 25000)
-               clock = 25000;
-       clock = clock * 2;
-
-       /* Permited delta is 0.5% as VESA Specification */
-       permitteddelta = clock * 5 / 1000;
-
-       for (i = 0 ; i < ARRAY_SIZE(pvalues_e4); 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;
-                                       n = testn;
-                                       p = testp;
-                               }
-                       }
-               }
-       }
-
-       fvv = pllreffreq * n / m;
-       fvv = (fvv - 800000) / 50000;
-       if (fvv > 15)
-               fvv = 15;
-       s = fvv << 1;
-
-       if (delta > permitteddelta) {
-               pr_warn("PLL delta too large\n");
-               return -EINVAL;
-       }
-
-       pixpllc->m = m;
-       pixpllc->n = n;
-       pixpllc->p = p;
-       pixpllc->s = s;
-
-       return 0;
-}
-
-static void mgag200_pixpll_update_g200se_04(struct mgag200_pll *pixpll,
-                                           const struct mgag200_pll_values *pixpllc)
-{
-       unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
-       u8 xpixpllcm, xpixpllcn, xpixpllcp;
-       struct mga_device *mdev = pixpll->mdev;
-
-       pixpllcm = pixpllc->m - 1;
-       pixpllcn = pixpllc->n - 1;
-       pixpllcp = pixpllc->p - 1;
-       pixpllcs = pixpllc->s;
-
-       xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1);
-       xpixpllcn = pixpllcn;
-       xpixpllcp = (pixpllcs << 3) | pixpllcp;
-
-       WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
-
-       WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
-       WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
-       WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
-
-       WREG_DAC(0x1a, 0x09);
-       msleep(20);
-       WREG_DAC(0x1a, 0x01);
-}
-
-static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200se_00 = {
-       .compute = mgag200_pixpll_compute_g200se_00,
-       .update = mgag200_pixpll_update_g200se_00,
-};
-
-static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200se_04 = {
-       .compute = mgag200_pixpll_compute_g200se_04,
-       .update = mgag200_pixpll_update_g200se_04,
-};
-
-/*
- * G200WB
- */
-
-static int mgag200_pixpll_compute_g200wb(struct mgag200_pll *pixpll, long clock,
-                                        struct mgag200_pll_values *pixpllc)
-{
-       static const unsigned int vcomax = 550000;
-       static const unsigned int vcomin = 150000;
-       static const unsigned int pllreffreq = 48000;
-
-       unsigned int delta, tmpdelta;
-       unsigned int testp, testm, testn;
-       unsigned int p, m, n, s;
-       unsigned int computed;
-
-       m = n = p = s = 0;
-       delta = 0xffffffff;
-
-       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;
-                                       m = testm;
-                                       p = testp;
-                                       s = 0;
-                               }
-                       }
-               }
-       }
-
-       pixpllc->m = m;
-       pixpllc->n = n;
-       pixpllc->p = p;
-       pixpllc->s = s;
-
-       return 0;
-}
-
-static void
-mgag200_pixpll_update_g200wb(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
-{
-       unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
-       u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
-       int i, j, tmpcount, vcount;
-       struct mga_device *mdev = pixpll->mdev;
-       bool pll_locked = false;
-
-       pixpllcm = pixpllc->m - 1;
-       pixpllcn = pixpllc->n - 1;
-       pixpllcp = pixpllc->p - 1;
-       pixpllcs = pixpllc->s;
-
-       xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm;
-       xpixpllcn = pixpllcn;
-       xpixpllcp = ((pixpllcn & GENMASK(10, 9)) >> 3) | (pixpllcs << 3) | pixpllcp;
-
-       WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
-
-       for (i = 0; i <= 32 && pll_locked == false; i++) {
-               if (i > 0) {
-                       WREG8(MGAREG_CRTC_INDEX, 0x1e);
-                       tmp = RREG8(MGAREG_CRTC_DATA);
-                       if (tmp < 0xff)
-                               WREG8(MGAREG_CRTC_DATA, tmp+1);
-               }
-
-               /* set pixclkdis to 1 */
-               WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
-               tmp = RREG8(DAC_DATA);
-               tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
-               WREG8(DAC_DATA, tmp);
-
-               WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
-               tmp = RREG8(DAC_DATA);
-               tmp |= MGA1064_REMHEADCTL_CLKDIS;
-               WREG8(DAC_DATA, tmp);
-
-               /* select PLL Set C */
-               tmp = RREG8(MGAREG_MEM_MISC_READ);
-               tmp |= 0x3 << 2;
-               WREG8(MGAREG_MEM_MISC_WRITE, tmp);
-
-               WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
-               tmp = RREG8(DAC_DATA);
-               tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80;
-               WREG8(DAC_DATA, tmp);
-
-               udelay(500);
-
-               /* reset the PLL */
-               WREG8(DAC_INDEX, MGA1064_VREF_CTL);
-               tmp = RREG8(DAC_DATA);
-               tmp &= ~0x04;
-               WREG8(DAC_DATA, tmp);
-
-               udelay(50);
-
-               /* program pixel pll register */
-               WREG_DAC(MGA1064_WB_PIX_PLLC_N, xpixpllcn);
-               WREG_DAC(MGA1064_WB_PIX_PLLC_M, xpixpllcm);
-               WREG_DAC(MGA1064_WB_PIX_PLLC_P, xpixpllcp);
-
-               udelay(50);
-
-               /* turn pll on */
-               WREG8(DAC_INDEX, MGA1064_VREF_CTL);
-               tmp = RREG8(DAC_DATA);
-               tmp |= 0x04;
-               WREG_DAC(MGA1064_VREF_CTL, tmp);
-
-               udelay(500);
-
-               /* select the pixel pll */
-               WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
-               tmp = RREG8(DAC_DATA);
-               tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
-               tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
-               WREG8(DAC_DATA, tmp);
-
-               WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
-               tmp = RREG8(DAC_DATA);
-               tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK;
-               tmp |= MGA1064_REMHEADCTL_CLKSL_PLL;
-               WREG8(DAC_DATA, tmp);
-
-               /* reset dotclock rate bit */
-               WREG8(MGAREG_SEQ_INDEX, 1);
-               tmp = RREG8(MGAREG_SEQ_DATA);
-               tmp &= ~0x8;
-               WREG8(MGAREG_SEQ_DATA, tmp);
-
-               WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
-               tmp = RREG8(DAC_DATA);
-               tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
-               WREG8(DAC_DATA, tmp);
-
-               vcount = RREG8(MGAREG_VCOUNT);
-
-               for (j = 0; j < 30 && pll_locked == false; j++) {
-                       tmpcount = RREG8(MGAREG_VCOUNT);
-                       if (tmpcount < vcount)
-                               vcount = 0;
-                       if ((tmpcount - vcount) > 2)
-                               pll_locked = true;
-                       else
-                               udelay(5);
-               }
-       }
-
-       WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
-       tmp = RREG8(DAC_DATA);
-       tmp &= ~MGA1064_REMHEADCTL_CLKDIS;
-       WREG_DAC(MGA1064_REMHEADCTL, tmp);
-}
-
-static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200wb = {
-       .compute = mgag200_pixpll_compute_g200wb,
-       .update = mgag200_pixpll_update_g200wb,
-};
-
-/*
- * G200EV
- */
-
-static int mgag200_pixpll_compute_g200ev(struct mgag200_pll *pixpll, long clock,
-                                        struct mgag200_pll_values *pixpllc)
-{
-       static const unsigned int vcomax = 550000;
-       static const unsigned int vcomin = 150000;
-       static const unsigned int pllreffreq = 50000;
-
-       unsigned int delta, tmpdelta;
-       unsigned int testp, testm, testn;
-       unsigned int p, m, n, s;
-       unsigned int computed;
-
-       m = n = p = s = 0;
-       delta = 0xffffffff;
-
-       for (testp = 16; testp > 0; testp--) {
-               if (clock * testp > vcomax)
-                       continue;
-               if (clock * testp < vcomin)
-                       continue;
-
-               for (testn = 1; testn < 257; testn++) {
-                       for (testm = 1; testm < 17; testm++) {
-                               computed = (pllreffreq * testn) /
-                                       (testm * testp);
-                               if (computed > clock)
-                                       tmpdelta = computed - clock;
-                               else
-                                       tmpdelta = clock - computed;
-                               if (tmpdelta < delta) {
-                                       delta = tmpdelta;
-                                       n = testn;
-                                       m = testm;
-                                       p = testp;
-                               }
-                       }
-               }
-       }
-
-       pixpllc->m = m;
-       pixpllc->n = n;
-       pixpllc->p = p;
-       pixpllc->s = s;
-
-       return 0;
-}
-
-static void
-mgag200_pixpll_update_g200ev(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
-{
-       unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
-       u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
-       struct mga_device *mdev = pixpll->mdev;
-
-       pixpllcm = pixpllc->m - 1;
-       pixpllcn = pixpllc->n - 1;
-       pixpllcp = pixpllc->p - 1;
-       pixpllcs = pixpllc->s;
-
-       xpixpllcm = pixpllcm;
-       xpixpllcn = pixpllcn;
-       xpixpllcp = (pixpllcs << 3) | pixpllcp;
-
-       WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
-
-       WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
-       tmp = RREG8(DAC_DATA);
-       tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
-       WREG8(DAC_DATA, tmp);
-
-       tmp = RREG8(MGAREG_MEM_MISC_READ);
-       tmp |= 0x3 << 2;
-       WREG8(MGAREG_MEM_MISC_WRITE, tmp);
-
-       WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);
-       tmp = RREG8(DAC_DATA);
-       WREG8(DAC_DATA, tmp & ~0x40);
-
-       WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
-       tmp = RREG8(DAC_DATA);
-       tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
-       WREG8(DAC_DATA, tmp);
-
-       WREG_DAC(MGA1064_EV_PIX_PLLC_M, xpixpllcm);
-       WREG_DAC(MGA1064_EV_PIX_PLLC_N, xpixpllcn);
-       WREG_DAC(MGA1064_EV_PIX_PLLC_P, xpixpllcp);
-
-       udelay(50);
-
-       WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
-       tmp = RREG8(DAC_DATA);
-       tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
-       WREG8(DAC_DATA, tmp);
-
-       udelay(500);
-
-       WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
-       tmp = RREG8(DAC_DATA);
-       tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
-       tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
-       WREG8(DAC_DATA, tmp);
-
-       WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);
-       tmp = RREG8(DAC_DATA);
-       WREG8(DAC_DATA, tmp | 0x40);
-
-       tmp = RREG8(MGAREG_MEM_MISC_READ);
-       tmp |= (0x3 << 2);
-       WREG8(MGAREG_MEM_MISC_WRITE, tmp);
-
-       WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
-       tmp = RREG8(DAC_DATA);
-       tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
-       WREG8(DAC_DATA, tmp);
-}
-
-static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200ev = {
-       .compute = mgag200_pixpll_compute_g200ev,
-       .update = mgag200_pixpll_update_g200ev,
-};
-
-/*
- * G200EH
- */
-
-static int mgag200_pixpll_compute_g200eh(struct mgag200_pll *pixpll, long clock,
-                                        struct mgag200_pll_values *pixpllc)
-{
-       static const unsigned int vcomax = 800000;
-       static const unsigned int vcomin = 400000;
-       static const unsigned int pllreffreq = 33333;
-
-       unsigned int delta, tmpdelta;
-       unsigned int testp, testm, testn;
-       unsigned int p, m, n, s;
-       unsigned int computed;
-
-       m = n = p = s = 0;
-       delta = 0xffffffff;
-
-       for (testp = 16; testp > 0; testp >>= 1) {
-               if (clock * testp > vcomax)
-                       continue;
-               if (clock * testp < vcomin)
-                       continue;
-
-               for (testm = 1; testm < 33; testm++) {
-                       for (testn = 17; testn < 257; testn++) {
-                               computed = (pllreffreq * testn) / (testm * testp);
-                               if (computed > clock)
-                                       tmpdelta = computed - clock;
-                               else
-                                       tmpdelta = clock - computed;
-                               if (tmpdelta < delta) {
-                                       delta = tmpdelta;
-                                       n = testn;
-                                       m = testm;
-                                       p = testp;
-                               }
-                       }
-               }
-       }
-
-       pixpllc->m = m;
-       pixpllc->n = n;
-       pixpllc->p = p;
-       pixpllc->s = s;
-
-       return 0;
-}
-
-static void
-mgag200_pixpll_update_g200eh(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
-{
-       unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
-       u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
-       int i, j, tmpcount, vcount;
-       struct mga_device *mdev = pixpll->mdev;
-       bool pll_locked = false;
-
-       pixpllcm = pixpllc->m - 1;
-       pixpllcn = pixpllc->n - 1;
-       pixpllcp = pixpllc->p - 1;
-       pixpllcs = pixpllc->s;
-
-       xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm;
-       xpixpllcn = pixpllcn;
-       xpixpllcp = (pixpllcs << 3) | pixpllcp;
-
-       WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
-
-       for (i = 0; i <= 32 && pll_locked == false; i++) {
-               WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
-               tmp = RREG8(DAC_DATA);
-               tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
-               WREG8(DAC_DATA, tmp);
-
-               tmp = RREG8(MGAREG_MEM_MISC_READ);
-               tmp |= 0x3 << 2;
-               WREG8(MGAREG_MEM_MISC_WRITE, tmp);
-
-               WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
-               tmp = RREG8(DAC_DATA);
-               tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
-               WREG8(DAC_DATA, tmp);
-
-               udelay(500);
-
-               WREG_DAC(MGA1064_EH_PIX_PLLC_M, xpixpllcm);
-               WREG_DAC(MGA1064_EH_PIX_PLLC_N, xpixpllcn);
-               WREG_DAC(MGA1064_EH_PIX_PLLC_P, xpixpllcp);
-
-               udelay(500);
-
-               WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
-               tmp = RREG8(DAC_DATA);
-               tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
-               tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
-               WREG8(DAC_DATA, tmp);
-
-               WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
-               tmp = RREG8(DAC_DATA);
-               tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
-               tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
-               WREG8(DAC_DATA, tmp);
-
-               vcount = RREG8(MGAREG_VCOUNT);
-
-               for (j = 0; j < 30 && pll_locked == false; j++) {
-                       tmpcount = RREG8(MGAREG_VCOUNT);
-                       if (tmpcount < vcount)
-                               vcount = 0;
-                       if ((tmpcount - vcount) > 2)
-                               pll_locked = true;
-                       else
-                               udelay(5);
-               }
-       }
-}
-
-static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200eh = {
-       .compute = mgag200_pixpll_compute_g200eh,
-       .update = mgag200_pixpll_update_g200eh,
-};
-
-/*
- * G200EH3
- */
-
-static int mgag200_pixpll_compute_g200eh3(struct mgag200_pll *pixpll, long clock,
-                                         struct mgag200_pll_values *pixpllc)
-{
-       static const unsigned int vcomax = 3000000;
-       static const unsigned int vcomin = 1500000;
-       static const unsigned int pllreffreq = 25000;
-
-       unsigned int delta, tmpdelta;
-       unsigned int testp, testm, testn;
-       unsigned int p, m, n, s;
-       unsigned int computed;
-
-       m = n = p = s = 0;
-       delta = 0xffffffff;
-       testp = 0;
-
-       for (testm = 150; testm >= 6; testm--) {
-               if (clock * testm > vcomax)
-                       continue;
-               if (clock * testm < vcomin)
-                       continue;
-               for (testn = 120; testn >= 60; testn--) {
-                       computed = (pllreffreq * testn) / testm;
-                       if (computed > clock)
-                               tmpdelta = computed - clock;
-                       else
-                               tmpdelta = clock - computed;
-                       if (tmpdelta < delta) {
-                               delta = tmpdelta;
-                               n = testn + 1;
-                               m = testm + 1;
-                               p = testp + 1;
-                       }
-                       if (delta == 0)
-                               break;
-               }
-               if (delta == 0)
-                       break;
-       }
-
-       pixpllc->m = m;
-       pixpllc->n = n;
-       pixpllc->p = p;
-       pixpllc->s = s;
-
-       return 0;
-}
-
-static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200eh3 = {
-       .compute = mgag200_pixpll_compute_g200eh3,
-       .update = mgag200_pixpll_update_g200eh, // same as G200EH
-};
-
-/*
- * G200ER
- */
-
-static int mgag200_pixpll_compute_g200er(struct mgag200_pll *pixpll, long clock,
-                                        struct mgag200_pll_values *pixpllc)
-{
-       static const unsigned int vcomax = 1488000;
-       static const unsigned int vcomin = 1056000;
-       static const unsigned int pllreffreq = 48000;
-       static const unsigned int m_div_val[] = { 1, 2, 4, 8 };
-
-       unsigned int delta, tmpdelta;
-       int testr, testn, testm, testo;
-       unsigned int p, m, n, s;
-       unsigned int computed, vco;
-
-       m = n = p = s = 0;
-       delta = 0xffffffff;
-
-       for (testr = 0; testr < 4; testr++) {
-               if (delta == 0)
-                       break;
-               for (testn = 5; testn < 129; testn++) {
-                       if (delta == 0)
-                               break;
-                       for (testm = 3; testm >= 0; testm--) {
-                               if (delta == 0)
-                                       break;
-                               for (testo = 5; testo < 33; testo++) {
-                                       vco = pllreffreq * (testn + 1) /
-                                               (testr + 1);
-                                       if (vco < vcomin)
-                                               continue;
-                                       if (vco > vcomax)
-                                               continue;
-                                       computed = vco / (m_div_val[testm] * (testo + 1));
-                                       if (computed > clock)
-                                               tmpdelta = computed - clock;
-                                       else
-                                               tmpdelta = clock - computed;
-                                       if (tmpdelta < delta) {
-                                               delta = tmpdelta;
-                                               m = (testm | (testo << 3)) + 1;
-                                               n = testn + 1;
-                                               p = testr + 1;
-                                               s = testr;
-                                       }
-                               }
-                       }
-               }
-       }
-
-       pixpllc->m = m;
-       pixpllc->n = n;
-       pixpllc->p = p;
-       pixpllc->s = s;
-
-       return 0;
-}
-
-static void
-mgag200_pixpll_update_g200er(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
-{
-       unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
-       u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
-       struct mga_device *mdev = pixpll->mdev;
-
-       pixpllcm = pixpllc->m - 1;
-       pixpllcn = pixpllc->n - 1;
-       pixpllcp = pixpllc->p - 1;
-       pixpllcs = pixpllc->s;
-
-       xpixpllcm = pixpllcm;
-       xpixpllcn = pixpllcn;
-       xpixpllcp = (pixpllcs << 3) | pixpllcp;
-
-       WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
-
-       WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
-       tmp = RREG8(DAC_DATA);
-       tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
-       WREG8(DAC_DATA, tmp);
-
-       WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
-       tmp = RREG8(DAC_DATA);
-       tmp |= MGA1064_REMHEADCTL_CLKDIS;
-       WREG8(DAC_DATA, tmp);
-
-       tmp = RREG8(MGAREG_MEM_MISC_READ);
-       tmp |= (0x3<<2) | 0xc0;
-       WREG8(MGAREG_MEM_MISC_WRITE, tmp);
-
-       WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
-       tmp = RREG8(DAC_DATA);
-       tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
-       tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
-       WREG8(DAC_DATA, tmp);
-
-       udelay(500);
-
-       WREG_DAC(MGA1064_ER_PIX_PLLC_N, xpixpllcn);
-       WREG_DAC(MGA1064_ER_PIX_PLLC_M, xpixpllcm);
-       WREG_DAC(MGA1064_ER_PIX_PLLC_P, xpixpllcp);
-
-       udelay(50);
-}
-
-static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200er = {
-       .compute = mgag200_pixpll_compute_g200er,
-       .update = mgag200_pixpll_update_g200er,
-};
-
-/*
- * G200EW3
- */
-
-static int mgag200_pixpll_compute_g200ew3(struct mgag200_pll *pixpll, long clock,
-                                         struct mgag200_pll_values *pixpllc)
-{
-       static const unsigned int vcomax = 800000;
-       static const unsigned int vcomin = 400000;
-       static const unsigned int pllreffreq = 25000;
-
-       unsigned int delta, tmpdelta;
-       unsigned int testp, testm, testn, testp2;
-       unsigned int p, m, n, s;
-       unsigned int computed;
-
-       m = n = p = s = 0;
-       delta = 0xffffffff;
-
-       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 = testm + 1;
-                                               n = testn + 1;
-                                               p = testp + 1;
-                                               s = testp2;
-                                       }
-                               }
-                       }
-               }
-       }
-
-       pixpllc->m = m;
-       pixpllc->n = n;
-       pixpllc->p = p;
-       pixpllc->s = s;
-
-       return 0;
-}
-
-static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200ew3 = {
-       .compute = mgag200_pixpll_compute_g200ew3,
-       .update = mgag200_pixpll_update_g200wb, // same as G200WB
-};
-
-/*
- * PLL initialization
- */
-
-int mgag200_pixpll_init(struct mgag200_pll *pixpll, struct mga_device *mdev)
-{
-       struct drm_device *dev = &mdev->base;
-       struct mgag200_g200se_device *g200se;
-
-       pixpll->mdev = mdev;
-
-       switch (mdev->type) {
-       case G200_PCI:
-       case G200_AGP:
-               pixpll->funcs = &mgag200_pixpll_funcs_g200;
-               break;
-       case G200_SE_A:
-       case G200_SE_B:
-               g200se = to_mgag200_g200se_device(dev);
-
-               if (g200se->unique_rev_id >= 0x04)
-                       pixpll->funcs = &mgag200_pixpll_funcs_g200se_04;
-               else
-                       pixpll->funcs = &mgag200_pixpll_funcs_g200se_00;
-               break;
-       case G200_WB:
-               pixpll->funcs = &mgag200_pixpll_funcs_g200wb;
-               break;
-       case G200_EV:
-               pixpll->funcs = &mgag200_pixpll_funcs_g200ev;
-               break;
-       case G200_EH:
-               pixpll->funcs = &mgag200_pixpll_funcs_g200eh;
-               break;
-       case G200_EH3:
-               pixpll->funcs = &mgag200_pixpll_funcs_g200eh3;
-               break;
-       case G200_ER:
-               pixpll->funcs = &mgag200_pixpll_funcs_g200er;
-               break;
-       case G200_EW3:
-               pixpll->funcs = &mgag200_pixpll_funcs_g200ew3;
-               break;
-       default:
-               drm_err(dev, "unknown device type %d\n", mdev->type);
-               return -ENODEV;
-       }
-
-       return 0;
-}