2 * Copyright 2012 Red Hat Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
28 #include <core/object.h>
29 #include <core/device.h>
31 #include <subdev/gpio.h>
32 #include <subdev/timer.h>
35 nouveau_fan_update(struct nouveau_fan
*fan
, bool immediate
, int target
)
37 struct nouveau_therm
*therm
= fan
->parent
;
38 struct nouveau_therm_priv
*priv
= (void *)therm
;
39 struct nouveau_timer
*ptimer
= nouveau_timer(priv
);
44 /* update target fan speed, restricting to allowed range */
45 spin_lock_irqsave(&fan
->lock
, flags
);
47 target
= fan
->percent
;
48 target
= max_t(u8
, target
, fan
->bios
.min_duty
);
49 target
= min_t(u8
, target
, fan
->bios
.max_duty
);
50 if (fan
->percent
!= target
) {
51 nv_debug(therm
, "FAN target: %d\n", target
);
52 fan
->percent
= target
;
55 /* check that we're not already at the target duty cycle */
56 duty
= fan
->get(therm
);
58 spin_unlock_irqrestore(&fan
->lock
, flags
);
62 /* smooth out the fanspeed increase/decrease */
63 if (!immediate
&& duty
>= 0) {
64 /* the constant "3" is a rough approximation taken from
66 * it is meant to bump the fan speed more incrementally
69 duty
= min(duty
+ 3, target
);
70 else if (duty
> target
)
71 duty
= max(duty
- 3, target
);
76 nv_debug(therm
, "FAN update: %d\n", duty
);
77 ret
= fan
->set(therm
, duty
);
79 spin_unlock_irqrestore(&fan
->lock
, flags
);
83 /* fan speed updated, drop the fan lock before grabbing the
84 * alarm-scheduling lock and risking a deadlock
86 spin_unlock_irqrestore(&fan
->lock
, flags
);
88 /* schedule next fan update, if not at target speed already */
89 if (list_empty(&fan
->alarm
.head
) && target
!= duty
) {
90 u16 bump_period
= fan
->bios
.bump_period
;
91 u16 slow_down_period
= fan
->bios
.slow_down_period
;
95 delay
= slow_down_period
;
96 else if (duty
== target
)
97 delay
= min(bump_period
, slow_down_period
) ;
101 ptimer
->alarm(ptimer
, delay
* 1000 * 1000, &fan
->alarm
);
108 nouveau_fan_alarm(struct nouveau_alarm
*alarm
)
110 struct nouveau_fan
*fan
= container_of(alarm
, struct nouveau_fan
, alarm
);
111 nouveau_fan_update(fan
, false, -1);
115 nouveau_therm_fan_get(struct nouveau_therm
*therm
)
117 struct nouveau_therm_priv
*priv
= (void *)therm
;
118 return priv
->fan
->get(therm
);
122 nouveau_therm_fan_set(struct nouveau_therm
*therm
, bool immediate
, int percent
)
124 struct nouveau_therm_priv
*priv
= (void *)therm
;
125 return nouveau_fan_update(priv
->fan
, immediate
, percent
);
129 nouveau_therm_fan_sense(struct nouveau_therm
*therm
)
131 struct nouveau_therm_priv
*priv
= (void *)therm
;
132 struct nouveau_timer
*ptimer
= nouveau_timer(therm
);
133 struct nouveau_gpio
*gpio
= nouveau_gpio(therm
);
134 u32 cycles
, cur
, prev
;
135 u64 start
, end
, tach
;
137 if (priv
->fan
->tach
.func
== DCB_GPIO_UNUSED
)
140 /* Time a complete rotation and extrapolate to RPM:
141 * When the fan spins, it changes the value of GPIO FAN_SENSE.
142 * We get 4 changes (0 -> 1 -> 0 -> 1) per complete rotation.
144 start
= ptimer
->read(ptimer
);
145 prev
= gpio
->get(gpio
, 0, priv
->fan
->tach
.func
, priv
->fan
->tach
.line
);
148 usleep_range(500, 1000); /* supports 0 < rpm < 7500 */
150 cur
= gpio
->get(gpio
, 0, priv
->fan
->tach
.func
, priv
->fan
->tach
.line
);
153 start
= ptimer
->read(ptimer
);
157 } while (cycles
< 5 && ptimer
->read(ptimer
) - start
< 250000000);
158 end
= ptimer
->read(ptimer
);
161 tach
= (u64
)60000000000ULL;
162 do_div(tach
, (end
- start
));
169 nouveau_therm_fan_user_get(struct nouveau_therm
*therm
)
171 return nouveau_therm_fan_get(therm
);
175 nouveau_therm_fan_user_set(struct nouveau_therm
*therm
, int percent
)
177 struct nouveau_therm_priv
*priv
= (void *)therm
;
179 if (priv
->mode
!= NOUVEAU_THERM_CTRL_MANUAL
)
182 return nouveau_therm_fan_set(therm
, true, percent
);
186 nouveau_therm_fan_set_defaults(struct nouveau_therm
*therm
)
188 struct nouveau_therm_priv
*priv
= (void *)therm
;
190 priv
->fan
->bios
.pwm_freq
= 0;
191 priv
->fan
->bios
.min_duty
= 0;
192 priv
->fan
->bios
.max_duty
= 100;
193 priv
->fan
->bios
.bump_period
= 500;
194 priv
->fan
->bios
.slow_down_period
= 2000;
195 /*XXX: talk to mupuf */
197 priv
->fan
->bios
.linear_min_temp
= 40;
198 priv
->fan
->bios
.linear_max_temp
= 85;
203 nouveau_therm_fan_safety_checks(struct nouveau_therm
*therm
)
205 struct nouveau_therm_priv
*priv
= (void *)therm
;
207 if (priv
->fan
->bios
.min_duty
> 100)
208 priv
->fan
->bios
.min_duty
= 100;
209 if (priv
->fan
->bios
.max_duty
> 100)
210 priv
->fan
->bios
.max_duty
= 100;
212 if (priv
->fan
->bios
.min_duty
> priv
->fan
->bios
.max_duty
)
213 priv
->fan
->bios
.min_duty
= priv
->fan
->bios
.max_duty
;
217 nouveau_therm_fan_init(struct nouveau_therm
*therm
)
223 nouveau_therm_fan_fini(struct nouveau_therm
*therm
, bool suspend
)
225 struct nouveau_therm_priv
*priv
= (void *)therm
;
226 struct nouveau_timer
*ptimer
= nouveau_timer(therm
);
229 ptimer
->alarm_cancel(ptimer
, &priv
->fan
->alarm
);
234 nouveau_therm_fan_ctor(struct nouveau_therm
*therm
)
236 struct nouveau_therm_priv
*priv
= (void *)therm
;
237 struct nouveau_gpio
*gpio
= nouveau_gpio(therm
);
238 struct nouveau_bios
*bios
= nouveau_bios(therm
);
239 struct dcb_gpio_func func
;
242 /* attempt to locate a drivable fan, and determine control method */
243 ret
= gpio
->find(gpio
, 0, DCB_GPIO_FAN
, 0xff, &func
);
245 if (func
.log
[0] & DCB_GPIO_LOG_DIR_IN
) {
246 nv_debug(therm
, "GPIO_FAN is in input mode\n");
249 ret
= nouveau_fanpwm_create(therm
, &func
);
251 ret
= nouveau_fantog_create(therm
, &func
);
255 /* no controllable fan found, create a dummy fan module */
257 ret
= nouveau_fannil_create(therm
);
262 nv_info(therm
, "FAN control: %s\n", priv
->fan
->type
);
264 /* read the current speed, it is useful when resuming */
265 priv
->fan
->percent
= nouveau_therm_fan_get(therm
);
267 /* attempt to detect a tachometer connection */
268 ret
= gpio
->find(gpio
, 0, DCB_GPIO_FAN_SENSE
, 0xff, &priv
->fan
->tach
);
270 priv
->fan
->tach
.func
= DCB_GPIO_UNUSED
;
272 /* initialise fan bump/slow update handling */
273 priv
->fan
->parent
= therm
;
274 nouveau_alarm_init(&priv
->fan
->alarm
, nouveau_fan_alarm
);
275 spin_lock_init(&priv
->fan
->lock
);
277 /* other random init... */
278 nouveau_therm_fan_set_defaults(therm
);
279 nvbios_perf_fan_parse(bios
, &priv
->fan
->perf
);
280 if (nvbios_therm_fan_parse(bios
, &priv
->fan
->bios
))
281 nv_error(therm
, "parsing the thermal table failed\n");
282 nouveau_therm_fan_safety_checks(therm
);