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;
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)
{
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)
{
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;
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 */