drm/nouveau/bios/volt: add support for pwm-based volt management
authorMartin Peres <martin.peres@free.fr>
Wed, 9 Sep 2015 01:05:50 +0000 (04:05 +0300)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 3 Nov 2015 05:02:18 +0000 (15:02 +1000)
Signed-off-by: Martin Peres <martin.peres@free.fr>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/volt.h
drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c

index eb2de4b..b0df610 100644 (file)
@@ -1,11 +1,24 @@
 #ifndef __NVBIOS_VOLT_H__
 #define __NVBIOS_VOLT_H__
+
+enum nvbios_volt_type {
+       NVBIOS_VOLT_GPIO = 0,
+       NVBIOS_VOLT_PWM,
+};
+
 struct nvbios_volt {
-       u8  vidmask;
+       enum nvbios_volt_type type;
        u32 min;
        u32 max;
        u32 base;
+
+       /* GPIO mode */
+       u8  vidmask;
        s16 step;
+
+       /* PWM mode */
+       u32 pwm_freq;
+       u32 pwm_range;
 };
 
 u16 nvbios_volt_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
index 615804c..6e0a336 100644 (file)
@@ -73,15 +73,19 @@ nvbios_volt_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
        memset(info, 0x00, sizeof(*info));
        switch (!!volt * *ver) {
        case 0x12:
+               info->type    = NVBIOS_VOLT_GPIO;
                info->vidmask = nvbios_rd08(bios, volt + 0x04);
                break;
        case 0x20:
+               info->type    = NVBIOS_VOLT_GPIO;
                info->vidmask = nvbios_rd08(bios, volt + 0x05);
                break;
        case 0x30:
+               info->type    = NVBIOS_VOLT_GPIO;
                info->vidmask = nvbios_rd08(bios, volt + 0x04);
                break;
        case 0x40:
+               info->type    = NVBIOS_VOLT_GPIO;
                info->base    = nvbios_rd32(bios, volt + 0x04);
                info->step    = nvbios_rd16(bios, volt + 0x08);
                info->vidmask = nvbios_rd08(bios, volt + 0x0b);
@@ -90,11 +94,20 @@ nvbios_volt_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
                info->max     = info->base;
                break;
        case 0x50:
-               info->vidmask = nvbios_rd08(bios, volt + 0x06);
                info->min     = nvbios_rd32(bios, volt + 0x0a);
                info->max     = nvbios_rd32(bios, volt + 0x0e);
                info->base    = nvbios_rd32(bios, volt + 0x12) & 0x00ffffff;
-               info->step    = nvbios_rd16(bios, volt + 0x16);
+
+               /* offset 4 seems to be a flag byte */
+               if (nvbios_rd32(bios, volt + 0x4) & 1) {
+                       info->type      = NVBIOS_VOLT_PWM;
+                       info->pwm_freq  = nvbios_rd32(bios, volt + 0x5) / 1000;
+                       info->pwm_range = nvbios_rd32(bios, volt + 0x16);
+               } else {
+                       info->type      = NVBIOS_VOLT_GPIO;
+                       info->vidmask   = nvbios_rd08(bios, volt + 0x06);
+                       info->step      = nvbios_rd16(bios, volt + 0x16);
+               }
                break;
        }
        return volt;