[v3,18/29] volt: add coefficients I found on my gpu

Submitted by Karol Herbst on April 7, 2016, 9:24 p.m.

Details

Message ID 1460064259-1243-19-git-send-email-nouveau@karolherbst.de
State New
Headers show
Series "Volting/Clocking improvements for Fermi and newer" ( rev: 3 ) in Nouveau

Not browsing as part of any series.

Commit Message

Karol Herbst April 7, 2016, 9:24 p.m.
I am sure that those are a bit different on other GPUs, but while testing
the error range compared to nvidia was around 100%+-3%.

Without this change we are most of the time around 10% below nvidias voltage,
so this change causes no harm and improves the situation a lot already.

The remaining task for this is to figure out which of these constants are
chip specific and from where to get the chip specific factors

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.

Signed-off-by: Karol Herbst <nouveau@karolherbst.de>
---
 drm/nouveau/nvkm/subdev/volt/base.c | 53 ++++++++++++++++++++++++++++++++-----
 1 file changed, 47 insertions(+), 6 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drm/nouveau/nvkm/subdev/volt/base.c b/drm/nouveau/nvkm/subdev/volt/base.c
index 552fecd..654b88e 100644
--- a/drm/nouveau/nvkm/subdev/volt/base.c
+++ b/drm/nouveau/nvkm/subdev/volt/base.c
@@ -110,13 +110,54 @@  nvkm_volt_map(struct nvkm_volt *volt, u8 id, u8 temp)
 
 	vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info);
 	if (vmap) {
-		if (info.link != 0xff) {
-			int ret = nvkm_volt_map(volt, info.link, temp);
-			if (ret < 0)
-				return ret;
-			info.min += ret;
+		switch (ver) {
+		case 0x10:
+			if (info.link != 0xff) {
+				int ret = nvkm_volt_map(volt, info.link, temp);
+				if (ret < 0)
+					return ret;
+				info.min += ret;
+			}
+			return info.min;
+		case 0x20: {
+			s32 result;
+			switch (info.mode) {
+			case 0x0:
+				result =  info.arg[0] / 10;
+				result += info.arg[1] * 168;
+				result += info.arg[2] * 28;
+				break;
+			case 0x1:
+				result =  (info.arg[0] / 1675) * 100;
+				result += info.arg[1]          * 100;
+				result += (info.arg[2] / 10)   * 153 * temp;
+				result += info.arg[3]          * 100 * temp;
+				result += info.arg[4]          * 41;
+				result += (info.arg[5] * (temp * temp)) / 15;
+				break;
+			case 0x3:
+				result = (info.min + info.max) / 2;
+				break;
+			case 0x2:
+			default:
+				result = info.min;
+				break;
+			}
+			result = min(max(result, (s32)info.min),
+				     (s32)info.max);
+
+			if (info.link != 0xff) {
+				int ret = nvkm_volt_map(volt, info.link, temp);
+				if (ret < 0)
+					return ret;
+				result += ret;
+			}
+
+			return result;
+		}
+		default:
+			return -ENODEV;
 		}
-		return info.min;
 	}
 
 	return id ? id * 10000 : -ENODEV;