drm/nouveau/volt: Don't require perfect fit
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:25 +0000 (17:29 +1000)
If we calculate the voltage in the table right, we get all kinds of values,
which never fit the hardware steps, so we use the closest higher value the
hardware can do.

v3: Simplify the implementation.
v5: Initialize best_err with volt->max_uv.

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/nvkm/subdev/volt/base.c

index 5e07bd3aaccc446600f615718c13119f5e8c86bf..ec59d58becdcd2d9310b021fe8b4010c93e18b6d 100644 (file)
@@ -51,18 +51,30 @@ static int
 nvkm_volt_set(struct nvkm_volt *volt, u32 uv)
 {
        struct nvkm_subdev *subdev = &volt->subdev;
-       int i, ret = -EINVAL;
+       int i, ret = -EINVAL, best_err = volt->max_uv, best = -1;
 
        if (volt->func->volt_set)
                return volt->func->volt_set(volt, uv);
 
        for (i = 0; i < volt->vid_nr; i++) {
-               if (volt->vid[i].uv == uv) {
-                       ret = volt->func->vid_set(volt, volt->vid[i].vid);
-                       nvkm_debug(subdev, "set %duv: %d\n", uv, ret);
+               int err = volt->vid[i].uv - uv;
+               if (err < 0 || err > best_err)
+                       continue;
+
+               best_err = err;
+               best = i;
+               if (best_err == 0)
                        break;
-               }
        }
+
+       if (best == -1) {
+               nvkm_error(subdev, "couldn't set %iuv\n", uv);
+               return ret;
+       }
+
+       ret = volt->func->vid_set(volt, volt->vid[best].vid);
+       nvkm_debug(subdev, "set req %duv to %duv: %d\n", uv,
+                  volt->vid[best].uv, ret);
        return ret;
 }