@@ -87,14 +87,25 @@ nvbios_vmap_entry_parse(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len,
u16 vmap = nvbios_vmap_entry(bios, idx, ver, len);
memset(info, 0x00, sizeof(*info));
switch (!!vmap * *ver) {
- case 0x10:
+ case 0x10: {
+ s32 accum, b, c;
+
info->link = 0xff;
info->min = nv_ro32(bios, vmap + 0x00);
info->max = nv_ro32(bios, vmap + 0x04);
- info->arg[0] = nv_ro32(bios, vmap + 0x08);
- info->arg[1] = nv_ro32(bios, vmap + 0x0c);
- info->arg[2] = nv_ro32(bios, vmap + 0x10);
+
+ accum = nv_ro32(bios, vmap + 0x08);
+ b = nv_ro32(bios, vmap + 0x0c);
+ c = nv_ro32(bios, vmap + 0x10);
+
+ accum += b * 1505;
+ accum += (c * 453 / 2) + c / 400;
+ accum /= 10;
+
+ if (accum > info->min)
+ info->min = min((u32)accum, info->max);
break;
+ }
case 0x20:
info->unk0 = nv_ro08(bios, vmap + 0x00);
info->link = nv_ro08(bios, vmap + 0x01);
@@ -50,12 +50,23 @@ nouveau_volt_set(struct nouveau_volt *volt, u32 uv)
{
if (volt->vid_set) {
int i, ret = -EINVAL;
+ u32 best_uv = INT_MAX, best_vid = 0;
+
for (i = 0; i < volt->vid_nr; i++) {
- if (volt->vid[i].uv == uv) {
- ret = volt->vid_set(volt, volt->vid[i].vid);
- nv_debug(volt, "set %duv: %d\n", uv, ret);
+ s32 delta = volt->vid[i].uv - uv;
+
+ if (delta < 0 || best_uv < volt->vid[i].uv)
+ continue;
+
+ best_uv = volt->vid[i].uv;
+ best_vid = volt->vid[i].vid;
+ if (!delta)
break;
- }
+ }
+
+ if (best_uv < INT_MAX) {
+ ret = volt->vid_set(volt, best_vid);
+ nv_debug(volt, "set %duv from %duv: %d\n", best_uv, uv, ret);
}
return ret;
}
Coefficients are based on the formula: uV = 0.1 * arg[0] + 150.5 * arg[1] + 22.65025 * arg[2] It seems to be rounded downwards. I have no idea why the voltage isn't specified in the bios directly. Signed-off-by: Maarten Lankhorst <maarten.lankhorst@canonical.com> ----