These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / nouveau / nvkm / subdev / clk / gk104.c
index e9b2310..396f7e4 100644 (file)
  *
  * Authors: Ben Skeggs
  */
-#include <subdev/clk.h>
+#define gk104_clk(p) container_of((p), struct gk104_clk, base)
+#include "priv.h"
 #include "pll.h"
 
-#include <core/device.h>
 #include <subdev/timer.h>
 #include <subdev/bios.h>
 #include <subdev/bios/pll.h>
@@ -38,28 +38,30 @@ struct gk104_clk_info {
        u32 coef;
 };
 
-struct gk104_clk_priv {
+struct gk104_clk {
        struct nvkm_clk base;
        struct gk104_clk_info eng[16];
 };
 
-static u32 read_div(struct gk104_clk_priv *, int, u32, u32);
-static u32 read_pll(struct gk104_clk_priv *, u32);
+static u32 read_div(struct gk104_clk *, int, u32, u32);
+static u32 read_pll(struct gk104_clk *, u32);
 
 static u32
-read_vco(struct gk104_clk_priv *priv, u32 dsrc)
+read_vco(struct gk104_clk *clk, u32 dsrc)
 {
-       u32 ssrc = nv_rd32(priv, dsrc);
+       struct nvkm_device *device = clk->base.subdev.device;
+       u32 ssrc = nvkm_rd32(device, dsrc);
        if (!(ssrc & 0x00000100))
-               return read_pll(priv, 0x00e800);
-       return read_pll(priv, 0x00e820);
+               return read_pll(clk, 0x00e800);
+       return read_pll(clk, 0x00e820);
 }
 
 static u32
-read_pll(struct gk104_clk_priv *priv, u32 pll)
+read_pll(struct gk104_clk *clk, u32 pll)
 {
-       u32 ctrl = nv_rd32(priv, pll + 0x00);
-       u32 coef = nv_rd32(priv, pll + 0x04);
+       struct nvkm_device *device = clk->base.subdev.device;
+       u32 ctrl = nvkm_rd32(device, pll + 0x00);
+       u32 coef = nvkm_rd32(device, pll + 0x04);
        u32 P = (coef & 0x003f0000) >> 16;
        u32 N = (coef & 0x0000ff00) >> 8;
        u32 M = (coef & 0x000000ff) >> 0;
@@ -72,22 +74,22 @@ read_pll(struct gk104_clk_priv *priv, u32 pll)
        switch (pll) {
        case 0x00e800:
        case 0x00e820:
-               sclk = nv_device(priv)->crystal;
+               sclk = device->crystal;
                P = 1;
                break;
        case 0x132000:
-               sclk = read_pll(priv, 0x132020);
+               sclk = read_pll(clk, 0x132020);
                P = (coef & 0x10000000) ? 2 : 1;
                break;
        case 0x132020:
-               sclk = read_div(priv, 0, 0x137320, 0x137330);
-               fN   = nv_rd32(priv, pll + 0x10) >> 16;
+               sclk = read_div(clk, 0, 0x137320, 0x137330);
+               fN   = nvkm_rd32(device, pll + 0x10) >> 16;
                break;
        case 0x137000:
        case 0x137020:
        case 0x137040:
        case 0x1370e0:
-               sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140);
+               sclk = read_div(clk, (pll & 0xff) / 0x20, 0x137120, 0x137140);
                break;
        default:
                return 0;
@@ -101,70 +103,73 @@ read_pll(struct gk104_clk_priv *priv, u32 pll)
 }
 
 static u32
-read_div(struct gk104_clk_priv *priv, int doff, u32 dsrc, u32 dctl)
+read_div(struct gk104_clk *clk, int doff, u32 dsrc, u32 dctl)
 {
-       u32 ssrc = nv_rd32(priv, dsrc + (doff * 4));
-       u32 sctl = nv_rd32(priv, dctl + (doff * 4));
+       struct nvkm_device *device = clk->base.subdev.device;
+       u32 ssrc = nvkm_rd32(device, dsrc + (doff * 4));
+       u32 sctl = nvkm_rd32(device, dctl + (doff * 4));
 
        switch (ssrc & 0x00000003) {
        case 0:
                if ((ssrc & 0x00030000) != 0x00030000)
-                       return nv_device(priv)->crystal;
+                       return device->crystal;
                return 108000;
        case 2:
                return 100000;
        case 3:
                if (sctl & 0x80000000) {
-                       u32 sclk = read_vco(priv, dsrc + (doff * 4));
+                       u32 sclk = read_vco(clk, dsrc + (doff * 4));
                        u32 sdiv = (sctl & 0x0000003f) + 2;
                        return (sclk * 2) / sdiv;
                }
 
-               return read_vco(priv, dsrc + (doff * 4));
+               return read_vco(clk, dsrc + (doff * 4));
        default:
                return 0;
        }
 }
 
 static u32
-read_mem(struct gk104_clk_priv *priv)
+read_mem(struct gk104_clk *clk)
 {
-       switch (nv_rd32(priv, 0x1373f4) & 0x0000000f) {
-       case 1: return read_pll(priv, 0x132020);
-       case 2: return read_pll(priv, 0x132000);
+       struct nvkm_device *device = clk->base.subdev.device;
+       switch (nvkm_rd32(device, 0x1373f4) & 0x0000000f) {
+       case 1: return read_pll(clk, 0x132020);
+       case 2: return read_pll(clk, 0x132000);
        default:
                return 0;
        }
 }
 
 static u32
-read_clk(struct gk104_clk_priv *priv, int clk)
+read_clk(struct gk104_clk *clk, int idx)
 {
-       u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4));
+       struct nvkm_device *device = clk->base.subdev.device;
+       u32 sctl = nvkm_rd32(device, 0x137250 + (idx * 4));
        u32 sclk, sdiv;
 
-       if (clk < 7) {
-               u32 ssel = nv_rd32(priv, 0x137100);
-               if (ssel & (1 << clk)) {
-                       sclk = read_pll(priv, 0x137000 + (clk * 0x20));
+       if (idx < 7) {
+               u32 ssel = nvkm_rd32(device, 0x137100);
+               if (ssel & (1 << idx)) {
+                       sclk = read_pll(clk, 0x137000 + (idx * 0x20));
                        sdiv = 1;
                } else {
-                       sclk = read_div(priv, clk, 0x137160, 0x1371d0);
+                       sclk = read_div(clk, idx, 0x137160, 0x1371d0);
                        sdiv = 0;
                }
        } else {
-               u32 ssrc = nv_rd32(priv, 0x137160 + (clk * 0x04));
+               u32 ssrc = nvkm_rd32(device, 0x137160 + (idx * 0x04));
                if ((ssrc & 0x00000003) == 0x00000003) {
-                       sclk = read_div(priv, clk, 0x137160, 0x1371d0);
+                       sclk = read_div(clk, idx, 0x137160, 0x1371d0);
                        if (ssrc & 0x00000100) {
                                if (ssrc & 0x40000000)
-                                       sclk = read_pll(priv, 0x1370e0);
+                                       sclk = read_pll(clk, 0x1370e0);
                                sdiv = 1;
                        } else {
                                sdiv = 0;
                        }
                } else {
-                       sclk = read_div(priv, clk, 0x137160, 0x1371d0);
+                       sclk = read_div(clk, idx, 0x137160, 0x1371d0);
                        sdiv = 0;
                }
        }
@@ -181,10 +186,11 @@ read_clk(struct gk104_clk_priv *priv, int clk)
 }
 
 static int
-gk104_clk_read(struct nvkm_clk *clk, enum nv_clk_src src)
+gk104_clk_read(struct nvkm_clk *base, enum nv_clk_src src)
 {
-       struct nvkm_device *device = nv_device(clk);
-       struct gk104_clk_priv *priv = (void *)clk;
+       struct gk104_clk *clk = gk104_clk(base);
+       struct nvkm_subdev *subdev = &clk->base.subdev;
+       struct nvkm_device *device = subdev->device;
 
        switch (src) {
        case nv_clk_src_crystal:
@@ -192,29 +198,29 @@ gk104_clk_read(struct nvkm_clk *clk, enum nv_clk_src src)
        case nv_clk_src_href:
                return 100000;
        case nv_clk_src_mem:
-               return read_mem(priv);
+               return read_mem(clk);
        case nv_clk_src_gpc:
-               return read_clk(priv, 0x00);
+               return read_clk(clk, 0x00);
        case nv_clk_src_rop:
-               return read_clk(priv, 0x01);
+               return read_clk(clk, 0x01);
        case nv_clk_src_hubk07:
-               return read_clk(priv, 0x02);
+               return read_clk(clk, 0x02);
        case nv_clk_src_hubk06:
-               return read_clk(priv, 0x07);
+               return read_clk(clk, 0x07);
        case nv_clk_src_hubk01:
-               return read_clk(priv, 0x08);
+               return read_clk(clk, 0x08);
        case nv_clk_src_daemon:
-               return read_clk(priv, 0x0c);
+               return read_clk(clk, 0x0c);
        case nv_clk_src_vdec:
-               return read_clk(priv, 0x0e);
+               return read_clk(clk, 0x0e);
        default:
-               nv_error(clk, "invalid clock source %d\n", src);
+               nvkm_error(subdev, "invalid clock source %d\n", src);
                return -EINVAL;
        }
 }
 
 static u32
-calc_div(struct gk104_clk_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv)
+calc_div(struct gk104_clk *clk, int idx, u32 ref, u32 freq, u32 *ddiv)
 {
        u32 div = min((ref * 2) / freq, (u32)65);
        if (div < 2)
@@ -225,7 +231,7 @@ calc_div(struct gk104_clk_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv)
 }
 
 static u32
-calc_src(struct gk104_clk_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv)
+calc_src(struct gk104_clk *clk, int idx, u32 freq, u32 *dsrc, u32 *ddiv)
 {
        u32 sclk;
 
@@ -247,28 +253,29 @@ calc_src(struct gk104_clk_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv)
        }
 
        /* otherwise, calculate the closest divider */
-       sclk = read_vco(priv, 0x137160 + (clk * 4));
-       if (clk < 7)
-               sclk = calc_div(priv, clk, sclk, freq, ddiv);
+       sclk = read_vco(clk, 0x137160 + (idx * 4));
+       if (idx < 7)
+               sclk = calc_div(clk, idx, sclk, freq, ddiv);
        return sclk;
 }
 
 static u32
-calc_pll(struct gk104_clk_priv *priv, int clk, u32 freq, u32 *coef)
+calc_pll(struct gk104_clk *clk, int idx, u32 freq, u32 *coef)
 {
-       struct nvkm_bios *bios = nvkm_bios(priv);
+       struct nvkm_subdev *subdev = &clk->base.subdev;
+       struct nvkm_bios *bios = subdev->device->bios;
        struct nvbios_pll limits;
        int N, M, P, ret;
 
-       ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits);
+       ret = nvbios_pll_parse(bios, 0x137000 + (idx * 0x20), &limits);
        if (ret)
                return 0;
 
-       limits.refclk = read_div(priv, clk, 0x137120, 0x137140);
+       limits.refclk = read_div(clk, idx, 0x137120, 0x137140);
        if (!limits.refclk)
                return 0;
 
-       ret = gt215_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P);
+       ret = gt215_pll_calc(subdev, &limits, freq, &N, NULL, &M, &P);
        if (ret <= 0)
                return 0;
 
