drm/nouveau: Associate memtimings with performance levels on cards <= nv98
authorMartin Peres <martin.peres@free.fr>
Wed, 13 Apr 2011 22:46:19 +0000 (00:46 +0200)
committerBen Skeggs <bskeggs@redhat.com>
Mon, 16 May 2011 00:50:30 +0000 (10:50 +1000)
v2 (Ben Skeggs): fix ramcfg strap, and remove bogus handling of perf 0x40

Signed-off-by: Martin Peres <martin.peres@ensi-bourges.fr>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
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

index e4c26a2..224d3a1 100644 (file)
@@ -410,6 +410,19 @@ struct nouveau_pm_voltage {
        int nr_level;
 };
 
+struct nouveau_pm_memtiming {
+       int id;
+       u32 reg_100220;
+       u32 reg_100224;
+       u32 reg_100228;
+       u32 reg_10022c;
+       u32 reg_100230;
+       u32 reg_100234;
+       u32 reg_100238;
+       u32 reg_10023c;
+       u32 reg_100240;
+};
+
 #define NOUVEAU_PM_MAX_LEVEL 8
 struct nouveau_pm_level {
        struct device_attribute dev_attr;
@@ -425,6 +438,7 @@ struct nouveau_pm_level {
        u8 fanspeed;
 
        u16 memscript;
+       struct nouveau_pm_memtiming *timing;
 };
 
 struct nouveau_pm_temp_sensor_constants {
@@ -441,18 +455,6 @@ struct nouveau_pm_threshold_temp {
        s16 fan_boost;
 };
 
-struct nouveau_pm_memtiming {
-       u32 reg_100220;
-       u32 reg_100224;
-       u32 reg_100228;
-       u32 reg_10022c;
-       u32 reg_100230;
-       u32 reg_100234;
-       u32 reg_100238;
-       u32 reg_10023c;
-       u32 reg_100240;
-};
-
 struct nouveau_pm_memtimings {
        bool supported;
        struct nouveau_pm_memtiming *timing;
index ce3cb5e..2960f58 100644 (file)
@@ -704,6 +704,7 @@ nouveau_mem_timing_init(struct drm_device *dev)
 
                        /* XXX: reg_100240? */
                }
+               timing->id = i;
 
                NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
                         timing->reg_100220, timing->reg_100224,
@@ -715,7 +716,7 @@ nouveau_mem_timing_init(struct drm_device *dev)
        }
 
        memtimings->nr_timing = entries;
-       memtimings->supported = true;
+       memtimings->supported = (dev_priv->chipset <= 0x98);
 }
 
 void
index 670e3cb..5b87e68 100644 (file)
@@ -82,6 +82,7 @@ nouveau_perf_init(struct drm_device *dev)
        u8 version, headerlen, recordlen, entries;
        u8 *perf, *entry;
        int vid, i;
+       u8 ramcfg = (nv_rd32(dev, NV_PEXTDEV_BOOT_0) & 0x3c) >> 2;
 
        if (bios->type == NVBIOS_BIT) {
                if (bit_table(dev, 'P', &P))
@@ -124,6 +125,8 @@ nouveau_perf_init(struct drm_device *dev)
        for (i = 0; i < entries; i++) {
                struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
 
+               perflvl->timing = NULL;
+
                if (entry[0] == 0xff) {
                        entry += recordlen;
                        continue;
@@ -190,6 +193,22 @@ nouveau_perf_init(struct drm_device *dev)
                        }
                }
 
+               /* get the corresponding memory timings */
+               if (pm->memtimings.supported) {
+                       u8  timing_id = 0xff;
+                       u16 extra_data;
+
+                       if (version > 0x15 && version < 0x40 &&
+                           ramcfg < perf[4]) {
+                               extra_data = perf[3] + (ramcfg * perf[5]);
+                               timing_id  = entry[extra_data + 1];
+                       }
+
+                       if (pm->memtimings.nr_timing > timing_id)
+                               perflvl->timing =
+                                       &pm->memtimings.timing[timing_id];
+               }
+
                snprintf(perflvl->name, sizeof(perflvl->name),
                         "performance_level_%d", i);
                perflvl->id = i;
index dc8a0cc..da8d994 100644 (file)
@@ -156,7 +156,7 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
 static void
 nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
 {
-       char c[16], s[16], v[16], f[16];
+       char c[16], s[16], v[16], f[16], t[16];
 
        c[0] = '\0';
        if (perflvl->core)
@@ -174,8 +174,12 @@ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
        if (perflvl->fanspeed)
                snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed);
 
-       snprintf(ptr, len, "memory %dMHz%s%s%s%s\n", perflvl->memory / 1000,
-                c, s, v, f);
+       t[0] = '\0';
+       if (perflvl->timing)
+               snprintf(t, sizeof(t), " timing %d", perflvl->timing->id);
+
+       snprintf(ptr, len, "memory %dMHz%s%s%s%s%s\n", perflvl->memory / 1000,
+                c, s, v, f, t);
 }
 
 static ssize_t
@@ -476,10 +480,10 @@ nouveau_pm_init(struct drm_device *dev)
        char info[256];
        int ret, i;
 
+       nouveau_mem_timing_init(dev);
        nouveau_volt_init(dev);
        nouveau_perf_init(dev);
        nouveau_temp_init(dev);
-       nouveau_mem_timing_init(dev);
 
        NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl);
        for (i = 0; i < pm->nr_perflvl; i++) {
@@ -525,10 +529,10 @@ nouveau_pm_fini(struct drm_device *dev)
        if (pm->cur != &pm->boot)
                nouveau_pm_perflvl_set(dev, &pm->boot);
 
-       nouveau_mem_timing_fini(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);