summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2012-02-02 11:43:31 +1000
committerBen Skeggs <bskeggs@redhat.com>2012-05-24 16:31:20 +1000
commit4719b55be5d43420b29e48c17208ec3db66e730f (patch)
tree9077de3101181dd8c957b26e5aa6572f9ad84dca /drivers/gpu/drm
parent30e533900ea74a3499dad5c4660ebaf80b50d152 (diff)
downloadlinux-3.10-4719b55be5d43420b29e48c17208ec3db66e730f.tar.gz
linux-3.10-4719b55be5d43420b29e48c17208ec3db66e730f.tar.bz2
linux-3.10-4719b55be5d43420b29e48c17208ec3db66e730f.zip
drm/nva3/pm: begin to restructure memory clock changes + another magic
The binary driver appears to do various bits and pieces of the memory clock frequency change at different times, depending on the particular transition that's occuring. I've attempted to replicate this here for div->pll, pll->div and div->div transitions. With some additional (patches upcoming) magic regs being bashed, this allows me to correctly transition between all 3 perflvls on NVS300. pll->pll transitions will *not* work correctly at the moment, pending me tricking the binary driver into doing one and seeing how to correctly handle it. This patch also handles (hopefully) 0x1110e0, which appears to need changing depending on whether in PLL or divider mode.. Maybe. We'll see. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/nouveau/nva3_pm.c48
1 files changed, 40 insertions, 8 deletions
diff --git a/drivers/gpu/drm/nouveau/nva3_pm.c b/drivers/gpu/drm/nouveau/nva3_pm.c
index 98588292c80..c9a1f63d1c9 100644
--- a/drivers/gpu/drm/nouveau/nva3_pm.c
+++ b/drivers/gpu/drm/nouveau/nva3_pm.c
@@ -360,14 +360,12 @@ mclk_clock_set(struct nouveau_mem_exec_func *exec)
u32 freq = perflvl->memory;
u8 *rammap, *ramcfg, ver, hdr, cnt, len;
- nv_wr32(dev, 0x004018, 0x00001000);
-
- prog_pll(dev, 0x02, 0x004000, &info->mclk);
-
- if (nv_rd32(dev, 0x4000) & 0x00000008)
- nv_wr32(dev, 0x004018, 0x1000d000);
- else
- nv_wr32(dev, 0x004018, 0x10005000);
+ if (!info->mclk.pll) {
+ nv_mask(dev, 0x004168, 0x003f3040, info->mclk.clk);
+ nv_mask(dev, 0x004000, 0x00000008, 0x00000008);
+ nv_mask(dev, 0x1110e0, 0x00088000, 0x00088000);
+ nv_wr32(dev, 0x004018, 0x1000d000); /*XXX*/
+ }
rammap = nouveau_perf_rammap(dev, freq, &ver, &hdr, &cnt, &len);
if (rammap && ver == 0x10 && hdr >= 5) {
@@ -388,6 +386,11 @@ mclk_clock_set(struct nouveau_mem_exec_func *exec)
nv_mask(dev, 0x10f804, 0x80000000, 0x00000000);
}
}
+
+ if (info->mclk.pll) {
+ nv_mask(dev, 0x1110e0, 0x00088000, 0x00011000);
+ nv_mask(dev, 0x004000, 0x00000008, 0x00000000);
+ }
}
static void
@@ -439,10 +442,39 @@ prog_mem(struct drm_device *dev, struct nva3_pm_state *info)
.timing_set = mclk_timing_set,
.priv = info
};
+ u32 ctrl;
+
+ ctrl = nv_rd32(dev, 0x004000);
+ if (ctrl & 0x00000008) {
+ if (info->mclk.pll) {
+ nv_mask(dev, 0x004128, 0x00000101, 0x00000101);
+ nv_wr32(dev, 0x004004, info->mclk.pll);
+ nv_wr32(dev, 0x004000, (ctrl |= 0x00000001));
+ nv_wr32(dev, 0x004000, (ctrl &= 0xffffffef));
+ nv_wait(dev, 0x004000, 0x00020000, 0x00020000);
+ nv_wr32(dev, 0x004000, (ctrl |= 0x00000010));
+ nv_wr32(dev, 0x004018, 0x00005000); /*XXX*/
+ nv_wr32(dev, 0x004000, (ctrl |= 0x00000004));
+ }
+ } else {
+ if (!info->mclk.pll) {
+ nv_mask(dev, 0x004168, 0x003f3141,
+ 0x00000101 | info->mclk.clk);
+ }
+ }
nv_wr32(dev, 0x611200, 0x00003300);
nouveau_mem_exec(&exec, info->perflvl);
nv_wr32(dev, 0x611200, 0x00003330);
+
+ if (info->mclk.pll) {
+ nv_mask(dev, 0x004168, 0x00000001, 0x00000000);
+ nv_mask(dev, 0x004168, 0x00000100, 0x00000000);
+ } else {
+ nv_mask(dev, 0x004000, 0x00000001, 0x00000000);
+ nv_mask(dev, 0x004128, 0x00000001, 0x00000000);
+ nv_mask(dev, 0x004128, 0x00000100, 0x00000000);
+ }
}
int