drm/nouveau/pm: calculate memory timings at perflvl creation time
authorBen Skeggs <bskeggs@redhat.com>
Tue, 17 Jan 2012 11:10:58 +0000 (21:10 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 13 Mar 2012 07:08:03 +0000 (17:08 +1000)
Statically generating the PFB register and MR values for each timing set
turns out to be insufficient.  There's at least one (so far) known piece
of information which effects MR values which is stored in the perflvl
entry on some chipsets (and in another table on later ones), which is
disconnected from the timing table entries.

After this change we will generate a timing set based on an input clock
frequency instead, and have this data stored in the performance level
data.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Signed-off-by: Martin Peres <martin.peres@labri.fr>
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_mem.c
drivers/gpu/drm/nouveau/nouveau_perf.c
drivers/gpu/drm/nouveau/nouveau_pm.c
drivers/gpu/drm/nouveau/nouveau_pm.h

index f5700418da3f2ef8113506aa17c7de2fe3626278..a8344c321ab510f2b2f8771a4f40aa2a568074b8 100644 (file)
@@ -526,14 +526,6 @@ struct nouveau_pm_threshold_temp {
        s16 fan_boost;
 };
 
-struct nouveau_pm_memtimings {
-       bool supported;
-       struct nouveau_pm_memtiming boot;
-       struct nouveau_pm_memtiming *timing;
-       int nr_timing;
-       int nr_timing_valid;
-};
-
 struct nouveau_pm_fan {
        u32 percent;
        u32 min_duty;
@@ -546,11 +538,11 @@ struct nouveau_pm_engine {
        struct nouveau_pm_voltage voltage;
        struct nouveau_pm_level perflvl[NOUVEAU_PM_MAX_LEVEL];
        int nr_perflvl;
-       struct nouveau_pm_memtimings memtimings;
        struct nouveau_pm_temp_sensor_constants sensor_constants;
        struct nouveau_pm_threshold_temp threshold_temp;
        struct nouveau_pm_fan fan;
 
+       struct nouveau_pm_memtiming boot_timing;
        struct nouveau_pm_level boot;
        struct nouveau_pm_level *cur;
 
@@ -922,6 +914,10 @@ extern int  nouveau_mem_init_agp(struct drm_device *);
 extern int  nouveau_mem_reset_agp(struct drm_device *);
 extern void nouveau_mem_close(struct drm_device *);
 extern bool nouveau_mem_flags_valid(struct drm_device *, u32 tile_flags);
+extern void nouveau_mem_timing_read(struct drm_device *,
+                                   struct nouveau_pm_memtiming *);
+extern struct nouveau_pm_memtiming *
+nouveau_mem_timing(struct drm_device *, u32 freq);
 extern int nouveau_mem_vbios_type(struct drm_device *);
 extern struct nouveau_tile_reg *nv10_mem_set_tiling(
        struct drm_device *dev, uint32_t addr, uint32_t size,
index 1cd29c02a7e9a3b052aab73fb413297adfeffaf9..33de772116399c905b15e349fba555531d17b81d 100644 (file)
@@ -471,13 +471,12 @@ nouveau_mem_gart_init(struct drm_device *dev)
        return 0;
 }
 
-static void
-nv40_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
-                     struct nouveau_pm_tbl_entry *e,
-                     struct nouveau_pm_memtiming *t,
-                     struct nouveau_pm_memtiming *boot)
+static int
+nv40_mem_timing_calc(struct drm_device *dev, u32 freq,
+                    struct nouveau_pm_tbl_entry *e, u8 len,
+                    struct nouveau_pm_memtiming *boot,
+                    struct nouveau_pm_memtiming *t)
 {
-
        t->reg[0] = (e->tRP << 24 | e->tRAS << 16 | e->tRFC << 8 | e->tRC);
 
        /* XXX: I don't trust the -1's and +1's... they must come
@@ -495,19 +494,23 @@ nv40_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
 
        NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x\n", t->id,
                 t->reg[0], t->reg[1], t->reg[2]);
+       return 0;
 }
 
-static void
-nv50_mem_timing_entry(struct drm_device *dev, struct bit_entry *P,
-                     struct nouveau_pm_tbl_header *hdr,
-                     struct nouveau_pm_tbl_entry *e,
-                     struct nouveau_pm_memtiming *t,
-                     struct nouveau_pm_memtiming *boot)
+static int
+nv50_mem_timing_calc(struct drm_device *dev, u32 freq,
+                    struct nouveau_pm_tbl_entry *e, u8 len,
+                    struct nouveau_pm_memtiming *boot,
+                    struct nouveau_pm_memtiming *t)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct bit_entry P;
        uint8_t unk18 = 1, unk20 = 0, unk21 = 0, tmp7_3;
 
-       switch (min(hdr->entry_len, (u8) 22)) {
+       if (bit_table(dev, 'P', &P))
+               return -EINVAL;
+
+       switch (min(len, (u8) 22)) {
        case 22:
                unk21 = e->tUNK_21;
        case 21:
@@ -537,7 +540,7 @@ nv50_mem_timing_entry(struct drm_device *dev, struct bit_entry *P,
 
        t->reg[8] = boot->reg[8] & 0xffffff00;
 
-       if (P->version == 1) {
+       if (P.version == 1) {
                t->reg[1] |= (e->tCL + 2 - (t->tCWL - 1));
 
                t->reg[3] = (0x14 + e->tCL) << 24 |
@@ -592,13 +595,14 @@ nv50_mem_timing_entry(struct drm_device *dev, struct bit_entry *P,
        NV_DEBUG(dev, "         230: %08x %08x %08x %08x\n",
                 t->reg[4], t->reg[5], t->reg[6], t->reg[7]);
        NV_DEBUG(dev, "         240: %08x\n", t->reg[8]);
+       return 0;
 }
 
-static void
-nvc0_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
-                     struct nouveau_pm_tbl_entry *e,
-                     struct nouveau_pm_memtiming *t,
-                     struct nouveau_pm_memtiming *boot)
+static int
+nvc0_mem_timing_calc(struct drm_device *dev, u32 freq,
+                    struct nouveau_pm_tbl_entry *e, u8 len,
+                    struct nouveau_pm_memtiming *boot,
+                    struct nouveau_pm_memtiming *t)
 {
        if (e->tCWL > 0)
                t->tCWL = e->tCWL;
@@ -625,20 +629,21 @@ nvc0_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
        NV_DEBUG(dev, "Entry %d: 290: %08x %08x %08x %08x\n", t->id,
                 t->reg[0], t->reg[1], t->reg[2], t->reg[3]);
        NV_DEBUG(dev, "         2a0: %08x\n", t->reg[4]);
+       return 0;
 }
 
 /**
  * MR generation methods
  */
 
-static bool
-nouveau_mem_ddr2_mr(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
-                   struct nouveau_pm_tbl_entry *e,
-                   struct nouveau_pm_memtiming *t,
-                   struct nouveau_pm_memtiming *boot)
+static int
+nouveau_mem_ddr2_mr(struct drm_device *dev, u32 freq,
+                   struct nouveau_pm_tbl_entry *e, u8 len,
+                   struct nouveau_pm_memtiming *boot,
+                   struct nouveau_pm_memtiming *t)
 {
        t->drive_strength = 0;
-       if (hdr->entry_len < 15) {
+       if (len < 15) {
                t->odt = boot->odt;
        } else {
                t->odt = e->RAM_FT1 & 0x07;
@@ -646,12 +651,12 @@ nouveau_mem_ddr2_mr(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
 
        if (e->tCL >= NV_MEM_CL_DDR2_MAX) {
                NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL);
-               return false;
+               return -ERANGE;
        }
 
        if (e->tWR >= NV_MEM_WR_DDR2_MAX) {
                NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR);
-               return false;
+               return -ERANGE;
        }
 
        if (t->odt > 3) {
@@ -668,22 +673,22 @@ nouveau_mem_ddr2_mr(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
                   (t->odt & 0x2) << 5;
 
        NV_DEBUG(dev, "(%u) MR: %08x", t->id, t->mr[0]);
-       return true;
+       return 0;
 }
 
 uint8_t nv_mem_wr_lut_ddr3[NV_MEM_WR_DDR3_MAX] = {
        0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 0, 0};
 
-static bool
-nouveau_mem_ddr3_mr(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
-                   struct nouveau_pm_tbl_entry *e,
-                   struct nouveau_pm_memtiming *t,
-                   struct nouveau_pm_memtiming *boot)
+static int
+nouveau_mem_ddr3_mr(struct drm_device *dev, u32 freq,
+                   struct nouveau_pm_tbl_entry *e, u8 len,
+                   struct nouveau_pm_memtiming *boot,
+                   struct nouveau_pm_memtiming *t)
 {
        u8 cl = e->tCL - 4;
 
        t->drive_strength = 0;
-       if (hdr->entry_len < 15) {
+       if (len < 15) {
                t->odt = boot->odt;
        } else {
                t->odt = e->RAM_FT1 & 0x07;
@@ -691,17 +696,17 @@ nouveau_mem_ddr3_mr(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
 
        if (e->tCL >= NV_MEM_CL_DDR3_MAX || e->tCL < 4) {
                NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL);
-               return false;
+               return -ERANGE;
        }
 
        if (e->tWR >= NV_MEM_WR_DDR3_MAX || e->tWR < 4) {
                NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR);
-               return false;
+               return -ERANGE;
        }
 
        if (e->tCWL < 5) {
                NV_WARN(dev, "(%u) Invalid tCWL: %u", t->id, e->tCWL);
-               return false;
+               return -ERANGE;
        }
 
        t->mr[0] = (boot->mr[0] & 0x180b) |
@@ -716,7 +721,7 @@ nouveau_mem_ddr3_mr(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
        t->mr[2] = (boot->mr[2] & 0x20ffb7) | (e->tCWL - 5) << 3;
 
        NV_DEBUG(dev, "(%u) MR: %08x %08x", t->id, t->mr[0], t->mr[2]);
-       return true;
+       return 0;
 }
 
 uint8_t nv_mem_cl_lut_gddr3[NV_MEM_CL_GDDR3_MAX] = {
@@ -724,13 +729,13 @@ uint8_t nv_mem_cl_lut_gddr3[NV_MEM_CL_GDDR3_MAX] = {
 uint8_t nv_mem_wr_lut_gddr3[NV_MEM_WR_GDDR3_MAX] = {
        0, 0, 0, 0, 0, 2, 3, 8, 9, 10, 11, 0, 0, 1, 1, 0, 3};
 
-static bool
-nouveau_mem_gddr3_mr(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
-                    struct nouveau_pm_tbl_entry *e,
-                    struct nouveau_pm_memtiming *t,
-                    struct nouveau_pm_memtiming *boot)
+static int
+nouveau_mem_gddr3_mr(struct drm_device *dev, u32 freq,
+                    struct nouveau_pm_tbl_entry *e, u8 len,
+                    struct nouveau_pm_memtiming *boot,
+                    struct nouveau_pm_memtiming *t)
 {
-       if (hdr->entry_len < 15) {
+       if (len < 15) {
                t->drive_strength = boot->drive_strength;
                t->odt = boot->odt;
        } else {
@@ -740,12 +745,12 @@ nouveau_mem_gddr3_mr(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
 
        if (e->tCL >= NV_MEM_CL_GDDR3_MAX) {
                NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL);
-               return false;
+               return -ERANGE;
        }
 
        if (e->tWR >= NV_MEM_WR_GDDR3_MAX) {
                NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR);
-               return false;
+               return -ERANGE;
        }
 
        if (t->odt > 3) {
@@ -763,16 +768,16 @@ nouveau_mem_gddr3_mr(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
                   (nv_mem_wr_lut_gddr3[e->tWR] & 0xf) << 4;
 
        NV_DEBUG(dev, "(%u) MR: %08x %08x", t->id, t->mr[0], t->mr[1]);
-       return true;
+       return 0;
 }
 
-static bool
-nouveau_mem_gddr5_mr(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
-                    struct nouveau_pm_tbl_entry *e,
-                    struct nouveau_pm_memtiming *t,
-                    struct nouveau_pm_memtiming *boot)
+static int
+nouveau_mem_gddr5_mr(struct drm_device *dev, u32 freq,
+                    struct nouveau_pm_tbl_entry *e, u8 len,
+                    struct nouveau_pm_memtiming *boot,
+                    struct nouveau_pm_memtiming *t)
 {
-       if (hdr->entry_len < 15) {
+       if (len < 15) {
                t->drive_strength = boot->drive_strength;
                t->odt = boot->odt;
        } else {
@@ -782,12 +787,12 @@ nouveau_mem_gddr5_mr(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
 
        if (e->tCL >= NV_MEM_CL_GDDR5_MAX) {
                NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL);
-               return false;
+               return -ERANGE;
        }
 
        if (e->tWR >= NV_MEM_WR_GDDR5_MAX) {
                NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR);
-               return false;
+               return -ERANGE;
        }
 
        if (t->odt > 3) {
@@ -804,12 +809,70 @@ nouveau_mem_gddr5_mr(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
                   (t->odt << 2);
 
        NV_DEBUG(dev, "(%u) MR: %08x %08x", t->id, t->mr[0], t->mr[1]);
-       return true;
+       return 0;
 }
 
-static void
-nouveau_mem_copy_current_timings(struct drm_device *dev,
-                                struct nouveau_pm_memtiming *t)
+struct nouveau_pm_memtiming *
+nouveau_mem_timing(struct drm_device *dev, u32 freq)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nouveau_pm_memtiming *boot = &pm->boot_timing;
+       struct nouveau_pm_memtiming *t;
+       struct nouveau_pm_tbl_entry *e;
+       u8 ver, len, *ptr;
+       int ret;
+
+       ptr = nouveau_perf_timing(dev, freq, &ver, &len);
+       if (!ptr || ptr[0] == 0x00)
+               return boot;
+       e = (struct nouveau_pm_tbl_entry *)ptr;
+
+       t = kzalloc(sizeof(*t), GFP_KERNEL);
+       if (t) {
+               t->tCWL = boot->tCWL;
+
+               switch (dev_priv->card_type) {
+               case NV_40:
+                       ret = nv40_mem_timing_calc(dev, freq, e, len, boot, t);
+                       break;
+               case NV_50:
+                       ret = nv50_mem_timing_calc(dev, freq, e, len, boot, t);
+                       break;
+               case NV_C0:
+                       ret = nvc0_mem_timing_calc(dev, freq, e, len, boot, t);
+                       break;
+               default:
+                       ret = -ENODEV;
+                       break;
+               }
+
+               switch (dev_priv->vram_type * !ret) {
+               case NV_MEM_TYPE_GDDR3:
+                       ret = nouveau_mem_gddr3_mr(dev, freq, e, len, boot, t);
+                       break;
+               case NV_MEM_TYPE_GDDR5:
+                       ret = nouveau_mem_gddr5_mr(dev, freq, e, len, boot, t);
+                       break;
+               case NV_MEM_TYPE_DDR2:
+                       ret = nouveau_mem_ddr2_mr(dev, freq, e, len, boot, t);
+                       break;
+               case NV_MEM_TYPE_DDR3:
+                       ret = nouveau_mem_ddr3_mr(dev, freq, e, len, boot, t);
+                       break;
+               }
+
+               if (ret) {
+                       kfree(t);
+                       t = NULL;
+               }
+       }
+
+       return t;
+}
+
+void
+nouveau_mem_timing_read(struct drm_device *dev, struct nouveau_pm_memtiming *t)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        u32 timing_base, timing_regs, mr_base;
@@ -874,212 +937,6 @@ nouveau_mem_copy_current_timings(struct drm_device *dev,
        }
 }
 
-static bool
-nouveau_mem_compare_timings(struct drm_device *dev,
-                           struct nouveau_pm_memtiming *t1,
-                           struct nouveau_pm_memtiming *t2)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       switch (dev_priv->card_type) {
-       case 0x50:
-               if (t1->reg[8] != t2->reg[8] ||
-                   t1->reg[7] != t2->reg[7] ||
-                   t1->reg[6] != t2->reg[6] ||
-                   t1->reg[5] != t2->reg[5])
-                       return false;
-       case 0xC0:
-               if (t1->reg[4] != t2->reg[4] ||
-                   t1->reg[3] != t2->reg[3])
-                       return false;
-       case 0x40:
-               if (t1->reg[2] != t2->reg[2] ||
-                   t1->reg[1] != t2->reg[1] ||
-                   t1->reg[0] != t2->reg[0])
-                       return false;
-               break;
-       default:
-               return false;
-       }
-
-       /* RSpliet: may generate many false negatives */
-       switch (dev_priv->vram_type) {
-       case NV_MEM_TYPE_GDDR3:
-       case NV_MEM_TYPE_GDDR5:
-               if (t1->mr[0] == t2->mr[0] ||
-                   t1->mr[1] != t2->mr[1])
-                       return true;
-               break;
-       case NV_MEM_TYPE_DDR3:
-               if (t1->mr[2] == t2->mr[2])
-                       return true;
-       case NV_MEM_TYPE_DDR2:
-               if (t1->mr[0] == t2->mr[0])
-                       return true;
-               break;
-       default:
-               return false;
-       }
-
-       return false;
-}
-
-/**
- * Processes the Memory Timing BIOS table, stores generated
- * register values
- * @pre init scripts were run, memtiming regs are initialized
- */
-void
-nouveau_mem_timing_init(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
-       struct nouveau_pm_memtimings *memtimings = &pm->memtimings;
-       struct nvbios *bios = &dev_priv->vbios;
-       struct bit_entry P;
-       struct nouveau_pm_tbl_header *hdr = NULL;
-       bool valid_generation = false;
-       u8 *entry;
-       int i;
-
-       memtimings->nr_timing = 0;
-       memtimings->nr_timing_valid = 0;
-       memtimings->supported = 0;
-
-       if (dev_priv->card_type < NV_40) {
-               NV_ERROR(dev, "Timing entry format unknown for card_type %x. "
-                        "please contact nouveau developers",
-                        dev_priv->card_type);
-               return;
-       }
-
-       /* Copy the current timings */
-       nouveau_mem_copy_current_timings(dev, &memtimings->boot);
-
-       if (bios->type == NVBIOS_BIT) {
-               if (bit_table(dev, 'P', &P))
-                       return;
-
-               if (P.version == 1)
-                       hdr = (struct nouveau_pm_tbl_header *) ROMPTR(dev,
-                                                                    P.data[4]);
-               else if (P.version == 2)
-                       hdr = (struct nouveau_pm_tbl_header *) ROMPTR(dev,
-                                                                    P.data[8]);
-               else
-                       NV_WARN(dev, "unknown mem for BIT P %d\n", P.version);
-       } else {
-               NV_DEBUG(dev, "BMP version too old for memory\n");
-               return;
-       }
-
-       if (!hdr) {
-               NV_DEBUG(dev, "memory timing table pointer invalid\n");
-               return;
-       }
-
-       if (hdr->version != 0x10) {
-               NV_WARN(dev, "memory timing table 0x%02x unknown\n",
-                       hdr->version);
-               return;
-       }
-
-       /* validate record length */
-       if (hdr->entry_len < 15) {
-               NV_ERROR(dev, "mem timing table length unknown: %d\n",
-                        hdr->entry_len);
-               return;
-       }
-
-       /* parse vbios entries into common format */
-       memtimings->timing = kcalloc(hdr->entry_cnt,
-                                    sizeof(*memtimings->timing), GFP_KERNEL);
-       if (!memtimings->timing)
-               return;
-
-       entry = (u8 *) hdr + hdr->header_len;
-       for (i = 0; i < hdr->entry_cnt; i++, entry += hdr->entry_len) {
-               struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i];
-               struct nouveau_pm_tbl_entry *entry_struct =
-                                         (struct nouveau_pm_tbl_entry *) entry;
-               if (entry[0] == 0)
-                       continue;
-               memtimings->nr_timing_valid++;
-
-               timing->id = i;
-               timing->tCWL = memtimings->boot.tCWL;
-
-               /* generate the timngs */
-               if (dev_priv->card_type == NV_40) {
-                       nv40_mem_timing_entry(dev, hdr, entry_struct,
-                                             &pm->memtimings.timing[i],
-                                             &memtimings->boot);
-               } else if (dev_priv->card_type == NV_50) {
-                       nv50_mem_timing_entry(dev, &P, hdr, entry_struct,
-                                             &pm->memtimings.timing[i],
-                                             &memtimings->boot);
-               } else if (dev_priv->card_type == NV_C0) {
-                       nvc0_mem_timing_entry(dev, hdr, entry_struct,
-                                             &pm->memtimings.timing[i],
-                                             &memtimings->boot);
-               }
-
-               /* generate the MR/EMR/...  */
-               switch (dev_priv->vram_type) {
-               case NV_MEM_TYPE_GDDR3:
-                       nouveau_mem_gddr3_mr(dev, hdr, entry_struct, timing,
-                                            &memtimings->boot);
-                       break;
-               case NV_MEM_TYPE_GDDR5:
-                       nouveau_mem_gddr5_mr(dev, hdr, entry_struct, timing,
-                                            &memtimings->boot);
-                       break;
-               case NV_MEM_TYPE_DDR2:
-                       nouveau_mem_ddr2_mr(dev, hdr, entry_struct, timing,
-                                           &memtimings->boot);
-                       break;
-               case NV_MEM_TYPE_DDR3:
-                       nouveau_mem_ddr3_mr(dev, hdr, entry_struct, timing,
-                                           &memtimings->boot);
-                       break;
-               default:
-                       valid_generation = false;
-                       break;
-               }
-
-               /* some kind of validation */
-               if (nouveau_mem_compare_timings(dev, timing,
-                                               &memtimings->boot)) {
-                       NV_DEBUG(dev, "Copy boot timings from entry %d\n",
-                               timing->id);
-                       memtimings->boot = *timing;
-                       valid_generation = true;
-               }
-       }
-
-       memtimings->nr_timing = hdr->entry_cnt;
-       memtimings->supported = (P.version == 1) && valid_generation;
-
-       /* if there are no timing entries that cannot
-        * re-generate the current timings
-        */
-       if (memtimings->nr_timing_valid > 0  && !valid_generation) {
-               NV_INFO(dev,
-                        "Memory timings management may not be working."
-                        " please report to nouveau devs\n");
-       }
-}
-
-void
-nouveau_mem_timing_fini(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pm_memtimings *mem = &dev_priv->engine.pm.memtimings;
-
-       kfree(mem->timing);
-       mem->timing = NULL;
-}
-
 int
 nouveau_mem_vbios_type(struct drm_device *dev)
 {
index ad990553d11541be45de3f975d37ab6a0e8e71dc..150ff415a17267564fe6e6b69720c0f2c83dabe1 100644 (file)
@@ -89,7 +89,7 @@ nouveau_perf_rammap(struct drm_device *dev, u32 freq,
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct bit_entry P;
-       u8 *perf, i;
+       u8 *perf, i = 0;
 
        if (!bit_table(dev, 'P', &P) && P.version == 2) {
                u8 *rammap = ROMPTR(dev, P.data[4]);
@@ -158,7 +158,7 @@ nouveau_perf_ramcfg(struct drm_device *dev, u32 freq, u8 *ver, u8 *len)
        return NULL;
 }
 
-static u8 *
+u8 *
 nouveau_perf_timing(struct drm_device *dev, u32 freq, u8 *ver, u8 *len)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -384,24 +384,7 @@ nouveau_perf_init(struct drm_device *dev)
                }
 
                /* get the corresponding memory timings */
-#if 0
-               if (version == 0x15) {
-                       memtimings->timing[i].id = i;
-                       nv30_mem_timing_entry(dev, &mt_hdr,
-                                    (struct nouveau_pm_tbl_entry *) &entry[41],
-                                    0, &memtimings->timing[i]);
-                       perflvl->timing = &memtimings->timing[i];
-               } else if (version > 0x15) {
-                       /* last 3 args are for < 0x40, ignored for >= 0x40 */
-                       perflvl->timing =
-                               nouveau_perf_timing(dev, &P,
-                                                   perflvl->memory / 1000,
-                                                   entry + perf[3],
-                                                   perf[5], perf[4]);
-               }
-#else
-               perflvl->timing = NULL;
-#endif
+               perflvl->timing = nouveau_mem_timing(dev, perflvl->memory);
 
                snprintf(perflvl->name, sizeof(perflvl->name),
                         "performance_level_%d", i);
index a9a2e367f9d1f688f7d595774b2e1d72c9a5c61e..4f299f4df71c7bd76c83e32f698c25d48c9b7caa 100644 (file)
@@ -238,6 +238,7 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
        if (ret > 0)
                perflvl->fanspeed = ret;
 
+       nouveau_mem_timing_read(dev, &perflvl->timing);
        return 0;
 }
 
@@ -793,8 +794,6 @@ nouveau_pm_init(struct drm_device *dev)
        char info[256];
        int ret, i;
 
-       nouveau_mem_timing_init(dev);
-
        /* parse aux tables from vbios */
        nouveau_volt_init(dev);
        nouveau_temp_init(dev);
@@ -807,7 +806,6 @@ nouveau_pm_init(struct drm_device *dev)
        }
 
        strncpy(pm->boot.name, "boot", 4);
-       pm->boot.timing = &pm->memtimings.boot;
        pm->cur = &pm->boot;
 
        /* add performance levels from vbios */
@@ -857,7 +855,6 @@ nouveau_pm_fini(struct drm_device *dev)
        nouveau_temp_fini(dev);
        nouveau_perf_fini(dev);
        nouveau_volt_fini(dev);
-       nouveau_mem_timing_fini(dev);
 
 #if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
        unregister_acpi_notifier(&pm->acpi_nb);
index 2f8e14fbcff85237cfc4120d19355f1a01793225..9e7ad33aa091d531075965c56e6b5e3039c33e39 100644 (file)
@@ -41,6 +41,7 @@ int  nouveau_voltage_gpio_set(struct drm_device *, int voltage);
 /* nouveau_perf.c */
 void nouveau_perf_init(struct drm_device *);
 void nouveau_perf_fini(struct drm_device *);
+u8 *nouveau_perf_timing(struct drm_device *, u32 freq, u8 *ver, u8 *len);
 
 /* nouveau_mem.c */
 void nouveau_mem_timing_init(struct drm_device *);