Commit | Line | Data |
---|---|---|
025f8bfb HR |
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 | * Author: Huang Rui <ray.huang@amd.com> | |
23 | * | |
24 | */ | |
25 | #include <asm/div64.h> | |
26 | #include "iceland_thermal.h" | |
27 | #include "iceland_hwmgr.h" | |
28 | #include "iceland_smumgr.h" | |
29 | #include "atombios.h" | |
30 | #include "ppsmc.h" | |
31 | ||
32 | #include "gmc/gmc_8_1_d.h" | |
33 | #include "gmc/gmc_8_1_sh_mask.h" | |
34 | ||
35 | #include "bif/bif_5_0_d.h" | |
36 | #include "bif/bif_5_0_sh_mask.h" | |
37 | ||
38 | #include "smu/smu_7_1_1_d.h" | |
39 | #include "smu/smu_7_1_1_sh_mask.h" | |
40 | ||
41 | ||
42 | /** | |
43 | * Get Fan Speed Control Parameters. | |
44 | * @param hwmgr the address of the powerplay hardware manager. | |
45 | * @param pSpeed is the address of the structure where the result is to be placed. | |
46 | * @exception Always succeeds except if we cannot zero out the output structure. | |
47 | */ | |
48 | int iceland_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, | |
49 | struct phm_fan_speed_info *fan_speed_info) | |
50 | { | |
51 | ||
52 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | |
53 | return 0; | |
54 | ||
55 | fan_speed_info->supports_percent_read = true; | |
56 | fan_speed_info->supports_percent_write = true; | |
57 | fan_speed_info->min_percent = 0; | |
58 | fan_speed_info->max_percent = 100; | |
59 | ||
60 | if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) { | |
61 | fan_speed_info->supports_rpm_read = true; | |
62 | fan_speed_info->supports_rpm_write = true; | |
63 | fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM; | |
64 | fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM; | |
65 | } else { | |
66 | fan_speed_info->min_rpm = 0; | |
67 | fan_speed_info->max_rpm = 0; | |
68 | } | |
69 | ||
70 | return 0; | |
71 | } | |
72 | ||
73 | /** | |
74 | * Get Fan Speed in percent. | |
75 | * @param hwmgr the address of the powerplay hardware manager. | |
76 | * @param pSpeed is the address of the structure where the result is to be placed. | |
77 | * @exception Fails is the 100% setting appears to be 0. | |
78 | */ | |
79 | int iceland_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed) | |
80 | { | |
81 | uint32_t duty100; | |
82 | uint32_t duty; | |
83 | uint64_t tmp64; | |
84 | ||
85 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | |
86 | return 0; | |
87 | ||
88 | duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100); | |
89 | duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_STATUS, FDO_PWM_DUTY); | |
90 | ||
91 | if (0 == duty100) | |
92 | return -EINVAL; | |
93 | ||
94 | ||
95 | tmp64 = (uint64_t)duty * 100; | |
96 | do_div(tmp64, duty100); | |
97 | *speed = (uint32_t)tmp64; | |
98 | ||
99 | if (*speed > 100) | |
100 | *speed = 100; | |
101 | ||
102 | return 0; | |
103 | } | |
104 | ||
105 | /** | |
106 | * Get Fan Speed in RPM. | |
107 | * @param hwmgr the address of the powerplay hardware manager. | |
108 | * @param speed is the address of the structure where the result is to be placed. | |
109 | * @exception Returns not supported if no fan is found or if pulses per revolution are not set | |
110 | */ | |
111 | int iceland_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed) | |
112 | { | |
113 | return 0; | |
114 | } | |
115 | ||
116 | /** | |
117 | * Set Fan Speed Control to static mode, so that the user can decide what speed to use. | |
118 | * @param hwmgr the address of the powerplay hardware manager. | |
119 | * mode the fan control mode, 0 default, 1 by percent, 5, by RPM | |
120 | * @exception Should always succeed. | |
121 | */ | |
122 | int iceland_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode) | |
123 | { | |
124 | ||
125 | if (hwmgr->fan_ctrl_is_in_default_mode) { | |
126 | hwmgr->fan_ctrl_default_mode = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE); | |
127 | hwmgr->tmin = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN); | |
128 | hwmgr->fan_ctrl_is_in_default_mode = false; | |
129 | } | |
130 | ||
131 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, 0); | |
132 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, mode); | |
133 | ||
134 | return 0; | |
135 | } | |
136 | ||
137 | /** | |
138 | * Reset Fan Speed Control to default mode. | |
139 | * @param hwmgr the address of the powerplay hardware manager. | |
140 | * @exception Should always succeed. | |
141 | */ | |
142 | static int iceland_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr) | |
143 | { | |
144 | if (!hwmgr->fan_ctrl_is_in_default_mode) { | |
145 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode); | |
146 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, hwmgr->tmin); | |
147 | hwmgr->fan_ctrl_is_in_default_mode = true; | |
148 | } | |
149 | ||
150 | return 0; | |
151 | } | |
152 | ||
153 | int iceland_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr) | |
154 | { | |
155 | return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl) == 0) ? 0 : -EINVAL; | |
156 | } | |
157 | ||
158 | ||
159 | int iceland_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr) | |
160 | { | |
161 | return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl) == 0) ? 0 : -EINVAL; | |
162 | } | |
163 | ||
164 | /** | |
165 | * Set Fan Speed in percent. | |
166 | * @param hwmgr the address of the powerplay hardware manager. | |
167 | * @param speed is the percentage value (0% - 100%) to be set. | |
168 | * @exception Fails is the 100% setting appears to be 0. | |
169 | */ | |
170 | int iceland_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed) | |
171 | { | |
172 | uint32_t duty100; | |
173 | uint32_t duty; | |
174 | uint64_t tmp64; | |
175 | ||
176 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | |
177 | return -EINVAL; | |
178 | ||
179 | if (speed > 100) { | |
180 | pr_warning("Cannot set more than 100%% duty cycle. Set it to 100.\n"); | |
181 | speed = 100; | |
182 | } | |
183 | ||
184 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) | |
185 | iceland_fan_ctrl_stop_smc_fan_control(hwmgr); | |
186 | ||
187 | duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100); | |
188 | ||
189 | if (0 == duty100) | |
190 | return -EINVAL; | |
191 | ||
192 | tmp64 = (uint64_t)speed * duty100; | |
193 | do_div(tmp64, 100); | |
194 | duty = (uint32_t)tmp64; | |
195 | ||
196 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL0, FDO_STATIC_DUTY, duty); | |
197 | ||
198 | return iceland_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC); | |
199 | } | |
200 | ||
201 | /** | |
202 | * Reset Fan Speed to default. | |
203 | * @param hwmgr the address of the powerplay hardware manager. | |
204 | * @exception Always succeeds. | |
205 | */ | |
206 | int iceland_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr) | |
207 | { | |
208 | int result; | |
209 | ||
210 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | |
211 | return 0; | |
212 | ||
213 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) { | |
214 | result = iceland_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC); | |
215 | if (0 == result) | |
216 | result = iceland_fan_ctrl_start_smc_fan_control(hwmgr); | |
217 | } else | |
218 | result = iceland_fan_ctrl_set_default_mode(hwmgr); | |
219 | ||
220 | return result; | |
221 | } | |
222 | ||
223 | /** | |
224 | * Set Fan Speed in RPM. | |
225 | * @param hwmgr the address of the powerplay hardware manager. | |
226 | * @param speed is the percentage value (min - max) to be set. | |
227 | * @exception Fails is the speed not lie between min and max. | |
228 | */ | |
229 | int iceland_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed) | |
230 | { | |
231 | return 0; | |
232 | } | |
233 | ||
234 | /** | |
235 | * Reads the remote temperature from the SIslands thermal controller. | |
236 | * | |
237 | * @param hwmgr The address of the hardware manager. | |
238 | */ | |
239 | int iceland_thermal_get_temperature(struct pp_hwmgr *hwmgr) | |
240 | { | |
241 | int temp; | |
242 | ||
243 | temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_STATUS, CTF_TEMP); | |
244 | ||
245 | /* | |
246 | * Bit 9 means the reading is lower than the lowest usable | |
247 | * value. | |
248 | */ | |
249 | if (0 != (0x200 & temp)) | |
250 | temp = ICELAND_THERMAL_MAXIMUM_TEMP_READING; | |
251 | else | |
252 | temp = (temp & 0x1ff); | |
253 | ||
254 | temp = temp * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
255 | ||
256 | return temp; | |
257 | } | |
258 | ||
259 | /** | |
260 | * Set the requested temperature range for high and low alert signals | |
261 | * | |
262 | * @param hwmgr The address of the hardware manager. | |
263 | * @param range Temperature range to be programmed for high and low alert signals | |
264 | * @exception PP_Result_BadInput if the input data is not valid. | |
265 | */ | |
266 | static int iceland_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, uint32_t low_temp, uint32_t high_temp) | |
267 | { | |
268 | uint32_t low = ICELAND_THERMAL_MINIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
269 | uint32_t high = ICELAND_THERMAL_MAXIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
270 | ||
271 | if (low < low_temp) | |
272 | low = low_temp; | |
273 | if (high > high_temp) | |
274 | high = high_temp; | |
275 | ||
276 | if (low > high) | |
277 | return -EINVAL; | |
278 | ||
279 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)); | |
280 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)); | |
281 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL, DIG_THERM_DPM, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)); | |
282 | ||
283 | return 0; | |
284 | } | |
285 | ||
286 | /** | |
287 | * Programs thermal controller one-time setting registers | |
288 | * | |
289 | * @param hwmgr The address of the hardware manager. | |
290 | */ | |
291 | static int iceland_thermal_initialize(struct pp_hwmgr *hwmgr) | |
292 | { | |
293 | if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) | |
294 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, | |
295 | CG_TACH_CTRL, EDGE_PER_REV, | |
296 | hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution - 1); | |
297 | ||
298 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28); | |
299 | ||
300 | return 0; | |
301 | } | |
302 | ||
303 | /** | |
304 | * Enable thermal alerts on the RV770 thermal controller. | |
305 | * | |
306 | * @param hwmgr The address of the hardware manager. | |
307 | */ | |
308 | static int iceland_thermal_enable_alert(struct pp_hwmgr *hwmgr) | |
309 | { | |
310 | uint32_t alert; | |
311 | ||
312 | alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK); | |
313 | alert &= ~(ICELAND_THERMAL_HIGH_ALERT_MASK | ICELAND_THERMAL_LOW_ALERT_MASK); | |
314 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert); | |
315 | ||
316 | /* send message to SMU to enable internal thermal interrupts */ | |
317 | return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable) == 0) ? 0 : -1; | |
318 | } | |
319 | ||
320 | /** | |
321 | * Disable thermal alerts on the RV770 thermal controller. | |
322 | * @param hwmgr The address of the hardware manager. | |
323 | */ | |
324 | static int iceland_thermal_disable_alert(struct pp_hwmgr *hwmgr) | |
325 | { | |
326 | uint32_t alert; | |
327 | ||
328 | alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK); | |
329 | alert |= (ICELAND_THERMAL_HIGH_ALERT_MASK | ICELAND_THERMAL_LOW_ALERT_MASK); | |
330 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert); | |
331 | ||
332 | /* send message to SMU to disable internal thermal interrupts */ | |
333 | return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable) == 0) ? 0 : -1; | |
334 | } | |
335 | ||
336 | /** | |
337 | * Uninitialize the thermal controller. | |
338 | * Currently just disables alerts. | |
339 | * @param hwmgr The address of the hardware manager. | |
340 | */ | |
341 | int iceland_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr) | |
342 | { | |
343 | int result = iceland_thermal_disable_alert(hwmgr); | |
344 | ||
345 | if (result) | |
346 | pr_warning("Failed to disable thermal alerts!\n"); | |
347 | ||
348 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | |
349 | iceland_fan_ctrl_set_default_mode(hwmgr); | |
350 | ||
351 | return result; | |
352 | } | |
353 | ||
354 | /** | |
355 | * Set up the fan table to control the fan using the SMC. | |
356 | * @param hwmgr the address of the powerplay hardware manager. | |
357 | * @param pInput the pointer to input data | |
358 | * @param pOutput the pointer to output data | |
359 | * @param pStorage the pointer to temporary storage | |
360 | * @param Result the last failure code | |
361 | * @return result from set temperature range routine | |
362 | */ | |
363 | int tf_iceland_thermal_setup_fan_table(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result) | |
364 | { | |
365 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | |
366 | SMU71_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE }; | |
367 | uint32_t duty100; | |
368 | uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2; | |
369 | uint16_t fdo_min, slope1, slope2; | |
370 | uint32_t reference_clock; | |
371 | int res; | |
372 | uint64_t tmp64; | |
373 | ||
374 | if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) | |
375 | return 0; | |
376 | ||
377 | if (0 == data->fan_table_start) { | |
378 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl); | |
379 | return 0; | |
380 | } | |
381 | ||
382 | duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100); | |
383 | ||
384 | if (0 == duty100) { | |
385 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl); | |
386 | return 0; | |
387 | } | |
388 | ||
389 | tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin * duty100; | |
390 | do_div(tmp64, 10000); | |
391 | fdo_min = (uint16_t)tmp64; | |
392 | ||
393 | t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed - hwmgr->thermal_controller.advanceFanControlParameters.usTMin; | |
394 | t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh - hwmgr->thermal_controller.advanceFanControlParameters.usTMed; | |
395 | ||
396 | pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin; | |
397 | pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed; | |
398 | ||
399 | slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100); | |
400 | slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100); | |
401 | ||
402 | fan_table.TempMin = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMin) / 100); | |
403 | fan_table.TempMed = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMed) / 100); | |
404 | fan_table.TempMax = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMax) / 100); | |
405 | ||
406 | fan_table.Slope1 = cpu_to_be16(slope1); | |
407 | fan_table.Slope2 = cpu_to_be16(slope2); | |
408 | ||
409 | fan_table.FdoMin = cpu_to_be16(fdo_min); | |
410 | ||
411 | fan_table.HystDown = cpu_to_be16(hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst); | |
412 | ||
413 | fan_table.HystUp = cpu_to_be16(1); | |
414 | ||
415 | fan_table.HystSlope = cpu_to_be16(1); | |
416 | ||
417 | fan_table.TempRespLim = cpu_to_be16(5); | |
418 | ||
419 | reference_clock = iceland_get_xclk(hwmgr); | |
420 | ||
421 | fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600); | |
422 | ||
423 | fan_table.FdoMax = cpu_to_be16((uint16_t)duty100); | |
424 | ||
425 | fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_CTRL, TEMP_SEL); | |
426 | ||
427 | //fan_table.FanControl_GL_Flag = 1; | |
428 | ||
429 | res = iceland_copy_bytes_to_smc(hwmgr->smumgr, data->fan_table_start, (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table), data->sram_end); | |
430 | /* TO DO FOR SOME DEVICE ID 0X692b, send this msg return invalid command. | |
431 | if (res == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit != 0) | |
432 | res = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanMinPwm, \ | |
433 | hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit) ? 0 : -1); | |
434 | ||
435 | if (res == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit != 0) | |
436 | res = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanSclkTarget, \ | |
437 | hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit) ? 0 : -1); | |
438 | ||
439 | if (0 != res) | |
440 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl); | |
441 | */ | |
442 | return 0; | |
443 | } | |
444 | ||
445 | /** | |
446 | * Start the fan control on the SMC. | |
447 | * @param hwmgr the address of the powerplay hardware manager. | |
448 | * @param pInput the pointer to input data | |
449 | * @param pOutput the pointer to output data | |
450 | * @param pStorage the pointer to temporary storage | |
451 | * @param Result the last failure code | |
452 | * @return result from set temperature range routine | |
453 | */ | |
454 | int tf_iceland_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result) | |
455 | { | |
456 | /* If the fantable setup has failed we could have disabled PHM_PlatformCaps_MicrocodeFanControl even after this function was included in the table. | |
457 | * Make sure that we still think controlling the fan is OK. | |
458 | */ | |
459 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) { | |
460 | iceland_fan_ctrl_start_smc_fan_control(hwmgr); | |
461 | iceland_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC); | |
462 | } | |
463 | ||
464 | return 0; | |
465 | } | |
466 | ||
467 | /** | |
468 | * Set temperature range for high and low alerts | |
469 | * @param hwmgr the address of the powerplay hardware manager. | |
470 | * @param pInput the pointer to input data | |
471 | * @param pOutput the pointer to output data | |
472 | * @param pStorage the pointer to temporary storage | |
473 | * @param Result the last failure code | |
474 | * @return result from set temperature range routine | |
475 | */ | |
476 | static int tf_iceland_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, | |
477 | void *input, void *output, void *storage, int result) | |
478 | { | |
479 | struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input; | |
480 | ||
481 | if (range == NULL) | |
482 | return -EINVAL; | |
483 | ||
484 | return iceland_thermal_set_temperature_range(hwmgr, range->min, range->max); | |
485 | } | |
486 | ||
487 | /** | |
488 | * Programs one-time setting registers | |
489 | * @param hwmgr the address of the powerplay hardware manager. | |
490 | * @param pInput the pointer to input data | |
491 | * @param pOutput the pointer to output data | |
492 | * @param pStorage the pointer to temporary storage | |
493 | * @param Result the last failure code | |
494 | * @return result from initialize thermal controller routine | |
495 | */ | |
496 | static int tf_iceland_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, | |
497 | void *output, void *storage, int result) | |
498 | { | |
499 | return iceland_thermal_initialize(hwmgr); | |
500 | } | |
501 | ||
502 | /** | |
503 | * Enable high and low alerts | |
504 | * @param hwmgr the address of the powerplay hardware manager. | |
505 | * @param pInput the pointer to input data | |
506 | * @param pOutput the pointer to output data | |
507 | * @param pStorage the pointer to temporary storage | |
508 | * @param Result the last failure code | |
509 | * @return result from enable alert routine | |
510 | */ | |
511 | static int tf_iceland_thermal_enable_alert(struct pp_hwmgr *hwmgr, | |
512 | void *input, void *output, void *storage, int result) | |
513 | { | |
514 | return iceland_thermal_enable_alert(hwmgr); | |
515 | } | |
516 | ||
517 | /** | |
518 | * Disable high and low alerts | |
519 | * @param hwmgr the address of the powerplay hardware manager. | |
520 | * @param pInput the pointer to input data | |
521 | * @param pOutput the pointer to output data | |
522 | * @param pStorage the pointer to temporary storage | |
523 | * @param Result the last failure code | |
524 | * @return result from disable alert routine | |
525 | */ | |
526 | static int tf_iceland_thermal_disable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result) | |
527 | { | |
528 | return iceland_thermal_disable_alert(hwmgr); | |
529 | } | |
530 | ||
531 | static const struct phm_master_table_item iceland_thermal_start_thermal_controller_master_list[] = { | |
532 | { NULL, tf_iceland_thermal_initialize }, | |
533 | { NULL, tf_iceland_thermal_set_temperature_range }, | |
534 | { NULL, tf_iceland_thermal_enable_alert }, | |
535 | /* | |
536 | * We should restrict performance levels to low before we halt | |
537 | * the SMC. On the other hand we are still in boot state when | |
538 | * we do this so it would be pointless. If this assumption | |
539 | * changes we have to revisit this table. | |
540 | */ | |
541 | { NULL, tf_iceland_thermal_setup_fan_table}, | |
542 | { NULL, tf_iceland_thermal_start_smc_fan_control}, | |
543 | { NULL, NULL } | |
544 | }; | |
545 | ||
546 | static const struct phm_master_table_header iceland_thermal_start_thermal_controller_master = { | |
547 | 0, | |
548 | PHM_MasterTableFlag_None, | |
549 | iceland_thermal_start_thermal_controller_master_list | |
550 | }; | |
551 | ||
552 | static const struct phm_master_table_item iceland_thermal_set_temperature_range_master_list[] = { | |
553 | { NULL, tf_iceland_thermal_disable_alert}, | |
554 | { NULL, tf_iceland_thermal_set_temperature_range}, | |
555 | { NULL, tf_iceland_thermal_enable_alert}, | |
556 | { NULL, NULL } | |
557 | }; | |
558 | ||
559 | static const struct phm_master_table_header iceland_thermal_set_temperature_range_master = { | |
560 | 0, | |
561 | PHM_MasterTableFlag_None, | |
562 | iceland_thermal_set_temperature_range_master_list | |
563 | }; | |
564 | ||
565 | int iceland_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr) | |
566 | { | |
567 | if (!hwmgr->thermal_controller.fanInfo.bNoFan) | |
568 | iceland_fan_ctrl_set_default_mode(hwmgr); | |
569 | return 0; | |
570 | } | |
571 | ||
572 | /** | |
573 | * Initializes the thermal controller related functions in the Hardware Manager structure. | |
574 | * @param hwmgr The address of the hardware manager. | |
575 | * @exception Any error code from the low-level communication. | |
576 | */ | |
577 | int pp_iceland_thermal_initialize(struct pp_hwmgr *hwmgr) | |
578 | { | |
579 | int result; | |
580 | ||
581 | result = phm_construct_table(hwmgr, &iceland_thermal_set_temperature_range_master, &(hwmgr->set_temperature_range)); | |
582 | ||
583 | if (0 == result) { | |
584 | result = phm_construct_table(hwmgr, | |
585 | &iceland_thermal_start_thermal_controller_master, | |
586 | &(hwmgr->start_thermal_controller)); | |
587 | if (0 != result) | |
588 | phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range)); | |
589 | } | |
590 | ||
591 | if (0 == result) | |
592 | hwmgr->fan_ctrl_is_in_default_mode = true; | |
593 | return result; | |
594 | } | |
595 |