drm/nouveau/therm: calculate the pwm divisor on nv50+

v2: Martin Peres <martin.peres@labri.fr>
- fixed unintentional use of floating point

Signed-off-by: Martin Peres <martin.peres@labri.fr>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c
index b7339b5..409b95d 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c
@@ -81,10 +81,10 @@
 	if (ret == 0) {
 		divs = priv->bios_perf_fan.pwm_divisor;
 		if (priv->bios_fan.pwm_freq) {
-			/*XXX: PNVIO clock more than likely... */
-			divs = 135000 /priv->bios_fan.pwm_freq;
-			if (nv_device(therm)->chipset < 0xa3)
-				divs /= 4;
+			divs = 1;
+			if (priv->fan.pwm_clock)
+				divs = priv->fan.pwm_clock(therm);
+			divs /= priv->bios_fan.pwm_freq;
 		}
 
 		duty = ((divs * percent) + 99) / 100;
@@ -163,6 +163,11 @@
 		priv->bios_fan.min_duty = priv->bios_fan.max_duty;
 }
 
+int nouveau_fan_pwm_clock_dummy(struct nouveau_therm *therm)
+{
+	return 1;
+}
+
 int
 nouveau_therm_fan_ctor(struct nouveau_therm *therm)
 {
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c
index f7f51f3..de7dc20 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c
@@ -80,6 +80,32 @@
 }
 
 int
+nv50_fan_pwm_clock(struct nouveau_therm *therm)
+{
+	int chipset = nv_device(therm)->chipset;
+	int crystal = nv_device(therm)->crystal;
+	int pwm_clock;
+
+	/* determine the PWM source clock */
+	if (chipset > 0x50 && chipset < 0x94) {
+		u8 pwm_div = nv_rd32(therm, 0x410c);
+		if (nv_rd32(therm, 0xc040) & 0x800000) {
+			/* Use the HOST clock (100 MHz)
+			* Where does this constant(2.4) comes from? */
+			pwm_clock = (100000000 >> pwm_div) / 10 / 24;
+		} else {
+			/* Where does this constant(20) comes from? */
+			pwm_clock = (crystal * 1000) >> pwm_div;
+			pwm_clock /= 20;
+		}
+	} else {
+		pwm_clock = (crystal * 1000) / 20;
+	}
+
+	return pwm_clock;
+}
+
+int
 nv50_temp_get(struct nouveau_therm *therm)
 {
 	return nv_rd32(therm, 0x20400);
@@ -107,6 +133,7 @@
 
 	priv->fan.pwm_get = nv50_fan_pwm_get;
 	priv->fan.pwm_set = nv50_fan_pwm_set;
+	priv->fan.pwm_clock = nv50_fan_pwm_clock;
 
 	therm->temp_get = nv50_temp_get;
 	therm->fan_get = nouveau_therm_fan_get;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h
index b7207b4..c53eb53 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h
+++ b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h
@@ -42,6 +42,7 @@
 
 		int (*pwm_get)(struct nouveau_therm *, int line, u32*, u32*);
 		int (*pwm_set)(struct nouveau_therm *, int line, u32, u32);
+		int (*pwm_clock)(struct nouveau_therm *);
 	} fan;
 
 	/* ic */