drm/nouveau/pm: initial attempt at parsing volt 0x40
authorBen Skeggs <bskeggs@redhat.com>
Thu, 9 Jun 2011 06:16:38 +0000 (16:16 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 20 Sep 2011 06:01:06 +0000 (16:01 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_volt.c

index 9eec275..471daec 100644 (file)
@@ -170,6 +170,13 @@ nouveau_volt_init(struct drm_device *dev)
                 */
                vidshift  = 2;
                break;
+       case 0x40:
+               headerlen = volt[1];
+               recordlen = volt[2];
+               entries   = volt[3]; /* not a clue what the entries are for.. */
+               vidmask   = volt[11]; /* guess.. */
+               vidshift  = 0;
+               break;
        default:
                NV_WARN(dev, "voltage table 0x%02x unknown\n", volt[0]);
                return;
@@ -197,16 +204,36 @@ nouveau_volt_init(struct drm_device *dev)
        }
 
        /* parse vbios entries into common format */
-       voltage->level = kcalloc(entries, sizeof(*voltage->level), GFP_KERNEL);
-       if (!voltage->level)
-               return;
+       if (volt[0] < 0x40) {
+               voltage->nr_level = entries;
+               voltage->level =
+                       kcalloc(entries, sizeof(*voltage->level), GFP_KERNEL);
+               if (!voltage->level)
+                       return;
 
-       entry = volt + headerlen;
-       for (i = 0; i < entries; i++, entry += recordlen) {
-               voltage->level[i].voltage = entry[0] * 10000;
-               voltage->level[i].vid     = entry[1] >> vidshift;
+               entry = volt + headerlen;
+               for (i = 0; i < entries; i++, entry += recordlen) {
+                       voltage->level[i].voltage = entry[0] * 10000;
+                       voltage->level[i].vid     = entry[1] >> vidshift;
+               }
+       } else {
+               u32 volt_uv = ROM32(volt[4]);
+               s16 step_uv = ROM16(volt[8]);
+               u8 vid;
+
+               voltage->nr_level = voltage->vid_mask + 1;
+               voltage->level = kcalloc(voltage->nr_level,
+                                        sizeof(*voltage->level), GFP_KERNEL);
+               if (!voltage->level)
+                       return;
+
+               for (vid = 0; vid <= voltage->vid_mask; vid++) {
+                       voltage->level[vid].voltage = volt_uv;
+                       voltage->level[vid].vid = vid;
+                       volt_uv += step_uv;
+               }
        }
-       voltage->nr_level  = entries;
+
        voltage->supported = true;
 }