drm/nouveau/fb/ram: Support strided regs
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / nouveau / core / subdev / fb / ramnve0.c
index afde4c1d6a4b0409fbea7190f5a3c1185e62dd1f..6bae474abb4476ed46510b74000c68b457e817f4 100644 (file)
@@ -237,7 +237,7 @@ nve0_ram_nuts(struct nve0_ram *ram, struct ramfuc_reg *reg,
 {
        struct nve0_fb_priv *priv = (void *)nouveau_fb(ram);
        struct ramfuc *fuc = &ram->fuc.base;
-       u32 addr = 0x110000 + (reg->addr[0] & 0xfff);
+       u32 addr = 0x110000 + (reg->addr & 0xfff);
        u32 mask = _mask | _copy;
        u32 data = (_data & _mask) | (reg->data & _copy);
        u32 i;
@@ -264,6 +264,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
        u32 mask, data;
 
        ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
+       ram_block(fuc);
        ram_wr32(fuc, 0x62c000, 0x0f0f0000);
 
        /* MR1: turn termination on early, for some reason.. */
@@ -662,6 +663,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
        if (next->bios.ramcfg_11_07_02)
                nve0_ram_train(fuc, 0x80020000, 0x01000000);
 
+       ram_unblock(fuc);
        ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
 
        if (next->bios.rammap_11_08_01)
@@ -691,6 +693,7 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
        u32 mask, data;
 
        ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
+       ram_block(fuc);
        ram_wr32(fuc, 0x62c000, 0x0f0f0000);
 
        if (vc == 1 && ram_have(fuc, gpio2E)) {
@@ -913,6 +916,7 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
        ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
        ram_nsec(fuc, 1000);
 
+       ram_unblock(fuc);
        ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
 
        if (next->bios.rammap_11_08_01)
@@ -960,8 +964,6 @@ nve0_ram_calc_xits(struct nouveau_fb *pfb, struct nouveau_ram_data *next)
        if (ret)
                return ret;
 
-       ram_fb_disable(fuc);
-
        ram->mode = (next->freq > fuc->refpll.vco1.max_freq) ? 2 : 1;
        ram->from = ram_rd32(fuc, 0x1373f4) & 0x0000000f;
 
@@ -1025,9 +1027,6 @@ nve0_ram_calc_xits(struct nouveau_fb *pfb, struct nouveau_ram_data *next)
                break;
        }
 
-       if (!ret)
-               ram_fb_enable(fuc);
-
        return ret;
 }
 
@@ -1073,13 +1072,99 @@ nve0_ram_calc(struct nouveau_fb *pfb, u32 freq)
        return nve0_ram_calc_xits(pfb, ram->base.next);
 }
 
+static void
+nve0_ram_prog_0(struct nouveau_fb *pfb, u32 freq)
+{
+       struct nve0_ram *ram = (void *)pfb->ram;
+       struct nouveau_ram_data *cfg;
+       u32 mhz = freq / 1000;
+       u32 mask, data;
+
+       list_for_each_entry(cfg, &ram->cfg, head) {
+               if (mhz >= cfg->bios.rammap_min &&
+                   mhz <= cfg->bios.rammap_max)
+                       break;
+       }
+
+       if (&cfg->head == &ram->cfg)
+               return;
+
+       if (mask = 0, data = 0, ram->diff.rammap_11_0a_03fe) {
+               data |= cfg->bios.rammap_11_0a_03fe << 12;
+               mask |= 0x001ff000;
+       }
+       if (ram->diff.rammap_11_09_01ff) {
+               data |= cfg->bios.rammap_11_09_01ff;
+               mask |= 0x000001ff;
+       }
+       nv_mask(pfb, 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);
+
+       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);
+
+       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);
+
+       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);
+
+       if (mask = 0, data = 0, ram->diff.rammap_11_0d) {
+               data |= cfg->bios.rammap_11_0d << 16;
+               mask |= 0x00ff0000;
+       }
+       if (ram->diff.rammap_11_0f) {
+               data |= cfg->bios.rammap_11_0f << 8;
+               mask |= 0x0000ff00;
+       }
+       nv_mask(pfb, 0x10f440, mask, data);
+
+       if (mask = 0, data = 0, ram->diff.rammap_11_0e) {
+               data |= cfg->bios.rammap_11_0e << 8;
+               mask |= 0x0000ff00;
+       }
+       if (ram->diff.rammap_11_0b_0800) {
+               data |= cfg->bios.rammap_11_0b_0800 << 7;
+               mask |= 0x00000080;
+       }
+       if (ram->diff.rammap_11_0b_0400) {
+               data |= cfg->bios.rammap_11_0b_0400 << 5;
+               mask |= 0x00000020;
+       }
+       nv_mask(pfb, 0x10f444, mask, data);
+}
+
 static int
 nve0_ram_prog(struct nouveau_fb *pfb)
 {
        struct nouveau_device *device = nv_device(pfb);
        struct nve0_ram *ram = (void *)pfb->ram;
        struct nve0_ramfuc *fuc = &ram->fuc;
-       ram_exec(fuc, nouveau_boolopt(device->cfgopt, "NvMemExec", true));
+       struct nouveau_ram_data *next = ram->base.next;
+
+       if (!nouveau_boolopt(device->cfgopt, "NvMemExec", true)) {
+               ram_exec(fuc, false);
+               return (ram->base.next == &ram->base.xition);
+       }
+
+       nve0_ram_prog_0(pfb, 1000);
+       ram_exec(fuc, true);
+       nve0_ram_prog_0(pfb, next->freq);
+
        return (ram->base.next == &ram->base.xition);
 }
 
@@ -1325,6 +1410,17 @@ nve0_ram_ctor_data(struct nve0_ram *ram, u8 ramcfg, int i)
        if (ret = 0, i == 0)
                goto done;
 
+       d->rammap_11_0a_03fe |= p->rammap_11_0a_03fe != n->rammap_11_0a_03fe;
+       d->rammap_11_09_01ff |= p->rammap_11_09_01ff != n->rammap_11_09_01ff;
+       d->rammap_11_0a_0400 |= p->rammap_11_0a_0400 != n->rammap_11_0a_0400;
+       d->rammap_11_0a_0800 |= p->rammap_11_0a_0800 != n->rammap_11_0a_0800;
+       d->rammap_11_0b_01f0 |= p->rammap_11_0b_01f0 != n->rammap_11_0b_01f0;
+       d->rammap_11_0b_0200 |= p->rammap_11_0b_0200 != n->rammap_11_0b_0200;
+       d->rammap_11_0d |= p->rammap_11_0d != n->rammap_11_0d;
+       d->rammap_11_0f |= p->rammap_11_0f != n->rammap_11_0f;
+       d->rammap_11_0e |= p->rammap_11_0e != n->rammap_11_0e;
+       d->rammap_11_0b_0800 |= p->rammap_11_0b_0800 != n->rammap_11_0b_0800;
+       d->rammap_11_0b_0400 |= p->rammap_11_0b_0400 != n->rammap_11_0b_0400;
        d->ramcfg_11_01_01 |= p->ramcfg_11_01_01 != n->ramcfg_11_01_01;
        d->ramcfg_11_01_02 |= p->ramcfg_11_01_02 != n->ramcfg_11_01_02;
        d->ramcfg_11_01_10 |= p->ramcfg_11_01_10 != n->ramcfg_11_01_10;