drm/nouveau/therm: calculate the pwm divisor on nv50+
authorMartin Peres <martin.peres@labri.fr>
Sun, 2 Sep 2012 02:01:43 +0000 (04:01 +0200)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 3 Oct 2012 03:13:14 +0000 (13:13 +1000)
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>
drivers/gpu/drm/nouveau/core/subdev/therm/fan.c
drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c
drivers/gpu/drm/nouveau/core/subdev/therm/priv.h

index b7339b5..409b95d 100644 (file)
@@ -81,10 +81,10 @@ nouveau_therm_fan_set(struct nouveau_therm *therm, int percent)
        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 @@ nouveau_therm_fan_safety_checks(struct nouveau_therm *therm)
                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)
 {
index f7f51f3..de7dc20 100644 (file)
@@ -79,6 +79,32 @@ nv50_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
        return 0;
 }
 
+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)
 {
@@ -107,6 +133,7 @@ nv50_therm_ctor(struct nouveau_object *parent,
 
        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;
index b7207b4..c53eb53 100644 (file)
@@ -42,6 +42,7 @@ struct nouveau_therm_priv {
 
                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 */