drm/nouveau/volt: Parse the max voltage map entries
authorKarol Herbst <karolherbst@gmail.com>
Tue, 12 Jul 2016 19:36:08 +0000 (21:36 +0200)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 12 Oct 2016 07:29:20 +0000 (17:29 +1000)
There are at least three "max" entries, which specify the max voltage.
Because they are actually normal voltage map entries, they can also be
affected by the temperature.

Nvidia respects those entries and if they get changed, nvidia uses the
lower voltage from all three.

We shouldn't exceed those voltages at any given time.

v2: State what those entries do in the source.
v3: Add the third max entry.
v5: Better describe the entries.

Signed-off-by: Karol Herbst <karolherbst@gmail.com>
Reviewed-by: Martin Peres <martin.peres@free.fr>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vmap.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h
drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c
drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c

index 6633c6db9281eb897b5f378fc5c0c2d360fc6399..ae2f27be3f2903034a29b920494435003e91f142 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef __NVBIOS_VMAP_H__
 #define __NVBIOS_VMAP_H__
 struct nvbios_vmap {
+       u8  max0;
+       u8  max1;
+       u8  max2;
 };
 
 u16 nvbios_vmap_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
index fc68825ffcbb8dacb6852f7fefebe6235dcb1a72..2612a04c49bbd0b9a4a720f2ddc233b264343cc9 100644 (file)
@@ -15,6 +15,16 @@ struct nvkm_volt {
 
        u32 max_uv;
        u32 min_uv;
+
+       /*
+        * These are fully functional map entries creating a sw ceiling for
+        * the voltage. These all can describe different kind of curves, so
+        * that for any given temperature a different one can return the lowest
+        * value of all three.
+        */
+       u8 max0_id;
+       u8 max1_id;
+       u8 max2_id;
 };
 
 int nvkm_volt_map_min(struct nvkm_volt *volt, u8 id);
index 2f13db745948a303d24c3970fac4a6d245451886..f2295e180e5e607dcc5e82d74c79c2ca9178b13a 100644 (file)
@@ -61,7 +61,17 @@ nvbios_vmap_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
        memset(info, 0x00, sizeof(*info));
        switch (!!vmap * *ver) {
        case 0x10:
+               info->max0 = 0xff;
+               info->max1 = 0xff;
+               info->max2 = 0xff;
+               break;
        case 0x20:
+               info->max0 = nvbios_rd08(bios, vmap + 0x7);
+               info->max1 = nvbios_rd08(bios, vmap + 0x8);
+               if (*len >= 0xc)
+                       info->max2 = nvbios_rd08(bios, vmap + 0xc);
+               else
+                       info->max2 = 0xff;
                break;
        }
        return vmap;
index 6eeb9d9de3344ca88b166ca52c48b0f428b60f1f..8445e4c9fe5492a0b4217f516c5d0953f70d80f0 100644 (file)
@@ -216,9 +216,22 @@ nvkm_volt_ctor(const struct nvkm_volt_func *func, struct nvkm_device *device,
 
        /* Assuming the non-bios device should build the voltage table later */
        if (bios) {
+               u8 ver, hdr, cnt, len;
+               struct nvbios_vmap vmap;
+
                nvkm_volt_parse_bios(bios, volt);
                nvkm_debug(&volt->subdev, "min: %iuv max: %iuv\n",
                           volt->min_uv, volt->max_uv);
+
+               if (nvbios_vmap_parse(bios, &ver, &hdr, &cnt, &len, &vmap)) {
+                       volt->max0_id = vmap.max0;
+                       volt->max1_id = vmap.max1;
+                       volt->max2_id = vmap.max2;
+               } else {
+                       volt->max0_id = 0xff;
+                       volt->max1_id = 0xff;
+                       volt->max2_id = 0xff;
+               }
        }
 
        if (volt->vid_nr) {