drm/nva3/clk: HOST clock

Signed-off-by: Roy Spliet <rspliet@eclipso.eu>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
Roy Spliet 2014-08-21 13:45:14 +02:00 committed by Ben Skeggs
parent 6a4a47cfd1
commit 70c7995d12
2 changed files with 78 additions and 8 deletions

View file

@ -136,12 +136,11 @@ static int
nva3_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
{
struct nva3_clock_priv *priv = (void *)clk;
u32 hsrc;
switch (src) {
case nv_clk_src_crystal:
return nv_device(priv)->crystal;
case nv_clk_src_href:
return 100000;
case nv_clk_src_core:
return read_pll(priv, 0x00, 0x4200);
case nv_clk_src_shader:
@ -154,6 +153,18 @@ nva3_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
return read_clk(priv, 0x21, false);
case nv_clk_src_daemon:
return read_clk(priv, 0x25, false);
case nv_clk_src_host:
hsrc = (nv_rd32(priv, 0xc040) & 0x30000000) >> 28;
switch (hsrc) {
case 0:
return read_clk(priv, 0x1d, false);
case 2:
case 3:
return 277000;
default:
nv_error(clk, "unknown HOST clock source %d\n", hsrc);
return -EINVAL;
}
default:
nv_error(clk, "invalid clock source %d\n", src);
return -EINVAL;
@ -258,6 +269,34 @@ calc_clk(struct nva3_clock_priv *priv, struct nouveau_cstate *cstate,
return ret;
}
static int
calc_host(struct nva3_clock_priv *priv, struct nouveau_cstate *cstate)
{
int ret = 0;
u32 kHz = cstate->domain[nv_clk_src_host];
struct nva3_clock_info *info = &priv->eng[nv_clk_src_host];
if (kHz == 277000) {
info->clk = 0;
info->host_out = NVA3_HOST_277;
return 0;
}
info->host_out = NVA3_HOST_CLK;
ret = nva3_clk_info(&priv->base, 0x1d, kHz, info);
if (ret >= 0)
return 0;
return ret;
}
static void
disable_clk_src(struct nva3_clock_priv *priv, u32 src)
{
nv_mask(priv, src, 0x00000100, 0x00000000);
nv_mask(priv, src, 0x00000001, 0x00000000);
}
static void
prog_pll(struct nva3_clock_priv *priv, int clk, u32 pll, int idx)
{
@ -275,15 +314,13 @@ prog_pll(struct nva3_clock_priv *priv, int clk, u32 pll, int idx)
nv_wait(priv, ctrl, 0x00020000, 0x00020000);
nv_mask(priv, ctrl, 0x00000010, 0x00000010);
nv_mask(priv, ctrl, 0x00000008, 0x00000000);
nv_mask(priv, src1, 0x00000100, 0x00000000);
nv_mask(priv, src1, 0x00000001, 0x00000000);
disable_clk_src(priv, src1);
} else {
nv_mask(priv, src1, 0x003f3141, 0x00000101 | info->clk);
nv_mask(priv, ctrl, 0x00000018, 0x00000018);
udelay(20);
nv_mask(priv, ctrl, 0x00000001, 0x00000000);
nv_mask(priv, src0, 0x00000100, 0x00000000);
nv_mask(priv, src0, 0x00000001, 0x00000000);
disable_clk_src(priv, src0);
}
}
@ -294,6 +331,33 @@ prog_clk(struct nva3_clock_priv *priv, int clk, int idx)
nv_mask(priv, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | info->clk);
}
static void
prog_host(struct nva3_clock_priv *priv)
{
struct nva3_clock_info *info = &priv->eng[nv_clk_src_host];
u32 hsrc = (nv_rd32(priv, 0xc040));
switch (info->host_out) {
case NVA3_HOST_277:
if ((hsrc & 0x30000000) == 0) {
nv_wr32(priv, 0xc040, hsrc | 0x20000000);
disable_clk_src(priv, 0x4194);
}
break;
case NVA3_HOST_CLK:
prog_clk(priv, 0x1d, nv_clk_src_host);
if ((hsrc & 0x30000000) >= 0x20000000) {
nv_wr32(priv, 0xc040, hsrc & ~0x30000000);
}
break;
default:
break;
}
/* This seems to be a clock gating factor on idle, always set to 64 */
nv_wr32(priv, 0xc044, 0x3e);
}
static int
nva3_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
{
@ -303,7 +367,8 @@ nva3_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
if ((ret = calc_clk(priv, cstate, 0x10, 0x4200, nv_clk_src_core)) ||
(ret = calc_clk(priv, cstate, 0x11, 0x4220, nv_clk_src_shader)) ||
(ret = calc_clk(priv, cstate, 0x20, 0x0000, nv_clk_src_disp)) ||
(ret = calc_clk(priv, cstate, 0x21, 0x0000, nv_clk_src_vdec)))
(ret = calc_clk(priv, cstate, 0x21, 0x0000, nv_clk_src_vdec)) ||
(ret = calc_host(priv, cstate)))
return ret;
return 0;
@ -317,6 +382,7 @@ nva3_clock_prog(struct nouveau_clock *clk)
prog_pll(priv, 0x01, 0x004220, nv_clk_src_shader);
prog_clk(priv, 0x20, nv_clk_src_disp);
prog_clk(priv, 0x21, nv_clk_src_vdec);
prog_host(priv);
return 0;
}
@ -328,12 +394,12 @@ nva3_clock_tidy(struct nouveau_clock *clk)
static struct nouveau_clocks
nva3_domain[] = {
{ nv_clk_src_crystal, 0xff },
{ nv_clk_src_href , 0xff },
{ nv_clk_src_core , 0x00, 0, "core", 1000 },
{ nv_clk_src_shader , 0x01, 0, "shader", 1000 },
{ nv_clk_src_mem , 0x02, 0, "memory", 1000 },
{ nv_clk_src_vdec , 0x03 },
{ nv_clk_src_disp , 0x04 },
{ nv_clk_src_host , 0x05 },
{ nv_clk_src_max }
};

View file

@ -6,6 +6,10 @@
struct nva3_clock_info {
u32 clk;
u32 pll;
enum {
NVA3_HOST_277,
NVA3_HOST_CLK,
} host_out;
};
int nva3_pll_info(struct nouveau_clock *, int, u32, u32,