@@ -277,10 +284,10 @@ calc_pll(struct gk104_clk_priv *priv, int clk, u32 freq, u32 *coef)
 }
 
 static int
-calc_clk(struct gk104_clk_priv *priv,
-        struct nvkm_cstate *cstate, int clk, int dom)
+calc_clk(struct gk104_clk *clk,
+        struct nvkm_cstate *cstate, int idx, int dom)
 {
-       struct gk104_clk_info *info = &priv->eng[clk];
+       struct gk104_clk_info *info = &clk->eng[idx];
        u32 freq = cstate->domain[dom];
        u32 src0, div0, div1D, div1P = 0;
        u32 clk0, clk1 = 0;
@@ -290,16 +297,16 @@ calc_clk(struct gk104_clk_priv *priv,
                return 0;
 
        /* first possible path, using only dividers */
-       clk0 = calc_src(priv, clk, freq, &src0, &div0);
-       clk0 = calc_div(priv, clk, clk0, freq, &div1D);
+       clk0 = calc_src(clk, idx, freq, &src0, &div0);
+       clk0 = calc_div(clk, idx, clk0, freq, &div1D);
 
        /* see if we can get any closer using PLLs */
-       if (clk0 != freq && (0x0000ff87 & (1 << clk))) {
-               if (clk <= 7)
-                       clk1 = calc_pll(priv, clk, freq, &info->coef);
+       if (clk0 != freq && (0x0000ff87 & (1 << idx))) {
+               if (idx <= 7)
+                       clk1 = calc_pll(clk, idx, freq, &info->coef);
                else
                        clk1 = cstate->domain[nv_clk_src_hubk06];
-               clk1 = calc_div(priv, clk, clk1, freq, &div1P);
+               clk1 = calc_div(clk, idx, clk1, freq, &div1P);
        }
 
        /* select the method which gets closest to target freq */
@@ -320,7 +327,7 @@ calc_clk(struct gk104_clk_priv *priv,
                        info->mdiv |= 0x80000000;
                        info->mdiv |= div1P << 8;
                }
-               info->ssel = (1 << clk);
+               info->ssel = (1 << idx);
                info->dsrc = 0x40000100;
                info->freq = clk1;
        }
@@ -329,98 +336,115 @@ calc_clk(struct gk104_clk_priv *priv,
 }
 
 static int
-gk104_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate)
+gk104_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate)
 {
-       struct gk104_clk_priv *priv = (void *)clk;
+       struct gk104_clk *clk = gk104_clk(base);
        int ret;
 
-       if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) ||
-           (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) ||
-           (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) ||
-           (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) ||
-           (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) ||
-           (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) ||
-           (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec)))
+       if ((ret = calc_clk(clk, cstate, 0x00, nv_clk_src_gpc)) ||
+           (ret = calc_clk(clk, cstate, 0x01, nv_clk_src_rop)) ||
+           (ret = calc_clk(clk, cstate, 0x02, nv_clk_src_hubk07)) ||
+           (ret = calc_clk(clk, cstate, 0x07, nv_clk_src_hubk06)) ||
+           (ret = calc_clk(clk, cstate, 0x08, nv_clk_src_hubk01)) ||
+           (ret = calc_clk(clk, cstate, 0x0c, nv_clk_src_daemon)) ||
+           (ret = calc_clk(clk, cstate, 0x0e, nv_clk_src_vdec)))
                return ret;
 
        return 0;
 }
 
 static void
-gk104_clk_prog_0(struct gk104_clk_priv *priv, int clk)
+gk104_clk_prog_0(struct gk104_clk *clk, int idx)
 {
-       struct gk104_clk_info *info = &priv->eng[clk];
+       struct gk104_clk_info *info = &clk->eng[idx];
+       struct nvkm_device *device = clk->base.subdev.device;
        if (!info->ssel) {
-               nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x8000003f, info->ddiv);
-               nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc);
+               nvkm_mask(device, 0x1371d0 + (idx * 0x04), 0x8000003f, info->ddiv);
+               nvkm_wr32(device, 0x137160 + (idx * 0x04), info->dsrc);
        }
 }
 
 static void
-gk104_clk_prog_1_0(struct gk104_clk_priv *priv, int clk)
+gk104_clk_prog_1_0(struct gk104_clk *clk, int idx)
 {
-       nv_mask(priv, 0x137100, (1 << clk), 0x00000000);
-       nv_wait(priv, 0x137100, (1 << clk), 0x00000000);
+       struct nvkm_device *device = clk->base.subdev.device;
+       nvkm_mask(device, 0x137100, (1 << idx), 0x00000000);
+       nvkm_msec(device, 2000,
+               if (!(nvkm_rd32(device, 0x137100) & (1 << idx)))
+                       break;
+       );
 }
 
 static void
-gk104_clk_prog_1_1(struct gk104_clk_priv *priv, int clk)
+gk104_clk_prog_1_1(struct gk104_clk *clk, int idx)
 {
-       nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000000);
+       struct nvkm_device *device = clk->base.subdev.device;
+       nvkm_mask(device, 0x137160 + (idx * 0x04), 0x00000100, 0x00000000);
 }
 
 static void
-gk104_clk_prog_2(struct gk104_clk_priv *priv, int clk)
+gk104_clk_prog_2(struct gk104_clk *clk, int idx)
 {
-       struct gk104_clk_info *info = &priv->eng[clk];
-       const u32 addr = 0x137000 + (clk * 0x20);
-       nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000);
-       nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000);
+       struct gk104_clk_info *info = &clk->eng[idx];
+       struct nvkm_device *device = clk->base.subdev.device;
+       const u32 addr = 0x137000 + (idx * 0x20);
+       nvkm_mask(device, addr + 0x00, 0x00000004, 0x00000000);
+       nvkm_mask(device, addr + 0x00, 0x00000001, 0x00000000);
        if (info->coef) {
-               nv_wr32(priv, addr + 0x04, info->coef);
-               nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001);
-               nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000);
-               nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004);
+               nvkm_wr32(device, addr + 0x04, info->coef);
+               nvkm_mask(device, addr + 0x00, 0x00000001, 0x00000001);
+               nvkm_msec(device, 2000,
+                       if (nvkm_rd32(device, addr + 0x00) & 0x00020000)
+                               break;
+               );
+               nvkm_mask(device, addr + 0x00, 0x00020004, 0x00000004);
        }
 }
 
 static void
-gk104_clk_prog_3(struct gk104_clk_priv *priv, int clk)
+gk104_clk_prog_3(struct gk104_clk *clk, int idx)
 {
-       struct gk104_clk_info *info = &priv->eng[clk];
+       struct gk104_clk_info *info = &clk->eng[idx];
+       struct nvkm_device *device = clk->base.subdev.device;
        if (info->ssel)
-               nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f00, info->mdiv);
+               nvkm_mask(device, 0x137250 + (idx * 0x04), 0x00003f00, info->mdiv);
        else
-               nv_mask(priv, 0x137250 + (clk * 0x04), 0x0000003f, info->mdiv);
+               nvkm_mask(device, 0x137250 + (idx * 0x04), 0x0000003f, info->mdiv);
 }
 
 static void
-gk104_clk_prog_4_0(struct gk104_clk_priv *priv, int clk)
+gk104_clk_prog_4_0(struct gk104_clk *clk, int idx)
 {
-       struct gk104_clk_info *info = &priv->eng[clk];
+       struct gk104_clk_info *info = &clk->eng[idx];
+       struct nvkm_device *device = clk->base.subdev.device;
        if (info->ssel) {
-               nv_mask(priv, 0x137100, (1 << clk), info->ssel);
-               nv_wait(priv, 0x137100, (1 << clk), info->ssel);
+               nvkm_mask(device, 0x137100, (1 << idx), info->ssel);
+               nvkm_msec(device, 2000,
+                       u32 tmp = nvkm_rd32(device, 0x137100) & (1 << idx);
+                       if (tmp == info->ssel)
+                               break;
+               );
        }
 }
 
 static void
-gk104_clk_prog_4_1(struct gk104_clk_priv *priv, int clk)
+gk104_clk_prog_4_1(struct gk104_clk *clk, int idx)
 {
-       struct gk104_clk_info *info = &priv->eng[clk];
+       struct gk104_clk_info *info = &clk->eng[idx];
+       struct nvkm_device *device = clk->base.subdev.device;
        if (info->ssel) {
-               nv_mask(priv, 0x137160 + (clk * 0x04), 0x40000000, 0x40000000);
-               nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000100);
+               nvkm_mask(device, 0x137160 + (idx * 0x04), 0x40000000, 0x40000000);
+               nvkm_mask(device, 0x137160 + (idx * 0x04), 0x00000100, 0x00000100);
        }
 }
 
 static int
-gk104_clk_prog(struct nvkm_clk *clk)
+gk104_clk_prog(struct nvkm_clk *base)
 {
-       struct gk104_clk_priv *priv = (void *)clk;
+       struct gk104_clk *clk = gk104_clk(base);
        struct {
                u32 mask;
-               void (*exec)(struct gk104_clk_priv *, int);
+               void (*exec)(struct gk104_clk *, int);
        } stage[] = {
                { 0x007f, gk104_clk_prog_0   }, /* div programming */
                { 0x007f, gk104_clk_prog_1_0 }, /* select div mode */
@@ -433,12 +457,12 @@ gk104_clk_prog(struct nvkm_clk *clk)
        int i, j;
 
        for (i = 0; i < ARRAY_SIZE(stage); i++) {
-               for (j = 0; j < ARRAY_SIZE(priv->eng); j++) {
+               for (j = 0; j < ARRAY_SIZE(clk->eng); j++) {
                        if (!(stage[i].mask & (1 << j)))
                                continue;
-                       if (!priv->eng[j].freq)
+                       if (!clk->eng[j].freq)
                                continue;
-                       stage[i].exec(priv, j);
+                       stage[i].exec(clk, j);
                }
        }
 
@@ -446,55 +470,41 @@ gk104_clk_prog(struct nvkm_clk *clk)
 }
 
 static void
-gk104_clk_tidy(struct nvkm_clk *clk)
+gk104_clk_tidy(struct nvkm_clk *base)
 {
-       struct gk104_clk_priv *priv = (void *)clk;
-       memset(priv->eng, 0x00, sizeof(priv->eng));
+       struct gk104_clk *clk = gk104_clk(base);
+       memset(clk->eng, 0x00, sizeof(clk->eng));
 }
 
-static struct nvkm_domain
-gk104_domain[] = {
-       { nv_clk_src_crystal, 0xff },
-       { nv_clk_src_href   , 0xff },
-       { nv_clk_src_gpc    , 0x00, NVKM_CLK_DOM_FLAG_CORE, "core", 2000 },
-       { nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE },
-       { nv_clk_src_rop    , 0x02, NVKM_CLK_DOM_FLAG_CORE },
-       { nv_clk_src_mem    , 0x03, 0, "memory", 500 },
-       { nv_clk_src_hubk06 , 0x04, NVKM_CLK_DOM_FLAG_CORE },
-       { nv_clk_src_hubk01 , 0x05 },
-       { nv_clk_src_vdec   , 0x06 },
-       { nv_clk_src_daemon , 0x07 },
-       { nv_clk_src_max }
+static const struct nvkm_clk_func
+gk104_clk = {
+       .read = gk104_clk_read,
+       .calc = gk104_clk_calc,
+       .prog = gk104_clk_prog,
+       .tidy = gk104_clk_tidy,
+       .domains = {
+               { nv_clk_src_crystal, 0xff },
+               { nv_clk_src_href   , 0xff },
+               { nv_clk_src_gpc    , 0x00, NVKM_CLK_DOM_FLAG_CORE, "core", 2000 },
+               { nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE },
+               { nv_clk_src_rop    , 0x02, NVKM_CLK_DOM_FLAG_CORE },
+               { nv_clk_src_mem    , 0x03, 0, "memory", 500 },
+               { nv_clk_src_hubk06 , 0x04, NVKM_CLK_DOM_FLAG_CORE },
+               { nv_clk_src_hubk01 , 0x05 },
+               { nv_clk_src_vdec   , 0x06 },
+               { nv_clk_src_daemon , 0x07 },
+               { nv_clk_src_max }
+       }
 };
 
-static int
-gk104_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-              struct nvkm_oclass *oclass, void *data, u32 size,
-              struct nvkm_object **pobject)
+int
+gk104_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk)
 {
-       struct gk104_clk_priv *priv;
-       int ret;
+       struct gk104_clk *clk;
 
-       ret = nvkm_clk_create(parent, engine, oclass, gk104_domain,
-                             NULL, 0, true, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
+       if (!(clk = kzalloc(sizeof(*clk), GFP_KERNEL)))
+               return -ENOMEM;
+       *pclk = &clk->base;
 
-       priv->base.read = gk104_clk_read;
-       priv->base.calc = gk104_clk_calc;
-       priv->base.prog = gk104_clk_prog;
-       priv->base.tidy = gk104_clk_tidy;
-       return 0;
+       return nvkm_clk_ctor(&gk104_clk, device, index, true, &clk->base);
 }
-
-struct nvkm_oclass
-gk104_clk_oclass = {
-       .handle = NV_SUBDEV(CLK, 0xe0),
-       .ofuncs = &(struct nvkm_ofuncs) {
-               .ctor = gk104_clk_ctor,
-               .dtor = _nvkm_clk_dtor,
-               .init = _nvkm_clk_init,
-               .fini = _nvkm_clk_fini,
-       },
-};