diff options
author | Karol Herbst <karolherbst@gmail.com> | 2016-07-12 21:36:09 +0200 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2016-10-12 17:29:28 +1000 |
commit | 114653c7593a4dd52cc1721b0d325d43b00e2371 (patch) | |
tree | eda522fa8354766f79d9fe3bb60e25ec97d371a3 /drivers/gpu/drm/nouveau | |
parent | 08de5743db9250dc915d85f9f7d1a9016a8f8975 (diff) |
drm/nouveau/volt: Make use of cvb coefficients
I'm quite sure that those coefficients are real close, because while
testing the biggest error compared to nvidia was around -1.5% (biggest
error with right coefficients is 12.5mV / 600mV = 2%).
These coefficients were REed by modifing the voltage map entries and by
calculating the set voltage back until I was able to forecast which voltage
nvidia sets for a given voltage map entry.
With these formulars I am able to precisely predict at which exact
temperature Nvidia down- or upvolts due to a changed therm reading.
That's why I am quite sure these are right, or at least really really
close.
v4: Use better coefficients and speedo.
v5: Add error message when speedo is missing.
Signed-off-by: Karol Herbst <karolherbst@gmail.com>
Reviewed-by: Martin Peres <martin.peres@free.fr>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c | 38 |
1 files changed, 36 insertions, 2 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c index 771419ff8338..90d234231eed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c @@ -110,13 +110,47 @@ nvkm_volt_map(struct nvkm_volt *volt, u8 id, u8 temp) vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info); if (vmap) { + s64 result; + + if (volt->speedo < 0) + return volt->speedo; + + if (ver == 0x10 || (ver == 0x20 && info.mode == 0)) { + result = (s64)info.arg[0] / 10; + result += ((s64)info.arg[1] * volt->speedo) / 10; + result += ((s64)info.arg[2] * volt->speedo * volt->speedo) / 100000; + } else if (ver == 0x20) { + switch (info.mode) { + /* 0x0 handled above! */ + case 0x1: + result = ((s64)info.arg[0] * 15625) >> 18; + result += ((s64)info.arg[1] * volt->speedo * 15625) >> 18; + result += ((s64)info.arg[2] * temp * 15625) >> 10; + result += ((s64)info.arg[3] * volt->speedo * temp * 15625) >> 18; + result += ((s64)info.arg[4] * volt->speedo * volt->speedo * 15625) >> 30; + result += ((s64)info.arg[5] * temp * temp * 15625) >> 18; + break; + case 0x3: + result = (info.min + info.max) / 2; + break; + case 0x2: + default: + result = info.min; + break; + } + } else { + return -ENODEV; + } + + result = min(max(result, (s64)info.min), (s64)info.max); + if (info.link != 0xff) { int ret = nvkm_volt_map(volt, info.link, temp); if (ret < 0) return ret; - info.min += ret; + result += ret; } - return info.min; + return result; } return id ? id * 10000 : -ENODEV; |