Commit 3d40a717 authored by Roy Spliet's avatar Roy Spliet Committed by Ben Skeggs

drm/nva3/clk: Set intermediate core clock on reclocking

Signed-off-by: default avatarRoy Spliet <rspliet@eclipso.eu>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent a749a1fb
...@@ -29,6 +29,7 @@ enum nv_clk_src { ...@@ -29,6 +29,7 @@ enum nv_clk_src {
nv_clk_src_mdiv, nv_clk_src_mdiv,
nv_clk_src_core, nv_clk_src_core,
nv_clk_src_core_intm,
nv_clk_src_shader, nv_clk_src_shader,
nv_clk_src_mem, nv_clk_src_mem,
......
...@@ -142,6 +142,7 @@ nva3_clock_read(struct nouveau_clock *clk, enum nv_clk_src src) ...@@ -142,6 +142,7 @@ nva3_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
case nv_clk_src_crystal: case nv_clk_src_crystal:
return nv_device(priv)->crystal; return nv_device(priv)->crystal;
case nv_clk_src_core: case nv_clk_src_core:
case nv_clk_src_core_intm:
return read_pll(priv, 0x00, 0x4200); return read_pll(priv, 0x00, 0x4200);
case nv_clk_src_shader: case nv_clk_src_shader:
return read_pll(priv, 0x01, 0x4220); return read_pll(priv, 0x01, 0x4220);
...@@ -226,7 +227,6 @@ nva3_pll_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz, ...@@ -226,7 +227,6 @@ nva3_pll_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz,
{ {
struct nouveau_bios *bios = nouveau_bios(clock); struct nouveau_bios *bios = nouveau_bios(clock);
struct nva3_clock_priv *priv = (void *)clock; struct nva3_clock_priv *priv = (void *)clock;
int clk_khz;
struct nvbios_pll limits; struct nvbios_pll limits;
int P, N, M, diff; int P, N, M, diff;
int ret; int ret;
...@@ -235,10 +235,10 @@ nva3_pll_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz, ...@@ -235,10 +235,10 @@ nva3_pll_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz,
/* If we can get a within [-2, 3) MHz of a divider, we'll disable the /* If we can get a within [-2, 3) MHz of a divider, we'll disable the
* PLL and use the divider instead. */ * PLL and use the divider instead. */
clk_khz = nva3_clk_info(clock, clk, khz, info); ret = nva3_clk_info(clock, clk, khz, info);
diff = khz - clk_khz; diff = khz - ret;
if (!pll || (diff >= -2000 && diff < 3000)) { if (!pll || (diff >= -2000 && diff < 3000)) {
return clk_khz; goto out;
} }
/* Try with PLL */ /* Try with PLL */
...@@ -246,8 +246,8 @@ nva3_pll_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz, ...@@ -246,8 +246,8 @@ nva3_pll_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz,
if (ret) if (ret)
return ret; return ret;
clk_khz = nva3_clk_info(clock, clk - 0x10, limits.refclk, info); ret = nva3_clk_info(clock, clk - 0x10, limits.refclk, info);
if (clk_khz != limits.refclk) if (ret != limits.refclk)
return -EINVAL; return -EINVAL;
ret = nva3_pll_calc(nv_subdev(priv), &limits, khz, &N, NULL, &M, &P); ret = nva3_pll_calc(nv_subdev(priv), &limits, khz, &N, NULL, &M, &P);
...@@ -255,6 +255,9 @@ nva3_pll_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz, ...@@ -255,6 +255,9 @@ nva3_pll_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz,
info->pll = (P << 16) | (N << 8) | M; info->pll = (P << 16) | (N << 8) | M;
} }
out:
info->fb_delay = max(((khz + 7566) / 15133), (u32) 18);
return ret ? ret : -ERANGE; return ret ? ret : -ERANGE;
} }
...@@ -371,10 +374,26 @@ prog_host(struct nva3_clock_priv *priv) ...@@ -371,10 +374,26 @@ prog_host(struct nva3_clock_priv *priv)
nv_wr32(priv, 0xc044, 0x3e); nv_wr32(priv, 0xc044, 0x3e);
} }
static void
prog_core(struct nva3_clock_priv *priv, int idx)
{
struct nva3_clock_info *info = &priv->eng[idx];
u32 fb_delay = nv_rd32(priv, 0x10002c);
if (fb_delay < info->fb_delay)
nv_wr32(priv, 0x10002c, info->fb_delay);
prog_pll(priv, 0x00, 0x004200, idx);
if (fb_delay > info->fb_delay)
nv_wr32(priv, 0x10002c, info->fb_delay);
}
static int static int
nva3_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate) nva3_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
{ {
struct nva3_clock_priv *priv = (void *)clk; struct nva3_clock_priv *priv = (void *)clk;
struct nva3_clock_info *core = &priv->eng[nv_clk_src_core];
int ret; int ret;
if ((ret = calc_clk(priv, cstate, 0x10, 0x4200, nv_clk_src_core)) || if ((ret = calc_clk(priv, cstate, 0x10, 0x4200, nv_clk_src_core)) ||
...@@ -384,6 +403,16 @@ nva3_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate) ...@@ -384,6 +403,16 @@ nva3_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
(ret = calc_host(priv, cstate))) (ret = calc_host(priv, cstate)))
return ret; return ret;
/* XXX: Should be reading the highest bit in the VBIOS clock to decide
* whether to use a PLL or not... but using a PLL defeats the purpose */
if (core->pll) {
ret = nva3_clk_info(clk, 0x10,
cstate->domain[nv_clk_src_core_intm],
&priv->eng[nv_clk_src_core_intm]);
if (ret < 0)
return ret;
}
return 0; return 0;
} }
...@@ -391,7 +420,12 @@ static int ...@@ -391,7 +420,12 @@ static int
nva3_clock_prog(struct nouveau_clock *clk) nva3_clock_prog(struct nouveau_clock *clk)
{ {
struct nva3_clock_priv *priv = (void *)clk; struct nva3_clock_priv *priv = (void *)clk;
prog_pll(priv, 0x00, 0x004200, nv_clk_src_core); struct nva3_clock_info *core = &priv->eng[nv_clk_src_core];
if (core->pll)
prog_core(priv, nv_clk_src_core_intm);
prog_core(priv, nv_clk_src_core);
prog_pll(priv, 0x01, 0x004220, nv_clk_src_shader); prog_pll(priv, 0x01, 0x004220, nv_clk_src_shader);
prog_clk(priv, 0x20, nv_clk_src_disp); prog_clk(priv, 0x20, nv_clk_src_disp);
prog_clk(priv, 0x21, nv_clk_src_vdec); prog_clk(priv, 0x21, nv_clk_src_vdec);
...@@ -406,13 +440,14 @@ nva3_clock_tidy(struct nouveau_clock *clk) ...@@ -406,13 +440,14 @@ nva3_clock_tidy(struct nouveau_clock *clk)
static struct nouveau_clocks static struct nouveau_clocks
nva3_domain[] = { nva3_domain[] = {
{ nv_clk_src_crystal, 0xff }, { nv_clk_src_crystal , 0xff },
{ nv_clk_src_core , 0x00, 0, "core", 1000 }, { nv_clk_src_core , 0x00, 0, "core", 1000 },
{ nv_clk_src_shader , 0x01, 0, "shader", 1000 }, { nv_clk_src_shader , 0x01, 0, "shader", 1000 },
{ nv_clk_src_mem , 0x02, 0, "memory", 1000 }, { nv_clk_src_mem , 0x02, 0, "memory", 1000 },
{ nv_clk_src_vdec , 0x03 }, { nv_clk_src_vdec , 0x03 },
{ nv_clk_src_disp , 0x04 }, { nv_clk_src_disp , 0x04 },
{ nv_clk_src_host , 0x05 }, { nv_clk_src_host , 0x05 },
{ nv_clk_src_core_intm, 0x06 },
{ nv_clk_src_max } { nv_clk_src_max }
}; };
......
...@@ -10,6 +10,7 @@ struct nva3_clock_info { ...@@ -10,6 +10,7 @@ struct nva3_clock_info {
NVA3_HOST_277, NVA3_HOST_277,
NVA3_HOST_CLK, NVA3_HOST_CLK,
} host_out; } host_out;
u32 fb_delay;
}; };
int nva3_pll_info(struct nouveau_clock *, int, u32, u32, int nva3_pll_info(struct nouveau_clock *, int, u32, u32,
......
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