drm/nva3/clk: Set intermediate core clock on reclocking
Signed-off-by: Roy Spliet <rspliet@eclipso.eu> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
a749a1fb55
commit
3d40a7176d
3 changed files with 51 additions and 14 deletions
|
@ -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)
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
|
|
||||||
/* 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,
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
(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
|
||||||
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)
|
||||||
|
|
||||||
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 {
|
||||||
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,
|
||||||
|
|
Loading…
Add table
Reference in a new issue