]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.c
Merge remote-tracking branches 'asoc/fix/intel', 'asoc/fix/topology' and 'asoc/fix...
[karo-tx-linux.git] / drivers / gpu / drm / amd / powerplay / hwmgr / smu7_thermal.c
1 /*
2  * Copyright 2016 Advanced Micro Devices, Inc.
3  *
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:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
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.
21  *
22  */
23
24 #include <asm/div64.h>
25 #include "smu7_thermal.h"
26 #include "smu7_hwmgr.h"
27 #include "smu7_common.h"
28
29 int smu7_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
30                 struct phm_fan_speed_info *fan_speed_info)
31 {
32         if (hwmgr->thermal_controller.fanInfo.bNoFan)
33                 return -ENODEV;
34
35         fan_speed_info->supports_percent_read = true;
36         fan_speed_info->supports_percent_write = true;
37         fan_speed_info->min_percent = 0;
38         fan_speed_info->max_percent = 100;
39
40         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
41                         PHM_PlatformCaps_FanSpeedInTableIsRPM) &&
42                 hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) {
43                 fan_speed_info->supports_rpm_read = true;
44                 fan_speed_info->supports_rpm_write = true;
45                 fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM;
46                 fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM;
47         } else {
48                 fan_speed_info->min_rpm = 0;
49                 fan_speed_info->max_rpm = 0;
50         }
51
52         return 0;
53 }
54
55 int smu7_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr,
56                 uint32_t *speed)
57 {
58         uint32_t duty100;
59         uint32_t duty;
60         uint64_t tmp64;
61
62         if (hwmgr->thermal_controller.fanInfo.bNoFan)
63                 return -ENODEV;
64
65         duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
66                         CG_FDO_CTRL1, FMAX_DUTY100);
67         duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
68                         CG_THERMAL_STATUS, FDO_PWM_DUTY);
69
70         if (duty100 == 0)
71                 return -EINVAL;
72
73
74         tmp64 = (uint64_t)duty * 100;
75         do_div(tmp64, duty100);
76         *speed = (uint32_t)tmp64;
77
78         if (*speed > 100)
79                 *speed = 100;
80
81         return 0;
82 }
83
84 int smu7_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
85 {
86         uint32_t tach_period;
87         uint32_t crystal_clock_freq;
88
89         if (hwmgr->thermal_controller.fanInfo.bNoFan ||
90                         (hwmgr->thermal_controller.fanInfo.
91                                 ucTachometerPulsesPerRevolution == 0))
92                 return -ENODEV;
93
94         tach_period = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
95                         CG_TACH_STATUS, TACH_PERIOD);
96
97         if (tach_period == 0)
98                 return -EINVAL;
99
100         crystal_clock_freq = smu7_get_xclk(hwmgr);
101
102         *speed = 60 * crystal_clock_freq * 10000 / tach_period;
103
104         return 0;
105 }
106
107 /**
108 * Set Fan Speed Control to static mode, so that the user can decide what speed to use.
109 * @param    hwmgr  the address of the powerplay hardware manager.
110 *           mode    the fan control mode, 0 default, 1 by percent, 5, by RPM
111 * @exception Should always succeed.
112 */
113 int smu7_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
114 {
115
116         if (hwmgr->fan_ctrl_is_in_default_mode) {
117                 hwmgr->fan_ctrl_default_mode =
118                                 PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,     CGS_IND_REG__SMC,
119                                                 CG_FDO_CTRL2, FDO_PWM_MODE);
120                 hwmgr->tmin =
121                                 PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
122                                                 CG_FDO_CTRL2, TMIN);
123                 hwmgr->fan_ctrl_is_in_default_mode = false;
124         }
125
126         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
127                         CG_FDO_CTRL2, TMIN, 0);
128         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
129                         CG_FDO_CTRL2, FDO_PWM_MODE, mode);
130
131         return 0;
132 }
133
134 /**
135 * Reset Fan Speed Control to default mode.
136 * @param    hwmgr  the address of the powerplay hardware manager.
137 * @exception Should always succeed.
138 */
139 int smu7_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
140 {
141         if (!hwmgr->fan_ctrl_is_in_default_mode) {
142                 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
143                                 CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode);
144                 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
145                                 CG_FDO_CTRL2, TMIN, hwmgr->tmin);
146                 hwmgr->fan_ctrl_is_in_default_mode = true;
147         }
148
149         return 0;
150 }
151
152 static int smu7_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
153 {
154         int result;
155
156         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
157                         PHM_PlatformCaps_ODFuzzyFanControlSupport)) {
158                 cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_FUZZY);
159                 result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl);
160
161                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
162                                 PHM_PlatformCaps_FanSpeedInTableIsRPM))
163                         hwmgr->hwmgr_func->set_max_fan_rpm_output(hwmgr,
164                                         hwmgr->thermal_controller.
165                                         advanceFanControlParameters.usMaxFanRPM);
166                 else
167                         hwmgr->hwmgr_func->set_max_fan_pwm_output(hwmgr,
168                                         hwmgr->thermal_controller.
169                                         advanceFanControlParameters.usMaxFanPWM);
170
171         } else {
172                 cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_TABLE);
173                 result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl);
174         }
175
176         if (!result && hwmgr->thermal_controller.
177                         advanceFanControlParameters.ucTargetTemperature)
178                 result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
179                                 PPSMC_MSG_SetFanTemperatureTarget,
180                                 hwmgr->thermal_controller.
181                                 advanceFanControlParameters.ucTargetTemperature);
182
183         return result;
184 }
185
186
187 int smu7_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
188 {
189         return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl);
190 }
191
192 /**
193 * Set Fan Speed in percent.
194 * @param    hwmgr  the address of the powerplay hardware manager.
195 * @param    speed is the percentage value (0% - 100%) to be set.
196 * @exception Fails is the 100% setting appears to be 0.
197 */
198 int smu7_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr,
199                 uint32_t speed)
200 {
201         uint32_t duty100;
202         uint32_t duty;
203         uint64_t tmp64;
204
205         if (hwmgr->thermal_controller.fanInfo.bNoFan)
206                 return 0;
207
208         if (speed > 100)
209                 speed = 100;
210
211         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
212                         PHM_PlatformCaps_MicrocodeFanControl))
213                 smu7_fan_ctrl_stop_smc_fan_control(hwmgr);
214
215         duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
216                         CG_FDO_CTRL1, FMAX_DUTY100);
217
218         if (duty100 == 0)
219                 return -EINVAL;
220
221         tmp64 = (uint64_t)speed * duty100;
222         do_div(tmp64, 100);
223         duty = (uint32_t)tmp64;
224
225         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
226                         CG_FDO_CTRL0, FDO_STATIC_DUTY, duty);
227
228         return smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
229 }
230
231 /**
232 * Reset Fan Speed to default.
233 * @param    hwmgr  the address of the powerplay hardware manager.
234 * @exception Always succeeds.
235 */
236 int smu7_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
237 {
238         int result;
239
240         if (hwmgr->thermal_controller.fanInfo.bNoFan)
241                 return 0;
242
243         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
244                         PHM_PlatformCaps_MicrocodeFanControl)) {
245                 result = smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
246                 if (!result)
247                         result = smu7_fan_ctrl_start_smc_fan_control(hwmgr);
248         } else
249                 result = smu7_fan_ctrl_set_default_mode(hwmgr);
250
251         return result;
252 }
253
254 /**
255 * Set Fan Speed in RPM.
256 * @param    hwmgr  the address of the powerplay hardware manager.
257 * @param    speed is the percentage value (min - max) to be set.
258 * @exception Fails is the speed not lie between min and max.
259 */
260 int smu7_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
261 {
262         uint32_t tach_period;
263         uint32_t crystal_clock_freq;
264
265         if (hwmgr->thermal_controller.fanInfo.bNoFan ||
266                         (hwmgr->thermal_controller.fanInfo.
267                         ucTachometerPulsesPerRevolution == 0) ||
268                         (speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) ||
269                         (speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM))
270                 return 0;
271
272         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
273                         PHM_PlatformCaps_MicrocodeFanControl))
274                 smu7_fan_ctrl_stop_smc_fan_control(hwmgr);
275
276         crystal_clock_freq = smu7_get_xclk(hwmgr);
277
278         tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
279
280         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
281                                 CG_TACH_STATUS, TACH_PERIOD, tach_period);
282
283         return smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
284 }
285
286 /**
287 * Reads the remote temperature from the SIslands thermal controller.
288 *
289 * @param    hwmgr The address of the hardware manager.
290 */
291 int smu7_thermal_get_temperature(struct pp_hwmgr *hwmgr)
292 {
293         int temp;
294
295         temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
296                         CG_MULT_THERMAL_STATUS, CTF_TEMP);
297
298         /* Bit 9 means the reading is lower than the lowest usable value. */
299         if (temp & 0x200)
300                 temp = SMU7_THERMAL_MAXIMUM_TEMP_READING;
301         else
302                 temp = temp & 0x1ff;
303
304         temp *= PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
305
306         return temp;
307 }
308
309 /**
310 * Set the requested temperature range for high and low alert signals
311 *
312 * @param    hwmgr The address of the hardware manager.
313 * @param    range Temperature range to be programmed for high and low alert signals
314 * @exception PP_Result_BadInput if the input data is not valid.
315 */
316 static int smu7_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
317                 uint32_t low_temp, uint32_t high_temp)
318 {
319         uint32_t low = SMU7_THERMAL_MINIMUM_ALERT_TEMP *
320                         PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
321         uint32_t high = SMU7_THERMAL_MAXIMUM_ALERT_TEMP *
322                         PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
323
324         if (low < low_temp)
325                 low = low_temp;
326         if (high > high_temp)
327                 high = high_temp;
328
329         if (low > high)
330                 return -EINVAL;
331
332         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
333                         CG_THERMAL_INT, DIG_THERM_INTH,
334                         (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
335         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
336                         CG_THERMAL_INT, DIG_THERM_INTL,
337                         (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
338         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
339                         CG_THERMAL_CTRL, DIG_THERM_DPM,
340                         (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
341
342         return 0;
343 }
344
345 /**
346 * Programs thermal controller one-time setting registers
347 *
348 * @param    hwmgr The address of the hardware manager.
349 */
350 static int smu7_thermal_initialize(struct pp_hwmgr *hwmgr)
351 {
352         if (hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
353                 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
354                                 CG_TACH_CTRL, EDGE_PER_REV,
355                                 hwmgr->thermal_controller.fanInfo.
356                                 ucTachometerPulsesPerRevolution - 1);
357
358         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
359                         CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28);
360
361         return 0;
362 }
363
364 /**
365 * Enable thermal alerts on the RV770 thermal controller.
366 *
367 * @param    hwmgr The address of the hardware manager.
368 */
369 int smu7_thermal_enable_alert(struct pp_hwmgr *hwmgr)
370 {
371         uint32_t alert;
372
373         alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
374                         CG_THERMAL_INT, THERM_INT_MASK);
375         alert &= ~(SMU7_THERMAL_HIGH_ALERT_MASK | SMU7_THERMAL_LOW_ALERT_MASK);
376         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
377                         CG_THERMAL_INT, THERM_INT_MASK, alert);
378
379         /* send message to SMU to enable internal thermal interrupts */
380         return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable);
381 }
382
383 /**
384 * Disable thermal alerts on the RV770 thermal controller.
385 * @param    hwmgr The address of the hardware manager.
386 */
387 int smu7_thermal_disable_alert(struct pp_hwmgr *hwmgr)
388 {
389         uint32_t alert;
390
391         alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
392                         CG_THERMAL_INT, THERM_INT_MASK);
393         alert |= (SMU7_THERMAL_HIGH_ALERT_MASK | SMU7_THERMAL_LOW_ALERT_MASK);
394         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
395                         CG_THERMAL_INT, THERM_INT_MASK, alert);
396
397         /* send message to SMU to disable internal thermal interrupts */
398         return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable);
399 }
400
401 /**
402 * Uninitialize the thermal controller.
403 * Currently just disables alerts.
404 * @param    hwmgr The address of the hardware manager.
405 */
406 int smu7_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
407 {
408         int result = smu7_thermal_disable_alert(hwmgr);
409
410         if (!hwmgr->thermal_controller.fanInfo.bNoFan)
411                 smu7_fan_ctrl_set_default_mode(hwmgr);
412
413         return result;
414 }
415
416 /**
417 * Start the fan control on the SMC.
418 * @param    hwmgr  the address of the powerplay hardware manager.
419 * @param    pInput the pointer to input data
420 * @param    pOutput the pointer to output data
421 * @param    pStorage the pointer to temporary storage
422 * @param    Result the last failure code
423 * @return   result from set temperature range routine
424 */
425 static int tf_smu7_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr,
426                 void *input, void *output, void *storage, int result)
427 {
428 /* If the fantable setup has failed we could have disabled
429  * PHM_PlatformCaps_MicrocodeFanControl even after
430  * this function was included in the table.
431  * Make sure that we still think controlling the fan is OK.
432 */
433         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
434                         PHM_PlatformCaps_MicrocodeFanControl)) {
435                 smu7_fan_ctrl_start_smc_fan_control(hwmgr);
436                 smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
437         }
438
439         return 0;
440 }
441
442 /**
443 * Set temperature range for high and low alerts
444 * @param    hwmgr  the address of the powerplay hardware manager.
445 * @param    pInput the pointer to input data
446 * @param    pOutput the pointer to output data
447 * @param    pStorage the pointer to temporary storage
448 * @param    Result the last failure code
449 * @return   result from set temperature range routine
450 */
451 static int tf_smu7_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
452                 void *input, void *output, void *storage, int result)
453 {
454         struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input;
455
456         if (range == NULL)
457                 return -EINVAL;
458
459         return smu7_thermal_set_temperature_range(hwmgr, range->min, range->max);
460 }
461
462 /**
463 * Programs one-time setting registers
464 * @param    hwmgr  the address of the powerplay hardware manager.
465 * @param    pInput the pointer to input data
466 * @param    pOutput the pointer to output data
467 * @param    pStorage the pointer to temporary storage
468 * @param    Result the last failure code
469 * @return   result from initialize thermal controller routine
470 */
471 static int tf_smu7_thermal_initialize(struct pp_hwmgr *hwmgr,
472                 void *input, void *output, void *storage, int result)
473 {
474         return smu7_thermal_initialize(hwmgr);
475 }
476
477 /**
478 * Enable high and low alerts
479 * @param    hwmgr  the address of the powerplay hardware manager.
480 * @param    pInput the pointer to input data
481 * @param    pOutput the pointer to output data
482 * @param    pStorage the pointer to temporary storage
483 * @param    Result the last failure code
484 * @return   result from enable alert routine
485 */
486 static int tf_smu7_thermal_enable_alert(struct pp_hwmgr *hwmgr,
487                 void *input, void *output, void *storage, int result)
488 {
489         return smu7_thermal_enable_alert(hwmgr);
490 }
491
492 /**
493 * Disable high and low alerts
494 * @param    hwmgr  the address of the powerplay hardware manager.
495 * @param    pInput the pointer to input data
496 * @param    pOutput the pointer to output data
497 * @param    pStorage the pointer to temporary storage
498 * @param    Result the last failure code
499 * @return   result from disable alert routine
500 */
501 static int tf_smu7_thermal_disable_alert(struct pp_hwmgr *hwmgr,
502                 void *input, void *output, void *storage, int result)
503 {
504         return smu7_thermal_disable_alert(hwmgr);
505 }
506
507 static const struct phm_master_table_item
508 phm_thermal_start_thermal_controller_master_list[] = {
509         { .tableFunction = tf_smu7_thermal_initialize },
510         { .tableFunction = tf_smu7_thermal_set_temperature_range },
511         { .tableFunction = tf_smu7_thermal_enable_alert },
512         { .tableFunction = smum_thermal_avfs_enable },
513 /* We should restrict performance levels to low before we halt the SMC.
514  * On the other hand we are still in boot state when we do this
515  * so it would be pointless.
516  * If this assumption changes we have to revisit this table.
517  */
518         { .tableFunction = smum_thermal_setup_fan_table },
519         { .tableFunction = tf_smu7_thermal_start_smc_fan_control },
520         { }
521 };
522
523 static const struct phm_master_table_header
524 phm_thermal_start_thermal_controller_master = {
525         0,
526         PHM_MasterTableFlag_None,
527         phm_thermal_start_thermal_controller_master_list
528 };
529
530 static const struct phm_master_table_item
531 phm_thermal_set_temperature_range_master_list[] = {
532         { .tableFunction = tf_smu7_thermal_disable_alert },
533         { .tableFunction = tf_smu7_thermal_set_temperature_range },
534         { .tableFunction = tf_smu7_thermal_enable_alert },
535         { }
536 };
537
538 static const struct phm_master_table_header
539 phm_thermal_set_temperature_range_master = {
540         0,
541         PHM_MasterTableFlag_None,
542         phm_thermal_set_temperature_range_master_list
543 };
544
545 int smu7_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
546 {
547         if (!hwmgr->thermal_controller.fanInfo.bNoFan)
548                 smu7_fan_ctrl_set_default_mode(hwmgr);
549         return 0;
550 }
551
552 /**
553 * Initializes the thermal controller related functions in the Hardware Manager structure.
554 * @param    hwmgr The address of the hardware manager.
555 * @exception Any error code from the low-level communication.
556 */
557 int pp_smu7_thermal_initialize(struct pp_hwmgr *hwmgr)
558 {
559         int result;
560
561         result = phm_construct_table(hwmgr,
562                         &phm_thermal_set_temperature_range_master,
563                         &(hwmgr->set_temperature_range));
564
565         if (!result) {
566                 result = phm_construct_table(hwmgr,
567                                 &phm_thermal_start_thermal_controller_master,
568                                 &(hwmgr->start_thermal_controller));
569                 if (result)
570                         phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
571         }
572
573         if (!result)
574                 hwmgr->fan_ctrl_is_in_default_mode = true;
575         return result;
576 }
577
578 void pp_smu7_thermal_fini(struct pp_hwmgr *hwmgr)
579 {
580         phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
581         phm_destroy_table(hwmgr, &(hwmgr->start_thermal_controller));
582         return;
583 }