drm/nouveau: Associate memtimings with performance levels on cards <= nv98

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>
diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c
index 670e3cb..5b87e68 100644
--- a/drivers/gpu/drm/nouveau/nouveau_perf.c
+++ b/drivers/gpu/drm/nouveau/nouveau_perf.c
@@ -82,6 +82,7 @@
 	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 @@
 	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 @@
 			}
 		}
 
+		/* 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;