Commit 2fe7eaa0 authored by Roy Spliet's avatar Roy Spliet Committed by Ben Skeggs

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: default avatarRoy Spliet <rspliet@eclipso.eu>
parent b485a700
......@@ -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
......
......@@ -15,5 +15,6 @@ struct nva3_clock_info {
int nva3_pll_info(struct nouveau_clock *, int, u32, u32,
struct nva3_clock_info *);
int nva3_clock_pre(struct nouveau_clock *clk, unsigned long *flags);
void nva3_clock_post(struct nouveau_clock *clk, unsigned long *flags);
#endif
......@@ -28,6 +28,7 @@
#include <subdev/timer.h>
#include <subdev/clock.h>
#include "nva3.h"
#include "pll.h"
struct nvaa_clock_priv {
......@@ -299,25 +300,14 @@ static int
nvaa_clock_prog(struct nouveau_clock *clk)
{
struct nvaa_clock_priv *priv = (void *)clk;
struct nouveau_fifo *pfifo = nouveau_fifo(clk);
u32 pllmask = 0, mast;
unsigned long flags;
u32 pllmask = 0, mast, ptherm_gate;
int ret = -EBUSY;
/* halt and idle execution engines */
ptherm_gate = 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))
goto resume;
if (pfifo)
pfifo->pause(pfifo, &flags);
unsigned long *f = &flags;
int ret = 0;
if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010))
goto resume;
if (!nv_wait(clk, 0x00251c, 0x0000003f, 0x0000003f))
goto resume;
ret = nva3_clock_pre(clk, f);
if (ret)
goto out;
/* First switch to safe clocks: href */
mast = nv_mask(clk, 0xc054, 0x03400e70, 0x03400640);
......@@ -375,15 +365,8 @@ nvaa_clock_prog(struct nouveau_clock *clk)
}
nv_wr32(clk, 0xc054, mast);
ret = 0;
resume:
if (pfifo)
pfifo->start(pfifo, &flags);
nv_mask(clk, 0x002504, 0x00000001, 0x00000000);
nv_wr32(clk, 0x020060, ptherm_gate);
/* Disable some PLLs and dividers when unused */
if (priv->csrc != nv_clk_src_core) {
nv_wr32(clk, 0x4040, 0x00000000);
......@@ -395,6 +378,12 @@ nvaa_clock_prog(struct nouveau_clock *clk)
nv_mask(clk, 0x4020, 0x80000000, 0x00000000);
}
out:
if (ret == -EBUSY)
f = NULL;
nva3_clock_post(clk, f);
return ret;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment