These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / nouveau / nvkm / subdev / fb / ramgk104.c
index 1ef15c3..9df4503 100644 (file)
  *
  * Authors: Ben Skeggs
  */
+#define gk104_ram(p) container_of((p), struct gk104_ram, base)
+#include "ram.h"
 #include "ramfuc.h"
-#include "gf100.h"
 
-#include <core/device.h>
 #include <core/option.h>
 #include <subdev/bios.h>
 #include <subdev/bios/init.h>
@@ -229,8 +229,9 @@ static void
 gk104_ram_nuts(struct gk104_ram *ram, struct ramfuc_reg *reg,
               u32 _mask, u32 _data, u32 _copy)
 {
-       struct gk104_fb_priv *priv = (void *)nvkm_fb(ram);
+       struct nvkm_fb *fb = ram->base.fb;
        struct ramfuc *fuc = &ram->fuc.base;
+       struct nvkm_device *device = fb->subdev.device;
        u32 addr = 0x110000 + (reg->addr & 0xfff);
        u32 mask = _mask | _copy;
        u32 data = (_data & _mask) | (reg->data & _copy);
@@ -238,7 +239,7 @@ gk104_ram_nuts(struct gk104_ram *ram, struct ramfuc_reg *reg,
 
        for (i = 0; i < 16; i++, addr += 0x1000) {
                if (ram->pnuts & (1 << i)) {
-                       u32 prev = nv_rd32(priv, addr);
+                       u32 prev = nvkm_rd32(device, addr);
                        u32 next = (prev & ~mask) | data;
                        nvkm_memx_wr32(fuc->memx, addr, next);
                }
@@ -248,9 +249,8 @@ gk104_ram_nuts(struct gk104_ram *ram, struct ramfuc_reg *reg,
        gk104_ram_nuts((s), &(s)->fuc.r_##r, (m), (d), (c))
 
 static int
-gk104_ram_calc_gddr5(struct nvkm_fb *pfb, u32 freq)
+gk104_ram_calc_gddr5(struct gk104_ram *ram, u32 freq)
 {
-       struct gk104_ram *ram = (void *)pfb->ram;
        struct gk104_ramfuc *fuc = &ram->fuc;
        struct nvkm_ram_data *next = ram->base.next;
        int vc = !next->bios.ramcfg_11_02_08;
@@ -673,10 +673,28 @@ gk104_ram_calc_gddr5(struct nvkm_fb *pfb, u32 freq)
  * DDR3
  ******************************************************************************/
 
+static void
+nvkm_sddr3_dll_reset(struct gk104_ramfuc *fuc)
+{
+       ram_nuke(fuc, mr[0]);
+       ram_mask(fuc, mr[0], 0x100, 0x100);
+       ram_mask(fuc, mr[0], 0x100, 0x000);
+}
+
+static void
+nvkm_sddr3_dll_disable(struct gk104_ramfuc *fuc)
+{
+       u32 mr1_old = ram_rd32(fuc, mr[1]);
+
+       if (!(mr1_old & 0x1)) {
+               ram_mask(fuc, mr[1], 0x1, 0x1);
+               ram_nsec(fuc, 1000);
+       }
+}
+
 static int
-gk104_ram_calc_sddr3(struct nvkm_fb *pfb, u32 freq)
+gk104_ram_calc_sddr3(struct gk104_ram *ram, u32 freq)
 {
-       struct gk104_ram *ram = (void *)pfb->ram;
        struct gk104_ramfuc *fuc = &ram->fuc;
        const u32 rcoef = ((  ram->P1 << 16) | (ram->N1 << 8) | ram->M1);
        const u32 runk0 = ram->fN1 << 16;
@@ -703,6 +721,10 @@ gk104_ram_calc_sddr3(struct nvkm_fb *pfb, u32 freq)
                ram_mask(fuc, 0x10f808, 0x04000000, 0x04000000);
 
        ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
+
+       if (next->bios.ramcfg_DLLoff)
+               nvkm_sddr3_dll_disable(fuc);
+
        ram_wr32(fuc, 0x10f210, 0x00000000); /* REFRESH_AUTO = 0 */
        ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
        ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
@@ -880,17 +902,20 @@ gk104_ram_calc_sddr3(struct nvkm_fb *pfb, u32 freq)
        ram_wr32(fuc, 0x10f210, 0x80000000); /* REFRESH_AUTO = 1 */
        ram_nsec(fuc, 1000);
 
-       ram_nuke(fuc, mr[0]);
-       ram_mask(fuc, mr[0], 0x100, 0x100);
-       ram_mask(fuc, mr[0], 0x100, 0x000);
+       if (!next->bios.ramcfg_DLLoff) {
+               ram_mask(fuc, mr[1], 0x1, 0x0);
+               nvkm_sddr3_dll_reset(fuc);
+       }
 
-       ram_mask(fuc, mr[2], 0xfff, ram->base.mr[2]);
+       ram_mask(fuc, mr[2], 0x00000fff, ram->base.mr[2]);
+       ram_mask(fuc, mr[1], 0xffffffff, ram->base.mr[1]);
        ram_wr32(fuc, mr[0], ram->base.mr[0]);
        ram_nsec(fuc, 1000);
 
-       ram_nuke(fuc, mr[0]);
-       ram_mask(fuc, mr[0], 0x100, 0x100);
-       ram_mask(fuc, mr[0], 0x100, 0x000);
+       if (!next->bios.ramcfg_DLLoff) {
+               nvkm_sddr3_dll_reset(fuc);
+               ram_nsec(fuc, 1000);
+       }
 
        if (vc == 0 && ram_have(fuc, gpio2E)) {
                u32 temp  = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[0]);
@@ -926,9 +951,9 @@ gk104_ram_calc_sddr3(struct nvkm_fb *pfb, u32 freq)
  ******************************************************************************/
 
 static int
-gk104_ram_calc_data(struct nvkm_fb *pfb, u32 khz, struct nvkm_ram_data *data)
+gk104_ram_calc_data(struct gk104_ram *ram, u32 khz, struct nvkm_ram_data *data)
 {
-       struct gk104_ram *ram = (void *)pfb->ram;
+       struct nvkm_subdev *subdev = &ram->base.fb->subdev;
        struct nvkm_ram_data *cfg;
        u32 mhz = khz / 1000;
 
@@ -941,19 +966,80 @@ gk104_ram_calc_data(struct nvkm_fb *pfb, u32 khz, struct nvkm_ram_data *data)
                }
        }
 
-       nv_error(ram, "ramcfg data for %dMHz not found\n", mhz);
+       nvkm_error(subdev, "ramcfg data for %dMHz not found\n", mhz);
        return -EINVAL;
 }
 
 static int
-gk104_ram_calc_xits(struct nvkm_fb *pfb, struct nvkm_ram_data *next)
+gk104_calc_pll_output(int fN, int M, int N, int P, int clk)
+{
+       return ((clk * N) + (((u16)(fN + 4096) * clk) >> 13)) / (M * P);
+}
+
+static int
+gk104_pll_calc_hiclk(int target_khz, int crystal,
+               int *N1, int *fN1, int *M1, int *P1,
+               int *N2, int *M2, int *P2)
+{
+       int best_clk = 0, best_err = target_khz, p_ref, n_ref;
+       bool upper = false;
+
+       *M1 = 1;
+       /* M has to be 1, otherwise it gets unstable */
+       *M2 = 1;
+       /* can be 1 or 2, sticking with 1 for simplicity */
+       *P2 = 1;
+
+       for (p_ref = 0x7; p_ref >= 0x5; --p_ref) {
+               for (n_ref = 0x25; n_ref <= 0x2b; ++n_ref) {
+                       int cur_N, cur_clk, cur_err;
+
+                       cur_clk = gk104_calc_pll_output(0, 1, n_ref, p_ref, crystal);
+                       cur_N = target_khz / cur_clk;
+                       cur_err = target_khz
+                               - gk104_calc_pll_output(0xf000, 1, cur_N, 1, cur_clk);
+
+                       /* we found a better combination */
+                       if (cur_err < best_err) {
+                               best_err = cur_err;
+                               best_clk = cur_clk;
+                               *N2 = cur_N;
+                               *N1 = n_ref;
+                               *P1 = p_ref;
+                               upper = false;
+                       }
+
+                       cur_N += 1;
+                       cur_err = gk104_calc_pll_output(0xf000, 1, cur_N, 1, cur_clk)
+                               - target_khz;
+                       if (cur_err < best_err) {
+                               best_err = cur_err;
+                               best_clk = cur_clk;
+                               *N2 = cur_N;
+                               *N1 = n_ref;
+                               *P1 = p_ref;
+                               upper = true;
+                       }
+               }
+       }
+
+       /* adjust fN to get closer to the target clock */
+       *fN1 = (u16)((((best_err / *N2 * *P2) * (*P1 * *M1)) << 13) / crystal);
+       if (upper)
+               *fN1 = (u16)(1 - *fN1);
+
+       return gk104_calc_pll_output(*fN1, 1, *N1, *P1, crystal);
+}
+
+static int
+gk104_ram_calc_xits(struct gk104_ram *ram, struct nvkm_ram_data *next)
 {
-       struct gk104_ram *ram = (void *)pfb->ram;
        struct gk104_ramfuc *fuc = &ram->fuc;
+       struct nvkm_subdev *subdev = &ram->base.fb->subdev;
        int refclk, i;
        int ret;
 
-       ret = ram_init(fuc, pfb);
+       ret = ram_init(fuc, ram->base.fb);
        if (ret)
                return ret;
 
@@ -969,31 +1055,24 @@ gk104_ram_calc_xits(struct nvkm_fb *pfb, struct nvkm_ram_data *next)
         * kepler boards, no idea how/why they're chosen.
         */
        refclk = next->freq;
-       if (ram->mode == 2)
-               refclk = fuc->mempll.refclk;
-
-       /* calculate refpll coefficients */
-       ret = gt215_pll_calc(nv_subdev(pfb), &fuc->refpll, refclk, &ram->N1,
-                            &ram->fN1, &ram->M1, &ram->P1);
-       fuc->mempll.refclk = ret;
-       if (ret <= 0) {
-               nv_error(pfb, "unable to calc refpll\n");
-               return -EINVAL;
-       }
-
-       /* calculate mempll coefficients, if we're using it */
        if (ram->mode == 2) {
-               /* post-divider doesn't work... the reg takes the values but
-                * appears to completely ignore it.  there *is* a bit at
-                * bit 28 that appears to divide the clock by 2 if set.
-                */
-               fuc->mempll.min_p = 1;
-               fuc->mempll.max_p = 2;
-
-               ret = gt215_pll_calc(nv_subdev(pfb), &fuc->mempll, next->freq,
-                                    &ram->N2, NULL, &ram->M2, &ram->P2);
+               ret = gk104_pll_calc_hiclk(next->freq, subdev->device->crystal,
+                               &ram->N1, &ram->fN1, &ram->M1, &ram->P1,
+                               &ram->N2, &ram->M2, &ram->P2);
+               fuc->mempll.refclk = ret;
                if (ret <= 0) {
-                       nv_error(pfb, "unable to calc mempll\n");
+                       nvkm_error(subdev, "unable to calc plls\n");
+                       return -EINVAL;
+               }
+               nvkm_debug(subdev, "sucessfully calced PLLs for clock %i kHz"
+                               " (refclock: %i kHz)\n", next->freq, ret);
+       } else {
+               /* calculate refpll coefficients */
+               ret = gt215_pll_calc(subdev, &fuc->refpll, refclk, &ram->N1,
+                                    &ram->fN1, &ram->M1, &ram->P1);
+               fuc->mempll.refclk = ret;
+               if (ret <= 0) {
+                       nvkm_error(subdev, "unable to calc refpll\n");
                        return -EINVAL;
                }
        }
@@ -1005,15 +1084,15 @@ gk104_ram_calc_xits(struct nvkm_fb *pfb, struct nvkm_ram_data *next)
        ram->base.freq = next->freq;
 
        switch (ram->base.type) {
-       case NV_MEM_TYPE_DDR3:
+       case NVKM_RAM_TYPE_DDR3:
                ret = nvkm_sddr3_calc(&ram->base);
                if (ret == 0)
-                       ret = gk104_ram_calc_sddr3(pfb, next->freq);
+                       ret = gk104_ram_calc_sddr3(ram, next->freq);
                break;
-       case NV_MEM_TYPE_GDDR5:
+       case NVKM_RAM_TYPE_GDDR5:
                ret = nvkm_gddr5_calc(&ram->base, ram->pnuts != 0);
                if (ret == 0)
-                       ret = gk104_ram_calc_gddr5(pfb, next->freq);
+                       ret = gk104_ram_calc_gddr5(ram, next->freq);
                break;
        default:
                ret = -ENOSYS;
@@ -1024,21 +1103,22 @@ gk104_ram_calc_xits(struct nvkm_fb *pfb, struct nvkm_ram_data *next)
 }
 
 static int
-gk104_ram_calc(struct nvkm_fb *pfb, u32 freq)
+gk104_ram_calc(struct nvkm_ram *base, u32 freq)
 {
-       struct nvkm_clk *clk = nvkm_clk(pfb);
-       struct gk104_ram *ram = (void *)pfb->ram;
+       struct gk104_ram *ram = gk104_ram(base);
+       struct nvkm_clk *clk = ram->base.fb->subdev.device->clk;
        struct nvkm_ram_data *xits = &ram->base.xition;
        struct nvkm_ram_data *copy;
        int ret;
 
        if (ram->base.next == NULL) {
-               ret = gk104_ram_calc_data(pfb, clk->read(clk, nv_clk_src_mem),
+               ret = gk104_ram_calc_data(ram,
+                                         nvkm_clk_read(clk, nv_clk_src_mem),
                                          &ram->base.former);
                if (ret)
                        return ret;
 
-               ret = gk104_ram_calc_data(pfb, freq, &ram->base.target);
+               ret = gk104_ram_calc_data(ram, freq, &ram->base.target);
                if (ret)
                        return ret;
 
@@ -1062,13 +1142,13 @@ gk104_ram_calc(struct nvkm_fb *pfb, u32 freq)
                ram->base.next = &ram->base.target;
        }
 
-       return gk104_ram_calc_xits(pfb, ram->base.next);
+       return gk104_ram_calc_xits(ram, ram->base.next);
 }
 
 static void
-gk104_ram_prog_0(struct nvkm_fb *pfb, u32 freq)
+gk104_ram_prog_0(struct gk104_ram *ram, u32 freq)
 {
-       struct gk104_ram *ram = (void *)pfb->ram;
+       struct nvkm_device *device = ram->base.fb->subdev.device;
        struct nvkm_ram_data *cfg;
        u32 mhz = freq / 1000;
        u32 mask, data;
@@ -1090,31 +1170,31 @@ gk104_ram_prog_0(struct nvkm_fb *pfb, u32 freq)
                data |= cfg->bios.rammap_11_09_01ff;
                mask |= 0x000001ff;
        }
-       nv_mask(pfb, 0x10f468, mask, data);
+       nvkm_mask(device, 0x10f468, mask, data);
 
        if (mask = 0, data = 0, ram->diff.rammap_11_0a_0400) {
                data |= cfg->bios.rammap_11_0a_0400;
                mask |= 0x00000001;
        }
-       nv_mask(pfb, 0x10f420, mask, data);
+       nvkm_mask(device, 0x10f420, mask, data);
 
        if (mask = 0, data = 0, ram->diff.rammap_11_0a_0800) {
                data |= cfg->bios.rammap_11_0a_0800;
                mask |= 0x00000001;
        }
-       nv_mask(pfb, 0x10f430, mask, data);
+       nvkm_mask(device, 0x10f430, mask, data);
 
        if (mask = 0, data = 0, ram->diff.rammap_11_0b_01f0) {
                data |= cfg->bios.rammap_11_0b_01f0;
                mask |= 0x0000001f;
        }
-       nv_mask(pfb, 0x10f400, mask, data);
+       nvkm_mask(device, 0x10f400, mask, data);
 
        if (mask = 0, data = 0, ram->diff.rammap_11_0b_0200) {
                data |= cfg->bios.rammap_11_0b_0200 << 9;
                mask |= 0x00000200;
        }
-       nv_mask(pfb, 0x10f410, mask, data);
+       nvkm_mask(device, 0x10f410, mask, data);
 
        if (mask = 0, data = 0, ram->diff.rammap_11_0d) {
                data |= cfg->bios.rammap_11_0d << 16;
@@ -1124,7 +1204,7 @@ gk104_ram_prog_0(struct nvkm_fb *pfb, u32 freq)
                data |= cfg->bios.rammap_11_0f << 8;
                mask |= 0x0000ff00;
        }
-       nv_mask(pfb, 0x10f440, mask, data);
+       nvkm_mask(device, 0x10f440, mask, data);
 
        if (mask = 0, data = 0, ram->diff.rammap_11_0e) {
                data |= cfg->bios.rammap_11_0e << 8;
@@ -1138,15 +1218,15 @@ gk104_ram_prog_0(struct nvkm_fb *pfb, u32 freq)
                data |= cfg->bios.rammap_11_0b_0400 << 5;
                mask |= 0x00000020;
        }
-       nv_mask(pfb, 0x10f444, mask, data);
+       nvkm_mask(device, 0x10f444, mask, data);
 }
 
 static int
-gk104_ram_prog(struct nvkm_fb *pfb)
+gk104_ram_prog(struct nvkm_ram *base)
 {
-       struct nvkm_device *device = nv_device(pfb);
-       struct gk104_ram *ram = (void *)pfb->ram;
+       struct gk104_ram *ram = gk104_ram(base);
        struct gk104_ramfuc *fuc = &ram->fuc;
+       struct nvkm_device *device = ram->base.fb->subdev.device;
        struct nvkm_ram_data *next = ram->base.next;
 
        if (!nvkm_boolopt(device->cfgopt, "NvMemExec", true)) {
@@ -1154,20 +1234,19 @@ gk104_ram_prog(struct nvkm_fb *pfb)
                return (ram->base.next == &ram->base.xition);
        }
 
-       gk104_ram_prog_0(pfb, 1000);
+       gk104_ram_prog_0(ram, 1000);
        ram_exec(fuc, true);
-       gk104_ram_prog_0(pfb, next->freq);
+       gk104_ram_prog_0(ram, next->freq);
 
        return (ram->base.next == &ram->base.xition);
 }
 
 static void
-gk104_ram_tidy(struct nvkm_fb *pfb)
+gk104_ram_tidy(struct nvkm_ram *base)
 {
-       struct gk104_ram *ram = (void *)pfb->ram;
-       struct gk104_ramfuc *fuc = &ram->fuc;
+       struct gk104_ram *ram = gk104_ram(base);
        ram->base.next = NULL;
-       ram_exec(fuc, false);
+       ram_exec(&ram->fuc, false);
 }
 
 struct gk104_ram_train {
@@ -1183,10 +1262,10 @@ struct gk104_ram_train {
 };
 
 static int
-gk104_ram_train_type(struct nvkm_fb *pfb, int i, u8 ramcfg,
+gk104_ram_train_type(struct nvkm_ram *ram, int i, u8 ramcfg,
                     struct gk104_ram_train *train)
 {
-       struct nvkm_bios *bios = nvkm_bios(pfb);
+       struct nvkm_bios *bios = ram->fb->subdev.device->bios;
        struct nvbios_M0205E M0205E;
        struct nvbios_M0205S M0205S;
        struct nvbios_M0209E M0209E;
@@ -1244,33 +1323,35 @@ gk104_ram_train_type(struct nvkm_fb *pfb, int i, u8 ramcfg,
 }
 
 static int
-gk104_ram_train_init_0(struct nvkm_fb *pfb, struct gk104_ram_train *train)
+gk104_ram_train_init_0(struct nvkm_ram *ram, struct gk104_ram_train *train)
 {
+       struct nvkm_subdev *subdev = &ram->fb->subdev;
+       struct nvkm_device *device = subdev->device;
        int i, j;
 
        if ((train->mask & 0x03d3) != 0x03d3) {
-               nv_warn(pfb, "missing link training data\n");
+               nvkm_warn(subdev, "missing link training data\n");
                return -EINVAL;
        }
 
        for (i = 0; i < 0x30; i++) {
                for (j = 0; j < 8; j += 4) {
-                       nv_wr32(pfb, 0x10f968 + j, 0x00000000 | (i << 8));
-                       nv_wr32(pfb, 0x10f920 + j, 0x00000000 |
+                       nvkm_wr32(device, 0x10f968 + j, 0x00000000 | (i << 8));
+                       nvkm_wr32(device, 0x10f920 + j, 0x00000000 |
                                                   train->type08.data[i] << 4 |
                                                   train->type06.data[i]);
-                       nv_wr32(pfb, 0x10f918 + j, train->type00.data[i]);
-                       nv_wr32(pfb, 0x10f920 + j, 0x00000100 |
+                       nvkm_wr32(device, 0x10f918 + j, train->type00.data[i]);
+                       nvkm_wr32(device, 0x10f920 + j, 0x00000100 |
                                                   train->type09.data[i] << 4 |
                                                   train->type07.data[i]);
-                       nv_wr32(pfb, 0x10f918 + j, train->type01.data[i]);
+                       nvkm_wr32(device, 0x10f918 + j, train->type01.data[i]);
                }
        }
 
        for (j = 0; j < 8; j += 4) {
                for (i = 0; i < 0x100; i++) {
-                       nv_wr32(pfb, 0x10f968 + j, i);
-                       nv_wr32(pfb, 0x10f900 + j, train->type04.data[i]);
+                       nvkm_wr32(device, 0x10f968 + j, i);
+                       nvkm_wr32(device, 0x10f900 + j, train->type04.data[i]);
                }
        }
 
@@ -1278,23 +1359,24 @@ gk104_ram_train_init_0(struct nvkm_fb *pfb, struct gk104_ram_train *train)
 }
 
 static int
-gk104_ram_train_init(struct nvkm_fb *pfb)
+gk104_ram_train_init(struct nvkm_ram *ram)
 {
-       u8 ramcfg = nvbios_ramcfg_index(nv_subdev(pfb));
+       u8 ramcfg = nvbios_ramcfg_index(&ram->fb->subdev);
        struct gk104_ram_train *train;
-       int ret = -ENOMEM, i;
+       int ret, i;
 
-       if ((train = kzalloc(sizeof(*train), GFP_KERNEL))) {
-               for (i = 0; i < 0x100; i++) {
-                       ret = gk104_ram_train_type(pfb, i, ramcfg, train);
-                       if (ret && ret != -ENOENT)
-                               break;
-               }
+       if (!(train = kzalloc(sizeof(*train), GFP_KERNEL)))
+               return -ENOMEM;
+
+       for (i = 0; i < 0x100; i++) {
+               ret = gk104_ram_train_type(ram, i, ramcfg, train);
+               if (ret && ret != -ENOENT)
+                       break;
        }
 
-       switch (pfb->ram->type) {
-       case NV_MEM_TYPE_GDDR5:
-               ret = gk104_ram_train_init_0(pfb, train);
+       switch (ram->type) {
+       case NVKM_RAM_TYPE_GDDR5:
+               ret = gk104_ram_train_init_0(ram, train);
                break;
        default:
                ret = 0;
@@ -1306,18 +1388,14 @@ gk104_ram_train_init(struct nvkm_fb *pfb)
 }
 
 int
-gk104_ram_init(struct nvkm_object *object)
+gk104_ram_init(struct nvkm_ram *ram)
 {
-       struct nvkm_fb *pfb = (void *)object->parent;
-       struct gk104_ram *ram   = (void *)object;
-       struct nvkm_bios *bios = nvkm_bios(pfb);
+       struct nvkm_subdev *subdev = &ram->fb->subdev;
+       struct nvkm_device *device = subdev->device;
+       struct nvkm_bios *bios = device->bios;
        u8  ver, hdr, cnt, len, snr, ssz;
        u32 data, save;
-       int ret, i;
-
-       ret = nvkm_ram_init(&ram->base);
-       if (ret)
-               return ret;
+       int i;
 
        /* run a bunch of tables from rammap table.  there's actually
         * individual pointers for each rammap entry too, but, nvidia
@@ -1334,33 +1412,32 @@ gk104_ram_init(struct nvkm_object *object)
        if (!data || hdr < 0x15)
                return -EINVAL;
 
-       cnt  = nv_ro08(bios, data + 0x14); /* guess at count */
-       data = nv_ro32(bios, data + 0x10); /* guess u32... */
-       save = nv_rd32(pfb, 0x10f65c) & 0x000000f0;
+       cnt  = nvbios_rd08(bios, data + 0x14); /* guess at count */
+       data = nvbios_rd32(bios, data + 0x10); /* guess u32... */
+       save = nvkm_rd32(device, 0x10f65c) & 0x000000f0;
        for (i = 0; i < cnt; i++, data += 4) {
                if (i != save >> 4) {
-                       nv_mask(pfb, 0x10f65c, 0x000000f0, i << 4);
+                       nvkm_mask(device, 0x10f65c, 0x000000f0, i << 4);
                        nvbios_exec(&(struct nvbios_init) {
-                                       .subdev = nv_subdev(pfb),
+                                       .subdev = subdev,
                                        .bios = bios,
-                                       .offset = nv_ro32(bios, data),
+                                       .offset = nvbios_rd32(bios, data),
                                        .execute = 1,
                                    });
                }
        }
-       nv_mask(pfb, 0x10f65c, 0x000000f0, save);
-       nv_mask(pfb, 0x10f584, 0x11000000, 0x00000000);
-       nv_wr32(pfb, 0x10ecc0, 0xffffffff);
-       nv_mask(pfb, 0x10f160, 0x00000010, 0x00000010);
+       nvkm_mask(device, 0x10f65c, 0x000000f0, save);
+       nvkm_mask(device, 0x10f584, 0x11000000, 0x00000000);
+       nvkm_wr32(device, 0x10ecc0, 0xffffffff);
+       nvkm_mask(device, 0x10f160, 0x00000010, 0x00000010);
 
-       return gk104_ram_train_init(pfb);
+       return gk104_ram_train_init(ram);
 }
 
 static int
 gk104_ram_ctor_data(struct gk104_ram *ram, u8 ramcfg, int i)
 {
-       struct nvkm_fb *pfb = (void *)nv_object(ram)->parent;
-       struct nvkm_bios *bios = nvkm_bios(pfb);
+       struct nvkm_bios *bios = ram->base.fb->subdev.device->bios;
        struct nvkm_ram_data *cfg;
        struct nvbios_ramcfg *d = &ram->diff;
        struct nvbios_ramcfg *p, *n;
@@ -1426,63 +1503,64 @@ done:
        return ret;
 }
 
-static void
-gk104_ram_dtor(struct nvkm_object *object)
+static void *
+gk104_ram_dtor(struct nvkm_ram *base)
 {
-       struct gk104_ram *ram = (void *)object;
+       struct gk104_ram *ram = gk104_ram(base);
        struct nvkm_ram_data *cfg, *tmp;
 
        list_for_each_entry_safe(cfg, tmp, &ram->cfg, head) {
                kfree(cfg);
        }
 
-       nvkm_ram_destroy(&ram->base);
+       return ram;
 }
 
-static int
-gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-              struct nvkm_oclass *oclass, void *data, u32 size,
-              struct nvkm_object **pobject)
+static const struct nvkm_ram_func
+gk104_ram_func = {
+       .dtor = gk104_ram_dtor,
+       .init = gk104_ram_init,
+       .get = gf100_ram_get,
+       .put = gf100_ram_put,
+       .calc = gk104_ram_calc,
+       .prog = gk104_ram_prog,
+       .tidy = gk104_ram_tidy,
+};
+
+int
+gk104_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
 {
-       struct nvkm_fb *pfb = nvkm_fb(parent);
-       struct nvkm_bios *bios = nvkm_bios(pfb);
-       struct nvkm_gpio *gpio = nvkm_gpio(pfb);
+       struct nvkm_subdev *subdev = &fb->subdev;
+       struct nvkm_device *device = subdev->device;
+       struct nvkm_bios *bios = device->bios;
+       struct nvkm_gpio *gpio = device->gpio;
        struct dcb_gpio_func func;
        struct gk104_ram *ram;
        int ret, i;
-       u8  ramcfg = nvbios_ramcfg_index(nv_subdev(pfb));
+       u8  ramcfg = nvbios_ramcfg_index(subdev);
        u32 tmp;
 
-       ret = gf100_ram_create(parent, engine, oclass, 0x022554, &ram);
-       *pobject = nv_object(ram);
+       if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL)))
+               return -ENOMEM;
+       *pram = &ram->base;
+
+       ret = gf100_ram_ctor(&gk104_ram_func, fb, 0x022554, &ram->base);
        if (ret)
                return ret;
 
        INIT_LIST_HEAD(&ram->cfg);
 
-       switch (ram->base.type) {
-       case NV_MEM_TYPE_DDR3:
-       case NV_MEM_TYPE_GDDR5:
-               ram->base.calc = gk104_ram_calc;
-               ram->base.prog = gk104_ram_prog;
-               ram->base.tidy = gk104_ram_tidy;
-               break;
-       default:
-               nv_warn(pfb, "reclocking of this RAM type is unsupported\n");
-               break;
-       }
-
        /* calculate a mask of differently configured memory partitions,
         * because, of course reclocking wasn't complicated enough
         * already without having to treat some of them differently to
         * the others....
         */
-       ram->parts = nv_rd32(pfb, 0x022438);
-       ram->pmask = nv_rd32(pfb, 0x022554);
+       ram->parts = nvkm_rd32(device, 0x022438);
+       ram->pmask = nvkm_rd32(device, 0x022554);
        ram->pnuts = 0;
        for (i = 0, tmp = 0; i < ram->parts; i++) {
                if (!(ram->pmask & (1 << i))) {
-                       u32 cfg1 = nv_rd32(pfb, 0x110204 + (i * 0x1000));
+                       u32 cfg1 = nvkm_rd32(device, 0x110204 + (i * 0x1000));
                        if (tmp && tmp != cfg1) {
                                ram->pnuts |= (1 << i);
                                continue;
@@ -1505,7 +1583,7 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
        for (i = 0; !ret; i++) {
                ret = gk104_ram_ctor_data(ram, ramcfg, i);
                if (ret && ret != -ENOENT) {
-                       nv_error(pfb, "failed to parse ramcfg data\n");
+                       nvkm_error(subdev, "failed to parse ramcfg data\n");
                        return ret;
                }
        }
@@ -1513,25 +1591,25 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
        /* parse bios data for both pll's */
        ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll);
        if (ret) {
-               nv_error(pfb, "mclk refpll data not found\n");
+               nvkm_error(subdev, "mclk refpll data not found\n");
                return ret;
        }
 
        ret = nvbios_pll_parse(bios, 0x04, &ram->fuc.mempll);
        if (ret) {
-               nv_error(pfb, "mclk pll data not found\n");
+               nvkm_error(subdev, "mclk pll data not found\n");
                return ret;
        }
 
        /* lookup memory voltage gpios */
-       ret = gpio->find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func);
+       ret = nvkm_gpio_find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func);
        if (ret == 0) {
                ram->fuc.r_gpioMV = ramfuc_reg(0x00d610 + (func.line * 0x04));
                ram->fuc.r_funcMV[0] = (func.log[0] ^ 2) << 12;
                ram->fuc.r_funcMV[1] = (func.log[1] ^ 2) << 12;
        }
 
-       ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
+       ret = nvkm_gpio_find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
        if (ret == 0) {
                ram->fuc.r_gpio2E = ramfuc_reg(0x00d610 + (func.line * 0x04));
                ram->fuc.r_func2E[0] = (func.log[0] ^ 2) << 12;
@@ -1588,7 +1666,7 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
        ram->fuc.r_0x10f914 = ramfuc_reg(0x10f914);
 
        switch (ram->base.type) {
-       case NV_MEM_TYPE_GDDR5:
+       case NVKM_RAM_TYPE_GDDR5:
                ram->fuc.r_mr[0] = ramfuc_reg(0x10f300);
                ram->fuc.r_mr[1] = ramfuc_reg(0x10f330);
                ram->fuc.r_mr[2] = ramfuc_reg(0x10f334);
@@ -1600,8 +1678,9 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
                ram->fuc.r_mr[8] = ramfuc_reg(0x10f354);
                ram->fuc.r_mr[15] = ramfuc_reg(0x10f34c);
                break;
-       case NV_MEM_TYPE_DDR3:
+       case NVKM_RAM_TYPE_DDR3:
                ram->fuc.r_mr[0] = ramfuc_reg(0x10f300);
+               ram->fuc.r_mr[1] = ramfuc_reg(0x10f304);
                ram->fuc.r_mr[2] = ramfuc_reg(0x10f320);
                break;
        default:
@@ -1626,14 +1705,3 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
        ram->fuc.r_0x100750 = ramfuc_reg(0x100750);
        return 0;
 }
-
-struct nvkm_oclass
-gk104_ram_oclass = {
-       .handle = 0,
-       .ofuncs = &(struct nvkm_ofuncs) {
-               .ctor = gk104_ram_ctor,
-               .dtor = gk104_ram_dtor,
-               .init = gk104_ram_init,
-               .fini = _nvkm_ram_fini,
-       }
-};