diff options
author | Roy Spliet | 2014-08-29 12:27:42 +0200 |
---|---|---|
committer | Ben Skeggs | 2014-09-15 14:25:12 +0200 |
commit | 2fe7eaa0d4c9cf26b379a8054a87c4bf7ac4dc12 (patch) | |
tree | aa2d658ab996de57ec37653a886f65a90a9a3142 /drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c | |
parent | drm/nouveau/gpio: rename g92 class to g94 (diff) | |
download | kernel-qcow2-linux-2fe7eaa0d4c9cf26b379a8054a87c4bf7ac4dc12.tar.gz kernel-qcow2-linux-2fe7eaa0d4c9cf26b379a8054a87c4bf7ac4dc12.tar.xz kernel-qcow2-linux-2fe7eaa0d4c9cf26b379a8054a87c4bf7ac4dc12.zip |
drm/nva3/clk: Pause the GPU before reclocking
V2: always call post correctly even if pre fails
V3: move function prototype to nva3.h
Signed-off-by: Roy Spliet <rspliet@eclipso.eu>
Diffstat (limited to 'drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c | 52 |
1 files changed, 51 insertions, 1 deletions
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c index ab0fe370b1f1..094551d8ad9b 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c @@ -23,6 +23,7 @@ * Roy Spliet */ +#include <engine/fifo.h> #include <subdev/bios.h> #include <subdev/bios/pll.h> #include <subdev/timer.h> @@ -293,6 +294,41 @@ calc_host(struct nva3_clock_priv *priv, struct nouveau_cstate *cstate) return ret; } +int +nva3_clock_pre(struct nouveau_clock *clk, unsigned long *flags) +{ + struct nouveau_fifo *pfifo = nouveau_fifo(clk); + + /* halt and idle execution engines */ + nv_mask(clk, 0x020060, 0x00070000, 0x00000000); + nv_mask(clk, 0x002504, 0x00000001, 0x00000001); + /* Wait until the interrupt handler is finished */ + if (!nv_wait(clk, 0x000100, 0xffffffff, 0x00000000)) + return -EBUSY; + + if (pfifo) + pfifo->pause(pfifo, flags); + + if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010)) + return -EIO; + if (!nv_wait(clk, 0x00251c, 0x0000003f, 0x0000003f)) + return -EIO; + + return 0; +} + +void +nva3_clock_post(struct nouveau_clock *clk, unsigned long *flags) +{ + struct nouveau_fifo *pfifo = nouveau_fifo(clk); + + if (pfifo && flags) + pfifo->start(pfifo, flags); + + nv_mask(clk, 0x002504, 0x00000001, 0x00000000); + nv_mask(clk, 0x020060, 0x00070000, 0x00040000); +} + static void disable_clk_src(struct nva3_clock_priv *priv, u32 src) { @@ -421,6 +457,13 @@ nva3_clock_prog(struct nouveau_clock *clk) { struct nva3_clock_priv *priv = (void *)clk; struct nva3_clock_info *core = &priv->eng[nv_clk_src_core]; + int ret = 0; + unsigned long flags; + unsigned long *f = &flags; + + ret = nva3_clock_pre(clk, f); + if (ret) + goto out; if (core->pll) prog_core(priv, nv_clk_src_core_intm); @@ -430,7 +473,14 @@ nva3_clock_prog(struct nouveau_clock *clk) prog_clk(priv, 0x20, nv_clk_src_disp); prog_clk(priv, 0x21, nv_clk_src_vdec); prog_host(priv); - return 0; + +out: + if (ret == -EBUSY) + f = NULL; + + nva3_clock_post(clk, f); + + return ret; } static void |