Commit | Line | Data |
---|---|---|
1e4854e9 RZ |
1 | /* |
2 | * Copyright 2015 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 | */ | |
8a0d560f | 23 | #include <asm/div64.h> |
1e4854e9 RZ |
24 | #include "tonga_thermal.h" |
25 | #include "tonga_hwmgr.h" | |
26 | #include "tonga_smumgr.h" | |
27 | #include "tonga_ppsmc.h" | |
28 | #include "smu/smu_7_1_2_d.h" | |
29 | #include "smu/smu_7_1_2_sh_mask.h" | |
30 | ||
31 | /** | |
32 | * Get Fan Speed Control Parameters. | |
33 | * @param hwmgr the address of the powerplay hardware manager. | |
34 | * @param pSpeed is the address of the structure where the result is to be placed. | |
35 | * @exception Always succeeds except if we cannot zero out the output structure. | |
36 | */ | |
37 | int tonga_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info) | |
38 | { | |
39 | ||
40 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | |
41 | return 0; | |
42 | ||
43 | fan_speed_info->supports_percent_read = true; | |
44 | fan_speed_info->supports_percent_write = true; | |
45 | fan_speed_info->min_percent = 0; | |
46 | fan_speed_info->max_percent = 100; | |
47 | ||
48 | if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) { | |
49 | fan_speed_info->supports_rpm_read = true; | |
50 | fan_speed_info->supports_rpm_write = true; | |
51 | fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM; | |
52 | fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM; | |
53 | } else { | |
54 | fan_speed_info->min_rpm = 0; | |
55 | fan_speed_info->max_rpm = 0; | |
56 | } | |
57 | ||
58 | return 0; | |
59 | } | |
60 | ||
61 | /** | |
62 | * Get Fan Speed in percent. | |
63 | * @param hwmgr the address of the powerplay hardware manager. | |
64 | * @param pSpeed is the address of the structure where the result is to be placed. | |
65 | * @exception Fails is the 100% setting appears to be 0. | |
66 | */ | |
67 | int tonga_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed) | |
68 | { | |
69 | uint32_t duty100; | |
70 | uint32_t duty; | |
71 | uint64_t tmp64; | |
72 | ||
73 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | |
74 | return 0; | |
75 | ||
76 | duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100); | |
77 | duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_STATUS, FDO_PWM_DUTY); | |
78 | ||
79 | if (0 == duty100) | |
80 | return -EINVAL; | |
81 | ||
82 | ||
83 | tmp64 = (uint64_t)duty * 100; | |
84 | do_div(tmp64, duty100); | |
85 | *speed = (uint32_t)tmp64; | |
86 | ||
87 | if (*speed > 100) | |
88 | *speed = 100; | |
89 | ||
90 | return 0; | |
91 | } | |
92 | ||
93 | /** | |
94 | * Get Fan Speed in RPM. | |
95 | * @param hwmgr the address of the powerplay hardware manager. | |
96 | * @param speed is the address of the structure where the result is to be placed. | |
97 | * @exception Returns not supported if no fan is found or if pulses per revolution are not set | |
98 | */ | |
99 | int tonga_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed) | |
100 | { | |
101 | return 0; | |
102 | } | |
103 | ||
104 | /** | |
105 | * Set Fan Speed Control to static mode, so that the user can decide what speed to use. | |
106 | * @param hwmgr the address of the powerplay hardware manager. | |
107 | * mode the fan control mode, 0 default, 1 by percent, 5, by RPM | |
108 | * @exception Should always succeed. | |
109 | */ | |
110 | int tonga_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode) | |
111 | { | |
112 | ||
113 | if (hwmgr->fan_ctrl_is_in_default_mode) { | |
114 | hwmgr->fan_ctrl_default_mode = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE); | |
115 | hwmgr->tmin = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN); | |
116 | hwmgr->fan_ctrl_is_in_default_mode = false; | |
117 | } | |
118 | ||
119 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, 0); | |
120 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, mode); | |
121 | ||
122 | return 0; | |
123 | } | |
124 | ||
125 | /** | |
126 | * Reset Fan Speed Control to default mode. | |
127 | * @param hwmgr the address of the powerplay hardware manager. | |
128 | * @exception Should always succeed. | |
129 | */ | |
130 | int tonga_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr) | |
131 | { | |
7ae0a661 | 132 | if (!hwmgr->fan_ctrl_is_in_default_mode) { |
1e4854e9 RZ |
133 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode); |
134 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, hwmgr->tmin); | |
135 | hwmgr->fan_ctrl_is_in_default_mode = true; | |
136 | } | |
137 | ||
138 | return 0; | |
139 | } | |
140 | ||
141 | int tonga_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr) | |
142 | { | |
143 | int result; | |
144 | ||
145 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ODFuzzyFanControlSupport)) { | |
146 | cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_FUZZY); | |
147 | result = (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl) == 0) ? 0 : -EINVAL; | |
148 | /* | |
149 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_FanSpeedInTableIsRPM)) | |
150 | hwmgr->set_max_fan_rpm_output(hwmgr, hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM); | |
151 | else | |
152 | hwmgr->set_max_fan_pwm_output(hwmgr, hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM); | |
153 | */ | |
154 | } else { | |
155 | cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_TABLE); | |
156 | result = (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl) == 0) ? 0 : -EINVAL; | |
157 | } | |
158 | /* TO DO FOR SOME DEVICE ID 0X692b, send this msg return invalid command. | |
159 | if (result == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature != 0) | |
160 | result = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanTemperatureTarget, \ | |
161 | hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature) ? 0 : -EINVAL); | |
162 | */ | |
163 | return result; | |
164 | } | |
165 | ||
166 | ||
167 | int tonga_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr) | |
168 | { | |
169 | return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl) == 0) ? 0 : -EINVAL; | |
170 | } | |
171 | ||
172 | /** | |
173 | * Set Fan Speed in percent. | |
174 | * @param hwmgr the address of the powerplay hardware manager. | |
175 | * @param speed is the percentage value (0% - 100%) to be set. | |
176 | * @exception Fails is the 100% setting appears to be 0. | |
177 | */ | |
178 | int tonga_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed) | |
179 | { | |
180 | uint32_t duty100; | |
181 | uint32_t duty; | |
182 | uint64_t tmp64; | |
183 | ||
184 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | |
185 | return -EINVAL; | |
186 | ||
187 | if (speed > 100) | |
188 | speed = 100; | |
189 | ||
190 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) | |
191 | tonga_fan_ctrl_stop_smc_fan_control(hwmgr); | |
192 | ||
193 | duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100); | |
194 | ||
195 | if (0 == duty100) | |
196 | return -EINVAL; | |
197 | ||
198 | tmp64 = (uint64_t)speed * 100; | |
199 | do_div(tmp64, duty100); | |
200 | duty = (uint32_t)tmp64; | |
201 | ||
202 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL0, FDO_STATIC_DUTY, duty); | |
203 | ||
204 | return tonga_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC); | |
205 | } | |
206 | ||
207 | /** | |
208 | * Reset Fan Speed to default. | |
209 | * @param hwmgr the address of the powerplay hardware manager. | |
210 | * @exception Always succeeds. | |
211 | */ | |
212 | int tonga_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr) | |
213 | { | |
214 | int result; | |
215 | ||
216 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | |
217 | return 0; | |
218 | ||
219 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) { | |
220 | result = tonga_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC); | |
221 | if (0 == result) | |
222 | result = tonga_fan_ctrl_start_smc_fan_control(hwmgr); | |
223 | } else | |
224 | result = tonga_fan_ctrl_set_default_mode(hwmgr); | |
225 | ||
226 | return result; | |
227 | } | |
228 | ||
229 | /** | |
230 | * Set Fan Speed in RPM. | |
231 | * @param hwmgr the address of the powerplay hardware manager. | |
232 | * @param speed is the percentage value (min - max) to be set. | |
233 | * @exception Fails is the speed not lie between min and max. | |
234 | */ | |
235 | int tonga_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed) | |
236 | { | |
237 | return 0; | |
238 | } | |
239 | ||
240 | /** | |
241 | * Reads the remote temperature from the SIslands thermal controller. | |
242 | * | |
243 | * @param hwmgr The address of the hardware manager. | |
244 | */ | |
245 | int tonga_thermal_get_temperature(struct pp_hwmgr *hwmgr) | |
246 | { | |
247 | int temp; | |
248 | ||
249 | temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_STATUS, CTF_TEMP); | |
250 | ||
251 | /* Bit 9 means the reading is lower than the lowest usable value. */ | |
252 | if (0 != (0x200 & temp)) | |
253 | temp = TONGA_THERMAL_MAXIMUM_TEMP_READING; | |
254 | else | |
255 | temp = (temp & 0x1ff); | |
256 | ||
257 | temp = temp * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
258 | ||
259 | return temp; | |
260 | } | |
261 | ||
262 | /** | |
263 | * Set the requested temperature range for high and low alert signals | |
264 | * | |
265 | * @param hwmgr The address of the hardware manager. | |
266 | * @param range Temperature range to be programmed for high and low alert signals | |
267 | * @exception PP_Result_BadInput if the input data is not valid. | |
268 | */ | |
269 | static int tonga_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, uint32_t low_temp, uint32_t high_temp) | |
270 | { | |
271 | uint32_t low = TONGA_THERMAL_MINIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
272 | uint32_t high = TONGA_THERMAL_MAXIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; | |
273 | ||
274 | if (low < low_temp) | |
275 | low = low_temp; | |
276 | if (high > high_temp) | |
277 | high = high_temp; | |
278 | ||
279 | if (low > high) | |
280 | return -EINVAL; | |
281 | ||
282 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)); | |
283 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)); | |
284 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL, DIG_THERM_DPM, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)); | |
285 | ||
286 | return 0; | |
287 | } | |
288 | ||
289 | /** | |
290 | * Programs thermal controller one-time setting registers | |
291 | * | |
292 | * @param hwmgr The address of the hardware manager. | |
293 | */ | |
294 | static int tonga_thermal_initialize(struct pp_hwmgr *hwmgr) | |
295 | { | |
296 | if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) | |
297 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, | |
298 | CG_TACH_CTRL, EDGE_PER_REV, | |
299 | hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution - 1); | |
300 | ||
301 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28); | |
302 | ||
303 | return 0; | |
304 | } | |
305 | ||
306 | /** | |
307 | * Enable thermal alerts on the RV770 thermal controller. | |
308 | * | |
309 | * @param hwmgr The address of the hardware manager. | |
310 | */ | |
311 | static int tonga_thermal_enable_alert(struct pp_hwmgr *hwmgr) | |
312 | { | |
313 | uint32_t alert; | |
314 | ||
315 | alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK); | |
316 | alert &= ~(TONGA_THERMAL_HIGH_ALERT_MASK | TONGA_THERMAL_LOW_ALERT_MASK); | |
317 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert); | |
318 | ||
319 | /* send message to SMU to enable internal thermal interrupts */ | |
320 | return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable) == 0) ? 0 : -1; | |
321 | } | |
322 | ||
323 | /** | |
324 | * Disable thermal alerts on the RV770 thermal controller. | |
325 | * @param hwmgr The address of the hardware manager. | |
326 | */ | |
327 | static int tonga_thermal_disable_alert(struct pp_hwmgr *hwmgr) | |
328 | { | |
329 | uint32_t alert; | |
330 | ||
331 | alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK); | |
332 | alert |= (TONGA_THERMAL_HIGH_ALERT_MASK | TONGA_THERMAL_LOW_ALERT_MASK); | |
333 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert); | |
334 | ||
335 | /* send message to SMU to disable internal thermal interrupts */ | |
336 | return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable) == 0) ? 0 : -1; | |
337 | } | |
338 | ||
339 | /** | |
340 | * Uninitialize the thermal controller. | |
341 | * Currently just disables alerts. | |
342 | * @param hwmgr The address of the hardware manager. | |
343 | */ | |
344 | int tonga_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr) | |
345 | { | |
346 | int result = tonga_thermal_disable_alert(hwmgr); | |
347 | ||
348 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | |
349 | tonga_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_tonga_thermal_setup_fan_table(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result) | |
364 | { | |
365 | struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); | |
366 | SMU72_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 | ||
45b0cf54 AD |
374 | if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) |
375 | return 0; | |
376 | ||
1e4854e9 RZ |
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 = tonga_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 = tonga_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_tonga_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 | tonga_fan_ctrl_start_smc_fan_control(hwmgr); | |
461 | tonga_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 | int tf_tonga_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result) | |
477 | { | |
478 | struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input; | |
479 | ||
480 | if (range == NULL) | |
481 | return -EINVAL; | |
482 | ||
483 | return tonga_thermal_set_temperature_range(hwmgr, range->min, range->max); | |
484 | } | |
485 | ||
486 | /** | |
487 | * Programs one-time setting registers | |
488 | * @param hwmgr the address of the powerplay hardware manager. | |
489 | * @param pInput the pointer to input data | |
490 | * @param pOutput the pointer to output data | |
491 | * @param pStorage the pointer to temporary storage | |
492 | * @param Result the last failure code | |
493 | * @return result from initialize thermal controller routine | |
494 | */ | |
495 | int tf_tonga_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result) | |
496 | { | |
497 | return tonga_thermal_initialize(hwmgr); | |
498 | } | |
499 | ||
500 | /** | |
501 | * Enable high and low alerts | |
502 | * @param hwmgr the address of the powerplay hardware manager. | |
503 | * @param pInput the pointer to input data | |
504 | * @param pOutput the pointer to output data | |
505 | * @param pStorage the pointer to temporary storage | |
506 | * @param Result the last failure code | |
507 | * @return result from enable alert routine | |
508 | */ | |
509 | int tf_tonga_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result) | |
510 | { | |
511 | return tonga_thermal_enable_alert(hwmgr); | |
512 | } | |
513 | ||
514 | /** | |
515 | * Disable high and low alerts | |
516 | * @param hwmgr the address of the powerplay hardware manager. | |
517 | * @param pInput the pointer to input data | |
518 | * @param pOutput the pointer to output data | |
519 | * @param pStorage the pointer to temporary storage | |
520 | * @param Result the last failure code | |
521 | * @return result from disable alert routine | |
522 | */ | |
523 | static int tf_tonga_thermal_disable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result) | |
524 | { | |
525 | return tonga_thermal_disable_alert(hwmgr); | |
526 | } | |
527 | ||
528 | static struct phm_master_table_item tonga_thermal_start_thermal_controller_master_list[] = { | |
529 | { NULL, tf_tonga_thermal_initialize }, | |
530 | { NULL, tf_tonga_thermal_set_temperature_range }, | |
531 | { NULL, tf_tonga_thermal_enable_alert }, | |
532 | /* We should restrict performance levels to low before we halt the SMC. | |
533 | * On the other hand we are still in boot state when we do this so it would be pointless. | |
534 | * If this assumption changes we have to revisit this table. | |
535 | */ | |
536 | { NULL, tf_tonga_thermal_setup_fan_table}, | |
537 | { NULL, tf_tonga_thermal_start_smc_fan_control}, | |
538 | { NULL, NULL } | |
539 | }; | |
540 | ||
541 | static struct phm_master_table_header tonga_thermal_start_thermal_controller_master = { | |
542 | 0, | |
543 | PHM_MasterTableFlag_None, | |
544 | tonga_thermal_start_thermal_controller_master_list | |
545 | }; | |
546 | ||
547 | static struct phm_master_table_item tonga_thermal_set_temperature_range_master_list[] = { | |
548 | { NULL, tf_tonga_thermal_disable_alert}, | |
549 | { NULL, tf_tonga_thermal_set_temperature_range}, | |
550 | { NULL, tf_tonga_thermal_enable_alert}, | |
551 | { NULL, NULL } | |
552 | }; | |
553 | ||
554 | struct phm_master_table_header tonga_thermal_set_temperature_range_master = { | |
555 | 0, | |
556 | PHM_MasterTableFlag_None, | |
557 | tonga_thermal_set_temperature_range_master_list | |
558 | }; | |
559 | ||
560 | int tonga_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr) | |
561 | { | |
562 | if (!hwmgr->thermal_controller.fanInfo.bNoFan) | |
563 | tonga_fan_ctrl_set_default_mode(hwmgr); | |
564 | return 0; | |
565 | } | |
566 | ||
567 | /** | |
568 | * Initializes the thermal controller related functions in the Hardware Manager structure. | |
569 | * @param hwmgr The address of the hardware manager. | |
570 | * @exception Any error code from the low-level communication. | |
571 | */ | |
572 | int pp_tonga_thermal_initialize(struct pp_hwmgr *hwmgr) | |
573 | { | |
574 | int result; | |
575 | ||
576 | result = phm_construct_table(hwmgr, &tonga_thermal_set_temperature_range_master, &(hwmgr->set_temperature_range)); | |
577 | ||
578 | if (0 == result) { | |
579 | result = phm_construct_table(hwmgr, | |
580 | &tonga_thermal_start_thermal_controller_master, | |
581 | &(hwmgr->start_thermal_controller)); | |
582 | if (0 != result) | |
583 | phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range)); | |
584 | } | |
585 | ||
586 | if (0 == result) | |
587 | hwmgr->fan_ctrl_is_in_default_mode = true; | |
588 | return result; | |
589 | } | |
590 |