summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoy Spliet <rspliet@eclipso.eu>2014-08-21 13:45:14 +0200
committerBen Skeggs <bskeggs@redhat.com>2014-10-02 13:25:43 +1000
commit9069f0c81e33caf9825e00065a319d01e07324d8 (patch)
tree8118864958aaf7fa3ba4311692a546a1d2b80c1f
parent965e7b83708ed1a9bf6e2427908dfe5ad87f2b47 (diff)
downloadnouveau-9069f0c81e33caf9825e00065a319d01e07324d8.tar.gz
clk/nva3: HOST clock
Signed-off-by: Roy Spliet <rspliet@eclipso.eu> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--nvkm/subdev/clock/nva3.c82
-rw-r--r--nvkm/subdev/clock/nva3.h4
2 files changed, 78 insertions, 8 deletions
diff --git a/nvkm/subdev/clock/nva3.c b/nvkm/subdev/clock/nva3.c
index 3ad8d64ff..c676de6d1 100644
--- a/nvkm/subdev/clock/nva3.c
+++ b/nvkm/subdev/clock/nva3.c
@@ -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 }
};
diff --git a/nvkm/subdev/clock/nva3.h b/nvkm/subdev/clock/nva3.h
index 2b4b3ead8..54f99491f 100644
--- a/nvkm/subdev/clock/nva3.h
+++ b/nvkm/subdev/clock/nva3.h
@@ -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,