drm/nva3/pm: make pll->pll mode work
authorBen Skeggs <bskeggs@redhat.com>
Fri, 3 Feb 2012 00:02:03 +0000 (10:02 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Thu, 24 May 2012 06:31:23 +0000 (16:31 +1000)
This probably wants a cleanup, but I'm holding off until I know for sure
how the rest of the things that need doing fit together.

Tested on NVS300 by hacking up perflvl 1 to require PLL mode, and switching
between perflvl 3 and 1.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nva3_pm.c

index 0ab6d436fbd12d649c57fe321d523636fcf35b2c..3a237887961e61abe4378b179a6082731e197f4a 100644 (file)
@@ -377,10 +377,23 @@ mclk_clock_set(struct nouveau_mem_exec_func *exec)
 {
        struct drm_device *dev = exec->dev;
        struct nva3_pm_state *info = exec->priv;
+       u32 ctrl;
 
+       ctrl = nv_rd32(dev, 0x004000);
+       if (!(ctrl & 0x00000008) && info->mclk.pll) {
+               nv_wr32(dev, 0x004000, (ctrl |=  0x00000008));
+               nv_mask(dev, 0x1110e0, 0x00088000, 0x00088000);
+               nv_wr32(dev, 0x004018, 0x00001000); /*XXX*/
+               nv_wr32(dev, 0x004000, (ctrl &= ~0x00000001));
+               nv_wr32(dev, 0x004004, info->mclk.pll);
+               nv_wr32(dev, 0x004000, (ctrl |=  0x00000001));
+               udelay(64);
+               nv_wr32(dev, 0x004018, 0x10005000); /*XXX*/
+               udelay(20);
+       } else
        if (!info->mclk.pll) {
                nv_mask(dev, 0x004168, 0x003f3040, info->mclk.clk);
-               nv_mask(dev, 0x004000, 0x00000008, 0x00000008);
+               nv_wr32(dev, 0x004000, (ctrl |= 0x00000008));
                nv_mask(dev, 0x1110e0, 0x00088000, 0x00088000);
                nv_wr32(dev, 0x004018, 0x1000d000); /*XXX*/
        }
@@ -406,7 +419,7 @@ mclk_clock_set(struct nouveau_mem_exec_func *exec)
 
        if (info->mclk.pll) {
                nv_mask(dev, 0x1110e0, 0x00088000, 0x00011000);
-               nv_mask(dev, 0x004000, 0x00000008, 0x00000000);
+               nv_wr32(dev, 0x004000, (ctrl &= ~0x00000008));
        }
 }
 
@@ -477,10 +490,12 @@ prog_mem(struct drm_device *dev, struct nva3_pm_state *info)
                        nv_wr32(dev, 0x004000, (ctrl |= 0x00000004));
                }
        } else {
-               if (!info->mclk.pll) {
-                       nv_mask(dev, 0x004168, 0x003f3141,
-                                              0x00000101 | info->mclk.clk);
-               }
+               u32 ssel = 0x00000101;
+               if (info->mclk.clk)
+                       ssel |= info->mclk.clk;
+               else
+                       ssel |= 0x00080000; /* 324MHz, shouldn't matter... */
+               nv_mask(dev, 0x004168, 0x003f3141, ctrl);
        }
 
        if (info->rammap && !(info->rammap[4] & 0x02))