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.
27 #include <subdev/bios/fan.h>
28 #include <subdev/gpio.h>
29 #include <subdev/timer.h>
32 nvkm_fan_update(struct nvkm_fan
*fan
, bool immediate
, int target
)
34 struct nvkm_therm
*therm
= fan
->parent
;
35 struct nvkm_subdev
*subdev
= &therm
->subdev
;
36 struct nvkm_timer
*tmr
= subdev
->device
->timer
;
41 /* update target fan speed, restricting to allowed range */
42 spin_lock_irqsave(&fan
->lock
, flags
);
44 target
= fan
->percent
;
45 target
= max_t(u8
, target
, fan
->bios
.min_duty
);
46 target
= min_t(u8
, target
, fan
->bios
.max_duty
);
47 if (fan
->percent
!= target
) {
48 nvkm_debug(subdev
, "FAN target: %d\n", target
);
49 fan
->percent
= target
;
52 /* check that we're not already at the target duty cycle */
53 duty
= fan
->get(therm
);
55 spin_unlock_irqrestore(&fan
->lock
, flags
);
59 /* smooth out the fanspeed increase/decrease */
60 if (!immediate
&& duty
>= 0) {
61 /* the constant "3" is a rough approximation taken from
63 * it is meant to bump the fan speed more incrementally
66 duty
= min(duty
+ 3, target
);
67 else if (duty
> target
)
68 duty
= max(duty
- 3, target
);
73 nvkm_debug(subdev
, "FAN update: %d\n", duty
);
74 ret
= fan
->set(therm
, duty
);
76 spin_unlock_irqrestore(&fan
->lock
, flags
);
80 /* fan speed updated, drop the fan lock before grabbing the
81 * alarm-scheduling lock and risking a deadlock
83 spin_unlock_irqrestore(&fan
->lock
, flags
);
85 /* schedule next fan update, if not at target speed already */
87 u16 bump_period
= fan
->bios
.bump_period
;
88 u16 slow_down_period
= fan
->bios
.slow_down_period
;
92 delay
= slow_down_period
;
93 else if (duty
== target
)
94 delay
= min(bump_period
, slow_down_period
) ;
98 nvkm_timer_alarm(tmr
, delay
* 1000 * 1000, &fan
->alarm
);
105 nvkm_fan_alarm(struct nvkm_alarm
*alarm
)
107 struct nvkm_fan
*fan
= container_of(alarm
, struct nvkm_fan
, alarm
);
108 nvkm_fan_update(fan
, false, -1);
112 nvkm_therm_fan_get(struct nvkm_therm
*therm
)
114 return therm
->fan
->get(therm
);
118 nvkm_therm_fan_set(struct nvkm_therm
*therm
, bool immediate
, int percent
)
120 return nvkm_fan_update(therm
->fan
, immediate
, percent
);
124 nvkm_therm_fan_sense(struct nvkm_therm
*therm
)
126 struct nvkm_device
*device
= therm
->subdev
.device
;
127 struct nvkm_timer
*tmr
= device
->timer
;
128 struct nvkm_gpio
*gpio
= device
->gpio
;
129 u32 cycles
, cur
, prev
;
130 u64 start
, end
, tach
;
132 if (therm
->func
->fan_sense
)
133 return therm
->func
->fan_sense(therm
);
135 if (therm
->fan
->tach
.func
== DCB_GPIO_UNUSED
)
138 /* Time a complete rotation and extrapolate to RPM:
139 * When the fan spins, it changes the value of GPIO FAN_SENSE.
140 * We get 4 changes (0 -> 1 -> 0 -> 1) per complete rotation.
142 start
= nvkm_timer_read(tmr
);
143 prev
= nvkm_gpio_get(gpio
, 0, therm
->fan
->tach
.func
,
144 therm
->fan
->tach
.line
);
147 usleep_range(500, 1000); /* supports 0 < rpm < 7500 */
149 cur
= nvkm_gpio_get(gpio
, 0, therm
->fan
->tach
.func
,
150 therm
->fan
->tach
.line
);
153 start
= nvkm_timer_read(tmr
);
157 } while (cycles
< 5 && nvkm_timer_read(tmr
) - start
< 250000000);
158 end
= nvkm_timer_read(tmr
);
161 tach
= (u64
)60000000000ULL;
162 do_div(tach
, (end
- start
));
169 nvkm_therm_fan_user_get(struct nvkm_therm
*therm
)
171 return nvkm_therm_fan_get(therm
);
175 nvkm_therm_fan_user_set(struct nvkm_therm
*therm
, int percent
)
177 if (therm
->mode
!= NVKM_THERM_CTRL_MANUAL
)
180 return nvkm_therm_fan_set(therm
, true, percent
);
184 nvkm_therm_fan_set_defaults(struct nvkm_therm
*therm
)
186 therm
->fan
->bios
.pwm_freq
= 0;
187 therm
->fan
->bios
.min_duty
= 0;
188 therm
->fan
->bios
.max_duty
= 100;
189 therm
->fan
->bios
.bump_period
= 500;
190 therm
->fan
->bios
.slow_down_period
= 2000;
191 therm
->fan
->bios
.linear_min_temp
= 40;
192 therm
->fan
->bios
.linear_max_temp
= 85;
196 nvkm_therm_fan_safety_checks(struct nvkm_therm
*therm
)
198 if (therm
->fan
->bios
.min_duty
> 100)
199 therm
->fan
->bios
.min_duty
= 100;
200 if (therm
->fan
->bios
.max_duty
> 100)
201 therm
->fan
->bios
.max_duty
= 100;
203 if (therm
->fan
->bios
.min_duty
> therm
->fan
->bios
.max_duty
)
204 therm
->fan
->bios
.min_duty
= therm
->fan
->bios
.max_duty
;
208 nvkm_therm_fan_init(struct nvkm_therm
*therm
)
214 nvkm_therm_fan_fini(struct nvkm_therm
*therm
, bool suspend
)
216 struct nvkm_timer
*tmr
= therm
->subdev
.device
->timer
;
218 nvkm_timer_alarm(tmr
, 0, &therm
->fan
->alarm
);
223 nvkm_therm_fan_ctor(struct nvkm_therm
*therm
)
225 struct nvkm_subdev
*subdev
= &therm
->subdev
;
226 struct nvkm_device
*device
= subdev
->device
;
227 struct nvkm_gpio
*gpio
= device
->gpio
;
228 struct nvkm_bios
*bios
= device
->bios
;
229 struct dcb_gpio_func func
;
232 /* attempt to locate a drivable fan, and determine control method */
233 ret
= nvkm_gpio_find(gpio
, 0, DCB_GPIO_FAN
, 0xff, &func
);
235 /* FIXME: is this really the place to perform such checks ? */
236 if (func
.line
!= 16 && func
.log
[0] & DCB_GPIO_LOG_DIR_IN
) {
237 nvkm_debug(subdev
, "GPIO_FAN is in input mode\n");
240 ret
= nvkm_fanpwm_create(therm
, &func
);
242 ret
= nvkm_fantog_create(therm
, &func
);
246 /* no controllable fan found, create a dummy fan module */
248 ret
= nvkm_fannil_create(therm
);
253 nvkm_debug(subdev
, "FAN control: %s\n", therm
->fan
->type
);
255 /* read the current speed, it is useful when resuming */
256 therm
->fan
->percent
= nvkm_therm_fan_get(therm
);
258 /* attempt to detect a tachometer connection */
259 ret
= nvkm_gpio_find(gpio
, 0, DCB_GPIO_FAN_SENSE
, 0xff,
262 therm
->fan
->tach
.func
= DCB_GPIO_UNUSED
;
264 /* initialise fan bump/slow update handling */
265 therm
->fan
->parent
= therm
;
266 nvkm_alarm_init(&therm
->fan
->alarm
, nvkm_fan_alarm
);
267 spin_lock_init(&therm
->fan
->lock
);
269 /* other random init... */
270 nvkm_therm_fan_set_defaults(therm
);
271 nvbios_perf_fan_parse(bios
, &therm
->fan
->perf
);
272 if (!nvbios_fan_parse(bios
, &therm
->fan
->bios
)) {
273 nvkm_debug(subdev
, "parsing the fan table failed\n");
274 if (nvbios_therm_fan_parse(bios
, &therm
->fan
->bios
))
275 nvkm_error(subdev
, "parsing both fan tables failed\n");
277 nvkm_therm_fan_safety_checks(therm
);